Don't call sys.exit from inside the class
Instead, we raise exceptions that can be caught and
handled by calling code instead
MODIFY
repo2docker/__main__.py
repo2docker/__main__.py
import argparse
import sys
import os
+import docker
from .app import Repo2Docker
from . import __version__
from .utils import validate_and_generate_port_mapping
@@ -314,8 +315,18 @@ def make_r2d(argv=None):
def main():
r2d = make_r2d()
r2d.initialize()
+ try:
r2d.start()
-
+ except docker.errors.BuildError as e:
+ # This is only raised by us
+ if r2d.debug:
+ r2d.log.exception(e)
+ sys.exit(1)
+ except docker.errors.ImageLoadError as e:
+ # This is only raised by us
+ if r2d.debug:
+ r2d.log.exception(e)
+ sys.exit(1)
if __name__ == '__main__':
main()

MODIFY
repo2docker/app.py
repo2docker/app.py
@@ -415,7 +415,7 @@ class Repo2Docker(Application):
progress = json.loads(line.decode('utf-8'))
if 'error' in progress:
self.log.error(progress['error'], extra=dict(phase='failed'))
- sys.exit(1)
+ raise docker.errors.ImageLoadError(progress['error'])
if 'id' not in progress:
continue
if 'progressDetail' in progress and progress['progressDetail']:
@@ -545,12 +545,8 @@ class Repo2Docker(Application):
api_client = docker.APIClient(version='auto',
**kwargs_from_env())
except DockerException as e:
- print("Docker client initialization error. Check if docker is"
- " running on the host.")
- print(e)
- if self.log_level == logging.DEBUG:
- raise e
- sys.exit(1)
+ self.log.exception(e)
+ raise
# If the source to be executed is a directory, continue using the
# directory. In the case of a local directory, it is used as both the
# source and target. Reusing a local directory seems better than
@@ -572,7 +568,7 @@ class Repo2Docker(Application):
if not os.path.isdir(checkout_path):
self.log.error('Subdirectory %s does not exist',
self.subdir, extra=dict(phase='failure'))
- sys.exit(1)
+ raise FileNotFoundError(f'Could not find {checkout_path}')
with chdir(checkout_path):
for BP in self.buildpacks:
@@ -608,7 +604,7 @@ class Repo2Docker(Application):
extra=dict(phase='building'))
elif 'error' in l:
self.log.info(l['error'], extra=dict(phase='failure'))
- sys.exit(1)
+ raise docker.errors.BuildError(l['error'])
elif 'status' in l:
self.log.info('Fetching base image...\r',
extra=dict(phase='building'))

MODIFY
repo2docker/contentproviders/git.py
repo2docker/contentproviders/git.py
@@ -38,7 +38,7 @@ class Git(ContentProvider):
if hash is None:
self.log.error('Failed to check out ref %s', ref,
extra=dict(phase='failed'))
- sys.exit(1)
+ raise ValueError(f'Failed to check out ref {ref}')
# If the hash is resolved above, we should be able to reset to it
for line in execute_cmd(['git', 'reset', '--hard', hash],
cwd=output_dir,

Don't call sys.exit from inside the class

Instead, we raise exceptions that can be caught and
handled by calling code instead