#!/usr/bin/python # The MIT License (MIT) # # Copyright (c) 2014 Austin Hyde # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import os import pwd import platform def cower_in_path(module): """ Determine if cower is available. """ rc, stdout, stderr = module.run_command('which cower', check_rc=False) return rc == 0 def pacman_in_path(module): """ Determine if pacman is available. """ rc, stdout, stderr = module.run_command('which pacman', check_rc=False) return rc == 0 def package_installed(module, pkg): """ Determine if a package is already installed. """ rc, stdout, stderr = module.run_command('pacman -Q %s' % pkg, check_rc=False) return rc == 0 def check_packages(module, pkgs): """ Inform the user what would change if the module were run. """ would_be_changed = [] for pkg in pkgs: installed = package_installed(module, pkg) if not installed: would_be_changed.append(pkg) if would_be_changed: module.exit_json(changed=True, msg='%s package(s) would be installed' % (len(would_be_changed))) else: module.exit_json(changed=False, msg='all packages are already installed') def download_packages(module, pkgs, dir, user): """ Download the specified packages. """ # Use cower, if available. if cower_in_path(module): cmds = ['sudo -u %s cower -dqf %s', ] # Otherwise, fall back to cURL else: cmds = ['sudo -u %s curl -O https://aur.archlinux.org/cgit/aur.git/snapshot/%s.tar.gz', 'sudo -u %s tar xzf %s.tar.gz'] for pkg in pkgs: # If the package is already installed, skip the download. if package_installed(module, pkg): continue # Change into the specified directory for download. os.chdir(dir) # Attempt to install the package. for cmd in cmds: rc, stdout, stderr = module.run_command(cmd % (user, pkg), check_rc=False) if rc != 0: module.fail_json(msg='failed to download package %s, because: %s' % (pkg,stderr)) def install_packages(module, pkgs, dir, user, virtual): """ Install the specified packages via makepkg. """ num_installed = 0 if platform.machine().startswith('arm') or platform.machine().startswith('aarch64'): makepkg_args = '-Acsrf' else: makepkg_args = '-csrf' cmd = 'sudo -u %s PKGEXT=".pkg.tar" makepkg %s --noconfirm --needed --noprogressbar' % (user, makepkg_args) if module.params['skip_pgp']: cmd += ' --skippgpcheck' for pkg in pkgs: # If the package is already installed, skip the install. if package_installed(module, pkg): continue # Change into the package directory. # Check if the package is a virtual package if virtual: os.chdir(os.path.join(dir, virtual)) else: os.chdir(os.path.join(dir, pkg)) # Attempt to build the directory. rc, stdout, stderr = module.run_command(cmd, check_rc=False) if rc != 0: module.fail_json(msg='failed to build package %s, because: %s' % (pkg,stderr)) # If the package was succesfully built, install it. rc, stdout, stderr = module.run_command('pacman -U --noconfirm *.pkg.tar*', check_rc=False, use_unsafe_shell=True) if rc != 0: module.fail_json(msg='failed to install package %s, because: %s' % (pkg,stderr)) else: num_installed += 1 # Exit with the number of packages succesfully installed. if num_installed > 0: module.exit_json(changed=True, msg='installed %s package(s)' % num_installed) else: module.exit_json(changed=False, msg='all packages were already installed') def main(): module = AnsibleModule( argument_spec = dict( name = dict(required=True, type='list'), user = dict(required=True), dir = dict(), skip_pgp = dict(default=False, type='bool'), virtual = dict(), ), supports_check_mode = True ) # Fail of pacman is not available. if not pacman_in_path(module): module.fail_json(msg="could not locate pacman executable") p = module.params # Get all the requested package names. pkgs = p['name'] # Fail if the specified user does not exist. try: pwd.getpwnam(p['user']) except KeyError: module.fail_json(msg="user %s does not exist" % p['user']) else: user = p['user'] # If no directory was given, assume the packages should be downloaded to # ~user/aur. if not p['dir']: home = os.path.expanduser('~%s' % user) if not os.path.exists(home): module.fail_json(msg="%s's home directory %s does not exist" % (user, home)) dir = os.path.join(home, 'aur') if not os.path.exists(dir): os.makedirs(dir) uid = pwd.getpwnam(user).pw_uid os.chown(dir, uid, -1) else: dir = os.path.expanduser(p['dir']) # Fail if the specified directory does not exist. if not os.path.exists(dir): module.fail_json(msg="directory %s does not exist" % dir) if module.check_mode: check_packages(module, pkgs) download_packages(module, pkgs, dir, user) # Check if the package is virtual if p['virtual']: virtual = p['virtual'] else: virtual = False install_packages(module, pkgs, dir, user, virtual) from ansible.module_utils.basic import * main()