return "fdroid.app:" + appid, apps[appid].Name
raise MetaDataException("Cannot resolve app id " + appid)
- nosigningkey = False
if not common.options.nosign:
- if 'repo_keyalias' not in common.config:
- nosigningkey = True
- logging.critical(_("'repo_keyalias' not found in config.py!"))
- if 'keystore' not in common.config:
- nosigningkey = True
- logging.critical(_("'keystore' not found in config.py!"))
- if 'keystorepass' not in common.config:
- nosigningkey = True
- logging.critical(_("'keystorepass' not found in config.py!"))
- if 'keypass' not in common.config:
- nosigningkey = True
- logging.critical(_("'keypass' not found in config.py!"))
- if not os.path.exists(common.config['keystore']):
- nosigningkey = True
- logging.critical("'" + common.config['keystore'] + "' does not exist!")
- if nosigningkey:
- raise FDroidException("`fdroid update` requires a signing key, " +
- "you can create one using: fdroid update --create-key")
+ common.assert_config_keystore(common.config)
repodict = collections.OrderedDict()
repodict['timestamp'] = datetime.utcnow()
# Java prefers milliseconds
# we also need to accound for time zone/daylight saving time
return int(calendar.timegm(obj.timetuple()) * 1000)
+ if isinstance(obj, dict):
+ d = collections.OrderedDict()
+ for key in sorted(obj.keys()):
+ d[key] = obj[key]
+ return d
raise TypeError(repr(obj) + " is not JSON serializable")
output = collections.OrderedDict()
k = k[:1].lower() + k[1:]
d[k] = v
+ # establish sort order in localized dicts
+ for app in output['apps']:
+ localized = app.get('localized')
+ if localized:
+ lordered = collections.OrderedDict()
+ for lkey, lvalue in sorted(localized.items()):
+ lordered[lkey] = collections.OrderedDict()
+ for ikey, iname in sorted(lvalue.items()):
+ lordered[lkey][ikey] = iname
+ app['localized'] = lordered
+
output_packages = collections.OrderedDict()
output['packages'] = output_packages
for package in packages:
if packageName not in apps:
logging.info(_('Ignoring package without metadata: ') + package['apkName'])
continue
+ if not package.get('versionName'):
+ app = apps[packageName]
+ versionCodeStr = str(package['versionCode']) # TODO build.versionCode should be int!
+ for build in app['builds']:
+ if build['versionCode'] == versionCodeStr:
+ versionName = build.get('versionName')
+ logging.info(_('Overriding blank versionName in {apkfilename} from metadata: {version}')
+ .format(apkfilename=package['apkName'], version=versionName))
+ package['versionName'] = versionName
+ break
if packageName in output_packages:
packagelist = output_packages[packageName]
else:
addElementNonEmpty('bitcoin', app.Bitcoin, doc, apel)
addElementNonEmpty('litecoin', app.Litecoin, doc, apel)
addElementNonEmpty('flattr', app.FlattrID, doc, apel)
+ addElementNonEmpty('liberapay', app.LiberapayID, doc, apel)
# These elements actually refer to the current version (i.e. which
# one is recommended. They are historically mis-named, and need
apkel = doc.createElement("package")
apel.appendChild(apkel)
- addElement('version', apk['versionName'], doc, apkel)
+
+ versionName = apk.get('versionName')
+ if not versionName:
+ versionCodeStr = str(apk['versionCode']) # TODO build.versionCode should be int!
+ for build in app.builds:
+ if build['versionCode'] == versionCodeStr and 'versionName' in build:
+ versionName = build['versionName']
+ break
+ if versionName:
+ addElement('version', versionName, doc, apkel)
+
addElement('versioncode', str(apk['versionCode']), doc, apkel)
addElement('apkname', apk['apkName'], doc, apkel)
addElementIfInApk('srcname', apk, 'srcname', doc, apkel)
segments.extend([branch, folder])
urls.append('/'.join(segments))
elif hostname == "gitlab.com":
- # Gitlab Raw "https://gitlab.com/user/repo/raw/branch/folder"
- gitlab_raw = segments + ['raw', branch, folder]
- urls.append('/'.join(gitlab_raw))
+ # Both these Gitlab URLs will work with F-Droid, but only the first will work in the browser
+ # This is because the `raw` URLs are not served with the correct mime types, so any
+ # index.html which is put in the repo will not be rendered. Putting an index.html file in
+ # the repo root is a common way for to make information about the repo available to end user.
+
# Gitlab-like Pages segments "https://user.gitlab.io/repo/folder"
gitlab_pages = ["https:", "", user + ".gitlab.io", repo, folder]
urls.append('/'.join(gitlab_pages))
+ # Gitlab Raw "https://gitlab.com/user/repo/raw/branch/folder"
+ gitlab_raw = segments + ['raw', branch, folder]
+ urls.append('/'.join(gitlab_raw))
return urls
return urls
jar = zipfile.ZipFile(fp)
# verify that the JAR signature is valid
+ logging.debug(_('Verifying index signature:'))
common.verify_jar_signature(fp.name)
# get public key and its fingerprint from JAR