diff --git a/library/bzr b/library/bzr new file mode 100644 index 00000000000..2181e10037b --- /dev/null +++ b/library/bzr @@ -0,0 +1,174 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013, André Paramés +# Based on the Git module by 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 . + +DOCUMENTATION = u''' +--- +module: bzr +author: André Paramés +version_added: 0.0.1 +short_description: Deploy software (or files) from bzr branches +description: + - Manage I(bzr) branches to deploy files or software. +options: + parent: + required: true + aliases: [ name ] + description: + - SSH or HTTP protocol address of the parent branch. + dest: + required: true + description: + - Absolute path of where the branch should be cloned to. + version: + required: false + default: "head" + description: + - What version of the branch to clone. This can be the + bzr revno or revid. + force: + required: false + default: "yes" + choices: [ yes, no ] + description: + - If C(yes), any modified files in the working + tree will be discarded. +examples: + - code: "bzr parent=bzr+ssh://foosball.example.org/path/to/branch dest=/srv/checkout version=22" + description: Example bzr checkout from Ansible Playbooks +''' + +import re +import tempfile + +def get_version(dest): + ''' samples the version of the bzr branch''' + os.chdir(dest) + cmd = "bzr revno" + revno = os.popen(cmd).read().strip() + return revno + +def clone(module, parent, dest, version): + ''' makes a new bzr branch if it does not already exist ''' + dest_dirname = os.path.dirname(dest) + try: + os.makedirs(dest_dirname) + except: + pass + os.chdir(dest_dirname) + if version.lower() != 'head': + cmd = "bzr branch -r %s %s %s" % (version, parent, dest) + else: + cmd = "bzr branch %s %s" % (parent, dest) + return module.run_command(cmd, check_rc=True) + +def has_local_mods(dest): + os.chdir(dest) + cmd = "bzr status -S" + lines = os.popen(cmd).read().splitlines() + lines = filter(lambda c: not re.search('^\\?\\?.*$', c), lines) + return len(lines) > 0 + +def reset(module,dest,force): + ''' + Resets the index and working tree to head. + Discards any changes to tracked files in the working + tree since that commit. + ''' + os.chdir(dest) + if not force and has_local_mods(dest): + module.fail_json(msg="Local modifications exist in branch (force=no).") + return module.run_command("bzr revert", check_rc=True) + +def fetch(module, dest, version): + ''' updates branch from remote sources ''' + os.chdir(dest) + if version.lower() != 'head': + (rc, out, err) = module.run_command("bzr pull -r %s" % version) + else: + (rc, out, err) = module.run_command("bzr pull") + if rc != 0: + module.fail_json(msg="Failed to pull") + return (rc, out, err) + +def switch_version(module, dest, version): + ''' once pulled, switch to a particular revno or revid''' + os.chdir(dest) + cmd = '' + if version.lower() != 'head': + cmd = "bzr revert -r %s" % version + else: + cmd = "bzr revert" + return module.run_command(cmd, check_rc=True) + +# =========================================== + +def main(): + module = AnsibleModule( + argument_spec = dict( + dest=dict(required=True), + parent=dict(required=True, aliases=['name']), + version=dict(default='head'), + force=dict(default='yes', type='bool') + ) + ) + + dest = os.path.abspath(os.path.expanduser(module.params['dest'])) + parent = module.params['parent'] + version = module.params['version'] + force = module.params['force'] + + bzrconfig = os.path.join(dest, '.bzr', 'branch', 'branch.conf') + + rc, out, err, status = (0, None, None, None) + + # if there is no bzr configuration, do a branch operation + # else pull and switch the version + before = None + local_mods = False + if not os.path.exists(bzrconfig): + (rc, out, err) = clone(module, parent, dest, version) + else: + # else do a pull + local_mods = has_local_mods(dest) + before = get_version(dest) + (rc, out, err) = reset(module, dest, force) + if rc != 0: + module.fail_json(msg=err) + (rc, out, err) = fetch(module, dest, version) + if rc != 0: + module.fail_json(msg=err) + + # switch to version specified regardless of whether + # we cloned or pulled + (rc, out, err) = switch_version(module, dest, version) + + # determine if we changed anything + after = get_version(dest) + changed = False + + if before != after or local_mods: + changed = True + + module.exit_json(changed=changed, before=before, after=after) + +# include magic from lib/ansible/module_common.py +#<> +main()