diff --git a/gilt/config.py b/gilt/config.py index 2e47084..15f14ac 100644 --- a/gilt/config.py +++ b/gilt/config.py @@ -24,7 +24,6 @@ import urllib.parse import yaml - from gilt import interpolation @@ -53,6 +52,8 @@ def config(filename): "src", "dst", "files", + "devel", + "remotes", "post_commands", ], ) @@ -105,6 +106,12 @@ def _get_files_config(src_dir, files_list): ] +def _get_remotes_config(remotes): + RemotesConfig = collections.namedtuple("RemotesConfig", ["name", "url"]) + + return [RemotesConfig(**d) for d in _get_remotes_generator(remotes)] + + def _get_config_generator(filename): """A generator which populates and return a dict. @@ -122,8 +129,11 @@ def _get_config_generator(filename): files = d.get("files") post_commands = d.get("post_commands", []) dst_dir = None + devel = d.get("devel", False) + remotes = [] if not files: dst_dir = _get_dst_dir(d["dst"]) + remotes = d.get("remotes") yield { "git": repo, "lock_file": os.path.join( @@ -134,6 +144,8 @@ def _get_config_generator(filename): "src": src_dir, "dst": dst_dir, "files": _get_files_config(src_dir, files), + "devel": devel, + "remotes": _get_remotes_config(remotes), "post_commands": post_commands, } @@ -155,6 +167,12 @@ def _get_files_generator(src_dir, files_list): } +def _get_remotes_generator(remotes): + if remotes: + for remote in remotes: + yield {"name": remote.get("name"), "url": remote.get("url")} + + def _get_config(filename): """Parse the provided YAML file and return a dict. diff --git a/gilt/git.py b/gilt/git.py index c309858..4d6da87 100644 --- a/gilt/git.py +++ b/gilt/git.py @@ -23,7 +23,6 @@ import shutil import sh - from gilt import util @@ -43,6 +42,28 @@ def clone(name, repository, destination, debug=False): util.run_command(cmd, debug=debug) +def sync(name, destination, version, debug=False): + os.chdir(destination) + msg = " - syncing {} with {} of origin".format(name, version) + util.print_info(msg) + _get_version(version, clean=False, debug=debug) + + +def remote_add(destination, name, url, debug=False): + os.chdir(destination) + msg = " - adding {} remote with url {}".format(name, url) + util.print_info(msg) + try: + cmd = sh.git.bake("remote", "remove", name) + util.run_command(cmd, debug=debug) + except sh.ErrorReturnCode: + pass + cmd = sh.git.bake("remote", "add", name, url) + util.run_command(cmd, debug=debug) + cmd = sh.git.bake("fetch", name) + util.run_command(cmd, debug=debug) + + def extract(repository, destination, version, debug=False): """Extract the specified repository/version into the directory and return None. @@ -60,7 +81,7 @@ def extract(repository, destination, version, debug=False): shutil.rmtree(destination) os.chdir(repository) - _get_version(version, debug) + _get_version(version, debug=debug) cmd = sh.git.bake( "checkout-index", force=True, all=True, prefix=destination ) @@ -83,7 +104,7 @@ def overlay(repository, files, version, debug=False): """ with util.saved_cwd(): os.chdir(repository) - _get_version(version, debug) + _get_version(version, debug=debug) for fc in files: if "*" in fc.src: @@ -103,7 +124,7 @@ def overlay(repository, files, version, debug=False): util.print_info(msg) -def _get_version(version, debug=False): +def _get_version(version, clean=True, debug=False): """Handle switching to the specified version and return None. 1. Fetch the origin. @@ -112,6 +133,7 @@ def _get_version(version, debug=False): 4. Pull the origin when a branch; _not_ a commit id. :param version: A string containing the branch/tag/sha to be exported. + :param clean: An optional bool to toggle running `git clean` before `git pull` :param debug: An optional bool to toggle debug output. :return: None """ @@ -126,11 +148,16 @@ def _get_version(version, debug=False): util.run_command(cmd, debug=debug) cmd = sh.git.bake("checkout", version) util.run_command(cmd, debug=debug) - cmd = sh.git.bake("clean", "-d", "-x", "-f") - util.run_command(cmd, debug=debug) - if _has_branch(version, debug): - cmd = sh.git.bake("pull", rebase=True, ff_only=True) + if clean: + cmd = sh.git.bake("clean", "-d", "-x", "-f") util.run_command(cmd, debug=debug) + if _has_branch(version, debug): + try: + cmd = sh.git.bake("pull", rebase=True, ff_only=True) + util.run_command(cmd, debug=debug) + except sh.ErrorReturnCode: + msg = " - pulling failed, local changes exist?" + util.print_warn(msg) def _has_commit(version, debug=False): diff --git a/gilt/shell.py b/gilt/shell.py index 8e532b5..72a90b3 100644 --- a/gilt/shell.py +++ b/gilt/shell.py @@ -23,11 +23,8 @@ import click import click_completion import fasteners - import gilt -from gilt import config -from gilt import git -from gilt import util +from gilt import config, git, util click_completion.init() @@ -87,23 +84,39 @@ def overlay(ctx): # pragma: no cover for c in config.config(filename): with fasteners.InterProcessLock(c.lock_file): util.print_info("{}:".format(c.name)) - if not os.path.exists(c.src): - git.clone(c.name, c.git, c.src, debug=debug) - if c.dst: - git.extract(c.src, c.dst, c.version, debug=debug) - post_commands = {c.dst: c.post_commands} + if c.devel: + if not os.path.exists(c.dst): + git.clone(c.name, c.git, c.dst, debug=debug) + elif not os.listdir(c.dst): + git.clone(c.name, c.git, c.dst, debug=debug) + elif not os.path.exists(c.dst + "/.git"): + msg = " {} not a git repository, skipping" + msg = msg.format(c.dst) + util.print_warn(msg) + continue + + git.sync(c.name, c.dst, c.version, debug=debug) + + for remote in c.remotes: + git.remote_add(c.dst, remote.name, remote.url, debug=debug) else: - git.overlay(c.src, c.files, c.version, debug=debug) - post_commands = { - conf.dst: conf.post_commands for conf in c.files - } - # Run post commands if any. - for dst, commands in post_commands.items(): - for command in commands: - msg = " - running `{}` in {}".format(command, dst) - util.print_info(msg) - cmd = util.build_sh_cmd(command, cwd=dst) - util.run_command(cmd, debug=debug) + if not os.path.exists(c.src): + git.clone(c.name, c.git, c.src, debug=debug) + if c.dst: + git.extract(c.src, c.dst, c.version, debug=debug) + post_commands = {c.dst: c.post_commands} + else: + git.overlay(c.src, c.files, c.version, debug=debug) + post_commands = { + conf.dst: conf.post_commands for conf in c.files + } + # Run post commands if any. + for dst, commands in post_commands.items(): + for command in commands: + msg = " - running `{}` in {}".format(command, dst) + util.print_info(msg) + cmd = util.build_sh_cmd(command, cwd=dst) + util.run_command(cmd, debug=debug) def _setup(filename): diff --git a/test/resources/gilt.yml b/test/resources/gilt.yml index 379d11e..801c4dc 100644 --- a/test/resources/gilt.yml +++ b/test/resources/gilt.yml @@ -2,6 +2,12 @@ - git: https://github.com/retr0h/ansible-etcd.git version: master dst: roles/retr0h.ansible-etcd/ + devel: true + remotes: + - name: mirror + url: https://github.com/retr0h/gilt.git + - name: upstream + url: https://github.com/retr0h/gilt.git - git: https://github.com/lorin/openstack-ansible-modules.git version: master