Misc improvements

- Renamed the state file from `fresh.yml` to `.fresh.yml`.
- Added option `--state` to override the state file name.
- Renamed the lock file from `fresh.lock` to `.fresh.lock`.
- Added option `--lockfile` to override lockfile file name.
This commit is contained in:
Chris 2022-03-21 00:48:19 +01:00
parent 702cc3101e
commit 214db1cee3
4 changed files with 115 additions and 36 deletions

29
CHANGES Normal file
View File

@ -0,0 +1,29 @@
# Changelog
**0.1.1**
- Moved the logic from the entrypoint script to its own class.
- Added locking (though `fresh.lock` lockfile) to prevent multiple instances.
- Added `--after` hook to invoke script after update.
- 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.
**0.1.3**
- Added a `--before` script hook, to complement the `--after` hook.
- Hooks now invoked both before and after deploy.
**0.1.4**
- Renamed the state file from `fresh.yml` to `.fresh.yml`.
- Added option `--state` to override the state file name.
- Renamed the lock file from `fresh.lock` to `.fresh.lock`.
- Added option `--lockfile` to override lockfile file name.

View File

@ -14,19 +14,24 @@ it can do a combination of things:
Fresh is designed to be invoked using cron or systemd timers, and as such provides Fresh is designed to be invoked using cron or systemd timers, and as such provides
a light-weight easy-to-use alternative to more complex toolkits. a light-weight easy-to-use alternative to more complex toolkits.
## Building ## How to install
Build using NoccyLabs Pharlite, included in the tools directory. Don't forget to run Fresh requires **PHP 8.0** or later.
composer to install dependencies first.
$ composer install
$ tools/pharlite
## Installing
Download the latest version (or build it yourself) and move it into `/usr/bin`. Download the latest version (or build it yourself) and move it into `/usr/bin`.
You can grab it at [https://dev.noccylabs.info/noccy/fresh/releases](https://dev.noccylabs.info/noccy/fresh/releases). You can grab it at [https://dev.noccylabs.info/noccy/fresh/releases](https://dev.noccylabs.info/noccy/fresh/releases).
### Building
Build using NoccyLabs Pharlite, included in the tools directory. Don't forget to run
composer to install dependencies first. In order to properly generate or update the
version file, use the `build.sh` script:
$ composer install
$ tools/build.sh
The generated .phar can be found as `fresh.phar` and `dist/fresh-VERSION.phar`.
## Usage ## Usage
To check for updates, pull updated images and recreate any containers defined in the To check for updates, pull updated images and recreate any containers defined in the
@ -50,6 +55,9 @@ Check a specific image:
For all available options, use the `--help` flag. For all available options, use the `--help` flag.
Some of the options can be read from environment variables, for example `FRESH_AFER`
or `FRESH_SLACK`. See `--help` for supported variables.
## Known Issues ## Known Issues
- Only checks authenticated registries for new versions. But if you are using - Only checks authenticated registries for new versions. But if you are using
@ -66,29 +74,8 @@ For all available options, use the `--help` flag.
- **How do I notify a Mattermost webhook?** Mattermost webhooks are compatible with - **How do I notify a Mattermost webhook?** Mattermost webhooks are compatible with
Slack webhooks, so simply use the `--slack` flag. Slack webhooks, so simply use the `--slack` flag.
## Changes
**0.1.1**
- Moved the logic from the entrypoint script to its own class.
- Added locking (though `fresh.lock` lockfile) to prevent multiple instances.
- Added `--after` hook to invoke script after update.
- 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.
**0.1.3**
- Added a `--before` script hook, to complement the `--after` hook.
- Hooks now invoked both before and after deploy.
## Thank you? ## Thank you?
You can show your appreciation for the time and sweat you have saved through You can show your appreciation by sending me a donation via Paypal.me:
Paypal.me: [https://paypal.me/noccy](paypal.me/noccy). [https://paypal.me/noccy](paypal.me/noccy).

View File

@ -2,6 +2,25 @@
namespace NoccyLabs\FreshDocker; namespace NoccyLabs\FreshDocker;
/*
Fresh.phar
Copyright (C) 2022 NoccyLabs
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
use NoccyLabs\FreshDocker\State\Log; use NoccyLabs\FreshDocker\State\Log;
use NoccyLabs\FreshDocker\Configuration\ComposeConfiguration; use NoccyLabs\FreshDocker\Configuration\ComposeConfiguration;
use NoccyLabs\FreshDocker\Configuration\LocalConfiguration; use NoccyLabs\FreshDocker\Configuration\LocalConfiguration;
@ -16,6 +35,11 @@ use NoccyLabs\FreshDocker\State\Lockfile;
class Refresher class Refresher
{ {
/**
* Map for determining options from command line and environment. Each item
* has the format:
* name => [ short, long, description, [envvar, [default]]]
*/
private static array $optionsMap = [ private static array $optionsMap = [
'General' => [ 'General' => [
'help' => [ 'h', 'help', "Show this help" ], 'help' => [ 'h', 'help', "Show this help" ],
@ -26,7 +50,7 @@ class Refresher
'pull' => [ null, 'pull', "Only pull if updated, don't up" ], 'pull' => [ null, 'pull', "Only pull if updated, don't up" ],
'check' => [ null, 'check', "Only check for updates, set exit code" ], 'check' => [ null, 'check', "Only check for updates, set exit code" ],
'prune' => [ null, 'prune', "Prune dangling images after pull and up" ], 'prune' => [ null, 'prune', "Prune dangling images after pull and up" ],
'write-state' => [ 'w', 'write-state', "Always write updated state (only useful with --check)", false ], 'write-state' => [ 'w', 'write-state', "Always write updated state (only useful with --check)", null, false ],
], ],
'Hooks' => [ 'Hooks' => [
'slack' => [ null, 'slack:', "Notify a slack webhook when updating", "FRESH_SLACK" ], 'slack' => [ null, 'slack:', "Notify a slack webhook when updating", "FRESH_SLACK" ],
@ -36,10 +60,16 @@ class Refresher
'Config' => [ 'Config' => [
'config' => [ 'c:', 'config:', "Use custom configuration file", "FRESH_CONFIG" ], 'config' => [ 'c:', 'config:', "Use custom configuration file", "FRESH_CONFIG" ],
'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" ],
'state' => [ 's:', 'state:', "Override the state file name", "FRESH_STATE", ".fresh.yml" ],
'lockfile' => [ 'l:', 'lockfile:', "Override the lockfile file name", "FRESH_LOCKFILE", ".fresh.lock" ],
'credentials' => [ null, 'credentials:', "Set credentials loader type (auto or basic)", "FRESH_CREDENTIALS", "auto" ], 'credentials' => [ null, 'credentials:', "Set credentials loader type (auto or basic)", "FRESH_CREDENTIALS", "auto" ],
] ]
]; ];
private static $StateFileName = ".fresh.yml";
private static $LockFileName = ".fresh.lock";
/** @var array The parsed options */
private array $options = []; private array $options = [];
/** @var HookInterface[] The hooks to invoke */ /** @var HookInterface[] The hooks to invoke */
@ -112,6 +142,11 @@ class Refresher
} }
/**
* Print the usage info (from --help or -h)
*
*
*/
public function printUsage() public function printUsage()
{ {
$tty = posix_isatty(STDOUT); $tty = posix_isatty(STDOUT);
@ -186,11 +221,13 @@ class Refresher
exit(($updated === null) ? 0 : 1); exit(($updated === null) ? 0 : 1);
} catch (\Throwable $t) { } catch (\Throwable $t) {
fprintf(STDERR, "fatal: %s (%s#%d)\n", $t->getMessage(), $t->getFile(), $t->getLine()); fprintf(STDERR, "fatal: %s (%s#%d)\n", $t->getMessage(), $t->getFile(), $t->getLine());
if (!$this->options['verbose']) { if (!$this->options['verbose']) {
fprintf(STDERR, $this->log->asString()."\n"); fprintf(STDERR, $this->log->asString()."\n");
} }
exit(2); exit(2);
} }
} }
@ -210,8 +247,14 @@ class Refresher
$this->log->append("Working dir: ".$this->path); $this->log->append("Working dir: ".$this->path);
chdir($this->path); chdir($this->path);
$this->state = new PersistentState($this->path . "/fresh.yml"); $statefile = $this->options['state'];
$this->lockfile = new Lockfile($this->path . "/fresh.lock"); if (!str_starts_with($statefile,'/')) $statefile = $this->path . "/" . $statefile;
$lockfile = $this->options['lockfile'];
if (!str_starts_with($lockfile,'/')) $lockfile = $this->path . "/" . $lockfile;
$this->state = new PersistentState($statefile); // $this->path . "/" . self::$StateFileName);
$this->lockfile = new Lockfile($lockfile); // $this->path . "/" . self::$LockFileName);
} }
/** /**
@ -224,7 +267,7 @@ class Refresher
case 'auto': case 'auto':
case 'basic': case 'basic':
$this->credentialsLoader = new BasicCredentialsLoader(); $this->credentialsLoader = new BasicCredentialsLoader();
$this->log->append("Using BasicCredentialsLoader for credentials"); $this->log->append("Using BasicCredentialsLoader");
break; break;
default: default:
fwrite(STDERR, "error: Invalid credentials loader type\n"); fwrite(STDERR, "error: Invalid credentials loader type\n");

20
tools/build.sh Executable file
View File

@ -0,0 +1,20 @@
#!/bin/bash
# chdir into the root from wherever we are
cd "$(dirname "$(realpath "$0")")/.."
# determine the tag and output base
TAG="$(git describe --tags)"
OUT="dist/fresh-${TAG}"
NOW="$(date +"%Y-%m-%d")"
# create output directory
mkdir -p dist
# update version.php and build thephar
echo "<?php define(\"APP_VERSION\", \"${TAG}\"); define(\"BUILD_DATE\", \"${NOW}\");" > src/version.php
tools/pharlite
# copy raw phar into destination
cp -v fresh.phar "$OUT.phar"