You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
5.7 KiB

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