From 9340dbe7201e9a02305f636e3711374be863c7a1 Mon Sep 17 00:00:00 2001 From: Adrian Malacoda Date: Sun, 28 Feb 2021 16:21:07 -0600 Subject: [PATCH] Parse command line config on startup and apply later, so we can load config files based on container name (and also just because it looks cleaner). Also wrap logging logic into function and expose to config files. --- otherworld | 205 +++++++++++++++++++++++++++++------------------------ 1 file changed, 111 insertions(+), 94 deletions(-) diff --git a/otherworld b/otherworld index 4c0b6c7..ba91007 100755 --- a/otherworld +++ b/otherworld @@ -132,6 +132,64 @@ def expand_user_volumes (volumes): return mappings +def parse_command_line (command, config=None): + if config is None: + config = { + "actions": [], + "user_volumes": [], + "command_env": {} + } + + while len(command) > 0: + arg = command[0] + if arg == "--quiet": + command = command[1:] + config['quiet'] = True + elif arg == "--notty": + command = command[1:] + config['tty'] = False + elif arg == "--rm": + config['actions'].append("rm") + command = command[1:] + elif arg == "--rmi": + config['actions'].append("rmi") + command = command[1:] + elif arg == "--commit": + config['actions'].append("commit") + command = command[1:] + elif arg == "--sudo": + config['command_user'] = "root" + command = command[1:] + elif arg.startswith("--container="): + config['container_name'] = arg[len("--container="):] + command = command[1:] + elif arg.startswith("--image="): + config['image_name'] = arg[len("--image="):] + command = command[1:] + elif arg.startswith("--build="): + config['build_path'] = arg[len("--build="):] + command = command[1:] + elif arg.startswith("--volume="): + config['user_volumes'].append(arg[len("--volume="):]) + command = command[1:] + elif arg.startswith("--env="): + env_pair = arg[len("--env="):] + (key, value) = env_pair.split("=", 1) + config['command_env'][key] = value + command = command[1:] + elif arg == "--cd": + config['command_workdir'] = os.getcwd() + command = command[1:] + elif arg.startswith("--cd="): + config['command_workdir'] = arg[len("--cd="):] + command = command[1:] + elif arg == "--pull": + command = command[1:] + config['pull'] = True + else: + break + return (config, command) + def find_config_files (config_names): config_files = [] directory = os.path.abspath(os.getcwd()) @@ -159,91 +217,59 @@ def load_config_files (namespace, config_files): exec(config_code.read(), {}, namespace) return dict([item for item in namespace.items() if item[0] in config_keys]) -user = os.environ["USER"] -uid = int(check_output(["id", "-u"]).strip()) -image_name = os.environ.get("OW_IMAGE", None) -container_name = os.environ.get("OW_CONTAINER", f"{CONTAINER_NAME}_{user}") -build_path = None +# parse options and command from command line +(command_line_options, command) = parse_command_line(sys.argv[1:]) +actions = command_line_options['actions'] -command = sys.argv[1:] -command_user = user -user_volumes = USER_VOLUMES -pull = False +quiet = command_line_options.get("quiet", False) +def log (message, *args, **kwargs): + if quiet: + return + print(">> {}".format(message.format(*args, **kwargs))) -actions = [] - -command_env = {} -command_workdir = None - -quiet = False tty = sys.stdout.isatty() -# load config from files -config = load_config_files({ +# default config +user = os.environ["USER"] +config = { "command": command, "user": user, - "uid": uid, - "command_user": command_user, - "image_name": image_name, - "container_name": container_name, - "build_path": build_path, - "command_workdir": command_workdir, - "user_volumes": user_volumes, - "pull": pull, - "command_env": command_env, + "uid": int(check_output(["id", "-u"]).strip()), + "command_user": user, + "image_name": os.environ.get("OW_IMAGE", None), + "container_name": command_line_options.get("container_name", os.environ.get("OW_CONTAINER", f"{CONTAINER_NAME}_{user}")), + "build_path": None, + "command_workdir": None, + "user_volumes": USER_VOLUMES, + "pull": False, + "command_env": {}, "cwd": os.getcwd(), - "tty": tty -}, find_config_files([OTHERWORLD_CONFIG, "{}{}".format(container_name, OTHERWORLD_CONFIG)])) -locals().update(config) + "tty": sys.stdout.isatty(), + "log": log +} -while len(command) > 0: - arg = command[0] - if arg == "--quiet": - command = command[1:] - quiet = True - elif arg == "--notty": - command = command[1:] - tty = False - elif arg == "--rm": - actions.append("rm") - command = command[1:] - elif arg == "--rmi": - actions.append("rmi") - command = command[1:] - elif arg == "--commit": - actions.append("commit") - command = command[1:] - elif arg == "--sudo": - command_user = "root" - command = command[1:] - elif arg.startswith("--container="): - container_name = arg[len("--container="):] - command = command[1:] - elif arg.startswith("--image="): - image_name = arg[len("--image="):] - command = command[1:] - elif arg.startswith("--build="): - build_path = arg[len("--build="):] - command = command[1:] - elif arg.startswith("--volume="): - user_volumes.append(arg[len("--volume="):]) - command = command[1:] - elif arg.startswith("--env="): - env_pair = arg[len("--env="):] - (key, value) = env_pair.split("=", 1) - command_env[key] = value - command = command[1:] - elif arg == "--cd": - command_workdir = os.getcwd() - command = command[1:] - elif arg.startswith("--cd="): - command_workdir = arg[len("--cd="):] - command = command[1:] - elif arg == "--pull": - command = command[1:] - pull = True +# load config from files +config_files = find_config_files([ + OTHERWORLD_CONFIG, + "{}{}".format(config['container_name'], OTHERWORLD_CONFIG) +]) + +for config_file in config_files: + log("Loading config file {}", config_file) + +config = load_config_files(config, config_files) + +# apply config from command line +for key, value in command_line_options.items(): + if key == "user_volumes": + config['user_volumes'] = config['user_volumes'] + value + elif key == "command_env": + config['command_env'].update(value) else: - break + config[key] = value + +# update local variables (FIXME: rewrite to avoid doing this) +locals().update(config) if command_workdir: user_volumes.append(command_workdir) @@ -252,19 +278,16 @@ if command_workdir: if actions: if "commit" in actions: target_image_name = get_generated_image_name(container_name) - if not quiet: - print(f">> Committing container: {container_name} to image: {target_image_name}") + log("Committing container: {} to image: {}", container_name, target_image_name) docker_commit(container_name, target_image_name) if "rm" in actions: - if not quiet: - print(f">> Removing container: {container_name}") + log("Removing container: {}", container_name) docker_rm(container_name) if "rmi" in actions: target_image_name = get_generated_image_name(container_name) - if not quiet: - print(f">> Removing image: {target_image_name}") + log("Removing image: {}", target_image_name) docker_rmi(target_image_name) if not command: @@ -285,18 +308,15 @@ except Exception: image_name = get_generated_image_name(container_name) try: docker_inspect(image_name) - if not quiet: - print(f">> Using default otherworld image {image_name}") + log("Using default otherworld image {}", image_name) except Exception: - if not quiet: - print(f">> Default otherworld image {image_name} not found, falling back to {DEFAULT_IMAGE_NAME}") + log("Default otherworld image {} not found, falling back to {}", image_name, DEFAULT_IMAGE_NAME) image_name = DEFAULT_IMAGE_NAME if pull: docker_pull(image_name) - if not quiet: - print(f">> Creating container: {container_name} (using image: {image_name})") + log("Creating container: {} (using image: {})", container_name, image_name) docker_create( image_name, container_name, @@ -306,18 +326,15 @@ except Exception: container = docker_inspect(container_name)[0] if not container["State"]["Running"]: - if not quiet: - print(f">> Starting container: {container_name}") + log("Starting container: {}", container_name) docker_start(container_name) container = docker_inspect(container_name)[0] try: docker_get_user(container_name, user) except Exception: - if not quiet: - print(f">> Creating container user: {user}") + log("Creating container user: {}", user) docker_create_user(container_name, user, uid) -if not quiet: - print(f">> Welcome to {container_name} (IP {container['NetworkSettings']['IPAddress']})") +log("Welcome to {} (IP {})", container_name, container['NetworkSettings']['IPAddress']) docker_exec(container_name, command, command_user, command_env, tty, command_workdir)