mirror of
https://gitlab.com/fdroid/fdroidserver.git
synced 2024-10-05 18:50:09 +02:00
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:
commit
2a9bc448ee
@ -473,6 +473,29 @@ def check_extlib_dir(apps):
|
|||||||
yield _("Unused extlib at %s") % os.path.join(dir_path, path)
|
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=""):
|
def check_for_unsupported_metadata_files(basedir=""):
|
||||||
"""Checks whether any non-metadata files are in metadata/"""
|
"""Checks whether any non-metadata files are in metadata/"""
|
||||||
|
|
||||||
@ -538,6 +561,7 @@ def main():
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
app_check_funcs = [
|
app_check_funcs = [
|
||||||
|
check_app_field_types,
|
||||||
check_regexes,
|
check_regexes,
|
||||||
check_update_check_data_url,
|
check_update_check_data_url,
|
||||||
check_vercode_operation,
|
check_vercode_operation,
|
||||||
|
@ -156,7 +156,7 @@ class App(dict):
|
|||||||
self.Disabled = None
|
self.Disabled = None
|
||||||
self.AntiFeatures = []
|
self.AntiFeatures = []
|
||||||
self.Provides = None
|
self.Provides = None
|
||||||
self.Categories = ['None']
|
self.Categories = []
|
||||||
self.License = 'Unknown'
|
self.License = 'Unknown'
|
||||||
self.AuthorName = None
|
self.AuthorName = None
|
||||||
self.AuthorEmail = None
|
self.AuthorEmail = None
|
||||||
@ -228,16 +228,15 @@ TYPE_LIST = 4
|
|||||||
TYPE_SCRIPT = 5
|
TYPE_SCRIPT = 5
|
||||||
TYPE_MULTILINE = 6
|
TYPE_MULTILINE = 6
|
||||||
TYPE_BUILD = 7
|
TYPE_BUILD = 7
|
||||||
TYPE_BUILD_V2 = 8
|
TYPE_INT = 8
|
||||||
TYPE_INT = 9
|
|
||||||
|
|
||||||
fieldtypes = {
|
fieldtypes = {
|
||||||
'Description': TYPE_MULTILINE,
|
'Description': TYPE_MULTILINE,
|
||||||
'MaintainerNotes': TYPE_MULTILINE,
|
'MaintainerNotes': TYPE_MULTILINE,
|
||||||
'Categories': TYPE_LIST,
|
'Categories': TYPE_LIST,
|
||||||
'AntiFeatures': TYPE_LIST,
|
'AntiFeatures': TYPE_LIST,
|
||||||
'BuildVersion': TYPE_BUILD,
|
'Build': TYPE_BUILD,
|
||||||
'Build': TYPE_BUILD_V2,
|
'BuildVersion': TYPE_OBSOLETE,
|
||||||
'UseBuilt': TYPE_OBSOLETE,
|
'UseBuilt': TYPE_OBSOLETE,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -902,12 +901,14 @@ def post_metadata_parse(app):
|
|||||||
if 'flavours' in app and app['flavours'] == [True]:
|
if 'flavours' in app and app['flavours'] == [True]:
|
||||||
app['flavours'] = 'yes'
|
app['flavours'] = 'yes'
|
||||||
|
|
||||||
if isinstance(app.Categories, str):
|
for field, fieldtype in fieldtypes.items():
|
||||||
app.Categories = [app.Categories]
|
if fieldtype != TYPE_LIST:
|
||||||
elif app.Categories is None:
|
continue
|
||||||
app.Categories = ['None']
|
value = app.get(field)
|
||||||
else:
|
if isinstance(value, str):
|
||||||
app.Categories = [str(i) for i in app.Categories]
|
app[field] = [value, ]
|
||||||
|
elif value is not None:
|
||||||
|
app[field] = [str(i) for i in value]
|
||||||
|
|
||||||
def _yaml_bool_unmapable(v):
|
def _yaml_bool_unmapable(v):
|
||||||
return v in (True, False, [True], [False])
|
return v in (True, False, [True], [False])
|
||||||
@ -1333,7 +1334,7 @@ def parse_txt_metadata(mf, app):
|
|||||||
f = f.replace(' ', '')
|
f = f.replace(' ', '')
|
||||||
|
|
||||||
ftype = fieldtype(f)
|
ftype = fieldtype(f)
|
||||||
if ftype not in [TYPE_BUILD, TYPE_BUILD_V2]:
|
if ftype not in [TYPE_BUILD]:
|
||||||
add_comments(f)
|
add_comments(f)
|
||||||
if ftype == TYPE_MULTILINE:
|
if ftype == TYPE_MULTILINE:
|
||||||
mode = 1
|
mode = 1
|
||||||
@ -1345,15 +1346,6 @@ def parse_txt_metadata(mf, app):
|
|||||||
elif ftype == TYPE_LIST:
|
elif ftype == TYPE_LIST:
|
||||||
app[f] = split_list_values(v)
|
app[f] = split_list_values(v)
|
||||||
elif ftype == TYPE_BUILD:
|
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(',')
|
vv = v.split(',')
|
||||||
if len(vv) != 2:
|
if len(vv) != 2:
|
||||||
warn_or_exception(_('Build should have comma-separated '
|
warn_or_exception(_('Build should have comma-separated '
|
||||||
@ -1372,7 +1364,9 @@ def parse_txt_metadata(mf, app):
|
|||||||
del buildlines[:]
|
del buildlines[:]
|
||||||
mode = 3
|
mode = 3
|
||||||
elif ftype == TYPE_OBSOLETE:
|
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:
|
else:
|
||||||
warn_or_exception(_("Unrecognised field '{field}' in {linedesc}")
|
warn_or_exception(_("Unrecognised field '{field}' in {linedesc}")
|
||||||
.format(field=f, linedesc=linedesc))
|
.format(field=f, linedesc=linedesc))
|
||||||
|
@ -70,6 +70,59 @@ class LintTest(unittest.TestCase):
|
|||||||
logging.debug(warn)
|
logging.debug(warn)
|
||||||
self.assertTrue(anywarns)
|
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):
|
def test_check_vercode_operation(self):
|
||||||
config = dict()
|
config = dict()
|
||||||
fdroidserver.common.fill_config_defaults(config)
|
fdroidserver.common.fill_config_defaults(config)
|
||||||
|
Loading…
Reference in New Issue
Block a user