diff --git a/README.md b/README.md index 2cc172e..704143b 100644 --- a/README.md +++ b/README.md @@ -48,3 +48,9 @@ For all available options, use the `--help` flag. - Disabled automatic flushing of the state to disk; --check will no longer update the state file, but --pull and default update will. +**0.1.2** + +- Fixed a bug in lockfile class preventing release of stale lockfile. +- The `--image` option finally works. +- Added a `--write-state`/`-w` option to write updated hashes to the state file. +- Implemented `--config` and `--config-type`options. diff --git a/bin/freshdocker b/bin/freshdocker index 1eeac9e..6b90e64 100755 --- a/bin/freshdocker +++ b/bin/freshdocker @@ -7,6 +7,7 @@ if (file_exists(__DIR__."/../src/version.php")) { require_once __DIR__."/../src/version.php"; } else { define("APP_VERSION", "DEV"); + define("BUILD_DATE", "src"); } $r = new NoccyLabs\FreshDocker\Refresher(); diff --git a/src/Configuration/SingleImageConfiguration.php b/src/Configuration/SingleImageConfiguration.php new file mode 100644 index 0000000..c7bd66e --- /dev/null +++ b/src/Configuration/SingleImageConfiguration.php @@ -0,0 +1,21 @@ +image = $image; + } + + public function getChecks(): array + { + return [ $this->image ]; + } +} \ No newline at end of file diff --git a/src/Refresher.php b/src/Refresher.php index cc713cd..04f6fa3 100644 --- a/src/Refresher.php +++ b/src/Refresher.php @@ -5,6 +5,7 @@ namespace NoccyLabs\FreshDocker; use NoccyLabs\FreshDocker\State\Log; use NoccyLabs\FreshDocker\Configuration\ComposeConfiguration; use NoccyLabs\FreshDocker\Configuration\LocalConfiguration; +use NoccyLabs\FreshDocker\Configuration\SingleImageConfiguration; use NoccyLabs\FreshDocker\Credentials\BasicCredentialsLoader; use NoccyLabs\FreshDocker\Credentials\CredentialsLoaderInterface; use NoccyLabs\FreshDocker\Hooks\SlackHook; @@ -25,6 +26,7 @@ class Refresher 'pull' => [ null, 'pull', "Only pull if updated, don't up" ], 'check' => [ null, 'check', "Only check for updates, set exit code" ], 'prune' => [ null, 'prune', "Prune dangling images after pull and up" ], + 'write-state' => [ 'w', 'write-state', "Always write updated state (only useful with --check)", false ], ], 'Hooks' => [ 'slack' => [ null, 'slack:', "Notify a slack webhook when updating", "FRESH_SLACK" ], @@ -32,7 +34,7 @@ class Refresher ], 'Config' => [ 'config' => [ 'c:', 'config:', "Use custom configuration file", "FRESH_CONFIG" ], - 'type' => [ 'C:', 'config-type:', "Configuration type (auto, fresh, compose)", "FRESH_CONFIG_TYPE", "auto" ], + 'config-type' => [ 'C:', 'config-type:', "Configuration type (auto, fresh, compose)", "FRESH_CONFIG_TYPE", "auto" ], 'credentials' => [ null, 'credentials:', "Set credentials loader type (auto or basic)", "FRESH_CREDENTIALS", "auto" ], ] ]; @@ -111,8 +113,9 @@ class Refresher public function printUsage() { + $tty = posix_isatty(STDOUT); - printf("fresh.phar v%s - (c) 2022, NoccyLabs / GPL v3 or later\n", APP_VERSION); + printf("fresh.phar v%s (%s) - (c) 2022, NoccyLabs / GPL v3 or later\n", APP_VERSION, BUILD_DATE); printf("Check for updates to docker images or compose stacks.\n\n"); printf("Usage:\n %s [options]\n\n", basename($GLOBALS['argv'][0])); printf("Options:\n"); @@ -129,10 +132,10 @@ class Refresher if ($s&&$l) $optkey .= ","; if ($l) $optkey .= "--" . $l; if ($h) $optkey .= " VALUE"; - printf(" %-25s %s", $optkey, $opt[2]); - if ($d) printf(" (default: %s)", $d); - if ($e) printf(" [\$%s]", $e); - echo "\n"; + $out = sprintf(" %-25s %s", $optkey, $opt[2]); + if ($d) $out.= sprintf(" (default: %s)", $d); + if ($e) $out.= sprintf(" [\$%s]", $e); + echo $out . "\n"; } } printf("\nNote:\n"); @@ -163,6 +166,11 @@ class Refresher // If called with --check, only return exit status if ($this->options['check']) { + if (($updated !== null) && $this->options['write-state']) { + // Flush state if called with -w/--write-state + $this->log->append("Flushing state..."); + $this->state->flush(); + } exit(($updated === null) ? 0 : 1); } @@ -227,13 +235,49 @@ class Refresher */ private function setupConfiguration() { - - if (file_exists($this->path."/docker-compose.yml")) { - $this->config = new ComposeConfiguration($this->path."/docker-compose.yml"); - } else { - fwrite(STDERR, "error: Couldn't find a supported configuration file\n"); - exit(2); + if ($this->options['image']) { + $this->config = new SingleImageConfiguration($this->options['image']); + return; } + + $configType = $this->options['config-type']; + $configFile = $this->options['config'] ? realpath($this->options['config']) : null; + + switch ($configType) { + case 'auto': + if ($configFile) { + if (basename($configFile) == "docker-compose.yml") { + $this->log->append("Using configuration file ".$configFile); + $this->config = new ComposeConfiguration($configFile); + return; + } + } else { + if (file_exists($this->path."/docker-compose.yml")) { + $this->log->append("Using configuration file ".$this->path."/docker-compose.yml"); + $this->config = new ComposeConfiguration($this->path."/docker-compose.yml"); + return; + } + } + break; + case 'compose': + if ($configFile) { + if (basename($configFile) == "docker-compose.yml") { + $this->log->append("Using configuration file ".$configFile); + $this->config = new ComposeConfiguration($configFile); + return; + } + } else { + if (file_exists($this->path."/docker-compose.yml")) { + $this->log->append("Using configuration file ".$this->path."/docker-compose.yml"); + $this->config = new ComposeConfiguration($this->path."/docker-compose.yml"); + return; + } + } + break; + } + + fwrite(STDERR, "error: Couldn't find a supported configuration file\n"); + exit(2); } /** diff --git a/src/State/Lockfile.php b/src/State/Lockfile.php index bf325f7..21abcc8 100644 --- a/src/State/Lockfile.php +++ b/src/State/Lockfile.php @@ -17,7 +17,7 @@ class Lockfile public function lock() { if (file_exists($this->filename)) { - if (time() - filemtime($this->filename) < $this-$maxLock) { + if (time() - filemtime($this->filename) < $this->maxLock) { throw new \RuntimeException("Lockfile {$this->filename} already exists"); } }