--- /dev/null
+Summary: SSH-based configuration management, deployment, and task execution system
+Name: ansible-core
+Version: 2.16.2
+Release: 1
+License: GPL v3+
+Group: Development/Libraries
+Source0: https://github.com/ansible/ansible/archive/refs/tags/v%{version}.tar.gz
+# Source0-md5: 91855c745f4304113e5f3bc8df7525cf
+Source2: poldek.py
+Patch0: poldek.patch
+URL: https://ansible.com
+BuildRequires: python3-PyYAML
+BuildRequires: python3-modules
+BuildRequires: rpm-pythonprov
+BuildRequires: rpmbuild(macros) >= 1.710
+BuildArch: noarch
+BuildRoot: %{tmpdir}/%{name}-%{version}-root-%(id -u -n)
+
+%description
+Ansible is a radically simple model-driven configuration management,
+multi-node deployment, and remote task execution system. Ansible works
+over SSH and does not require any software or daemons to be installed
+on remote nodes. Extension modules can be written in any language and
+are transferred to managed machines automatically.
+
+%prep
+%setup -q -n ansible-%{version}
+%patch0 -p1
+
+%{__sed} -i '1s,/usr/bin/env python,%{__python3},' \
+ bin/ansible-test \
+ test/lib/ansible_test/_util/target/cli/ansible_test_cli_stub.py
+
+%build
+%py3_build
+
+mkdir -p docs/man/man1
+LC_ALL=en_US.UTF-8 %{__python3} packaging/cli-doc/build.py man --output-dir docs/man/man1
+
+%install
+rm -rf $RPM_BUILD_ROOT
+%py3_install
+
+install -p %{SOURCE2} $RPM_BUILD_ROOT%{py3_sitescriptdir}/ansible/modules/
+
+install -d $RPM_BUILD_ROOT%{_mandir}
+cp -a docs/man/* $RPM_BUILD_ROOT%{_mandir}
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(644,root,root,755)
+%doc README.md
+%attr(755,root,root) %{_bindir}/ansible
+%attr(755,root,root) %{_bindir}/ansible-connection
+%attr(755,root,root) %{_bindir}/ansible-test
+%{_bindir}/ansible-config
+%{_bindir}/ansible-console
+%{_bindir}/ansible-doc
+%{_bindir}/ansible-galaxy
+%{_bindir}/ansible-inventory
+%{_bindir}/ansible-playbook
+%{_bindir}/ansible-pull
+%{_bindir}/ansible-vault
+%{_mandir}/man1/ansible-config.1*
+%{_mandir}/man1/ansible-console.1*
+%{_mandir}/man1/ansible-galaxy.1*
+%{_mandir}/man1/ansible-inventory.1*
+%{_mandir}/man1/ansible-vault.1*
+%{_mandir}/man1/ansible.1*
+%{_mandir}/man1/ansible-doc.1*
+%{_mandir}/man1/ansible-playbook.1*
+%{_mandir}/man1/ansible-pull.1*
+%{py3_sitescriptdir}/ansible
+%{py3_sitescriptdir}/ansible_core-%{version}-*.egg-info
+%{py3_sitescriptdir}/ansible_test
--- /dev/null
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2019, Marcin Krol <hawk@tld-linux.org>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import absolute_import, division, print_function
+__metaclass__ = type
+
+ANSIBLE_METADATA = {'metadata_version': '1.0',
+ 'status': ['preview'],
+ 'supported_by': 'community'}
+
+DOCUMENTATION = '''
+---
+module: poldek
+short_description: Manage packages with I(poldek)
+description:
+ - Manage packages with the I(poldek) package manager, which is used by TLD Linux and PLD Linux
+version_added: "1.0"
+author:
+ - Marcin Krol <hawk@tld-linux.org>
+options:
+ name:
+ description:
+ - Name or list of names of the package(s) or file(s) to install, upgrade, or remove.
+ Can't be used in combination with C(upgrade).
+ aliases: [ package, pkg ]
+
+ state:
+ description:
+ - Desired state of the package.
+ default: present
+ choices: [ absent, latest, present ]
+
+ extra_args:
+ description:
+ - Additional option to pass to poldek when enforcing C(state).
+ default:
+
+ update_cache:
+ description:
+ - Whether or not to refresh the master package lists.
+ - This can be run as part of a package installation or as a separate step.
+ default: no
+ type: bool
+ aliases: [ update-cache ]
+
+ update_cache_extra_args:
+ description:
+ - Additional option to pass to poldek when enforcing C(update_cache).
+ default:
+
+ upgrade:
+ description:
+ - Whether or not to upgrade the whole system.
+ Can't be used in combination with C(name).
+ default: no
+ type: bool
+
+ upgrade_extra_args:
+ description:
+ - Additional option to pass to poldek when enforcing C(upgrade).
+ default:
+'''
+
+RETURN = '''
+packages:
+ description: a list of packages that have been changed
+ returned: when upgrade is set to yes
+ type: list
+ sample: [ package, other-package ]
+'''
+
+EXAMPLES = '''
+- name: Install packages foo and bar
+ poldek:
+ name:
+ - foo
+ - bar
+ state: present
+
+- name: Update package cache and upgrade package foo
+ poldek:
+ name: foo
+ state: latest
+ update_cache: yes
+
+- name: Remove packages foo and bar
+ poldek:
+ name:
+ - foo
+ - bar
+ state: absent
+
+- name: Update package cache only
+ poldek:
+ update_cache: yes
+
+- name: Update package cache and upgrade all packages
+ poldek:
+ upgrade: yes
+ update_cache: yes
+'''
+
+import re
+
+from ansible.module_utils.basic import AnsibleModule
+
+
+def query_package(module, poldek_path, name):
+ """Query the package status in both the local system and the repository. Returns a boolean to indicate if the package is installed, a second
+ boolean to indicate if the package is up-to-date. Note: indexes must be up to date to ensure that poldek knows latest version of package.
+ """
+ lcmd = "%s -q --shcmd='ls -n --installed %s'" % (poldek_path, name)
+ lrc, lstdout, lstderr = module.run_command(lcmd, check_rc=False)
+ rcmd = "%s -q --shcmd='ls -n --installed --upgradeable %s'" % (poldek_path, name)
+ rrc, rstdout, rstderr = module.run_command(rcmd, check_rc=False)
+ if lrc != 0 or rrc != 0:
+ return False, False
+
+ pkg_latest = False
+ if rstdout == "":
+ return True, True
+ else:
+ return True, False
+
+
+def update_package_db(module, poldek_path):
+ if module.params['force']:
+ module.params["update_cache_extra_args"] += " --upa"
+
+ cmd = "%s --noask --up %s" % (poldek_path, module.params["update_cache_extra_args"])
+ rc, stdout, stderr = module.run_command(cmd, check_rc=False)
+
+ if rc == 0:
+ return True
+ else:
+ module.fail_json(msg="error updating package database")
+
+
+def upgrade(module, poldek_path):
+ cmdupgrade = "%s -v --noask --upgrade-dist %s" % (poldek_path, module.params["upgrade_extra_args"])
+ cmdupgradeable = "%s -q --shcmd='ls --upgradeable --qf=\"%%{NAME}-%%{VERSION}-%%{RELEASE}\n\"' %s" % (poldek_path, module.params["upgrade_extra_args"])
+ rc, stdout, stderr = module.run_command(cmdupgradeable, check_rc=False)
+
+ packages = stdout.split('\n')[:-1]
+ if stdout == "":
+ module.exit_json(changed=False, msg='Nothing to upgrade', packages=packages, stdout=stdout, stderr=stderr, rc=rc)
+ else:
+ if module.check_mode:
+ module.exit_json(changed=True, msg="%s package(s) would be upgraded" % (len(packages)), packages=packages, stdout=stdout, stderr=stderr, rc=rc)
+ rc, stdout, stderr = module.run_command(cmdupgrade, check_rc=False)
+ if rc == 0:
+ module.exit_json(changed=True, msg="%s package(s) upgraded" % (len(packages)), packages=packages, stdout=stdout, stderr=stderr, rc=rc)
+ else:
+ module.fail_json(msg="Error while upgrading packages", stdout=stdout, stderr=stderr, rc=rc)
+
+
+def remove_packages(module, poldek_path, packages):
+ if module.params["force"]:
+ module.params["extra_args"] += " --force --nodeps"
+
+ remove_c = 0
+ out = ""
+ err = ""
+
+ for package in packages:
+ installed, updated = query_package(module, poldek_path, package)
+ if not installed:
+ continue
+
+ cmd = "%s -v --noask --erase %s %s" % (poldek_path, module.params["extra_args"], package)
+ rc, stdout, stderr = module.run_command(cmd, check_rc=False)
+
+ out = out + stdout
+ err = err + stderr
+
+ if rc != 0:
+ module.fail_json(msg="failed to remove %s" % (package), stdout=out, stderr=err, rc=rc)
+
+ remove_c += 1
+
+ if remove_c > 0:
+ module.exit_json(changed=True, msg="removed %s package(s)" % (remove_c), packages=packages, stdout=out, stderr=err, rc=0)
+
+ module.exit_json(changed=False, msg="package(s) already absent", packages=packages, stdout=out, stderr=err, rc=0)
+
+
+def install_packages(module, poldek_path, state, packages):
+ if module.params["force"]:
+ module.params["extra_args"] += " --force --nodeps"
+
+ install_c = 0
+ out = ""
+ err = ""
+
+ for package in packages:
+ installed, updated = query_package(module, poldek_path, package)
+ if installed and (state == 'present' or (state == 'latest' and updated)):
+ continue
+
+ cmd = "%s -v --noask --upgrade %s %s" % (poldek_path, module.params["extra_args"], package)
+ rc, stdout, stderr = module.run_command(cmd, check_rc=False)
+
+ out = out + stdout
+ err = err + stderr
+
+ if rc != 0:
+ module.fail_json(msg="failed to install %s" % (package), stdout=out, stderr=err, rc=rc)
+
+ install_c += 1
+
+ if install_c > 0:
+ module.exit_json(changed=True, msg="installed %s package(s)" % (install_c), packages=packages, stdout=out, stderr=err, rc=0)
+
+ module.exit_json(changed=False, msg="package(s) already installed", packages=packages, stdout=out, stderr=err, rc=0)
+
+
+def check_packages(module, poldek_path, packages, state):
+ would_be_changed = []
+
+ for package in packages:
+ installed, updated = query_package(module, poldek_path, package)
+ if ((state in ["present", "latest"] and not installed) or
+ (state == "absent" and installed) or
+ (state == "latest" and not updated)):
+ would_be_changed.append(package)
+
+ if state == "absent":
+ state = "removed"
+ if state == "present" or state == "latest":
+ state = "installed"
+
+ if would_be_changed:
+ module.exit_json(changed=True, msg="%s package(s) would be %s" % (
+ len(would_be_changed), state))
+ else:
+ module.exit_json(changed=False, msg="package(s) already %s" % state)
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ name=dict(type='list', aliases=['pkg', 'package']),
+ state=dict(type='str', default='present', choices=['present', 'installed', 'latest', 'absent', 'removed']),
+ extra_args=dict(type='str', default=''),
+ upgrade=dict(type='bool', default=False),
+ upgrade_extra_args=dict(type='str', default=''),
+ update_cache=dict(type='bool', default=False, aliases=['update-cache']),
+ update_cache_extra_args=dict(type='str', default=''),
+ force=dict(type='bool', default=False),
+ ),
+ required_one_of=[['name', 'update_cache', 'upgrade']],
+ mutually_exclusive=[['name', 'upgrade']],
+ supports_check_mode=True,
+ )
+
+ poldek_path = module.get_bin_path('poldek', True)
+
+ p = module.params
+
+ if p['state'] in ['present', 'installed']:
+ p['state'] = 'present'
+ elif p['state'] in ['absent', 'removed']:
+ p['state'] = 'absent'
+
+ if p["update_cache"] and not module.check_mode:
+ update_package_db(module, poldek_path)
+ if not (p['name'] or p['upgrade']):
+ module.exit_json(changed=True, msg='Updated package database')
+
+ if p['update_cache'] and module.check_mode and not (p['name'] or p['upgrade']):
+ module.exit_json(changed=True, msg='Would have updated package database')
+
+ if p['upgrade']:
+ upgrade(module, poldek_path)
+
+ if p['name']:
+ pkgs = p['name']
+
+ if module.check_mode:
+ check_packages(module, poldek_path, pkgs, p['state'])
+
+ if p['state'] in ['present', 'latest']:
+ install_packages(module, poldek_path, p['state'], pkgs)
+ elif p['state'] == 'absent':
+ remove_packages(module, poldek_path, pkgs)
+ else:
+ module.exit_json(changed=False, msg="No package specified to work on")
+
+
+if __name__ == "__main__":
+ main()