- Go 100%
Run each registry's signcmd on its downloaded packages between download
and publish. The command template replaces the {file} placeholder with
the package file path.
created with help from number affine coworker
|
||
|---|---|---|
| cmd | ||
| deb | ||
| doc | ||
| github | ||
| rpm | ||
| utils | ||
| .gitignore | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| README.md | ||
paketier
⚠️ alpha software, still under development
paketier is a command-line tool written in Go. It matches software packages from a GitHub-compatible release page against Debian and RPM package registries, downloads the packages that are missing, and publishes them to the registries.
How it works
Automatic: ci
ci runs the whole pipeline in one step. It reads a YAML config file
(paketier.yaml by default) that lists the source and the registries. The
command fetches the source and registry indices, compares them, downloads the
missing packages, and publishes them to the registries. See
doc/*.example.yaml for an example config.
Manual pipeline
The tool also works in four steps. Each step reads the result of the previous step. All steps use the same config file and storage dir.
dumpreads the config file and downloads the source and registry indices.scancompares the indices. It writes the missing packages toscan.json.downloaddownloads the missing packages to<storage dir>/packages.signsigns the downloaded packages.publishuploads the downloaded packages to the package registry.
Requirements
- Go 1.24.4 or later.
- A Forgejo access token to publish packages. The token goes into the
credentials file that the config file references (see
doc/*.example.yaml).
Build
Run these commands in the project root directory.
go build ./...
go vet ./...
The binary is built from cmd/paketier:
go build -o paketier ./cmd/paketier
Workflow
Automatic: ci
Run the whole pipeline with a single command:
paketier ci
ci reads the paketier.yaml config file in the current directory. Use the
--config flag to pass another config file.
Flags for ci
| Flag | Default | Purpose |
|---|---|---|
--config |
paketier.yaml |
config file |
--storage |
(see below) | storage dir |
--continue |
false |
log HTTP 404 errors and continue |
--no-test |
false |
skip the registry index, upload all matching packages |
--save |
false |
store the fetched registry indices to disk |
--dry-run |
false |
compare only, do not download or publish |
Without --storage, the storage dir is the directory of the config file plus
the config file name without its extension. For the default paketier.yaml
the storage dir is paketier/. Downloaded packages go to
<storage dir>/packages.
With --save, ci writes the fetched indices to the storage dir as
source_<type>.json and registry_<name>.json.
Manual pipeline
Run the commands in this order.
- Run
paketier dump. - Run
paketier scan. - Run
paketier download. - Run
paketier sign. - Run
paketier publish.
Each command reads the config file (--config) and the storage dir
(--storage). Without --storage, the storage dir is the directory of the
config file plus the config file name without its extension.
sign runs the signcmd of each registry for its downloaded packages (see
Signing).
publish authenticates against each registry with the credentials file that
the config lists for that registry (see doc/*.example.yaml).
Commands
| Command | Alias | Purpose |
|---|---|---|
dump |
d |
download the source and registry indices |
scan |
s |
find the missing packages |
download |
l |
download the missing packages to <storage>/packages |
sign |
sign the downloaded packages | |
publish |
p |
upload the downloaded packages to the registry |
Every command that reads a value has a flag with a built-in default. You can override each default on the command line.
Helper commands
The CLI also provides helper commands:
| Command | Purpose |
|---|---|
config |
print and validate the config file (--raw prints as-is) |
manpage |
print the CLI help as a manpage |
markdown |
print the CLI help as markdown |
ghindex |
download the raw GitHub releases index |
debindex |
download the raw Debian index |
rpmindex |
download the raw RPM index |
The *index commands are experimental. ghindex downloads the release list
of an owner/project and writes the parsed JSON. --raw skips parsing, --latest
fetches only the latest release, --output writes to a file instead of stdout.
debindex downloads the package index of a Debian repository. It takes
baseurl, distribution and component. --arch selects the architecture,
--release fetches only the Release file. rpmindex downloads the primary
index of a yum repository. It takes the repository root as repository url;
--arch filters the parsed packages, --repomd fetches only repomd.xml.
Flags for dump
| Flag | Default | Purpose |
|---|---|---|
--config |
paketier.yaml |
config file |
--storage |
(see below) | storage dir |
The tool builds the source and registry URLs from the config file.
dump writes the fetched indices to the storage dir as source_<type>.json
and registry_<name>.json. Without --storage, the storage dir is the
directory of the config file plus the config file name without its extension,
the same default that ci --save uses.
Flags for scan
| Flag | Default | Purpose |
|---|---|---|
--config |
paketier.yaml |
config file |
--storage |
(see below) | storage dir |
--name |
(empty) | package name to compare |
--version |
(empty) | version range |
--platform |
(empty) | comma-separated architectures |
scan reads the source index and the registry indices from the storage dir
(source_<type>.json and registry_<name>.json, one per registry in the
config file). It writes the missing packages to <storage dir>/scan.json.
An empty --name matches every package. An empty --version matches every
version. An empty --platform uses the architectures that the registry already
carries.
Debian and RPM use different names for the same machine. Debian uses amd64.
RPM uses x86_64. Put both names into --platform to track both.
Examples:
paketier scan
paketier scan --name woodpecker-agent
paketier scan --name woodpecker-agent --version ">=3.17,<4.0"
paketier scan --platform amd64,x86_64
Version ranges
The --version flag accepts a semver-style range. An empty string matches
every version.
| Value | Matches |
|---|---|
3.17.0 |
exactly 3.17.0 |
=3.17.0 |
exactly 3.17.0 |
>3.17.0 |
higher than 3.17.0 |
>=3.17 |
3.17.0 or higher |
<4.0 |
lower than 4.0.0 |
<=3.17.0 |
3.17.0 or lower |
>=3.17,<4.0 |
from 3.17.0 to lower than 4.0.0 |
Comma-separated comparators form one range. They must all match.
Flags for sign
| Flag | Default | Purpose |
|---|---|---|
--config |
paketier.yaml |
config file |
--storage |
(see below) | storage dir |
sign reads <storage dir>/scan.json and runs the signcmd of each registry
for its packages (see Signing). It needs the downloaded packages
in <storage dir>/packages.
Flags for publish
| Flag | Default | Purpose |
|---|---|---|
--config |
paketier.yaml |
config file |
--storage |
(see below) | storage dir |
publish reads <storage dir>/scan.json, downloads nothing, and uploads each
listed package to the registry that the config file names for it. The token is
required. It comes from the credentials file that the config lists for the
registry.
Signing
Each registry can have a signcmd in the config file. When set, sign (and
the ci pipeline) runs this command for every downloaded package of that
registry, replacing the placeholder {file} with the package file path. The
command is run through /bin/sh. Registries without a signcmd are skipped.
Example:
registries:
qubes-dom0-rpm:
type: rpm
name: woodpecker-cli-*.x86_64.rpm
url: https://codeberg.org/api/packages/saces/rpm/qubpecker
credentials: secrets.yaml
signcmd: gpg --detach-sign --armor {file}
Publishing
The tool sends each package with an HTTP PUT request to the Forgejo API. It builds the upload URL from the registry URL in the config file.
- Debian packages go to
{registry url}/pool/{distribution}/{component}/upload. - RPM packages go to
{registry url}/upload.
The token belongs to the user that owns the registry packages. The tool sends the token as HTTP basic authentication.
Notes
- The tool skips draft and pre-release GitHub releases.
- Without
--platform, scan uses the architectures that the registry already carries. - The index files in the storage dir have fixed names:
source_<type>.json,registry_<name>.json,scan.json. - The tool stops with an error when the registry already has the package version.
downloadruns serially. For many packages, the tool can take a long time.downloadskips existing non-empty files, so an interrupted run can be resumed.