Repository: systemd/mkosi

Issue:
"-C" flag results in inconsistent relative path handling
When using the `-C` flag, most flags that take paths resolve relative paths early (before performing the `os.chdir`).
However, when using the `--package` flag and providing a local package (like `./foo.rpm`), the path is relative to the directory after `os.chdir`.
I see that this might be difficult to get consistent (especially since the `--package` expression is just forwarded to the package manager as a str), but I wonder if it makes sense to make all paths relative to the result of `os.chdir` for consistency.


Discussion:

Resolving patch:
diff --git a/mkosi/config.py b/mkosi/config.py
--- a/mkosi/config.py
+++ b/mkosi/config.py
@@ -1654,7 +1654,7 @@ def parse_ini(path: Path, only_sections: Sequence[str] = ()) -> Iterator[tuple[s
 )
 
 
-def create_argument_parser() -> argparse.ArgumentParser:
+def create_argument_parser(*, settings: bool) -> argparse.ArgumentParser:
     action = config_make_action(SETTINGS)
 
     parser = argparse.ArgumentParser(
@@ -1682,18 +1682,6 @@ def create_argument_parser() -> argparse.ArgumentParser:
         formatter_class=CustomHelpFormatter,
     )
 
-    parser.add_argument(
-        "verb",
-        type=Verb,
-        choices=list(Verb),
-        default=Verb.build,
-        help=argparse.SUPPRESS,
-    )
-    parser.add_argument(
-        "cmdline",
-        nargs=argparse.REMAINDER,
-        help=argparse.SUPPRESS,
-    )
     parser.add_argument(
         "-h", "--help",
         action=PagerHelpAction,
@@ -1786,6 +1774,22 @@ def create_argument_parser() -> argparse.ArgumentParser:
         help=argparse.SUPPRESS,
     )
 
+    if not settings:
+        return parser
+
+    parser.add_argument(
+        "verb",
+        type=Verb,
+        choices=list(Verb),
+        default=Verb.build,
+        help=argparse.SUPPRESS,
+    )
+    parser.add_argument(
+        "cmdline",
+        nargs=argparse.REMAINDER,
+        help=argparse.SUPPRESS,
+    )
+
     last_section = None
 
     for s in SETTINGS:
@@ -2001,7 +2005,19 @@ def finalize_defaults(namespace: argparse.Namespace, defaults: argparse.Namespac
     else:
         argv += ["--", "build"]
 
-    argparser = create_argument_parser()
+    # Don't parse the settings just yet so we can take --directory into account when parsing settings that
+    # take relative paths.
+    argparser = create_argument_parser(settings=False)
+    argparser.parse_known_args(argv, namespace)
+
+    if namespace.directory and not Path(namespace.directory).is_dir():
+        die(f"{namespace.directory} is not a directory!")
+
+    if namespace.directory:
+        os.chdir(namespace.directory)
+
+    namespace = argparse.Namespace()
+    argparser = create_argument_parser(settings=True)
     argparser.parse_args(argv, namespace)
 
     args = load_args(namespace)
@@ -2012,12 +2028,6 @@ def finalize_defaults(namespace: argparse.Namespace, defaults: argparse.Namespac
     if args.verb == Verb.help:
         PagerHelpAction.__call__(None, argparser, namespace)  # type: ignore
 
-    if args.directory and not Path(args.directory).is_dir():
-        die(f"{args.directory} is not a directory!")
-
-    if args.directory:
-        os.chdir(args.directory)
-
     if args.directory != "":
         parse_config(Path("."), namespace, defaults)
 


Test patch: