pmb.helpers package

Submodules

pmb.helpers.apk_static module

pmb.helpers.apk_static.download(file: str) Path

Download a single file from an Alpine mirror.

pmb.helpers.apk_static.extract(version: str, apk_path: Path) None

Extract everything to temporary locations, verify signatures and reported versions. When everything is right, move the extracted apk.static to the final location.

pmb.helpers.apk_static.extract_temp(tar: TarFile, sigfilename: str) dict[str, dict]

Extract apk.static and signature as temporary files.

pmb.helpers.apk_static.init() None

Download, verify, extract $WORK/apk.static.

pmb.helpers.apk_static.read_signature_info(tar: TarFile) tuple[str, str]

Find various information about the signature that was used to sign /sbin/apk.static inside the archive (not to be confused with the normal apk archive signature!)

Returns:

(sigfilename, sigkey_path)

pmb.helpers.apk_static.verify_signature(files: dict[str, dict], sigkey_path: str) None

Verify the signature with openssl.

Parameters:

files – return value from extract_temp()

Raises:

RuntimeError – when verification failed and removes temp files

pmb.helpers.apk module

pmb.helpers.apk.cache_clean(arch: Arch) None

Clean the APK cache for a specific architecture.

pmb.helpers.apk.check_outdated(version_installed: str, action_msg: str) None

Check if the provided alpine version is outdated.

This depends on the alpine mirrordir (edge, v3.12, …) related to currently checked out pmaports branch.

Parameters:
  • version_installed – currently installed apk version, e.g. “2.12.1-r0”

  • action_msg – string explaining what the user should do to resolve this

Raises:

RuntimeError if the version is outdated

pmb.helpers.apk.run(command: Sequence[Path | str], chroot: Chroot, with_progress: bool = True) None

Run an apk subcommand.

Parameters:
  • command – apk subcommand in list form

  • with_progress – whether to print a progress bar

  • chroot – chroot to run the command in

Raises:

RuntimeError – when the apk command fails

pmb.helpers.aportupgrade module

class pmb.helpers.aportupgrade.PackageVersionInfo

Bases: TypedDict

date: datetime
sha: str
pmb.helpers.aportupgrade.get_package_version_info_github(repo_name: str, ref: str | None) PackageVersionInfo
pmb.helpers.aportupgrade.get_package_version_info_gitlab(gitlab_host: str, repo_name: str, ref: str | None) PackageVersionInfo
pmb.helpers.aportupgrade.init_req_headers() None
pmb.helpers.aportupgrade.upgrade(args: PmbArgs, pkgname: str, git: bool = True, stable: bool = True) None

Find new versions of a single package and upgrade it.

Parameters:
  • pkgname – the name of the package

  • git – True if git packages should be upgraded

  • stable – True if stable packages should be upgraded

pmb.helpers.aportupgrade.upgrade_all(args: PmbArgs) None

Upgrade all packages, based on args.all, args.all_git and args.all_stable.

pmb.helpers.aportupgrade.upgrade_git_package(args: PmbArgs, pkgname: str, package: dict[str, Any]) None

Update _commit/pkgver/pkgrel in a git-APKBUILD (or pretend to do it if args.dry is set).

Parameters:
  • pkgname – the package name

  • package – a dict containing package information

pmb.helpers.aportupgrade.upgrade_stable_package(args: PmbArgs, pkgname: str, package: dict[str, Any]) None

Update _commit/pkgver/pkgrel in an APKBUILD (or pretend to do it if args.dry is set).

Parameters:
  • pkgname – the package name

  • package – a dict containing package information

pmb.helpers.args module

pmb.helpers.args.init(args: PmbArgs) PmbArgs

pmb.helpers.cli module

class pmb.helpers.cli.ReadlineTabCompleter(options: KeysView[str] | dict[str, Any] | list[str])

Bases: object

Store intermediate state for completer function.

completer_func(input_text: str, iteration: int) str | None
Parameters:
  • input_text – text that shall be autocompleted

  • iteration – how many times “tab” was hit

pmb.helpers.cli.ask(question: str = 'Continue?', choices: list[str] | None = ['y', 'n'], default: int | str | None = 'n', lowercase_answer: bool | None = True, validation_regex: str | None = None, complete: KeysView[str] | dict[str, Any] | list[str] | None = None) str

Ask a question on the terminal.

Parameters:
  • question – display prompt

  • choices – short list of possible answers, displayed after prompt if set

  • default – default value to return if user doesn’t input anything

  • lowercase_answer – if True, convert return value to lower case

  • validation_regex – if set, keep asking until regex matches

  • complete – set to a list to enable tab completion

pmb.helpers.cli.confirm(question: str = 'Continue?', default: bool = False, no_assumptions: bool = False) bool

Convenience wrapper around ask for simple yes-no questions with validation.

Parameters:

no_assumptions – ask for confirmation, even if “pmbootstrap -y’ is set

Returns:

True for “y”, False for “n”

pmb.helpers.cli.progress_flush() None

Finish printing a progress bar.

This will erase the line. Does nothing in non-interactive mode.

pmb.helpers.cli.progress_print(progress: float) None

Print a snapshot of a progress bar to STDOUT.

Call progress_flush to end printing progress and clear the line. No output is printed in non-interactive mode.

Parameters:

progress – completion percentage as a number between 0 and 1

pmb.helpers.devices module

pmb.helpers.devices.find_path(codename: str, file: str = '') Path | None

Find path to device APKBUILD under device/*/device-.

Parameters:
  • codename – device codename

  • file – file to look for (e.g. APKBUILD or deviceinfo), may be empty

Returns:

path to APKBUILD

pmb.helpers.devices.list_codenames(vendor: str | None = None, archived: bool = True) list[str]

Get all devices, for which aports are available.

Parameters:
  • vendor – vendor name to choose devices from, or None for all vendors

  • archived – include archived devices

Returns:

[“first-device”, “second-device”, …]

pmb.helpers.devices.list_vendors() set[str]

Get all device vendors, for which aports are available.

Returns:

{“vendor1”, “vendor2”, …}

pmb.helpers.exceptions module

exception pmb.helpers.exceptions.BuildFailedError

Bases: Exception

Exception to be raised when pmbootstrap fails to build a package. This is handled separately from NonBugError as it needs to be treated differently as we want to hint to users that they can check the log for more information when a build fails.

exception pmb.helpers.exceptions.NonBugError

Bases: Exception

Exception which originates from a problem not caused by pmbootstrap’s code. This could for example be raised if there is an error in a package pmbootstrap is interacting with in some way.

pmb.helpers.file module

pmb.helpers.file.is_older_than(path: Path, seconds: int) bool

Check if a single file is older than a given amount of seconds.

pmb.helpers.file.is_up_to_date(path_sources: list[Path], path_target: Path | None = None, lastmod_target: float | None = None) bool

Check if a file is up-to-date by comparing the last modified timestamps.

(just like make does it).

Parameters:
  • path_sources – list of full paths to the source files

  • path_target – full path to the target file

  • lastmod_target – the timestamp of the target file. specify this as alternative to specifying path_target.

pmb.helpers.file.replace(path: Path, old: str, new: str) None
pmb.helpers.file.replace_apkbuild(args: PmbArgs, pkgname: str, key: str, new: int | str, in_quotes: bool = False) None

Replace one key=value line in an APKBUILD and verify it afterwards.

Parameters:
  • pkgname – package name, e.g. “hello-world”

  • key – key that should be replaced, e.g. “pkgver”

  • new – new value

  • in_quotes – expect the value to be in quotation marks (“”)

Check if the symlink is already present, otherwise create it.

pmb.helpers.frontend module

pmb.helpers.frontend.apkbuild_parse(args: PmbArgs) None
pmb.helpers.frontend.apkindex_parse(args: PmbArgs) None
pmb.helpers.frontend.aportupgrade(args: PmbArgs) None
pmb.helpers.frontend.bootimg_analyze(args: PmbArgs) None
pmb.helpers.frontend.build(args: PmbArgs) None
pmb.helpers.frontend.build_init(args: PmbArgs) None
pmb.helpers.frontend.checksum(args: PmbArgs) None
pmb.helpers.frontend.chroot(args: PmbArgs) None
pmb.helpers.frontend.ci(args: PmbArgs) None
pmb.helpers.frontend.config(args: PmbArgs) None
pmb.helpers.frontend.export(args: PmbArgs) None
pmb.helpers.frontend.initfs(args: PmbArgs) None
pmb.helpers.frontend.install(args: PmbArgs) None
pmb.helpers.frontend.lint(args: PmbArgs) None
pmb.helpers.frontend.netboot(args: PmbArgs) None
pmb.helpers.frontend.newapkbuild(args: PmbArgs) None
pmb.helpers.frontend.qemu(args: PmbArgs) None
pmb.helpers.frontend.repo_missing(args: PmbArgs) None
pmb.helpers.frontend.sideload(args: PmbArgs) None
pmb.helpers.frontend.stats(args: PmbArgs) None
pmb.helpers.frontend.status(args: PmbArgs) NoReturn
pmb.helpers.frontend.update(args: PmbArgs) None
pmb.helpers.frontend.work_migrate(args: PmbArgs) None
pmb.helpers.frontend.zap(args: PmbArgs) None

pmb.helpers.git module

class pmb.helpers.git.RemoteType(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

FETCH = 'fetch'
PUSH = 'push'
static from_git_output(git_remote_type: str) RemoteType
pmb.helpers.git.branch_looks_official(repo: Path, branch: str) bool
Check if a given branch follows the patterns of official branches in

pmaports or aports.

Returns:

True if it looks official, False otherwise

pmb.helpers.git.can_fast_forward(path: Path, branch_upstream: str, branch: str = 'HEAD') bool
pmb.helpers.git.clean_worktree(path: Path, silent: bool = False) bool

Check if there are not any modified files in the git dir.

pmb.helpers.git.clone(name_repo: str) None

Clone a git repository to $WORK/cache_git/$name_repo.

(or to the overridden path set in args, as with pmbootstrap --aports).

Parameters:

name_repo – short alias used for the repository name, from pmb.config.git_repos (e.g. “aports_upstream”, “pmaports”)

pmb.helpers.git.get_files(repo: Path) list[str]

Get all files inside a git repository, that are either already in the git tree or are not in gitignore.

Do not list deleted files. To be used for creating a tarball of the git repository.

Parameters:

path – top dir of the git repository

Returns:

all files in a git repository as list, relative to path

pmb.helpers.git.get_path(name_repo: str) Path

Get the path to the repository.

The path is either the default one in the work dir, or a user-specified one in args.

Returns:

full path to repository

pmb.helpers.git.get_topdir(repo: Path) Path

Get top-dir of git repo.

Returns:

the top dir of the git repository

pmb.helpers.git.get_upstream_remote(aports: Path) str

Find the remote, which matches the git URL from the config.

Usually “origin”, but the user may have set up their git repository differently.

pmb.helpers.git.list_remotes(aports: Path) list[str]
pmb.helpers.git.migrate_upstream_remote() None

Migrate pmaports git remote URL from gitlab.com to gitlab.postmarketos.org.

pmb.helpers.git.pull(repo_name: str) int

Check if on official branch and essentially try git pull --ff-only.

Instead of really doing git pull --ff-only, do it in multiple steps (fetch, merge --ff-only), so we can display useful messages depending on which part fails.

Returns:

integer, >= 0 on success, < 0 on error

pmb.helpers.git.rev_parse(path: Path, revision: str = 'HEAD', extra_args: list = [], silent: bool = False) str

Run “git rev-parse” in a specific repository dir.

Parameters:
  • path – to the git repository

  • extra_args – additional arguments for git rev-parse. Pass --abbrev-ref to get the branch instead of the commit, if possible.

Returns:

commit string like “90cd0ad84d390897efdcf881c0315747a4f3a966” or (with --abbrev-ref): the branch name, e.g. “master”

pmb.helpers.git.set_remote_url(repo: Path, remote_name: str, remote_url: str, remote_type: RemoteType) None

pmb.helpers.http module

pmb.helpers.http.cache_file(prefix: str, url: str) Path
pmb.helpers.http.download(url: str, prefix: str, cache: bool = True, loglevel: int = 20, allow_404: Literal[False] = False, flush_progress_bar_on_404: bool = False) Path
pmb.helpers.http.download(url: str, prefix: str, cache: bool = True, loglevel: int = 20, allow_404: Literal[True] = False, flush_progress_bar_on_404: bool = False) Path | None

Download a file to disk.

Parameters:
  • url – the http(s) address of to the file to download

  • prefix – for the cache, to make it easier to find (cache files get a hash of the URL after the prefix)

  • cache – if True, and url is cached, do not download it again

  • loglevel – change to logging.DEBUG to only display the download message in ‘pmbootstrap log’, not in stdout. We use this when downloading many APKINDEX files at once, no point in showing a dozen messages.

  • allow_404 – do not raise an exception when the server responds with a 404 Not Found error. Only display a warning on stdout (no matter if loglevel is changed).

  • flush_progress_bar_on_404 – download happens while a progress bar is displayed, flush it before printing a warning for 404

Returns:

path to the downloaded file in the cache or None on 404

pmb.helpers.http.retrieve(url: str, headers: dict[str, str] | None = None, allow_404: Literal[False] = False) str
pmb.helpers.http.retrieve(url: str, headers: dict[str, str] | None = None, allow_404: Literal[True] = False) str | None

Fetch the content of a URL and returns it as string.

Parameters:
  • url – the http(s) address of to the resource to fetch

  • headers – dict of HTTP headers to use

  • allow_404 – do not raise an exception when the server responds with a 404 Not Found error. Only display a warning

Returns:

str with the content of the response

pmb.helpers.http.retrieve_json(url: str, headers: dict[str, str] | None = None) Any

Fetch the contents of a URL, parse it as JSON and return it.

See retrieve() for the meaning of the parameters.

pmb.helpers.lint module

pmb.helpers.lint.check(pkgnames: Sequence[str]) None

Run apkbuild-lint on the supplied packages.

Parameters:

pkgnames – Names of the packages to lint

pmb.helpers.lint.get_custom_valid_options() list[str]

Build a list of custom valid APKBUILD options that apkbuild-lint should not complain about. The list consists of hardcoded options from pmb.config.apkbuild_custom_valid_options like pmb:gpu-accel, as well as dynamically generated options from kconfigcheck.toml (pmb:kconfigcheck-libcamera etc.).

pmb.helpers.locale module

class pmb.helpers.locale.XkbLayout(layout: str = 'us', variant: str = '')

Bases: object

get_keyboard_config() str | None
get_profile_vars() str | None
is_default() bool
primary_layouts = ['at', 'au', 'br', 'ca', 'ch', 'de', 'dk', 'ee', 'es', 'fi', 'fo', 'fr', 'gb', 'ie', 'is', 'it', 'latam', 'lt', 'mt', 'nz', 'pl', 'pt', 'ro', 'se', 'sk', 'tr', 'us', 'vn']
pmb.helpers.locale.get_xkb_layout(locale: str) XkbLayout

Get Xkb layout for the given locale.

Parameters:

locale – Locale to get XkbLayout for.

Returns:

XkbLayout for the given locale.

pmb.helpers.logging module

pmb.helpers.logging.add_verbose_log_level() None

Add a new log level “verbose”, which is below “debug”.

Also monkeypatch logging, so it can be used with logging.verbose().

This function is based on work by Voitek Zylinski and sleepycal: https://stackoverflow.com/a/20602183 All stackoverflow user contributions are licensed as CC-BY-SA: https://creativecommons.org/licenses/by-sa/3.0/

pmb.helpers.logging.critical(msg: object, *args: str, **kwargs: Any) None
pmb.helpers.logging.debug(msg: object, *args: str, **kwargs: Any) None
pmb.helpers.logging.disable() None
pmb.helpers.logging.error(msg: object, *args: str, **kwargs: Any) None
pmb.helpers.logging.fatal(msg: object, *args: str, **kwargs: Any) None
pmb.helpers.logging.info(msg: object, *args: str, **kwargs: Any) None
pmb.helpers.logging.init(logfile: Path, verbose: bool, details_to_stdout: bool = False) None

Set log format and add the log file descriptor to logfd, add the verbose log level.

pmb.helpers.logging.log(level: int, msg: object, *args: str, **kwargs: Any) None
class pmb.helpers.logging.log_handler(details_to_stdout: bool = False, quiet: bool = False)

Bases: StreamHandler

Write to stdout and to the already opened log file.

emit(record: LogRecord) None

Emit a record.

If a formatter is specified, it is used to format the record. The record is then written to the stream with a trailing newline. If exception information is present, it is formatted using traceback.print_exception and appended to the stream. If the stream has an ‘encoding’ attribute, it is used to determine how to do the output to the stream.

pmb.helpers.logging.logfd: TextIO
pmb.helpers.logging.verbose(msg: object, *args: str, **kwargs: Any) None
pmb.helpers.logging.warning(msg: object, *args: str, **kwargs: Any) None

pmb.helpers.mount module

pmb.helpers.mount.bind(source: Path | str, destination: Path, create_folders: bool = True, umount: bool = False) None

Mount –bind a folder and create necessary directory structure.

Parameters:

umount – when destination is already a mount point, umount it first.

pmb.helpers.mount.bind_file(source: Path, destination: Path, create_folders: bool = False) None

Mount a file with the –bind option, and create the destination file, if necessary.

pmb.helpers.mount.ismount(folder: Path) bool

Ismount() implementation that works for mount –bind.

Workaround for: https://bugs.python.org/issue29707

pmb.helpers.mount.mount_device_rootfs(chroot_rootfs: ~pmb.core.chroot.Chroot, chroot_base: ~pmb.core.chroot.Chroot = <pmb.core.chroot.Chroot object>) PurePath

Mount the device rootfs.

Parameters:
  • chroot_rootfs – the chroot where the rootfs that will be installed on the device has been created (e.g. “rootfs_qemu-amd64”)

  • chroot_base – the chroot rootfs mounted to

Returns:

the mountpoint (relative to the chroot)

pmb.helpers.mount.umount_all(folder: Path) None

Umount all folders that are mounted inside a given folder.

pmb.helpers.mount.umount_all_list(prefix: Path, source: Path = PosixPath('/proc/mounts')) list[Path]

Parse /proc/mounts for all folders beginning with a prefix.

Source:

can be changed for testcases

Returns:

a list of folders that need to be umounted

pmb.helpers.other module

pmb.helpers.other.check_binfmt_misc() None

Check if the ‘binfmt_misc’ module is loaded.

This is done by checking, if /proc/sys/fs/binfmt_misc/ exists. If it exists, then do nothing. Otherwise, load the module and mount binfmt_misc. If that fails as well, raise an exception pointing the user to the wiki.

pmb.helpers.other.check_grsec() None

Check if the current kernel is based on the grsec patchset.

Also check if the chroot_deny_chmod option is enabled. Raise an exception in that case, with a link to the issue. Otherwise, do nothing.

pmb.helpers.other.folder_size(path: Path) int

Run du to calculate the size of a folder.

(this is less code and faster than doing the same task in pure Python) This result is only approximatelly right, but good enough for pmbootstrap’s use case (#760).

Returns:

folder size in kilobytes

pmb.helpers.other.migrate_success(work: Path, version: int) None
pmb.helpers.other.migrate_work_folder() None
pmb.helpers.other.normalize_hostname(hostname: str) str

Fixup default hostnames so that they don’t fail validate_hostname()

This should not be called on user-chosen hostnames as those should fail

pmb.helpers.other.validate_hostname(hostname: str) bool

Check whether the string is a valid hostname.

Check is performed according to <http://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names>

pmb.helpers.package module

Functions that work with both pmaports and binary package repos.

See also:

  • pmb/helpers/pmaports.py (work with pmaports)

  • pmb/helpers/repo.py (work with binary package repos)

pmb.helpers.package.check_arch(pkgname: str, arch: Arch, binary: bool = True) bool

Check if a package be built for a certain architecture, or is there a binary package for it.

Parameters:
  • pkgname – name of the package

  • arch – architecture to check against

  • binary – set to False to only look at the pmaports, not at binary packages

Returns:

True when the package can be built, or there is a binary package, False otherwise

pmb.helpers.package.remove_operators(package: str) str

pmb.helpers.pkgrel_bump module

class pmb.helpers.pkgrel_bump.BumpType(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

PKGREL = 'pkgrel'
PKGVER = 'pkgver'
pmb.helpers.pkgrel_bump.auto(dry: bool = False) list[str]
Returns:

list of aport names, where the pkgrel needed to be changed

pmb.helpers.pkgrel_bump.auto_apkindex_package(arch: Arch, aport: dict[str, Any], apk: ApkindexBlock, dry: bool = False) bool

Bump the pkgrel of a specific package if it is outdated in the given APKINDEX.

Parameters:
  • arch – the architecture, e.g. “armhf”

  • aport – parsed APKBUILD of the binary package’s origin: {“pkgname”: …, “pkgver”: …, “pkgrel”: …, …}

  • apk – information about the binary package from the APKINDEX: {“version”: …, “depends”: […], …}

  • dry – don’t modify the APKBUILD, just print the message

Returns:

True when there was an APKBUILD that needed to be changed.

pmb.helpers.pkgrel_bump.package(pkgname: str, reason: str = '', dry: bool = False, bump_type: BumpType = BumpType.PKGREL) None

Increase the pkgrel or pkgver in the APKBUILD of a specific package.

Parameters:
  • pkgname – name of the package

  • reason – string to display as reason why it was increased

  • dry – don’t modify the APKBUILD, just print the message

  • bump_type – whether to bump pkgrel or pkgver

pmb.helpers.pmaports module

Functions that work with pmaports.

See also: - pmb/helpers/repo.py (work with binary package repos) - pmb/helpers/package.py (work with both)

pmb.helpers.pmaports.check_arches(arches: list[str], arch: Arch) bool

Check if building for a certain arch is allowed.

Parameters:
  • arches – list of all supported arches, as it can be found in the arch=”” line of APKBUILDS (including all, noarch, !arch, …). For example: [“x86_64”, “x86”, “!armhf”]

  • arch – the architecture to check for

Returns:

True when building is allowed, False otherwise

pmb.helpers.pmaports.find_optional(package: str) Path | None
pmb.helpers.pmaports.find_providers(provide: str, default: list[str]) list[tuple[Any, Any]]

Search for providers of the specified (virtual) package in pmaports.

Note: Currently only providers from a single APKBUILD are returned.

Parameters:
  • provide – the (virtual) package to search providers for

  • default – the _pmb_default to look through for defaults

Returns:

tuple list (pkgname, apkbuild_pkg) with providers, sorted by provider_priority. The provider with the highest priority (which would be selected by default) comes first.

pmb.helpers.pmaports.get(pkgname: str, must_exist: Literal[True] = True, subpackages: bool = True, with_extra_repos: Literal['default', 'enabled', 'disabled'] = 'default') dict[str, Any]
pmb.helpers.pmaports.get(pkgname: str, must_exist: bool = True, subpackages: bool = True, with_extra_repos: Literal['default', 'enabled', 'disabled'] = 'default') dict[str, Any] | None
pmb.helpers.pmaports.get_channel_new(channel: str) str

Translate legacy channel names to the new ones.

Legacy names are still supported for compatibility with old branches (pmb#2015). :param channel: name as read from pmaports.cfg or channels.cfg, like “edge”, “v21.03” etc., or potentially a legacy name like “stable”.

Returns:

name in the new format, e.g. “edge” or “v21.03”

pmb.helpers.pmaports.get_list() list[str]
Returns:

list of all pmaport pkgnames ([“hello-world”, …])

pmb.helpers.pmaports.get_repo(pkgname: str) str | None

Get the repository folder of an aport.

Pkgname:

package name

Returns:

  • None if pkgname is not in extra-repos/

  • ”systemd” if the pkgname is in extra-repos/systemd/

pmb.helpers.pmaports.guess_main(subpkgname: str) Path | None

Find the main package by assuming it is a prefix of the subpkgname.

We do that, because in some APKBUILDs the subpkgname=”” variable gets filled with a shell loop and the APKBUILD parser in pmbootstrap can’t parse this right. (Intentionally, we don’t want to implement a full shell parser.)

Parameters:

subpkgname – subpackage name (e.g. “u-boot-some-device”)

Returns:

  • full path to the aport, e.g.: “/home/user/code/pmbootstrap/aports/main/u-boot”

  • None when we couldn’t find a main package

pmb.helpers.pmaports.guess_main_cross(subpkgname: str) Path | None

Check if a subpackage that is part of the cross toolchain is in pmaports or not, and log the appropriate message.

Don’t call this function directly, use guess_main() instead.

Parameters:

subpkgname – subpackage name

Returns:

full path to the pmaport or None

pmb.helpers.pmaports.guess_main_dev(subpkgname: str) Path | None

Check if a package without “-dev” at the end exists in pmaports or not, and log the appropriate message.

Don’t call this function directly, use guess_main() instead.

Parameters:

subpkgname – subpackage name, must end in “-dev”

Returns:

full path to the pmaport or None

pmb.helpers.pmaports.require_bootstrap(arch: Arch, trigger_str: str) None

Check if repo_bootstrap was done, if any is needed.

Parameters:
  • arch – for which architecture

  • trigger_str – message for the user to understand what caused this

pmb.helpers.pmaports.require_bootstrap_error(repo: str, arch: Arch, trigger_str: str) None

Tell the user that they need to do repo_bootstrap, with some context.

Parameters:
  • repo – which repository

  • arch – for which architecture

  • trigger_str – message for the user to understand what caused this

pmb.helpers.pmaports.show_pkg_not_found_systemd_hint(package: str, with_extra_repos: Literal['default', 'enabled', 'disabled']) None

Check if a package would be found if systemd was enabled and display a hint about it.

pmb.helpers.repo module

Functions that work with binary package repos.

See also: - pmb/helpers/pmaports.py (work with pmaports) - pmb/helpers/package.py (work with both)

pmb.helpers.repo.alpine_apkindex_path(repo: str = 'main', arch: Arch | None = None) Path

Get the path to a specific Alpine APKINDEX file on disk and download it if necessary.

Parameters:
  • repo – Alpine repository name (e.g. “main”)

  • arch – Alpine architecture (e.g. “armhf”), defaults to native arch.

Returns:

full path to the APKINDEX file

pmb.helpers.repo.apkindex_files(arch: Arch | None = None, user_repository: bool = True, exclude_mirrors: list[str] = []) list[Path]

Get a list of outside paths to all resolved APKINDEX.tar.gz files for a specific arch.

Parameters:
  • arch – defaults to native

  • user_repository – add path to index of locally built packages

  • exclude_mirrors – list of mirrors to exclude (e.g. [“alpine”, “pmaports”])

Returns:

list of absolute APKINDEX.tar.gz file paths

pmb.helpers.repo.apkindex_hash(url: str, length: int = 8) Path

Generate the hash that APK adds to the APKINDEX and apk packages in its apk cache folder.

It is the “12345678” part in this example: “APKINDEX.12345678.tar.gz”.

Parameters:

length – The length of the hash in the output file.

See also: official implementation in apk-tools: <https://git.alpinelinux.org/cgit/apk-tools/>

blob.c: apk_blob_push_hexdump(), “const char \*xd” apk_defines.h: APK_CACHE_CSUM_BYTES database.c: apk_repo_format_cache_index()

pmb.helpers.repo_missing module

pmb.helpers.repo_missing.filter_aport_packages(pkgnames: list[str]) list[str]

Create a subset of pkgnames where each one has an aport.

Parameters:

pkgnames – list of package names (e.g. [“hello-world”, “test12”])

Returns:

subset of pkgnames (e.g. [“hello-world”])

pmb.helpers.repo_missing.filter_arch_packages(arch: Arch, pkgnames: list[str]) list[str]

Create a subset of pkgnames with packages removed that can not be built for a certain arch.

Parameters:
  • arch – architecture (e.g. “armhf”)

  • pkgnames – list of package names (e.g. [“hello-world”, “test12”])

Returns:

subset of pkgnames (e.g. [“hello-world”])

pmb.helpers.repo_missing.filter_missing_packages(arch: Arch, pkgnames: list[str]) list[str]

Create a subset of pkgnames with missing or outdated binary packages.

Parameters:
  • arch – architecture (e.g. “armhf”)

  • pkgnames – list of package names (e.g. [“hello-world”, “test12”])

Returns:

subset of pkgnames (e.g. [“hello-world”])

pmb.helpers.repo_missing.generate(arch: Arch, overview: Literal[False], pkgname: str | None = None, built: bool = False) list[dict[str, Any]]
pmb.helpers.repo_missing.generate(arch: Arch, overview: Literal[True], pkgname: str | None = None, built: bool = False) list[str]
pmb.helpers.repo_missing.generate(arch: Arch, overview: bool, pkgname: str | None = None, built: bool = False) list[dict[str, Any]] | list[str]

Get packages that need to be built, with all their dependencies.

Parameters:
  • arch – architecture (e.g. “armhf”)

  • pkgname – only look at a specific package

  • built – include packages that have already been built

Returns:

a list like the following: [{“pkgname”: “hello-world”, “repo”: “main”, “version”: “1-r4”}, {“pkgname”: “package-depending-on-hello-world”, “version”: “0.5-r0”, “repo”: “main”}]

pmb.helpers.repo_missing.generate_output_format(arch: Arch, pkgnames: list[str]) list[dict[str, Any]]

Generate the detailed output format.

Parameters:
  • arch – architecture

  • pkgnames – list of package names that should be in the output, e.g.: [“hello-world”, “pkg-depending-on-hello-world”] :returns: a list like the following: [{“pkgname”: “hello-world”, “repo”: “main”, “version”: “1-r4”, “depends”: []}, {“pkgname”: “pkg-depending-on-hello-world”, “version”: “0.5-r0”, “repo”: “main”, “depends”: [“hello-world”]}]

pmb.helpers.repo_missing.get_relevant_packages(arch: Arch, pkgname: str | None = None, built: bool = False) list[str]

Get all packages that can be built for the architecture in question.

Parameters:
  • arch – architecture (e.g. “armhf”)

  • pkgname – only look at a specific package (and its dependencies)

  • built – include packages that have already been built

Returns:

an alphabetically sorted list of pkgnames, e.g.: [“devicepkg-dev”, “hello-world”, “osk-sdl”]

pmb.helpers.run module

pmb.helpers.run.root(cmd: Sequence[Path | str], working_dir: Path | None = None, output: Literal['background', 'pipe'] = 'log', output_return: Literal[False] = False, check: bool | None = None, env: dict[str, Path | str] = {}) Popen
pmb.helpers.run.root(cmd: Sequence[Path | str], working_dir: Path | None = None, output: Literal['log', 'stdout', 'interactive', 'tui', 'null'] = 'log', output_return: Literal[False] = False, check: bool | None = None, env: dict[str, Path | str] = {}) int
pmb.helpers.run.root(cmd: Sequence[Path | str], working_dir: Path | None = None, output: Literal['log', 'stdout', 'interactive', 'tui', 'null', 'background', 'pipe'] = 'log', output_return: Literal[True] = False, check: bool | None = None, env: dict[str, Path | str] = {}) str

Run a command on the host system as root, with sudo or doas.

Parameters:

env – dict of environment variables to be passed to the command, e.g. {“JOBS”: “5”}

See pmb.helpers.run_core.core() for a detailed description of all other arguments and the return value.

pmb.helpers.run.user(cmd: Sequence[Path | str], working_dir: Path | None = None, output: Literal['log', 'stdout', 'interactive', 'tui', 'null', 'background', 'pipe'] = 'log', output_return: bool = False, check: bool | None = None, env: dict[str, Path | str] = {}, sudo: bool = False) str | int | Popen

Run a command on the host system as user.

Parameters:

env – dict of environment variables to be passed to the command, e.g. {“JOBS”: “5”}

See pmb.helpers.run_core.core() for a detailed description of all other arguments and the return value.

pmb.helpers.run.user_output(cmd: Sequence[Path | str], working_dir: Path | None = None, output: Literal['log', 'stdout', 'interactive', 'tui', 'null', 'background', 'pipe'] = 'log', check: bool | None = None, env: dict[str, Path | str] = {}, sudo: bool = False) str

pmb.helpers.run_core module

pmb.helpers.run_core.add_proxy_env_vars(env: dict[str, Path | str]) None

Add proxy environment variables from host to the environment of the command we are running.

Parameters:

env – dict of environment variables, it will be extended with all of the proxy env vars that are set on the host

pmb.helpers.run_core.background(cmd: Path | str | Sequence[Path | str], working_dir: Path | str | None = None) Popen

Run a subprocess in background and redirect its output to the log.

pmb.helpers.run_core.check_return_code(code: int, log_message: str) None

Check the return code of a command.

Parameters:
  • code – exit code to check

  • log_message – simplified and more readable form of the command, e.g. “(native) % echo test” instead of the full command with entering the chroot and more escaping

Raises:

RuntimeError – when the code indicates that the command failed

pmb.helpers.run_core.core(log_message: str, cmd: Sequence[Path | str], working_dir: Path | None = None, output: Literal['log', 'stdout', 'interactive', 'tui', 'null', 'background', 'pipe'] = 'log', output_return: bool = False, check: bool | None = None, sudo: bool = False, disable_timeout: bool = False) str | int | Popen

Run a command and create a log entry.

This is a low level function not meant to be used directly. Use one of the following instead: pmb.helpers.run.user(), pmb.helpers.run.root(), pmb.chroot.user(), pmb.chroot.root()

Parameters:
  • log_message – simplified and more readable form of the command, e.g. “(native) % echo test” instead of the full command with entering the chroot and more escaping

  • cmd – command as list, e.g. [“echo”, “string with spaces”]

  • working_dir – path in host system where the command should run

  • output

    where to write the output (stdout and stderr) of the

    process. We almost always write to the log file, which can be read with “pmbootstrap log” (output values: “log”, “stdout”, “interactive”, “background”), so it’s easy to trace what pmbootstrap does.

    The exceptions are “tui” (text-based user interface), where it does not make sense to write to the log file (think of ncurses UIs, such as “menuconfig”) and “pipe” where the output is written to a pipe for manual asynchronous consumption by the caller.

    When the output is not set to “interactive”, “tui”, “background” or “pipe”, we kill the process if it does not output anything for 5 minutes (time can be set with “pmbootstrap –timeout”).

    The table below shows all possible values along with their properties. “wait” indicates that we wait for the process to complete.

    output value

    timeout

    out to log

    out to stdout

    wait

    pass stdin

    ”log”

    x

    x

    x

    ”stdout”

    x

    x

    x

    x

    ”interactive”

    x

    x

    x

    x

    ”tui”

    x

    x

    x

    ”background”

    x

    ”pipe”

    ”null”

  • output_return – in addition to writing the program’s output to the destinations above in real time, write to a buffer and return it as string when the command has completed. This is not possible when output is “background”, “pipe” or “tui”.

  • check – an exception will be raised when the command’s return code is not 0. Set this to False to disable the check. This parameter can not be used when the output is “background” or “pipe”.

  • sudo – use sudo to kill the process when it hits the timeout.

Returns:

  • program’s return code (default)

  • subprocess.Popen instance (output is “background” or “pipe”)

  • the program’s entire output (output_return is True)

pmb.helpers.run_core.flat_cmd(cmds: Sequence[Sequence[Path | str]], working_dir: Path | None = None, env: dict[str, Path | str] = {}) str

Convert a shell command passed as list into a flat shell string with proper escaping.

Parameters:
  • cmds – list of commands as list, e.g. [“echo”, “string with spaces”]

  • working_dir – when set, prepend “cd …;” to execute the command in the given working directory

  • env – dict of environment variables to be passed to the command, e.g. {“JOBS”: “5”}

Returns:

the flat string, e.g. echo ‘string with spaces’ cd /home/pmos;echo ‘string with spaces’

pmb.helpers.run_core.foreground_pipe(cmd: Path | str | Sequence[Path | str], working_dir: Path | None = None, output_to_stdout: bool = False, output_return: bool = False, output_log: bool = True, output_timeout: bool = True, sudo: bool = False, stdin: int | None = None) tuple[int, str]

Run a subprocess in foreground with redirected output.

Optionally kill it after being silent for too long.

Parameters:
  • cmd – command as list, e.g. [“echo”, “string with spaces”]

  • working_dir – path in host system where the command should run

  • output_to_stdout – copy all output to pmbootstrap’s stdout

  • output_return – return the output of the whole program

  • output_timeout – kill the process when it doesn’t print any output after a certain time (configured with –timeout) and raise a RuntimeError exception

  • sudo – use sudo to kill the process when it hits the timeout

Returns:

(code, output) * code: return code of the program * output: “” * output: full program output string (output_return is True)

pmb.helpers.run_core.foreground_tui(cmd: Path | str | Sequence[Path | str], working_dir: Path | str | None = None) int

Run a subprocess in foreground without redirecting any of its output.

This is the only way text-based user interfaces (ncurses programs like vim, nano or the kernel’s menuconfig) work properly.

pmb.helpers.run_core.kill_command(pid: int, sudo: bool) None

Kill a command process and recursively kill its child processes.

Parameters:
  • pid – process id that will be killed

  • sudo – use sudo to kill the process

pmb.helpers.run_core.kill_process_tree(pid: int | str, ppids: list[list[str]], sudo: bool) None

Recursively kill a pid and its child processes.

Parameters:
  • pid – process id that will be killed

  • ppids – list of process id and parent process id tuples (pid, ppid)

  • sudo – use sudo to kill the process

pmb.helpers.run_core.pipe(cmd: Path | str | Sequence[Path | str], working_dir: Path | str | None = None) Popen

Run a subprocess in background and redirect its output to a pipe.

pmb.helpers.run_core.pipe_read(process: Popen, output_to_stdout: bool = False, output_log: bool = True, output_return: Literal[False] = False, output_return_buffer: None = None) None
pmb.helpers.run_core.pipe_read(process: Popen, output_to_stdout: bool = False, output_log: bool = True, output_return: Literal[True] = False, output_return_buffer: list[bytes] = None) None
pmb.helpers.run_core.pipe_read(process: Popen, output_to_stdout: bool = False, output_log: bool = True, output_return: bool = False, output_return_buffer: list[bytes] | None = None) None

Read all output from a subprocess, copy it to the log and optionally stdout and a buffer variable.

This is only meant to be called by foreground_pipe() below.

Parameters:
  • process – subprocess.Popen instance

  • output_to_stdout – copy all output to pmbootstrap’s stdout

  • output_return – when set to True, output_return_buffer will be extended

  • output_return_buffer – list of bytes that gets extended with the current output in case output_return is True.

pmb.helpers.run_core.sanity_checks(output: Literal['log', 'stdout', 'interactive', 'tui', 'null', 'background', 'pipe'] = 'log', output_return: bool = False, check: bool | None = None) None

Raise an exception if the parameters passed to core() don’t make sense.

(all parameters are described in core() below).

pmb.helpers.run_core.sudo_timer_iterate() None

Run sudo -v and schedule a new timer to repeat the same.

pmb.helpers.run_core.sudo_timer_start() None

Start a timer to call sudo -v periodically, so that the password is only needed once.

pmb.helpers.status module

pmb.helpers.status.print_channel(config: Config) None
pmb.helpers.status.print_device(config: Config) None
pmb.helpers.status.print_status() None
Parameters:

details – if True, print each passing check instead of a summary

Returns:

True if all checks passed, False otherwise

pmb.helpers.status.print_status_line(key: str, value: str) None
pmb.helpers.status.print_systemd(config: Config) None
pmb.helpers.status.print_ui(config: Config) None

pmb.helpers.toml module

pmb.helpers.ui module

pmb.helpers.ui.check_option(ui: str, option: str, with_extra_repos: Literal['default', 'enabled', 'disabled'] = 'default') bool

Check if an option, such as pmb:systemd, is inside an UI’s APKBUILD.

pmb.helpers.ui.list_ui(arch: Arch) list[tuple[str, str]]

Get all UIs, for which aports are available with their description.

Parameters:

arch – device architecture, for which the UIs must be available

Returns:

[(“none”, “No graphical…”), (“weston”, “Wayland reference…”)]

Module contents