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 time
import urllib.parse
from fnmatch import fnmatch
from functools import cmp_to_key
import salt.fileserver
@ -275,6 +276,11 @@ def list_available(*names, **kwargs):
return_dict_always (bool):
Default ``False`` dict when a single package name is queried.
reverse_sort (bool):
Sort the versions for latest to oldest
.. versionadded:: 3007.2
Returns:
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(
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:
pkginfo = _get_package_info(names[0], saltenv=saltenv)
if not pkginfo:
return ""
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:
versions = {}
@ -314,11 +323,70 @@ def list_available(*names, **kwargs):
verlist = sorted(
list(pkginfo.keys()) if pkginfo else [],
key=cmp_to_key(_reverse_cmp_pkg_versions),
reverse=reverse_sort,
)
versions[name] = verlist
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):
"""
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:
'1.0.1':
full_name: 'My Software'
installer: 'C:\files\mysoftware.msi'
installer: 'C:\files\mysoftware101.msi'
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'
msiexec: True
reboot: False
@ -27,9 +44,47 @@ def pkg(modules):
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
repo_dir = state_tree / "winrepo_ng"
with pytest.helpers.temp_file("my-software.sls", pkg_def_contents, repo_dir):
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):
_PKG_TARGETS = ["figlet", "sl"]
if grains["os"] == "Windows":
_PKG_TARGETS = ["npp_x64", "winrar"]
_PKG_TARGETS = ["npp_x64", "putty"]
elif grains["os"] == "Amazon":
if grains["osfinger"] == "Amazon Linux-2023":
_PKG_TARGETS = ["lynx", "gnuplot-minimal"]
@ -225,6 +225,29 @@ def install_7zip(modules):
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_states("pkg.installed", "pkg.removed")
@pytest.mark.slow_test
@ -1126,3 +1149,14 @@ def test_pkg_removed_with_version_multiple(install_7zip, modules, states):
assert ret.result is True
current = modules.pkg.version("7zip")
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