diff --git a/fdroidserver/metadata.py b/fdroidserver/metadata.py index 4b62878e..869253c7 100644 --- a/fdroidserver/metadata.py +++ b/fdroidserver/metadata.py @@ -1049,6 +1049,7 @@ def _format_stringmap(appid, field, stringmap, versionCode=None): try: next(app_dir.glob('*/%s/*.txt' % field.lower())) files = [] + overwrites = [] for name, descdict in stringmap.items(): for locale, desc in descdict.items(): outdir = app_dir / locale / field.lower() @@ -1058,8 +1059,21 @@ def _format_stringmap(appid, field, stringmap, versionCode=None): filename = '%s.txt' % name outfile = outdir / filename files.append(str(outfile)) - with outfile.open('w') as fp: - fp.write(desc) + if outfile.exists(): + if desc != outfile.read_text(): + overwrites.append(str(outfile)) + else: + if not outfile.parent.exists(): + outfile.parent.mkdir(parents=True) + outfile.write_text(desc) + if overwrites: + _warn_or_exception( + _( + 'Conflicting "{field}" definitions between .yml and localized files:' + ).format(field=field) + + '\n' + + '\n'.join(sorted(overwrites)) + ) logging.warning( _('Moving Anti-Features declarations to localized files:') + '\n' diff --git a/tests/metadata.TestCase b/tests/metadata.TestCase index fb17c6df..59c2bafe 100755 --- a/tests/metadata.TestCase +++ b/tests/metadata.TestCase @@ -1858,6 +1858,55 @@ class MetadataTest(unittest.TestCase): {'AF': {'ko': 'b', 'uz': 'a', 'zh': 'c'}}, ) + def test_format_stringmap_app_antifeatures_conflict(self): + """Raise an error if a YAML Anti-Feature conflicts with a localized file.""" + os.chdir(self.testdir) + appid = 'a' + field = 'AntiFeatures' + locale = 'ko' + yml = Path('metadata/a.yml') + antifeatures_ko = yml.parent / appid / locale / field.lower() + antifeatures_ko.mkdir(parents=True) + afname = 'Anti-🔥' + (antifeatures_ko / (afname + '.txt')).write_text('SOMETHING ELSE') + with self.assertRaises(MetaDataException): + metadata._format_stringmap( + appid, field, {afname: {'uz': 'a', locale: 'b', 'zh': 'c'}} + ) + + def test_format_stringmap_app_antifeatures_conflict_same_contents(self): + """Raise an error if a YAML Anti-Feature conflicts with a localized file.""" + os.chdir(self.testdir) + appid = 'a' + field = 'AntiFeatures' + locale = 'ko' + yml = Path('metadata/a.yml') + antifeatures_ko = yml.parent / appid / locale / field.lower() + antifeatures_ko.mkdir(parents=True) + afname = 'Anti-🔥' + (antifeatures_ko / (afname + '.txt')).write_text('b') + metadata._format_stringmap( + appid, field, {afname: {'uz': 'a', locale: 'b', 'zh': 'c'}} + ) + + def test_format_stringmap_build_antifeatures_conflict(self): + """Raise an error if a YAML Anti-Feature conflicts with a localized file.""" + os.chdir(self.testdir) + appid = 'a' + field = 'antifeatures' + locale = 'ko' + versionCode = 123 + yml = Path('metadata/a.yml') + antifeatures_ko = yml.parent / appid / locale / field.lower() + antifeatures_ko.mkdir(parents=True) + afname = 'Anti-🔥' + with (antifeatures_ko / ('%d_%s.txt' % (versionCode, afname))).open('w') as fp: + fp.write('SOMETHING ELSE') + with self.assertRaises(MetaDataException): + metadata._format_stringmap( + appid, field, {afname: {'uz': 'a', locale: 'b', 'zh': 'c'}}, versionCode + ) + class PostMetadataParseTest(unittest.TestCase): """Test the functions that post process the YAML input.