Creating a Custom Repository
Creating a Custom Repository
In this chapter, we create a functional, standalone repository for our custom distribution. We will construct a packaging tool called byol-pkg that packages directories into compressed archives, generates indexed repository metadata, and serves them over HTTP.
+-----------------------------------------------------------+
| The byol-pkg Repository Structure |
| |
| /srv/repo/ |
| ├── x86_64/ |
| │ ├── index.json # Main repository catalog |
| │ ├── index.json.minisig # Cryptographic signature |
| │ ├── bash-5.2.21-1.tar.zst |
| │ └── coreutils-9.4-1.tar.zst |
| └── repo.conf # Client repository pointer |
+-----------------------------------------------------------+
Step 1: Defining the Package Manifest
Every package built in our distribution will include a PACKAGE.toml manifest:
# PACKAGE.toml
[package]
name = "bash"
version = "5.2.21"
release = 1
architecture = "x86_64"
summary = "The GNU Bourne Again SHell"
license = "GPL-3.0-or-later"
[dependencies]
runtime = ["glibc>=2.38", "ncurses>=6.4"]
[files]
prefix = "/usr"Step 2: Packaging Script (byol-pack)
Here is a clean POSIX shell script that packages a target directory tree into a signed BYOL archive:
#!/bin/sh
# byol-pack: Assembles a package payload into a compressed archive
set -eu
PKG_DIR="$1" # Directory containing staged binary files
MANIFEST="$2" # Path to PACKAGE.toml
OUTPUT_DIR="$3" # Destination directory
PKG_NAME=$(grep '^name =' "$MANIFEST" | cut -d '"' -f 2)
PKG_VER=$(grep '^version =' "$MANIFEST" | cut -d '"' -f 2)
PKG_REL=$(grep '^release =' "$MANIFEST" | awk '{print $3}')
PKG_ARCH=$(grep '^architecture =' "$MANIFEST" | cut -d '"' -f 2)
ARCHIVE_NAME="${PKG_NAME}-${PKG_VER}-${PKG_REL}-${PKG_ARCH}.byol.tar.zst"
echo "[byol-pack] Creating package: $ARCHIVE_NAME"
cp "$MANIFEST" "$PKG_DIR/.PACKAGE"
# Create reproducible tar archive compressed with zstd
tar --sort=name --owner=root:0 --group=root:0 \
-C "$PKG_DIR" -cf - . | zstd -19 -o "$OUTPUT_DIR/$ARCHIVE_NAME"
echo "[byol-pack] Package generated at $OUTPUT_DIR/$ARCHIVE_NAME"Step 3: Indexing the Repository (byol-index)
A repository indexing script parses all .byol.tar.zst packages in the directory, extracts their .PACKAGE manifest, computes SHA256 checksums, and outputs index.json:
#!/bin/sh
# byol-index: Generates repository metadata catalog
set -eu
REPO_DIR="$1"
cd "$REPO_DIR"
echo "{\"packages\": {" > index.json.tmp
FIRST=1
for pkg in *.byol.tar.zst; do
[ -f "$pkg" ] || continue
[ "$FIRST" -eq 0 ] && echo "," >> index.json.tmp
FIRST=0
# Extract manifest without decompressing entire package
MANIFEST=$(tar --zstd -xf "$pkg" .PACKAGE -O)
NAME=$(echo "$MANIFEST" | grep '^name =' | cut -d '"' -f 2)
VER=$(echo "$MANIFEST" | grep '^version =' | cut -d '"' -f 2)
SHA256=$(sha256sum "$pkg" | awk '{print $1}')
SIZE=$(stat -c%s "$pkg")
cat <<JSON >> index.json.tmp
"$NAME": {
"name": "$NAME",
"version": "$VER",
"filename": "$pkg",
"sha256": "$SHA256",
"size": $SIZE
}
JSON
rm -f .PACKAGE
done
echo "}}" >> index.json.tmp
mv index.json.tmp index.json
echo "[byol-index] Repository metadata catalog generated at $REPO_DIR/index.json"Step 4: Serving Over HTTP
To test your custom repository locally:
$ python3 -m http.server 8080 --directory /srv/repo/x86_64Your package manager can now fetch and verify packages via http://localhost:8080/index.json.