envstack 0.5.3__tar.gz → 0.5.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. {envstack-0.5.3 → envstack-0.5.4}/PKG-INFO +5 -5
  2. {envstack-0.5.3 → envstack-0.5.4}/README.md +4 -4
  3. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack/__init__.py +1 -1
  4. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack/cli.py +4 -2
  5. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack/env.py +19 -5
  6. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack/wrapper.py +97 -15
  7. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack.egg-info/PKG-INFO +5 -5
  8. {envstack-0.5.3 → envstack-0.5.4}/setup.py +1 -1
  9. envstack-0.5.4/stack.env +34 -0
  10. envstack-0.5.3/stack.env +0 -29
  11. {envstack-0.5.3 → envstack-0.5.4}/LICENSE +0 -0
  12. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack/config.py +0 -0
  13. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack/exceptions.py +0 -0
  14. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack/logger.py +0 -0
  15. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack/path.py +0 -0
  16. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack.egg-info/SOURCES.txt +0 -0
  17. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack.egg-info/dependency_links.txt +0 -0
  18. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack.egg-info/entry_points.txt +0 -0
  19. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack.egg-info/not-zip-safe +0 -0
  20. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack.egg-info/requires.txt +0 -0
  21. {envstack-0.5.3 → envstack-0.5.4}/lib/envstack.egg-info/top_level.txt +0 -0
  22. {envstack-0.5.3 → envstack-0.5.4}/setup.cfg +0 -0
  23. {envstack-0.5.3 → envstack-0.5.4}/tests/test_env.py +0 -0
  24. {envstack-0.5.3 → envstack-0.5.4}/tests/test_path.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: envstack
3
- Version: 0.5.3
3
+ Version: 0.5.4
4
4
  Summary: Stacked environment variable management system.
5
5
  Home-page: http://github.com/rsgalloway/envstack
6
6
  Author: Ryan Galloway
@@ -172,8 +172,8 @@ To init the environment stack, use the `init` function:
172
172
  'bar'
173
173
  ```
174
174
 
175
- Alternatively, `envstack.getenv` uses the default environment stack `stack` and
176
- can be a drop-in replacement for `os.getenv`
175
+ Alternatively, `envstack.getenv` can be a drop-in replacement for `os.getenv`
176
+ for the default environment stack:
177
177
 
178
178
  ```python
179
179
  >>> import envstack
@@ -234,7 +234,7 @@ alias envstack-set='source <(envstack "$1" --export)';
234
234
 
235
235
  #### cmd
236
236
  ```cmd
237
- doskey envstack-set=for /f "usebackq" %%i in (`envstack --export $*`) do %%i
237
+ doskey envstack-set=for /f "usebackq" %i in (`envstack --export $*`) do %%i
238
238
  ```
239
239
 
240
240
  Then you can set the environment stack in your shell with the `envstack-set`
@@ -248,7 +248,7 @@ alias envstack-clear='source <(envstack "$1" --clear)';
248
248
 
249
249
  #### cmd
250
250
  ```cmd
251
- doskey envstack-clear=for /f "usebackq" %%i in (`envstack --clear $*`) do %%i
251
+ doskey envstack-clear=for /f "usebackq" %i in (`envstack --clear $*`) do %%i
252
252
  ```
253
253
 
254
254
  Create a function for convenience that does both in one command:
@@ -161,8 +161,8 @@ To init the environment stack, use the `init` function:
161
161
  'bar'
162
162
  ```
163
163
 
164
- Alternatively, `envstack.getenv` uses the default environment stack `stack` and
165
- can be a drop-in replacement for `os.getenv`
164
+ Alternatively, `envstack.getenv` can be a drop-in replacement for `os.getenv`
165
+ for the default environment stack:
166
166
 
167
167
  ```python
168
168
  >>> import envstack
@@ -223,7 +223,7 @@ alias envstack-set='source <(envstack "$1" --export)';
223
223
 
224
224
  #### cmd
225
225
  ```cmd
226
- doskey envstack-set=for /f "usebackq" %%i in (`envstack --export $*`) do %%i
226
+ doskey envstack-set=for /f "usebackq" %i in (`envstack --export $*`) do %%i
227
227
  ```
228
228
 
229
229
  Then you can set the environment stack in your shell with the `envstack-set`
@@ -237,7 +237,7 @@ alias envstack-clear='source <(envstack "$1" --clear)';
237
237
 
238
238
  #### cmd
239
239
  ```cmd
240
- doskey envstack-clear=for /f "usebackq" %%i in (`envstack --clear $*`) do %%i
240
+ doskey envstack-clear=for /f "usebackq" %i in (`envstack --clear $*`) do %%i
241
241
  ```
242
242
 
243
243
  Create a function for convenience that does both in one command:
@@ -34,7 +34,7 @@ Stacked environment variable management system.
34
34
  """
35
35
 
36
36
  __prog__ = "envstack"
37
- __version__ = "0.5.3"
37
+ __version__ = "0.5.4"
38
38
 
39
39
  from envstack.env import Env
40
40
  from envstack.env import getenv, init, load_file
@@ -143,9 +143,11 @@ def main():
143
143
  elif args.export:
144
144
  print(export(args.namespace, config.SHELL))
145
145
  elif command:
146
- return run_command(args.namespace, command)
146
+ return run_command(command, args.namespace)
147
147
  else:
148
- env = load_environ(args.namespace, platform=args.platform, includes=True)
148
+ env = load_environ(
149
+ args.namespace, environ=None, platform=args.platform, includes=True
150
+ )
149
151
  for k, v in env.items():
150
152
  print(f"{k}={v}")
151
153
 
@@ -179,7 +179,7 @@ class EnvVar(string.Template, str):
179
179
 
180
180
  def value(self):
181
181
  """Returns EnvVar value."""
182
- return safe_eval(self.template)
182
+ return re.sub(r"(?<!\b[A-Za-z]):", os.pathsep, safe_eval(self.template))
183
183
 
184
184
  def vars(self):
185
185
  """Returns a list of embedded, named variables, e.g.: ::
@@ -528,7 +528,7 @@ def export(name, shell="bash", resolve=False, scope=None, clear=False):
528
528
  for k, v in env.items():
529
529
  if resolve:
530
530
  v = expandvars(v, env, recursive=False)
531
- if shell == "bash" or shell == "sh":
531
+ if shell in ["bash", "sh", "zsh"]:
532
532
  if clear:
533
533
  expList.append(f"unset {k}")
534
534
  else:
@@ -548,6 +548,8 @@ def export(name, shell="bash", resolve=False, scope=None, clear=False):
548
548
  expList.append(f"Remove-Item Env:{k}")
549
549
  else:
550
550
  expList.append(f'$env:{k}="{v}"')
551
+ elif shell == "unknown":
552
+ raise Exception("unknown shell")
551
553
  expList.sort()
552
554
  exp = "\n".join(expList)
553
555
  return exp
@@ -643,7 +645,7 @@ def load_file(path):
643
645
  return data
644
646
 
645
647
 
646
- def merge(env, other):
648
+ def merge(env, other, strict=False):
647
649
  """Merges values from other into env. For example, to merge values from
648
650
  the local environment into an env instance:
649
651
 
@@ -655,12 +657,24 @@ def merge(env, other):
655
657
 
656
658
  :param env: source env
657
659
  :param other: env to merge
660
+ :param strict: env value takes precedence (default: False)
658
661
  :returns: merged env
659
662
  """
660
663
  merged = env.copy()
661
- for key in merged:
664
+ for key, value in merged.items():
665
+ var = "${%s}" % key
662
666
  if key in other:
663
- merged[key] = other.get(key)
667
+ if var in str(value):
668
+ value = re.sub(
669
+ r"\${(\w+)}",
670
+ lambda match: other.get(match.group(1), match.group(0)),
671
+ value,
672
+ )
673
+ elif not strict:
674
+ value = other.get(key)
675
+ else:
676
+ value = value.replace(var, "")
677
+ merged[key] = value
664
678
  return merged
665
679
 
666
680
 
@@ -37,13 +37,14 @@ import os
37
37
  import subprocess
38
38
  import traceback
39
39
 
40
+ from envstack import config
40
41
  from envstack import logger
41
42
  from envstack.env import encode, expandvars, load_environ
42
43
 
43
44
 
44
45
  def to_args(cmd):
45
- """Converts a command line string to an arg list to be passed to subprocess.Popen
46
- that preserves args with quotes."""
46
+ """Converts a command line string to an arg list to be passed to
47
+ subprocess.Popen that preserves args with quotes."""
47
48
 
48
49
  import shlex
49
50
 
@@ -81,6 +82,7 @@ class Wrapper(object):
81
82
  super(Wrapper, self).__init__()
82
83
  self.args = args
83
84
  self.name = namespace
85
+ self.shell = True
84
86
  self.log = logger.log
85
87
  self.env = load_environ(namespace)
86
88
 
@@ -91,19 +93,16 @@ class Wrapper(object):
91
93
  def launch(self):
92
94
  """Launches the wrapped tool in a subprocess with env."""
93
95
  exitcode = 0
94
-
95
- # get subprocess env, cmd and args
96
96
  env = self.get_subprocess_env()
97
97
  cmd = expandvars(self.executable(), env, recursive=True)
98
- args = " ".join(['"%s"' % arg for arg in to_args(cmd) + self.args])
98
+ args = self.get_subprocess_args(cmd)
99
99
 
100
- # run command in subprocess
101
100
  try:
102
101
  process = subprocess.Popen(
103
102
  args=args,
104
103
  bufsize=0,
105
104
  env=env,
106
- shell=True,
105
+ shell=self.shell,
107
106
  )
108
107
 
109
108
  except Exception:
@@ -119,6 +118,10 @@ class Wrapper(object):
119
118
 
120
119
  return exitcode
121
120
 
121
+ def get_subprocess_args(self, cmd):
122
+ """Returns the arguments to be passed to the subprocess."""
123
+ return self.args
124
+
122
125
  def get_subprocess_env(self):
123
126
  """
124
127
  Returns the environment that gets passed to the subprocess when launch()
@@ -132,30 +135,109 @@ class Wrapper(object):
132
135
  class CommandWrapper(Wrapper):
133
136
  """Wrapper class for running wrapped commands from the command-line."""
134
137
 
135
- def __init__(self, namespace, args=[]):
138
+ def __init__(self, namespace=config.DEFAULT_NAMESPACE, args=[]):
136
139
  """
137
- Initializes the command wrapper with the given namespace and args.
140
+ Initializes the command wrapper with the given namespace and args, e.g.:
138
141
 
139
- :param namespace: stack namespace
140
- :param args: command line arguments
142
+ >>> cmd = CommandWrapper('stack', ['ls', '-al'])
143
+ >>> print(cmd.executable())
144
+ ls
145
+ >>> print(cmd.args)
146
+ ['-al']
147
+
148
+ :param namespace: stack namespace (default: 'stack')
149
+ :param args: command and arguments as a list
141
150
  """
142
151
  super(CommandWrapper, self).__init__(namespace, args)
143
152
  self.log.debug("running command [stack: %s] %s", namespace, args)
144
153
  self.cmd = args[0]
145
154
  self.args = args[1:]
146
155
 
156
+ def get_subprocess_args(self, cmd):
157
+ """Returns the arguments to be passed to the subprocess."""
158
+ return " ".join(['"%s"' % arg for arg in to_args(cmd) + self.args])
159
+
160
+ def executable(self):
161
+ """Returns the command to run."""
162
+ return self.cmd
163
+
164
+
165
+ class ShellWrapper(CommandWrapper):
166
+ """Wrapper class for running wrapped commands in bash, sh, or zsh."""
167
+
168
+ def __init__(self, namespace=config.DEFAULT_NAMESPACE, args=[]):
169
+ """
170
+ Initializes the command wrapper with the given namespace and args,
171
+ replacing the original command with the shell command, e.g.:
172
+
173
+ >>> cmd = ShellWrapper('stack', ['ls', '-l'])
174
+ >>> print(cmd.executable())
175
+ bash
176
+ >>> print(cmd.args)
177
+ ['-i', '-c', 'ls -l']
178
+
179
+ :param namespace: stack namespace (default: 'stack')
180
+ :param args: command and arguments as a list
181
+ """
182
+ super(ShellWrapper, self).__init__(namespace, args)
183
+ self.args = ["-i", "-c", "%s" % " ".join([self.cmd] + self.args)]
184
+
147
185
  def executable(self):
186
+ """Returns the shell command to run the original command."""
187
+ self.cmd = config.SHELL
148
188
  return self.cmd
149
189
 
150
190
 
151
- def run_command(namespace, command):
191
+ class CmdWrapper(CommandWrapper):
192
+ """Wrapper class for running wrapped commands in command prompt."""
193
+
194
+ def __init__(self, namespace=config.DEFAULT_NAMESPACE, args=[]):
195
+ """
196
+ Initializes the command wrapper with the given namespace and args,
197
+ replacing the original command with the shell command, e.g.:
198
+
199
+ >>> cmd = CmdWrapper('stack', ['ls', '-l'])
200
+ >>> print(cmd.executable())
201
+ bash
202
+ >>> print(cmd.args)
203
+ ['-i', '-c', 'ls -l']
204
+
205
+ :param namespace: stack namespace (default: 'stack')
206
+ :param args: command and arguments as a list
207
+ """
208
+ super(CmdWrapper, self).__init__(namespace, args)
209
+ self.args = ["/c", "%s" % " ".join([self.cmd] + self.args)]
210
+ self.shell = False
211
+
212
+ def get_subprocess_args(self, cmd):
213
+ """Returns the arguments to be passed to the subprocess."""
214
+ return [cmd] + self.args
215
+
216
+ def executable(self):
217
+ """Returns the shell command to run the original command."""
218
+ self.cmd = config.SHELL
219
+ return self.cmd
220
+
221
+
222
+ def run_command(command, namespace=config.DEFAULT_NAMESPACE):
152
223
  """
153
224
  Runs a given command with the given stack namespace.
154
225
 
155
- :param namespace: stack namespace
156
- :param command: command to run as arg list
226
+ >>> run_command(['ls', '-l'])
227
+
228
+ Or to run in a specific stack namespace:
229
+
230
+ >>> run_command(['ls', '-l'], 'my-stack')
231
+
232
+ :param command: command to run as a list of arguments
233
+ :param namespace: environment stack namespace (default: 'stack')
157
234
  :returns: exit code
158
235
  """
159
236
  logger.setup_stream_handler()
160
- cmd = CommandWrapper(namespace, command)
237
+ if config.SHELL in ["bash", "sh", "zsh"]:
238
+ cmd = ShellWrapper(namespace, command)
239
+ elif config.SHELL in ["cmd"]:
240
+ cmd = CmdWrapper(namespace, command)
241
+ else:
242
+ cmd = CommandWrapper(namespace, command)
161
243
  return cmd.launch()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: envstack
3
- Version: 0.5.3
3
+ Version: 0.5.4
4
4
  Summary: Stacked environment variable management system.
5
5
  Home-page: http://github.com/rsgalloway/envstack
6
6
  Author: Ryan Galloway
@@ -172,8 +172,8 @@ To init the environment stack, use the `init` function:
172
172
  'bar'
173
173
  ```
174
174
 
175
- Alternatively, `envstack.getenv` uses the default environment stack `stack` and
176
- can be a drop-in replacement for `os.getenv`
175
+ Alternatively, `envstack.getenv` can be a drop-in replacement for `os.getenv`
176
+ for the default environment stack:
177
177
 
178
178
  ```python
179
179
  >>> import envstack
@@ -234,7 +234,7 @@ alias envstack-set='source <(envstack "$1" --export)';
234
234
 
235
235
  #### cmd
236
236
  ```cmd
237
- doskey envstack-set=for /f "usebackq" %%i in (`envstack --export $*`) do %%i
237
+ doskey envstack-set=for /f "usebackq" %i in (`envstack --export $*`) do %%i
238
238
  ```
239
239
 
240
240
  Then you can set the environment stack in your shell with the `envstack-set`
@@ -248,7 +248,7 @@ alias envstack-clear='source <(envstack "$1" --clear)';
248
248
 
249
249
  #### cmd
250
250
  ```cmd
251
- doskey envstack-clear=for /f "usebackq" %%i in (`envstack --clear $*`) do %%i
251
+ doskey envstack-clear=for /f "usebackq" %i in (`envstack --clear $*`) do %%i
252
252
  ```
253
253
 
254
254
  Create a function for convenience that does both in one command:
@@ -74,7 +74,7 @@ class PostInstallCommand(install):
74
74
 
75
75
  setup(
76
76
  name="envstack",
77
- version="0.5.3",
77
+ version="0.5.4",
78
78
  description="Stacked environment variable management system.",
79
79
  long_description=long_description,
80
80
  long_description_content_type="text/markdown",
@@ -0,0 +1,34 @@
1
+ # Stacked environment variable management system.
2
+ #
3
+ # Environment variables are declared in namespaced .env files using yaml syntax.
4
+ # The default stack declares env variables in stack.env files.
5
+ # Create any new stack by creating new .env files, e.g. to create a new stack
6
+ # called "thing", just create thing.env files in any given context.
7
+ #
8
+ # $ pip install envstack
9
+
10
+ all: &default
11
+ ENV: prod
12
+ HELLO: world
13
+ LOG_LEVEL: INFO
14
+ DEFAULT_ENV_DIR: ${DEPLOY_ROOT}/env
15
+ DEPLOY_ROOT: ${ROOT}/${ENV}
16
+ BIN: ${DEPLOY_ROOT}/bin
17
+ LIB: ${DEPLOY_ROOT}/lib/python
18
+ PATH: "${BIN}:${PATH}"
19
+ PYTHONPATH: "${LIB}:${PYTHONPATH}"
20
+
21
+ darwin:
22
+ <<: *default
23
+ ROOT: "${HOME}/Library/Application Support/envstack"
24
+ # ROOT: /Volumes/tools
25
+
26
+ linux:
27
+ <<: *default
28
+ ROOT: ${HOME}/.local/envstack
29
+ # ROOT: /mnt/tools
30
+
31
+ windows:
32
+ <<: *default
33
+ ROOT: C:/ProgramData/envstack
34
+ # ROOT: //server/tools
envstack-0.5.3/stack.env DELETED
@@ -1,29 +0,0 @@
1
- # stack.env is the default envstack file
2
- #
3
- # https://github.com/rsgalloway/envstack
4
-
5
- all: &default
6
- ENV: prod
7
- HELLO: world
8
- LOG_LEVEL: INFO
9
- DEFAULT_ENV_DIR: ${DEPLOY_ROOT}/env
10
- DEPLOY_ROOT: ${ROOT}/${ENV}
11
- # BIN: ${DEPLOY_ROOT}/bin
12
- # LIB: ${DEPLOY_ROOT}/lib/python
13
- # PATH: "${BIN}:${PATH}"
14
- # PYTHONPATH: "${LIB}/python:${PYTHONPATH}"
15
-
16
- darwin:
17
- <<: *default
18
- ROOT: "${HOME}/Library/Application Support/envstack"
19
- # ROOT: /Volumes/tools
20
-
21
- linux:
22
- <<: *default
23
- ROOT: ${HOME}/.local/envstack
24
- # ROOT: /mnt/tools
25
-
26
- windows:
27
- <<: *default
28
- ROOT: C:/ProgramData/envstack
29
- # ROOT: //server/tools
File without changes
File without changes
File without changes
File without changes
File without changes