mirror of
https://github.com/f-droid/fdroidserver.git
synced 2025-11-04 22:40:29 +03:00
metadata: break out write_yaml to standalone function and add unit tests
This commit is contained in:
parent
784bebfee9
commit
2cb12f9594
2 changed files with 127 additions and 80 deletions
|
|
@ -1044,6 +1044,89 @@ def _del_duplicated_NoSourceSince(app):
|
||||||
del app['AntiFeatures'][key]
|
del app['AntiFeatures'][key]
|
||||||
|
|
||||||
|
|
||||||
|
def _field_to_yaml(typ, value):
|
||||||
|
"""Convert data to YAML 1.2 format that keeps the right TYPE_*."""
|
||||||
|
if typ == TYPE_STRING:
|
||||||
|
return str(value)
|
||||||
|
elif typ == TYPE_INT:
|
||||||
|
return int(value)
|
||||||
|
elif typ == TYPE_MULTILINE:
|
||||||
|
if '\n' in value:
|
||||||
|
return ruamel.yaml.scalarstring.preserve_literal(str(value))
|
||||||
|
else:
|
||||||
|
return str(value)
|
||||||
|
elif typ == TYPE_SCRIPT:
|
||||||
|
if type(value) == list:
|
||||||
|
if len(value) == 1:
|
||||||
|
return value[0]
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def _builds_to_yaml(app):
|
||||||
|
builds = ruamel.yaml.comments.CommentedSeq()
|
||||||
|
for build in app.get('Builds', []):
|
||||||
|
if not isinstance(build, Build):
|
||||||
|
build = Build(build)
|
||||||
|
b = ruamel.yaml.comments.CommentedMap()
|
||||||
|
for field in build_flags:
|
||||||
|
if hasattr(build, field):
|
||||||
|
value = getattr(build, field)
|
||||||
|
if field == 'gradle' and value == ['off']:
|
||||||
|
value = [
|
||||||
|
ruamel.yaml.scalarstring.SingleQuotedScalarString('off')
|
||||||
|
]
|
||||||
|
typ = flagtype(field)
|
||||||
|
# don't check value == True for TYPE_INT as it could be 0
|
||||||
|
if value is not None and (typ == TYPE_INT or value):
|
||||||
|
b.update({field: _field_to_yaml(typ, value)})
|
||||||
|
builds.append(b)
|
||||||
|
|
||||||
|
# insert extra empty lines between build entries
|
||||||
|
for i in range(1, len(builds)):
|
||||||
|
builds.yaml_set_comment_before_after_key(i, 'bogus')
|
||||||
|
builds.ca.items[i][1][-1].value = '\n'
|
||||||
|
|
||||||
|
return builds
|
||||||
|
|
||||||
|
|
||||||
|
def _app_to_yaml(app):
|
||||||
|
cm = ruamel.yaml.comments.CommentedMap()
|
||||||
|
insert_newline = False
|
||||||
|
for field in yaml_app_field_order:
|
||||||
|
if field == '\n':
|
||||||
|
# next iteration will need to insert a newline
|
||||||
|
insert_newline = True
|
||||||
|
else:
|
||||||
|
if app.get(field) or field == 'Builds':
|
||||||
|
if field == 'Builds':
|
||||||
|
if app.get('Builds'):
|
||||||
|
cm.update({field: _builds_to_yaml(app)})
|
||||||
|
elif field == 'CurrentVersionCode':
|
||||||
|
cm.update({field: _field_to_yaml(TYPE_INT, getattr(app, field))})
|
||||||
|
elif field == 'AllowedAPKSigningKeys':
|
||||||
|
value = getattr(app, field)
|
||||||
|
if value:
|
||||||
|
value = [str(i).lower() for i in value]
|
||||||
|
if len(value) == 1:
|
||||||
|
cm.update({field: _field_to_yaml(TYPE_STRING, value[0])})
|
||||||
|
else:
|
||||||
|
cm.update({field: _field_to_yaml(TYPE_LIST, value)})
|
||||||
|
else:
|
||||||
|
cm.update({field: _field_to_yaml(fieldtype(field), getattr(app, field))})
|
||||||
|
|
||||||
|
if insert_newline:
|
||||||
|
# we need to prepend a newline in front of this field
|
||||||
|
insert_newline = False
|
||||||
|
# inserting empty lines is not supported so we add a
|
||||||
|
# bogus comment and over-write its value
|
||||||
|
cm.yaml_set_comment_before_after_key(field, 'bogus')
|
||||||
|
cm.ca.items[field][1][-1].value = '\n'
|
||||||
|
return cm
|
||||||
|
|
||||||
|
|
||||||
def write_yaml(mf, app):
|
def write_yaml(mf, app):
|
||||||
"""Write metadata in yaml format.
|
"""Write metadata in yaml format.
|
||||||
|
|
||||||
|
|
@ -1053,87 +1136,8 @@ def write_yaml(mf, app):
|
||||||
active file discriptor for writing
|
active file discriptor for writing
|
||||||
app
|
app
|
||||||
app metadata to written to the yaml file
|
app metadata to written to the yaml file
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def _field_to_yaml(typ, value):
|
|
||||||
"""Convert data to YAML 1.2 format that keeps the right TYPE_*."""
|
|
||||||
if typ == TYPE_STRING:
|
|
||||||
return str(value)
|
|
||||||
elif typ == TYPE_INT:
|
|
||||||
return int(value)
|
|
||||||
elif typ == TYPE_MULTILINE:
|
|
||||||
if '\n' in value:
|
|
||||||
return ruamel.yaml.scalarstring.preserve_literal(str(value))
|
|
||||||
else:
|
|
||||||
return str(value)
|
|
||||||
elif typ == TYPE_SCRIPT:
|
|
||||||
if type(value) == list:
|
|
||||||
if len(value) == 1:
|
|
||||||
return value[0]
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
|
|
||||||
def _app_to_yaml(app):
|
|
||||||
cm = ruamel.yaml.comments.CommentedMap()
|
|
||||||
insert_newline = False
|
|
||||||
for field in yaml_app_field_order:
|
|
||||||
if field == '\n':
|
|
||||||
# next iteration will need to insert a newline
|
|
||||||
insert_newline = True
|
|
||||||
else:
|
|
||||||
if app.get(field) or field == 'Builds':
|
|
||||||
if field == 'Builds':
|
|
||||||
if app.get('Builds'):
|
|
||||||
cm.update({field: _builds_to_yaml(app)})
|
|
||||||
elif field == 'CurrentVersionCode':
|
|
||||||
cm.update({field: _field_to_yaml(TYPE_INT, getattr(app, field))})
|
|
||||||
elif field == 'AllowedAPKSigningKeys':
|
|
||||||
value = getattr(app, field)
|
|
||||||
if value:
|
|
||||||
value = [str(i).lower() for i in value]
|
|
||||||
if len(value) == 1:
|
|
||||||
cm.update({field: _field_to_yaml(TYPE_STRING, value[0])})
|
|
||||||
else:
|
|
||||||
cm.update({field: _field_to_yaml(TYPE_LIST, value)})
|
|
||||||
else:
|
|
||||||
cm.update({field: _field_to_yaml(fieldtype(field), getattr(app, field))})
|
|
||||||
|
|
||||||
if insert_newline:
|
|
||||||
# we need to prepend a newline in front of this field
|
|
||||||
insert_newline = False
|
|
||||||
# inserting empty lines is not supported so we add a
|
|
||||||
# bogus comment and over-write its value
|
|
||||||
cm.yaml_set_comment_before_after_key(field, 'bogus')
|
|
||||||
cm.ca.items[field][1][-1].value = '\n'
|
|
||||||
return cm
|
|
||||||
|
|
||||||
def _builds_to_yaml(app):
|
|
||||||
builds = ruamel.yaml.comments.CommentedSeq()
|
|
||||||
for build in app.get('Builds', []):
|
|
||||||
if not isinstance(build, Build):
|
|
||||||
build = Build(build)
|
|
||||||
b = ruamel.yaml.comments.CommentedMap()
|
|
||||||
for field in build_flags:
|
|
||||||
if hasattr(build, field):
|
|
||||||
value = getattr(build, field)
|
|
||||||
if field == 'gradle' and value == ['off']:
|
|
||||||
value = [
|
|
||||||
ruamel.yaml.scalarstring.SingleQuotedScalarString('off')
|
|
||||||
]
|
|
||||||
typ = flagtype(field)
|
|
||||||
# don't check value == True for TYPE_INT as it could be 0
|
|
||||||
if value is not None and (typ == TYPE_INT or value):
|
|
||||||
b.update({field: _field_to_yaml(typ, value)})
|
|
||||||
builds.append(b)
|
|
||||||
|
|
||||||
# insert extra empty lines between build entries
|
|
||||||
for i in range(1, len(builds)):
|
|
||||||
builds.yaml_set_comment_before_after_key(i, 'bogus')
|
|
||||||
builds.ca.items[i][1][-1].value = '\n'
|
|
||||||
|
|
||||||
return builds
|
|
||||||
|
|
||||||
_del_duplicated_NoSourceSince(app)
|
_del_duplicated_NoSourceSince(app)
|
||||||
yaml_app = _app_to_yaml(app)
|
yaml_app = _app_to_yaml(app)
|
||||||
yaml = ruamel.yaml.YAML()
|
yaml = ruamel.yaml.YAML()
|
||||||
|
|
|
||||||
|
|
@ -1684,6 +1684,49 @@ class MetadataTest(unittest.TestCase):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_app_to_yaml_smokecheck(self):
|
||||||
|
self.assertTrue(
|
||||||
|
isinstance(metadata._app_to_yaml(dict()), ruamel.yaml.comments.CommentedMap)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_app_to_yaml_build_list_empty(self):
|
||||||
|
app = metadata.App({'Builds': [metadata.Build({'rm': []})]})
|
||||||
|
self.assertEqual(dict(), metadata._app_to_yaml(app)['Builds'][0])
|
||||||
|
|
||||||
|
def test_app_to_yaml_build_list_string(self):
|
||||||
|
app = metadata.App({'Builds': [metadata.Build({'rm': 'one'})]})
|
||||||
|
self.assertEqual({'rm': 'one'}, metadata._app_to_yaml(app)['Builds'][0])
|
||||||
|
|
||||||
|
def test_app_to_yaml_build_list_one(self):
|
||||||
|
app = metadata.App({'Builds': [metadata.Build({'rm': ['one']})]})
|
||||||
|
self.assertEqual({'rm': ['one']}, metadata._app_to_yaml(app)['Builds'][0])
|
||||||
|
|
||||||
|
def test_app_to_yaml_build_list(self):
|
||||||
|
app = metadata.App({'Builds': [metadata.Build({'rm': ['b2', 'NO1']})]})
|
||||||
|
self.assertEqual({'rm': ['b2', 'NO1']}, metadata._app_to_yaml(app)['Builds'][0])
|
||||||
|
|
||||||
|
def test_app_to_yaml_AllowedAPKSigningKeys_two(self):
|
||||||
|
cm = metadata._app_to_yaml(metadata.App({'AllowedAPKSigningKeys': ['b', 'A']}))
|
||||||
|
self.assertEqual(['b', 'a'], cm['AllowedAPKSigningKeys'])
|
||||||
|
|
||||||
|
def test_app_to_yaml_AllowedAPKSigningKeys_one(self):
|
||||||
|
cm = metadata._app_to_yaml(metadata.App({'AllowedAPKSigningKeys': ['One']}))
|
||||||
|
self.assertEqual('one', cm['AllowedAPKSigningKeys'])
|
||||||
|
|
||||||
|
def test_app_to_yaml_int_hex(self):
|
||||||
|
cm = metadata._app_to_yaml(metadata.App({'CurrentVersionCode': 0xFF}))
|
||||||
|
self.assertEqual(255, cm['CurrentVersionCode'])
|
||||||
|
|
||||||
|
def test_app_to_yaml_int_underscore(self):
|
||||||
|
cm = metadata._app_to_yaml(metadata.App({'CurrentVersionCode': 1_2_3}))
|
||||||
|
self.assertEqual(123, cm['CurrentVersionCode'])
|
||||||
|
|
||||||
|
def test_app_to_yaml_int_0(self):
|
||||||
|
"""Document that 0 values fail to make it through."""
|
||||||
|
# TODO it should be possible to use `CurrentVersionCode: 0`
|
||||||
|
cm = metadata._app_to_yaml(metadata.App({'CurrentVersionCode': 0}))
|
||||||
|
self.assertFalse('CurrentVersionCode' in cm)
|
||||||
|
|
||||||
|
|
||||||
class PostMetadataParseTest(unittest.TestCase):
|
class PostMetadataParseTest(unittest.TestCase):
|
||||||
"""Test the functions that post process the YAML input.
|
"""Test the functions that post process the YAML input.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue