InstallCommand.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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 RocketTheme\Toolbox\File\YamlFile;
  11. use Symfony\Component\Console\Input\InputArgument;
  12. use Symfony\Component\Console\Input\InputOption;
  13. class InstallCommand extends ConsoleCommand
  14. {
  15. /** @var array */
  16. protected $config;
  17. /** @var array */
  18. protected $local_config;
  19. /** @var string */
  20. protected $destination;
  21. /** @var string */
  22. protected $user_path;
  23. protected function configure()
  24. {
  25. $this
  26. ->setName('install')
  27. ->addOption(
  28. 'symlink',
  29. 's',
  30. InputOption::VALUE_NONE,
  31. 'Symlink the required bits'
  32. )
  33. ->addArgument(
  34. 'destination',
  35. InputArgument::OPTIONAL,
  36. 'Where to install the required bits (default to current project)'
  37. )
  38. ->setDescription('Installs the dependencies needed by Grav. Optionally can create symbolic links')
  39. ->setHelp('The <info>install</info> command installs the dependencies needed by Grav. Optionally can create symbolic links');
  40. }
  41. protected function serve()
  42. {
  43. $dependencies_file = '.dependencies';
  44. $this->destination = $this->input->getArgument('destination') ?: ROOT_DIR;
  45. // fix trailing slash
  46. $this->destination = rtrim($this->destination, DS) . DS;
  47. $this->user_path = $this->destination . USER_PATH;
  48. if ($local_config_file = $this->loadLocalConfig()) {
  49. $this->output->writeln('Read local config from <cyan>' . $local_config_file . '</cyan>');
  50. }
  51. // Look for dependencies file in ROOT and USER dir
  52. if (file_exists($this->user_path . $dependencies_file)) {
  53. $file = YamlFile::instance($this->user_path . $dependencies_file);
  54. } elseif (file_exists($this->destination . $dependencies_file)) {
  55. $file = YamlFile::instance($this->destination . $dependencies_file);
  56. } else {
  57. $this->output->writeln('<red>ERROR</red> Missing .dependencies file in <cyan>user/</cyan> folder');
  58. if ($this->input->getArgument('destination')) {
  59. $this->output->writeln('<yellow>HINT</yellow> <info>Are you trying to install a plugin or a theme? Make sure you use <cyan>bin/gpm install <something></cyan>, not <cyan>bin/grav install</cyan>. This command is only used to install Grav skeletons.');
  60. } else {
  61. $this->output->writeln('<yellow>HINT</yellow> <info>Are you trying to install Grav? Grav is already installed. You need to run this command only if you download a skeleton from GitHub directly.');
  62. }
  63. return;
  64. }
  65. $this->config = $file->content();
  66. $file->free();
  67. // If yaml config, process
  68. if ($this->config) {
  69. if (!$this->input->getOption('symlink')) {
  70. // Updates composer first
  71. $this->output->writeln("\nInstalling vendor dependencies");
  72. $this->output->writeln($this->composerUpdate(GRAV_ROOT, 'install'));
  73. $this->gitclone();
  74. } else {
  75. $this->symlink();
  76. }
  77. } else {
  78. $this->output->writeln('<red>ERROR</red> invalid YAML in ' . $dependencies_file);
  79. }
  80. }
  81. /**
  82. * Clones from Git
  83. */
  84. private function gitclone()
  85. {
  86. $this->output->writeln('');
  87. $this->output->writeln('<green>Cloning Bits</green>');
  88. $this->output->writeln('============');
  89. $this->output->writeln('');
  90. foreach ($this->config['git'] as $repo => $data) {
  91. $this->destination = rtrim($this->destination, DS);
  92. $path = $this->destination . DS . $data['path'];
  93. if (!file_exists($path)) {
  94. exec('cd "' . $this->destination . '" && git clone -b ' . $data['branch'] . ' --depth 1 ' . $data['url'] . ' ' . $data['path'], $output, $return);
  95. if (!$return) {
  96. $this->output->writeln('<green>SUCCESS</green> cloned <magenta>' . $data['url'] . '</magenta> -> <cyan>' . $path . '</cyan>');
  97. } else {
  98. $this->output->writeln('<red>ERROR</red> cloning <magenta>' . $data['url']);
  99. }
  100. $this->output->writeln('');
  101. } else {
  102. $this->output->writeln('<red>' . $path . ' already exists, skipping...</red>');
  103. $this->output->writeln('');
  104. }
  105. }
  106. }
  107. /**
  108. * Symlinks
  109. */
  110. private function symlink()
  111. {
  112. $this->output->writeln('');
  113. $this->output->writeln('<green>Symlinking Bits</green>');
  114. $this->output->writeln('===============');
  115. $this->output->writeln('');
  116. if (!$this->local_config) {
  117. $this->output->writeln('<red>No local configuration available, aborting...</red>');
  118. $this->output->writeln('');
  119. return;
  120. }
  121. exec('cd ' . $this->destination);
  122. foreach ($this->config['links'] as $repo => $data) {
  123. $repos = (array) $this->local_config[$data['scm'] . '_repos'];
  124. $from = false;
  125. $to = $this->destination . $data['path'];
  126. foreach ($repos as $repo) {
  127. $path = $repo . $data['src'];
  128. if (file_exists($path)) {
  129. $from = $path;
  130. continue;
  131. }
  132. }
  133. if (!$from) {
  134. $this->output->writeln('<red>source for ' . $data['src'] . ' does not exists, skipping...</red>');
  135. $this->output->writeln('');
  136. } else {
  137. if (!file_exists($to)) {
  138. symlink($from, $to);
  139. $this->output->writeln('<green>SUCCESS</green> symlinked <magenta>' . $data['src'] . '</magenta> -> <cyan>' . $data['path'] . '</cyan>');
  140. $this->output->writeln('');
  141. } else {
  142. $this->output->writeln('<red>destination: ' . $to . ' already exists, skipping...</red>');
  143. $this->output->writeln('');
  144. }
  145. }
  146. }
  147. }
  148. }