/
InstallPackageCommand.php
188 lines (170 loc) · 7.97 KB
/
InstallPackageCommand.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
<?php
namespace Concrete\Core\Console\Command;
use Concrete\Core\Console\Command;
use Concrete\Core\Console\ConsoleAwareInterface;
use Concrete\Core\Error\ErrorList\ErrorList;
use Concrete\Core\Localization\Service\TranslationsInstaller;
use Concrete\Core\Marketplace\Marketplace;
use Concrete\Core\Package\PackageService;
use Concrete\Core\Support\Facade\Application;
use Exception;
use Symfony\Component\Console\Exception\InvalidOptionException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Style\SymfonyStyle;
class InstallPackageCommand extends Command
{
protected function configure()
{
$okExitCode = static::SUCCESS;
$errExitCode = static::FAILURE;
$this
->setName('c5:package:install')
->setAliases([
'c5:package-install',
'c5:install-package',
])
->addOption('full-content-swap', null, InputOption::VALUE_NONE, 'If this option is specified a full content swap will be performed (if the package supports it)')
->addOption('languages', 'l', InputOption::VALUE_REQUIRED, 'Force to install ("yes") or to not install ("no") language files. If "auto", language files will be installed if the package is connected to the project ("auto" requires that the canonical URL is set)', 'auto')
->setDescription('Install a package')
->addEnvOption()
->setCanRunAsRoot(false)
->addArgument('package', InputArgument::REQUIRED, 'The handle of the package to be installed')
->addArgument('package-options', InputArgument::IS_ARRAY, 'List of key-value pairs to pass to the package install routine (example: foo=bar baz=foo)')
->setHelp(<<<EOT
Returns codes:
$okExitCode operation completed successfully
$errExitCode errors occurred
More info at http://documentation.concrete5.org/developers/appendix/cli-commands#c5-package-install
EOT
)
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$app = Application::getFacadeApplication();
$config = $app->make('config');
$packageService = $app->make(PackageService::class);
$pkgHandle = $input->getArgument('package');
switch (strtolower($input->getOption('languages'))) {
case 'yes':
case 'y':
$getLanguages = true;
break;
case 'no':
case 'n':
$getLanguages = false;
break;
case 'auto':
$associatedPackages = Marketplace::getAvailableMarketplaceItems(false);
$getLanguages = isset($associatedPackages[$pkgHandle]);
break;
default:
throw new InvalidOptionException('Invalid value for the --languages option. Valid values are "yes", "no", "auto"');
}
$packageOptions = [];
foreach ($input->getArgument('package-options') as $keyValuePair) {
list($key, $value) = explode('=', $keyValuePair, 2);
$key = trim($key);
if (substr($key, -2) === '[]') {
$isArray = true;
$key = rtrim(substr($key, 0, -2));
} else {
$isArray = false;
}
if ($key === '' || !isset($value)) {
throw new Exception(sprintf("Unable to parse the package option '%s': it must be in the form of key=value", $keyValuePair));
}
if (isset($packageOptions[$key])) {
if (!($isArray && is_array($packageOptions[$key]))) {
throw new Exception(sprintf("Duplicated package option '%s'", $key));
}
$packageOptions[$key][] = $value;
} else {
$packageOptions[$key] = $isArray ? ((array) $value) : $value;
}
}
$output->write("Looking for package '$pkgHandle'... ");
foreach ($packageService->getInstalledList() as $installed) {
if ($installed->getPackageHandle() === $pkgHandle) {
throw new Exception(sprintf("The package '%s' (%s) is already installed", $pkgHandle, $installed->getPackageName()));
}
}
$pkg = null;
foreach ($packageService->getAvailablePackages() as $available) {
if ($available->getPackageHandle() === $pkgHandle) {
$pkg = $available;
break;
}
}
if ($pkg === null) {
throw new Exception(sprintf("No package with handle '%s' was found", $pkgHandle));
}
// Provide the console objects to objects that are aware of the console
if ($pkg instanceof ConsoleAwareInterface) {
$pkg->setConsole($this->getApplication(), $output, $input);
}
$output->writeln(sprintf('<info>found (%s).</info>', $pkg->getPackageName()));
$output->write('Checking preconditions... ');
$test = $pkg->testForInstall();
if (is_object($test)) {
throw new Exception(implode("\n", $test->getList()));
}
$output->writeln('<info>passed.</info>');
$output->write('Installing... ');
$r = $packageService->install($pkg, []);
if ($r instanceof ErrorList) {
throw new Exception(implode("\n", $r->getList()));
}
$output->writeln('<info>installed.</info>');
if ($getLanguages) {
$output->write('Fetching language files... ');
$languageResult = $app->make(TranslationsInstaller::class)->installMissingPackageTranslations($pkg);
if (count($languageResult) === 0) {
$output->writeln('<info>no languages downloaded.</info>');
} else {
$output->writeln('done. Results:');
foreach ($languageResult as $localeID => $result) {
if ($result === true) {
$output->writeln(" - {$localeID}: <info>downloaded</info>");
} elseif ($result === false) {
$output->writeln(" - {$localeID}: <error>non available</error>");
} else {
$output->writeln(" - $localeID: <error>" . ((string) $result) . '</error>');
}
}
}
}
$swapper = $pkg->getContentSwapper();
if ($swapper->allowsFullContentSwap($pkg) && $input->getOption('full-content-swap')) {
$options = [];
if (count($pkg->getContentSwapFiles()) > 1) {
$contentSwapFiles = [];
$contentSwapTemplateNames = [];
$index = 1;
foreach($pkg->getContentSwapFiles() as $contentSwapFile => $contentSwapTemplateName) {
$contentSwapFiles[$index] = $contentSwapFile;
$contentSwapTemplateNames[] = sprintf("%s: %s", $index, $contentSwapTemplateName);
$index++;
}
$io = new SymfonyStyle($input, $output);
$io->listing($contentSwapTemplateNames);
$helper = $this->getHelper('question');
$selectedContentSwapFile = $helper->ask($input, $output, new Question('Select the number of the content swap file you want to install: ', 1));
if (isset($contentSwapFiles[$selectedContentSwapFile])) {
$options["contentSwapFile"] = $contentSwapFiles[$selectedContentSwapFile];
}
}
$output->write('Performing full content swap... ');
$swapper->swapContent($pkg, $options);
if (method_exists($pkg, 'on_after_swap_content')) {
$pkg->on_after_swap_content([]);
}
$output->writeln('<info>done.</info>');
}
return static::SUCCESS;
}
}