-
Notifications
You must be signed in to change notification settings - Fork 16
/
Composer.php
125 lines (98 loc) 路 3.52 KB
/
Composer.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
<?php
namespace Castor\Remote;
use Castor\PathHelper;
use Castor\Remote\Exception\ComposerError;
use Psr\Log\LoggerInterface;
use Symfony\Component\Process\Process;
class Composer
{
public const VENDOR_DIR = '/.castor/vendor/';
public const PATH_CASTOR_REQUIREMENTS = self::VENDOR_DIR . 'castor-requirements.json';
public function __construct(
private readonly LoggerInterface $logger,
) {
}
/**
* @return array<string, mixed>
*/
public function getConfiguration(): array
{
return $this->readJsonFile(PathHelper::getRoot() . self::VENDOR_DIR . 'composer.json');
}
/**
* @param array<string, mixed> $configuration
*/
public function setConfiguration(array $configuration): void
{
$this->logger->debug('Updating Composer configuration.', [
'configuration' => $configuration,
]);
$dir = PathHelper::getRoot() . self::VENDOR_DIR;
if (!is_dir($dir)) {
mkdir($dir, recursive: true);
}
file_put_contents($dir . '.gitignore', "*\n");
$this->writeJsonFile($dir . 'composer.json', $configuration);
}
public function require(string $package, string $version): void
{
$requirements = $this->readJsonFile(PathHelper::getRoot() . self::PATH_CASTOR_REQUIREMENTS);
if (isset($requirements[$package]) && $requirements[$package] === $version) {
$this->logger->debug('The package is already required, no need to run Composer.', [
'package' => $package,
'version' => $version,
]);
return;
}
if (isset($requirements[$package]) && $version !== $requirements[$package]) {
$this->logger->debug('The package is already required but in another version, let\'s empty requirements cache to force Composer re-installation of every package.', [
'package' => $package,
'version' => $version,
]);
$requirements = [];
}
$this->run('require', $package . ':' . $version);
$requirements[$package] = $version;
$this->writeJsonFile(PathHelper::getRoot() . self::PATH_CASTOR_REQUIREMENTS, $requirements);
}
private function run(string ...$args): void
{
$this->logger->debug('Running Composer command.', [
'args' => implode(' ', $args),
]);
$dir = PathHelper::getRoot() . self::VENDOR_DIR;
$process = new Process(['composer', ...$args, '--working-dir', $dir]);
$process->setEnv([
'COMPOSER_VENDOR_DIR' => $dir,
]);
$process->run();
if (!$process->isSuccessful()) {
throw new ComposerError('The Composer process failed: ' . $process->getErrorOutput());
}
$this->logger->debug('Composer command was successful.', [
'args' => implode(' ', $args),
'output' => $process->getOutput(),
]);
}
/**
* @return array<string, mixed>
*/
private function readJsonFile(string $path): array
{
if (!file_exists($path)) {
return [];
}
$json = file_get_contents($path);
if (!$json) {
return [];
}
return json_decode($json, true, flags: \JSON_THROW_ON_ERROR);
}
/**
* @param array<string, mixed> $json
*/
private function writeJsonFile(string $path, array $json): void
{
file_put_contents($path, json_encode($json, \JSON_PRETTY_PRINT | \JSON_THROW_ON_ERROR));
}
}