-
Notifications
You must be signed in to change notification settings - Fork 16
/
RepackCommand.php
126 lines (106 loc) 路 4.53 KB
/
RepackCommand.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
<?php
namespace Castor\Console\Command;
use Castor\FunctionFinder;
use Castor\PathHelper;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\ExecutableFinder;
use Symfony\Component\Process\Process;
/**
* @internal
*/
class RepackCommand extends Command
{
protected function configure(): void
{
$this
->setName('castor:repack')
->setAliases(['repack'])
->addOption('app-name', null, InputOption::VALUE_REQUIRED, 'The name of the phar application', 'my-app')
->addOption('app-version', null, InputOption::VALUE_REQUIRED, 'The version of the phar application', '1.0.0')
->addOption('os', null, InputOption::VALUE_REQUIRED, 'The targeted OS', 'linux', ['linux', 'darwin', 'windows'])
->setHidden(true)
;
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
if (str_starts_with(__FILE__, 'phar:')) {
throw new \RuntimeException('This command cannot be run from a phar. You must install castor with its sources.');
}
$os = $input->getOption('os');
if (!\in_array($os, ['linux', 'darwin', 'windows'])) {
throw new \InvalidArgumentException('The os option must be one of linux, darwin or windows.');
}
$finder = new ExecutableFinder();
$box = $finder->find('box');
if (!$box) {
throw new \RuntimeException('Could not find box. Please install it: https://github.com/box-project/box/blob/main/doc/installation.md#installation.');
}
$castorSourceDir = PathHelper::realpath(__DIR__ . '/../../..');
$boxConfigFile = "{$castorSourceDir}/tools/phar/box.{$os}-amd64.json";
if (!file_exists($boxConfigFile)) {
throw new \RuntimeException('Could not find the phar configuration.');
}
$appName = $input->getOption('app-name');
$appVersion = $input->getOption('app-version');
$alias = 'alias.phar';
$main = <<<PHP
<?php
require __DIR__ . '/vendor/autoload.php';
use Castor\\Console\\ApplicationFactory;
use Castor\\Console\\Application;
class RepackedApplication extends Application
{
const NAME = '{$appName}';
const VERSION = '{$appVersion}';
const ROOT_DIR = 'phar://{$alias}';
}
ApplicationFactory::create()->run();
PHP;
$boxConfig = json_decode((string) file_get_contents($boxConfigFile), true, 512, \JSON_THROW_ON_ERROR);
if (file_exists($localBoxConfigFile = $castorSourceDir . '/box.json')) {
$boxConfig = array_merge_recursive(
json_decode((string) file_get_contents($localBoxConfigFile), true, 512, \JSON_THROW_ON_ERROR),
$boxConfig,
);
}
$boxConfig['base-path'] = '.';
$boxConfig['main'] = '.main.php';
$boxConfig['alias'] = $alias;
$boxConfig['output'] = sprintf('%s.%s.phar', $appName, $os);
// update all paths to point to the castor source
foreach (['files', 'files-bin', 'directories', 'directories-bin'] as $key) {
if (!\array_key_exists($key, $boxConfig)) {
continue;
}
$boxConfig[$key] = [
...array_map(
fn (string $file): string => $castorSourceDir . '/' . $file,
$boxConfig[$key] ?? []
),
];
}
// add all files from the FunctionFinder, this is useful if the file
// are in a hidden directory, because it's not included by default by
// box
$boxConfig['files'] = [
...array_map(
fn (string $file): string => str_replace(PathHelper::getRoot() . '/', '', $file),
FunctionFinder::$files,
),
...$boxConfig['files'] ?? [],
];
file_put_contents('.box.json', json_encode($boxConfig, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES));
file_put_contents('.main.php', $main);
$process = new Process([$box, 'compile', '--config=.box.json']);
try {
$process->mustRun(fn ($type, $buffer) => print $buffer);
} finally {
unlink('.box.json');
unlink('.main.php');
}
return Command::SUCCESS;
}
}