From 1727bd3b7aa99ec126b1f0ac6f9d33faf0ee38b8 Mon Sep 17 00:00:00 2001 From: Stephen Fromm Date: Thu, 26 Jul 2012 00:22:30 -0700 Subject: [PATCH] Update git module to handle branches better This drops the branch option. The version option is overloaded to mean either a sha1, branch, or tag. This also adds the option 'remote' which defaults to 'origin'. clone() was simplified by removing the checkout operation. That happens later when switch_version() is called. Added the methods get_branches(), is_remote_branch(), and is_local_branch(). get_branches() returns an array listing all of the branches for the git repository. is_remote_branch() checks whether the arguments supplied correspond to a remote branch. Similarly, is_local_branch() checks for a local branch. The pull() method now checks to see if it is on the desired branch. If not, it checks out the requested branch and then does a pull. This should keep issue #604 still fixed. switch_version(), formerly switchver(), looks to see if it is checking out a branch. If a branch, it checks it out with the --track option. This type of checkout was in pull() before. Updated pull, clone, and switch_version to return (rc, out, err). --- library/git | 130 ++++++++++++++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 60 deletions(-) diff --git a/library/git b/library/git index 2f3076e1efa..31bb12c7aba 100755 --- a/library/git +++ b/library/git @@ -71,8 +71,8 @@ for x in items: dest = params['dest'] repo = params['repo'] -branch = params.get('branch', 'master') version = params.get('version', 'HEAD') +remote = params.get('remote', 'origin') # =========================================== @@ -84,7 +84,7 @@ def get_version(dest): sha = sha[0].split()[1] return sha -def clone(repo, dest, branch): +def clone(repo, dest): ''' makes a new git repo if it does not already exist ''' try: os.makedirs(os.path.dirname(dest)) @@ -94,14 +94,7 @@ def clone(repo, dest, branch): cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (out, err) = cmd.communicate() rc = cmd.returncode - - if branch is None or rc != 0: - return (out, err) - - os.chdir(dest) - cmd = "git checkout -b %s origin/%s" % (branch, branch) - cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - return cmd.communicate() + return (rc, out, err) def reset(dest): ''' @@ -121,52 +114,67 @@ def switchLocalBranch( branch ): cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) return cmd.communicate() -def pull(repo, dest, branch): - ''' updates repo from remote sources ''' - os.chdir(dest) - cmd = "git branch -a" - cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (gbranch_out, gbranch_err) = cmd.communicate() - - try: - m = re.search( '^\* (\S+|\(no branch\))$', gbranch_out, flags=re.M ) - cur_branch = m.group(1) - m = re.search( '\s+remotes/origin/HEAD -> origin/(\S+)', gbranch_out, flags=re.M ) - default_branch = m.group(1) - except: - fail_json(msg="could not determine branch data - received: %s" % gbranch_out) - - if branch is None: - if cur_branch != default_branch: - (out, err) = switchLocalBranch( default_branch ) - - cmd = "git pull -u origin" - - elif branch == cur_branch: - cmd = "git pull -u origin" - - else: - m = re.search( '^\s+%s$' % branch, gbranch_out, flags=re.M ) #see if we've already checked it out - if m is None: - cmd = "git checkout --track -b %s origin/%s" % (branch, branch) - - else: - cmd = "git pull -u origin" - - cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - return cmd.communicate() - -def switchver(version, dest): - ''' once pulled, switch to a particular SHA or tag ''' - os.chdir(dest) - if version != 'HEAD': - cmd = "git checkout %s --force" % version - else: - # is there a better way to do this? - cmd = "git rebase origin" - cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (out, err) = cmd.communicate() - return (out, err) +def get_branches(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: + fail_json(msg="Could not determine branch data - received %s" % out) + for line in out.split('\n'): + branches.append(line.strip()) + return branches + +def is_remote_branch(dest, remote, branch): + branches = get_branches(dest) + rbranch = 'remotes/%s/%s' % (remote, branch) + if rbranch in branches: + return True + else: + return False + +def is_local_branch(dest, branch): + branches = get_branches(dest) + lbranch = '%s' % branch + if lbranch in branches: + return True + else: + return False + +def pull(repo, dest, version): + ''' updates repo from remote sources ''' + os.chdir(dest) + branches = get_branches(dest) + cur_branch = '' + for b in branches: + if b.startswith('* '): + cur_branch = b + if is_local_branch(dest, version) and version != cur_branch: + (out, err) = switchLocalBranch(version) + + cmd = "git pull -u origin" + cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = cmd.communicate() + rc = cmd.returncode + return (rc, out, err) + +def switch_version(dest, remote, version): + ''' once pulled, switch to a particular SHA or tag ''' + os.chdir(dest) + cmd = '' + if version != 'HEAD': + if not is_local_branch(dest, version) and is_remote_branch(dest, remote, version): + cmd = "git checkout --track -b %s %s/%s" % (version, remote, version) + else: + cmd = "git checkout --force %s" % version + else: + # is there a better way to do this? + cmd = "git rebase origin" + cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (out, err) = cmd.communicate() + rc = cmd.returncode + return (rc, out, err) gitconfig = os.path.join(dest, '.git', 'config') @@ -178,14 +186,16 @@ out, err, status = (None, None, None) before = None if not os.path.exists(gitconfig): - (out, err) = clone(repo, dest, branch) + (rc, out, err) = clone(repo, dest) + if rc != 0: + fail_json(out=out, err=err, rc=rc) else: # else do a pull before = get_version(dest) (rc, out, err) = reset(dest) if rc != 0: - fail_json(out=out, err=err) - (out, err) = pull(repo, dest, branch) + fail_json(out=out, err=err, rc=rc) + (rc, out, err) = pull(repo, dest, version) # handle errors from clone or pull @@ -195,7 +205,7 @@ if out.find('error') != -1 or err.find('ERROR') != -1: # switch to version specified regardless of whether # we cloned or pulled -(out, err) = switchver(version, dest) +(rc, out, err) = switch_version(dest, remote, version) if err.find('error') != -1: fail_json(out=out, err=err)