def setup(self): if self._setup: return self._setup = True # path self.setup_path() # new configuration data = {} # runtime yml_path = os.path.join(self.data['path'], '.rock.yml') if yml_path and os.path.isfile(yml_path): data = self.parse(yml_path) if not isinstance(data, dict): raise ConfigError('.rock.yml syntax error') data.update(self.data) else: data = copy.deepcopy(self.data) # project for name in ('path', 'runtime'): if name not in data: raise ConfigError('%s is required' % name) # paths runtime = self.runtime(data['runtime']) etc_path = self.etc_path('runtime') runtime_yml = data['runtime'] + '.yml' data_path = self.data_path('runtime', runtime_yml) if not os.path.exists(data_path): file_name = data['runtime'].rstrip('0123456789') + '.yml' data_path = self.data_path('runtime', file_name) # ensure runtime exists if not os.path.isdir(runtime.path()): raise ConfigError("runtime path doesn't exist") # parse configs runtime_config = self.parse(runtime.path('rock.yml')) rock_config = self.parse(data_path, require_exists=False) etc_config = self.parse(os.path.join(etc_path, runtime_yml), require_exists=False) # merge self.data = { 'env': { 'ROCK_ENV': self.env, 'ROCK_PATH': data['path'], 'ROCK_RUNTIME': data['runtime'], }, } # merge runtime self.merge(runtime_config, self.data) # merge runtime config self.merge(rock_config, self.data) self.merge(etc_config, self.data) # merge project self.merge(data, self.data)
def parse(path, require_exists=True, require_parses=True): """ Parse and return configuration file. """ if not os.path.isfile(path): if require_exists: raise ConfigError('not found: ' + path) return try: with open(path) as f: return yaml.safe_load(f) except Exception as error: if require_parses: raise ConfigError('parse error: ' + path)
def merge_env(self, src, dst, env=None): """ Merge environment variables. """ env = 'env_%s' % env if env else 'env' if env in src: if not isinstance(src[env], dict): raise ConfigError('%s must be an associative array' % env) # evaluate env variables for name, value in src[env].items(): if not isstr(value): if isinstance(value, (int, float)): src[env][name] = str(value) else: raise ConfigError('%s.%s must be a string' % (env, name)) dst['env'][name] = string.Template( src[env][name]).safe_substitute(**dst['env']) del src[env]
def merge(self, src, dst): if src is None: return dst # merge global environment variables self.merge_env(src, dst) # merge env-specific environment variables self.merge_env(src, dst, self.env) # merge sections for name in list(src.keys()): if name not in dst: if isstr(src[name]): src[name] = PARENT_RE.sub('', src[name]) elif isinstance(src[name], dict): for subname in src[name]: value = src[name][subname] if isstr(value): src[name][subname] = PARENT_RE.sub('', value) dst[name] = src[name] elif isstr(src[name]): if not isstr(dst[name]): raise ConfigError('unable to merge "%s" into "str"' % type(dst[name]).__name__) dst[name] = PARENT_RE.sub(raw(dst[name]), src[name]) elif isinstance(src[name], dict): dst_is_dict = isinstance(dst[name], dict) for subname in src[name]: if isstr(dst[name]): src[name][subname] = PARENT_RE.sub(raw(dst[name]), src[name][subname]) elif dst_is_dict: if subname in dst[name]: src[name][subname] = PARENT_RE.sub( raw(dst[name][subname]), src[name][subname], ) del dst[name][subname] else: src[name][subname] = PARENT_RE.sub( '', src[name][subname], ) if dst_is_dict: src[name].update(dst[name]) dst[name] = src[name] del src[name] dst.update(src)
def evaluate(data): changed = False for _ in range(5): changed = False for n1, v1 in data.items(): if not isstr(v1): continue n = re.escape(n1) r = re.compile(r'\{\{\s*' + n + r'\s*\}\}', re.MULTILINE) for n2, v2 in data.items(): if not isstr(v2): continue data[n2] = r.sub(raw(data[n1]), data[n2]).rstrip('\n') changed |= v2 != data[n2] if not changed: break if changed: raise ConfigError('.rock.yml circular reference')
def run(self): if not isexecutable(ROCK_SHELL[0]): raise ConfigError('invalid ROCK_SHELL: %s' % ROCK_SHELL) os.execl(*(ROCK_SHELL + [self.stdin.getvalue()]))
def check(): if section not in self.config: raise ConfigError('section not found: %s' % section) if not isstr(self.config[section]): raise ConfigError('section must be a string: %s' % section)