Merge branch 'enforce-list-data-types' into 'master'

Enforce list data types

Closes #578

See merge request fdroid/fdroidserver!583
This commit is contained in:
Hans-Christoph Steiner 2018-10-10 12:39:29 +00:00
commit 2a9bc448ee
3 changed files with 93 additions and 22 deletions

View File

@ -473,6 +473,29 @@ def check_extlib_dir(apps):
yield _("Unused extlib at %s") % os.path.join(dir_path, path)
def check_app_field_types(app):
"""Check the fields have valid data types"""
for field in app.keys():
v = app.get(field)
t = metadata.fieldtype(field)
if v is None:
continue
elif field == 'builds':
if not isinstance(v, list):
yield(_("{appid}: {field} must be a '{type}', but it is a '{fieldtype}'!")
.format(appid=app.id, field=field,
type='list', fieldtype=v.__class__.__name__))
elif t == metadata.TYPE_LIST and not isinstance(v, list):
yield(_("{appid}: {field} must be a '{type}', but it is a '{fieldtype}!'")
.format(appid=app.id, field=field,
type='list', fieldtype=v.__class__.__name__))
elif t == metadata.TYPE_STRING and not type(v) in (str, bool, dict):
yield(_("{appid}: {field} must be a '{type}', but it is a '{fieldtype}'!")
.format(appid=app.id, field=field,
type='str', fieldtype=v.__class__.__name__))
def check_for_unsupported_metadata_files(basedir=""):
"""Checks whether any non-metadata files are in metadata/"""
@ -538,6 +561,7 @@ def main():
continue
app_check_funcs = [
check_app_field_types,
check_regexes,
check_update_check_data_url,
check_vercode_operation,

View File

@ -156,7 +156,7 @@ class App(dict):
self.Disabled = None
self.AntiFeatures = []
self.Provides = None
self.Categories = ['None']
self.Categories = []
self.License = 'Unknown'
self.AuthorName = None
self.AuthorEmail = None
@ -228,16 +228,15 @@ TYPE_LIST = 4
TYPE_SCRIPT = 5
TYPE_MULTILINE = 6
TYPE_BUILD = 7
TYPE_BUILD_V2 = 8
TYPE_INT = 9
TYPE_INT = 8
fieldtypes = {
'Description': TYPE_MULTILINE,
'MaintainerNotes': TYPE_MULTILINE,
'Categories': TYPE_LIST,
'AntiFeatures': TYPE_LIST,
'BuildVersion': TYPE_BUILD,
'Build': TYPE_BUILD_V2,
'Build': TYPE_BUILD,
'BuildVersion': TYPE_OBSOLETE,
'UseBuilt': TYPE_OBSOLETE,
}
@ -902,12 +901,14 @@ def post_metadata_parse(app):
if 'flavours' in app and app['flavours'] == [True]:
app['flavours'] = 'yes'
if isinstance(app.Categories, str):
app.Categories = [app.Categories]
elif app.Categories is None:
app.Categories = ['None']
else:
app.Categories = [str(i) for i in app.Categories]
for field, fieldtype in fieldtypes.items():
if fieldtype != TYPE_LIST:
continue
value = app.get(field)
if isinstance(value, str):
app[field] = [value, ]
elif value is not None:
app[field] = [str(i) for i in value]
def _yaml_bool_unmapable(v):
return v in (True, False, [True], [False])
@ -1333,7 +1334,7 @@ def parse_txt_metadata(mf, app):
f = f.replace(' ', '')
ftype = fieldtype(f)
if ftype not in [TYPE_BUILD, TYPE_BUILD_V2]:
if ftype not in [TYPE_BUILD]:
add_comments(f)
if ftype == TYPE_MULTILINE:
mode = 1
@ -1345,15 +1346,6 @@ def parse_txt_metadata(mf, app):
elif ftype == TYPE_LIST:
app[f] = split_list_values(v)
elif ftype == TYPE_BUILD:
if v.endswith("\\"):
mode = 2
del buildlines[:]
buildlines.append(v[:-1])
else:
build = parse_buildline([v])
app.builds.append(build)
add_comments('build:' + app.builds[-1].versionCode)
elif ftype == TYPE_BUILD_V2:
vv = v.split(',')
if len(vv) != 2:
warn_or_exception(_('Build should have comma-separated '
@ -1372,7 +1364,9 @@ def parse_txt_metadata(mf, app):
del buildlines[:]
mode = 3
elif ftype == TYPE_OBSOLETE:
pass # Just throw it away!
warn_or_exception(_("'{field}' in {linedesc} is obsolete, see docs for current fields:")
.format(field=f, linedesc=linedesc)
+ '\nhttps://f-droid.org/docs/')
else:
warn_or_exception(_("Unrecognised field '{field}' in {linedesc}")
.format(field=f, linedesc=linedesc))

View File

@ -70,6 +70,59 @@ class LintTest(unittest.TestCase):
logging.debug(warn)
self.assertTrue(anywarns)
def test_check_app_field_types(self):
config = dict()
fdroidserver.common.fill_config_defaults(config)
fdroidserver.common.config = config
fdroidserver.lint.config = config
app = fdroidserver.metadata.App()
app.id = 'fake.app'
app.Name = 'Bad App'
app.Summary = 'We pwn you'
app.Description = 'These are some back'
fields = {
'AntiFeatures': {
'good': [
['KnownVuln', ],
['NonFreeNet', 'KnownVuln'],
],
'bad': [
'KnownVuln',
'NonFreeNet,KnownVuln',
],
},
'Categories': {
'good': [
['Sports & Health', ],
['Multimedia', 'Graphics'],
],
'bad': [
'Science & Education',
'Multimedia,Graphics',
],
},
}
for field, values in fields.items():
for bad in values['bad']:
anywarns = False
app[field] = bad
for warn in fdroidserver.lint.check_app_field_types(app):
anywarns = True
logging.debug(warn)
self.assertTrue(anywarns)
for good in values['good']:
anywarns = False
app[field] = good
for warn in fdroidserver.lint.check_app_field_types(app):
anywarns = True
logging.debug(warn)
self.assertFalse(anywarns)
def test_check_vercode_operation(self):
config = dict()
fdroidserver.common.fill_config_defaults(config)