This makes the tree functions a little more generic.
with complete_step("Copying in base trees…"):
for path in state.config.base_trees:
- install_tree(state.config, path, state.root)
+ install_tree(path, state.root, use_subvolumes=state.config.use_subvolumes)
def install_skeleton_trees(state: MkosiState) -> None:
with complete_step("Copying in skeleton file trees…"):
for tree in state.config.skeleton_trees:
source, target = tree.with_prefix()
- install_tree(state.config, source, state.root, target)
+ install_tree(source, state.root, target, use_subvolumes=state.config.use_subvolumes)
def install_package_manager_trees(state: MkosiState) -> None:
with complete_step("Copying in package manager file trees…"):
for tree in state.config.package_manager_trees:
source, target = tree.with_prefix()
- install_tree(state.config, source, state.workspace / "pkgmngr", target)
+ install_tree(source, state.workspace / "pkgmngr", target, use_subvolumes=state.config.use_subvolumes)
def install_extra_trees(state: MkosiState) -> None:
with complete_step("Copying in extra file trees…"):
for tree in state.config.extra_trees:
source, target = tree.with_prefix()
- install_tree(state.config, source, state.root, target)
+ install_tree(source, state.root, target, use_subvolumes=state.config.use_subvolumes)
def install_build_dest(state: MkosiState) -> None:
return
with complete_step("Copying in build tree…"):
- copy_tree(state.config, state.install_dir, state.root)
+ copy_tree(state.install_dir, state.root, use_subvolumes=state.config.use_subvolumes)
def gzip_binary() -> str:
def maybe_compress(config: MkosiConfig, compression: Compression, src: Path, dst: Optional[Path] = None) -> None:
if not compression or src.is_dir():
if dst:
- move_tree(config, src, dst)
+ move_tree(src, dst, use_subvolumes=config.use_subvolumes)
return
if not dst:
# We only use the cache-overlay directory for caching if we have a base tree, otherwise we just
# cache the root directory.
if (state.workspace / "cache-overlay").exists():
- move_tree(state.config, state.workspace / "cache-overlay", final)
+ move_tree(state.workspace / "cache-overlay", final, use_subvolumes=state.config.use_subvolumes)
else:
- move_tree(state.config, state.root, final)
+ move_tree(state.root, final, use_subvolumes=state.config.use_subvolumes)
if need_build_overlay(state.config) and (state.workspace / "build-overlay").exists():
rmtree(build)
- move_tree(state.config, state.workspace / "build-overlay", build)
+ move_tree(state.workspace / "build-overlay", build, use_subvolumes=state.config.use_subvolumes)
manifest.write_text(
json.dumps(
return False
with complete_step("Copying cached trees"):
- copy_tree(state.config, final, state.root)
+ copy_tree(final, state.root, use_subvolumes=state.config.use_subvolumes)
if need_build_overlay(state.config):
(state.workspace / "build-overlay").symlink_to(build)
# Make sure all build outputs that are not directories are owned by the user running mkosi.
if not f.is_dir():
os.chown(f, INVOKING_USER.uid, INVOKING_USER.gid, follow_symlinks=False)
- move_tree(state.config, f, state.config.output_dir_or_cwd())
+ move_tree(f, state.config.output_dir_or_cwd(), use_subvolumes=state.config.use_subvolumes)
def normalize_mtime(root: Path, mtime: Optional[int], directory: Optional[Path] = None) -> None:
for d in ("binpkgs", "distfiles", "repos/gentoo"):
(state.cache_dir / d).mkdir(parents=True, exist_ok=True)
- copy_tree(state.config, state.pkgmngr, stage3, preserve_owner=False)
+ copy_tree(state.pkgmngr, stage3, preserve_owner=False, use_subvolumes=state.config.use_subvolumes)
features = " ".join([
# Disable sandboxing in emerge because we already do it in mkosi.
(macros / "macros.lang").write_text(f"%_install_langs {state.config.locale}")
rpmconfigdir = Path(run(["rpm", "--eval", "%{_rpmconfigdir}"], stdout=subprocess.PIPE).stdout.strip())
- copy_tree(state.config, rpmconfigdir, state.pkgmngr / "usr/lib/rpm", clobber=False)
+ copy_tree(rpmconfigdir, state.pkgmngr / "usr/lib/rpm", clobber=False, use_subvolumes=state.config.use_subvolumes)
def dnf_cmd(state: MkosiState) -> list[PathString]:
tmp = src.parent / f"{src.name}-{uuid.uuid4().hex}"
try:
- copy_tree(config, src, tmp)
+ copy_tree(src, tmp, use_subvolumes=config.use_subvolumes)
yield tmp
finally:
rmtree(tmp)
if config.overlay:
self.root.mkdir()
else:
- make_tree(self.config, self.root)
+ make_tree(self.root, use_subvolumes=self.config.use_subvolumes)
self.staging.mkdir()
self.pkgmngr.mkdir()
from typing import Optional
from mkosi.archive import extract_tar
-from mkosi.config import ConfigFeature, MkosiConfig
+from mkosi.config import ConfigFeature
from mkosi.log import die
from mkosi.run import run
from mkosi.types import PathString
return path.is_dir() and statfs(path) == "btrfs" and path.stat().st_ino == 256
-def make_tree(config: MkosiConfig, path: Path) -> None:
- if config.use_subvolumes == ConfigFeature.enabled and not shutil.which("btrfs"):
+def make_tree(path: Path, use_subvolumes: ConfigFeature = ConfigFeature.disabled) -> None:
+ if use_subvolumes == ConfigFeature.enabled and not shutil.which("btrfs"):
die("Subvolumes requested but the btrfs command was not found")
if statfs(path.parent) != "btrfs":
- if config.use_subvolumes == ConfigFeature.enabled:
+ if use_subvolumes == ConfigFeature.enabled:
die(f"Subvolumes requested but {path} is not located on a btrfs filesystem")
path.mkdir()
return
- if config.use_subvolumes != ConfigFeature.disabled and shutil.which("btrfs") is not None:
+ if use_subvolumes != ConfigFeature.disabled and shutil.which("btrfs") is not None:
result = run(["btrfs", "subvolume", "create", path],
- check=config.use_subvolumes == ConfigFeature.enabled).returncode
+ check=use_subvolumes == ConfigFeature.enabled).returncode
else:
result = 1
return GenericVersion(run(["cp", "--version"], stdout=subprocess.PIPE).stdout.strip().splitlines()[0].split()[3])
-def copy_tree(config: MkosiConfig, src: Path, dst: Path, *, preserve_owner: bool = True, clobber: bool = True) -> None:
- subvolume = (config.use_subvolumes == ConfigFeature.enabled or
- config.use_subvolumes == ConfigFeature.auto and shutil.which("btrfs") is not None)
+def copy_tree(
+ src: Path,
+ dst: Path,
+ *,
+ preserve_owner: bool = True,
+ clobber: bool = True,
+ use_subvolumes: ConfigFeature = ConfigFeature.disabled,
+) -> None:
+ subvolume = (use_subvolumes == ConfigFeature.enabled or
+ use_subvolumes == ConfigFeature.auto and shutil.which("btrfs") is not None)
- if config.use_subvolumes == ConfigFeature.enabled and not shutil.which("btrfs"):
+ if use_subvolumes == ConfigFeature.enabled and not shutil.which("btrfs"):
die("Subvolumes requested but the btrfs command was not found")
copy: list[PathString] = [
if shutil.which("btrfs"):
result = run(["btrfs", "subvolume", "snapshot", src, dst],
- check=config.use_subvolumes == ConfigFeature.enabled).returncode
+ check=use_subvolumes == ConfigFeature.enabled).returncode
else:
result = 1
run(["rm", "-rf", "--", *paths])
-def move_tree(config: MkosiConfig, src: Path, dst: Path) -> None:
+def move_tree(src: Path, dst: Path, use_subvolumes: ConfigFeature = ConfigFeature.disabled) -> None:
if src == dst:
return
if e.errno != errno.EXDEV:
raise e
- copy_tree(config, src, dst)
+ copy_tree(src, dst, use_subvolumes=use_subvolumes)
rmtree(src)
-def install_tree(config: MkosiConfig, src: Path, dst: Path, target: Optional[Path] = None) -> None:
+def install_tree(
+ src: Path,
+ dst: Path,
+ target: Optional[Path] = None,
+ use_subvolumes: ConfigFeature = ConfigFeature.disabled,
+) -> None:
t = dst
if target:
t = dst / target.relative_to("/")
t.parent.mkdir(parents=True, exist_ok=True)
if src.is_dir() or (src.is_file() and target):
- copy_tree(config, src, t, preserve_owner=False)
+ copy_tree(src, t, preserve_owner=False, use_subvolumes=use_subvolumes)
elif src.suffix == ".tar":
extract_tar(src, t)
elif src.suffix == ".raw":