Merge pull request #1746 from njharman/subversion

Subverion module improvements
pull/1770/head
Michael DeHaan 12 years ago
commit f2893b6418

@ -23,8 +23,12 @@ DOCUMENTATION = '''
module: subversion module: subversion
short_description: Deploys a subversion repository. short_description: Deploys a subversion repository.
description: description:
- This module is really simple, it checks out from the given branch of a repo or at a particular tag. - Deploy given repository URL / revision to dest.
version_added: "0.7" version_added: "0.7"
author: Dane Summers, njharman@gmail.com
notes:
- Requres I(svn) to be installed on the client.
requirements: []
options: options:
repo: repo:
description: description:
@ -36,141 +40,136 @@ options:
- Absolute path where the repository should be deployed. - Absolute path where the repository should be deployed.
required: true required: true
default: null default: null
revision:
description:
- Specific revision to checkout.
required: false
default: HEAD
force: force:
description: description:
- If C(yes), any modified files in the working repository will be discarded. If C(no), this module will fail if it encounters modified files. - If C(yes), modified files will be discarded. If C(no), module will fail if it encounters modified files.
required: false required: false
default: yes default: yes
choices: [ "yes", "no" ] choices: [ "yes", "no" ]
username:
description:
- --username parameter passed to svn.
required: false
default: null
password:
description:
- --password parameter passed to svn.
required: false
default: null
examples: examples:
- code: "subversion: repo=svn+ssh://an.example.org/path/to/repo dest=/src/checkout" - code: "subversion: repo=svn+ssh://an.example.org/path/to/repo dest=/src/checkout"
description: Export subversion repository in a specified folder description: Checkout subversion repository to specified folder.
notes:
- Requires I(subversion) and I(grep) on the client.
requirements: [ ]
author: Dane Summers
''' '''
import re import re
def get_version(dest):
''' samples the version of the git repo ''' class Subversion(object):
os.chdir(dest) def __init__(self, module, dest, repo, revision, username, password):
cmd = "svn info" self.module = module
revision = filter(lambda l: re.search('Revision',l) != None,os.popen(cmd).read().splitlines()) self.dest = dest
url = filter(lambda l: re.search('^URL',l) != None,os.popen(cmd).read().splitlines()) self.repo = repo
return [revision[0],url[0]] self.revision = revision
self.username = username
def checkout(repo, dest): self.password = password
''' makes a new svn repo if it does not already exist '''
cmd = "svn co %s %s" % (repo, dest) def _exec(self, args):
cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) bits = ["svn --non-interactive --no-auth-cache", ]
(out, err) = cmd.communicate() if self.username:
rc = cmd.returncode bits.append("--username '%s'" % self.username)
return (rc, out, err) if self.password:
bits.append("--password '%s'" % self.password)
def switch(repo, dest): bits.append(args)
''' makes a new svn repo if it does not already exist ''' cmd = subprocess.Popen(' '.join(bits), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
cmd = "svn sw %s %s" % (repo, dest) out, err = cmd.communicate()
cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) rc = cmd.returncode
(out, err) = cmd.communicate() if rc != 0:
rc = cmd.returncode self.module.fail_json(msg=err)
return (rc, out, err) return out.splitlines()
def has_local_mods(dest): def checkout(self):
os.chdir(dest) '''Creates new svn working directory if it does not already exist.'''
cmd = "svn status" self._exec("checkout -r %s '%s' '%s'" % (self.revision, self.repo, self.dest))
lines = os.popen(cmd).read().splitlines()
filtered = filter(lambda c: re.search('^\\?.*$',c) == None,lines) def switch(self):
return len(filtered) > 0 '''Change working directory's repo.'''
# switch to ensure we are pointing at correct repo.
def reset(dest,force): self._exec("switch '%s' '%s'" % (self.repo, self.dest))
'''
Reset the repo: def update(self):
force: if true, then remove any local modifications. Else, fail if there are local modifications '''Update existing svn working directory.'''
''' self._exec("update -r %s '%s'" % (self.revision, self.dest))
if has_local_mods(dest):
if force: def revert(self):
cmd = "svn revert -R ." '''Revert svn working directory.'''
cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self._exec("revert -R '%s'" % self.dest)
(out, err) = cmd.communicate()
rc = cmd.returncode def get_revision(self):
return (rc, out, err) '''Revision and URL of subversion working directory.'''
else: text = '\n'.join(self._exec("info '%s'" % self.dest))
return (-1,"ERROR: modified files exist in the repository.","") rev = re.search(r'^Revision:.*$', text, re.MULTILINE).group(0)
return (0,"","") url = re.search(r'^URL:.*$', text, re.MULTILINE).group(0)
return rev, url
def update(module, dest, version):
''' update an existing svn repo ''' def has_local_mods(self):
os.chdir(dest) '''True if revisioned files have been added or modified. Unrevisioned files are ignored.'''
cmd = '' lines = self._exec("status '%s'" % self.dest)
if version != 'HEAD': # Match only revisioned files, i.e. ignore status '?'.
cmd = "svn up -r %s" % version regex = re.compile(r'^[^?]')
else: # Has local mods if more than 0 modifed revisioned files.
cmd = "svn up" return len(filter(regex.match, lines)) > 0
cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = cmd.communicate()
rc = cmd.returncode
return (rc, out, err)
# =========================================== # ===========================================
def main(): def main():
module = AnsibleModule( module = AnsibleModule(
argument_spec = dict( argument_spec=dict(
dest=dict(required=True), dest=dict(required=True),
repo=dict(required=True, aliases=['name']), repo=dict(required=True, aliases=['name', 'repository']),
revision=dict(default='HEAD'), revision=dict(default='HEAD', aliases=['rev']),
force=dict(default='yes', choices=['yes', 'no'], aliases=['force']) force=dict(default='yes', choices=['yes', 'no']),
username=dict(required=False),
password=dict(required=False),
) )
) )
dest = os.path.expanduser(module.params['dest']) dest = os.path.expanduser(module.params['dest'])
repo = module.params['repo'] repo = module.params['repo']
revision = module.params['revision'] revision = module.params['revision']
force = module.boolean(module.params['force']) force = module.boolean(module.params['force'])
username = module.params['username']
rc, out, err, status = (0, None, None, None) password = module.params['password']
# if there is no .svn folder, do a checkout svn = Subversion(module, dest, repo, revision, username, password)
# else update.
before = None if not os.path.exists(dest):
local_mods = False before = None
if not os.path.exists("%s/.svn" % (dest)): local_mods = False
if os.path.exists(dest): svn.checkout()
module.fail_json(msg="%s folder already exists, but its not a subversion repository." % (dest)) elif os.path.exists("%s/.svn" % (dest, )):
else: # Order matters. Need to get local mods before switch to avoid false
(rc, out, err) = checkout(repo, dest) # positives. Need to switch before revert to ensure we are reverting to
if rc != 0: # correct repo.
module.fail_json(msg=err) before = svn.get_revision()
local_mods = svn.has_local_mods()
svn.switch()
if local_mods:
if force:
svn.revert()
else:
module.fail_json(msg="ERROR: modified files exist in the repository.")
svn.update()
else: else:
local_mods = has_local_mods(dest) module.fail_json(msg="ERROR: %s folder already exists, but its not a subversion repository." % (dest, ))
# else do an update
before = get_version(dest)
(rc, out, err) = reset(dest,force)
if rc != 0:
module.fail_json(msg=err)
(rc, out, err) = switch(repo, dest)
if rc != 0:
module.fail_json(msg=err)
# handle errors from switch or pull
if err.find('ERROR') != -1:
module.fail_json(msg=err)
# switch to version specified regardless of whether
# we cloned or pulled
(rc, out, err) = update(module, dest, revision)
if rc != 0:
module.fail_json(msg=err)
# determine if we changed anything
after = get_version(dest)
changed = False
if before != after or local_mods:
changed = True
after = svn.get_revision()
changed = before != after or local_mods
module.exit_json(changed=changed, before=before, after=after) module.exit_json(changed=changed, before=before, after=after)
# include magic from lib/ansible/module_common.py # include magic from lib/ansible/module_common.py

Loading…
Cancel
Save