diff --git a/src/dotenv/cli.py b/src/dotenv/cli.py index 65ead461..2d69ae6e 100644 --- a/src/dotenv/cli.py +++ b/src/dotenv/cli.py @@ -1,10 +1,11 @@ import json import os import shlex +import shutil import sys from contextlib import contextmanager from subprocess import Popen -from typing import Any, Dict, IO, Iterator, List +from typing import Any, Dict, IO, Iterator, Tuple try: import click @@ -32,7 +33,7 @@ def enumerate_env(): @click.group() -@click.option('-f', '--file', default=enumerate_env(), +@click.option('-f', '--file', default=enumerate_env, type=click.Path(file_okay=True), help="Location of the .env file, defaults to .env file in current working directory.") @click.option('-q', '--quote', default='always', @@ -144,7 +145,7 @@ def unset(ctx: click.Context, key: Any) -> None: help="Override variables from the environment file with those from the .env file.", ) @click.argument('commandline', nargs=-1, type=click.UNPROCESSED) -def run(ctx: click.Context, override: bool, commandline: List[str]) -> None: +def run(ctx: click.Context, override: bool, commandline: Tuple[str, ...]) -> None: """Run command with environment variables present.""" file = ctx.obj['FILE'] if not os.path.isfile(file): @@ -165,7 +166,7 @@ def run(ctx: click.Context, override: bool, commandline: List[str]) -> None: exit(ret) -def run_command(command: List[str], env: Dict[str, str]) -> int: +def run_command(command: Tuple[str, ...], env: Dict[str, str]) -> int: """Run command in sub process. Runs the command in a sub process with the variables from `env` @@ -189,6 +190,11 @@ def run_command(command: List[str], env: Dict[str, str]) -> int: cmd_env = os.environ.copy() cmd_env.update(env) + # Resolve path in a consistent way + app = shutil.which(command[0]) + if app is not None: + command = (app,) + command[1:] + p = Popen(command, universal_newlines=True, bufsize=0, diff --git a/tests/test_cli.py b/tests/test_cli.py index fc309b48..b43ce2a1 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -208,18 +208,27 @@ def test_run_with_other_env(dotenv_path): assert result == "b\n" -def test_run_without_cmd(cli): +def test_run_without_env(cli): result = cli.invoke(dotenv_cli, ['run']) assert result.exit_code == 2 assert "Invalid value for '-f'" in result.output +def test_run_without_cmd(cli): + Path(".env").write_text("") + result = cli.invoke(dotenv_cli, ['run']) + + assert result.exit_code == 1 + assert "No command given" in result.output + + def test_run_with_invalid_cmd(cli): + Path(".env").write_text("") result = cli.invoke(dotenv_cli, ['run', 'i_do_not_exist']) - assert result.exit_code == 2 - assert "Invalid value for '-f'" in result.output + assert result.exit_code == 1 + assert isinstance(result.exception, FileNotFoundError) def test_run_with_version(cli):