Skip to content

Commit 44adcc3

Browse files
committed
plumbing
Signed-off-by: Ayush Kamat <ayush@latch.bio>
1 parent 28dc0d9 commit 44adcc3

2 files changed

Lines changed: 118 additions & 18 deletions

File tree

src/latch_cli/main.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,106 @@ def execute(
543543
_exec(execution_id=execution_id, egn_id=egn_id, container_index=container_index)
544544

545545

546+
@main.group()
547+
def image():
548+
"""Manage Private Image Uploads"""
549+
550+
551+
@image.command("build")
552+
@click.argument("root", type=click.Path(exists=True, file_okay=False))
553+
@click.option("-n", "--image-name", is_flag=False, type=str)
554+
@click.option("-v", "--version", is_flag=False, type=str)
555+
@click.option(
556+
"-d",
557+
"--dockerfile-path",
558+
is_flag=False,
559+
type=click.Path(exists=True, dir_okay=False),
560+
help="Path to Dockerfile, defaults to the Dockerfile in specified root directory.",
561+
)
562+
@click.option(
563+
"--remote/--no-remote",
564+
is_flag=True,
565+
default=True,
566+
type=bool,
567+
help="Use a remote server to build workflow.",
568+
)
569+
@click.option(
570+
"-y",
571+
"--yes",
572+
is_flag=True,
573+
default=False,
574+
type=bool,
575+
help="Skip the confirmation dialog.",
576+
)
577+
@click.option(
578+
"--docker-progress",
579+
type=click.Choice(["plain", "tty", "auto"], case_sensitive=False),
580+
default="auto",
581+
help=(
582+
"`tty` shows only the last N lines of the build log. `plain` does no special"
583+
" handling. `auto` chooses `tty` when stdout is a terminal and `plain`"
584+
" otherwise. Equivalent to Docker's `--progress` flag."
585+
),
586+
)
587+
@requires_login
588+
def build_and_upload_image(
589+
root: Path,
590+
*,
591+
image_name: str,
592+
version: Optional[str] = None,
593+
dockerfile_path: Optional[Path] = None,
594+
remote: bool = True,
595+
yes: bool = False,
596+
docker_progress: str,
597+
):
598+
"""Builds and uploads a Docker image to Latch ECR"""
599+
600+
from .services.private_images import build_and_upload_image
601+
602+
build_and_upload_image(
603+
root,
604+
image_name=image_name,
605+
version=version,
606+
dockerfile_path=dockerfile_path,
607+
remote=remote,
608+
skip_confirmation=yes,
609+
progress_plain=(docker_progress == "auto" and not sys.stdout.isatty())
610+
or docker_progress == "plain",
611+
)
612+
613+
614+
@image.command("upload")
615+
@click.argument("image-reference", type=str, help="The image you wish to upload")
616+
@click.option("-n", "--image-name", is_flag=False, type=str)
617+
@click.option("-v", "--version", is_flag=False, type=str)
618+
@click.option(
619+
"-y",
620+
"--yes",
621+
is_flag=True,
622+
default=False,
623+
type=bool,
624+
help="Skip the confirmation dialog.",
625+
)
626+
@requires_login
627+
def upload_image(
628+
image_reference: str,
629+
*,
630+
image_name: Optional[str] = None,
631+
version: Optional[str] = None,
632+
yes: bool = False,
633+
):
634+
"""Uploads an existing Docker image to Latch ECR"""
635+
636+
from .services.private_images import upload_image
637+
638+
upload_image(
639+
image_ref=image_reference,
640+
image_name=image_name,
641+
version=version,
642+
skip_confirmation=yes,
643+
)
644+
645+
546646
@main.command("register")
547647
@click.argument("pkg_root", type=click.Path(exists=True, file_okay=False))
548648
@click.option(

src/latch_cli/services/private_images.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def record_in_db(ws_id: str, image_name: str, version: str):
5959
)
6060
valid_version_expr = re.compile(r"[\w][\w.-]{0,127}")
6161
image_ref_expr = re.compile(
62-
r"((?P<registry>[^/:]+)/)?(?P<image>[^:]+):(?P<version>[^:/])"
62+
r"((?P<registry>[^/:]+)/)?(?P<image>[^:]+)(:(?P<version>[^:/]))?"
6363
)
6464

6565

@@ -106,17 +106,17 @@ def validate_version(version: str):
106106
def upload_image(
107107
image_ref: str,
108108
*,
109-
new_image_name: Optional[str] = None,
110-
new_version: Optional[str] = None,
109+
image_name: Optional[str] = None,
110+
version: Optional[str] = None,
111111
skip_confirmation: bool = False,
112112
):
113113
click.secho("Beginning image upload:")
114114
match = image_ref_expr.match(image_ref)
115115

116-
if new_image_name is not None:
117-
validate_image_name(new_image_name)
116+
if image_name is not None:
117+
validate_image_name(image_name)
118118
elif match is not None:
119-
new_image_name = match["image"]
119+
image_name = match["image"]
120120
else:
121121
click.secho(
122122
dedent(f"""\
@@ -131,10 +131,12 @@ def upload_image(
131131

132132
raise click.exceptions.Exit(1)
133133

134-
if new_version is not None:
135-
validate_version(new_version)
134+
if version is not None:
135+
validate_version(version)
136+
elif match is not None and match["version"] is not None:
137+
version = match["version"]
136138
elif match is not None:
137-
new_version = match["version"]
139+
version = "latest"
138140
else:
139141
click.secho(
140142
dedent(f"""\
@@ -149,14 +151,14 @@ def upload_image(
149151

150152
raise click.exceptions.Exit(1)
151153

152-
assert new_image_name is not None
153-
assert new_version is not None
154+
assert image_name is not None
155+
assert version is not None
154156

155157
ws_id = current_workspace()
156158

157-
namespaced_image_name = f"{ws_id}_{new_image_name}"
159+
namespaced_image_name = f"{ws_id}_{image_name}"
158160

159-
full_image_ref = f"{ecr_base}/{namespaced_image_name}:{new_version}"
161+
full_image_ref = f"{ecr_base}/{namespaced_image_name}:{version}"
160162

161163
click.secho(f"Image Destination: {full_image_ref}")
162164

@@ -172,9 +174,7 @@ def upload_image(
172174
print_header=False,
173175
)
174176

175-
client.tag(
176-
image_ref, repository=f"{ecr_base}/{namespaced_image_name}", tag=new_version
177-
)
177+
client.tag(image_ref, repository=f"{ecr_base}/{namespaced_image_name}", tag=version)
178178

179179
client._auth_configs = docker.auth.AuthConfig({ # noqa: SLF001
180180
"auths": {ecr_base: asdict(credentials)}
@@ -183,15 +183,15 @@ def upload_image(
183183
print_upload_logs(
184184
client.push(
185185
repository=f"{ecr_base}/{namespaced_image_name}",
186-
tag=new_version,
186+
tag=version,
187187
stream=True,
188188
decode=True,
189189
auth_config=asdict(credentials),
190190
),
191191
namespaced_image_name,
192192
)
193193

194-
# record_in_db(ws_id, namespaced_image_name, new_version)
194+
record_in_db(ws_id, namespaced_image_name, version)
195195

196196
click.secho(f"Successfully built and tagged {full_image_ref}", fg="green")
197197

0 commit comments

Comments
 (0)