pw_env_setup: Dump actions to json
Dump environment variable operations to JSON for easy parsing by tools
that can't grab their environment from the shell, like certain IDEs.
Change-Id: I3bf58564473d1d022286a1c6690bc74d30bf63c1
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/21460
Reviewed-by: Michael Spang <spang@google.com>
Commit-Queue: Rob Mohr <mohrr@google.com>
diff --git a/bootstrap.sh b/bootstrap.sh
index 6d00895..8321bf3 100644
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -84,7 +84,7 @@
if [ "$(basename "$_BOOTSTRAP_PATH")" = "bootstrap.sh" ] || \
[ ! -f "$SETUP_SH" ] || \
[ ! -s "$SETUP_SH" ]; then
- pw_bootstrap --shell-file "$SETUP_SH" --install-dir "$_PW_ACTUAL_ENVIRONMENT_ROOT" --use-pigweed-defaults
+ pw_bootstrap --shell-file "$SETUP_SH" --install-dir "$_PW_ACTUAL_ENVIRONMENT_ROOT" --use-pigweed-defaults --json-file "$_PW_ACTUAL_ENVIRONMENT_ROOT/actions.json"
pw_finalize bootstrap "$SETUP_SH"
else
pw_activate
diff --git a/pw_env_setup/py/pw_env_setup/env_setup.py b/pw_env_setup/py/pw_env_setup/env_setup.py
index a642f29..b213249 100755
--- a/pw_env_setup/py/pw_env_setup/env_setup.py
+++ b/pw_env_setup/py/pw_env_setup/env_setup.py
@@ -174,7 +174,7 @@
def __init__(self, pw_root, cipd_cache_dir, shell_file, quiet, install_dir,
use_pigweed_defaults, cipd_package_file,
virtualenv_requirements, virtualenv_setup_py_root,
- cargo_package_file, enable_cargo, *args, **kwargs):
+ cargo_package_file, enable_cargo, json_file, *args, **kwargs):
super(EnvSetup, self).__init__(*args, **kwargs)
self._env = environment.Environment()
self._pw_root = pw_root
@@ -198,6 +198,8 @@
self._cargo_package_file = []
self._enable_cargo = enable_cargo
+ self._json_file = json_file
+
setup_root = os.path.join(pw_root, 'pw_env_setup', 'py',
'pw_env_setup')
@@ -337,6 +339,9 @@
outs.write(
json.dumps(config, indent=4, separators=(',', ': ')) + '\n')
+ with open(os.path.join(self._json_file), 'w') as outs:
+ self._env.json(outs)
+
return 0
def cipd(self):
@@ -510,6 +515,12 @@
action='store_true',
)
+ parser.add_argument(
+ '--json-file',
+ help='Dump environment variable operations to a JSON file.',
+ default=None,
+ )
+
args = parser.parse_args(argv)
one_required = (
diff --git a/pw_env_setup/py/pw_env_setup/environment.py b/pw_env_setup/py/pw_env_setup/environment.py
index 57b3fca..efe523b 100644
--- a/pw_env_setup/py/pw_env_setup/environment.py
+++ b/pw_env_setup/py/pw_env_setup/environment.py
@@ -14,6 +14,7 @@
"""Stores the environment changes necessary for Pigweed."""
import contextlib
+import json
import os
import re
@@ -49,6 +50,9 @@
def unapply(self, env, orig_env): # pylint: disable=no-self-use
del env, orig_env # Only used in _VariableAction and subclasses.
+ def json(self, data): # pylint: disable=no-self-use
+ del data # Unused.
+
class _VariableAction(_Action):
# pylint: disable=redefined-builtin,too-few-public-methods
@@ -121,6 +125,9 @@
def apply(self, env):
env[self.name] = self.value
+ def json(self, data):
+ data['set'][self.name] = self.value
+
class Clear(_VariableAction):
"""Remove a variable from the environment."""
@@ -140,6 +147,14 @@
if self.name in env:
del env[self.name]
+ def json(self, data):
+ data['set'][self.name] = None
+
+
+def _initialize_path_like_variable(data, name):
+ default = {'append': [], 'prepend': [], 'remove': []}
+ data['modify'].setdefault(name, default)
+
class Remove(_VariableAction):
"""Remove a value from a PATH-like variable."""
@@ -179,6 +194,14 @@
env[self.name] = env[self.name].replace(
'{}{}'.format(self._pathsep, self.value), '')
+ def json(self, data):
+ _initialize_path_like_variable(data, self.name)
+ data['modify'][self.name]['remove'].append(self.value)
+ if self.value in data['modify'][self.name]['append']:
+ data['modify'][self.name]['append'].remove(self.value)
+ if self.value in data['modify'][self.name]['prepend']:
+ data['modify'][self.name]['prepend'].remove(self.value)
+
class BadVariableValue(ValueError):
pass
@@ -216,6 +239,12 @@
super(Prepend, self)._check()
_append_prepend_check(self)
+ def json(self, data):
+ _initialize_path_like_variable(data, self.name)
+ data['modify'][self.name]['prepend'].append(self.value)
+ if self.value in data['modify'][self.name]['remove']:
+ data['modify'][self.name]['remove'].remove(self.value)
+
class Append(_VariableAction):
"""Append a value to a PATH-like variable. (Uncommon, see Prepend.)"""
@@ -244,6 +273,12 @@
super(Append, self)._check()
_append_prepend_check(self)
+ def json(self, data):
+ _initialize_path_like_variable(data, self.name)
+ data['modify'][self.name]['append'].append(self.value)
+ if self.value in data['modify'][self.name]['remove']:
+ data['modify'][self.name]['remove'].remove(self.value)
+
class BadEchoValue(ValueError):
pass
@@ -495,6 +530,18 @@
if self._windows:
outs.write(':{}\n'.format(_SCRIPT_END_LABEL))
+ def json(self, outs):
+ data = {
+ 'modify': {},
+ 'set': {},
+ }
+
+ for action in self._actions:
+ action.json(data)
+
+ json.dump(data, outs, indent=4, separators=(',', ': '))
+ outs.write('\n')
+
@contextlib.contextmanager
def __call__(self, export=True):
"""Set environment as if this was written to a file and sourced.