APT Provider

This document describes the implementation details of the APT package provider for Debian-based systems.

Environment

All commands are executed with the following environment variables to ensure non-interactive operation:

VariableValuePurpose
DEBIAN_FRONTENDnoninteractivePrevents dpkg from prompting for user input
APT_LISTBUGS_FRONTENDnoneSuppresses apt-listbugs prompts
APT_LISTCHANGES_FRONTENDnoneSuppresses apt-listchanges prompts

Concurrency

A global package lock (model.PackageGlobalLock) is held during all command executions to prevent concurrent apt/dpkg operations within the same process. This prevents lock contention on /var/lib/dpkg/lock.

Operations

Status Check

Command:

dpkg-query -W -f='${Package} ${Version} ${Architecture} ${db:Status-Status}' <package>

Behavior:

  • Exit code 0 with installed status → Package is present, returns version info
  • Exit code non-zero OR status not installed → Package is absent

Package States: The db:Status-Status field can return various values. Only installed is treated as present:

StatusTreated AsDescription
installedPresentPackage fully installed
config-filesAbsentRemoved but config files remain
half-installedAbsentInstallation started but failed
half-configuredAbsentConfiguration failed
unpackedAbsentUnpacked but not configured
not-installedAbsentNot installed

Treating non-installed states as absent allows apt-get install to repair broken installations.

Install

Ensure Present:

apt-get install -y -q -o DPkg::Options::=--force-confold <package>

Ensure Latest:

apt-cache policy <package>                    # Get candidate version
apt-get install -y -q -o DPkg::Options::=--force-confold <package>=<version>

Specific Version:

apt-get install -y -q -o DPkg::Options::=--force-confold --allow-downgrades <package>=<version>

Flags:

FlagPurpose
-yAssume yes to prompts
-qQuiet output
-o DPkg::Options::=--force-confoldKeep existing config files on upgrade
--allow-downgradesAllow installing older versions (specific version only)

Upgrade

Delegates to Install() with the target version. The --allow-downgrades flag is only added for specific version requests, not for latest.

Downgrade

Delegates to Install() with the target version. The --allow-downgrades flag enables this operation.

Uninstall

Command:

apt-get -q -y remove <package>

Note: Uses remove not purge, so configuration files are preserved. A subsequent install will find existing config files.

Latest Available Version

Command:

apt-cache policy <package>

Parsing: Extracts the Candidate: line from output.

Example output:

zsh:
  Installed: 5.9-8+b18
  Candidate: 5.9-8+b18
  Version table:
 *** 5.9-8+b18 500
        500 http://deb.debian.org/debian trixie/main amd64 Packages
        100 /var/lib/dpkg/status

Version Comparison

Version comparison follows the Debian Policy Manual algorithm.

Version Format

[epoch:]upstream_version[-debian_revision]
ComponentRequiredDescription
epochNoInteger, default 0. Higher epoch always wins.
upstream_versionYesThe main version from upstream
debian_revisionNoDebian-specific revision

Examples:

  • 1.0 → epoch=0, upstream=1.0, revision=""
  • 1:2.0-3 → epoch=1, upstream=2.0, revision=3
  • 2:1.0.0+git-20190109-0ubuntu2 → epoch=2, upstream=1.0.0+git-20190109, revision=0ubuntu2

Comparison Algorithm

  1. Compare epochs numerically - Higher epoch wins regardless of other components

  2. Compare upstream_version and debian_revision using the Debian string comparison:

    The string is processed left-to-right in segments:

    a. Tildes (~) - Compared first. More tildes = earlier version. Tilde sorts before everything, even empty string.

    • 1.0~alpha < 1.0 (tilde before empty)
    • 1.0~~ < 1.0~ (more tildes = earlier)

    b. Letters (A-Za-z) - Compared lexically (ASCII order)

    • Letters sort before non-letters

    c. Non-letters (., +, -) - Compared lexically

    d. Digits - Compared numerically (not lexically)

    • 9 < 13 (numeric comparison)

    These steps repeat until a difference is found or both strings are exhausted.

Comparison Examples

ABResultReason
1.02.0A < BNumeric comparison
1:1.02.0A > BEpoch 1 > epoch 0
1.0~alpha1.0A < BTilde sorts before empty
1.0~alpha1.0~betaA < BLexical: alpha < beta
1.0.11.0.2A < BNumeric: 1 < 2
1.0-11.0-2A < BRevision comparison
1.0a1.0-A < BLetters sort before non-letters

Implementation

The version comparison is implemented in version.go, ported from Puppet’s Puppet::Util::Package::Version::Debian module. It provides:

  • ParseVersion(string) - Parse a version string into components
  • CompareVersionStrings(a, b) - Compare two version strings directly
  • Version.Compare(other) - Compare parsed versions (-1, 0, 1)
  • Helper methods: LessThan, GreaterThan, Equal, etc.