Merge branch 'purge-config.py' into 'master'

purge config.py

See merge request fdroid/fdroidserver!1607
This commit is contained in:
Jochen Sprickerhof 2025-03-05 14:42:01 +00:00
commit 16fb0fbe91
24 changed files with 319 additions and 383 deletions

1
.gitignore vendored
View file

@ -27,7 +27,6 @@ tmp/
/tests/repo/status /tests/repo/status
# files used in manual testing # files used in manual testing
/config.py
/config.yml /config.yml
/tmp/ /tmp/
/logs/ /logs/

View file

@ -274,6 +274,35 @@ safety:
- python3 -m safety --key "$SAFETY_API_KEY" --stage cicd scan - 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. # Run all the various linters and static analysis tools.
locales: locales:
image: debian:bookworm-slim image: debian:bookworm-slim
@ -555,11 +584,11 @@ servergitmirrors:
- ./tests/key-tricks.py - ./tests/key-tricks.py
- ssh-keyscan gitlab.com >> /root/.ssh/known_hosts - ssh-keyscan gitlab.com >> /root/.ssh/known_hosts
- test -d /tmp/fdroid/repo || mkdir -p /tmp/fdroid/repo - 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/ - cp tests/repo/com.politedroid_6.apk /tmp/fdroid/repo/
- cd /tmp/fdroid - cd /tmp/fdroid
- touch fdroid-icon.png - 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 update --verbose --create-metadata
- $PYTHONPATH/fdroid deploy --verbose - $PYTHONPATH/fdroid deploy --verbose
- export DLURL=`grep -Eo 'https://gitlab.com/fdroid/ci-test-servergitmirrors-repo[^"]+' repo/index-v1.json` - export DLURL=`grep -Eo 'https://gitlab.com/fdroid/ci-test-servergitmirrors-repo[^"]+' repo/index-v1.json`

View file

@ -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/build-tools/generate.sh
include tests/check-fdroid-apk include tests/check-fdroid-apk
include tests/com.fake.IpaApp_1000000000001.ipa include tests/com.fake.IpaApp_1000000000001.ipa
include tests/config.py include tests/config.yml
include tests/config/antiFeatures.yml include tests/config/antiFeatures.yml
include tests/config/categories.yml include tests/config/categories.yml
include tests/config/de/antiFeatures.yml include tests/config/de/antiFeatures.yml

View file

@ -126,6 +126,7 @@ CONFIG_NAMES = (
RELEASECHANNELS_CONFIG_NAME, RELEASECHANNELS_CONFIG_NAME,
) )
CONFIG_FILE = 'config.yml'
config = None config = None
options = None options = None
@ -525,14 +526,13 @@ def config_type_check(path, data):
def read_config(): def read_config():
"""Read the repository 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 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 there is a local metadata file in the git repo, then the config is
not required, just use defaults. not required, just use defaults.
config.yml is the preferred form because no code is executed when config.yml is the preferred form because no code is executed when
reading it. config.py is deprecated and supported for backwards reading it. config.py is deprecated and no longer supported.
compatibility.
config.yml requires ASCII or UTF-8 encoding because this code does 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 not auto-detect the file's encoding. That is left up to the YAML
@ -547,33 +547,22 @@ def read_config():
return config return config
config = {} config = {}
config_file = 'config.yml'
old_config_file = 'config.py'
if os.path.exists(config_file) and os.path.exists(old_config_file): if os.path.exists(CONFIG_FILE):
logging.error(_("""Conflicting config files! Using {newfile}, ignoring {oldfile}!""") logging.debug(_("Reading '{config_file}'").format(config_file=CONFIG_FILE))
.format(oldfile=old_config_file, newfile=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) config = yaml.safe_load(fp)
if not config: if not config:
config = {} config = {}
config_type_check(config_file, 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
for k in ('mirrors', 'install_list', 'uninstall_list', 'serverwebroot', 'servergitroot'): old_config_file = 'config.py'
if k in config: if os.path.exists(old_config_file):
if not type(config[k]) in (str, list, tuple):
logging.warning( logging.warning(
_("'{field}' will be in random order! Use () or [] brackets if order is important!") _("""Ignoring deprecated {oldfile}, use {newfile}!""").format(
.format(field=k)) oldfile=old_config_file, newfile=CONFIG_FILE
)
)
# smartcardoptions must be a list since its command line args for Popen # smartcardoptions must be a list since its command line args for Popen
smartcardoptions = config.get('smartcardoptions') smartcardoptions = config.get('smartcardoptions')
@ -588,14 +577,13 @@ def read_config():
'-providerArg', 'opensc-fdroid.cfg'] '-providerArg', 'opensc-fdroid.cfg']
if any(k in config for k in ["keystore", "keystorepass", "keypass"]): if any(k in config for k in ["keystore", "keystorepass", "keypass"]):
if os.path.exists(config_file): st = os.stat(CONFIG_FILE)
f = config_file
elif os.path.exists(old_config_file):
f = old_config_file
st = os.stat(f)
if st.st_mode & stat.S_IRWXG or st.st_mode & stat.S_IRWXO: if st.st_mode & stat.S_IRWXG or st.st_mode & stat.S_IRWXO:
logging.warning(_("unsafe permissions on '{config_file}' (should be 0600)!") logging.warning(
.format(config_file=f)) _("unsafe permissions on '{config_file}' (should be 0600)!").format(
config_file=CONFIG_FILE
)
)
fill_config_defaults(config) 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')) return json.loads(str(f.read('publishsigkeys.json'), 'utf-8'))
def write_to_config(thisconfig, key, value=None, config_file=None): def write_config_file(config):
"""Write a key/value to the local config.yml or config.py. """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. NOTE: only supports writing string variables.
@ -4216,61 +4212,42 @@ def write_to_config(thisconfig, key, value=None, config_file=None):
value value
optional value to be written, instead of fetched optional value to be written, instead of fetched
from 'thisconfig' dictionary. from 'thisconfig' dictionary.
""" """
if value is None: if value is None:
origkey = key + '_orig' origkey = key + '_orig'
value = thisconfig[origkey] if origkey in thisconfig else thisconfig[key] 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 # load config file, create one if it doesn't exist
if not os.path.exists(cfg): if not os.path.exists(CONFIG_FILE):
open(cfg, 'a').close() write_config_file('')
logging.info("Creating empty " + cfg) logging.info(_("Creating empty {config_file}").format(config_file=CONFIG_FILE))
with open(cfg, 'r') as f: with open(CONFIG_FILE) as fp:
lines = f.readlines() lines = fp.readlines()
# make sure the file ends with a carraige return # make sure the file ends with a carraige return
if len(lines) > 0: if len(lines) > 0:
if not lines[-1].endswith('\n'): if not lines[-1].endswith('\n'):
lines[-1] += '\n' lines[-1] += '\n'
# regex for finding and replacing python string variable pattern = re.compile(r'^[\s#]*' + key + r':.*\n')
# definitions/initializations repl = yaml.dump({key: value})
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
# If we replaced this line once, we make sure won't be a # If we replaced this line once, we make sure won't be a
# second instance of this line for this key in the document. # second instance of this line for this key in the document.
didRepl = False didRepl = False
# edit config file # edit config file
with open(cfg, 'w') as f: with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
for line in lines: for line in lines:
if pattern.match(line) or pattern2.match(line): if pattern.match(line):
if not didRepl: if not didRepl:
line = pattern.sub(repl, line) line = pattern.sub(repl, line)
line = pattern2.sub(repl2, line)
f.write(line) f.write(line)
didRepl = True didRepl = True
else: else:
f.write(line) f.write(line)
if not didRepl: if not didRepl:
f.write('\n')
f.write(repl) f.write(repl)
f.write('\n')
def parse_xml(path): def parse_xml(path):

View file

@ -38,13 +38,13 @@ def disable_in_config(key, value):
"""Write a key/value to the local config.yml, then comment it out.""" """Write a key/value to the local config.yml, then comment it out."""
import yaml import yaml
with open('config.yml') as f: with open(common.CONFIG_FILE) as fp:
data = f.read() data = fp.read()
pattern = r'\n[\s#]*' + key + r':.*' pattern = r'\n[\s#]*' + key + r':.*'
repl = '\n#' + yaml.dump({key: value}, default_flow_style=False) repl = '\n#' + yaml.dump({key: value}, default_flow_style=False)
data = re.sub(pattern, repl, data) data = re.sub(pattern, repl, data)
with open('config.yml', 'w') as f: with open(common.CONFIG_FILE, 'w') as fp:
f.writelines(data) fp.writelines(data)
def main(): def main():
@ -138,24 +138,24 @@ def main():
_("Android SDK not found at {path}!").format(path=test_config['sdk_path']) _("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 # 'metadata' and 'tmp' are created in fdroid
if not os.path.exists('repo'): if not os.path.exists('repo'):
os.mkdir('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): if os.path.exists(example_config_yml):
shutil.copyfile(example_config_yml, 'config.yml') shutil.copyfile(example_config_yml, common.CONFIG_FILE)
else: else:
from pkg_resources import get_distribution from pkg_resources import get_distribution
versionstr = get_distribution('fdroidserver').version versionstr = get_distribution('fdroidserver').version
if not versionstr: if not versionstr:
versionstr = 'master' 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('# see https://gitlab.com/fdroid/fdroidserver/blob/')
fp.write(versionstr) fp.write(versionstr)
fp.write('/examples/config.yml\n') fp.write(f'/examples/{common.CONFIG_FILE}\n')
os.chmod('config.yml', 0o0600) os.chmod(common.CONFIG_FILE, 0o0600)
# If android_home is None, test_config['sdk_path'] will be used and # 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. # "$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 # If android_home is not None, the path given from the command line

View file

@ -976,7 +976,7 @@ def main():
paths = list() paths = list()
for arg in options.appid: for arg in options.appid:
if ( if (
arg == 'config.yml' arg == common.CONFIG_FILE
or Path(arg).parent.name == 'config' or Path(arg).parent.name == 'config'
or Path(arg).parent.parent.name == 'config' # localized or Path(arg).parent.parent.name == 'config' # localized
): ):

View file

@ -423,9 +423,9 @@ Last updated: {date}'''.format(repo_git_base=repo_git_base,
'keydname': DISTINGUISHED_NAME, 'keydname': DISTINGUISHED_NAME,
'make_current_version_link': False, '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) yaml.dump(config, fp, default_flow_style=False)
os.chmod('config.yml', 0o600) os.chmod(common.CONFIG_FILE, 0o600)
config = common.read_config() config = common.read_config()
common.assert_config_keystore(config) common.assert_config_keystore(config)

View file

@ -1,4 +1,3 @@
Summary: This should be overridden by metadata/info.guardianproject.urzip.yml Summary: This should be overridden by metadata/info.guardianproject.urzip.yml
Builds: Builds:
- versionCode: 50 - versionCode: 50

View file

@ -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"

27
tests/config.yml Normal file
View file

@ -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

View file

@ -593,9 +593,9 @@ class BuildTest(unittest.TestCase):
os.chdir(self.testdir) os.chdir(self.testdir)
sdk_path = os.path.join(self.testdir, 'android-sdk') sdk_path = os.path.join(self.testdir, 'android-sdk')
self.create_fake_android_home(sdk_path) 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) 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() fdroidserver.build.config = fdroidserver.common.read_config()
os.mkdir('metadata') os.mkdir('metadata')

View file

@ -58,6 +58,9 @@ class CommonTest(unittest.TestCase):
os.makedirs(self.tmpdir) os.makedirs(self.tmpdir)
os.chdir(basedir) 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 # these are declared as None at the top of the module file
fdroidserver.common.config = None fdroidserver.common.config = None
fdroidserver.common.options = None fdroidserver.common.options = None
@ -642,65 +645,59 @@ class CommonTest(unittest.TestCase):
) )
def test_write_to_config(self): def test_write_to_config(self):
with tempfile.TemporaryDirectory() as tmpPath: """Test that config items can be added without messing up config.yml.
cfgPath = os.path.join(tmpPath, 'config.py')
with open(cfgPath, 'w') as f: The '_orig' key are where the original string values of paths
f.write( 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( textwrap.dedent(
"""\ """\
# abc # abc
# test = 'example value' # test: 'example value'
default_me= '%%%' a_path: ~/android-sdk
# comment # comment
do_not_touch = "good value" do_not_touch: good value
default_me="!!!" a_path: "!!!"
key="123" # inline""" key: "123" # inline"""
) )
) )
cfg = {'key': '111', 'default_me_orig': 'orig'} config = {'key': 111, 'a_path_orig': '~/android-sdk'}
fdroidserver.common.write_to_config(cfg, 'key', config_file=cfgPath) fdroidserver.common.write_to_config(config, 'key')
fdroidserver.common.write_to_config(cfg, 'default_me', config_file=cfgPath) fdroidserver.common.write_to_config(config, 'a_path')
fdroidserver.common.write_to_config(cfg, 'test', value='test value', config_file=cfgPath) fdroidserver.common.write_to_config(config, 'test', value='test value')
fdroidserver.common.write_to_config(cfg, 'new_key', value='new', config_file=cfgPath) fdroidserver.common.write_to_config(config, 'new_key', value='new')
with open(cfgPath, 'r') as f: with open(fdroidserver.common.CONFIG_FILE) as fp:
self.assertEqual( self.assertEqual(
f.read(), fp.read(),
textwrap.dedent( textwrap.dedent(
"""\ """\
# abc # abc
test = 'test value' test: test value
default_me = 'orig' a_path: ~/android-sdk
# comment # comment
do_not_touch = "good value" do_not_touch: good value
key = "111" # inline key: 111
new_key: new
new_key = "new"
""" """
), ),
) )
def test_write_to_config_when_empty(self): def test_write_to_config_when_empty(self):
with tempfile.TemporaryDirectory() as tmpPath: os.chdir(self.testdir)
cfgPath = os.path.join(tmpPath, 'config.py') config_yml = Path(fdroidserver.common.CONFIG_FILE)
with open(cfgPath, 'w') as f: config_yml.write_text('', encoding='utf-8')
pass fdroidserver.common.write_to_config({}, 'key', 'val')
fdroidserver.common.write_to_config({}, 'key', 'val', cfgPath) self.assertEqual(config_yml.read_text(), 'key: val\n')
with open(cfgPath, 'r') as f:
self.assertEqual(
f.read(),
textwrap.dedent(
"""\
key = "val"
"""
),
)
def test_apk_name_regex(self): def test_apk_name_regex(self):
good = [ good = [
@ -1882,27 +1879,23 @@ class CommonTest(unittest.TestCase):
def test_with_no_config(self): def test_with_no_config(self):
"""It should set defaults if no config file is found""" """It should set defaults if no config file is found"""
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
self.assertFalse(os.path.exists('config.yml')) self.assertFalse(os.path.exists(fdroidserver.common.CONFIG_FILE))
self.assertFalse(os.path.exists('config.py'))
config = fdroidserver.common.read_config() config = fdroidserver.common.read_config()
self.assertIsNotNone(config.get('char_limits')) self.assertIsNotNone(config.get('char_limits'))
def test_with_zero_size_config(self): def test_with_zero_size_config(self):
"""It should set defaults if config file has nothing in it""" """It should set defaults if config file has nothing in it"""
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
open('config.yml', 'w').close() fdroidserver.common.write_config_file('')
self.assertTrue(os.path.exists('config.yml')) self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE))
self.assertFalse(os.path.exists('config.py'))
config = fdroidserver.common.read_config() config = fdroidserver.common.read_config()
self.assertIsNotNone(config.get('char_limits')) self.assertIsNotNone(config.get('char_limits'))
def test_with_config_yml(self): def test_with_config_yml(self):
"""Make sure it is possible to use config.yml alone.""" """Make sure it is possible to use config.yml alone."""
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
with open('config.yml', 'w') as fp: fdroidserver.common.write_config_file('apksigner: yml')
fp.write('apksigner: yml') self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE))
self.assertTrue(os.path.exists('config.yml'))
self.assertFalse(os.path.exists('config.py'))
config = fdroidserver.common.read_config() config = fdroidserver.common.read_config()
self.assertEqual('yml', config.get('apksigner')) 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.""" """Make sure it is possible to use config.yml in UTF-8 encoding."""
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
teststr = '/πÇÇ现代通用字-български-عربي1/ö/yml' teststr = '/πÇÇ现代通用字-български-عربي1/ö/yml'
with open('config.yml', 'w', encoding='utf-8') as fp: fdroidserver.common.write_config_file('apksigner: ' + teststr)
fp.write('apksigner: ' + teststr) self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE))
self.assertTrue(os.path.exists('config.yml'))
self.assertFalse(os.path.exists('config.py'))
config = fdroidserver.common.read_config() config = fdroidserver.common.read_config()
self.assertEqual(teststr, config.get('apksigner')) 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.""" """Make sure it is possible to use config.yml Unicode encoded as ASCII."""
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
teststr = '/πÇÇ现代通用字-български-عربي1/ö/yml' 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) yaml.dump({'apksigner': teststr}, fp)
self.assertTrue(os.path.exists('config.yml')) self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE))
self.assertFalse(os.path.exists('config.py'))
config = fdroidserver.common.read_config() config = fdroidserver.common.read_config()
self.assertEqual(teststr, config.get('apksigner')) self.assertEqual(teststr, config.get('apksigner'))
@ -1933,144 +1923,106 @@ class CommonTest(unittest.TestCase):
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
with mock.patch.dict(os.environ): with mock.patch.dict(os.environ):
os.environ['SECRET'] = 'mysecretpassword' # nosec B105 os.environ['SECRET'] = 'mysecretpassword' # nosec B105
with open('config.yml', 'w') as fp: fdroidserver.common.write_config_file("""keypass: {'env': 'SECRET'}\n""")
fp.write("""keypass: {'env': 'SECRET'}""") self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE))
self.assertTrue(os.path.exists('config.yml'))
self.assertFalse(os.path.exists('config.py'))
config = fdroidserver.common.read_config() config = fdroidserver.common.read_config()
self.assertEqual(os.getenv('SECRET', 'fail'), config.get('keypass')) self.assertEqual(os.getenv('SECRET', 'fail'), config.get('keypass'))
def test_with_config_yml_is_dict(self): def test_with_config_yml_is_dict(self):
os.chdir(self.tmpdir) 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): with self.assertRaises(TypeError):
fdroidserver.common.read_config() fdroidserver.common.read_config()
def test_with_config_yml_is_not_mixed_type(self): def test_with_config_yml_is_not_mixed_type(self):
os.chdir(self.tmpdir) 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): with self.assertRaises(yaml.scanner.ScannerError):
fdroidserver.common.read_config() 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): def test_config_perm_warning(self):
"""Exercise the code path that issues a warning about unsafe permissions.""" """Exercise the code path that issues a warning about unsafe permissions."""
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
with open('config.yml', 'w') as fp: fdroidserver.common.write_config_file('keystore: foo.jks')
fp.write('keystore: foo.jks') self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE))
self.assertTrue(os.path.exists(fp.name)) os.chmod(fdroidserver.common.CONFIG_FILE, 0o666) # nosec B103
os.chmod(fp.name, 0o666) # nosec B103
fdroidserver.common.read_config() fdroidserver.common.read_config()
os.remove(fp.name) os.remove(fdroidserver.common.CONFIG_FILE)
fdroidserver.common.config = None 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): def test_config_repo_url(self):
"""repo_url ends in /repo, archive_url ends in /archive.""" """repo_url ends in /repo, archive_url ends in /archive."""
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
with open('config.yml', 'w') as fp: fdroidserver.common.write_config_file(
fp.write('repo_url: https://MyFirstFDroidRepo.org/fdroid/repo\n') textwrap.dedent(
fp.write('archive_url: https://MyFirstFDroidRepo.org/fdroid/archive') """\
repo_url: https://MyFirstFDroidRepo.org/fdroid/repo
archive_url: https://MyFirstFDroidRepo.org/fdroid/archive
"""
)
)
config = fdroidserver.common.read_config() config = fdroidserver.common.read_config()
self.assertEqual('https://MyFirstFDroidRepo.org/fdroid/repo', config.get('repo_url')) self.assertEqual(
self.assertEqual('https://MyFirstFDroidRepo.org/fdroid/archive', config.get('archive_url')) '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): def test_config_repo_url_extra_slash(self):
"""repo_url ends in /repo, archive_url ends in /archive.""" """repo_url ends in /repo, archive_url ends in /archive."""
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
with open('config.yml', 'w') as fp: fdroidserver.common.write_config_file('repo_url: https://MyFirstFDroidRepo.org/fdroid/repo/')
fp.write('repo_url: https://MyFirstFDroidRepo.org/fdroid/repo/')
with self.assertRaises(FDroidException): with self.assertRaises(FDroidException):
fdroidserver.common.read_config() fdroidserver.common.read_config()
def test_config_repo_url_not_repo(self): def test_config_repo_url_not_repo(self):
"""repo_url ends in /repo, archive_url ends in /archive.""" """repo_url ends in /repo, archive_url ends in /archive."""
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
with open('config.yml', 'w') as fp: fdroidserver.common.write_config_file('repo_url: https://MyFirstFDroidRepo.org/fdroid/foo')
fp.write('repo_url: https://MyFirstFDroidRepo.org/fdroid/foo')
with self.assertRaises(FDroidException): with self.assertRaises(FDroidException):
fdroidserver.common.read_config() fdroidserver.common.read_config()
def test_config_archive_url_extra_slash(self): def test_config_archive_url_extra_slash(self):
"""repo_url ends in /repo, archive_url ends in /archive.""" """repo_url ends in /repo, archive_url ends in /archive."""
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
with open('config.yml', 'w') as fp: fdroidserver.common.write_config_file('archive_url: https://MyFirstFDroidRepo.org/fdroid/archive/')
fp.write('archive_url: https://MyFirstFDroidRepo.org/fdroid/archive/')
with self.assertRaises(FDroidException): with self.assertRaises(FDroidException):
fdroidserver.common.read_config() fdroidserver.common.read_config()
def test_config_archive_url_not_repo(self): def test_config_archive_url_not_repo(self):
"""repo_url ends in /repo, archive_url ends in /archive.""" """repo_url ends in /repo, archive_url ends in /archive."""
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
with open('config.yml', 'w') as fp: fdroidserver.common.write_config_file('archive_url: https://MyFirstFDroidRepo.org/fdroid/foo')
fp.write('archive_url: https://MyFirstFDroidRepo.org/fdroid/foo')
with self.assertRaises(FDroidException): with self.assertRaises(FDroidException):
fdroidserver.common.read_config() fdroidserver.common.read_config()
def test_write_to_config_yml(self): def test_write_to_config_yml(self):
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
with open('config.yml', 'w') as fp: fdroidserver.common.write_config_file('apksigner: yml')
fp.write('apksigner: yml') os.chmod(fdroidserver.common.CONFIG_FILE, 0o0600)
self.assertTrue(os.path.exists(fp.name)) self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE))
self.assertFalse(os.path.exists('config.py'))
config = fdroidserver.common.read_config() config = fdroidserver.common.read_config()
self.assertFalse('keypass' in config) self.assertFalse('keypass' in config)
self.assertEqual('yml', config.get('apksigner')) self.assertEqual('yml', config.get('apksigner'))
fdroidserver.common.write_to_config(config, 'keypass', 'mysecretpassword') 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 fdroidserver.common.config = None
config = fdroidserver.common.read_config() config = fdroidserver.common.read_config()
self.assertEqual('mysecretpassword', config['keypass']) self.assertEqual('mysecretpassword', config['keypass'])
def test_config_dict_with_int_keys(self): def test_config_dict_with_int_keys(self):
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
with open('config.yml', 'w') as fp: fdroidserver.common.write_config_file(
fp.write('java_paths:\n 8: /usr/lib/jvm/java-8-openjdk\n') textwrap.dedent(
self.assertTrue(os.path.exists(fp.name)) """
self.assertFalse(os.path.exists('config.py')) java_paths:
8: /usr/lib/jvm/java-8-openjdk
"""
)
)
self.assertTrue(os.path.exists(fdroidserver.common.CONFIG_FILE))
config = fdroidserver.common.read_config() 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) @mock.patch.dict(os.environ, {'PATH': os.getenv('PATH')}, clear=True)
def test_test_sdk_exists_fails_on_bad_sdk_path(self): 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): def test_loading_config_buildserver_yml(self):
"""Smoke check to make sure this file is properly parsed""" """Smoke check to make sure this file is properly parsed"""
os.chdir(self.tmpdir) os.chdir(self.testdir)
shutil.copy(os.path.join(basedir, '..', 'buildserver', 'config.buildserver.yml'), shutil.copy(
'config.yml') os.path.join(basedir, '..', 'buildserver', 'config.buildserver.yml'),
self.assertFalse(os.path.exists('config.py')) fdroidserver.common.CONFIG_FILE,
)
fdroidserver.common.read_config() fdroidserver.common.read_config()
def test_setup_status_output(self): def test_setup_status_output(self):
@ -2653,7 +2606,7 @@ class CommonTest(unittest.TestCase):
def test_get_apksigner_smartcardoptions(self): def test_get_apksigner_smartcardoptions(self):
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
with open('config.yml', 'w') as fp: with open(fdroidserver.common.CONFIG_FILE, 'w', encoding='utf-8') as fp:
d = { d = {
'smartcardoptions': '-storetype PKCS11' 'smartcardoptions': '-storetype PKCS11'
' -providerName SunPKCS11-OpenSC' ' -providerName SunPKCS11-OpenSC'
@ -2681,8 +2634,7 @@ class CommonTest(unittest.TestCase):
def test_get_smartcardoptions_list(self): def test_get_smartcardoptions_list(self):
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
with open('config.yml', 'w') as fp: fdroidserver.common.write_config_file(
fp.write(
textwrap.dedent( textwrap.dedent(
""" """
smartcardoptions: smartcardoptions:
@ -2716,14 +2668,13 @@ class CommonTest(unittest.TestCase):
def test_get_smartcardoptions_spaces(self): def test_get_smartcardoptions_spaces(self):
os.chdir(self.tmpdir) os.chdir(self.tmpdir)
with open('config.yml', 'w') as fp: fdroidserver.common.write_config_file(
fp.write(
textwrap.dedent( textwrap.dedent(
"""smartcardoptions: | """
smartcardoptions: |
-storetype PKCS11 -storetype PKCS11
-providerClass sun.security.pkcs11.SunPKCS11 -providerClass sun.security.pkcs11.SunPKCS11
-providerArg /etc/pkcs11_java.cfg -providerArg /etc/pkcs11_java.cfg
""" """
) )
) )
@ -2742,35 +2693,6 @@ class CommonTest(unittest.TestCase):
config['smartcardoptions'], 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): def test_load_localized_config(self):
"""It should load""" """It should load"""
antiFeatures = fdroidserver.common.load_localized_config( antiFeatures = fdroidserver.common.load_localized_config(
@ -2877,7 +2799,9 @@ class CommonTest(unittest.TestCase):
def test_config_serverwebroot_str(self): def test_config_serverwebroot_str(self):
os.chdir(self.testdir) 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( self.assertEqual(
[{'url': 'foo@example.com:/var/www/'}], [{'url': 'foo@example.com:/var/www/'}],
fdroidserver.common.read_config()['serverwebroot'], fdroidserver.common.read_config()['serverwebroot'],
@ -2885,7 +2809,9 @@ class CommonTest(unittest.TestCase):
def test_config_serverwebroot_list(self): def test_config_serverwebroot_list(self):
os.chdir(self.testdir) 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( self.assertEqual(
[{'url': 'foo@example.com:/var/www/'}], [{'url': 'foo@example.com:/var/www/'}],
fdroidserver.common.read_config()['serverwebroot'], fdroidserver.common.read_config()['serverwebroot'],
@ -2893,7 +2819,9 @@ class CommonTest(unittest.TestCase):
def test_config_serverwebroot_dict(self): def test_config_serverwebroot_dict(self):
os.chdir(self.testdir) 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( self.assertEqual(
[{'url': 'foo@example.com:/var/www/'}], [{'url': 'foo@example.com:/var/www/'}],
fdroidserver.common.read_config()['serverwebroot'], fdroidserver.common.read_config()['serverwebroot'],

View file

@ -38,8 +38,8 @@ class IndexTest(unittest.TestCase):
cls.index_v1_jar = basedir / 'repo' / 'index-v1.jar' cls.index_v1_jar = basedir / 'repo' / 'index-v1.jar'
def setUp(self): def setUp(self):
(basedir / 'config.py').chmod(0o600) (basedir / common.CONFIG_FILE).chmod(0o600)
os.chdir(basedir) # so read_config() can find config.py os.chdir(basedir) # so read_config() can find config.yml
common.config = None common.config = None
common.options = Options common.options = Options
@ -380,8 +380,7 @@ class IndexTest(unittest.TestCase):
with zipfile.ZipFile(jarfile, 'w', zipfile.ZIP_DEFLATED) as jar: with zipfile.ZipFile(jarfile, 'w', zipfile.ZIP_DEFLATED) as jar:
jar.writestr('publishsigkeys.json', json.dumps(sigkeyfps)) jar.writestr('publishsigkeys.json', json.dumps(sigkeyfps))
publish.sign_sig_key_fingerprint_list(jarfile) publish.sign_sig_key_fingerprint_list(jarfile)
with open('config.py', 'w'): common.write_config_file('')
pass
index.v1_sort_packages( index.v1_sort_packages(
i, common.load_stats_fdroid_signing_key_fingerprints() i, common.load_stats_fdroid_signing_key_fingerprints()
@ -701,7 +700,7 @@ class IndexTest(unittest.TestCase):
) )
def test_add_mirrors_to_repodict(self): 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']} repodict = {'address': common.config['repo_url']}
index.add_mirrors_to_repodict('repo', repodict) index.add_mirrors_to_repodict('repo', repodict)
self.assertEqual( self.assertEqual(
@ -718,7 +717,7 @@ class IndexTest(unittest.TestCase):
os.chdir(self.testdir) os.chdir(self.testdir)
repo_url = 'https://example.com/fdroid/repo' repo_url = 'https://example.com/fdroid/repo'
c = {'repo_url': repo_url, 'mirrors': ['http://one/fdroid']} 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) yaml.dump(c, fp)
common.config = None common.config = None
common.read_config() common.read_config()

View file

@ -28,12 +28,13 @@ class InitTest(unittest.TestCase):
self._td.cleanup() self._td.cleanup()
def test_disable_in_config(self): def test_disable_in_config(self):
configfile = pathlib.Path('config.yml') test = 'mysupersecrets'
configfile.write_text('keystore: NONE\nkeypass: mysupersecrets\n') configfile = pathlib.Path(fdroidserver.common.CONFIG_FILE)
configfile.write_text(f'keystore: NONE\nkeypass: {test}\n', encoding='utf-8')
configfile.chmod(0o600) configfile.chmod(0o600)
config = fdroidserver.common.read_config() config = fdroidserver.common.read_config()
self.assertEqual('NONE', config['keystore']) self.assertEqual('NONE', config['keystore'])
self.assertEqual('mysupersecrets', config['keypass']) self.assertEqual(test, config['keypass'])
fdroidserver.init.disable_in_config('keypass', 'comment') fdroidserver.init.disable_in_config('keypass', 'comment')
self.assertIn('#keypass:', configfile.read_text()) self.assertIn('#keypass:', configfile.read_text())
fdroidserver.common.config = None fdroidserver.common.config = None

View file

@ -148,7 +148,7 @@ class IntegrationTest(unittest.TestCase):
+ ["init", "--keystore", keystore_path, "--repo-keyalias", "sova"] + ["init", "--keystore", keystore_path, "--repo-keyalias", "sova"]
) )
self.update_yaml( self.update_yaml(
"config.yml", common.CONFIG_FILE,
{ {
"keystorepass": "r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI=", "keystorepass": "r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI=",
"keypass": "r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI=", "keypass": "r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI=",
@ -160,7 +160,7 @@ class IntegrationTest(unittest.TestCase):
shutil.copy(FILES / "keystore.jks", "keystore.jks") shutil.copy(FILES / "keystore.jks", "keystore.jks")
self.fdroid_init_with_prebuilt_keystore("keystore.jks") self.fdroid_init_with_prebuilt_keystore("keystore.jks")
self.update_yaml( self.update_yaml(
"config.yml", common.CONFIG_FILE,
{ {
"make_current_version_link": True, "make_current_version_link": True,
"keydname": "CN=Birdman, OU=Cell, O=Alcatraz, L=Alcatraz, S=California, C=US", "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): def test_utf8_metadata(self):
self.fdroid_init_with_prebuilt_keystore() self.fdroid_init_with_prebuilt_keystore()
self.update_yaml( self.update_yaml(
"config.yml", common.CONFIG_FILE,
{ {
"repo_description": "获取已安装在您的设备上的应用的", "repo_description": "获取已安装在您的设备上的应用的",
"mirrors": ["https://foo.bar/fdroid", "http://secret.onion/fdroid"], "mirrors": ["https://foo.bar/fdroid", "http://secret.onion/fdroid"],
@ -247,7 +247,7 @@ class IntegrationTest(unittest.TestCase):
shutil.copytree(FILES / "gnupghome", gnupghome) shutil.copytree(FILES / "gnupghome", gnupghome)
os.chmod(gnupghome, 0o700) os.chmod(gnupghome, 0o700)
self.update_yaml( self.update_yaml(
"config.yml", common.CONFIG_FILE,
{ {
"install_list": "org.adaway", "install_list": "org.adaway",
"uninstall_list": ["com.android.vending", "com.facebook.orca"], "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"), FILES.glob("repo/obb.main.twoversions_110161[357].apk"),
): ):
shutil.copy(f, "repo") 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"]) self.assert_run(self.fdroid_cmd + ["update", "--pretty", "--nosign"])
with open("archive/index.xml") as f: with open("archive/index.xml") as f:
@ -356,7 +356,7 @@ class IntegrationTest(unittest.TestCase):
shutil.copy(FILES / "metadata/com.politedroid.yml", "metadata") shutil.copy(FILES / "metadata/com.politedroid.yml", "metadata")
for f in FILES.glob("repo/com.politedroid_[0-9].apk"): for f in FILES.glob("repo/com.politedroid_[0-9].apk"):
shutil.copy(f, "repo") 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"]) self.assert_run(self.fdroid_cmd + ["update", "--pretty", "--nosign"])
repo = Path("repo/index.xml").read_text() repo = Path("repo/index.xml").read_text()
@ -456,7 +456,7 @@ class IntegrationTest(unittest.TestCase):
self.remove_lines("metadata/com.politedroid.yml", ["ArchivePolicy:"]) self.remove_lines("metadata/com.politedroid.yml", ["ArchivePolicy:"])
for f in FILES.glob("repo/com.politedroid_[0-9].apk"): for f in FILES.glob("repo/com.politedroid_[0-9].apk"):
shutil.copy(f, "repo") 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"]) self.assert_run(self.fdroid_cmd + ["update", "--pretty", "--nosign"])
repo = Path("repo/index.xml").read_text() repo = Path("repo/index.xml").read_text()
@ -474,7 +474,7 @@ class IntegrationTest(unittest.TestCase):
self.assertIn("com.politedroid_3.apk", archive) self.assertIn("com.politedroid_3.apk", archive)
self.assertTrue(Path("archive/com.politedroid_3.apk").is_file()) 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"]) self.assert_run(self.fdroid_cmd + ["update", "--pretty", "--nosign"])
repo = Path("repo/index.xml").read_text() repo = Path("repo/index.xml").read_text()
repo_cnt = sum(1 for line in repo.splitlines() if "<package>" in line) repo_cnt = sum(1 for line in repo.splitlines() if "<package>" in line)
@ -555,7 +555,7 @@ class IntegrationTest(unittest.TestCase):
def test_allowing_disabled_signatures_in_repo_and_archive(self): def test_allowing_disabled_signatures_in_repo_and_archive(self):
self.fdroid_init_with_prebuilt_keystore() self.fdroid_init_with_prebuilt_keystore()
self.update_yaml( 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() Path("metadata").mkdir()
shutil.copy(FILES / "metadata/com.politedroid.yml", "metadata") 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()) self.assertTrue(Path("archive/urzip-badsig.apk").is_file())
# test unarchiving when disabled_algorithms are allowed again # 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"]) self.assert_run(self.fdroid_cmd + ["update", "--pretty", "--nosign"])
with open("archive/index.xml") as f: with open("archive/index.xml") as f:
archive_cnt = sum(1 for line in f if "<package>" in line) archive_cnt = sum(1 for line in f if "<package>" 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): def test_rename_apks_with_fdroid_update_rename_apks_opt_nosign_opt_for_speed(self):
self.fdroid_init_with_prebuilt_keystore() self.fdroid_init_with_prebuilt_keystore()
self.update_yaml( self.update_yaml(
"config.yml", common.CONFIG_FILE,
{ {
"keydname": "CN=Birdman, OU=Cell, O=Alcatraz, L=Alcatraz, S=California, C=US" "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): def test_for_added_date_being_set_correctly_for_repo_and_archive(self):
self.fdroid_init_with_prebuilt_keystore() 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("metadata").mkdir()
Path("archive").mkdir() Path("archive").mkdir()
Path("stats").mkdir() Path("stats").mkdir()
@ -803,12 +803,14 @@ class IntegrationTest(unittest.TestCase):
) )
# fake that no JDKs are available # fake that no JDKs are available
self.update_yaml( 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 = self.testdir / "local_copy_dir/fdroid"
(local_copy_dir / "repo").mkdir(parents=True) (local_copy_dir / "repo").mkdir(parents=True)
self.update_yaml( 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"]) subprocess.run(self.fdroid_cmd + ["checkupdates", "--allow-dirty"])
@ -879,7 +881,7 @@ class IntegrationTest(unittest.TestCase):
new_tmp_repo.mkdir() new_tmp_repo.mkdir()
os.chdir(new_tmp_repo) os.chdir(new_tmp_repo)
self.fdroid_init_with_prebuilt_keystore() 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.assert_run(
self.fdroid_cmd + ["deploy", "--local-copy-dir", local_copy_dir] 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 # 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( @unittest.skipUnless(
"ANDROID_HOME" in os.environ, "runs only with ANDROID_HOME set" "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 # now set up fake, non-working keystore setup
Path("keystore.p12").touch() Path("keystore.p12").touch()
self.update_yaml( self.update_yaml(
"config.yml", common.CONFIG_FILE,
{ {
"keystore": "keystore.p12", "keystore": "keystore.p12",
"repo_keyalias": "foo", "repo_keyalias": "foo",
@ -1115,7 +1117,9 @@ class IntegrationTest(unittest.TestCase):
shutil.copytree(FILES / "repo", "repo", dirs_exist_ok=True) shutil.copytree(FILES / "repo", "repo", dirs_exist_ok=True)
shutil.copytree(FILES / "metadata", "metadata") shutil.copytree(FILES / "metadata", "metadata")
git_remote = self.testdir / "git_remote" 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 + ["update", "--verbose"])
self.assert_run(self.fdroid_cmd + ["deploy", "--verbose"]) self.assert_run(self.fdroid_cmd + ["deploy", "--verbose"])
self.assertIn("<application id=", Path("repo/index.xml").read_text()) self.assertIn("<application id=", Path("repo/index.xml").read_text())
@ -1146,7 +1150,7 @@ class IntegrationTest(unittest.TestCase):
self.assertTrue(apkcache.stat().st_size > 0) self.assertTrue(apkcache.stat().st_size > 0)
# now set fake repo_keyalias # 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 # this should fail because this repo has a bad repo_keyalias
self.assert_run_fail(self.fdroid_cmd + ["update"]) self.assert_run_fail(self.fdroid_cmd + ["update"])
@ -1179,7 +1183,7 @@ class IntegrationTest(unittest.TestCase):
self.fdroid_init_with_prebuilt_keystore() self.fdroid_init_with_prebuilt_keystore()
self.update_yaml( self.update_yaml(
"config.yml", common.CONFIG_FILE,
{"archive_older": 3, "servergitmirrors": str(server_git_mirror)}, {"archive_older": 3, "servergitmirrors": str(server_git_mirror)},
) )
for f in FILES.glob("repo/com.politedroid_[345].apk"): 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() 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 + ["update"])
self.assert_run(self.fdroid_cmd + ["deploy"]) self.assert_run(self.fdroid_cmd + ["deploy"])
self.assertTrue(Path("archive/com.politedroid_3.apk").is_file()) self.assertTrue(Path("archive/com.politedroid_3.apk").is_file())
@ -1274,7 +1278,7 @@ class IntegrationTest(unittest.TestCase):
Path("unsigned").mkdir() Path("unsigned").mkdir()
shutil.copy(FILES / "urzip-release-unsigned.apk", "unsigned") shutil.copy(FILES / "urzip-release-unsigned.apk", "unsigned")
self.update_yaml( self.update_yaml(
"config.yml", common.CONFIG_FILE,
{ {
"archive_older": 3, "archive_older": 3,
"mirrors": [ "mirrors": [
@ -1312,7 +1316,7 @@ class IntegrationTest(unittest.TestCase):
) )
os.chdir(online_root) os.chdir(online_root)
self.update_yaml( self.update_yaml(
"config.yml", common.CONFIG_FILE,
{ {
"local_copy_dir": str(local_copy_dir), "local_copy_dir": str(local_copy_dir),
"sync_from_local_copy_dir": True, "sync_from_local_copy_dir": True,
@ -1344,7 +1348,7 @@ class IntegrationTest(unittest.TestCase):
def test_extracting_and_publishing_with_developer_signature(self): def test_extracting_and_publishing_with_developer_signature(self):
self.fdroid_init_with_prebuilt_keystore() self.fdroid_init_with_prebuilt_keystore()
self.update_yaml( self.update_yaml(
"config.yml", common.CONFIG_FILE,
{ {
"keydname": "CN=Birdman, OU=Cell, O=Alcatraz, L=Alcatraz, S=California, C=US" "keydname": "CN=Birdman, OU=Cell, O=Alcatraz, L=Alcatraz, S=California, C=US"
}, },

View file

@ -345,7 +345,7 @@ class LintTest(unittest.TestCase):
def test_check_categories_from_config_yml(self): def test_check_categories_from_config_yml(self):
"""In config.yml, categories is a list.""" """In config.yml, categories is a list."""
os.chdir(self.testdir) 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.config = fdroidserver.common.read_config()
fdroidserver.lint.load_categories_config() fdroidserver.lint.load_categories_config()
self.assertEqual(fdroidserver.lint.CATEGORIES_KEYS, ['foo', 'bar']) self.assertEqual(fdroidserver.lint.CATEGORIES_KEYS, ['foo', 'bar'])
@ -434,9 +434,11 @@ class LintTest(unittest.TestCase):
def test_lint_invalid_config_keys(self): def test_lint_invalid_config_keys(self):
os.chdir(self.testdir) os.chdir(self.testdir)
Path('config').mkdir() os.mkdir('config')
Path('config/config.yml').write_text('repo:\n invalid_key: test\n') config_yml = fdroidserver.common.CONFIG_FILE
self.assertFalse(fdroidserver.lint.lint_config('config/config.yml')) 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): def test_lint_invalid_localized_config_keys(self):
os.chdir(self.testdir) os.chdir(self.testdir)
@ -534,7 +536,7 @@ class LintAntiFeaturesTest(unittest.TestCase):
class ConfigYmlTest(LintTest): class ConfigYmlTest(LintTest):
def setUp(self): def setUp(self):
super().setUp() 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): def test_config_yml_int(self):
self.config_yml.write_text('repo_maxage: 1\n') self.config_yml.write_text('repo_maxage: 1\n')

View file

@ -250,7 +250,6 @@ class NightlyTest(unittest.TestCase):
raise raise
self.assertEqual(called, [['ssh', '-Tvi'], ['fdroid', 'deploy']]) self.assertEqual(called, [['ssh', '-Tvi'], ['fdroid', 'deploy']])
self.assertFalse(os.path.exists('config.py'))
git_url = 'git@github.com:f-droid/test-nightly' git_url = 'git@github.com:f-droid/test-nightly'
mirror_url = index.get_mirror_service_urls({"url": git_url})[0] mirror_url = index.get_mirror_service_urls({"url": git_url})[0]
expected = { expected = {
@ -269,7 +268,7 @@ class NightlyTest(unittest.TestCase):
'repo_url': mirror_url + '/repo', 'repo_url': mirror_url + '/repo',
'servergitmirrors': [{"url": git_url}], 'servergitmirrors': [{"url": git_url}],
} }
with open('config.yml') as fp: with open(common.CONFIG_FILE) as fp:
config = yaml.safe_load(fp) config = yaml.safe_load(fp)
# .ssh is random tmpdir set in nightly.py, so test basename only # .ssh is random tmpdir set in nightly.py, so test basename only
self.assertEqual( self.assertEqual(
@ -324,7 +323,6 @@ class NightlyTest(unittest.TestCase):
raise raise
self.assertEqual(called, [['ssh', '-Tvi'], ['fdroid', 'deploy']]) self.assertEqual(called, [['ssh', '-Tvi'], ['fdroid', 'deploy']])
self.assertFalse(os.path.exists('config.py'))
expected = { expected = {
'archive_description': 'Old nightly builds that have been archived.', 'archive_description': 'Old nightly builds that have been archived.',
'archive_name': 'fdroid/test-nightly archive', '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', 'repo_url': 'https://gitlab.com/fdroid/test-nightly/-/raw/master/fdroid/repo',
'servergitmirrors': [{"url": 'git@gitlab.com:fdroid/test-nightly'}], '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) config = yaml.safe_load(fp)
# .ssh is random tmpdir set in nightly.py, so test basename only # .ssh is random tmpdir set in nightly.py, so test basename only
self.assertEqual( self.assertEqual(

View file

@ -13,6 +13,7 @@
import json import json
import os import os
import pathlib import pathlib
import ruamel.yaml
import shutil import shutil
import sys import sys
import unittest import unittest
@ -94,8 +95,7 @@ class PublishTest(unittest.TestCase):
] ]
os.chdir(self.testdir) os.chdir(self.testdir)
with open('config.py', 'w') as f: common.write_config_file('')
pass
publish.store_stats_fdroid_signing_key_fingerprints(appids, indent=2) publish.store_stats_fdroid_signing_key_fingerprints(appids, indent=2)
@ -116,10 +116,12 @@ class PublishTest(unittest.TestCase):
} }
self.assertEqual(expected, common.load_stats_fdroid_signing_key_fingerprints()) self.assertEqual(expected, common.load_stats_fdroid_signing_key_fingerprints())
with open('config.py', 'r') as f: yaml = ruamel.yaml.YAML(typ='safe')
with open(common.CONFIG_FILE) as fp:
config = yaml.load(fp)
self.assertEqual( self.assertEqual(
'\nrepo_key_sha256 = "c58460800c7b250a619c30c13b07b7359a43e5af71a4352d86c58ae18c9f6d41"\n', 'c58460800c7b250a619c30c13b07b7359a43e5af71a4352d86c58ae18c9f6d41',
f.read(), config['repo_key_sha256'],
) )
def test_store_and_load_fdroid_signing_key_fingerprints_with_missmatch(self): def test_store_and_load_fdroid_signing_key_fingerprints_with_missmatch(self):

View file

@ -800,7 +800,7 @@ class Test_ScannerTool(unittest.TestCase):
def test_refresh_from_config(self): def test_refresh_from_config(self):
os.chdir(self.testdir) 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: with mock.patch('fdroidserver.scanner.ScannerTool.refresh') as refresh:
fdroidserver.scanner.ScannerTool() fdroidserver.scanner.ScannerTool()
refresh.assert_called_once() refresh.assert_called_once()
@ -809,7 +809,7 @@ class Test_ScannerTool(unittest.TestCase):
fdroidserver.common.options = mock.Mock() fdroidserver.common.options = mock.Mock()
fdroidserver.common.options.refresh_scanner = True fdroidserver.common.options.refresh_scanner = True
os.chdir(self.testdir) 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: with mock.patch('fdroidserver.scanner.ScannerTool.refresh') as refresh:
fdroidserver.scanner.ScannerTool() fdroidserver.scanner.ScannerTool()
refresh.assert_called_once() refresh.assert_called_once()

View file

@ -1787,7 +1787,9 @@ class UpdateTest(unittest.TestCase):
def test_categories_txt_is_removed_by_delete_unknown(self): def test_categories_txt_is_removed_by_delete_unknown(self):
"""categories.txt used to be a part of this system, now its nothing.""" """categories.txt used to be a part of this system, now its nothing."""
os.chdir(self.testdir) 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 = Path('repo/categories.txt')
categories_txt.parent.mkdir() categories_txt.parent.mkdir()
@ -1803,8 +1805,8 @@ class UpdateTest(unittest.TestCase):
os.chdir(self.testdir) os.chdir(self.testdir)
os.mkdir('metadata') os.mkdir('metadata')
os.mkdir('repo') os.mkdir('repo')
Path('config.yml').write_text( fdroidserver.common.write_config_file(
'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff' 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff\n'
) )
testapk = os.path.join('repo', 'com.politedroid_6.apk') testapk = os.path.join('repo', 'com.politedroid_6.apk')
@ -1822,8 +1824,8 @@ class UpdateTest(unittest.TestCase):
os.chdir(self.testdir) os.chdir(self.testdir)
os.mkdir('metadata') os.mkdir('metadata')
os.mkdir('repo') os.mkdir('repo')
Path('config.yml').write_text( fdroidserver.common.write_config_file(
'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff' 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff\n'
) )
testapk = os.path.join('repo', 'com.politedroid_6.apk') testapk = os.path.join('repo', 'com.politedroid_6.apk')
@ -1844,8 +1846,8 @@ class UpdateTest(unittest.TestCase):
os.chdir(self.testdir) os.chdir(self.testdir)
os.mkdir('metadata') os.mkdir('metadata')
os.mkdir('repo') os.mkdir('repo')
Path('config.yml').write_text( fdroidserver.common.write_config_file(
'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff' 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff\n'
) )
testapk = os.path.join('repo', 'com.politedroid_6.apk') 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}') Path('config/categories.yml').write_text('System: {name: System Apps}')
os.mkdir('metadata') os.mkdir('metadata')
os.mkdir('repo') os.mkdir('repo')
Path('config.yml').write_text( fdroidserver.common.write_config_file(
'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff' 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff\n'
) )
testapk = os.path.join('repo', 'com.politedroid_6.apk') 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') Path('config/categories.yml').write_text('System: {name: S}\nTime: {name: T}\n')
os.mkdir('metadata') os.mkdir('metadata')
os.mkdir('repo') os.mkdir('repo')
Path('config.yml').write_text( fdroidserver.common.write_config_file(
'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff' 'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff\n'
) )
testapk = os.path.join('repo', 'com.politedroid_6.apk') testapk = os.path.join('repo', 'com.politedroid_6.apk')