diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 13aaebb0..49323357 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -361,6 +361,26 @@ def regsub_file(pattern, repl, path): f.write(text) +def config_type_check(path, data): + if Path(path).name == 'mirrors.yml': + expected_type = list + else: + expected_type = dict + if expected_type == dict: + if not isinstance(data, dict): + msg = _('{path} is not "key: value" dict, but a {datatype}!') + raise TypeError(msg.format(path=path, datatype=type(data).__name__)) + elif not isinstance(data, expected_type): + msg = _('{path} is not {expected_type}, but a {datatype}!') + raise TypeError( + msg.format( + path=path, + expected_type=expected_type.__name__, + datatype=type(data).__name__, + ) + ) + + def read_config(opts=None): """Read the repository config. @@ -401,11 +421,7 @@ def read_config(opts=None): config = yaml.safe_load(fp) if not config: config = {} - if not isinstance(config, dict): - msg = _('{path} is not "key: value" dict, but a {datatype}!') - raise TypeError( - msg.format(path=config_file, datatype=type(config).__name__) - ) + config_type_check(config_file, config) elif os.path.exists(old_config_file): logging.warning(_("""{oldfile} is deprecated, use {newfile}""") .format(oldfile=old_config_file, newfile=config_file)) diff --git a/fdroidserver/lint.py b/fdroidserver/lint.py index 0fb97d9c..04b03b25 100644 --- a/fdroidserver/lint.py +++ b/fdroidserver/lint.py @@ -20,6 +20,7 @@ from argparse import ArgumentParser import re import sys import platform +import ruamel.yaml import urllib.parse from pathlib import Path @@ -739,6 +740,21 @@ def check_certificate_pinned_binaries(app): return +def lint_config(arg): + path = Path(arg) + passed = True + yamllintresult = common.run_yamllint(path) + if yamllintresult: + print(yamllintresult) + passed = False + + with path.open() as fp: + data = ruamel.yaml.YAML(typ='safe').load(fp) + common.config_type_check(arg, data) + + return passed + + def main(): global config, options @@ -777,6 +793,33 @@ def main(): yamllint # make pyflakes ignore this + paths = list() + for arg in options.appid: + if ( + arg == 'config.yml' + or Path(arg).parent.name == 'config' + or Path(arg).parent.parent.name == 'config' # localized + ): + paths.append(arg) + + failed = 0 + if paths: + for path in paths: + options.appid.remove(path) + if not lint_config(path): + failed += 1 + # an empty list of appids means check all apps, avoid that if files were given + if not options.appid: + sys.exit(failed) + + if not lint_metadata(options): + failed += 1 + + if failed: + sys.exit(failed) + + +def lint_metadata(options): # Get all apps... allapps = metadata.read_metadata(options.appid) apps = common.read_app_args(options.appid, allapps, False) @@ -856,8 +899,7 @@ def main(): anywarns = True print("%s: %s" % (appid, warn)) - if anywarns: - sys.exit(1) + return not anywarns # A compiled, public domain list of official SPDX license tags. generated diff --git a/tests/common.TestCase b/tests/common.TestCase index 8a7ec438..4d9ce009 100755 --- a/tests/common.TestCase +++ b/tests/common.TestCase @@ -2838,6 +2838,36 @@ class CommonTest(unittest.TestCase): with self.assertRaises(TypeError): fdroidserver.common.load_localized_config(CATEGORIES_CONFIG_NAME, 'repo') + def test_config_type_check_config_yml_dict(self): + fdroidserver.common.config_type_check('config.yml', dict()) + + def test_config_type_check_config_yml_list(self): + with self.assertRaises(TypeError): + fdroidserver.common.config_type_check('config.yml', list()) + + def test_config_type_check_config_yml_set(self): + with self.assertRaises(TypeError): + fdroidserver.common.config_type_check('config.yml', set()) + + def test_config_type_check_config_yml_str(self): + with self.assertRaises(TypeError): + fdroidserver.common.config_type_check('config.yml', str()) + + def test_config_type_check_mirrors_list(self): + fdroidserver.common.config_type_check('config/mirrors.yml', list()) + + def test_config_type_check_mirrors_dict(self): + with self.assertRaises(TypeError): + fdroidserver.common.config_type_check('config/mirrors.yml', dict()) + + def test_config_type_check_mirrors_set(self): + with self.assertRaises(TypeError): + fdroidserver.common.config_type_check('config/mirrors.yml', set()) + + def test_config_type_check_mirrors_str(self): + with self.assertRaises(TypeError): + fdroidserver.common.config_type_check('config/mirrors.yml', str()) + if __name__ == "__main__": os.chdir(os.path.dirname(__file__))