diff --git a/fdroidserver/metadata.py b/fdroidserver/metadata.py index ff8bf2c3..15008e95 100644 --- a/fdroidserver/metadata.py +++ b/fdroidserver/metadata.py @@ -717,36 +717,48 @@ def parse_yaml_metadata(mf): cause=e) if yamldata is None or yamldata == '': - return dict() + yamldata = dict() + if not isinstance(yamldata, dict): + _warn_or_exception( + _("'{path}' has invalid format, it should be a dictionary!").format( + path=mf.name + ) + ) + logging.error(_('Using blank dictionary instead of contents of {path}!').format( + path=mf.name) + ) + yamldata = dict() deprecated_in_yaml = ['Provides'] - if yamldata: - for field in tuple(yamldata.keys()): - if field not in yaml_app_fields + deprecated_in_yaml: - msg = (_("Unrecognised app field '{fieldname}' in '{path}'") - .format(fieldname=field, path=mf.name)) - if Path(mf.name).name == '.fdroid.yml': - logging.error(msg) - del yamldata[field] - else: - _warn_or_exception(msg) + for field in tuple(yamldata.keys()): + if field not in yaml_app_fields + deprecated_in_yaml: + msg = _("Unrecognised app field '{fieldname}' in '{path}'").format( + fieldname=field, path=mf.name + ) + if Path(mf.name).name == '.fdroid.yml': + logging.error(msg) + del yamldata[field] + else: + _warn_or_exception(msg) - for deprecated_field in deprecated_in_yaml: - if deprecated_field in yamldata: - logging.warning(_("Ignoring '{field}' in '{metapath}' " - "metadata because it is deprecated.") - .format(field=deprecated_field, - metapath=mf.name)) - del yamldata[deprecated_field] + for deprecated_field in deprecated_in_yaml: + if deprecated_field in yamldata: + del yamldata[deprecated_field] + logging.warning( + _( + "Ignoring '{field}' in '{metapath}' " + "metadata because it is deprecated." + ).format(field=deprecated_field, metapath=mf.name) + ) - msg = _("Unrecognised build flag '{build_flag}' in '{path}'") - for build in yamldata.get('Builds', []): - for build_flag in build: - if build_flag not in build_flags: - _warn_or_exception(msg.format(build_flag=build_flag, path=mf.name)) + msg = _("Unrecognised build flag '{build_flag}' in '{path}'") + for build in yamldata.get('Builds', []): + for build_flag in build: + if build_flag not in build_flags: + _warn_or_exception(msg.format(build_flag=build_flag, path=mf.name)) - post_parse_yaml_metadata(yamldata) + post_parse_yaml_metadata(yamldata) return yamldata diff --git a/tests/metadata.TestCase b/tests/metadata.TestCase index 67d63f24..b340038b 100755 --- a/tests/metadata.TestCase +++ b/tests/metadata.TestCase @@ -419,6 +419,22 @@ class MetadataTest(unittest.TestCase): with self.assertRaises(MetaDataException): fdroidserver.metadata.parse_yaml_metadata(mf) + def test_parse_yaml_metadata_continue_on_warning(self): + """When errors are disabled, parsing should provide something that can work. + + When errors are disabled, then it should try to give data that + lets something happen. A zero-length file is valid for + operation, it just declares a Application ID as "known" and + nothing else. This example gives a list as the base in the + .yml file, which is unparsable, so it gives a warning message + and carries on with a blank dict. + + """ + fdroidserver.metadata.warnings_action = None + mf = io.StringIO('[AntiFeatures: Tracking]') + mf.name = 'mock_filename.yaml' + self.assertEqual(fdroidserver.metadata.parse_yaml_metadata(mf), dict()) + def test_parse_yaml_srclib_corrupt_file(self): with tempfile.TemporaryDirectory() as testdir: testdir = Path(testdir)