Files

54 lines
1.8 KiB
Python

#!/usr/bin/env python3
"""Run a command with one or more Docker-style env files.
Values are parsed literally rather than sourced by a shell. Tokens containing
`$`, `#`, spaces or shell metacharacters therefore remain unchanged.
"""
from __future__ import annotations
import os
import pathlib
import sys
def load_env(path: pathlib.Path) -> None:
if not path.is_file():
raise SystemExit(f"secret environment file is missing: {path}")
for raw in path.read_text(encoding="utf-8").splitlines():
line = raw.strip()
if not line or line.startswith("#"):
continue
if line.startswith("export "):
line = line[7:].lstrip()
if "=" not in line:
raise SystemExit(f"invalid environment line in {path}: {raw!r}")
key, value = line.split("=", 1)
key = key.strip()
if not key or not key.replace("_", "A").isalnum() or key[0].isdigit():
raise SystemExit(f"invalid environment variable in {path}: {key!r}")
value = value.strip()
if len(value) >= 2 and value[0] == value[-1] and value[0] in "\"'":
value = value[1:-1]
os.environ[key] = value
def main() -> None:
if len(sys.argv) < 3:
raise SystemExit("usage: run-with-env ENV_FILE [ENV_FILE ...] -- COMMAND [ARG ...]")
try:
separator = sys.argv.index("--")
except ValueError as exc:
raise SystemExit("missing -- before command") from exc
env_files = [pathlib.Path(item) for item in sys.argv[1:separator]]
command = sys.argv[separator + 1 :]
if not env_files or not command:
raise SystemExit("at least one env file and a command are required")
for env_file in env_files:
load_env(env_file)
os.execvp(command[0], command)
if __name__ == "__main__":
main()