105 lines
4.0 KiB
Markdown
105 lines
4.0 KiB
Markdown
# upd (Go)
|
||
|
||
A port of the Perl `upd` one directory up. Same command line, same config file,
|
||
same state and cache files - the two can be used interchangeably on the same
|
||
machine.
|
||
|
||
## Build
|
||
|
||
```sh
|
||
./build.sh
|
||
```
|
||
|
||
builds every platform into `./bin`, statically linked and stripped, and bumps
|
||
the patch version by 0.0.1 on each run. `version.txt` holds the version just
|
||
built; the same number goes into the binaries via `-ldflags -X main.version`,
|
||
so `upd --version` and the release tag always agree. One platform only:
|
||
|
||
```sh
|
||
PLATFORMS="linux/amd64" ./build.sh
|
||
```
|
||
|
||
The asset names in `./bin` - `upd-<goos>-<goarch>` - are exactly what
|
||
`--update` looks for in a release, so a release is `./bin` uploaded as it is.
|
||
A plain `go build -o ~/bin/upd .` still works; it just reports the fallback
|
||
version from `main.go`.
|
||
|
||
`go test ./...` runs the asset selection against the release JSON in
|
||
`../t/corpus`, the same corpus `t/select.t` uses, and fails if the two
|
||
implementations start disagreeing.
|
||
|
||
## Updating itself
|
||
|
||
upd installs itself the same way it installs everything else - same forge
|
||
layer, same CA fallback, same checksum check, same atomic replace:
|
||
|
||
```sh
|
||
upd --version # what is running
|
||
upd --check-update # look, change nothing
|
||
upd --update # download the newest release and replace the binary
|
||
```
|
||
|
||
`--update` replaces the file the running binary actually is, following a
|
||
symlink into `./bin` to the file behind it. It refuses before downloading if
|
||
that directory is not writable, and it runs the downloaded binary once with
|
||
`--version` before letting it take over, so a truncated file or one for the
|
||
wrong platform never replaces a working one. `--force` reinstalls the current
|
||
version, `--dry-run` says what it would do.
|
||
|
||
Beyond that, an ordinary run looks for a new release once a day, in the
|
||
background, and mentions it on stderr:
|
||
|
||
```
|
||
Note: upd 2.0.7 is available, run 'upd --update'.
|
||
```
|
||
|
||
The look never happens in the foreground - the run itself is never slowed down
|
||
or made to depend on the network - and never when stderr is not a terminal, so
|
||
cron and pipelines stay silent. `UPD_NO_UPDATE_CHECK=1` switches it off
|
||
altogether. The note lives in `~/.cache/upd/selfupdate.json`.
|
||
|
||
The mechanism is the one in `dx`; here it goes through upd's own machinery
|
||
instead of bringing its own HTTP client.
|
||
|
||
## Why a port
|
||
|
||
The Perl version needs curl or wget for HTTPS, which is exactly what breaks on
|
||
an older system: a curl linked against OpenSSL 1.0.x cannot complete a
|
||
handshake with a server that requires TLS 1.2, and there is nothing upd can do
|
||
about it beyond falling back to wget. The Go binary brings its own TLS stack,
|
||
so the transport question disappears - along with `--stderr` juggling, exit
|
||
code translation and the wget fallback.
|
||
|
||
## Certificates
|
||
|
||
Verification uses the system CA store. If that store does not know the issuer -
|
||
the usual case on a machine whose `ca-certificates` package predates Let's
|
||
Encrypt's ISRG roots - upd says so once and retries with the Mozilla CA list
|
||
embedded in `ca-bundle.pem`, so the binary stays self-sufficient. Refresh that
|
||
file with:
|
||
|
||
```sh
|
||
curl -o ca-bundle.pem https://curl.se/ca/cacert.pem
|
||
```
|
||
|
||
`--cacert FILE` (or `$UPD_CACERT`) replaces the system store, for a private CA.
|
||
`--insecure` skips verification altogether and warns on every run. Both switch
|
||
the automatic fallback off: an explicit choice stays the choice.
|
||
|
||
## Differences
|
||
|
||
| | Perl | Go |
|
||
|---|---|---|
|
||
| TLS | curl / wget / IO::Socket::SSL | built in |
|
||
| CA roots | whatever the system has | system, with the Mozilla list as fallback |
|
||
| `--cacert`, `--insecure` | – | yes |
|
||
| `tar`, `unzip` | external | in-process |
|
||
| `.gz`, `.bz2` | external | in-process |
|
||
| `.xz`, `.zst`, `.lz4`, `.7z` | external | external (unchanged) |
|
||
| Archive paths | trusted to `tar` | checked against traversal |
|
||
| `version-flag=` in the config file | overwritten by its own default | honoured |
|
||
|
||
Behaviour that deliberately stayed identical: asset scoring (same picks on the
|
||
whole corpus), the `--install` file-or-directory rule, state and cache file
|
||
layout, exit codes 0/1/2/10.
|