mirror of
https://gitlab.postmarketos.org/postmarketOS/pmbootstrap.git
synced 2025-07-13 03:19:47 +03:00
Replace "args.logfd" with "pmb.helpers.logging.logfd" in order to avoid passing "args" to all functions that only use it to write to logfd. This is the first step to get rid of this args-passed-to-all-functions pattern in pmbootstrap.
190 lines
7.2 KiB
Python
190 lines
7.2 KiB
Python
# Copyright 2021 Oliver Smith
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
import copy
|
|
import os
|
|
import pmb.config
|
|
import pmb.helpers.git
|
|
|
|
""" 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
|
|
information it stores.
|
|
|
|
1. Argparse
|
|
Variables directly from command line argument parsing (see
|
|
pmb/parse/arguments.py, the "dest" parameter of the add_argument()
|
|
calls defines where it is stored in args).
|
|
|
|
Examples:
|
|
args.action ("zap", "chroot", "build" etc.)
|
|
args.as_root (True when --as-root is passed)
|
|
...
|
|
|
|
2. Argparse merged with others
|
|
Variables from the user's config file (~/.config/pmbootstrap.cfg) that
|
|
can be overridden from the command line (pmb/parse/arguments.py) and
|
|
fall back to the defaults defined in pmb/config/__init__.py (see
|
|
"defaults = {..."). The user's config file gets generated interactively
|
|
with "pmbootstrap init".
|
|
|
|
Examples:
|
|
args.aports ("$WORK/cache_git/pmaports", override with --aports)
|
|
args.device ("samsung-i9100", "qemu-amd64" etc.)
|
|
args.work ("/home/user/.local/var/pmbootstrap", override with --work)
|
|
|
|
3. Shortcuts
|
|
Long variables or function calls that always return the same information
|
|
may have a shortcut defined, to make the code more readable (see
|
|
add_shortcuts() below).
|
|
|
|
Example:
|
|
args.arch_native ("x86_64" etc.)
|
|
|
|
4. Cache
|
|
pmbootstrap uses this dictionary to save the result of expensive
|
|
results, so they work a lot faster the next time they are needed in the
|
|
same session. Usually the cache is written to and read from in the same
|
|
Python file, with code similar to the following:
|
|
|
|
def lookup(args, key):
|
|
if key in args.cache["mycache"]:
|
|
return args.cache["mycache"][key]
|
|
ret = expensive_operation(args, key)
|
|
args.cache["mycache"][key] = ret
|
|
return ret
|
|
|
|
See add_cache() below for details.
|
|
|
|
5. Parsed configs
|
|
Similar to the cache above, specific config files get parsed and added
|
|
to args, so they can get accessed quickly (without parsing the configs
|
|
over and over). These configs are not only used in one specific
|
|
location, so having a short name for them increases readability of the
|
|
code as well.
|
|
|
|
Examples:
|
|
args.deviceinfo (e.g. {"name": "Mydevice", "arch": "armhf", ...})
|
|
"""
|
|
|
|
|
|
def fix_mirrors_postmarketos(args):
|
|
""" Fix args.mirrors_postmarketos when it is supposed to be empty or the
|
|
default value.
|
|
|
|
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
|
|
specify multiple custom mirrors by specifying -mp multiple times on the
|
|
command line. Here we fix the default and no mirrors case.
|
|
|
|
NOTE: we don't use nargs="+", because it does not play nicely with
|
|
subparsers: <https://bugs.python.org/issue9338> """
|
|
# -mp not specified: use default mirrors
|
|
if not args.mirrors_postmarketos:
|
|
cfg = pmb.config.load(args)
|
|
args.mirrors_postmarketos = \
|
|
cfg["pmbootstrap"]["mirrors_postmarketos"].split(",")
|
|
|
|
# -mp="": use no postmarketOS mirrors (build everything locally)
|
|
if args.mirrors_postmarketos == [""]:
|
|
args.mirrors_postmarketos = []
|
|
|
|
|
|
def check_pmaports_path(args):
|
|
""" 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. """
|
|
if args.from_argparse.aports and not os.path.exists(args.aports):
|
|
raise ValueError("pmaports path (specified with --aports) does"
|
|
" not exist: " + args.aports)
|
|
|
|
|
|
def replace_placeholders(args):
|
|
""" Replace $WORK and ~ (for path variables) in variables from any config
|
|
(user's config file, default config settings or config parameters
|
|
specified on commandline) """
|
|
|
|
# Replace $WORK
|
|
for key, value in pmb.config.defaults.items():
|
|
if key not in args:
|
|
continue
|
|
old = getattr(args, key)
|
|
if isinstance(old, str):
|
|
setattr(args, key, old.replace("$WORK", args.work))
|
|
|
|
# Replace ~ (path variables only)
|
|
for key in ["aports", "config", "log", "work"]:
|
|
if key in args:
|
|
setattr(args, key, os.path.expanduser(getattr(args, key)))
|
|
|
|
|
|
def add_shortcuts(args):
|
|
""" Add convenience shortcuts """
|
|
setattr(args, "arch_native", pmb.parse.arch.alpine_native())
|
|
|
|
|
|
def add_cache(args):
|
|
""" Add a caching dict (caches parsing of files etc. for the current
|
|
session) """
|
|
repo_update = {"404": [], "offline_msg_shown": False}
|
|
setattr(args, "cache", {"apkindex": {},
|
|
"apkbuild": {},
|
|
"apk_min_version_checked": [],
|
|
"apk_repository_list_updated": [],
|
|
"built": {},
|
|
"find_aport": {},
|
|
"pmb.helpers.package.depends_recurse": {},
|
|
"pmb.helpers.package.get": {},
|
|
"pmb.helpers.repo.update": repo_update,
|
|
"pmb.helpers.git.parse_channels_cfg": {},
|
|
"pmb.config.pmaports.read_config": None})
|
|
|
|
|
|
def add_deviceinfo(args):
|
|
""" Add and verify the deviceinfo (only after initialization) """
|
|
setattr(args, "deviceinfo", pmb.parse.deviceinfo(args))
|
|
arch = args.deviceinfo["arch"]
|
|
if (arch != args.arch_native and
|
|
arch not in pmb.config.build_device_architectures):
|
|
raise ValueError("Arch '" + arch + "' is not available in"
|
|
" postmarketOS. If you would like to add it, see:"
|
|
" <https://postmarketos.org/newarch>")
|
|
|
|
|
|
def init(args):
|
|
# Basic initialization
|
|
fix_mirrors_postmarketos(args)
|
|
pmb.config.merge_with_args(args)
|
|
replace_placeholders(args)
|
|
add_shortcuts(args)
|
|
add_cache(args)
|
|
|
|
# Initialize logs (we could raise errors below)
|
|
pmb.helpers.logging.init(args)
|
|
|
|
# Initialization code which may raise errors
|
|
check_pmaports_path(args)
|
|
if args.action not in ["init", "config", "bootimg_analyze", "log",
|
|
"pull", "shutdown", "zap"]:
|
|
pmb.config.pmaports.read_config(args)
|
|
add_deviceinfo(args)
|
|
pmb.helpers.git.parse_channels_cfg(args)
|
|
|
|
return args
|
|
|
|
|
|
def update_work(args, work):
|
|
""" Update the work path in args.work and wherever $WORK was used. """
|
|
# Start with the unmodified args from argparse
|
|
args_new = copy.deepcopy(args.from_argparse)
|
|
|
|
# Keep from the modified args:
|
|
# * the unmodified args from argparse (to check if --aports was specified)
|
|
args_new.from_argparse = args.from_argparse
|
|
|
|
# Generate modified args again, replacing $WORK with the new work folder
|
|
# When args.log is different, this also opens the log in the new location
|
|
args_new.work = work
|
|
args_new = pmb.helpers.args.init(args_new)
|
|
|
|
# Overwrite old attributes of args with the new attributes
|
|
for key in vars(args_new):
|
|
setattr(args, key, getattr(args_new, key))
|