From db17b5c869b174639b0c24e5413bc9b517950940 Mon Sep 17 00:00:00 2001 From: sgoral-splunk <138458044+sgoral-splunk@users.noreply.github.com> Date: Wed, 27 Nov 2024 13:47:31 +0100 Subject: [PATCH] fix: support Windows when checking library version (#1482) **Issue number:[ADDON-76665](https://splunk.atlassian.net/browse/ADDON-76665)** ### PR Type **What kind of change does this PR introduce?** * [ ] Feature * [x] Bug Fix * [ ] Refactoring (no functional or API changes) * [ ] Documentation Update * [ ] Maintenance (dependency updates, CI, etc.) ## Summary We were missing a command to fetch data from stdout (`pip show --version {lib}`) for windows. For unix we use "grep" and for windows "findstr". ### Changes Changed logic of `_pip_is_lib_installed` to also check library version using "findstr" if "grep" returns non 0 status. ### User experience Fixed an issue where Windows users were unable to build an add-on because of the error `SplunktaucclibNotFound` ## Checklist If an item doesn't apply to your changes, leave it unchecked. * [x] I have performed a self-review of this change according to the [development guidelines](https://splunk.github.io/addonfactory-ucc-generator/contributing/#development-guidelines) * [x] Tests have been added/modified to cover the changes [(testing doc)](https://splunk.github.io/addonfactory-ucc-generator/contributing/#build-and-test) * [ ] Changes are documented * [x] PR title and description follows the [contributing principles](https://splunk.github.io/addonfactory-ucc-generator/contributing/#pull-requests) --------- Co-authored-by: Artem Rys Co-authored-by: srv-rr-github-token <94607705+srv-rr-github-token@users.noreply.github.com> Co-authored-by: soleksy-splunk <143183665+soleksy-splunk@users.noreply.github.com> Co-authored-by: Viktor Tsvetkov <142901247+vtsvetkov-splunk@users.noreply.github.com> --- .../install_python_libraries.py | 28 ++++++++--------- tests/unit/test_install_python_libraries.py | 31 ++++++++++++++----- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/splunk_add_on_ucc_framework/install_python_libraries.py b/splunk_add_on_ucc_framework/install_python_libraries.py index d63130762..40ae0baea 100644 --- a/splunk_add_on_ucc_framework/install_python_libraries.py +++ b/splunk_add_on_ucc_framework/install_python_libraries.py @@ -95,13 +95,6 @@ def _pip_is_lib_installed( lib_installed_cmd = f"{installer} -m pip show --version {libname}" - if version and allow_higher_version: - cmd = f'{lib_installed_cmd} | grep "Version"' - elif version and not allow_higher_version: - cmd = f'{lib_installed_cmd} | grep "Version: {version}"' - else: - cmd = lib_installed_cmd - try: my_env = os.environ.copy() my_env["PYTHONPATH"] = target @@ -109,15 +102,20 @@ def _pip_is_lib_installed( # Disable writing of .pyc files (__pycache__) my_env["PYTHONDONTWRITEBYTECODE"] = "1" - if allow_higher_version: - result = _subprocess_run(command=cmd, env=my_env) - if result.returncode != 0: - return False - result_version = result.stdout.decode("utf-8").split("Version:")[1].strip() - return Version(result_version) >= Version(version) + result = _subprocess_run(command=lib_installed_cmd, env=my_env) + if result.returncode != 0 or "Version:" not in result.stdout.decode("utf-8"): + return False + + if version: + pip_show_result = result.stdout.decode("utf-8").splitlines() + result_row = next(el for el in pip_show_result if el.startswith("Version:")) + result_version = result_row.split("Version:")[1].strip() + if allow_higher_version: + return Version(result_version) >= Version(version) + return Version(result_version) == Version(version) else: - return_code = _subprocess_run(command=cmd, env=my_env).returncode - return return_code == 0 + return result.returncode == 0 + except OSError as e: raise CouldNotInstallRequirements from e diff --git a/tests/unit/test_install_python_libraries.py b/tests/unit/test_install_python_libraries.py index 12192831b..d6740fbf0 100644 --- a/tests/unit/test_install_python_libraries.py +++ b/tests/unit/test_install_python_libraries.py @@ -5,6 +5,7 @@ from unittest import mock import pytest + import tests.unit.helpers as helpers from splunk_add_on_ucc_framework.global_config import OSDependentLibraryConfig @@ -28,8 +29,9 @@ class MockSubprocessResult: - def __init__(self, returncode): + def __init__(self, returncode, stdout=b""): self.returncode = returncode + self.stdout = stdout @mock.patch("subprocess.run", autospec=True) @@ -281,8 +283,23 @@ def test_install_libraries_valid_os_libraries( "valid_config_with_os_libraries.json" ) global_config = gc.GlobalConfig(global_config_path) - - mock_subprocess_run.return_value = MockSubprocessResult(0) + mock_subprocess_run.side_effect = [ + MockSubprocessResult(0), # mock subprocess.run from _pip_install + MockSubprocessResult(0), # mock subprocess.run from _pip_install + MockSubprocessResult( + 0, b"Version: 41.0.5" + ), # mock subprocess.run from _pip_is_lib_installed + MockSubprocessResult(0), # mock subprocess.run from _pip_install + MockSubprocessResult( + 0, b"Version: 41.0.5" + ), # mock subprocess.run from _pip_is_lib_installed + MockSubprocessResult(0), # mock subprocess.run from _pip_install + MockSubprocessResult( + 0, b"Version: 1.5.1" + ), # mock subprocess.run from _pip_is_lib_installed + MockSubprocessResult(0), # mock subprocess.run from _pip_install + MockSubprocessResult(0), # mock subprocess.run from _pip_install + ] tmp_ucc_lib_target = tmp_path / "ucc-lib-target" tmp_lib_path = tmp_path / "lib" tmp_lib_path.mkdir() @@ -369,15 +386,13 @@ def test_install_libraries_version_mismatch( tmp_lib_reqs_file = tmp_lib_path / "requirements.txt" tmp_lib_reqs_file.write_text("splunktaucclib\n") - version_mismatch_shell_cmd = ( - 'python3 -m pip show --version cryptography | grep "Version: 41.0.5"' - ) + version_mismatch_shell_cmd = "python3 -m pip show --version cryptography" mock_subprocess_run.side_effect = ( lambda command, shell=True, env=None, capture_output=True: ( MockSubprocessResult(1) if command == version_mismatch_shell_cmd and ucc_lib_target == env["PYTHONPATH"] - else MockSubprocessResult(0) + else MockSubprocessResult(0, b"Version: 40.0.0") ) ) @@ -521,7 +536,7 @@ def run(command, env): assert command == "python3 -m pip show --version libname" assert env["PYTHONPATH"] == "target" assert env["PYTHONDONTWRITEBYTECODE"] == "1" - return Result(0, b"", b"") + return Result(0, b"Version: 1.0.0", b"") monkeypatch.setattr(install_python_libraries_module, "_subprocess_run", run) assert _pip_is_lib_installed("python3", "target", "libname")