mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 07:17:55 +03:00
add limited interpolation to eden config parsing
Summary: This allows us to templatize centrally managed config files Reviewed By: bolinfest Differential Revision: D4444058 fbshipit-source-id: a44372084d32dcf0b27922490ab40a48478a720d
This commit is contained in:
parent
bafc809c36
commit
dff225b60e
@ -14,10 +14,17 @@ python_library(
|
||||
name = 'lib',
|
||||
srcs = [
|
||||
'config.py',
|
||||
'configinterpolator.py',
|
||||
'util.py',
|
||||
],
|
||||
)
|
||||
|
||||
python_unittest(
|
||||
name = 'test',
|
||||
srcs = glob(['test/*.py']),
|
||||
deps = [':lib']
|
||||
)
|
||||
|
||||
for build_target, suffix in get_daemon_versions():
|
||||
# The :all rule is a convenience to ensure that both the CLI and the daemon
|
||||
# are built.
|
||||
|
@ -20,7 +20,7 @@ import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
from . import util
|
||||
from . import (util, configinterpolator)
|
||||
import eden.thrift
|
||||
import facebook.eden.ttypes as eden_ttypes
|
||||
from fb303.ttypes import fb_status
|
||||
@ -61,9 +61,18 @@ class Config:
|
||||
if not self._system_config_dir:
|
||||
self._system_config_dir = SYSTEM_CONFIG_DIR
|
||||
self._user_config_path = os.path.join(home_dir, USER_CONFIG)
|
||||
self._home_dir = home_dir
|
||||
|
||||
def _loadConfig(self):
|
||||
parser = configparser.ConfigParser()
|
||||
''' to facilitate templatizing a centrally deployed config, we
|
||||
allow a limited set of env vars to be expanded.
|
||||
${HOME} will be replaced by the user's home dir,
|
||||
${USER} will be replaced by the user's login name.
|
||||
'''
|
||||
defaults = {'USER': os.environ.get('USER'),
|
||||
'HOME': self._home_dir}
|
||||
parser = configparser.ConfigParser(
|
||||
interpolation=configinterpolator.EdenConfigInterpolator(defaults))
|
||||
parser.read(self.get_rc_files())
|
||||
return parser
|
||||
|
||||
|
45
eden/fs/cli/configinterpolator.py
Normal file
45
eden/fs/cli/configinterpolator.py
Normal file
@ -0,0 +1,45 @@
|
||||
# Copyright (c) 2017-present, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the BSD-style license found in the
|
||||
# LICENSE file in the root directory of this source tree. An additional grant
|
||||
# of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import configparser
|
||||
|
||||
|
||||
class EdenConfigInterpolator(configparser.Interpolation):
|
||||
''' Python provides a couple of interpolation options but neither
|
||||
of them quite match the simplicity that we want. This class
|
||||
will interpolate the keys of the provided map and replace
|
||||
those tokens with the values from the map. There is no
|
||||
recursion or referencing of values from other sections of
|
||||
the config.
|
||||
Limiting the scope interpolation makes it easier to replicate
|
||||
this approach in the C++ implementation of the parser.
|
||||
'''
|
||||
|
||||
def __init__(self, defaults):
|
||||
self._defaults = {}
|
||||
''' pre-construct the token name that we're going to substitute.
|
||||
eg: {"foo": "bar"} is stored as {"${foo}": "bar"} internally
|
||||
'''
|
||||
for k, v in defaults.items():
|
||||
self._defaults['${' + k + '}'] = v
|
||||
|
||||
def _interpolate(self, value):
|
||||
''' simple brute force replacement using the defaults that were
|
||||
provided to us during construction '''
|
||||
for k, v in self._defaults.items():
|
||||
value = value.replace(k, v)
|
||||
return value
|
||||
|
||||
def before_get(self, parser, section, option, value, defaults):
|
||||
return self._interpolate(value)
|
||||
|
||||
def before_read(self, parser, section, option, value):
|
||||
return self._interpolate(value)
|
42
eden/fs/cli/test/interp_test.py
Normal file
42
eden/fs/cli/test/interp_test.py
Normal file
@ -0,0 +1,42 @@
|
||||
# Copyright (c) 2017-present, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the BSD-style license found in the
|
||||
# LICENSE file in the root directory of this source tree. An additional grant
|
||||
# of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from .. import configinterpolator
|
||||
import configparser
|
||||
import unittest
|
||||
|
||||
|
||||
class InterpolatorTest(unittest.TestCase):
|
||||
def test_basic_subs(self):
|
||||
defaults = {'USER': 'wez', 'RECURSIVE': 'a${RECURSIVE}b'}
|
||||
parser = configparser.ConfigParser(
|
||||
interpolation=configinterpolator.EdenConfigInterpolator(defaults))
|
||||
parser.add_section('section')
|
||||
parser.set('section', 'user', '${USER}')
|
||||
parser.set('section', 'rec', '${RECURSIVE}')
|
||||
parser.set('section', 'simple', 'value')
|
||||
|
||||
self.assertEqual('wez', parser.get('section', 'user'))
|
||||
self.assertEqual('value', parser.get('section', 'simple'))
|
||||
self.assertEqual('a${RECURSIVE}b', parser.get('section', 'rec'))
|
||||
|
||||
actual = {}
|
||||
for section in parser.sections():
|
||||
actual[section] = dict(parser.items(section))
|
||||
|
||||
expect = {
|
||||
'section': {
|
||||
'user': 'wez',
|
||||
'simple': 'value',
|
||||
'rec': 'a${RECURSIVE}b',
|
||||
}
|
||||
}
|
||||
self.assertEqual(expect, actual)
|
Loading…
Reference in New Issue
Block a user