Add list_repo_pkgs to win_pkg module

This commit is contained in:
Twangboy 2025-02-27 14:14:20 -07:00 committed by Daniel Wozniak
parent adf62acf9c
commit dd2c86d844
4 changed files with 166 additions and 6 deletions

3
changelog/67171.fixed.md Normal file
View file

@ -0,0 +1,3 @@
Fix a stacktrace on Windows with pkg.installed and test=True. The
`pkg.list_repo_pkgs` function does not exist on Windows. This uses the
`pkg.list_available` function instead for Windows.

View file

@ -45,6 +45,7 @@ import re
import sys import sys
import time import time
import urllib.parse import urllib.parse
from fnmatch import fnmatch
from functools import cmp_to_key from functools import cmp_to_key
import salt.fileserver import salt.fileserver
@ -275,6 +276,11 @@ def list_available(*names, **kwargs):
return_dict_always (bool): return_dict_always (bool):
Default ``False`` dict when a single package name is queried. Default ``False`` dict when a single package name is queried.
reverse_sort (bool):
Sort the versions for latest to oldest
.. versionadded:: 3007.2
Returns: Returns:
dict: The package name with its available versions dict: The package name with its available versions
@ -298,12 +304,15 @@ def list_available(*names, **kwargs):
return_dict_always = salt.utils.data.is_true( return_dict_always = salt.utils.data.is_true(
kwargs.get("return_dict_always", False) kwargs.get("return_dict_always", False)
) )
reverse_sort = salt.utils.data.is_true(kwargs.get("reverse_sort", False))
if len(names) == 1 and not return_dict_always: if len(names) == 1 and not return_dict_always:
pkginfo = _get_package_info(names[0], saltenv=saltenv) pkginfo = _get_package_info(names[0], saltenv=saltenv)
if not pkginfo: if not pkginfo:
return "" return ""
versions = sorted( versions = sorted(
list(pkginfo.keys()), key=cmp_to_key(_reverse_cmp_pkg_versions) list(pkginfo.keys()),
key=cmp_to_key(_reverse_cmp_pkg_versions),
reverse=reverse_sort,
) )
else: else:
versions = {} versions = {}
@ -314,11 +323,70 @@ def list_available(*names, **kwargs):
verlist = sorted( verlist = sorted(
list(pkginfo.keys()) if pkginfo else [], list(pkginfo.keys()) if pkginfo else [],
key=cmp_to_key(_reverse_cmp_pkg_versions), key=cmp_to_key(_reverse_cmp_pkg_versions),
reverse=reverse_sort,
) )
versions[name] = verlist versions[name] = verlist
return versions return versions
def list_repo_pkgs(*args, saltenv="base", **kwargs):
"""
.. versionadded:: 3007.2
This function was added to match a similar function in Linux. It will
return all available packages. Optionally, package names (and name globs)
can be passed and the results will be filtered to packages matching those
names.
This function can be helpful in discovering the version or repo to specify
in a :mod:`pkg.installed <salt.states.pkg.installed>` state.
The return data will be a dictionary mapping package names to a list of
version numbers, ordered from newest to oldest. For example:
.. code-block:: python
{
'bash': ['4.3-14ubuntu1.1',
'4.3-14ubuntu1'],
'nginx': ['1.10.0-0ubuntu0.16.04.4',
'1.9.15-0ubuntu1']
}
CLI Examples:
.. code-block:: bash
salt '*' pkg.list_repo_pkgs
salt '*' pkg.list_repo_pkgs foo bar baz
"""
# Get all the repo data
pkgs = get_repo_data(saltenv=saltenv).get("repo", {})
# Generate a list of packages and their available versions
repo_pkgs = {}
for pkg in pkgs:
repo_pkgs.update({pkg: list(pkgs[pkg].keys())})
# If no args passed, just return everything
if not args:
return repo_pkgs
# Loop through the args and return info for each specified package
ret = {}
for arg in args:
for pkg in repo_pkgs:
if fnmatch(pkg, arg):
ret.update({pkg: repo_pkgs[pkg]})
# If ret is empty, return everything
if not ret:
ret = repo_pkgs
return ret
def version(*names, **kwargs): def version(*names, **kwargs):
""" """
Returns a string representing the package version or an empty string if not Returns a string representing the package version or an empty string if not

View file

@ -13,9 +13,26 @@ def pkg_def_contents(state_tree):
my-software: my-software:
'1.0.1': '1.0.1':
full_name: 'My Software' full_name: 'My Software'
installer: 'C:\files\mysoftware.msi' installer: 'C:\files\mysoftware101.msi'
install_flags: '/qn /norestart' install_flags: '/qn /norestart'
uninstaller: 'C:\files\mysoftware.msi' uninstaller: 'C:\files\mysoftware101.msi'
uninstall_flags: '/qn /norestart'
msiexec: True
reboot: False
'1.0.2':
full_name: 'My Software'
installer: 'C:\files\mysoftware102.msi'
install_flags: '/qn /norestart'
uninstaller: 'C:\files\mysoftware102.msi'
uninstall_flags: '/qn /norestart'
msiexec: True
reboot: False
your-software:
'1.0.0':
full_name: 'Your Software'
installer: 'C:\files\yoursoftware101.msi'
install_flags: '/qn /norestart'
uninstaller: 'C:\files\yoursoftware101.msi'
uninstall_flags: '/qn /norestart' uninstall_flags: '/qn /norestart'
msiexec: True msiexec: True
reboot: False reboot: False
@ -27,9 +44,47 @@ def pkg(modules):
yield modules.pkg yield modules.pkg
def test_refresh_db(pkg, pkg_def_contents, state_tree, minion_opts): @pytest.fixture(scope="function")
def repo(pkg, state_tree, pkg_def_contents):
assert len(pkg.get_package_info("my-software")) == 0 assert len(pkg.get_package_info("my-software")) == 0
repo_dir = state_tree / "winrepo_ng" repo_dir = state_tree / "winrepo_ng"
with pytest.helpers.temp_file("my-software.sls", pkg_def_contents, repo_dir): with pytest.helpers.temp_file("my-software.sls", pkg_def_contents, repo_dir):
pkg.refresh_db() pkg.refresh_db()
assert len(pkg.get_package_info("my-software")) == 1
def test_refresh_db(pkg, repo):
assert len(pkg.get_package_info("my-software")) == 2
assert len(pkg.get_package_info("your-software")) == 1
@pytest.mark.parametrize(
"as_dict, reverse, expected",
[
(False, False, ["1.0.1", "1.0.2"]),
(False, True, ["1.0.2", "1.0.1"]),
(True, False, {"my-software": ["1.0.1", "1.0.2"]}),
(True, True, {"my-software": ["1.0.2", "1.0.1"]}),
],
)
def test_list_available(pkg, repo, as_dict, reverse, expected):
result = pkg.list_available(
"my-software", return_dict_always=as_dict, reverse_sort=reverse
)
assert result == expected
@pytest.mark.parametrize(
"pkg_name, expected",
[
("my-software", {"my-software": ["1.0.1", "1.0.2"]}),
("my-soft*", {"my-software": ["1.0.1", "1.0.2"]}),
("your-software", {"your-software": ["1.0.0"]}),
(None, {"my-software": ["1.0.1", "1.0.2"], "your-software": ["1.0.0"]}),
],
)
def test_list_repo_pkgs(pkg, repo, pkg_name, expected):
if pkg_name is None:
result = pkg.list_repo_pkgs()
else:
result = pkg.list_repo_pkgs(pkg_name)
assert result == expected

View file

@ -58,7 +58,7 @@ def refresh_keys(grains, modules):
def PKG_TARGETS(grains): def PKG_TARGETS(grains):
_PKG_TARGETS = ["figlet", "sl"] _PKG_TARGETS = ["figlet", "sl"]
if grains["os"] == "Windows": if grains["os"] == "Windows":
_PKG_TARGETS = ["npp_x64", "winrar"] _PKG_TARGETS = ["npp_x64", "putty"]
elif grains["os"] == "Amazon": elif grains["os"] == "Amazon":
if grains["osfinger"] == "Amazon Linux-2023": if grains["osfinger"] == "Amazon Linux-2023":
_PKG_TARGETS = ["lynx", "gnuplot-minimal"] _PKG_TARGETS = ["lynx", "gnuplot-minimal"]
@ -225,6 +225,29 @@ def install_7zip(modules):
assert "22.01.00.0" not in versions assert "22.01.00.0" not in versions
@pytest.fixture(scope="module")
def pkg_def_contents(state_tree):
return r"""
my-software:
'1.0.1':
full_name: 'My Software'
installer: 'C:\files\mysoftware101.msi'
install_flags: '/qn /norestart'
uninstaller: 'C:\files\mysoftware101.msi'
uninstall_flags: '/qn /norestart'
msiexec: True
reboot: False
'1.0.2':
full_name: 'My Software'
installer: 'C:\files\mysoftware102.msi'
install_flags: '/qn /norestart'
uninstaller: 'C:\files\mysoftware102.msi'
uninstall_flags: '/qn /norestart'
msiexec: True
reboot: False
"""
@pytest.mark.requires_salt_modules("pkg.version") @pytest.mark.requires_salt_modules("pkg.version")
@pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed")
@pytest.mark.slow_test @pytest.mark.slow_test
@ -1126,3 +1149,14 @@ def test_pkg_removed_with_version_multiple(install_7zip, modules, states):
assert ret.result is True assert ret.result is True
current = modules.pkg.version("7zip") current = modules.pkg.version("7zip")
assert "22.01.00.0" in current assert "22.01.00.0" in current
@pytest.mark.skip_unless_on_windows()
def test_pkg_latest_test_true(states, modules, state_tree, pkg_def_contents):
repo_dir = state_tree / "winrepo_ng"
with pytest.helpers.temp_file("my-software.sls", pkg_def_contents, repo_dir):
modules.pkg.refresh_db()
assert len(modules.pkg.get_package_info("my-software")) == 2
result = states.pkg.latest("my-software", test=True)
expected = {"my-software": {"new": "1.0.2", "old": ""}}
assert result.changes == expected