Skip to content

Commit 74ab14b

Browse files
committed
Simple stage files.
1 parent 0561c71 commit 74ab14b

File tree

4 files changed

+23
-114
lines changed

4 files changed

+23
-114
lines changed

cwltool/docker.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import shutil
88
import subprocess # nosec
99
import sys
10-
import tempfile
1110
import threading
1211
from distutils import spawn
1312
from io import StringIO, open # pylint: disable=redefined-builtin
@@ -103,9 +102,6 @@ def __init__(
103102
super(DockerCommandLineJob, self).__init__(
104103
builder, joborder, make_path_mapper, requirements, hints, name
105104
)
106-
# TODO: Unused; Implement for docker as well.
107-
self.universal_file_bindmount_dir = tempfile.mkdtemp(suffix='-cwl-docker-mnt')
108-
self.bindings_map = []
109105

110106
@staticmethod
111107
def get_image(

cwltool/job.py

Lines changed: 4 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@
44
import logging
55
import os
66
import re
7-
import resource
87
import shutil
98
import subprocess # nosec
109
import sys
1110
import tempfile
12-
import textwrap
1311
import threading
1412
import time
1513
import uuid
@@ -531,15 +529,6 @@ def run(
531529
tmpdir_lock: Optional[threading.Lock] = None,
532530
) -> None:
533531

534-
# attempt to set an "unlimited" (-1) heap size for this process
535-
# (& thus commandline size) on any system that supports it
536-
# TODO: Do containers inherit the processes's limits?
537-
# Can they be configured from outside of the container?
538-
try:
539-
resource.setrlimit(resource.RLIMIT_DATA, (-1, -1))
540-
except Exception:
541-
pass
542-
543532
if tmpdir_lock:
544533
with tmpdir_lock:
545534
if not os.path.exists(self.tmpdir):
@@ -600,20 +589,6 @@ def run(
600589

601590
class ContainerCommandLineJob(JobBase, metaclass=ABCMeta):
602591
"""Commandline job using containers."""
603-
def __init__(
604-
self,
605-
builder: Builder,
606-
joborder: CWLObjectType,
607-
make_path_mapper: Callable[..., PathMapper],
608-
requirements: List[CWLObjectType],
609-
hints: List[CWLObjectType],
610-
name: str,
611-
) -> None:
612-
super(JobBase, self).__init__(
613-
builder, joborder, make_path_mapper, requirements, hints, name
614-
)
615-
self.universal_file_bindmount_dir = None
616-
self.bindings_map = None
617592

618593
@abstractmethod
619594
def get_from_requirements(
@@ -706,69 +681,10 @@ def add_volumes(
706681
any_path_okay: bool = False,
707682
) -> None:
708683
"""Append volume mappings to the runtime option list."""
709-
container_outdir = self.builder.outdir
710-
for key, vol in (itm for itm in pathmapper.items() if itm[1].staged):
711-
host_outdir_tgt = None # type: Optional[str]
712-
if vol.target.startswith(container_outdir + "/"):
713-
host_outdir_tgt = os.path.join(
714-
self.outdir, vol.target[len(container_outdir) + 1 :]
715-
)
716-
if not host_outdir_tgt and not any_path_okay:
717-
raise WorkflowException(
718-
"No mandatory DockerRequirement, yet path is outside "
719-
"the designated output directory, also know as "
720-
"$(runtime.outdir): {}".format(vol)
721-
)
722-
if vol.type in ("File", "Directory"):
723-
self.add_file_or_directory_volume(runtime, vol, host_outdir_tgt)
724-
elif vol.type == "WritableFile":
725-
self.add_writable_file_volume(
726-
runtime, vol, host_outdir_tgt, tmpdir_prefix
727-
)
728-
elif vol.type == "WritableDirectory":
729-
self.add_writable_directory_volume(
730-
runtime, vol, host_outdir_tgt, tmpdir_prefix
731-
)
732-
elif vol.type in ["CreateFile", "CreateWritableFile"]:
733-
new_path = self.create_file_and_add_volume(
734-
runtime, vol, host_outdir_tgt, secret_store, tmpdir_prefix
735-
)
736-
pathmapper.update(key, new_path, vol.target, vol.type, vol.staged)
737-
738-
# Dir of individual file inputs for the job (all named as uuid4).
739-
# This creates the same dir inside of the container as exists outside of it,
740-
# Overlayfs must be supported/enabled (which should always be true for CWL).
741-
src = dst = self.universal_file_bindmount_dir
742-
runtime.append(f"--bind={src}:{dst}:rw")
743-
744-
# Make a TSV of the file mappings.
745-
mapping_tsv = os.path.join(self.universal_file_bindmount_dir, 'mapping.tsv')
746-
with open(mapping_tsv, 'w') as f:
747-
# 1. Sort by the destination path, which should sort alphabetically
748-
# and by shortest path first.
749-
# 2. Then, when we go to hardlink the files, we
750-
# should then just be able to hardlink them in order.
751-
for (src, dst, writable) in sorted(self.bindings_map, key=lambda x: len(x[1])):
752-
f.write('\t'.join((src, dst, writable)) + '\n')
753-
754-
# Make the script that uses the TSV file mappings to hardlink everything
755-
# inside of the container to where the job expects to find them.
756-
# This script needs to be the first thing run inside of the container.
757-
linking_script = os.path.join(self.universal_file_bindmount_dir, 'hard_linking_script.py')
758-
# TODO: Write in bash instead. All images might not have python.
759-
with open(linking_script, 'w') as f:
760-
f.write(textwrap.dedent(f"""
761-
import os
762-
763-
with open('{mapping_tsv}', 'r') as f:
764-
for line in f:
765-
src, dst, writable = line.split('\\t')
766-
os.makedirs(os.path.dirname(dst), exist_ok=True)
767-
os.link(src, dst)
768-
# TODO: set the permissions on the file here after linking
769-
770-
"""[1:]))
771-
os.chmod(linking_script, 0o777)
684+
staging_dir = tempfile.mkdtemp()
685+
pathmapper.reset_stagedir(staging_dir)
686+
stage_files(pathmapper, symlink=False)
687+
self.append_volume(runtime, staging_dir, staging_dir)
772688

773689
def run(
774690
self,

cwltool/pathmapper.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,18 @@ def __init__(
6464
separateDirs: bool = True,
6565
) -> None:
6666
"""Initialize the PathMapper."""
67+
self.referenced_files = dedup(referenced_files)
68+
self.basedir = basedir
6769
self._pathmap = {} # type: Dict[str, MapperEnt]
6870
self.stagedir = stagedir
6971
self.separateDirs = separateDirs
70-
self.setup(dedup(referenced_files), basedir)
72+
self.setup(self.referenced_files, basedir)
73+
74+
def reset_stagedir(self, stagedir: str) -> None:
75+
"""Changes the target stagedir for mapped files."""
76+
self.stagedir = stagedir
77+
self._pathmap = {} # type: Dict[str, MapperEnt]
78+
self.setup(self.referenced_files, self.basedir)
7179

7280
def visitlisting(
7381
self,

cwltool/singularity.py

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
import re
66
import shutil
77
import sys
8-
import tempfile
9-
from uuid import uuid4
108
from distutils import spawn
119
from subprocess import ( # nosec
1210
DEVNULL,
@@ -104,8 +102,6 @@ def __init__(
104102
super(SingularityCommandLineJob, self).__init__(
105103
builder, joborder, make_path_mapper, requirements, hints, name
106104
)
107-
self.universal_file_bindmount_dir = tempfile.mkdtemp(suffix='-cwl-singularity-mnt')
108-
self.bindings_map = []
109105

110106
@staticmethod
111107
def get_image(
@@ -282,25 +278,18 @@ def get_from_requirements(
282278

283279
return os.path.abspath(cast(str, r["dockerImageId"]))
284280

281+
@staticmethod
285282
def append_volume(
286-
self, runtime: List[str], source: str, target: str, writable: bool = False
283+
runtime: List[str], source: str, target: str, writable: bool = False
287284
) -> None:
288-
src = docker_windows_path_adjust(source)
289-
dst = docker_windows_path_adjust(target)
290-
writable = "rw" if writable else "ro"
291-
292-
# use only "os.path.isfile(source)" for Windows? check on this...
293-
if os.path.isfile(source) or os.path.isfile(src):
294-
bindmount_path = os.path.join(self.universal_file_bindmount_dir, str(uuid4()))
295-
os.link(src, bindmount_path)
296-
self.bindings_map.append((bindmount_path, dst, writable))
297-
# don't add a bind arg for the shared self.universal_file_bindmount_dir
298-
# here but at the very end
299-
else:
300-
# TODO: We can still bind enough dirs to exceed the max command line length.
301-
# Not sure how to handle this, since outputs deposited in mounted dirs
302-
# need to be there after the run.
303-
runtime.append(f"--bind={src}:{dst}:{writable}")
285+
runtime.append("--bind")
286+
runtime.append(
287+
"{}:{}:{}".format(
288+
docker_windows_path_adjust(source),
289+
docker_windows_path_adjust(target),
290+
"rw" if writable else "ro",
291+
)
292+
)
304293

305294
def add_file_or_directory_volume(
306295
self, runtime: List[str], volume: MapperEnt, host_outdir_tgt: Optional[str]

0 commit comments

Comments
 (0)