Skip to content

Commit

Permalink
Revert "Use shared package cache directory by default"
Browse files Browse the repository at this point in the history
At least pacman isn't ready just yet for cache sharing, so let's
temporarily revert this commit. We'll reintroduce it in a later
PR.

This reverts commit 98a2948.
  • Loading branch information
DaanDeMeyer committed Jan 27, 2024
1 parent 145456f commit 252db4e
Show file tree
Hide file tree
Showing 12 changed files with 61 additions and 131 deletions.
43 changes: 17 additions & 26 deletions mkosi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
clean_package_manager_metadata,
finalize_package_manager_mounts,
package_manager_scripts,
rchown_package_manager_cache_dirs,
)
from mkosi.kmod import gen_required_kernel_modules, process_kernel_modules
from mkosi.log import ARG_DEBUG, complete_step, die, log_notice, log_step
Expand Down Expand Up @@ -1487,8 +1486,7 @@ def build_initrd(context: Context) -> Path:
"--cache-only", str(context.config.cache_only),
"--output-dir", str(context.workspace / "initrd"),
*(["--workspace-dir", str(context.config.workspace_dir)] if context.config.workspace_dir else []),
*(["--cache-dir", str(context.config.cache_dir)] if context.config.cache_dir else []),
*(["--package-cache-dir", str(context.config.package_cache_dir)] if context.config.package_cache_dir else []),
"--cache-dir", str(context.cache_dir),
*(["--local-mirror", str(context.config.local_mirror)] if context.config.local_mirror else []),
"--incremental", str(context.config.incremental),
"--acl", str(context.config.acl),
Expand Down Expand Up @@ -3417,7 +3415,6 @@ def finalize_default_tools(args: Args, config: Config, *, resources: Path) -> Co
*(["--output-dir", str(config.output_dir)] if config.output_dir else []),
*(["--workspace-dir", str(config.workspace_dir)] if config.workspace_dir else []),
*(["--cache-dir", str(config.cache_dir)] if config.cache_dir else []),
*(["--package-cache-dir", str(config.package_cache_dir)] if config.package_cache_dir else []),
"--incremental", str(config.incremental),
"--acl", str(config.acl),
*([f"--package={package}" for package in config.tools_tree_packages]),
Expand Down Expand Up @@ -3499,16 +3496,11 @@ def run_clean(args: Args, config: Config) -> None:
with complete_step(f"Clearing out build directory of {config.name()} image…"):
rmtree(*config.build_dir.iterdir())

if (
remove_package_cache and
config.package_cache_dir and
config.package_cache_dir.exists() and
any(config.package_cache_dir.iterdir())
):
if remove_package_cache and config.cache_dir and config.cache_dir.exists() and any(config.cache_dir.iterdir()):
with complete_step(f"Clearing out package cache of {config.name()} image…"):
rmtree(
*(
config.package_cache_dir / p / d
config.cache_dir / p / d
for p in ("cache", "lib")
for d in ("apt", "dnf", "libdnf5", "pacman", "zypp")
),
Expand All @@ -3529,26 +3521,25 @@ def run_build(args: Args, config: Config, *, resources: Path) -> None:
if Path(d).exists():
run(["mount", "--rbind", d, d, "--options", "ro"])

# Create these as the invoking user to make sure they're owned by the user running mkosi.
for p in (
config.output_dir,
config.cache_dir,
config.package_cache_dir_or_default(),
config.package_state_dir_or_default(),
config.build_dir,
config.workspace_dir,
):
if p:
INVOKING_USER.mkdir(p)

with (
complete_step(f"Building {config.name()} image"),
prepend_to_environ_path(config),
acl_toggle_build(config, INVOKING_USER.uid),
rchown_package_manager_cache_dirs(config),
):
# After tools have been mounted, check if we have what we need
check_tools(config, Verb.build)
build_image(args, config, resources=resources)

# Create these as the invoking user to make sure they're owned by the user running mkosi.
for p in (
config.output_dir,
config.cache_dir,
config.build_dir,
config.workspace_dir,
):
if p:
run(["mkdir", "--parents", p], user=INVOKING_USER.uid, group=INVOKING_USER.gid)

with acl_toggle_build(config, INVOKING_USER.uid):
build_image(args, config, resources=resources)


def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
Expand Down
35 changes: 16 additions & 19 deletions mkosi/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1171,7 +1171,6 @@ class Config:
output_dir: Optional[Path]
workspace_dir: Optional[Path]
cache_dir: Optional[Path]
package_cache_dir: Optional[Path]
build_dir: Optional[Path]
image_id: Optional[str]
image_version: Optional[str]
Expand Down Expand Up @@ -1297,17 +1296,24 @@ def workspace_dir_or_default(self) -> Path:
if self.workspace_dir:
return self.workspace_dir

if (cache := INVOKING_USER.cache_dir()) and cache != Path("/var/cache"):
return cache
if (cache := os.getenv("XDG_CACHE_HOME")) and Path(cache).exists():
return Path(cache)

# If we're running from /home and there's a cache or output directory in /home, we want to use a workspace
# directory in /home as well as /home might be on a separate partition or subvolume which means that to take
# advantage of reflinks and such, the workspace directory has to be on the same partition/subvolume.
if (
Path.cwd().is_relative_to(INVOKING_USER.home()) and
(INVOKING_USER.home() / ".cache").exists() and
(
self.cache_dir and self.cache_dir.is_relative_to(INVOKING_USER.home()) or
self.output_dir and self.output_dir.is_relative_to(INVOKING_USER.home())
)
):
return INVOKING_USER.home() / ".cache"

return Path("/var/tmp")

def package_cache_dir_or_default(self) -> Path:
return self.package_cache_dir or INVOKING_USER.cache_dir()

def package_state_dir_or_default(self) -> Path:
return self.package_cache_dir or INVOKING_USER.state_dir()

def tools(self) -> Path:
return self.tools_tree or Path("/")

Expand Down Expand Up @@ -1731,15 +1737,7 @@ def parse_ini(path: Path, only_sections: Collection[str] = ()) -> Iterator[tuple
section="Output",
parse=config_make_path_parser(required=False),
paths=("mkosi.cache",),
help="Incremental cache directory",
),
ConfigSetting(
dest="package_cache_dir",
metavar="PATH",
name="PackageCacheDirectory",
section="Output",
parse=config_make_path_parser(required=False),
help="Package cache directory",
help="Package cache path",
),
ConfigSetting(
dest="build_dir",
Expand Down Expand Up @@ -3435,7 +3433,6 @@ def bold(s: Any) -> str:
Output Directory: {config.output_dir_or_cwd()}
Workspace Directory: {config.workspace_dir_or_default()}
Cache Directory: {none_to_none(config.cache_dir)}
Package Cache Directory: {none_to_default(config.package_cache_dir)}
Build Directory: {none_to_none(config.build_dir)}
Image ID: {config.image_id}
Image Version: {config.image_version}
Expand Down
5 changes: 5 additions & 0 deletions mkosi/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def __init__(self, args: Args, config: Config, *, workspace: Path, resources: Pa
self.pkgmngr.mkdir()
self.packages.mkdir()
self.install_dir.mkdir(exist_ok=True)
self.cache_dir.mkdir(parents=True, exist_ok=True)

@property
def root(self) -> Path:
Expand All @@ -54,6 +55,10 @@ def pkgmngr(self) -> Path:
def packages(self) -> Path:
return self.workspace / "packages"

@property
def cache_dir(self) -> Path:
return self.config.cache_dir or (self.workspace / "cache")

@property
def install_dir(self) -> Path:
return self.workspace / "dest"
Expand Down
2 changes: 1 addition & 1 deletion mkosi/distributions/debian.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def install(cls, context: Context) -> None:
with (
# The deb paths will be in the form of "/var/cache/apt/<deb>" so we transform them to the corresponding
# path in mkosi's package cache directory.
open(context.config.package_cache_dir_or_default() / Path(deb).relative_to("/var/cache"), "rb") as i,
open(context.cache_dir / Path(deb).relative_to("/var"), "rb") as i,
tempfile.NamedTemporaryFile() as o
):
run(["dpkg-deb", "--fsys-tarfile", "/dev/stdin"], stdin=i, stdout=o, sandbox=context.sandbox())
Expand Down
37 changes: 11 additions & 26 deletions mkosi/installer/__init__.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
# SPDX-License-Identifier: LGPL-2.1+

import contextlib
import os
from collections.abc import Iterator
from pathlib import Path

from mkosi.config import Config, ConfigFeature
from mkosi.config import ConfigFeature
from mkosi.context import Context
from mkosi.log import complete_step
from mkosi.sandbox import apivfs_cmd, finalize_crypto_mounts
from mkosi.tree import rmtree
from mkosi.types import PathString
from mkosi.user import INVOKING_USER
from mkosi.util import flatten


Expand Down Expand Up @@ -78,27 +74,16 @@ def finalize_package_manager_mounts(context: Context) -> list[PathString]:
]

mounts += flatten(
["--bind", context.config.package_cache_dir_or_default() / d, Path("/var/cache") / d]
for d in ("apt", dnf_subdir(context), "pacman/pkg", "zypp")
if (context.config.package_cache_dir_or_default() / d).exists()
)

mounts += flatten(
["--bind", context.config.package_state_dir_or_default() / d, Path("/var/lib") / d]
for d in ("apt", dnf_subdir(context))
if (context.config.package_state_dir_or_default() / d).exists()
["--bind", context.cache_dir / d, Path("/var") / d]
for d in (
"lib/apt",
"cache/apt",
f"cache/{dnf_subdir(context)}",
f"lib/{dnf_subdir(context)}",
"cache/pacman/pkg",
"cache/zypp",
)
if (context.cache_dir / d).exists()
)

return mounts


@contextlib.contextmanager
def rchown_package_manager_cache_dirs(config: Config) -> Iterator[None]:
try:
yield
finally:
if INVOKING_USER.is_regular_user():
with complete_step("Fixing ownership of package manager cache directories"):
for p in ("apt", "dnf", "libdnf5", "pacman", "zypp"):
for d in (config.package_cache_dir_or_default(), config.package_state_dir_or_default()):
INVOKING_USER.rchown(d / p)
5 changes: 2 additions & 3 deletions mkosi/installer/apt.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from mkosi.run import find_binary, run
from mkosi.sandbox import apivfs_cmd
from mkosi.types import PathString
from mkosi.user import INVOKING_USER
from mkosi.util import sort_packages, umask


Expand Down Expand Up @@ -44,8 +43,8 @@ def setup_apt(context: Context, repos: Iterable[AptRepository]) -> None:
(context.root / "var/lib/dpkg").mkdir(parents=True, exist_ok=True)
(context.root / "var/lib/dpkg/status").touch()

INVOKING_USER.mkdir(context.config.package_cache_dir_or_default() / "apt")
INVOKING_USER.mkdir(context.config.package_state_dir_or_default() / "apt")
(context.cache_dir / "lib/apt").mkdir(exist_ok=True, parents=True)
(context.cache_dir / "cache/apt").mkdir(exist_ok=True, parents=True)

# We have a special apt.conf outside of pkgmngr dir that only configures "Dir::Etc" that we pass to APT_CONFIG to
# tell apt it should read config files from /etc/apt in case this is overridden by distributions. This is required
Expand Down
5 changes: 2 additions & 3 deletions mkosi/installer/dnf.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from mkosi.run import find_binary, run
from mkosi.sandbox import apivfs_cmd
from mkosi.types import PathString
from mkosi.user import INVOKING_USER
from mkosi.util import sort_packages


Expand All @@ -31,8 +30,8 @@ def setup_dnf(context: Context, repositories: Iterable[RpmRepository], filelists
(context.pkgmngr / "etc/dnf/vars").mkdir(exist_ok=True, parents=True)
(context.pkgmngr / "etc/yum.repos.d").mkdir(exist_ok=True, parents=True)

INVOKING_USER.mkdir(context.config.package_cache_dir_or_default() / dnf_subdir(context))
INVOKING_USER.mkdir(context.config.package_state_dir_or_default() / dnf_subdir(context))
(context.cache_dir / "cache" / dnf_subdir(context)).mkdir(exist_ok=True, parents=True)
(context.cache_dir / "lib" / dnf_subdir(context)).mkdir(exist_ok=True, parents=True)

config = context.pkgmngr / "etc/dnf/dnf.conf"

Expand Down
3 changes: 1 addition & 2 deletions mkosi/installer/pacman.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from mkosi.run import run
from mkosi.sandbox import apivfs_cmd
from mkosi.types import PathString
from mkosi.user import INVOKING_USER
from mkosi.util import sort_packages, umask
from mkosi.versioncomp import GenericVersion

Expand All @@ -32,7 +31,7 @@ def setup_pacman(context: Context, repositories: Iterable[PacmanRepository]) ->
with umask(~0o755):
(context.root / "var/lib/pacman").mkdir(exist_ok=True, parents=True)

INVOKING_USER.mkdir(context.config.package_cache_dir_or_default() / "pacman/pkg")
(context.cache_dir / "cache/pacman/pkg").mkdir(parents=True, exist_ok=True)

config = context.pkgmngr / "etc/pacman.conf"
if config.exists():
Expand Down
3 changes: 1 addition & 2 deletions mkosi/installer/zypper.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@
from mkosi.run import run
from mkosi.sandbox import apivfs_cmd
from mkosi.types import PathString
from mkosi.user import INVOKING_USER
from mkosi.util import sort_packages


def setup_zypper(context: Context, repos: Iterable[RpmRepository]) -> None:
config = context.pkgmngr / "etc/zypp/zypp.conf"
config.parent.mkdir(exist_ok=True, parents=True)

INVOKING_USER.mkdir(context.config.package_cache_dir_or_default() / "zypp")
(context.cache_dir / "cache/zypp").mkdir(exist_ok=True, parents=True)

# rpm.install.excludedocs can only be configured in zypp.conf so we append
# to any user provided config file. Let's also bump the refresh delay to
Expand Down
15 changes: 4 additions & 11 deletions mkosi/resources/mkosi.md
Original file line number Diff line number Diff line change
Expand Up @@ -695,17 +695,10 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`,

`CacheDirectory=`, `--cache-dir=`

: Takes a path to a directory to use as the incremental cache directory
for the incremental images produced when the `Incremental=` option is
enabled. If this option is not used, but a `mkosi.cache/` directory is
found in the local directory it is automatically used for this
purpose.

`PackageCacheDirectory=`, `--package-cache-dir`

: Takes a path to a directory to use as the package cache directory for
the distribution package manager used. If unset, a suitable directory
in the user's home directory or system is used.
: Takes a path to a directory to use as package cache for the
distribution package manager used. If this option is not used, but a
`mkosi.cache/` directory is found in the local directory it is
automatically used for this purpose.

`BuildDirectory=`, `--build-dir=`

Expand Down
37 changes: 1 addition & 36 deletions mkosi/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pathlib import Path

from mkosi.log import die
from mkosi.run import run, spawn
from mkosi.run import spawn
from mkosi.util import flock

SUBRANGE = 65536
Expand Down Expand Up @@ -39,41 +39,6 @@ def name(cls) -> str:
def home(cls) -> Path:
return Path(f"~{cls.name()}").expanduser()

@classmethod
def is_regular_user(cls) -> bool:
return cls.uid >= 1000

@classmethod
def cache_dir(cls) -> Path:
if (cache := os.getenv("XDG_CACHE_HOME") or (cache := os.getenv("CACHE_DIRECTORY"))):
return Path(cache)

if (cls.is_regular_user() and Path.cwd().is_relative_to(INVOKING_USER.home())):
return INVOKING_USER.home() / ".cache"

return Path("/var/cache")

@classmethod
def state_dir(cls) -> Path:
if (state := os.getenv("XDG_STATE_HOME") or (state := os.getenv("STATE_DIRECTORY"))):
return Path(state)

if (cls.is_regular_user() and Path.cwd().is_relative_to(INVOKING_USER.home())):
return INVOKING_USER.home() / ".local/state"

return Path("/var/lib")

@classmethod
def mkdir(cls, path: Path) -> None:
user = cls.uid if cls.is_regular_user() and path.is_relative_to(cls.home()) else os.getuid()
group = cls.gid if cls.is_regular_user() and path.is_relative_to(cls.home()) else os.getgid()
run(["mkdir", "--parents", path], user=user, group=group)

@classmethod
def rchown(cls, path: Path) -> None:
if cls.is_regular_user() and path.is_relative_to(INVOKING_USER.home()) and path.exists():
run(["chown", "--recursive", f"{INVOKING_USER.uid}:{INVOKING_USER.gid}", path])


def read_subrange(path: Path) -> int:
uid = str(os.getuid())
Expand Down
2 changes: 0 additions & 2 deletions tests/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ def test_config() -> None:
"Output": "outfile",
"OutputDirectory": "/your/output/here",
"Overlay": true,
"PackageCacheDirectory": "/a/b/c",
"PackageDirectories": [],
"PackageManagerTrees": [
{
Expand Down Expand Up @@ -357,7 +356,6 @@ def test_config() -> None:
output_dir = Path("/your/output/here"),
output_format = OutputFormat.uki,
overlay = True,
package_cache_dir = Path("/a/b/c"),
package_directories = [],
package_manager_trees = [ConfigTree(Path("/foo/bar"), None)],
packages = [],
Expand Down

0 comments on commit 252db4e

Please sign in to comment.