From 039b55363f78e35e97b0e876f99f75f31d315fab Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 7 Apr 2025 00:17:33 +0200 Subject: [PATCH] feat(role): Build AUR packages locally in chroot --- files/etc/pacman.d/repo-local-aur.conf | 11 ++ tasks/arch-linux-local-aur-repo-chroot.yml | 174 +++++++++++++++++++++ tasks/main.yml | 3 + 3 files changed, 188 insertions(+) create mode 100644 files/etc/pacman.d/repo-local-aur.conf create mode 100644 tasks/arch-linux-local-aur-repo-chroot.yml diff --git a/files/etc/pacman.d/repo-local-aur.conf b/files/etc/pacman.d/repo-local-aur.conf new file mode 100644 index 0000000..fd2f36d --- /dev/null +++ b/files/etc/pacman.d/repo-local-aur.conf @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: MIT +[options] +# This 'CacheDir' is the second one in our 'pacman.conf' file once we 'Include =' this file into it. The default dir at +# '/var/cache/pacman/pkg/' is not writable for unprivileged users. Pacman checks for the first writable cache when +# deciding where to store newly built packages. Thus all official packages keep ending up in '/var/cache/pacman/pkg/' +# while all AUR packages automatically end up at '/var/cache/aur/pkg/'. +CacheDir = /var/cache/aur/pkg/ + +[local-aur] +SigLevel = PackageOptional DatabaseOptional +Server = file:///var/cache/aur/pkg diff --git a/tasks/arch-linux-local-aur-repo-chroot.yml b/tasks/arch-linux-local-aur-repo-chroot.yml new file mode 100644 index 0000000..6446739 --- /dev/null +++ b/tasks/arch-linux-local-aur-repo-chroot.yml @@ -0,0 +1,174 @@ +# SPDX-License-Identifier: MIT +- name: 'If Arch Linux make sure devtools dependency is installed' + ansible.builtin.package: + name: 'devtools' + state: 'present' + +- name: 'If Arch Linux check if ZFS functional' + register: 'role_common_packages__archlinux_zfs_paru_chroot_os_has_functional_zfs' + changed_when: false + failed_when: false + ansible.builtin.shell: | + zpool list + +- name: 'If Arch Linux and if ZFS functional check if paru chroot dataset exists' + when: 'role_common_packages__archlinux_zfs_paru_chroot_os_has_functional_zfs.rc == 0' + register: 'role_common_packages__archlinux_zfs_paru_chroot_dataset_present' + changed_when: false + failed_when: false + ansible.builtin.shell: | + zfs list zpool/root/archlinux/var/cache/paru/chroot + +- name: 'If Arch Linux and if no paru chroot /dataset/ present check if a chroot /dir/ exists' + when: 'role_common_packages__archlinux_zfs_paru_chroot_dataset_present.rc > 0' + register: 'role_common_packages__archlinux_zfs_paru_chroot_dir_stat' + changed_when: false + failed_when: false + ansible.builtin.stat: + path: '/var/cache/paru/chroot' + +- name: 'If Arch Linux and if a paru chroot dir exists move it out of the way' + when: '(role_common_packages__archlinux_zfs_paru_chroot_dataset_present.rc > 0) and (role_common_packages__archlinux_zfs_paru_chroot_dir_stat.stat.isdir is defined and role_common_packages__archlinux_zfs_paru_chroot_dir_stat.stat.isdir)' + register: 'role_common_packages__archlinux_zfs_paru_chroot_dir_was_moved' + changed_when: 'role_common_packages__archlinux_zfs_paru_chroot_dir_was_moved.rc == 0' + ansible.builtin.shell: + cmd: | + mv ''/var/cache/paru/chroot''{,''.bak''} + removes: '/var/cache/paru/chroot' + creates: '/var/cache/paru/chroot.bak' + +- name: 'If Arch Linux and if no paru chroot dataset exists create dataset' + when: 'role_common_packages__archlinux_zfs_paru_chroot_dataset_present.rc > 0' + register: 'role_common_packages__archlinux_zfs_paru_chroot_dataset_was_created' + changed_when: 'role_common_packages__archlinux_zfs_paru_chroot_dataset_was_created.rc == 0' + ansible.builtin.shell: + cmd: | + if ! zfs list zpool/root/archlinux/var &>/dev/null; then zfs create -o canmount=off -o space.quico:auto-snapshot=- zpool/root/archlinux/var; fi && \ + if ! zfs list zpool/root/archlinux/var/cache &>/dev/null; then zfs create -o canmount=off zpool/root/archlinux/var/cache; fi && \ + if ! zfs list zpool/root/archlinux/var/cache/paru &>/dev/null; then zfs create -o canmount=off zpool/root/archlinux/var/cache/paru; fi && \ + zfs create zpool/root/archlinux/var/cache/paru/chroot + +- name: 'If Arch Linux and if a paru chroot dataset now exists and if paru chroot dir was moved out of the way move it back in place' + when: '(role_common_packages__archlinux_zfs_paru_chroot_dir_was_moved.rc is defined and role_common_packages__archlinux_zfs_paru_chroot_dir_was_moved.rc == 0) and (role_common_packages__archlinux_zfs_paru_chroot_dataset_was_created.rc == 0)' + ansible.builtin.shell: + cmd: | + rsync -a --remove-source-files ''/var/cache/paru/chroot''{''.bak'',}''/'' && \ + find ''/var/cache/paru/chroot.bak'' -type d -empty -delete + removes: '/var/cache/paru/chroot.bak' + +- name: 'If Arch Linux and if ZFS functional check if AUR package cache dataset exists' + when: 'role_common_packages__archlinux_zfs_paru_chroot_os_has_functional_zfs.rc == 0' + register: 'role_common_packages__archlinux_zfs_aur_pkg_cache_dataset_present' + changed_when: false + failed_when: false + ansible.builtin.shell: | + zfs list zpool/root/archlinux/var/cache/aur/pkg + +- name: 'If Arch Linux and if no AUR package cache /dataset/ present check if a chroot /dir/ exists' + when: 'role_common_packages__archlinux_zfs_aur_pkg_cache_dataset_present.rc > 0' + register: 'role_common_packages__archlinux_zfs_aur_pkg_cache_dir_stat' + changed_when: false + failed_when: false + ansible.builtin.stat: + path: '/var/cache/aur/pkg' + +- name: 'If Arch Linux and if an AUR package cache dir exists move it out of the way' + when: '(role_common_packages__archlinux_zfs_aur_pkg_cache_dataset_present.rc > 0) and (role_common_packages__archlinux_zfs_aur_pkg_cache_dir_stat.stat.isdir is defined and role_common_packages__archlinux_zfs_aur_pkg_cache_dir_stat.stat.isdir)' + register: 'role_common_packages__archlinux_zfs_aur_pkg_cache_dir_was_moved' + changed_when: 'role_common_packages__archlinux_zfs_aur_pkg_cache_dir_was_moved.rc == 0' + ansible.builtin.shell: + cmd: | + mv ''/var/cache/aur/pkg''{,''.bak''} + removes: '/var/cache/aur/pkg' + creates: '/var/cache/aur/pkg.bak' + +- name: 'If Arch Linux and if no AUR package cache dataset exists create dataset' + when: 'role_common_packages__archlinux_zfs_aur_pkg_cache_dataset_present.rc > 0' + register: 'role_common_packages__archlinux_zfs_aur_pkg_cache_dataset_was_created' + changed_when: 'role_common_packages__archlinux_zfs_aur_pkg_cache_dataset_was_created.rc == 0' + ansible.builtin.shell: + cmd: | + if ! zfs list zpool/root/archlinux/var &>/dev/null; then zfs create -o canmount=off -o space.quico:auto-snapshot=- zpool/root/archlinux/var; fi && \ + if ! zfs list zpool/root/archlinux/var/cache &>/dev/null; then zfs create -o canmount=off zpool/root/archlinux/var/cache; fi && \ + if ! zfs list zpool/root/archlinux/var/cache/aur &>/dev/null; then zfs create -o canmount=off zpool/root/archlinux/var/cache/aur; fi && \ + zfs create zpool/root/archlinux/var/cache/aur/pkg + +- name: 'If Arch Linux and if a AUR package cache dataset now exists and if AUR package cache dir was moved out of the way move it back in place' + when: '(role_common_packages__archlinux_zfs_aur_pkg_cache_dir_was_moved.rc is defined and role_common_packages__archlinux_zfs_aur_pkg_cache_dir_was_moved.rc == 0) and (role_common_packages__archlinux_zfs_aur_pkg_cache_dataset_was_created.rc == 0)' + ansible.builtin.shell: + cmd: | + rsync -a --remove-source-files ''/var/cache/aur/pkg''{''.bak'',}''/'' && \ + find ''/var/cache/aur/pkg.bak'' -type d -empty -delete + removes: '/var/cache/aur/pkg.bak' + +- name: 'If Arch Linux set global write perms (0777) on AUR package cache dir ''/var/cache/aur/pkg''' + ansible.builtin.file: + path: '/var/cache/aur/pkg' + mode: '0777' + +- name: 'If Arch Linux copy local AUR repo config file' + ansible.builtin.copy: + src: 'etc/pacman.d/repo-local-aur.conf' + dest: '/etc/pacman.d/repo-local-aur.conf' + +- name: 'If Arch Linux include local AUR repo config in main pacman config' + loop_control: + loop_var: 'pacman_opt' + index_var: 'i' + label: 'Set ''{{ pacman_opt.name }}'' to ''{{ pacman_opt.value }}'', this {{ pacman_opt.value }}' + loop: + - { name: 'CacheDir', value: '/var/cache/pacman/pkg/', exclusive: false, purpose_human_readable: 'adds an AUR-specific cache dir (since we make this one user-writable)' } + - { name: 'Include', value: '/etc/pacman.d/repo-local-aur.conf', exclusive: false, purpose_human_readable: 'adds our local AUR repo' } + community.general.ini_file: + path: '/etc/pacman.conf' + section: 'options' + option: '{{ pacman_opt.name }}' + value: '{{ pacman_opt.value }}' + exclusive: '{{ pacman_opt.exclusive }}' + +- name: 'If Arch Linux set ''/etc/paru.conf'' settings for local repo chroot AUR builds' + loop_control: + loop_var: 'paru_option' + index_var: 'i' + label: 'Set ''{{ paru_option.name }}'' {% if paru_option.value %}to ''{{ paru_option.value }}''{% else %}without a value{% endif %}, {{ paru_option.purpose_human_readable }}' + loop: + - { name: 'LocalRepo', value: '', allow_no_value: true, purpose_human_readable: 'this builds AUR packages into the local repo(s) specified in ''/etc/pacman.conf''' } + - { name: 'Chroot', value: '/var/cache/paru/chroot/root', allow_no_value: false, purpose_human_readable: 'this builds AUR packages in a clean chroot' } + community.general.ini_file: + path: '/etc/paru.conf' + section: 'options' + option: '{{ paru_option.name }}' + value: '{{ paru_option.value }}' + allow_no_value: '{{ paru_option.allow_no_value }}' + +- name: 'If Arch Linux initialize local AUR repo' + changed_when: false + failed_when: false + ansible.builtin.shell: + cmd: | + paru -Ly + +- name: 'If Arch Linux remove package ''paru-bin-debug''' + ansible.builtin.package: + name: 'paru-bin-debug' + state: 'absent' + +- name: 'If Arch Linux check if any non-local AUR packages remain to be moved into our local AUR repo' + register: 'role_common_packages__archlinux_zfs_aur_pkg_cache_non_local_pkgs' + changed_when: false + failed_when: false + ansible.builtin.shell: + cmd: | + comm -23 <(paru -Qem | awk '{print $1}' | sort) <(paru -Ll | awk '{ print $2 }' | sort) + +- name: 'If Arch Linux and if any non-local AUR packages exist move non-local AUR packages into local AUR repo' + become: 'yes' + become_user: 'build' + loop_control: + loop_var: 'pkg' + index_var: 'i' + label: 'Move pkg into local AUR repo: ''{{ pkg }}''' + loop: '{{ role_common_packages__archlinux_zfs_aur_pkg_cache_non_local_pkgs.stdout_lines }}' + ansible.builtin.shell: + cmd: | + paru -S --noconfirm '{{ pkg }}'; diff --git a/tasks/main.yml b/tasks/main.yml index e1a36ea..a9518ca 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -18,5 +18,8 @@ become: 'yes' become_user: 'build' +- import_tasks: 'arch-linux-local-aur-repo-chroot.yml' + when: 'ansible_facts[''os_family''] | lower == ''archlinux''' + - import_tasks: 'maintenance-unattended-upgrades.yml' when: 'ansible_facts[''os_family''] | lower == ''debian'''