gpm.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. <?php
  2. namespace Grav\Plugin\Admin;
  3. use Grav\Common\GravTrait;
  4. use Grav\Common\GPM\GPM as GravGPM;
  5. use Grav\Common\GPM\Installer;
  6. use Grav\Common\GPM\Response;
  7. use Grav\Common\GPM\Upgrader;
  8. use Grav\Common\Filesystem\Folder;
  9. use Grav\Common\GPM\Common\Package;
  10. class Gpm
  11. {
  12. use GravTrait;
  13. // Probably should move this to Grav DI container?
  14. protected static $GPM;
  15. public static function GPM()
  16. {
  17. if (!static::$GPM) {
  18. static::$GPM = new GravGPM();
  19. }
  20. return static::$GPM;
  21. }
  22. /**
  23. * Default options for the install
  24. * @var array
  25. */
  26. protected static $options = [
  27. 'destination' => GRAV_ROOT,
  28. 'overwrite' => true,
  29. 'ignore_symlinks' => true,
  30. 'skip_invalid' => true,
  31. 'install_deps' => true,
  32. 'theme' => false
  33. ];
  34. public static function install($packages, $options)
  35. {
  36. $options = array_merge(self::$options, $options);
  37. if (
  38. !Installer::isGravInstance($options['destination']) ||
  39. !Installer::isValidDestination($options['destination'], [Installer::EXISTS, Installer::IS_LINK])
  40. ) {
  41. return false;
  42. }
  43. $packages = is_array($packages) ? $packages : [ $packages ];
  44. $count = count($packages);
  45. $packages = array_filter(array_map(function ($p) {
  46. return !is_string($p) ? $p instanceof Package ? $p : false : self::GPM()->findPackage($p);
  47. }, $packages));
  48. if (!$options['skip_invalid'] && $count !== count($packages)) {
  49. return false;
  50. }
  51. foreach ($packages as $package) {
  52. if (isset($package->dependencies) && $options['install_deps']) {
  53. $result = static::install($package->dependencies, $options);
  54. if (!$result) {
  55. return false;
  56. }
  57. }
  58. // Check destination
  59. Installer::isValidDestination($options['destination'] . DS . $package->install_path);
  60. if (Installer::lastErrorCode() === Installer::EXISTS && !$options['overwrite']) {
  61. return false;
  62. }
  63. if (Installer::lastErrorCode() === Installer::IS_LINK && !$options['ignore_symlinks']) {
  64. return false;
  65. }
  66. $local = static::download($package);
  67. Installer::install($local, $options['destination'], ['install_path' => $package->install_path, 'theme' => $options['theme']]);
  68. Folder::delete(dirname($local));
  69. $errorCode = Installer::lastErrorCode();
  70. if (Installer::lastErrorCode() & (Installer::ZIP_OPEN_ERROR | Installer::ZIP_EXTRACT_ERROR)) {
  71. return false;
  72. }
  73. }
  74. return true;
  75. }
  76. public static function update($packages, $options)
  77. {
  78. $options['overwrite'] = true;
  79. return static::install($packages, $options);
  80. }
  81. public static function uninstall($packages, $options)
  82. {
  83. $options = array_merge(self::$options, $options);
  84. $packages = is_array($packages) ? $packages : [ $packages ];
  85. $count = count($packages);
  86. $packages = array_filter(array_map(function ($p) {
  87. if (is_string($p)) {
  88. $p = strtolower($p);
  89. $plugin = static::GPM()->getInstalledPlugin($p);
  90. $p = $plugin ?: static::GPM()->getInstalledTheme($p);
  91. }
  92. return $p instanceof Package ? $p : false;
  93. }, $packages));
  94. if (!$options['skip_invalid'] && $count !== count($packages)) {
  95. return false;
  96. }
  97. foreach ($packages as $package) {
  98. $location = self::getGrav()['locator']->findResource($package->package_type . '://' . $package->slug);
  99. // Check destination
  100. Installer::isValidDestination($location);
  101. if (Installer::lastErrorCode() === Installer::IS_LINK && !$options['ignore_symlinks']) {
  102. return false;
  103. }
  104. Installer::uninstall($location);
  105. $errorCode = Installer::lastErrorCode();
  106. if ($errorCode && $errorCode !== Installer::IS_LINK && $errorCode !== Installer::EXISTS) {
  107. return false;
  108. }
  109. }
  110. return true;
  111. }
  112. private static function download($package)
  113. {
  114. $contents = Response::get($package->zipball_url, []);
  115. $cache_dir = self::getGrav()['locator']->findResource('cache://', true);
  116. $cache_dir = $cache_dir . DS . 'tmp/Grav-' . uniqid();
  117. Folder::mkdir($cache_dir);
  118. $filename = $package->slug . basename($package->zipball_url);
  119. file_put_contents($cache_dir . DS . $filename, $contents);
  120. return $cache_dir . DS . $filename;
  121. }
  122. private static function _downloadSelfupgrade($package, $tmp)
  123. {
  124. $output = Response::get($package['download'], []);
  125. Folder::mkdir($tmp);
  126. file_put_contents($tmp . DS . $package['name'], $output);
  127. return $tmp . DS . $package['name'];
  128. }
  129. public static function selfupgrade() {
  130. $upgrader = new Upgrader();
  131. if (!Installer::isGravInstance(GRAV_ROOT)) {
  132. return false;
  133. }
  134. if (is_link(GRAV_ROOT . DS . 'index.php')) {
  135. Installer::setError(Installer::IS_LINK);
  136. return false;
  137. }
  138. $update = $upgrader->getAssets()['grav-update'];
  139. $tmp = CACHE_DIR . 'tmp/Grav-' . uniqid();
  140. $file = self::_downloadSelfupgrade($update, $tmp);
  141. Installer::install($file, GRAV_ROOT,
  142. ['sophisticated' => true, 'overwrite' => true, 'ignore_symlinks' => true]);
  143. $errorCode = Installer::lastErrorCode();
  144. Folder::delete($tmp);
  145. if ($errorCode & (Installer::ZIP_OPEN_ERROR | Installer::ZIP_EXTRACT_ERROR)) {
  146. return false;
  147. }
  148. return true;
  149. }
  150. }