Skip to content

Commit

Permalink
Return absolute path without resolving symlinks (#4341)
Browse files Browse the repository at this point in the history
After the rewrite of `util.abs_path` to use `pathlib` instead of
`os.path` (000d200,
c20dc08) the function now resolves
symlinks in the given path whereas it did not do before.
This breaks setups where the `molecule.yml` file in a scenario is a
symlink. E.g.

/common-files/molecule.yml
/roles/role1/molecule/default/molecule.yml -> /common-files/molecule.yml
/roles/role1/molecule/some-scenario/molecule.yml ->
/common-files/molecule.yml
/roles/role2/molecule/default/molecule.yml -> /common-files/molecule.yml

Where a common `molecule.yml` can be used for multiple roles / scenarios
and where changes to this file should reflect everywhere.

In this case `molecule test` executed in `/roles/role1` returns
`Scenario 'default' not found. Exiting.` or `molecule test -s
some-scenario` executed in `/roles/role1` returns `Scenario
'some-scenario' not found. Exiting.` (see
https://github.com/ansible/molecule/blob/f58ac30d5cee79a073ce0893701c8e82ec669078/src/molecule/scenarios.py#L127)

Unfortunately `pathlib` is not a drop-in replacement for `os.path` (see
https://docs.python.org/3/library/pathlib.html#comparison-to-the-os-and-os-path-modules).


[Path.absolute()](https://docs.python.org/3/library/pathlib.html#pathlib.Path.absolute)
does not resolve symlink but does not reduce `/../` segments in the
path.
[Path.resolve()](https://docs.python.org/3/library/pathlib.html#pathlib.Path.resolve)
does reduce `/../` path elements, but also resolves symlinks.

There is no method or combination of methods in the `Path` object that
can deliver the same functionality as
[os.path.abspath()](https://docs.python.org/3/library/os.path.html#os.path.abspath).
Hence the code reverts back to using `os.path.abspath()`, but keeps
accepting `Path` objects as input and returns the absolute path as such
in these cases.

---------

Signed-off-by: Ruediger Pluem <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Kate Case <[email protected]>
  • Loading branch information
3 people authored Dec 12, 2024
1 parent 2ab3c64 commit 9026471
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 4 deletions.
8 changes: 4 additions & 4 deletions src/molecule/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ def abs_path(path: str | Path | None) -> str | Path:
"""Return absolute path.
Args:
path: File path to resolve absolute path from.
path: File path to create absolute path from.
Returns:
Absolute path of path.
Expand All @@ -411,9 +411,9 @@ def abs_path(path: str | Path | None) -> str | Path:
return ""

output_type = type(path)
if isinstance(path, str):
path = Path(path)
path = path.resolve()
if isinstance(path, Path):
path = str(path)
path = os.path.abspath(path) # noqa: PTH100

return output_type(path)

Expand Down
12 changes: 12 additions & 0 deletions tests/unit/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import binascii
import os
import tempfile
import warnings

from pathlib import Path
Expand Down Expand Up @@ -340,6 +341,17 @@ def test_abs_path_with_empty_path() -> None:
assert util.abs_path("") == ""


def test_abs_path_with_symlink() -> None:
"""Test the `abs_path` function not resolving symlinks."""
with tempfile.NamedTemporaryFile() as tmp_file:
tmpfile_path = Path(tmp_file.name)
symlink_path = Path(tmp_file.name + "_sym")
symlink_path.symlink_to(tmpfile_path)
abs_path_result = util.abs_path(symlink_path)
symlink_path.unlink()
assert abs_path_result == symlink_path


@pytest.mark.parametrize(
("a", "b", "x"),
[ # noqa: PT007
Expand Down

0 comments on commit 9026471

Please sign in to comment.