Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pkgbuild option to build local package #46

Merged
merged 3 commits into from
Oct 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ The following helpers are supported and automatically selected, if present, in t
|use |**auto**, yay, pacaur, trizen, pikaur, aurman, makepkg |The tool to use, 'auto' uses the first known helper found and makepkg as a fallback.|
|extra_args |**null** |A list of additional arguments to pass directly to the tool. Cannot be used in 'auto' mode.|
|aur_only |yes, **no** |Limit helper operation to the AUR.|
|local_pkgbuild |Local directory with PKGBUILD, **null** |Only valid with makepkg or pikaur. Don't download the package from AUR. Build the package using a local PKGBUILD and the other build files.|
|skip_pgp_check |yes, **no** |Only valid with makepkg. Skip PGP signatures verification of source file, useful when installing packages without GnuPG properly configured.|
|ignore_arch |yes, **no** |Only valid with makepkg. Ignore a missing or incomplete arch field, useful when the PKGBUILD does not have the arch=('yourarch') field.|

Expand All @@ -30,7 +31,8 @@ The following helpers are supported and automatically selected, if present, in t
## Installing
### AUR package
The [ansible-aur-git](https://aur.archlinux.org/packages/ansible-aur-git) package is available in the AUR.
Note the module is installed in `/usr/share/ansible/plugins/modules` which is one of the default module library paths.

Note: The module is installed in `/usr/share/ansible/plugins/modules` which is one of the default module library paths.

### Manual installation
Just clone the *ansible-aur* repository into your user custom-module directory:
Expand All @@ -44,7 +46,7 @@ git clone https://github.com/kewlfft/ansible-aur.git ~/.ansible/plugins/modules/
ansible-galaxy install kewlfft.aur
```

Note that if this module is installed from Ansible Galaxy, you will need to list it explicitly in your playbook:
Note: If this module is installed from Ansible Galaxy, you will need to list it explicitly in your playbook:
```
# playbook.yml
- hosts: localhost
Expand Down Expand Up @@ -106,6 +108,17 @@ Use it in a task, as in the following examples:
- package_name_1
- package_name_2

# Upgrade the system using yay, only act on AUR packages, note that dependency resolving will still include repository packages
# Upgrade the system using yay, only act on AUR packages.
# Note: Dependency resolving will still include repository packages.
- aur: upgrade=yes use=yay aur_only=yes

# Install gnome-shell-extension-caffeine-git using pikaur and a local PKGBUILD.
# Skip if it is already installed
- aur:
name: gnome-shell-extension-caffeine-git
use: pikaur
local_pkgbuild: {{ role_path }}/files/gnome-shell-extension-caffeine-git
state: present
become: yes
become_user: aur_builder
```
104 changes: 83 additions & 21 deletions library/aur.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from ansible.module_utils.basic import *
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import open_url
import json
import shlex
import tarfile
import os
import os.path
import shutil
import tempfile
import urllib.parse

Expand Down Expand Up @@ -72,6 +73,14 @@
- Limit helper operation to the AUR.
type: bool
default: no

local_pkgbuild:
description:
- Only valid with makepkg or pikaur.
Directory with PKGBUILD and build files.
Cannot be used unless use is set to 'makepkg' or 'pikaur'.
type: path
default: no
notes:
- When used with a `loop:` each package will be processed individually,
it is much more efficient to pass the list directly to the `name` option.
Expand Down Expand Up @@ -102,6 +111,11 @@
'makepkg': ['makepkg', '--syncdeps', '--install', '--noconfirm', '--needed']
}

use_cmd_local_pkgbuild = {
'pikaur': ['pikaur', '-P', '--noconfirm', '--noedit', '--needed', '--install'],
'makepkg': ['makepkg', '--syncdeps', '--install', '--noconfirm', '--needed']
}

has_aur_option = ['yay', 'pacaur', 'trizen', 'pikaur', 'aurman']


Expand Down Expand Up @@ -145,39 +159,61 @@ def check_packages(module, packages):
module.exit_json(changed=status, msg=message, diff=diff)


def build_command_prefix(use, extra_args, skip_pgp_check=False, ignore_arch=False, aur_only=False):
def build_command_prefix(use, extra_args, skip_pgp_check=False, ignore_arch=False, aur_only=False, local_pkgbuild=None):
"""
Create the prefix of a command that can be used by the install and upgrade functions.
"""
command = def_lang + use_cmd[use]
if local_pkgbuild:
command = def_lang + use_cmd_local_pkgbuild[use]
else:
command = def_lang + use_cmd[use]
if skip_pgp_check:
command.append('--skippgpcheck')
if ignore_arch:
command.append('--ignorearch')
if aur_only and use in has_aur_option:
command.append('--aur')
if local_pkgbuild and use != 'makepkg':
command.append(local_pkgbuild)
if extra_args:
command += shlex.split(extra_args)
return command


def install_with_makepkg(module, package, extra_args, skip_pgp_check, ignore_arch):
def install_with_makepkg(module, package, extra_args, skip_pgp_check, ignore_arch, local_pkgbuild=None):
"""
Install the specified package with makepkg
Install the specified package or a local PKGBUILD with makepkg
"""
module.get_bin_path('fakeroot', required=True)
f = open_url('https://aur.archlinux.org/rpc/?v=5&type=info&arg={}'.format(urllib.parse.quote(package)))
result = json.loads(f.read().decode('utf8'))
if result['resultcount'] != 1:
return (1, '', 'package {} not found'.format(package))
result = result['results'][0]
f = open_url('https://aur.archlinux.org/{}'.format(result['URLPath']))
if not local_pkgbuild:
module.get_bin_path('fakeroot', required=True)
f = open_url('https://aur.archlinux.org/rpc/?v=5&type=info&arg={}'.format(urllib.parse.quote(package)))
result = json.loads(f.read().decode('utf8'))
if result['resultcount'] != 1:
return (1, '', 'package {} not found'.format(package))
result = result['results'][0]
f = open_url('https://aur.archlinux.org/{}'.format(result['URLPath']))
with tempfile.TemporaryDirectory() as tmpdir:
tar = tarfile.open(mode='r|*', fileobj=f)
tar.extractall(tmpdir)
tar.close()
command = build_command_prefix('makepkg', extra_args, skip_pgp_check=skip_pgp_check, ignore_arch=ignore_arch)
rc, out, err = module.run_command(command, cwd=os.path.join(tmpdir, result['Name']), check_rc=True)
if local_pkgbuild:
shutil.copytree(local_pkgbuild, tmpdir, dirs_exist_ok=True)
command = build_command_prefix('makepkg', extra_args)
rc, out, err = module.run_command(command, cwd=tmpdir, check_rc=True)
else:
tar = tarfile.open(mode='r|*', fileobj=f)
tar.extractall(tmpdir)
tar.close()
command = build_command_prefix('makepkg', extra_args, skip_pgp_check=skip_pgp_check, ignore_arch=ignore_arch)
rc, out, err = module.run_command(command, cwd=os.path.join(tmpdir, result['Name']), check_rc=True)
return (rc, out, err)


def install_local_package(module, package, use, extra_args, local_pkgbuild):
"""
Install the specified package with a local PKGBUILD
"""
with tempfile.TemporaryDirectory() as tmpdir:
shutil.copytree(local_pkgbuild, tmpdir, dirs_exist_ok=True)
command = build_command_prefix(use, extra_args, local_pkgbuild=tmpdir + '/PKGBUILD')
rc, out, err = module.run_command(command, check_rc=True)
return (rc, out, err)


Expand Down Expand Up @@ -213,11 +249,14 @@ def upgrade(module, use, extra_args, aur_only):
)


def install_packages(module, packages, use, extra_args, state, skip_pgp_check, ignore_arch, aur_only):
def install_packages(module, packages, use, extra_args, state, skip_pgp_check, ignore_arch, aur_only, local_pkgbuild):
"""
Install the specified packages
"""
assert use in use_cmd
if local_pkgbuild:
assert use in use_cmd_local_pkgbuild
else:
assert use in use_cmd

changed_iter = False

Expand All @@ -227,7 +266,9 @@ def install_packages(module, packages, use, extra_args, state, skip_pgp_check, i
rc = 0
continue
if use == 'makepkg':
rc, out, err = install_with_makepkg(module, package, extra_args, skip_pgp_check, ignore_arch)
rc, out, err = install_with_makepkg(module, package, extra_args, skip_pgp_check, ignore_arch, local_pkgbuild)
elif local_pkgbuild:
rc, out, err = install_local_package(module, package, use, extra_args, local_pkgbuild)
else:
command = build_command_prefix(use, extra_args, aur_only=aur_only)
command.append(package)
Expand Down Expand Up @@ -278,6 +319,10 @@ def make_module():
'default': False,
'type': 'bool',
},
'local_pkgbuild': {
'default': None,
'type': 'path',
},
},
mutually_exclusive=[['name', 'upgrade']],
required_one_of=[['name', 'upgrade']],
Expand All @@ -301,6 +346,15 @@ def make_module():
if use != 'makepkg' and (params['skip_pgp_check'] or params['ignore_arch']):
module.fail_json(msg="This option is only available with 'makepkg'.")

if not (use in use_cmd_local_pkgbuild) and params['local_pkgbuild']:
module.fail_json(msg="This option is not available with '%s'" % use)

if params['local_pkgbuild'] and not os.path.isdir(params['local_pkgbuild']):
module.fail_json(msg="Directory %s not found" % (params['local_pkgbuild']))

if params['local_pkgbuild'] and not os.access(params['local_pkgbuild'] + '/PKGBUILD', os.R_OK):
module.fail_json(msg="PKGBUILD inside %s not readable" % (params['local_pkgbuild']))

if params.get('upgrade', False) and use == 'makepkg':
module.fail_json(msg="The 'upgrade' action cannot be used with 'makepkg'.")

Expand All @@ -319,7 +373,15 @@ def apply_module(module, use):
if module.check_mode:
check_packages(module, params['name'])
else:
install_packages(module, params['name'], use, params['extra_args'], params['state'], params['skip_pgp_check'], params['ignore_arch'], params['aur_only'])
install_packages(module,
params['name'],
use,
params['extra_args'],
params['state'],
params['skip_pgp_check'],
params['ignore_arch'],
params['aur_only'],
params['local_pkgbuild'])


def main():
Expand Down