mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
* * pkgin query_package(..) understands now also package name with version (my-package-1.2nb123456). * pkgin query_package(..) will distinct between not-installed and not-found packages. * pkgin install_package(..) fails with proper error if a non-existing package is attempted to be installed.
* fixup ansibot comments
* add changelog fragment
* add example
* use more pythonic condition
Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
* remove extra dot between description and link to PR
Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
* fix file extension of changelog fragment
* add pkgin unit tests for query_package function
* fix pep8 issues
* use enum Flag instead mix of strings, bools and None as return value
* use IntEnum instead Flag to support Python versions >= 2.6
* fix pep8 and pylint errors
* use regular class instead enum to avoid issues with older Python releases
* fix comment
* remove the combined package state since without an IntFlag or Flag the usage of it would require to use logical operators
Co-authored-by: Erik van Nooijen <eric.vannooijen@tomtom.com>
Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
(cherry picked from commit ece0202507
)
Co-authored-by: Martin Migasiewicz <616250+martinm82@users.noreply.github.com>
This commit is contained in:
parent
9279e4532d
commit
07e35f7505
3 changed files with 175 additions and 16 deletions
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- pkgin - add support for installation of full versioned package names (https://github.com/ansible-collections/community.general/pull/1256).
|
|
@ -77,6 +77,11 @@ EXAMPLES = '''
|
||||||
name: foo
|
name: foo
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
|
- name: Install specific version of foo package
|
||||||
|
community.general.pkgin:
|
||||||
|
name: foo-2.0.1
|
||||||
|
state: present
|
||||||
|
|
||||||
- name: Update cache and install foo package
|
- name: Update cache and install foo package
|
||||||
community.general.pkgin:
|
community.general.pkgin:
|
||||||
name: foo
|
name: foo
|
||||||
|
@ -120,13 +125,15 @@ import re
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
|
||||||
def query_package(module, name):
|
class PackageState(object):
|
||||||
"""Search for the package by name.
|
PRESENT = 1
|
||||||
|
NOT_INSTALLED = 2
|
||||||
|
OUTDATED = 4
|
||||||
|
NOT_FOUND = 8
|
||||||
|
|
||||||
Possible return values:
|
|
||||||
* "present" - installed, no upgrade needed
|
def query_package(module, name):
|
||||||
* "outdated" - installed, but can be upgraded
|
"""Search for the package by name and return state of the package.
|
||||||
* False - not installed or not found
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# test whether '-p' (parsable) flag is supported.
|
# test whether '-p' (parsable) flag is supported.
|
||||||
|
@ -172,20 +179,24 @@ def query_package(module, name):
|
||||||
# Grab matched string
|
# Grab matched string
|
||||||
pkgname_without_version = pkg_search_obj.group(1)
|
pkgname_without_version = pkg_search_obj.group(1)
|
||||||
|
|
||||||
if name != pkgname_without_version:
|
if name not in (pkgname_with_version, pkgname_without_version):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# The package was found; now return its state
|
# The package was found; now return its state
|
||||||
if raw_state == '<':
|
if raw_state == '<':
|
||||||
return 'outdated'
|
return PackageState.OUTDATED
|
||||||
elif raw_state == '=' or raw_state == '>':
|
elif raw_state == '=' or raw_state == '>':
|
||||||
return 'present'
|
return PackageState.PRESENT
|
||||||
else:
|
else:
|
||||||
return False
|
# Package found but not installed
|
||||||
|
return PackageState.NOT_INSTALLED
|
||||||
# no fall-through
|
# no fall-through
|
||||||
|
|
||||||
# No packages were matched, so return False
|
# No packages were matched
|
||||||
return False
|
return PackageState.NOT_FOUND
|
||||||
|
|
||||||
|
# Search failed
|
||||||
|
return PackageState.NOT_FOUND
|
||||||
|
|
||||||
|
|
||||||
def format_action_message(module, action, count):
|
def format_action_message(module, action, count):
|
||||||
|
@ -233,13 +244,13 @@ def remove_packages(module, packages):
|
||||||
# Using a for loop in case of error, we can report the package that failed
|
# Using a for loop in case of error, we can report the package that failed
|
||||||
for package in packages:
|
for package in packages:
|
||||||
# Query the package first, to see if we even need to remove
|
# Query the package first, to see if we even need to remove
|
||||||
if not query_package(module, package):
|
if query_package(module, package) in [PackageState.NOT_INSTALLED, PackageState.NOT_FOUND]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
rc, out, err = module.run_command(
|
rc, out, err = module.run_command(
|
||||||
format_pkgin_command(module, "remove", package))
|
format_pkgin_command(module, "remove", package))
|
||||||
|
|
||||||
if not module.check_mode and query_package(module, package):
|
if not module.check_mode and query_package(module, package) in [PackageState.PRESENT, PackageState.OUTDATED]:
|
||||||
module.fail_json(msg="failed to remove %s: %s" % (package, out))
|
module.fail_json(msg="failed to remove %s: %s" % (package, out))
|
||||||
|
|
||||||
remove_c += 1
|
remove_c += 1
|
||||||
|
@ -255,13 +266,16 @@ def install_packages(module, packages):
|
||||||
install_c = 0
|
install_c = 0
|
||||||
|
|
||||||
for package in packages:
|
for package in packages:
|
||||||
if query_package(module, package):
|
query_result = query_package(module, package)
|
||||||
|
if query_result in [PackageState.PRESENT, PackageState.OUTDATED]:
|
||||||
continue
|
continue
|
||||||
|
elif query_result is PackageState.NOT_FOUND:
|
||||||
|
module.fail_json(msg="failed to find package %s for installation" % package)
|
||||||
|
|
||||||
rc, out, err = module.run_command(
|
rc, out, err = module.run_command(
|
||||||
format_pkgin_command(module, "install", package))
|
format_pkgin_command(module, "install", package))
|
||||||
|
|
||||||
if not module.check_mode and not query_package(module, package):
|
if not module.check_mode and not query_package(module, package) in [PackageState.PRESENT, PackageState.OUTDATED]:
|
||||||
module.fail_json(msg="failed to install %s: %s" % (package, out))
|
module.fail_json(msg="failed to install %s: %s" % (package, out))
|
||||||
|
|
||||||
install_c += 1
|
install_c += 1
|
||||||
|
|
143
tests/unit/plugins/modules/packaging/os/test_pkgin.py
Normal file
143
tests/unit/plugins/modules/packaging/os/test_pkgin.py
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
# 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
|
||||||
|
|
||||||
|
from ansible_collections.community.general.tests.unit.compat import mock
|
||||||
|
from ansible_collections.community.general.tests.unit.compat import unittest
|
||||||
|
|
||||||
|
from ansible_collections.community.general.plugins.modules.packaging.os import pkgin
|
||||||
|
|
||||||
|
|
||||||
|
class TestPkginQueryPackage(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
pkgin.PKGIN_PATH = ""
|
||||||
|
|
||||||
|
@mock.patch('ansible_collections.community.general.plugins.modules.packaging.os.pkgin.AnsibleModule')
|
||||||
|
def test_package_without_version_is_present(self, mock_module):
|
||||||
|
# given
|
||||||
|
package = 'py37-conan'
|
||||||
|
parseable_flag_not_supported = 1
|
||||||
|
mock_module.run_command.side_effect = [
|
||||||
|
(parseable_flag_not_supported, "pkgin 0.11.7 for Darwin-18.6.0 x86_64 (using SQLite 3.27.2)", None),
|
||||||
|
(0, "%s-1.21.0 = C/C++ package manager" % package, None),
|
||||||
|
]
|
||||||
|
|
||||||
|
# when
|
||||||
|
command_result = pkgin.query_package(mock_module, package)
|
||||||
|
|
||||||
|
# then
|
||||||
|
self.assertEquals(command_result, pkgin.PackageState.PRESENT)
|
||||||
|
|
||||||
|
@mock.patch('ansible_collections.community.general.plugins.modules.packaging.os.pkgin.AnsibleModule')
|
||||||
|
def test_package_with_version_is_present(self, mock_module):
|
||||||
|
# given
|
||||||
|
package = 'py37-conan-1.21.0'
|
||||||
|
parseable_flag_not_supported = 1
|
||||||
|
mock_module.run_command.side_effect = [
|
||||||
|
(parseable_flag_not_supported, "pkgin 0.11.7 for Darwin-18.6.0 x86_64 (using SQLite 3.27.2)", None),
|
||||||
|
(0, "%s = C/C++ package manager" % package, None),
|
||||||
|
]
|
||||||
|
|
||||||
|
# when
|
||||||
|
command_result = pkgin.query_package(mock_module, package)
|
||||||
|
|
||||||
|
# then
|
||||||
|
self.assertEquals(command_result, pkgin.PackageState.PRESENT)
|
||||||
|
|
||||||
|
@mock.patch('ansible_collections.community.general.plugins.modules.packaging.os.pkgin.AnsibleModule')
|
||||||
|
def test_package_found_but_not_installed(self, mock_module):
|
||||||
|
# given
|
||||||
|
package = 'cmake'
|
||||||
|
parseable_flag_not_supported = 1
|
||||||
|
mock_module.run_command.side_effect = [
|
||||||
|
(parseable_flag_not_supported, "pkgin 0.11.7 for Darwin-18.6.0 x86_64 (using SQLite 3.27.2)", None),
|
||||||
|
(0, "cmake316-3.16.0nb1 = Cross platform make\ncmake314-3.14.6nb1 = Cross platform make\ncmake-3.14.0 Cross platform make", None),
|
||||||
|
]
|
||||||
|
|
||||||
|
# when
|
||||||
|
command_result = pkgin.query_package(mock_module, package)
|
||||||
|
|
||||||
|
# then
|
||||||
|
self.assertEquals(command_result, pkgin.PackageState.NOT_INSTALLED)
|
||||||
|
|
||||||
|
@mock.patch('ansible_collections.community.general.plugins.modules.packaging.os.pkgin.AnsibleModule')
|
||||||
|
def test_package_found_outdated(self, mock_module):
|
||||||
|
# given
|
||||||
|
package = 'cmake316'
|
||||||
|
parseable_flag_not_supported = 1
|
||||||
|
mock_module.run_command.side_effect = [
|
||||||
|
(parseable_flag_not_supported, "pkgin 0.11.7 for Darwin-18.6.0 x86_64 (using SQLite 3.27.2)", None),
|
||||||
|
(0, "cmake316-3.16.0nb1 < Cross platform make", None),
|
||||||
|
]
|
||||||
|
|
||||||
|
# when
|
||||||
|
command_result = pkgin.query_package(mock_module, package)
|
||||||
|
|
||||||
|
# then
|
||||||
|
self.assertEquals(command_result, pkgin.PackageState.OUTDATED)
|
||||||
|
|
||||||
|
@mock.patch('ansible_collections.community.general.plugins.modules.packaging.os.pkgin.AnsibleModule')
|
||||||
|
def test_package_with_version_found_outdated(self, mock_module):
|
||||||
|
# given
|
||||||
|
package = 'cmake316-3.16.0nb1'
|
||||||
|
parseable_flag_not_supported = 1
|
||||||
|
mock_module.run_command.side_effect = [
|
||||||
|
(parseable_flag_not_supported, "pkgin 0.11.7 for Darwin-18.6.0 x86_64 (using SQLite 3.27.2)", None),
|
||||||
|
(0, "cmake316-3.16.0nb1 < Cross platform make", None),
|
||||||
|
]
|
||||||
|
|
||||||
|
# when
|
||||||
|
command_result = pkgin.query_package(mock_module, package)
|
||||||
|
|
||||||
|
# then
|
||||||
|
self.assertEquals(command_result, pkgin.PackageState.OUTDATED)
|
||||||
|
|
||||||
|
@mock.patch('ansible_collections.community.general.plugins.modules.packaging.os.pkgin.AnsibleModule')
|
||||||
|
def test_package_not_found(self, mock_module):
|
||||||
|
# given
|
||||||
|
package = 'cmake320-3.20.0nb1'
|
||||||
|
parseable_flag_not_supported = 1
|
||||||
|
mock_module.run_command.side_effect = [
|
||||||
|
(parseable_flag_not_supported, "pkgin 0.11.7 for Darwin-18.6.0 x86_64 (using SQLite 3.27.2)", None),
|
||||||
|
(1, None, "No results found for %s" % package),
|
||||||
|
]
|
||||||
|
|
||||||
|
# when
|
||||||
|
command_result = pkgin.query_package(mock_module, package)
|
||||||
|
|
||||||
|
# then
|
||||||
|
self.assertEquals(command_result, pkgin.PackageState.NOT_FOUND)
|
||||||
|
|
||||||
|
@mock.patch('ansible_collections.community.general.plugins.modules.packaging.os.pkgin.AnsibleModule')
|
||||||
|
def test_with_parseable_flag_supported_package_is_present(self, mock_module):
|
||||||
|
# given
|
||||||
|
package = 'py37-conan'
|
||||||
|
parseable_flag_supported = 0
|
||||||
|
mock_module.run_command.side_effect = [
|
||||||
|
(parseable_flag_supported, "pkgin 0.11.7 for Darwin-18.6.0 x86_64 (using SQLite 3.27.2)", None),
|
||||||
|
(0, "%s-1.21.0;=;C/C++ package manager" % package, None),
|
||||||
|
]
|
||||||
|
|
||||||
|
# when
|
||||||
|
command_result = pkgin.query_package(mock_module, package)
|
||||||
|
|
||||||
|
# then
|
||||||
|
self.assertEquals(command_result, pkgin.PackageState.PRESENT)
|
||||||
|
|
||||||
|
@mock.patch('ansible_collections.community.general.plugins.modules.packaging.os.pkgin.AnsibleModule')
|
||||||
|
def test_with_parseable_flag_not_supported_package_is_present(self, mock_module):
|
||||||
|
# given
|
||||||
|
package = 'py37-conan'
|
||||||
|
parseable_flag_not_supported = 1
|
||||||
|
mock_module.run_command.side_effect = [
|
||||||
|
(parseable_flag_not_supported, "pkgin 0.11.7 for Darwin-18.6.0 x86_64 (using SQLite 3.27.2)", None),
|
||||||
|
(0, "%s-1.21.0 = C/C++ package manager" % package, None),
|
||||||
|
]
|
||||||
|
|
||||||
|
# when
|
||||||
|
command_result = pkgin.query_package(mock_module, package)
|
||||||
|
|
||||||
|
# then
|
||||||
|
self.assertEquals(command_result, pkgin.PackageState.PRESENT)
|
Loading…
Reference in a new issue