mirror of
https://github.com/f-droid/fdroidserver.git
synced 2025-11-04 22:40:29 +03:00
Merge branch 'api-fixes' into 'master'
API fixes to work with plain dicts read by any YAML parser Closes #851 See merge request fdroid/fdroidserver!838
This commit is contained in:
commit
03aba988b2
19 changed files with 287 additions and 289 deletions
|
|
@ -25,7 +25,7 @@ metadata_v0:
|
||||||
image: registry.gitlab.com/fdroid/ci-images-base
|
image: registry.gitlab.com/fdroid/ci-images-base
|
||||||
variables:
|
variables:
|
||||||
GIT_DEPTH: 1000
|
GIT_DEPTH: 1000
|
||||||
RELEASE_COMMIT_ID: 37f37ebd88e79ebe93239b72ed5503d5bde13f4b # 2.0a~
|
RELEASE_COMMIT_ID: 37c95f59a17d86723fdb71e984121726db777f32 # 2.0a5~
|
||||||
script:
|
script:
|
||||||
- git fetch https://gitlab.com/fdroid/fdroidserver.git $RELEASE_COMMIT_ID
|
- git fetch https://gitlab.com/fdroid/fdroidserver.git $RELEASE_COMMIT_ID
|
||||||
- cd tests
|
- cd tests
|
||||||
|
|
|
||||||
|
|
@ -1017,7 +1017,7 @@ def main():
|
||||||
apps = common.read_app_args(options.appid, allapps, True)
|
apps = common.read_app_args(options.appid, allapps, True)
|
||||||
|
|
||||||
for appid, app in list(apps.items()):
|
for appid, app in list(apps.items()):
|
||||||
if (app.Disabled and not options.force) or not app.RepoType or not app.builds:
|
if (app.get('Disabled') and not options.force) or not app.get('RepoType') or not app.get('Builds', []):
|
||||||
del apps[appid]
|
del apps[appid]
|
||||||
|
|
||||||
if not apps:
|
if not apps:
|
||||||
|
|
@ -1038,10 +1038,10 @@ def main():
|
||||||
|
|
||||||
if options.latest:
|
if options.latest:
|
||||||
for app in apps.values():
|
for app in apps.values():
|
||||||
for build in reversed(app.builds):
|
for build in reversed(app.get('Builds', [])):
|
||||||
if build.disable and not options.force:
|
if build.disable and not options.force:
|
||||||
continue
|
continue
|
||||||
app.builds = [build]
|
app['Builds'] = [build]
|
||||||
break
|
break
|
||||||
|
|
||||||
if options.wiki:
|
if options.wiki:
|
||||||
|
|
@ -1062,7 +1062,7 @@ def main():
|
||||||
|
|
||||||
first = True
|
first = True
|
||||||
|
|
||||||
for build in app.builds:
|
for build in app.get('Builds', []):
|
||||||
if time.time() > endtime:
|
if time.time() > endtime:
|
||||||
max_build_time_reached = True
|
max_build_time_reached = True
|
||||||
break
|
break
|
||||||
|
|
|
||||||
|
|
@ -221,8 +221,8 @@ def check_repomanifest(app, branch=None):
|
||||||
vcs.gotorevision(None)
|
vcs.gotorevision(None)
|
||||||
|
|
||||||
last_build = metadata.Build()
|
last_build = metadata.Build()
|
||||||
if len(app.builds) > 0:
|
if len(app.get('Builds', [])) > 0:
|
||||||
last_build = app.builds[-1]
|
last_build = app.get('Builds', [])[-1]
|
||||||
|
|
||||||
try_init_submodules(app, last_build, vcs)
|
try_init_submodules(app, last_build, vcs)
|
||||||
|
|
||||||
|
|
@ -506,7 +506,7 @@ def checkupdates_app(app):
|
||||||
|
|
||||||
gotcur = False
|
gotcur = False
|
||||||
latest = None
|
latest = None
|
||||||
for build in app.builds:
|
for build in app.get('Builds', []):
|
||||||
if int(build.versionCode) >= int(app.CurrentVersionCode):
|
if int(build.versionCode) >= int(app.CurrentVersionCode):
|
||||||
gotcur = True
|
gotcur = True
|
||||||
if not latest or int(build.versionCode) > int(latest.versionCode):
|
if not latest or int(build.versionCode) > int(latest.versionCode):
|
||||||
|
|
@ -524,7 +524,7 @@ def checkupdates_app(app):
|
||||||
commit = pattern.replace('%v', app.CurrentVersion)
|
commit = pattern.replace('%v', app.CurrentVersion)
|
||||||
commit = commit.replace('%c', newbuild.versionCode)
|
commit = commit.replace('%c', newbuild.versionCode)
|
||||||
newbuild.commit = commit
|
newbuild.commit = commit
|
||||||
app.builds.append(newbuild)
|
app['Builds'].append(newbuild)
|
||||||
name = _getappname(app)
|
name = _getappname(app)
|
||||||
ver = _getcvname(app)
|
ver = _getcvname(app)
|
||||||
commitmsg = "Update %s to %s" % (name, ver)
|
commitmsg = "Update %s to %s" % (name, ver)
|
||||||
|
|
|
||||||
|
|
@ -641,10 +641,10 @@ def read_app_args(appid_versionCode_pairs, allapps, allow_vercodes=False):
|
||||||
vc = vercodes[appid]
|
vc = vercodes[appid]
|
||||||
if not vc:
|
if not vc:
|
||||||
continue
|
continue
|
||||||
app.builds = [b for b in app.builds if b.versionCode in vc]
|
app['Builds'] = [b for b in app.get('Builds', []) if b.versionCode in vc]
|
||||||
if len(app.builds) != len(vercodes[appid]):
|
if len(app.get('Builds', [])) != len(vercodes[appid]):
|
||||||
error = True
|
error = True
|
||||||
allvcs = [b.versionCode for b in app.builds]
|
allvcs = [b.versionCode for b in app.get('Builds', [])]
|
||||||
for v in vercodes[appid]:
|
for v in vercodes[appid]:
|
||||||
if v not in allvcs:
|
if v not in allvcs:
|
||||||
logging.critical(_("No such versionCode {versionCode} for app {appid}")
|
logging.critical(_("No such versionCode {versionCode} for app {appid}")
|
||||||
|
|
@ -1538,8 +1538,8 @@ def parse_androidmanifests(paths, app):
|
||||||
flavour = None
|
flavour = None
|
||||||
temp_app_id = None
|
temp_app_id = None
|
||||||
temp_version_name = None
|
temp_version_name = None
|
||||||
if app.builds and 'gradle' in app.builds[-1] and app.builds[-1].gradle:
|
if len(app.get('Builds', [])) > 0 and 'gradle' in app['Builds'][-1] and app['Builds'][-1].gradle:
|
||||||
flavour = app.builds[-1].gradle[-1]
|
flavour = app['Builds'][-1].gradle[-1]
|
||||||
|
|
||||||
if path.endswith('.gradle') or path.endswith('.gradle.kts'):
|
if path.endswith('.gradle') or path.endswith('.gradle.kts'):
|
||||||
with open(path, 'r') as f:
|
with open(path, 'r') as f:
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,7 @@ def main():
|
||||||
|
|
||||||
metadata.post_metadata_parse(app)
|
metadata.post_metadata_parse(app)
|
||||||
|
|
||||||
app.builds.append(build)
|
app['Builds'].append(build)
|
||||||
|
|
||||||
if write_local_file:
|
if write_local_file:
|
||||||
metadata.write_metadata('.fdroid.yml', app)
|
metadata.write_metadata('.fdroid.yml', app)
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
|
||||||
for k, v in sorted(appdict.items()):
|
for k, v in sorted(appdict.items()):
|
||||||
if not v:
|
if not v:
|
||||||
continue
|
continue
|
||||||
if k in ('builds', 'comments', 'metadatapath',
|
if k in ('Builds', 'comments', 'metadatapath',
|
||||||
'ArchivePolicy', 'AutoUpdateMode', 'MaintainerNotes',
|
'ArchivePolicy', 'AutoUpdateMode', 'MaintainerNotes',
|
||||||
'Provides', 'Repo', 'RepoType', 'RequiresRoot',
|
'Provides', 'Repo', 'RepoType', 'RequiresRoot',
|
||||||
'UpdateCheckData', 'UpdateCheckIgnore', 'UpdateCheckMode',
|
'UpdateCheckData', 'UpdateCheckIgnore', 'UpdateCheckMode',
|
||||||
|
|
@ -201,7 +201,7 @@ def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
|
||||||
if not package.get('versionName'):
|
if not package.get('versionName'):
|
||||||
app = apps[packageName]
|
app = apps[packageName]
|
||||||
versionCodeStr = str(package['versionCode']) # TODO build.versionCode should be int!
|
versionCodeStr = str(package['versionCode']) # TODO build.versionCode should be int!
|
||||||
for build in app['builds']:
|
for build in app.get('Builds', []):
|
||||||
if build['versionCode'] == versionCodeStr:
|
if build['versionCode'] == versionCodeStr:
|
||||||
versionName = build.get('versionName')
|
versionName = build.get('versionName')
|
||||||
logging.info(_('Overriding blank versionName in {apkfilename} from metadata: {version}')
|
logging.info(_('Overriding blank versionName in {apkfilename} from metadata: {version}')
|
||||||
|
|
@ -358,7 +358,7 @@ def make_v0(apps, apks, repodir, repodict, requestsdict, fdroid_signing_key_fing
|
||||||
for appid, appdict in apps.items():
|
for appid, appdict in apps.items():
|
||||||
app = metadata.App(appdict)
|
app = metadata.App(appdict)
|
||||||
|
|
||||||
if app.Disabled is not None:
|
if app.get('Disabled') is not None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Get a list of the apks for this app...
|
# Get a list of the apks for this app...
|
||||||
|
|
@ -477,7 +477,7 @@ def make_v0(apps, apks, repodir, repodict, requestsdict, fdroid_signing_key_fing
|
||||||
versionName = apk.get('versionName')
|
versionName = apk.get('versionName')
|
||||||
if not versionName:
|
if not versionName:
|
||||||
versionCodeStr = str(apk['versionCode']) # TODO build.versionCode should be int!
|
versionCodeStr = str(apk['versionCode']) # TODO build.versionCode should be int!
|
||||||
for build in app.builds:
|
for build in app.get('Builds', []):
|
||||||
if build['versionCode'] == versionCodeStr and 'versionName' in build:
|
if build['versionCode'] == versionCodeStr and 'versionName' in build:
|
||||||
versionName = build['versionName']
|
versionName = build['versionName']
|
||||||
break
|
break
|
||||||
|
|
|
||||||
|
|
@ -234,7 +234,7 @@ def check_vercode_operation(app):
|
||||||
|
|
||||||
|
|
||||||
def check_ucm_tags(app):
|
def check_ucm_tags(app):
|
||||||
lastbuild = get_lastbuild(app.builds)
|
lastbuild = get_lastbuild(app.get('Builds', []))
|
||||||
if (lastbuild is not None
|
if (lastbuild is not None
|
||||||
and lastbuild.commit
|
and lastbuild.commit
|
||||||
and app.UpdateCheckMode == 'RepoManifest'
|
and app.UpdateCheckMode == 'RepoManifest'
|
||||||
|
|
@ -389,7 +389,7 @@ def check_bulleted_lists(app):
|
||||||
def check_builds(app):
|
def check_builds(app):
|
||||||
supported_flags = set(metadata.build_flags)
|
supported_flags = set(metadata.build_flags)
|
||||||
# needed for YAML and JSON
|
# needed for YAML and JSON
|
||||||
for build in app.builds:
|
for build in app.get('Builds', []):
|
||||||
if build.disable:
|
if build.disable:
|
||||||
if build.disable.startswith('Generated by import.py'):
|
if build.disable.startswith('Generated by import.py'):
|
||||||
yield _("Build generated by `fdroid import` - remove disable line once ready")
|
yield _("Build generated by `fdroid import` - remove disable line once ready")
|
||||||
|
|
@ -424,7 +424,7 @@ def check_files_dir(app):
|
||||||
files.add(name)
|
files.add(name)
|
||||||
|
|
||||||
used = {'signatures', }
|
used = {'signatures', }
|
||||||
for build in app.builds:
|
for build in app.get('Builds', []):
|
||||||
for fname in build.patch:
|
for fname in build.patch:
|
||||||
if fname not in files:
|
if fname not in files:
|
||||||
yield _("Unknown file '{filename}' in build '{versionName}'")\
|
yield _("Unknown file '{filename}' in build '{versionName}'")\
|
||||||
|
|
@ -466,7 +466,7 @@ def check_extlib_dir(apps):
|
||||||
|
|
||||||
used = set()
|
used = set()
|
||||||
for app in apps:
|
for app in apps:
|
||||||
for build in app.builds:
|
for build in app.get('Builds', []):
|
||||||
for path in build.extlibs:
|
for path in build.extlibs:
|
||||||
if path not in unused_extlib_files:
|
if path not in unused_extlib_files:
|
||||||
yield _("{appid}: Unknown extlib {path} in build '{versionName}'")\
|
yield _("{appid}: Unknown extlib {path} in build '{versionName}'")\
|
||||||
|
|
@ -494,7 +494,7 @@ def check_app_field_types(app):
|
||||||
t = metadata.fieldtype(field)
|
t = metadata.fieldtype(field)
|
||||||
if v is None:
|
if v is None:
|
||||||
continue
|
continue
|
||||||
elif field == 'builds':
|
elif field == 'Builds':
|
||||||
if not isinstance(v, list):
|
if not isinstance(v, list):
|
||||||
yield(_("{appid}: {field} must be a '{type}', but it is a '{fieldtype}'!")
|
yield(_("{appid}: {field} must be a '{type}', but it is a '{fieldtype}'!")
|
||||||
.format(appid=app.id, field=field,
|
.format(appid=app.id, field=field,
|
||||||
|
|
@ -544,7 +544,7 @@ def check_current_version_code(app):
|
||||||
if cv is not None and int(cv) == 0:
|
if cv is not None and int(cv) == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
builds = app.get('builds')
|
builds = app.get('Builds')
|
||||||
active_builds = 0
|
active_builds = 0
|
||||||
min_versionCode = None
|
min_versionCode = None
|
||||||
if builds:
|
if builds:
|
||||||
|
|
@ -617,7 +617,7 @@ def main():
|
||||||
|
|
||||||
# run yamllint on srclib metadata
|
# run yamllint on srclib metadata
|
||||||
srclibs = set()
|
srclibs = set()
|
||||||
for build in app.builds:
|
for build in app.get('Builds', []):
|
||||||
for srclib in build.srclibs:
|
for srclib in build.srclibs:
|
||||||
srclibs.add(srclib)
|
srclibs.add(srclib)
|
||||||
for srclib in srclibs:
|
for srclib in srclibs:
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ class App(dict):
|
||||||
|
|
||||||
self.id = None
|
self.id = None
|
||||||
self.metadatapath = None
|
self.metadatapath = None
|
||||||
self.builds = []
|
self.Builds = []
|
||||||
self.comments = {}
|
self.comments = {}
|
||||||
self.added = None
|
self.added = None
|
||||||
self.lastUpdated = None
|
self.lastUpdated = None
|
||||||
|
|
@ -179,8 +179,8 @@ class App(dict):
|
||||||
raise AttributeError("No such attribute: " + name)
|
raise AttributeError("No such attribute: " + name)
|
||||||
|
|
||||||
def get_last_build(self):
|
def get_last_build(self):
|
||||||
if len(self.builds) > 0:
|
if len(self.Builds) > 0:
|
||||||
return self.builds[-1]
|
return self.Builds[-1]
|
||||||
else:
|
else:
|
||||||
return Build()
|
return Build()
|
||||||
|
|
||||||
|
|
@ -633,9 +633,6 @@ def post_metadata_parse(app):
|
||||||
if type(v) in (float, int):
|
if type(v) in (float, int):
|
||||||
app[k] = str(v)
|
app[k] = str(v)
|
||||||
|
|
||||||
if 'Builds' in app:
|
|
||||||
app['builds'] = app.pop('Builds')
|
|
||||||
|
|
||||||
if 'flavours' in app and app['flavours'] == [True]:
|
if 'flavours' in app and app['flavours'] == [True]:
|
||||||
app['flavours'] = 'yes'
|
app['flavours'] = 'yes'
|
||||||
|
|
||||||
|
|
@ -664,8 +661,8 @@ def post_metadata_parse(app):
|
||||||
_bool_allowed = ('maven', 'buildozer')
|
_bool_allowed = ('maven', 'buildozer')
|
||||||
|
|
||||||
builds = []
|
builds = []
|
||||||
if 'builds' in app:
|
if 'Builds' in app:
|
||||||
for build in app['builds']:
|
for build in app.get('Builds', []):
|
||||||
if not isinstance(build, Build):
|
if not isinstance(build, Build):
|
||||||
build = Build(build)
|
build = Build(build)
|
||||||
for k, v in build.items():
|
for k, v in build.items():
|
||||||
|
|
@ -693,7 +690,7 @@ def post_metadata_parse(app):
|
||||||
build[k] = str(v)
|
build[k] = str(v)
|
||||||
builds.append(build)
|
builds.append(build)
|
||||||
|
|
||||||
app.builds = sorted_builds(builds)
|
app['Builds'] = sorted_builds(builds)
|
||||||
|
|
||||||
|
|
||||||
# Parse metadata for a single application.
|
# Parse metadata for a single application.
|
||||||
|
|
@ -710,8 +707,6 @@ def post_metadata_parse(app):
|
||||||
#
|
#
|
||||||
# Known keys not originating from the metadata are:
|
# Known keys not originating from the metadata are:
|
||||||
#
|
#
|
||||||
# 'builds' - a list of dictionaries containing build information
|
|
||||||
# for each defined build
|
|
||||||
# 'comments' - a list of comments from the metadata file. Each is
|
# 'comments' - a list of comments from the metadata file. Each is
|
||||||
# a list of the form [field, comment] where field is
|
# a list of the form [field, comment] where field is
|
||||||
# the name of the field it preceded in the metadata
|
# the name of the field it preceded in the metadata
|
||||||
|
|
@ -771,8 +766,8 @@ def parse_metadata(metadatapath, check_vcs=False, refresh=True):
|
||||||
post_metadata_parse(app)
|
post_metadata_parse(app)
|
||||||
|
|
||||||
if not app.id:
|
if not app.id:
|
||||||
if app.builds:
|
if app.get('Builds'):
|
||||||
build = app.builds[-1]
|
build = app['Builds'][-1]
|
||||||
if build.subdir:
|
if build.subdir:
|
||||||
root_dir = build.subdir
|
root_dir = build.subdir
|
||||||
else:
|
else:
|
||||||
|
|
@ -925,9 +920,8 @@ def write_yaml(mf, app):
|
||||||
insert_newline = True
|
insert_newline = True
|
||||||
else:
|
else:
|
||||||
if app.get(field) or field == 'Builds':
|
if app.get(field) or field == 'Builds':
|
||||||
# .txt called it 'builds' internally, everywhere else its 'Builds'
|
|
||||||
if field == 'Builds':
|
if field == 'Builds':
|
||||||
if app.get('builds'):
|
if app.get('Builds'):
|
||||||
cm.update({field: _builds_to_yaml(app)})
|
cm.update({field: _builds_to_yaml(app)})
|
||||||
elif field == 'CurrentVersionCode':
|
elif field == 'CurrentVersionCode':
|
||||||
cm.update({field: _field_to_yaml(TYPE_INT, getattr(app, field))})
|
cm.update({field: _field_to_yaml(TYPE_INT, getattr(app, field))})
|
||||||
|
|
@ -945,7 +939,9 @@ def write_yaml(mf, app):
|
||||||
|
|
||||||
def _builds_to_yaml(app):
|
def _builds_to_yaml(app):
|
||||||
builds = ruamel.yaml.comments.CommentedSeq()
|
builds = ruamel.yaml.comments.CommentedSeq()
|
||||||
for build in app.builds:
|
for build in app.get('Builds', []):
|
||||||
|
if not isinstance(build, Build):
|
||||||
|
build = Build(build)
|
||||||
b = ruamel.yaml.comments.CommentedMap()
|
b = ruamel.yaml.comments.CommentedMap()
|
||||||
for field in build_flags:
|
for field in build_flags:
|
||||||
value = getattr(build, field)
|
value = getattr(build, field)
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ def main():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
newbuilds = []
|
newbuilds = []
|
||||||
for build in app.builds:
|
for build in app.get('Builds', []):
|
||||||
new = metadata.Build()
|
new = metadata.Build()
|
||||||
for k in metadata.build_flags:
|
for k in metadata.build_flags:
|
||||||
v = build[k]
|
v = build[k]
|
||||||
|
|
@ -86,7 +86,7 @@ def main():
|
||||||
continue
|
continue
|
||||||
new[k] = v
|
new[k] = v
|
||||||
newbuilds.append(new)
|
newbuilds.append(new)
|
||||||
app.builds = newbuilds
|
app['Builds'] = newbuilds
|
||||||
|
|
||||||
# rewrite to temporary file before overwriting existsing
|
# rewrite to temporary file before overwriting existsing
|
||||||
# file in case there's a bug in write_metadata
|
# file in case there's a bug in write_metadata
|
||||||
|
|
|
||||||
|
|
@ -420,7 +420,7 @@ def main():
|
||||||
else:
|
else:
|
||||||
build_dir = os.path.join('build', appid)
|
build_dir = os.path.join('build', appid)
|
||||||
|
|
||||||
if app.builds:
|
if app.get('Builds'):
|
||||||
logging.info(_("Processing {appid}").format(appid=appid))
|
logging.info(_("Processing {appid}").format(appid=appid))
|
||||||
# Set up vcs interface and make sure we have the latest code...
|
# Set up vcs interface and make sure we have the latest code...
|
||||||
vcs = common.getvcs(app.RepoType, app.Repo, build_dir)
|
vcs = common.getvcs(app.RepoType, app.Repo, build_dir)
|
||||||
|
|
@ -434,9 +434,9 @@ def main():
|
||||||
logging.warning(_('Scanner found {count} problems in {appid}:')
|
logging.warning(_('Scanner found {count} problems in {appid}:')
|
||||||
.format(count=count, appid=appid))
|
.format(count=count, appid=appid))
|
||||||
probcount += count
|
probcount += count
|
||||||
app.builds = []
|
app['Builds'] = []
|
||||||
|
|
||||||
for build in app.builds:
|
for build in app.get('Builds', []):
|
||||||
json_per_build = DEFAULT_JSON_PER_BUILD
|
json_per_build = DEFAULT_JSON_PER_BUILD
|
||||||
json_per_appid[build.versionCode] = json_per_build
|
json_per_appid[build.versionCode] = json_per_build
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,9 +157,8 @@ def status_update_json(apps, apks):
|
||||||
for apk in apks:
|
for apk in apks:
|
||||||
if apk['packageName'] == appid:
|
if apk['packageName'] == appid:
|
||||||
apklist.append(apk)
|
apklist.append(apk)
|
||||||
builds = app.get('builds', [])
|
|
||||||
validapks = 0
|
validapks = 0
|
||||||
for build in builds:
|
for build in app.get('Builds', []):
|
||||||
if not build.get('disable'):
|
if not build.get('disable'):
|
||||||
builtit = False
|
builtit = False
|
||||||
for apk in apklist:
|
for apk in apklist:
|
||||||
|
|
@ -248,13 +247,13 @@ def update_wiki(apps, apks):
|
||||||
buildfails = False
|
buildfails = False
|
||||||
for apk in apks:
|
for apk in apks:
|
||||||
if apk['packageName'] == appid:
|
if apk['packageName'] == appid:
|
||||||
if str(apk['versionCode']) == app.CurrentVersionCode:
|
if str(apk['versionCode']) == app.get('CurrentVersionCode'):
|
||||||
gotcurrentver = True
|
gotcurrentver = True
|
||||||
apklist.append(apk)
|
apklist.append(apk)
|
||||||
# Include ones we can't build, as a special case...
|
# Include ones we can't build, as a special case...
|
||||||
for build in app.builds:
|
for build in app.get('Builds', []):
|
||||||
if build.disable:
|
if build.disable:
|
||||||
if build.versionCode == app.CurrentVersionCode:
|
if build.versionCode == app.get('CurrentVersionCode'):
|
||||||
cantupdate = True
|
cantupdate = True
|
||||||
# TODO: Nasty: vercode is a string in the build, and an int elsewhere
|
# TODO: Nasty: vercode is a string in the build, and an int elsewhere
|
||||||
apklist.append({'versionCode': int(build.versionCode),
|
apklist.append({'versionCode': int(build.versionCode),
|
||||||
|
|
@ -273,7 +272,7 @@ def update_wiki(apps, apks):
|
||||||
'versionName': build.versionName,
|
'versionName': build.versionName,
|
||||||
'buildproblem': "The build for this version appears to have failed. Check the [[{0}/lastbuild_{1}|build log]].".format(appid, build.versionCode),
|
'buildproblem': "The build for this version appears to have failed. Check the [[{0}/lastbuild_{1}|build log]].".format(appid, build.versionCode),
|
||||||
})
|
})
|
||||||
if app.CurrentVersionCode == '0':
|
if app.get('CurrentVersionCode') == '0':
|
||||||
cantupdate = True
|
cantupdate = True
|
||||||
# Sort with most recent first...
|
# Sort with most recent first...
|
||||||
apklist = sorted(apklist, key=lambda apk: apk['versionCode'], reverse=True)
|
apklist = sorted(apklist, key=lambda apk: apk['versionCode'], reverse=True)
|
||||||
|
|
@ -411,7 +410,7 @@ def delete_disabled_builds(apps, apkcache, repodirs):
|
||||||
:param repodirs: the repo directories to process
|
:param repodirs: the repo directories to process
|
||||||
"""
|
"""
|
||||||
for appid, app in apps.items():
|
for appid, app in apps.items():
|
||||||
for build in app['builds']:
|
for build in app.get('Builds', []):
|
||||||
if not build.disable:
|
if not build.disable:
|
||||||
continue
|
continue
|
||||||
apkfilename = common.get_release_filename(app, build)
|
apkfilename = common.get_release_filename(app, build)
|
||||||
|
|
@ -742,7 +741,7 @@ def translate_per_build_anti_features(apps, apks):
|
||||||
antiFeatures = dict()
|
antiFeatures = dict()
|
||||||
for packageName, app in apps.items():
|
for packageName, app in apps.items():
|
||||||
d = dict()
|
d = dict()
|
||||||
for build in app['builds']:
|
for build in app.get('Builds', []):
|
||||||
afl = build.get('antifeatures')
|
afl = build.get('antifeatures')
|
||||||
if afl:
|
if afl:
|
||||||
d[int(build.versionCode)] = afl
|
d[int(build.versionCode)] = afl
|
||||||
|
|
@ -1022,8 +1021,8 @@ def copy_triple_t_store_metadata(apps):
|
||||||
if os.path.exists(p):
|
if os.path.exists(p):
|
||||||
gradle_subdirs.add(p)
|
gradle_subdirs.add(p)
|
||||||
flavors = set()
|
flavors = set()
|
||||||
if app.builds:
|
if app.get('Builds'):
|
||||||
flavors = app.builds[0].gradle
|
flavors = app['Builds'][0].gradle
|
||||||
for flavor in flavors:
|
for flavor in flavors:
|
||||||
if flavor not in ('yes', 'no'):
|
if flavor not in ('yes', 'no'):
|
||||||
p = os.path.join('build', packageName, gradle_path, 'src', flavor, 'play')
|
p = os.path.join('build', packageName, gradle_path, 'src', flavor, 'play')
|
||||||
|
|
@ -1148,9 +1147,12 @@ def insert_localized_app_metadata(apps):
|
||||||
|
|
||||||
# flavours specified in build receipt
|
# flavours specified in build receipt
|
||||||
build_flavours = ""
|
build_flavours = ""
|
||||||
if apps[packageName] and 'builds' in apps[packageName] and len(apps[packageName].builds) > 0\
|
if (
|
||||||
and 'gradle' in apps[packageName].builds[-1]:
|
apps[packageName]
|
||||||
build_flavours = apps[packageName].builds[-1].gradle
|
and len(apps[packageName].get('Builds', [])) > 0
|
||||||
|
and 'gradle' in apps[packageName]['Builds'][-1]
|
||||||
|
):
|
||||||
|
build_flavours = apps[packageName]['Builds'][-1]['gradle']
|
||||||
|
|
||||||
if len(segments) >= 5 and segments[4] == "fastlane" and segments[3] not in build_flavours:
|
if len(segments) >= 5 and segments[4] == "fastlane" and segments[3] not in build_flavours:
|
||||||
logging.debug("ignoring due to wrong flavour")
|
logging.debug("ignoring due to wrong flavour")
|
||||||
|
|
@ -1910,7 +1912,7 @@ def apply_info_from_latest_apk(apps, apks):
|
||||||
if app.get('Name') is None:
|
if app.get('Name') is None:
|
||||||
app['Name'] = bestapk['name']
|
app['Name'] = bestapk['name']
|
||||||
app['icon'] = bestapk['icon'] if 'icon' in bestapk else None
|
app['icon'] = bestapk['icon'] if 'icon' in bestapk else None
|
||||||
if app['CurrentVersionCode'] is None:
|
if app.get('CurrentVersionCode') is None:
|
||||||
app['CurrentVersionCode'] = str(bestver)
|
app['CurrentVersionCode'] = str(bestver)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1929,8 +1931,8 @@ def archive_old_apks(apps, apks, archapks, repodir, archivedir, defaultkeepversi
|
||||||
currentVersionApk = None
|
currentVersionApk = None
|
||||||
for apk in apk_list:
|
for apk in apk_list:
|
||||||
if apk['packageName'] == appid:
|
if apk['packageName'] == appid:
|
||||||
if app.CurrentVersionCode is not None:
|
if app.get('CurrentVersionCode') is not None:
|
||||||
if apk['versionCode'] == common.version_code_string_to_int(app.CurrentVersionCode):
|
if apk['versionCode'] == common.version_code_string_to_int(app['CurrentVersionCode']):
|
||||||
currentVersionApk = apk
|
currentVersionApk = apk
|
||||||
continue
|
continue
|
||||||
apkList.append(apk)
|
apkList.append(apk)
|
||||||
|
|
@ -1944,8 +1946,8 @@ def archive_old_apks(apps, apks, archapks, repodir, archivedir, defaultkeepversi
|
||||||
|
|
||||||
for appid, app in apps.items():
|
for appid, app in apps.items():
|
||||||
|
|
||||||
if app.ArchivePolicy:
|
if app.get('ArchivePolicy'):
|
||||||
keepversions = int(app.ArchivePolicy[:-9])
|
keepversions = int(app['ArchivePolicy'][:-9])
|
||||||
else:
|
else:
|
||||||
keepversions = defaultkeepversions
|
keepversions = defaultkeepversions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,13 +49,13 @@ class CheckupdatesTest(unittest.TestCase):
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.versionCode = app.CurrentVersionCode
|
build.versionCode = app.CurrentVersionCode
|
||||||
build.versionName = app.CurrentVersion
|
build.versionName = app.CurrentVersion
|
||||||
app.builds.append(build)
|
app['Builds'].append(build)
|
||||||
|
|
||||||
with mock.patch('fdroidserver.checkupdates.check_http', lambda app: ('1.1.9', 10109)):
|
with mock.patch('fdroidserver.checkupdates.check_http', lambda app: ('1.1.9', 10109)):
|
||||||
with mock.patch('fdroidserver.metadata.write_metadata', mock.Mock()):
|
with mock.patch('fdroidserver.metadata.write_metadata', mock.Mock()):
|
||||||
with mock.patch('subprocess.call', lambda cmd: 0):
|
with mock.patch('subprocess.call', lambda cmd: 0):
|
||||||
fdroidserver.checkupdates.checkupdates_app(app)
|
fdroidserver.checkupdates.checkupdates_app(app)
|
||||||
build = app.builds[-1]
|
build = app['Builds'][-1]
|
||||||
self.assertEqual(build.versionName, '1.1.9')
|
self.assertEqual(build.versionName, '1.1.9')
|
||||||
self.assertEqual(build.commit, '1.1.9')
|
self.assertEqual(build.commit, '1.1.9')
|
||||||
|
|
||||||
|
|
@ -75,13 +75,13 @@ class CheckupdatesTest(unittest.TestCase):
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.versionCode = app.CurrentVersionCode
|
build.versionCode = app.CurrentVersionCode
|
||||||
build.versionName = app.CurrentVersion
|
build.versionName = app.CurrentVersion
|
||||||
app.builds.append(build)
|
app['Builds'].append(build)
|
||||||
|
|
||||||
with mock.patch('fdroidserver.checkupdates.check_http', lambda app: ('1.1.9', 10109)):
|
with mock.patch('fdroidserver.checkupdates.check_http', lambda app: ('1.1.9', 10109)):
|
||||||
with mock.patch('fdroidserver.metadata.write_metadata', mock.Mock()):
|
with mock.patch('fdroidserver.metadata.write_metadata', mock.Mock()):
|
||||||
with mock.patch('subprocess.call', lambda cmd: 0):
|
with mock.patch('subprocess.call', lambda cmd: 0):
|
||||||
fdroidserver.checkupdates.checkupdates_app(app)
|
fdroidserver.checkupdates.checkupdates_app(app)
|
||||||
build = app.builds[-1]
|
build = app['Builds'][-1]
|
||||||
self.assertEqual(build.versionName, '1.1.9.10109-fdroid')
|
self.assertEqual(build.versionName, '1.1.9.10109-fdroid')
|
||||||
self.assertEqual(build.commit, 'v1.1.9_10109')
|
self.assertEqual(build.commit, 'v1.1.9_10109')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -943,7 +943,7 @@ class CommonTest(unittest.TestCase):
|
||||||
app = fdroidserver.metadata.App()
|
app = fdroidserver.metadata.App()
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.gradle = ['devVersion']
|
build.gradle = ['devVersion']
|
||||||
app.builds = [build]
|
app['Builds'] = [build]
|
||||||
app.id = 'org.fdroid.fdroid.dev'
|
app.id = 'org.fdroid.fdroid.dev'
|
||||||
paths = [
|
paths = [
|
||||||
os.path.join('source-files', 'fdroid', 'fdroidclient', 'AndroidManifest.xml'),
|
os.path.join('source-files', 'fdroid', 'fdroidclient', 'AndroidManifest.xml'),
|
||||||
|
|
@ -957,7 +957,7 @@ class CommonTest(unittest.TestCase):
|
||||||
app = fdroidserver.metadata.App()
|
app = fdroidserver.metadata.App()
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.gradle = ['free']
|
build.gradle = ['free']
|
||||||
app.builds = [build]
|
app['Builds'] = [build]
|
||||||
app.id = 'eu.siacs.conversations'
|
app.id = 'eu.siacs.conversations'
|
||||||
paths = [
|
paths = [
|
||||||
os.path.join('source-files', 'eu.siacs.conversations', 'build.gradle'),
|
os.path.join('source-files', 'eu.siacs.conversations', 'build.gradle'),
|
||||||
|
|
@ -970,7 +970,7 @@ class CommonTest(unittest.TestCase):
|
||||||
app = fdroidserver.metadata.App()
|
app = fdroidserver.metadata.App()
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.gradle = ['generic']
|
build.gradle = ['generic']
|
||||||
app.builds = [build]
|
app['Builds'] = [build]
|
||||||
app.id = 'com.nextcloud.client'
|
app.id = 'com.nextcloud.client'
|
||||||
paths = [
|
paths = [
|
||||||
os.path.join('source-files', 'com.nextcloud.client', 'build.gradle'),
|
os.path.join('source-files', 'com.nextcloud.client', 'build.gradle'),
|
||||||
|
|
@ -983,7 +983,7 @@ class CommonTest(unittest.TestCase):
|
||||||
app = fdroidserver.metadata.App()
|
app = fdroidserver.metadata.App()
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.gradle = ['versionDev']
|
build.gradle = ['versionDev']
|
||||||
app.builds = [build]
|
app['Builds'] = [build]
|
||||||
app.id = 'com.nextcloud.android.beta'
|
app.id = 'com.nextcloud.android.beta'
|
||||||
paths = [
|
paths = [
|
||||||
os.path.join('source-files', 'com.nextcloud.client', 'build.gradle'),
|
os.path.join('source-files', 'com.nextcloud.client', 'build.gradle'),
|
||||||
|
|
@ -996,7 +996,7 @@ class CommonTest(unittest.TestCase):
|
||||||
app = fdroidserver.metadata.App()
|
app = fdroidserver.metadata.App()
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.gradle = ['standard']
|
build.gradle = ['standard']
|
||||||
app.builds = [build]
|
app['Builds'] = [build]
|
||||||
app.id = 'at.bitfire.davdroid'
|
app.id = 'at.bitfire.davdroid'
|
||||||
paths = [
|
paths = [
|
||||||
os.path.join('source-files', 'at.bitfire.davdroid', 'build.gradle'),
|
os.path.join('source-files', 'at.bitfire.davdroid', 'build.gradle'),
|
||||||
|
|
@ -1009,7 +1009,7 @@ class CommonTest(unittest.TestCase):
|
||||||
app = fdroidserver.metadata.App()
|
app = fdroidserver.metadata.App()
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.gradle = ['libre']
|
build.gradle = ['libre']
|
||||||
app.builds = [build]
|
app['Builds'] = [build]
|
||||||
app.id = 'com.kunzisoft.fdroidtest.applicationidsuffix.libre'
|
app.id = 'com.kunzisoft.fdroidtest.applicationidsuffix.libre'
|
||||||
paths = [
|
paths = [
|
||||||
os.path.join('source-files', 'com.kunzisoft.testcase', 'build.gradle'),
|
os.path.join('source-files', 'com.kunzisoft.testcase', 'build.gradle'),
|
||||||
|
|
@ -1022,7 +1022,7 @@ class CommonTest(unittest.TestCase):
|
||||||
app = fdroidserver.metadata.App()
|
app = fdroidserver.metadata.App()
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.gradle = ['pro']
|
build.gradle = ['pro']
|
||||||
app.builds = [build]
|
app['Builds'] = [build]
|
||||||
app.id = 'com.kunzisoft.fdroidtest.applicationidsuffix.pro'
|
app.id = 'com.kunzisoft.fdroidtest.applicationidsuffix.pro'
|
||||||
paths = [
|
paths = [
|
||||||
os.path.join('source-files', 'com.kunzisoft.testcase', 'build.gradle'),
|
os.path.join('source-files', 'com.kunzisoft.testcase', 'build.gradle'),
|
||||||
|
|
@ -1035,7 +1035,7 @@ class CommonTest(unittest.TestCase):
|
||||||
app = fdroidserver.metadata.App()
|
app = fdroidserver.metadata.App()
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.gradle = ['free']
|
build.gradle = ['free']
|
||||||
app.builds = [build]
|
app['Builds'] = [build]
|
||||||
app.id = 'com.kunzisoft.fdroidtest.applicationidsuffix'
|
app.id = 'com.kunzisoft.fdroidtest.applicationidsuffix'
|
||||||
paths = [
|
paths = [
|
||||||
os.path.join('source-files', 'com.kunzisoft.testcase', 'build.gradle'),
|
os.path.join('source-files', 'com.kunzisoft.testcase', 'build.gradle'),
|
||||||
|
|
@ -1048,7 +1048,7 @@ class CommonTest(unittest.TestCase):
|
||||||
app = fdroidserver.metadata.App()
|
app = fdroidserver.metadata.App()
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.gradle = ['underscore']
|
build.gradle = ['underscore']
|
||||||
app.builds = [build]
|
app['Builds'] = [build]
|
||||||
app.id = 'com.kunzisoft.fdroidtest.applicationidsuffix.underscore'
|
app.id = 'com.kunzisoft.fdroidtest.applicationidsuffix.underscore'
|
||||||
paths = [
|
paths = [
|
||||||
os.path.join('source-files', 'com.kunzisoft.testcase', 'build.gradle'),
|
os.path.join('source-files', 'com.kunzisoft.testcase', 'build.gradle'),
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
build.disable = 'Generated by import.py ...'
|
build.disable = 'Generated by import.py ...'
|
||||||
build.commit = 'Unknown'
|
build.commit = 'Unknown'
|
||||||
build.gradle = [True]
|
build.gradle = [True]
|
||||||
app.builds = [build]
|
app['Builds'] = [build]
|
||||||
|
|
||||||
fdroidserver.metadata.write_yaml(mf, app)
|
fdroidserver.metadata.write_yaml(mf, app)
|
||||||
|
|
||||||
|
|
@ -464,7 +464,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
mf = io.StringIO()
|
mf = io.StringIO()
|
||||||
app = fdroidserver.metadata.App()
|
app = fdroidserver.metadata.App()
|
||||||
app.Categories = ['None']
|
app.Categories = ['None']
|
||||||
app.builds = []
|
app['Builds'] = []
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.versionCode = 102030
|
build.versionCode = 102030
|
||||||
build.versionName = 'v1.2.3'
|
build.versionName = 'v1.2.3'
|
||||||
|
|
@ -472,7 +472,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
build.init = "sed -i -e 'g/what/ever/' /some/file"
|
build.init = "sed -i -e 'g/what/ever/' /some/file"
|
||||||
build.prebuild = "sed -i 'd/that wrong config/' gradle.properties"
|
build.prebuild = "sed -i 'd/that wrong config/' gradle.properties"
|
||||||
build.build = "./gradlew compile"
|
build.build = "./gradlew compile"
|
||||||
app.builds.append(build)
|
app['Builds'].append(build)
|
||||||
fdroidserver.metadata.write_yaml(mf, app)
|
fdroidserver.metadata.write_yaml(mf, app)
|
||||||
mf.seek(0)
|
mf.seek(0)
|
||||||
self.assertEqual(mf.read(), textwrap.dedent("""\
|
self.assertEqual(mf.read(), textwrap.dedent("""\
|
||||||
|
|
@ -496,7 +496,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
mf = io.StringIO()
|
mf = io.StringIO()
|
||||||
app = fdroidserver.metadata.App()
|
app = fdroidserver.metadata.App()
|
||||||
app.Categories = ['None']
|
app.Categories = ['None']
|
||||||
app.builds = []
|
app['Builds'] = []
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.versionCode = 102030
|
build.versionCode = 102030
|
||||||
build.versionName = 'v1.2.3'
|
build.versionName = 'v1.2.3'
|
||||||
|
|
@ -504,7 +504,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
build.init = ["sed -i -e 'g/what/ever/' /some/file"]
|
build.init = ["sed -i -e 'g/what/ever/' /some/file"]
|
||||||
build.prebuild = ["sed -i 'd/that wrong config/' gradle.properties"]
|
build.prebuild = ["sed -i 'd/that wrong config/' gradle.properties"]
|
||||||
build.build = ["./gradlew compile"]
|
build.build = ["./gradlew compile"]
|
||||||
app.builds.append(build)
|
app['Builds'].append(build)
|
||||||
fdroidserver.metadata.write_yaml(mf, app)
|
fdroidserver.metadata.write_yaml(mf, app)
|
||||||
mf.seek(0)
|
mf.seek(0)
|
||||||
self.assertEqual(mf.read(), textwrap.dedent("""\
|
self.assertEqual(mf.read(), textwrap.dedent("""\
|
||||||
|
|
@ -528,7 +528,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
mf = io.StringIO()
|
mf = io.StringIO()
|
||||||
app = fdroidserver.metadata.App()
|
app = fdroidserver.metadata.App()
|
||||||
app.Categories = ['None']
|
app.Categories = ['None']
|
||||||
app.builds = []
|
app['Builds'] = []
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.versionCode = 102030
|
build.versionCode = 102030
|
||||||
build.versionName = 'v1.2.3'
|
build.versionName = 'v1.2.3'
|
||||||
|
|
@ -542,7 +542,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
build.build = ["./gradlew someSpecialTask",
|
build.build = ["./gradlew someSpecialTask",
|
||||||
"sed -i 'd/that wrong config/' gradle.properties",
|
"sed -i 'd/that wrong config/' gradle.properties",
|
||||||
"./gradlew compile"]
|
"./gradlew compile"]
|
||||||
app.builds.append(build)
|
app['Builds'].append(build)
|
||||||
fdroidserver.metadata.write_yaml(mf, app)
|
fdroidserver.metadata.write_yaml(mf, app)
|
||||||
mf.seek(0)
|
mf.seek(0)
|
||||||
self.assertEqual(mf.read(), textwrap.dedent("""\
|
self.assertEqual(mf.read(), textwrap.dedent("""\
|
||||||
|
|
@ -576,7 +576,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
mf = io.StringIO()
|
mf = io.StringIO()
|
||||||
app = fdroidserver.metadata.App()
|
app = fdroidserver.metadata.App()
|
||||||
app.Categories = ['None']
|
app.Categories = ['None']
|
||||||
app.builds = []
|
app['Builds'] = []
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.versionCode = 102030
|
build.versionCode = 102030
|
||||||
build.versionName = 'v1.2.3'
|
build.versionName = 'v1.2.3'
|
||||||
|
|
@ -584,7 +584,7 @@ class MetadataTest(unittest.TestCase):
|
||||||
build.init = "bash generate_some_file.sh && sed -i -e 'g/what/ever/' /some/file"
|
build.init = "bash generate_some_file.sh && sed -i -e 'g/what/ever/' /some/file"
|
||||||
build.prebuild = "npm something && echo 'important setting' >> /a/file"
|
build.prebuild = "npm something && echo 'important setting' >> /a/file"
|
||||||
build.build = "./gradlew someSpecialTask && sed -i 'd/that wrong config/' gradle.properties && ./gradlew compile"
|
build.build = "./gradlew someSpecialTask && sed -i 'd/that wrong config/' gradle.properties && ./gradlew compile"
|
||||||
app.builds.append(build)
|
app['Builds'].append(build)
|
||||||
fdroidserver.metadata.write_yaml(mf, app)
|
fdroidserver.metadata.write_yaml(mf, app)
|
||||||
mf.seek(0)
|
mf.seek(0)
|
||||||
self.assertEqual(mf.read(), textwrap.dedent("""\
|
self.assertEqual(mf.read(), textwrap.dedent("""\
|
||||||
|
|
@ -619,12 +619,12 @@ class MetadataTest(unittest.TestCase):
|
||||||
app = fdroidserver.metadata.App()
|
app = fdroidserver.metadata.App()
|
||||||
app.Categories = ['None']
|
app.Categories = ['None']
|
||||||
app.Provides = 'this.is.deprecated'
|
app.Provides = 'this.is.deprecated'
|
||||||
app.builds = []
|
app['Builds'] = []
|
||||||
build = fdroidserver.metadata.Build()
|
build = fdroidserver.metadata.Build()
|
||||||
build.versionCode = 102030
|
build.versionCode = 102030
|
||||||
build.versionName = 'v1.2.3'
|
build.versionName = 'v1.2.3'
|
||||||
build.gradle = ['yes']
|
build.gradle = ['yes']
|
||||||
app.builds.append(build)
|
app['Builds'].append(build)
|
||||||
fdroidserver.metadata.write_yaml(mf, app)
|
fdroidserver.metadata.write_yaml(mf, app)
|
||||||
mf.seek(0)
|
mf.seek(0)
|
||||||
self.assertEqual(mf.read(), textwrap.dedent("""\
|
self.assertEqual(mf.read(), textwrap.dedent("""\
|
||||||
|
|
|
||||||
|
|
@ -7,39 +7,7 @@ AutoName: Polite Droid
|
||||||
AutoUpdateMode: Version v%v
|
AutoUpdateMode: Version v%v
|
||||||
Binaries: null
|
Binaries: null
|
||||||
Bitcoin: null
|
Bitcoin: null
|
||||||
Categories:
|
Builds:
|
||||||
- Time
|
|
||||||
Changelog: ''
|
|
||||||
CurrentVersion: '1.5'
|
|
||||||
CurrentVersionCode: '6'
|
|
||||||
Description: Activates silent mode during calendar events.
|
|
||||||
Disabled: null
|
|
||||||
Donate: null
|
|
||||||
FlattrID: null
|
|
||||||
IssueTracker: https://github.com/miguelvps/PoliteDroid/issues
|
|
||||||
Liberapay: null
|
|
||||||
LiberapayID: null
|
|
||||||
License: GPL-3.0-only
|
|
||||||
Litecoin: null
|
|
||||||
MaintainerNotes: ''
|
|
||||||
Name: null
|
|
||||||
NoSourceSince: '1.5'
|
|
||||||
OpenCollective: null
|
|
||||||
Provides: null
|
|
||||||
Repo: https://github.com/miguelvps/PoliteDroid.git
|
|
||||||
RepoType: git
|
|
||||||
RequiresRoot: false
|
|
||||||
SourceCode: https://github.com/miguelvps/PoliteDroid
|
|
||||||
Summary: Calendar tool
|
|
||||||
Translation: ''
|
|
||||||
UpdateCheckData: null
|
|
||||||
UpdateCheckIgnore: null
|
|
||||||
UpdateCheckMode: Tags
|
|
||||||
UpdateCheckName: null
|
|
||||||
VercodeOperation: null
|
|
||||||
WebSite: ''
|
|
||||||
added: null
|
|
||||||
builds:
|
|
||||||
- androidupdate: []
|
- androidupdate: []
|
||||||
antcommands: []
|
antcommands: []
|
||||||
antifeatures:
|
antifeatures:
|
||||||
|
|
@ -180,6 +148,38 @@ builds:
|
||||||
timeout: null
|
timeout: null
|
||||||
versionCode: '6'
|
versionCode: '6'
|
||||||
versionName: '1.5'
|
versionName: '1.5'
|
||||||
|
Categories:
|
||||||
|
- Time
|
||||||
|
Changelog: ''
|
||||||
|
CurrentVersion: '1.5'
|
||||||
|
CurrentVersionCode: '6'
|
||||||
|
Description: Activates silent mode during calendar events.
|
||||||
|
Disabled: null
|
||||||
|
Donate: null
|
||||||
|
FlattrID: null
|
||||||
|
IssueTracker: https://github.com/miguelvps/PoliteDroid/issues
|
||||||
|
Liberapay: null
|
||||||
|
LiberapayID: null
|
||||||
|
License: GPL-3.0-only
|
||||||
|
Litecoin: null
|
||||||
|
MaintainerNotes: ''
|
||||||
|
Name: null
|
||||||
|
NoSourceSince: '1.5'
|
||||||
|
OpenCollective: null
|
||||||
|
Provides: null
|
||||||
|
Repo: https://github.com/miguelvps/PoliteDroid.git
|
||||||
|
RepoType: git
|
||||||
|
RequiresRoot: false
|
||||||
|
SourceCode: https://github.com/miguelvps/PoliteDroid
|
||||||
|
Summary: Calendar tool
|
||||||
|
Translation: ''
|
||||||
|
UpdateCheckData: null
|
||||||
|
UpdateCheckIgnore: null
|
||||||
|
UpdateCheckMode: Tags
|
||||||
|
UpdateCheckName: null
|
||||||
|
VercodeOperation: null
|
||||||
|
WebSite: ''
|
||||||
|
added: null
|
||||||
comments: {}
|
comments: {}
|
||||||
id: com.politedroid
|
id: com.politedroid
|
||||||
lastUpdated: null
|
lastUpdated: null
|
||||||
|
|
|
||||||
|
|
@ -7,62 +7,7 @@ AutoName: AdAway
|
||||||
AutoUpdateMode: Version v%v
|
AutoUpdateMode: Version v%v
|
||||||
Binaries: null
|
Binaries: null
|
||||||
Bitcoin: null
|
Bitcoin: null
|
||||||
Categories:
|
Builds:
|
||||||
- System
|
|
||||||
- Security
|
|
||||||
Changelog: ''
|
|
||||||
CurrentVersion: '3.0'
|
|
||||||
CurrentVersionCode: '52'
|
|
||||||
Description: 'An ad blocker that uses the hosts file. The hosts file
|
|
||||||
|
|
||||||
contains a list of mappings between hostnames and IP addresses. When
|
|
||||||
|
|
||||||
an app requests an ad, that request is directed to 127.0.0.1 which does
|
|
||||||
|
|
||||||
nothing. There are options to run a web server
|
|
||||||
|
|
||||||
to respond to blocked hostnames and to direct requests to the IP
|
|
||||||
|
|
||||||
address of your choosing. You can download hosts files from the
|
|
||||||
|
|
||||||
app but it is possible to use your own and to add certain sites
|
|
||||||
|
|
||||||
to the white- and black-lists.
|
|
||||||
|
|
||||||
|
|
||||||
[https://github.com/dschuermann/ad-away/raw/HEAD/CHANGELOG Changelog]
|
|
||||||
|
|
||||||
|
|
||||||
Requires root: Yes. The hosts files is located in /system which is normally
|
|
||||||
|
|
||||||
read-only.'
|
|
||||||
Disabled: null
|
|
||||||
Donate: http://sufficientlysecure.org/index.php/adaway
|
|
||||||
FlattrID: '369138'
|
|
||||||
IssueTracker: https://github.com/dschuermann/ad-away/issues
|
|
||||||
Liberapay: null
|
|
||||||
LiberapayID: '1234567890'
|
|
||||||
License: GPL-3.0-only
|
|
||||||
Litecoin: null
|
|
||||||
MaintainerNotes: ''
|
|
||||||
Name: null
|
|
||||||
NoSourceSince: ''
|
|
||||||
OpenCollective: null
|
|
||||||
Provides: null
|
|
||||||
Repo: https://github.com/dschuermann/ad-away.git
|
|
||||||
RepoType: git
|
|
||||||
RequiresRoot: false
|
|
||||||
SourceCode: https://github.com/dschuermann/ad-away
|
|
||||||
Summary: Block advertisements
|
|
||||||
Translation: https://www.transifex.com/dominikschuermann/adaway
|
|
||||||
UpdateCheckData: null
|
|
||||||
UpdateCheckIgnore: null
|
|
||||||
UpdateCheckMode: Tags
|
|
||||||
UpdateCheckName: null
|
|
||||||
VercodeOperation: null
|
|
||||||
WebSite: http://sufficientlysecure.org/index.php/adaway
|
|
||||||
added: null
|
|
||||||
builds:
|
|
||||||
- androidupdate: []
|
- androidupdate: []
|
||||||
antcommands: []
|
antcommands: []
|
||||||
antifeatures: []
|
antifeatures: []
|
||||||
|
|
@ -1086,6 +1031,61 @@ builds:
|
||||||
timeout: null
|
timeout: null
|
||||||
versionCode: '52'
|
versionCode: '52'
|
||||||
versionName: '3.0'
|
versionName: '3.0'
|
||||||
|
Categories:
|
||||||
|
- System
|
||||||
|
- Security
|
||||||
|
Changelog: ''
|
||||||
|
CurrentVersion: '3.0'
|
||||||
|
CurrentVersionCode: '52'
|
||||||
|
Description: 'An ad blocker that uses the hosts file. The hosts file
|
||||||
|
|
||||||
|
contains a list of mappings between hostnames and IP addresses. When
|
||||||
|
|
||||||
|
an app requests an ad, that request is directed to 127.0.0.1 which does
|
||||||
|
|
||||||
|
nothing. There are options to run a web server
|
||||||
|
|
||||||
|
to respond to blocked hostnames and to direct requests to the IP
|
||||||
|
|
||||||
|
address of your choosing. You can download hosts files from the
|
||||||
|
|
||||||
|
app but it is possible to use your own and to add certain sites
|
||||||
|
|
||||||
|
to the white- and black-lists.
|
||||||
|
|
||||||
|
|
||||||
|
[https://github.com/dschuermann/ad-away/raw/HEAD/CHANGELOG Changelog]
|
||||||
|
|
||||||
|
|
||||||
|
Requires root: Yes. The hosts files is located in /system which is normally
|
||||||
|
|
||||||
|
read-only.'
|
||||||
|
Disabled: null
|
||||||
|
Donate: http://sufficientlysecure.org/index.php/adaway
|
||||||
|
FlattrID: '369138'
|
||||||
|
IssueTracker: https://github.com/dschuermann/ad-away/issues
|
||||||
|
Liberapay: null
|
||||||
|
LiberapayID: '1234567890'
|
||||||
|
License: GPL-3.0-only
|
||||||
|
Litecoin: null
|
||||||
|
MaintainerNotes: ''
|
||||||
|
Name: null
|
||||||
|
NoSourceSince: ''
|
||||||
|
OpenCollective: null
|
||||||
|
Provides: null
|
||||||
|
Repo: https://github.com/dschuermann/ad-away.git
|
||||||
|
RepoType: git
|
||||||
|
RequiresRoot: false
|
||||||
|
SourceCode: https://github.com/dschuermann/ad-away
|
||||||
|
Summary: Block advertisements
|
||||||
|
Translation: https://www.transifex.com/dominikschuermann/adaway
|
||||||
|
UpdateCheckData: null
|
||||||
|
UpdateCheckIgnore: null
|
||||||
|
UpdateCheckMode: Tags
|
||||||
|
UpdateCheckName: null
|
||||||
|
VercodeOperation: null
|
||||||
|
WebSite: http://sufficientlysecure.org/index.php/adaway
|
||||||
|
added: null
|
||||||
comments: {}
|
comments: {}
|
||||||
id: org.adaway
|
id: org.adaway
|
||||||
lastUpdated: null
|
lastUpdated: null
|
||||||
|
|
|
||||||
|
|
@ -7,59 +7,7 @@ AutoName: SMSSecure
|
||||||
AutoUpdateMode: Version v%v
|
AutoUpdateMode: Version v%v
|
||||||
Binaries: null
|
Binaries: null
|
||||||
Bitcoin: null
|
Bitcoin: null
|
||||||
Categories:
|
Builds:
|
||||||
- Phone & SMS
|
|
||||||
Changelog: ''
|
|
||||||
CurrentVersion: 0.6.0
|
|
||||||
CurrentVersionCode: '102'
|
|
||||||
Description: 'SMSSecure is an SMS/MMS application that allows you to protect your
|
|
||||||
privacy while communicating with friends.
|
|
||||||
|
|
||||||
Using SMSSecure, you can send SMS messages and share media or attachments with complete
|
|
||||||
privacy.
|
|
||||||
|
|
||||||
|
|
||||||
* Easy. SMSSecure works like any other SMS application. There''s nothing to sign
|
|
||||||
up for and no new service your friends need to join.
|
|
||||||
|
|
||||||
* Reliable. SMSSecure communicates using encrypted SMS messages. No servers or internet
|
|
||||||
connection required.
|
|
||||||
|
|
||||||
* Private. SMSSecure uses the TextSecure encryption protocol to provide privacy
|
|
||||||
for every message, every time.
|
|
||||||
|
|
||||||
* Safe. All messages are encrypted locally, so if your phone is lost or stolen,
|
|
||||||
your messages are protected.
|
|
||||||
|
|
||||||
* Open Source. SMSSecure is Free and Open Source, enabling anyone to verify its
|
|
||||||
security by auditing the code.'
|
|
||||||
Disabled: null
|
|
||||||
Donate: null
|
|
||||||
FlattrID: null
|
|
||||||
IssueTracker: https://github.com/SMSSecure/SMSSecure/issues
|
|
||||||
Liberapay: null
|
|
||||||
LiberapayID: null
|
|
||||||
License: GPL-3.0-only
|
|
||||||
Litecoin: null
|
|
||||||
MaintainerNotes: ''
|
|
||||||
Name: null
|
|
||||||
NoSourceSince: ''
|
|
||||||
OpenCollective: null
|
|
||||||
Provides: null
|
|
||||||
Repo: https://github.com/SMSSecure/SMSSecure
|
|
||||||
RepoType: git
|
|
||||||
RequiresRoot: false
|
|
||||||
SourceCode: https://github.com/SMSSecure/SMSSecure
|
|
||||||
Summary: Send encrypted text messages (SMS)
|
|
||||||
Translation: https://www.transifex.com/silence/silence
|
|
||||||
UpdateCheckData: null
|
|
||||||
UpdateCheckIgnore: null
|
|
||||||
UpdateCheckMode: Tags
|
|
||||||
UpdateCheckName: null
|
|
||||||
VercodeOperation: null
|
|
||||||
WebSite: http://www.smssecure.org
|
|
||||||
added: null
|
|
||||||
builds:
|
|
||||||
- androidupdate: []
|
- androidupdate: []
|
||||||
antcommands: []
|
antcommands: []
|
||||||
antifeatures: []
|
antifeatures: []
|
||||||
|
|
@ -362,6 +310,58 @@ builds:
|
||||||
timeout: null
|
timeout: null
|
||||||
versionCode: '102'
|
versionCode: '102'
|
||||||
versionName: 0.6.0
|
versionName: 0.6.0
|
||||||
|
Categories:
|
||||||
|
- Phone & SMS
|
||||||
|
Changelog: ''
|
||||||
|
CurrentVersion: 0.6.0
|
||||||
|
CurrentVersionCode: '102'
|
||||||
|
Description: 'SMSSecure is an SMS/MMS application that allows you to protect your
|
||||||
|
privacy while communicating with friends.
|
||||||
|
|
||||||
|
Using SMSSecure, you can send SMS messages and share media or attachments with complete
|
||||||
|
privacy.
|
||||||
|
|
||||||
|
|
||||||
|
* Easy. SMSSecure works like any other SMS application. There''s nothing to sign
|
||||||
|
up for and no new service your friends need to join.
|
||||||
|
|
||||||
|
* Reliable. SMSSecure communicates using encrypted SMS messages. No servers or internet
|
||||||
|
connection required.
|
||||||
|
|
||||||
|
* Private. SMSSecure uses the TextSecure encryption protocol to provide privacy
|
||||||
|
for every message, every time.
|
||||||
|
|
||||||
|
* Safe. All messages are encrypted locally, so if your phone is lost or stolen,
|
||||||
|
your messages are protected.
|
||||||
|
|
||||||
|
* Open Source. SMSSecure is Free and Open Source, enabling anyone to verify its
|
||||||
|
security by auditing the code.'
|
||||||
|
Disabled: null
|
||||||
|
Donate: null
|
||||||
|
FlattrID: null
|
||||||
|
IssueTracker: https://github.com/SMSSecure/SMSSecure/issues
|
||||||
|
Liberapay: null
|
||||||
|
LiberapayID: null
|
||||||
|
License: GPL-3.0-only
|
||||||
|
Litecoin: null
|
||||||
|
MaintainerNotes: ''
|
||||||
|
Name: null
|
||||||
|
NoSourceSince: ''
|
||||||
|
OpenCollective: null
|
||||||
|
Provides: null
|
||||||
|
Repo: https://github.com/SMSSecure/SMSSecure
|
||||||
|
RepoType: git
|
||||||
|
RequiresRoot: false
|
||||||
|
SourceCode: https://github.com/SMSSecure/SMSSecure
|
||||||
|
Summary: Send encrypted text messages (SMS)
|
||||||
|
Translation: https://www.transifex.com/silence/silence
|
||||||
|
UpdateCheckData: null
|
||||||
|
UpdateCheckIgnore: null
|
||||||
|
UpdateCheckMode: Tags
|
||||||
|
UpdateCheckName: null
|
||||||
|
VercodeOperation: null
|
||||||
|
WebSite: http://www.smssecure.org
|
||||||
|
added: null
|
||||||
comments: {}
|
comments: {}
|
||||||
id: org.smssecure.smssecure
|
id: org.smssecure.smssecure
|
||||||
lastUpdated: null
|
lastUpdated: null
|
||||||
|
|
|
||||||
|
|
@ -7,61 +7,7 @@ AutoName: VLC
|
||||||
AutoUpdateMode: None
|
AutoUpdateMode: None
|
||||||
Binaries: null
|
Binaries: null
|
||||||
Bitcoin: null
|
Bitcoin: null
|
||||||
Categories:
|
Builds:
|
||||||
- Multimedia
|
|
||||||
Changelog: ''
|
|
||||||
CurrentVersion: 1.2.6
|
|
||||||
CurrentVersionCode: '1030005'
|
|
||||||
Description: 'Video and audio player that supports a wide range of formats,
|
|
||||||
|
|
||||||
for both local and remote playback.
|
|
||||||
|
|
||||||
|
|
||||||
[http://git.videolan.org/?p=vlc-ports/android.git;a=blob_plain;f=NEWS NEWS]
|
|
||||||
|
|
||||||
'
|
|
||||||
Disabled: null
|
|
||||||
Donate: http://www.videolan.org/contribute.html#money
|
|
||||||
FlattrID: null
|
|
||||||
IssueTracker: http://www.videolan.org/support/index.html#bugs
|
|
||||||
Liberapay: null
|
|
||||||
LiberapayID: null
|
|
||||||
License: GPL-3.0-only
|
|
||||||
Litecoin: null
|
|
||||||
MaintainerNotes: 'Instructions and dependencies here: http://wiki.videolan.org/AndroidCompile
|
|
||||||
|
|
||||||
see http://buildbot.videolan.org/builders/ for version code scheme
|
|
||||||
|
|
||||||
The VLC srclib commit can be found out from TESTED_HASH value in compile.sh
|
|
||||||
|
|
||||||
|
|
||||||
On new releases remove the updatecheck and force the CV to the last working
|
|
||||||
|
|
||||||
build. This will make sure users don''t get notified about the update until
|
|
||||||
|
|
||||||
the final build from the BS has been reviewed and tested. Once done, undo
|
|
||||||
|
|
||||||
those changes.
|
|
||||||
|
|
||||||
'
|
|
||||||
Name: null
|
|
||||||
NoSourceSince: ''
|
|
||||||
OpenCollective: null
|
|
||||||
Provides: null
|
|
||||||
Repo: git://git.videolan.org/vlc-ports/android.git
|
|
||||||
RepoType: git
|
|
||||||
RequiresRoot: false
|
|
||||||
SourceCode: http://git.videolan.org/?p=vlc-ports/android.git;a=summary
|
|
||||||
Summary: Media player
|
|
||||||
Translation: ''
|
|
||||||
UpdateCheckData: null
|
|
||||||
UpdateCheckIgnore: null
|
|
||||||
UpdateCheckMode: Tags
|
|
||||||
UpdateCheckName: null
|
|
||||||
VercodeOperation: '%c + 5'
|
|
||||||
WebSite: http://www.videolan.org/vlc/download-android.html
|
|
||||||
added: null
|
|
||||||
builds:
|
|
||||||
- androidupdate:
|
- androidupdate:
|
||||||
- .
|
- .
|
||||||
- ../java-libs/SlidingMenu
|
- ../java-libs/SlidingMenu
|
||||||
|
|
@ -2444,6 +2390,60 @@ builds:
|
||||||
timeout: null
|
timeout: null
|
||||||
versionCode: '1030005'
|
versionCode: '1030005'
|
||||||
versionName: 1.2.6
|
versionName: 1.2.6
|
||||||
|
Categories:
|
||||||
|
- Multimedia
|
||||||
|
Changelog: ''
|
||||||
|
CurrentVersion: 1.2.6
|
||||||
|
CurrentVersionCode: '1030005'
|
||||||
|
Description: 'Video and audio player that supports a wide range of formats,
|
||||||
|
|
||||||
|
for both local and remote playback.
|
||||||
|
|
||||||
|
|
||||||
|
[http://git.videolan.org/?p=vlc-ports/android.git;a=blob_plain;f=NEWS NEWS]
|
||||||
|
|
||||||
|
'
|
||||||
|
Disabled: null
|
||||||
|
Donate: http://www.videolan.org/contribute.html#money
|
||||||
|
FlattrID: null
|
||||||
|
IssueTracker: http://www.videolan.org/support/index.html#bugs
|
||||||
|
Liberapay: null
|
||||||
|
LiberapayID: null
|
||||||
|
License: GPL-3.0-only
|
||||||
|
Litecoin: null
|
||||||
|
MaintainerNotes: 'Instructions and dependencies here: http://wiki.videolan.org/AndroidCompile
|
||||||
|
|
||||||
|
see http://buildbot.videolan.org/builders/ for version code scheme
|
||||||
|
|
||||||
|
The VLC srclib commit can be found out from TESTED_HASH value in compile.sh
|
||||||
|
|
||||||
|
|
||||||
|
On new releases remove the updatecheck and force the CV to the last working
|
||||||
|
|
||||||
|
build. This will make sure users don''t get notified about the update until
|
||||||
|
|
||||||
|
the final build from the BS has been reviewed and tested. Once done, undo
|
||||||
|
|
||||||
|
those changes.
|
||||||
|
|
||||||
|
'
|
||||||
|
Name: null
|
||||||
|
NoSourceSince: ''
|
||||||
|
OpenCollective: null
|
||||||
|
Provides: null
|
||||||
|
Repo: git://git.videolan.org/vlc-ports/android.git
|
||||||
|
RepoType: git
|
||||||
|
RequiresRoot: false
|
||||||
|
SourceCode: http://git.videolan.org/?p=vlc-ports/android.git;a=summary
|
||||||
|
Summary: Media player
|
||||||
|
Translation: ''
|
||||||
|
UpdateCheckData: null
|
||||||
|
UpdateCheckIgnore: null
|
||||||
|
UpdateCheckMode: Tags
|
||||||
|
UpdateCheckName: null
|
||||||
|
VercodeOperation: '%c + 5'
|
||||||
|
WebSite: http://www.videolan.org/vlc/download-android.html
|
||||||
|
added: null
|
||||||
comments: {}
|
comments: {}
|
||||||
id: org.videolan.vlc
|
id: org.videolan.vlc
|
||||||
lastUpdated: null
|
lastUpdated: null
|
||||||
|
|
|
||||||
|
|
@ -116,15 +116,15 @@ class UpdateTest(unittest.TestCase):
|
||||||
|
|
||||||
buildnextcloudclient = fdroidserver.metadata.Build()
|
buildnextcloudclient = fdroidserver.metadata.Build()
|
||||||
buildnextcloudclient.gradle = ['generic']
|
buildnextcloudclient.gradle = ['generic']
|
||||||
apps['com.nextcloud.client']['builds'] = [buildnextcloudclient]
|
apps['com.nextcloud.client']['Builds'] = [buildnextcloudclient]
|
||||||
|
|
||||||
buildnextclouddevclient = fdroidserver.metadata.Build()
|
buildnextclouddevclient = fdroidserver.metadata.Build()
|
||||||
buildnextclouddevclient.gradle = ['versionDev']
|
buildnextclouddevclient.gradle = ['versionDev']
|
||||||
apps['com.nextcloud.client.dev']['builds'] = [buildnextclouddevclient]
|
apps['com.nextcloud.client.dev']['Builds'] = [buildnextclouddevclient]
|
||||||
|
|
||||||
build_conversations = fdroidserver.metadata.Build()
|
build_conversations = fdroidserver.metadata.Build()
|
||||||
build_conversations.gradle = ['free']
|
build_conversations.gradle = ['free']
|
||||||
apps['eu.siacs.conversations']['builds'] = [build_conversations]
|
apps['eu.siacs.conversations']['Builds'] = [build_conversations]
|
||||||
|
|
||||||
fdroidserver.update.insert_localized_app_metadata(apps)
|
fdroidserver.update.insert_localized_app_metadata(apps)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue