diff --git a/bin/bin/stow b/bin/bin/stow index 20dd1e0..eb940a9 100755 --- a/bin/bin/stow +++ b/bin/bin/stow @@ -11,36 +11,98 @@ function line(string $line): void echo $line . PHP_EOL; } -$cwd = getcwd(); -$action = 'stow'; -$backup = $force = false; -array_shift($argv); // we don't care about the script name +class argParsed +{ + public function __construct( + private array $parsed = [], + ) {} -if (count($argv) === 0) { - line("Usage: stow [-u] [-b] [-f] "); + public function initOptions(array $options, mixed $default = false): self + { + foreach (array_keys($options) as $name) { + $this->set($name, $default); + } + + return $this; + } + + public function get(string $key, mixed $default = null): mixed + { + return $this->parsed[$key] ?? $default; + } + + public function set(string $key, mixed $value): self + { + $this->parsed[$key] = $value; + return $this; + } +} + +readonly class argvParser +{ + /** + * @param array $options + * @param array $arguments + */ + public function __construct( + private array $options = [], + private array $arguments = [], + ) {} + + public function getOptionsHelp(): string + { + $line = ''; + foreach ($this->options as $option => $description) { + $line .= sprintf('[-%s (%s)] ', $option, $description); + } + foreach ($this->arguments as $argument => $description) { + $line .= sprintf('<%s (%s)> ', $argument, $description); + } + return $line; + } + + public function parseArgv(array $argv): argParsed|false + { + array_shift($argv); // shift the script name + if (count($argv) < count($this->arguments)) { + return false; + } + + $parsed = (new argParsed())->initOptions($this->options); + while (str_starts_with($argv[0], '-')) { + $option = substr($argv[0], 1); + if ($this->options[$option]) { + $parsed->set($option, true); + } + array_shift($argv); + } + if (count($argv) !== count($this->arguments)) { + return false; + } + foreach ($this->arguments as $arg => $description) { + $parsed->set($arg, array_shift($argv)); + } + + return $parsed; + } +} + +$argvParser = new ArgvParser( + ['u' => 'Unstow files', 'b' => 'Backup existing files', 'f' => 'Force overwrite'], + ['stow-directory' => 'The directory to stow'] +); +$parsed = $argvParser->parseArgv($argv); +if ($parsed === false) { + line('Usage: ' . __FILE__ . ' ' . $argvParser->getOptionsHelp()); exit(1); } -while (str_starts_with($argv[0], '-')) { - $option = substr($argv[0], 1); - switch ($option) { - case 'u': - $action = 'unstow'; - break; - case 'b': - $backup = true; - break; - case 'f': - $force = true; - break; - default: - line("Unknown option: $option"); - exit(1); - } - array_shift($argv); -} +$cwd = getcwd(); +$action = $parsed->get('u') ? 'unstow' : 'stow'; +$backup = $parsed->get('b'); +$force = $parsed->get('f'); -$stowName = $argv[0]; +$stowName = $parsed->get('stow-directory'); $stowPath = path($cwd, $stowName); $targetPath = dirname($stowPath, 2); @@ -125,4 +187,6 @@ readonly class stow } $stow = new stow($action, $backup, $force); -$stow->run($stowPath, $targetPath); \ No newline at end of file +$stow->run($stowPath, $targetPath); + +exit(0); \ No newline at end of file