#!/usr/bin/python # -*- coding: utf-8 -*- # (c) 2012, Michael DeHaan # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . # I wanted to keep this simple at first, so for now this checks out # from the given branch of a repo at a particular SHA or # tag. Latest is not supported, you should not be doing # that. Contribs welcome! -- MPD # requires subversion on the client. import re import logging logger = logging.getLogger('subversion') #hdlr = logging.FileHandler('/tmp/subversion.log') #hdlr.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s')) #logger.addHandler(hdlr) logger.setLevel(logging.DEBUG) # TODO test scenarios: # hacking/test-module -m library/subversion ; cat /tmp/subversion.log # hacking/test-module -m library/subversion -a "repo=\"svn+ssh://pen.syskey.com/opt/subversion/gnconf\"" ; cat /tmp/subversion.log # hacking/test-module -m library/subversion -a "dest=\"/tmp/gnconf\"" ; cat /tmp/subversion.log # when /tmp/gnconf doesn't exist: # hacking/test-module -m library/subversion -a "repo=\"svn+ssh://pen.syskey.com/opt/subversion/gnconf\" dest=\"/tmp/gnconf\"" ; cat /tmp/subversion.log # when /tmp/gnconf is a folder, but its not an svn repo # hacking/test-module -m library/subversion -a "repo=\"svn+ssh://pen.syskey.com/opt/subversion/gnconf\" dest=\"/tmp/gnconf\"" ; cat /tmp/subversion.log # when /tmp/gnconf is a folder, but its a file (not a folder) # hacking/test-module -m library/subversion -a "repo=\"svn+ssh://pen.syskey.com/opt/subversion/gnconf\" dest=\"/tmp/gnconf\"" ; cat /tmp/subversion.log # when /tmp/gnconf is a folder, when its a different svn URL # hacking/test-module -m library/subversion -a "repo=\"svn+ssh://pen.syskey.com/opt/subversion/gnconf\" dest=\"/tmp/gnconf\"" ; cat /tmp/subversion.log # when /tmp/gnconf is a folder, when its a different revision # hacking/test-module -m library/subversion -a "repo=\"svn+ssh://pen.syskey.com/opt/subversion/gnconf\" dest=\"/tmp/gnconf\"" ; cat /tmp/subversion.log def get_version(dest): ''' samples the version of the git repo ''' logger.debug('get_version') os.chdir(dest) cmd = "svn info | grep Revision" logger.debug(cmd) return os.popen(cmd).read() def checkout(repo, dest): ''' makes a new svn repo if it does not already exist ''' logger.debug('checkout') try: os.makedirs(os.path.dirname(dest)) except: pass cmd = "svn co %s %s" % (repo, dest) logger.debug(cmd) cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (out, err) = cmd.communicate() rc = cmd.returncode logger.debug('rc, error: %s, %s ' % (rc,err)) return (rc, out, err) def reset(dest): ''' throw away any changes? TODO doesn't seem like a good idea to me... TODO throw away non-tracked files? -- svn st | grep '?' | awk '{print $2}' | xargs rm -rf ''' logger.debug('reset') os.chdir(dest) cmd = "svn revert -R ." logger.debug(cmd) cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (out, err) = cmd.communicate() rc = cmd.returncode return (rc, out, err) def update(module, dest, version): ''' update an existing svn repo ''' logger.debug('update') os.chdir(dest) cmd = '' if version != 'HEAD': cmd = "svn up -r %s" % version else: cmd = "svn up" logger.debug(cmd) 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(): module = AnsibleModule( argument_spec = dict( dest=dict(required=True), repo=dict(required=True, aliases=['name']), revision=dict(default='HEAD') ) ) dest = module.params['dest'] repo = module.params['repo'] revision = module.params['revision'] rc, out, err, status = (0, None, None, None) # if there is no .svn folder, do a checkout # else update. before = None if not os.path.exists("%s/.svn" % (dest)): logger.debug('.svn exists') (rc, out, err) = checkout(repo, dest) if rc != 0: logger.debug('checkout failure') module.fail_json(msg=err) else: # else do an update before = get_version(dest) (rc, out, err) = reset(dest) if rc != 0: module.fail_json(msg=err) # handle errors from checkout or pull logger.debug('ERROR: %s' % (err.find('ERROR') != -1)) if err.find('ERROR') != -1: logger.debug('err:\n%s' % (err)) 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: changed = True module.exit_json(changed=changed, before=before, after=after, msg="fell thru the bag") # include magic from lib/ansible/module_common.py #<> main()