Added documentation and installer support for the github secondary mirror
Container image / image (push) Successful in 1m42s
Container image / image (push) Successful in 1m42s
This commit is contained in:
+6
-3
@@ -44,10 +44,13 @@ Initial public release.
|
|||||||
`quptime` user, `ProtectSystem=strict`, all capabilities dropped by
|
`quptime` user, `ProtectSystem=strict`, all capabilities dropped by
|
||||||
default.
|
default.
|
||||||
- **Multi-arch Docker images** (`linux/amd64`, `linux/arm64`)
|
- **Multi-arch Docker images** (`linux/amd64`, `linux/arm64`)
|
||||||
published to `git.cer.sh/axodouble/quptime`.
|
published to `git.cer.sh/axodouble/quptime` (primary) and
|
||||||
|
`ghcr.io/axodouble/quptime` (GitHub push-mirror) on every tag.
|
||||||
- **Static Linux binaries** (`amd64`, `arm64`) published per tag with
|
- **Static Linux binaries** (`amd64`, `arm64`) published per tag with
|
||||||
a `SHA256SUMS` file; the official installer verifies the checksum
|
a `SHA256SUMS` file to both Gitea Releases (primary) and GitHub
|
||||||
before placing the binary on disk.
|
Releases (mirror). The official installer prefers Gitea, falls back
|
||||||
|
to GitHub on failure, and verifies the checksum before placing the
|
||||||
|
binary on disk.
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
|
|||||||
@@ -14,12 +14,37 @@ trust — no central CA, no shared secret.
|
|||||||
|
|
||||||
### From pre-built binary
|
### From pre-built binary
|
||||||
|
|
||||||
This can be done in one step, either by downloading the latest release from
|
The canonical home is Gitea; the repo is push-mirrored to GitHub on
|
||||||
the [Gitea releases page](https://git.cer.sh/axodouble/quptime/releases) or by running the following script:
|
every tag. Releases and multi-arch container images are published to
|
||||||
|
both.
|
||||||
|
|
||||||
|
| Source | Releases | Container image |
|
||||||
|
| ---------------- | ------------------------------------------------------------ | -------------------------------- |
|
||||||
|
| Gitea (primary) | <https://git.cer.sh/axodouble/quptime/releases> | `git.cer.sh/axodouble/quptime` |
|
||||||
|
| GitHub (mirror) | <https://github.com/Axodouble/QUptime/releases> | `ghcr.io/axodouble/quptime` |
|
||||||
|
|
||||||
|
One-step install — tries Gitea first, falls back to GitHub automatically:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl -fsSL https://git.cer.sh/Axodouble/QUptime/raw/branch/master/install.sh | sudo bash
|
curl -fsSL https://git.cer.sh/Axodouble/QUptime/raw/branch/master/install.sh | sudo bash
|
||||||
|
# or, via the GitHub mirror:
|
||||||
|
# curl -fsSL https://raw.githubusercontent.com/Axodouble/QUptime/master/install.sh | sudo bash
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The script verifies the binary against the published `SHA256SUMS`
|
||||||
|
before installing and refuses to proceed on a mismatch.
|
||||||
|
|
||||||
|
### From Docker
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker pull git.cer.sh/axodouble/quptime:latest
|
||||||
|
# or, via the GitHub mirror:
|
||||||
|
# docker pull ghcr.io/axodouble/quptime:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
See [docs/deployment/docker.md](docs/deployment/docker.md) for compose
|
||||||
|
recipes.
|
||||||
|
|
||||||
## Why
|
## Why
|
||||||
|
|
||||||
Most uptime monitors are either a SaaS or a single box that, by
|
Most uptime monitors are either a SaaS or a single box that, by
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
quptime:
|
quptime:
|
||||||
image: git.cer.sh/axodouble/quptime:master
|
image: git.cer.sh/axodouble/quptime:latest
|
||||||
container_name: quptime
|
container_name: quptime
|
||||||
environment:
|
environment:
|
||||||
# host:port other QUptime nodes use to reach this one. Use the
|
# host:port other QUptime nodes use to reach this one. Use the
|
||||||
|
|||||||
@@ -7,6 +7,13 @@ daemon can bind privileged ports and open ICMP sockets; override with
|
|||||||
|
|
||||||
## Image references
|
## Image references
|
||||||
|
|
||||||
|
The same multi-arch (amd64 + arm64) image is published to two
|
||||||
|
registries. **The Gitea registry is the canonical source** — it also
|
||||||
|
publishes canary `:master` builds on every branch push. GHCR is a
|
||||||
|
tag-only push-mirror for users who can't reach `git.cer.sh`.
|
||||||
|
|
||||||
|
Primary — Gitea registry:
|
||||||
|
|
||||||
```
|
```
|
||||||
git.cer.sh/axodouble/quptime:master # tip of main, multi-arch
|
git.cer.sh/axodouble/quptime:master # tip of main, multi-arch
|
||||||
git.cer.sh/axodouble/quptime:latest # latest tagged release
|
git.cer.sh/axodouble/quptime:latest # latest tagged release
|
||||||
@@ -14,6 +21,14 @@ git.cer.sh/axodouble/quptime:v0.0.1 # specific tagged release
|
|||||||
git.cer.sh/axodouble/quptime:latest-amd64 # single-arch (if you must pin)
|
git.cer.sh/axodouble/quptime:latest-amd64 # single-arch (if you must pin)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Fallback — GitHub Container Registry:
|
||||||
|
|
||||||
|
```
|
||||||
|
ghcr.io/axodouble/quptime:latest # latest tagged release
|
||||||
|
ghcr.io/axodouble/quptime:v0.0.1 # specific tagged release
|
||||||
|
ghcr.io/axodouble/quptime:0.0 # latest patch in the 0.0 minor line
|
||||||
|
```
|
||||||
|
|
||||||
The image embeds `QUPTIME_DIR=/etc/quptime` and declares it a volume —
|
The image embeds `QUPTIME_DIR=/etc/quptime` and declares it a volume —
|
||||||
treat it as the only piece of state worth persisting.
|
treat it as the only piece of state worth persisting.
|
||||||
|
|
||||||
|
|||||||
+48
-17
@@ -10,22 +10,36 @@ matches how you manage software on the host.
|
|||||||
|
|
||||||
## Pre-built binary (recommended)
|
## Pre-built binary (recommended)
|
||||||
|
|
||||||
Releases are published to the [Gitea releases
|
Every tag triggers identical builds on both sources, so either one
|
||||||
page](https://git.cer.sh/axodouble/quptime/releases) with a
|
serves the same artefact set. Gitea is the canonical home; GitHub is a
|
||||||
`SHA256SUMS` file. Two architectures are built: `linux-amd64` and
|
push-mirror.
|
||||||
`linux-arm64`.
|
|
||||||
|
Primary — Gitea releases:
|
||||||
|
<https://git.cer.sh/axodouble/quptime/releases>
|
||||||
|
|
||||||
|
Fallback — GitHub releases (mirrored from the same tag):
|
||||||
|
<https://github.com/Axodouble/QUptime/releases>
|
||||||
|
|
||||||
|
Each release ships `qu-${TAG}-linux-amd64`, `qu-${TAG}-linux-arm64`,
|
||||||
|
and a `SHA256SUMS` file.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Always pin to a tag — `latest` resolves on the server side.
|
# Always pin to a tag — `latest` resolves on the server side.
|
||||||
TAG=v0.1.0
|
TAG=v0.0.1
|
||||||
ARCH=amd64 # or arm64
|
ARCH=amd64 # or arm64
|
||||||
|
|
||||||
|
# Primary: Gitea
|
||||||
curl -fSL -o qu \
|
curl -fSL -o qu \
|
||||||
"https://git.cer.sh/axodouble/quptime/releases/download/${TAG}/qu-${TAG}-linux-${ARCH}"
|
"https://git.cer.sh/axodouble/quptime/releases/download/${TAG}/qu-${TAG}-linux-${ARCH}"
|
||||||
curl -fSL -o SHA256SUMS \
|
curl -fSL -o SHA256SUMS \
|
||||||
"https://git.cer.sh/axodouble/quptime/releases/download/${TAG}/SHA256SUMS"
|
"https://git.cer.sh/axodouble/quptime/releases/download/${TAG}/SHA256SUMS"
|
||||||
|
|
||||||
# Verify before installing.
|
# (or the GitHub mirror — substitute the host below if Gitea is unreachable)
|
||||||
|
# https://github.com/Axodouble/QUptime/releases/download/${TAG}/qu-${TAG}-linux-${ARCH}
|
||||||
|
# https://github.com/Axodouble/QUptime/releases/download/${TAG}/SHA256SUMS
|
||||||
|
|
||||||
|
# Verify before installing. Use the SHA256SUMS from the SAME source
|
||||||
|
# as the binary — never mix.
|
||||||
sha256sum --check --ignore-missing SHA256SUMS
|
sha256sum --check --ignore-missing SHA256SUMS
|
||||||
|
|
||||||
install -m 0755 qu /usr/local/bin/qu
|
install -m 0755 qu /usr/local/bin/qu
|
||||||
@@ -34,31 +48,37 @@ install -m 0755 qu /usr/local/bin/qu
|
|||||||
## One-line install script
|
## One-line install script
|
||||||
|
|
||||||
The repo ships an `install.sh` that handles the download, checksum,
|
The repo ships an `install.sh` that handles the download, checksum,
|
||||||
shell-completion installation, and a default systemd unit file. Run it
|
shell-completion installation, and a hardened systemd unit. Run it
|
||||||
under `sudo` so it can write to `/usr/local/bin` and
|
under `sudo` so it can write to `/usr/local/bin` and
|
||||||
`/etc/systemd/system`.
|
`/etc/systemd/system`.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl -fsSL https://git.cer.sh/Axodouble/QUptime/raw/branch/master/install.sh | sudo bash
|
curl -fsSL https://git.cer.sh/Axodouble/QUptime/raw/branch/master/install.sh | sudo bash
|
||||||
|
# or, via the GitHub mirror:
|
||||||
|
# curl -fsSL https://raw.githubusercontent.com/Axodouble/QUptime/master/install.sh | sudo bash
|
||||||
```
|
```
|
||||||
|
|
||||||
What it does:
|
What it does:
|
||||||
|
|
||||||
1. Looks up the latest release via the Gitea API.
|
1. Looks up the latest release via the Gitea API; falls back to the
|
||||||
2. Downloads the binary to `/usr/local/bin/qu`.
|
GitHub API if Gitea is unreachable.
|
||||||
|
2. Downloads the per-arch binary and the matching `SHA256SUMS` from
|
||||||
|
the same source, then verifies the checksum. Refuses to install on
|
||||||
|
a mismatch.
|
||||||
3. Installs bash / zsh / fish completion if a target directory exists.
|
3. Installs bash / zsh / fish completion if a target directory exists.
|
||||||
4. Writes `/etc/systemd/system/qu-serve.service` and enables it (but
|
4. Creates a dedicated `quptime` system user and writes
|
||||||
does **not** start it — you need to run `qu init` first).
|
`/etc/systemd/system/quptime.service` (hardened — matches the unit
|
||||||
|
in [systemd.md](deployment/systemd.md)). Enables but does not start
|
||||||
The unit it writes is minimal. For a production unit with hardening,
|
the service, so you can configure identity before first boot.
|
||||||
see the [systemd deployment guide](deployment/systemd.md).
|
|
||||||
|
|
||||||
## Build from source
|
## Build from source
|
||||||
|
|
||||||
Requires Go 1.24.2 or newer.
|
Requires Go 1.24.2 or newer.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
# Either remote — Gitea is canonical, GitHub is a push-mirror.
|
||||||
git clone https://git.cer.sh/axodouble/quptime.git
|
git clone https://git.cer.sh/axodouble/quptime.git
|
||||||
|
# git clone https://github.com/Axodouble/QUptime.git
|
||||||
cd quptime
|
cd quptime
|
||||||
go build -ldflags "-X main.version=$(git describe --tags --always)" -o qu ./cmd/qu
|
go build -ldflags "-X main.version=$(git describe --tags --always)" -o qu ./cmd/qu
|
||||||
|
|
||||||
@@ -74,15 +94,26 @@ CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o qu ./cmd/qu
|
|||||||
|
|
||||||
## Docker image
|
## Docker image
|
||||||
|
|
||||||
A multi-arch (`amd64` + `arm64`) image is published to the Gitea
|
The same multi-arch (`amd64` + `arm64`) image is published to two
|
||||||
registry on every tag and every push to `master`:
|
registries on every tag. The Gitea registry is the canonical source
|
||||||
|
and also gets canary `:master` builds; GHCR is a tag-only mirror.
|
||||||
|
|
||||||
|
Primary — Gitea registry:
|
||||||
|
|
||||||
```
|
```
|
||||||
git.cer.sh/axodouble/quptime:master # tip of main
|
git.cer.sh/axodouble/quptime:master # tip of main (canary)
|
||||||
git.cer.sh/axodouble/quptime:latest # latest tagged release
|
git.cer.sh/axodouble/quptime:latest # latest tagged release
|
||||||
git.cer.sh/axodouble/quptime:v0.0.1 # pinned release
|
git.cer.sh/axodouble/quptime:v0.0.1 # pinned release
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Fallback — GitHub Container Registry:
|
||||||
|
|
||||||
|
```
|
||||||
|
ghcr.io/axodouble/quptime:latest # latest tagged release
|
||||||
|
ghcr.io/axodouble/quptime:v0.0.1 # pinned release
|
||||||
|
ghcr.io/axodouble/quptime:0.0 # latest 0.0.x
|
||||||
|
```
|
||||||
|
|
||||||
See the [Docker deployment guide](deployment/docker.md) for compose
|
See the [Docker deployment guide](deployment/docker.md) for compose
|
||||||
files and volume layout.
|
files and volume layout.
|
||||||
|
|
||||||
|
|||||||
+92
-40
@@ -1,12 +1,17 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# QUptime installer.
|
# QUptime installer.
|
||||||
#
|
#
|
||||||
# Downloads the latest released `qu` binary from the Gitea release
|
# Downloads the latest released `qu` binary, verifies it against the
|
||||||
# page, verifies it against the published SHA256SUMS, installs it to
|
# published SHA256SUMS, installs it to /usr/local/bin, and (on systemd
|
||||||
# /usr/local/bin, and (on systemd hosts) drops in a hardened
|
# hosts) drops in a hardened quptime.service that matches the unit
|
||||||
# quptime.service that matches the unit documented in
|
# documented in docs/deployment/systemd.md.
|
||||||
# docs/deployment/systemd.md. Idempotent — re-running upgrades the
|
#
|
||||||
# binary and refreshes the unit without touching the data directory.
|
# Release sources, tried in order:
|
||||||
|
# 1. Gitea: git.cer.sh/axodouble/quptime/releases (primary — canonical home)
|
||||||
|
# 2. GitHub: github.com/Axodouble/QUptime/releases (push-mirror fallback)
|
||||||
|
#
|
||||||
|
# Idempotent — re-running upgrades the binary and refreshes the unit
|
||||||
|
# without touching the data directory.
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
INSTALL_BIN="/usr/local/bin/qu"
|
INSTALL_BIN="/usr/local/bin/qu"
|
||||||
@@ -15,8 +20,15 @@ SERVICE_NAME="$(basename "$SERVICE_FILE")"
|
|||||||
SERVICE_USER="quptime"
|
SERVICE_USER="quptime"
|
||||||
SERVICE_GROUP="quptime"
|
SERVICE_GROUP="quptime"
|
||||||
DATA_DIR="/etc/quptime"
|
DATA_DIR="/etc/quptime"
|
||||||
REPO_API="https://git.cer.sh/api/v1/repos/axodouble/quptime/releases/latest"
|
|
||||||
RELEASE_BASE="https://git.cer.sh/axodouble/quptime/releases/download"
|
# Release sources, in preference order. Each row is:
|
||||||
|
# <name>|<latest-release API endpoint>|<release-asset base URL>
|
||||||
|
# The asset URL is concatenated with `/<tag>/<filename>`. Adjust here
|
||||||
|
# if the project moves hosts.
|
||||||
|
SOURCES=(
|
||||||
|
"gitea|https://git.cer.sh/api/v1/repos/axodouble/quptime/releases/latest|https://git.cer.sh/axodouble/quptime/releases/download"
|
||||||
|
"github|https://api.github.com/repos/Axodouble/QUptime/releases/latest|https://github.com/Axodouble/QUptime/releases/download"
|
||||||
|
)
|
||||||
|
|
||||||
fail() {
|
fail() {
|
||||||
echo "Error: $*" >&2
|
echo "Error: $*" >&2
|
||||||
@@ -38,6 +50,51 @@ write_completion() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# fetch_from_source tries one release source end-to-end: pulls the
|
||||||
|
# latest tag from its API, downloads the per-arch binary and the
|
||||||
|
# accompanying SHA256SUMS, and verifies the checksum. Returns 0 on
|
||||||
|
# success (with RELEASE and BINARY_NAME set as globals) or 1 if any
|
||||||
|
# step fails — callers can then try the next source. Stderr is kept
|
||||||
|
# quiet so a failed primary doesn't spam the operator before the
|
||||||
|
# fallback is attempted.
|
||||||
|
fetch_from_source() {
|
||||||
|
local api_url=$1
|
||||||
|
local release_base=$2
|
||||||
|
local tmpdir=$3
|
||||||
|
|
||||||
|
local release
|
||||||
|
release=$(curl -fsSL --proto '=https' --tlsv1.2 "$api_url" 2>/dev/null | jq -r '.tag_name' 2>/dev/null) \
|
||||||
|
|| return 1
|
||||||
|
[ -n "$release" ] && [ "$release" != "null" ] || return 1
|
||||||
|
|
||||||
|
local binary_name="qu-${release}-linux-${ARCH}"
|
||||||
|
local binary_url="${release_base}/${release}/${binary_name}"
|
||||||
|
local sums_url="${release_base}/${release}/SHA256SUMS"
|
||||||
|
|
||||||
|
curl -fsSL --proto '=https' --tlsv1.2 -o "$tmpdir/$binary_name" "$binary_url" 2>/dev/null \
|
||||||
|
|| return 1
|
||||||
|
curl -fsSL --proto '=https' --tlsv1.2 -o "$tmpdir/SHA256SUMS" "$sums_url" 2>/dev/null \
|
||||||
|
|| return 1
|
||||||
|
|
||||||
|
# Verify against the SHA256SUMS that came from the same source as
|
||||||
|
# the binary. Never mix sources here — verifying a GitHub-hosted
|
||||||
|
# binary against a Gitea-hosted SHA256SUMS would defeat the
|
||||||
|
# tamper check.
|
||||||
|
(
|
||||||
|
cd "$tmpdir"
|
||||||
|
if ! grep -E "[[:space:]]\\*?${binary_name}\$" SHA256SUMS > expected.sum; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! sha256sum -c expected.sum >/dev/null 2>&1; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
) || return 1
|
||||||
|
|
||||||
|
RELEASE="$release"
|
||||||
|
BINARY_NAME="$binary_name"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
require_command curl
|
require_command curl
|
||||||
require_command jq
|
require_command jq
|
||||||
require_command sha256sum
|
require_command sha256sum
|
||||||
@@ -55,44 +112,39 @@ if [ ! -w "$(dirname "$INSTALL_BIN")" ]; then
|
|||||||
fail "Cannot write to $(dirname "$INSTALL_BIN"). Run this script with sudo, or set INSTALL_BIN to a writable location."
|
fail "Cannot write to $(dirname "$INSTALL_BIN"). Run this script with sudo, or set INSTALL_BIN to a writable location."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- latest release tag -------------------------------------------------
|
# --- download + verify (with fallback) ----------------------------------
|
||||||
RELEASE=$(curl -fsSL "$REPO_API" | jq -r '.tag_name')
|
|
||||||
[ -n "$RELEASE" ] && [ "$RELEASE" != "null" ] \
|
|
||||||
|| fail "could not determine the latest release tag from $REPO_API"
|
|
||||||
|
|
||||||
BINARY_NAME="qu-${RELEASE}-linux-${ARCH}"
|
|
||||||
BINARY_URL="${RELEASE_BASE}/${RELEASE}/${BINARY_NAME}"
|
|
||||||
SUMS_URL="${RELEASE_BASE}/${RELEASE}/SHA256SUMS"
|
|
||||||
|
|
||||||
# --- download + verify --------------------------------------------------
|
|
||||||
# Stage in a temp dir so a failed verification never leaves a partial
|
|
||||||
# or unverified binary on disk.
|
|
||||||
TMPDIR=$(mktemp -d)
|
TMPDIR=$(mktemp -d)
|
||||||
trap 'rm -rf "$TMPDIR"' EXIT
|
trap 'rm -rf "$TMPDIR"' EXIT
|
||||||
|
|
||||||
echo "> downloading $BINARY_NAME"
|
# Globals filled in by fetch_from_source on success.
|
||||||
curl -fsSL --proto '=https' --tlsv1.2 -o "$TMPDIR/$BINARY_NAME" "$BINARY_URL"
|
RELEASE=""
|
||||||
echo "> downloading SHA256SUMS"
|
BINARY_NAME=""
|
||||||
curl -fsSL --proto '=https' --tlsv1.2 -o "$TMPDIR/SHA256SUMS" "$SUMS_URL"
|
INSTALLED_FROM=""
|
||||||
|
INSTALLED_TMP=""
|
||||||
|
|
||||||
echo "> verifying checksum"
|
for source_spec in "${SOURCES[@]}"; do
|
||||||
# Pull just our binary's entry so sha256sum -c doesn't fail on the
|
IFS='|' read -r src_name src_api src_base <<<"$source_spec"
|
||||||
# arches we didn't download.
|
src_tmp="$TMPDIR/$src_name"
|
||||||
(
|
mkdir -p "$src_tmp"
|
||||||
cd "$TMPDIR"
|
echo "> trying release source: $src_name"
|
||||||
if ! grep -E "[[:space:]]\\*?${BINARY_NAME}\$" SHA256SUMS > expected.sum; then
|
# `set -e` would abort the whole script the moment fetch_from_source
|
||||||
fail "no entry for $BINARY_NAME in published SHA256SUMS — refusing to install"
|
# returns nonzero; we want the loop to fall through to the next
|
||||||
|
# source instead. Wrap the call so a failure is just data.
|
||||||
|
if fetch_from_source "$src_api" "$src_base" "$src_tmp"; then
|
||||||
|
INSTALLED_FROM="$src_name"
|
||||||
|
INSTALLED_TMP="$src_tmp"
|
||||||
|
echo "> $src_name: ${RELEASE} ✓ checksum OK"
|
||||||
|
break
|
||||||
fi
|
fi
|
||||||
if ! sha256sum -c expected.sum >/dev/null 2>&1; then
|
echo "> $src_name: unavailable"
|
||||||
echo "expected: $(awk '{print $1}' expected.sum)"
|
done
|
||||||
echo "actual: $(sha256sum "$BINARY_NAME" | awk '{print $1}')"
|
|
||||||
fail "checksum mismatch for $BINARY_NAME — refusing to install"
|
|
||||||
fi
|
|
||||||
)
|
|
||||||
echo "> checksum OK"
|
|
||||||
|
|
||||||
install -m 0755 "$TMPDIR/$BINARY_NAME" "$INSTALL_BIN"
|
if [ -z "$INSTALLED_FROM" ]; then
|
||||||
echo "> qu ${RELEASE} installed to $INSTALL_BIN"
|
fail "no release source reachable — tried: $(printf '%s ' "${SOURCES[@]%%|*}"). Check network access to git.cer.sh and github.com."
|
||||||
|
fi
|
||||||
|
|
||||||
|
install -m 0755 "$INSTALLED_TMP/$BINARY_NAME" "$INSTALL_BIN"
|
||||||
|
echo "> qu ${RELEASE} installed to $INSTALL_BIN (source: $INSTALLED_FROM)"
|
||||||
|
|
||||||
# --- shell completions --------------------------------------------------
|
# --- shell completions --------------------------------------------------
|
||||||
if "$INSTALL_BIN" --help 2>/dev/null | grep -q "completion"; then
|
if "$INSTALL_BIN" --help 2>/dev/null | grep -q "completion"; then
|
||||||
|
|||||||
Reference in New Issue
Block a user