2020 StyxRuntimeError ,
2121)
2222
23+ if os .name == "posix" :
24+ _HOST_UID : int | None = os .getuid ()
25+ else :
26+ _HOST_UID = None
2327
24- def _podman_mount (host_path : str , container_path : str , readonly : bool ) -> str :
25- """Construct Podman mount argument.
26-
27- Args:
28- host_path: Path on the host filesystem to mount.
29- container_path: Path inside the container where the host path will be mounted.
30- readonly: If True, mount as read-only; otherwise mount as read-write.
3128
32- Returns:
33- Formatted mount string in the format "host:container[:ro]".
34-
35- Raises:
36- ValueError: If host_path or container_path contains illegal characters
37- (comma, backslash, or colon).
38- """
39- # Check for illegal characters
40- charset = set (host_path + container_path )
41- if any (c in charset for c in r",\\:" ):
42- raise ValueError ("Illegal characters in path" )
43- return f"{ host_path } :{ container_path } { ':ro' if readonly else '' } "
29+ def _podman_mount (host_path : str , container_path : str , readonly : bool ) -> str :
30+ """Construct Podman mount argument."""
31+ host_path = host_path .replace ('"' , r"\"" )
32+ container_path = container_path .replace ('"' , r"\"" )
33+ host_path = host_path .replace ("\\ " , "\\ \\ " )
34+ container_path = container_path .replace ("\\ " , "\\ \\ " )
35+ readonly_str = ",readonly" if readonly else ""
36+ return f"type=bind,source={ host_path } ,target={ container_path } { readonly_str } "
4437
4538
4639class StyxPodmanError (StyxRuntimeError ):
@@ -55,14 +48,7 @@ def __init__(
5548 command_args : list [str ] | None = None ,
5649 podman_args : list [str ] | None = None ,
5750 ) -> None :
58- """Create StyxPodmanError.
59-
60- Args:
61- return_code: The exit code returned by the failed process.
62- command_args: The command arguments that were executed inside the container.
63- podman_args: The Podman-specific arguments used to run the
64- container.
65- """
51+ """Create StyxPodmanError."""
6652 super ().__init__ (
6753 return_code = return_code ,
6854 command_args = command_args ,
@@ -87,19 +73,10 @@ def __init__(
8773 container_tag : str ,
8874 podman_executable : str ,
8975 podman_extra_args : list [str ],
76+ podman_user_id : int | None ,
9077 environ : dict [str , str ],
9178 ) -> None :
92- """Create PodmanExecution.
93-
94- Args:
95- logger: Logger instance for execution logging.
96- output_dir: Directory where output files will be written.
97- metadata: Metadata about the command being executed.
98- container_tag: Podman container image tag (e.g., "docker://ubuntu:20.04").
99- podman_executable: Path to the podman executable.
100- podman_extra_args: Additional arguments to pass to podman.
101- environ: Environment variables to set in the container.
102- """
79+ """Create PodmanExecution."""
10380 self .logger : logging .Logger = logger
10481 self .input_mounts : list [tuple [pl .Path , str , bool ]] = []
10582 self .input_file_next_id = 0
@@ -108,6 +85,7 @@ def __init__(
10885 self .container_tag = container_tag
10986 self .podman_executable = podman_executable
11087 self .podman_extra_args = podman_extra_args
88+ self .podman_user_id = podman_user_id
11189 self .environ = environ
11290
11391 def input_file (
@@ -291,36 +269,20 @@ def __init__(
291269 image_overrides : dict [str , str ] | None = None ,
292270 podman_executable : str = "podman" ,
293271 podman_extra_args : list [str ] | None = None ,
272+ podman_user_id : int | None = None ,
294273 data_dir : InputPathType | None = None ,
295274 environ : dict [str , str ] | None = None ,
296275 ) -> None :
297- """Create a new PodmanRunner.
298-
299- Args:
300- image_overrides: Dictionary mapping container image tags to alternative
301- tags. Useful for using local or custom container images.
302- podman_executable: Path to the podman executable. Defaults to
303- "podman" (assumes it's in PATH).
304- podman_extra_args: Additional arguments to pass to all
305- podman commands.
306- Defaults to ["--no-mount", "hostfs"] to prevent automatic host
307- filesystem mounting.
308- data_dir: Directory for temporary execution data and outputs.
309- Defaults to "styx_tmp" in the current directory.
310- environ: Environment variables to set in all container executions.
311-
312- Raises:
313- ValueError: If running on Windows (Podman is not supported on Windows).
314- """
315- if os .name == "nt" :
316- raise ValueError ("PodmanRunner is not supported on Windows" )
317-
276+ """Create a new PodmanRunner."""
318277 self .data_dir = pl .Path (data_dir or "styx_tmp" )
319278 self .uid = os .urandom (8 ).hex ()
320279 self .execution_counter = 0
321- self .image_overrides = image_overrides or {}
322280 self .podman_executable = podman_executable
323- self .podman_extra_args = podman_extra_args or ["--no-mount" , "hostfs" ]
281+ self .podman_extra_args = podman_extra_args or []
282+ self .podman_user_id = (
283+ podman_user_id if podman_user_id is not None else _HOST_UID
284+ )
285+ self .image_overrides = image_overrides or {}
324286 self .environ = environ or {}
325287
326288 # Configure logger
@@ -334,28 +296,14 @@ def __init__(
334296 self .logger .addHandler (ch )
335297
336298 def start_execution (self , metadata : Metadata ) -> Execution :
337- """Start a new execution context.
338-
339- Creates a new execution instance with a unique output directory
340- and configured container image.
341-
342- Args:
343- metadata: Metadata describing the command to execute, including
344- the container image tag.
345-
346- Returns:
347- Execution context for running commands in the container.
348-
349- Raises:
350- ValueError: If metadata doesn't specify a container image tag.
351- """
299+ """Start a new execution context."""
352300 if metadata .container_image_tag is None :
353301 raise ValueError ("No container image tag specified in metadata" )
354302 container_tag = self .image_overrides .get (
355303 metadata .container_image_tag , metadata .container_image_tag
356304 )
357- if not container_tag .startswith ("docker:/ /" ):
358- container_tag = f"docker:/ /{ container_tag } "
305+ if not container_tag .startswith ("docker.io /" ):
306+ container_tag = f"docker.io /{ container_tag } "
359307
360308 self .execution_counter += 1
361309 return _PodmanExecution (
@@ -364,6 +312,7 @@ def start_execution(self, metadata: Metadata) -> Execution:
364312 / f"{ self .uid } _{ self .execution_counter - 1 } _{ metadata .name } " ,
365313 metadata = metadata ,
366314 container_tag = container_tag ,
315+ podman_user_id = self .podman_user_id ,
367316 podman_executable = self .podman_executable ,
368317 podman_extra_args = self .podman_extra_args ,
369318 environ = self .environ ,
0 commit comments