mirror of
https://github.com/kiwix/kiwix-apple-custom.git
synced 2025-09-22 03:40:45 -04:00
Merge pull request #21 from kiwix/feature/cd-per-brand-p3
Update tag/version number validation
This commit is contained in:
commit
44809e4631
@ -3,7 +3,7 @@
|
||||
"about_text": "Für Schreibende, Lernende, Lehrende und Sprachinteressierte: Das Digitale Wörterbuch der deutschen Sprache (DWDS) ist das große Bedeutungswörterbuch des Deutschen der Gegenwart. Es bietet umfassende und wissenschaftlich verlässliche lexikalische Informationen, kostenlos und werbefrei.",
|
||||
"app_name": "DWDS",
|
||||
"app_store_id": "id6473090365",
|
||||
"build_version": 3,
|
||||
"build_number": 3,
|
||||
"enforced_lang": "de",
|
||||
"settings_default_external_link_to": "alwaysLoad",
|
||||
"settings_show_external_link_option": false,
|
||||
|
17
src/brand.py
17
src/brand.py
@ -1,22 +1,21 @@
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
INFO_JSON = 'info.json'
|
||||
|
||||
|
||||
class Brand:
|
||||
|
||||
|
||||
def __init__(self, name):
|
||||
if Path(name).is_dir() == False:
|
||||
self._exit_with_error(f"The directory of the brand: '{name}' does not exist")
|
||||
raise FileExistsError(
|
||||
f"The directory for brand: '{name}' does not exist")
|
||||
self.info_file = Path(name)/INFO_JSON
|
||||
if self.info_file.exists() == False:
|
||||
self._exit_with_error(f"There is no {INFO_JSON} file for brand {name}")
|
||||
raise FileExistsError(
|
||||
f"There is no {INFO_JSON} file for brand '{name}'")
|
||||
|
||||
self.name = name
|
||||
|
||||
|
||||
@staticmethod
|
||||
def all_info_files():
|
||||
return list(Path().rglob(INFO_JSON))
|
||||
|
||||
def _exit_with_error(self, msg):
|
||||
print(f"Error: {msg}")
|
||||
sys.exit(1)
|
||||
|
@ -7,8 +7,8 @@ INFO_JSON = 'info.json'
|
||||
|
||||
class CustomApps:
|
||||
|
||||
def __init__(self, brands=["all"], build_version=None):
|
||||
self.build_version = build_version
|
||||
def __init__(self, brands=["all"], build_number=None):
|
||||
self.build_number = build_number
|
||||
if brands == ["all"]:
|
||||
self.info_files = Brand.all_info_files()
|
||||
else:
|
||||
@ -28,7 +28,7 @@ class CustomApps:
|
||||
dict = {"include": ["project.yml"]}
|
||||
targets = {}
|
||||
for info in self.info_files:
|
||||
parser = InfoParser(info, build_version=self.build_version)
|
||||
parser = InfoParser(info, build_number=self.build_number)
|
||||
targets = targets | parser.as_project_yml()
|
||||
|
||||
dict["targets"] = targets
|
||||
@ -43,7 +43,7 @@ class CustomApps:
|
||||
it should be a copy from the Kiwix target
|
||||
"""
|
||||
for info in self.info_files:
|
||||
parser = InfoParser(info, build_version=self.build_version)
|
||||
parser = InfoParser(info, build_number=self.build_number)
|
||||
parser.create_plist(based_on_plist_file=custom_plist)
|
||||
|
||||
def download_zim_files(self):
|
||||
@ -60,7 +60,7 @@ class CustomApps:
|
||||
array: commands that can be feeded into subprocess.call()
|
||||
"""
|
||||
for info in self.info_files:
|
||||
parser = InfoParser(info, build_version=self.build_version)
|
||||
parser = InfoParser(info, build_number=self.build_number)
|
||||
url = parser.zimurl()
|
||||
file_path = parser.zim_file_path()
|
||||
auth = parser.download_auth()
|
||||
|
@ -19,17 +19,17 @@ def main():
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"build_version",
|
||||
"build_number",
|
||||
nargs='?',
|
||||
default=None,
|
||||
help="The optional build version to use, if not provided will fall back to the build_version defined in the info.json value",
|
||||
help="The optional build version to use, if not provided will fall back to the build_number defined in the info.json value",
|
||||
type=int
|
||||
)
|
||||
args = parser.parse_args()
|
||||
brand = args.brand_name
|
||||
build_version = args.build_version
|
||||
build_number = args.build_number
|
||||
|
||||
custom_apps = CustomApps(brands=[brand], build_version=build_version)
|
||||
custom_apps = CustomApps(brands=[brand], build_number=build_number)
|
||||
# create the plist files
|
||||
custom_apps.create_plists(custom_plist=Path("Custom.plist"))
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
from urllib.parse import urlparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
from version import Version
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import plistlib
|
||||
|
||||
@ -23,20 +23,22 @@ JSON_TO_PLIST_MAPPING = {
|
||||
|
||||
class InfoParser:
|
||||
|
||||
def __init__(self, json_path, build_version=None):
|
||||
def __init__(self, json_path, build_number=None):
|
||||
"""Parse a specific info.json file for a brand
|
||||
|
||||
Args:
|
||||
json_path (Path): of the branded info.json file
|
||||
build_number (int, optional): If defined it will be used instead of the info.json[build_version]. Defaults to None.
|
||||
build_number (int, optional): If defined it will be used instead of the info.json[build_number]. Defaults to None.
|
||||
"""
|
||||
self.brand_name = self._brandname_from(json_path)
|
||||
self.build_version = build_version
|
||||
content = json_path.read_text()
|
||||
self.data = json.loads(content)
|
||||
assert (JSON_KEY_ZIM_URL in self.data)
|
||||
self.zim_file_name = self._filename_from(
|
||||
self.data[JSON_KEY_ZIM_URL])
|
||||
build_number = build_number or self.data["build_number"]
|
||||
self.version = Version.from_file_name(file_name=self.zim_file_name,
|
||||
build_number=build_number)
|
||||
|
||||
def create_plist(self, based_on_plist_file):
|
||||
with based_on_plist_file.open(mode="rb") as file:
|
||||
@ -54,7 +56,7 @@ class InfoParser:
|
||||
dict = {
|
||||
"templates": ["ApplicationTemplate"],
|
||||
"settings": {"base": {
|
||||
"MARKETING_VERSION": self._app_version(),
|
||||
"MARKETING_VERSION": self.version.semantic,
|
||||
"PRODUCT_BUNDLE_IDENTIFIER": f"org.kiwix.custom.{self.brand_name}",
|
||||
"INFOPLIST_FILE": f"custom/{self._info_plist_path()}",
|
||||
"INFOPLIST_KEY_CFBundleDisplayName": self._app_name(),
|
||||
@ -104,10 +106,6 @@ class InfoParser:
|
||||
value = self.data[json_key]
|
||||
yield {plistKey: value}
|
||||
|
||||
def _app_version(self):
|
||||
build_version = self.build_version or self.data["build_version"]
|
||||
return f"{self._app_version_from(self.zim_file_name)}.{build_version}"
|
||||
|
||||
def _app_name(self):
|
||||
return self.data[JSON_KEY_APP_NAME]
|
||||
|
||||
@ -130,18 +128,6 @@ class InfoParser:
|
||||
def _filename_from(self, url):
|
||||
return Path(urlparse(url).path).stem
|
||||
|
||||
def _app_version_from(self, file_name):
|
||||
p = re.compile('(?P<year>\d{4})-(?P<month>\d{1,2})')
|
||||
m = p.search(file_name)
|
||||
year = int(m.group('year'))
|
||||
month = int(m.group('month'))
|
||||
assert (year > 2000)
|
||||
assert (month > 0)
|
||||
assert (month <= 12)
|
||||
# downgrade the version by 1000 for testing the release
|
||||
year -= 1000
|
||||
return ".".join([str(year), str(month)])
|
||||
|
||||
def _excluded_languages(self):
|
||||
enforced = self._enforced_language()
|
||||
if enforced == None:
|
||||
|
@ -4,20 +4,42 @@ import argparse
|
||||
import re
|
||||
import sys
|
||||
from brand import Brand
|
||||
from version import Version
|
||||
from info_parser import InfoParser
|
||||
|
||||
|
||||
def _is_valid(tag):
|
||||
# Regex verify the tag format
|
||||
# Regex verify the tag format: folder_YYYY.MM.buildNr(_extra)
|
||||
pattern = re.compile(
|
||||
r'^(?P<brand_folder>\w+)_(?P<build_nr>\d+)(?:_(?P<extra_tag>\w+))?$')
|
||||
r'^(?P<brand_name>\w+)_(?P<year>\d{4})\.(?P<month>\d{1,2})\.(?P<build_number>\d+)(?:_(?P<extra_tag>\w+))?$'
|
||||
)
|
||||
match = pattern.match(tag)
|
||||
|
||||
if match:
|
||||
groups = match.groupdict()
|
||||
brand_name = groups.get('brand_folder')
|
||||
build_nr = int(groups.get('build_nr'))
|
||||
brand = Brand(brand_name)
|
||||
print(f"{brand.name} {build_nr}")
|
||||
brand_name = groups.get('brand_name')
|
||||
year = int(groups.get('year'))
|
||||
month = int(groups.get('month'))
|
||||
build_number = int(groups.get('build_number'))
|
||||
|
||||
try:
|
||||
brand = Brand(brand_name)
|
||||
except FileExistsError as e:
|
||||
_exit_with_error(f"Invalid tag {tag}: {e}")
|
||||
|
||||
try:
|
||||
version = Version(
|
||||
year=year, month=month, build_number=build_number
|
||||
)
|
||||
except ValueError as e:
|
||||
_exit_with_error(f"Invalid tag {tag}: {e}")
|
||||
|
||||
parser = InfoParser(json_path=brand.info_file, build_number=version.build_number)
|
||||
if parser.version != version:
|
||||
_exit_with_error(f"Ivalid date in tag: {tag}, does not match year.month of ZIM file in {brand.info_file}, it should be: {parser.version.semantic}")
|
||||
|
||||
print(f"{brand.name} {version.semantic_downgraded}")
|
||||
|
||||
else:
|
||||
_exit_with_error(f"Invalid tag: {tag}")
|
||||
return False
|
||||
|
31
src/version.py
Normal file
31
src/version.py
Normal file
@ -0,0 +1,31 @@
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class Version:
|
||||
|
||||
def __init__(self, year: int, month: int, build_number: int):
|
||||
if (1 <= month <= 12) == False:
|
||||
raise ValueError(f"invalid month: {month}")
|
||||
if (0 <= build_number) == False:
|
||||
raise ValueError(f"invalid build number: {build_number}")
|
||||
max_year = datetime.now().year + 5
|
||||
if (2000 < year < max_year) == False:
|
||||
raise ValueError(f"invalid year: {year}")
|
||||
|
||||
self.semantic = f"{year}.{month}.{build_number}"
|
||||
self.semantic_downgraded = f"{year-1000}.{month}.{build_number}"
|
||||
self.build_number = build_number
|
||||
|
||||
@classmethod
|
||||
def from_file_name(self, file_name: str, build_number: int):
|
||||
p = re.compile('(?P<year>\d{4})-(?P<month>\d{1,2})')
|
||||
m = p.search(file_name)
|
||||
return Version(year=int(m.group('year')),
|
||||
month=int(m.group('month')),
|
||||
build_number=build_number)
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
if isinstance(other, Version):
|
||||
return self.semantic == other.semantic
|
||||
return False
|
@ -8,7 +8,7 @@ import os
|
||||
class InfoParserTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.parser = InfoParser(Path()/"tests"/"test.json")
|
||||
self.parser = InfoParser(Path("tests")/"test.json")
|
||||
|
||||
def test_json_to_project_yml(self):
|
||||
project = self.parser.as_project_yml()
|
||||
@ -17,7 +17,7 @@ class InfoParserTest(unittest.TestCase):
|
||||
|
||||
def test_info_plist_path(self):
|
||||
custom_info = self.parser._info_plist_path()
|
||||
self.assertEqual(custom_info, Path()/"tests"/"tests.plist")
|
||||
self.assertEqual(custom_info, Path("tests")/"tests.plist")
|
||||
|
||||
def test_file_name_from_url(self):
|
||||
url = "https://www.dwds.de/kiwix/f/dwds_de_dictionary_nopic_2023-11-20.zim"
|
||||
@ -33,23 +33,6 @@ class InfoParserTest(unittest.TestCase):
|
||||
brand_name = self.parser._brandname_from(filepath)
|
||||
self.assertEqual(brand_name, "dwds")
|
||||
|
||||
def test_version_from_filename(self):
|
||||
version = self.parser._app_version_from(
|
||||
"dwds_de_dictionary_nopic_2023-11-20")
|
||||
self.assertEqual(version, "1023.11")
|
||||
|
||||
version = self.parser._app_version_from(
|
||||
"dwds_de_dictionary_nopic_2023-09-20")
|
||||
self.assertEqual(version, "1023.9")
|
||||
|
||||
version = self.parser._app_version_from(
|
||||
"dwds_de_dictionary_nopic_2023-01")
|
||||
self.assertEqual(version, "1023.1")
|
||||
|
||||
version = self.parser._app_version_from(
|
||||
"dwds_de_dictionary_nopic_2023-12")
|
||||
self.assertEqual(version, "1023.12")
|
||||
|
||||
def test_app_name(self):
|
||||
app_name = self.parser._app_name()
|
||||
self.assertEqual(app_name, "DWDS")
|
||||
@ -62,15 +45,18 @@ class InfoParserTest(unittest.TestCase):
|
||||
excluded = self.parser._excluded_languages()
|
||||
self.assertIn("**/*.lproj", excluded)
|
||||
|
||||
def test_app_version(self):
|
||||
self.assertEqual(self.parser._app_version(), "1023.12.3")
|
||||
def test_app_version_with_default_json_build_number(self):
|
||||
self.assertEqual(self.parser.version.semantic, "2023.12.3")
|
||||
self.assertEqual(self.parser.version.semantic_downgraded, "1023.12.3")
|
||||
|
||||
def test_app_version_using_a_tag(self):
|
||||
parser = InfoParser(Path()/"tests"/"test.json", build_version=15)
|
||||
self.assertEqual(parser._app_version(), "1023.12.15")
|
||||
def test_app_version_using_a_specific_build_number(self):
|
||||
parser = InfoParser(Path("tests")/"test.json", build_number=15)
|
||||
self.assertEqual(parser.version.semantic, "2023.12.15")
|
||||
self.assertEqual(parser.version.semantic_downgraded, "1023.12.15")
|
||||
|
||||
parser = InfoParser(Path()/"tests"/"test.json", build_version=33)
|
||||
self.assertEqual(parser._app_version(), "1023.12.33")
|
||||
parser = InfoParser(Path("tests")/"test.json", build_number=33)
|
||||
self.assertEqual(parser.version.semantic, "2023.12.33")
|
||||
self.assertEqual(parser.version.semantic_downgraded, "1023.12.33")
|
||||
|
||||
def test_as_plist(self):
|
||||
self.parser.create_plist(
|
||||
|
@ -9,5 +9,5 @@
|
||||
"settings_show_external_link_option": false,
|
||||
"zim_auth": "DWDS_HTTP_BASIC_ACCESS_AUTHENTICATION",
|
||||
"zim_url": "https://www.dwds.de/kiwix/f/dwds_de_dictionary_nopic_2023-12-15.zim",
|
||||
"build_version": 3
|
||||
"build_number": 3
|
||||
}
|
||||
|
26
tests/version_test.py
Normal file
26
tests/version_test.py
Normal file
@ -0,0 +1,26 @@
|
||||
import unittest
|
||||
from src.version import Version
|
||||
|
||||
|
||||
class VersionTest(unittest.TestCase):
|
||||
|
||||
def test_version_from_filename(self):
|
||||
version = Version.from_file_name(
|
||||
"dwds_de_dictionary_nopic_2023-11-20", build_number=10)
|
||||
self.assertEqual(version.semantic, "2023.11.10")
|
||||
self.assertEqual(version.semantic_downgraded, "1023.11.10")
|
||||
|
||||
version = Version.from_file_name(
|
||||
"dwds_de_dictionary_nopic_2023-09-20", build_number=0)
|
||||
self.assertEqual(version.semantic, "2023.9.0")
|
||||
self.assertEqual(version.semantic_downgraded, "1023.9.0")
|
||||
|
||||
version = Version.from_file_name(
|
||||
"dwds_de_dictionary_nopic_2023-01", build_number=7)
|
||||
self.assertEqual(version.semantic, "2023.1.7")
|
||||
self.assertEqual(version.semantic_downgraded, "1023.1.7")
|
||||
|
||||
version = Version.from_file_name(
|
||||
"dwds_de_dictionary_nopic_2023-12", build_number=129)
|
||||
self.assertEqual(version.semantic, "2023.12.129")
|
||||
self.assertEqual(version.semantic_downgraded, "1023.12.129")
|
Loading…
x
Reference in New Issue
Block a user