Skip to content

Commit

Permalink
Allow use without virtualenv activation
Browse files Browse the repository at this point in the history
Fixes: #1507
  • Loading branch information
ssbarnea committed Feb 11, 2022
1 parent 17e7fa9 commit af4da26
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 0 deletions.
25 changes: 25 additions & 0 deletions src/ansiblelint/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import logging
import os
import pathlib
import shutil
import subprocess
import sys
from contextlib import contextmanager
Expand Down Expand Up @@ -138,6 +139,9 @@ def _do_list(rules: "RulesCollection") -> int:

def main(argv: Optional[List[str]] = None) -> int:
"""Linter CLI entry point."""
# alter PATH if needed (venv support)
path_inject()

if argv is None:
argv = sys.argv
initialize_options(argv[1:])
Expand Down Expand Up @@ -250,5 +254,26 @@ def _run_cli_entrypoint() -> None:
raise SystemExit(str(e))


def path_inject() -> None:
"""Add python interpreter path to top of PATH to fix outside venv calling."""
# This make it possible to call ansible-lint that was installed inside a
# virtualenv without having to pre-activate it. Otherwise subprocess will
# either fail to find ansible executables or call the wrong ones.
#
# This must be run before we do run any subprocesses, and loading config
# does this as part of the ansible detection.
paths = [x for x in os.environ.get("PATH", "").split(os.pathsep) if x]
ansible_path = shutil.which("ansible")
if ansible_path:
ansible_path = os.path.dirname(ansible_path)
py_path = os.path.dirname(sys.executable)
# Determine if we need to manipulate PATH
if ansible_path not in paths or py_path != ansible_path: # pragma: no cover
# tested by test_call_from_outside_venv but coverage cannot detect it
paths.insert(0, py_path)
os.environ["PATH"] = os.pathsep.join(paths)
print(f"WARNING: PATH altered to include {py_path}", file=sys.stderr)


if __name__ == "__main__":
_run_cli_entrypoint()
33 changes: 33 additions & 0 deletions test/test_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Tests related to ansiblelint.__main__ module."""
import os
import subprocess
import sys
from pathlib import Path

import pytest


@pytest.mark.parametrize(
("expected_warning"),
(False, True),
ids=("normal", "isolated"),
)
def test_call_from_outside_venv(expected_warning: bool) -> None:
"""Asserts ability to be called w/ or w/o venv activation."""
env = None
if expected_warning:
env = {"HOME": Path.home()}
py_path = os.path.dirname(sys.executable)
# Passing custom env prevents the process from inheriting PATH or other
# environment variables from the current process, so we emulate being
# called from outside the venv.
proc = subprocess.run(
[f"{py_path}/ansible-lint", "--version"],
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True,
env=env,
)
warning_found = "PATH altered to include" in proc.stderr
assert warning_found is expected_warning

0 comments on commit af4da26

Please sign in to comment.