Skip to content

Commit 0a4fa3a

Browse files
committed
Do not require docker save
1 parent 823b687 commit 0a4fa3a

File tree

4 files changed

+42
-24
lines changed

4 files changed

+42
-24
lines changed

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ the software container images in Docker format.
4949

5050
.. code:: bash
5151
52-
cwl-docker-extract DIRECTORY path_to_my_workflow.cwl
52+
cwl-docker-extract path_to_my_workflow.cwl
5353
5454
Or you can use the Singularity software container engine to download and
5555
save the software container images and convert them to the Singularity
5656
format at the same time.
5757

5858
.. code:: bash
5959
60-
cwl-docker-extract --singularity DIRECTORY path_to_my_workflow.cwl
60+
cwl-docker-extract --singularity --dir DIRECTORY path_to_my_workflow.cwl
6161
6262
6363
Print all referenced software packages

cwl_utils/docker_extract.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ def arg_parser() -> argparse.ArgumentParser:
2121
description="Save container images specified in a CWL document (Workflow or CommandLineTool). "
2222
"For CWL Workflows, all steps will also be searched (recursively)."
2323
)
24-
parser.add_argument("dir", help="Directory in which to save images")
2524
parser.add_argument(
2625
"input", help="Input CWL document (CWL Workflow or CWL CommandLineTool)"
2726
)
27+
parser.add_argument("--dir", help="Directory in which to save images")
2828
parser.add_argument(
2929
"-s",
3030
"--singularity",
@@ -45,7 +45,12 @@ def arg_parser() -> argparse.ArgumentParser:
4545

4646
def run(args: argparse.Namespace) -> List[cwl.DockerRequirement]:
4747
"""Extract the docker reqs and download them using Singularity or Docker."""
48-
os.makedirs(args.dir, exist_ok=True)
48+
if args.singularity and not args.dir:
49+
print("Error! Must specify --dir if using --singularity")
50+
sys.exit(1)
51+
52+
if args.dir:
53+
os.makedirs(args.dir, exist_ok=True)
4954

5055
top = cwl.load_document_by_uri(args.input)
5156
reqs: List[cwl.DockerRequirement] = []

cwl_utils/image_puller.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import subprocess # nosec
66
from abc import ABC, abstractmethod
77
from pathlib import Path
8-
from typing import List, Union
8+
from typing import List, Optional, Union
99

1010
from .singularity import get_version as get_singularity_version
1111
from .singularity import is_version_2_6 as is_singularity_version_2_6
@@ -17,7 +17,11 @@
1717

1818
class ImagePuller(ABC):
1919
def __init__(
20-
self, req: str, save_directory: Union[str, Path], cmd: str, force_pull: bool
20+
self,
21+
req: str,
22+
save_directory: Optional[Union[str, Path]],
23+
cmd: str,
24+
force_pull: bool,
2125
) -> None:
2226
"""Create an ImagePuller."""
2327
self.req = req
@@ -62,22 +66,24 @@ def generate_udocker_loading_command(self) -> str:
6266

6367
def save_docker_image(self) -> None:
6468
"""Download and save the software container image to disk as a docker tarball."""
65-
_LOGGER.info(f"Pulling {self.req} with Docker...")
69+
_LOGGER.info(f"Pulling {self.req} with {self.cmd}...")
6670
cmd_pull = [self.cmd, "pull", self.req]
6771
ImagePuller._run_command_pull(cmd_pull)
68-
dest = os.path.join(self.save_directory, self.get_image_name())
69-
if self.force_pull:
70-
os.remove(dest)
71-
cmd_save = [
72-
self.cmd,
73-
"save",
74-
"-o",
75-
dest,
76-
self.req,
77-
]
78-
subprocess.run(cmd_save, check=True) # nosec
79-
_LOGGER.info(f"Image successfully pulled: {dest!r}.")
80-
print(self.generate_udocker_loading_command())
72+
_LOGGER.info(f"Image successfully pulled: {self.req}")
73+
if self.save_directory:
74+
dest = os.path.join(self.save_directory, self.get_image_name())
75+
if self.save_directory and self.force_pull:
76+
os.remove(dest)
77+
cmd_save = [
78+
self.cmd,
79+
"save",
80+
"-o",
81+
dest,
82+
self.req,
83+
]
84+
subprocess.run(cmd_save, check=True) # nosec
85+
_LOGGER.info(f"Image successfully saved: {dest!r}.")
86+
print(self.generate_udocker_loading_command())
8187

8288

8389
class SingularityImagePuller(ImagePuller):
@@ -103,8 +109,11 @@ def get_image_name(self) -> str:
103109

104110
def save_docker_image(self) -> None:
105111
"""Pull down the Docker software container image and save it in the Singularity image format."""
112+
save_directory: Union[str, Path]
113+
if self.save_directory:
114+
save_directory = self.save_directory
106115
if (
107-
os.path.exists(os.path.join(self.save_directory, self.get_image_name()))
116+
os.path.exists(os.path.join(save_directory, self.get_image_name()))
108117
and not self.force_pull
109118
):
110119
_LOGGER.info(f"Already cached {self.req} with Singularity.")
@@ -119,11 +128,11 @@ def save_docker_image(self) -> None:
119128
cmd_pull.extend(
120129
[
121130
"--name",
122-
os.path.join(self.save_directory, self.get_image_name()),
131+
os.path.join(save_directory, self.get_image_name()),
123132
f"docker://{self.req}",
124133
]
125134
)
126135
ImagePuller._run_command_pull(cmd_pull)
127136
_LOGGER.info(
128-
f"Image successfully pulled: {self.save_directory}/{self.get_image_name()}"
137+
f"Image successfully pulled: {save_directory}/{self.get_image_name()}"
129138
)

tests/test_docker_extract.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
def test_container_extraction(target: str, engine: str, tmp_path: Path) -> None:
2424
"""Test container extraction tool."""
2525

26-
args = [str(tmp_path), get_data(target), "--container-engine", engine]
26+
args = ["--dir", str(tmp_path), get_data(target), "--container-engine", engine]
2727
if engine == "singularity":
2828
args.append("--singularity")
2929
reqs = run(arg_parser().parse_args(args))
@@ -43,6 +43,7 @@ def test_container_extraction_force(engine: str, tmp_path: Path) -> None:
4343
"""Test force pull container extraction."""
4444

4545
args = [
46+
"--dir",
4647
str(tmp_path),
4748
get_data("testdata/md5sum.cwl"),
4849
"--container-engine",
@@ -54,6 +55,7 @@ def test_container_extraction_force(engine: str, tmp_path: Path) -> None:
5455
assert len(reqs) == 1
5556
assert len(list(tmp_path.iterdir())) == 1
5657
args = [
58+
"--dir",
5759
str(tmp_path),
5860
get_data("testdata/md5sum.cwl"),
5961
"--container-engine",
@@ -81,6 +83,7 @@ def test_container_extraction_no_dockerPull(
8183
"""Test container extraction tool when dockerPull is missing."""
8284

8385
args = [
86+
"--dir",
8487
str(tmp_path),
8588
get_data("testdata/debian_image_id.cwl"),
8689
"--container-engine",
@@ -113,6 +116,7 @@ def test_container_extraction_embedded_step(engine: str, tmp_path: Path) -> None
113116
"""Test container extraction tool."""
114117

115118
args = [
119+
"--dir",
116120
str(tmp_path),
117121
get_data("testdata/workflows/count-lines16-wf.cwl"),
118122
"--container-engine",

0 commit comments

Comments
 (0)