pmb.*: various comment reformatting to assist with generating docs (MR 2266)
This commit is contained in:
parent
415e7364f4
commit
044d3b5a6a
|
@ -15,8 +15,11 @@ import pmb.helpers.cli
|
||||||
def get_cross_package_arches(pkgname):
|
def get_cross_package_arches(pkgname):
|
||||||
"""
|
"""
|
||||||
Get the arches for which we want to build cross packages.
|
Get the arches for which we want to build cross packages.
|
||||||
|
|
||||||
:param pkgname: package name, e.g. "gcc-aarch64", "gcc-x86_64"
|
:param pkgname: package name, e.g. "gcc-aarch64", "gcc-x86_64"
|
||||||
|
|
||||||
:returns: string of architecture(s) (space separated)
|
:returns: string of architecture(s) (space separated)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if pkgname.endswith("-x86_64"):
|
if pkgname.endswith("-x86_64"):
|
||||||
return "aarch64"
|
return "aarch64"
|
||||||
|
@ -32,7 +35,9 @@ def properties(pkgname):
|
||||||
Example: "musl-armhf" => ("musl", "cross", {"confirm_overwrite": False})
|
Example: "musl-armhf" => ("musl", "cross", {"confirm_overwrite": False})
|
||||||
|
|
||||||
:param pkgname: package name
|
:param pkgname: package name
|
||||||
|
|
||||||
:returns: (prefix, folder, options)
|
:returns: (prefix, folder, options)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
for folder, options in pmb.config.aportgen.items():
|
for folder, options in pmb.config.aportgen.items():
|
||||||
for prefix in options["prefixes"]:
|
for prefix in options["prefixes"]:
|
||||||
|
|
|
@ -21,6 +21,7 @@ def format_function(name, body, remove_indent=4):
|
||||||
"""
|
"""
|
||||||
Format the body of a shell function passed to rewrite() below, so it fits
|
Format the body of a shell function passed to rewrite() below, so it fits
|
||||||
the format of the original APKBUILD.
|
the format of the original APKBUILD.
|
||||||
|
|
||||||
:param remove_indent: Maximum number of spaces to remove from the
|
:param remove_indent: Maximum number of spaces to remove from the
|
||||||
beginning of each line of the function body.
|
beginning of each line of the function body.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -26,9 +26,9 @@ class BootstrapStage(enum.IntEnum):
|
||||||
|
|
||||||
|
|
||||||
def skip_already_built(pkgname, arch):
|
def skip_already_built(pkgname, arch):
|
||||||
"""
|
"""Check if the package was already built in this session.
|
||||||
Check if the package was already built in this session, and add it
|
|
||||||
to the cache in case it was not built yet.
|
Add it to the cache in case it was not built yet.
|
||||||
|
|
||||||
:returns: True when it can be skipped or False
|
:returns: True when it can be skipped or False
|
||||||
"""
|
"""
|
||||||
|
@ -45,9 +45,9 @@ def skip_already_built(pkgname, arch):
|
||||||
|
|
||||||
|
|
||||||
def get_apkbuild(args, pkgname, arch):
|
def get_apkbuild(args, pkgname, arch):
|
||||||
"""
|
"""Parse the APKBUILD path for pkgname.
|
||||||
Parse the APKBUILD path for pkgname. When there is none, try to find it in
|
|
||||||
the binary package APKINDEX files or raise an exception.
|
When there is none, try to find it in the binary package APKINDEX files or raise an exception.
|
||||||
|
|
||||||
:param pkgname: package name to be built, as specified in the APKBUILD
|
:param pkgname: package name to be built, as specified in the APKBUILD
|
||||||
:returns: None or parsed APKBUILD
|
:returns: None or parsed APKBUILD
|
||||||
|
@ -66,8 +66,8 @@ def get_apkbuild(args, pkgname, arch):
|
||||||
|
|
||||||
|
|
||||||
def check_build_for_arch(args, pkgname, arch):
|
def check_build_for_arch(args, pkgname, arch):
|
||||||
"""
|
"""Check if pmaport can be built or exists as binary for a specific arch.
|
||||||
Check if pmaport can be built or exists as binary for a specific arch.
|
|
||||||
:returns: * True when it can be built
|
:returns: * True when it can be built
|
||||||
* False when it can't be built, but exists in a binary repo
|
* False when it can't be built, but exists in a binary repo
|
||||||
(e.g. temp/mesa can't be built for x86_64, but Alpine has it)
|
(e.g. temp/mesa can't be built for x86_64, but Alpine has it)
|
||||||
|
@ -100,9 +100,10 @@ def check_build_for_arch(args, pkgname, arch):
|
||||||
|
|
||||||
|
|
||||||
def get_depends(args, apkbuild):
|
def get_depends(args, apkbuild):
|
||||||
"""
|
"""Alpine's abuild always builds/installs the "depends" and "makedepends" of a package
|
||||||
Alpine's abuild always builds/installs the "depends" and "makedepends"
|
before building it.
|
||||||
of a package before building it. We used to only care about "makedepends"
|
|
||||||
|
We used to only care about "makedepends"
|
||||||
and it's still possible to ignore the depends with --ignore-depends.
|
and it's still possible to ignore the depends with --ignore-depends.
|
||||||
|
|
||||||
:returns: list of dependency pkgnames (eg. ["sdl2", "sdl2_net"])
|
:returns: list of dependency pkgnames (eg. ["sdl2", "sdl2_net"])
|
||||||
|
@ -126,8 +127,7 @@ def get_depends(args, apkbuild):
|
||||||
|
|
||||||
|
|
||||||
def build_depends(args, apkbuild, arch, strict):
|
def build_depends(args, apkbuild, arch, strict):
|
||||||
"""
|
"""Get and build dependencies with verbose logging messages.
|
||||||
Get and build dependencies with verbose logging messages.
|
|
||||||
|
|
||||||
:returns: (depends, depends_built)
|
:returns: (depends, depends_built)
|
||||||
"""
|
"""
|
||||||
|
@ -173,9 +173,7 @@ def build_depends(args, apkbuild, arch, strict):
|
||||||
|
|
||||||
|
|
||||||
def is_necessary_warn_depends(args, apkbuild, arch, force, depends_built):
|
def is_necessary_warn_depends(args, apkbuild, arch, force, depends_built):
|
||||||
"""
|
"""Check if a build is necessary, and warn if it is not, but there were dependencies built.
|
||||||
Check if a build is necessary, and warn if it is not, but there were
|
|
||||||
dependencies built.
|
|
||||||
|
|
||||||
:returns: True or False
|
:returns: True or False
|
||||||
"""
|
"""
|
||||||
|
@ -197,8 +195,9 @@ def is_necessary_warn_depends(args, apkbuild, arch, force, depends_built):
|
||||||
|
|
||||||
def init_buildenv(args, apkbuild, arch, strict=False, force=False, cross=None,
|
def init_buildenv(args, apkbuild, arch, strict=False, force=False, cross=None,
|
||||||
suffix="native", skip_init_buildenv=False, src=None):
|
suffix="native", skip_init_buildenv=False, src=None):
|
||||||
"""
|
"""Build all dependencies.
|
||||||
Build all dependencies, check if we need to build at all (otherwise we've
|
|
||||||
|
Check if we need to build at all (otherwise we've
|
||||||
just initialized the build environment for nothing) and then setup the
|
just initialized the build environment for nothing) and then setup the
|
||||||
whole build environment (abuild, gcc, dependencies, cross-compiler).
|
whole build environment (abuild, gcc, dependencies, cross-compiler).
|
||||||
|
|
||||||
|
@ -245,11 +244,11 @@ def init_buildenv(args, apkbuild, arch, strict=False, force=False, cross=None,
|
||||||
|
|
||||||
|
|
||||||
def get_pkgver(original_pkgver, original_source=False, now=None):
|
def get_pkgver(original_pkgver, original_source=False, now=None):
|
||||||
"""
|
"""Get the original pkgver when using the original source.
|
||||||
Get the original pkgver when using the original source. Otherwise, get the
|
|
||||||
pkgver with an appended suffix of current date and time. For example:
|
Otherwise, get the pkgver with an appended suffix of current date and time.
|
||||||
_p20180218550502
|
For example: ``_p20180218550502``
|
||||||
When appending the suffix, an existing suffix (e.g. _git20171231) gets
|
When appending the suffix, an existing suffix (e.g. ``_git20171231``) gets
|
||||||
replaced.
|
replaced.
|
||||||
|
|
||||||
:param original_pkgver: unmodified pkgver from the package's APKBUILD.
|
:param original_pkgver: unmodified pkgver from the package's APKBUILD.
|
||||||
|
@ -268,8 +267,7 @@ def get_pkgver(original_pkgver, original_source=False, now=None):
|
||||||
|
|
||||||
|
|
||||||
def override_source(args, apkbuild, pkgver, src, suffix="native"):
|
def override_source(args, apkbuild, pkgver, src, suffix="native"):
|
||||||
"""
|
"""Mount local source inside chroot and append new functions (prepare() etc.)
|
||||||
Mount local source inside chroot and append new functions (prepare() etc.)
|
|
||||||
to the APKBUILD to make it use the local source.
|
to the APKBUILD to make it use the local source.
|
||||||
"""
|
"""
|
||||||
if not src:
|
if not src:
|
||||||
|
@ -346,8 +344,7 @@ def mount_pmaports(args, destination, suffix="native"):
|
||||||
|
|
||||||
|
|
||||||
def link_to_git_dir(args, suffix):
|
def link_to_git_dir(args, suffix):
|
||||||
"""
|
""" Make ``/home/pmos/build/.git`` point to the .git dir from pmaports.git, with a
|
||||||
Make /home/pmos/build/.git point to the .git dir from pmaports.git, with a
|
|
||||||
symlink so abuild does not fail (#1841).
|
symlink so abuild does not fail (#1841).
|
||||||
|
|
||||||
abuild expects the current working directory to be a subdirectory of a
|
abuild expects the current working directory to be a subdirectory of a
|
||||||
|
@ -457,9 +454,7 @@ def run_abuild(args, apkbuild, arch, strict=False, force=False, cross=None,
|
||||||
|
|
||||||
|
|
||||||
def finish(args, apkbuild, arch, output, strict=False, suffix="native"):
|
def finish(args, apkbuild, arch, output, strict=False, suffix="native"):
|
||||||
"""
|
"""Various finishing tasks that need to be done after a build."""
|
||||||
Various finishing tasks that need to be done after a build.
|
|
||||||
"""
|
|
||||||
# Verify output file
|
# Verify output file
|
||||||
channel = pmb.config.pmaports.read_config(args)["channel"]
|
channel = pmb.config.pmaports.read_config(args)["channel"]
|
||||||
path = f"{args.work}/packages/{channel}/{output}"
|
path = f"{args.work}/packages/{channel}/{output}"
|
||||||
|
|
|
@ -9,7 +9,7 @@ import pmb.helpers.pmaports
|
||||||
|
|
||||||
|
|
||||||
def update(args, pkgname):
|
def update(args, pkgname):
|
||||||
""" Fetch all sources and update the checksums in the APKBUILD. """
|
"""Fetch all sources and update the checksums in the APKBUILD."""
|
||||||
pmb.build.init_abuild_minimal(args)
|
pmb.build.init_abuild_minimal(args)
|
||||||
pmb.build.copy_to_buildpath(args, pkgname)
|
pmb.build.copy_to_buildpath(args, pkgname)
|
||||||
logging.info("(native) generate checksums for " + pkgname)
|
logging.info("(native) generate checksums for " + pkgname)
|
||||||
|
@ -23,7 +23,7 @@ def update(args, pkgname):
|
||||||
|
|
||||||
|
|
||||||
def verify(args, pkgname):
|
def verify(args, pkgname):
|
||||||
""" Fetch all sources and verify their checksums. """
|
"""Fetch all sources and verify their checksums."""
|
||||||
pmb.build.init_abuild_minimal(args)
|
pmb.build.init_abuild_minimal(args)
|
||||||
pmb.build.copy_to_buildpath(args, pkgname)
|
pmb.build.copy_to_buildpath(args, pkgname)
|
||||||
logging.info("(native) verify checksums for " + pkgname)
|
logging.info("(native) verify checksums for " + pkgname)
|
||||||
|
|
|
@ -13,8 +13,7 @@ import pmb.parse
|
||||||
|
|
||||||
|
|
||||||
def match_kbuild_out(word):
|
def match_kbuild_out(word):
|
||||||
"""
|
"""Look for paths in the following formats:
|
||||||
Look for paths in the following formats:
|
|
||||||
"<prefix>/<kbuild_out>/arch/<arch>/boot"
|
"<prefix>/<kbuild_out>/arch/<arch>/boot"
|
||||||
"<prefix>/<kbuild_out>/include/config/kernel.release"
|
"<prefix>/<kbuild_out>/include/config/kernel.release"
|
||||||
|
|
||||||
|
@ -48,16 +47,15 @@ def match_kbuild_out(word):
|
||||||
|
|
||||||
|
|
||||||
def find_kbuild_output_dir(function_body):
|
def find_kbuild_output_dir(function_body):
|
||||||
"""
|
"""Guess what the kernel build output directory is.
|
||||||
Guess what the kernel build output directory is. Parses each line of the
|
|
||||||
function word by word, looking for paths which contain the kbuild output
|
Parses each line of the function word by word, looking for paths which
|
||||||
directory.
|
contain the kbuild output directory.
|
||||||
|
|
||||||
:param function_body: contents of a function from the kernel APKBUILD
|
:param function_body: contents of a function from the kernel APKBUILD
|
||||||
:returns: kbuild output dir
|
:returns: kbuild output dir
|
||||||
None, when output dir is not found
|
None, when output dir is not found
|
||||||
"""
|
"""
|
||||||
|
|
||||||
guesses = []
|
guesses = []
|
||||||
for line in function_body:
|
for line in function_body:
|
||||||
for item in line.split():
|
for item in line.split():
|
||||||
|
@ -87,9 +85,7 @@ def find_kbuild_output_dir(function_body):
|
||||||
|
|
||||||
|
|
||||||
def modify_apkbuild(args, pkgname, aport):
|
def modify_apkbuild(args, pkgname, aport):
|
||||||
"""
|
"""Modify kernel APKBUILD to package build output from envkernel.sh."""
|
||||||
Modify kernel APKBUILD to package build output from envkernel.sh
|
|
||||||
"""
|
|
||||||
apkbuild_path = aport + "/APKBUILD"
|
apkbuild_path = aport + "/APKBUILD"
|
||||||
apkbuild = pmb.parse.apkbuild(apkbuild_path)
|
apkbuild = pmb.parse.apkbuild(apkbuild_path)
|
||||||
if os.path.exists(args.work + "/aportgen"):
|
if os.path.exists(args.work + "/aportgen"):
|
||||||
|
@ -174,10 +170,7 @@ def run_abuild(args, pkgname, arch, apkbuild_path, kbuild_out):
|
||||||
|
|
||||||
|
|
||||||
def package_kernel(args):
|
def package_kernel(args):
|
||||||
"""
|
"""Frontend for 'pmbootstrap build --envkernel': creates a package from envkernel output."""
|
||||||
Frontend for 'pmbootstrap build --envkernel': creates a package from
|
|
||||||
envkernel output.
|
|
||||||
"""
|
|
||||||
pkgname = args.packages[0]
|
pkgname = args.packages[0]
|
||||||
if len(args.packages) > 1 or not pkgname.startswith("linux-"):
|
if len(args.packages) > 1 or not pkgname.startswith("linux-"):
|
||||||
raise RuntimeError("--envkernel needs exactly one linux-* package as "
|
raise RuntimeError("--envkernel needs exactly one linux-* package as "
|
||||||
|
|
|
@ -14,8 +14,7 @@ import pmb.parse.arch
|
||||||
|
|
||||||
|
|
||||||
def init_abuild_minimal(args, suffix="native"):
|
def init_abuild_minimal(args, suffix="native"):
|
||||||
""" Initialize a minimal chroot with abuild where one can do
|
"""Initialize a minimal chroot with abuild where one can do 'abuild checksum'."""
|
||||||
'abuild checksum'. """
|
|
||||||
marker = f"{args.work}/chroot_{suffix}/tmp/pmb_chroot_abuild_init_done"
|
marker = f"{args.work}/chroot_{suffix}/tmp/pmb_chroot_abuild_init_done"
|
||||||
if os.path.exists(marker):
|
if os.path.exists(marker):
|
||||||
return
|
return
|
||||||
|
@ -35,7 +34,7 @@ def init_abuild_minimal(args, suffix="native"):
|
||||||
|
|
||||||
|
|
||||||
def init(args, suffix="native"):
|
def init(args, suffix="native"):
|
||||||
""" Initialize a chroot for building packages with abuild. """
|
"""Initialize a chroot for building packages with abuild."""
|
||||||
marker = f"{args.work}/chroot_{suffix}/tmp/pmb_chroot_build_init_done"
|
marker = f"{args.work}/chroot_{suffix}/tmp/pmb_chroot_build_init_done"
|
||||||
if os.path.exists(marker):
|
if os.path.exists(marker):
|
||||||
return
|
return
|
||||||
|
|
|
@ -15,13 +15,15 @@ import pmb.parse
|
||||||
|
|
||||||
|
|
||||||
def get_arch(apkbuild):
|
def get_arch(apkbuild):
|
||||||
"""
|
"""Take the architecture from the APKBUILD or complain if it's ambiguous.
|
||||||
Take the architecture from the APKBUILD or complain if it's ambiguous. This
|
|
||||||
function only gets called if --arch is not set.
|
This function only gets called if --arch is not set.
|
||||||
|
|
||||||
:param apkbuild: looks like: {"pkgname": "linux-...",
|
:param apkbuild: looks like: {"pkgname": "linux-...",
|
||||||
"arch": ["x86_64", "armhf", "aarch64"]}
|
"arch": ["x86_64", "armhf", "aarch64"]}
|
||||||
or: {"pkgname": "linux-...", "arch": ["armhf"]}
|
|
||||||
|
or: {"pkgname": "linux-...", "arch": ["armhf"]}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
pkgname = apkbuild["pkgname"]
|
pkgname = apkbuild["pkgname"]
|
||||||
|
|
||||||
|
@ -40,8 +42,8 @@ def get_arch(apkbuild):
|
||||||
|
|
||||||
|
|
||||||
def get_outputdir(args, pkgname, apkbuild):
|
def get_outputdir(args, pkgname, apkbuild):
|
||||||
"""
|
"""Get the folder for the kernel compilation output.
|
||||||
Get the folder for the kernel compilation output.
|
|
||||||
For most APKBUILDs, this is $builddir. But some older ones still use
|
For most APKBUILDs, this is $builddir. But some older ones still use
|
||||||
$srcdir/build (see the discussion in #1551).
|
$srcdir/build (see the discussion in #1551).
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -43,9 +43,9 @@ def copy_to_buildpath(args, package, suffix="native"):
|
||||||
|
|
||||||
|
|
||||||
def is_necessary(args, arch, apkbuild, indexes=None):
|
def is_necessary(args, arch, apkbuild, indexes=None):
|
||||||
"""
|
"""Check if the package has already been built.
|
||||||
Check if the package has already been built. Compared to abuild's check,
|
|
||||||
this check also works for different architectures.
|
Compared to abuild's check, this check also works for different architectures.
|
||||||
|
|
||||||
:param arch: package target architecture
|
:param arch: package target architecture
|
||||||
:param apkbuild: from pmb.parse.apkbuild()
|
:param apkbuild: from pmb.parse.apkbuild()
|
||||||
|
@ -89,8 +89,7 @@ def is_necessary(args, arch, apkbuild, indexes=None):
|
||||||
|
|
||||||
|
|
||||||
def index_repo(args, arch=None):
|
def index_repo(args, arch=None):
|
||||||
"""
|
"""Recreate the APKINDEX.tar.gz for a specific repo, and clear the parsing
|
||||||
Recreate the APKINDEX.tar.gz for a specific repo, and clear the parsing
|
|
||||||
cache for that file for the current pmbootstrap session (to prevent
|
cache for that file for the current pmbootstrap session (to prevent
|
||||||
rebuilding packages twice, in case the rebuild takes less than a second).
|
rebuilding packages twice, in case the rebuild takes less than a second).
|
||||||
|
|
||||||
|
@ -126,8 +125,7 @@ def index_repo(args, arch=None):
|
||||||
|
|
||||||
|
|
||||||
def configure_abuild(args, suffix, verify=False):
|
def configure_abuild(args, suffix, verify=False):
|
||||||
"""
|
"""Set the correct JOBS count in ``abuild.conf``.
|
||||||
Set the correct JOBS count in abuild.conf
|
|
||||||
|
|
||||||
:param verify: internally used to test if changing the config has worked.
|
:param verify: internally used to test if changing the config has worked.
|
||||||
"""
|
"""
|
||||||
|
@ -152,8 +150,7 @@ def configure_abuild(args, suffix, verify=False):
|
||||||
|
|
||||||
|
|
||||||
def configure_ccache(args, suffix="native", verify=False):
|
def configure_ccache(args, suffix="native", verify=False):
|
||||||
"""
|
"""Set the maximum ccache size.
|
||||||
Set the maximum ccache size
|
|
||||||
|
|
||||||
:param verify: internally used to test if changing the config has worked.
|
:param verify: internally used to test if changing the config has worked.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -256,13 +256,15 @@ def installed(args, suffix="native"):
|
||||||
|
|
||||||
:returns: a dictionary with the following structure:
|
:returns: a dictionary with the following structure:
|
||||||
{ "postmarketos-mkinitfs":
|
{ "postmarketos-mkinitfs":
|
||||||
{
|
{
|
||||||
"pkgname": "postmarketos-mkinitfs"
|
"pkgname": "postmarketos-mkinitfs"
|
||||||
"version": "0.0.4-r10",
|
"version": "0.0.4-r10",
|
||||||
"depends": ["busybox-extras", "lddtree", ...],
|
"depends": ["busybox-extras", "lddtree", ...],
|
||||||
"provides": ["mkinitfs=0.0.1"]
|
"provides": ["mkinitfs=0.0.1"]
|
||||||
}, ...
|
}, ...
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
path = f"{args.work}/chroot_{suffix}/lib/apk/db/installed"
|
path = f"{args.work}/chroot_{suffix}/lib/apk/db/installed"
|
||||||
return pmb.parse.apkindex.parse(path, False)
|
return pmb.parse.apkindex.parse(path, False)
|
||||||
|
|
|
@ -13,12 +13,12 @@ def get_ci_scripts(topdir):
|
||||||
""" Find 'pmbootstrap ci'-compatible scripts inside a git repository, and
|
""" Find 'pmbootstrap ci'-compatible scripts inside a git repository, and
|
||||||
parse their metadata (description, options). The reference is at:
|
parse their metadata (description, options). The reference is at:
|
||||||
https://postmarketos.org/pmb-ci
|
https://postmarketos.org/pmb-ci
|
||||||
:param topdir: top directory of the git repository, get it with:
|
|
||||||
pmb.helpers.git.get_topdir()
|
:param topdir: top directory of the git repository, get it with: pmb.helpers.git.get_topdir()
|
||||||
|
|
||||||
:returns: a dict of CI scripts found in the git repository, e.g.
|
:returns: a dict of CI scripts found in the git repository, e.g.
|
||||||
{"ruff": {"description": "lint all python scripts",
|
{"ruff": {"description": "lint all python scripts", "options": []}, ...}
|
||||||
"options": []},
|
"""
|
||||||
...} """
|
|
||||||
ret = {}
|
ret = {}
|
||||||
for script in glob.glob(f"{topdir}/.ci/*.sh"):
|
for script in glob.glob(f"{topdir}/.ci/*.sh"):
|
||||||
is_pmb_ci_script = False
|
is_pmb_ci_script = False
|
||||||
|
@ -59,9 +59,13 @@ def sort_scripts_by_speed(scripts):
|
||||||
""" Order the scripts, so fast scripts run before slow scripts. Whether a
|
""" Order the scripts, so fast scripts run before slow scripts. Whether a
|
||||||
script is fast or not is determined by the '# Options: slow' comment in
|
script is fast or not is determined by the '# Options: slow' comment in
|
||||||
the file.
|
the file.
|
||||||
:param scripts: return of get_ci_scripts()
|
|
||||||
:returns: same format as get_ci_scripts(), but as ordered dict with
|
:param scripts: return of get_ci_scripts()
|
||||||
fast scripts before slow scripts """
|
|
||||||
|
:returns: same format as get_ci_scripts(), but as ordered dict with
|
||||||
|
fast scripts before slow scripts
|
||||||
|
|
||||||
|
"""
|
||||||
ret = collections.OrderedDict()
|
ret = collections.OrderedDict()
|
||||||
|
|
||||||
# Fast scripts first
|
# Fast scripts first
|
||||||
|
@ -81,8 +85,12 @@ def sort_scripts_by_speed(scripts):
|
||||||
def ask_which_scripts_to_run(scripts_available):
|
def ask_which_scripts_to_run(scripts_available):
|
||||||
""" Display an interactive prompt about which of the scripts the user
|
""" Display an interactive prompt about which of the scripts the user
|
||||||
wishes to run, or all of them.
|
wishes to run, or all of them.
|
||||||
:param scripts_available: same format as get_ci_scripts()
|
|
||||||
:returns: either full scripts_available (all selected), or a subset """
|
:param scripts_available: same format as get_ci_scripts()
|
||||||
|
|
||||||
|
:returns: either full scripts_available (all selected), or a subset
|
||||||
|
|
||||||
|
"""
|
||||||
count = len(scripts_available.items())
|
count = len(scripts_available.items())
|
||||||
choices = ["all"]
|
choices = ["all"]
|
||||||
|
|
||||||
|
@ -107,8 +115,11 @@ def ask_which_scripts_to_run(scripts_available):
|
||||||
def copy_git_repo_to_chroot(args, topdir):
|
def copy_git_repo_to_chroot(args, topdir):
|
||||||
""" Create a tarball of the git repo (including unstaged changes and new
|
""" Create a tarball of the git repo (including unstaged changes and new
|
||||||
files) and extract it in chroot_native.
|
files) and extract it in chroot_native.
|
||||||
:param topdir: top directory of the git repository, get it with:
|
|
||||||
pmb.helpers.git.get_topdir() """
|
:param topdir: top directory of the git repository, get it with:
|
||||||
|
pmb.helpers.git.get_topdir()
|
||||||
|
|
||||||
|
"""
|
||||||
pmb.chroot.init(args)
|
pmb.chroot.init(args)
|
||||||
tarball_path = f"{args.work}/chroot_native/tmp/git.tar.gz"
|
tarball_path = f"{args.work}/chroot_native/tmp/git.tar.gz"
|
||||||
files = pmb.helpers.git.get_files(args, topdir)
|
files = pmb.helpers.git.get_files(args, topdir)
|
||||||
|
@ -132,9 +143,13 @@ def run_scripts(args, topdir, scripts):
|
||||||
""" Run one of the given scripts after another, either natively or in a
|
""" Run one of the given scripts after another, either natively or in a
|
||||||
chroot. Display a progress message and stop on error (without printing
|
chroot. Display a progress message and stop on error (without printing
|
||||||
a python stack trace).
|
a python stack trace).
|
||||||
:param topdir: top directory of the git repository, get it with:
|
|
||||||
pmb.helpers.git.get_topdir()
|
:param topdir: top directory of the git repository, get it with:
|
||||||
:param scripts: return of get_ci_scripts() """
|
pmb.helpers.git.get_topdir()
|
||||||
|
|
||||||
|
:param scripts: return of get_ci_scripts()
|
||||||
|
|
||||||
|
"""
|
||||||
steps = len(scripts)
|
steps = len(scripts)
|
||||||
step = 0
|
step = 0
|
||||||
repo_copied = False
|
repo_copied = False
|
||||||
|
|
|
@ -559,7 +559,7 @@ kconfig_options_containers = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
">=3.13": {
|
">=3.13": {
|
||||||
"all": { # needed for iptables-nft (used by docker,tailscale)
|
"all": { # needed for iptables-nft (used by docker,tailscale)
|
||||||
"NFT_COMPAT": True,
|
"NFT_COMPAT": True,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -831,17 +831,17 @@ deviceinfo_attributes = [
|
||||||
"flash_heimdall_partition_kernel",
|
"flash_heimdall_partition_kernel",
|
||||||
"flash_heimdall_partition_initfs",
|
"flash_heimdall_partition_initfs",
|
||||||
"flash_heimdall_partition_rootfs",
|
"flash_heimdall_partition_rootfs",
|
||||||
"flash_heimdall_partition_system", # deprecated
|
"flash_heimdall_partition_system", # deprecated
|
||||||
"flash_heimdall_partition_vbmeta",
|
"flash_heimdall_partition_vbmeta",
|
||||||
"flash_heimdall_partition_dtbo",
|
"flash_heimdall_partition_dtbo",
|
||||||
"flash_fastboot_partition_kernel",
|
"flash_fastboot_partition_kernel",
|
||||||
"flash_fastboot_partition_rootfs",
|
"flash_fastboot_partition_rootfs",
|
||||||
"flash_fastboot_partition_system", # deprecated
|
"flash_fastboot_partition_system", # deprecated
|
||||||
"flash_fastboot_partition_vbmeta",
|
"flash_fastboot_partition_vbmeta",
|
||||||
"flash_fastboot_partition_dtbo",
|
"flash_fastboot_partition_dtbo",
|
||||||
"flash_rk_partition_kernel",
|
"flash_rk_partition_kernel",
|
||||||
"flash_rk_partition_rootfs",
|
"flash_rk_partition_rootfs",
|
||||||
"flash_rk_partition_system", # deprecated
|
"flash_rk_partition_system", # deprecated
|
||||||
"flash_mtkclient_partition_kernel",
|
"flash_mtkclient_partition_kernel",
|
||||||
"flash_mtkclient_partition_rootfs",
|
"flash_mtkclient_partition_rootfs",
|
||||||
"flash_mtkclient_partition_vbmeta",
|
"flash_mtkclient_partition_vbmeta",
|
||||||
|
@ -851,7 +851,7 @@ deviceinfo_attributes = [
|
||||||
"generate_bootimg",
|
"generate_bootimg",
|
||||||
"header_version",
|
"header_version",
|
||||||
"bootimg_qcdt",
|
"bootimg_qcdt",
|
||||||
"bootimg_mtk_mkimage", # deprecated
|
"bootimg_mtk_mkimage", # deprecated
|
||||||
"bootimg_mtk_label_kernel",
|
"bootimg_mtk_label_kernel",
|
||||||
"bootimg_mtk_label_ramdisk",
|
"bootimg_mtk_label_ramdisk",
|
||||||
"bootimg_dtb_second",
|
"bootimg_dtb_second",
|
||||||
|
|
|
@ -35,8 +35,7 @@ def require_programs():
|
||||||
|
|
||||||
|
|
||||||
def ask_for_username(args):
|
def ask_for_username(args):
|
||||||
"""
|
"""Ask for a reasonable username for the non-root user.
|
||||||
Ask for a reasonable username for the non-root user.
|
|
||||||
|
|
||||||
:returns: the username
|
:returns: the username
|
||||||
"""
|
"""
|
||||||
|
@ -52,13 +51,12 @@ def ask_for_username(args):
|
||||||
|
|
||||||
|
|
||||||
def ask_for_work_path(args):
|
def ask_for_work_path(args):
|
||||||
"""
|
"""Ask for the work path, until we can create it (when it does not exist) and write into it.
|
||||||
Ask for the work path, until we can create it (when it does not exist) and
|
|
||||||
write into it.
|
|
||||||
:returns: (path, exists)
|
:returns: (path, exists)
|
||||||
* path: is the full path, with expanded ~ sign
|
* path: is the full path, with expanded ~ sign
|
||||||
* exists: is False when the folder did not exist before we tested
|
* exists: is False when the folder did not exist before we tested whether we can create it
|
||||||
whether we can create it
|
|
||||||
"""
|
"""
|
||||||
logging.info("Location of the 'work' path. Multiple chroots"
|
logging.info("Location of the 'work' path. Multiple chroots"
|
||||||
" (native, device arch, device rootfs) will be created"
|
" (native, device arch, device rootfs) will be created"
|
||||||
|
@ -100,10 +98,12 @@ def ask_for_work_path(args):
|
||||||
|
|
||||||
|
|
||||||
def ask_for_channel(args):
|
def ask_for_channel(args):
|
||||||
""" Ask for the postmarketOS release channel. The channel dictates, which
|
"""Ask for the postmarketOS release channel.
|
||||||
pmaports branch pmbootstrap will check out, and which repository URLs
|
The channel dictates, which pmaports branch pmbootstrap will check out,
|
||||||
will be used when initializing chroots.
|
and which repository URLs will be used when initializing chroots.
|
||||||
:returns: channel name (e.g. "edge", "v21.03") """
|
|
||||||
|
:returns: channel name (e.g. "edge", "v21.03")
|
||||||
|
"""
|
||||||
channels_cfg = pmb.helpers.git.parse_channels_cfg(args)
|
channels_cfg = pmb.helpers.git.parse_channels_cfg(args)
|
||||||
count = len(channels_cfg["channels"])
|
count = len(channels_cfg["channels"])
|
||||||
|
|
||||||
|
@ -257,9 +257,7 @@ def ask_for_timezone(args):
|
||||||
|
|
||||||
|
|
||||||
def ask_for_provider_select(args, apkbuild, providers_cfg):
|
def ask_for_provider_select(args, apkbuild, providers_cfg):
|
||||||
"""
|
"""Ask for selectable providers that are specified using "_pmb_select" in a APKBUILD.
|
||||||
Ask for selectable providers that are specified using "_pmb_select"
|
|
||||||
in a APKBUILD.
|
|
||||||
|
|
||||||
:param apkbuild: the APKBUILD with the _pmb_select
|
:param apkbuild: the APKBUILD with the _pmb_select
|
||||||
:param providers_cfg: the configuration section with previously selected
|
:param providers_cfg: the configuration section with previously selected
|
||||||
|
@ -314,8 +312,7 @@ def ask_for_provider_select(args, apkbuild, providers_cfg):
|
||||||
|
|
||||||
|
|
||||||
def ask_for_provider_select_pkg(args, pkgname, providers_cfg):
|
def ask_for_provider_select_pkg(args, pkgname, providers_cfg):
|
||||||
"""
|
"""Look up the APKBUILD for the specified pkgname and ask for selectable
|
||||||
Look up the APKBUILD for the specified pkgname and ask for selectable
|
|
||||||
providers that are specified using "_pmb_select".
|
providers that are specified using "_pmb_select".
|
||||||
|
|
||||||
:param pkgname: name of the package to search APKBUILD for
|
:param pkgname: name of the package to search APKBUILD for
|
||||||
|
@ -331,12 +328,14 @@ def ask_for_provider_select_pkg(args, pkgname, providers_cfg):
|
||||||
|
|
||||||
|
|
||||||
def ask_for_device_kernel(args, device):
|
def ask_for_device_kernel(args, device):
|
||||||
"""
|
"""Ask for the kernel that should be used with the device.
|
||||||
Ask for the kernel that should be used with the device.
|
|
||||||
|
|
||||||
:param device: code name, e.g. "lg-mako"
|
:param device: code name, e.g. "lg-mako"
|
||||||
|
|
||||||
:returns: None if the kernel is hardcoded in depends without subpackages
|
:returns: None if the kernel is hardcoded in depends without subpackages
|
||||||
|
|
||||||
:returns: kernel type ("downstream", "stable", "mainline", ...)
|
:returns: kernel type ("downstream", "stable", "mainline", ...)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Get kernels
|
# Get kernels
|
||||||
kernels = pmb.parse._apkbuild.kernels(args, device)
|
kernels = pmb.parse._apkbuild.kernels(args, device)
|
||||||
|
|
|
@ -4,8 +4,7 @@ import pmb.config
|
||||||
|
|
||||||
|
|
||||||
def merge_with_args(args):
|
def merge_with_args(args):
|
||||||
"""
|
"""We have the internal config (pmb/config/__init__.py) and the user config
|
||||||
We have the internal config (pmb/config/__init__.py) and the user config
|
|
||||||
(usually ~/.config/pmbootstrap.cfg, can be changed with the '-c'
|
(usually ~/.config/pmbootstrap.cfg, can be changed with the '-c'
|
||||||
parameter).
|
parameter).
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ def read_config_repos(args):
|
||||||
|
|
||||||
|
|
||||||
def read_config(args):
|
def read_config(args):
|
||||||
""" Read and verify pmaports.cfg. """
|
"""Read and verify pmaports.cfg."""
|
||||||
# Try cache first
|
# Try cache first
|
||||||
cache_key = "pmb.config.pmaports.read_config"
|
cache_key = "pmb.config.pmaports.read_config"
|
||||||
if pmb.helpers.other.cache[cache_key]:
|
if pmb.helpers.other.cache[cache_key]:
|
||||||
|
@ -140,12 +140,16 @@ def read_config(args):
|
||||||
|
|
||||||
|
|
||||||
def read_config_channel(args):
|
def read_config_channel(args):
|
||||||
""" Get the properties of the currently active channel in pmaports.git,
|
"""Get the properties of the currently active channel in pmaports.git.
|
||||||
as specified in channels.cfg (https://postmarketos.org/channels.cfg).
|
|
||||||
:returns: {"description: ...,
|
As specified in channels.cfg (https://postmarketos.org/channels.cfg).
|
||||||
"branch_pmaports": ...,
|
|
||||||
"branch_aports": ...,
|
:returns: {"description: ...,
|
||||||
"mirrordir_alpine": ...} """
|
"branch_pmaports": ...,
|
||||||
|
"branch_aports": ...,
|
||||||
|
"mirrordir_alpine": ...}
|
||||||
|
|
||||||
|
"""
|
||||||
channel = read_config(args)["channel"]
|
channel = read_config(args)["channel"]
|
||||||
channels_cfg = pmb.helpers.git.parse_channels_cfg(args)
|
channels_cfg = pmb.helpers.git.parse_channels_cfg(args)
|
||||||
|
|
||||||
|
@ -179,9 +183,12 @@ def init(args):
|
||||||
|
|
||||||
|
|
||||||
def switch_to_channel_branch(args, channel_new):
|
def switch_to_channel_branch(args, channel_new):
|
||||||
""" Checkout the channel's branch in pmaports.git.
|
"""Checkout the channel's branch in pmaports.git.
|
||||||
:channel_new: channel name (e.g. "edge", "v21.03")
|
|
||||||
:returns: True if another branch was checked out, False otherwise """
|
:channel_new: channel name (e.g. "edge", "v21.03")
|
||||||
|
|
||||||
|
:returns: True if another branch was checked out, False otherwise
|
||||||
|
"""
|
||||||
# Check current pmaports branch channel
|
# Check current pmaports branch channel
|
||||||
channel_current = read_config(args)["channel"]
|
channel_current = read_config(args)["channel"]
|
||||||
if channel_current == channel_new:
|
if channel_current == channel_new:
|
||||||
|
|
|
@ -8,12 +8,11 @@ from typing import Optional
|
||||||
|
|
||||||
@lru_cache()
|
@lru_cache()
|
||||||
def which_sudo() -> Optional[str]:
|
def which_sudo() -> Optional[str]:
|
||||||
"""Returns a command required to run commands as root, if any.
|
"""Return a command required to run commands as root, if any.
|
||||||
|
|
||||||
Find whether sudo or doas is installed for commands that require root.
|
Find whether sudo or doas is installed for commands that require root.
|
||||||
Allows user to override preferred sudo with PMB_SUDO env variable.
|
Allows user to override preferred sudo with PMB_SUDO env variable.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if os.getuid() == 0:
|
if os.getuid() == 0:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import pmb.config.pmaports
|
||||||
|
|
||||||
|
|
||||||
def chroot_save_init(args, suffix):
|
def chroot_save_init(args, suffix):
|
||||||
""" Save the chroot initialization data in $WORK/workdir.cfg. """
|
"""Save the chroot initialization data in $WORK/workdir.cfg."""
|
||||||
# Read existing cfg
|
# Read existing cfg
|
||||||
cfg = configparser.ConfigParser()
|
cfg = configparser.ConfigParser()
|
||||||
path = args.work + "/workdir.cfg"
|
path = args.work + "/workdir.cfg"
|
||||||
|
@ -88,10 +88,12 @@ def chroot_check_channel(args, suffix):
|
||||||
|
|
||||||
|
|
||||||
def clean(args):
|
def clean(args):
|
||||||
""" Remove obsolete data data from workdir.cfg.
|
"""Remove obsolete data data from workdir.cfg.
|
||||||
:returns: None if workdir does not exist,
|
|
||||||
True if config was rewritten,
|
:returns: None if workdir does not exist,
|
||||||
False if config did not change """
|
True if config was rewritten,
|
||||||
|
False if config did not change
|
||||||
|
"""
|
||||||
# Skip if workdir.cfg doesn't exist
|
# Skip if workdir.cfg doesn't exist
|
||||||
path = args.work + "/workdir.cfg"
|
path = args.work + "/workdir.cfg"
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
|
|
|
@ -11,8 +11,7 @@ import pmb.parse.version
|
||||||
|
|
||||||
|
|
||||||
def _run(args, command, chroot=False, suffix="native", output="log"):
|
def _run(args, command, chroot=False, suffix="native", output="log"):
|
||||||
"""
|
"""Run a command.
|
||||||
Run a command.
|
|
||||||
|
|
||||||
:param command: command in list form
|
:param command: command in list form
|
||||||
:param chroot: whether to run the command inside the chroot or on the host
|
:param chroot: whether to run the command inside the chroot or on the host
|
||||||
|
@ -29,8 +28,7 @@ def _run(args, command, chroot=False, suffix="native", output="log"):
|
||||||
|
|
||||||
|
|
||||||
def _prepare_fifo(args, chroot=False, suffix="native"):
|
def _prepare_fifo(args, chroot=False, suffix="native"):
|
||||||
"""
|
"""Prepare the progress fifo for reading / writing.
|
||||||
Prepare the progress fifo for reading / writing.
|
|
||||||
|
|
||||||
:param chroot: whether to run the command inside the chroot or on the host
|
:param chroot: whether to run the command inside the chroot or on the host
|
||||||
:param suffix: chroot suffix. Only applies if the "chroot" parameter is
|
:param suffix: chroot suffix. Only applies if the "chroot" parameter is
|
||||||
|
@ -53,9 +51,7 @@ def _prepare_fifo(args, chroot=False, suffix="native"):
|
||||||
|
|
||||||
|
|
||||||
def _create_command_with_progress(command, fifo):
|
def _create_command_with_progress(command, fifo):
|
||||||
"""
|
"""Build a full apk command from a subcommand, set up to redirect progress into a fifo.
|
||||||
Build a full apk command from a subcommand, set up to redirect progress
|
|
||||||
into a fifo.
|
|
||||||
|
|
||||||
:param command: apk subcommand in list form
|
:param command: apk subcommand in list form
|
||||||
:param fifo: path of the fifo
|
:param fifo: path of the fifo
|
||||||
|
@ -69,8 +65,7 @@ def _create_command_with_progress(command, fifo):
|
||||||
|
|
||||||
|
|
||||||
def _compute_progress(line):
|
def _compute_progress(line):
|
||||||
"""
|
"""Compute the progress as a number between 0 and 1.
|
||||||
Compute the progress as a number between 0 and 1.
|
|
||||||
|
|
||||||
:param line: line as read from the progress fifo
|
:param line: line as read from the progress fifo
|
||||||
:returns: progress as a number between 0 and 1
|
:returns: progress as a number between 0 and 1
|
||||||
|
@ -86,8 +81,7 @@ def _compute_progress(line):
|
||||||
|
|
||||||
|
|
||||||
def apk_with_progress(args, command, chroot=False, suffix="native"):
|
def apk_with_progress(args, command, chroot=False, suffix="native"):
|
||||||
"""
|
"""Run an apk subcommand while printing a progress bar to STDOUT.
|
||||||
Run an apk subcommand while printing a progress bar to STDOUT.
|
|
||||||
|
|
||||||
:param command: apk subcommand in list form
|
:param command: apk subcommand in list form
|
||||||
:param chroot: whether to run commands inside the chroot or on the host
|
:param chroot: whether to run commands inside the chroot or on the host
|
||||||
|
@ -112,10 +106,10 @@ def apk_with_progress(args, command, chroot=False, suffix="native"):
|
||||||
|
|
||||||
|
|
||||||
def check_outdated(args, version_installed, action_msg):
|
def check_outdated(args, version_installed, action_msg):
|
||||||
"""
|
"""Check if the provided alpine version is outdated.
|
||||||
Check if the provided alpine version is outdated, depending on the alpine
|
|
||||||
mirrordir (edge, v3.12, ...) related to currently checked out pmaports
|
This depends on the alpine mirrordir (edge, v3.12, ...) related to currently checked out
|
||||||
branch.
|
pmaports branch.
|
||||||
|
|
||||||
:param version_installed: currently installed apk version, e.g. "2.12.1-r0"
|
:param version_installed: currently installed apk version, e.g. "2.12.1-r0"
|
||||||
:param action_msg: string explaining what the user should do to resolve
|
:param action_msg: string explaining what the user should do to resolve
|
||||||
|
|
|
@ -96,9 +96,8 @@ def get_package_version_info_gitlab(gitlab_host: str, repo_name: str,
|
||||||
|
|
||||||
|
|
||||||
def upgrade_git_package(args, pkgname: str, package) -> None:
|
def upgrade_git_package(args, pkgname: str, package) -> None:
|
||||||
"""
|
"""Update _commit/pkgver/pkgrel in a git-APKBUILD (or pretend to do it if args.dry is set).
|
||||||
Update _commit/pkgver/pkgrel in a git-APKBUILD (or pretend to do it if
|
|
||||||
args.dry is set).
|
|
||||||
:param pkgname: the package name
|
:param pkgname: the package name
|
||||||
:param package: a dict containing package information
|
:param package: a dict containing package information
|
||||||
"""
|
"""
|
||||||
|
@ -254,8 +253,7 @@ def upgrade_stable_package(args, pkgname: str, package) -> None:
|
||||||
|
|
||||||
|
|
||||||
def upgrade(args, pkgname, git=True, stable=True) -> None:
|
def upgrade(args, pkgname, git=True, stable=True) -> None:
|
||||||
"""
|
"""Find new versions of a single package and upgrade it.
|
||||||
Find new versions of a single package and upgrade it.
|
|
||||||
|
|
||||||
:param pkgname: the name of the package
|
:param pkgname: the name of the package
|
||||||
:param git: True if git packages should be upgraded
|
:param git: True if git packages should be upgraded
|
||||||
|
@ -275,9 +273,7 @@ def upgrade(args, pkgname, git=True, stable=True) -> None:
|
||||||
|
|
||||||
|
|
||||||
def upgrade_all(args) -> None:
|
def upgrade_all(args) -> None:
|
||||||
"""
|
"""Upgrade all packages, based on args.all, args.all_git and args.all_stable."""
|
||||||
Upgrade all packages, based on args.all, args.all_git and args.all_stable.
|
|
||||||
"""
|
|
||||||
for pkgname in pmb.helpers.pmaports.get_list(args):
|
for pkgname in pmb.helpers.pmaports.get_list(args):
|
||||||
# Always ignore postmarketOS-specific packages that have no upstream
|
# Always ignore postmarketOS-specific packages that have no upstream
|
||||||
# source
|
# source
|
||||||
|
|
|
@ -5,9 +5,9 @@ import os
|
||||||
import pmb.config
|
import pmb.config
|
||||||
import pmb.helpers.git
|
import pmb.helpers.git
|
||||||
|
|
||||||
""" This file constructs the args variable, which is passed to almost all
|
"""This file constructs the args variable, which is passed to almost all
|
||||||
functions in the pmbootstrap code base. Here's a listing of the kind of
|
functions in the pmbootstrap code base. Here's a listing of the kind of
|
||||||
information it stores.
|
information it stores.
|
||||||
|
|
||||||
1. Argparse
|
1. Argparse
|
||||||
Variables directly from command line argument parsing (see
|
Variables directly from command line argument parsing (see
|
||||||
|
@ -44,16 +44,16 @@ import pmb.helpers.git
|
||||||
|
|
||||||
|
|
||||||
def fix_mirrors_postmarketos(args):
|
def fix_mirrors_postmarketos(args):
|
||||||
""" Fix args.mirrors_postmarketos when it is supposed to be empty or the
|
"""Fix args.mirrors_postmarketos when it is supposed to be empty or the default value.
|
||||||
default value.
|
|
||||||
|
|
||||||
In pmb/parse/arguments.py, we set the -mp/--mirror-pmOS argument to
|
In pmb/parse/arguments.py, we set the -mp/--mirror-pmOS argument to
|
||||||
action="append" and start off with an empty list. That way, users can
|
action="append" and start off with an empty list. That way, users can
|
||||||
specify multiple custom mirrors by specifying -mp multiple times on the
|
specify multiple custom mirrors by specifying -mp multiple times on the
|
||||||
command line. Here we fix the default and no mirrors case.
|
command line. Here we fix the default and no mirrors case.
|
||||||
|
|
||||||
NOTE: we don't use nargs="+", because it does not play nicely with
|
NOTE: we don't use nargs="+", because it does not play nicely with
|
||||||
subparsers: <https://bugs.python.org/issue9338> """
|
subparsers: <https://bugs.python.org/issue9338>
|
||||||
|
"""
|
||||||
# -mp not specified: use default mirrors
|
# -mp not specified: use default mirrors
|
||||||
if not args.mirrors_postmarketos:
|
if not args.mirrors_postmarketos:
|
||||||
cfg = pmb.config.load(args)
|
cfg = pmb.config.load(args)
|
||||||
|
@ -66,19 +66,21 @@ def fix_mirrors_postmarketos(args):
|
||||||
|
|
||||||
|
|
||||||
def check_pmaports_path(args):
|
def check_pmaports_path(args):
|
||||||
""" Make sure that args.aports exists when it was overridden by --aports.
|
"""Make sure that args.aports exists when it was overridden by --aports.
|
||||||
Without this check, 'pmbootstrap init' would start cloning the
|
|
||||||
pmaports into the default folder when args.aports does not exist. """
|
Without this check, 'pmbootstrap init' would start cloning the
|
||||||
|
pmaports into the default folder when args.aports does not exist.
|
||||||
|
"""
|
||||||
if args.from_argparse.aports and not os.path.exists(args.aports):
|
if args.from_argparse.aports and not os.path.exists(args.aports):
|
||||||
raise ValueError("pmaports path (specified with --aports) does"
|
raise ValueError("pmaports path (specified with --aports) does"
|
||||||
" not exist: " + args.aports)
|
" not exist: " + args.aports)
|
||||||
|
|
||||||
|
|
||||||
def replace_placeholders(args):
|
def replace_placeholders(args):
|
||||||
""" Replace $WORK and ~ (for path variables) in variables from any config
|
"""Replace $WORK and ~ (for path variables) in variables from any config.
|
||||||
(user's config file, default config settings or config parameters
|
|
||||||
specified on commandline) """
|
|
||||||
|
|
||||||
|
(user's config file, default config settings or config parameters specified on commandline)
|
||||||
|
"""
|
||||||
# Replace $WORK
|
# Replace $WORK
|
||||||
for key, value in pmb.config.defaults.items():
|
for key, value in pmb.config.defaults.items():
|
||||||
if key not in args:
|
if key not in args:
|
||||||
|
@ -94,7 +96,7 @@ def replace_placeholders(args):
|
||||||
|
|
||||||
|
|
||||||
def add_deviceinfo(args):
|
def add_deviceinfo(args):
|
||||||
""" Add and verify the deviceinfo (only after initialization) """
|
"""Add and verify the deviceinfo (only after initialization)"""
|
||||||
setattr(args, "deviceinfo", pmb.parse.deviceinfo(args))
|
setattr(args, "deviceinfo", pmb.parse.deviceinfo(args))
|
||||||
arch = args.deviceinfo["arch"]
|
arch = args.deviceinfo["arch"]
|
||||||
if (arch != pmb.config.arch_native and
|
if (arch != pmb.config.arch_native and
|
||||||
|
@ -126,7 +128,7 @@ def init(args):
|
||||||
|
|
||||||
|
|
||||||
def update_work(args, work):
|
def update_work(args, work):
|
||||||
""" Update the work path in args.work and wherever $WORK was used. """
|
"""Update the work path in args.work and wherever $WORK was used."""
|
||||||
# Start with the unmodified args from argparse
|
# Start with the unmodified args from argparse
|
||||||
args_new = copy.deepcopy(args.from_argparse)
|
args_new = copy.deepcopy(args.from_argparse)
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,10 @@ import pmb.config
|
||||||
|
|
||||||
|
|
||||||
class ReadlineTabCompleter:
|
class ReadlineTabCompleter:
|
||||||
""" Stores intermediate state for completer function """
|
"""Store intermediate state for completer function."""
|
||||||
|
|
||||||
def __init__(self, options):
|
def __init__(self, options):
|
||||||
"""
|
""":param options: list of possible completions."""
|
||||||
:param options: list of possible completions
|
|
||||||
"""
|
|
||||||
self.options = sorted(options)
|
self.options = sorted(options)
|
||||||
self.matches = []
|
self.matches = []
|
||||||
|
|
||||||
|
@ -40,11 +39,10 @@ class ReadlineTabCompleter:
|
||||||
|
|
||||||
def ask(question="Continue?", choices=["y", "n"], default="n",
|
def ask(question="Continue?", choices=["y", "n"], default="n",
|
||||||
lowercase_answer=True, validation_regex=None, complete=None):
|
lowercase_answer=True, validation_regex=None, complete=None):
|
||||||
"""
|
"""Ask a question on the terminal.
|
||||||
Ask a question on the terminal.
|
|
||||||
:param question: display prompt
|
:param question: display prompt
|
||||||
:param choices: short list of possible answers,
|
:param choices: short list of possible answers, displayed after prompt if set
|
||||||
displayed after prompt if set
|
|
||||||
:param default: default value to return if user doesn't input anything
|
:param default: default value to return if user doesn't input anything
|
||||||
:param lowercase_answer: if True, convert return value to lower case
|
:param lowercase_answer: if True, convert return value to lower case
|
||||||
:param validation_regex: if set, keep asking until regex matches
|
:param validation_regex: if set, keep asking until regex matches
|
||||||
|
@ -99,11 +97,9 @@ def ask(question="Continue?", choices=["y", "n"], default="n",
|
||||||
|
|
||||||
|
|
||||||
def confirm(args, question="Continue?", default=False, no_assumptions=False):
|
def confirm(args, question="Continue?", default=False, no_assumptions=False):
|
||||||
"""
|
"""Convenience wrapper around ask for simple yes-no questions with validation.
|
||||||
Convenience wrapper around ask for simple yes-no questions with validation.
|
|
||||||
|
|
||||||
:param no_assumptions: ask for confirmation, even if "pmbootstrap -y'
|
:param no_assumptions: ask for confirmation, even if "pmbootstrap -y' is set
|
||||||
is set
|
|
||||||
:returns: True for "y", False for "n"
|
:returns: True for "y", False for "n"
|
||||||
"""
|
"""
|
||||||
default_str = "y" if default else "n"
|
default_str = "y" if default else "n"
|
||||||
|
@ -115,9 +111,9 @@ def confirm(args, question="Continue?", default=False, no_assumptions=False):
|
||||||
|
|
||||||
|
|
||||||
def progress_print(args, progress):
|
def progress_print(args, progress):
|
||||||
"""
|
"""Print a snapshot of a progress bar to STDOUT.
|
||||||
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
|
Call progress_flush to end printing progress and clear the line. No output is printed in
|
||||||
non-interactive mode.
|
non-interactive mode.
|
||||||
|
|
||||||
:param progress: completion percentage as a number between 0 and 1
|
:param progress: completion percentage as a number between 0 and 1
|
||||||
|
@ -138,9 +134,9 @@ def progress_print(args, progress):
|
||||||
|
|
||||||
|
|
||||||
def progress_flush(args):
|
def progress_flush(args):
|
||||||
"""
|
"""Finish printing a progress bar.
|
||||||
Finish printing a progress bar. This will erase the line. Does nothing in
|
|
||||||
non-interactive mode.
|
This will erase the line. Does nothing in non-interactive mode.
|
||||||
"""
|
"""
|
||||||
if pmb.config.is_interactive and not args.details_to_stdout:
|
if pmb.config.is_interactive and not args.details_to_stdout:
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
|
@ -6,8 +6,8 @@ import pmb.parse
|
||||||
|
|
||||||
|
|
||||||
def find_path(args, codename, file=''):
|
def find_path(args, codename, file=''):
|
||||||
"""
|
"""Find path to device APKBUILD under `device/*/device-`.
|
||||||
Find path to device APKBUILD under `device/*/device-`.
|
|
||||||
:param codename: device codename
|
:param codename: device codename
|
||||||
:param file: file to look for (e.g. APKBUILD or deviceinfo), may be empty
|
:param file: file to look for (e.g. APKBUILD or deviceinfo), may be empty
|
||||||
:returns: path to APKBUILD
|
:returns: path to APKBUILD
|
||||||
|
@ -24,8 +24,8 @@ def find_path(args, codename, file=''):
|
||||||
|
|
||||||
|
|
||||||
def list_codenames(args, vendor=None, unmaintained=True):
|
def list_codenames(args, vendor=None, unmaintained=True):
|
||||||
"""
|
"""Get all devices, for which aports are available.
|
||||||
Get all devices, for which aports are available
|
|
||||||
:param vendor: vendor name to choose devices from, or None for all vendors
|
:param vendor: vendor name to choose devices from, or None for all vendors
|
||||||
:param unmaintained: include unmaintained devices
|
:param unmaintained: include unmaintained devices
|
||||||
:returns: ["first-device", "second-device", ...]
|
:returns: ["first-device", "second-device", ...]
|
||||||
|
@ -41,8 +41,8 @@ def list_codenames(args, vendor=None, unmaintained=True):
|
||||||
|
|
||||||
|
|
||||||
def list_vendors(args):
|
def list_vendors(args):
|
||||||
"""
|
"""Get all device vendors, for which aports are available.
|
||||||
Get all device vendors, for which aports are available
|
|
||||||
:returns: {"vendor1", "vendor2", ...}
|
:returns: {"vendor1", "vendor2", ...}
|
||||||
"""
|
"""
|
||||||
ret = set()
|
ret = set()
|
||||||
|
@ -53,9 +53,7 @@ def list_vendors(args):
|
||||||
|
|
||||||
|
|
||||||
def list_apkbuilds(args):
|
def list_apkbuilds(args):
|
||||||
"""
|
""":returns: { "first-device": {"pkgname": ..., "pkgver": ...}, ... }"""
|
||||||
:returns: { "first-device": {"pkgname": ..., "pkgver": ...}, ... }
|
|
||||||
"""
|
|
||||||
ret = {}
|
ret = {}
|
||||||
for device in list_codenames(args):
|
for device in list_codenames(args):
|
||||||
apkbuild_path = f"{args.aports}/device/*/device-{device}/APKBUILD"
|
apkbuild_path = f"{args.aports}/device/*/device-{device}/APKBUILD"
|
||||||
|
@ -64,9 +62,7 @@ def list_apkbuilds(args):
|
||||||
|
|
||||||
|
|
||||||
def list_deviceinfos(args):
|
def list_deviceinfos(args):
|
||||||
"""
|
""":returns: { "first-device": {"name": ..., "screen_width": ...}, ... }"""
|
||||||
:returns: { "first-device": {"name": ..., "screen_width": ...}, ... }
|
|
||||||
"""
|
|
||||||
ret = {}
|
ret = {}
|
||||||
for device in list_codenames(args):
|
for device in list_codenames(args):
|
||||||
ret[device] = pmb.parse.deviceinfo(args, device)
|
ret[device] = pmb.parse.deviceinfo(args, device)
|
||||||
|
|
|
@ -19,11 +19,13 @@ def replace(path, old, new):
|
||||||
|
|
||||||
|
|
||||||
def replace_apkbuild(args, pkgname, key, new, in_quotes=False):
|
def replace_apkbuild(args, pkgname, key, new, in_quotes=False):
|
||||||
""" Replace one key=value line in an APKBUILD and verify it afterwards.
|
"""Replace one key=value line in an APKBUILD and verify it afterwards.
|
||||||
:param pkgname: package name, e.g. "hello-world"
|
|
||||||
:param key: key that should be replaced, e.g. "pkgver"
|
:param pkgname: package name, e.g. "hello-world"
|
||||||
:param new: new value
|
:param key: key that should be replaced, e.g. "pkgver"
|
||||||
:param in_quotes: expect the value to be in quotation marks ("") """
|
:param new: new value
|
||||||
|
:param in_quotes: expect the value to be in quotation marks ("")
|
||||||
|
"""
|
||||||
# Read old value
|
# Read old value
|
||||||
path = pmb.helpers.pmaports.find(args, pkgname) + "/APKBUILD"
|
path = pmb.helpers.pmaports.find(args, pkgname) + "/APKBUILD"
|
||||||
apkbuild = pmb.parse.apkbuild(path)
|
apkbuild = pmb.parse.apkbuild(path)
|
||||||
|
@ -51,8 +53,8 @@ def replace_apkbuild(args, pkgname, key, new, in_quotes=False):
|
||||||
|
|
||||||
|
|
||||||
def is_up_to_date(path_sources, path_target=None, lastmod_target=None):
|
def is_up_to_date(path_sources, path_target=None, lastmod_target=None):
|
||||||
"""
|
"""Check if a file is up-to-date by comparing the last modified timestamps.
|
||||||
Check if a file is up-to-date by comparing the last modified timestamps
|
|
||||||
(just like make does it).
|
(just like make does it).
|
||||||
|
|
||||||
:param path_sources: list of full paths to the source files
|
:param path_sources: list of full paths to the source files
|
||||||
|
@ -78,9 +80,7 @@ def is_up_to_date(path_sources, path_target=None, lastmod_target=None):
|
||||||
|
|
||||||
|
|
||||||
def is_older_than(path, seconds):
|
def is_older_than(path, seconds):
|
||||||
"""
|
"""Check if a single file is older than a given amount of seconds."""
|
||||||
Check if a single file is older than a given amount of seconds.
|
|
||||||
"""
|
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
return True
|
return True
|
||||||
lastmod = os.path.getmtime(path)
|
lastmod = os.path.getmtime(path)
|
||||||
|
@ -88,9 +88,7 @@ def is_older_than(path, seconds):
|
||||||
|
|
||||||
|
|
||||||
def symlink(args, file, link):
|
def symlink(args, file, link):
|
||||||
"""
|
"""Check if the symlink is already present, otherwise create it."""
|
||||||
Checks if the symlink is already present, otherwise create it.
|
|
||||||
"""
|
|
||||||
if os.path.exists(link):
|
if os.path.exists(link):
|
||||||
if (os.path.islink(link) and
|
if (os.path.islink(link) and
|
||||||
os.path.realpath(os.readlink(link)) == os.path.realpath(file)):
|
os.path.realpath(os.readlink(link)) == os.path.realpath(file)):
|
||||||
|
|
|
@ -38,8 +38,8 @@ from argparse import Namespace
|
||||||
|
|
||||||
|
|
||||||
def _parse_flavor(args, autoinstall=True):
|
def _parse_flavor(args, autoinstall=True):
|
||||||
"""
|
"""Verify the flavor argument if specified, or return a default value.
|
||||||
Verify the flavor argument if specified, or return a default value.
|
|
||||||
:param autoinstall: make sure that at least one kernel flavor is installed
|
:param autoinstall: make sure that at least one kernel flavor is installed
|
||||||
"""
|
"""
|
||||||
# Install a kernel and get its "flavor", where flavor is a pmOS-specific
|
# Install a kernel and get its "flavor", where flavor is a pmOS-specific
|
||||||
|
|
|
@ -12,22 +12,25 @@ import pmb.helpers.run
|
||||||
|
|
||||||
|
|
||||||
def get_path(args, name_repo):
|
def get_path(args, name_repo):
|
||||||
""" Get the path to the repository, which is either the default one in the
|
"""Get the path to the repository.
|
||||||
work dir, or a user-specified one in args.
|
|
||||||
|
|
||||||
:returns: full path to repository """
|
The path is either the default one in the work dir, or a user-specified one in args.
|
||||||
|
|
||||||
|
:returns: full path to repository
|
||||||
|
"""
|
||||||
if name_repo == "pmaports":
|
if name_repo == "pmaports":
|
||||||
return args.aports
|
return args.aports
|
||||||
return args.work + "/cache_git/" + name_repo
|
return args.work + "/cache_git/" + name_repo
|
||||||
|
|
||||||
|
|
||||||
def clone(args, name_repo):
|
def clone(args, name_repo):
|
||||||
""" Clone a git repository to $WORK/cache_git/$name_repo (or to the
|
"""Clone a git repository to $WORK/cache_git/$name_repo.
|
||||||
overridden path set in args, as with pmbootstrap --aports).
|
|
||||||
|
|
||||||
:param name_repo: short alias used for the repository name, from
|
(or to the overridden path set in args, as with ``pmbootstrap --aports``).
|
||||||
pmb.config.git_repos (e.g. "aports_upstream",
|
|
||||||
"pmaports") """
|
:param name_repo: short alias used for the repository name, from pmb.config.git_repos
|
||||||
|
(e.g. "aports_upstream", "pmaports")
|
||||||
|
"""
|
||||||
# Check for repo name in the config
|
# Check for repo name in the config
|
||||||
if name_repo not in pmb.config.git_repos:
|
if name_repo not in pmb.config.git_repos:
|
||||||
raise ValueError("No git repository configured for " + name_repo)
|
raise ValueError("No git repository configured for " + name_repo)
|
||||||
|
@ -52,14 +55,14 @@ def clone(args, name_repo):
|
||||||
|
|
||||||
|
|
||||||
def rev_parse(args, path, revision="HEAD", extra_args: list = []):
|
def rev_parse(args, path, revision="HEAD", extra_args: list = []):
|
||||||
""" Run "git rev-parse" in a specific repository dir.
|
"""Run "git rev-parse" in a specific repository dir.
|
||||||
|
|
||||||
:param path: to the git repository
|
:param path: to the git repository
|
||||||
:param extra_args: additional arguments for "git rev-parse". Pass
|
:param extra_args: additional arguments for ``git rev-parse``. Pass
|
||||||
"--abbrev-ref" to get the branch instead of the
|
``--abbrev-ref`` to get the branch instead of the commit, if possible.
|
||||||
commit, if possible.
|
:returns: commit string like "90cd0ad84d390897efdcf881c0315747a4f3a966"
|
||||||
:returns: commit string like "90cd0ad84d390897efdcf881c0315747a4f3a966"
|
or (with ``--abbrev-ref``): the branch name, e.g. "master"
|
||||||
or (with --abbrev-ref): the branch name, e.g. "master" """
|
"""
|
||||||
command = ["git", "rev-parse"] + extra_args + [revision]
|
command = ["git", "rev-parse"] + extra_args + [revision]
|
||||||
rev = pmb.helpers.run.user(args, command, path, output_return=True)
|
rev = pmb.helpers.run.user(args, command, path, output_return=True)
|
||||||
return rev.rstrip()
|
return rev.rstrip()
|
||||||
|
@ -77,15 +80,16 @@ def can_fast_forward(args, path, branch_upstream, branch="HEAD"):
|
||||||
|
|
||||||
|
|
||||||
def clean_worktree(args, path):
|
def clean_worktree(args, path):
|
||||||
""" Check if there are not any modified files in the git dir. """
|
"""Check if there are not any modified files in the git dir."""
|
||||||
command = ["git", "status", "--porcelain"]
|
command = ["git", "status", "--porcelain"]
|
||||||
return pmb.helpers.run.user(args, command, path, output_return=True) == ""
|
return pmb.helpers.run.user(args, command, path, output_return=True) == ""
|
||||||
|
|
||||||
|
|
||||||
def get_upstream_remote(args, name_repo):
|
def get_upstream_remote(args, name_repo):
|
||||||
""" Find the remote, which matches the git URL from the config. Usually
|
"""Find the remote, which matches the git URL from the config.
|
||||||
"origin", but the user may have set up their git repository
|
|
||||||
differently. """
|
Usually "origin", but the user may have set up their git repository differently.
|
||||||
|
"""
|
||||||
url = pmb.config.git_repos[name_repo]
|
url = pmb.config.git_repos[name_repo]
|
||||||
path = get_path(args, name_repo)
|
path = get_path(args, name_repo)
|
||||||
command = ["git", "remote", "-v"]
|
command = ["git", "remote", "-v"]
|
||||||
|
@ -98,14 +102,17 @@ def get_upstream_remote(args, name_repo):
|
||||||
|
|
||||||
|
|
||||||
def parse_channels_cfg(args):
|
def parse_channels_cfg(args):
|
||||||
""" Parse channels.cfg from pmaports.git, origin/master branch.
|
"""Parse channels.cfg from pmaports.git, origin/master branch.
|
||||||
Reference: https://postmarketos.org/channels.cfg
|
|
||||||
:returns: dict like: {"meta": {"recommended": "edge"},
|
Reference: https://postmarketos.org/channels.cfg
|
||||||
"channels": {"edge": {"description": ...,
|
|
||||||
"branch_pmaports": ...,
|
:returns: dict like: {"meta": {"recommended": "edge"},
|
||||||
"branch_aports": ...,
|
"channels": {"edge": {"description": ...,
|
||||||
"mirrordir_alpine": ...},
|
"branch_pmaports": ...,
|
||||||
...}} """
|
"branch_aports": ...,
|
||||||
|
"mirrordir_alpine": ...},
|
||||||
|
...}}
|
||||||
|
"""
|
||||||
# Cache during one pmbootstrap run
|
# Cache during one pmbootstrap run
|
||||||
cache_key = "pmb.helpers.git.parse_channels_cfg"
|
cache_key = "pmb.helpers.git.parse_channels_cfg"
|
||||||
if pmb.helpers.other.cache[cache_key]:
|
if pmb.helpers.other.cache[cache_key]:
|
||||||
|
@ -151,8 +158,10 @@ def parse_channels_cfg(args):
|
||||||
|
|
||||||
|
|
||||||
def get_branches_official(args, name_repo):
|
def get_branches_official(args, name_repo):
|
||||||
""" Get all branches that point to official release channels.
|
"""Get all branches that point to official release channels.
|
||||||
:returns: list of supported branches, e.g. ["master", "3.11"] """
|
|
||||||
|
:returns: list of supported branches, e.g. ["master", "3.11"]
|
||||||
|
"""
|
||||||
# This functions gets called with pmaports and aports_upstream, because
|
# This functions gets called with pmaports and aports_upstream, because
|
||||||
# both are displayed in "pmbootstrap status". But it only makes sense
|
# both are displayed in "pmbootstrap status". But it only makes sense
|
||||||
# to display pmaports there, related code will be refactored soon (#1903).
|
# to display pmaports there, related code will be refactored soon (#1903).
|
||||||
|
@ -167,12 +176,14 @@ def get_branches_official(args, name_repo):
|
||||||
|
|
||||||
|
|
||||||
def pull(args, name_repo):
|
def pull(args, name_repo):
|
||||||
""" Check if on official branch and essentially try 'git pull --ff-only'.
|
"""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 """
|
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
|
||||||
|
"""
|
||||||
branches_official = get_branches_official(args, name_repo)
|
branches_official = get_branches_official(args, name_repo)
|
||||||
|
|
||||||
# Skip if repo wasn't cloned
|
# Skip if repo wasn't cloned
|
||||||
|
@ -229,18 +240,24 @@ def pull(args, name_repo):
|
||||||
|
|
||||||
|
|
||||||
def get_topdir(args, path):
|
def get_topdir(args, path):
|
||||||
""" :returns: a string with the top dir of the git repository, or an
|
"""Get top-dir of git repo.
|
||||||
empty string if it's not a git repository. """
|
|
||||||
|
:returns: a string with the top dir of the git repository,
|
||||||
|
or an empty string if it's not a git repository.
|
||||||
|
"""
|
||||||
return pmb.helpers.run.user(args, ["git", "rev-parse", "--show-toplevel"],
|
return pmb.helpers.run.user(args, ["git", "rev-parse", "--show-toplevel"],
|
||||||
path, output_return=True, check=False).rstrip()
|
path, output_return=True, check=False).rstrip()
|
||||||
|
|
||||||
|
|
||||||
def get_files(args, path):
|
def get_files(args, path):
|
||||||
""" Get all files inside a git repository, that are either already in the
|
"""Get all files inside a git repository, that are either already in the git tree or are not in gitignore.
|
||||||
git tree or are not in gitignore. Do not list deleted files. To be used
|
|
||||||
for creating a tarball of the git repository.
|
Do not list deleted files. To be used for creating a tarball of the git repository.
|
||||||
:param path: top dir of the git repository
|
|
||||||
:returns: all files in a git repository as list, relative to path """
|
:param path: top dir of the git repository
|
||||||
|
|
||||||
|
:returns: all files in a git repository as list, relative to path
|
||||||
|
"""
|
||||||
ret = []
|
ret = []
|
||||||
files = pmb.helpers.run.user(args, ["git", "ls-files"], path,
|
files = pmb.helpers.run.user(args, ["git", "ls-files"], path,
|
||||||
output_return=True).split("\n")
|
output_return=True).split("\n")
|
||||||
|
|
|
@ -12,20 +12,21 @@ import pmb.helpers.run
|
||||||
|
|
||||||
def download(args, url, prefix, cache=True, loglevel=logging.INFO,
|
def download(args, url, prefix, cache=True, loglevel=logging.INFO,
|
||||||
allow_404=False):
|
allow_404=False):
|
||||||
""" Download a file to disk.
|
"""Download a file to disk.
|
||||||
|
|
||||||
:param url: the http(s) address of to the file to download
|
:param url: the http(s) address of to the file to download
|
||||||
:param prefix: for the cache, to make it easier to find (cache files
|
:param prefix: for the cache, to make it easier to find (cache files
|
||||||
get a hash of the URL after the prefix)
|
get a hash of the URL after the prefix)
|
||||||
:param cache: if True, and url is cached, do not download it again
|
:param cache: if True, and url is cached, do not download it again
|
||||||
:param loglevel: change to logging.DEBUG to only display the download
|
:param loglevel: change to logging.DEBUG to only display the download
|
||||||
message in 'pmbootstrap log', not in stdout. We use
|
message in 'pmbootstrap log', not in stdout.
|
||||||
this when downloading many APKINDEX files at once, no
|
We use this when downloading many APKINDEX files at once, no
|
||||||
point in showing a dozen messages.
|
point in showing a dozen messages.
|
||||||
:param allow_404: do not raise an exception when the server responds
|
:param allow_404: do not raise an exception when the server responds with a 404 Not Found error.
|
||||||
with a 404 Not Found error. Only display a warning on
|
Only display a warning on stdout (no matter if loglevel is changed).
|
||||||
stdout (no matter if loglevel is changed).
|
|
||||||
:returns: path to the downloaded file in the cache or None on 404 """
|
:returns: path to the downloaded file in the cache or None on 404
|
||||||
|
"""
|
||||||
# Create cache folder
|
# Create cache folder
|
||||||
if not os.path.exists(args.work + "/cache_http"):
|
if not os.path.exists(args.work + "/cache_http"):
|
||||||
pmb.helpers.run.user(args, ["mkdir", "-p", args.work + "/cache_http"])
|
pmb.helpers.run.user(args, ["mkdir", "-p", args.work + "/cache_http"])
|
||||||
|
@ -62,13 +63,14 @@ def download(args, url, prefix, cache=True, loglevel=logging.INFO,
|
||||||
|
|
||||||
|
|
||||||
def retrieve(url, headers=None, allow_404=False):
|
def retrieve(url, headers=None, allow_404=False):
|
||||||
""" Fetch the content of a URL and returns it as string.
|
"""Fetch the content of a URL and returns it as string.
|
||||||
|
|
||||||
:param url: the http(s) address of to the resource to fetch
|
:param url: the http(s) address of to the resource to fetch
|
||||||
:param headers: dict of HTTP headers to use
|
:param headers: dict of HTTP headers to use
|
||||||
:param allow_404: do not raise an exception when the server responds
|
:param allow_404: do not raise an exception when the server responds with a
|
||||||
with a 404 Not Found error. Only display a warning
|
404 Not Found error. Only display a warning
|
||||||
:returns: str with the content of the response
|
|
||||||
|
:returns: str with the content of the response
|
||||||
"""
|
"""
|
||||||
# Download the file
|
# Download the file
|
||||||
logging.verbose("Retrieving " + url)
|
logging.verbose("Retrieving " + url)
|
||||||
|
@ -89,6 +91,8 @@ def retrieve(url, headers=None, allow_404=False):
|
||||||
|
|
||||||
|
|
||||||
def retrieve_json(*args, **kwargs):
|
def retrieve_json(*args, **kwargs):
|
||||||
""" Fetch the contents of a URL, parse it as JSON and return it. See
|
"""Fetch the contents of a URL, parse it as JSON and return it.
|
||||||
retrieve() for the list of all parameters. """
|
|
||||||
|
See retrieve() for the list of all parameters.
|
||||||
|
"""
|
||||||
return json.loads(retrieve(*args, **kwargs))
|
return json.loads(retrieve(*args, **kwargs))
|
||||||
|
|
|
@ -11,8 +11,7 @@ import pmb.helpers.pmaports
|
||||||
|
|
||||||
|
|
||||||
def check(args, pkgnames):
|
def check(args, pkgnames):
|
||||||
"""
|
"""Run apkbuild-lint on the supplied packages.
|
||||||
Run apkbuild-lint on the supplied packages
|
|
||||||
|
|
||||||
:param pkgnames: Names of the packages to lint
|
:param pkgnames: Names of the packages to lint
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -9,9 +9,7 @@ logfd = None
|
||||||
|
|
||||||
|
|
||||||
class log_handler(logging.StreamHandler):
|
class log_handler(logging.StreamHandler):
|
||||||
"""
|
"""Write to stdout and to the already opened log file."""
|
||||||
Write to stdout and to the already opened log file.
|
|
||||||
"""
|
|
||||||
_args = None
|
_args = None
|
||||||
|
|
||||||
def emit(self, record):
|
def emit(self, record):
|
||||||
|
@ -72,9 +70,9 @@ class log_handler(logging.StreamHandler):
|
||||||
|
|
||||||
|
|
||||||
def add_verbose_log_level():
|
def add_verbose_log_level():
|
||||||
"""
|
"""Add a new log level "verbose", which is below "debug".
|
||||||
Add a new log level "verbose", which is below "debug". Also monkeypatch
|
|
||||||
logging, so it can be used with logging.verbose().
|
Also monkeypatch logging, so it can be used with logging.verbose().
|
||||||
|
|
||||||
This function is based on work by Voitek Zylinski and sleepycal:
|
This function is based on work by Voitek Zylinski and sleepycal:
|
||||||
https://stackoverflow.com/a/20602183
|
https://stackoverflow.com/a/20602183
|
||||||
|
@ -91,10 +89,7 @@ def add_verbose_log_level():
|
||||||
|
|
||||||
|
|
||||||
def init(args):
|
def init(args):
|
||||||
"""
|
"""Set log format and add the log file descriptor to logfd, add the verbose log level."""
|
||||||
Set log format and add the log file descriptor to logfd, add the
|
|
||||||
verbose log level.
|
|
||||||
"""
|
|
||||||
global logfd
|
global logfd
|
||||||
# Set log file descriptor (logfd)
|
# Set log file descriptor (logfd)
|
||||||
if args.details_to_stdout:
|
if args.details_to_stdout:
|
||||||
|
|
|
@ -5,8 +5,8 @@ import pmb.helpers.run
|
||||||
|
|
||||||
|
|
||||||
def ismount(folder):
|
def ismount(folder):
|
||||||
"""
|
"""Ismount() implementation that works for mount --bind.
|
||||||
Ismount() implementation that works for mount --bind.
|
|
||||||
Workaround for: https://bugs.python.org/issue29707
|
Workaround for: https://bugs.python.org/issue29707
|
||||||
"""
|
"""
|
||||||
folder = os.path.realpath(os.path.realpath(folder))
|
folder = os.path.realpath(os.path.realpath(folder))
|
||||||
|
@ -21,8 +21,8 @@ def ismount(folder):
|
||||||
|
|
||||||
|
|
||||||
def bind(args, source, destination, create_folders=True, umount=False):
|
def bind(args, source, destination, create_folders=True, umount=False):
|
||||||
"""
|
"""Mount --bind a folder and create necessary directory structure.
|
||||||
Mount --bind a folder and create necessary directory structure.
|
|
||||||
:param umount: when destination is already a mount point, umount it first.
|
:param umount: when destination is already a mount point, umount it first.
|
||||||
"""
|
"""
|
||||||
# Check/umount destination
|
# Check/umount destination
|
||||||
|
@ -51,10 +51,7 @@ def bind(args, source, destination, create_folders=True, umount=False):
|
||||||
|
|
||||||
|
|
||||||
def bind_file(args, source, destination, create_folders=False):
|
def bind_file(args, source, destination, create_folders=False):
|
||||||
"""
|
"""Mount a file with the --bind option, and create the destination file, if necessary."""
|
||||||
Mount a file with the --bind option, and create the destination file,
|
|
||||||
if necessary.
|
|
||||||
"""
|
|
||||||
# Skip existing mountpoint
|
# Skip existing mountpoint
|
||||||
if ismount(destination):
|
if ismount(destination):
|
||||||
return
|
return
|
||||||
|
@ -74,10 +71,12 @@ def bind_file(args, source, destination, create_folders=False):
|
||||||
|
|
||||||
|
|
||||||
def umount_all_list(prefix, source="/proc/mounts"):
|
def umount_all_list(prefix, source="/proc/mounts"):
|
||||||
"""
|
"""Parse `/proc/mounts` for all folders beginning with a prefix.
|
||||||
Parses `/proc/mounts` for all folders beginning with a prefix.
|
|
||||||
:source: can be changed for testcases
|
:source: can be changed for testcases
|
||||||
|
|
||||||
:returns: a list of folders that need to be umounted
|
:returns: a list of folders that need to be umounted
|
||||||
|
|
||||||
"""
|
"""
|
||||||
ret = []
|
ret = []
|
||||||
prefix = os.path.realpath(prefix)
|
prefix = os.path.realpath(prefix)
|
||||||
|
@ -99,9 +98,7 @@ def umount_all_list(prefix, source="/proc/mounts"):
|
||||||
|
|
||||||
|
|
||||||
def umount_all(args, folder):
|
def umount_all(args, folder):
|
||||||
"""
|
"""Umount all folders that are mounted inside a given folder."""
|
||||||
Umount all folders that are mounted inside a given folder.
|
|
||||||
"""
|
|
||||||
for mountpoint in umount_all_list(folder):
|
for mountpoint in umount_all_list(folder):
|
||||||
pmb.helpers.run.root(args, ["umount", mountpoint])
|
pmb.helpers.run.root(args, ["umount", mountpoint])
|
||||||
if ismount(mountpoint):
|
if ismount(mountpoint):
|
||||||
|
|
|
@ -12,10 +12,10 @@ import pmb.helpers.run
|
||||||
|
|
||||||
|
|
||||||
def folder_size(args, path):
|
def folder_size(args, path):
|
||||||
"""
|
"""Run `du` to calculate the size of a folder.
|
||||||
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
|
(this is less code and faster than doing the same task in pure Python)
|
||||||
approximatelly right, but good enough for pmbootstrap's use case (#760).
|
This result is only approximatelly right, but good enough for pmbootstrap's use case (#760).
|
||||||
|
|
||||||
:returns: folder size in kilobytes
|
:returns: folder size in kilobytes
|
||||||
"""
|
"""
|
||||||
|
@ -30,10 +30,10 @@ def folder_size(args, path):
|
||||||
|
|
||||||
|
|
||||||
def check_grsec():
|
def check_grsec():
|
||||||
"""
|
"""Check if the current kernel is based on the grsec patchset.
|
||||||
Check if the current kernel is based on the grsec patchset, and if
|
|
||||||
the chroot_deny_chmod option is enabled. Raise an exception in that
|
Also check if the chroot_deny_chmod option is enabled.
|
||||||
case, with a link to the issue. Otherwise, do nothing.
|
Raise an exception in that case, with a link to the issue. Otherwise, do nothing.
|
||||||
"""
|
"""
|
||||||
path = "/proc/sys/kernel/grsecurity/chroot_deny_chmod"
|
path = "/proc/sys/kernel/grsecurity/chroot_deny_chmod"
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
|
@ -44,9 +44,10 @@ def check_grsec():
|
||||||
|
|
||||||
|
|
||||||
def check_binfmt_misc(args):
|
def check_binfmt_misc(args):
|
||||||
"""
|
"""Check if the 'binfmt_misc' module is loaded.
|
||||||
Check if the 'binfmt_misc' module is loaded by checking, if
|
|
||||||
/proc/sys/fs/binfmt_misc/ exists. If it exists, then do nothing.
|
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.
|
Otherwise, load the module and mount binfmt_misc.
|
||||||
If that fails as well, raise an exception pointing the user to the wiki.
|
If that fails as well, raise an exception pointing the user to the wiki.
|
||||||
"""
|
"""
|
||||||
|
@ -241,11 +242,10 @@ def migrate_work_folder(args):
|
||||||
|
|
||||||
|
|
||||||
def check_old_devices(args):
|
def check_old_devices(args):
|
||||||
"""
|
"""Check if there are any device ports in device/\\*/APKBUILD.
|
||||||
Check if there are any device ports in device/*/APKBUILD,
|
|
||||||
rather than device/*/*/APKBUILD (e.g. device/testing/...).
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
Devices should be in device/\\*/\\*/APKBUILD (e.g. device/testing/...).
|
||||||
|
"""
|
||||||
g = glob.glob(args.aports + "/device/*/APKBUILD")
|
g = glob.glob(args.aports + "/device/*/APKBUILD")
|
||||||
if not g:
|
if not g:
|
||||||
return
|
return
|
||||||
|
@ -257,8 +257,9 @@ def check_old_devices(args):
|
||||||
|
|
||||||
|
|
||||||
def validate_hostname(hostname):
|
def validate_hostname(hostname):
|
||||||
"""
|
"""Check whether the string is a valid hostname.
|
||||||
Check whether the string is a valid hostname, according to
|
|
||||||
|
Check is performed according to
|
||||||
<http://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names>
|
<http://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names>
|
||||||
"""
|
"""
|
||||||
# Check length
|
# Check length
|
||||||
|
@ -299,8 +300,7 @@ cache = None
|
||||||
|
|
||||||
def init_cache():
|
def init_cache():
|
||||||
global cache
|
global cache
|
||||||
""" Add a caching dict (caches parsing of files etc. for the current
|
"""Add a caching dict (caches parsing of files etc. for the current session)."""
|
||||||
session) """
|
|
||||||
repo_update = {"404": [], "offline_msg_shown": False}
|
repo_update = {"404": [], "offline_msg_shown": False}
|
||||||
cache = {"apkindex": {},
|
cache = {"apkindex": {},
|
||||||
"apkbuild": {},
|
"apkbuild": {},
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
# Copyright 2023 Oliver Smith
|
# Copyright 2023 Oliver Smith
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
"""
|
"""Functions that work with both pmaports and binary package repos.
|
||||||
Functions that work with both pmaports and binary package repos. See also:
|
|
||||||
- pmb/helpers/pmaports.py (work with pmaports)
|
See also:
|
||||||
- pmb/helpers/repo.py (work with binary package repos)
|
|
||||||
|
- pmb/helpers/pmaports.py (work with pmaports)
|
||||||
|
|
||||||
|
- pmb/helpers/repo.py (work with binary package repos)
|
||||||
"""
|
"""
|
||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
|
@ -21,24 +24,24 @@ def remove_operators(package):
|
||||||
|
|
||||||
|
|
||||||
def get(args, pkgname, arch, replace_subpkgnames=False, must_exist=True):
|
def get(args, pkgname, arch, replace_subpkgnames=False, must_exist=True):
|
||||||
""" Find a package in pmaports, and as fallback in the APKINDEXes of the
|
"""Find a package in pmaports, and as fallback in the APKINDEXes of the binary packages.
|
||||||
binary packages.
|
|
||||||
:param pkgname: package name (e.g. "hello-world")
|
:param pkgname: package name (e.g. "hello-world")
|
||||||
:param arch: preferred architecture of the binary package. When it
|
:param arch: preferred architecture of the binary package.
|
||||||
can't be found for this arch, we'll still look for another
|
When it can't be found for this arch, we'll still look for another arch to see whether the
|
||||||
arch to see whether the package exists at all. So make
|
package exists at all. So make sure to check the returned arch against what you wanted
|
||||||
sure to check the returned arch against what you wanted
|
with check_arch(). Example: "armhf"
|
||||||
with check_arch(). Example: "armhf"
|
:param replace_subpkgnames: replace all subpkgnames with their main pkgnames in the depends
|
||||||
:param replace_subpkgnames: replace all subpkgnames with their main
|
(see #1733)
|
||||||
pkgnames in the depends (see #1733)
|
:param must_exist: raise an exception, if not found
|
||||||
:param must_exist: raise an exception, if not found
|
|
||||||
:returns: * data from the parsed APKBUILD or APKINDEX in the following
|
:returns: * data from the parsed APKBUILD or APKINDEX in the following format:
|
||||||
format: {"arch": ["noarch"],
|
{"arch": ["noarch"], "depends": ["busybox-extras", "lddtree", ...],
|
||||||
"depends": ["busybox-extras", "lddtree", ...],
|
"pkgname": "postmarketos-mkinitfs", "provides": ["mkinitfs=0..1"],
|
||||||
"pkgname": "postmarketos-mkinitfs",
|
"version": "0.0.4-r10"}
|
||||||
"provides": ["mkinitfs=0..1"],
|
|
||||||
"version": "0.0.4-r10"}
|
* None if the package was not found
|
||||||
* None if the package was not found """
|
"""
|
||||||
# Cached result
|
# Cached result
|
||||||
cache_key = "pmb.helpers.package.get"
|
cache_key = "pmb.helpers.package.get"
|
||||||
if (
|
if (
|
||||||
|
@ -127,12 +130,14 @@ def get(args, pkgname, arch, replace_subpkgnames=False, must_exist=True):
|
||||||
|
|
||||||
|
|
||||||
def depends_recurse(args, pkgname, arch):
|
def depends_recurse(args, pkgname, arch):
|
||||||
""" Recursively resolve all of the package's dependencies.
|
"""Recursively resolve all of the package's dependencies.
|
||||||
:param pkgname: name of the package (e.g. "device-samsung-i9100")
|
|
||||||
:param arch: preferred architecture for binary packages
|
:param pkgname: name of the package (e.g. "device-samsung-i9100")
|
||||||
:returns: a list of pkgname_start and all its dependencies, e.g:
|
:param arch: preferred architecture for binary packages
|
||||||
["busybox-static-armhf", "device-samsung-i9100",
|
:returns: a list of pkgname_start and all its dependencies, e.g:
|
||||||
"linux-samsung-i9100", ...] """
|
["busybox-static-armhf", "device-samsung-i9100",
|
||||||
|
"linux-samsung-i9100", ...]
|
||||||
|
"""
|
||||||
# Cached result
|
# Cached result
|
||||||
cache_key = "pmb.helpers.package.depends_recurse"
|
cache_key = "pmb.helpers.package.depends_recurse"
|
||||||
if (arch in pmb.helpers.other.cache[cache_key] and
|
if (arch in pmb.helpers.other.cache[cache_key] and
|
||||||
|
@ -164,15 +169,14 @@ def depends_recurse(args, pkgname, arch):
|
||||||
|
|
||||||
|
|
||||||
def check_arch(args, pkgname, arch, binary=True):
|
def check_arch(args, pkgname, arch, binary=True):
|
||||||
""" Can a package be built for a certain architecture, or is there a binary
|
"""Check if a package be built for a certain architecture, or is there a binary package for it.
|
||||||
package for it?
|
|
||||||
|
|
||||||
:param pkgname: name of the package
|
:param pkgname: name of the package
|
||||||
:param arch: architecture to check against
|
:param arch: architecture to check against
|
||||||
:param binary: set to False to only look at the pmaports, not at binary
|
:param binary: set to False to only look at the pmaports, not at binary
|
||||||
packages
|
packages
|
||||||
:returns: True when the package can be built, or there is a binary
|
|
||||||
package, False otherwise
|
:returns: True when the package can be built, or there is a binary package, False otherwise
|
||||||
"""
|
"""
|
||||||
if binary:
|
if binary:
|
||||||
arches = get(args, pkgname, arch)["arch"]
|
arches = get(args, pkgname, arch)["arch"]
|
||||||
|
|
|
@ -9,8 +9,7 @@ import pmb.parse
|
||||||
|
|
||||||
|
|
||||||
def package(args, pkgname, reason="", dry=False):
|
def package(args, pkgname, reason="", dry=False):
|
||||||
"""
|
"""Increase the pkgrel in the APKBUILD of a specific package.
|
||||||
Increase the pkgrel in the APKBUILD of a specific package.
|
|
||||||
|
|
||||||
:param pkgname: name of the package
|
:param pkgname: name of the package
|
||||||
:param reason: string to display as reason why it was increased
|
:param reason: string to display as reason why it was increased
|
||||||
|
@ -44,9 +43,7 @@ def package(args, pkgname, reason="", dry=False):
|
||||||
|
|
||||||
|
|
||||||
def auto_apkindex_package(args, arch, aport, apk, dry=False):
|
def auto_apkindex_package(args, arch, aport, apk, dry=False):
|
||||||
"""
|
"""Bump the pkgrel of a specific package if it is outdated in the given APKINDEX.
|
||||||
Bump the pkgrel of a specific package if it is outdated in the given
|
|
||||||
APKINDEX.
|
|
||||||
|
|
||||||
:param arch: the architecture, e.g. "armhf"
|
:param arch: the architecture, e.g. "armhf"
|
||||||
:param aport: parsed APKBUILD of the binary package's origin:
|
:param aport: parsed APKBUILD of the binary package's origin:
|
||||||
|
@ -103,9 +100,7 @@ def auto_apkindex_package(args, arch, aport, apk, dry=False):
|
||||||
|
|
||||||
|
|
||||||
def auto(args, dry=False):
|
def auto(args, dry=False):
|
||||||
"""
|
""":returns: list of aport names, where the pkgrel needed to be changed"""
|
||||||
:returns: list of aport names, where the pkgrel needed to be changed
|
|
||||||
"""
|
|
||||||
ret = []
|
ret = []
|
||||||
for arch in pmb.config.build_device_architectures:
|
for arch in pmb.config.build_device_architectures:
|
||||||
paths = pmb.helpers.repo.apkindex_files(args, arch, alpine=False)
|
paths = pmb.helpers.repo.apkindex_files(args, arch, alpine=False)
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
# Copyright 2023 Oliver Smith
|
# Copyright 2023 Oliver Smith
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
"""
|
"""Functions that work with pmaports.
|
||||||
Functions that work with pmaports. See also:
|
|
||||||
|
See also:
|
||||||
- pmb/helpers/repo.py (work with binary package repos)
|
- pmb/helpers/repo.py (work with binary package repos)
|
||||||
- pmb/helpers/package.py (work with both)
|
- pmb/helpers/package.py (work with both)
|
||||||
"""
|
"""
|
||||||
|
@ -42,10 +43,9 @@ def get_list(args):
|
||||||
|
|
||||||
|
|
||||||
def guess_main_dev(args, subpkgname):
|
def guess_main_dev(args, subpkgname):
|
||||||
"""
|
"""Check if a package without "-dev" at the end exists in pmaports or not, and log the appropriate message.
|
||||||
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
|
Don't call this function directly, use guess_main() instead.
|
||||||
guess_main() instead.
|
|
||||||
|
|
||||||
:param subpkgname: subpackage name, must end in "-dev"
|
:param subpkgname: subpackage name, must end in "-dev"
|
||||||
:returns: full path to the pmaport or None
|
:returns: full path to the pmaport or None
|
||||||
|
@ -64,8 +64,8 @@ def guess_main_dev(args, subpkgname):
|
||||||
|
|
||||||
|
|
||||||
def guess_main(args, subpkgname):
|
def guess_main(args, subpkgname):
|
||||||
"""
|
"""Find the main package by assuming it is a prefix of the subpkgname.
|
||||||
Find the main package by assuming it is a prefix of the subpkgname.
|
|
||||||
We do that, because in some APKBUILDs the subpkgname="" variable gets
|
We do that, because in some APKBUILDs the subpkgname="" variable gets
|
||||||
filled with a shell loop and the APKBUILD parser in pmbootstrap can't
|
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
|
parse this right. (Intentionally, we don't want to implement a full shell
|
||||||
|
@ -101,9 +101,8 @@ def guess_main(args, subpkgname):
|
||||||
|
|
||||||
|
|
||||||
def _find_package_in_apkbuild(package, path):
|
def _find_package_in_apkbuild(package, path):
|
||||||
"""
|
"""Look through subpackages and all provides to see if the APKBUILD at the specified path
|
||||||
Look through subpackages and all provides to see if the APKBUILD at the
|
contains (or provides) the specified package.
|
||||||
specified path contains (or provides) the specified package.
|
|
||||||
|
|
||||||
:param package: The package to search for
|
:param package: The package to search for
|
||||||
:param path: The path to the apkbuild
|
:param path: The path to the apkbuild
|
||||||
|
@ -136,8 +135,8 @@ def _find_package_in_apkbuild(package, path):
|
||||||
|
|
||||||
|
|
||||||
def find(args, package, must_exist=True):
|
def find(args, package, must_exist=True):
|
||||||
"""
|
"""Find the aport path that provides a certain subpackage.
|
||||||
Find the aport path that provides a certain subpackage.
|
|
||||||
If you want the parsed APKBUILD instead, use pmb.helpers.pmaports.get().
|
If you want the parsed APKBUILD instead, use pmb.helpers.pmaports.get().
|
||||||
|
|
||||||
:param must_exist: Raise an exception, when not found
|
:param must_exist: Raise an exception, when not found
|
||||||
|
@ -191,22 +190,23 @@ def find(args, package, must_exist=True):
|
||||||
|
|
||||||
|
|
||||||
def get(args, pkgname, must_exist=True, subpackages=True):
|
def get(args, pkgname, must_exist=True, subpackages=True):
|
||||||
""" Find and parse an APKBUILD file.
|
"""Find and parse an APKBUILD file.
|
||||||
Run 'pmbootstrap apkbuild_parse hello-world' for a full output example.
|
|
||||||
Relevant variables are defined in pmb.config.apkbuild_attributes.
|
|
||||||
|
|
||||||
:param pkgname: the package name to find
|
Run 'pmbootstrap apkbuild_parse hello-world' for a full output example.
|
||||||
:param must_exist: raise an exception when it can't be found
|
Relevant variables are defined in pmb.config.apkbuild_attributes.
|
||||||
:param subpackages: also search for subpackages with the specified
|
|
||||||
names (slow! might need to parse all APKBUILDs to
|
:param pkgname: the package name to find
|
||||||
find it)
|
:param must_exist: raise an exception when it can't be found
|
||||||
:returns: relevant variables from the APKBUILD as dictionary, e.g.:
|
:param subpackages: also search for subpackages with the specified
|
||||||
|
names (slow! might need to parse all APKBUILDs to find it)
|
||||||
|
|
||||||
|
:returns: relevant variables from the APKBUILD as dictionary, e.g.:
|
||||||
{ "pkgname": "hello-world",
|
{ "pkgname": "hello-world",
|
||||||
"arch": ["all"],
|
"arch": ["all"],
|
||||||
"pkgrel": "4",
|
"pkgrel": "4",
|
||||||
"pkgrel": "1",
|
"pkgrel": "1",
|
||||||
"options": [],
|
"options": [],
|
||||||
... }
|
... }
|
||||||
"""
|
"""
|
||||||
pkgname = pmb.helpers.package.remove_operators(pkgname)
|
pkgname = pmb.helpers.package.remove_operators(pkgname)
|
||||||
if subpackages:
|
if subpackages:
|
||||||
|
@ -225,8 +225,8 @@ def get(args, pkgname, must_exist=True, subpackages=True):
|
||||||
|
|
||||||
|
|
||||||
def find_providers(args, provide):
|
def find_providers(args, provide):
|
||||||
"""
|
"""Search for providers of the specified (virtual) package in pmaports.
|
||||||
Search for providers of the specified (virtual) package in pmaports.
|
|
||||||
Note: Currently only providers from a single APKBUILD are returned.
|
Note: Currently only providers from a single APKBUILD are returned.
|
||||||
|
|
||||||
:param provide: the (virtual) package to search providers for
|
:param provide: the (virtual) package to search providers for
|
||||||
|
@ -249,12 +249,13 @@ def find_providers(args, provide):
|
||||||
|
|
||||||
|
|
||||||
def get_repo(args, pkgname, must_exist=True):
|
def get_repo(args, pkgname, must_exist=True):
|
||||||
""" Get the repository folder of an aport.
|
"""Get the repository folder of an aport.
|
||||||
|
|
||||||
:pkgname: package name
|
:pkgname: package name
|
||||||
:must_exist: raise an exception when it can't be found
|
:must_exist: raise an exception when it can't be found
|
||||||
:returns: a string like "main", "device", "cross", ...
|
:returns: a string like "main", "device", "cross", ...
|
||||||
or None when the aport could not be found """
|
or None when the aport could not be found
|
||||||
|
"""
|
||||||
aport = find(args, pkgname, must_exist)
|
aport = find(args, pkgname, must_exist)
|
||||||
if not aport:
|
if not aport:
|
||||||
return None
|
return None
|
||||||
|
@ -262,13 +263,15 @@ def get_repo(args, pkgname, must_exist=True):
|
||||||
|
|
||||||
|
|
||||||
def check_arches(arches, arch):
|
def check_arches(arches, arch):
|
||||||
""" Check if building for a certain arch is allowed.
|
"""Check if building for a certain arch is allowed.
|
||||||
|
|
||||||
:param arches: list of all supported arches, as it can be found in the
|
:param arches: list of all supported arches, as it can be found in the
|
||||||
arch="" line of APKBUILDS (including all, noarch,
|
arch="" line of APKBUILDS (including all, noarch, !arch, ...).
|
||||||
!arch, ...). For example: ["x86_64", "x86", "!armhf"]
|
For example: ["x86_64", "x86", "!armhf"]
|
||||||
:param arch: the architecture to check for
|
|
||||||
:returns: True when building is allowed, False otherwise
|
:param arch: the architecture to check for
|
||||||
|
|
||||||
|
:returns: True when building is allowed, False otherwise
|
||||||
"""
|
"""
|
||||||
if "!" + arch in arches:
|
if "!" + arch in arches:
|
||||||
return False
|
return False
|
||||||
|
@ -279,12 +282,13 @@ def check_arches(arches, arch):
|
||||||
|
|
||||||
|
|
||||||
def get_channel_new(channel):
|
def get_channel_new(channel):
|
||||||
""" Translate legacy channel names to the new ones. Legacy names are still
|
"""Translate legacy channel names to the new ones.
|
||||||
supported for compatibility with old branches (pmb#2015).
|
|
||||||
:param channel: name as read from pmaports.cfg or channels.cfg, like
|
Legacy names are still supported for compatibility with old branches (pmb#2015).
|
||||||
"edge", "v21.03" etc., or potentially a legacy name
|
:param channel: name as read from pmaports.cfg or channels.cfg, like "edge", "v21.03" etc.,
|
||||||
like "stable".
|
or potentially a legacy name like "stable".
|
||||||
:returns: name in the new format, e.g. "edge" or "v21.03"
|
|
||||||
|
:returns: name in the new format, e.g. "edge" or "v21.03"
|
||||||
"""
|
"""
|
||||||
legacy_cfg = pmb.config.pmaports_channels_legacy
|
legacy_cfg = pmb.config.pmaports_channels_legacy
|
||||||
if channel in legacy_cfg:
|
if channel in legacy_cfg:
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
# Copyright 2023 Oliver Smith
|
# Copyright 2023 Oliver Smith
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
"""
|
"""
|
||||||
Functions that work with binary package repos. See also:
|
Functions that work with binary package repos.
|
||||||
|
|
||||||
|
See also:
|
||||||
- pmb/helpers/pmaports.py (work with pmaports)
|
- pmb/helpers/pmaports.py (work with pmaports)
|
||||||
- pmb/helpers/package.py (work with both)
|
- pmb/helpers/package.py (work with both)
|
||||||
"""
|
"""
|
||||||
|
@ -14,9 +16,9 @@ import pmb.helpers.run
|
||||||
|
|
||||||
|
|
||||||
def hash(url, length=8):
|
def hash(url, length=8):
|
||||||
"""
|
r"""Generate the hash that APK adds to the APKINDEX and apk packages in its apk cache folder.
|
||||||
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:
|
It is the "12345678" part in this example:
|
||||||
"APKINDEX.12345678.tar.gz".
|
"APKINDEX.12345678.tar.gz".
|
||||||
|
|
||||||
:param length: The length of the hash in the output file.
|
:param length: The length of the hash in the output file.
|
||||||
|
@ -24,7 +26,7 @@ def hash(url, length=8):
|
||||||
See also: official implementation in apk-tools:
|
See also: official implementation in apk-tools:
|
||||||
<https://git.alpinelinux.org/cgit/apk-tools/>
|
<https://git.alpinelinux.org/cgit/apk-tools/>
|
||||||
|
|
||||||
blob.c: apk_blob_push_hexdump(), "const char *xd"
|
blob.c: apk_blob_push_hexdump(), "const char \\*xd"
|
||||||
apk_defines.h: APK_CACHE_CSUM_BYTES
|
apk_defines.h: APK_CACHE_CSUM_BYTES
|
||||||
database.c: apk_repo_format_cache_index()
|
database.c: apk_repo_format_cache_index()
|
||||||
"""
|
"""
|
||||||
|
@ -41,8 +43,8 @@ def hash(url, length=8):
|
||||||
|
|
||||||
|
|
||||||
def urls(args, user_repository=True, postmarketos_mirror=True, alpine=True):
|
def urls(args, user_repository=True, postmarketos_mirror=True, alpine=True):
|
||||||
"""
|
"""Get a list of repository URLs, as they are in /etc/apk/repositories.
|
||||||
Get a list of repository URLs, as they are in /etc/apk/repositories.
|
|
||||||
:param user_repository: add /mnt/pmbootstrap/packages
|
:param user_repository: add /mnt/pmbootstrap/packages
|
||||||
:param postmarketos_mirror: add postmarketos mirror URLs
|
:param postmarketos_mirror: add postmarketos mirror URLs
|
||||||
:param alpine: add alpine mirror URLs
|
:param alpine: add alpine mirror URLs
|
||||||
|
@ -86,9 +88,8 @@ def urls(args, user_repository=True, postmarketos_mirror=True, alpine=True):
|
||||||
|
|
||||||
def apkindex_files(args, arch=None, user_repository=True, pmos=True,
|
def apkindex_files(args, arch=None, user_repository=True, pmos=True,
|
||||||
alpine=True):
|
alpine=True):
|
||||||
"""
|
"""Get a list of outside paths to all resolved APKINDEX.tar.gz files for a specific arch.
|
||||||
Get a list of outside paths to all resolved APKINDEX.tar.gz files for a
|
|
||||||
specific arch.
|
|
||||||
:param arch: defaults to native
|
:param arch: defaults to native
|
||||||
:param user_repository: add path to index of locally built packages
|
:param user_repository: add path to index of locally built packages
|
||||||
:param pmos: add paths to indexes of postmarketos mirrors
|
:param pmos: add paths to indexes of postmarketos mirrors
|
||||||
|
@ -113,8 +114,7 @@ def apkindex_files(args, arch=None, user_repository=True, pmos=True,
|
||||||
|
|
||||||
|
|
||||||
def update(args, arch=None, force=False, existing_only=False):
|
def update(args, arch=None, force=False, existing_only=False):
|
||||||
"""
|
"""Download the APKINDEX files for all URLs depending on the architectures.
|
||||||
Download the APKINDEX files for all URLs depending on the architectures.
|
|
||||||
|
|
||||||
:param arch: * one Alpine architecture name ("x86_64", "armhf", ...)
|
:param arch: * one Alpine architecture name ("x86_64", "armhf", ...)
|
||||||
* None for all architectures
|
* None for all architectures
|
||||||
|
@ -196,9 +196,7 @@ def update(args, arch=None, force=False, existing_only=False):
|
||||||
|
|
||||||
|
|
||||||
def alpine_apkindex_path(args, repo="main", arch=None):
|
def alpine_apkindex_path(args, repo="main", arch=None):
|
||||||
"""
|
"""Get the path to a specific Alpine APKINDEX file on disk and download it if necessary.
|
||||||
Get the path to a specific Alpine APKINDEX file on disk and download it if
|
|
||||||
necessary.
|
|
||||||
|
|
||||||
:param repo: Alpine repository name (e.g. "main")
|
:param repo: Alpine repository name (e.g. "main")
|
||||||
:param arch: Alpine architecture (e.g. "armhf"), defaults to native arch.
|
:param arch: Alpine architecture (e.g. "armhf"), defaults to native arch.
|
||||||
|
|
|
@ -8,11 +8,12 @@ import pmb.helpers.pmaports
|
||||||
|
|
||||||
|
|
||||||
def filter_missing_packages(args, arch, pkgnames):
|
def filter_missing_packages(args, arch, pkgnames):
|
||||||
""" Create a subset of pkgnames with missing or outdated binary packages.
|
"""Create a subset of pkgnames with missing or outdated binary packages.
|
||||||
|
|
||||||
:param arch: architecture (e.g. "armhf")
|
:param arch: architecture (e.g. "armhf")
|
||||||
:param pkgnames: list of package names (e.g. ["hello-world", "test12"])
|
:param pkgnames: list of package names (e.g. ["hello-world", "test12"])
|
||||||
:returns: subset of pkgnames (e.g. ["hello-world"]) """
|
:returns: subset of pkgnames (e.g. ["hello-world"])
|
||||||
|
"""
|
||||||
ret = []
|
ret = []
|
||||||
for pkgname in pkgnames:
|
for pkgname in pkgnames:
|
||||||
binary = pmb.parse.apkindex.package(args, pkgname, arch, False)
|
binary = pmb.parse.apkindex.package(args, pkgname, arch, False)
|
||||||
|
@ -24,11 +25,12 @@ def filter_missing_packages(args, arch, pkgnames):
|
||||||
|
|
||||||
|
|
||||||
def filter_aport_packages(args, arch, pkgnames):
|
def filter_aport_packages(args, arch, pkgnames):
|
||||||
""" Create a subset of pkgnames where each one has an aport.
|
"""Create a subset of pkgnames where each one has an aport.
|
||||||
|
|
||||||
:param arch: architecture (e.g. "armhf")
|
:param arch: architecture (e.g. "armhf")
|
||||||
:param pkgnames: list of package names (e.g. ["hello-world", "test12"])
|
:param pkgnames: list of package names (e.g. ["hello-world", "test12"])
|
||||||
:returns: subset of pkgnames (e.g. ["hello-world"]) """
|
:returns: subset of pkgnames (e.g. ["hello-world"])
|
||||||
|
"""
|
||||||
ret = []
|
ret = []
|
||||||
for pkgname in pkgnames:
|
for pkgname in pkgnames:
|
||||||
if pmb.helpers.pmaports.find(args, pkgname, False):
|
if pmb.helpers.pmaports.find(args, pkgname, False):
|
||||||
|
@ -37,12 +39,12 @@ def filter_aport_packages(args, arch, pkgnames):
|
||||||
|
|
||||||
|
|
||||||
def filter_arch_packages(args, arch, pkgnames):
|
def filter_arch_packages(args, arch, pkgnames):
|
||||||
""" Create a subset of pkgnames with packages removed that can not be
|
"""Create a subset of pkgnames with packages removed that can not be built for a certain arch.
|
||||||
built for a certain arch.
|
|
||||||
|
|
||||||
:param arch: architecture (e.g. "armhf")
|
:param arch: architecture (e.g. "armhf")
|
||||||
:param pkgnames: list of package names (e.g. ["hello-world", "test12"])
|
:param pkgnames: list of package names (e.g. ["hello-world", "test12"])
|
||||||
:returns: subset of pkgnames (e.g. ["hello-world"]) """
|
:returns: subset of pkgnames (e.g. ["hello-world"])
|
||||||
|
"""
|
||||||
ret = []
|
ret = []
|
||||||
for pkgname in pkgnames:
|
for pkgname in pkgnames:
|
||||||
if pmb.helpers.package.check_arch(args, pkgname, arch, False):
|
if pmb.helpers.package.check_arch(args, pkgname, arch, False):
|
||||||
|
@ -51,13 +53,14 @@ def filter_arch_packages(args, arch, pkgnames):
|
||||||
|
|
||||||
|
|
||||||
def get_relevant_packages(args, arch, pkgname=None, built=False):
|
def get_relevant_packages(args, arch, pkgname=None, built=False):
|
||||||
""" Get all packages that can be built for the architecture in question.
|
"""Get all packages that can be built for the architecture in question.
|
||||||
|
|
||||||
:param arch: architecture (e.g. "armhf")
|
:param arch: architecture (e.g. "armhf")
|
||||||
:param pkgname: only look at a specific package (and its dependencies)
|
:param pkgname: only look at a specific package (and its dependencies)
|
||||||
:param built: include packages that have already been built
|
:param built: include packages that have already been built
|
||||||
:returns: an alphabetically sorted list of pkgnames, e.g.:
|
:returns: an alphabetically sorted list of pkgnames, e.g.:
|
||||||
["devicepkg-dev", "hello-world", "unl0kr"] """
|
["devicepkg-dev", "hello-world", "osk-sdl"]
|
||||||
|
"""
|
||||||
if pkgname:
|
if pkgname:
|
||||||
if not pmb.helpers.package.check_arch(args, pkgname, arch, False):
|
if not pmb.helpers.package.check_arch(args, pkgname, arch, False):
|
||||||
raise RuntimeError(pkgname + " can't be built for " + arch + ".")
|
raise RuntimeError(pkgname + " can't be built for " + arch + ".")
|
||||||
|
@ -84,19 +87,21 @@ def get_relevant_packages(args, arch, pkgname=None, built=False):
|
||||||
|
|
||||||
|
|
||||||
def generate_output_format(args, arch, pkgnames):
|
def generate_output_format(args, arch, pkgnames):
|
||||||
""" Generate the detailed output format.
|
"""Generate the detailed output format.
|
||||||
:param arch: architecture
|
|
||||||
:param pkgnames: list of package names that should be in the output,
|
:param arch: architecture
|
||||||
e.g.: ["hello-world", "pkg-depending-on-hello-world"]
|
:param 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:
|
:returns: a list like the following:
|
||||||
[{"pkgname": "hello-world",
|
[{"pkgname": "hello-world",
|
||||||
"repo": "main",
|
"repo": "main",
|
||||||
"version": "1-r4",
|
"version": "1-r4",
|
||||||
"depends": []},
|
"depends": []},
|
||||||
{"pkgname": "pkg-depending-on-hello-world",
|
{"pkgname": "pkg-depending-on-hello-world",
|
||||||
"version": "0.5-r0",
|
"version": "0.5-r0",
|
||||||
"repo": "main",
|
"repo": "main",
|
||||||
"depends": ["hello-world"]}] """
|
"depends": ["hello-world"]}]
|
||||||
|
"""
|
||||||
ret = []
|
ret = []
|
||||||
for pkgname in pkgnames:
|
for pkgname in pkgnames:
|
||||||
entry = pmb.helpers.package.get(args, pkgname, arch, True)
|
entry = pmb.helpers.package.get(args, pkgname, arch, True)
|
||||||
|
@ -108,18 +113,14 @@ def generate_output_format(args, arch, pkgnames):
|
||||||
|
|
||||||
|
|
||||||
def generate(args, arch, overview, pkgname=None, built=False):
|
def generate(args, arch, overview, pkgname=None, built=False):
|
||||||
""" Get packages that need to be built, with all their dependencies.
|
"""Get packages that need to be built, with all their dependencies.
|
||||||
|
|
||||||
:param arch: architecture (e.g. "armhf")
|
:param arch: architecture (e.g. "armhf")
|
||||||
:param pkgname: only look at a specific package
|
:param pkgname: only look at a specific package
|
||||||
:param built: include packages that have already been built
|
:param built: include packages that have already been built
|
||||||
:returns: a list like the following:
|
:returns: a list like the following:
|
||||||
[{"pkgname": "hello-world",
|
[{"pkgname": "hello-world", "repo": "main", "version": "1-r4"},
|
||||||
"repo": "main",
|
{"pkgname": "package-depending-on-hello-world", "version": "0.5-r0", "repo": "main"}]
|
||||||
"version": "1-r4"},
|
|
||||||
{"pkgname": "package-depending-on-hello-world",
|
|
||||||
"version": "0.5-r0",
|
|
||||||
"repo": "main"}]
|
|
||||||
"""
|
"""
|
||||||
# Log message
|
# Log message
|
||||||
packages_str = pkgname if pkgname else "all packages"
|
packages_str = pkgname if pkgname else "all packages"
|
||||||
|
|
|
@ -35,8 +35,7 @@ def user(args: Namespace, cmd: List[str], working_dir: Optional[str]=None, outpu
|
||||||
|
|
||||||
def root(args, cmd, working_dir=None, output="log", output_return=False,
|
def root(args, cmd, working_dir=None, output="log", output_return=False,
|
||||||
check=None, env={}):
|
check=None, env={}):
|
||||||
"""
|
"""Run a command on the host system as root, with sudo or doas.
|
||||||
Run a command on the host system as root, with sudo or doas.
|
|
||||||
|
|
||||||
:param env: dict of environment variables to be passed to the command, e.g.
|
:param env: dict of environment variables to be passed to the command, e.g.
|
||||||
{"JOBS": "5"}
|
{"JOBS": "5"}
|
||||||
|
|
|
@ -11,15 +11,13 @@ import threading
|
||||||
import time
|
import time
|
||||||
import pmb.helpers.run
|
import pmb.helpers.run
|
||||||
|
|
||||||
""" For a detailed description of all output modes, read the description of
|
"""For a detailed description of all output modes, read the description of
|
||||||
core() at the bottom. All other functions in this file get (indirectly)
|
core() at the bottom. All other functions in this file get (indirectly)
|
||||||
called by core(). """
|
called by core(). """
|
||||||
|
|
||||||
|
|
||||||
def flat_cmd(cmd, working_dir=None, env={}):
|
def flat_cmd(cmd, working_dir=None, env={}):
|
||||||
"""
|
"""Convert a shell command passed as list into a flat shell string with proper escaping.
|
||||||
Convert a shell command passed as list into a flat shell string with
|
|
||||||
proper escaping.
|
|
||||||
|
|
||||||
:param cmd: command as list, e.g. ["echo", "string with spaces"]
|
:param cmd: command as list, e.g. ["echo", "string with spaces"]
|
||||||
:param working_dir: when set, prepend "cd ...;" to execute the command
|
:param working_dir: when set, prepend "cd ...;" to execute the command
|
||||||
|
@ -46,8 +44,8 @@ def flat_cmd(cmd, working_dir=None, env={}):
|
||||||
|
|
||||||
|
|
||||||
def sanity_checks(output="log", output_return=False, check=None):
|
def sanity_checks(output="log", output_return=False, check=None):
|
||||||
"""
|
"""Raise an exception if the parameters passed to core() don't make sense.
|
||||||
Raise an exception if the parameters passed to core() don't make sense
|
|
||||||
(all parameters are described in core() below).
|
(all parameters are described in core() below).
|
||||||
"""
|
"""
|
||||||
vals = ["log", "stdout", "interactive", "tui", "background", "pipe"]
|
vals = ["log", "stdout", "interactive", "tui", "background", "pipe"]
|
||||||
|
@ -66,7 +64,7 @@ def sanity_checks(output="log", output_return=False, check=None):
|
||||||
|
|
||||||
|
|
||||||
def background(cmd, working_dir=None):
|
def background(cmd, working_dir=None):
|
||||||
""" Run a subprocess in background and redirect its output to the log. """
|
"""Run a subprocess in background and redirect its output to the log."""
|
||||||
ret = subprocess.Popen(cmd, stdout=pmb.helpers.logging.logfd,
|
ret = subprocess.Popen(cmd, stdout=pmb.helpers.logging.logfd,
|
||||||
stderr=pmb.helpers.logging.logfd, cwd=working_dir)
|
stderr=pmb.helpers.logging.logfd, cwd=working_dir)
|
||||||
logging.debug(f"New background process: pid={ret.pid}, output=background")
|
logging.debug(f"New background process: pid={ret.pid}, output=background")
|
||||||
|
@ -74,7 +72,7 @@ def background(cmd, working_dir=None):
|
||||||
|
|
||||||
|
|
||||||
def pipe(cmd, working_dir=None):
|
def pipe(cmd, working_dir=None):
|
||||||
""" Run a subprocess in background and redirect its output to a pipe. """
|
"""Run a subprocess in background and redirect its output to a pipe."""
|
||||||
ret = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
ret = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||||
stdin=subprocess.DEVNULL,
|
stdin=subprocess.DEVNULL,
|
||||||
stderr=pmb.helpers.logging.logfd, cwd=working_dir)
|
stderr=pmb.helpers.logging.logfd, cwd=working_dir)
|
||||||
|
@ -84,10 +82,9 @@ def pipe(cmd, working_dir=None):
|
||||||
|
|
||||||
def pipe_read(process, output_to_stdout=False, output_return=False,
|
def pipe_read(process, output_to_stdout=False, output_return=False,
|
||||||
output_return_buffer=False):
|
output_return_buffer=False):
|
||||||
"""
|
"""Read all output from a subprocess, copy it to the log and optionally stdout and a buffer variable.
|
||||||
Read all available output from a subprocess and copy it to the log and
|
|
||||||
optionally stdout and a buffer variable. This is only meant to be called by
|
This is only meant to be called by foreground_pipe() below.
|
||||||
foreground_pipe() below.
|
|
||||||
|
|
||||||
:param process: subprocess.Popen instance
|
:param process: subprocess.Popen instance
|
||||||
:param output_to_stdout: copy all output to pmbootstrap's stdout
|
:param output_to_stdout: copy all output to pmbootstrap's stdout
|
||||||
|
@ -115,8 +112,7 @@ def pipe_read(process, output_to_stdout=False, output_return=False,
|
||||||
|
|
||||||
|
|
||||||
def kill_process_tree(args, pid, ppids, sudo):
|
def kill_process_tree(args, pid, ppids, sudo):
|
||||||
"""
|
"""Recursively kill a pid and its child processes.
|
||||||
Recursively kill a pid and its child processes
|
|
||||||
|
|
||||||
:param pid: process id that will be killed
|
:param pid: process id that will be killed
|
||||||
:param ppids: list of process id and parent process id tuples (pid, ppid)
|
:param ppids: list of process id and parent process id tuples (pid, ppid)
|
||||||
|
@ -135,8 +131,7 @@ def kill_process_tree(args, pid, ppids, sudo):
|
||||||
|
|
||||||
|
|
||||||
def kill_command(args, pid, sudo):
|
def kill_command(args, pid, sudo):
|
||||||
"""
|
"""Kill a command process and recursively kill its child processes.
|
||||||
Kill a command process and recursively kill its child processes
|
|
||||||
|
|
||||||
:param pid: process id that will be killed
|
:param pid: process id that will be killed
|
||||||
:param sudo: use sudo to kill the process
|
:param sudo: use sudo to kill the process
|
||||||
|
@ -157,9 +152,9 @@ def kill_command(args, pid, sudo):
|
||||||
def foreground_pipe(args, cmd, working_dir=None, output_to_stdout=False,
|
def foreground_pipe(args, cmd, working_dir=None, output_to_stdout=False,
|
||||||
output_return=False, output_timeout=True,
|
output_return=False, output_timeout=True,
|
||||||
sudo=False, stdin=None):
|
sudo=False, stdin=None):
|
||||||
"""
|
"""Run a subprocess in foreground with redirected output.
|
||||||
Run a subprocess in foreground with redirected output and optionally kill
|
|
||||||
it after being silent for too long.
|
Optionally kill it after being silent for too long.
|
||||||
|
|
||||||
:param cmd: command as list, e.g. ["echo", "string with spaces"]
|
:param cmd: command as list, e.g. ["echo", "string with spaces"]
|
||||||
:param working_dir: path in host system where the command should run
|
:param working_dir: path in host system where the command should run
|
||||||
|
@ -220,13 +215,11 @@ def foreground_pipe(args, cmd, working_dir=None, output_to_stdout=False,
|
||||||
|
|
||||||
|
|
||||||
def foreground_tui(cmd, working_dir=None):
|
def foreground_tui(cmd, working_dir=None):
|
||||||
"""
|
"""Run a subprocess in foreground without redirecting any of its output.
|
||||||
Run a subprocess in foreground without redirecting any of its output.
|
|
||||||
|
|
||||||
This is the only way text-based user interfaces (ncurses programs like
|
This is the only way text-based user interfaces (ncurses programs like
|
||||||
vim, nano or the kernel's menuconfig) work properly.
|
vim, nano or the kernel's menuconfig) work properly.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
logging.debug("*** output passed to pmbootstrap stdout, not to this log"
|
logging.debug("*** output passed to pmbootstrap stdout, not to this log"
|
||||||
" ***")
|
" ***")
|
||||||
process = subprocess.Popen(cmd, cwd=working_dir)
|
process = subprocess.Popen(cmd, cwd=working_dir)
|
||||||
|
@ -234,8 +227,7 @@ def foreground_tui(cmd, working_dir=None):
|
||||||
|
|
||||||
|
|
||||||
def check_return_code(args, code, log_message):
|
def check_return_code(args, code, log_message):
|
||||||
"""
|
"""Check the return code of a command.
|
||||||
Check the return code of a command.
|
|
||||||
|
|
||||||
:param code: exit code to check
|
:param code: exit code to check
|
||||||
:param log_message: simplified and more readable form of the command, e.g.
|
:param log_message: simplified and more readable form of the command, e.g.
|
||||||
|
@ -243,7 +235,6 @@ def check_return_code(args, code, log_message):
|
||||||
entering the chroot and more escaping
|
entering the chroot and more escaping
|
||||||
:raises RuntimeError: when the code indicates that the command failed
|
:raises RuntimeError: when the code indicates that the command failed
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if code:
|
if code:
|
||||||
logging.debug("^" * 70)
|
logging.debug("^" * 70)
|
||||||
logging.info("NOTE: The failed command's output is above the ^^^ line"
|
logging.info("NOTE: The failed command's output is above the ^^^ line"
|
||||||
|
@ -253,10 +244,7 @@ def check_return_code(args, code, log_message):
|
||||||
|
|
||||||
|
|
||||||
def sudo_timer_iterate():
|
def sudo_timer_iterate():
|
||||||
"""
|
"""Run sudo -v and schedule a new timer to repeat the same."""
|
||||||
Run sudo -v and schedule a new timer to repeat the same.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if pmb.config.which_sudo() == "sudo":
|
if pmb.config.which_sudo() == "sudo":
|
||||||
subprocess.Popen(["sudo", "-v"]).wait()
|
subprocess.Popen(["sudo", "-v"]).wait()
|
||||||
else:
|
else:
|
||||||
|
@ -268,11 +256,7 @@ def sudo_timer_iterate():
|
||||||
|
|
||||||
|
|
||||||
def sudo_timer_start():
|
def sudo_timer_start():
|
||||||
"""
|
"""Start a timer to call sudo -v periodically, so that the password is only needed once."""
|
||||||
Start a timer to call sudo -v periodically, so that the password is only
|
|
||||||
needed once.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if "sudo_timer_active" in pmb.helpers.other.cache:
|
if "sudo_timer_active" in pmb.helpers.other.cache:
|
||||||
return
|
return
|
||||||
pmb.helpers.other.cache["sudo_timer_active"] = True
|
pmb.helpers.other.cache["sudo_timer_active"] = True
|
||||||
|
@ -281,11 +265,10 @@ def sudo_timer_start():
|
||||||
|
|
||||||
|
|
||||||
def add_proxy_env_vars(env):
|
def add_proxy_env_vars(env):
|
||||||
"""
|
"""Add proxy environment variables from host to the environment of the command we are running.
|
||||||
Add proxy environment variables present on the host to the environment of
|
|
||||||
the command we are running.
|
:param env: dict of environment variables, it will be extended with all of the proxy env vars
|
||||||
:param env: dict of environment variables, it will be extended with all of
|
that are set on the host
|
||||||
the proxy env vars that are set on the host
|
|
||||||
"""
|
"""
|
||||||
proxy_env_vars = [
|
proxy_env_vars = [
|
||||||
"FTP_PROXY",
|
"FTP_PROXY",
|
||||||
|
@ -304,12 +287,11 @@ def add_proxy_env_vars(env):
|
||||||
|
|
||||||
def core(args, log_message, cmd, working_dir=None, output="log",
|
def core(args, log_message, cmd, working_dir=None, output="log",
|
||||||
output_return=False, check=None, sudo=False, disable_timeout=False):
|
output_return=False, check=None, sudo=False, disable_timeout=False):
|
||||||
"""
|
"""Run a command and create a log entry.
|
||||||
Run a command and create a log entry.
|
|
||||||
|
|
||||||
This is a low level function not meant to be used directly. Use one of the
|
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(),
|
following instead: pmb.helpers.run.user(), pmb.helpers.run.root(),
|
||||||
pmb.chroot.user(), pmb.chroot.root()
|
pmb.chroot.user(), pmb.chroot.root()
|
||||||
|
|
||||||
:param log_message: simplified and more readable form of the command, e.g.
|
:param log_message: simplified and more readable form of the command, e.g.
|
||||||
"(native) % echo test" instead of the full command with
|
"(native) % echo test" instead of the full command with
|
||||||
|
@ -337,24 +319,23 @@ def core(args, log_message, cmd, working_dir=None, output="log",
|
||||||
their properties. "wait" indicates that we wait for the
|
their properties. "wait" indicates that we wait for the
|
||||||
process to complete.
|
process to complete.
|
||||||
|
|
||||||
output value | timeout | out to log | out to stdout | wait | pass stdin
|
============= ======= ========== ============= ==== ==========
|
||||||
------------------------------------------------------------------------
|
output value timeout out to log out to stdout wait pass stdin
|
||||||
"log" | x | x | | x |
|
============= ======= ========== ============= ==== ==========
|
||||||
"stdout" | x | x | x | x |
|
"log" x x x
|
||||||
"interactive" | | x | x | x | x
|
"stdout" x x x x
|
||||||
"tui" | | | x | x | x
|
"interactive" x x x x
|
||||||
"background" | | x | | |
|
"tui" x x x
|
||||||
"pipe" | | | | |
|
"background" x
|
||||||
|
"pipe"
|
||||||
|
============= ======= ========== ============= ==== ==========
|
||||||
|
|
||||||
:param output_return: in addition to writing the program's output to the
|
:param output_return: in addition to writing the program's output to the
|
||||||
destinations above in real time, write to a buffer
|
destinations above in real time, write to a buffer and return it as string when the
|
||||||
and return it as string when the command has
|
command has completed. This is not possible when output is "background", "pipe" or "tui".
|
||||||
completed. This is not possible when output is
|
:param check: an exception will be raised when the command's return code is not 0.
|
||||||
"background", "pipe" or "tui".
|
Set this to False to disable the check. This parameter can not be used when the output is
|
||||||
:param check: an exception will be raised when the command's return code
|
"background" or "pipe".
|
||||||
is not 0. Set this to False to disable the check. This
|
|
||||||
parameter can not be used when the output is "background" or
|
|
||||||
"pipe".
|
|
||||||
:param sudo: use sudo to kill the process when it hits the timeout.
|
:param sudo: use sudo to kill the process when it hits the timeout.
|
||||||
:returns: * program's return code (default)
|
:returns: * program's return code (default)
|
||||||
* subprocess.Popen instance (output is "background" or "pipe")
|
* subprocess.Popen instance (output is "background" or "pipe")
|
||||||
|
|
|
@ -7,8 +7,7 @@ import pmb.parse
|
||||||
|
|
||||||
|
|
||||||
def list(args, arch):
|
def list(args, arch):
|
||||||
"""
|
"""Get all UIs, for which aports are available with their description.
|
||||||
Get all UIs, for which aports are available with their description.
|
|
||||||
|
|
||||||
:param arch: device architecture, for which the UIs must be available
|
:param arch: device architecture, for which the UIs must be available
|
||||||
:returns: [("none", "No graphical..."), ("weston", "Wayland reference...")]
|
:returns: [("none", "No graphical..."), ("weston", "Wayland reference...")]
|
||||||
|
|
|
@ -11,30 +11,27 @@ import pmb.parse.version
|
||||||
|
|
||||||
|
|
||||||
def parse_next_block(path, lines, start):
|
def parse_next_block(path, lines, start):
|
||||||
"""
|
"""Parse the next block in an APKINDEX.
|
||||||
Parse the next block in an APKINDEX.
|
|
||||||
|
|
||||||
:param path: to the APKINDEX.tar.gz
|
:param path: to the APKINDEX.tar.gz
|
||||||
:param start: current index in lines, gets increased in this
|
:param start: current index in lines, gets increased in this
|
||||||
function. Wrapped into a list, so it can be modified
|
function. Wrapped into a list, so it can be modified
|
||||||
"by reference". Example: [5]
|
"by reference". Example: [5]
|
||||||
:param lines: all lines from the "APKINDEX" file inside the archive
|
:param lines: all lines from the "APKINDEX" file inside the archive
|
||||||
:returns: a dictionary with the following structure:
|
:returns: Dictionary with the following structure:
|
||||||
{ "arch": "noarch",
|
``{ "arch": "noarch", "depends": ["busybox-extras", "lddtree", ... ],
|
||||||
"depends": ["busybox-extras", "lddtree", ... ],
|
"origin": "postmarketos-mkinitfs",
|
||||||
"origin": "postmarketos-mkinitfs",
|
"pkgname": "postmarketos-mkinitfs",
|
||||||
"pkgname": "postmarketos-mkinitfs",
|
"provides": ["mkinitfs=0.0.1"],
|
||||||
"provides": ["mkinitfs=0.0.1"],
|
"timestamp": "1500000000",
|
||||||
"timestamp": "1500000000",
|
"version": "0.0.4-r10" }``
|
||||||
"version": "0.0.4-r10" }
|
|
||||||
NOTE: "depends" is not set for packages without any dependencies,
|
NOTE: "depends" is not set for packages without any dependencies, e.g. ``musl``.
|
||||||
e.g. musl.
|
|
||||||
NOTE: "timestamp" and "origin" are not set for virtual packages
|
NOTE: "timestamp" and "origin" are not set for virtual packages (#1273).
|
||||||
(#1273). We use that information to skip these virtual
|
We use that information to skip these virtual packages in parse().
|
||||||
packages in parse().
|
|
||||||
:returns: None, when there are no more blocks
|
:returns: None, when there are no more blocks
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Parse until we hit an empty line or end of file
|
# Parse until we hit an empty line or end of file
|
||||||
ret = {}
|
ret = {}
|
||||||
mapping = {
|
mapping = {
|
||||||
|
@ -100,8 +97,7 @@ def parse_next_block(path, lines, start):
|
||||||
|
|
||||||
|
|
||||||
def parse_add_block(ret, block, alias=None, multiple_providers=True):
|
def parse_add_block(ret, block, alias=None, multiple_providers=True):
|
||||||
"""
|
"""Add one block to the return dictionary of parse().
|
||||||
Add one block to the return dictionary of parse().
|
|
||||||
|
|
||||||
:param ret: dictionary of all packages in the APKINDEX that is
|
:param ret: dictionary of all packages in the APKINDEX that is
|
||||||
getting built right now. This function will extend it.
|
getting built right now. This function will extend it.
|
||||||
|
@ -113,7 +109,6 @@ def parse_add_block(ret, block, alias=None, multiple_providers=True):
|
||||||
APKINDEX files from a repository (#1122), but
|
APKINDEX files from a repository (#1122), but
|
||||||
not when parsing apk's installed packages DB.
|
not when parsing apk's installed packages DB.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Defaults
|
# Defaults
|
||||||
pkgname = block["pkgname"]
|
pkgname = block["pkgname"]
|
||||||
alias = alias or pkgname
|
alias = alias or pkgname
|
||||||
|
@ -142,8 +137,7 @@ def parse_add_block(ret, block, alias=None, multiple_providers=True):
|
||||||
|
|
||||||
|
|
||||||
def parse(path, multiple_providers=True):
|
def parse(path, multiple_providers=True):
|
||||||
"""
|
r"""Parse an APKINDEX.tar.gz file, and return its content as dictionary.
|
||||||
Parse an APKINDEX.tar.gz file, and return its content as dictionary.
|
|
||||||
|
|
||||||
:param path: path to an APKINDEX.tar.gz file or apk package database
|
:param path: path to an APKINDEX.tar.gz file or apk package database
|
||||||
(almost the same format, but not compressed).
|
(almost the same format, but not compressed).
|
||||||
|
@ -152,22 +146,23 @@ def parse(path, multiple_providers=True):
|
||||||
APKINDEX files from a repository (#1122), but
|
APKINDEX files from a repository (#1122), but
|
||||||
not when parsing apk's installed packages DB.
|
not when parsing apk's installed packages DB.
|
||||||
:returns: (without multiple_providers)
|
:returns: (without multiple_providers)
|
||||||
generic format:
|
|
||||||
{ pkgname: block, ... }
|
|
||||||
|
|
||||||
example:
|
Generic format:
|
||||||
{ "postmarketos-mkinitfs": block,
|
``{ pkgname: block, ... }``
|
||||||
"so:libGL.so.1": block, ...}
|
|
||||||
|
Example:
|
||||||
|
``{ "postmarketos-mkinitfs": block, "so:libGL.so.1": block, ...}``
|
||||||
|
|
||||||
:returns: (with multiple_providers)
|
:returns: (with multiple_providers)
|
||||||
generic format:
|
|
||||||
{ provide: { pkgname: block, ... }, ... }
|
|
||||||
|
|
||||||
example:
|
Generic format:
|
||||||
{ "postmarketos-mkinitfs": {"postmarketos-mkinitfs": block},
|
``{ provide: { pkgname: block, ... }, ... }``
|
||||||
"so:libGL.so.1": {"mesa-egl": block, "libhybris": block}, ...}
|
|
||||||
|
Example:
|
||||||
|
``{ "postmarketos-mkinitfs": {"postmarketos-mkinitfs": block},"so:libGL.so.1": {"mesa-egl": block, "libhybris": block}, ...}``
|
||||||
|
|
||||||
|
*NOTE:* ``block`` is the return value from ``parse_next_block()`` above.
|
||||||
|
|
||||||
NOTE: "block" is the return value from parse_next_block() above.
|
|
||||||
"""
|
"""
|
||||||
# Require the file to exist
|
# Require the file to exist
|
||||||
if not os.path.isfile(path):
|
if not os.path.isfile(path):
|
||||||
|
@ -230,7 +225,7 @@ def parse_blocks(path):
|
||||||
:returns: all blocks in the APKINDEX, without restructuring them by
|
:returns: all blocks in the APKINDEX, without restructuring them by
|
||||||
pkgname or removing duplicates with lower versions (use
|
pkgname or removing duplicates with lower versions (use
|
||||||
parse() if you need these features). Structure:
|
parse() if you need these features). Structure:
|
||||||
[block, block, ...]
|
``[block, block, ...]``
|
||||||
|
|
||||||
NOTE: "block" is the return value from parse_next_block() above.
|
NOTE: "block" is the return value from parse_next_block() above.
|
||||||
"""
|
"""
|
||||||
|
@ -276,10 +271,9 @@ def providers(args, package, arch=None, must_exist=True, indexes=None):
|
||||||
:param indexes: list of APKINDEX.tar.gz paths, defaults to all index files
|
:param indexes: list of APKINDEX.tar.gz paths, defaults to all index files
|
||||||
(depending on arch)
|
(depending on arch)
|
||||||
:returns: list of parsed packages. Example for package="so:libGL.so.1":
|
:returns: list of parsed packages. Example for package="so:libGL.so.1":
|
||||||
{"mesa-egl": block, "libhybris": block}
|
``{"mesa-egl": block, "libhybris": block}``
|
||||||
block is the return value from parse_next_block() above.
|
block is the return value from parse_next_block() above.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not indexes:
|
if not indexes:
|
||||||
arch = arch or pmb.config.arch_native
|
arch = arch or pmb.config.arch_native
|
||||||
indexes = pmb.helpers.repo.apkindex_files(args, arch)
|
indexes = pmb.helpers.repo.apkindex_files(args, arch)
|
||||||
|
@ -319,8 +313,7 @@ def providers(args, package, arch=None, must_exist=True, indexes=None):
|
||||||
|
|
||||||
|
|
||||||
def provider_highest_priority(providers, pkgname):
|
def provider_highest_priority(providers, pkgname):
|
||||||
"""
|
"""Get the provider(s) with the highest provider_priority and log a message.
|
||||||
Get the provider(s) with the highest provider_priority and log a message.
|
|
||||||
|
|
||||||
:param providers: returned dict from providers(), must not be empty
|
:param providers: returned dict from providers(), must not be empty
|
||||||
:param pkgname: the package name we are interested in (for the log message)
|
:param pkgname: the package name we are interested in (for the log message)
|
||||||
|
@ -346,8 +339,7 @@ def provider_highest_priority(providers, pkgname):
|
||||||
|
|
||||||
|
|
||||||
def provider_shortest(providers, pkgname):
|
def provider_shortest(providers, pkgname):
|
||||||
"""
|
"""Get the provider with the shortest pkgname and log a message. In most cases
|
||||||
Get the provider with the shortest pkgname and log a message. In most cases
|
|
||||||
this should be sufficient, e.g. 'mesa-purism-gc7000-egl, mesa-egl' or
|
this should be sufficient, e.g. 'mesa-purism-gc7000-egl, mesa-egl' or
|
||||||
'gtk+2.0-maemo, gtk+2.0'.
|
'gtk+2.0-maemo, gtk+2.0'.
|
||||||
|
|
||||||
|
@ -374,10 +366,10 @@ def package(args, package, arch=None, must_exist=True, indexes=None):
|
||||||
(depending on arch)
|
(depending on arch)
|
||||||
:returns: a dictionary with the following structure:
|
:returns: a dictionary with the following structure:
|
||||||
{ "arch": "noarch",
|
{ "arch": "noarch",
|
||||||
"depends": ["busybox-extras", "lddtree", ... ],
|
"depends": ["busybox-extras", "lddtree", ... ],
|
||||||
"pkgname": "postmarketos-mkinitfs",
|
"pkgname": "postmarketos-mkinitfs",
|
||||||
"provides": ["mkinitfs=0.0.1"],
|
"provides": ["mkinitfs=0.0.1"],
|
||||||
"version": "0.0.4-r10" }
|
"version": "0.0.4-r10" }
|
||||||
or None when the package was not found.
|
or None when the package was not found.
|
||||||
"""
|
"""
|
||||||
# Provider with the same package
|
# Provider with the same package
|
||||||
|
|
|
@ -15,23 +15,27 @@ import pmb.parse.arch
|
||||||
import pmb.helpers.args
|
import pmb.helpers.args
|
||||||
import pmb.helpers.pmaports
|
import pmb.helpers.pmaports
|
||||||
|
|
||||||
""" This file is about parsing command line arguments passed to pmbootstrap, as
|
"""This file is about parsing command line arguments passed to pmbootstrap, as
|
||||||
well as generating the help pages (pmbootstrap -h). All this is done with
|
well as generating the help pages (pmbootstrap -h). All this is done with
|
||||||
Python's argparse. The parsed arguments get extended and finally stored in
|
Python's argparse. The parsed arguments get extended and finally stored in
|
||||||
the "args" variable, which is prominently passed to most functions all
|
the "args" variable, which is prominently passed to most functions all
|
||||||
over the pmbootstrap code base.
|
over the pmbootstrap code base.
|
||||||
|
|
||||||
See pmb/helpers/args.py for more information about the args variable. """
|
See pmb/helpers/args.py for more information about the args variable.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def toggle_other_boolean_flags(*other_destinations, value=True):
|
def toggle_other_boolean_flags(*other_destinations, value=True):
|
||||||
""" Helper function to group several argparse flags to one. Sets multiple
|
"""Group several argparse flags to one.
|
||||||
other_destination to value.
|
|
||||||
|
|
||||||
:param other_destinations: 'the other argument names' str
|
Sets multiple other_destination to value.
|
||||||
:param value 'the value to set the other_destinations to' bool
|
|
||||||
:returns custom Action"""
|
|
||||||
|
|
||||||
|
:param other_destinations: 'the other argument names' str
|
||||||
|
|
||||||
|
:param value 'the value to set the other_destinations to' bool
|
||||||
|
|
||||||
|
:returns custom Action
|
||||||
|
"""
|
||||||
class SetOtherDestinationsAction(argparse.Action):
|
class SetOtherDestinationsAction(argparse.Action):
|
||||||
def __init__(self, option_strings, dest, **kwargs):
|
def __init__(self, option_strings, dest, **kwargs):
|
||||||
super().__init__(option_strings, dest, nargs=0, const=value,
|
super().__init__(option_strings, dest, nargs=0, const=value,
|
||||||
|
@ -45,10 +49,12 @@ def toggle_other_boolean_flags(*other_destinations, value=True):
|
||||||
|
|
||||||
|
|
||||||
def type_ondev_cp(val):
|
def type_ondev_cp(val):
|
||||||
""" Parse and validate arguments to 'pmbootstrap install --ondev --cp'.
|
"""Parse and validate arguments to 'pmbootstrap install --ondev --cp'.
|
||||||
|
|
||||||
:param val: 'HOST_SRC:CHROOT_DEST' string
|
:param val: 'HOST_SRC:CHROOT_DEST' string
|
||||||
:returns: (HOST_SRC, CHROOT_DEST) """
|
|
||||||
|
:returns: (HOST_SRC, CHROOT_DEST)
|
||||||
|
"""
|
||||||
ret = val.split(":")
|
ret = val.split(":")
|
||||||
|
|
||||||
if len(ret) != 2:
|
if len(ret) != 2:
|
||||||
|
|
|
@ -18,7 +18,7 @@ def get_mtk_label(path):
|
||||||
an extracted boot.img.
|
an extracted boot.img.
|
||||||
:param path: to either the kernel or ramdisk extracted from boot.img
|
:param path: to either the kernel or ramdisk extracted from boot.img
|
||||||
:returns: * None: file does not exist or does not have MediaTek header
|
:returns: * None: file does not exist or does not have MediaTek header
|
||||||
* Label string (e.g. "ROOTFS", "KERNEL") """
|
* Label string (e.g. "ROOTFS", "KERNEL") """
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -48,7 +48,8 @@ def get_qcdt_type(path):
|
||||||
""" Get the dt.img type by reading the first four bytes of the file.
|
""" Get the dt.img type by reading the first four bytes of the file.
|
||||||
:param path: to the qcdt image extracted from boot.img
|
:param path: to the qcdt image extracted from boot.img
|
||||||
:returns: * None: dt.img is of unknown type
|
:returns: * None: dt.img is of unknown type
|
||||||
* Type string (e.g. "qcom", "sprd", "exynos") """
|
* Type string (e.g. "qcom", "sprd", "exynos")
|
||||||
|
"""
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,7 @@ def check_config_options_set(config, config_path, config_arch, options,
|
||||||
component, pkgver, details=False):
|
component, pkgver, details=False):
|
||||||
"""
|
"""
|
||||||
Check, whether all the kernel config passes all rules of one component.
|
Check, whether all the kernel config passes all rules of one component.
|
||||||
|
|
||||||
Print a warning if any is missing.
|
Print a warning if any is missing.
|
||||||
|
|
||||||
:param config: full kernel config as string
|
:param config: full kernel config as string
|
||||||
|
@ -128,10 +129,10 @@ def check_config_options_set(config, config_path, config_arch, options,
|
||||||
:param config_arch: architecture name (alpine format, e.g. aarch64, x86_64)
|
:param config_arch: architecture name (alpine format, e.g. aarch64, x86_64)
|
||||||
:param options: kconfig_options* var passed from pmb/config/__init__.py:
|
:param options: kconfig_options* var passed from pmb/config/__init__.py:
|
||||||
kconfig_options_example = {
|
kconfig_options_example = {
|
||||||
">=0.0.0": { # all versions
|
">=0.0.0": { # all versions
|
||||||
"all": { # all arches
|
"all": { # all arches
|
||||||
"ANDROID_PARANOID_NETWORK": False,
|
"ANDROID_PARANOID_NETWORK": False,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
:param component: name of the component to test (postmarketOS, waydroid, …)
|
:param component: name of the component to test (postmarketOS, waydroid, …)
|
||||||
:param pkgver: kernel version
|
:param pkgver: kernel version
|
||||||
|
|
|
@ -101,9 +101,9 @@ def parse_suffix(rest):
|
||||||
:returns: (rest, value, invalid_suffix)
|
:returns: (rest, value, invalid_suffix)
|
||||||
- rest: is the input "rest" string without the suffix
|
- rest: is the input "rest" string without the suffix
|
||||||
- value: is a signed integer (negative for pre-,
|
- value: is a signed integer (negative for pre-,
|
||||||
positive for post-suffixes).
|
positive for post-suffixes).
|
||||||
- invalid_suffix: is true, when rest does not start
|
- invalid_suffix: is true, when rest does not start
|
||||||
with anything from the suffixes variable.
|
with anything from the suffixes variable.
|
||||||
|
|
||||||
C equivalent: get_token(), case TOKEN_SUFFIX
|
C equivalent: get_token(), case TOKEN_SUFFIX
|
||||||
"""
|
"""
|
||||||
|
@ -284,6 +284,7 @@ def check_string(a_version, rule):
|
||||||
:param a_version: "3.4.1"
|
:param a_version: "3.4.1"
|
||||||
:param rule: ">=1.0.0"
|
:param rule: ">=1.0.0"
|
||||||
:returns: True if a_version matches rule, false otherwise.
|
:returns: True if a_version matches rule, false otherwise.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Operators and the expected returns of compare(a,b)
|
# Operators and the expected returns of compare(a,b)
|
||||||
operator_results = {">=": [1, 0],
|
operator_results = {">=": [1, 0],
|
||||||
|
|
|
@ -35,7 +35,9 @@ def system_image(args):
|
||||||
def create_second_storage(args):
|
def create_second_storage(args):
|
||||||
"""
|
"""
|
||||||
Generate a second storage image if it does not exist.
|
Generate a second storage image if it does not exist.
|
||||||
|
|
||||||
:returns: path to the image or None
|
:returns: path to the image or None
|
||||||
|
|
||||||
"""
|
"""
|
||||||
path = f"{args.work}/chroot_native/home/pmos/rootfs/{args.device}-2nd.img"
|
path = f"{args.work}/chroot_native/home/pmos/rootfs/{args.device}-2nd.img"
|
||||||
pmb.helpers.run.root(args, ["touch", path])
|
pmb.helpers.run.root(args, ["touch", path])
|
||||||
|
|
Loading…
Reference in New Issue