Skip to content

Commit 54ce6da

Browse files
Added cmake-compile command, changed prefixing (#7)
* Added cmake-compile command, changed prefixing + Added the cmake-compile command and all associated functionality ~ Changed tag prefixing to use a function in most cases + Added tag prefixing for base tags as well as image tags to make the interface more consistent. * Tiny documentation change. * setup_conda_dev bugfix ~ Removed a bug that causes errors when building the conda dev image. * Lock file update ~ Updated the lock files. * Bugfixes ~ Updated the GCC version in the lockfiles ~ Added a Test option for docker init images to avoid unintended removals * Added ISCE3 test fixtures and CMake build test. * Documentation updates * ISCE3 fixtures: No-Cache -> False --------- Co-authored-by: tyler-g-hudson <[email protected]>
1 parent ecf73ee commit 54ce6da

14 files changed

+893
-689
lines changed

docker_cli/_docker_cmake.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,29 @@ def cmake_config_dockerfile(base: str, build_type: str, with_cuda: bool = True)
6060
).strip()
6161

6262
return dockerfile
63+
64+
65+
def cmake_build_dockerfile(base: str) -> str:
66+
"""
67+
Creates a dockerfile for compiling with CMake.
68+
69+
Parameters
70+
----------
71+
base : str
72+
The base image tag.
73+
74+
Returns
75+
-------
76+
dockerfile: str
77+
The generated Dockerfile.
78+
"""
79+
# Begin constructing the dockerfile with the initial FROM line.
80+
dockerfile = f"FROM {base}\n\n"
81+
82+
# Run as the $MAMBA_USER and activate the micromamba environment.
83+
dockerfile += f"{micromamba_docker_lines()}\n\n"
84+
85+
# Build the project.
86+
dockerfile += "RUN cmake --build $BUILD_PREFIX --parallel"
87+
88+
return dockerfile

docker_cli/_docker_init.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from textwrap import dedent
22

33

4-
def init_dockerfile(base: str, custom_lines: str) -> str:
4+
def init_dockerfile(base: str, custom_lines: str, test: bool = False) -> str:
55
"""
66
Set up the initial configuration image.
77
@@ -11,13 +11,16 @@ def init_dockerfile(base: str, custom_lines: str) -> str:
1111
The name of the image upon this one will be based.
1212
custom_lines : str
1313
Custom installation and configuration lines to be added to the Dockerfile.
14+
test : bool, optional
15+
Add a "test" directory mkdir command to the Dockerfile if True. Used for test
16+
images. Defaults to False.
1417
1518
Returns
1619
-------
1720
str
1821
The generated Dockerfile.
1922
"""
20-
return (
23+
dockerfile = (
2124
f"FROM {base}\n\n"
2225
+ custom_lines
2326
+ "\n"
@@ -35,3 +38,8 @@ def init_dockerfile(base: str, custom_lines: str) -> str:
3538
"""
3639
).strip()
3740
)
41+
42+
if test:
43+
dockerfile += "\n\nRUN mkdir /test_directory"
44+
45+
return dockerfile

docker_cli/_utils.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@
1818
from .defaults import universal_tag_prefix
1919

2020

21+
def prefix_image_tag(tag: str):
22+
"""Prepends the image tag prefix to the tag if it is not already there."""
23+
prefix = universal_tag_prefix()
24+
prefixed_tag = tag if tag.startswith(prefix) else f"{prefix}-{tag}"
25+
return prefixed_tag
26+
27+
2128
@contextmanager
2229
def temp_image(
2330
base: str,
@@ -53,7 +60,7 @@ def temp_image(
5360
# inherently pulls from the internet if the base image isn't already present on
5461
# the local environment. This ensures that, if the image exists anywhere accessible,
5562
# it will be found automatically without the need for additional logic.
56-
tag = f"{universal_tag_prefix()}-temp-{generate_random_string(k=10)}"
63+
tag = prefix_image_tag(f"temp-{generate_random_string(k=10)}")
5764
try:
5865
temp: Image = Image.build( # type: ignore
5966
tag=tag,

docker_cli/cli/build_commands.py

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from pathlib import Path
33
from typing import List
44

5-
from ..commands import configure_cmake, copy_dir, get_archive
5+
from ..commands import compile_cmake, configure_cmake, copy_dir, get_archive
66
from ._utils import add_tag_argument, help_formatter
77

88

@@ -13,7 +13,11 @@ def init_build_parsers(subparsers: argparse._SubParsersAction) -> None:
1313
The build commands are the group of commands to be completed after the CUDA and
1414
conda environments have been installed to the image, with the purpose of acquiring
1515
and building the ISCE3 repository and any further repositories.
16-
These commands consist of the "get-archive", "copydir", and "cmake-config" commands,
16+
These commands consist of the following commands:
17+
get-archive,
18+
copydir,
19+
cmake-config,
20+
cmake-compile,
1721
and more are being added.
1822
1923
Parameters
@@ -57,31 +61,33 @@ def init_build_parsers(subparsers: argparse._SubParsersAction) -> None:
5761
help="If used, the build configuration will not use CUDA.",
5862
)
5963

60-
setup_parse = argparse.ArgumentParser(add_help=False)
61-
setup_parse.add_argument(
64+
setup_params = argparse.ArgumentParser(add_help=False)
65+
setup_params.add_argument(
6266
"--base",
6367
"-b",
6468
type=str,
6569
required=True,
6670
help="The name of the base Docker image.",
6771
)
6872

73+
no_cache_params = argparse.ArgumentParser(add_help=False)
74+
no_cache_params.add_argument(
75+
"--no-cache",
76+
action="store_true",
77+
help="Run Docker build with no cache if used.",
78+
)
79+
6980
archive_parser = subparsers.add_parser(
7081
"get-archive",
71-
parents=[setup_parse, archive_params],
82+
parents=[setup_params, archive_params, no_cache_params],
7283
help="Set up the GitHub repository image, in [USER]/[REPO_NAME] format.",
7384
formatter_class=help_formatter,
7485
)
7586
add_tag_argument(parser=archive_parser, default="repo")
76-
archive_parser.add_argument(
77-
"--no-cache",
78-
action="store_true",
79-
help="Run Docker build with no cache if used.",
80-
)
8187

8288
copy_dir_parser = subparsers.add_parser(
8389
"copydir",
84-
parents=[setup_parse],
90+
parents=[setup_params, no_cache_params],
8591
help="Insert the contents of a directory at the given path.",
8692
formatter_class=help_formatter,
8793
)
@@ -101,24 +107,22 @@ def init_build_parsers(subparsers: argparse._SubParsersAction) -> None:
101107
help="The path on the image to copy the source directory to. If not given, "
102108
"the base name of the path given by the directory argument will be used.",
103109
)
104-
copy_dir_parser.add_argument(
105-
"--no-cache",
106-
action="store_true",
107-
help="Run Docker build with no cache if used.",
108-
)
109110

110111
config_parser = subparsers.add_parser(
111112
"cmake-config",
112-
parents=[setup_parse, config_params],
113+
parents=[setup_params, config_params, no_cache_params],
113114
help="Creates an image with a configured compiler.",
114115
formatter_class=help_formatter,
115116
)
116117
add_tag_argument(parser=config_parser, default="configured")
117-
config_parser.add_argument(
118-
"--no-cache",
119-
action="store_true",
120-
help="Run Docker build with no cache if used.",
118+
119+
compile_parser = subparsers.add_parser(
120+
"cmake-compile",
121+
parents=[setup_params, no_cache_params],
122+
help="Creates an image with the project built.",
123+
formatter_class=help_formatter,
121124
)
125+
add_tag_argument(parser=compile_parser, default="compiled")
122126

123127

124128
def build_command_names() -> List[str]:
@@ -133,3 +137,5 @@ def run_build(args: argparse.Namespace, command: str) -> None:
133137
copy_dir(**vars(args))
134138
if command == "cmake-config":
135139
configure_cmake(**vars(args))
140+
if command == "cmake-compile":
141+
compile_cmake(**vars(args))

docker_cli/commands.py

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
from subprocess import DEVNULL, PIPE, run
66
from typing import Iterable, List
77

8-
from ._docker_cmake import cmake_config_dockerfile
8+
from ._docker_cmake import cmake_build_dockerfile, cmake_config_dockerfile
99
from ._docker_git import git_extract_dockerfile
1010
from ._docker_insert import insert_dir_dockerfile
1111
from ._docker_mamba import mamba_lockfile_command
1212
from ._image import Image
1313
from ._url_reader import URLReader
14-
from ._utils import image_command_check, is_conda_pkg_name, temp_image
15-
from .defaults import universal_tag_prefix
14+
from ._utils import image_command_check, is_conda_pkg_name, prefix_image_tag, temp_image
1615

1716

1817
def get_archive(
@@ -54,11 +53,11 @@ def get_archive(
5453
with temp_image(base) as temp_img:
5554
_, url_reader, _ = image_command_check(temp_img)
5655

57-
prefix = universal_tag_prefix()
58-
img_tag = tag if tag.startswith(prefix) else f"{prefix}-{tag}"
56+
img_tag = prefix_image_tag(tag)
57+
base_tag = prefix_image_tag(base)
5958

6059
dockerfile = git_extract_dockerfile(
61-
base=base,
60+
base=base_tag,
6261
directory=directory,
6362
archive_url=archive_url,
6463
url_reader=url_reader,
@@ -106,8 +105,7 @@ def copy_dir(
106105
The generated image.
107106
"""
108107

109-
prefix = universal_tag_prefix()
110-
img_tag = tag if tag.startswith(prefix) else f"{prefix}-{tag}"
108+
img_tag = prefix_image_tag(tag)
111109

112110
dir_str = os.fspath(directory)
113111

@@ -128,8 +126,9 @@ def copy_dir(
128126

129127
# Generate the dockerfile. The source directory will be "." since the build context
130128
# will be at the source path when the image is built.
129+
base_tag = prefix_image_tag(base)
131130
dockerfile: str = insert_dir_dockerfile(
132-
base=base,
131+
base=base_tag,
133132
target_dir=target_dir,
134133
source_dir=".",
135134
)
@@ -176,17 +175,49 @@ def configure_cmake(
176175
Image
177176
The generated image.
178177
"""
178+
base_tag = prefix_image_tag(base)
179+
179180
dockerfile: str = cmake_config_dockerfile(
180-
base=base,
181+
base=base_tag,
181182
build_type=build_type,
182183
with_cuda=not no_cuda,
183184
)
184185

185-
prefix = universal_tag_prefix()
186-
img_tag = tag if tag.startswith(prefix) else f"{prefix}-{tag}"
186+
img_tag = prefix_image_tag(tag)
187187
return Image.build(tag=img_tag, dockerfile_string=dockerfile, no_cache=no_cache)
188188

189189

190+
def compile_cmake(tag: str, base: str, no_cache: bool = False) -> Image:
191+
"""
192+
Produces an image with the working directory compiled.
193+
194+
Parameters
195+
----------
196+
tag : str
197+
The image tag.
198+
base : str
199+
The base image tag.
200+
no_cache : bool, optional
201+
Run Docker build with no cache if True. Defaults to False.
202+
203+
Returns
204+
-------
205+
Image
206+
The generated image.
207+
"""
208+
209+
prefixed_tag: str = prefix_image_tag(tag)
210+
prefixed_base_tag: str = prefix_image_tag(base)
211+
212+
dockerfile: str = cmake_build_dockerfile(base=prefixed_base_tag)
213+
214+
return Image.build(
215+
tag=prefixed_tag,
216+
dockerfile_string=dockerfile,
217+
no_cache=no_cache,
218+
)
219+
220+
190221
def dropin(tag: str) -> None:
191222
"""
192223
Initiates a drop-in session on an image.
@@ -196,6 +227,7 @@ def dropin(tag: str) -> None:
196227
tag : str
197228
The tag or ID of the image.
198229
"""
230+
tag = prefix_image_tag(tag)
199231
image: Image = Image(tag)
200232

201233
image.drop_in()
@@ -234,18 +266,18 @@ def remove(
234266

235267
# Search for and delete all images matching each tag or wildcard.
236268
for tag in tags:
237-
prefix = universal_tag_prefix()
238-
search = tag if (tag.startswith(prefix) or ignore_prefix) else f"{prefix}-{tag}"
269+
if not ignore_prefix:
270+
tag = prefix_image_tag(tag)
239271
if verbose:
240-
print(f"Attempting removal for tag: {search}")
272+
print(f"Attempting removal for tag: {tag}")
241273

242274
# Search for all images whose name matches this tag, acquire a list
243-
search_command = split(f'docker images --filter=reference="{search}" -q')
275+
search_command = split(f'docker images --filter=reference="{tag}" -q')
244276
search_result = run(search_command, text=True, stdout=PIPE, stderr=output)
245277
# An empty return indicates that no such images were found. Skip to the next.
246278
if search_result.stdout == "":
247279
if verbose:
248-
print(f"No images found matching pattern {search}. Proceeding.")
280+
print(f"No images found matching pattern {tag}. Proceeding.")
249281
continue
250282
# The names come in a list delimited by newlines. Reform this to be delimited
251283
# by spaces to use with `Docker rmi`.
@@ -277,6 +309,7 @@ def make_lockfile(
277309
The name of the environment. Defaults to "base".
278310
"""
279311
cmd: str = mamba_lockfile_command(env_name=env_name)
312+
tag = prefix_image_tag(tag)
280313
image: Image = Image(tag)
281314
lockfile: str = image.run(command=cmd, stdout=PIPE)
282315
assert isinstance(lockfile, str)

0 commit comments

Comments
 (0)