diff --git a/.gitignore b/.gitignore index 04e92ad6..ce3a0e9a 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,6 @@ tmp/ /tests/repo/status # files used in manual testing -/config.py /config.yml /tmp/ /logs/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 394c41a4..6ebc12da 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -274,6 +274,35 @@ safety: - python3 -m safety --key "$SAFETY_API_KEY" --stage cicd scan +# TODO tests/*/*/*.yaml are not covered +yamllint: + image: debian:bookworm-slim + rules: + # once only:/changes: are ported to rules:, this could be removed: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + when: never + - if: $CI_PIPELINE_SOURCE == "push" + changes: + - .gitlab-ci.yml + - .safety-policy.yml + - .yamllint + - tests/*.yml + - tests/*/*.yml + - tests/*/*/.*.yml + <<: *apt-template + variables: + LANG: C.UTF-8 + script: + - apt-get install yamllint + - yamllint + .gitlab-ci.yml + .safety-policy.yml + .yamllint + tests/*.yml + tests/*/*.yml + tests/*/*/.*.yml + + # Run all the various linters and static analysis tools. locales: image: debian:bookworm-slim @@ -555,11 +584,11 @@ servergitmirrors: - ./tests/key-tricks.py - ssh-keyscan gitlab.com >> /root/.ssh/known_hosts - test -d /tmp/fdroid/repo || mkdir -p /tmp/fdroid/repo - - cp tests/config.py tests/keystore.jks /tmp/fdroid/ + - cp tests/config.yml tests/keystore.jks /tmp/fdroid/ - cp tests/repo/com.politedroid_6.apk /tmp/fdroid/repo/ - cd /tmp/fdroid - touch fdroid-icon.png - - printf "\nservergitmirrors = 'git@gitlab.com:fdroid/ci-test-servergitmirrors-repo.git'\n" >> config.py + - printf "\nservergitmirrors\x3a 'git@gitlab.com:fdroid/ci-test-servergitmirrors-repo.git'\n" >> config.yml - $PYTHONPATH/fdroid update --verbose --create-metadata - $PYTHONPATH/fdroid deploy --verbose - export DLURL=`grep -Eo 'https://gitlab.com/fdroid/ci-test-servergitmirrors-repo[^"]+' repo/index-v1.json` diff --git a/MANIFEST.in b/MANIFEST.in index 4f14a48d..0dac052c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -548,7 +548,7 @@ include tests/build-tools/28.0.3/aapt-output-souch.smsbypass_9.txt include tests/build-tools/generate.sh include tests/check-fdroid-apk include tests/com.fake.IpaApp_1000000000001.ipa -include tests/config.py +include tests/config.yml include tests/config/antiFeatures.yml include tests/config/categories.yml include tests/config/de/antiFeatures.yml diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 21944364..bda93d65 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -126,6 +126,7 @@ CONFIG_NAMES = ( RELEASECHANNELS_CONFIG_NAME, ) +CONFIG_FILE = 'config.yml' config = None options = None @@ -525,14 +526,13 @@ def config_type_check(path, data): def read_config(): """Read the repository config. - The config is read from config_file, which is in the current + The config is read from config.yml, which is in the current directory when any of the repo management commands are used. If there is a local metadata file in the git repo, then the config is not required, just use defaults. config.yml is the preferred form because no code is executed when - reading it. config.py is deprecated and supported for backwards - compatibility. + reading it. config.py is deprecated and no longer supported. config.yml requires ASCII or UTF-8 encoding because this code does not auto-detect the file's encoding. That is left up to the YAML @@ -547,33 +547,22 @@ def read_config(): return config config = {} - config_file = 'config.yml' - old_config_file = 'config.py' - if os.path.exists(config_file) and os.path.exists(old_config_file): - logging.error(_("""Conflicting config files! Using {newfile}, ignoring {oldfile}!""") - .format(oldfile=old_config_file, newfile=config_file)) - - if os.path.exists(config_file): - logging.debug(_("Reading '{config_file}'").format(config_file=config_file)) - with open(config_file, encoding='utf-8') as fp: + if os.path.exists(CONFIG_FILE): + logging.debug(_("Reading '{config_file}'").format(config_file=CONFIG_FILE)) + with open(CONFIG_FILE, encoding='utf-8') as fp: config = yaml.safe_load(fp) if not config: config = {} - config_type_check(config_file, config) - elif os.path.exists(old_config_file): - logging.warning(_("""{oldfile} is deprecated, use {newfile}""") - .format(oldfile=old_config_file, newfile=config_file)) - with io.open(old_config_file, "rb") as fp: - code = compile(fp.read(), old_config_file, 'exec') - exec(code, None, config) # nosec TODO automatically migrate + config_type_check(CONFIG_FILE, config) - for k in ('mirrors', 'install_list', 'uninstall_list', 'serverwebroot', 'servergitroot'): - if k in config: - if not type(config[k]) in (str, list, tuple): - logging.warning( - _("'{field}' will be in random order! Use () or [] brackets if order is important!") - .format(field=k)) + old_config_file = 'config.py' + if os.path.exists(old_config_file): + logging.warning( + _("""Ignoring deprecated {oldfile}, use {newfile}!""").format( + oldfile=old_config_file, newfile=CONFIG_FILE + ) + ) # smartcardoptions must be a list since its command line args for Popen smartcardoptions = config.get('smartcardoptions') @@ -588,14 +577,13 @@ def read_config(): '-providerArg', 'opensc-fdroid.cfg'] if any(k in config for k in ["keystore", "keystorepass", "keypass"]): - if os.path.exists(config_file): - f = config_file - elif os.path.exists(old_config_file): - f = old_config_file - st = os.stat(f) + st = os.stat(CONFIG_FILE) if st.st_mode & stat.S_IRWXG or st.st_mode & stat.S_IRWXO: - logging.warning(_("unsafe permissions on '{config_file}' (should be 0600)!") - .format(config_file=f)) + logging.warning( + _("unsafe permissions on '{config_file}' (should be 0600)!").format( + config_file=CONFIG_FILE + ) + ) fill_config_defaults(config) @@ -4202,8 +4190,16 @@ def load_stats_fdroid_signing_key_fingerprints(): return json.loads(str(f.read('publishsigkeys.json'), 'utf-8')) -def write_to_config(thisconfig, key, value=None, config_file=None): - """Write a key/value to the local config.yml or config.py. +def write_config_file(config): + """Write the provided string to config.yml with the right path and encoding.""" + Path(CONFIG_FILE).write_text(config, encoding='utf-8') + + +def write_to_config(thisconfig, key, value=None): + """Write a key/value to the local config.yml. + + The config.yml is defined as YAML 1.2 in UTF-8 encoding on all + platforms. NOTE: only supports writing string variables. @@ -4216,61 +4212,42 @@ def write_to_config(thisconfig, key, value=None, config_file=None): value optional value to be written, instead of fetched from 'thisconfig' dictionary. + """ if value is None: origkey = key + '_orig' value = thisconfig[origkey] if origkey in thisconfig else thisconfig[key] - if config_file: - cfg = config_file - elif os.path.exists('config.py') and not os.path.exists('config.yml'): - cfg = 'config.py' - else: - cfg = 'config.yml' # load config file, create one if it doesn't exist - if not os.path.exists(cfg): - open(cfg, 'a').close() - logging.info("Creating empty " + cfg) - with open(cfg, 'r') as f: - lines = f.readlines() + if not os.path.exists(CONFIG_FILE): + write_config_file('') + logging.info(_("Creating empty {config_file}").format(config_file=CONFIG_FILE)) + with open(CONFIG_FILE) as fp: + lines = fp.readlines() # make sure the file ends with a carraige return if len(lines) > 0: if not lines[-1].endswith('\n'): lines[-1] += '\n' - # regex for finding and replacing python string variable - # definitions/initializations - if cfg.endswith('.py'): - pattern = re.compile(r'^[\s#]*' + key + r'\s*=\s*"[^"]*"') - repl = key + ' = "' + value + '"' - pattern2 = re.compile(r'^[\s#]*' + key + r"\s*=\s*'[^']*'") - repl2 = key + " = '" + value + "'" - else: - # assume .yml as default - pattern = re.compile(r'^[\s#]*' + key + r':.*') - repl = yaml.dump({key: value}, default_flow_style=False) - pattern2 = pattern - repl2 = repl + pattern = re.compile(r'^[\s#]*' + key + r':.*\n') + repl = yaml.dump({key: value}) # If we replaced this line once, we make sure won't be a # second instance of this line for this key in the document. didRepl = False # edit config file - with open(cfg, 'w') as f: + with open(CONFIG_FILE, 'w', encoding='utf-8') as f: for line in lines: - if pattern.match(line) or pattern2.match(line): + if pattern.match(line): if not didRepl: line = pattern.sub(repl, line) - line = pattern2.sub(repl2, line) f.write(line) didRepl = True else: f.write(line) if not didRepl: - f.write('\n') f.write(repl) - f.write('\n') def parse_xml(path): diff --git a/fdroidserver/init.py b/fdroidserver/init.py index b77fea72..a5575fea 100644 --- a/fdroidserver/init.py +++ b/fdroidserver/init.py @@ -38,13 +38,13 @@ def disable_in_config(key, value): """Write a key/value to the local config.yml, then comment it out.""" import yaml - with open('config.yml') as f: - data = f.read() + with open(common.CONFIG_FILE) as fp: + data = fp.read() pattern = r'\n[\s#]*' + key + r':.*' repl = '\n#' + yaml.dump({key: value}, default_flow_style=False) data = re.sub(pattern, repl, data) - with open('config.yml', 'w') as f: - f.writelines(data) + with open(common.CONFIG_FILE, 'w') as fp: + fp.writelines(data) def main(): @@ -138,24 +138,24 @@ def main(): _("Android SDK not found at {path}!").format(path=test_config['sdk_path']) ) - if not os.path.exists('config.yml') and not os.path.exists('config.py'): + if not os.path.exists(common.CONFIG_FILE): # 'metadata' and 'tmp' are created in fdroid if not os.path.exists('repo'): os.mkdir('repo') - example_config_yml = os.path.join(examplesdir, 'config.yml') + example_config_yml = os.path.join(examplesdir, common.CONFIG_FILE) if os.path.exists(example_config_yml): - shutil.copyfile(example_config_yml, 'config.yml') + shutil.copyfile(example_config_yml, common.CONFIG_FILE) else: from pkg_resources import get_distribution versionstr = get_distribution('fdroidserver').version if not versionstr: versionstr = 'master' - with open('config.yml', 'w') as fp: + with open(common.CONFIG_FILE, 'w') as fp: fp.write('# see https://gitlab.com/fdroid/fdroidserver/blob/') fp.write(versionstr) - fp.write('/examples/config.yml\n') - os.chmod('config.yml', 0o0600) + fp.write(f'/examples/{common.CONFIG_FILE}\n') + os.chmod(common.CONFIG_FILE, 0o0600) # If android_home is None, test_config['sdk_path'] will be used and # "$ANDROID_HOME" may be used if the env var is set up correctly. # If android_home is not None, the path given from the command line diff --git a/fdroidserver/lint.py b/fdroidserver/lint.py index f8589897..64770476 100644 --- a/fdroidserver/lint.py +++ b/fdroidserver/lint.py @@ -976,7 +976,7 @@ def main(): paths = list() for arg in options.appid: if ( - arg == 'config.yml' + arg == common.CONFIG_FILE or Path(arg).parent.name == 'config' or Path(arg).parent.parent.name == 'config' # localized ): diff --git a/fdroidserver/nightly.py b/fdroidserver/nightly.py index 84c2da2e..5b8983e9 100644 --- a/fdroidserver/nightly.py +++ b/fdroidserver/nightly.py @@ -423,9 +423,9 @@ Last updated: {date}'''.format(repo_git_base=repo_git_base, 'keydname': DISTINGUISHED_NAME, 'make_current_version_link': False, } - with open('config.yml', 'w') as fp: + with open(common.CONFIG_FILE, 'w', encoding='utf-8') as fp: yaml.dump(config, fp, default_flow_style=False) - os.chmod('config.yml', 0o600) + os.chmod(common.CONFIG_FILE, 0o600) config = common.read_config() common.assert_config_keystore(config) diff --git a/tests/build/info.guardianproject.urzip/.fdroid.yml b/tests/build/info.guardianproject.urzip/.fdroid.yml index 7f2b3c1c..beea89be 100644 --- a/tests/build/info.guardianproject.urzip/.fdroid.yml +++ b/tests/build/info.guardianproject.urzip/.fdroid.yml @@ -1,4 +1,3 @@ - Summary: This should be overridden by metadata/info.guardianproject.urzip.yml Builds: - versionCode: 50 diff --git a/tests/config.py b/tests/config.py deleted file mode 100644 index fa118db2..00000000 --- a/tests/config.py +++ /dev/null @@ -1,31 +0,0 @@ - -# TODO convert to config.yml! - -repo_url = "https://MyFirstFDroidRepo.org/fdroid/repo" -repo_name = "My First F-Droid Repo Demo" -repo_description = """This is a repository of apps to be used with F-Droid. Applications in this repository are either official binaries built by the original application developers, or are binaries built from source by the admin of f-droid.org using the tools on https://gitlab.com/fdroid.""" - -archive_older = 3 -archive_url = "https://f-droid.org/archive" -archive_name = "My First F-Droid Archive Demo" -archive_description = """ -The repository of older versions of applications from the main demo repository. -""" - -make_current_version_link = False - -repo_keyalias = "sova" -keystore = "keystore.jks" -keystorepass = "r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI=" -keypass = "r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI=" -keydname = "CN=sova, OU=F-Droid" - -mirrors = ( - 'http://foobarfoobarfoobar.onion/fdroid', - 'https://foo.bar/fdroid', -) - -install_list = 'org.adaway' -uninstall_list = ('com.android.vending', 'com.facebook.orca', ) - -repo_key_sha256 = "f49af3f11efddf20dffd70f5e3117b9976674167adca280e6b1932a0601b26f6" diff --git a/tests/config.yml b/tests/config.yml new file mode 100644 index 00000000..b6f62a44 --- /dev/null +++ b/tests/config.yml @@ -0,0 +1,27 @@ +--- + +repo_url: https://MyFirstFDroidRepo.org/fdroid/repo +repo_name: My First F-Droid Repo Demo +repo_description: This is a repository of apps to be used with F-Droid. Applications in this repository are either official binaries built by the original application developers, or are binaries built from source by the admin of f-droid.org using the tools on https://gitlab.com/fdroid. + +archive_older: 3 +archive_url: https://f-droid.org/archive +archive_name: My First F-Droid Archive Demo +archive_description: The repository of older versions of applications from the main demo repository. + +make_current_version_link: false + +repo_keyalias: sova +keystore: keystore.jks +keystorepass: "r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI=" +keypass: "r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI=" +keydname: "CN=sova, OU=F-Droid" + +mirrors: + - http://foobarfoobarfoobar.onion/fdroid + - https://foo.bar/fdroid + +install_list: org.adaway +uninstall_list: ['com.android.vending', 'com.facebook.orca'] + +repo_key_sha256: f49af3f11efddf20dffd70f5e3117b9976674167adca280e6b1932a0601b26f6 diff --git a/tests/metadata/duplicate.permisssions.yml b/tests/metadata/duplicate.permisssions.yml index 3401c235..1b721fdb 100644 --- a/tests/metadata/duplicate.permisssions.yml +++ b/tests/metadata/duplicate.permisssions.yml @@ -1,4 +1,4 @@ Categories: -- tests + - tests Name: Duplicate Permisssions Summary: 'Test app for all possible ' diff --git a/tests/metadata/info.guardianproject.urzip.yml b/tests/metadata/info.guardianproject.urzip.yml index d35f7887..cf783f89 100644 --- a/tests/metadata/info.guardianproject.urzip.yml +++ b/tests/metadata/info.guardianproject.urzip.yml @@ -3,10 +3,10 @@ AutoUpdateMode: None Bitcoin: 1Fi5xUHiAPRKxHvyUGVFGt9extBe8Srdbk OpenCollective: f-droid-just-testing Categories: -- Development -- GuardianProject -- 1 -- 2.0 + - Development + - GuardianProject + - 1 + - 2.0 CurrentVersionCode: 2147483647 AuthorWebSite: https://guardianproject.info Description: | diff --git a/tests/metadata/info.zwanenburg.caffeinetile.yml b/tests/metadata/info.zwanenburg.caffeinetile.yml index a1c0b284..50321a81 100644 --- a/tests/metadata/info.zwanenburg.caffeinetile.yml +++ b/tests/metadata/info.zwanenburg.caffeinetile.yml @@ -1,4 +1,4 @@ Categories: -- Development + - Development Name: Caffeine Tile Summary: Test app for extracting icons when an XML one is default diff --git a/tests/metadata/org.videolan.vlc.yml b/tests/metadata/org.videolan.vlc.yml index 266f517d..3d40e9e9 100644 --- a/tests/metadata/org.videolan.vlc.yml +++ b/tests/metadata/org.videolan.vlc.yml @@ -317,7 +317,7 @@ Builds: prebuild: sed -i '/ant/d' ../Makefile && ln -s vlc-android/$$VLC-2.2$$ ../vlc build: cd ../ && ANDROID_ABI=armeabi-v7a ./compile.sh release -#0.9.10 vercodes were off + # 0.9.10 vercodes were off - versionName: 1.0.0 versionCode: 10006 disable: doesn't build @@ -328,7 +328,7 @@ Builds: prebuild: sed -i '/ant/d' ../Makefile && ln -s vlc-android/$$VLC-2.2$$ ../vlc build: cd ../ && ANDROID_ABI=x86 ./compile.sh release -#0.9.10 vercodes were off + # 0.9.10 vercodes were off - versionName: 1.0.0 versionCode: 10007 disable: doesn't build @@ -339,7 +339,7 @@ Builds: prebuild: sed -i '/ant/d' ../Makefile && ln -s vlc-android/$$VLC-2.2$$ ../vlc build: cd ../ && ANDROID_ABI=armeabi ./compile.sh release -#0.9.10 vercodes were off + # 0.9.10 vercodes were off - versionName: 1.0.0 versionCode: 10008 disable: doesn't build diff --git a/tests/test_build.py b/tests/test_build.py index 83e33eb2..5290552e 100755 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -593,9 +593,9 @@ class BuildTest(unittest.TestCase): os.chdir(self.testdir) sdk_path = os.path.join(self.testdir, 'android-sdk') self.create_fake_android_home(sdk_path) - with open('config.yml', 'w') as fp: + with open(fdroidserver.common.CONFIG_FILE, 'w') as fp: yaml.dump({'sdk_path': sdk_path, 'keep_when_not_allowed': True}, fp) - os.chmod('config.yml', 0o600) + os.chmod(fdroidserver.common.CONFIG_FILE, 0o600) fdroidserver.build.config = fdroidserver.common.read_config() os.mkdir('metadata') diff --git a/tests/test_common.py b/tests/test_common.py index 79b676aa..17690f59 100755 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -58,6 +58,9 @@ class CommonTest(unittest.TestCase): os.makedirs(self.tmpdir) os.chdir(basedir) + self.verbose = '-v' in sys.argv or '--verbose' in sys.argv + fdroidserver.common.set_console_logging(self.verbose) + # these are declared as None at the top of the module file fdroidserver.common.config = None fdroidserver.common.options = None @@ -642,65 +645,59 @@ class CommonTest(unittest.TestCase): ) def test_write_to_config(self): - with tempfile.TemporaryDirectory() as tmpPath: - cfgPath = os.path.join(tmpPath, 'config.py') - with open(cfgPath, 'w') as f: - f.write( - textwrap.dedent( - """\ + """Test that config items can be added without messing up config.yml. + + The '_orig' key are where the original string values of paths + are stored. Paths have tilde expansion and env vars replaced + in fill_config_defaults(). + + """ + os.chdir(self.testdir) + fdroidserver.common.write_config_file( + textwrap.dedent( + """\ + # abc + # test: 'example value' + a_path: ~/android-sdk + + # comment + do_not_touch: good value + a_path: "!!!" + + key: "123" # inline""" + ) + ) + + config = {'key': 111, 'a_path_orig': '~/android-sdk'} + fdroidserver.common.write_to_config(config, 'key') + fdroidserver.common.write_to_config(config, 'a_path') + fdroidserver.common.write_to_config(config, 'test', value='test value') + fdroidserver.common.write_to_config(config, 'new_key', value='new') + + with open(fdroidserver.common.CONFIG_FILE) as fp: + self.assertEqual( + fp.read(), + textwrap.dedent( + """\ # abc - # test = 'example value' - default_me= '%%%' + test: test value + a_path: ~/android-sdk # comment - do_not_touch = "good value" - default_me="!!!" + do_not_touch: good value - key="123" # inline""" - ) - ) - - cfg = {'key': '111', 'default_me_orig': 'orig'} - fdroidserver.common.write_to_config(cfg, 'key', config_file=cfgPath) - fdroidserver.common.write_to_config(cfg, 'default_me', config_file=cfgPath) - fdroidserver.common.write_to_config(cfg, 'test', value='test value', config_file=cfgPath) - fdroidserver.common.write_to_config(cfg, 'new_key', value='new', config_file=cfgPath) - - with open(cfgPath, 'r') as f: - self.assertEqual( - f.read(), - textwrap.dedent( - """\ - # abc - test = 'test value' - default_me = 'orig' - - # comment - do_not_touch = "good value" - - key = "111" # inline - - new_key = "new" + key: 111 + new_key: new """ - ), - ) + ), + ) def test_write_to_config_when_empty(self): - with tempfile.TemporaryDirectory() as tmpPath: - cfgPath = os.path.join(tmpPath, 'config.py') - with open(cfgPath, 'w') as f: - pass - fdroidserver.common.write_to_config({}, 'key', 'val', cfgPath) - with open(cfgPath, 'r') as f: - self.assertEqual( - f.read(), - textwrap.dedent( - """\ - - key = "val" - """ - ), - ) + os.chdir(self.testdir) + config_yml = Path(fdroidserver.common.CONFIG_FILE) + config_yml.write_text('', encoding='utf-8') + fdroidserver.common.write_to_config({}, 'key', 'val') + self.assertEqual(config_yml.read_text(), 'key: val\n') def test_apk_name_regex(self): good = [ @@ -1882,27 +1879,23 @@ class CommonTest(unittest.TestCase): def test_with_no_config(self): """It should set defaults if no config file is found""" os.chdir(self.tmpdir) - self.assertFalse(os.path.exists('config.yml')) - self.assertFalse(os.path.exists('config.py')) + self.assertFalse(os.path.exists(fdroidserver.common.CONFIG_FILE)) config = fdroidserver.common.read_config() self.assertIsNotNone(config.get('char_limits')) def test_with_zero_size_config(self): """It should set defaults if config file has nothing in it""" os.chdir(self.tmpdir) - open('config.yml', 'w').close() - self.assertTrue(os.path.exists('config.yml')) - self.assertFalse(os.path.exists('config.py')) + fdroidserver.common.write_config_file('') + self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE)) config = fdroidserver.common.read_config() self.assertIsNotNone(config.get('char_limits')) def test_with_config_yml(self): """Make sure it is possible to use config.yml alone.""" os.chdir(self.tmpdir) - with open('config.yml', 'w') as fp: - fp.write('apksigner: yml') - self.assertTrue(os.path.exists('config.yml')) - self.assertFalse(os.path.exists('config.py')) + fdroidserver.common.write_config_file('apksigner: yml') + self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE)) config = fdroidserver.common.read_config() self.assertEqual('yml', config.get('apksigner')) @@ -1910,10 +1903,8 @@ class CommonTest(unittest.TestCase): """Make sure it is possible to use config.yml in UTF-8 encoding.""" os.chdir(self.tmpdir) teststr = '/πÇÇ现代通用字-български-عربي1/ö/yml' - with open('config.yml', 'w', encoding='utf-8') as fp: - fp.write('apksigner: ' + teststr) - self.assertTrue(os.path.exists('config.yml')) - self.assertFalse(os.path.exists('config.py')) + fdroidserver.common.write_config_file('apksigner: ' + teststr) + self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE)) config = fdroidserver.common.read_config() self.assertEqual(teststr, config.get('apksigner')) @@ -1921,10 +1912,9 @@ class CommonTest(unittest.TestCase): """Make sure it is possible to use config.yml Unicode encoded as ASCII.""" os.chdir(self.tmpdir) teststr = '/πÇÇ现代通用字-български-عربي1/ö/yml' - with open('config.yml', 'w') as fp: + with open(fdroidserver.common.CONFIG_FILE, 'w', encoding='utf-8') as fp: yaml.dump({'apksigner': teststr}, fp) - self.assertTrue(os.path.exists('config.yml')) - self.assertFalse(os.path.exists('config.py')) + self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE)) config = fdroidserver.common.read_config() self.assertEqual(teststr, config.get('apksigner')) @@ -1933,144 +1923,106 @@ class CommonTest(unittest.TestCase): os.chdir(self.tmpdir) with mock.patch.dict(os.environ): os.environ['SECRET'] = 'mysecretpassword' # nosec B105 - with open('config.yml', 'w') as fp: - fp.write("""keypass: {'env': 'SECRET'}""") - self.assertTrue(os.path.exists('config.yml')) - self.assertFalse(os.path.exists('config.py')) + fdroidserver.common.write_config_file("""keypass: {'env': 'SECRET'}\n""") + self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE)) config = fdroidserver.common.read_config() self.assertEqual(os.getenv('SECRET', 'fail'), config.get('keypass')) def test_with_config_yml_is_dict(self): os.chdir(self.tmpdir) - Path('config.yml').write_text('apksigner = /placeholder/path') + Path(fdroidserver.common.CONFIG_FILE).write_text('apksigner = /bin/apksigner') with self.assertRaises(TypeError): fdroidserver.common.read_config() def test_with_config_yml_is_not_mixed_type(self): os.chdir(self.tmpdir) - Path('config.yml').write_text('k: v\napksigner = /placeholder/path') + Path(fdroidserver.common.CONFIG_FILE).write_text('k: v\napksigner = /bin/apk') with self.assertRaises(yaml.scanner.ScannerError): fdroidserver.common.read_config() - def test_with_config_py(self): - """Make sure it is still possible to use config.py alone.""" - os.chdir(self.tmpdir) - with open('config.py', 'w') as fp: - fp.write('apksigner = "py"') - self.assertFalse(os.path.exists('config.yml')) - self.assertTrue(os.path.exists('config.py')) - config = fdroidserver.common.read_config() - self.assertEqual("py", config.get('apksigner')) - def test_config_perm_warning(self): """Exercise the code path that issues a warning about unsafe permissions.""" os.chdir(self.tmpdir) - with open('config.yml', 'w') as fp: - fp.write('keystore: foo.jks') - self.assertTrue(os.path.exists(fp.name)) - os.chmod(fp.name, 0o666) # nosec B103 + fdroidserver.common.write_config_file('keystore: foo.jks') + self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE)) + os.chmod(fdroidserver.common.CONFIG_FILE, 0o666) # nosec B103 fdroidserver.common.read_config() - os.remove(fp.name) + os.remove(fdroidserver.common.CONFIG_FILE) fdroidserver.common.config = None - with open('config.py', 'w') as fp: - fp.write('keystore = "foo.jks"') - self.assertTrue(os.path.exists(fp.name)) - os.chmod(fp.name, 0o666) # nosec B103 - fdroidserver.common.read_config() - - def test_with_both_config_yml_py(self): - """If config.yml and config.py are present, config.py should be ignored.""" - os.chdir(self.tmpdir) - with open('config.yml', 'w') as fp: - fp.write('apksigner: yml') - with open('config.py', 'w') as fp: - fp.write('apksigner = "py"') - self.assertTrue(os.path.exists('config.yml')) - self.assertTrue(os.path.exists('config.py')) - config = fdroidserver.common.read_config() - self.assertEqual('yml', config.get('apksigner')) - def test_config_repo_url(self): """repo_url ends in /repo, archive_url ends in /archive.""" os.chdir(self.tmpdir) - with open('config.yml', 'w') as fp: - fp.write('repo_url: https://MyFirstFDroidRepo.org/fdroid/repo\n') - fp.write('archive_url: https://MyFirstFDroidRepo.org/fdroid/archive') + fdroidserver.common.write_config_file( + textwrap.dedent( + """\ + repo_url: https://MyFirstFDroidRepo.org/fdroid/repo + archive_url: https://MyFirstFDroidRepo.org/fdroid/archive + """ + ) + ) config = fdroidserver.common.read_config() - self.assertEqual('https://MyFirstFDroidRepo.org/fdroid/repo', config.get('repo_url')) - self.assertEqual('https://MyFirstFDroidRepo.org/fdroid/archive', config.get('archive_url')) + self.assertEqual( + 'https://MyFirstFDroidRepo.org/fdroid/repo', config.get('repo_url') + ) + self.assertEqual( + 'https://MyFirstFDroidRepo.org/fdroid/archive', config.get('archive_url') + ) def test_config_repo_url_extra_slash(self): """repo_url ends in /repo, archive_url ends in /archive.""" os.chdir(self.tmpdir) - with open('config.yml', 'w') as fp: - fp.write('repo_url: https://MyFirstFDroidRepo.org/fdroid/repo/') + fdroidserver.common.write_config_file('repo_url: https://MyFirstFDroidRepo.org/fdroid/repo/') with self.assertRaises(FDroidException): fdroidserver.common.read_config() def test_config_repo_url_not_repo(self): """repo_url ends in /repo, archive_url ends in /archive.""" os.chdir(self.tmpdir) - with open('config.yml', 'w') as fp: - fp.write('repo_url: https://MyFirstFDroidRepo.org/fdroid/foo') + fdroidserver.common.write_config_file('repo_url: https://MyFirstFDroidRepo.org/fdroid/foo') with self.assertRaises(FDroidException): fdroidserver.common.read_config() def test_config_archive_url_extra_slash(self): """repo_url ends in /repo, archive_url ends in /archive.""" os.chdir(self.tmpdir) - with open('config.yml', 'w') as fp: - fp.write('archive_url: https://MyFirstFDroidRepo.org/fdroid/archive/') + fdroidserver.common.write_config_file('archive_url: https://MyFirstFDroidRepo.org/fdroid/archive/') with self.assertRaises(FDroidException): fdroidserver.common.read_config() def test_config_archive_url_not_repo(self): """repo_url ends in /repo, archive_url ends in /archive.""" os.chdir(self.tmpdir) - with open('config.yml', 'w') as fp: - fp.write('archive_url: https://MyFirstFDroidRepo.org/fdroid/foo') + fdroidserver.common.write_config_file('archive_url: https://MyFirstFDroidRepo.org/fdroid/foo') with self.assertRaises(FDroidException): fdroidserver.common.read_config() def test_write_to_config_yml(self): os.chdir(self.tmpdir) - with open('config.yml', 'w') as fp: - fp.write('apksigner: yml') - self.assertTrue(os.path.exists(fp.name)) - self.assertFalse(os.path.exists('config.py')) + fdroidserver.common.write_config_file('apksigner: yml') + os.chmod(fdroidserver.common.CONFIG_FILE, 0o0600) + self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE)) config = fdroidserver.common.read_config() self.assertFalse('keypass' in config) self.assertEqual('yml', config.get('apksigner')) fdroidserver.common.write_to_config(config, 'keypass', 'mysecretpassword') - with open(fp.name) as fp: - print(fp.read()) - fdroidserver.common.config = None - config = fdroidserver.common.read_config() - self.assertEqual('mysecretpassword', config['keypass']) - - def test_write_to_config_py(self): - os.chdir(self.tmpdir) - with open('config.py', 'w') as fp: - fp.write('apksigner = "py"') - self.assertTrue(os.path.exists(fp.name)) - self.assertFalse(os.path.exists('config.yml')) - config = fdroidserver.common.read_config() - self.assertFalse('keypass' in config) - self.assertEqual('py', config.get('apksigner')) - fdroidserver.common.write_to_config(config, 'keypass', 'mysecretpassword') fdroidserver.common.config = None config = fdroidserver.common.read_config() self.assertEqual('mysecretpassword', config['keypass']) def test_config_dict_with_int_keys(self): os.chdir(self.tmpdir) - with open('config.yml', 'w') as fp: - fp.write('java_paths:\n 8: /usr/lib/jvm/java-8-openjdk\n') - self.assertTrue(os.path.exists(fp.name)) - self.assertFalse(os.path.exists('config.py')) + fdroidserver.common.write_config_file( + textwrap.dedent( + """ + java_paths: + 8: /usr/lib/jvm/java-8-openjdk + """ + ) + ) + self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE)) config = fdroidserver.common.read_config() - self.assertEqual('/usr/lib/jvm/java-8-openjdk', config.get('java_paths', {}).get('8')) + self.assertEqual('/usr/lib/jvm/java-8-openjdk', config['java_paths']['8']) @mock.patch.dict(os.environ, {'PATH': os.getenv('PATH')}, clear=True) def test_test_sdk_exists_fails_on_bad_sdk_path(self): @@ -2143,10 +2095,11 @@ class CommonTest(unittest.TestCase): def test_loading_config_buildserver_yml(self): """Smoke check to make sure this file is properly parsed""" - os.chdir(self.tmpdir) - shutil.copy(os.path.join(basedir, '..', 'buildserver', 'config.buildserver.yml'), - 'config.yml') - self.assertFalse(os.path.exists('config.py')) + os.chdir(self.testdir) + shutil.copy( + os.path.join(basedir, '..', 'buildserver', 'config.buildserver.yml'), + fdroidserver.common.CONFIG_FILE, + ) fdroidserver.common.read_config() def test_setup_status_output(self): @@ -2653,7 +2606,7 @@ class CommonTest(unittest.TestCase): def test_get_apksigner_smartcardoptions(self): os.chdir(self.tmpdir) - with open('config.yml', 'w') as fp: + with open(fdroidserver.common.CONFIG_FILE, 'w', encoding='utf-8') as fp: d = { 'smartcardoptions': '-storetype PKCS11' ' -providerName SunPKCS11-OpenSC' @@ -2681,10 +2634,9 @@ class CommonTest(unittest.TestCase): def test_get_smartcardoptions_list(self): os.chdir(self.tmpdir) - with open('config.yml', 'w') as fp: - fp.write( - textwrap.dedent( - """ + fdroidserver.common.write_config_file( + textwrap.dedent( + """ smartcardoptions: - -storetype - PKCS11 @@ -2694,9 +2646,9 @@ class CommonTest(unittest.TestCase): - sun.security.pkcs11.SunPKCS11 - -providerArg - opensc-fdroid.cfg - """ - ) + """ ) + ) config = fdroidserver.common.read_config() fdroidserver.common.config = config self.assertTrue(isinstance(config['smartcardoptions'], list)) @@ -2716,17 +2668,16 @@ class CommonTest(unittest.TestCase): def test_get_smartcardoptions_spaces(self): os.chdir(self.tmpdir) - with open('config.yml', 'w') as fp: - fp.write( - textwrap.dedent( - """smartcardoptions: | - -storetype PKCS11 - -providerClass sun.security.pkcs11.SunPKCS11 - -providerArg /etc/pkcs11_java.cfg - - """ - ) + fdroidserver.common.write_config_file( + textwrap.dedent( + """ + smartcardoptions: | + -storetype PKCS11 + -providerClass sun.security.pkcs11.SunPKCS11 + -providerArg /etc/pkcs11_java.cfg + """ ) + ) config = fdroidserver.common.read_config() fdroidserver.common.config = config self.assertTrue(isinstance(config['smartcardoptions'], list)) @@ -2742,35 +2693,6 @@ class CommonTest(unittest.TestCase): config['smartcardoptions'], ) - def test_get_smartcardoptions_config_py(self): - os.chdir(self.tmpdir) - with open('config.py', 'w') as fp: - fp.write( - textwrap.dedent( - """ - smartcardoptions = ''' - \t-storetype\tPKCS11 - \t-providerClass\tsun.security.pkcs11.SunPKCS11 - \t-providerArg\t/etc/pkcs11_java.cfg - - ''' - """ - ) - ) - config = fdroidserver.common.read_config() - fdroidserver.common.config = config - self.assertEqual( - [ - '-storetype', - 'PKCS11', - '-providerClass', - 'sun.security.pkcs11.SunPKCS11', - '-providerArg', - '/etc/pkcs11_java.cfg', - ], - config['smartcardoptions'], - ) - def test_load_localized_config(self): """It should load""" antiFeatures = fdroidserver.common.load_localized_config( @@ -2877,7 +2799,9 @@ class CommonTest(unittest.TestCase): def test_config_serverwebroot_str(self): os.chdir(self.testdir) - Path('config.yml').write_text("""serverwebroot: 'foo@example.com:/var/www'""") + fdroidserver.common.write_config_file( + """serverwebroot: 'foo@example.com:/var/www'""" + ) self.assertEqual( [{'url': 'foo@example.com:/var/www/'}], fdroidserver.common.read_config()['serverwebroot'], @@ -2885,7 +2809,9 @@ class CommonTest(unittest.TestCase): def test_config_serverwebroot_list(self): os.chdir(self.testdir) - Path('config.yml').write_text("""serverwebroot:\n - foo@example.com:/var/www""") + fdroidserver.common.write_config_file( + """serverwebroot:\n - foo@example.com:/var/www""" + ) self.assertEqual( [{'url': 'foo@example.com:/var/www/'}], fdroidserver.common.read_config()['serverwebroot'], @@ -2893,7 +2819,9 @@ class CommonTest(unittest.TestCase): def test_config_serverwebroot_dict(self): os.chdir(self.testdir) - Path('config.yml').write_text("""serverwebroot:\n - url: 'foo@example.com:/var/www'""") + fdroidserver.common.write_config_file( + """serverwebroot:\n - url: 'foo@example.com:/var/www'""" + ) self.assertEqual( [{'url': 'foo@example.com:/var/www/'}], fdroidserver.common.read_config()['serverwebroot'], diff --git a/tests/test_index.py b/tests/test_index.py index ea08653b..059386fb 100755 --- a/tests/test_index.py +++ b/tests/test_index.py @@ -38,8 +38,8 @@ class IndexTest(unittest.TestCase): cls.index_v1_jar = basedir / 'repo' / 'index-v1.jar' def setUp(self): - (basedir / 'config.py').chmod(0o600) - os.chdir(basedir) # so read_config() can find config.py + (basedir / common.CONFIG_FILE).chmod(0o600) + os.chdir(basedir) # so read_config() can find config.yml common.config = None common.options = Options @@ -380,8 +380,7 @@ class IndexTest(unittest.TestCase): with zipfile.ZipFile(jarfile, 'w', zipfile.ZIP_DEFLATED) as jar: jar.writestr('publishsigkeys.json', json.dumps(sigkeyfps)) publish.sign_sig_key_fingerprint_list(jarfile) - with open('config.py', 'w'): - pass + common.write_config_file('') index.v1_sort_packages( i, common.load_stats_fdroid_signing_key_fingerprints() @@ -701,7 +700,7 @@ class IndexTest(unittest.TestCase): ) def test_add_mirrors_to_repodict(self): - """Test based on the contents of tests/config.py""" + """Test based on the contents of tests/config.yml""" repodict = {'address': common.config['repo_url']} index.add_mirrors_to_repodict('repo', repodict) self.assertEqual( @@ -718,7 +717,7 @@ class IndexTest(unittest.TestCase): os.chdir(self.testdir) repo_url = 'https://example.com/fdroid/repo' c = {'repo_url': repo_url, 'mirrors': ['http://one/fdroid']} - with open('config.yml', 'w') as fp: + with open(common.CONFIG_FILE, 'w', encoding='utf-8') as fp: yaml.dump(c, fp) common.config = None common.read_config() diff --git a/tests/test_init.py b/tests/test_init.py index b448192f..179f06c7 100755 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -28,12 +28,13 @@ class InitTest(unittest.TestCase): self._td.cleanup() def test_disable_in_config(self): - configfile = pathlib.Path('config.yml') - configfile.write_text('keystore: NONE\nkeypass: mysupersecrets\n') + test = 'mysupersecrets' + configfile = pathlib.Path(fdroidserver.common.CONFIG_FILE) + configfile.write_text(f'keystore: NONE\nkeypass: {test}\n', encoding='utf-8') configfile.chmod(0o600) config = fdroidserver.common.read_config() self.assertEqual('NONE', config['keystore']) - self.assertEqual('mysupersecrets', config['keypass']) + self.assertEqual(test, config['keypass']) fdroidserver.init.disable_in_config('keypass', 'comment') self.assertIn('#keypass:', configfile.read_text()) fdroidserver.common.config = None diff --git a/tests/test_integration.py b/tests/test_integration.py index d7f1231d..7c527b57 100755 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -148,7 +148,7 @@ class IntegrationTest(unittest.TestCase): + ["init", "--keystore", keystore_path, "--repo-keyalias", "sova"] ) self.update_yaml( - "config.yml", + common.CONFIG_FILE, { "keystorepass": "r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI=", "keypass": "r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI=", @@ -160,7 +160,7 @@ class IntegrationTest(unittest.TestCase): shutil.copy(FILES / "keystore.jks", "keystore.jks") self.fdroid_init_with_prebuilt_keystore("keystore.jks") self.update_yaml( - "config.yml", + common.CONFIG_FILE, { "make_current_version_link": True, "keydname": "CN=Birdman, OU=Cell, O=Alcatraz, L=Alcatraz, S=California, C=US", @@ -193,7 +193,7 @@ class IntegrationTest(unittest.TestCase): def test_utf8_metadata(self): self.fdroid_init_with_prebuilt_keystore() self.update_yaml( - "config.yml", + common.CONFIG_FILE, { "repo_description": "获取已安装在您的设备上的应用的", "mirrors": ["https://foo.bar/fdroid", "http://secret.onion/fdroid"], @@ -247,7 +247,7 @@ class IntegrationTest(unittest.TestCase): shutil.copytree(FILES / "gnupghome", gnupghome) os.chmod(gnupghome, 0o700) self.update_yaml( - "config.yml", + common.CONFIG_FILE, { "install_list": "org.adaway", "uninstall_list": ["com.android.vending", "com.facebook.orca"], @@ -334,7 +334,7 @@ class IntegrationTest(unittest.TestCase): FILES.glob("repo/obb.main.twoversions_110161[357].apk"), ): shutil.copy(f, "repo") - self.update_yaml("config.yml", {"archive_older": 3}) + self.update_yaml(common.CONFIG_FILE, {"archive_older": 3}) self.assert_run(self.fdroid_cmd + ["update", "--pretty", "--nosign"]) with open("archive/index.xml") as f: @@ -356,7 +356,7 @@ class IntegrationTest(unittest.TestCase): shutil.copy(FILES / "metadata/com.politedroid.yml", "metadata") for f in FILES.glob("repo/com.politedroid_[0-9].apk"): shutil.copy(f, "repo") - self.update_yaml("config.yml", {"archive_older": 3}) + self.update_yaml(common.CONFIG_FILE, {"archive_older": 3}) self.assert_run(self.fdroid_cmd + ["update", "--pretty", "--nosign"]) repo = Path("repo/index.xml").read_text() @@ -456,7 +456,7 @@ class IntegrationTest(unittest.TestCase): self.remove_lines("metadata/com.politedroid.yml", ["ArchivePolicy:"]) for f in FILES.glob("repo/com.politedroid_[0-9].apk"): shutil.copy(f, "repo") - self.update_yaml("config.yml", {"archive_older": 3}) + self.update_yaml(common.CONFIG_FILE, {"archive_older": 3}) self.assert_run(self.fdroid_cmd + ["update", "--pretty", "--nosign"]) repo = Path("repo/index.xml").read_text() @@ -474,7 +474,7 @@ class IntegrationTest(unittest.TestCase): self.assertIn("com.politedroid_3.apk", archive) self.assertTrue(Path("archive/com.politedroid_3.apk").is_file()) - self.update_yaml("config.yml", {"archive_older": 1}) + self.update_yaml(common.CONFIG_FILE, {"archive_older": 1}) self.assert_run(self.fdroid_cmd + ["update", "--pretty", "--nosign"]) repo = Path("repo/index.xml").read_text() repo_cnt = sum(1 for line in repo.splitlines() if "" in line) @@ -555,7 +555,7 @@ class IntegrationTest(unittest.TestCase): def test_allowing_disabled_signatures_in_repo_and_archive(self): self.fdroid_init_with_prebuilt_keystore() self.update_yaml( - "config.yml", {"allow_disabled_algorithms": True, "archive_older": 3} + common.CONFIG_FILE, {"allow_disabled_algorithms": True, "archive_older": 3} ) Path("metadata").mkdir() shutil.copy(FILES / "metadata/com.politedroid.yml", "metadata") @@ -650,7 +650,7 @@ class IntegrationTest(unittest.TestCase): self.assertTrue(Path("archive/urzip-badsig.apk").is_file()) # test unarchiving when disabled_algorithms are allowed again - self.update_yaml("config.yml", {"allow_disabled_algorithms": True}) + self.update_yaml(common.CONFIG_FILE, {"allow_disabled_algorithms": True}) self.assert_run(self.fdroid_cmd + ["update", "--pretty", "--nosign"]) with open("archive/index.xml") as f: archive_cnt = sum(1 for line in f if "" in line) @@ -689,7 +689,7 @@ class IntegrationTest(unittest.TestCase): def test_rename_apks_with_fdroid_update_rename_apks_opt_nosign_opt_for_speed(self): self.fdroid_init_with_prebuilt_keystore() self.update_yaml( - "config.yml", + common.CONFIG_FILE, { "keydname": "CN=Birdman, OU=Cell, O=Alcatraz, L=Alcatraz, S=California, C=US" }, @@ -744,7 +744,7 @@ class IntegrationTest(unittest.TestCase): def test_for_added_date_being_set_correctly_for_repo_and_archive(self): self.fdroid_init_with_prebuilt_keystore() - self.update_yaml("config.yml", {"archive_older": 3}) + self.update_yaml(common.CONFIG_FILE, {"archive_older": 3}) Path("metadata").mkdir() Path("archive").mkdir() Path("stats").mkdir() @@ -803,12 +803,14 @@ class IntegrationTest(unittest.TestCase): ) # fake that no JDKs are available self.update_yaml( - "config.yml", {"categories": ["Internet"], "java_paths": {}}, replace=True + common.CONFIG_FILE, + {"categories": ["Internet"], "java_paths": {}}, + replace=True, ) local_copy_dir = self.testdir / "local_copy_dir/fdroid" (local_copy_dir / "repo").mkdir(parents=True) self.update_yaml( - "config.yml", {"local_copy_dir": str(local_copy_dir.resolve())} + common.CONFIG_FILE, {"local_copy_dir": str(local_copy_dir.resolve())} ) subprocess.run(self.fdroid_cmd + ["checkupdates", "--allow-dirty"]) @@ -879,7 +881,7 @@ class IntegrationTest(unittest.TestCase): new_tmp_repo.mkdir() os.chdir(new_tmp_repo) self.fdroid_init_with_prebuilt_keystore() - self.update_yaml("config.yml", {"sync_from_local_copy_dir": True}) + self.update_yaml(common.CONFIG_FILE, {"sync_from_local_copy_dir": True}) self.assert_run( self.fdroid_cmd + ["deploy", "--local-copy-dir", local_copy_dir] ) @@ -946,7 +948,7 @@ class IntegrationTest(unittest.TestCase): ] ) # the value set in --android-home should override $ANDROID_HOME - self.assertIn(str(fake_android_home), Path("config.yml").read_text()) + self.assertIn(str(fake_android_home), Path(common.CONFIG_FILE).read_text()) @unittest.skipUnless( "ANDROID_HOME" in os.environ, "runs only with ANDROID_HOME set" @@ -1097,7 +1099,7 @@ class IntegrationTest(unittest.TestCase): # now set up fake, non-working keystore setup Path("keystore.p12").touch() self.update_yaml( - "config.yml", + common.CONFIG_FILE, { "keystore": "keystore.p12", "repo_keyalias": "foo", @@ -1115,7 +1117,9 @@ class IntegrationTest(unittest.TestCase): shutil.copytree(FILES / "repo", "repo", dirs_exist_ok=True) shutil.copytree(FILES / "metadata", "metadata") git_remote = self.testdir / "git_remote" - self.update_yaml("config.yml", {"binary_transparency_remote": str(git_remote)}) + self.update_yaml( + common.CONFIG_FILE, {"binary_transparency_remote": str(git_remote)} + ) self.assert_run(self.fdroid_cmd + ["update", "--verbose"]) self.assert_run(self.fdroid_cmd + ["deploy", "--verbose"]) self.assertIn(" 0) # now set fake repo_keyalias - self.update_yaml("config.yml", {"repo_keyalias": "fake"}) + self.update_yaml(common.CONFIG_FILE, {"repo_keyalias": "fake"}) # this should fail because this repo has a bad repo_keyalias self.assert_run_fail(self.fdroid_cmd + ["update"]) @@ -1179,7 +1183,7 @@ class IntegrationTest(unittest.TestCase): self.fdroid_init_with_prebuilt_keystore() self.update_yaml( - "config.yml", + common.CONFIG_FILE, {"archive_older": 3, "servergitmirrors": str(server_git_mirror)}, ) for f in FILES.glob("repo/com.politedroid_[345].apk"): @@ -1226,7 +1230,7 @@ class IntegrationTest(unittest.TestCase): f.stat().st_size for f in (git_mirror / ".git").glob("**/*") if f.is_file() ) - self.update_yaml("config.yml", {"git_mirror_size_limit": "60kb"}) + self.update_yaml(common.CONFIG_FILE, {"git_mirror_size_limit": "60kb"}) self.assert_run(self.fdroid_cmd + ["update"]) self.assert_run(self.fdroid_cmd + ["deploy"]) self.assertTrue(Path("archive/com.politedroid_3.apk").is_file()) @@ -1274,7 +1278,7 @@ class IntegrationTest(unittest.TestCase): Path("unsigned").mkdir() shutil.copy(FILES / "urzip-release-unsigned.apk", "unsigned") self.update_yaml( - "config.yml", + common.CONFIG_FILE, { "archive_older": 3, "mirrors": [ @@ -1312,7 +1316,7 @@ class IntegrationTest(unittest.TestCase): ) os.chdir(online_root) self.update_yaml( - "config.yml", + common.CONFIG_FILE, { "local_copy_dir": str(local_copy_dir), "sync_from_local_copy_dir": True, @@ -1344,7 +1348,7 @@ class IntegrationTest(unittest.TestCase): def test_extracting_and_publishing_with_developer_signature(self): self.fdroid_init_with_prebuilt_keystore() self.update_yaml( - "config.yml", + common.CONFIG_FILE, { "keydname": "CN=Birdman, OU=Cell, O=Alcatraz, L=Alcatraz, S=California, C=US" }, diff --git a/tests/test_lint.py b/tests/test_lint.py index ff6c2247..6816ab69 100755 --- a/tests/test_lint.py +++ b/tests/test_lint.py @@ -345,7 +345,7 @@ class LintTest(unittest.TestCase): def test_check_categories_from_config_yml(self): """In config.yml, categories is a list.""" os.chdir(self.testdir) - Path('config.yml').write_text('categories: [foo, bar]\n') + fdroidserver.common.write_config_file('categories: [foo, bar]\n') fdroidserver.lint.config = fdroidserver.common.read_config() fdroidserver.lint.load_categories_config() self.assertEqual(fdroidserver.lint.CATEGORIES_KEYS, ['foo', 'bar']) @@ -434,9 +434,11 @@ class LintTest(unittest.TestCase): def test_lint_invalid_config_keys(self): os.chdir(self.testdir) - Path('config').mkdir() - Path('config/config.yml').write_text('repo:\n invalid_key: test\n') - self.assertFalse(fdroidserver.lint.lint_config('config/config.yml')) + os.mkdir('config') + config_yml = fdroidserver.common.CONFIG_FILE + with open(f'config/{config_yml}', 'w', encoding='utf-8') as fp: + fp.write('repo:\n invalid_key: test\n') + self.assertFalse(fdroidserver.lint.lint_config(f'config/{config_yml}')) def test_lint_invalid_localized_config_keys(self): os.chdir(self.testdir) @@ -534,7 +536,7 @@ class LintAntiFeaturesTest(unittest.TestCase): class ConfigYmlTest(LintTest): def setUp(self): super().setUp() - self.config_yml = Path(self.testdir) / 'config.yml' + self.config_yml = Path(self.testdir) / fdroidserver.common.CONFIG_FILE def test_config_yml_int(self): self.config_yml.write_text('repo_maxage: 1\n') diff --git a/tests/test_nightly.py b/tests/test_nightly.py index 09d8fbcf..750a22fc 100755 --- a/tests/test_nightly.py +++ b/tests/test_nightly.py @@ -250,7 +250,6 @@ class NightlyTest(unittest.TestCase): raise self.assertEqual(called, [['ssh', '-Tvi'], ['fdroid', 'deploy']]) - self.assertFalse(os.path.exists('config.py')) git_url = 'git@github.com:f-droid/test-nightly' mirror_url = index.get_mirror_service_urls({"url": git_url})[0] expected = { @@ -269,7 +268,7 @@ class NightlyTest(unittest.TestCase): 'repo_url': mirror_url + '/repo', 'servergitmirrors': [{"url": git_url}], } - with open('config.yml') as fp: + with open(common.CONFIG_FILE) as fp: config = yaml.safe_load(fp) # .ssh is random tmpdir set in nightly.py, so test basename only self.assertEqual( @@ -324,7 +323,6 @@ class NightlyTest(unittest.TestCase): raise self.assertEqual(called, [['ssh', '-Tvi'], ['fdroid', 'deploy']]) - self.assertFalse(os.path.exists('config.py')) expected = { 'archive_description': 'Old nightly builds that have been archived.', 'archive_name': 'fdroid/test-nightly archive', @@ -341,7 +339,7 @@ class NightlyTest(unittest.TestCase): 'repo_url': 'https://gitlab.com/fdroid/test-nightly/-/raw/master/fdroid/repo', 'servergitmirrors': [{"url": 'git@gitlab.com:fdroid/test-nightly'}], } - with open('config.yml') as fp: + with open(common.CONFIG_FILE) as fp: config = yaml.safe_load(fp) # .ssh is random tmpdir set in nightly.py, so test basename only self.assertEqual( diff --git a/tests/test_publish.py b/tests/test_publish.py index 2f8be36a..099c4188 100755 --- a/tests/test_publish.py +++ b/tests/test_publish.py @@ -13,6 +13,7 @@ import json import os import pathlib +import ruamel.yaml import shutil import sys import unittest @@ -94,8 +95,7 @@ class PublishTest(unittest.TestCase): ] os.chdir(self.testdir) - with open('config.py', 'w') as f: - pass + common.write_config_file('') publish.store_stats_fdroid_signing_key_fingerprints(appids, indent=2) @@ -116,11 +116,13 @@ class PublishTest(unittest.TestCase): } self.assertEqual(expected, common.load_stats_fdroid_signing_key_fingerprints()) - with open('config.py', 'r') as f: - self.assertEqual( - '\nrepo_key_sha256 = "c58460800c7b250a619c30c13b07b7359a43e5af71a4352d86c58ae18c9f6d41"\n', - f.read(), - ) + yaml = ruamel.yaml.YAML(typ='safe') + with open(common.CONFIG_FILE) as fp: + config = yaml.load(fp) + self.assertEqual( + 'c58460800c7b250a619c30c13b07b7359a43e5af71a4352d86c58ae18c9f6d41', + config['repo_key_sha256'], + ) def test_store_and_load_fdroid_signing_key_fingerprints_with_missmatch(self): common.config = {} diff --git a/tests/test_scanner.py b/tests/test_scanner.py index 592680ef..4899a219 100755 --- a/tests/test_scanner.py +++ b/tests/test_scanner.py @@ -800,7 +800,7 @@ class Test_ScannerTool(unittest.TestCase): def test_refresh_from_config(self): os.chdir(self.testdir) - pathlib.Path('config.yml').write_text('refresh_scanner: true') + fdroidserver.common.write_config_file('refresh_scanner: true\n') with mock.patch('fdroidserver.scanner.ScannerTool.refresh') as refresh: fdroidserver.scanner.ScannerTool() refresh.assert_called_once() @@ -809,7 +809,7 @@ class Test_ScannerTool(unittest.TestCase): fdroidserver.common.options = mock.Mock() fdroidserver.common.options.refresh_scanner = True os.chdir(self.testdir) - pathlib.Path('config.yml').write_text('refresh_scanner: false') + fdroidserver.common.write_config_file('refresh_scanner: false\n') with mock.patch('fdroidserver.scanner.ScannerTool.refresh') as refresh: fdroidserver.scanner.ScannerTool() refresh.assert_called_once() diff --git a/tests/test_update.py b/tests/test_update.py index 28dd27f9..6c551694 100755 --- a/tests/test_update.py +++ b/tests/test_update.py @@ -1787,7 +1787,9 @@ class UpdateTest(unittest.TestCase): def test_categories_txt_is_removed_by_delete_unknown(self): """categories.txt used to be a part of this system, now its nothing.""" os.chdir(self.testdir) - Path('config.yml').write_text('repo_pubkey: ffffffffffffffffffffffffffffffffffffffff') + fdroidserver.common.write_config_file( + 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff\n' + ) categories_txt = Path('repo/categories.txt') categories_txt.parent.mkdir() @@ -1803,8 +1805,8 @@ class UpdateTest(unittest.TestCase): os.chdir(self.testdir) os.mkdir('metadata') os.mkdir('repo') - Path('config.yml').write_text( - 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff' + fdroidserver.common.write_config_file( + 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff\n' ) testapk = os.path.join('repo', 'com.politedroid_6.apk') @@ -1822,8 +1824,8 @@ class UpdateTest(unittest.TestCase): os.chdir(self.testdir) os.mkdir('metadata') os.mkdir('repo') - Path('config.yml').write_text( - 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff' + fdroidserver.common.write_config_file( + 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff\n' ) testapk = os.path.join('repo', 'com.politedroid_6.apk') @@ -1844,8 +1846,8 @@ class UpdateTest(unittest.TestCase): os.chdir(self.testdir) os.mkdir('metadata') os.mkdir('repo') - Path('config.yml').write_text( - 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff' + fdroidserver.common.write_config_file( + 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff\n' ) testapk = os.path.join('repo', 'com.politedroid_6.apk') @@ -1871,8 +1873,8 @@ class UpdateTest(unittest.TestCase): Path('config/categories.yml').write_text('System: {name: System Apps}') os.mkdir('metadata') os.mkdir('repo') - Path('config.yml').write_text( - 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff' + fdroidserver.common.write_config_file( + 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff\n' ) testapk = os.path.join('repo', 'com.politedroid_6.apk') @@ -1901,8 +1903,8 @@ class UpdateTest(unittest.TestCase): Path('config/categories.yml').write_text('System: {name: S}\nTime: {name: T}\n') os.mkdir('metadata') os.mkdir('repo') - Path('config.yml').write_text( - 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff' + fdroidserver.common.write_config_file( + 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff\n' ) testapk = os.path.join('repo', 'com.politedroid_6.apk')