Use enum to standardise `phase`
MODIFY
repo2docker/__main__.py
repo2docker/__main__.py
@@ -5,7 +5,11 @@ import logging
from .app import Repo2Docker
from .engine import BuildError, ImageLoadError
from . import __version__
-from .utils import validate_and_generate_port_mapping, is_valid_docker_image_name
+from .utils import (
+ validate_and_generate_port_mapping,
+ is_valid_docker_image_name,
+ R2dState,
+)
def validate_image_name(image_name):
@@ -302,7 +306,7 @@ def make_r2d(argv=None):
r2d.log.error(
'Cannot mount "{}" in editable mode '
"as it is not a directory".format(args.repo),
- extra=dict(phase="failed"),
+ extra=dict(phase=R2dState.FAILED),
)
sys.exit(1)

MODIFY
repo2docker/app.py
repo2docker/app.py
@@ -38,7 +38,7 @@ from .buildpacks import (
)
from . import contentproviders
from .engine import BuildError, ContainerEngineException, ImageLoadError
-from .utils import ByteSpecification, chdir
+from .utils import ByteSpecification, chdir, R2dState
class Repo2Docker(Application):
@@ -465,7 +465,7 @@ class Repo2Docker(Application):
for log_line in picked_content_provider.fetch(
spec, checkout_path, yield_output=self.json_logs
):
- self.log.info(log_line, extra=dict(phase="fetching"))
+ self.log.info(log_line, extra=dict(phase=R2dState.FETCHING))
if not self.output_image_spec:
image_spec = "r2d" + self.repo
@@ -491,7 +491,7 @@ class Repo2Docker(Application):
"Error during build: %s",
evalue,
exc_info=(etype, evalue, traceback),
- extra=dict(phase="failed"),
+ extra=dict(phase=R2dState.FAILED),
)
def initialize(self, *args, **kwargs):
@@ -532,7 +532,7 @@ class Repo2Docker(Application):
last_emit_time = time.time()
for chunk in client.push(self.output_image_spec):
if client.string_output:
- self.log.info(chunk, extra=dict(phase="pushing"))
+ self.log.info(chunk, extra=dict(phase=R2dState.PUSHING))
continue
# else this is Docker output
@@ -546,7 +546,7 @@ class Repo2Docker(Application):
self.log.warning("Not a JSON progress line: %r", line)
continue
if "error" in progress:
- self.log.error(progress["error"], extra=dict(phase="failed"))
+ self.log.error(progress["error"], extra=dict(phase=R2dState.FAILED))
raise ImageLoadError(progress["error"])
if "id" not in progress:
continue
@@ -561,13 +561,15 @@ class Repo2Docker(Application):
self.log.info(
"Pushing image\n",
extra=dict(
- progress=progress_layers, layers=layers, phase="pushing"
+ progress=progress_layers,
+ layers=layers,
+ phase=R2dState.PUSHING,
),
)
last_emit_time = time.time()
self.log.info(
"Successfully pushed {}".format(self.output_image_spec),
- extra=dict(phase="pushing"),
+ extra=dict(phase=R2dState.PUSHING),
)
def run_image(self):
@@ -659,24 +661,27 @@ class Repo2Docker(Application):
for line in container.logs(stream=True, timestamps=True):
line = line.decode("utf-8")
last_timestamp, line = line.split(" ", maxsplit=1)
- self.log.info(line, extra=dict(phase="running"))
+ self.log.info(line, extra=dict(phase=R2dState.RUNNING))
finally:
container.reload()
if container.status == "running":
- self.log.info("Stopping container...\n", extra=dict(phase="running"))
+ self.log.info(
+ "Stopping container...\n", extra=dict(phase=R2dState.RUNNING)
+ )
container.kill()
exit_code = container.exitcode
container.wait()
self.log.info(
- "Container finished running.\n".upper(), extra=dict(phase="running")
+ "Container finished running.\n".upper(),
+ extra=dict(phase=R2dState.RUNNING),
)
# are there more logs? Let's send them back too
late_logs = container.logs(since=last_timestamp).decode("utf-8")
for line in late_logs.split("\n"):
- self.log.debug(line + "\n", extra=dict(phase="running"))
+ self.log.debug(line + "\n", extra=dict(phase=R2dState.RUNNING))
container.remove()
if exit_code:
@@ -751,7 +756,7 @@ class Repo2Docker(Application):
self.log.error(
"Subdirectory %s does not exist",
self.subdir,
- extra=dict(phase="failure"),
+ extra=dict(phase=R2dState.FAILED),
)
raise FileNotFoundError("Could not find {}".format(checkout_path))
@@ -786,7 +791,7 @@ class Repo2Docker(Application):
else:
self.log.debug(
picked_buildpack.render(build_args),
- extra=dict(phase="building"),
+ extra=dict(phase=R2dState.BUILDING),
)
if self.user_id == 0:
raise ValueError(
@@ -796,7 +801,7 @@ class Repo2Docker(Application):
self.log.info(
"Using %s builder\n",
bp.__class__.__name__,
- extra=dict(phase="building"),
+ extra=dict(phase=R2dState.BUILDING),
)
for l in picked_buildpack.build(
@@ -808,19 +813,24 @@ class Repo2Docker(Application):
self.extra_build_kwargs,
):
if docker_client.string_output:
- self.log.info(l, extra=dict(phase="building"))
+ self.log.info(l, extra=dict(phase=R2dState.BUILDING))
# else this is Docker output
elif "stream" in l:
- self.log.info(l["stream"], extra=dict(phase="building"))
+ self.log.info(
+ l["stream"], extra=dict(phase=R2dState.BUILDING)
+ )
elif "error" in l:
- self.log.info(l["error"], extra=dict(phase="failure"))
+ self.log.info(l["error"], extra=dict(phase=R2dState.FAILED))
raise BuildError(l["error"])
elif "status" in l:
self.log.info(
- "Fetching base image...\r", extra=dict(phase="building")
+ "Fetching base image...\r",
+ extra=dict(phase=R2dState.BUILDING),
)
else:
- self.log.info(json.dumps(l), extra=dict(phase="building"))
+ self.log.info(
+ json.dumps(l), extra=dict(phase=R2dState.BUILDING)
+ )
finally:
# Cleanup checkout if necessary

MODIFY
repo2docker/contentproviders/git.py
repo2docker/contentproviders/git.py
import subprocess
from .base import ContentProvider, ContentProviderException
-from ..utils import execute_cmd, check_ref
+from ..utils import execute_cmd, check_ref, R2dState
class Git(ContentProvider):
@@ -44,7 +44,7 @@ class Git(ContentProvider):
hash = check_ref(ref, output_dir)
if hash is None:
self.log.error(
- "Failed to check out ref %s", ref, extra=dict(phase="failed")
+ "Failed to check out ref %s", ref, extra=dict(phase=R2dState.FAILED)
)
if ref == "master":
msg = (

MODIFY
repo2docker/contentproviders/mercurial.py
repo2docker/contentproviders/mercurial.py
import subprocess
from .base import ContentProvider, ContentProviderException
-from ..utils import execute_cmd
+from ..utils import execute_cmd, R2dState
args_enabling_topic = ["--config", "extensions.topic="]
@@ -62,7 +62,7 @@ class Mercurial(ContentProvider):
yield line
except subprocess.CalledProcessError:
self.log.error(
- "Failed to update to ref %s", ref, extra=dict(phase="failed")
+ "Failed to update to ref %s", ref, extra=dict(phase=R2dState.FAILED)
)
raise ValueError("Failed to update to ref {}".format(ref))

MODIFY
repo2docker/utils.py
repo2docker/utils.py
from contextlib import contextmanager
+from enum import Enum
from functools import partial
import os
import re
@@ -10,6 +11,21 @@ from shutil import copystat, copy2
from traitlets import Integer, TraitError
+class R2dState(Enum):
+ """
+ The current state of repo2docker
+ """
+
+ FETCHING = "fetching"
+ BUILDING = "building"
+ PUSHING = "pushing"
+ RUNNING = "running"
+ FAILED = "failed"
+
+ def __str__(self):
+ return self.value
+
+
def execute_cmd(cmd, capture=False, **kwargs):
"""
Call given command, yielding output line by line if capture=True.

Use enum to standardise `phase`