PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/system/console/OctoberUtil.php

https://bitbucket.org/egerstudio/livskilden
PHP | 339 lines | 215 code | 55 blank | 69 comment | 24 complexity | 98adef94c83524ee9d21dc5240c62e99 MD5 | raw file
Possible License(s): MIT, BSD-3-Clause, Apache-2.0
  1. <?php namespace System\Console;
  2. use App;
  3. use Lang;
  4. use File;
  5. use Config;
  6. use Illuminate\Console\Command;
  7. use Symfony\Component\Console\Input\InputOption;
  8. use Symfony\Component\Console\Input\InputArgument;
  9. use System\Classes\UpdateManager;
  10. use System\Classes\CombineAssets;
  11. use Exception;
  12. /**
  13. * Console command for other utility commands.
  14. *
  15. * This provides functionality that doesn't quite deserve its own dedicated
  16. * console class. It is used mostly developer tools and maintenance tasks.
  17. *
  18. * Currently supported commands:
  19. *
  20. * - purge thumbs: Deletes all thumbnail files in the uploads directory.
  21. * - git pull: Perform "git pull" on all plugins and themes.
  22. * - compile assets: Compile registered Language, LESS and JS files.
  23. * - compile js: Compile registered JS files only.
  24. * - compile less: Compile registered LESS files only.
  25. * - compile scss: Compile registered SCSS files only.
  26. * - compile lang: Compile registered Language files only.
  27. * - set build: Pull the latest stable build number from the update gateway and set it as the current build number.
  28. *
  29. * @package october\system
  30. * @author Alexey Bobkov, Samuel Georges
  31. */
  32. class OctoberUtil extends Command
  33. {
  34. use \Illuminate\Console\ConfirmableTrait;
  35. /**
  36. * The console command name.
  37. */
  38. protected $name = 'october:util';
  39. /**
  40. * The console command description.
  41. */
  42. protected $description = 'Utility commands for October';
  43. /**
  44. * Create a new command instance.
  45. */
  46. public function __construct()
  47. {
  48. parent::__construct();
  49. }
  50. /**
  51. * Execute the console command.
  52. */
  53. public function handle()
  54. {
  55. $command = implode(' ', (array) $this->argument('name'));
  56. $method = 'util'.studly_case($command);
  57. $methods = preg_grep('/^util/', get_class_methods(get_called_class()));
  58. $list = array_map(function ($item) {
  59. return "october:".snake_case($item, " ");
  60. }, $methods);
  61. if (!$this->argument('name')) {
  62. $message = 'There are no commands defined in the "util" namespace.';
  63. if (1 == count($list)) {
  64. $message .= "\n\nDid you mean this?\n ";
  65. } else {
  66. $message .= "\n\nDid you mean one of these?\n ";
  67. }
  68. $message .= implode("\n ", $list);
  69. throw new \InvalidArgumentException($message);
  70. }
  71. if (!method_exists($this, $method)) {
  72. $this->error(sprintf('Utility command "%s" does not exist!', $command));
  73. return;
  74. }
  75. $this->$method();
  76. }
  77. /**
  78. * Get the console command arguments.
  79. * @return array
  80. */
  81. protected function getArguments()
  82. {
  83. return [
  84. ['name', InputArgument::IS_ARRAY, 'The utility command to perform, For more info "http://octobercms.com/docs/console/commands#october-util-command".'],
  85. ];
  86. }
  87. /**
  88. * Get the console command options.
  89. */
  90. protected function getOptions()
  91. {
  92. return [
  93. ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],
  94. ['debug', null, InputOption::VALUE_NONE, 'Run the operation in debug / development mode.'],
  95. ];
  96. }
  97. //
  98. // Utilties
  99. //
  100. protected function utilSetBuild()
  101. {
  102. $this->comment('-');
  103. /*
  104. * Skip setting the build number if no database is detected to set it within
  105. */
  106. if (!App::hasDatabase()) {
  107. $this->comment('No database detected - skipping setting the build number.');
  108. return;
  109. }
  110. try {
  111. $build = UpdateManager::instance()->setBuildNumberManually();
  112. $this->comment('*** October sets build: '.$build);
  113. }
  114. catch (Exception $ex) {
  115. $this->comment('*** You were kicked from #october by Ex: ('.$ex->getMessage().')');
  116. }
  117. $this->comment('-');
  118. sleep(1);
  119. $this->comment('Ping? Pong!');
  120. $this->comment('-');
  121. sleep(1);
  122. $this->comment('Ping? Pong!');
  123. $this->comment('-');
  124. }
  125. protected function utilCompileJs()
  126. {
  127. $this->utilCompileAssets('js');
  128. }
  129. protected function utilCompileLess()
  130. {
  131. $this->utilCompileAssets('less');
  132. }
  133. protected function utilCompileScss()
  134. {
  135. $this->utilCompileAssets('scss');
  136. }
  137. protected function utilCompileAssets($type = null)
  138. {
  139. $this->comment('Compiling registered asset bundles...');
  140. Config::set('cms.enableAssetMinify', !$this->option('debug'));
  141. $combiner = CombineAssets::instance();
  142. $bundles = $combiner->getBundles($type);
  143. if (!$bundles){
  144. $this->comment('Nothing to compile!');
  145. return;
  146. }
  147. if ($type) {
  148. $bundles = [$bundles];
  149. }
  150. foreach ($bundles as $bundleType) {
  151. foreach ($bundleType as $destination => $assets) {
  152. $destination = File::symbolizePath($destination);
  153. $publicDest = File::localToPublic(realpath(dirname($destination))) . '/' . basename($destination);
  154. $combiner->combineToFile($assets, $destination);
  155. $shortAssets = implode(', ', array_map('basename', $assets));
  156. $this->comment($shortAssets);
  157. $this->comment(sprintf(' -> %s', $publicDest));
  158. }
  159. }
  160. if ($type === null) {
  161. $this->utilCompileLang();
  162. }
  163. }
  164. protected function utilCompileLang()
  165. {
  166. if (!$locales = Lang::get('system::lang.locale')) {
  167. return;
  168. }
  169. $this->comment('Compiling client-side language files...');
  170. $locales = array_keys($locales);
  171. $stub = base_path() . '/modules/system/assets/js/lang/lang.stub';
  172. foreach ($locales as $locale) {
  173. /*
  174. * Generate messages
  175. */
  176. $fallbackPath = base_path() . '/modules/system/lang/en/client.php';
  177. $srcPath = base_path() . '/modules/system/lang/'.$locale.'/client.php';
  178. $messages = require $fallbackPath;
  179. if (File::isFile($srcPath) && $fallbackPath != $srcPath) {
  180. $messages = array_replace_recursive($messages, require $srcPath);
  181. }
  182. /*
  183. * Load possible replacements from /lang
  184. */
  185. $overridePath = base_path() . '/lang/'.$locale.'/system/client.php';
  186. if (File::isFile($overridePath)) {
  187. $messages = array_replace_recursive($messages, require $overridePath);
  188. }
  189. /*
  190. * Compile from stub and save file
  191. */
  192. $destPath = base_path() . '/modules/system/assets/js/lang/lang.'.$locale.'.js';
  193. $contents = str_replace(
  194. ['{{locale}}', '{{messages}}'],
  195. [$locale, json_encode($messages)],
  196. File::get($stub)
  197. );
  198. /*
  199. * Include the moment localization data
  200. */
  201. $momentPath = base_path() . '/modules/system/assets/ui/vendor/moment/locale/'.$locale.'.js';
  202. if (File::exists($momentPath)) {
  203. $contents .= PHP_EOL.PHP_EOL.File::get($momentPath).PHP_EOL;
  204. }
  205. File::put($destPath, $contents);
  206. /*
  207. * Output notes
  208. */
  209. $publicDest = File::localToPublic(realpath(dirname($destPath))) . '/' . basename($destPath);
  210. $this->comment($locale.'/'.basename($srcPath));
  211. $this->comment(sprintf(' -> %s', $publicDest));
  212. }
  213. }
  214. protected function utilPurgeThumbs()
  215. {
  216. if (!$this->confirmToProceed('This will PERMANENTLY DELETE all thumbs in the uploads directory.')) {
  217. return;
  218. }
  219. $totalCount = 0;
  220. $uploadsPath = Config::get('filesystems.disks.local.root', storage_path('app'));
  221. $uploadsPath .= '/uploads';
  222. /*
  223. * Recursive function to scan the directory for files beginning
  224. * with "thumb_" and repeat itself on directories.
  225. */
  226. $purgeFunc = function ($targetDir) use (&$purgeFunc, &$totalCount) {
  227. if ($files = File::glob($targetDir.'/thumb_*')) {
  228. foreach ($files as $file) {
  229. $this->info('Purged: '. basename($file));
  230. $totalCount++;
  231. @unlink($file);
  232. }
  233. }
  234. if ($dirs = File::directories($targetDir)) {
  235. foreach ($dirs as $dir) {
  236. $purgeFunc($dir);
  237. }
  238. }
  239. };
  240. $purgeFunc($uploadsPath);
  241. if ($totalCount > 0) {
  242. $this->comment(sprintf('Successfully deleted %s thumbs', $totalCount));
  243. }
  244. else {
  245. $this->comment('No thumbs found to delete');
  246. }
  247. }
  248. protected function utilPurgeUploads()
  249. {
  250. if (!$this->confirmToProceed('This will PERMANENTLY DELETE files in the uploads directory that do not exist in the "system_files" table.')) {
  251. return;
  252. }
  253. // @todo
  254. }
  255. protected function utilPurgeOrphans()
  256. {
  257. if (!$this->confirmToProceed('This will PERMANENTLY DELETE files in "system_files" that do not belong to any other model.')) {
  258. return;
  259. }
  260. // @todo
  261. }
  262. /**
  263. * This command requires the git binary to be installed.
  264. */
  265. protected function utilGitPull()
  266. {
  267. foreach (File::directories(plugins_path()) as $authorDir) {
  268. foreach (File::directories($authorDir) as $pluginDir) {
  269. if (!File::isDirectory($pluginDir.'/.git')) continue;
  270. $exec = 'cd ' . $pluginDir . ' && ';
  271. $exec .= 'git pull 2>&1';
  272. echo 'Updating plugin: '. basename(dirname($pluginDir)) .'.'. basename($pluginDir) . PHP_EOL;
  273. echo shell_exec($exec);
  274. }
  275. }
  276. foreach (File::directories(themes_path()) as $themeDir) {
  277. if (!File::isDirectory($themeDir.'/.git')) continue;
  278. $exec = 'cd ' . $themeDir . ' && ';
  279. $exec .= 'git pull 2>&1';
  280. echo 'Updating theme: '. basename($themeDir) . PHP_EOL;
  281. echo shell_exec($exec);
  282. }
  283. }
  284. }