Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
cli.py237 linesDownload Raw Back to dotenv
1import json2import os3import shlex4import sys5from contextlib import contextmanager6from typing import IO, Any, Dict, Iterator, List, Optional7 8if sys.platform == "win32":9    from subprocess import Popen10 11try:12    import click13except ImportError:14    sys.stderr.write(15        "It seems python-dotenv is not installed with cli option. \n"16        'Run pip install "python-dotenv[cli]" to fix this.'17    )18    sys.exit(1)19 20from .main import dotenv_values, set_key, unset_key21from .version import __version__22 23 24def enumerate_env() -> Optional[str]:25    """26    Return a path for the ${pwd}/.env file.27 28    If pwd does not exist, return None.29    """30    try:31        cwd = os.getcwd()32    except FileNotFoundError:33        return None34    path = os.path.join(cwd, ".env")35    return path36 37 38@click.group()39@click.option(40    "-f",41    "--file",42    default=enumerate_env(),43    type=click.Path(file_okay=True),44    help="Location of the .env file, defaults to .env file in current working directory.",45)46@click.option(47    "-q",48    "--quote",49    default="always",50    type=click.Choice(["always", "never", "auto"]),51    help="Whether to quote or not the variable values. Default mode is always. This does not affect parsing.",52)53@click.option(54    "-e",55    "--export",56    default=False,57    type=click.BOOL,58    help="Whether to write the dot file as an executable bash script.",59)60@click.version_option(version=__version__)61@click.pass_context62def cli(ctx: click.Context, file: Any, quote: Any, export: Any) -> None:63    """This script is used to set, get or unset values from a .env file."""64    ctx.obj = {"QUOTE": quote, "EXPORT": export, "FILE": file}65 66 67@contextmanager68def stream_file(path: os.PathLike) -> Iterator[IO[str]]:69    """70    Open a file and yield the corresponding (decoded) stream.71 72    Exits with error code 2 if the file cannot be opened.73    """74 75    try:76        with open(path) as stream:77            yield stream78    except OSError as exc:79        print(f"Error opening env file: {exc}", file=sys.stderr)80        sys.exit(2)81 82 83@cli.command(name="list")84@click.pass_context85@click.option(86    "--format",87    "output_format",88    default="simple",89    type=click.Choice(["simple", "json", "shell", "export"]),90    help="The format in which to display the list. Default format is simple, "91    "which displays name=value without quotes.",92)93def list_values(ctx: click.Context, output_format: str) -> None:94    """Display all the stored key/value."""95    file = ctx.obj["FILE"]96 97    with stream_file(file) as stream:98        values = dotenv_values(stream=stream)99 100    if output_format == "json":101        click.echo(json.dumps(values, indent=2, sort_keys=True))102    else:103        prefix = "export " if output_format == "export" else ""104        for k in sorted(values):105            v = values[k]106            if v is not None:107                if output_format in ("export", "shell"):108                    v = shlex.quote(v)109                click.echo(f"{prefix}{k}={v}")110 111 112@cli.command(name="set")113@click.pass_context114@click.argument("key", required=True)115@click.argument("value", required=True)116def set_value(ctx: click.Context, key: Any, value: Any) -> None:117    """118    Store the given key/value.119 120    This doesn't follow symlinks, to avoid accidentally modifying a file at a121    potentially untrusted path.122    """123 124    file = ctx.obj["FILE"]125    quote = ctx.obj["QUOTE"]126    export = ctx.obj["EXPORT"]127    success, key, value = set_key(file, key, value, quote, export)128    if success:129        click.echo(f"{key}={value}")130    else:131        sys.exit(1)132 133 134@cli.command()135@click.pass_context136@click.argument("key", required=True)137def get(ctx: click.Context, key: Any) -> None:138    """Retrieve the value for the given key."""139    file = ctx.obj["FILE"]140 141    with stream_file(file) as stream:142        values = dotenv_values(stream=stream)143 144    stored_value = values.get(key)145    if stored_value:146        click.echo(stored_value)147    else:148        sys.exit(1)149 150 151@cli.command()152@click.pass_context153@click.argument("key", required=True)154def unset(ctx: click.Context, key: Any) -> None:155    """156    Removes the given key.157 158    This doesn't follow symlinks, to avoid accidentally modifying a file at a159    potentially untrusted path.160    """161    file = ctx.obj["FILE"]162    quote = ctx.obj["QUOTE"]163    success, key = unset_key(file, key, quote)164    if success:165        click.echo(f"Successfully removed {key}")166    else:167        sys.exit(1)168 169 170@cli.command(171    context_settings={172        "allow_extra_args": True,173        "allow_interspersed_args": False,174        "ignore_unknown_options": True,175    }176)177@click.pass_context178@click.option(179    "--override/--no-override",180    default=True,181    help="Override variables from the environment file with those from the .env file.",182)183@click.argument("commandline", nargs=-1, type=click.UNPROCESSED)184def run(ctx: click.Context, override: bool, commandline: tuple[str, ...]) -> None:185    """Run command with environment variables present."""186    file = ctx.obj["FILE"]187    if not os.path.isfile(file):188        raise click.BadParameter(189            f"Invalid value for '-f' \"{file}\" does not exist.", ctx=ctx190        )191    dotenv_as_dict = {192        k: v193        for (k, v) in dotenv_values(file).items()194        if v is not None and (override or k not in os.environ)195    }196 197    if not commandline:198        click.echo("No command given.")199        sys.exit(1)200 201    run_command([*commandline, *ctx.args], dotenv_as_dict)202 203 204def run_command(command: List[str], env: Dict[str, str]) -> None:205    """Replace the current process with the specified command.206 207    Replaces the current process with the specified command and the variables from `env`208    added in the current environment variables.209 210    Parameters211    ----------212    command: List[str]213        The command and it's parameters214    env: Dict215        The additional environment variables216 217    Returns218    -------219    None220        This function does not return any value. It replaces the current process with the new one.221 222    """223    # copy the current environment variables and add the vales from224    # `env`225    cmd_env = os.environ.copy()226    cmd_env.update(env)227 228    if sys.platform == "win32":229        # execvpe on Windows returns control immediately230        # rather than once the command has finished.231        p = Popen(command, universal_newlines=True, bufsize=0, shell=False, env=cmd_env)232        _, _ = p.communicate()233 234        sys.exit(p.returncode)235    else:236        os.execvpe(command[0], args=command, env=cmd_env)237 
codekingpro/portable-devtools · Team Ai