meta_package_manager.managers.pkg module¶

FreeBSD package managers.

Two managers share this module because they share the FreeBSD ecosystem and the same on-disk install database:

  • PKG wraps the binary pkg frontend, which fetches pre-compiled artifacts from the official FreeBSD repository.

  • Ports wraps the source-build workflow rooted at /usr/ports, driving make recipes directly and delegating registry queries back to pkg.

References:

meta_package_manager.managers.pkg.PORTS_TREE = PosixPath('/usr/ports')¶

Canonical location of the FreeBSD ports tree.

The Handbook documents this path as the convention; PORTSDIR can override it, but every tool and consumer in the wild assumes this default.

class meta_package_manager.managers.pkg.PKG[source]¶

Bases: PackageManager

FreeBSD’s binary pkg frontend, fetching pre-compiled artifacts from the official FreeBSD repository.

Only root may modify the package database, so mutating operations escalate through sudo by default, like the Ports sibling.

Note

outdated parses pkg upgrade --dry-run rather than pkg version, because only the dry-run names the target version each package would move to.

Caution

sync forces IGNORE_OSVERSION=yes: a package built for a newer FreeBSD than the running kernel would otherwise trigger an interactive confirmation that hangs the subprocess. It is passed as a -o command-line option rather than an environment variable, which sudo’s environment reset would strip from the escalated call. Support for that setting is also why the version floor is 1.11.

Initialize cli_errors list.

name: str = 'FreeBSD pkg'¶

Return package manager’s common name.

Default value is based on class name.

homepage_url: str | None = 'https://github.com/freebsd/pkg'¶

Home page of the project, only used in documentation for reference.

Slug of the brand mark standing for this manager in the documentation.

Names an SVG vendored under docs/assets/managers/, whose provenance and license are recorded in docs/assets/managers/logos.yaml. Inlined at the top of the manager’s page by meta_package_manager._docs; a manager leaving it unset keeps the page’s default package glyph.

Several managers legitimately share one slug, either because they wrap the same upstream (brew and cask) or because the tool has no mark of its own and its ecosystem’s stands in (apt under Debian’s swirl, cargo under Rust’s gear). Documentation-only, like homepage_url: no CLI output reads it.

platforms: frozenset[Platform] | Group | Platform | Iterable[Platform | Group] = frozenset({Platform(id='freebsd', name='FreeBSD')})¶

List of platforms supported by the manager.

Allows for a mishmash of platforms and groups of platforms. Will be normalized into a frozenset of Platform instances at instantiation.

default_sudo: bool = True¶

Built-in escalation default, used when sudo is None.

False on the base: most managers install into user-writable trees and never need root. The system package managers whose privileged operations require root (apt, dnf, pacman, zypper, …) set this to True so their build_cli(..., sudo=True) operations escalate out of the box, while staying switchable off through sudo (--no-sudo or config) for rootless setups.

requirement: str | None = '>=1.11'¶

1.11 is the first version to support the IGNORE_OSVERSION setting.

$ pkg --version
1.20.9
pre_args: tuple[str, ...] = ('--quiet',)¶
property installed: Iterator[Package]¶

Fetch installed packages.

$ pkg query "%n %v %c"
7-zip 21.07_2 Console version of the 7-Zip file archiver
ap24-mod_mpm_itk 2.4.7_2 Run each vhost under a separate uid and gid
apache24 2.4.57 Version 2.4.x of Apache web server
aquantia-atlantic-kmod 0.0.5_1 Aquantia AQtion (Atlantic) Network Driver
arcconf 3.07.23971,1 Adaptec SCSI/SAS RAID administration tool
areca-cli-amd64 1.14.7.150519,1 Command Line Interface for ARC-xxxx RAID
base64 1.5_1 Utility to encode and decode base64 files
bash 5.1.12 GNU Project's Bourne Again SHell
beadm 1.4_1 Solaris-like utility to manage Boot Environments on ZFS
property outdated: Iterator[Package]¶

Fetch outdated packages.

$ pkg upgrade --dry-run
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
Checking for upgrades (312 candidates): 100%
Processing candidates (312 candidates): 100%
The following 466 package(s) will be affected (of 0 checked):

Installed packages to be REMOVED:
    freenas-files: 13.0_1700495253
    py39-midcli: 20190509171453
    py39-middlewared: 13.0_1700495253

New packages to be INSTALLED:
    abseil: 20230125.3 [FreeBSD]
    argp-standalone: 1.5.0 [FreeBSD]
    brotli: 1.1.0,1 [FreeBSD]

Installed packages to be UPGRADED:
    7-zip: 21.07_2 -> 23.01 [FreeBSD]
    apache24: 2.4.57 -> 2.4.58_1 [FreeBSD]
    apr: 1.7.0.1.6.1_1 -> 1.7.3.1.6.3_1 [FreeBSD]
    aquantia-atlantic-kmod: 0.0.5_1 -> 0.0.5_2 [FreeBSD]
    bash: 5.1.12 -> 5.2.21 [FreeBSD]

Note

We rely on pkg upgrade instead of pkg version because the latter does not provides the new version:

$ pkg version --like "<"
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
7-zip-21.07_2                      <
apache24-2.4.57                    <
apr-1.7.0.1.6.1_1                  <
aquantia-atlantic-kmod-0.0.5_1     <
bash-5.1.12                        <
property orphans: Iterator[Package]¶

Fetch packages installed as dependencies that nothing requires anymore.

--dry-run turns autoremove into a read-only report of the would-be-removed packages.

$ pkg --quiet autoremove --dry-run
Checking integrity... done (0 conflicting)
Deinstallation has been requested for the following 2 packages:

Installed packages to be REMOVED:
    libiconv: 1.17
    pcre: 8.45_3

Number of packages to be removed: 2
search(query, extended, exact)[source]¶

Fetch matching packages.

Default search on ID substring:

$ pkg search --raw --raw-format json-compact --search name nginx
{
    "name": "nginx",
    "version": "1.24.0_14,3",
    "comment": "Robust and small WWW server",
    (...)
}
{
    "name": "nginx-devel",
    "version": "1.25.3_9",
    "comment": "Robust and small WWW server",
    (...)
}
{
    "name": "nginx-ultimate-bad-bot-blocker",
    "version": "4.2020.03.2005_1",
    "comment": "Nginx bad bot and other things blocker",
    (...)
}
{
    "name": "p5-Nginx-ReadBody",
    "version": "0.07_1",
    "comment": "Nginx embedded perl module to read a request",
    (...)
}
(...)

Exact search on ID:

$ pkg search --raw --raw-format json-compact --search name --exact nginx
{
    "name": "nginx",
    "origin": "www/nginx",
    "version": "1.24.0_14,3",
    "comment": "Robust and small WWW server",
    "maintainer": "[email protected]",
    "www": "https://nginx.com/",
    "abi": "FreeBSD:13:amd64",
    "arch": "freebsd:13:x86:64",
    "prefix": "/usr/local",
    "sum": "c39a7696e6eda7bfedba251e4480e50d4c65c520d5a783a584b19b3ef883",
    "flatsize": 1464332,
    "path": "All/nginx-1.24.0_14,3.pkg",
    "repopath": "All/nginx-1.24.0_14,3.pkg",
    "licenselogic": "single",
    "licenses": [
        "BSD2CLAUSE"
    ],
    "pkgsize": 473632,
    "desc": "NGINX is a high performance edge web server with the (...)",
    "deps": {
        "pcre2": {
            "origin": "devel/pcre2",
            "version": "10.42"
        }
    },
    "categories": [
        "www"
    ],
    "shlibs_required": [
        "libpcre2-8.so.0"
    ],
    "options": {
        "AJP": "off",
        "ARRAYVAR": "off",
        "AWS_AUTH": "off",
        "BROTLI": "off",
        "CACHE_PURGE": "off",
        "CLOJURE": "off",
        "COOKIE_FLAG": "off",
        "CT": "off",
        "DEBUG": "off",
        "DEBUGLOG": "off",
        "DEVEL_KIT": "off",
        "DRIZZLE": "off",
        "DSO": "on",
        "DYNAMIC_UPSTREAM": "off",
        "ECHO": "off",
        "ENCRYPTSESSION": "off",
        "FILE_AIO": "on",
        "FIPS_CHECK": "off",
        "FORMINPUT": "off",
        "GOOGLE_PERFTOOLS": "off",
        "GRIDFS": "off",
        "GSSAPI_HEIMDAL": "off",
        "GSSAPI_MIT": "off",
        "HEADERS_MORE": "off",
        "HTTP": "on",
        "HTTPV2": "on",
        "HTTPV3": "off",
        "HTTPV3_BORING": "off",
        "HTTPV3_LSSL": "off",
        "HTTPV3_QTLS": "off",
        "HTTP_ACCEPT_LANGUAGE": "off",
        "HTTP_ADDITION": "on",
        "HTTP_AUTH_DIGEST": "off",
        "HTTP_AUTH_KRB5": "off",
        "HTTP_AUTH_LDAP": "off",
        "HTTP_AUTH_PAM": "off",
        "HTTP_AUTH_REQ": "on",
        "HTTP_CACHE": "on",
        "HTTP_DAV": "on",
        "HTTP_DAV_EXT": "off",
        "HTTP_DEGRADATION": "off",
        "HTTP_EVAL": "off",
        "HTTP_FANCYINDEX": "off",
        "HTTP_SUBS_FILTER": "off",
        "HTTP_TARANTOOL": "off",
        "HTTP_UPLOAD": "off",
        "HTTP_UPLOAD_PROGRESS": "off",
        "HTTP_UPSTREAM_CHECK": "off",
        "HTTP_UPSTREAM_FAIR": "off",
        "HTTP_UPSTREAM_STICKY": "off",
        "HTTP_VIDEO_THUMBEXTRACTOR": "off",
        "HTTP_XSLT": "off",
        "HTTP_ZIP": "off",
        "ICONV": "off",
        "IPV6": "on",
        "LET": "off",
        "LINK": "off",
        "LUA": "off",
        "MAIL": "on",
        "MAIL_IMAP": "off",
        "MAIL_POP3": "off",
        "MAIL_SMTP": "off",
        "MAIL_SSL": "on",
        "MEMC": "off",
        "MODSECURITY3": "off",
        "NAXSI": "off",
        "NJS": "off",
        "NJS_XML": "off",
        "OPENTRACING": "off",
        "PASSENGER": "off",
        "POSTGRES": "off",
        "RDS_CSV": "off",
        "RDS_JSON": "off",
        "REDIS2": "off",
        "RTMP": "off",
        "SET_MISC": "off",
        "SFLOW": "off",
        "SHIBBOLETH": "off",
        "SLOWFS_CACHE": "off",
        "SRCACHE": "off",
        "STREAM": "on",
        "STREAM_REALIP": "on",
        "STREAM_SSL": "on",
        "STREAM_SSL_PREREAD": "on",
        "STS": "off",
        "THREADS": "on",
        "VOD": "off",
        "VTS": "off",
        "WEBSOCKIFY": "off",
        "WWW": "on",
        "XSS": "off"
    },
    "annotations": {
        "FreeBSD_version": "1302001",
        "build_timestamp": "2024-01-07T10:41:34+0000",
        "built_by": "poudriere-git-3.4.0",
        "cpe": "cpe:2.3:a:f5:nginx:1.24.0:::::freebsd13:x64:14",
        "port_checkout_unclean": "no",
        "port_git_hash": "756e18783",
        "ports_top_checkout_unclean": "no",
        "ports_top_git_hash": "756e18783"
    }
}

Extended search:

$ pkg search --raw --raw-format json-compact           --search name --search comment --search description nginx
Return type:

Iterator[Package]

install(package_id, version=None)[source]¶

Install one package.

$ sudo pkg --quiet install --yes dmg2img
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
Checking integrity... done (0 conflicting)
The following 1 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
    dmg2img: 1.6.7 [FreeBSD]

Number of packages to be installed: 1
[1/1] Installing dmg2img-1.6.7...
[1/1] Extracting dmg2img-1.6.7: 100%
Return type:

str

upgrade_all_cli()[source]¶

Generates the CLI to upgrade all outdated packages.

$ sudo pkg --quiet upgrade --yes
Return type:

tuple[str, ...]

upgrade_one_cli(package_id, version=None)[source]¶

Generates the CLI to upgrade the provided package.

$ sudo pkg --quiet upgrade --yes dmg2img
Return type:

tuple[str, ...]

remove(package_id)[source]¶

Remove one package.

$ sudo pkg --quiet delete --yes dmg2img
Checking integrity... done (0 conflicting)
Deinstallation has been requested for the following 1 packages:

Installed packages to be REMOVED:
    dmg2img: 1.6.7

Number of packages to be removed: 1
[1/1] Deinstalling dmg2img-1.6.7...
[1/1] Deleting files for dmg2img-1.6.7: 100%
pkg: Package database is busy while closing!
Return type:

str

sync()[source]¶

Sync package metadata.

$ sudo pkg --quiet -o IGNORE_OSVERSION=yes update
Updating FreeBSD repository catalogue...
Fetching meta.conf: 100%    163 B   0.2kB/s    00:01
Fetching packagesite.pkg: 100%    7 MiB   3.6MB/s    00:02
Processing entries: 100%
FreeBSD repository update completed. 33804 packages processed.
All repositories are up to date.

The IGNORE_OSVERSION=yes prevents blocking update:

$ pkg --quiet update
Updating FreeBSD repository catalogue...
Fetching meta.conf: 100%    163 B   0.2kB/s    00:01
Fetching packagesite.pkg: 100%    7 MiB   3.6MB/s    00:02
Processing entries:   0%
Newer FreeBSD version for package zziplib:
To ignore this error set IGNORE_OSVERSION=yes
- package: 1302001
- running kernel: 1301000
Ignore the mismatch and continue? [y/N]:
Return type:

None

cleanup_orphan()[source]¶

Remove every package installed as a dependency and no longer required.

$ sudo pkg --quiet autoremove --yes
Checking integrity... done (0 conflicting)
Nothing to do.
Return type:

None

cleanup_cache()[source]¶

Delete every cached package from the local cache directory.

$ sudo pkg --quiet clean --yes --all
Nothing to do.
Return type:

None

doctor_cli()[source]¶

Generates the CLI running the native self-diagnosis.

check --checksums validates every installed package’s files against their recorded checksums, exiting non-zero on mismatches.

$ pkg --quiet check --checksums --all
Return type:

tuple[str, ...]

cli_names: tuple[str, ...] = ('pkg',)¶

List of CLI names the package manager is known as.

This list of recognized CLI names is ordered by priority. That way we can influence the search of the right binary.

..hint::

This was helpful in the case of the Python transition from 2.x to 3.x, where multiple versions of the same executable were named python or python3.

By default, this property’s value is derived from the manager’s ID (see the MetaPackageManager.__init__ method above).

id: str = 'pkg'¶

Package manager’s ID.

Derived by defaults from the lower-cased class name in which underscores _ are replaced by dashes -.

This ID must be unique among all package manager definitions and lower-case, as they’re used as feature flags for the mpm CLI.

virtual: bool = False¶

Should we expose the package manager to the user?

Virtual package manager are just skeleton classes used to factorize code among managers of the same family.

class meta_package_manager.managers.pkg.Ports[source]¶

Bases: PackageManager

FreeBSD ports tree: the source-build workflow rooted at /usr/ports.

Note

Coexists with PKG on the same system: both share the install database maintained by pkg. Ports builds and tracks ports compiled from source under /usr/ports, while PKG handles binary packages from the FreeBSD repository. Listing operations may overlap because pkg does not distinguish ports-built from binary-installed packages once they are registered.

Note

installed and outdated delegate to the sibling pkg binary, since the ports tree keeps no registry of its own. Builds drive FreeBSD’s make directly with BATCH=yes to accept default build options without prompting. Upgrades shell out to the third-party portmaster: the ports tree ships no batch upgrader. sync refreshes the tree with git (portsnap was removed after FreeBSD 13).

Caution

Mutating operations require root privileges and a populated ports tree at /usr/ports. The manager flags itself unavailable when the tree is missing.

Initialize cli_errors list.

name: str = 'FreeBSD Ports Collection'¶

Return package manager’s common name.

Default value is based on class name.

homepage_url: str | None = 'https://www.freebsd.org/ports/'¶

Home page of the project, only used in documentation for reference.

Slug of the brand mark standing for this manager in the documentation.

Names an SVG vendored under docs/assets/managers/, whose provenance and license are recorded in docs/assets/managers/logos.yaml. Inlined at the top of the manager’s page by meta_package_manager._docs; a manager leaving it unset keeps the page’s default package glyph.

Several managers legitimately share one slug, either because they wrap the same upstream (brew and cask) or because the tool has no mark of its own and its ecosystem’s stands in (apt under Debian’s swirl, cargo under Rust’s gear). Documentation-only, like homepage_url: no CLI output reads it.

platforms: frozenset[Platform] | Group | Platform | Iterable[Platform | Group] = frozenset({Platform(id='freebsd', name='FreeBSD')})¶

List of platforms supported by the manager.

Allows for a mishmash of platforms and groups of platforms. Will be normalized into a frozenset of Platform instances at instantiation.

default_sudo: bool = True¶

Built-in escalation default, used when sudo is None.

False on the base: most managers install into user-writable trees and never need root. The system package managers whose privileged operations require root (apt, dnf, pacman, zypper, …) set this to True so their build_cli(..., sudo=True) operations escalate out of the box, while staying switchable off through sudo (--no-sudo or config) for rootless setups.

cli_names: tuple[str, ...] = ('make',)¶

The ports tree is driven by FreeBSD’s make.

No dedicated frontend exists; each port is a directory whose Makefile targets are invoked directly.

extra_env: ClassVar = {'BATCH': 'yes'}¶

Force non-interactive builds.

Many ports prompt for build option dialogs by default. BATCH=yes accepts the saved or default options without user interaction, which is the only sensible behavior for an automated tool. See ports(7).

version_cli_options: tuple[str, ...] = ('-V', '.MAKE.VERSION')¶

FreeBSD make exposes its version via internal variable expansion.

GNU Make’s --version flag does not work on BSD make; using -V .MAKE.VERSION keeps the probe portable and avoids accidentally matching a GNU Make installation shadowing the BSD binary.

version_regexes: tuple[str, ...] = ('(?P<version>\\d{8,})',)¶

BSD make reports its version as a date-like integer (e.g. 20240218).

property available: bool[source]¶

Available only when make is found and the ports tree exists.

The make binary alone is not enough: without a populated /usr/ports directory, every operation would fail. Treat the tree as part of the manager’s runtime requirement.

id: str = 'ports'¶

Package manager’s ID.

Derived by defaults from the lower-cased class name in which underscores _ are replaced by dashes -.

This ID must be unique among all package manager definitions and lower-case, as they’re used as feature flags for the mpm CLI.

property installed: Iterator[Package]¶

Fetch packages currently registered as installed.

Delegates to pkg query because the ports tree itself maintains no registry: ports installs are recorded in the same database as binary pkg installs.

$ pkg query "%n %v %o %c"
curl 8.7.1 ftp/curl Non-interactive tool to get files from FTP/HTTP servers
python311 3.11.9 lang/python311 Interpreted object-oriented programming language
virtual: bool = False¶

Should we expose the package manager to the user?

Virtual package manager are just skeleton classes used to factorize code among managers of the same family.

property outdated: Iterator[Package]¶

Fetch packages whose installed version lags the ports tree.

Uses pkg version in ports-comparison mode (-PL=): it walks the local tree for each installed package and reports those with a newer Makefile version available.

$ pkg version -vIPL=
curl-8.7.1                         <   needs updating (port has 8.8.0)
python311-3.11.9                   <   needs updating (port has 3.11.10)
vim-9.1.0                          =   up-to-date with port
install(package_id, version=None)[source]¶

Build and install a port from source.

package_id may be either a bare port name (e.g. nginx) or its full origin (e.g. www/nginx). When given a bare name, the origin is resolved through pkg search -o against the active repository.

$ cd /usr/ports/www/nginx && sudo make BATCH=yes install clean
Return type:

str

upgrade_all_cli()[source]¶

Generate the CLI to upgrade every outdated port.

The ports tree has no first-party batch upgrader; the workflow relies on the third-party portmaster tool. We build the command line without checking that portmaster is installed, because upgrade commands are typically printed for the user to inspect before running.

$ sudo portmaster --no-confirm --no-term-title -a
Return type:

tuple[str, ...]

upgrade_one_cli(package_id, version=None)[source]¶

Generate the CLI to upgrade one port via portmaster.

$ sudo portmaster --no-confirm --no-term-title www/nginx
Return type:

tuple[str, ...]

remove¶

Reuses PKG.remove(): the ports tree has no native uninstaller, and removal goes through the shared install database regardless of how the package was originally built.

sync()[source]¶

Refresh the local ports tree from upstream.

Modern FreeBSD distributes the ports tree via Git; portsnap was deprecated and removed after FreeBSD 13. We pull from whatever remote the tree was checked out from.

$ sudo git -C /usr/ports pull --ff-only
Return type:

None

cleanup_cache()[source]¶

Remove cached build artifacts from the ports tree.

Walks the tree once and invokes make clean at the root, which recursively cleans every port’s work directory. DISTCLEAN=yes also removes downloaded distfiles.

$ sudo make -C /usr/ports clean DISTCLEAN=yes BATCH=yes
Return type:

None