Repository: systemd/mkosi

Issue:
build fails if mkosi.workspace directory present
Using main branch on Debian Sid.

Failure:
```
ander@m720q:smtng-is-borkd$ mkdir mkosi.workspace
ander@m720q:smtng-is-borkd$ PATH="/usr/sbin:$PATH" mkosi --debug run 
+ timedatectl show -p Timezone --value
Bus n/a: changing state UNSET → OPENING
sd-bus: starting bus by connecting to /run/dbus/system_bus_socket...
Bus n/a: changing state OPENING → AUTHENTICATING
Bus n/a: changing state AUTHENTICATING → HELLO
Sent message type=method_call sender=n/a destination=org.freedesktop.DBus path=/org/freedesktop/DBus interface=org.freedesktop.DBus member=Hello cookie=1 reply_cookie=0 signature=n/a error-name=n/a error-message=n/a
Got message type=method_return sender=org.freedesktop.DBus destination=:1.188 path=n/a interface=n/a member=n/a cookie=1 reply_cookie=1 signature=s error-name=n/a error-message=n/a
Bus n/a: changing state HELLO → RUNNING
Sent message type=method_call sender=n/a destination=org.freedesktop.timedate1 path=/org/freedesktop/timedate1 interface=org.freedesktop.DBus.Properties member=GetAll cookie=2 reply_cookie=0 signature=s error-name=n/a error-message=n/a
Got message type=method_return sender=:1.189 destination=:1.188 path=n/a interface=n/a member=n/a cookie=4 reply_cookie=2 signature=a{sv} error-name=n/a error-message=n/a
Bus n/a: changing state RUNNING → CLOSED
+ newuidmap 273188 0 100000 65436 65436 1000 1 65437 165437 99
+ newgidmap 273188 0 100000 65436 65436 100 1 65437 165437 99
‣ Removing output files…
+ newuidmap 273193 0 100000 65436 65436 1000 1 65437 165437 99
+ newgidmap 273193 0 100000 65436 65436 100 1 65437 165437 99
+ mount --make-rslave /
+ mkdir -p mkosi.workspace/.mkosi.tmp5qalyq65/cache
+ mkdir -p mkosi.workspace/.mkosi.tmp5qalyq65/dest
‣ Building image
‣  Mounting image…
+ debootstrap --no-check-valid-until
+ bwrap --unshare-pid --dev-bind / / --tmpfs mkosi.workspace/.mkosi.tmp5qalyq65/root/run --tmpfs mkosi.workspace/.mkosi.tmp5qalyq65/root/tmp --proc mkosi.workspace/.mkosi.tmp5qalyq65/root/proc --dev mkosi.workspace/.mkosi.tmp5qalyq65/root/dev --ro-bind /sys mkosi.workspace/.mkosi.tmp5qalyq65/root/sys --bind mkosi.workspace/.mkosi.tmp5qalyq65/var-tmp mkosi.workspace/.mkosi.tmp5qalyq65/root/var/tmp --die-with-parent sh -c 'chmod 1777 mkosi.workspace/.mkosi.tmp5qalyq65/root/tmp mkosi.workspace/.mkosi.tmp5qalyq65/root/var/tmp mkosi.workspace/.mkosi.tmp5qalyq65/root/dev/shm && exec debootstrap --variant=minbase --include=ca-certificates --merged-usr --cache-dir=/tmp/smtng-is-borkd/mkosi.workspace/.mkosi.tmp5qalyq65/cache --components=main --arch=amd64 bookworm mkosi.workspace/.mkosi.tmp5qalyq65/root http://deb.debian.org/debian || exit $?'
bwrap: Can't mkdir parents for mkosi.workspace/.mkosi.tmp5qalyq65/root/run: Permission denied
+ bwrap --unshare-pid --dev-bind / / --tmpfs mkosi.workspace/.mkosi.tmp5qalyq65/root/run --tmpfs mkosi.workspace/.mkosi.tmp5qalyq65/root/tmp --proc mkosi.workspace/.mkosi.tmp5qalyq65/root/proc --dev mkosi.workspace/.mkosi.tmp5qalyq65/root/dev --ro-bind /sys mkosi.workspace/.mkosi.tmp5qalyq65/root/sys --bind mkosi.workspace/.mkosi.tmp5qalyq65/var-tmp mkosi.workspace/.mkosi.tmp5qalyq65/root/var/tmp --die-with-parent sh -c 'chmod 1777 mkosi.workspace/.mkosi.tmp5qalyq65/root/tmp mkosi.workspace/.mkosi.tmp5qalyq65/root/var/tmp mkosi.workspace/.mkosi.tmp5qalyq65/root/dev/shm && exec sh || exit $?'
bwrap: Can't mkdir parents for mkosi.workspace/.mkosi.tmp5qalyq65/root/run: Permission denied
‣ Error: "debootstrap --variant=minbase --include=ca-certificates --merged-usr --cache-dir=/tmp/smtng-is-borkd/mkosi.workspace/.mkosi.tmp5qalyq65/cache --components=main --arch=amd64 bookworm mkosi.workspace/.mkosi.tmp5qalyq65/root http://deb.debian.org/debian" returned non-zero exit code 1.
```

All good:
```
ander@m720q:smtng-is-borkd$ rmdir mkosi.workspace/
ander@m720q:smtng-is-borkd$ PATH="/usr/sbin:$PATH" mkosi --debug run 
+ timedatectl show -p Timezone --value
Bus n/a: changing state UNSET → OPENING
sd-bus: starting bus by connecting to /run/dbus/system_bus_socket...
Bus n/a: changing state OPENING → AUTHENTICATING
Bus n/a: changing state AUTHENTICATING → HELLO
Sent message type=method_call sender=n/a destination=org.freedesktop.DBus path=/org/freedesktop/DBus interface=org.freedesktop.DBus member=Hello cookie=1 reply_cookie=0 signature=n/a error-name=n/a error-message=n/a
Got message type=method_return sender=org.freedesktop.DBus destination=:1.190 path=n/a interface=n/a member=n/a cookie=1 reply_cookie=1 signature=s error-name=n/a error-message=n/a
Bus n/a: changing state HELLO → RUNNING
Sent message type=method_call sender=n/a destination=org.freedesktop.timedate1 path=/org/freedesktop/timedate1 interface=org.freedesktop.DBus.Properties member=GetAll cookie=2 reply_cookie=0 signature=s error-name=n/a error-message=n/a
Got message type=method_return sender=:1.191 destination=:1.190 path=n/a interface=n/a member=n/a cookie=4 reply_cookie=2 signature=a{sv} error-name=n/a error-message=n/a
Bus n/a: changing state RUNNING → CLOSED
+ newuidmap 273266 0 100000 65436 65436 1000 1 65437 165437 99
+ newgidmap 273266 0 100000 65436 65436 100 1 65437 165437 99
‣ Removing output files…
+ newuidmap 273271 0 100000 65436 65436 1000 1 65437 165437 99
+ newgidmap 273271 0 100000 65436 65436 100 1 65437 165437 99
+ mount --make-rslave /
+ mkdir -p /tmp/smtng-is-borkd/.mkosi.tmp01txex0p/cache
+ mkdir -p /tmp/smtng-is-borkd/.mkosi.tmp01txex0p/dest
‣ Building image
‣  Mounting image…
+ debootstrap --no-check-valid-until
+ bwrap --unshare-pid --dev-bind / / --tmpfs /tmp/smtng-is-borkd/.mkosi.tmp01txex0p/root/run --tmpfs /tmp/smtng-is-borkd/.mkosi.tmp01txex0p/root/tmp --proc /tmp/smtng-is-borkd/.mkosi.tmp01txex0p/root/proc --dev /tmp/smtng-is-borkd/.mkosi.tmp01txex0p/root/dev --ro-bind /sys /tmp/smtng-is-borkd/.mkosi.tmp01txex0p/root/sys --bind /tmp/smtng-is-borkd/.mkosi.tmp01txex0p/var-tmp /tmp/smtng-is-borkd/.mkosi.tmp01txex0p/root/var/tmp --die-with-parent sh -c 'chmod 1777 /tmp/smtng-is-borkd/.mkosi.tmp01txex0p/root/tmp /tmp/smtng-is-borkd/.mkosi.tmp01txex0p/root/var/tmp /tmp/smtng-is-borkd/.mkosi.tmp01txex0p/root/dev/shm && exec debootstrap --variant=minbase --include=ca-certificates --merged-usr --cache-dir=/tmp/smtng-is-borkd/.mkosi.tmp01txex0p/cache --components=main --arch=amd64 bookworm /tmp/smtng-is-borkd/.mkosi.tmp01txex0p/root http://deb.debian.org/debian || exit $?'
I: Retrieving InRelease 
I: Checking Release signature
I: Valid Release signature (key id A7236886F3CCCAAD148A27F80E98404D386FA1D9)
I: Retrieving Packages 
I: Validating Packages 
I: Resolving dependencies of required packages...
---8<--- snip ---8<---
```


Discussion:

Resolving patch:
diff --git a/mkosi/__init__.py b/mkosi/__init__.py
--- a/mkosi/__init__.py
+++ b/mkosi/__init__.py
@@ -1130,6 +1130,7 @@ def load_args(args: argparse.Namespace) -> MkosiConfig:
             args.output = args.output_dir / args.output
         else:
             warn("Ignoring configured output directory as output file is a qualified path.")
+            args.output = args.output.absolute()
 
     if args.environment:
         env = {}
diff --git a/mkosi/config.py b/mkosi/config.py
--- a/mkosi/config.py
+++ b/mkosi/config.py
@@ -45,9 +45,9 @@ def parse_source_target_paths(value: str) -> tuple[Path, Optional[Path]]:
     src, _, target = value.partition(':')
     if not Path(src).exists():
         die(f"{src} does not exist")
-    if target and not Path(target).absolute():
+    if target and not Path(target).is_absolute():
         die("Target path must be absolute")
-    return Path(src), Path(target) if target else None
+    return Path(src).absolute(), Path(target) if target else None
 
 
 def config_parse_string(dest: str, value: Optional[str], namespace: argparse.Namespace) -> Optional[str]:
@@ -71,7 +71,7 @@ def config_parse_script(dest: str, value: Optional[str], namespace: argparse.Nam
         if not os.access(value, os.X_OK):
             die(f"{value} is not executable")
 
-    return Path(value) if value else None
+    return Path(value).absolute() if value else None
 
 
 def config_parse_boolean(dest: str, value: Optional[str], namespace: argparse.Namespace) -> bool:
@@ -196,7 +196,7 @@ def parse_path(value: str) -> Path:
         if required and not Path(value).exists():
             die(f"{value} does not exist")
 
-        return Path(value)
+        return Path(value).absolute()
 
     return parse_path
 
@@ -209,7 +209,7 @@ def config_parse_path(dest: str, value: Optional[str], namespace: argparse.Names
         if value and required and not Path(value).exists():
             die(f"{value} does not exist")
 
-        return Path(value) if value else None
+        return Path(value).absolute() if value else None
 
     return config_parse_path
 
diff --git a/mkosi/run.py b/mkosi/run.py
--- a/mkosi/run.py
+++ b/mkosi/run.py
@@ -259,6 +259,7 @@ def run_with_apivfs(
         # Required to make chroot detection via /proc/1/root work properly.
         "--unshare-pid",
         "--dev-bind", "/", "/",
+        "--chdir", Path.cwd(),
         "--tmpfs", state.root / "run",
         "--tmpfs", state.root / "tmp",
         "--proc", state.root / "proc",


Test patch: