Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • postmarketOS/pmbootstrap
  • fossdd/pmbootstrap
  • Adrian/pmbootstrap
  • JustSoup321/pmbootstrap
  • longnoserob/pmbootstrap
  • sixthkrum/pmbootstrap
  • ollieparanoid/pmbootstrap
  • magdesign/pmbootstrap
  • anjandev/pmbootstrap
  • HenriDellal/pmbootstrap
  • Minecrell/pmbootstrap
  • chipiguay/pmbootstrap
  • ijiki16/pmbootstrap
  • whynothugo/pmbootstrap
  • amessier/pmbootstrap
  • Eisenbahnfan/pmbootstrap
  • user0-07161/pmbootstrap
  • SzczurekYT/pmbootstrap
  • neuschaefer/pmbootstrap
  • knuxify/pmbootstrap
  • Frieder.Hannenheim/pmbootstrap
  • tgirl/pmbootstrap
22 results
Show changes
Commits on Source (16)
Showing
with 285 additions and 150 deletions
......@@ -17,6 +17,8 @@ before_script: &global_before_scripts
# Force IPv4 for gitlab.postmarketos.org until it supports IPv6 too, OSUOSL is
# working on it (infra#195)
- "echo '140.211.167.182 gitlab.postmarketos.org' >> /etc/hosts"
# python 3.10 tests: need to have tomli installed, see pmb/helpers/toml.py
- "if grep -q VERSION_ID=3\\.17 /etc/os-release; then apk add py3-tomli; fi"
stages:
- lint
......@@ -46,6 +48,11 @@ pytest:
- "log_testsuite.txt"
- "log.txt"
# Ensure that tests pass on Python 3.10
pytest-python3.10:
extends: pytest
image: alpine:3.17
ruff:
stage: lint
script:
......@@ -125,6 +132,11 @@ install amd64:
# ARM64 on AMD64
- .ci/integration_tests/build_images postmarketos-trailblazer console
# Test that building images works on Python 3.10
install amd64 python3.10:
extends: install amd64
image: alpine:3.17
install aarch64:
extends: .integration
tags: [arm64]
......
......@@ -12,14 +12,6 @@ pmb.chroot.apk module
:undoc-members:
:show-inheritance:
pmb.chroot.apk\_static module
-----------------------------
.. automodule:: pmb.chroot.apk_static
:members:
:undoc-members:
:show-inheritance:
pmb.chroot.binfmt module
------------------------
......
......@@ -4,6 +4,14 @@ pmb.helpers package
Submodules
----------
pmb.helpers.apk\_static module
-----------------------------
.. automodule:: pmb.helpers.apk_static
:members:
:undoc-members:
:show-inheritance:
pmb.helpers.apk module
----------------------
......
......@@ -14,7 +14,6 @@ if TYPE_CHECKING:
from . import config
from . import parse
from . import types
from .config import init as config_init
from .helpers import frontend
from .helpers import logging
......
......@@ -4,7 +4,6 @@ from pathlib import Path
import pmb.aportgen.core
import pmb.build
import pmb.chroot.apk
import pmb.chroot.apk_static
import pmb.helpers.run
import pmb.parse.apkindex
from pmb.core import Chroot
......
......@@ -4,7 +4,6 @@ from pathlib import Path
import pmb.aportgen.core
import pmb.build
import pmb.chroot.apk
import pmb.chroot.apk_static
from pmb.core.arch import Arch
import pmb.helpers.run
import pmb.parse.apkindex
......
......@@ -4,7 +4,6 @@ from pathlib import Path
import pmb.aportgen.core
import pmb.build
import pmb.chroot.apk
import pmb.chroot.apk_static
import pmb.helpers.run
import pmb.parse.apkindex
from pmb.core import Chroot
......
import enum
from pathlib import Path
from pmb.core.pkgrepo import pkgrepo_paths
from pmb.core.pkgrepo import pkgrepo_name, pkgrepo_paths
import pmb.helpers.run
import pmb.chroot
......@@ -126,10 +126,10 @@ def mount_pmaports(chroot: Chroot = Chroot.native()) -> dict[str, Path]:
"""
dest_paths = {}
for repo in pkgrepo_paths(skip_extras=True):
destination = Path("/mnt") / repo.name
destination = Path("/mnt") / pkgrepo_name(repo)
outside_destination = chroot / destination
pmb.helpers.mount.bind(repo, outside_destination, umount=True)
dest_paths[repo.name] = destination
dest_paths[pkgrepo_name(repo)] = destination
return dest_paths
......
......@@ -6,10 +6,8 @@ from __future__ import annotations
import os
from pathlib import Path
import traceback
import pmb.chroot.apk_static
from pmb.core.arch import Arch
from pmb.helpers import logging
import shlex
from collections.abc import Sequence
import pmb.build
......@@ -30,57 +28,6 @@ from pmb.types import PathString
from pmb.helpers.exceptions import NonBugError
@Cache("chroot", "user_repository", mirrors_exclude=[])
def update_repository_list(
chroot: Chroot,
user_repository: bool = False,
mirrors_exclude: list[str] = [],
check: bool = False,
) -> None:
"""
Update /etc/apk/repositories, if it is outdated (when the user changed the
--mirror-alpine or --mirror-pmOS parameters).
:param mirrors_exclude: mirrors to exclude from the repository list
:param check: This function calls it self after updating the
/etc/apk/repositories file, to check if it was successful.
Only for this purpose, the "check" parameter should be set to
True.
"""
# Read old entries or create folder structure
path = chroot / "etc/apk/repositories"
lines_old: list[str] = []
if path.exists():
# Read all old lines
lines_old = []
with path.open() as handle:
for line in handle:
lines_old.append(line[:-1])
else:
pmb.helpers.run.root(["mkdir", "-p", path.parent])
# Up to date: Save cache, return
lines_new = pmb.helpers.repo.urls(
user_repository=user_repository, mirrors_exclude=mirrors_exclude
)
if lines_old == lines_new:
return
# Check phase: raise error when still outdated
if check:
raise RuntimeError(f"Failed to update: {path}")
# Update the file
logging.debug(f"({chroot}) update /etc/apk/repositories")
if path.exists():
pmb.helpers.run.root(["rm", path])
for line in lines_new:
pmb.helpers.run.root(["sh", "-c", "echo " f"{shlex.quote(line)} >> {path}"])
update_repository_list(
chroot, user_repository=user_repository, mirrors_exclude=mirrors_exclude, check=True
)
@Cache("chroot")
def check_min_version(chroot: Chroot = Chroot.native()) -> None:
"""
......@@ -163,9 +110,7 @@ def packages_get_locally_built_apks(package_list: list[str], arch: Arch) -> list
for channel in channels:
apk_path = get_context().config.work / "packages" / channel / arch / apk_file
if apk_path.exists():
# FIXME: use /mnt/pmb… until MR 2351 is reverted (pmb#2388)
# local.append(apk_path)
local.append(Path("/mnt/pmbootstrap/packages/") / channel / arch / apk_file)
local.append(apk_path)
break
# Record all the packages we have visited so far
......@@ -233,24 +178,17 @@ def install_run_apk(
user_repo += ["--repository", context.config.work / "packages" / channel]
for i, command in enumerate(commands):
# --no-interactive is a parameter to `add`, so it must be appended or apk
# gets confused
command += ["--no-interactive"]
command = user_repo + command
# Ignore missing repos before initial build (bpo#137)
if os.getenv("PMB_APK_FORCE_MISSING_REPOSITORIES") == "1":
command = ["--force-missing-repositories"] + command
if context.offline:
command = ["--no-network"] + command
if i == 0:
pmb.helpers.apk.apk_with_progress(command, chroot)
else:
# Virtual package related commands don't actually install or remove
# packages, but only mark the right ones as explicitly installed.
# They finish up almost instantly, so don't display a progress bar.
pmb.chroot.root(["apk", "--no-progress"] + command, chroot)
# Virtual package related commands don't actually install or remove
# packages, but only mark the right ones as explicitly installed.
# So only display a progress bar for the "apk add" command which is
# always the first one we process (i == 0).
pmb.helpers.apk.run(command, chroot, with_progress=(i == 0))
def install(packages: list[str], chroot: Chroot, build: bool = True, quiet: bool = False) -> None:
......
......@@ -9,14 +9,16 @@ import os
import pmb.chroot
import pmb.chroot.binfmt
import pmb.chroot.apk
import pmb.chroot.apk_static
import pmb.config
import pmb.config.workdir
import pmb.helpers.apk_static
import pmb.helpers.apk
import pmb.helpers.repo
import pmb.helpers.run
import pmb.helpers.other
from pmb.core import Chroot, ChrootType
from pmb.core.context import get_context
from pmb.types import PathString
class UsrMerge(enum.Enum):
......@@ -136,33 +138,27 @@ def init(chroot: Chroot, usr_merge: UsrMerge = UsrMerge.AUTO) -> None:
mark_in_chroot(chroot)
if chroot.exists():
copy_resolv_conf(chroot)
pmb.chroot.apk.update_repository_list(chroot)
pmb.helpers.apk.update_repository_list(chroot.path)
warn_if_chroots_outdated()
return
# Require apk-tools-static
pmb.chroot.apk_static.init()
# Fetch apk.static
pmb.helpers.apk_static.init()
logging.info(f"({chroot}) Creating chroot")
# Initialize cache
apk_cache = config.work / f"cache_apk_{arch}"
pmb.helpers.run.root(["ln", "-s", "-f", "/var/cache/apk", chroot / "etc/apk/cache"])
# Initialize /etc/apk/keys/, resolv.conf, repositories
init_keys()
copy_resolv_conf(chroot)
pmb.chroot.apk.update_repository_list(chroot)
pmb.helpers.apk.update_repository_list(chroot.path)
pmb.config.workdir.chroot_save_init(chroot)
# Install alpine-base
pmb.helpers.repo.update(arch)
pkgs = ["alpine-base"]
cmd = ["--root", chroot.path, "--cache-dir", apk_cache, "--initdb", "--arch", arch]
for channel in pmb.config.pmaports.all_channels():
cmd += ["--repository", config.work / "packages" / channel]
pmb.chroot.apk_static.run(cmd + ["add", *pkgs])
cmd: list[PathString] = ["--initdb"]
pmb.helpers.apk.run(cmd + ["add", *pkgs], chroot)
# Merge /usr
if usr_merge is UsrMerge.AUTO and pmb.config.is_systemd_selected(config):
......
......@@ -51,7 +51,7 @@ def delete(hook: str, suffix: Chroot) -> None:
if hook not in list_chroot(suffix):
raise RuntimeError("There is no such hook installed!")
prefix = pmb.config.initfs_hook_prefix
pmb.chroot.root(["apk", "del", f"{prefix}{hook}"], suffix)
pmb.helpers.apk.run(["del", f"{prefix}{hook}"], suffix)
def update(suffix: Chroot) -> None:
......
......@@ -11,6 +11,7 @@ import pmb.config.workdir
import pmb.chroot
import pmb.config.pmaports
import pmb.config.workdir
import pmb.helpers.apk
import pmb.helpers.cli
import pmb.helpers.pmaports
import pmb.helpers.run
......@@ -107,7 +108,7 @@ def zap(
pmb.config.workdir.clean()
# Chroots were zapped, so no repo lists exist anymore
pmb.chroot.apk.update_repository_list.cache_clear()
pmb.helpers.apk.update_repository_list.cache_clear()
# Let chroot.init be called again
pmb.chroot.init.cache_clear()
......@@ -183,18 +184,6 @@ def zap_pkgs_online_mismatch(confirm=True, dry=False):
# Iterate over existing apk caches
for path in paths:
arch = Arch.from_str(path.name.split("_", 2)[2])
if arch.is_native():
chroot = Chroot.native()
else:
chroot = Chroot.buildroot(arch)
# Skip if chroot does not exist
# FIXME: should we init the buildroot to do it anyway?
# what if we run apk.static with --arch instead?
if not chroot.exists():
continue
# Clean the cache with apk
logging.info(f"({chroot}) apk -v cache clean")
if not dry:
pmb.chroot.root(["apk", "-v", "cache", "clean"], chroot)
pmb.helpers.apk.cache_clean(arch)
......@@ -47,7 +47,6 @@ unmigrated_commands = [
"install",
"checksum",
"build",
"deviceinfo_parse",
"apkbuild_parse",
"apkindex_parse",
"config",
......
......@@ -57,7 +57,7 @@ class RepoBootstrap(commands.Command):
self.check_repo_arg()
def get_packages(self, bootstrap_line):
def get_packages(self, bootstrap_line: str) -> list[str]:
ret = []
for word in bootstrap_line.split(" "):
if word.startswith("["):
......@@ -65,7 +65,7 @@ class RepoBootstrap(commands.Command):
ret += [word]
return ret
def set_progress_total(self, steps):
def set_progress_total(self, steps: dict[str, str]) -> None:
self.progress_total = 0
# Add one progress point per package
......@@ -85,7 +85,7 @@ class RepoBootstrap(commands.Command):
self.progress_done += 1
def run_steps(self, steps):
def run_steps(self, steps: dict[str, str]) -> None:
chroot: Chroot
if self.arch.cpu_emulation_required():
chroot = Chroot(ChrootType.BUILDROOT, self.arch)
......@@ -109,7 +109,7 @@ class RepoBootstrap(commands.Command):
self.log_progress(f"initializing {chroot} chroot (merge /usr: {usr_merge.name})")
# Initialize without pmOS binary package repo
pmb.chroot.apk.update_repository_list(chroot, mirrors_exclude=[self.repo])
pmb.helpers.apk.update_repository_list(chroot.path, mirrors_exclude=[self.repo])
pmb.chroot.init(chroot, usr_merge)
bootstrap_stage = int(step.split("bootstrap_", 1)[1])
......@@ -149,10 +149,10 @@ class RepoBootstrap(commands.Command):
raise RuntimeError(f"{msg}!")
def get_steps(self):
def get_steps(self) -> dict[str, str]:
cfg = pmb.config.pmaports.read_config_repos()
prev_step = 0
ret = {}
ret: dict[str, str] = {}
for key, packages in cfg[self.repo].items():
if not key.startswith("bootstrap_"):
......
......@@ -14,6 +14,7 @@ from collections.abc import Sequence
from pmb.config.file import load, save, serialize
from pmb.config.sudo import which_sudo
from pmb.config.other import is_systemd_selected
from . import workdir
#
......
......@@ -83,7 +83,7 @@ def ask_for_username(default_user: str) -> str:
return ret
def ask_for_work_path(args: PmbArgs) -> tuple[Path, bool]:
def ask_for_work_path(default: Path | None) -> tuple[Path, bool]:
"""Ask for the work path, until we can create it (when it does not exist) and write into it.
:returns: (path, exists)
......@@ -98,9 +98,7 @@ def ask_for_work_path(args: PmbArgs) -> tuple[Path, bool]:
)
while True:
try:
work = os.path.expanduser(
pmb.helpers.cli.ask("Work path", None, get_context().config.work, False)
)
work = os.path.expanduser(pmb.helpers.cli.ask("Work path", None, default, False))
work = os.path.realpath(work)
exists = os.path.exists(work)
......@@ -697,15 +695,15 @@ def frontend(args: PmbArgs) -> None:
require_programs()
# Work folder (needs to be first, so we can create chroots early)
config = pmb.config.load(args.config)
# Update context to point to new config
get_context().config = config
config = get_context().config
using_default_pmaports = config.aports[-1].is_relative_to(config.work)
config.work, work_exists = ask_for_work_path(args)
config.work, work_exists = ask_for_work_path(config.work)
# If the work dir is not the default, reset aports and make
# it relative to the work dir
if not config.aports[0].is_relative_to(config.work):
# If the work dir changed then we need to update the pmaports path
# to be relative to the new workdir
if using_default_pmaports:
config.aports = [config.work / "cache_git/pmaports"]
# Update args and save config (so chroots and 'pmbootstrap log' work)
......
......@@ -2,7 +2,12 @@
# SPDX-License-Identifier: GPL-3.0-or-later
import configparser
from pathlib import Path
from pmb.core.pkgrepo import pkgrepo_default_path, pkgrepo_paths, pkgrepo_relative_path
from pmb.core.pkgrepo import (
pkgrepo_default_path,
pkgrepo_name,
pkgrepo_paths,
pkgrepo_relative_path,
)
from pmb.helpers import logging
import os
import sys
......@@ -97,7 +102,7 @@ def read_config(aports: Path | None = None) -> dict[str, Any]:
if aports is None:
aports = pkgrepo_paths()[0]
systemd = aports.name == "systemd"
systemd = pkgrepo_name(aports) == "systemd"
# extra-repos don't have a pmaports.cfg
# so jump up the main aports dir
if "extra-repos" in aports.parts:
......
......@@ -50,7 +50,7 @@ class Chroot:
"riscv64",
]
if self.__type not in ChrootType:
if self.__type not in ChrootType._member_map_.values():
raise ValueError(f"Invalid chroot type: '{self.__type}'")
# A buildroot suffix must have a name matching one of alpines
......
......@@ -28,21 +28,42 @@ def pkgrepo_paths(skip_extras: bool = False) -> list[Path]:
return out_paths
@Cache()
def pkgrepo_default_path() -> Path:
return pkgrepo_paths(skip_extras=True)[0]
def pkgrepo_names(skip_exras: bool = False) -> list[str]:
"""
Return a list of all the package repository names.
Return a list of all the package repository names. We REQUIRE
that the last repository is "pmaports", though the directory
may be named differently. So we hardcode the name here.
"""
return [aports.name for aports in pkgrepo_paths(skip_exras)]
names = [aports.name for aports in pkgrepo_paths(skip_exras)]
names[-1] = "pmaports"
return names
def pkgrepo_name(path: Path) -> str:
"""
Return the name of the package repository with the given path. This
MUST be used instead of "path.name" as we need special handling
for the pmaports repository.
"""
if path == get_context().config.aports[-1]:
return "pmaports"
return path.name
def pkgrepo_path(name: str) -> Path:
"""
Return the absolute path to the package repository with the given name.
"""
# The pmaports repo is always last, and we hardcode the name.
if name == "pmaports":
return get_context().config.aports[-1]
for aports in pkgrepo_paths():
if aports.name == name:
return aports
......@@ -56,7 +77,7 @@ def pkgrepo_name_from_subdir(subdir: Path) -> str:
"""
for aports in pkgrepo_paths():
if subdir.is_relative_to(aports):
return aports.name
return pkgrepo_name(aports)
raise RuntimeError(f"aports subdir '{subdir}' not found")
......@@ -105,14 +126,14 @@ def pkgrepo_iter_package_dirs(skip_extra_repos: bool = False) -> Generator[Path,
if "extra-repos" not in repo.parts and "extra-repos" in pdir.parts:
continue
pkg = os.path.basename(pdir)
if pkg in seen[repo.name]:
if pkg in seen[pkgrepo_name(repo)]:
raise RuntimeError(
f"Package {pkg} found in multiple aports "
"subfolders. Please put it only in one folder."
)
if pkg in [x for li in seen.values() for x in li]:
continue
seen[repo.name].append(pkg)
seen[pkgrepo_name(repo)].append(pkg)
yield pdir
......
# Copyright 2023 Johannes Marbach, Oliver Smith
# SPDX-License-Identifier: GPL-3.0-or-later
import os
import shlex
from collections.abc import Sequence
from pathlib import Path
from typing import Literal
import pmb.chroot
import pmb.config.pmaports
......@@ -10,10 +12,74 @@ from pmb.core.arch import Arch
from pmb.core.chroot import Chroot
from pmb.types import PathString
import pmb.helpers.cli
import pmb.helpers.repo
import pmb.helpers.run
import pmb.helpers.run_core
import pmb.parse.version
from pmb.core.context import get_context
from pmb.helpers import logging
from pmb.meta import Cache
@Cache("root", "user_repository", mirrors_exclude=[])
def update_repository_list(
root: Path,
user_repository: bool | Path = False,
mirrors_exclude: list[str] | Literal[True] = [],
check: bool = False,
) -> None:
"""
Update /etc/apk/repositories, if it is outdated (when the user changed the
--mirror-alpine or --mirror-pmOS parameters).
:param root: the root directory to operate on
:param mirrors_exclude: mirrors to exclude from the repository list
:param check: This function calls it self after updating the
/etc/apk/repositories file, to check if it was successful.
Only for this purpose, the "check" parameter should be set to
True.
"""
# Read old entries or create folder structure
path = root / "etc/apk/repositories"
lines_old: list[str] = []
if path.exists():
# Read all old lines
lines_old = []
with path.open() as handle:
for line in handle:
lines_old.append(line[:-1])
else:
pmb.helpers.run.root(["mkdir", "-p", path.parent])
user_repo_dir: Path | None
if isinstance(user_repository, Path):
user_repo_dir = user_repository
else:
user_repo_dir = Path("/mnt/pmbootstrap/packages") if user_repository else None
# Up to date: Save cache, return
lines_new = pmb.helpers.repo.urls(
user_repository=user_repo_dir, mirrors_exclude=mirrors_exclude
)
if lines_old == lines_new:
return
# Check phase: raise error when still outdated
if check:
raise RuntimeError(f"Failed to update: {path}")
# Update the file
logging.debug(f"({root.name}) update /etc/apk/repositories")
if path.exists():
pmb.helpers.run.root(["rm", path])
for line in lines_new:
pmb.helpers.run.root(["sh", "-c", "echo " f"{shlex.quote(line)} >> {path}"])
update_repository_list(
root,
user_repository=user_repository,
mirrors_exclude=mirrors_exclude,
check=True,
)
def _prepare_fifo() -> Path:
......@@ -43,7 +109,7 @@ def _create_command_with_progress(command, fifo):
:param fifo: path of the fifo
:returns: full command in list form
"""
flags = ["--no-progress", "--progress-fd", "3"]
flags = ["--progress-fd", "3"]
command_full = [command[0]] + flags + command[1:]
command_flat = pmb.helpers.run_core.flat_cmd([command_full])
command_flat = f"exec 3>{fifo}; {command_flat}"
......@@ -66,23 +132,15 @@ def _compute_progress(line):
return cur / tot if tot > 0 else 0
def apk_with_progress(command: Sequence[PathString], chroot: Chroot | None = None) -> None:
def _apk_with_progress(command: Sequence[str]) -> None:
"""Run an apk subcommand while printing a progress bar to STDOUT.
:param command: apk subcommand in list form
:raises RuntimeError: when the apk command fails
"""
fifo = _prepare_fifo()
_command: list[str] = [str(get_context().config.work / "apk.static")]
if chroot:
_command.extend(["--root", str(chroot.path), "--arch", str(chroot.arch)])
for c in command:
if isinstance(c, Arch):
_command.append(str(c))
else:
_command.append(os.fspath(c))
command_with_progress = _create_command_with_progress(_command, fifo)
log_msg = " ".join(_command)
command_with_progress = _create_command_with_progress(command, fifo)
log_msg = " ".join(command)
with pmb.helpers.run.root(["cat", fifo], output="pipe") as p_cat:
with pmb.helpers.run.root(command_with_progress, output="background") as p_apk:
while p_apk.poll() is None:
......@@ -96,6 +154,128 @@ def apk_with_progress(command: Sequence[PathString], chroot: Chroot | None = Non
pmb.helpers.run_core.check_return_code(p_apk.returncode, log_msg)
def _prepare_cmd(command: Sequence[PathString], chroot: Chroot | None) -> list[str]:
"""Prepare the apk command.
Returns a tuple of the first part of the command with generic apk flags, and the second part
with the subcommand and its arguments.
"""
config = get_context().config
# Our _apk_with_progress() wrapper also need --no-progress, since all that does is
# prevent apk itself from rendering progress bars. We instead want it to tell us
# the progress so we can render it. So we always set --no-progress.
_command: list[str] = [str(config.work / "apk.static"), "--no-progress"]
if chroot:
cache_dir = config.work / f"cache_apk_{chroot.arch}"
_command.extend(
[
"--root",
str(chroot.path),
"--arch",
str(chroot.arch),
"--cache-dir",
str(cache_dir),
]
)
local_repos = pmb.helpers.repo.urls(
user_repository=config.work / "packages", mirrors_exclude=True
)
for repo in local_repos:
_command.extend(["--repository", repo])
if get_context().offline:
_command.append("--no-network")
for c in command:
_command.append(os.fspath(c))
# Always be non-interactive
if c == "add":
_command.append("--no-interactive")
return _command
def run(command: Sequence[PathString], chroot: Chroot, with_progress: bool = True) -> None:
"""Run an apk subcommand.
:param command: apk subcommand in list form
:param with_progress: whether to print a progress bar
:param chroot: chroot to run the command in
:raises RuntimeError: when the apk command fails
"""
_command = _prepare_cmd(command, chroot)
# Sanity checks. We should avoid accidentally writing to
# /var/cache/apk on the host!
if "add" in command:
if "--no-interactive" not in _command:
raise RuntimeError(
"Encountered an 'apk add' command without --no-interactive! This is a bug."
)
if "--cache-dir" not in _command:
raise RuntimeError(
"Encountered an 'apk add' command without --cache-dir! This is a bug."
)
if with_progress:
_apk_with_progress(_command)
else:
pmb.helpers.run.root(_command)
def cache_clean(arch: Arch) -> None:
"""Clean the APK cache for a specific architecture."""
work = get_context().config.work
cache_dir = work / f"cache_apk_{arch}"
if not cache_dir.exists():
return
# The problem here is that apk's "cache clean" command really
# expects to be run against an apk-managed rootfs and will return
# errors if it can't access certain paths (even though it will
# actually clean the cache like we want).
# We could just ignore the return value, but then we wouldn't know
# if something actually went wrong with apk...
# So we do this dance of creating a rootfs with only the files that
# APK needs to be happy
tmproot = work / "tmp" / "apk_root"
if not (tmproot / "etc/apk/repositories").exists():
tmproot.mkdir(exist_ok=True)
(tmproot / "var/cache").mkdir(exist_ok=True, parents=True)
(tmproot / "etc/apk").mkdir(exist_ok=True, parents=True)
(tmproot / "lib/apk/db").mkdir(exist_ok=True, parents=True)
(tmproot / "etc/apk/world").touch(exist_ok=True)
(tmproot / "lib/apk/db/installed").touch(exist_ok=True)
(tmproot / "lib/apk/db/triggers").touch(exist_ok=True)
(tmproot / "etc/apk/keys").symlink_to(work / "config_apk_keys")
# Our fake rootfs needs a valid repositories file for apk
# to have something to compare the cache against
update_repository_list(tmproot, user_repository=work / "packages")
# Point our tmproot cache dir to the real cache dir
# this is much simpler than passing --cache-dir to apk
# since even with that flag apk will also check it's
# "static cache".
(tmproot / "var/cache/apk").unlink(missing_ok=True)
(tmproot / "var/cache/apk").symlink_to(cache_dir)
command: list[PathString] = [
"-v",
"--root",
tmproot,
"--arch",
str(arch),
]
command += ["cache", "clean"]
_command = _prepare_cmd(command, None)
pmb.helpers.run.root(_command)
def check_outdated(version_installed, action_msg):
"""Check if the provided alpine version is outdated.
......