Merge pull request #727 from sfromm/git

Git module ported to use module magic
pull/728/merge
Michael DeHaan 13 years ago
commit 47cead3603

@ -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()

@ -9,6 +9,7 @@ import ansible.runner
import os import os
import shutil import shutil
import time import time
import tempfile
try: try:
import json import json
except: except:
@ -188,8 +189,22 @@ class TestRunner(unittest.TestCase):
assert 'failed' not in result assert 'failed' not in result
def test_git(self): def test_git(self):
# TODO: tests for the git module if not get_binary("yum"):
pass raise SkipTest
repo = 'git://github.com/ansible/ansible.git'
dest = tempfile.mkdtemp()
result = self._run('git', ['repo=%s' % repo, 'dest=%s' % dest])
assert 'failed' not in result
result = self._run('git', [
'repo=%s' % repo,
'dest=%s' % dest,
'version=master'
])
assert 'false' not in result
try:
shutil.rmtree(dest)
except OSError, e:
print "Failed to remove temp dir %s" % dest
def test_service(self): def test_service(self):
# TODO: tests for the service module # TODO: tests for the service module

Loading…
Cancel
Save