diff --git a/changelogs/fragments/2521-flatpak-list.yml b/changelogs/fragments/2521-flatpak-list.yml new file mode 100644 index 0000000000..e30607b306 --- /dev/null +++ b/changelogs/fragments/2521-flatpak-list.yml @@ -0,0 +1,2 @@ +minor_changes: +- flatpak - allows installing or uninstalling a list of packages (https://github.com/ansible-collections/community.general/pull/2521). diff --git a/plugins/modules/packaging/os/flatpak.py b/plugins/modules/packaging/os/flatpak.py index 4a9e214fde..7f3963ad3e 100644 --- a/plugins/modules/packaging/os/flatpak.py +++ b/plugins/modules/packaging/os/flatpak.py @@ -38,7 +38,8 @@ options: default: system name: description: - - The name of the flatpak to manage. + - The name of the flatpak to manage. To operate on several packages this + can accept a list of packages. - When used with I(state=present), I(name) can be specified as a URL to a C(flatpakref) file or the unique reverse DNS name that identifies a flatpak. - Both C(https://) and C(http://) URLs are supported. @@ -50,7 +51,8 @@ options: installed flatpak based on the name of the flatpakref to remove it. However, there is no guarantee that the names of the flatpakref file and the reverse DNS name of the installed flatpak do match. - type: str + type: list + elements: str required: true no_dependencies: description: @@ -101,10 +103,25 @@ EXAMPLES = r''' state: present remote: gnome +- name: Install multiple packages + community.general.flatpak: + name: + - org.gimp.GIMP + - org.inkscape.Inkscape + - org.mozilla.firefox + - name: Remove the gedit flatpak community.general.flatpak: name: org.gnome.gedit state: absent + +- name: Remove multiple packages + community.general.flatpak: + name: + - org.gimp.GIMP + - org.inkscape.Inkscape + - org.mozilla.firefox + state: absent ''' RETURN = r''' @@ -143,47 +160,64 @@ from ansible.module_utils.basic import AnsibleModule OUTDATED_FLATPAK_VERSION_ERROR_MESSAGE = "Unknown option --columns=application" -def install_flat(module, binary, remote, name, method, no_dependencies): - """Add a new flatpak.""" +def install_flat(module, binary, remote, names, method, no_dependencies): + """Add new flatpaks.""" global result + uri_names = [] + id_names = [] + for name in names: + if name.startswith('http://') or name.startswith('https://'): + uri_names.append(name) + else: + id_names.append(name) + base_command = [binary, "install", "--{0}".format(method)] + flatpak_version = _flatpak_version(module, binary) + if StrictVersion(flatpak_version) < StrictVersion('1.1.3'): + base_command += ["-y"] + else: + base_command += ["--noninteractive"] + if no_dependencies: + base_command += ["--no-deps"] + if uri_names: + command = base_command + uri_names + _flatpak_command(module, module.check_mode, command) + if id_names: + command = base_command + [remote] + id_names + _flatpak_command(module, module.check_mode, command) + result['changed'] = True + + +def uninstall_flat(module, binary, names, method): + """Remove existing flatpaks.""" + global result + installed_flat_names = [ + _match_installed_flat_name(module, binary, name, method) + for name in names + ] + command = [binary, "uninstall"] flatpak_version = _flatpak_version(module, binary) - command = [binary, "install", "--{0}".format(method)] if StrictVersion(flatpak_version) < StrictVersion('1.1.3'): command += ["-y"] else: command += ["--noninteractive"] - if no_dependencies: - command += ["--no-deps"] - if name.startswith('http://') or name.startswith('https://'): - command += [name] - else: - command += [remote, name] + command += ["--{0}".format(method)] + installed_flat_names _flatpak_command(module, module.check_mode, command) result['changed'] = True -def uninstall_flat(module, binary, name, method): - """Remove an existing flatpak.""" - global result - flatpak_version = _flatpak_version(module, binary) - if StrictVersion(flatpak_version) < StrictVersion('1.1.3'): - noninteractive_arg = "-y" - else: - noninteractive_arg = "--noninteractive" - installed_flat_name = _match_installed_flat_name(module, binary, name, method) - command = [binary, "uninstall", "--{0}".format(method), noninteractive_arg, name] - _flatpak_command(module, module.check_mode, command) - result['changed'] = True - - -def flatpak_exists(module, binary, name, method): - """Check if the flatpak is installed.""" +def flatpak_exists(module, binary, names, method): + """Check if the flatpaks are installed.""" command = [binary, "list", "--{0}".format(method), "--app"] output = _flatpak_command(module, False, command) - name = _parse_flatpak_name(name).lower() - if name in output.lower(): - return True - return False + installed = [] + not_installed = [] + for name in names: + parsed_name = _parse_flatpak_name(name).lower() + if parsed_name in output.lower(): + installed.append(name) + else: + not_installed.append(name) + return installed, not_installed def _match_installed_flat_name(module, binary, name, method): @@ -266,7 +300,7 @@ def main(): # This module supports check mode module = AnsibleModule( argument_spec=dict( - name=dict(type='str', required=True), + name=dict(type='list', elements='str', required=True), remote=dict(type='str', default='flathub'), method=dict(type='str', default='system', choices=['user', 'system']), @@ -295,10 +329,11 @@ def main(): if not binary: module.fail_json(msg="Executable '%s' was not found on the system." % executable, **result) - if state == 'present' and not flatpak_exists(module, binary, name, method): - install_flat(module, binary, remote, name, method, no_dependencies) - elif state == 'absent' and flatpak_exists(module, binary, name, method): - uninstall_flat(module, binary, name, method) + installed, not_installed = flatpak_exists(module, binary, name, method) + if state == 'present' and not_installed: + install_flat(module, binary, remote, not_installed, method, no_dependencies) + elif state == 'absent' and installed: + uninstall_flat(module, binary, installed, method) module.exit_json(**result) diff --git a/tests/integration/targets/flatpak/tasks/setup.yml b/tests/integration/targets/flatpak/tasks/setup.yml index 98b07cd480..8fc0a23566 100644 --- a/tests/integration/targets/flatpak/tasks/setup.yml +++ b/tests/integration/targets/flatpak/tasks/setup.yml @@ -36,7 +36,9 @@ - name: Remove (if necessary) flatpak for testing check mode on absent flatpak flatpak: - name: com.dummy.App1 + name: + - com.dummy.App1 + - com.dummy.App3 remote: dummy-remote state: absent no_dependencies: true diff --git a/tests/integration/targets/flatpak/tasks/test.yml b/tests/integration/targets/flatpak/tasks/test.yml index 7442e4b468..e1bfdbee09 100644 --- a/tests/integration/targets/flatpak/tasks/test.yml +++ b/tests/integration/targets/flatpak/tasks/test.yml @@ -139,3 +139,146 @@ that: - double_url_removal_result is not changed msg: "state=absent with url as name shall not do anything when flatpak is not present" + +- name: Make sure flatpak is really gone - {{ method }} + flatpak: + name: com.dummy.App1 + state: absent + method: "{{ method }}" + no_dependencies: true + +# state=present with list of packages + +- name: Test addition with list - {{ method }} + flatpak: + name: + - com.dummy.App1 + - http://127.0.0.1:8000/repo/com.dummy.App2.flatpakref + remote: dummy-remote + state: present + method: "{{ method }}" + no_dependencies: true + register: addition_result + +- name: Verify addition with list test result - {{ method }} + assert: + that: + - addition_result is changed + msg: "state=present shall add flatpak when absent" + +- name: Test idempotency of addition with list - {{ method }} + flatpak: + name: + - com.dummy.App1 + - http://127.0.0.1:8000/repo/com.dummy.App2.flatpakref + remote: dummy-remote + state: present + method: "{{ method }}" + no_dependencies: true + register: double_addition_result + +- name: Verify idempotency of addition with list test result - {{ method }} + assert: + that: + - double_addition_result is not changed + msg: "state=present shall not do anything when flatpak is already present" + +- name: Test addition with list partially installed - {{ method }} + flatpak: + name: + - com.dummy.App1 + - http://127.0.0.1:8000/repo/com.dummy.App2.flatpakref + - com.dummy.App3 + remote: dummy-remote + state: present + method: "{{ method }}" + no_dependencies: true + register: addition_result + +- name: Verify addition with list partially installed test result - {{ method }} + assert: + that: + - addition_result is changed + msg: "state=present shall add flatpak when absent" + +- name: Test idempotency of addition with list partially installed - {{ method }} + flatpak: + name: + - com.dummy.App1 + - http://127.0.0.1:8000/repo/com.dummy.App2.flatpakref + - com.dummy.App3 + remote: dummy-remote + state: present + method: "{{ method }}" + no_dependencies: true + register: double_addition_result + +- name: Verify idempotency of addition with list partially installed test result - {{ method }} + assert: + that: + - double_addition_result is not changed + msg: "state=present shall not do anything when flatpak is already present" + +# state=absent with list of packages + +- name: Test removal with list - {{ method }} + flatpak: + name: + - com.dummy.App1 + - com.dummy.App2 + state: absent + method: "{{ method }}" + register: removal_result + +- name: Verify removal with list test result - {{ method }} + assert: + that: + - removal_result is changed + msg: "state=absent shall remove flatpak when present" + +- name: Test idempotency of removal with list - {{ method }} + flatpak: + name: + - com.dummy.App1 + - com.dummy.App2 + state: absent + method: "{{ method }}" + register: double_removal_result + +- name: Verify idempotency of removal with list test result - {{ method }} + assert: + that: + - double_removal_result is not changed + msg: "state=absent shall not do anything when flatpak is not present" + +- name: Test removal with list partially removed - {{ method }} + flatpak: + name: + - com.dummy.App1 + - com.dummy.App2 + - com.dummy.App3 + state: absent + method: "{{ method }}" + register: removal_result + +- name: Verify removal with list partially removed test result - {{ method }} + assert: + that: + - removal_result is changed + msg: "state=absent shall remove flatpak when present" + +- name: Test idempotency of removal with list partially removed - {{ method }} + flatpak: + name: + - com.dummy.App1 + - com.dummy.App2 + - com.dummy.App3 + state: absent + method: "{{ method }}" + register: double_removal_result + +- name: Verify idempotency of removal with list partially removed test result - {{ method }} + assert: + that: + - double_removal_result is not changed + msg: "state=absent shall not do anything when flatpak is not present" diff --git a/tests/integration/targets/setup_flatpak_remote/create-repo.sh b/tests/integration/targets/setup_flatpak_remote/create-repo.sh index 4ece76ccfc..3f44fe96f2 100755 --- a/tests/integration/targets/setup_flatpak_remote/create-repo.sh +++ b/tests/integration/targets/setup_flatpak_remote/create-repo.sh @@ -18,7 +18,7 @@ flatpak install -y --system flathub org.freedesktop.Platform//1.6 org.freedeskto # Add individual flatpaks echo $'#!/bin/sh\necho hello world' > hello.sh -for NUM in 1 2; do +for NUM in 1 2 3; do flatpak build-init appdir${NUM} com.dummy.App${NUM} org.freedesktop.Sdk org.freedesktop.Platform 1.6; flatpak build appdir${NUM} mkdir /app/bin; flatpak build appdir${NUM} install --mode=750 hello.sh /app/bin; diff --git a/tests/integration/targets/setup_flatpak_remote/files/repo.tar.xz b/tests/integration/targets/setup_flatpak_remote/files/repo.tar.xz index bed20ff713..609acaad7b 100644 Binary files a/tests/integration/targets/setup_flatpak_remote/files/repo.tar.xz and b/tests/integration/targets/setup_flatpak_remote/files/repo.tar.xz differ