浏览代码

Fix escaped environment variable in configuration (#546).

Reviewed-on: https://projects.torsion.org/borgmatic-collective/borgmatic/pulls/549
Dan Helfman 3 年之前
父节点
当前提交
c664c6b17b
共有 2 个文件被更改,包括 23 次插入3 次删除
  1. 7 3
      borgmatic/config/environment.py
  2. 16 0
      tests/unit/config/test_environment.py

+ 7 - 3
borgmatic/config/environment.py

@@ -1,7 +1,7 @@
 import os
 import os
 import re
 import re
 
 
-_VARIABLE_PATTERN = re.compile(r'(?<!\\)\$\{(?P<name>[A-Za-z0-9_]+)((:?-)(?P<default>[^}]+))?\}')
+_VARIABLE_PATTERN = re.compile(r'(?P<escape>\\)?(?P<variable>\$\{(?P<name>[A-Za-z0-9_]+)((:?-)(?P<default>[^}]+))?\})')
 
 
 
 
 def _resolve_string(matcher):
 def _resolve_string(matcher):
@@ -9,10 +9,14 @@ def _resolve_string(matcher):
     Get the value from environment given a matcher containing a name and an optional default value.
     Get the value from environment given a matcher containing a name and an optional default value.
     If the variable is not defined in environment and no default value is provided, an Error is raised.
     If the variable is not defined in environment and no default value is provided, an Error is raised.
     '''
     '''
-    name, default = matcher.group("name"), matcher.group("default")
+    if matcher.group('escape') is not None:
+        # in case of escaped envvar, unescape it
+        return matcher.group('variable')
+    # resolve the env var
+    name, default = matcher.group('name'), matcher.group('default')
     out = os.getenv(name, default=default)
     out = os.getenv(name, default=default)
     if out is None:
     if out is None:
-        raise ValueError("Cannot find variable ${name} in environment".format(name=name))
+        raise ValueError('Cannot find variable ${name} in environment'.format(name=name))
     return out
     return out
 
 
 
 

+ 16 - 0
tests/unit/config/test_environment.py

@@ -16,6 +16,20 @@ def test_env_braces(monkeypatch):
     module.resolve_env_variables(config)
     module.resolve_env_variables(config)
     assert config == {'key': 'Hello foo'}
     assert config == {'key': 'Hello foo'}
 
 
+def test_env_multi(monkeypatch):
+    monkeypatch.setenv('MY_CUSTOM_VALUE', 'foo')
+    monkeypatch.setenv('MY_CUSTOM_VALUE2', 'bar')
+    config = {'key': 'Hello ${MY_CUSTOM_VALUE}${MY_CUSTOM_VALUE2}'}
+    module.resolve_env_variables(config)
+    assert config == {'key': 'Hello foobar'}
+
+def test_env_escape(monkeypatch):
+    monkeypatch.setenv('MY_CUSTOM_VALUE', 'foo')
+    monkeypatch.setenv('MY_CUSTOM_VALUE2', 'bar')
+    config = {'key': r'Hello ${MY_CUSTOM_VALUE} \${MY_CUSTOM_VALUE}'}
+    module.resolve_env_variables(config)
+    assert config == {'key': r'Hello foo ${MY_CUSTOM_VALUE}'}
+
 
 
 def test_env_default_value(monkeypatch):
 def test_env_default_value(monkeypatch):
     monkeypatch.delenv('MY_CUSTOM_VALUE', raising=False)
     monkeypatch.delenv('MY_CUSTOM_VALUE', raising=False)
@@ -41,6 +55,7 @@ def test_env_full(monkeypatch):
             'anotherdict': {
             'anotherdict': {
                 'key': 'My ${MY_CUSTOM_VALUE} here',
                 'key': 'My ${MY_CUSTOM_VALUE} here',
                 'other': '${MY_CUSTOM_VALUE}',
                 'other': '${MY_CUSTOM_VALUE}',
+                'escaped': r'\${MY_CUSTOM_VALUE}',
                 'list': [
                 'list': [
                     '/home/${MY_CUSTOM_VALUE}/.local',
                     '/home/${MY_CUSTOM_VALUE}/.local',
                     '/var/log/',
                     '/var/log/',
@@ -62,6 +77,7 @@ def test_env_full(monkeypatch):
             'anotherdict': {
             'anotherdict': {
                 'key': 'My foo here',
                 'key': 'My foo here',
                 'other': 'foo',
                 'other': 'foo',
+                'escaped': '${MY_CUSTOM_VALUE}',
                 'list': ['/home/foo/.local', '/var/log/', '/home/bar/.config'],
                 'list': ['/home/foo/.local', '/var/log/', '/home/bar/.config'],
             },
             },
         },
         },