Skip to content

Commit

Permalink
Ensure that cache directory is writable
Browse files Browse the repository at this point in the history
  • Loading branch information
ssbarnea committed Jan 28, 2025
1 parent 83c5cfb commit 8af9cdc
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 7 deletions.
35 changes: 29 additions & 6 deletions src/ansible_compat/prerun.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""Utilities for configuring ansible runtime environment."""

import hashlib
import os
import tempfile
from pathlib import Path


Expand All @@ -13,17 +15,38 @@ def get_cache_dir(project_dir: Path, *, isolated: bool = True) -> Path:
Returns:
Cache directory path.
Raises:
RuntimeError: if cache directory is not writable.
"""
cache_dir = Path(os.environ.get("ANSIBLE_HOME", "~/.ansible")).expanduser()

if "VIRTUAL_ENV" in os.environ:
cache_dir = Path(os.environ["VIRTUAL_ENV"]) / ".ansible"
path = Path(os.environ["VIRTUAL_ENV"])
if not path.exists():
msg = f"VIRTUAL_ENV={os.environ['VIRTUAL_ENV']} does not exist."
raise RuntimeError(msg)

Check warning on line 28 in src/ansible_compat/prerun.py

View check run for this annotation

Codecov / codecov/patch

src/ansible_compat/prerun.py#L27-L28

Added lines #L27 - L28 were not covered by tests
cache_dir = path.resolve() / ".ansible"
elif isolated:
cache_dir = project_dir / ".ansible"
else:
cache_dir = Path(os.environ.get("ANSIBLE_HOME", "~/.ansible")).expanduser()
if not project_dir.exists() or not os.access(project_dir, os.W_OK):
# As "project_dir" can also be "/" and user might not be able
# to write to it, we use a temporary directory as fallback.
checksum = hashlib.sha256(
project_dir.as_posix().encode("utf-8"),
).hexdigest()[:4]

cache_dir = Path(tempfile.gettempdir()) / f".ansible-{checksum}"
cache_dir.mkdir(parents=True, exist_ok=True)
else:
cache_dir = project_dir.resolve() / ".ansible"

# Ensure basic folder structure exists so `ansible-galaxy list` does not
# fail with: None of the provided paths were usable. Please specify a valid path with
for name in ("roles", "collections"): # pragma: no cover
(cache_dir / name).mkdir(parents=True, exist_ok=True)
try:
for name in ("roles", "collections"): # pragma: no cover
(cache_dir / name).mkdir(parents=True, exist_ok=True)
except OSError as exc:
msg = "Failed to create cache directory."
raise RuntimeError(msg) from exc

Check warning on line 50 in src/ansible_compat/prerun.py

View check run for this annotation

Codecov / codecov/patch

src/ansible_compat/prerun.py#L48-L50

Added lines #L48 - L50 were not covered by tests

return cache_dir
16 changes: 15 additions & 1 deletion test/test_prerun.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

import tempfile
from pathlib import Path
from typing import TYPE_CHECKING

Expand Down Expand Up @@ -37,4 +38,17 @@ def test_get_cache_dir_isolation_no_venv(monkeypatch: MonkeyPatch) -> None:
"""
monkeypatch.delenv("VIRTUAL_ENV", raising=False)
monkeypatch.delenv("ANSIBLE_HOME", raising=False)
assert get_cache_dir(Path(), isolated=True) == Path() / ".ansible"
cache_dir = get_cache_dir(Path(), isolated=True)
assert cache_dir == Path().cwd() / ".ansible"


def test_get_cache_dir_isolation_no_venv_root(monkeypatch: MonkeyPatch) -> None:
"""Test behaviors of get_cache_dir.
Args:
monkeypatch: Pytest fixture for monkeypatching
"""
monkeypatch.delenv("VIRTUAL_ENV", raising=False)
monkeypatch.delenv("ANSIBLE_HOME", raising=False)
cache_dir = get_cache_dir(Path("/"), isolated=True)
assert cache_dir.as_posix().startswith(tempfile.gettempdir())

0 comments on commit 8af9cdc

Please sign in to comment.