Application.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Joas Schilling <coding@schilljs.com>
  6. * @author Jörn Friedrich Dreyer <jfd@butonic.de>
  7. * @author Lukas Reschke <lukas@statuscode.ch>
  8. * @author Miha Frangez <miha.frangez@gmail.com>
  9. * @author Morris Jobke <hey@morrisjobke.de>
  10. * @author noveens <noveen.sachdeva@research.iiit.ac.in>
  11. * @author Robin Appelman <robin@icewind.nl>
  12. * @author Thomas Müller <thomas.mueller@tmit.eu>
  13. * @author Victor Dubiniuk <dubiniuk@owncloud.com>
  14. *
  15. * @license AGPL-3.0
  16. *
  17. * This code is free software: you can redistribute it and/or modify
  18. * it under the terms of the GNU Affero General Public License, version 3,
  19. * as published by the Free Software Foundation.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU Affero General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU Affero General Public License, version 3,
  27. * along with this program. If not, see <http://www.gnu.org/licenses/>
  28. *
  29. */
  30. namespace OC\Console;
  31. use OC\NeedsUpdateException;
  32. use OC_App;
  33. use OCP\AppFramework\QueryException;
  34. use OCP\Console\ConsoleEvent;
  35. use OCP\IConfig;
  36. use OCP\ILogger;
  37. use OCP\IRequest;
  38. use Symfony\Component\Console\Application as SymfonyApplication;
  39. use Symfony\Component\Console\Input\InputInterface;
  40. use Symfony\Component\Console\Input\InputOption;
  41. use Symfony\Component\Console\Output\OutputInterface;
  42. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  43. class Application {
  44. /** @var IConfig */
  45. private $config;
  46. /** @var EventDispatcherInterface */
  47. private $dispatcher;
  48. /** @var IRequest */
  49. private $request;
  50. /** @var ILogger */
  51. private $logger;
  52. /**
  53. * @param IConfig $config
  54. * @param EventDispatcherInterface $dispatcher
  55. * @param IRequest $request
  56. * @param ILogger $logger
  57. */
  58. public function __construct(IConfig $config, EventDispatcherInterface $dispatcher, IRequest $request, ILogger $logger) {
  59. $defaults = \OC::$server->getThemingDefaults();
  60. $this->config = $config;
  61. $this->application = new SymfonyApplication($defaults->getName(), \OC_Util::getVersionString());
  62. $this->dispatcher = $dispatcher;
  63. $this->request = $request;
  64. $this->logger = $logger;
  65. }
  66. /**
  67. * @param InputInterface $input
  68. * @param OutputInterface $output
  69. * @throws \Exception
  70. */
  71. public function loadCommands(InputInterface $input, OutputInterface $output) {
  72. // $application is required to be defined in the register_command scripts
  73. $application = $this->application;
  74. $inputDefinition = $application->getDefinition();
  75. $inputDefinition->addOption(
  76. new InputOption(
  77. 'no-warnings',
  78. null,
  79. InputOption::VALUE_NONE,
  80. 'Skip global warnings, show command output only',
  81. null
  82. )
  83. );
  84. try {
  85. $input->bind($inputDefinition);
  86. } catch (\RuntimeException $e) {
  87. //expected if there are extra options
  88. }
  89. if ($input->getOption('no-warnings')) {
  90. $output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
  91. }
  92. try {
  93. require_once __DIR__ . '/../../../core/register_command.php';
  94. if ($this->config->getSystemValue('installed', false)) {
  95. if (\OCP\Util::needUpgrade()) {
  96. throw new NeedsUpdateException();
  97. } elseif ($this->config->getSystemValue('maintenance', false)) {
  98. if ($input->getArgument('command') !== '_completion') {
  99. $errOutput = $output->getErrorOutput();
  100. $errOutput->writeln('<comment>Nextcloud is in maintenance mode - no apps have been loaded</comment>' . PHP_EOL);
  101. }
  102. } else {
  103. OC_App::loadApps();
  104. foreach (\OC::$server->getAppManager()->getInstalledApps() as $app) {
  105. $appPath = \OC_App::getAppPath($app);
  106. if ($appPath === false) {
  107. continue;
  108. }
  109. // load commands using info.xml
  110. $info = \OC_App::getAppInfo($app);
  111. if (isset($info['commands'])) {
  112. $this->loadCommandsFromInfoXml($info['commands']);
  113. }
  114. // load from register_command.php
  115. \OC_App::registerAutoloading($app, $appPath);
  116. $file = $appPath . '/appinfo/register_command.php';
  117. if (file_exists($file)) {
  118. try {
  119. require $file;
  120. } catch (\Exception $e) {
  121. $this->logger->logException($e);
  122. }
  123. }
  124. }
  125. }
  126. } else if ($input->getArgument('command') !== '_completion' && $input->getArgument('command') !== 'maintenance:install') {
  127. $output->writeln("Nextcloud is not installed - only a limited number of commands are available");
  128. }
  129. } catch(NeedsUpdateException $e) {
  130. if ($input->getArgument('command') !== '_completion') {
  131. $output->writeln("Nextcloud or one of the apps require upgrade - only a limited number of commands are available");
  132. $output->writeln("You may use your browser or the occ upgrade command to do the upgrade");
  133. }
  134. }
  135. if ($input->getFirstArgument() !== 'check') {
  136. $errors = \OC_Util::checkServer(\OC::$server->getSystemConfig());
  137. if (!empty($errors)) {
  138. foreach ($errors as $error) {
  139. $output->writeln((string)$error['error']);
  140. $output->writeln((string)$error['hint']);
  141. $output->writeln('');
  142. }
  143. throw new \Exception("Environment not properly prepared.");
  144. }
  145. }
  146. }
  147. /**
  148. * Sets whether to automatically exit after a command execution or not.
  149. *
  150. * @param bool $boolean Whether to automatically exit after a command execution or not
  151. */
  152. public function setAutoExit($boolean) {
  153. $this->application->setAutoExit($boolean);
  154. }
  155. /**
  156. * @param InputInterface $input
  157. * @param OutputInterface $output
  158. * @return int
  159. * @throws \Exception
  160. */
  161. public function run(InputInterface $input = null, OutputInterface $output = null) {
  162. $this->dispatcher->dispatch(ConsoleEvent::EVENT_RUN, new ConsoleEvent(
  163. ConsoleEvent::EVENT_RUN,
  164. $this->request->server['argv']
  165. ));
  166. return $this->application->run($input, $output);
  167. }
  168. private function loadCommandsFromInfoXml($commands) {
  169. foreach ($commands as $command) {
  170. try {
  171. $c = \OC::$server->query($command);
  172. } catch (QueryException $e) {
  173. if (class_exists($command)) {
  174. $c = new $command();
  175. } else {
  176. throw new \Exception("Console command '$command' is unknown and could not be loaded");
  177. }
  178. }
  179. $this->application->add($c);
  180. }
  181. }
  182. }