Merge pull request #727 from sfromm/git

Git module ported to use module magic
reviewable/pr18780/r1
Michael DeHaan 12 years ago
commit 07880e6301

246
git

@ -22,136 +22,98 @@
# tag. Latest is not supported, you should not be doing # tag. Latest is not supported, you should not be doing
# that. Contribs welcome! -- MPD # that. Contribs welcome! -- MPD
try:
import json
except ImportError:
import simplejson as json
import os import os
import re import re
import sys
import shlex
import subprocess import subprocess
import syslog
# ===========================================
# Basic support methods
def exit_json(rc=0, **kwargs):
print json.dumps(kwargs)
sys.exit(rc)
def fail_json(**kwargs):
kwargs['failed'] = True
exit_json(**kwargs)
# ===========================================
# convert arguments of form a=b c=d
# to a dictionary
# FIXME: make more idiomatic
if len(sys.argv) == 1:
fail_json(msg="the command module requires arguments (-a)")
argfile = sys.argv[1]
if not os.path.exists(argfile):
fail_json(msg="Argument file not found")
args = open(argfile, 'r').read()
items = shlex.split(args)
syslog.openlog('ansible-%s' % os.path.basename(__file__))
syslog.syslog(syslog.LOG_NOTICE, 'Invoked with %s' % args)
if not len(items):
fail_json(msg="the command module requires arguments (-a)")
params = {}
for x in items:
(k, v) = x.split("=")
params[k] = v
dest = params['dest']
repo = params['repo']
version = params.get('version', 'HEAD')
remote = params.get('remote', 'origin')
# ===========================================
def get_version(dest): def get_version(dest):
''' samples the version of the git repo ''' ''' samples the version of the git repo '''
os.chdir(dest) os.chdir(dest)
cmd = "git show --abbrev-commit" cmd = "git show --abbrev-commit"
sha = os.popen(cmd).read().split("\n") sha = os.popen(cmd).read().split("\n")
sha = sha[0].split()[1] sha = sha[0].split()[1]
return sha return sha
def clone(repo, dest): def clone(repo, dest):
''' makes a new git repo if it does not already exist ''' ''' makes a new git repo if it does not already exist '''
try: try:
os.makedirs(os.path.dirname(dest)) os.makedirs(os.path.dirname(dest))
except: except:
pass pass
cmd = "git clone %s %s" % (repo, dest) cmd = "git clone %s %s" % (repo, dest)
cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = cmd.communicate() (out, err) = cmd.communicate()
rc = cmd.returncode rc = cmd.returncode
return (rc, out, err) return (rc, out, err)
def reset(dest): def reset(dest):
''' '''
Resets the index and working tree to HEAD. Resets the index and working tree to HEAD.
Discards any changes to tracked files in working Discards any changes to tracked files in working
tree since that commit. tree since that commit.
''' '''
os.chdir(dest) os.chdir(dest)
cmd = "git reset --hard HEAD" cmd = "git reset --hard HEAD"
cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = cmd.communicate() (out, err) = cmd.communicate()
rc = cmd.returncode rc = cmd.returncode
return (rc, out, err) return (rc, out, err)
def switchLocalBranch( branch ): def switchLocalBranch( branch ):
cmd = "git checkout %s" % branch cmd = "git checkout %s" % branch
cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return cmd.communicate() return cmd.communicate()
def get_branches(dest): def get_branches(module, dest):
os.chdir(dest) os.chdir(dest)
branches = [] branches = []
cmd = "git branch -a" cmd = "git branch -a"
cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = cmd.communicate() out, err = cmd.communicate()
if cmd.returncode != 0: if cmd.returncode != 0:
fail_json(msg="Could not determine branch data - received %s" % out) module.fail_json(msg="Could not determine branch data - received %s" % out)
for line in out.split('\n'): for line in out.split('\n'):
branches.append(line.strip()) branches.append(line.strip())
return branches return branches
def is_remote_branch(dest, remote, branch): def is_remote_branch(module, dest, remote, branch):
branches = get_branches(dest) branches = get_branches(module, dest)
rbranch = 'remotes/%s/%s' % (remote, branch) rbranch = 'remotes/%s/%s' % (remote, branch)
if rbranch in branches: if rbranch in branches:
return True return True
else: else:
return False return False
def is_local_branch(dest, branch): def is_local_branch(module, dest, branch):
branches = get_branches(dest) branches = get_branches(module, dest)
lbranch = '%s' % branch lbranch = '%s' % branch
if lbranch in branches: if lbranch in branches:
return True return True
elif '* %s' % branch in branches:
return True
else: else:
return False return False
def pull(repo, dest, version): def is_current_branch(module, dest, branch):
branches = get_branches(module, dest)
for b in branches:
if b.startswith('* '):
cur_branch = b
if branch == cur_branch or '* %s' % branch == cur_branch:
return True
else:
return True
def pull(module, repo, dest, version):
''' updates repo from remote sources ''' ''' updates repo from remote sources '''
os.chdir(dest) os.chdir(dest)
branches = get_branches(dest) branches = get_branches(module, dest)
cur_branch = '' cur_branch = ''
for b in branches: for b in branches:
if b.startswith('* '): if b.startswith('* '):
cur_branch = b cur_branch = b
if is_local_branch(dest, version) and version != cur_branch: if is_local_branch(module, dest, version) and not is_current_branch(module, dest, version):
(out, err) = switchLocalBranch(version) (out, err) = switch_version(module, dest, remote, version)
cmd = "git pull -u origin" cmd = "git pull -u origin"
cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@ -159,12 +121,12 @@ def pull(repo, dest, version):
rc = cmd.returncode rc = cmd.returncode
return (rc, out, err) return (rc, out, err)
def switch_version(dest, remote, version): def switch_version(module, dest, remote, version):
''' once pulled, switch to a particular SHA or tag ''' ''' once pulled, switch to a particular SHA, tag, or branch '''
os.chdir(dest) os.chdir(dest)
cmd = '' cmd = ''
if version != 'HEAD': if version != 'HEAD':
if not is_local_branch(dest, version) and is_remote_branch(dest, remote, version): if not is_local_branch(module, dest, version) and is_remote_branch(module, dest, remote, version):
cmd = "git checkout --track -b %s %s/%s" % (version, remote, version) cmd = "git checkout --track -b %s %s/%s" % (version, remote, version)
else: else:
cmd = "git checkout --force %s" % version cmd = "git checkout --force %s" % version
@ -175,46 +137,62 @@ def switch_version(dest, remote, version):
(out, err) = cmd.communicate() (out, err) = cmd.communicate()
rc = cmd.returncode rc = cmd.returncode
return (rc, out, err) return (rc, out, err)
gitconfig = os.path.join(dest, '.git', 'config')
out, err, status = (None, None, None) # ===========================================
# if there is no git configuration, do a clone operation
# else pull and switch the version
before = None
if not os.path.exists(gitconfig):
(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, rc=rc)
(rc, out, err) = pull(repo, dest, version)
# handle errors from clone or pull
if out.find('error') != -1 or err.find('ERROR') != -1:
fail_json(out=out, err=err)
# switch to version specified regardless of whether
# we cloned or pulled
(rc, out, err) = switch_version(dest, remote, version)
if err.find('error') != -1:
fail_json(out=out, err=err)
# determine if we changed anything
after = get_version(dest)
changed = False
if before != after:
changed = True
exit_json(changed=changed, before=before, after=after) def main():
module = AnsibleModule(
argument_spec = dict(
dest=dict(required=True),
repo=dict(required=True),
version=dict(default='HEAD'),
remote=dict(default='origin')
)
)
dest = module.params['dest']
repo = module.params['repo']
version = module.params['version']
remote = module.params['remote']
gitconfig = os.path.join(dest, '.git', 'config')
out, err, status = (None, None, None)
# if there is no git configuration, do a clone operation
# else pull and switch the version
before = None
if not os.path.exists(gitconfig):
(rc, out, err) = clone(repo, dest)
if rc != 0:
module.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:
module.fail_json(out=out, err=err, rc=rc)
(rc, out, err) = pull(module, repo, dest, version)
# handle errors from clone or pull
if out.find('error') != -1 or err.find('ERROR') != -1:
module.fail_json(out=out, err=err)
# switch to version specified regardless of whether
# we cloned or pulled
(rc, out, err) = switch_version(module, dest, remote, version)
if err.find('error') != -1:
module.fail_json(out=out, err=err)
# determine if we changed anything
after = get_version(dest)
changed = False
if before != after:
changed = True
module.exit_json(changed=changed, before=before, after=after)
# include magic from lib/ansible/module_common.py
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
main()

Loading…
Cancel
Save