102 lines
3.1 KiB
PHP
102 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace Toolbox;
|
|
|
|
/**
|
|
* Copia (o enlaza) los archivos de un componente al proyecto respetando la
|
|
* regla de destino, el modo y el drift.
|
|
*/
|
|
final class Copier
|
|
{
|
|
public function __construct(private readonly FileSync $sync = new FileSync())
|
|
{
|
|
}
|
|
|
|
/**
|
|
* @param list<string> $files rutas relativas al paquete
|
|
* @param array<string, string> $expectedFiles rel -> hash previo (lock)
|
|
* @param array<string, string>|null $destinations
|
|
* @param array{force?:bool, backup?:bool, keepLocal?:bool, dryRun?:bool} $options
|
|
* @return array{files: array<string,string>, actions: array<string,string>, aborted: list<string>}
|
|
*/
|
|
public function install(
|
|
array $files,
|
|
string $sourceDir,
|
|
string $rootDir,
|
|
string $rootCore,
|
|
?array $destinations,
|
|
string $mode,
|
|
array $options = [],
|
|
array $expectedFiles = []
|
|
): array {
|
|
$installed = [];
|
|
$actions = [];
|
|
$aborted = [];
|
|
|
|
foreach ($files as $file) {
|
|
$relative = Destination::relative($file, $rootDir, $rootCore, $destinations);
|
|
$source = rtrim($sourceDir, '/') . '/' . ltrim($file, '/');
|
|
$target = rtrim($rootDir, '/') . '/' . $relative;
|
|
$expected = $expectedFiles[$relative] ?? null;
|
|
|
|
if (($options['dryRun'] ?? false)) {
|
|
$actions[$relative] = 'planned';
|
|
continue;
|
|
}
|
|
|
|
if ($mode === 'link') {
|
|
$action = $this->link($source, $target, $options);
|
|
} else {
|
|
$contents = file_get_contents($source);
|
|
if ($contents === false) {
|
|
throw new ToolboxException("No se pudo leer el archivo de origen: {$source}");
|
|
}
|
|
$action = $this->sync->write($target, $contents, $expected, $options);
|
|
}
|
|
|
|
$actions[$relative] = $action;
|
|
|
|
if ($action === FileSync::ABORTED) {
|
|
$aborted[] = $relative;
|
|
|
|
continue;
|
|
}
|
|
|
|
$installed[$relative] = is_file($source) ? Drift::hash($source) : '';
|
|
}
|
|
|
|
return ['files' => $installed, 'actions' => $actions, 'aborted' => $aborted];
|
|
}
|
|
|
|
/**
|
|
* @param array{force?:bool, keepLocal?:bool} $options
|
|
*/
|
|
private function link(string $source, string $target, array $options): string
|
|
{
|
|
if (is_link($target)) {
|
|
if (readlink($target) === $source) {
|
|
return FileSync::WRITTEN;
|
|
}
|
|
unlink($target);
|
|
} elseif (is_file($target)) {
|
|
if ($options['keepLocal'] ?? false) {
|
|
return FileSync::SKIPPED;
|
|
}
|
|
if (!($options['force'] ?? false)) {
|
|
return FileSync::ABORTED;
|
|
}
|
|
unlink($target);
|
|
}
|
|
|
|
if (!is_dir(dirname($target))) {
|
|
mkdir(dirname($target), 0777, true);
|
|
}
|
|
|
|
if (!symlink($source, $target)) {
|
|
throw new ToolboxException("No se pudo enlazar {$target} -> {$source}");
|
|
}
|
|
|
|
return FileSync::WRITTEN;
|
|
}
|
|
}
|