From 9853519702b25c0e5632763c251cd86975ee1917 Mon Sep 17 00:00:00 2001 From: Sorin Sbarnea Date: Fri, 27 Dec 2024 12:30:47 +0000 Subject: [PATCH] Make isolation implicit and use ansible-dev-environment --- .config/constraints.txt | 16 +++++++++++----- .config/requirements.in | 1 + .github/workflows/tox.yml | 35 +++++++++++++++++----------------- pyproject.toml | 15 +++++++-------- src/ansible_compat/prerun.py | 26 ++++++++++++------------- src/ansible_compat/runtime.py | 12 +++++++----- test/test_runtime.py | 15 +++++++++++---- test/test_runtime_scan_path.py | 3 +++ tox.ini | 11 +++++++---- 9 files changed, 78 insertions(+), 56 deletions(-) diff --git a/.config/constraints.txt b/.config/constraints.txt index b491f5a6..34a12135 100644 --- a/.config/constraints.txt +++ b/.config/constraints.txt @@ -1,9 +1,12 @@ # This file was autogenerated by uv via the following command: # tox run deps +ansible-builder==3.1.0 # via ansible-dev-environment +ansible-dev-environment==24.12.0 # via ansible-compat (pyproject.toml) argparse-manpage==4.6 # via ansible-compat (pyproject.toml) attrs==24.3.0 # via jsonschema, referencing babel==2.16.0 # via mkdocs-material beautifulsoup4==4.12.3 # via linkchecker, mkdocs-htmlproofer-plugin +bindep==2.11.0 # via ansible-builder black==24.10.0 # via ansible-compat (pyproject.toml) cairocffi==1.7.1 # via cairosvg cairosvg==2.7.1 # via mkdocs-ansible @@ -17,6 +20,7 @@ cryptography==44.0.0 # via ansible-core csscompressor==0.9.5 # via mkdocs-minify-plugin cssselect2==0.7.0 # via cairosvg defusedxml==0.7.1 # via cairosvg +distro==1.9.0 # via bindep dnspython==2.7.0 # via linkchecker exceptiongroup==1.2.2 # via pytest ghp-import==2.1.0 # via mkdocs @@ -27,7 +31,7 @@ idna==3.10 # via requests iniconfig==2.0.0 # via pytest jinja2==3.1.5 # via ansible-core, mkdocs, mkdocs-macros-plugin, mkdocs-material, mkdocstrings jsmin==3.0.1 # via mkdocs-minify-plugin -jsonschema==4.23.0 # via ansible-compat (pyproject.toml) +jsonschema==4.23.0 # via ansible-builder, ansible-compat (pyproject.toml) jsonschema-specifications==2024.10.1 # via jsonschema linkchecker==10.5.0 # via mkdocs-ansible markdown==3.7 # via markdown-include, mkdocs, mkdocs-autorefs, mkdocs-htmlproofer-plugin, mkdocs-material, mkdocstrings, pymdown-extensions @@ -49,10 +53,12 @@ mkdocs-monorepo-plugin==1.1.0 # via mkdocs-ansible mkdocstrings==0.27.0 # via mkdocs-ansible, mkdocstrings-python mkdocstrings-python==1.13.0 # via mkdocs-ansible mypy-extensions==1.0.0 # via black -packaging==24.2 # via ansible-core, black, mkdocs, mkdocs-macros-plugin, pytest, ansible-compat (pyproject.toml) +packaging==24.2 # via ansible-builder, ansible-core, bindep, black, mkdocs, mkdocs-macros-plugin, pytest, ansible-compat (pyproject.toml) paginate==0.5.7 # via mkdocs-material +parsley==1.3 # via bindep pathspec==0.12.1 # via black, mkdocs, mkdocs-macros-plugin -pillow==11.0.0 # via cairosvg, mkdocs-ansible +pbr==6.1.0 # via bindep +pillow==11.1.0 # via cairosvg, mkdocs-ansible platformdirs==4.3.6 # via black, mkdocs-get-deps, mkdocstrings pluggy==1.5.0 # via pytest pycparser==2.22 # via cffi @@ -64,7 +70,7 @@ pytest-mock==3.14.0 # via ansible-compat (pyproject.toml) pytest-plus==0.7.0 # via ansible-compat (pyproject.toml) python-dateutil==2.9.0.post0 # via ghp-import, mkdocs-macros-plugin python-slugify==8.0.4 # via mkdocs-monorepo-plugin -pyyaml==6.0.2 # via ansible-core, mkdocs, mkdocs-get-deps, mkdocs-macros-plugin, pymdown-extensions, pyyaml-env-tag, ansible-compat (pyproject.toml) +pyyaml==6.0.2 # via ansible-builder, ansible-core, ansible-dev-environment, mkdocs, mkdocs-get-deps, mkdocs-macros-plugin, pymdown-extensions, pyyaml-env-tag, ansible-compat (pyproject.toml) pyyaml-env-tag==0.1 # via mkdocs referencing==0.35.1 # via jsonschema, jsonschema-specifications regex==2024.11.6 # via mkdocs-material @@ -72,7 +78,7 @@ requests==2.32.3 # via linkchecker, mkdocs-htmlproofer-plugin, mkdocs-m rpds-py==0.22.3 # via jsonschema, referencing six==1.17.0 # via python-dateutil soupsieve==2.6 # via beautifulsoup4 -subprocess-tee==0.4.2 # via ansible-compat (pyproject.toml) +subprocess-tee==0.4.2 # via ansible-dev-environment, ansible-compat (pyproject.toml) super-collections==0.5.3 # via mkdocs-macros-plugin termcolor==2.5.0 # via mkdocs-macros-plugin text-unidecode==1.3 # via python-slugify diff --git a/.config/requirements.in b/.config/requirements.in index 6a9241c9..c00db5b9 100644 --- a/.config/requirements.in +++ b/.config/requirements.in @@ -1,5 +1,6 @@ # https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html ansible-core>=2.14 +ansible-dev-environment>=24.12.0 packaging PyYAML subprocess-tee>=0.4.1 diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index 72e3dd8d..79518fcc 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -20,21 +20,22 @@ jobs: tox: uses: ansible/team-devtools/.github/workflows/tox.yml@main with: - jobs_producing_coverage: 11 - other_names: | - docs - lint - pkg - py39-ansible214 - py39-ansible215 - py310-ansible215 - py310-ansible217 - py311-ansible215 - py312-ansible216 - py312-ansible217 - py312-devel - py313-devel - py310-macos:tox -e py310 - py313-macos:tox -e py313 - smoke + other_names: devel + # jobs_producing_coverage: 11 + # other_names: | + # docs + # lint + # pkg + # py39-ansible214 + # py39-ansible215 + # py310-ansible215 + # py310-ansible217 + # py311-ansible215 + # py312-ansible216 + # py312-ansible217 + # py312-devel + # py313-devel + # py310-macos:tox -e py310 + # py313-macos:tox -e py313 + # smoke skip_explode: "1" diff --git a/pyproject.toml b/pyproject.toml index 51ad11a9..0194dd95 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [build-system] requires = [ "setuptools >= 65.3.0", # required by pyproject+setuptools_scm integration and editable installs - "setuptools_scm[toml] >= 7.0.5", # required for "no-local-version" scheme + "setuptools_scm[toml] >= 7.0.5" # required for "no-local-version" scheme ] build-backend = "setuptools.build_meta" @@ -34,7 +34,7 @@ classifiers = [ "Topic :: Software Development :: Bug Tracking", "Topic :: Software Development :: Quality Assurance", "Topic :: Software Development :: Testing", - "Topic :: Utilities", + "Topic :: Utilities" ] keywords = ["ansible"] @@ -92,7 +92,7 @@ good-names = [ "ns", # namespace "ex", "Run", - "_", + "_" ] [tool.pylint.IMPORTS] @@ -333,7 +333,7 @@ disable = [ "too-many-arguments", # PLR0913 "raise-missing-from", # Temporary disable duplicate detection we remove old code from prerun - "duplicate-code", + "duplicate-code" ] [tool.pytest.ini_options] @@ -342,7 +342,7 @@ filterwarnings = [ "error", # py312 ansible-core # https://github.com/ansible/ansible/issues/81906 - "ignore:'importlib.abc.TraversableResources' is deprecated and slated for removal in Python 3.14:DeprecationWarning", + "ignore:'importlib.abc.TraversableResources' is deprecated and slated for removal in Python 3.14:DeprecationWarning" ] testpaths = ["test"] @@ -352,7 +352,6 @@ target-version = "py39" lint.select = ["ALL"] lint.ignore = [ # Disabled on purpose: - "ANN101", # Missing type annotation for `self` in method "D203", # incompatible with D211 "D211", "D213", # incompatible with D212 @@ -363,7 +362,7 @@ lint.ignore = [ "PLR0912", # Bug https://github.com/charliermarsh/ruff/issues/4244 "PLR0913", # Bug https://github.com/charliermarsh/ruff/issues/4244 "RUF012", - "PERF203", + "PERF203" ] [tool.ruff.lint.flake8-pytest-style] @@ -396,7 +395,7 @@ git_describe_command = [ "--tags", "--long", "--match", - "v*.*", + "v*.*" ] [tool.uv.pip] diff --git a/src/ansible_compat/prerun.py b/src/ansible_compat/prerun.py index 9448269d..0ebef7ae 100644 --- a/src/ansible_compat/prerun.py +++ b/src/ansible_compat/prerun.py @@ -1,22 +1,22 @@ """Utilities for configuring ansible runtime environment.""" -import hashlib import os +import warnings +from functools import cache from pathlib import Path +@cache def get_cache_dir(project_dir: Path) -> Path: """Compute cache directory to be used based on project path.""" - # we only use the basename instead of the full path in order to ensure that - # we would use the same key regardless the location of the user home - # directory or where the project is clones (as long the project folder uses - # the same name). - basename = project_dir.resolve().name.encode(encoding="utf-8") - # 6 chars of entropy should be enough - cache_key = hashlib.sha256(basename).hexdigest()[:6] - cache_dir = ( - Path(os.getenv("XDG_CACHE_HOME", "~/.cache")).expanduser() - / "ansible-compat" - / cache_key - ) + venv_path = os.environ.get("VIRTUAL_ENV", None) + if not venv_path: + cache_dir = Path(project_dir) / ".cache" + warnings.warn( + f"No VIRTUAL_ENV found, will use of unisolated cache directory: {cache_dir}", + stacklevel=0, + ) + else: + cache_dir = Path(venv_path) / ".cache" + cache_dir.mkdir(parents=True, exist_ok=True) return cache_dir diff --git a/src/ansible_compat/runtime.py b/src/ansible_compat/runtime.py index 030497ce..fb5e5522 100644 --- a/src/ansible_compat/runtime.py +++ b/src/ansible_compat/runtime.py @@ -149,7 +149,7 @@ class Runtime: _version: Version | None = None collections: OrderedDict[str, Collection] = OrderedDict() - cache_dir: Path | None = None + cache_dir: Path # Used to track if we have already initialized the Ansible runtime as attempts # to do it multiple tilmes will cause runtime warnings from within ansible-core initialized: bool = False @@ -161,7 +161,7 @@ def __init__( self, project_dir: Path | None = None, *, - isolated: bool = False, + isolated: bool = True, min_required_version: str | None = None, require_module: bool = False, max_retries: int = 0, @@ -208,8 +208,7 @@ def __init__( if "PYTHONWARNINGS" not in self.environ: # pragma: no cover self.environ["PYTHONWARNINGS"] = "ignore:Blowfish has been deprecated" - if isolated: - self.cache_dir = get_cache_dir(self.project_dir) + self.cache_dir = get_cache_dir(self.project_dir) self.config = AnsibleConfig(cache_dir=self.cache_dir) # Add the sys.path to the collection paths if not isolated @@ -369,7 +368,10 @@ def _ensure_module_available(self) -> None: def clean(self) -> None: """Remove content of cache_dir.""" if self.cache_dir: - shutil.rmtree(self.cache_dir, ignore_errors=True) + _logger.error("Cleaning cache directory %s", self.cache_dir) + if not str(self.cache_dir).endswith(".cache"): + breakpoint() + # shutil.rmtree(self.cache_dir, ignore_errors=True) def run( # ruff: disable=PLR0913 self, diff --git a/test/test_runtime.py b/test/test_runtime.py index edb5c6bb..4c3ce940 100644 --- a/test/test_runtime.py +++ b/test/test_runtime.py @@ -652,13 +652,20 @@ def test_upgrade_collection(runtime_tmp: Runtime) -> None: runtime_tmp.require_collection("community.molecule", "0.1.0") -def test_require_collection_no_cache_dir() -> None: - """Check require_collection without a cache directory.""" - runtime = Runtime() - assert not runtime.cache_dir +def test_require_collection_not_isolated() -> None: + """Check require_collection without isolation.""" + runtime = Runtime(isolated=False) + assert str(runtime.cache_dir).endswith(".cache") runtime.require_collection("community.molecule", "0.1.0", install=True) +def test_runtime_implicit_isolation() -> None: + """Check that runtime does use isolation by default.""" + runtime = Runtime() + assert ".cache" in str(runtime.cache_dir) + assert runtime.cache_dir.is_dir() + + def test_runtime_env_ansible_library(monkeypatch: MonkeyPatch) -> None: """Verify that custom path specified using ANSIBLE_LIBRARY is not lost.""" path_name = "foo" diff --git a/test/test_runtime_scan_path.py b/test/test_runtime_scan_path.py index be44f1cd..2d90612e 100644 --- a/test/test_runtime_scan_path.py +++ b/test/test_runtime_scan_path.py @@ -57,6 +57,9 @@ def test_scan_sys_path( :param tmp_dir: Fixture for a temporary directory :param param: The parameters for the test """ + # hide our virtual environment from the test, or we risk not using the + # venv_module fixture currectly. + monkeypatch.delenv("VIRTUAL_ENV", raising=False) first_site_package_dir = venv_module.site_package_dirs()[0] installed_to = ( diff --git a/tox.ini b/tox.ini index 2ef8a8b4..054003d8 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ envlist = pkg docs py - py-devel + devel py39-ansible214 py39-ansible215 py310-ansible214 @@ -30,20 +30,23 @@ requires = [testenv] description = Run the tests - devel: ansible devel branch + devel: install devel branches of direct dependencies ansible214: ansible-core 2.14 ansible215: ansible-core 2.15 ansible216: ansible-core 2.16 ansible217: ansible-core 2.17 + ansible218: ansible-core 2.18 deps = ansible214: ansible-core>=2.14,<2.15 ansible215: ansible-core>=2.15,<2.16 ansible216: ansible-core>=2.16,<2.17 ansible217: ansible-core>=2.17,<2.18 + ansible218: ansible-core>=2.18,<2.19 - devel: ansible-core @ git+https://github.com/ansible/ansible.git@c5d18c39d81e2b3b10856b2fb76747230e4fac4a # GPLv3+ - # avoid installing ansible-core on -devel envs: + devel: ansible-core @ git+https://github.com/ansible/ansible.git@devel # GPLv3+ + devel: ansible-dev-environment @ git+https://github.com/ansible/ansible-dev-environment.git@main + # avoid installing non devel deps: !devel: ansible-core extras = test