update: add all categories in metadata files to repo definitions

!1366 makes it so categories are now defined by the repo. Categories can be
defined in the config so that lint has a list of categories to enforce. This
also provides a place for localization and icons for the categories. The old
way of defining categories was just listing them in app metadata files. This
restores that way of functioning when using index-v2.

closes #1137
This commit is contained in:
Hans-Christoph Steiner 2023-06-07 13:36:02 +02:00
parent 64b8ee772c
commit 2c566cf68f
4 changed files with 111 additions and 5 deletions

View File

@ -711,6 +711,7 @@ def make_v2(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
output_packages = collections.OrderedDict()
output['packages'] = output_packages
categories_used_by_apps = set()
for package in packages:
packageName = package['packageName']
if packageName not in apps:
@ -730,7 +731,9 @@ def make_v2(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
else:
packagelist = {}
output_packages[packageName] = packagelist
packagelist["metadata"] = package_metadata(apps[packageName], repodir)
app = apps[packageName]
categories_used_by_apps.update(app.get('Categories', []))
packagelist["metadata"] = package_metadata(app, repodir)
if "signer" in package:
packagelist["metadata"]["preferredSigner"] = package["signer"]
@ -738,6 +741,12 @@ def make_v2(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
packagelist["versions"][package["hash"]] = convert_version(package, apps[packageName], repodir)
if categories_used_by_apps and not output['repo'].get(CATEGORIES_CONFIG_NAME):
output['repo'][CATEGORIES_CONFIG_NAME] = dict()
for category in sorted(categories_used_by_apps):
if category not in output['repo'][CATEGORIES_CONFIG_NAME]:
output['repo'][CATEGORIES_CONFIG_NAME][category] = dict()
entry = {}
entry["timestamp"] = repodict["timestamp"]

View File

@ -3,8 +3,8 @@
"version": 20002,
"index": {
"name": "/index-v2.json",
"sha256": "7117ee6ff4ff2dd71ec3f3d3ad2ef7e9fd4afead9b1f2d39d0b224a1812e78b5",
"size": 53233,
"sha256": "b613858aa7a2ec476fcef5c841a5b8ff4b3b0f67f07678da981e2843f49c71ba",
"size": 53283,
"numPackages": 10
},
"diffs": {}

View File

@ -533,7 +533,10 @@
"name": {
"en-US": "System"
}
}
},
"1": {},
"2.0": {},
"tests": {}
},
"requests": {
"install": [
@ -1443,4 +1446,4 @@
}
}
}
}
}

View File

@ -53,6 +53,7 @@ import fdroidserver.common
import fdroidserver.exception
import fdroidserver.metadata
import fdroidserver.update
from fdroidserver.common import CATEGORIES_CONFIG_NAME
DONATION_FIELDS = ('Donate', 'Liberapay', 'OpenCollective')
@ -1804,6 +1805,99 @@ class UpdateTest(unittest.TestCase):
fdroidserver.update.main()
self.assertFalse(categories_txt.exists())
def test_no_blank_auto_defined_categories(self):
"""When no app has Categories, there should be no definitions in the repo."""
os.chdir(self.testdir)
os.mkdir('metadata')
os.mkdir('repo')
Path('config.yml').write_text(
'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff'
)
testapk = os.path.join('repo', 'com.politedroid_6.apk')
shutil.copy(os.path.join(self.basedir, testapk), testapk)
Path('metadata/com.politedroid.yml').write_text('Name: Polite')
with mock.patch('sys.argv', ['fdroid update', '--delete-unknown', '--nosign']):
fdroidserver.update.main()
with open('repo/index-v2.json') as fp:
index = json.load(fp)
self.assertFalse(CATEGORIES_CONFIG_NAME in index['repo'])
def test_auto_defined_categories(self):
"""Repos that don't define categories in config/ should use auto-generated."""
os.chdir(self.testdir)
os.mkdir('metadata')
os.mkdir('repo')
Path('config.yml').write_text(
'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff'
)
testapk = os.path.join('repo', 'com.politedroid_6.apk')
shutil.copy(os.path.join(self.basedir, testapk), testapk)
Path('metadata/com.politedroid.yml').write_text('Categories: [Time]')
with mock.patch('sys.argv', ['fdroid update', '--delete-unknown', '--nosign']):
fdroidserver.update.main()
with open('repo/index-v2.json') as fp:
index = json.load(fp)
self.assertEqual(
{'Time': dict()},
index['repo'][CATEGORIES_CONFIG_NAME],
)
def test_auto_defined_categories_two_apps(self):
"""Repos that don't define categories in config/ should use auto-generated."""
os.chdir(self.testdir)
os.mkdir('metadata')
os.mkdir('repo')
Path('config.yml').write_text(
'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff'
)
testapk = os.path.join('repo', 'com.politedroid_6.apk')
shutil.copy(os.path.join(self.basedir, testapk), testapk)
Path('metadata/com.politedroid.yml').write_text('Categories: [bar]')
testapk = os.path.join('repo', 'souch.smsbypass_9.apk')
shutil.copy(os.path.join(self.basedir, testapk), testapk)
Path('metadata/souch.smsbypass.yml').write_text('Categories: [foo, bar]')
with mock.patch('sys.argv', ['fdroid update', '--delete-unknown', '--nosign']):
fdroidserver.update.main()
with open('repo/index-v2.json') as fp:
index = json.load(fp)
self.assertEqual(
{'bar': dict(), 'foo': dict()},
index['repo'][CATEGORIES_CONFIG_NAME],
)
def test_auto_defined_categories_mix_into_config_categories(self):
"""Repos that don't define all categories in config/ also use auto-generated."""
os.chdir(self.testdir)
os.mkdir('config')
Path('config/categories.yml').write_text('System: {name: System Apps}')
os.mkdir('metadata')
os.mkdir('repo')
Path('config.yml').write_text(
'repo_pubkey: ffffffffffffffffffffffffffffffffffffffff'
)
testapk = os.path.join('repo', 'com.politedroid_6.apk')
shutil.copy(os.path.join(self.basedir, testapk), testapk)
Path('metadata/com.politedroid.yml').write_text('Categories: [Time]')
testapk = os.path.join('repo', 'souch.smsbypass_9.apk')
shutil.copy(os.path.join(self.basedir, testapk), testapk)
Path('metadata/souch.smsbypass.yml').write_text('Categories: [System, Time]')
with mock.patch('sys.argv', ['fdroid update', '--delete-unknown', '--nosign']):
fdroidserver.update.main()
with open('repo/index-v2.json') as fp:
index = json.load(fp)
self.assertEqual(
{'System': {'name': {'en-US': 'System Apps'}}, 'Time': dict()},
index['repo'][CATEGORIES_CONFIG_NAME],
)
if __name__ == "__main__":
os.chdir(os.path.dirname(__file__))