From 7f06bbc3769ce67fe9d3ab5160e0135dc634a842 Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Tue, 22 Dec 2020 11:54:48 -0500 Subject: Add support for --no-export options. This is intended for use in shell rc files, where variables need to be set for the current shell but not exported. --- README.md | 6 ++++++ envdir/cli.py | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3296195..f5f4439 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,12 @@ I've replaced all of that with a single line: eval "$(envdir-helper)" +This program also supports setting non-exported shell variables, using the +`--no-export` flag. This is useful for prompts and other shell configuration +that should not be propagated through to subshells and other programs. This behaviour is the default if the env directory's name ends in `rc`: + + eval "$(envdir-helper .envdir.rc)" + ## Security As alluded to above, one of the use cases for this is env-specific tokens. These diff --git a/envdir/cli.py b/envdir/cli.py index 3eea246..9a06baf 100644 --- a/envdir/cli.py +++ b/envdir/cli.py @@ -10,12 +10,17 @@ 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=pathlib.Path.home() / ".envdir", + default=str(pathlib.Path.home() / ".envdir"), metavar="DIR", ) -def main(context, envdir): +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 @@ -40,12 +45,30 @@ def main(context, envdir): 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 env_script(name, content): +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 @@ -56,6 +79,14 @@ def env_script(name, 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. -- cgit v1.2.3