202 lines
6.5 KiB
Plaintext
202 lines
6.5 KiB
Plaintext
|
#!/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()
|