2026-08-14 10:13:10 +02:00
2026-08-14 09:09:59 +02:00
2026-08-14 09:09:59 +02:00
2026-08-14 09:09:59 +02:00
2026-08-14 09:09:59 +02:00
2026-08-14 09:09:59 +02:00
2026-08-14 10:13:10 +02:00
2026-08-14 09:09:59 +02:00
2026-08-14 10:13:10 +02:00
2026-08-14 09:09:59 +02:00
2026-08-14 09:09:59 +02:00
2026-08-14 09:09:59 +02:00
2026-08-14 09:09:59 +02:00

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

./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:

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.

The first one

upd --update needs an upd to run it. loadupd.sh fetches that first one - POSIX sh, curl or wget, no upd required:

./loadupd.sh              # into the current directory
./loadupd.sh ~/bin        # into a directory of your choosing

It reads the newest release, picks the asset matching uname -s/uname -m, runs it once before putting it in place, and says if the directory is not in $PATH. $UPD_REPO_URL points it at a mirror. From there on upd takes over.

Updating itself

upd installs itself the same way it installs everything else - same forge layer, same CA fallback, same checksum check, same atomic replace:

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:

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.

S
Description
No description provided
Readme
186 KiB
2.0.3
Latest
2026-08-14 09:10:15 +02:00
Languages
Go 94.3%
Shell 5.7%