aptbase

command module
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 20, 2026 License: MIT Imports: 1 Imported by: 0

README

aptbase

A human-friendly command-line client for the aptly REST API. aptbase drives one or more remote aptly servers over HTTP so you can manage Debian/Ubuntu package repositories from your terminal — upload and publish packages, inspect what is live, and run day-to-day operations — with colored output, aligned tables, live task progress, and a config file so you are not retyping URLs and credentials.

It is a friendly adapter, not a reimplementation: every command maps onto aptly's own API. The flagship command, aptbase deploy, takes a .deb from your disk to live-and-verified in a single step.


Installation

Requires Go 1.25+.

go install github.com/7c/aptbase@latest

This builds and installs the aptbase binary into your Go bin directory. Make sure it is on your PATH:

export PATH="$PATH:$(go env GOPATH)/bin"   # add to ~/.zshrc or ~/.bashrc

Verify:

aptbase --version

To install a specific release:

go install github.com/7c/aptbase@v1.0.0
From source
git clone https://github.com/7c/aptbase.git
cd aptbase
make build        # produces ./bin/aptbase
# or:
make install      # installs into $GOBIN via `go install` with version metadata

make build injects the version, git commit, and build date via -ldflags. go install builds without the Makefile but still reports the module version and VCS commit embedded by Go.


Quick start

# 1. Point aptbase at your aptly API and check connectivity
aptbase --api http://localhost:8080 ping

# 2. Scaffold a config file so you stop retyping flags
aptbase config new --path ~/aptbase.ini
$EDITOR ~/aptbase.ini

# 3. See what aptbase resolved (and where each value came from)
aptbase config list

# 4. Release a package end to end
aptbase deploy app-stable ./app_1.2.3_amd64.deb -d noble

Configuration

aptbase reads settings from layered sources. Later layers override earlier ones (last value wins):

built-in defaults
  → /etc/aptbase.ini
  → ~/aptbase.ini
  → APTBASE_* environment variables
  → command-line flags

When --config <path> (or APTBASE_CONFIG) names an explicit file, only that file is read instead of the two well-known locations.

Inspect the fully resolved configuration at any time, including the source of each value and its built-in default:

aptbase config list
SETTING        VALUE                          SOURCE                   DEFAULT
─────────────  ─────────────────────────────  ───────────────────────  ───────────────
api            http://localhost:8080          ~/aptbase.ini            (none)
distributions  noble jammy focal              ~/aptbase.ini            (none)
prefix         .                              default                  .
timeout        1m0s                           default                  1m0s
...
The config file

Generate an annotated starter file:

aptbase config new                                   # writes /etc/aptbase.ini (needs sudo)
aptbase config new --path ./aptbase.ini              # write anywhere
aptbase config new --path ~/aptbase.ini --force

Example config.ini:

[default]
# One or more aptly API base URLs. Commands fan out to all of them unless
# narrowed with --api or --server. Whitespace- or comma-separated.
api           = http://prod:8080 http://replica:8080

# Basic-auth username and password (both optional — see Authentication).
user          = deploy
# password    = s3cr3t        ; if set here, chmod 600 this file

# Default distributions used when -d/--distribution is omitted.
distributions = noble jammy focal

# Default local repos used when the <repo> argument is omitted.
repos         = app-stable

# Default publish prefix, TLS, timeout, output.
prefix        = .
insecure      = false
timeout       = 60s
json          = false
no-color      = false

# A named server, selected with: aptbase --server staging ...
[server:staging]
api           = http://staging:8080
distributions = noble
Multiple servers (fan-out)

List several URLs under api (or pass --api repeatedly) and commands run against all of them, with a per-server status line and an aggregate exit code:

aptbase --api http://prod:8080 --api http://replica:8080 deploy app-stable ./app.deb -d noble

Use [server:NAME] sections plus --server NAME to switch between named environments.

Environment variables

Every setting has an APTBASE_* counterpart:

Variable Setting
APTBASE_API api (space/comma list)
APTBASE_USER user
APTBASE_PASSWORD password
APTBASE_DISTRIBUTIONS distributions
APTBASE_REPOS repos
APTBASE_PREFIX prefix
APTBASE_INSECURE insecure
APTBASE_TIMEOUT timeout
APTBASE_JSON json
APTBASE_NO_COLOR no-color
APTBASE_YES yes
APTBASE_CONFIG explicit config file path
Global flags
Flag Description
--api (repeatable) aptly API base URL; fans out to all
--server named [server:NAME] config section
--user HTTP Basic auth username
--password HTTP Basic auth password (prompted on 401 if omitted)
--config explicit config file path
-d, --distributions (repeatable) target distribution
--prefix publish prefix (default .)
--json machine-readable JSON output
--no-color disable colored output
--insecure skip TLS certificate verification
--timeout per-request timeout (default 1m0s)
--yes assume yes; skip destructive-action confirmations

Authentication

HTTP Basic auth is optional and server-triggered:

  • If your aptly API needs no auth (trusted network / localhost), do nothing.
  • If it sits behind Basic auth and you have not supplied a password, aptbase prompts for it (hidden input) the first time the server returns 401.
  • To skip the prompt — for automation/CI — supply the password ahead of time via any of: password in config.ini, APTBASE_PASSWORD, or --password.
# Interactive: prompts for the password only if the server challenges
aptbase --api https://apt.example.com --user deploy ping

# Non-interactive: credentials supplied up front
aptbase --api https://apt.example.com --user deploy --password "$APT_PW" ping

If you store the password in a config file, restrict it: chmod 600. On a shared machine, prefer APTBASE_PASSWORD or the interactive prompt.


Commands

Run aptbase <command> --help for full, example-rich help on any command.

Connectivity
aptbase ping             # reach every configured server, print its aptly version
aptbase version          # local build info + remote aptly versions
aptbase --version        # just the version string
aptbase discover         # detailed overview of each server (see below)
Discover

discover probes each configured server and prints a rich overview: aptly version and auth status, a summary count of repositories, mirrors, snapshots, publications and tasks, and detailed tables for each. By default it counts packages per local repository and previews the top few from each (newest version first); --no-counts skips the package query entirely, and --top N controls how many to preview (0 disables it, a negative value shows all).

aptbase --api http://aptbase:8080 discover
aptbase --api http://aptbase:8080 discover --top 10
aptbase --api http://aptbase:8080 discover --no-counts
aptbase --api http://aptbase:8080 discover --json | jq '.[].repos'
http://aptbase:8080
aptly 1.5.0  •  auth: none

Summary
repositories  2
mirrors       0
snapshots     0
publications  6
tasks         0

Local repositories
NAME    DIST   COMPONENT  PACKAGES  COMMENT
──────  ─────  ─────────  ────────  ───────
app     noble  main       8

Packages (top 5 per repo)
app
NAME   VERSION   ARCH
─────  ────────  ─────
nginx  1.20.1-1  amd64
...
Config
aptbase config new [--path FILE] [--force]   # scaffold an annotated config.ini
aptbase config print                         # resolved config as config.ini to stdout (pipeable)
aptbase config list [--json]                 # resolved settings, sources, defaults

# Capture an ad-hoc invocation as a system config file:
aptbase --api http://aptbase:8080 -d noble config print | sudo tee /etc/aptbase.ini
Repositories
aptbase repo list                            # all local repos (per server)
aptbase repo show app-stable                 # repo details
aptbase repo create app-stable --distribution noble --component main
aptbase repo edit app-stable --comment "stable channel"
aptbase repo drop app-edge [--force] [--yes] # delete (asks to confirm unless --yes)
aptbase repo packages app-stable -q 'nginx (>= 1.20)'
Add packages

Upload one or more .deb files and add them to a repo. Runs as an async aptly task whose progress is streamed live; the temporary upload directory is cleaned up afterward.

aptbase repo add app-stable ./app_1.2.3_amd64.deb
aptbase repo add ./a_1_amd64.deb ./b_1_amd64.deb     # repo(s) from config defaults
Deploy (flagship)

deploy is the one-command release workflow. For each target server it:

  1. uploads the .deb file(s),
  2. adds them to the target repo(s),
  3. refreshes every publication that sources the repo so the package goes live — the publication prefix and distribution are discovered from the server (no need to know the prefix), and
  4. verifies the package is present in the repo.

Repos come from the positional argument, --repo (repeatable), or the configured repos. By default every distribution the repo is published to is refreshed; narrow that with -d/--distribution. It fans out across every configured server.

# Repo published under a non-root prefix — prefix is auto-detected
aptbase deploy ./app_1.2.3_amd64.deb --repo 99835

# Single repo, narrow to two distributions
aptbase deploy app-stable ./app_1.2.3_amd64.deb -d noble -d jammy

# Use config defaults for repo / distributions / servers
aptbase deploy ./app_1.2.3_amd64.deb

# Signed publish
aptbase deploy app-stable ./app.deb -d noble --gpg-key DEADBEEF --batch

# Unsigned (lab) publish, no confirmation prompts
aptbase deploy app-stable ./app.deb -d noble --skip-signing --yes

Deploy and publish accept signing flags: --gpg-key, --keyring, --passphrase, --batch, --skip-signing, and --force-overwrite. Deploy also takes --no-verify to skip the post-publish check.

Publish
aptbase publish list                         # all publications (per server)
aptbase publish update noble                 # re-publish a distribution
aptbase publish update                       # re-publish configured distributions
aptbase publish update noble jammy --gpg-key DEADBEEF --batch
Packages
aptbase package list                         # all packages, NAME/VERSION/ARCH table
aptbase package list --latest                # newest version of each package only
aptbase package list --details --repo app    # full records: version, arch, size, maintainer
aptbase package list --arch amd64 --limit 20 # filter by arch, cap output
aptbase package list --keys                  # raw aptly package keys
aptbase package search 'nginx (>= 1.20)'     # same options, query required
aptbase package show 'Pamd64 nginx 1.20.1-1 abc123'

Both list and search query each target repo (--repo, else the configured repos); aptly has no global package index. list lists everything (an optional query narrows it); search requires a query. Queries use aptly's query syntax (names match exactly; use % for wildcards, e.g. Name (% nginx*)).

Shared options:

Flag Effect
--repo (repeatable) repos to query (default: configured repos)
--latest only the newest version of each package (client-side)
--details full records as a wider table (version, arch, size, maintainer)
--arch (repeatable) filter by architecture
--limit N cap results per repo
--sort name|version sort order (default name)
--keys print raw aptly keys instead of the parsed table

Output defaults to a parsed NAME / VERSION / ARCH table grouped by repo; --json emits structured results. --latest and version sorting use Debian version comparison, so 0.0.9 precedes 0.0.10.

Tasks

aptbase uses aptly's asynchronous task API for long operations and streams output live. You can also inspect tasks directly:

aptbase task list                            # tasks on a server
aptbase task show 7                          # a task's state
aptbase task wait 7                          # block until done, streaming output
aptbase task output 7                        # print accumulated output

Task IDs are server-local; with multiple servers configured, task subcommands act on the first one (narrow with --api/--server).


Output

  • Human-readable colored tables by default.
  • --json on any command emits machine-readable JSON for scripting.
  • Color auto-disables when output is piped or NO_COLOR is set; force it off with --no-color.
aptbase --json publish list | jq '.[].Distribution'

Debugging & bug reports

--debug is available on every command and prints debug-level diagnostics to stderr (so it never pollutes --json on stdout): config resolution (files read, resolved values + sources), every HTTP request/response with status and timing, request/error bodies, and async task polling.

aptbase --debug discover                       # trace to the terminal
aptbase --debug deploy ./app.deb --repo myrepo 2> debug.log   # capture for a report
APTBASE_DEBUG=1 aptbase ping                    # or via env / 'debug = true' in config

Secrets are redacted: the Basic-auth password is never printed (only auth=y user=…), --password is masked in the startup args line, and password / Passphrase / GpgKeyArmor are masked in any logged request body. When filing a bug, re-run with --debug and attach the stderr output.


Exit codes

aptbase exits non-zero when an operation fails. With multiple servers, it attempts all of them and exits non-zero if any failed, after printing a per-server result.


Development

make build      # compile to ./bin/aptbase (with version metadata)
make test       # run unit tests
make vet        # go vet
make fmt        # gofmt
make version    # print the current version
make bump       # bump version.txt (PART=patch|minor|major, default patch)
make help       # list all targets
Versioning & releasing

version.txt at the repo root is the single source of truth for the build version (a semver string). make build reads it and injects the version, git commit, and build date into the binary via -ldflags, so aptbase version is self-describing on any host. A plain go build (without the Makefile) shows the placeholder dev, which is a useful signal that the binary was not built through the release path.

Release flow:

make bump PART=minor          # e.g. 0.1.0 -> 0.2.0 (or PART=patch|major)
git commit -am "release v$(cat version.txt)"
git tag "v$(cat version.txt)" && git push --tags

Tagging the commit to match version.txt keeps go install github.com/7c/aptbase@latest reporting the same version: a go install build cannot read version.txt, so it falls back to the version and commit Go embeds from the module's VCS tag.

The codebase is organized by concern:

version.txt         single source of truth for the build version (semver)
cmd/                cobra commands (thin, human-facing)
internal/config/    layered config resolver
internal/client/    typed aptly API client (+ async tasks, 401 auth)
internal/target/    multi-server fan-out
internal/ui/        colored output and tables
internal/render/    human vs JSON rendering
tools/              dev tools (e.g. increaseversion.go); not part of the binary

License

MIT © 7c

Documentation

Overview

Command aptbase is an internal CLI for apt repository operations.

Directories

Path Synopsis
Package cmd holds the cobra command tree for aptbase.
Package cmd holds the cobra command tree for aptbase.
internal
client
Package client is a typed Go client for the aptly REST API.
Package client is a typed Go client for the aptly REST API.
config
Package config resolves aptbase settings from layered sources.
Package config resolves aptbase settings from layered sources.
debug
Package debug provides a process-global, stderr-based debug logger.
Package debug provides a process-global, stderr-based debug logger.
render
Package render switches command output between human-readable and JSON.
Package render switches command output between human-readable and JSON.
target
Package target resolves the set of aptly servers (and default repos / distributions) an invocation acts on, and runs work across servers with an aggregated result.
Package target resolves the set of aptly servers (and default repos / distributions) an invocation acts on, and runs work across servers with an aggregated result.
ui
Package ui provides small helpers for colorful, consistent terminal output.
Package ui provides small helpers for colorful, consistent terminal output.
Command increaseversion bumps the semantic version in version.txt — the single source of truth for aptbase's build version (see docs/version.md).
Command increaseversion bumps the semantic version in version.txt — the single source of truth for aptbase's build version (see docs/version.md).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL