summaryrefslogtreecommitdiff
path: root/envdir/cli.py
diff options
context:
space:
mode:
Diffstat (limited to 'envdir/cli.py')
-rw-r--r--envdir/cli.py145
1 files changed, 0 insertions, 145 deletions
diff --git a/envdir/cli.py b/envdir/cli.py
deleted file mode 100644
index 9a06baf..0000000
--- a/envdir/cli.py
+++ /dev/null
@@ -1,145 +0,0 @@
-import click
-import os
-import os.path as op
-import pathlib
-import shlex
-import stat
-import subprocess as sp
-
-
-@click.command()
-@click.pass_context
-@click.version_option()
-@click.option(
- "--export/--no-export",
- default=None,
- help="Export generated environment variables [default: --export]",
-)
-@click.argument(
- "envdir",
- default=str(pathlib.Path.home() / ".envdir"),
- metavar="DIR",
-)
-def main(context, export, envdir):
- r"""Load environment variables from DIR (or ~/.envdir).
-
- For each non-directory entry in DIR, this will output a brief shell script
- to set an environment with the same name. If the entry is an executable
- program, it will be run (with the current environment) and its output will
- be used as the value of the environment variable. Otherwise, it will be
- read, and its content will be used. In either case, a single trailing
- newline will be removed, if present.
-
- This process skips any file which can't be run or read, as appropriate, and
- outputs a warning on stderr.
-
- The intended use case for this is in shell profiles, in the form:
-
- eval "$(envdir-helper)"
-
- The generated output is compatible with sh, and thus with bash and zsh.
- """
-
- def warn_on_skipped(path, reason):
- """Log any skipped paths to stderr."""
- stderr = click.get_text_stream("stderr")
- click.echo(f"{context.info_name}: skipping {path}: {reason}", file=stderr)
-
- if export is None:
- env_script = detect_env_script(
- envdir, rc=no_export_env_script, default=export_env_script
- )
- elif export:
- env_script = export_env_script
- else:
- env_script = no_export_env_script
-
- for name, content in walk_entries(envdir, on_skipped=warn_on_skipped):
- script = env_script(name, content)
- click.echo(script)
-
-
-def detect_env_script(path, rc, default): # pylint: disable=invalid-name
- """Detect which of two values to use based on whether `path` ends with
- `"rc"`. If it does, returns `rc`; otherwise, returns `default`.
- """
- if path.endswith("rc"):
- return rc
- return default
-
-
-def export_env_script(name, content):
- """Given a name and contents, generate a shell script that will set and
- export the corresponding environment variable, with that content."""
- # use sh-friendly syntax here: don't assume `export` can have assignment
- # side effects, so don't use `export FOO=BAR`. `FOO=BAR; export FOO` is
- # portable to all posix shells.
- qname = shlex.quote(name)
- qcontent = shlex.quote(content)
- return f"{qname}={qcontent}; export {qname}"
-
-
-def no_export_env_script(name, content):
- """Given a name and contents, generate a shell script that will set and NOT
- export the corresponding environment variable, with that content."""
- qname = shlex.quote(name)
- qcontent = shlex.quote(content)
- return f"{qname}={qcontent}"
-
-
-def walk_entries(envdir, on_skipped):
- """Yields a name, value pair for each environment file in envdir.
-
- The path for any skipped items (generally, failing or unrunnable programs,
- or unreadable files) will be passed to the `on_skipped` callback, along with
- the exception that caused it to be skipped.
- """
- for name in sorted(os.listdir(envdir)):
- path = op.join(envdir, name)
- try:
- path_stat = os.stat(path)
- if directory(path_stat):
- continue
-
- if executable(path_stat):
- content = from_program(path)
- else:
- content = from_file(path)
- except Exception as reason: # pylint: disable=broad-except
- on_skipped(path, reason)
- continue
- if content.endswith("\n"):
- content = content[:-1]
- yield name, content
-
-
-def directory(item):
- """True iff item is a stat_result representing a directory."""
- return stat.S_ISDIR(item.st_mode)
-
-
-def executable(item):
- """True iff item is a stat_result representing something executable.
-
- This doesn't distinguish between dirs and files; both are considered
- executable if any +x bit is set.
- """
- mode = stat.S_IMODE(item.st_mode)
- mask = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
- return mode & mask != 0
-
-
-def from_program(path):
- """Reads a program's complete stdout into a string."""
- result = sp.run(
- [path],
- check=True,
- stdout=sp.PIPE,
- )
- return result.stdout.decode("UTF-8")
-
-
-def from_file(path):
- """Reads a file's complete content into a string."""
- with open(path, "r") as file:
- return file.read()