Package workstation tools, reuse emulator sessions, and derive build versions

This commit is contained in:
2026-09-23 03:45:48 +08:00
parent 6bfcce8070
commit f5d9f96409
79 changed files with 878 additions and 132 deletions
+5 -2
View File
@@ -3,6 +3,7 @@
source "$(dirname -- "${BASH_SOURCE[0]}")/lib.sh"
[[ $# == 0 ]] || die 'Usage: tools/build-base-packages'
cd "$FDS_ROOT"
fds_version=$(tools/version)
use_xbps
check_void_pin
mkdir -p out/logs out/packages out/manifests
@@ -12,7 +13,7 @@ flock -n 8 || die 'Another base package build is already running'
tools/build-fds-package
tools/build-kernel
tools/build-dasungd
input="$FDS_VOID/hostdir/sources/fds-init-0.1.0"
input="$FDS_VOID/hostdir/sources/fds-init-${fds_version}"
if [[ -d $input ]]; then
previous=$(mktemp -d "$FDS_ROOT/out/init-source.XXXXXX")
mv "$input" "$previous/"
@@ -35,7 +36,9 @@ for package in fds-dhcpcd fds-eink fds-base-files fds-init fds-base; do
xbps_src -a aarch64 clean "$package"
xbps_src -f -a aarch64 pkg "$package"
) 2>&1 | tee "out/logs/xbps-$package.log"
cp "$FDS_VOID/hostdir/binpkgs/$package-"*.aarch64.xbps out/packages/
package_version=$fds_version
[[ $package != fds-dhcpcd ]] || package_version=10.3.2
tools/export-package "$FDS_VOID/hostdir/binpkgs/${package}-${package_version}_1.aarch64.xbps"
done
XBPS_ARCH=aarch64 xbps-rindex -fa out/packages/fds-*.aarch64.xbps
printf 'PASS: all FDS base packages exported to out/packages/\n'
+6 -6
View File
@@ -2,12 +2,13 @@
source "$(dirname -- "${BASH_SOURCE[0]}")/lib.sh"
[[ $# == 0 ]] || die 'Usage: tools/build-dasungd'
cd "$FDS_ROOT"
fds_version=$(tools/version)
use_xbps
check_void_pin
mkdir -p out/logs out/manifests out/packages
# These are build-container tools; no Arch packages or host services are changed.
missing=()
for package in cross-aarch64-linux-musl pkg-config s6-rc; do
for package in cross-aarch64-linux-musl pkg-config s6-rc python3 git; do
if ! XBPS_ARCH=x86_64 xbps-query -r "$FDS_VOID/masterdir-x86_64" "$package" >/dev/null 2>&1; then
missing+=("$package")
fi
@@ -26,7 +27,7 @@ tools/in-void env LIBUSB_NO_PKG_CONFIG=1 LIBUDEV_NO_PKG_CONFIG=1 \
binary=target/aarch64-unknown-linux-musl/release/dasungd
tools/verify-elf "$binary" aarch64 static
cp -- "$binary" out/dasungd
input="$FDS_VOID/hostdir/sources/fds-dasungd-0.1.0"
input="$FDS_VOID/hostdir/sources/fds-dasungd-${fds_version}"
mkdir -p "$input"
cp -- "$binary" "$input/dasungd"
cp rust/dasungd/LICENSE rust/dasungd/profiles/paperlike13k-37hz.edid "$input/"
@@ -62,10 +63,9 @@ tools/prepare-void
cd "$FDS_VOID"
xbps_src -f -a aarch64 pkg fds-dasungd
) 2>&1 | tee out/logs/xbps-fds-dasungd.log
package=fds-dasungd-0.1.0_1.aarch64.xbps
cp "$FDS_VOID/hostdir/binpkgs/$package" out/packages/
XBPS_ARCH=aarch64 xbps-rindex -fa "out/packages/$package"
package="fds-dasungd-${fds_version}_1.aarch64.xbps"
tools/export-package "$FDS_VOID/hostdir/binpkgs/$package"
sha256sum out/dasungd "out/packages/$package" >out/manifests/dasung-artifacts.sha256
XBPS_ARCH=x86_64 xbps-query -r "$FDS_VOID/masterdir-x86_64" -l >out/manifests/dasung-build-packages.txt
sha256sum Cargo.toml Cargo.lock rust-toolchain.toml .cargo/config.toml tools/cargo-build tools/lib.sh tools/build-dasungd >out/manifests/dasung-rust-inputs.sha256
sha256sum tools/version tools/fds_version.py tools/version-build.rs Cargo.toml Cargo.lock rust-toolchain.toml .cargo/config.toml tools/cargo-build tools/lib.sh tools/build-dasungd >out/manifests/dasung-rust-inputs.sha256
printf 'PASS: Dasung static ARM executable, base package, and s6 database built\n'
+1 -1
View File
@@ -15,5 +15,5 @@ cp out/fds out/fds-power
sha256sum out/fds-control out/fds-program out/fds-release out/fds-burn out/fds-inspect out/fds-eject out/fds-power out/fds out/fds-stage0 out/fds-boottrace out/fds-cartridged out/fds-profile >out/manifests/fds-tools.sha256
find rust/fds-control rust/fds-software rust/fds-common rust/fds-cli rust/fds-stage0 rust/fds-boottrace rust/fds-cartridged rust/fds-burn rust/fds-release -type f -print0 | sort -z | \
xargs -0 sha256sum >out/manifests/fds-tools-inputs.sha256
sha256sum Cargo.toml Cargo.lock rust-toolchain.toml .cargo/config.toml tools/cargo-build tools/lib.sh tools/build-fds >>out/manifests/fds-tools-inputs.sha256
sha256sum tools/version tools/fds_version.py tools/version-build.rs Cargo.toml Cargo.lock rust-toolchain.toml .cargo/config.toml tools/cargo-build tools/lib.sh tools/build-fds >>out/manifests/fds-tools-inputs.sha256
printf 'PASS: static ARM FDS CLI and stage0 tools built\n'
+5 -6
View File
@@ -2,10 +2,11 @@
source "$(dirname -- "${BASH_SOURCE[0]}")/lib.sh"
[[ $# == 0 ]] || die 'Usage: tools/build-fds-package'
cd "$FDS_ROOT"
fds_version=$(tools/version)
use_xbps
tools/build-fds
tools/prepare-void
input="$FDS_VOID/hostdir/sources/fds-cli-0.1.0"
input="$FDS_VOID/hostdir/sources/fds-cli-${fds_version}"
mkdir -p "$input" out/packages
cp out/fds out/fds-control out/fds-program out/fds-boottrace out/fds-burn out/fds-inspect out/fds-eject out/fds-power out/fds-release LICENSE "$input/"
notices=$(mktemp -d "$FDS_ROOT/out/rust-notices.XXXXXX")
@@ -17,9 +18,8 @@ cp "$notices/RUST-NOTICES.txt" "$input/"
xbps_src -a aarch64 clean fds-cli
xbps_src -f -a aarch64 pkg fds-cli
) 2>&1 | tee out/logs/xbps-fds-cli.log
cp "$FDS_VOID/hostdir/binpkgs/fds-cli-0.1.0_1.aarch64.xbps" out/packages/
XBPS_ARCH=aarch64 xbps-rindex -fa out/packages/fds-cli-0.1.0_1.aarch64.xbps
input="$FDS_VOID/hostdir/sources/fds-cartridged-0.1.0"
tools/export-package "$FDS_VOID/hostdir/binpkgs/fds-cli-${fds_version}_1.aarch64.xbps"
input="$FDS_VOID/hostdir/sources/fds-cartridged-${fds_version}"
if [[ -d $input ]]; then
previous=$(mktemp -d "$FDS_ROOT/out/cartridged-source.XXXXXX")
mv "$input" "$previous/"
@@ -37,6 +37,5 @@ cp s6/source/boot/contents.d/cartridged "$input/s6-source/boot/contents.d/"
xbps_src -a aarch64 clean fds-cartridged
xbps_src -f -a aarch64 pkg fds-cartridged
) 2>&1 | tee out/logs/xbps-fds-cartridged.log
cp "$FDS_VOID/hostdir/binpkgs/fds-cartridged-0.1.0_1.aarch64.xbps" out/packages/
XBPS_ARCH=aarch64 xbps-rindex -fa out/packages/fds-cartridged-0.1.0_1.aarch64.xbps
tools/export-package "$FDS_VOID/hostdir/binpkgs/fds-cartridged-${fds_version}_1.aarch64.xbps"
printf 'PASS: FDS CLI package built without a dynamic libc dependency\n'
+1
View File
@@ -69,6 +69,7 @@ if [[ ${FDS_OFFLINE:-0} == 1 ]]; then
fi
python3 tools/rootfs-archive "$root" "$work" "${archive_inputs[@]}"
{
printf 'version=%s\n' "$(tools/version)"
printf 'profile=%s\nvoid_commit=%s\n' "$profile" "$(cat VOID_PACKAGES_COMMIT)"
printf 'emulation=private-user-namespace-binfmt\n'
tools/in-void xbps-query -p pkgver qemu-user-aarch64
+18 -10
View File
@@ -1,15 +1,23 @@
#!/usr/bin/env bash
# Native Linux host binaries; independent of the Pi and Void build container.
# Build an installable Arch package without installing host packages implicitly.
set -euo pipefail
[[ $# == 0 ]] || { printf 'Usage: tools/build-workstation\n' >&2; exit 2; }
[[ $(uname -s) == Linux ]] || { printf 'A Linux workstation is required\n' >&2; exit 2; }
(( EUID != 0 )) || { printf 'Build as an ordinary user\n' >&2; exit 2; }
cd "$(dirname -- "${BASH_SOURCE[0]}")/.."
command -v cargo >/dev/null || { printf 'Install Rust with Cargo before building workstation tools\n' >&2; exit 2; }
fds_host_target=$(rustc -vV | sed -n 's/^host: //p')
[[ $fds_host_target == *-linux-* ]] || { printf 'Rust must target the native Linux host\n' >&2; exit 2; }
cargo build --locked --release --target "$fds_host_target" -p fds-workstation
mkdir -p out/workstation
install -m755 "target/$fds_host_target/release/fds-cartridge" out/workstation/fds-cartridge
install -m755 "target/$fds_host_target/release/fds-emulator" out/workstation/fds-emulator
printf 'Built native Linux tools in out/workstation/\n'
for tool in makepkg pacman cargo rustc python3 git; do
command -v "$tool" >/dev/null || { printf 'Missing %s; see docs/workstation.md\n' "$tool" >&2; exit 1; }
done
export FDS_SOURCE_DIR="$PWD"
mkdir -p out/workstation out/workstation-package
exec 9>out/.workstation-package.lock
flock -n 9 || { printf 'Another workstation package build is running\n' >&2; exit 1; }
cp packaging/arch/PKGBUILD out/workstation-package/PKGBUILD
export PKGDEST="$PWD/out/workstation"
cd out/workstation-package
# Dependencies are checked by their actual build commands. Runtime features
# are optional, and package installation is a separate explicit Make target.
makepkg --nodeps --force
mapfile -t packages < <(makepkg --packagelist)
(( ${#packages[@]} == 1 )) && [[ -s ${packages[0]} ]] || { printf 'Expected one fds-tools package\n' >&2; exit 1; }
printf '%s\n' "${packages[0]}" >../workstation/package-path.txt
printf 'Built Arch package: %s\nInstall with make workstation-install\n' "${packages[0]}"
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Native Linux host binaries; independent of the Pi and Void build container.
set -euo pipefail
[[ $# == 0 ]] || { printf 'Usage: tools/build-workstation-binaries\n' >&2; exit 2; }
[[ $(uname -s) == Linux ]] || { printf 'A Linux workstation is required\n' >&2; exit 2; }
(( EUID != 0 )) || { printf 'Build as an ordinary user\n' >&2; exit 2; }
cd "$(dirname -- "${BASH_SOURCE[0]}")/.."
command -v cargo >/dev/null || { printf 'Install Rust with Cargo before building workstation tools\n' >&2; exit 2; }
fds_host_target=$(rustc -vV | sed -n 's/^host: //p')
[[ $fds_host_target == *-linux-* ]] || { printf 'Rust must target the native Linux host\n' >&2; exit 2; }
cargo build --locked --release --target "$fds_host_target" -p fds-workstation
mkdir -p out/workstation
install -m755 "target/$fds_host_target/release/fds-cartridge" out/workstation/fds-cartridge
install -m755 "target/$fds_host_target/release/fds-emulator" out/workstation/fds-emulator
printf 'Built native Linux tools in out/workstation/\n'
+4 -2
View File
@@ -24,15 +24,17 @@ PREFIXES = (
'm9-images', 'm9-vm', 'm9-system', 'm10-vm', 'm11-vm', 'm11-faults',
'm12-clock', 'm12-development', 'm12-eeprom', 'm12-internal',
'm12-recovery', 'm12-release-contracts', 'm12-signing',
'rust-profiles', 'workstation-images', 'emu-test',
'rust-profiles', 'workstation-images', 'emu-test', 'arch-package-test', 'version-image-test',
)
GENERATED = re.compile(r'(?:' + '|'.join(PREFIXES) + r')\.[A-Za-z0-9_-]{6,8}')
POINTERS = (
'out/arch-package-current.txt',
'out/version-image-current.txt',
'out/workstation-images-current.txt',
'out/workstation-emulator-current.txt',
'out/manifests/dasung-s6-database.txt',
)
LOCKS = ('.clean.lock', '.rootfs.lock', '.base-packages.lock', '.image-tools.lock')
LOCKS = ('.clean.lock', '.rootfs.lock', '.base-packages.lock', '.image-tools.lock', '.workstation-package.lock')
def within(path, parent):
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env python3
"""Export one FDS XBPS package, retaining superseded builds outside the active index."""
import argparse
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
project = Path(__file__).resolve().parents[1]
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('package', type=Path)
args = parser.parse_args()
source = args.package.resolve(strict=True)
name, release = source.name.rsplit('-', 1)
if not name.startswith('fds-') or not release.endswith('.aarch64.xbps'):
parser.error('Expected an FDS AArch64 package')
out = project / 'out/packages'
out.mkdir(exist_ok=True)
old = [p for p in out.glob(f'{name}-*.aarch64.xbps') if p.name.rsplit('-', 1)[0] == name]
if old:
history = project / 'out/package-history'
history.mkdir(exist_ok=True)
saved = Path(tempfile.mkdtemp(prefix=f'{name}.', dir=history))
for path in old:
path.rename(saved / path.name)
# Prune entries for archived versions before indexing the selected package.
env = dict(os.environ, XBPS_ARCH='aarch64')
index = project / '.host/xbps/usr/bin/xbps-rindex'
subprocess.run([str(index), '-c', str(out)], env=env, check=True)
shutil.copy2(source, out / source.name)
subprocess.run([str(index), '-fa', str(out / source.name)], env=env, check=True)
print(f'Exported {source.name}; previous builds retained under out/package-history')
+59
View File
@@ -0,0 +1,59 @@
"""Canonical FDS build version, shared by Cargo, images and package builders."""
from pathlib import Path
import re
import subprocess
ROOT = Path(__file__).resolve().parents[1]
RELEASE = re.compile(r'v?([0-9]+(?:\.[0-9]+){1,2})\Z')
VALID = re.compile(r'[0-9][A-Za-z0-9.]{0,31}\Z')
def validate(value):
if not isinstance(value, str) or not VALID.fullmatch(value):
raise ValueError(f'Invalid FDS version: {value!r}')
return value
def git(root, *args):
return subprocess.check_output(['git', '-C', str(root), *args], text=True, stderr=subprocess.DEVNULL).strip()
def version(root=ROOT):
root = Path(root).resolve()
# Source exports carry the value resolved when the export was created.
# Never accidentally describe a containing repository during offline builds.
if not (root / '.git').exists():
return validate((root / 'FDS_VERSION').read_text().strip())
revision = git(root, 'rev-parse', '--short=12', 'HEAD')
tags = [tag for tag in git(root, 'tag', '--merged', 'HEAD').splitlines() if RELEASE.fullmatch(tag)]
if tags:
description = git(root, 'describe', '--tags', '--long', '--abbrev=12', *[f'--match={tag}' for tag in tags], 'HEAD')
tag, distance, commit = description.rsplit('-', 2)
value = RELEASE.fullmatch(tag)[1]
if int(distance):
value += f'.r{distance}.{commit}'
else:
value = f'0.dev.g{revision}'
if git(root, 'status', '--porcelain', '--untracked-files=no'):
value += '.dirty'
return validate(value)
def cargo(root=ROOT):
print(f'cargo:rustc-env=FDS_BUILD_VERSION={version(root)}')
for path in [root / 'tools/fds_version.py', root / 'tools/version', root / 'tools/version-build.rs']:
print(f'cargo:rerun-if-changed={path}')
if not (root / '.git').exists():
print(f'cargo:rerun-if-changed={root / "FDS_VERSION"}')
return
# Tag creation, ref changes, staging and edits must invalidate cached binaries.
for name in ['HEAD', 'index', 'packed-refs', 'refs']:
path = git(root, 'rev-parse', '--path-format=absolute', '--git-path', name)
print(f'cargo:rerun-if-changed={path}')
head = subprocess.run(['git', '-C', str(root), 'symbolic-ref', '-q', 'HEAD'], capture_output=True, text=True)
if head.returncode == 0:
print('cargo:rerun-if-changed=' + git(root, 'rev-parse', '--path-format=absolute', '--git-path', head.stdout.strip()))
paths = git(root, 'ls-files', '--cached', '--others', '--exclude-standard').splitlines()
for name in paths:
if name != 'vendor/void-packages':
print(f'cargo:rerun-if-changed={root / name}')
+5 -3
View File
@@ -12,11 +12,12 @@ import stat
import subprocess
import sys
import tomllib
from fds_version import version, validate
project = Path(__file__).resolve().parents[1]
OWNED = ('.cargo', '.gitignore', '.gitmodules', 'AGENTS.md', 'Cargo.lock',
'Cargo.toml', 'LICENSE', 'Makefile', 'README.md', 'VOID_PACKAGES_COMMIT',
'config', 'docs', 'image', 'packages', 'profiles', 'rust-toolchain.toml',
'config', 'docs', 'examples', 'image', 'packaging', 'packages', 'profiles', 'rust-toolchain.toml',
'rust', 's6', 'tests', 'tools')
@@ -119,6 +120,7 @@ def create(destination):
new_directory(destination)
for name in OWNED:
copy(project / name, destination / 'project' / name)
(destination / 'project/FDS_VERSION').write_text(version(project) + '\n')
run('git', '-C', void, 'bundle', 'create', destination / 'void.bundle', 'HEAD')
# Bundles carry commit objects, but do not retain a shallow checkout's
# boundary file. Without it, history-aware commands follow missing parents.
@@ -205,7 +207,7 @@ def create(destination):
('tar', ['tar', '--version']), ('rustup', ['rustup', '--version'])]:
host[name] = subprocess.check_output(command, text=True, stderr=subprocess.DEVNULL).splitlines()[0]
files = inventory(destination)
lock = {'format': 1, 'version': '0.1.0', 'void_commit': pin, 'source_epoch': epoch,
lock = {'format': 1, 'version': version(project), 'void_commit': pin, 'source_epoch': epoch,
'source_sha256': source_digest(files), 'rust_toolchain': toolchain_version,
'host_prerequisites': host, 'files': files}
(destination / 'lock.json').write_text(json.dumps(lock, indent=2) + '\n')
@@ -219,7 +221,7 @@ def verify(directory):
if lockfile.is_symlink() or not lockfile.is_file() or lockfile.stat().st_size > 64 * 1024 * 1024:
raise ValueError('Missing or invalid frozen input lock')
lock = json.loads(lockfile.read_text())
if lock.get('format') != 1 or lock.get('version') != '0.1.0':
if lock.get('format') != 1 or not validate(lock.get('version')):
raise ValueError('Unsupported frozen input format')
if (set(lock) != {'format', 'version', 'void_commit', 'source_epoch', 'source_sha256',
'rust_toolchain', 'host_prerequisites', 'files'}
+12
View File
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
# Only this explicit target changes the host package database.
set -euo pipefail
[[ $# == 0 ]] || { printf 'Usage: tools/install-workstation\n' >&2; exit 2; }
cd "$(dirname -- "${BASH_SOURCE[0]}")/.."
package=$(cat out/workstation/package-path.txt)
[[ -f $package ]] || { printf 'Build fds-tools with make workstation first\n' >&2; exit 1; }
if (( EUID == 0 )); then
exec pacman -U -- "$package"
else
exec sudo pacman -U -- "$package"
fi
+2
View File
@@ -3,6 +3,8 @@ source "$(dirname -- "${BASH_SOURCE[0]}")/lib.sh"
[[ $# == 0 ]] || die 'Usage: tools/prepare-void'
"$FDS_ROOT/tools/prepare-void-workspace"
check_void_pin
"$FDS_ROOT/tools/version" >"$FDS_VOID/fds-version.next"
mv "$FDS_VOID/fds-version.next" "$FDS_VOID/fds-version"
# xbps-src reads this ignored local configuration instead of user-global settings.
if [[ -f $FDS_VOID/etc/conf ]] && ! cmp -s "$FDS_ROOT/config/xbps-src.conf" "$FDS_VOID/etc/conf"; then
die '.host/void-packages/etc/conf differs from config/xbps-src.conf; reconcile it explicitly'
+2 -1
View File
@@ -2,6 +2,7 @@
import hashlib
import json
from pathlib import Path
from fds_version import validate
def digest(path):
@@ -42,7 +43,7 @@ def artifacts(project):
def read_lock(project):
path = Path(project) / '.host/frozen/lock.json'
lock = json.loads(path.read_text())
if lock.get('format') != 1 or lock.get('version') != '0.1.0':
if lock.get('format') != 1 or not validate(lock.get('version')):
raise ValueError('Build does not identify a supported frozen input snapshot')
return lock, digest(path)
+8
View File
@@ -6,6 +6,8 @@ import pathlib
import stat
import struct
import sys
import shlex
from fds_version import validate
from rootfs_lib import package_db, rooted
@@ -29,6 +31,12 @@ def audit(root, configured=True):
assert path.is_dir() and not path.is_symlink(), f"Missing directory: {name}"
assert stat.S_IMODE(path.stat().st_mode) == int(mode, 8), f"Wrong directory mode: {name}"
assert 'ID=fds\n' in (root / "usr/lib/os-release").read_text(), "Wrong OS identity"
identity = dict(line.split('=', 1) for line in shlex.split((root / 'usr/lib/os-release').read_text(), comments=True))
version = validate(identity['VERSION_ID'])
assert identity['VERSION'] == version and identity['PRETTY_NAME'] == f'FDS/OS {version}', 'Inconsistent OS version'
assert (root / 'etc/issue').read_text() == f'FDS/OS {version}\n', 'Inconsistent login version'
for package in ('fds-base', 'fds-base-files', 'fds-init', 'fds-cli', 'fds-cartridged', 'fds-dasungd', 'fds-eink'):
assert db[package]['pkgver'] == f'{package}-{version}_1', f'OS/package version mismatch: {package}'
release = (root / "usr/share/fds/kernel-release").read_text().strip()
assert (root / "usr/lib/modules" / release / "modules.dep").is_file(), "Missing matching kernel module index"
assert (root / "etc/shadow").stat().st_mode & 0o777 == 0o600, "Shadow file is exposed"
+4 -1
View File
@@ -26,7 +26,10 @@ trap 'rm -f "$log"' EXIT
dasungd --config /etc/dasungd.toml check
fds --json info | grep -q aarch64
fds-cartridged --help | grep -q SYSFS_ROOT
fds-release --version | grep -qx "fds-release 0.1.0"
. /etc/os-release
fds-release --version | grep -Fx "fds-release $VERSION_ID"
fds --version | grep -Fx "fds $VERSION_ID"
dasungd --version | grep -Fx "dasungd $VERSION_ID"
s6-rc-db -c /etc/s6-rc/compiled list all | grep -qx cartridged
s6-rc-db -c /etc/s6-rc/compiled list all | grep -qx dasungd
s6-rc-db -c /etc/s6-rc/compiled list all | grep -qx test-echo
Executable
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env python3
"""Print the FDS version derived from release tags or a Git source export."""
import argparse
import subprocess
from pathlib import Path
from fds_version import ROOT, cargo, version
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--root', type=Path, default=ROOT)
parser.add_argument('--cargo', action='store_true', help='emit Cargo build metadata and change tracking')
args = parser.parse_args()
try:
if args.cargo:
cargo(args.root.resolve())
else:
print(version(args.root))
except (OSError, ValueError, subprocess.CalledProcessError) as error:
parser.exit(1, f'Cannot determine FDS version: {error}\n')
+20
View File
@@ -0,0 +1,20 @@
// Every workspace crate uses the same resolver, including direct Cargo builds.
use std::{env, path::PathBuf, process::Command};
fn main() {
let manifest = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let root = manifest.parent().unwrap().parent().unwrap();
let output = Command::new("python3")
.arg(root.join("tools/version"))
.arg("--cargo")
.output()
.expect("Python 3 is required to resolve the FDS build version");
assert!(
output.status.success(),
"FDS version discovery failed: {}",
String::from_utf8_lossy(&output.stderr)
);
print!(
"{}",
String::from_utf8(output.stdout).expect("Version metadata must be UTF-8")
);
}