diff options
Diffstat (limited to 'packaging/build')
| -rwxr-xr-x | packaging/build/build-cli.sh | 91 | ||||
| -rwxr-xr-x | packaging/build/build-common.sh | 26 | ||||
| -rwxr-xr-x | packaging/build/build-node.sh | 22 | ||||
| -rwxr-xr-x | packaging/build/build-packages.sh | 16 |
4 files changed, 138 insertions, 17 deletions
diff --git a/packaging/build/build-cli.sh b/packaging/build/build-cli.sh new file mode 100755 index 0000000..b6bd563 --- /dev/null +++ b/packaging/build/build-cli.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +# Build the meshbay-cli package: the command-line client, and the Python +# packages only it needs, on top of meshbay-common. +# +# Expects build-common.sh to have run first: it installed the CLI last, after +# listing the servers' packages in servers-site.txt and servers-bin.txt, so +# everything not in those lists is the CLI's and moves here. +# +# Usage: ./build-cli.sh [staging-dir] +set -euo pipefail + +REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +STAGING="${1:-/tmp/meshbay-build}" +COMMON_ROOT="$STAGING/meshbay-common-root" +ROOT="$STAGING/meshbay-cli-root" + +VENV="$COMMON_ROOT/opt/meshbay-common/venv" +PYVER=$(basename "$VENV"/lib/python3.*) +SITE="$VENV/lib/$PYVER/site-packages" + +VERSION=$(python3 -c " +import tomllib, pathlib +p = pathlib.Path('$REPO/packages/meshbay-cli/pyproject.toml') +print(tomllib.loads(p.read_text())['project']['version']) +") +echo "==> meshbay-cli $VERSION" + +[ -d "$VENV" ] || { echo "!! shared venv not found — run build-common.sh first" >&2; exit 1; } +[ -f "$STAGING/servers-site.txt" ] || { + echo "!! $STAGING/servers-site.txt missing — run build-common.sh first" >&2; exit 1; } +[ -d "$SITE/meshbay_cli" ] || { + echo "!! meshbay_cli not in the shared venv — was build-cli.sh already run?" >&2; exit 1; } + +rm -rf "$ROOT" +mkdir -p "$ROOT/opt/meshbay-cli" + +# Run from the staged venv with no bytecode written: whatever it imports +# would otherwise leave __pycache__ in files other packages own. +run_venv() { PYTHONDONTWRITEBYTECODE=1 "$VENV/bin/python" "$@"; } + +# --- Before moving anything: the notices and the man page ----------------- +# Both need the CLI importable, which it is only where build-common.sh put it. +echo " writing THIRD-PARTY-NOTICES.txt" +run_venv "$REPO/packaging/third_party_notices.py" \ + -o "$ROOT/opt/meshbay-cli/THIRD-PARTY-NOTICES.txt" meshbay-cli + +echo " generating the man page" +mkdir -p "$ROOT/usr/share/man/man1" +run_venv -m meshbay_cli.manpage | gzip -9n > "$ROOT/usr/share/man/man1/meshbay-cli.1.gz" +[ "$(gzip -dc "$ROOT/usr/share/man/man1/meshbay-cli.1.gz" | head -c 3)" = ".TH" ] || { + echo "!! the man page did not generate" >&2; exit 1; } + +# bash-completion loads it the first time Tab is pressed after `meshbay-cli`. +echo " generating the bash completion" +COMPLETIONS="$ROOT/usr/share/bash-completion/completions" +mkdir -p "$COMPLETIONS" +MESHBAY_CLI_HOME="$STAGING/cli-home" run_venv -m meshbay_cli completion bash \ + > "$COMPLETIONS/meshbay-cli" +grep -q '^complete -F _meshbay_cli meshbay-cli$' "$COMPLETIONS/meshbay-cli" || { + echo "!! the bash completion did not generate" >&2; exit 1; } + +# --- The CLI and its own dependencies, out of the common tree --------------- +# MOVE (not copy), as build-hub.sh and build-node.sh do: dpkg/rpm then know +# these files belong to meshbay-cli. The list is kept for the maintainer +# scripts, which remove the bytecode compiled next to these files. +CLI_SITE="$ROOT/opt/meshbay-common/venv/lib/$PYVER/site-packages" +CLI_BIN="$ROOT/opt/meshbay-common/venv/bin" +mkdir -p "$CLI_SITE" "$CLI_BIN" +: > "$ROOT/opt/meshbay-cli/site-packages.list" +while IFS= read -r entry; do + mv "$SITE/$entry" "$CLI_SITE/" + echo "$entry" >> "$ROOT/opt/meshbay-cli/site-packages.list" +done < <(LC_ALL=C comm -13 "$STAGING/servers-site.txt" <(LC_ALL=C ls -1A "$SITE")) +while IFS= read -r entry; do + mv "$VENV/bin/$entry" "$CLI_BIN/" +done < <(LC_ALL=C comm -13 "$STAGING/servers-bin.txt" <(LC_ALL=C ls -1A "$VENV/bin")) +echo " moved: $(tr '\n' ' ' < "$ROOT/opt/meshbay-cli/site-packages.list")" + +# Only the client is on PATH; the dependencies' own scripts (pygmentize, +# keyring, ...) stay inside the venv. +mkdir -p "$ROOT/usr/bin" +ln -sf /opt/meshbay-common/venv/bin/meshbay-cli "$ROOT/usr/bin/meshbay-cli" + +find "$ROOT" -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true + +# What the venv holds of this package, for the rpm spec's %files: the entries +# differ with every dependency upgrade, so no list is kept by hand. +( cd "$ROOT" && find opt/meshbay-common/venv/lib/*/site-packages opt/meshbay-common/venv/bin \ + -mindepth 1 -maxdepth 1 | LC_ALL=C sort | sed 's|^|/|' ) > "$ROOT.files" + +echo "==> meshbay-cli staging ready at $ROOT" diff --git a/packaging/build/build-common.sh b/packaging/build/build-common.sh index 5f119c6..ca5bd1b 100755 --- a/packaging/build/build-common.sh +++ b/packaging/build/build-common.sh @@ -29,9 +29,9 @@ echo " creating venv at $VENV_BUILD" python3 -m venv "$VENV_BUILD" "$VENV_BUILD/bin/pip" install --upgrade pip wheel 2>&1 | tail -1 -# --- Build wheels for all three packages ----------------------------------- +# --- Build wheels for every package ---------------------------------------- echo " building wheels" -for pkg in meshbay-common meshbay-hub meshbay-node; do +for pkg in meshbay-common meshbay-hub meshbay-node meshbay-cli; do "$VENV_BUILD/bin/pip" wheel \ --no-deps \ --wheel-dir "$WHEEL_DIR" \ @@ -44,11 +44,29 @@ echo " installing all packages + dependencies" --find-links "$WHEEL_DIR" \ meshbay-common meshbay-hub meshbay-node 2>&1 | tail -3 +# The command-line client goes in last, after a list of what the servers need: +# whatever its install adds is the CLI's alone, and build-cli.sh moves it into +# the meshbay-cli package, so a server carries no Textual. +SITE_BUILD=$(echo "$VENV_BUILD"/lib/python3.*/site-packages) +LC_ALL=C ls -1A "$SITE_BUILD" > "$STAGING/servers-site.txt" +LC_ALL=C ls -1A "$VENV_BUILD/bin" > "$STAGING/servers-bin.txt" +echo " installing meshbay-cli + its own dependencies" +"$VENV_BUILD/bin/pip" install \ + --find-links "$WHEEL_DIR" \ + meshbay-cli 2>&1 | tail -1 + # --- Third-party notices: every package the venv ships, with its licence ------- echo " writing THIRD-PARTY-NOTICES.txt" "$VENV_BUILD/bin/python" "$REPO/packaging/third_party_notices.py" \ -o "$ROOT/opt/meshbay-common/THIRD-PARTY-NOTICES.txt" meshbay-hub meshbay-node +# --- Known vulnerabilities in what ships ----------------------------------- +# One stops the build unless packaging/pip-audit-ignore.txt says why it does not +# apply; no network only skips the audit, with a warning. pip-audit runs from a +# venv of its own under the staging dir, never from the one shipped. +echo " auditing dependencies (pip-audit)" +"$VENV_BUILD/bin/python" "$REPO/packaging/audit_deps.py" --tool-dir "$STAGING/pip-audit" + # --- Strip build tools from the venv (not needed at runtime) --------------- echo " stripping build tools" "$VENV_BUILD/bin/pip" uninstall -y pip setuptools wheel 2>&1 | tail -1 @@ -64,7 +82,9 @@ for f in "$VENV_BUILD/bin"/*; do [ -f "$f" ] || continue [ -L "$f" ] && continue head -1 "$f" | grep -q "^#!" || continue - sed -i "1s|$ROOT||" "$f" + # Line 2 too: past 127 characters, pip writes a `#!/bin/sh` trampoline that + # names the interpreter on the next line. + sed -i "1,2s|$ROOT||" "$f" done sed -i "s|$ROOT||g" "$VENV_BUILD/pyvenv.cfg" diff --git a/packaging/build/build-node.sh b/packaging/build/build-node.sh index b9d542c..74d1d40 100755 --- a/packaging/build/build-node.sh +++ b/packaging/build/build-node.sh @@ -45,18 +45,22 @@ ln -sf /opt/meshbay-common/venv/bin/meshbay-node "$ROOT/usr/bin/meshbay-node" # --- Node-specific assets ------------------------------------------------- mkdir -p "$ROOT/opt/meshbay-node/share" -# default.env: the shared TMDB token, copied as is from QE/default.env (never -# versioned), one line: MESHBAY_TMDB_DEFAULT_TOKEN=eyJ... The daemon reads it -# beneath <config>/node.env and the operator's own token, so it is only the -# fallback. 0644: a per-user node must read it, and it is the same token in -# every copy of the package. No token, no build: an empty one goes unnoticed. +# default.env: the shared TMDB token, taken from QE/default.env (never +# versioned). Only its first line ships, and only once it is exactly +# MESHBAY_TMDB_DEFAULT_TOKEN=<JWT>: anything else written in that file stays +# out of a public package. The daemon reads it beneath <config>/node.env and +# the operator's own token, so it is only the fallback. 0644: a per-user node +# must read it, and it is the same token in every copy of the package. No +# token, no build: an empty one goes unnoticed. DEFAULT_ENV="$REPO/QE/default.env" -if [ "$(head -c 30 "$DEFAULT_ENV" 2>/dev/null)" != "MESHBAY_TMDB_DEFAULT_TOKEN=eyJ" ]; then - echo "!! $DEFAULT_ENV missing, or not starting with MESHBAY_TMDB_DEFAULT_TOKEN=eyJ... (no BOM)" >&2 +TOKEN_LINE="$(head -n 1 "$DEFAULT_ENV" 2>/dev/null | tr -d '\r' || true)" +if ! [[ "$TOKEN_LINE" =~ ^MESHBAY_TMDB_DEFAULT_TOKEN=eyJ[A-Za-z0-9_.-]+$ ]]; then + echo "!! $DEFAULT_ENV missing, or its first line is not MESHBAY_TMDB_DEFAULT_TOKEN=eyJ... (no BOM)" >&2 exit 1 fi -install -m 644 "$DEFAULT_ENV" "$ROOT/opt/meshbay-node/share/default.env" -echo " default.env copied from QE/" +printf '%s\n' "$TOKEN_LINE" > "$ROOT/opt/meshbay-node/share/default.env" +chmod 644 "$ROOT/opt/meshbay-node/share/default.env" +echo " default.env: token line taken from QE/" # --- Systemd units -------------------------------------------------------- mkdir -p "$ROOT/usr/lib/systemd/system" diff --git a/packaging/build/build-packages.sh b/packaging/build/build-packages.sh index 8ca0e23..7bbf6b5 100755 --- a/packaging/build/build-packages.sh +++ b/packaging/build/build-packages.sh @@ -63,19 +63,23 @@ mkdir -p "$OUT" # --- Step 1: Build staging trees ------------------------------------------ -echo "--- [1/4] meshbay-common (shared venv + all deps) ---" +echo "--- [1/5] meshbay-common (shared venv + all deps) ---" bash "$SCRIPT_DIR/build-common.sh" "$STAGING" echo "" -echo "--- [2/4] meshbay-hub ---" +echo "--- [2/5] meshbay-hub ---" bash "$SCRIPT_DIR/build-hub.sh" "$STAGING" echo "" -echo "--- [3/4] meshbay-node ---" +echo "--- [3/5] meshbay-node ---" bash "$SCRIPT_DIR/build-node.sh" "$STAGING" echo "" -echo "--- [4/4] meshbay-client ---" +echo "--- [4/5] meshbay-cli ---" +bash "$SCRIPT_DIR/build-cli.sh" "$STAGING" + +echo "" +echo "--- [5/5] meshbay-client ---" bash "$SCRIPT_DIR/build-client.sh" "$STAGING" $ARM64_FLAG # --- Step 2: Package ------------------------------------------------------ @@ -143,6 +147,7 @@ if [ "$FORMAT" = "deb" ]; then build_deb meshbay-common build_deb meshbay-hub build_deb meshbay-node + build_deb meshbay-cli build_deb meshbay-client elif [ "$FORMAT" = "rpm" ]; then @@ -175,6 +180,7 @@ elif [ "$FORMAT" = "rpm" ]; then build_rpm meshbay-common build_rpm meshbay-hub build_rpm meshbay-node + build_rpm meshbay-cli build_rpm meshbay-client fi @@ -187,5 +193,5 @@ ls -lh "$OUT"/ echo "" echo "Install order:" echo " 1. meshbay-common" -echo " 2. meshbay-hub and/or meshbay-node" +echo " 2. meshbay-hub, meshbay-node and/or meshbay-cli" echo " 3. meshbay-client" |