From 8f21f1e510b01d97c7e44986c00234117a5a92af Mon Sep 17 00:00:00 2001 From: linsui Date: Tue, 8 Jun 2021 21:31:55 +0800 Subject: [PATCH] metadata.py/rewritemeta.py: use pathlib and support Windows --- fdroidserver/common.py | 12 +- fdroidserver/metadata.py | 97 ++-- fdroidserver/rewritemeta.py | 16 +- tests/build.TestCase | 166 ++++++- tests/checkupdates.TestCase | 3 - tests/import.TestCase | 3 - tests/metadata.TestCase | 911 +++++++++++++++++++++--------------- tests/rewritemeta.TestCase | 71 ++- 8 files changed, 768 insertions(+), 511 deletions(-) diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 44dd32f9..8d1a81c7 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -669,8 +669,8 @@ def get_metadata_files(vercodes): found_invalid = False metadatafiles = [] for appid in vercodes.keys(): - f = os.path.join('metadata', '%s.yml' % appid) - if os.path.exists(f): + f = Path('metadata') / ('%s.yml' % appid) + if f.exists(): metadatafiles.append(f) else: found_invalid = True @@ -795,9 +795,9 @@ def get_build_dir(app): '''get the dir that this app will be built in''' if app.RepoType == 'srclib': - return os.path.join('build', 'srclib', app.Repo) + return Path('build/srclib') / app.Repo - return os.path.join('build', app.id) + return Path('build') / app.id class Encoder(json.JSONEncoder): @@ -869,6 +869,8 @@ def get_head_commit_id(git_repo): def setup_vcs(app): '''checkout code from VCS and return instance of vcs and the build dir''' build_dir = get_build_dir(app) + # TODO: Remove this + build_dir = str(build_dir) # Set up vcs interface and make sure we have the latest code... logging.debug("Getting {0} vcs interface for {1}" @@ -3982,6 +3984,8 @@ YAML_LINT_CONFIG = {'extends': 'default', def run_yamllint(path, indent=0): + # TODO: Remove this + path = str(path) try: import yamllint.config import yamllint.linter diff --git a/fdroidserver/metadata.py b/fdroidserver/metadata.py index cc2e7876..947a119e 100644 --- a/fdroidserver/metadata.py +++ b/fdroidserver/metadata.py @@ -19,9 +19,9 @@ # along with this program. If not, see . import git -import os +from pathlib import Path, PurePosixPath +import platform import re -import glob import logging import yaml try: @@ -31,9 +31,9 @@ except ImportError: import importlib from collections import OrderedDict -import fdroidserver.common -from fdroidserver import _ -from fdroidserver.exception import MetaDataException, FDroidException +from . import common +from . import _ +from .exception import MetaDataException, FDroidException srclibs = None warnings_action = None @@ -330,7 +330,7 @@ class Build(dict): ndk = self.ndk if isinstance(ndk, list): ndk = self.ndk[0] - return fdroidserver.common.config['ndk_paths'].get(ndk, '') + return common.config['ndk_paths'].get(ndk, '') flagtypes = { @@ -470,15 +470,22 @@ def parse_yaml_srclib(metadatapath): 'Subdir': None, 'Prepare': None} - if not os.path.exists(metadatapath): + if not metadatapath.exists(): _warn_or_exception(_("Invalid scrlib metadata: '{file}' " "does not exist" .format(file=metadatapath))) return thisinfo - with open(metadatapath, "r", encoding="utf-8") as f: + with metadatapath.open("r", encoding="utf-8") as f: try: data = yaml.load(f, Loader=SafeLoader) + if type(data) is not dict: + if platform.system() == 'Windows': + # Handle symlink on Windows + symlink = metadatapath.parent / metadatapath.read_text() + if symlink.is_file(): + with symlink.open("r", encoding="utf-8") as s: + data = yaml.load(s, Loader=SafeLoader) if type(data) is not dict: raise yaml.error.YAMLError(_('{file} is blank or corrupt!') .format(file=metadatapath)) @@ -486,8 +493,7 @@ def parse_yaml_srclib(metadatapath): _warn_or_exception(_("Invalid srclib metadata: could not " "parse '{file}'") .format(file=metadatapath) + '\n' - + fdroidserver.common.run_yamllint(metadatapath, - indent=4), + + common.run_yamllint(metadatapath, indent=4), cause=e) return thisinfo @@ -531,13 +537,11 @@ def read_srclibs(): srclibs = {} - srcdir = 'srclibs' - if not os.path.exists(srcdir): - os.makedirs(srcdir) + srcdir = Path('srclibs') + srcdir.mkdir(exist_ok=True) - for metadatapath in sorted(glob.glob(os.path.join(srcdir, '*.yml'))): - srclibname = os.path.basename(metadatapath[:-4]) - srclibs[srclibname] = parse_yaml_srclib(metadatapath) + for metadatapath in sorted(srcdir.glob('*.yml')): + srclibs[metadatapath.stem] = parse_yaml_srclib(metadatapath) def read_metadata(appids={}, sort_by_time=False): @@ -559,18 +563,17 @@ def read_metadata(appids={}, sort_by_time=False): apps = OrderedDict() for basedir in ('metadata', 'tmp'): - if not os.path.exists(basedir): - os.makedirs(basedir) + Path(basedir).mkdir(exist_ok=True) if appids: - vercodes = fdroidserver.common.read_pkg_args(appids) - metadatafiles = fdroidserver.common.get_metadata_files(vercodes) + vercodes = common.read_pkg_args(appids) + metadatafiles = common.get_metadata_files(vercodes) else: - metadatafiles = (glob.glob(os.path.join('metadata', '*.yml')) - + glob.glob('.fdroid.yml')) + metadatafiles = list(Path('metadata').glob('*.yml')) + list( + Path('.').glob('.fdroid.yml')) if sort_by_time: - entries = ((os.stat(path).st_mtime, path) for path in metadatafiles) + entries = ((path.stat().st_mtime, path) for path in metadatafiles) metadatafiles = [] for _ignored, path in sorted(entries, reverse=True): metadatafiles.append(path) @@ -579,8 +582,8 @@ def read_metadata(appids={}, sort_by_time=False): metadatafiles = sorted(metadatafiles) for metadatapath in metadatafiles: - appid, _ignored = fdroidserver.common.get_extension(os.path.basename(metadatapath)) - if appid != '.fdroid' and not fdroidserver.common.is_valid_package_name(appid): + appid = metadatapath.stem + if appid != '.fdroid' and not common.is_valid_package_name(appid): _warn_or_exception(_("{appid} from {path} is not a valid Java Package Name!") .format(appid=appid, path=metadatapath)) if appid in apps: @@ -684,7 +687,7 @@ def post_metadata_parse(app): # Parse metadata for a single application. # -# 'metadatapath' - the filename to read. The "Application ID" aka +# 'metadatapath' - the file path to read. The "Application ID" aka # "Package Name" for the application comes from this # filename. Pass None to get a blank entry. # @@ -729,27 +732,27 @@ def parse_metadata(metadatapath): the source code. """ - + metadatapath = Path(metadatapath) app = App() - app.metadatapath = metadatapath - metadata_file = os.path.basename(metadatapath) - name, _ignored = fdroidserver.common.get_extension(metadata_file) + app.metadatapath = str(PurePosixPath(metadatapath)) + name = metadatapath.stem if name != '.fdroid': app.id = name - if metadatapath.endswith('.yml'): - with open(metadatapath, 'r') as mf: + if metadatapath.suffix == '.yml': + with metadatapath.open('r') as mf: parse_yaml_metadata(mf, app) else: _warn_or_exception(_('Unknown metadata format: {path} (use: *.yml)') .format(path=metadatapath)) - if metadata_file != '.fdroid.yml' and app.Repo: - build_dir = fdroidserver.common.get_build_dir(app) - metadata_in_repo = os.path.join(build_dir, '.fdroid.yml') - if os.path.isfile(metadata_in_repo): + if metadatapath.name != '.fdroid.yml' and app.Repo: + build_dir = common.get_build_dir(app) + metadata_in_repo = build_dir / '.fdroid.yml' + if metadata_in_repo.is_file(): try: - commit_id = fdroidserver.common.get_head_commit_id(git.repo.Repo(build_dir)) + # TODO: Python3.6: Should accept path-like + commit_id = common.get_head_commit_id(git.Repo(str(build_dir))) logging.debug(_('Including metadata from %s@%s') % (metadata_in_repo, commit_id)) except git.exc.InvalidGitRepositoryError: logging.debug(_('Including metadata from {path}').format(metadata_in_repo)) @@ -764,11 +767,11 @@ def parse_metadata(metadatapath): if app.get('Builds'): build = app['Builds'][-1] if build.subdir: - root_dir = build.subdir + root_dir = Path(build.subdir) else: - root_dir = '.' - paths = fdroidserver.common.manifest_paths(root_dir, build.gradle) - _ignored, _ignored, app.id = fdroidserver.common.parse_androidmanifests(paths, app) + root_dir = Path('.') + paths = common.manifest_paths(root_dir, build.gradle) + _ignored, _ignored, app.id = common.parse_androidmanifests(paths, app) return app @@ -790,8 +793,7 @@ def parse_yaml_metadata(mf, app): except yaml.YAMLError as e: _warn_or_exception(_("could not parse '{path}'") .format(path=mf.name) + '\n' - + fdroidserver.common.run_yamllint(mf.name, - indent=4), + + common.run_yamllint(mf.name, indent=4), cause=e) deprecated_in_yaml = ['Provides'] @@ -801,7 +803,7 @@ def parse_yaml_metadata(mf, app): if field not in yaml_app_fields + deprecated_in_yaml: msg = (_("Unrecognised app field '{fieldname}' in '{path}'") .format(fieldname=field, path=mf.name)) - if os.path.basename(mf.name) == '.fdroid.yml': + if Path(mf.name).name == '.fdroid.yml': logging.error(msg) del yamldata[field] else: @@ -978,11 +980,10 @@ build_cont = re.compile(r'^[ \t]') def write_metadata(metadatapath, app): - # TODO: Remove this - metadatapath = str(metadatapath) - if metadatapath.endswith('.yml'): + metadatapath = Path(metadatapath) + if metadatapath.suffix == '.yml': if importlib.util.find_spec('ruamel.yaml'): - with open(metadatapath, 'w') as mf: + with metadatapath.open('w') as mf: return write_yaml(mf, app) else: raise FDroidException(_('ruamel.yaml not installed, can not write metadata.')) diff --git a/fdroidserver/rewritemeta.py b/fdroidserver/rewritemeta.py index 66ddf98a..172359b8 100644 --- a/fdroidserver/rewritemeta.py +++ b/fdroidserver/rewritemeta.py @@ -18,11 +18,11 @@ # along with this program. If not, see . from argparse import ArgumentParser -import os import logging import io import tempfile import shutil +from pathlib import Path from . import _ from . import common @@ -36,9 +36,8 @@ def proper_format(app): s = io.StringIO() # TODO: currently reading entire file again, should reuse first # read in metadata.py - with open(app.metadatapath, 'r') as f: - cur_content = f.read() - if app.metadatapath.endswith('.yml'): + cur_content = Path(app.metadatapath).read_text() + if Path(app.metadatapath).suffix == '.yml': metadata.write_yaml(s, app) content = s.getvalue() s.close() @@ -65,8 +64,8 @@ def main(): apps = common.read_app_args(options.appid, allapps, False) for appid, app in apps.items(): - path = app.metadatapath - if path.endswith('.yml'): + path = Path(app.metadatapath) + if path.suffix == '.yml': logging.info(_("Rewriting '{appid}'").format(appid=appid)) else: logging.warning(_('Cannot rewrite "{path}"').format(path=path)) @@ -91,9 +90,10 @@ def main(): # rewrite to temporary file before overwriting existsing # file in case there's a bug in write_metadata with tempfile.TemporaryDirectory() as tmpdir: - tmp_path = os.path.join(tmpdir, os.path.basename(path)) + tmp_path = Path(tmpdir) / path.name metadata.write_metadata(tmp_path, app) - shutil.move(tmp_path, path) + # TODO: Python3.6: Accept path-lik + shutil.move(str(tmp_path), str(path)) logging.debug(_("Finished")) diff --git a/tests/build.TestCase b/tests/build.TestCase index 51ae8fea..3763712d 100755 --- a/tests/build.TestCase +++ b/tests/build.TestCase @@ -14,6 +14,7 @@ import unittest import yaml import zipfile from unittest import mock +from pathlib import Path localmodule = os.path.realpath( os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..') @@ -67,31 +68,134 @@ class BuildTest(unittest.TestCase): pass # aapt is not required if androguard is present testcases = [ - ('repo/obb.main.twoversions_1101613.apk', 'obb.main.twoversions', '1101613', '0.1', None), - ('org.bitbucket.tickytacky.mirrormirror_1.apk', 'org.bitbucket.tickytacky.mirrormirror', '1', '1.0', None), - ('org.bitbucket.tickytacky.mirrormirror_2.apk', 'org.bitbucket.tickytacky.mirrormirror', '2', '1.0.1', None), - ('org.bitbucket.tickytacky.mirrormirror_3.apk', 'org.bitbucket.tickytacky.mirrormirror', '3', '1.0.2', None), - ('org.bitbucket.tickytacky.mirrormirror_4.apk', 'org.bitbucket.tickytacky.mirrormirror', '4', '1.0.3', None), - ('org.dyndns.fules.ck_20.apk', 'org.dyndns.fules.ck', '20', 'v1.6pre2', - ['arm64-v8a', 'armeabi', 'armeabi-v7a', 'mips', 'mips64', 'x86', 'x86_64']), + ( + 'repo/obb.main.twoversions_1101613.apk', + 'obb.main.twoversions', + '1101613', + '0.1', + None, + ), + ( + 'org.bitbucket.tickytacky.mirrormirror_1.apk', + 'org.bitbucket.tickytacky.mirrormirror', + '1', + '1.0', + None, + ), + ( + 'org.bitbucket.tickytacky.mirrormirror_2.apk', + 'org.bitbucket.tickytacky.mirrormirror', + '2', + '1.0.1', + None, + ), + ( + 'org.bitbucket.tickytacky.mirrormirror_3.apk', + 'org.bitbucket.tickytacky.mirrormirror', + '3', + '1.0.2', + None, + ), + ( + 'org.bitbucket.tickytacky.mirrormirror_4.apk', + 'org.bitbucket.tickytacky.mirrormirror', + '4', + '1.0.3', + None, + ), + ( + 'org.dyndns.fules.ck_20.apk', + 'org.dyndns.fules.ck', + '20', + 'v1.6pre2', + [ + 'arm64-v8a', + 'armeabi', + 'armeabi-v7a', + 'mips', + 'mips64', + 'x86', + 'x86_64', + ], + ), ('urzip.apk', 'info.guardianproject.urzip', '100', '0.1', None), ('urzip-badcert.apk', 'info.guardianproject.urzip', '100', '0.1', None), ('urzip-badsig.apk', 'info.guardianproject.urzip', '100', '0.1', None), ('urzip-release.apk', 'info.guardianproject.urzip', '100', '0.1', None), - ('urzip-release-unsigned.apk', 'info.guardianproject.urzip', '100', '0.1', None), + ( + 'urzip-release-unsigned.apk', + 'info.guardianproject.urzip', + '100', + '0.1', + None, + ), ('repo/com.politedroid_3.apk', 'com.politedroid', '3', '1.2', None), ('repo/com.politedroid_4.apk', 'com.politedroid', '4', '1.3', None), ('repo/com.politedroid_5.apk', 'com.politedroid', '5', '1.4', None), ('repo/com.politedroid_6.apk', 'com.politedroid', '6', '1.5', None), - ('repo/duplicate.permisssions_9999999.apk', 'duplicate.permisssions', '9999999', '', None), - ('repo/info.zwanenburg.caffeinetile_4.apk', 'info.zwanenburg.caffeinetile', '4', '1.3', None), - ('repo/obb.main.oldversion_1444412523.apk', 'obb.main.oldversion', '1444412523', '0.1', None), - ('repo/obb.mainpatch.current_1619_another-release-key.apk', 'obb.mainpatch.current', '1619', '0.1', None), - ('repo/obb.mainpatch.current_1619.apk', 'obb.mainpatch.current', '1619', '0.1', None), - ('repo/obb.main.twoversions_1101613.apk', 'obb.main.twoversions', '1101613', '0.1', None), - ('repo/obb.main.twoversions_1101615.apk', 'obb.main.twoversions', '1101615', '0.1', None), - ('repo/obb.main.twoversions_1101617.apk', 'obb.main.twoversions', '1101617', '0.1', None), - ('repo/urzip-; Рахма́, [rɐxˈmanʲɪnəf] سيرجي_رخمانينوف 谢·.apk', 'info.guardianproject.urzip', '100', '0.1', None), + ( + 'repo/duplicate.permisssions_9999999.apk', + 'duplicate.permisssions', + '9999999', + '', + None, + ), + ( + 'repo/info.zwanenburg.caffeinetile_4.apk', + 'info.zwanenburg.caffeinetile', + '4', + '1.3', + None, + ), + ( + 'repo/obb.main.oldversion_1444412523.apk', + 'obb.main.oldversion', + '1444412523', + '0.1', + None, + ), + ( + 'repo/obb.mainpatch.current_1619_another-release-key.apk', + 'obb.mainpatch.current', + '1619', + '0.1', + None, + ), + ( + 'repo/obb.mainpatch.current_1619.apk', + 'obb.mainpatch.current', + '1619', + '0.1', + None, + ), + ( + 'repo/obb.main.twoversions_1101613.apk', + 'obb.main.twoversions', + '1101613', + '0.1', + None, + ), + ( + 'repo/obb.main.twoversions_1101615.apk', + 'obb.main.twoversions', + '1101615', + '0.1', + None, + ), + ( + 'repo/obb.main.twoversions_1101617.apk', + 'obb.main.twoversions', + '1101617', + '0.1', + None, + ), + ( + 'repo/urzip-; Рахма́, [rɐxˈmanʲɪnəf] سيرجي_رخمانينوف 谢·.apk', + 'info.guardianproject.urzip', + '100', + '0.1', + None, + ), ] for apkfilename, appid, versionCode, versionName, nativecode in testcases: app = fdroidserver.metadata.App() @@ -259,14 +363,26 @@ class BuildTest(unittest.TestCase): with mock.patch('fdroidserver.common.replace_build_vars', wraps=make_fake_apk): with mock.patch('fdroidserver.common.get_native_code', return_value='x86'): - with mock.patch('fdroidserver.common.get_apk_id', - return_value=(app.id, build.versionCode, build.versionName)): - with mock.patch('fdroidserver.common.is_apk_and_debuggable', return_value=False): + with mock.patch( + 'fdroidserver.common.get_apk_id', + return_value=(app.id, build.versionCode, build.versionName), + ): + with mock.patch( + 'fdroidserver.common.is_apk_and_debuggable', return_value=False + ): fdroidserver.build.build_local( - app, build, vcs, - build_dir=testdir, output_dir=testdir, - log_dir=None, srclib_dir=None, extlib_dir=None, tmp_dir=None, - force=False, onserver=False, refresh=False + app, + build, + vcs, + build_dir=testdir, + output_dir=testdir, + log_dir=None, + srclib_dir=None, + extlib_dir=None, + tmp_dir=None, + force=False, + onserver=False, + refresh=False, ) self.assertTrue(os.path.exists('foo.aar')) @@ -360,7 +476,7 @@ class BuildTest(unittest.TestCase): } ) app['Builds'] = [build] - fdroidserver.metadata.write_metadata(metadata_file, app) + fdroidserver.metadata.write_metadata(Path(metadata_file), app) os.makedirs(os.path.join('unsigned', 'binaries')) production_result = os.path.join( diff --git a/tests/checkupdates.TestCase b/tests/checkupdates.TestCase index c0a85c37..d8cd1f64 100755 --- a/tests/checkupdates.TestCase +++ b/tests/checkupdates.TestCase @@ -220,9 +220,6 @@ class CheckupdatesTest(unittest.TestCase): if __name__ == "__main__": - # TODO: Python3.6: Accept path-like object. - os.chdir(str(Path(__file__).parent)) - parser = optparse.OptionParser() parser.add_option( "-v", diff --git a/tests/import.TestCase b/tests/import.TestCase index 9803648d..81aeac39 100755 --- a/tests/import.TestCase +++ b/tests/import.TestCase @@ -121,9 +121,6 @@ class ImportTest(unittest.TestCase): if __name__ == "__main__": - # TODO: Python3.6: Support added to accept objects implementing the os.PathLike interface. - os.chdir(str(Path(__file__).parent)) - parser = optparse.OptionParser() parser.add_option( "-v", diff --git a/tests/metadata.TestCase b/tests/metadata.TestCase index b269e98d..297271ab 100755 --- a/tests/metadata.TestCase +++ b/tests/metadata.TestCase @@ -1,10 +1,6 @@ #!/usr/bin/env python3 -# http://www.drdobbs.com/testing/unit-testing-with-python/240165163 - import io -import glob -import inspect import logging import optparse import os @@ -12,25 +8,27 @@ import random import shutil import sys import unittest -import yaml +from unittest import mock import tempfile import textwrap from collections import OrderedDict -from unittest import mock +from pathlib import Path + + +import yaml +from testcommon import TmpCwd + try: from yaml import CSafeLoader as SafeLoader except ImportError: from yaml import SafeLoader -localmodule = os.path.realpath( - os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..') -) -print('localmodule: ' + localmodule) +localmodule = Path(__file__).resolve().parent.parent +print('localmodule: ' + str(localmodule)) if localmodule not in sys.path: - sys.path.insert(0, localmodule) + sys.path.insert(0, str(localmodule)) -from testcommon import TmpCwd import fdroidserver.common import fdroidserver.metadata @@ -42,11 +40,11 @@ class MetadataTest(unittest.TestCase): def setUp(self): logging.basicConfig(level=logging.DEBUG) - self.basedir = os.path.join(localmodule, 'tests') - self.tmpdir = os.path.abspath(os.path.join(self.basedir, '..', '.testfiles')) - if not os.path.exists(self.tmpdir): - os.makedirs(self.tmpdir) - os.chdir(self.basedir) + self.basedir = localmodule / 'tests' + self.tmpdir = localmodule / '.testfiles' + self.tmpdir.mkdir(exist_ok=True) + # TODO: Python3.6: Accepts a path-like object. + os.chdir(str(self.basedir)) def test_FieldValidator_BitcoinAddress(self): validator = None @@ -59,23 +57,53 @@ class MetadataTest(unittest.TestCase): fdroidserver.metadata.warnings_action = 'error' # some valid addresses (P2PKH, P2SH, Bech32) - self.assertIsNone(validator.check('1BrrrrErsrWetrTrnrrrrm4GFg7xJaNVN2', 'fake.app.id')) - self.assertIsNone(validator.check('3JrrrrWrEZr3rNrrvrecrnyirrnqRhWNLy', 'fake.app.id')) - self.assertIsNone(validator.check('bc1qar0srrr7xrkvr5lr43lrdnwrre5rgtrzrf5rrq', 'fake.app.id')) + self.assertIsNone( + validator.check('1BrrrrErsrWetrTrnrrrrm4GFg7xJaNVN2', 'fake.app.id') + ) + self.assertIsNone( + validator.check('3JrrrrWrEZr3rNrrvrecrnyirrnqRhWNLy', 'fake.app.id') + ) + self.assertIsNone( + validator.check('bc1qar0srrr7xrkvr5lr43lrdnwrre5rgtrzrf5rrq', 'fake.app.id') + ) # some invalid addresses - self.assertRaises(fdroidserver.exception.MetaDataException, validator.check, - '21BvMrSYsrWrtrrlL5A10mlGFr7rrarrN2', 'fake.app.id') - self.assertRaises(fdroidserver.exception.MetaDataException, validator.check, - '5Hrgr3ur5rGLrfKrrrrrrHSrqJrroGrrzrQrrrrrrLNrsrDrrrA', 'fake.app.id') - self.assertRaises(fdroidserver.exception.MetaDataException, validator.check, - '92rr46rUrgTrrromrVrirW6r1rrrdrerrdbJrrrhrCsYrrrrrrc', 'fake.app.id') - self.assertRaises(fdroidserver.exception.MetaDataException, validator.check, - 'K1BvMrSYsrWrtrrrn5Au4m4GFr7rrarrN2', 'fake.app.id') - self.assertRaises(fdroidserver.exception.MetaDataException, validator.check, - 'L1BvMrSYsrWrtrrrn5Au4m4GFr7rrarrN2', 'fake.app.id') - self.assertRaises(fdroidserver.exception.MetaDataException, validator.check, - 'tb1qw5r8drrejxrrg4y5rrrrrraryrrrrwrkxrjrsx', 'fake.app.id') + self.assertRaises( + fdroidserver.exception.MetaDataException, + validator.check, + '21BvMrSYsrWrtrrlL5A10mlGFr7rrarrN2', + 'fake.app.id', + ) + self.assertRaises( + fdroidserver.exception.MetaDataException, + validator.check, + '5Hrgr3ur5rGLrfKrrrrrrHSrqJrroGrrzrQrrrrrrLNrsrDrrrA', + 'fake.app.id', + ) + self.assertRaises( + fdroidserver.exception.MetaDataException, + validator.check, + '92rr46rUrgTrrromrVrirW6r1rrrdrerrdbJrrrhrCsYrrrrrrc', + 'fake.app.id', + ) + self.assertRaises( + fdroidserver.exception.MetaDataException, + validator.check, + 'K1BvMrSYsrWrtrrrn5Au4m4GFr7rrarrN2', + 'fake.app.id', + ) + self.assertRaises( + fdroidserver.exception.MetaDataException, + validator.check, + 'L1BvMrSYsrWrtrrrn5Au4m4GFr7rrarrN2', + 'fake.app.id', + ) + self.assertRaises( + fdroidserver.exception.MetaDataException, + validator.check, + 'tb1qw5r8drrejxrrg4y5rrrrrraryrrrrwrkxrjrsx', + 'fake.app.id', + ) def test_FieldValidator_LitecoinAddress(self): validator = None @@ -88,27 +116,55 @@ class MetadataTest(unittest.TestCase): fdroidserver.metadata.warnings_action = 'error' # some valid addresses (L, M, 3) - self.assertIsNone(validator.check('LgeGrrrrJAxyXprrPrrBrrX5Qrrrrrrrrd', 'fake.app.id')) - self.assertIsNone(validator.check('MrrrrrrrJAxyXpanPtrrRAX5QHxvUJo8id', 'fake.app.id')) + self.assertIsNone( + validator.check('LgeGrrrrJAxyXprrPrrBrrX5Qrrrrrrrrd', 'fake.app.id') + ) + self.assertIsNone( + validator.check('MrrrrrrrJAxyXpanPtrrRAX5QHxvUJo8id', 'fake.app.id') + ) self.assertIsNone(validator.check('3rereVr9rAryrranrrrrrAXrrHx', 'fake.app.id')) # some invalid addresses (various special use/testnet addresses, invalid chars) - self.assertRaises(fdroidserver.exception.MetaDataException, validator.check, - '21BvMrSYsrWrtrrrn5Au4l4GFr7rrarrN2', 'fake.app.id') - self.assertRaises(fdroidserver.exception.MetaDataException, validator.check, - '5Hrgr3ur5rGLrfKrrrrrr1SrqJrroGrrzrQrrrrrrLNrsrDrrrA', 'fake.app.id') - self.assertRaises(fdroidserver.exception.MetaDataException, validator.check, - '92rr46rUrgTrrromrVrirW6r1rrrdrerrdbJrrrhrCsYrrrrrrc', 'fake.app.id') - self.assertRaises(fdroidserver.exception.MetaDataException, validator.check, - 'K1BvMrSYsrWrtrrrn5Au4m4GFr7rrarrN2', 'fake.app.id') - self.assertRaises(fdroidserver.exception.MetaDataException, validator.check, - 'L0000rSYsrWrtrrrn5Au4m4GFr7rrarrN2', 'fake.app.id') - self.assertRaises(fdroidserver.exception.MetaDataException, validator.check, - 'tb1qw5r8drrejxrrg4y5rrrrrraryrrrrwrkxrjrsx', 'fake.app.id') + self.assertRaises( + fdroidserver.exception.MetaDataException, + validator.check, + '21BvMrSYsrWrtrrrn5Au4l4GFr7rrarrN2', + 'fake.app.id', + ) + self.assertRaises( + fdroidserver.exception.MetaDataException, + validator.check, + '5Hrgr3ur5rGLrfKrrrrrr1SrqJrroGrrzrQrrrrrrLNrsrDrrrA', + 'fake.app.id', + ) + self.assertRaises( + fdroidserver.exception.MetaDataException, + validator.check, + '92rr46rUrgTrrromrVrirW6r1rrrdrerrdbJrrrhrCsYrrrrrrc', + 'fake.app.id', + ) + self.assertRaises( + fdroidserver.exception.MetaDataException, + validator.check, + 'K1BvMrSYsrWrtrrrn5Au4m4GFr7rrarrN2', + 'fake.app.id', + ) + self.assertRaises( + fdroidserver.exception.MetaDataException, + validator.check, + 'L0000rSYsrWrtrrrn5Au4m4GFr7rrarrN2', + 'fake.app.id', + ) + self.assertRaises( + fdroidserver.exception.MetaDataException, + validator.check, + 'tb1qw5r8drrejxrrg4y5rrrrrraryrrrrwrkxrjrsx', + 'fake.app.id', + ) def test_valid_funding_yml_regex(self): """Check the regex can find all the cases""" - with open(os.path.join(self.basedir, 'funding-usernames.yaml')) as fp: + with (self.basedir / 'funding-usernames.yaml').open() as fp: data = yaml.load(fp, Loader=SafeLoader) for k, entries in data.items(): @@ -117,12 +173,15 @@ class MetadataTest(unittest.TestCase): if k == 'custom': pass elif k == 'bad': - self.assertIsNone(m, 'this is an invalid %s username: {%s}' % (k, entry)) + self.assertIsNone( + m, 'this is an invalid %s username: {%s}' % (k, entry) + ) else: - self.assertIsNotNone(m, 'this is a valid %s username: {%s}' % (k, entry)) + self.assertIsNotNone( + m, 'this is a valid %s username: {%s}' % (k, entry) + ) def test_read_metadata(self): - def _build_yaml_representer(dumper, data): '''Creates a YAML representation of a Build instance''' return dumper.represent_dict(data) @@ -141,77 +200,83 @@ class MetadataTest(unittest.TestCase): 'org.videolan.vlc', 'com.politedroid', ): - savepath = os.path.join('metadata', 'dump', appid + '.yaml') + savepath = Path('metadata/dump') / (appid + '.yaml') frommeta = dict(apps[appid]) self.assertTrue(appid in apps) - with open(savepath, 'r') as f: + with savepath.open('r') as f: from_yaml = yaml.load(f, Loader=SafeLoader) self.assertEqual(frommeta, from_yaml) # comment above assert and uncomment below to update test # files when new metadata fields are added - # with open(savepath, 'w') as f: + # with savepath.open('w') as f: # yaml.add_representer(fdroidserver.metadata.Build, _build_yaml_representer) # yaml.dump(frommeta, f, default_flow_style=False) def test_rewrite_yaml_fakeotaupdate(self): - testdir = tempfile.mkdtemp( - prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir - ) - fdroidserver.common.config = {'accepted_formats': ['yml']} - fdroidserver.metadata.warnings_action = None + # TODO: Pytohn3.6: The dir parameter now accepts a path-like object. + with tempfile.TemporaryDirectory(dir=str(self.tmpdir)) as testdir: + testdir = Path(testdir) + fdroidserver.common.config = {'accepted_formats': ['yml']} + fdroidserver.metadata.warnings_action = None - # rewrite metadata - allapps = fdroidserver.metadata.read_metadata() - for appid, app in allapps.items(): - if appid == 'fake.ota.update': - fdroidserver.metadata.write_metadata( - os.path.join(testdir, appid + '.yml'), app - ) + # rewrite metadata + allapps = fdroidserver.metadata.read_metadata() + for appid, app in allapps.items(): + if appid == 'fake.ota.update': + fdroidserver.metadata.write_metadata( + testdir / (appid + '.yml'), app + ) - # assert rewrite result - with open(os.path.join(testdir, 'fake.ota.update.yml'), 'r') as result: - with open('metadata-rewrite-yml/fake.ota.update.yml', 'r') as orig: - self.maxDiff = None - self.assertEqual(result.read(), orig.read()) + # assert rewrite result + self.maxDiff = None + file_name = 'fake.ota.update.yml' + self.assertEqual( + (testdir / file_name).read_text(), + (Path('metadata-rewrite-yml') / file_name).read_text(), + ) def test_rewrite_yaml_fdroidclient(self): - testdir = tempfile.mkdtemp( - prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir - ) - fdroidserver.common.config = {'accepted_formats': ['yml']} + # TODO: Pytohn3.6: The dir parameter now accepts a path-like object. + with tempfile.TemporaryDirectory(dir=str(self.tmpdir)) as testdir: + testdir = Path(testdir) + fdroidserver.common.config = {'accepted_formats': ['yml']} - # rewrite metadata - allapps = fdroidserver.metadata.read_metadata() - for appid, app in allapps.items(): - if appid == 'org.fdroid.fdroid': - fdroidserver.metadata.write_metadata( - os.path.join(testdir, appid + '.yml'), app - ) + # rewrite metadata + allapps = fdroidserver.metadata.read_metadata() + for appid, app in allapps.items(): + if appid == 'org.fdroid.fdroid': + fdroidserver.metadata.write_metadata( + testdir / (appid + '.yml'), app + ) - # assert rewrite result - with open(os.path.join(testdir, 'org.fdroid.fdroid.yml'), 'r') as result: - with open('metadata-rewrite-yml/org.fdroid.fdroid.yml', 'r') as orig: - self.maxDiff = None - self.assertEqual(result.read(), orig.read()) + # assert rewrite result + self.maxDiff = None + file_name = 'org.fdroid.fdroid.yml' + self.assertEqual( + (testdir / file_name).read_text(), + (Path('metadata-rewrite-yml') / file_name).read_text(), + ) def test_rewrite_yaml_special_build_params(self): - testdir = tempfile.mkdtemp( - prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir - ) + # TODO: Pytohn3.6: The dir parameter now accepts a path-like object. + with tempfile.TemporaryDirectory(dir=str(self.tmpdir)) as testdir: + testdir = Path(testdir) - # rewrite metadata - allapps = fdroidserver.metadata.read_metadata() - for appid, app in allapps.items(): - if appid == 'app.with.special.build.params': - fdroidserver.metadata.write_metadata( - os.path.join(testdir, appid + '.yml'), app - ) + # rewrite metadata + allapps = fdroidserver.metadata.read_metadata() + for appid, app in allapps.items(): + if appid == 'app.with.special.build.params': + fdroidserver.metadata.write_metadata( + testdir / (appid + '.yml'), app + ) - # assert rewrite result - with open(os.path.join(testdir, 'app.with.special.build.params.yml'), 'r') as result: - with open('metadata-rewrite-yml/app.with.special.build.params.yml', 'r') as orig: - self.maxDiff = None - self.assertEqual(result.read(), orig.read()) + # assert rewrite result + self.maxDiff = None + file_name = 'app.with.special.build.params.yml' + self.assertEqual( + (testdir / file_name).read_text(), + (Path('metadata-rewrite-yml') / file_name).read_text(), + ) def test_post_parse_yaml_metadata(self): fdroidserver.metadata.warnings_action = 'error' @@ -222,12 +287,18 @@ class MetadataTest(unittest.TestCase): builds.append(build) build['versionCode'] = 1.1 - self.assertRaises(fdroidserver.exception.MetaDataException, - fdroidserver.metadata.post_parse_yaml_metadata, yamldata) + self.assertRaises( + fdroidserver.exception.MetaDataException, + fdroidserver.metadata.post_parse_yaml_metadata, + yamldata, + ) build['versionCode'] = '1' - self.assertRaises(fdroidserver.exception.MetaDataException, - fdroidserver.metadata.post_parse_yaml_metadata, yamldata) + self.assertRaises( + fdroidserver.exception.MetaDataException, + fdroidserver.metadata.post_parse_yaml_metadata, + yamldata, + ) build['versionCode'] = 1 build['versionName'] = 1 @@ -258,39 +329,42 @@ class MetadataTest(unittest.TestCase): self.assertEqual('1234567890', yamldata['Builds'][0]['commit']) def test_read_metadata_sort_by_time(self): - testdir = tempfile.mkdtemp( - prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir - ) - metadatadir = os.path.join(testdir, 'metadata') - os.makedirs(metadatadir) + # TODO: Pytohn3.6: The dir parameter now accepts a path-like object. + with tempfile.TemporaryDirectory(dir=str(self.tmpdir)) as testdir, TmpCwd( + testdir + ): + testdir = Path(testdir) + metadatadir = testdir / 'metadata' + metadatadir.mkdir() - randomlist = [] - randomapps = glob.glob(os.path.join(self.basedir, 'metadata', '*.yml')) - random.shuffle(randomapps) - i = 1 - for f in randomapps: - shutil.copy(f, metadatadir) - new = os.path.join(metadatadir, os.path.basename(f)) - stat = os.stat(new) - os.utime(new, (stat.st_ctime, stat.st_mtime + i)) - # prepend new item so newest is always first - randomlist = [os.path.basename(f)[:-4]] + randomlist - i += 1 - os.chdir(testdir) - allapps = fdroidserver.metadata.read_metadata(sort_by_time=True) - allappids = [] - for appid, app in allapps.items(): - allappids.append(appid) - self.assertEqual(randomlist, allappids) + randomlist = [] + randomapps = list((self.basedir / 'metadata').glob('*.yml')) + random.shuffle(randomapps) + i = 1 + for f in randomapps: + # TODO: Pytohn3.6: The parameter now accepts a path-like object. + shutil.copy(str(f), str(metadatadir)) + new = metadatadir / f.name + stat = new.stat() + # TODO: Changed in version 3.6: Accepts a path-like object. + os.utime(str(new), (stat.st_ctime, stat.st_mtime + i)) + # prepend new item so newest is always first + randomlist = [f.stem] + randomlist + i += 1 + allapps = fdroidserver.metadata.read_metadata(sort_by_time=True) + allappids = [] + for appid, app in allapps.items(): + allappids.append(appid) + self.assertEqual(randomlist, allappids) def test_parse_yaml_metadata_unknown_app_field(self): mf = io.StringIO( textwrap.dedent( """\ - AutoName: F-Droid - RepoType: git - Builds: [] - bad: value""" + AutoName: F-Droid + RepoType: git + Builds: [] + bad: value""" ) ) mf.name = 'mock_filename.yaml' @@ -302,10 +376,10 @@ class MetadataTest(unittest.TestCase): mf = io.StringIO( textwrap.dedent( """\ - AutoName: F-Droid - RepoType: git - Builds: - - bad: value""" + AutoName: F-Droid + RepoType: git + Builds: + - bad: value""" ) ) mf.name = 'mock_filename.yaml' @@ -314,23 +388,23 @@ class MetadataTest(unittest.TestCase): fdroidserver.metadata.parse_yaml_metadata(mf, {}) def test_parse_yaml_srclib_corrupt_file(self): - testdir = tempfile.mkdtemp( - prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir - ) - srclibfile = os.path.join(testdir, 'srclib', 'mock.yml') - os.mkdir(os.path.dirname(srclibfile)) - with open(srclibfile, 'w') as fp: - fp.write( - textwrap.dedent( - """ - - RepoType: git - - Repo: https://github.com/realm/realm-js.git - """ + # TODO: Pytohn3.6: The dir parameter now accepts a path-like object. + with tempfile.TemporaryDirectory(dir=str(self.tmpdir)) as testdir: + testdir = Path(testdir) + srclibfile = testdir / 'srclib/mock.yml' + srclibfile.parent.mkdir() + with srclibfile.open('w') as fp: + fp.write( + textwrap.dedent( + """ + - RepoType: git + - Repo: https://github.com/realm/realm-js.git + """ + ) ) - ) - with mock.patch('fdroidserver.metadata.warnings_action', 'error'): - with self.assertRaises(MetaDataException): - fdroidserver.metadata.parse_yaml_srclib(srclibfile) + with mock.patch('fdroidserver.metadata.warnings_action', 'error'): + with self.assertRaises(MetaDataException): + fdroidserver.metadata.parse_yaml_srclib(srclibfile) def test_write_yaml_with_placeholder_values(self): mf = io.StringIO() @@ -358,26 +432,26 @@ class MetadataTest(unittest.TestCase): mf.read(), textwrap.dedent( """\ - Categories: - - None - License: Unknown - SourceCode: https://gitlab.com/fdroid/fdroidclient.git - IssueTracker: https://gitlab.com/fdroid/fdroidclient/issues + Categories: + - None + License: Unknown + SourceCode: https://gitlab.com/fdroid/fdroidclient.git + IssueTracker: https://gitlab.com/fdroid/fdroidclient/issues - RepoType: git - Repo: https://gitlab.com/fdroid/fdroidclient.git + RepoType: git + Repo: https://gitlab.com/fdroid/fdroidclient.git - Builds: - - versionName: Unknown - versionCode: 0 - disable: Generated by import.py ... - commit: Unknown - gradle: - - true + Builds: + - versionName: Unknown + versionCode: 0 + disable: Generated by import.py ... + commit: Unknown + gradle: + - true - AutoUpdateMode: None - UpdateCheckMode: Tags - """ + AutoUpdateMode: None + UpdateCheckMode: Tags + """ ), ) @@ -385,26 +459,26 @@ class MetadataTest(unittest.TestCase): mf = io.StringIO( textwrap.dedent( """\ - AutoName: F-Droid - RepoType: git - Builds: - - versionCode: 1 - versionName: v0.1.0 - sudo: - - apt-get update - - apt-get install -y whatever - - sed -i -e 's/> /a/file - build: - - ./gradlew someSpecialTask - - sed -i 'd/that wrong config/' gradle.properties - - ./gradlew compile - """ + AutoName: F-Droid + RepoType: git + Builds: + - versionCode: 1 + versionName: v0.1.0 + sudo: + - apt-get update + - apt-get install -y whatever + - sed -i -e 's/> /a/file + build: + - ./gradlew someSpecialTask + - sed -i 'd/that wrong config/' gradle.properties + - ./gradlew compile + """ ) ) mf.name = 'mock_filename.yaml' @@ -413,36 +487,45 @@ class MetadataTest(unittest.TestCase): with mock.patch('fdroidserver.metadata.warnings_action', 'error'): fdroidserver.metadata.parse_yaml_metadata(mf, result) self.maxDiff = None - self.assertDictEqual(result, {'AutoName': 'F-Droid', - 'RepoType': 'git', - 'Builds': [{'versionCode': 1, - 'versionName': 'v0.1.0', - 'sudo': "apt-get update && " - "apt-get install -y whatever && " - "sed -i -e 's/> /a/file", - 'build': "./gradlew someSpecialTask && " - "sed -i 'd/that wrong config/' gradle.properties && " - "./gradlew compile"}]}) + self.assertDictEqual( + result, + { + 'AutoName': 'F-Droid', + 'RepoType': 'git', + 'Builds': [ + { + 'versionCode': 1, + 'versionName': 'v0.1.0', + 'sudo': "apt-get update && " + "apt-get install -y whatever && " + "sed -i -e 's/> /a/file", + 'build': "./gradlew someSpecialTask && " + "sed -i 'd/that wrong config/' gradle.properties && " + "./gradlew compile", + } + ], + }, + ) def test_parse_yaml_metadata_prebuild_strings(self): mf = io.StringIO( textwrap.dedent( """\ - AutoName: F-Droid - RepoType: git - Builds: - - versionCode: 1 - versionName: v0.1.0 - sudo: |- - apt-get update && apt-get install -y whatever && sed -i -e 's/> /a/file - build: |- - ./gradlew someSpecialTask && sed -i 'd/that wrong config/' gradle.properties && ./gradlew compile - """ + AutoName: F-Droid + RepoType: git + Builds: + - versionCode: 1 + versionName: v0.1.0 + sudo: |- + apt-get update && apt-get install -y whatever && sed -i -e 's/> /a/file + build: |- + ./gradlew someSpecialTask && sed -i 'd/that wrong config/' gradle.properties && ./gradlew compile + """ ) ) mf.name = 'mock_filename.yaml' @@ -451,32 +534,41 @@ class MetadataTest(unittest.TestCase): with mock.patch('fdroidserver.metadata.warnings_action', 'error'): fdroidserver.metadata.parse_yaml_metadata(mf, result) self.maxDiff = None - self.assertDictEqual(result, {'AutoName': 'F-Droid', - 'RepoType': 'git', - 'Builds': [{'versionCode': 1, - 'versionName': 'v0.1.0', - 'sudo': "apt-get update && " - "apt-get install -y whatever && " - "sed -i -e 's/> /a/file", - 'build': "./gradlew someSpecialTask && " - "sed -i 'd/that wrong config/' gradle.properties && " - "./gradlew compile"}]}) + self.assertDictEqual( + result, + { + 'AutoName': 'F-Droid', + 'RepoType': 'git', + 'Builds': [ + { + 'versionCode': 1, + 'versionName': 'v0.1.0', + 'sudo': "apt-get update && " + "apt-get install -y whatever && " + "sed -i -e 's/> /a/file", + 'build': "./gradlew someSpecialTask && " + "sed -i 'd/that wrong config/' gradle.properties && " + "./gradlew compile", + } + ], + }, + ) def test_parse_yaml_metadata_prebuild_string(self): mf = io.StringIO( textwrap.dedent( """\ - AutoName: F-Droid - RepoType: git - Builds: - - versionCode: 1 - versionName: v0.1.0 - prebuild: |- - a && b && sed -i 's,a,b,' - """ + AutoName: F-Droid + RepoType: git + Builds: + - versionCode: 1 + versionName: v0.1.0 + prebuild: |- + a && b && sed -i 's,a,b,' + """ ) ) mf.name = 'mock_filename.yaml' @@ -484,26 +576,34 @@ class MetadataTest(unittest.TestCase): result = {} with mock.patch('fdroidserver.metadata.warnings_action', 'error'): fdroidserver.metadata.parse_yaml_metadata(mf, result) - self.assertDictEqual(result, {'AutoName': 'F-Droid', - 'RepoType': 'git', - 'Builds': [{'versionCode': 1, - 'versionName': 'v0.1.0', - 'prebuild': "a && b && " - "sed -i 's,a,b,'"}]}) + self.assertDictEqual( + result, + { + 'AutoName': 'F-Droid', + 'RepoType': 'git', + 'Builds': [ + { + 'versionCode': 1, + 'versionName': 'v0.1.0', + 'prebuild': "a && b && " "sed -i 's,a,b,'", + } + ], + }, + ) def test_parse_yaml_provides_should_be_ignored(self): mf = io.StringIO( textwrap.dedent( """\ - Provides: this.is.deprecated - AutoName: F-Droid - RepoType: git - Builds: - - versionCode: 1 - versionName: v0.1.0 - prebuild: |- - a && b && sed -i 's,a,b,' - """ + Provides: this.is.deprecated + AutoName: F-Droid + RepoType: git + Builds: + - versionCode: 1 + versionName: v0.1.0 + prebuild: |- + a && b && sed -i 's,a,b,' + """ ) ) mf.name = 'mock_filename.yaml' @@ -533,21 +633,21 @@ class MetadataTest(unittest.TestCase): mf.read(), textwrap.dedent( """\ - Categories: - - None - License: Unknown + Categories: + - None + License: Unknown - Builds: - - versionName: v1.2.3 - versionCode: 102030 - sudo: chmod +rwx /opt - init: sed -i -e 'g/what/ever/' /some/file - prebuild: sed -i 'd/that wrong config/' gradle.properties - build: ./gradlew compile + Builds: + - versionName: v1.2.3 + versionCode: 102030 + sudo: chmod +rwx /opt + init: sed -i -e 'g/what/ever/' /some/file + prebuild: sed -i 'd/that wrong config/' gradle.properties + build: ./gradlew compile - AutoUpdateMode: None - UpdateCheckMode: None - """ + AutoUpdateMode: None + UpdateCheckMode: None + """ ), ) @@ -570,21 +670,21 @@ class MetadataTest(unittest.TestCase): mf.read(), textwrap.dedent( """\ - Categories: - - None - License: Unknown + Categories: + - None + License: Unknown - Builds: - - versionName: v1.2.3 - versionCode: 102030 - sudo: chmod +rwx /opt - init: sed -i -e 'g/what/ever/' /some/file - prebuild: sed -i 'd/that wrong config/' gradle.properties - build: ./gradlew compile + Builds: + - versionName: v1.2.3 + versionCode: 102030 + sudo: chmod +rwx /opt + init: sed -i -e 'g/what/ever/' /some/file + prebuild: sed -i 'd/that wrong config/' gradle.properties + build: ./gradlew compile - AutoUpdateMode: None - UpdateCheckMode: None - """ + AutoUpdateMode: None + UpdateCheckMode: None + """ ), ) @@ -596,16 +696,21 @@ class MetadataTest(unittest.TestCase): build = fdroidserver.metadata.Build() build.versionCode = 102030 build.versionName = 'v1.2.3' - build.sudo = ["apt-get update", - "apt-get install -y whatever", - "sed -i -e 's/> /a/file"] - build.build = ["./gradlew someSpecialTask", - "sed -i 'd/that wrong config/' gradle.properties", - "./gradlew compile"] + build.sudo = [ + "apt-get update", + "apt-get install -y whatever", + "sed -i -e 's/> /a/file"] + build.build = [ + "./gradlew someSpecialTask", + "sed -i 'd/that wrong config/' gradle.properties", + "./gradlew compile", + ] app['Builds'].append(build) fdroidserver.metadata.write_yaml(mf, app) mf.seek(0) @@ -705,65 +810,81 @@ class MetadataTest(unittest.TestCase): mf.read(), textwrap.dedent( """\ - Categories: - - None - License: Unknown + Categories: + - None + License: Unknown - Builds: - - versionName: v1.2.3 - versionCode: 102030 - gradle: - - yes + Builds: + - versionName: v1.2.3 + versionCode: 102030 + gradle: + - yes - AutoUpdateMode: None - UpdateCheckMode: None - """ + AutoUpdateMode: None + UpdateCheckMode: None + """ ), ) def test_parse_yaml_srclib_unknown_key(self): fdroidserver.metadata.warnings_action = 'error' with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir): - with open('test.yml', 'w', encoding='utf-8') as f: - f.write(textwrap.dedent('''\ - RepoType: git - Repo: https://example.com/test.git - Evil: I should not be here. - ''')) - with self.assertRaisesRegex(MetaDataException, - "Invalid srclib metadata: " - "unknown key 'Evil' in " - "'test.yml'"): - fdroidserver.metadata.parse_yaml_srclib('test.yml') + with Path('test.yml').open('w', encoding='utf-8') as f: + f.write( + textwrap.dedent( + '''\ + RepoType: git + Repo: https://example.com/test.git + Evil: I should not be here. + ''' + ) + ) + with self.assertRaisesRegex( + MetaDataException, + "Invalid srclib metadata: " "unknown key 'Evil' in " "'test.yml'", + ): + fdroidserver.metadata.parse_yaml_srclib(Path('test.yml')) def test_parse_yaml_srclib_does_not_exists(self): fdroidserver.metadata.warnings_action = 'error' - with self.assertRaisesRegex(MetaDataException, - "Invalid scrlib metadata: " - "'non/existent-test-srclib.yml' " - "does not exist"): - fdroidserver.metadata.parse_yaml_srclib('non/existent-test-srclib.yml') + with self.assertRaisesRegex( + MetaDataException, + "Invalid scrlib metadata: " + r"'non(/|\\)existent-test-srclib.yml' " + "does not exist", + ): + fdroidserver.metadata.parse_yaml_srclib( + Path('non/existent-test-srclib.yml') + ) def test_parse_yaml_srclib_simple(self): fdroidserver.metadata.warnings_action = 'error' with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir): - with open('simple.yml', 'w', encoding='utf-8') as f: - f.write(textwrap.dedent('''\ + with Path('simple.yml').open('w', encoding='utf-8') as f: + f.write( + textwrap.dedent( + '''\ # this should be simple RepoType: git Repo: https://git.host/repo.git - ''')) - srclib = fdroidserver.metadata.parse_yaml_srclib('simple.yml') - self.assertDictEqual({'Repo': 'https://git.host/repo.git', - 'RepoType': 'git', - 'Subdir': None, - 'Prepare': None}, - srclib) + ''' + ) + ) + srclib = fdroidserver.metadata.parse_yaml_srclib(Path('simple.yml')) + self.assertDictEqual( + { + 'Repo': 'https://git.host/repo.git', + 'RepoType': 'git', + 'Subdir': None, + 'Prepare': None, + }, + srclib, + ) def test_parse_yaml_srclib_simple_with_blanks(self): fdroidserver.metadata.warnings_action = 'error' with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir): - with open('simple.yml', 'w', encoding='utf-8') as f: + with Path('simple.yml').open('w', encoding='utf-8') as f: f.write( textwrap.dedent( '''\ @@ -779,17 +900,21 @@ class MetadataTest(unittest.TestCase): ''' ) ) - srclib = fdroidserver.metadata.parse_yaml_srclib('simple.yml') - self.assertDictEqual({'Repo': 'https://git.host/repo.git', - 'RepoType': 'git', - 'Subdir': [''], - 'Prepare': ''}, - srclib) + srclib = fdroidserver.metadata.parse_yaml_srclib(Path('simple.yml')) + self.assertDictEqual( + { + 'Repo': 'https://git.host/repo.git', + 'RepoType': 'git', + 'Subdir': [''], + 'Prepare': '', + }, + srclib, + ) def test_parse_yaml_srclib_Changelog_cketti(self): fdroidserver.metadata.warnings_action = 'error' with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir): - with open('Changelog-cketti.yml', 'w', encoding='utf-8') as f: + with Path('Changelog-cketti.yml').open('w', encoding='utf-8') as f: f.write( textwrap.dedent( '''\ @@ -801,21 +926,27 @@ class MetadataTest(unittest.TestCase): ''' ) ) - srclib = fdroidserver.metadata.parse_yaml_srclib('Changelog-cketti.yml') - self.assertDictEqual(srclib, - {'Repo': 'https://github.com/cketti/ckChangeLog', - 'RepoType': 'git', - 'Subdir': ['library', 'ckChangeLog/src/main'], - 'Prepare': "[ -f project.properties ] || echo 'source.dir=java' > " - "ant.properties && echo -e " - "'android.library=true\\ntarget=android-19' > project.properties"}) + srclib = fdroidserver.metadata.parse_yaml_srclib( + Path('Changelog-cketti.yml') + ) + self.assertDictEqual( + srclib, + { + 'Repo': 'https://github.com/cketti/ckChangeLog', + 'RepoType': 'git', + 'Subdir': ['library', 'ckChangeLog/src/main'], + 'Prepare': "[ -f project.properties ] || echo 'source.dir=java' > " + "ant.properties && echo -e " + "'android.library=true\\ntarget=android-19' > project.properties", + }, + ) def test_read_srclibs_yml_subdir_list(self): fdroidserver.metadata.warnings_action = 'error' fdroidserver.metadata.srclibs = None with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir): - os.mkdir('srclibs') - with open('srclibs/with-list.yml', 'w', encoding='utf-8') as f: + Path('srclibs').mkdir() + with Path('srclibs/with-list.yml').open('w', encoding='utf-8') as f: f.write( textwrap.dedent( '''\ @@ -839,25 +970,33 @@ class MetadataTest(unittest.TestCase): ) fdroidserver.metadata.read_srclibs() self.maxDiff = None - self.assertDictEqual(fdroidserver.metadata.srclibs, - {'with-list': {'RepoType': 'git', - 'Repo': 'https://git.host/repo.git', - 'Subdir': ['This is your last chance.', - 'After this, there is no turning back.', - 'You take the blue pill—the story ends,', - 'you wake up in your bed', - 'and believe whatever you want to believe.', - 'You take the red pill—you stay in Wonderland', - 'and I show you how deep the rabbit-hole goes.'], - 'Prepare': 'There is a difference between knowing the path ' - 'and walking the path.'}}) + self.assertDictEqual( + fdroidserver.metadata.srclibs, + { + 'with-list': { + 'RepoType': 'git', + 'Repo': 'https://git.host/repo.git', + 'Subdir': [ + 'This is your last chance.', + 'After this, there is no turning back.', + 'You take the blue pill—the story ends,', + 'you wake up in your bed', + 'and believe whatever you want to believe.', + 'You take the red pill—you stay in Wonderland', + 'and I show you how deep the rabbit-hole goes.', + ], + 'Prepare': 'There is a difference between knowing the path ' + 'and walking the path.', + } + }, + ) def test_read_srclibs_yml_prepare_list(self): fdroidserver.metadata.warnings_action = 'error' fdroidserver.metadata.srclibs = None with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir): - os.mkdir('srclibs') - with open('srclibs/with-list.yml', 'w', encoding='utf-8') as f: + Path('srclibs').mkdir() + with Path('srclibs/with-list.yml').open('w', encoding='utf-8') as f: f.write( textwrap.dedent( '''\ @@ -880,25 +1019,31 @@ class MetadataTest(unittest.TestCase): ) fdroidserver.metadata.read_srclibs() self.maxDiff = None - self.assertDictEqual(fdroidserver.metadata.srclibs, - {'with-list': {'RepoType': 'git', - 'Repo': 'https://git.host/repo.git', - 'Subdir': [''], - 'Prepare': 'The Matrix is a system, Neo. && ' - 'That system is our enemy. && ' - 'But when you\'re inside, you look around, what do you see? && ' - 'Businessmen, teachers, lawyers, carpenters. && ' - 'The very minds of the people we are trying to save. && ' - 'But until we do, these people are still a part of that system and that makes them our enemy. && ' - 'You have to understand, most of these people are not ready to be unplugged. && ' - 'And many of them are so inert, so hopelessly dependent on the system that they will fight to protect it.'}}) + self.assertDictEqual( + fdroidserver.metadata.srclibs, + { + 'with-list': { + 'RepoType': 'git', + 'Repo': 'https://git.host/repo.git', + 'Subdir': [''], + 'Prepare': 'The Matrix is a system, Neo. && ' + 'That system is our enemy. && ' + 'But when you\'re inside, you look around, what do you see? && ' + 'Businessmen, teachers, lawyers, carpenters. && ' + 'The very minds of the people we are trying to save. && ' + 'But until we do, these people are still a part of that system and that makes them our enemy. && ' + 'You have to understand, most of these people are not ready to be unplugged. && ' + 'And many of them are so inert, so hopelessly dependent on the system that they will fight to protect it.', + } + }, + ) def test_read_srclibs(self): fdroidserver.metadata.warnings_action = 'error' fdroidserver.metadata.srclibs = None with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir): - os.mkdir('srclibs') - with open('srclibs/simple.yml', 'w', encoding='utf-8') as f: + Path('srclibs').mkdir() + with Path('srclibs/simple.yml').open('w', encoding='utf-8') as f: f.write( textwrap.dedent( '''\ @@ -907,7 +1052,7 @@ class MetadataTest(unittest.TestCase): ''' ) ) - with open('srclibs/simple-wb.yml', 'w', encoding='utf-8') as f: + with Path('srclibs/simple-wb.yml').open('w', encoding='utf-8') as f: f.write( textwrap.dedent( '''\ @@ -921,20 +1066,26 @@ class MetadataTest(unittest.TestCase): ) ) fdroidserver.metadata.read_srclibs() - self.assertDictEqual(fdroidserver.metadata.srclibs, - {'simple-wb': {'RepoType': 'git', - 'Repo': 'https://git.host/repo.git', - 'Subdir': [''], - 'Prepare': ''}, - 'simple': {'RepoType': 'git', - 'Repo': 'https://git.host/repo.git', - 'Subdir': None, - 'Prepare': None}}) + self.assertDictEqual( + fdroidserver.metadata.srclibs, + { + 'simple-wb': { + 'RepoType': 'git', + 'Repo': 'https://git.host/repo.git', + 'Subdir': [''], + 'Prepare': '', + }, + 'simple': { + 'RepoType': 'git', + 'Repo': 'https://git.host/repo.git', + 'Subdir': None, + 'Prepare': None, + }, + }, + ) if __name__ == "__main__": - os.chdir(os.path.dirname(__file__)) - parser = optparse.OptionParser() parser.add_option( "-v", diff --git a/tests/rewritemeta.TestCase b/tests/rewritemeta.TestCase index be87c3cb..1271f9d8 100755 --- a/tests/rewritemeta.TestCase +++ b/tests/rewritemeta.TestCase @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -import inspect import logging import optparse import os @@ -9,14 +8,15 @@ import unittest import tempfile import textwrap from unittest import mock +from pathlib import Path + + from testcommon import TmpCwd -localmodule = os.path.realpath( - os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..') -) -print('localmodule: ' + localmodule) +localmodule = Path(__file__).resolve().parent.parent +print('localmodule: ' + str(localmodule)) if localmodule not in sys.path: - sys.path.insert(0, localmodule) + sys.path.insert(0, str(localmodule)) from fdroidserver import common from fdroidserver import rewritemeta @@ -28,30 +28,29 @@ class RewriteMetaTest(unittest.TestCase): def setUp(self): logging.basicConfig(level=logging.DEBUG) - self.basedir = os.path.join(localmodule, 'tests') - self.tmpdir = os.path.abspath(os.path.join(self.basedir, '..', '.testfiles')) - if not os.path.exists(self.tmpdir): - os.makedirs(self.tmpdir) - os.chdir(self.basedir) + self.basedir = localmodule / 'tests' + self.tmpdir = localmodule / '.testfiles' + self.tmpdir.mkdir(exist_ok=True) + # TODO: Python3.6: Accepts a path-like object. + os.chdir(str(self.basedir)) def test_rewrite_scenario_trivial(self): sys.argv = ['rewritemeta', 'a', 'b'] with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir): - os.mkdir('metadata') - with open('metadata/a.yml', 'w') as f: + Path('metadata').mkdir() + with Path('metadata/a.yml').open('w') as f: f.write('AutoName: a') - with open('metadata/b.yml', 'w') as f: + with Path('metadata/b.yml').open('w') as f: f.write('AutoName: b') rewritemeta.main() - with open('metadata/a.yml') as f: - self.assertEqual( - f.read(), - textwrap.dedent( - '''\ + self.assertEqual( + Path('metadata/a.yml').read_text(), + textwrap.dedent( + '''\ License: Unknown AutoName: a @@ -59,14 +58,13 @@ class RewriteMetaTest(unittest.TestCase): AutoUpdateMode: None UpdateCheckMode: None ''' - ), - ) + ), + ) - with open('metadata/b.yml') as f: - self.assertEqual( - f.read(), - textwrap.dedent( - '''\ + self.assertEqual( + Path('metadata/b.yml').read_text(), + textwrap.dedent( + '''\ License: Unknown AutoName: b @@ -74,14 +72,14 @@ class RewriteMetaTest(unittest.TestCase): AutoUpdateMode: None UpdateCheckMode: None ''' - ), - ) + ), + ) def test_rewrite_scenario_yml_no_ruamel(self): sys.argv = ['rewritemeta', 'a'] with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir): - os.mkdir('metadata') - with open('metadata/a.yml', 'w') as f: + Path('metadata').mkdir() + with Path('metadata/a.yml').open('w') as f: f.write('AutoName: a') def boom(*args): @@ -91,19 +89,12 @@ class RewriteMetaTest(unittest.TestCase): with self.assertRaises(FDroidException): rewritemeta.main() - with open('metadata/a.yml') as f: - self.assertEqual( - f.read(), - textwrap.dedent( - '''\ - AutoName: a''' - ), - ) + self.assertEqual( + Path('metadata/a.yml').read_text(), 'AutoName: a' + ) if __name__ == "__main__": - os.chdir(os.path.dirname(__file__)) - parser = optparse.OptionParser() parser.add_option( "-v",