1<?php 2/* Copyright (c) 2016 Richard Klees <richard.klees@concepts-and-training.de> Extended GPL, see docs/LICENSE */ 3 4namespace ILIAS\Setup\CLI; 5 6use ILIAS\Setup\UnachievableException; 7use ILIAS\Setup\NoConfirmationException; 8use ILIAS\Setup\Agent; 9use ILIAS\Setup\Objective; 10use ILIAS\Setup\Environment; 11use ILIAS\Setup\Config; 12use ILIAS\Setup\ObjectiveIterator; 13use ILIAS\Setup\ObjectiveWithPreconditions; 14use Symfony\Component\Console\Command\Command; 15use Symfony\Component\Console\Input\InputInterface; 16use Symfony\Component\Console\Input\InputArgument; 17use Symfony\Component\Console\Input\InputOption; 18use Symfony\Component\Console\Output\OutputInterface; 19 20/** 21 * Command base class. 22 */ 23abstract class BaseCommand extends Command 24{ 25 protected static $defaultName = "install"; 26 27 /** 28 * @var callable 29 */ 30 protected $lazy_agent; 31 32 /** 33 * @var Agent|null 34 */ 35 protected $agent; 36 37 /** 38 * @var ConfigReader 39 */ 40 protected $config_reader; 41 42 /** 43 * var Objective[] 44 */ 45 protected $preconditions; 46 47 /** 48 * @var callable $lazy_agent must return a Setup\Agent 49 * @var Objective[] $preconditions will be achieved before command invocation 50 */ 51 public function __construct(callable $lazy_agent, ConfigReader $config_reader, array $preconditions) 52 { 53 parent::__construct(); 54 $this->lazy_agent = $lazy_agent; 55 $this->agent = null; 56 $this->config_reader = $config_reader; 57 $this->preconditions = $preconditions; 58 } 59 60 protected function getAgent() : Agent 61 { 62 if ($this->agent !== null) { 63 return $this->agent; 64 } 65 $this->agent = ($this->lazy_agent)(); 66 return $this->agent; 67 } 68 69 public function configure() 70 { 71 $this 72 ->addArgument("config", InputArgument::REQUIRED, "Configuration file for the Setup") 73 ->addOption("config", null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, "Define fields in the configuration file that should be overwritten, e.g. \"a.b.c=foo\"", []) 74 ->addOption("yes", "y", InputOption::VALUE_NONE, "Confirm every message of the setup."); 75 } 76 77 public function execute(InputInterface $input, OutputInterface $output) 78 { 79 $io = new IOWrapper($input, $output, $this->shouldSayYes($input)); 80 81 $this->printLicenseMessage($io, $input); 82 83 $this->printIntroMessage($io); 84 85 $config = $this->readAgentConfig($this->getAgent(), $input); 86 $environment = $this->buildEnvironment($this->getAgent(), $config, $io); 87 $goal = $this->getObjective($this->getAgent(), $config); 88 if (count($this->preconditions) > 0) { 89 $goal = new ObjectiveWithPreconditions( 90 $goal, 91 ...$this->preconditions 92 ); 93 } 94 $goals = new ObjectiveIterator($environment, $goal); 95 96 try { 97 while ($goals->valid()) { 98 $current = $goals->current(); 99 $io->startObjective($current->getLabel(), $current->isNotable()); 100 try { 101 $environment = $current->achieve($environment); 102 $io->finishedLastObjective($current->getLabel(), $current->isNotable()); 103 $goals->setEnvironment($environment); 104 } catch (UnachievableException $e) { 105 $goals->markAsFailed($current); 106 $io->error($e->getMessage()); 107 $io->failedLastObjective($current->getLabel()); 108 } 109 $goals->next(); 110 } 111 $this->printOutroMessage($io); 112 } catch (NoConfirmationException $e) { 113 $io->error("Aborting Setup, a necessary confirmation is missing:\n\n" . $e->getRequestedConfirmation()); 114 } 115 } 116 117 protected function shouldSayYes(InputInterface $input) : bool 118 { 119 return $input->getOption("yes") ?? false; 120 } 121 122 protected function printLicenseMessage(IOWrapper $io, InputInterface $input) : void 123 { 124 if ($this->shouldSayYes($input) || ($input->hasOption("no-interaction") && $input->getOption("no-interaction"))) { 125 return; 126 } 127 $io->text( 128 " ILIAS Copyright (C) 1998-2019 ILIAS Open Source e.V. - GPLv3\n\n" . 129 "This program comes with ABSOLUTELY NO WARRANTY. This is free software,\n" . 130 "and you are welcome to redistribute it under certain conditions. Look\n" . 131 "into the LICENSE file for details." 132 ); 133 } 134 135 abstract protected function printIntroMessage(IOWrapper $io); 136 137 abstract protected function printOutroMessage(IOWrapper $io); 138 139 protected function readAgentConfig(Agent $agent, InputInterface $input) : ?Config 140 { 141 if (!$agent->hasConfig()) { 142 return null; 143 } 144 145 $config_file = $input->getArgument("config"); 146 $config_overwrites_raw = $input->getOption("config"); 147 $config_overwrites = []; 148 foreach ($config_overwrites_raw as $o) { 149 list($k, $v) = explode("=", $o); 150 $config_overwrites[$k] = $v; 151 } 152 $config_content = $this->config_reader->readConfigFile($config_file, $config_overwrites); 153 $trafo = $this->agent->getArrayToConfigTransformation(); 154 return $trafo->transform($config_content); 155 } 156 157 abstract protected function buildEnvironment(Agent $agent, ?Config $config, IOWrapper $io); 158 159 abstract protected function getObjective(Agent $agent, ?Config $config) : Objective; 160} 161