From d6f7ffd4bcd53bfb906eccd500b925efca5a017d Mon Sep 17 00:00:00 2001 From: Stephen Fromm Date: Mon, 22 Oct 2012 23:08:27 -0700 Subject: [PATCH 1/4] More work in git module Rename pull() to fetch(). It does a git fetch and then a git fetch --tags. Add _run() method to handle all subprocess.Popen calls. Change all previous calls to subprocess.Popen to use _run(). --- git | 66 +++++++++++++++++++++---------------------------------------- 1 file changed, 22 insertions(+), 44 deletions(-) diff --git a/git b/git index 41208f6e839..fe354b45bfe 100755 --- a/git +++ b/git @@ -63,6 +63,12 @@ examples: import re import tempfile +def _run(args): + cmd = subprocess.Popen(args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = cmd.communicate() + rc = cmd.returncode + return (rc, out, err) + def get_version(dest): ''' samples the version of the git repo ''' os.chdir(dest) @@ -77,12 +83,7 @@ def clone(repo, dest): os.makedirs(os.path.dirname(dest)) except: pass - cmd = "git clone %s %s" % (repo, dest) - cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=tempfile.gettempdir()) - (out, err) = cmd.communicate() - rc = cmd.returncode - return (rc, out, err) - + return _run("git clone %s %s" % (repo, dest)) def has_local_mods(dest): os.chdir(dest) @@ -100,19 +101,13 @@ def reset(module,dest,force): os.chdir(dest) if not force and has_local_mods(dest): module.fail_json(msg="Local modifications exist in repository (force=no).") - cmd = "git reset --hard HEAD" - cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (out, err) = cmd.communicate() - rc = cmd.returncode - return (rc, out, err) + return _run("git reset --hard HEAD") def get_branches(module, dest): os.chdir(dest) branches = [] - cmd = "git branch -a" - cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() - if cmd.returncode != 0: + (rc, out, err) = _run("git branch -a") + if rc != 0: module.fail_json(msg="Could not determine branch data - received %s" % out) for line in out.split('\n'): branches.append(line.strip()) @@ -156,39 +151,25 @@ def is_not_a_branch(module, dest): def get_head_branch(module, dest, remote): os.chdir(dest) head = '' - cmd = "git remote show %s" % remote - cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() - if cmd.returncode != 0: + (rc, out, err) = _run("git remote show %s" % remote) + if rc != 0: module.fail_json(msg="Could not determine HEAD branch via git remote show") for line in out.split('\n'): if 'HEAD branch' in line: head = line.split()[-1].strip() return head -def pull(module, repo, dest, version, remote): +def fetch(module, repo, dest, version, remote): ''' updates repo from remote sources ''' os.chdir(dest) - branches = get_branches(module, dest) - cur_branch = '' - for b in branches: - if b.startswith('* '): - cur_branch = b - if is_local_branch(module, dest, version) and not is_current_branch(module, dest, version): - (rc, out, err) = switch_version(module, dest, remote, version) - if rc != 0: - module.fail_json(msg=err) - if is_not_a_branch(module, dest): - head_branch = get_head_branch(module, dest, remote) - (rc, out, err) = switch_version(module, dest, remote, head_branch) - if rc != 0: - module.fail_json(msg=err) + (rc, out1, err1) = _run("git fetch %s" % remote) + if rc != 0: + module.fail_json(msg="Failed to download remote objects and refs") - cmd = "git pull -u %s" % remote - cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = cmd.communicate() - rc = cmd.returncode - return (rc, out, err) + (rc, out2, err2) = _run("git fetch --tags %s" % remote) + if rc != 0: + module.fail_json(msg="Failed to download remote objects and refs") + return (rc, out1 + out2, err1 + err2) def switch_version(module, dest, remote, version): ''' once pulled, switch to a particular SHA, tag, or branch ''' @@ -202,10 +183,7 @@ def switch_version(module, dest, remote, version): else: # is there a better way to do this? cmd = "git rebase %s" % remote - cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (out, err) = cmd.communicate() - rc = cmd.returncode - return (rc, out, err) + return _run(cmd) # =========================================== @@ -245,7 +223,7 @@ def main(): (rc, out, err) = reset(module,dest,force) if rc != 0: module.fail_json(msg=err) - (rc, out, err) = pull(module, repo, dest, version, remote) + (rc, out, err) = fetch(module, repo, dest, version, remote) if rc != 0: module.fail_json(msg=err) From 3ec51ce5878b2d52c7410521e64b184c22528063 Mon Sep 17 00:00:00 2001 From: Stephen Fromm Date: Tue, 23 Oct 2012 23:34:53 -0700 Subject: [PATCH 2/4] Checkout branch before rebase in switch_version --- git | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/git b/git index fe354b45bfe..dbc0cf5857d 100755 --- a/git +++ b/git @@ -182,6 +182,10 @@ def switch_version(module, dest, remote, version): cmd = "git checkout --force %s" % version else: # is there a better way to do this? + branch = get_head_branch(module, dest, remote) + (rc, out, err) = _run("git checkout --force %s" % branch) + if rc != 0: + module.fail_json(msg="Failed to checkout branch %s" % branch) cmd = "git rebase %s" % remote return _run(cmd) From 048044375929be53c7a0ec34903eec8bf21ff5f7 Mon Sep 17 00:00:00 2001 From: Stephen Fromm Date: Wed, 7 Nov 2012 12:15:22 -0800 Subject: [PATCH 3/4] Use supplied remote name when cloning git repository --- git | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git b/git index dbc0cf5857d..1962f0e5ec6 100755 --- a/git +++ b/git @@ -77,13 +77,13 @@ def get_version(dest): sha = sha[0].split()[1] return sha -def clone(repo, dest): +def clone(repo, dest, remote): ''' makes a new git repo if it does not already exist ''' try: os.makedirs(os.path.dirname(dest)) except: pass - return _run("git clone %s %s" % (repo, dest)) + return _run("git clone -o %s %s %s" % (remote, repo, dest)) def has_local_mods(dest): os.chdir(dest) @@ -217,7 +217,7 @@ def main(): before = None local_mods = False if not os.path.exists(gitconfig): - (rc, out, err) = clone(repo, dest) + (rc, out, err) = clone(repo, dest, remote) if rc != 0: module.fail_json(msg=err) else: From 88e4be48a3b666781c9ab2400502b5d2857b2690 Mon Sep 17 00:00:00 2001 From: Stephen Fromm Date: Wed, 7 Nov 2012 16:33:22 -0800 Subject: [PATCH 4/4] Rewrite switch_version() to detect branch Rewrote switch_version() to read .git/HEAD to find branch associated with HEAD. If in a detached HEAD state, will read .git/refs/remotes//HEAD. --- git | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/git b/git index 1962f0e5ec6..f5cf10b0f6e 100755 --- a/git +++ b/git @@ -149,15 +149,35 @@ def is_not_a_branch(module, dest): return False def get_head_branch(module, dest, remote): - os.chdir(dest) - head = '' - (rc, out, err) = _run("git remote show %s" % remote) - if rc != 0: - module.fail_json(msg="Could not determine HEAD branch via git remote show") - for line in out.split('\n'): - if 'HEAD branch' in line: - head = line.split()[-1].strip() - return head + ''' + Determine what branch HEAD is associated with. This is partly + taken from lib/ansible/utils/__init__.py. It finds the correct + path to .git/HEAD and reads from that file the branch that HEAD is + associated with. In the case of a detached HEAD, this will look + up the branch in .git/refs/remotes//HEAD. + ''' + repo_path = os.path.join(dest, '.git') + # Check if the .git is a file. If it is a file, it means that we are in a submodule structure. + if os.path.isfile(repo_path): + try: + gitdir = yaml.load(open(repo_path)).get('gitdir') + # There is a posibility the .git file to have an absolute path. + if os.path.isabs(gitdir): + repo_path = gitdir + else: + repo_path = os.path.join(repo_path.split('.git')[0], gitdir) + except (IOError, AttributeError): + return '' + # Read .git/HEAD for the name of the branch. + # If we're in a detached HEAD state, look up the branch associated with + # the remote HEAD in .git/refs/remotes//HEAD + f = open(os.path.join(repo_path, "HEAD")) + if is_not_a_branch(module, dest): + f.close() + f = open(os.path.join(repo_path, 'refs', 'remotes', remote, 'HEAD')) + branch = f.readline().split('/')[-1].rstrip("\n") + f.close() + return branch def fetch(module, repo, dest, version, remote): ''' updates repo from remote sources ''' @@ -181,12 +201,11 @@ def switch_version(module, dest, remote, version): else: cmd = "git checkout --force %s" % version else: - # is there a better way to do this? branch = get_head_branch(module, dest, remote) (rc, out, err) = _run("git checkout --force %s" % branch) if rc != 0: module.fail_json(msg="Failed to checkout branch %s" % branch) - cmd = "git rebase %s" % remote + cmd = "git reset --hard %s" % remote return _run(cmd) # ===========================================