]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Stop using workspace directories in source directories
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 6 Nov 2023 12:58:56 +0000 (13:58 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 6 Nov 2023 16:09:34 +0000 (17:09 +0100)
Preparation for making source directories volatile while running
scripts. Overlapping overlayfs directories cause massive mayhem so
to keep our sanity, let's make sure the workspace directory is never
a subdirectory of any source directories.

XDG doesn't provide an equivalent of /var/tmp but when running in /home
we really want the workspace to be located in /home as well so we can use
reflinks if /home is a separate partition so we opt to use XDG_CACHE_HOME
or $HOME/.cache instead.

mkosi/__init__.py
mkosi/config.py
mkosi/resources/mkosi.md

index 10891ae723bf642beb631a7cb3c5056d297e5c37..abb2149615e9243c596752272c8a62e66a1b3b24 100644 (file)
@@ -2101,7 +2101,7 @@ def normalize_mtime(root: Path, mtime: Optional[int], directory: Optional[Path]
 
 def build_image(args: MkosiArgs, config: MkosiConfig) -> None:
     manifest = Manifest(config) if config.manifest_format else None
-    workspace = tempfile.TemporaryDirectory(dir=config.workspace_dir_or_cwd(), prefix=".mkosi-tmp")
+    workspace = tempfile.TemporaryDirectory(dir=config.workspace_dir_or_default(), prefix=".mkosi-tmp")
 
     with workspace, scopedenv({"TMPDIR" : workspace.name}):
         state = MkosiState(args, config, Path(workspace.name))
@@ -2599,6 +2599,19 @@ def mount_tools(tree: Optional[Path]) -> Iterator[None]:
         yield
 
 
+def check_workspace_directory(config: MkosiConfig) -> None:
+    wd = config.workspace_dir_or_default()
+
+    if wd.is_relative_to(Path.cwd()):
+        die(f"The workspace directory ({wd}) cannot be located in the current working directory ({Path.cwd()})",
+            hint="Use WorkspaceDirectory= to configure a different workspace directory")
+
+    for src, _ in config.build_sources:
+        if wd.is_relative_to(src):
+            die(f"The workspace directory ({wd}) cannot be a subdirectory of any source directory ({src})",
+                hint="Use WorkspaceDirectory= to configure a different workspace directory")
+
+
 def run_verb(args: MkosiArgs, images: Sequence[MkosiConfig]) -> None:
     if args.verb.needs_root() and os.getuid() != 0:
         die(f"Must be root to run the {args.verb} command")
@@ -2630,6 +2643,9 @@ def run_verb(args: MkosiArgs, images: Sequence[MkosiConfig]) -> None:
         page(text, args.pager)
         return
 
+    for config in images:
+        check_workspace_directory(config)
+
     images = finalize_tools(args, images)
     last = images[-1]
 
index 8d5456db3fd2e0645f79671b227f5bc2b2a82d5f..c4a01ee6b8a8e0acc56eaa42378749f718f81018 100644 (file)
@@ -848,8 +848,26 @@ class MkosiConfig:
     def output_dir_or_cwd(self) -> Path:
         return self.output_dir or Path.cwd()
 
-    def workspace_dir_or_cwd(self) -> Path:
-        return self.workspace_dir or Path.cwd()
+    def workspace_dir_or_default(self) -> Path:
+        if self.workspace_dir:
+            return self.workspace_dir
+
+        if (cache := os.getenv("XDG_CACHE_HOME")) and Path(cache).exists():
+            return Path(cache)
+
+        # If there's a cache directory and we're running from /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 (
+            (home := os.getenv("HOME")) and
+            "/home" in home and
+            self.cache_dir and
+            self.cache_dir.is_relative_to(home) and
+            (Path(home) / ".cache").exists()
+        ):
+            return Path(home) / ".cache"
+
+        return Path("/var/tmp")
 
     @classmethod
     def default(cls) -> "MkosiConfig":
@@ -1218,7 +1236,6 @@ SETTINGS = (
         name="WorkspaceDirectory",
         section="Output",
         parse=config_make_path_parser(required=False),
-        paths=("mkosi.workspace",),
         help="Workspace directory",
     ),
     MkosiConfigSetting(
index 35c606e39137fdb54070a379edd4763a5dcd0f2d..9c3dc5eccd1e2a68828e1ae675d20f0a0f52ee3d 100644 (file)
@@ -602,9 +602,8 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`,
 : Path to a directory where to store data required temporarily while
   building the image. This directory should have enough space to store
   the full OS image, though in most modes the actually used disk space
-  is smaller. If not specified, and `mkosi.workspace/` exists in the
-  local directory, it is used for this purpose. Otherwise, hidden
-  subdirectories of the current working directory are used.
+  is smaller. If not specified, a subdirectory of `$XDG_CACHE_HOME` (if
+  set), `$HOME/.cache` (if set) or `/var/tmp` is used.
 
 : The data in this directory is removed automatically after each
   build. It's safe to manually remove the contents of this directory