mirror of
https://github.com/f-droid/fdroidserver.git
synced 2025-09-13 14:32:28 +03:00
Merge branch 'clean-up-metadata' into 'master'
collection of cleanups, tests and minor refactoring related to metadata See merge request fdroid/fdroidserver!1351
This commit is contained in:
commit
acc774f91e
8 changed files with 231 additions and 206 deletions
|
@ -110,7 +110,7 @@ def check_tags(app, pattern):
|
||||||
|
|
||||||
vcs.gotorevision(None)
|
vcs.gotorevision(None)
|
||||||
|
|
||||||
last_build = app.get_last_build()
|
last_build = get_last_build_from_app(app)
|
||||||
|
|
||||||
try_init_submodules(app, last_build, vcs)
|
try_init_submodules(app, last_build, vcs)
|
||||||
|
|
||||||
|
@ -252,10 +252,7 @@ def check_repomanifest(app, branch=None):
|
||||||
elif repotype == 'bzr':
|
elif repotype == 'bzr':
|
||||||
vcs.gotorevision(None)
|
vcs.gotorevision(None)
|
||||||
|
|
||||||
last_build = metadata.Build()
|
last_build = get_last_build_from_app(app)
|
||||||
if app.get('Builds', []):
|
|
||||||
last_build = app.get('Builds', [])[-1]
|
|
||||||
|
|
||||||
try_init_submodules(app, last_build, vcs)
|
try_init_submodules(app, last_build, vcs)
|
||||||
|
|
||||||
hpak = None
|
hpak = None
|
||||||
|
@ -364,7 +361,7 @@ def possible_subdirs(app):
|
||||||
else:
|
else:
|
||||||
build_dir = Path('build') / app.id
|
build_dir = Path('build') / app.id
|
||||||
|
|
||||||
last_build = app.get_last_build()
|
last_build = get_last_build_from_app(app)
|
||||||
|
|
||||||
for d in dirs_with_manifest(build_dir):
|
for d in dirs_with_manifest(build_dir):
|
||||||
m_paths = common.manifest_paths(d, last_build.gradle)
|
m_paths = common.manifest_paths(d, last_build.gradle)
|
||||||
|
@ -399,7 +396,7 @@ def fetch_autoname(app, tag):
|
||||||
except VCSException:
|
except VCSException:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
last_build = app.get_last_build()
|
last_build = get_last_build_from_app(app)
|
||||||
|
|
||||||
logging.debug("...fetch auto name from " + str(build_dir))
|
logging.debug("...fetch auto name from " + str(build_dir))
|
||||||
new_name = None
|
new_name = None
|
||||||
|
@ -579,6 +576,13 @@ def checkupdates_app(app):
|
||||||
raise FDroidException("Git commit failed")
|
raise FDroidException("Git commit failed")
|
||||||
|
|
||||||
|
|
||||||
|
def get_last_build_from_app(app):
|
||||||
|
if app.get('Builds'):
|
||||||
|
return app['Builds'][-1]
|
||||||
|
else:
|
||||||
|
return metadata.Build()
|
||||||
|
|
||||||
|
|
||||||
def status_update_json(processed, failed):
|
def status_update_json(processed, failed):
|
||||||
"""Output a JSON file with metadata about this run."""
|
"""Output a JSON file with metadata about this run."""
|
||||||
logging.debug(_('Outputting JSON'))
|
logging.debug(_('Outputting JSON'))
|
||||||
|
|
|
@ -24,14 +24,12 @@ import platform
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import logging
|
import logging
|
||||||
import importlib
|
import ruamel.yaml
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from ruamel.yaml import YAML, YAMLError
|
|
||||||
|
|
||||||
from . import common
|
from . import common
|
||||||
from . import _
|
from . import _
|
||||||
from .exception import MetaDataException, FDroidException
|
from .exception import MetaDataException
|
||||||
|
|
||||||
srclibs = None
|
srclibs = None
|
||||||
warnings_action = None
|
warnings_action = None
|
||||||
|
@ -109,7 +107,6 @@ yaml_app_fields = [x for x in yaml_app_field_order if x != '\n']
|
||||||
|
|
||||||
|
|
||||||
class App(dict):
|
class App(dict):
|
||||||
|
|
||||||
def __init__(self, copydict=None):
|
def __init__(self, copydict=None):
|
||||||
if copydict:
|
if copydict:
|
||||||
super().__init__(copydict)
|
super().__init__(copydict)
|
||||||
|
@ -177,12 +174,6 @@ class App(dict):
|
||||||
else:
|
else:
|
||||||
raise AttributeError("No such attribute: " + name)
|
raise AttributeError("No such attribute: " + name)
|
||||||
|
|
||||||
def get_last_build(self):
|
|
||||||
if len(self.Builds) > 0:
|
|
||||||
return self.Builds[-1]
|
|
||||||
else:
|
|
||||||
return Build()
|
|
||||||
|
|
||||||
|
|
||||||
TYPE_STRING = 2
|
TYPE_STRING = 2
|
||||||
TYPE_BOOL = 3
|
TYPE_BOOL = 3
|
||||||
|
@ -252,7 +243,6 @@ build_flags = [
|
||||||
|
|
||||||
|
|
||||||
class Build(dict):
|
class Build(dict):
|
||||||
|
|
||||||
def __init__(self, copydict=None):
|
def __init__(self, copydict=None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.disable = ''
|
self.disable = ''
|
||||||
|
@ -307,6 +297,10 @@ class Build(dict):
|
||||||
else:
|
else:
|
||||||
raise AttributeError("No such attribute: " + name)
|
raise AttributeError("No such attribute: " + name)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def to_yaml(cls, representer, node):
|
||||||
|
return representer.represent_dict(node)
|
||||||
|
|
||||||
def build_method(self):
|
def build_method(self):
|
||||||
for f in ['maven', 'gradle']:
|
for f in ['maven', 'gradle']:
|
||||||
if self.get(f):
|
if self.get(f):
|
||||||
|
@ -375,7 +369,7 @@ def flagtype(name):
|
||||||
return TYPE_STRING
|
return TYPE_STRING
|
||||||
|
|
||||||
|
|
||||||
class FieldValidator():
|
class FieldValidator:
|
||||||
"""Designate App metadata field types and checks that it matches.
|
"""Designate App metadata field types and checks that it matches.
|
||||||
|
|
||||||
'name' - The long name of the field type
|
'name' - The long name of the field type
|
||||||
|
@ -399,8 +393,13 @@ class FieldValidator():
|
||||||
values = [v]
|
values = [v]
|
||||||
for v in values:
|
for v in values:
|
||||||
if not self.compiled.match(v):
|
if not self.compiled.match(v):
|
||||||
_warn_or_exception(_("'{value}' is not a valid {field} in {appid}. Regex pattern: {pattern}")
|
_warn_or_exception(
|
||||||
.format(value=v, field=self.name, appid=appid, pattern=self.matching))
|
_(
|
||||||
|
"'{value}' is not a valid {field} in {appid}. Regex pattern: {pattern}"
|
||||||
|
).format(
|
||||||
|
value=v, field=self.name, appid=appid, pattern=self.matching
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Generic value types
|
# Generic value types
|
||||||
|
@ -471,21 +470,19 @@ def check_metadata(app):
|
||||||
|
|
||||||
|
|
||||||
def parse_yaml_srclib(metadatapath):
|
def parse_yaml_srclib(metadatapath):
|
||||||
|
thisinfo = {'RepoType': '', 'Repo': '', 'Subdir': None, 'Prepare': None}
|
||||||
thisinfo = {'RepoType': '',
|
|
||||||
'Repo': '',
|
|
||||||
'Subdir': None,
|
|
||||||
'Prepare': None}
|
|
||||||
|
|
||||||
if not metadatapath.exists():
|
if not metadatapath.exists():
|
||||||
_warn_or_exception(_("Invalid scrlib metadata: '{file}' "
|
_warn_or_exception(
|
||||||
"does not exist"
|
_("Invalid scrlib metadata: '{file}' does not exist").format(
|
||||||
.format(file=metadatapath)))
|
file=metadatapath
|
||||||
|
)
|
||||||
|
)
|
||||||
return thisinfo
|
return thisinfo
|
||||||
|
|
||||||
with metadatapath.open("r", encoding="utf-8") as f:
|
with metadatapath.open("r", encoding="utf-8") as f:
|
||||||
try:
|
try:
|
||||||
yaml = YAML(typ='safe')
|
yaml = ruamel.yaml.YAML(typ='safe')
|
||||||
data = yaml.load(f)
|
data = yaml.load(f)
|
||||||
if type(data) is not dict:
|
if type(data) is not dict:
|
||||||
if platform.system() == 'Windows':
|
if platform.system() == 'Windows':
|
||||||
|
@ -495,9 +492,10 @@ def parse_yaml_srclib(metadatapath):
|
||||||
with symlink.open("r", encoding="utf-8") as s:
|
with symlink.open("r", encoding="utf-8") as s:
|
||||||
data = yaml.load(s)
|
data = yaml.load(s)
|
||||||
if type(data) is not dict:
|
if type(data) is not dict:
|
||||||
raise YAMLError(_('{file} is blank or corrupt!')
|
raise ruamel.yaml.YAMLError(
|
||||||
.format(file=metadatapath))
|
_('{file} is blank or corrupt!').format(file=metadatapath)
|
||||||
except YAMLError as e:
|
)
|
||||||
|
except ruamel.yaml.YAMLError as e:
|
||||||
_warn_or_exception(_("Invalid srclib metadata: could not "
|
_warn_or_exception(_("Invalid srclib metadata: could not "
|
||||||
"parse '{file}'")
|
"parse '{file}'")
|
||||||
.format(file=metadatapath) + '\n'
|
.format(file=metadatapath) + '\n'
|
||||||
|
@ -507,9 +505,11 @@ def parse_yaml_srclib(metadatapath):
|
||||||
|
|
||||||
for key in data:
|
for key in data:
|
||||||
if key not in thisinfo:
|
if key not in thisinfo:
|
||||||
_warn_or_exception(_("Invalid srclib metadata: unknown key "
|
_warn_or_exception(
|
||||||
"'{key}' in '{file}'")
|
_("Invalid srclib metadata: unknown key '{key}' in '{file}'").format(
|
||||||
.format(key=key, file=metadatapath))
|
key=key, file=metadatapath
|
||||||
|
)
|
||||||
|
)
|
||||||
return thisinfo
|
return thisinfo
|
||||||
else:
|
else:
|
||||||
if key == 'Subdir':
|
if key == 'Subdir':
|
||||||
|
@ -580,7 +580,8 @@ def read_metadata(appids={}, sort_by_time=False):
|
||||||
metadatafiles = common.get_metadata_files(vercodes)
|
metadatafiles = common.get_metadata_files(vercodes)
|
||||||
else:
|
else:
|
||||||
metadatafiles = list(Path('metadata').glob('*.yml')) + list(
|
metadatafiles = list(Path('metadata').glob('*.yml')) + list(
|
||||||
Path('.').glob('.fdroid.yml'))
|
Path('.').glob('.fdroid.yml')
|
||||||
|
)
|
||||||
|
|
||||||
if sort_by_time:
|
if sort_by_time:
|
||||||
entries = ((path.stat().st_mtime, path) for path in metadatafiles)
|
entries = ((path.stat().st_mtime, path) for path in metadatafiles)
|
||||||
|
@ -594,11 +595,15 @@ def read_metadata(appids={}, sort_by_time=False):
|
||||||
for metadatapath in metadatafiles:
|
for metadatapath in metadatafiles:
|
||||||
appid = metadatapath.stem
|
appid = metadatapath.stem
|
||||||
if appid != '.fdroid' and not common.is_valid_package_name(appid):
|
if appid != '.fdroid' and not common.is_valid_package_name(appid):
|
||||||
_warn_or_exception(_("{appid} from {path} is not a valid Java Package Name!")
|
_warn_or_exception(
|
||||||
.format(appid=appid, path=metadatapath))
|
_("{appid} from {path} is not a valid Java Package Name!").format(
|
||||||
|
appid=appid, path=metadatapath
|
||||||
|
)
|
||||||
|
)
|
||||||
if appid in apps:
|
if appid in apps:
|
||||||
_warn_or_exception(_("Found multiple metadata files for {appid}")
|
_warn_or_exception(
|
||||||
.format(appid=appid))
|
_("Found multiple metadata files for {appid}").format(appid=appid)
|
||||||
|
)
|
||||||
app = parse_metadata(metadatapath)
|
app = parse_metadata(metadatapath)
|
||||||
check_metadata(app)
|
check_metadata(app)
|
||||||
apps[app.id] = app
|
apps[app.id] = app
|
||||||
|
@ -654,8 +659,9 @@ def parse_metadata(metadatapath):
|
||||||
with metadatapath.open('r', encoding='utf-8') as mf:
|
with metadatapath.open('r', encoding='utf-8') as mf:
|
||||||
app.update(parse_yaml_metadata(mf))
|
app.update(parse_yaml_metadata(mf))
|
||||||
else:
|
else:
|
||||||
_warn_or_exception(_('Unknown metadata format: {path} (use: *.yml)')
|
_warn_or_exception(
|
||||||
.format(path=metadatapath))
|
_('Unknown metadata format: {path} (use: *.yml)').format(path=metadatapath)
|
||||||
|
)
|
||||||
|
|
||||||
if metadatapath.name != '.fdroid.yml' and app.Repo:
|
if metadatapath.name != '.fdroid.yml' and app.Repo:
|
||||||
build_dir = common.get_build_dir(app)
|
build_dir = common.get_build_dir(app)
|
||||||
|
@ -663,11 +669,15 @@ def parse_metadata(metadatapath):
|
||||||
if metadata_in_repo.is_file():
|
if metadata_in_repo.is_file():
|
||||||
try:
|
try:
|
||||||
commit_id = common.get_head_commit_id(git.Repo(build_dir))
|
commit_id = common.get_head_commit_id(git.Repo(build_dir))
|
||||||
logging.debug(_('Including metadata from %s@%s') % (metadata_in_repo, commit_id))
|
logging.debug(
|
||||||
|
_('Including metadata from %s@%s') % (metadata_in_repo, commit_id)
|
||||||
|
)
|
||||||
# See https://github.com/PyCQA/pylint/issues/2856 .
|
# See https://github.com/PyCQA/pylint/issues/2856 .
|
||||||
# pylint: disable-next=no-member
|
# pylint: disable-next=no-member
|
||||||
except git.exc.InvalidGitRepositoryError:
|
except git.exc.InvalidGitRepositoryError:
|
||||||
logging.debug(_('Including metadata from {path}').format(metadata_in_repo))
|
logging.debug(
|
||||||
|
_('Including metadata from {path}').format(metadata_in_repo)
|
||||||
|
)
|
||||||
app_in_repo = parse_metadata(metadata_in_repo)
|
app_in_repo = parse_metadata(metadata_in_repo)
|
||||||
for k, v in app_in_repo.items():
|
for k, v in app_in_repo.items():
|
||||||
if k not in app:
|
if k not in app:
|
||||||
|
@ -708,13 +718,15 @@ def parse_yaml_metadata(mf):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
yaml = YAML(typ='safe')
|
yaml = ruamel.yaml.YAML(typ='safe')
|
||||||
yamldata = yaml.load(mf)
|
yamldata = yaml.load(mf)
|
||||||
except YAMLError as e:
|
except ruamel.yaml.YAMLError as e:
|
||||||
_warn_or_exception(_("could not parse '{path}'")
|
_warn_or_exception(
|
||||||
.format(path=mf.name) + '\n'
|
_("could not parse '{path}'").format(path=mf.name)
|
||||||
+ common.run_yamllint(mf.name, indent=4),
|
+ '\n'
|
||||||
cause=e)
|
+ common.run_yamllint(mf.name, indent=4),
|
||||||
|
cause=e,
|
||||||
|
)
|
||||||
|
|
||||||
if yamldata is None or yamldata == '':
|
if yamldata is None or yamldata == '':
|
||||||
yamldata = dict()
|
yamldata = dict()
|
||||||
|
@ -788,15 +800,16 @@ def post_parse_yaml_metadata(yamldata):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
for k, v in yamldata.items():
|
for k, v in yamldata.items():
|
||||||
if fieldtype(k) == TYPE_LIST:
|
_fieldtype = fieldtype(k)
|
||||||
|
if _fieldtype == TYPE_LIST:
|
||||||
if isinstance(v, str):
|
if isinstance(v, str):
|
||||||
yamldata[k] = [v, ]
|
yamldata[k] = [v]
|
||||||
elif v:
|
elif v:
|
||||||
yamldata[k] = [str(i) for i in v]
|
yamldata[k] = [str(i) for i in v]
|
||||||
elif fieldtype(k) == TYPE_INT:
|
elif _fieldtype == TYPE_INT:
|
||||||
if v:
|
if v:
|
||||||
yamldata[k] = int(v)
|
yamldata[k] = int(v)
|
||||||
elif fieldtype(k) == TYPE_STRING:
|
elif _fieldtype == TYPE_STRING:
|
||||||
if v or v == 0:
|
if v or v == 0:
|
||||||
yamldata[k] = _normalize_type_string(v)
|
yamldata[k] = _normalize_type_string(v)
|
||||||
else:
|
else:
|
||||||
|
@ -810,10 +823,10 @@ def post_parse_yaml_metadata(yamldata):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
_flagtype = flagtype(k)
|
_flagtype = flagtype(k)
|
||||||
if _flagtype is TYPE_STRING:
|
if _flagtype == TYPE_STRING:
|
||||||
if v or v == 0:
|
if v or v == 0:
|
||||||
build[k] = _normalize_type_string(v)
|
build[k] = _normalize_type_string(v)
|
||||||
elif _flagtype is TYPE_INT:
|
elif _flagtype == TYPE_INT:
|
||||||
build[k] = v
|
build[k] = v
|
||||||
# versionCode must be int
|
# versionCode must be int
|
||||||
if not isinstance(v, int):
|
if not isinstance(v, int):
|
||||||
|
@ -851,33 +864,18 @@ def write_yaml(mf, app):
|
||||||
app
|
app
|
||||||
app metadata to written to the yaml file
|
app metadata to written to the yaml file
|
||||||
"""
|
"""
|
||||||
# import rumael.yaml and check version
|
|
||||||
try:
|
|
||||||
import ruamel.yaml
|
|
||||||
except ImportError as e:
|
|
||||||
raise FDroidException('ruamel.yaml not installed, can not write metadata.') from e
|
|
||||||
if not ruamel.yaml.__version__:
|
|
||||||
raise FDroidException('ruamel.yaml.__version__ not accessible. Please make sure a ruamel.yaml >= 0.13 is installed..')
|
|
||||||
m = re.match(r'(?P<major>[0-9]+)\.(?P<minor>[0-9]+)\.(?P<patch>[0-9]+)(-.+)?',
|
|
||||||
ruamel.yaml.__version__)
|
|
||||||
if not m:
|
|
||||||
raise FDroidException('ruamel.yaml version malfored, please install an upstream version of ruamel.yaml')
|
|
||||||
if int(m.group('major')) < 0 or int(m.group('minor')) < 13:
|
|
||||||
raise FDroidException('currently installed version of ruamel.yaml ({}) is too old, >= 1.13 required.'.format(ruamel.yaml.__version__))
|
|
||||||
# suiteable version ruamel.yaml imported successfully
|
|
||||||
|
|
||||||
def _field_to_yaml(typ, value):
|
def _field_to_yaml(typ, value):
|
||||||
"""Convert data to YAML 1.2 format that keeps the right TYPE_*."""
|
"""Convert data to YAML 1.2 format that keeps the right TYPE_*."""
|
||||||
if typ is TYPE_STRING:
|
if typ == TYPE_STRING:
|
||||||
return str(value)
|
return str(value)
|
||||||
elif typ is TYPE_INT:
|
elif typ == TYPE_INT:
|
||||||
return int(value)
|
return int(value)
|
||||||
elif typ is TYPE_MULTILINE:
|
elif typ == TYPE_MULTILINE:
|
||||||
if '\n' in value:
|
if '\n' in value:
|
||||||
return ruamel.yaml.scalarstring.preserve_literal(str(value))
|
return ruamel.yaml.scalarstring.preserve_literal(str(value))
|
||||||
else:
|
else:
|
||||||
return str(value)
|
return str(value)
|
||||||
elif typ is TYPE_SCRIPT:
|
elif typ == TYPE_SCRIPT:
|
||||||
if type(value) == list:
|
if type(value) == list:
|
||||||
if len(value) == 1:
|
if len(value) == 1:
|
||||||
return value[0]
|
return value[0]
|
||||||
|
@ -930,7 +928,9 @@ def write_yaml(mf, app):
|
||||||
if hasattr(build, field):
|
if hasattr(build, field):
|
||||||
value = getattr(build, field)
|
value = getattr(build, field)
|
||||||
if field == 'gradle' and value == ['off']:
|
if field == 'gradle' and value == ['off']:
|
||||||
value = [ruamel.yaml.scalarstring.SingleQuotedScalarString('off')]
|
value = [
|
||||||
|
ruamel.yaml.scalarstring.SingleQuotedScalarString('off')
|
||||||
|
]
|
||||||
typ = flagtype(field)
|
typ = flagtype(field)
|
||||||
# don't check value == True for TYPE_INT as it could be 0
|
# don't check value == True for TYPE_INT as it could be 0
|
||||||
if value is not None and (typ == TYPE_INT or value):
|
if value is not None and (typ == TYPE_INT or value):
|
||||||
|
@ -945,27 +945,25 @@ def write_yaml(mf, app):
|
||||||
return builds
|
return builds
|
||||||
|
|
||||||
yaml_app = _app_to_yaml(app)
|
yaml_app = _app_to_yaml(app)
|
||||||
try:
|
yaml = ruamel.yaml.YAML()
|
||||||
yaml = ruamel.yaml.YAML()
|
yaml.indent(mapping=4, sequence=4, offset=2)
|
||||||
yaml.indent(mapping=4, sequence=4, offset=2)
|
yaml.dump(yaml_app, stream=mf)
|
||||||
yaml.dump(yaml_app, stream=mf)
|
|
||||||
except AttributeError: # Debian/stretch's version does not have YAML()
|
|
||||||
ruamel.yaml.round_trip_dump(yaml_app, mf, indent=4, block_seq_indent=2)
|
|
||||||
|
|
||||||
|
|
||||||
def write_metadata(metadatapath, app):
|
def write_metadata(metadatapath, app):
|
||||||
metadatapath = Path(metadatapath)
|
metadatapath = Path(metadatapath)
|
||||||
if metadatapath.suffix == '.yml':
|
if metadatapath.suffix == '.yml':
|
||||||
if importlib.util.find_spec('ruamel.yaml'):
|
with metadatapath.open('w') as mf:
|
||||||
with metadatapath.open('w') as mf:
|
return write_yaml(mf, app)
|
||||||
return write_yaml(mf, app)
|
|
||||||
else:
|
|
||||||
raise FDroidException(_('ruamel.yaml not installed, can not write metadata.'))
|
|
||||||
|
|
||||||
_warn_or_exception(_('Unknown metadata format: %s') % metadatapath)
|
_warn_or_exception(_('Unknown metadata format: %s') % metadatapath)
|
||||||
|
|
||||||
|
|
||||||
def add_metadata_arguments(parser):
|
def add_metadata_arguments(parser):
|
||||||
"""Add common command line flags related to metadata processing."""
|
"""Add common command line flags related to metadata processing."""
|
||||||
parser.add_argument("-W", choices=['error', 'warn', 'ignore'], default='error',
|
parser.add_argument(
|
||||||
help=_("force metadata errors (default) to be warnings, or to be ignored."))
|
"-W",
|
||||||
|
choices=['error', 'warn', 'ignore'],
|
||||||
|
default='error',
|
||||||
|
help=_("force metadata errors (default) to be warnings, or to be ignored."),
|
||||||
|
)
|
||||||
|
|
|
@ -6,22 +6,17 @@ import logging
|
||||||
import optparse
|
import optparse
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
import ruamel.yaml
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
from unittest import mock
|
|
||||||
import tempfile
|
import tempfile
|
||||||
import textwrap
|
import textwrap
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
from testcommon import TmpCwd
|
from testcommon import TmpCwd
|
||||||
|
|
||||||
from ruamel.yaml import YAML
|
|
||||||
|
|
||||||
yaml = YAML(typ='safe')
|
|
||||||
|
|
||||||
localmodule = Path(__file__).resolve().parent.parent
|
localmodule = Path(__file__).resolve().parent.parent
|
||||||
print('localmodule: ' + str(localmodule))
|
print('localmodule: ' + str(localmodule))
|
||||||
if localmodule not in sys.path:
|
if localmodule not in sys.path:
|
||||||
|
@ -32,6 +27,12 @@ from fdroidserver import metadata
|
||||||
from fdroidserver.exception import MetaDataException
|
from fdroidserver.exception import MetaDataException
|
||||||
|
|
||||||
|
|
||||||
|
def _get_mock_mf(s):
|
||||||
|
mf = io.StringIO(s)
|
||||||
|
mf.name = 'mock_filename.yaml'
|
||||||
|
return mf
|
||||||
|
|
||||||
|
|
||||||
class MetadataTest(unittest.TestCase):
|
class MetadataTest(unittest.TestCase):
|
||||||
'''fdroidserver/metadata.py'''
|
'''fdroidserver/metadata.py'''
|
||||||
|
|
||||||
|
@ -39,6 +40,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
self.basedir = localmodule / 'tests'
|
self.basedir = localmodule / 'tests'
|
||||||
os.chdir(self.basedir)
|
os.chdir(self.basedir)
|
||||||
|
fdroidserver.metadata.warnings_action = 'error'
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
# auto-generated dirs by functions, not tests, so they are not always cleaned up
|
# auto-generated dirs by functions, not tests, so they are not always cleaned up
|
||||||
|
@ -67,8 +69,6 @@ class MetadataTest(unittest.TestCase):
|
||||||
break
|
break
|
||||||
self.assertIsNotNone(validator, "could not find 'Bitcoin address' validator")
|
self.assertIsNotNone(validator, "could not find 'Bitcoin address' validator")
|
||||||
|
|
||||||
fdroidserver.metadata.warnings_action = 'error'
|
|
||||||
|
|
||||||
# some valid addresses (P2PKH, P2SH, Bech32)
|
# some valid addresses (P2PKH, P2SH, Bech32)
|
||||||
self.assertIsNone(
|
self.assertIsNone(
|
||||||
validator.check('1BrrrrErsrWetrTrnrrrrm4GFg7xJaNVN2', 'fake.app.id')
|
validator.check('1BrrrrErsrWetrTrnrrrrm4GFg7xJaNVN2', 'fake.app.id')
|
||||||
|
@ -126,8 +126,6 @@ class MetadataTest(unittest.TestCase):
|
||||||
break
|
break
|
||||||
self.assertIsNotNone(validator, "could not find 'Litecoin address' validator")
|
self.assertIsNotNone(validator, "could not find 'Litecoin address' validator")
|
||||||
|
|
||||||
fdroidserver.metadata.warnings_action = 'error'
|
|
||||||
|
|
||||||
# some valid addresses (L, M, 3, segwit)
|
# some valid addresses (L, M, 3, segwit)
|
||||||
self.assertIsNone(
|
self.assertIsNone(
|
||||||
validator.check('LgeGrrrrJAxyXprrPrrBrrX5Qrrrrrrrrd', 'fake.app.id')
|
validator.check('LgeGrrrrJAxyXprrPrrBrrX5Qrrrrrrrrd', 'fake.app.id')
|
||||||
|
@ -180,9 +178,30 @@ class MetadataTest(unittest.TestCase):
|
||||||
'fake.app.id',
|
'fake.app.id',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_check_metadata_AntiFeatures(self):
|
||||||
|
fdroidserver.metadata.warnings_action = 'error'
|
||||||
|
|
||||||
|
app = fdroidserver.metadata.App()
|
||||||
|
self.assertIsNone(metadata.check_metadata(app))
|
||||||
|
|
||||||
|
app['AntiFeatures'] = []
|
||||||
|
self.assertIsNone(metadata.check_metadata(app))
|
||||||
|
|
||||||
|
app['AntiFeatures'] = ['Ads', 'UpstreamNonFree']
|
||||||
|
self.assertIsNone(metadata.check_metadata(app))
|
||||||
|
|
||||||
|
app['AntiFeatures'] = ['Ad']
|
||||||
|
with self.assertRaises(fdroidserver.exception.MetaDataException):
|
||||||
|
metadata.check_metadata(app)
|
||||||
|
|
||||||
|
app['AntiFeatures'] = ['Adss']
|
||||||
|
with self.assertRaises(fdroidserver.exception.MetaDataException):
|
||||||
|
metadata.check_metadata(app)
|
||||||
|
|
||||||
def test_valid_funding_yml_regex(self):
|
def test_valid_funding_yml_regex(self):
|
||||||
"""Check the regex can find all the cases"""
|
"""Check the regex can find all the cases"""
|
||||||
with (self.basedir / 'funding-usernames.yaml').open() as fp:
|
with (self.basedir / 'funding-usernames.yaml').open() as fp:
|
||||||
|
yaml = ruamel.yaml.YAML(typ='safe')
|
||||||
data = yaml.load(fp)
|
data = yaml.load(fp)
|
||||||
|
|
||||||
for k, entries in data.items():
|
for k, entries in data.items():
|
||||||
|
@ -200,10 +219,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_read_metadata(self):
|
def test_read_metadata(self):
|
||||||
def _build_yaml_representer(dumper, data):
|
"""Read specified metadata files included in tests/, compare to stored output"""
|
||||||
'''Creates a YAML representation of a Build instance'''
|
|
||||||
return dumper.represent_dict(data)
|
|
||||||
|
|
||||||
self.maxDiff = None
|
self.maxDiff = None
|
||||||
|
|
||||||
config = dict()
|
config = dict()
|
||||||
|
@ -211,6 +227,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
fdroidserver.common.config = config
|
fdroidserver.common.config = config
|
||||||
fdroidserver.metadata.warnings_action = None
|
fdroidserver.metadata.warnings_action = None
|
||||||
|
|
||||||
|
yaml = ruamel.yaml.YAML(typ='safe')
|
||||||
apps = fdroidserver.metadata.read_metadata()
|
apps = fdroidserver.metadata.read_metadata()
|
||||||
for appid in (
|
for appid in (
|
||||||
'org.smssecure.smssecure',
|
'org.smssecure.smssecure',
|
||||||
|
@ -226,9 +243,10 @@ class MetadataTest(unittest.TestCase):
|
||||||
self.assertEqual(frommeta, from_yaml)
|
self.assertEqual(frommeta, from_yaml)
|
||||||
# comment above assert and uncomment below to update test
|
# comment above assert and uncomment below to update test
|
||||||
# files when new metadata fields are added
|
# files when new metadata fields are added
|
||||||
# with savepath.open('w') as f:
|
# with savepath.open('w') as fp:
|
||||||
# yaml.add_representer(fdroidserver.metadata.Build, _build_yaml_representer)
|
# yaml.default_flow_style = False
|
||||||
# yaml.dump(frommeta, f, default_flow_style=False)
|
# yaml.register_class(metadata.Build)
|
||||||
|
# yaml.dump(frommeta, fp)
|
||||||
|
|
||||||
def test_rewrite_yaml_fakeotaupdate(self):
|
def test_rewrite_yaml_fakeotaupdate(self):
|
||||||
with tempfile.TemporaryDirectory() as testdir:
|
with tempfile.TemporaryDirectory() as testdir:
|
||||||
|
@ -306,7 +324,20 @@ class MetadataTest(unittest.TestCase):
|
||||||
self.assertEqual('true', metadata._normalize_type_string(True))
|
self.assertEqual('true', metadata._normalize_type_string(True))
|
||||||
|
|
||||||
def test_post_parse_yaml_metadata(self):
|
def test_post_parse_yaml_metadata(self):
|
||||||
fdroidserver.metadata.warnings_action = 'error'
|
yamldata = dict()
|
||||||
|
metadata.post_parse_yaml_metadata(yamldata)
|
||||||
|
|
||||||
|
yamldata[
|
||||||
|
'AllowedAPKSigningKeys'
|
||||||
|
] = 'c03dac71394d6c26766f1b04d3e31cfcac5d03b55d8aa40cc9b9fa6b74354c66'
|
||||||
|
metadata.post_parse_yaml_metadata(yamldata)
|
||||||
|
|
||||||
|
def test_post_parse_yaml_metadata_fails(self):
|
||||||
|
yamldata = {'AllowedAPKSigningKeys': True}
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
metadata.post_parse_yaml_metadata(yamldata)
|
||||||
|
|
||||||
|
def test_post_parse_yaml_metadata_builds(self):
|
||||||
yamldata = OrderedDict()
|
yamldata = OrderedDict()
|
||||||
builds = []
|
builds = []
|
||||||
yamldata['Builds'] = builds
|
yamldata['Builds'] = builds
|
||||||
|
@ -380,17 +411,45 @@ class MetadataTest(unittest.TestCase):
|
||||||
self.assertEqual(randomlist, allappids)
|
self.assertEqual(randomlist, allappids)
|
||||||
|
|
||||||
def test_parse_yaml_metadata_0size_file(self):
|
def test_parse_yaml_metadata_0size_file(self):
|
||||||
mf = io.StringIO('')
|
self.assertEqual(dict(), metadata.parse_yaml_metadata(_get_mock_mf('')))
|
||||||
mf.name = 'mock_filename.yaml'
|
|
||||||
self.assertEqual(fdroidserver.metadata.parse_yaml_metadata(mf), dict())
|
|
||||||
|
|
||||||
def test_parse_yaml_metadata_empty_dict_file(self):
|
def test_parse_yaml_metadata_empty_dict_file(self):
|
||||||
mf = io.StringIO('{}')
|
self.assertEqual(dict(), metadata.parse_yaml_metadata(_get_mock_mf('{}')))
|
||||||
mf.name = 'mock_filename.yaml'
|
|
||||||
self.assertEqual(fdroidserver.metadata.parse_yaml_metadata(mf), dict())
|
|
||||||
|
|
||||||
def test_parse_yaml_metadata_empty_string_file(self):
|
def test_parse_yaml_metadata_empty_string_file(self):
|
||||||
mf = io.StringIO('""')
|
self.assertEqual(dict(), metadata.parse_yaml_metadata(_get_mock_mf('""')))
|
||||||
|
|
||||||
|
def test_parse_yaml_metadata_fail_on_root_list(self):
|
||||||
|
with self.assertRaises(MetaDataException):
|
||||||
|
metadata.parse_yaml_metadata(_get_mock_mf('-'))
|
||||||
|
with self.assertRaises(MetaDataException):
|
||||||
|
metadata.parse_yaml_metadata(_get_mock_mf('[]'))
|
||||||
|
with self.assertRaises(MetaDataException):
|
||||||
|
metadata.parse_yaml_metadata(_get_mock_mf('- AutoName: fake'))
|
||||||
|
|
||||||
|
def test_parse_yaml_metadata_type_list_str(self):
|
||||||
|
v = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
|
||||||
|
mf = _get_mock_mf('AllowedAPKSigningKeys: "%s"' % v)
|
||||||
|
self.assertEqual(
|
||||||
|
v,
|
||||||
|
metadata.parse_yaml_metadata(mf)['AllowedAPKSigningKeys'][0],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_parse_yaml_metadata_type_list_build_str(self):
|
||||||
|
mf = _get_mock_mf('Builds: [{versionCode: 1, rm: s}]')
|
||||||
|
self.assertEqual(
|
||||||
|
metadata.parse_yaml_metadata(mf),
|
||||||
|
{'Builds': [{'rm': ['s'], 'versionCode': 1}]},
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_parse_yaml_metadata_app_type_list_fails(self):
|
||||||
|
mf = _get_mock_mf('AllowedAPKSigningKeys: true')
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
metadata.parse_yaml_metadata(mf)
|
||||||
|
mf = _get_mock_mf('AllowedAPKSigningKeys: 1')
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
metadata.parse_yaml_metadata(mf)
|
||||||
|
|
||||||
mf.name = 'mock_filename.yaml'
|
mf.name = 'mock_filename.yaml'
|
||||||
self.assertEqual(fdroidserver.metadata.parse_yaml_metadata(mf), dict())
|
self.assertEqual(fdroidserver.metadata.parse_yaml_metadata(mf), dict())
|
||||||
|
|
||||||
|
@ -405,9 +464,8 @@ class MetadataTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
mf.name = 'mock_filename.yaml'
|
mf.name = 'mock_filename.yaml'
|
||||||
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
with self.assertRaises(MetaDataException):
|
||||||
with self.assertRaises(MetaDataException):
|
fdroidserver.metadata.parse_yaml_metadata(mf)
|
||||||
fdroidserver.metadata.parse_yaml_metadata(mf)
|
|
||||||
|
|
||||||
def test_parse_yaml_metadata_unknown_build_flag(self):
|
def test_parse_yaml_metadata_unknown_build_flag(self):
|
||||||
mf = io.StringIO(
|
mf = io.StringIO(
|
||||||
|
@ -420,9 +478,8 @@ class MetadataTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
mf.name = 'mock_filename.yaml'
|
mf.name = 'mock_filename.yaml'
|
||||||
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
with self.assertRaises(MetaDataException):
|
||||||
with self.assertRaises(MetaDataException):
|
fdroidserver.metadata.parse_yaml_metadata(mf)
|
||||||
fdroidserver.metadata.parse_yaml_metadata(mf)
|
|
||||||
|
|
||||||
def test_parse_yaml_metadata_continue_on_warning(self):
|
def test_parse_yaml_metadata_continue_on_warning(self):
|
||||||
"""When errors are disabled, parsing should provide something that can work.
|
"""When errors are disabled, parsing should provide something that can work.
|
||||||
|
@ -436,8 +493,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
fdroidserver.metadata.warnings_action = None
|
fdroidserver.metadata.warnings_action = None
|
||||||
mf = io.StringIO('[AntiFeatures: Tracking]')
|
mf = _get_mock_mf('[AntiFeatures: Tracking]')
|
||||||
mf.name = 'mock_filename.yaml'
|
|
||||||
self.assertEqual(fdroidserver.metadata.parse_yaml_metadata(mf), dict())
|
self.assertEqual(fdroidserver.metadata.parse_yaml_metadata(mf), dict())
|
||||||
|
|
||||||
def test_parse_yaml_srclib_corrupt_file(self):
|
def test_parse_yaml_srclib_corrupt_file(self):
|
||||||
|
@ -454,9 +510,8 @@ class MetadataTest(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
with self.assertRaises(MetaDataException):
|
||||||
with self.assertRaises(MetaDataException):
|
fdroidserver.metadata.parse_yaml_srclib(srclibfile)
|
||||||
fdroidserver.metadata.parse_yaml_srclib(srclibfile)
|
|
||||||
|
|
||||||
def test_write_yaml_with_placeholder_values(self):
|
def test_write_yaml_with_placeholder_values(self):
|
||||||
mf = io.StringIO()
|
mf = io.StringIO()
|
||||||
|
@ -535,8 +590,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
mf.name = 'mock_filename.yaml'
|
mf.name = 'mock_filename.yaml'
|
||||||
mf.seek(0)
|
mf.seek(0)
|
||||||
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
result = fdroidserver.metadata.parse_yaml_metadata(mf)
|
||||||
result = fdroidserver.metadata.parse_yaml_metadata(mf)
|
|
||||||
self.maxDiff = None
|
self.maxDiff = None
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
result,
|
result,
|
||||||
|
@ -590,8 +644,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
mf.name = 'mock_filename.yaml'
|
mf.name = 'mock_filename.yaml'
|
||||||
mf.seek(0)
|
mf.seek(0)
|
||||||
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
result = fdroidserver.metadata.parse_yaml_metadata(mf)
|
||||||
result = fdroidserver.metadata.parse_yaml_metadata(mf)
|
|
||||||
self.maxDiff = None
|
self.maxDiff = None
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
result,
|
result,
|
||||||
|
@ -640,8 +693,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
mf.name = 'mock_filename.yaml'
|
mf.name = 'mock_filename.yaml'
|
||||||
mf.seek(0)
|
mf.seek(0)
|
||||||
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
result = fdroidserver.metadata.parse_yaml_metadata(mf)
|
||||||
result = fdroidserver.metadata.parse_yaml_metadata(mf)
|
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
result,
|
result,
|
||||||
{
|
{
|
||||||
|
@ -674,10 +726,9 @@ class MetadataTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
mf.name = 'mock_filename.yaml'
|
mf.name = 'mock_filename.yaml'
|
||||||
mf.seek(0)
|
mf.seek(0)
|
||||||
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
result = fdroidserver.metadata.parse_yaml_metadata(mf)
|
||||||
result = fdroidserver.metadata.parse_yaml_metadata(mf)
|
self.assertNotIn('Provides', result)
|
||||||
self.assertNotIn('Provides', result)
|
self.assertNotIn('provides', result)
|
||||||
self.assertNotIn('provides', result)
|
|
||||||
|
|
||||||
def test_write_yaml_1_line_scripts_as_string(self):
|
def test_write_yaml_1_line_scripts_as_string(self):
|
||||||
mf = io.StringIO()
|
mf = io.StringIO()
|
||||||
|
@ -903,7 +954,6 @@ class MetadataTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_parse_yaml_srclib_unknown_key(self):
|
def test_parse_yaml_srclib_unknown_key(self):
|
||||||
fdroidserver.metadata.warnings_action = 'error'
|
|
||||||
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
||||||
with Path('test.yml').open('w', encoding='utf-8') as f:
|
with Path('test.yml').open('w', encoding='utf-8') as f:
|
||||||
f.write(
|
f.write(
|
||||||
|
@ -922,7 +972,6 @@ class MetadataTest(unittest.TestCase):
|
||||||
fdroidserver.metadata.parse_yaml_srclib(Path('test.yml'))
|
fdroidserver.metadata.parse_yaml_srclib(Path('test.yml'))
|
||||||
|
|
||||||
def test_parse_yaml_srclib_does_not_exists(self):
|
def test_parse_yaml_srclib_does_not_exists(self):
|
||||||
fdroidserver.metadata.warnings_action = 'error'
|
|
||||||
with self.assertRaisesRegex(
|
with self.assertRaisesRegex(
|
||||||
MetaDataException,
|
MetaDataException,
|
||||||
"Invalid scrlib metadata: "
|
"Invalid scrlib metadata: "
|
||||||
|
@ -934,7 +983,6 @@ class MetadataTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_parse_yaml_srclib_simple(self):
|
def test_parse_yaml_srclib_simple(self):
|
||||||
fdroidserver.metadata.warnings_action = 'error'
|
|
||||||
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
||||||
with Path('simple.yml').open('w', encoding='utf-8') as f:
|
with Path('simple.yml').open('w', encoding='utf-8') as f:
|
||||||
f.write(
|
f.write(
|
||||||
|
@ -958,7 +1006,6 @@ class MetadataTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_parse_yaml_srclib_simple_with_blanks(self):
|
def test_parse_yaml_srclib_simple_with_blanks(self):
|
||||||
fdroidserver.metadata.warnings_action = 'error'
|
|
||||||
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
||||||
with Path('simple.yml').open('w', encoding='utf-8') as f:
|
with Path('simple.yml').open('w', encoding='utf-8') as f:
|
||||||
f.write(
|
f.write(
|
||||||
|
@ -988,7 +1035,6 @@ class MetadataTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_parse_yaml_srclib_Changelog_cketti(self):
|
def test_parse_yaml_srclib_Changelog_cketti(self):
|
||||||
fdroidserver.metadata.warnings_action = 'error'
|
|
||||||
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
||||||
with Path('Changelog-cketti.yml').open('w', encoding='utf-8') as f:
|
with Path('Changelog-cketti.yml').open('w', encoding='utf-8') as f:
|
||||||
f.write(
|
f.write(
|
||||||
|
@ -1020,7 +1066,6 @@ class MetadataTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_read_srclibs_yml_subdir_list(self):
|
def test_read_srclibs_yml_subdir_list(self):
|
||||||
fdroidserver.metadata.warnings_action = 'error'
|
|
||||||
fdroidserver.metadata.srclibs = None
|
fdroidserver.metadata.srclibs = None
|
||||||
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
||||||
Path('srclibs').mkdir()
|
Path('srclibs').mkdir()
|
||||||
|
@ -1072,7 +1117,6 @@ class MetadataTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_read_srclibs_yml_prepare_list(self):
|
def test_read_srclibs_yml_prepare_list(self):
|
||||||
fdroidserver.metadata.warnings_action = 'error'
|
|
||||||
fdroidserver.metadata.srclibs = None
|
fdroidserver.metadata.srclibs = None
|
||||||
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
||||||
Path('srclibs').mkdir()
|
Path('srclibs').mkdir()
|
||||||
|
@ -1113,7 +1157,6 @@ class MetadataTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_read_srclibs(self):
|
def test_read_srclibs(self):
|
||||||
fdroidserver.metadata.warnings_action = 'error'
|
|
||||||
fdroidserver.metadata.srclibs = None
|
fdroidserver.metadata.srclibs = None
|
||||||
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
||||||
Path('srclibs').mkdir()
|
Path('srclibs').mkdir()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
AllowedAPKSigningKeys: []
|
AllowedAPKSigningKeys: []
|
||||||
AntiFeatures: ['NonFreeNet']
|
AntiFeatures:
|
||||||
|
- NonFreeNet
|
||||||
ArchivePolicy: 4 versions
|
ArchivePolicy: 4 versions
|
||||||
AuthorEmail: null
|
AuthorEmail: null
|
||||||
AuthorName: null
|
AuthorName: null
|
||||||
|
@ -130,7 +131,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
|
|
@ -15,7 +15,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: ea5378a94ee0dc1d99d2cec95fae7e6d81afb2b9
|
commit: ea5378a94ee0dc1d99d2cec95fae7e6d81afb2b9
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -51,7 +51,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: 4128e59da2eac5c2904c7c7568d298ca51e79540
|
commit: 4128e59da2eac5c2904c7c7568d298ca51e79540
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -88,7 +88,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: 0b9985398b9eef7baf6aadd0dbb12002bc199d2e
|
commit: 0b9985398b9eef7baf6aadd0dbb12002bc199d2e
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -125,7 +125,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: ab27f4dab5f3ea5e228cfb4a6b0e1fbf53695f22
|
commit: ab27f4dab5f3ea5e228cfb4a6b0e1fbf53695f22
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -162,7 +162,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: 695e3801e4081026c8f7213a2345fc451d5eb89c
|
commit: 695e3801e4081026c8f7213a2345fc451d5eb89c
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -199,7 +199,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: 65138c11cc8b6affd28b68e125fbc1dff0886a4e
|
commit: 65138c11cc8b6affd28b68e125fbc1dff0886a4e
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -271,7 +271,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: f811e53e1e1d2ee047b18715fd7d2072b90ae76b
|
commit: f811e53e1e1d2ee047b18715fd7d2072b90ae76b
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -308,7 +308,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: ff97932761cdee68638dc2550751a64b2cbe18e7
|
commit: ff97932761cdee68638dc2550751a64b2cbe18e7
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -345,7 +345,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: 33d4d80998f30bafc88c04c80cbae00b03916f99
|
commit: 33d4d80998f30bafc88c04c80cbae00b03916f99
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -382,7 +382,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: 743d25a7e287505461f33f4b8e57e4cf988fffea
|
commit: 743d25a7e287505461f33f4b8e57e4cf988fffea
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -419,7 +419,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: eaa07f4
|
commit: eaa07f4
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -688,7 +688,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: v2.1
|
commit: v2.1
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -738,7 +738,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: v2.3
|
commit: v2.3
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -784,7 +784,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: v2.6
|
commit: v2.6
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -792,7 +792,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
@ -822,7 +822,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: v2.7
|
commit: v2.7
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -830,7 +830,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
@ -860,7 +860,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: v2.8
|
commit: v2.8
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -868,7 +868,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
@ -898,7 +898,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: v2.8.1
|
commit: v2.8.1
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -906,7 +906,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
@ -936,7 +936,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: v2.9
|
commit: v2.9
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -944,7 +944,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
@ -974,7 +974,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: v2.9.1
|
commit: v2.9.1
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -982,7 +982,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
@ -1012,7 +1012,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: v2.9.2
|
commit: v2.9.2
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -1020,7 +1020,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
@ -1050,7 +1050,7 @@ Builds:
|
||||||
binary: null
|
binary: null
|
||||||
build: ''
|
build: ''
|
||||||
buildjni:
|
buildjni:
|
||||||
- 'yes'
|
- yes
|
||||||
commit: v3.0
|
commit: v3.0
|
||||||
disable: ''
|
disable: ''
|
||||||
encoding: null
|
encoding: null
|
||||||
|
@ -1058,7 +1058,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
|
|
@ -22,7 +22,7 @@ Builds:
|
||||||
forcevercode: true
|
forcevercode: true
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
@ -83,7 +83,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
@ -126,7 +126,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
@ -167,7 +167,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
@ -208,7 +208,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
@ -248,7 +248,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
@ -288,7 +288,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
@ -328,7 +328,7 @@ Builds:
|
||||||
forcevercode: false
|
forcevercode: false
|
||||||
forceversion: false
|
forceversion: false
|
||||||
gradle:
|
gradle:
|
||||||
- 'yes'
|
- yes
|
||||||
gradleprops: []
|
gradleprops: []
|
||||||
init: ''
|
init: ''
|
||||||
maven: null
|
maven: null
|
||||||
|
|
|
@ -2640,7 +2640,7 @@ UpdateCheckIgnore: null
|
||||||
UpdateCheckMode: Tags
|
UpdateCheckMode: Tags
|
||||||
UpdateCheckName: null
|
UpdateCheckName: null
|
||||||
VercodeOperation:
|
VercodeOperation:
|
||||||
- '%c + 5'
|
- '%c + 5'
|
||||||
WebSite: http://www.videolan.org/vlc/download-android.html
|
WebSite: http://www.videolan.org/vlc/download-android.html
|
||||||
added: null
|
added: null
|
||||||
id: org.videolan.vlc
|
id: org.videolan.vlc
|
||||||
|
|
|
@ -7,10 +7,8 @@ import sys
|
||||||
import unittest
|
import unittest
|
||||||
import tempfile
|
import tempfile
|
||||||
import textwrap
|
import textwrap
|
||||||
from unittest import mock
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
from testcommon import TmpCwd
|
from testcommon import TmpCwd
|
||||||
|
|
||||||
localmodule = Path(__file__).resolve().parent.parent
|
localmodule = Path(__file__).resolve().parent.parent
|
||||||
|
@ -20,7 +18,6 @@ if localmodule not in sys.path:
|
||||||
|
|
||||||
from fdroidserver import common
|
from fdroidserver import common
|
||||||
from fdroidserver import rewritemeta
|
from fdroidserver import rewritemeta
|
||||||
from fdroidserver.exception import FDroidException
|
|
||||||
|
|
||||||
|
|
||||||
class RewriteMetaTest(unittest.TestCase):
|
class RewriteMetaTest(unittest.TestCase):
|
||||||
|
@ -71,24 +68,6 @@ class RewriteMetaTest(unittest.TestCase):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_rewrite_scenario_yml_no_ruamel(self):
|
|
||||||
sys.argv = ['rewritemeta', 'a']
|
|
||||||
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
|
||||||
Path('metadata').mkdir()
|
|
||||||
with Path('metadata/a.yml').open('w') as f:
|
|
||||||
f.write('AutoName: a')
|
|
||||||
|
|
||||||
def boom(*args):
|
|
||||||
raise FDroidException(' '.join((str(x) for x in args)))
|
|
||||||
|
|
||||||
with mock.patch('importlib.util.find_spec', boom):
|
|
||||||
with self.assertRaises(FDroidException):
|
|
||||||
rewritemeta.main()
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
Path('metadata/a.yml').read_text(encoding='utf-8'), 'AutoName: a'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = optparse.OptionParser()
|
parser = optparse.OptionParser()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue