SandboxCommand.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. <?php
  2. /**
  3. * @package Grav\Console\Cli
  4. *
  5. * @copyright Copyright (C) 2015 - 2019 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Console\Cli;
  9. use Grav\Console\ConsoleCommand;
  10. use Grav\Common\Filesystem\Folder;
  11. use Symfony\Component\Console\Input\InputArgument;
  12. use Symfony\Component\Console\Input\InputOption;
  13. class SandboxCommand extends ConsoleCommand
  14. {
  15. /** @var array */
  16. protected $directories = [
  17. '/assets',
  18. '/backup',
  19. '/cache',
  20. '/images',
  21. '/logs',
  22. '/tmp',
  23. '/user/accounts',
  24. '/user/config',
  25. '/user/data',
  26. '/user/pages',
  27. '/user/plugins',
  28. '/user/themes',
  29. ];
  30. /** @var array */
  31. protected $files = [
  32. '/.dependencies',
  33. '/.htaccess',
  34. '/user/config/site.yaml',
  35. '/user/config/system.yaml',
  36. ];
  37. /** @var array */
  38. protected $mappings = [
  39. '/.gitignore' => '/.gitignore',
  40. '/.editorconfig' => '/.editorconfig',
  41. '/CHANGELOG.md' => '/CHANGELOG.md',
  42. '/LICENSE.txt' => '/LICENSE.txt',
  43. '/README.md' => '/README.md',
  44. '/CONTRIBUTING.md' => '/CONTRIBUTING.md',
  45. '/index.php' => '/index.php',
  46. '/composer.json' => '/composer.json',
  47. '/bin' => '/bin',
  48. '/system' => '/system',
  49. '/vendor' => '/vendor',
  50. '/webserver-configs' => '/webserver-configs',
  51. ];
  52. /** @var string */
  53. protected $default_file = "---\ntitle: HomePage\n---\n# HomePage\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque porttitor eu felis sed ornare. Sed a mauris venenatis, pulvinar velit vel, dictum enim. Phasellus ac rutrum velit. Nunc lorem purus, hendrerit sit amet augue aliquet, iaculis ultricies nisl. Suspendisse tincidunt euismod risus, quis feugiat arcu tincidunt eget. Nulla eros mi, commodo vel ipsum vel, aliquet congue odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque velit orci, laoreet at adipiscing eu, interdum quis nibh. Nunc a accumsan purus.";
  54. protected $source;
  55. protected $destination;
  56. protected function configure()
  57. {
  58. $this
  59. ->setName('sandbox')
  60. ->setDescription('Setup of a base Grav system in your webroot, good for development, playing around or starting fresh')
  61. ->addArgument(
  62. 'destination',
  63. InputArgument::REQUIRED,
  64. 'The destination directory to symlink into'
  65. )
  66. ->addOption(
  67. 'symlink',
  68. 's',
  69. InputOption::VALUE_NONE,
  70. 'Symlink the base grav system'
  71. )
  72. ->setHelp("The <info>sandbox</info> command help create a development environment that can optionally use symbolic links to link the core of grav to the git cloned repository.\nGood for development, playing around or starting fresh");
  73. $this->source = getcwd();
  74. }
  75. protected function serve()
  76. {
  77. $this->destination = $this->input->getArgument('destination');
  78. // Symlink the Core Stuff
  79. if ($this->input->getOption('symlink')) {
  80. // Create Some core stuff if it doesn't exist
  81. $this->createDirectories();
  82. // Loop through the symlink mappings and create the symlinks
  83. $this->symlink();
  84. // Copy the Core STuff
  85. } else {
  86. // Create Some core stuff if it doesn't exist
  87. $this->createDirectories();
  88. // Loop through the symlink mappings and copy what otherwise would be symlinks
  89. $this->copy();
  90. }
  91. $this->pages();
  92. $this->initFiles();
  93. $this->perms();
  94. }
  95. private function createDirectories()
  96. {
  97. $this->output->writeln('');
  98. $this->output->writeln('<comment>Creating Directories</comment>');
  99. $dirs_created = false;
  100. if (!file_exists($this->destination)) {
  101. Folder::create($this->destination);
  102. }
  103. foreach ($this->directories as $dir) {
  104. if (!file_exists($this->destination . $dir)) {
  105. $dirs_created = true;
  106. $this->output->writeln(' <cyan>' . $dir . '</cyan>');
  107. Folder::create($this->destination . $dir);
  108. }
  109. }
  110. if (!$dirs_created) {
  111. $this->output->writeln(' <red>Directories already exist</red>');
  112. }
  113. }
  114. private function copy()
  115. {
  116. $this->output->writeln('');
  117. $this->output->writeln('<comment>Copying Files</comment>');
  118. foreach ($this->mappings as $source => $target) {
  119. if ((string)(int)$source === (string)$source) {
  120. $source = $target;
  121. }
  122. $from = $this->source . $source;
  123. $to = $this->destination . $target;
  124. $this->output->writeln(' <cyan>' . $source . '</cyan> <comment>-></comment> ' . $to);
  125. @Folder::rcopy($from, $to);
  126. }
  127. }
  128. private function symlink()
  129. {
  130. $this->output->writeln('');
  131. $this->output->writeln('<comment>Resetting Symbolic Links</comment>');
  132. foreach ($this->mappings as $source => $target) {
  133. if ((string)(int)$source === (string)$source) {
  134. $source = $target;
  135. }
  136. $from = $this->source . $source;
  137. $to = $this->destination . $target;
  138. $this->output->writeln(' <cyan>' . $source . '</cyan> <comment>-></comment> ' . $to);
  139. if (is_dir($to)) {
  140. @Folder::delete($to);
  141. } else {
  142. @unlink($to);
  143. }
  144. symlink($from, $to);
  145. }
  146. }
  147. private function initFiles()
  148. {
  149. $this->check();
  150. $this->output->writeln('');
  151. $this->output->writeln('<comment>File Initializing</comment>');
  152. $files_init = false;
  153. // Copy files if they do not exist
  154. foreach ($this->files as $source => $target) {
  155. if ((string)(int)$source === (string)$source) {
  156. $source = $target;
  157. }
  158. $from = $this->source . $source;
  159. $to = $this->destination . $target;
  160. if (!file_exists($to)) {
  161. $files_init = true;
  162. copy($from, $to);
  163. $this->output->writeln(' <cyan>' . $target . '</cyan> <comment>-></comment> Created');
  164. }
  165. }
  166. if (!$files_init) {
  167. $this->output->writeln(' <red>Files already exist</red>');
  168. }
  169. }
  170. private function pages()
  171. {
  172. $this->output->writeln('');
  173. $this->output->writeln('<comment>Pages Initializing</comment>');
  174. // get pages files and initialize if no pages exist
  175. $pages_dir = $this->destination . '/user/pages';
  176. $pages_files = array_diff(scandir($pages_dir), ['..', '.']);
  177. if (\count($pages_files) === 0) {
  178. $destination = $this->source . '/user/pages';
  179. Folder::rcopy($destination, $pages_dir);
  180. $this->output->writeln(' <cyan>' . $destination . '</cyan> <comment>-></comment> Created');
  181. }
  182. }
  183. private function perms()
  184. {
  185. $this->output->writeln('');
  186. $this->output->writeln('<comment>Permissions Initializing</comment>');
  187. $dir_perms = 0755;
  188. $binaries = glob($this->destination . DS . 'bin' . DS . '*');
  189. foreach ($binaries as $bin) {
  190. chmod($bin, $dir_perms);
  191. $this->output->writeln(' <cyan>bin/' . basename($bin) . '</cyan> permissions reset to ' . decoct($dir_perms));
  192. }
  193. $this->output->writeln("");
  194. }
  195. private function check()
  196. {
  197. $success = true;
  198. if (!file_exists($this->destination)) {
  199. $this->output->writeln(' file: <red>$this->destination</red> does not exist!');
  200. $success = false;
  201. }
  202. foreach ($this->directories as $dir) {
  203. if (!file_exists($this->destination . $dir)) {
  204. $this->output->writeln(' directory: <red>' . $dir . '</red> does not exist!');
  205. $success = false;
  206. }
  207. }
  208. foreach ($this->mappings as $target => $link) {
  209. if (!file_exists($this->destination . $target)) {
  210. $this->output->writeln(' mappings: <red>' . $target . '</red> does not exist!');
  211. $success = false;
  212. }
  213. }
  214. if (!$success) {
  215. $this->output->writeln('');
  216. $this->output->writeln('<comment>install should be run with --symlink|--s to symlink first</comment>');
  217. exit;
  218. }
  219. }
  220. }