diff --git a/fdroidserver/index.py b/fdroidserver/index.py index ddb51546..d05d159e 100644 --- a/fdroidserver/index.py +++ b/fdroidserver/index.py @@ -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"] diff --git a/tests/repo/entry.json b/tests/repo/entry.json index 5c0ca528..0e8828e0 100644 --- a/tests/repo/entry.json +++ b/tests/repo/entry.json @@ -3,8 +3,8 @@ "version": 20002, "index": { "name": "/index-v2.json", - "sha256": "7117ee6ff4ff2dd71ec3f3d3ad2ef7e9fd4afead9b1f2d39d0b224a1812e78b5", - "size": 53233, + "sha256": "b613858aa7a2ec476fcef5c841a5b8ff4b3b0f67f07678da981e2843f49c71ba", + "size": 53283, "numPackages": 10 }, "diffs": {} diff --git a/tests/repo/index-v2.json b/tests/repo/index-v2.json index 6ea92407..f45c1514 100644 --- a/tests/repo/index-v2.json +++ b/tests/repo/index-v2.json @@ -533,7 +533,10 @@ "name": { "en-US": "System" } - } + }, + "1": {}, + "2.0": {}, + "tests": {} }, "requests": { "install": [ @@ -1443,4 +1446,4 @@ } } } -} +} \ No newline at end of file diff --git a/tests/update.TestCase b/tests/update.TestCase index 391dec93..e859e04f 100755 --- a/tests/update.TestCase +++ b/tests/update.TestCase @@ -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__))