93 lines
2.5 KiB
PHP
93 lines
2.5 KiB
PHP
<?php
|
|
|
|
namespace Toolbox;
|
|
|
|
/**
|
|
* Escribe archivos respetando el drift: sin edición local escribe; con edición
|
|
* decide según `--force`, `--backup`, `--keep-local` o aborta.
|
|
*/
|
|
final class FileSync
|
|
{
|
|
public const WRITTEN = 'written';
|
|
public const OVERWRITTEN = 'overwritten';
|
|
public const BACKED_UP = 'backed_up';
|
|
public const SKIPPED = 'skipped';
|
|
public const ABORTED = 'aborted';
|
|
|
|
/**
|
|
* @param array{force?:bool, backup?:bool, keepLocal?:bool} $options
|
|
*/
|
|
public function write(string $path, string $contents, ?string $expected, array $options = []): string
|
|
{
|
|
if (!is_dir(dirname($path))) {
|
|
mkdir(dirname($path), 0777, true);
|
|
}
|
|
|
|
$existed = is_file($path);
|
|
$drifted = $existed && Drift::isDrifted($path, $expected);
|
|
|
|
if (!$drifted) {
|
|
// Sin hash previo (p. ej. primera canonicalización de un proyecto
|
|
// heredado) un archivo existente también puede respaldarse.
|
|
$changed = $existed && (string) file_get_contents($path) !== $contents;
|
|
if ($changed && ($options['backup'] ?? false)) {
|
|
copy($path, $path . '.bak');
|
|
file_put_contents($path, $contents);
|
|
|
|
return self::BACKED_UP;
|
|
}
|
|
|
|
file_put_contents($path, $contents);
|
|
|
|
return $existed ? self::OVERWRITTEN : self::WRITTEN;
|
|
}
|
|
|
|
if ($options['force'] ?? false) {
|
|
file_put_contents($path, $contents);
|
|
|
|
return self::OVERWRITTEN;
|
|
}
|
|
|
|
if ($options['backup'] ?? false) {
|
|
copy($path, $path . '.bak');
|
|
file_put_contents($path, $contents);
|
|
|
|
return self::BACKED_UP;
|
|
}
|
|
|
|
if ($options['keepLocal'] ?? false) {
|
|
return self::SKIPPED;
|
|
}
|
|
|
|
return self::ABORTED;
|
|
}
|
|
|
|
/**
|
|
* @param array{force?:bool, backup?:bool, keepLocal?:bool} $options
|
|
*/
|
|
public function remove(string $path, ?string $expected, array $options = []): string
|
|
{
|
|
if (!is_file($path)) {
|
|
return self::SKIPPED;
|
|
}
|
|
|
|
$drifted = Drift::isDrifted($path, $expected);
|
|
|
|
if ($drifted && !($options['force'] ?? false)) {
|
|
if ($options['keepLocal'] ?? false) {
|
|
return self::SKIPPED;
|
|
}
|
|
|
|
if ($options['backup'] ?? false) {
|
|
copy($path, $path . '.bak');
|
|
} else {
|
|
return self::ABORTED;
|
|
}
|
|
}
|
|
|
|
unlink($path);
|
|
|
|
return self::OVERWRITTEN;
|
|
}
|
|
}
|