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)