From 9af05f4d2fecdd52f792e860c1278c2c29fbeb90 Mon Sep 17 00:00:00 2001 From: Yap Sok Ann Date: Wed, 16 Oct 2013 14:16:25 +0800 Subject: [PATCH 1/6] git: Full length SHA-1 in, full length SHA-1 out. This removes ambiguity at the expense of slight backward incompatibility. --- library/source_control/git | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/library/source_control/git b/library/source_control/git index b839540e84..cbc005f539 100644 --- a/library/source_control/git +++ b/library/source_control/git @@ -41,7 +41,8 @@ options: default: "HEAD" description: - What version of the repository to check out. This can be the - git I(SHA), the literal string C(HEAD), a branch name, or a tag name. + full 40-character I(SHA-1) hash, the literal string C(HEAD), a + branch name, or a tag name. remote: required: false default: "origin" @@ -107,7 +108,7 @@ import tempfile def get_version(git_path, dest): ''' samples the version of the git repo ''' os.chdir(dest) - cmd = "%s show --abbrev-commit" % (git_path,) + cmd = "%s show" % (git_path,) sha = os.popen(cmd).read().split("\n") sha = sha[0].split()[1] return sha @@ -354,8 +355,7 @@ def main(): if rc != 0: module.fail_json(msg=err) # exit if already at desired sha version - # abbreviate version in case full sha is given - if before == str(version)[:7]: + if before == version: module.exit_json(changed=False) # check or get changes from remote remote_head = get_remote_head(git_path, module, dest, version, remote) @@ -370,7 +370,6 @@ def main(): else: changed = True else: - remote_head = remote_head[0:7] if before != remote_head: changed = True else: From 2ad4d77c9a5b0733a9cece82864499ea85c14e56 Mon Sep 17 00:00:00 2001 From: Yap Sok Ann Date: Wed, 16 Oct 2013 18:51:36 +0800 Subject: [PATCH 2/6] git: Remove unnecessary return code checking. The functions either return rc=0 or call fail_json themselves. --- library/source_control/git | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/library/source_control/git b/library/source_control/git index cbc005f539..64450428b7 100644 --- a/library/source_control/git +++ b/library/source_control/git @@ -337,7 +337,7 @@ def main(): if not os.path.exists(gitconfig): if module.check_mode: module.exit_json(changed=True) - (rc, out, err) = clone(git_path, module, repo, dest, remote, depth, version) + clone(git_path, module, repo, dest, remote, depth, version) elif not update: # Just return having found a repo already in the dest path # this does no checking that the repo is the actual repo @@ -351,9 +351,7 @@ def main(): # if force, do a reset if local_mods and module.check_mode: module.exit_json(changed=True, msg='Local modifications exist') - (rc, out, err) = reset(git_path, module, dest, force) - if rc != 0: - module.fail_json(msg=err) + reset(git_path, module, dest, force) # exit if already at desired sha version if before == version: module.exit_json(changed=False) @@ -375,15 +373,11 @@ def main(): else: changed = False module.exit_json(changed=changed, before=before, after=remote_head) - (rc, out, err) = fetch(git_path, module, repo, dest, version, remote) - if rc != 0: - module.fail_json(msg=err) + fetch(git_path, module, repo, dest, version, remote) # switch to version specified regardless of whether # we cloned or pulled - (rc, out, err) = switch_version(git_path, module, dest, remote, version) - if rc != 0: - module.fail_json(msg=err) + switch_version(git_path, module, dest, remote, version) # determine if we changed anything after = get_version(git_path, dest) From b9558828e8069a57881f731019e53258923abc5a Mon Sep 17 00:00:00 2001 From: Yap Sok Ann Date: Wed, 16 Oct 2013 19:02:11 +0800 Subject: [PATCH 3/6] git: Make function get_remote_head usable when cloning. This allows the module to return the before/after revisions in all cases. --- library/source_control/git | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/library/source_control/git b/library/source_control/git index 64450428b7..9488283a7b 100644 --- a/library/source_control/git +++ b/library/source_control/git @@ -149,11 +149,19 @@ def reset(git_path, module, dest, force): return module.run_command(cmd, check_rc=True) def get_remote_head(git_path, module, dest, version, remote): - cmd = '' - os.chdir(dest) + cloning = False + if remote == module.params['repo']: + cloning = True + else: + os.chdir(dest) if version == 'HEAD': - version = get_head_branch(git_path, module, dest, remote) - if is_remote_branch(git_path, module, dest, remote, version): + if cloning: + # cloning the repo, just get the remote's HEAD version + cmd = '%s ls-remote %s -h HEAD' % (git_path, remote) + else: + head_branch = get_head_branch(git_path, module, dest, remote) + cmd = '%s ls-remote %s -h refs/heads/%s' % (git_path, remote, head_branch) + elif is_remote_branch(git_path, module, dest, remote, version): cmd = '%s ls-remote %s -h refs/heads/%s' % (git_path, remote, version) elif is_remote_tag(git_path, module, dest, remote, version): cmd = '%s ls-remote %s -t refs/tags/%s' % (git_path, remote, version) @@ -168,7 +176,6 @@ def get_remote_head(git_path, module, dest, version, remote): return rev def is_remote_tag(git_path, module, dest, remote, version): - os.chdir(dest) cmd = '%s ls-remote %s -t refs/tags/%s' % (git_path, remote, version) (rc, out, err) = module.run_command(cmd) if version in out: @@ -187,10 +194,10 @@ def get_branches(git_path, module, dest): branches.append(line.strip()) return branches -def is_remote_branch(git_path, module, dest, remote, branch): - branches = get_branches(git_path, module, dest) - rbranch = 'remotes/%s/%s' % (remote, branch) - if rbranch in branches: +def is_remote_branch(git_path, module, dest, remote, version): + cmd = '%s ls-remote %s -h refs/heads/%s' % (git_path, remote, version) + (rc, out, err) = module.run_command(cmd) + if version in out: return True else: return False From a53e7045a6b3311ad16b0ce4837937d89fd198ea Mon Sep 17 00:00:00 2001 From: Yap Sok Ann Date: Wed, 16 Oct 2013 20:08:52 +0800 Subject: [PATCH 4/6] git: Always return the before/after revisions, even in check mode. The return values from check mode and non-check mode should match in all cases, except when a SHA-1 hash is used as version, as there is no way to check if it is a valid hash using `git ls-remote`. Also, to accomodate this change, the force flag for the reset function has been removed so that we can do the checking in main. --- library/source_control/git | 45 +++++++++++++++----------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/library/source_control/git b/library/source_control/git index 9488283a7b..569a26875b 100644 --- a/library/source_control/git +++ b/library/source_control/git @@ -136,15 +136,13 @@ def has_local_mods(git_path, dest): lines = filter(lambda c: not re.search('^\\?\\?.*$', c), lines) return len(lines) > 0 -def reset(git_path, module, dest, force): +def reset(git_path, module, dest): ''' Resets the index and working tree to HEAD. Discards any changes to tracked files in working tree since that commit. ''' os.chdir(dest) - if not force and has_local_mods(git_path, dest): - module.fail_json(msg="Local modifications exist in repository (force=no).") cmd = "%s reset --hard HEAD" % (git_path,) return module.run_command(cmd, check_rc=True) @@ -343,7 +341,8 @@ def main(): local_mods = False if not os.path.exists(gitconfig): if module.check_mode: - module.exit_json(changed=True) + remote_head = get_remote_head(git_path, module, dest, version, repo) + module.exit_json(changed=True, before=before, after=remote_head) clone(git_path, module, repo, dest, remote, depth, version) elif not update: # Just return having found a repo already in the dest path @@ -355,31 +354,23 @@ def main(): # else do a pull local_mods = has_local_mods(git_path, dest) before = get_version(git_path, dest) - # if force, do a reset - if local_mods and module.check_mode: - module.exit_json(changed=True, msg='Local modifications exist') - reset(git_path, module, dest, force) - # exit if already at desired sha version - if before == version: - module.exit_json(changed=False) - # check or get changes from remote remote_head = get_remote_head(git_path, module, dest, version, remote) - if module.check_mode: - changed = False - if remote_head == version: - # get_remote_head returned version as-is - # were given a sha1 object, see if it is present - (rc, out, err) = module.run_command("%s show %s" % (git_path, version)) - if version in out: - changed = False - else: - changed = True + if local_mods: + # failure should happen regardless of check mode + if not force: + module.fail_json(msg="Local modifications exist in repository (force=no).") + # if force and in non-check mode, do a reset + if not module.check_mode: + reset(git_path, module, dest) + # exit if already at desired sha version + if before == remote_head: + if local_mods: + module.exit_json(changed=True, before=before, after=remote_head, + msg="Local modifications exist") else: - if before != remote_head: - changed = True - else: - changed = False - module.exit_json(changed=changed, before=before, after=remote_head) + module.exit_json(changed=False, before=before, after=remote_head) + if module.check_mode: + module.exit_json(changed=True, before=before, after=remote_head) fetch(git_path, module, repo, dest, version, remote) # switch to version specified regardless of whether From 9f8cdac0aa4b4ca4dd73979726cd2ff8b7505493 Mon Sep 17 00:00:00 2001 From: Yap Sok Ann Date: Wed, 16 Oct 2013 20:18:01 +0800 Subject: [PATCH 5/6] git: Handle network problem when running `git ls-remote`. --- library/source_control/git | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/source_control/git b/library/source_control/git index 569a26875b..a22c9cabdf 100644 --- a/library/source_control/git +++ b/library/source_control/git @@ -175,7 +175,7 @@ def get_remote_head(git_path, module, dest, version, remote): def is_remote_tag(git_path, module, dest, remote, version): cmd = '%s ls-remote %s -t refs/tags/%s' % (git_path, remote, version) - (rc, out, err) = module.run_command(cmd) + (rc, out, err) = module.run_command(cmd, check_rc=True) if version in out: return True else: @@ -194,7 +194,7 @@ def get_branches(git_path, module, dest): def is_remote_branch(git_path, module, dest, remote, version): cmd = '%s ls-remote %s -h refs/heads/%s' % (git_path, remote, version) - (rc, out, err) = module.run_command(cmd) + (rc, out, err) = module.run_command(cmd, check_rc=True) if version in out: return True else: From 8519d586baf6f2ca6da57b936faec7fd44ae8acd Mon Sep 17 00:00:00 2001 From: Yap Sok Ann Date: Wed, 16 Oct 2013 20:31:25 +0800 Subject: [PATCH 6/6] git: Don't add --branch while cloning if the version is a SHA-1 hash. --- library/source_control/git | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/source_control/git b/library/source_control/git index a22c9cabdf..c241b8b5e6 100644 --- a/library/source_control/git +++ b/library/source_control/git @@ -122,8 +122,9 @@ def clone(git_path, module, repo, dest, remote, depth, version): pass os.chdir(dest_dirname) cmd = [ git_path, 'clone', '-o', remote, '--recursive' ] - if version and version != 'HEAD': - cmd.extend([ '--branch', str(version) ]) + if is_remote_branch(git_path, module, dest, repo, version) \ + or is_remote_tag(git_path, module, dest, repo, version): + cmd.extend([ '--branch', version ]) if depth: cmd.extend([ '--depth', str(depth) ]) cmd.extend([ repo, dest ])