@ -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
@ -176,45 +138,61 @@ def switch_version(dest, remote, version):
rc = cmd.returncode
rc = cmd.returncode
return (rc, out, err)
return (rc, out, err)
# ===========================================
gitconfig = os.path.join(dest, '.git', 'config')
def main():
module = AnsibleModule(
out, err, status = (None, None, None)
argument_spec = dict(
dest=dict(required=True),
# if there is no git configuration, do a clone operation
repo=dict(required=True),
# else pull and switch the version
version=dict(default='HEAD'),
remote=dict(default='origin')
before = None
)
if not os.path.exists(gitconfig):
)
(rc, out, err) = clone(repo, dest)
if rc != 0:
dest = module.params['dest']
fail_json(out=out, err=err, rc=rc)
repo = module.params['repo']
else:
version = module.params['version']
# else do a pull
remote = module.params['remote']
before = get_version(dest)
(rc, out, err) = reset(dest)
gitconfig = os.path.join(dest, '.git', 'config')
if rc != 0:
fail_json(out=out, err=err, rc=rc)
out, err, status = (None, None, None)
(rc, out, err) = pull(repo, dest, version)
# if there is no git configuration, do a clone operation
# handle errors from clone or pull
# else pull and switch the version
before = None
if out.find('error') != -1 or err.find('ERROR') != -1:
if not os.path.exists(gitconfig):
fail_json(out=out, err=err)
(rc, out, err) = clone(repo, dest)
if rc != 0:
# switch to version specified regardless of whether
module.fail_json(out=out, err=err, rc=rc)
# we cloned or pulled
else:
# else do a pull
(rc, out, err) = switch_version(dest, remote, version)
before = get_version(dest)
if err.find('error') != -1:
(rc, out, err) = reset(dest)
fail_json(out=out, err=err)
if rc != 0:
module.fail_json(out=out, err=err, rc=rc)
# determine if we changed anything
(rc, out, err) = pull(module, repo, dest, version)
after = get_version(dest)
# handle errors from clone or pull
changed = False
if out.find('error') != -1 or err.find('ERROR') != -1:
module.fail_json(out=out, err=err)
if before != after:
changed = True
# switch to version specified regardless of whether
# we cloned or pulled
exit_json(changed=changed, before=before, after=after)
(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()