diff --git a/php/bin/stow b/php/bin/stow index d56a7e3..9f76913 100755 --- a/php/bin/stow +++ b/php/bin/stow @@ -3,95 +3,7 @@ require_once __DIR__ . '/../argvParser.php'; require_once __DIR__ . '/../functions.php'; - -readonly class stow -{ - public function __construct( - private string $action = 'stow', - private bool $backup = false, - private bool $force = false, - ) {} - - private function getNoStow(string $path): array - { - if (file_exists(path($path, '.nostow'))) { - $noStow = file_get_contents(path($path, '.nostow')); - if ($noStow === false) { - return []; - } - return array_values(array_filter(array_map('trim', explode(PHP_EOL, $noStow)))); - } else { - return []; - } - } - - function run(string $sourcePath, string $targetPath): void - { - $noStow = $this->getNoStow($sourcePath); - $sourceFiles = array_diff(scandir($sourcePath), ['..', '.', '.nostow', ...$noStow]); - - foreach ($sourceFiles as $sourceFile) { - $targetFile = path($targetPath, $sourceFile); - $stowFile = path($sourcePath, $sourceFile); - - if ($this->action === 'stow') { - if (is_link($targetFile)) { - $targetLink = readlink($targetFile); - if ($targetLink === $stowFile) { - line("File $targetFile is already stowed from $stowFile"); - } else { - line("File $targetFile is linked from $targetLink"); - } - continue; - } - if (is_dir($targetFile)) { - if (is_dir($stowFile)) { - line("File $targetFile and $stowFile are folders, recurse into existing folders"); - $this->run($stowFile, $targetFile); - } else { - line("File $targetFile is a folder, but stow file $stowFile is not a folder"); - } - continue; - } - if (is_file($targetFile)) { - if ($this->backup) { - $backFile = $targetFile . '.bak'; - if (is_file($backFile)) { - line("Backup file $backFile already exists"); - continue; - } - rename($targetFile, $backFile); - line("Backup file $targetFile to $backFile"); - } elseif ($this->force) { - line("Todo: delete file $targetFile"); - continue; - } else { - line("File $targetFile already exists"); - continue; - } - } - line("Stow $targetFile from $stowFile"); - symlink($stowFile, $targetFile); - } elseif ($this->action === 'unstow') { - if (is_link($targetFile) && readlink($targetFile) === $stowFile) { - line("Unstow $targetFile from $stowFile"); - unlink($targetFile); - continue; - } - if (is_dir($targetFile)) { - if (is_dir($stowFile)) { - line("File $targetFile and $stowFile are folders, recurse into existing folders"); - $this->run($stowFile, $targetFile); - continue; - } else { - line("File $targetFile is a folder, but stow file $stowFile is not a folder"); - } - } - line("File $targetFile is not stowed from $stowFile"); - } - } - } -} +require_once __DIR__ . '/../stow.php'; $argvParser = new ArgvParser( ['u' => 'Unstow files', 'b' => 'Backup existing files', 'f' => 'Force overwrite'], @@ -104,7 +16,7 @@ if ($parsed === false) { } $cwd = getcwd(); -$action = $parsed->get('u') ? 'unstow' : 'stow'; +$action = $parsed->get('u') ? stow::ACTION_UNSTOW : stow::ACTION_STOW; $backup = $parsed->get('b'); $force = $parsed->get('f'); diff --git a/php/stow.php b/php/stow.php new file mode 100644 index 0000000..6d06357 --- /dev/null +++ b/php/stow.php @@ -0,0 +1,109 @@ +getNoStow($sourcePath); + $sourceFiles = array_diff(scandir($sourcePath), ['..', '.', '.nostow', ...$noStow]); + + foreach ($sourceFiles as $sourceFile) { + $targetFile = path($targetPath, $sourceFile); + $stowFile = path($sourcePath, $sourceFile); + + switch ($this->action) { + case self::ACTION_STOW: + $this->stow($targetFile, $stowFile); + break; + case self::ACTION_UNSTOW: + $this->unstow($targetFile, $stowFile); + break; + default: + line("Unknown action: {$this->action}"); + return; + } + } + } + + public function stow(string $targetFile, string $stowFile): void + { + if (is_link($targetFile)) { + $targetLink = readlink($targetFile); + if ($targetLink === $stowFile) { + line("File $targetFile is already stowed from $stowFile"); + } else { + line("File $targetFile is linked from $targetLink"); + } + return; + } + if (is_dir($targetFile)) { + if (is_dir($stowFile)) { + line("File $targetFile and $stowFile are folders, recurse into existing folders"); + $this->run($stowFile, $targetFile); + } else { + line("File $targetFile is a folder, but stow file $stowFile is not a folder"); + } + return; + } + if (is_file($targetFile)) { + if ($this->backup) { + $backFile = $targetFile . '.bak'; + if (is_file($backFile)) { + line("Backup file $backFile already exists"); + return; + } + rename($targetFile, $backFile); + line("Backup file $targetFile to $backFile"); + } elseif ($this->force) { + line("Todo: delete file $targetFile"); + return; + } else { + line("File $targetFile already exists"); + return; + } + } + line("Stow $targetFile from $stowFile"); + symlink($stowFile, $targetFile); + } + + public function unstow(string $targetFile, string $stowFile): void + { + if (is_link($targetFile) && readlink($targetFile) === $stowFile) { + line("Unstow $targetFile from $stowFile"); + unlink($targetFile); + return; + } + if (is_dir($targetFile)) { + if (is_dir($stowFile)) { + line("File $targetFile and $stowFile are folders, recurse into existing folders"); + $this->run($stowFile, $targetFile); + return; + } else { + line("File $targetFile is a folder, but stow file $stowFile is not a folder"); + } + } + line("File $targetFile is not stowed from $stowFile"); + } +}