Source code

Revision control

Copy as Markdown

Other Tools

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import errno
import logging
from compare_locales import mozpath
from .project import ProjectConfig
from .matcher import expand
import toml
class ConfigNotFound(EnvironmentError):
def __init__(self, path):
super().__init__(
errno.ENOENT,
'Configuration file not found',
path)
class ParseContext:
def __init__(self, path, env, ignore_missing_includes):
self.path = path
self.env = env
self.ignore_missing_includes = ignore_missing_includes
self.data = None
self.pc = ProjectConfig(path)
class TOMLParser:
def parse(self, path, env=None, ignore_missing_includes=False):
ctx = self.context(
path, env=env, ignore_missing_includes=ignore_missing_includes
)
self.load(ctx)
self.processBasePath(ctx)
self.processEnv(ctx)
self.processPaths(ctx)
self.processFilters(ctx)
self.processIncludes(ctx)
self.processExcludes(ctx)
self.processLocales(ctx)
return self.asConfig(ctx)
def context(self, path, env=None, ignore_missing_includes=False):
return ParseContext(
path,
env if env is not None else {},
ignore_missing_includes,
)
def load(self, ctx):
try:
with open(ctx.path, 'rt') as fin:
ctx.data = toml.load(fin)
except (toml.TomlDecodeError, OSError):
raise ConfigNotFound(ctx.path)
def processBasePath(self, ctx):
assert ctx.data is not None
ctx.pc.set_root(ctx.data.get('basepath', '.'))
def processEnv(self, ctx):
assert ctx.data is not None
ctx.pc.add_environment(**ctx.data.get('env', {}))
# add parser environment, possibly overwriting file variables
ctx.pc.add_environment(**ctx.env)
def processLocales(self, ctx):
assert ctx.data is not None
if 'locales' in ctx.data:
ctx.pc.set_locales(ctx.data['locales'])
def processPaths(self, ctx):
assert ctx.data is not None
for data in ctx.data.get('paths', []):
paths = {
"l10n": data['l10n']
}
if 'locales' in data:
paths['locales'] = data['locales']
if 'reference' in data:
paths['reference'] = data['reference']
if 'test' in data:
paths['test'] = data['test']
ctx.pc.add_paths(paths)
def processFilters(self, ctx):
assert ctx.data is not None
for data in ctx.data.get('filters', []):
paths = data['path']
if isinstance(paths, str):
paths = [paths]
rule = {
"path": paths,
"action": data['action']
}
if 'key' in data:
rule['key'] = data['key']
ctx.pc.add_rules(rule)
def processIncludes(self, ctx):
for child in self._processChild(ctx, 'includes'):
ctx.pc.add_child(child)
def processExcludes(self, ctx):
for child in self._processChild(ctx, 'excludes'):
ctx.pc.exclude(child)
def _processChild(self, ctx, field):
assert ctx.data is not None
if field not in ctx.data:
return
for child_config in ctx.data[field]:
# resolve child_config['path'] against our root and env
p = mozpath.normpath(
expand(
ctx.pc.root,
child_config['path'],
ctx.pc.environ
)
)
try:
child = self.parse(
p, env=ctx.env,
ignore_missing_includes=ctx.ignore_missing_includes
)
except ConfigNotFound as e:
if not ctx.ignore_missing_includes:
raise
(logging
.getLogger('compare-locales.io')
.error('%s: %s', e.strerror, e.filename))
continue
yield child
def asConfig(self, ctx):
return ctx.pc