From 43b990505d861eb2fbc0e629834408c72f8c22d8 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 20 Oct 2017 08:59:56 +0200 Subject: [PATCH 1/8] travis-ci: only run one round of the test suite on OSX The OSX tests seem to run slower, they often timeout. So only run the test suite with the installed version of fdroid, instead of the three rounds that ./complete-ci-tests does. --- .travis.yml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3dab550a..27df250a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,9 @@ matrix: env: ANDROID_SDK_ROOT=/usr/local/share/android-sdk env: ANDROID_HOME=/usr/local/share/android-sdk +# On Ubuntu/trusty 14.04, the PPA is needed on to provide lots of the +# dependencies, but this then also serves as a test of the PPA, which +# is used on Windows Subsystem for Linux. addons: apt: sources: @@ -46,15 +49,13 @@ android: - 'android-sdk-preview-.+' - 'android-sdk-license-.+' -# the PPA is needed on Ubuntu 14.04 precise, and with python3, trusty too -# the pip thing is a hack that can go away with trusty. -# # * ensure java8 is installed since Android SDK doesn't work with Java9 # * Java needs to be at least 1.8.0_131 to have MD5 properly disabled # https://blogs.oracle.com/java-platform-group/oracle-jre-will-no-longer-trust-md5-signed-code-by-default # https://opsech.io/posts/2017/Jun/09/openjdk-april-2017-security-update-131-8u131-and-md5-signed-jars.html install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + set -x; brew update > /dev/null; brew install dash bash python3 gradle jenv; brew install gnu-sed --with-default-names; @@ -86,11 +87,19 @@ install: which jarsigner; keytool -help; which keytool; + set +x; fi +# The OSX tests seem to run slower, they often timeout. So only run +# the test suite with the installed version of fdroid, instead of the +# three rounds that ./complete-ci-tests does. script: - cd tests - - ./complete-ci-tests + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + ./run-tests; + else + ./complete-ci-tests; + fi after_failure: - cd $TRAVIS_BUILD_DIR From e0df6d24795237dbe586627d13ad2c9ef404f614 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 20 Oct 2017 11:35:48 +0200 Subject: [PATCH 2/8] choose the most recent available version of Java This came about testing on OSX, where there are often multiple versions of the JDK installed. This was choosing the oldest version. It should choose the most recent version. --- .travis.yml | 2 ++ fdroidserver/common.py | 59 ++++++++++++++++++++++++++---------------- tests/common.TestCase | 39 ++++++++++++++++++++++++++-- 3 files changed, 75 insertions(+), 25 deletions(-) diff --git a/.travis.yml b/.travis.yml index 27df250a..8af32606 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,6 +75,8 @@ install: sudo pip3 install --quiet --editable . ; sudo rm -rf fdroidserver.egg-info; + ls -l /System/Library/Java/JavaVirtualMachines || true; + ls -l /Library/Java/JavaVirtualMachines || true; echo $PATH; echo $JAVA_HOME; jenv versions; diff --git a/fdroidserver/common.py b/fdroidserver/common.py index c6fbf0d2..7e76513d 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -132,6 +132,41 @@ def setup_global_opts(parser): help=_("Restrict output to warnings and errors")) +def _add_java_paths_to_config(pathlist, thisconfig): + def path_version_key(s): + versionlist = [] + for u in re.split('[^0-9]+', s): + try: + versionlist.append(int(u)) + except ValueError: + pass + return versionlist + + for d in sorted(pathlist, key=path_version_key): + if os.path.islink(d): + continue + j = os.path.basename(d) + # the last one found will be the canonical one, so order appropriately + for regex in [ + r'^1\.([6-9])\.0\.jdk$', # OSX + r'^jdk1\.([6-9])\.0_[0-9]+.jdk$', # OSX and Oracle tarball + r'^jdk1\.([6-9])\.0_[0-9]+$', # Oracle Windows + r'^jdk([6-9])-openjdk$', # Arch + r'^java-([6-9])-openjdk$', # Arch + r'^java-([6-9])-jdk$', # Arch (oracle) + r'^java-1\.([6-9])\.0-.*$', # RedHat + r'^java-([6-9])-oracle$', # Debian WebUpd8 + r'^jdk-([6-9])-oracle-.*$', # Debian make-jpkg + r'^java-([6-9])-openjdk-[^c][^o][^m].*$', # Debian + ]: + m = re.match(regex, j) + if not m: + continue + for p in [d, os.path.join(d, 'Contents', 'Home')]: + if os.path.exists(os.path.join(p, 'bin', 'javac')): + thisconfig['java_paths'][m.group(1)] = p + + def fill_config_defaults(thisconfig): for k, v in default_config.items(): if k not in thisconfig: @@ -167,29 +202,7 @@ def fill_config_defaults(thisconfig): pathlist.append(os.getenv('JAVA_HOME')) if os.getenv('PROGRAMFILES') is not None: pathlist += glob.glob(os.path.join(os.getenv('PROGRAMFILES'), 'Java', 'jdk1.[6-9].*')) - for d in sorted(pathlist): - if os.path.islink(d): - continue - j = os.path.basename(d) - # the last one found will be the canonical one, so order appropriately - for regex in [ - r'^1\.([6-9])\.0\.jdk$', # OSX - r'^jdk1\.([6-9])\.0_[0-9]+.jdk$', # OSX and Oracle tarball - r'^jdk1\.([6-9])\.0_[0-9]+$', # Oracle Windows - r'^jdk([6-9])-openjdk$', # Arch - r'^java-([6-9])-openjdk$', # Arch - r'^java-([6-9])-jdk$', # Arch (oracle) - r'^java-1\.([6-9])\.0-.*$', # RedHat - r'^java-([6-9])-oracle$', # Debian WebUpd8 - r'^jdk-([6-9])-oracle-.*$', # Debian make-jpkg - r'^java-([6-9])-openjdk-[^c][^o][^m].*$', # Debian - ]: - m = re.match(regex, j) - if not m: - continue - for p in [d, os.path.join(d, 'Contents', 'Home')]: - if os.path.exists(os.path.join(p, 'bin', 'javac')): - thisconfig['java_paths'][m.group(1)] = p + _add_java_paths_to_config(pathlist, thisconfig) for java_version in ('7', '8', '9'): if java_version not in thisconfig['java_paths']: diff --git a/tests/common.TestCase b/tests/common.TestCase index 3a10b7bb..2c261267 100755 --- a/tests/common.TestCase +++ b/tests/common.TestCase @@ -92,6 +92,41 @@ class CommonTest(unittest.TestCase): else: print('no build-tools found: ' + build_tools) + def test_find_java_root_path(self): + tmptestsdir = tempfile.mkdtemp(prefix='test_find_java_root_path', dir=self.tmpdir) + os.chdir(tmptestsdir) + + all_pathlists = [ + ([ # Debian + '/usr/lib/jvm/java-1.5.0-gcj-5-amd64', + '/usr/lib/jvm/java-8-openjdk-amd64', + '/usr/lib/jvm/java-1.8.0-openjdk-amd64', + ], '/usr/lib/jvm/java-8-openjdk-amd64'), + ([ # OSX + '/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk', + '/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk', + '/System/Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk', + ], '/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk'), + ] + + for pathlist, choice in all_pathlists: + # strip leading / to make relative paths to test without root + pathlist = [p[1:] for p in pathlist] + + # create test file used in common._add_java_paths_to_config() + for p in pathlist: + if p.startswith('/System') or p.startswith('/Library'): + basedir = os.path.join(p, 'Contents', 'Home', 'bin') + else: + basedir = os.path.join(p, 'bin') + os.makedirs(basedir) + open(os.path.join(basedir, 'javac'), 'w').close() + + config = dict() + config['java_paths'] = dict() + fdroidserver.common._add_java_paths_to_config(pathlist, config) + self.assertEqual(config['java_paths']['8'], choice[1:]) + def testIsApkDebuggable(self): config = dict() fdroidserver.common.fill_config_defaults(config) @@ -177,7 +212,7 @@ class CommonTest(unittest.TestCase): def test_prepare_sources_refresh(self): packageName = 'org.fdroid.ci.test.app' - testdir = tempfile.mkdtemp(prefix='test_verify_apks', dir=self.tmpdir) + testdir = tempfile.mkdtemp(prefix='test_prepare_sources_refresh', dir=self.tmpdir) print('testdir', testdir) os.chdir(testdir) os.mkdir('build') @@ -462,4 +497,4 @@ if __name__ == "__main__": newSuite = unittest.TestSuite() newSuite.addTest(unittest.makeSuite(CommonTest)) - unittest.main() + unittest.main(failfast=False) From 17efa13183561af7aa39270f8718eadb7eb8fb32 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 20 Oct 2017 11:51:59 +0200 Subject: [PATCH 3/8] tests: pre-set failfast as reminder of a handy time saver --- tests/build.TestCase | 2 +- tests/common.TestCase | 2 +- tests/exception.TestCase | 2 +- tests/import.TestCase | 2 +- tests/index.TestCase | 2 +- tests/install.TestCase | 2 +- tests/lint.TestCase | 2 +- tests/metadata.TestCase | 2 +- tests/publish.TestCase | 2 +- tests/signatures.TestCase | 2 +- tests/update.TestCase | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/build.TestCase b/tests/build.TestCase index 9391a042..b595f3fa 100755 --- a/tests/build.TestCase +++ b/tests/build.TestCase @@ -74,4 +74,4 @@ if __name__ == "__main__": newSuite = unittest.TestSuite() newSuite.addTest(unittest.makeSuite(BuildTest)) - unittest.main() + unittest.main(failfast=False) diff --git a/tests/common.TestCase b/tests/common.TestCase index 2c261267..ecd16a8d 100755 --- a/tests/common.TestCase +++ b/tests/common.TestCase @@ -497,4 +497,4 @@ if __name__ == "__main__": newSuite = unittest.TestSuite() newSuite.addTest(unittest.makeSuite(CommonTest)) - unittest.main(failfast=False) + unittest.main(failfast=True) diff --git a/tests/exception.TestCase b/tests/exception.TestCase index 01d0a5af..6c2f0c3e 100755 --- a/tests/exception.TestCase +++ b/tests/exception.TestCase @@ -62,4 +62,4 @@ if __name__ == "__main__": newSuite = unittest.TestSuite() newSuite.addTest(unittest.makeSuite(ExceptionTest)) - unittest.main() + unittest.main(failfast=False) diff --git a/tests/import.TestCase b/tests/import.TestCase index 9c7b99d5..a41028c9 100755 --- a/tests/import.TestCase +++ b/tests/import.TestCase @@ -54,4 +54,4 @@ if __name__ == "__main__": newSuite = unittest.TestSuite() newSuite.addTest(unittest.makeSuite(ImportTest)) - unittest.main() + unittest.main(failfast=False) diff --git a/tests/index.TestCase b/tests/index.TestCase index bf76b812..4a7463fb 100755 --- a/tests/index.TestCase +++ b/tests/index.TestCase @@ -236,4 +236,4 @@ if __name__ == "__main__": newSuite = unittest.TestSuite() newSuite.addTest(unittest.makeSuite(IndexTest)) - unittest.main() + unittest.main(failfast=False) diff --git a/tests/install.TestCase b/tests/install.TestCase index ce516117..27573eae 100755 --- a/tests/install.TestCase +++ b/tests/install.TestCase @@ -43,4 +43,4 @@ if __name__ == "__main__": newSuite = unittest.TestSuite() newSuite.addTest(unittest.makeSuite(InstallTest)) - unittest.main() + unittest.main(failfast=False) diff --git a/tests/lint.TestCase b/tests/lint.TestCase index 158c5cb1..f2a411c5 100755 --- a/tests/lint.TestCase +++ b/tests/lint.TestCase @@ -53,4 +53,4 @@ if __name__ == "__main__": newSuite = unittest.TestSuite() newSuite.addTest(unittest.makeSuite(LintTest)) - unittest.main() + unittest.main(failfast=False) diff --git a/tests/metadata.TestCase b/tests/metadata.TestCase index f3d58077..306f1c46 100755 --- a/tests/metadata.TestCase +++ b/tests/metadata.TestCase @@ -129,4 +129,4 @@ if __name__ == "__main__": newSuite = unittest.TestSuite() newSuite.addTest(unittest.makeSuite(MetadataTest)) - unittest.main() + unittest.main(failfast=False) diff --git a/tests/publish.TestCase b/tests/publish.TestCase index 7a31d39e..8e165608 100755 --- a/tests/publish.TestCase +++ b/tests/publish.TestCase @@ -144,4 +144,4 @@ if __name__ == "__main__": newSuite = unittest.TestSuite() newSuite.addTest(unittest.makeSuite(PublishTest)) - unittest.main() + unittest.main(failfast=False) diff --git a/tests/signatures.TestCase b/tests/signatures.TestCase index 42a69c7c..bd6648cd 100755 --- a/tests/signatures.TestCase +++ b/tests/signatures.TestCase @@ -62,4 +62,4 @@ if __name__ == "__main__": newSuite = unittest.TestSuite() newSuite.addTest(unittest.makeSuite(SignaturesTest)) - unittest.main() + unittest.main(failfast=False) diff --git a/tests/update.TestCase b/tests/update.TestCase index 76a93802..8a88fc4e 100755 --- a/tests/update.TestCase +++ b/tests/update.TestCase @@ -576,4 +576,4 @@ if __name__ == "__main__": newSuite = unittest.TestSuite() newSuite.addTest(unittest.makeSuite(UpdateTest)) - unittest.main() + unittest.main(failfast=False) From dd6d4b20121a51431df186d0de4dac2f95b0b5c2 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 20 Oct 2017 22:07:28 +0200 Subject: [PATCH 4/8] preserve metadata when copying APK signatures Since this code was not setting the "create system" and "compress type", Python uses it's defaults. Those will be different than what the Android tools produces if this is run on UNIX. The Android tools uses the bare bones "Windows" ZIP format, e.g. no permissions, etc. For example: https://verification.f-droid.org/eu.siacs.conversations_234.apk.diffoscope.html --- fdroidserver/common.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 7e76513d..9129dfdf 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -2251,15 +2251,15 @@ def apk_strip_signatures(signed_apk, strip_manifest=False): os.rename(signed_apk, tmp_apk) with ZipFile(tmp_apk, 'r') as in_apk: with ZipFile(signed_apk, 'w') as out_apk: - for f in in_apk.infolist(): - if not apk_sigfile.match(f.filename): + for info in in_apk.infolist(): + if not apk_sigfile.match(info.filename): if strip_manifest: - if f.filename != 'META-INF/MANIFEST.MF': - buf = in_apk.read(f.filename) - out_apk.writestr(f.filename, buf) + if info.filename != 'META-INF/MANIFEST.MF': + buf = in_apk.read(info.filename) + out_apk.writestr(info, buf) else: - buf = in_apk.read(f.filename) - out_apk.writestr(f.filename, buf) + buf = in_apk.read(info.filename) + out_apk.writestr(info, buf) def apk_implant_signatures(apkpath, signaturefile, signedfile, manifest): @@ -2272,19 +2272,21 @@ def apk_implant_signatures(apkpath, signaturefile, signedfile, manifest): """ # get list of available signature files in metadata with tempfile.TemporaryDirectory() as tmpdir: - # orig_apk = os.path.join(tmpdir, 'orig.apk') - # os.rename(apkpath, orig_apk) apkwithnewsig = os.path.join(tmpdir, 'newsig.apk') with ZipFile(apkpath, 'r') as in_apk: with ZipFile(apkwithnewsig, 'w') as out_apk: for sig_file in [signaturefile, signedfile, manifest]: - out_apk.write(sig_file, arcname='META-INF/' + - os.path.basename(sig_file)) - for f in in_apk.infolist(): - if not apk_sigfile.match(f.filename): - if f.filename != 'META-INF/MANIFEST.MF': - buf = in_apk.read(f.filename) - out_apk.writestr(f.filename, buf) + with open(sig_file, 'rb') as fp: + buf = fp.read() + info = zipfile.ZipInfo('META-INF/' + os.path.basename(sig_file)) + info.compress_type = zipfile.ZIP_DEFLATED + info.create_system = 0 # "Windows" aka "FAT", what Android SDK uses + out_apk.writestr(info, buf) + for info in in_apk.infolist(): + if not apk_sigfile.match(info.filename): + if info.filename != 'META-INF/MANIFEST.MF': + buf = in_apk.read(info.filename) + out_apk.writestr(info, buf) os.remove(apkpath) p = SdkToolsPopen(['zipalign', '-v', '4', apkwithnewsig, apkpath]) if p.returncode != 0: From ffc91e301a2ea7046e4996fa085859b27264bc4f Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 24 Oct 2017 16:48:42 +0200 Subject: [PATCH 5/8] make _ always be the gettext function, nothing else This avoids hard bugs where the _() function gets overidden by a str or something else. --- fdroidserver/common.py | 4 ++-- fdroidserver/metadata.py | 6 +++--- fdroidserver/scanner.py | 2 +- fdroidserver/update.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 9129dfdf..634de8b5 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -519,7 +519,7 @@ def get_extension(filename): def has_extension(filename, ext): - _, f_ext = get_extension(filename) + _ignored, f_ext = get_extension(filename) return ext == f_ext @@ -1745,7 +1745,7 @@ class KnownApks: default_date = datetime.utcnow() self.apks[apkName] = (app, default_date) self.changed = True - _, added = self.apks[apkName] + _ignored, added = self.apks[apkName] return added def getapp(self, apkname): diff --git a/fdroidserver/metadata.py b/fdroidserver/metadata.py index 16c40a88..cc094258 100644 --- a/fdroidserver/metadata.py +++ b/fdroidserver/metadata.py @@ -921,7 +921,7 @@ def _decode_bool(s): def parse_metadata(metadatapath, check_vcs=False): '''parse metadata file, optionally checking the git repo for metadata first''' - _, ext = fdroidserver.common.get_extension(metadatapath) + _ignored, ext = fdroidserver.common.get_extension(metadatapath) accepted = fdroidserver.common.config['accepted_formats'] if ext not in accepted: warn_or_exception('"%s" is not an accepted format, convert to: %s' % ( @@ -970,7 +970,7 @@ def parse_metadata(metadatapath, check_vcs=False): else: root_dir = '.' paths = fdroidserver.common.manifest_paths(root_dir, build.gradle) - _, _, app.id = fdroidserver.common.parse_androidmanifests(paths, app) + _ignored, _ignored, app.id = fdroidserver.common.parse_androidmanifests(paths, app) return app @@ -1498,7 +1498,7 @@ def write_txt(mf, app): def write_metadata(metadatapath, app): - _, ext = fdroidserver.common.get_extension(metadatapath) + _ignored, ext = fdroidserver.common.get_extension(metadatapath) accepted = fdroidserver.common.config['accepted_formats'] if ext not in accepted: warn_or_exception('Cannot write "%s", not an accepted format, use: %s' diff --git a/fdroidserver/scanner.py b/fdroidserver/scanner.py index 030ac7c4..cad0026b 100644 --- a/fdroidserver/scanner.py +++ b/fdroidserver/scanner.py @@ -185,7 +185,7 @@ def scan_source(build_dir, build): continue path_in_build_dir = os.path.relpath(filepath, build_dir) - _, ext = common.get_extension(path_in_build_dir) + _ignored, ext = common.get_extension(path_in_build_dir) if ext == 'so': count += handleproblem('shared library', path_in_build_dir, filepath) diff --git a/fdroidserver/update.py b/fdroidserver/update.py index 6b31f162..83018a75 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -824,7 +824,7 @@ def insert_localized_app_metadata(apps): locale = segments[-2] destdir = os.path.join('repo', packageName, locale) for f in glob.glob(os.path.join(root, d, '*.*')): - _, extension = common.get_extension(f) + _ignored, extension = common.get_extension(f) if extension in ALLOWED_EXTENSIONS: screenshotdestdir = os.path.join(destdir, d) os.makedirs(screenshotdestdir, mode=0o755, exist_ok=True) From ac69d5b17d2459563b048d1d41d5e60745da0486 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 19 Oct 2017 21:03:39 +0200 Subject: [PATCH 6/8] update: make all strings translatable --- fdroidserver/update.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fdroidserver/update.py b/fdroidserver/update.py index 83018a75..50c4d462 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -846,24 +846,24 @@ def insert_localized_app_metadata(apps): base, extension = common.get_extension(filename) if packageName not in apps: - logging.warning('Found "%s" graphic without metadata for app "%s"!' - % (filename, packageName)) + logging.warning(_('Found "{path}" graphic without metadata for app "{name}"!') + .format(path=filename, name=packageName)) continue graphics = _get_localized_dict(apps[packageName], locale) if extension not in ALLOWED_EXTENSIONS: - logging.warning('Only PNG and JPEG are supported for graphics, found: ' + f) + logging.warning(_('Only PNG and JPEG are supported for graphics, found: {path}').format(path=f)) elif base in GRAPHIC_NAMES: # there can only be zero or one of these per locale graphics[base] = filename elif screenshotdir in SCREENSHOT_DIRS: # there can any number of these per locale - logging.debug('adding to ' + screenshotdir + ': ' + f) + logging.debug(_('adding to {name}: {path}').format(name=screenshotdir, path=f)) if screenshotdir not in graphics: graphics[screenshotdir] = [] graphics[screenshotdir].append(filename) else: - logging.warning('Unsupported graphics file found: ' + f) + logging.warning(_('Unsupported graphics file found: {path}').format(path=f)) def scan_repo_files(apkcache, repodir, knownapks, use_date_from_file=False): From 230d8971baf65695960d0f94ff1a4f586ad18de8 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 24 Oct 2017 16:47:53 +0200 Subject: [PATCH 7/8] metadata: make all strings translatable --- fdroidserver/metadata.py | 88 ++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/fdroidserver/metadata.py b/fdroidserver/metadata.py index cc094258..d65eb81a 100644 --- a/fdroidserver/metadata.py +++ b/fdroidserver/metadata.py @@ -380,8 +380,8 @@ class FieldValidator(): values = [v] for v in values: if not self.compiled.match(v): - warn_or_exception("'%s' is not a valid %s in %s. Regex pattern: %s" - % (v, self.name, appid, self.matching)) + warn_or_exception(_("'{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 @@ -534,7 +534,7 @@ class DescriptionFormatter: if txt.startswith("[["): index = txt.find("]]") if index == -1: - warn_or_exception("Unterminated ]]") + warn_or_exception(_("Unterminated ]]")) url = txt[2:index] if self.linkResolver: url, urltext = self.linkResolver(url) @@ -546,7 +546,7 @@ class DescriptionFormatter: else: index = txt.find("]") if index == -1: - warn_or_exception("Unterminated ]") + warn_or_exception(_("Unterminated ]")) url = txt[1:index] index2 = url.find(' ') if index2 == -1: @@ -555,7 +555,7 @@ class DescriptionFormatter: urltxt = url[index2 + 1:] url = url[:index2] if url == urltxt: - warn_or_exception("Url title is just the URL - use [url]") + warn_or_exception(_("URL title is just the URL, use brackets: [URL]")) res_html += '' + html.escape(urltxt, quote=False) + '' res_plain += urltxt if urltxt != url: @@ -664,7 +664,7 @@ def parse_srclib(metadatapath): try: f, v = line.split(':', 1) except ValueError: - warn_or_exception("Invalid metadata in %s:%d" % (line, n)) + warn_or_exception(_("Invalid metadata in %s:%d") % (line, n)) if f == "Subdir": thisinfo[f] = v.split(',') @@ -734,7 +734,8 @@ def read_metadata(xref=True, check_vcs=[]): + glob.glob('.fdroid.yml')): packageName, _ignored = fdroidserver.common.get_extension(os.path.basename(metadatapath)) if packageName in apps: - warn_or_exception("Found multiple metadata files for " + packageName) + warn_or_exception(_("Found multiple metadata files for {appid}") + .format(path=packageName)) app = parse_metadata(metadatapath, packageName in check_vcs) check_metadata(app) apps[app.id] = app @@ -745,14 +746,14 @@ def read_metadata(xref=True, check_vcs=[]): def linkres(appid): if appid in apps: return ("fdroid.app:" + appid, "Dummy name - don't know yet") - warn_or_exception("Cannot resolve app id " + appid) + warn_or_exception(_("Cannot resolve app id {appid}").format(appid=appid)) for appid, app in apps.items(): try: description_html(app.Description, linkres) except MetaDataException as e: - warn_or_exception("Problem with description of " + appid + - " - " + str(e)) + warn_or_exception(_("Problem with description of {appid}: {error}") + .format(appid=appid, error=str(e))) return apps @@ -795,7 +796,8 @@ def get_default_app_info(metadatapath=None): manifestroot = fdroidserver.common.parse_xml(os.path.join(root, 'AndroidManifest.xml')) break if manifestroot is None: - warn_or_exception("Cannot find a packageName for {0}!".format(metadatapath)) + warn_or_exception(_("Cannot find a packageName for {path}!") + .format(path=metadatapath)) appid = manifestroot.attrib['package'] app = App() @@ -915,7 +917,7 @@ def _decode_bool(s): return True if bool_false.match(s): return False - warn_or_exception("Invalid bool '%s'" % s) + warn_or_exception(_("Invalid boolean '%s'") % s) def parse_metadata(metadatapath, check_vcs=False): @@ -924,8 +926,8 @@ def parse_metadata(metadatapath, check_vcs=False): _ignored, ext = fdroidserver.common.get_extension(metadatapath) accepted = fdroidserver.common.config['accepted_formats'] if ext not in accepted: - warn_or_exception('"%s" is not an accepted format, convert to: %s' % ( - metadatapath, ', '.join(accepted))) + warn_or_exception(_('"{path}" is not an accepted format, convert to: {formats}') + .format(path=metadatapath, formats=', '.join(accepted))) app = App() app.metadatapath = metadatapath @@ -943,7 +945,8 @@ def parse_metadata(metadatapath, check_vcs=False): elif ext == 'yml': parse_yaml_metadata(mf, app) else: - warn_or_exception('Unknown metadata format: %s' % metadatapath) + warn_or_exception(_('Unknown metadata format: {path}') + .format(path=metadatapath)) if check_vcs and app.Repo: build_dir = fdroidserver.common.get_build_dir(app) @@ -1162,12 +1165,12 @@ def parse_txt_metadata(mf, app): def add_buildflag(p, build): if not p.strip(): - warn_or_exception("Empty build flag at {1}" - .format(buildlines[0], linedesc)) + warn_or_exception(_("Empty build flag at {linedesc}") + .format(linedesc=linedesc)) bv = p.split('=', 1) if len(bv) != 2: - warn_or_exception("Invalid build flag at {0} in {1}" - .format(buildlines[0], linedesc)) + warn_or_exception(_("Invalid build flag at {line} in {linedesc}") + .format(line=buildlines[0], linedesc=linedesc)) pk, pv = bv pk = pk.lstrip() @@ -1186,7 +1189,8 @@ def parse_txt_metadata(mf, app): v = "".join(lines) parts = [p.replace("\\,", ",") for p in re.split(build_line_sep, v)] if len(parts) < 3: - warn_or_exception("Invalid build format: " + v + " in " + mf.name) + warn_or_exception(_("Invalid build format: {value} in {name}") + .format(value=v, name=mf.name)) build = Build() build.versionName = parts[0] build.versionCode = parts[1] @@ -1214,7 +1218,8 @@ def parse_txt_metadata(mf, app): try: int(versionCode) except ValueError: - warn_or_exception('Invalid versionCode: "' + versionCode + '" is not an integer!') + warn_or_exception(_('Invalid versionCode: "{versionCode}" is not an integer!') + .format(versionCode=versionCode)) def add_comments(key): if not curcomments: @@ -1247,8 +1252,8 @@ def parse_txt_metadata(mf, app): del buildlines[:] else: if not build.commit and not build.disable: - warn_or_exception("No commit specified for {0} in {1}" - .format(build.versionName, linedesc)) + warn_or_exception(_("No commit specified for {versionName} in {linedesc}") + .format(versionName=build.versionName, linedesc=linedesc)) app.builds.append(build) add_comments('build:' + build.versionCode) @@ -1263,10 +1268,10 @@ def parse_txt_metadata(mf, app): try: f, v = line.split(':', 1) except ValueError: - warn_or_exception("Invalid metadata in " + linedesc) + warn_or_exception(_("Invalid metadata in: ") + linedesc) if f not in app_fields: - warn_or_exception('Unrecognised app field: ' + f) + warn_or_exception(_('Unrecognised app field: ') + f) # Translate obsolete fields... if f == 'Market Version': @@ -1282,8 +1287,8 @@ def parse_txt_metadata(mf, app): if ftype == TYPE_MULTILINE: mode = 1 if v: - warn_or_exception("Unexpected text on same line as " - + f + " in " + linedesc) + warn_or_exception(_("Unexpected text on same line as {field} in {linedesc}") + .format(field=f, linedesc=linedesc)) elif ftype == TYPE_STRING: app[f] = v elif ftype == TYPE_LIST: @@ -1300,24 +1305,26 @@ def parse_txt_metadata(mf, app): elif ftype == TYPE_BUILD_V2: vv = v.split(',') if len(vv) != 2: - warn_or_exception('Build should have comma-separated', - 'versionName and versionCode,', - 'not "{0}", in {1}'.format(v, linedesc)) + warn_or_exception(_('Build should have comma-separated ' + 'versionName and versionCode, ' + 'not "{value}", in {linedesc}') + .format(value=v, linedesc=linedesc)) build = Build() build.versionName = vv[0] build.versionCode = vv[1] check_versionCode(build.versionCode) if build.versionCode in vc_seen: - warn_or_exception('Duplicate build recipe found for versionCode %s in %s' - % (build.versionCode, linedesc)) + warn_or_exception(_('Duplicate build recipe found for versionCode {versionCode} in {linedesc}') + .format(versionCode=build.versionCode, linedesc=linedesc)) vc_seen.add(build.versionCode) del buildlines[:] mode = 3 elif ftype == TYPE_OBSOLETE: pass # Just throw it away! else: - warn_or_exception("Unrecognised field '" + f + "' in " + linedesc) + warn_or_exception(_("Unrecognised field '{field}' in {linedesc}") + .format(field=f, linedesc=linedesc)) elif mode == 1: # Multiline field if line == '.': mode = 0 @@ -1338,11 +1345,14 @@ def parse_txt_metadata(mf, app): # Mode at end of file should always be 0 if mode == 1: - warn_or_exception(f + " not terminated in " + mf.name) + warn_or_exception(_("{field} not terminated in {name}") + .format(field=f, name=mf.name)) if mode == 2: - warn_or_exception("Unterminated continuation in " + mf.name) + warn_or_exception(_("Unterminated continuation in {name}") + .format(name=mf.name)) if mode == 3: - warn_or_exception("Unterminated build in " + mf.name) + warn_or_exception(_("Unterminated build in {name}") + .format(name=mf.name)) return app @@ -1501,8 +1511,8 @@ def write_metadata(metadatapath, app): _ignored, ext = fdroidserver.common.get_extension(metadatapath) accepted = fdroidserver.common.config['accepted_formats'] if ext not in accepted: - warn_or_exception('Cannot write "%s", not an accepted format, use: %s' - % (metadatapath, ', '.join(accepted))) + warn_or_exception(_('Cannot write "{path}", not an accepted format, use: {formats}') + .format(path=metadatapath, formats=', '.join(accepted))) try: with open(metadatapath, 'w', encoding='utf8') as mf: @@ -1514,7 +1524,7 @@ def write_metadata(metadatapath, app): os.remove(metadatapath) raise e - warn_or_exception('Unknown metadata format: %s' % metadatapath) + warn_or_exception(_('Unknown metadata format: %s') % metadatapath) def add_metadata_arguments(parser): From 505d2c132558edf484509b8169cc6375cb35476b Mon Sep 17 00:00:00 2001 From: Ciaran Gultnieks Date: Tue, 24 Oct 2017 22:11:13 +0200 Subject: [PATCH 8/8] update bombs out when no icons (closes #402) --- fdroidserver/update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdroidserver/update.py b/fdroidserver/update.py index 50c4d462..574f1c24 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -1625,7 +1625,7 @@ def move_apk_between_sections(from_dir, to_dir, apk): for density in all_screen_densities: from_icon_dir = get_icon_dir(from_dir, density) to_icon_dir = get_icon_dir(to_dir, density) - if density not in apk['icons']: + if density not in apk.get('icons', []): continue _move_file(from_icon_dir, to_icon_dir, apk['icons'][density], True) if 'srcname' in apk: