diff --git a/_validate/createJson.py b/_validate/createJson.py index 9b8163c..d81f4ed 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -60,7 +60,7 @@ def generateJsonFile( licenseName: str, licenseUrl: str | None, ) -> None: - data = _createDataclassMatchingJsonSchema( + data = createDataclassMatchingJsonSchema( manifest=manifest, sha=getSha256(addonPath), channel=channel, @@ -99,7 +99,7 @@ def buildOutputFilePath(data: AddonData, parentDir: str) -> os.PathLike[str]: return cast(os.PathLike[str], filePath) -def _createDataclassMatchingJsonSchema( +def createDataclassMatchingJsonSchema( manifest: AddonManifest, sha: str, channel: str, diff --git a/_validate/regenerateJson.py b/_validate/regenerateJson.py new file mode 100644 index 0000000..d8395bf --- /dev/null +++ b/_validate/regenerateJson.py @@ -0,0 +1,81 @@ +# Copyright (C) 2023-2026 NV Access Limited, Noelia Ruiz Martínez +# This file may be used under the terms of the GNU General Public License, version 2 or later. +# For more details see: https://www.gnu.org/licenses/gpl-2.0.html + +import argparse +import glob +import json +from urllib.request import urlretrieve +from dataclasses import asdict + +from .manifestLoader import getAddonManifest +from .validate import checkSha256 +from .createJson import createDataclassMatchingJsonSchema + + +def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: + with open(filePath, encoding="utf-8") as f: + addonData = json.load(f) + if addonData.get("legacy"): + return + addonFilePath, _ = urlretrieve(addonData["URL"]) + addonSha = addonData["sha256"] + checksumErrors = list(checkSha256(addonFilePath, addonSha)) + if checksumErrors: + if errorFilePath: + with open(errorFilePath, "a") as errorFile: + errorFile.write(f"Validation errors:\n{'\n'.join(checksumErrors)}") + return + manifest = getAddonManifest(addonFilePath) + if manifest.errors: + if errorFilePath: + with open(errorFilePath, "a") as errorFile: + errorFile.write(f"Validation Errors:\n{manifest.errors}") + return + regeneratedData = createDataclassMatchingJsonSchema( + manifest, + addonSha, + addonData["channel"], + addonData["publisher"], + addonData["sourceURL"], + addonData["URL"], + addonData["license"], + addonData["licenseURL"], + ) + submissionTime = addonData.get("submissionTime") + regeneratedAddonData = asdict( + regeneratedData, + # The JSON schema does not permit null values, but does contain optional keys. + # We have already ensured that all required keys are present in the metadata, + # So we can safely delete all keys whose value is None as optional. + dict_factory=lambda args: dict(filter(lambda item: item[1] is not None, args)), + ) + if submissionTime: + regeneratedAddonData["submissionTime"] = submissionTime + with open(filePath, "wt", encoding="utf-8") as f: + json.dump(regeneratedAddonData, f, indent="\t", ensure_ascii=False) + print(f"Wrote json file: {filePath}") + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--dir", + dest="parentDir", + help="Parent directory to regenerate the JSON files inside.", + required=True, + ) + parser.add_argument( + "--output", + dest="errorOutputFile", + help="The text file to output errors from the validation, if any.", + default=None, + ) + args = parser.parse_args() + errorFilePath: str | None = args.errorOutputFile + for addonJsonFile in glob.glob(f"{args.parentDir}/**/*.json"): + regenerateJsonFile(addonJsonFile, errorFilePath) + + +if __name__ == "__main__": + main() diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py deleted file mode 100644 index 0998672..0000000 --- a/_validate/regenerateTranslations.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (C) 2023-2025 NV Access Limited -# This file may be used under the terms of the GNU General Public License, version 2 or later. -# For more details see: https://www.gnu.org/licenses/gpl-2.0.html - -import argparse -import glob -import json -from urllib.request import urlretrieve -from typing import cast - -from .manifestLoader import getAddonManifest, getAddonManifestLocalizations -from .validate import parseConfigValue - - -def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: - with open(filePath, encoding="utf-8") as f: - addonData = json.load(f) - if addonData.get("legacy"): - return - addonData["translations"] = [] - addonFilePath, _ = urlretrieve(addonData["URL"]) - manifest = getAddonManifest(addonFilePath) - if manifest.errors: - if errorFilePath: - with open(errorFilePath, "w") as errorFile: - errorFile.write(f"Validation Errors:\n{manifest.errors}") - return - for langCode, manifest in getAddonManifestLocalizations(manifest): - translatedChangelog: str | None = parseConfigValue(manifest, "changelog") - translation: dict[str, str] = { - "language": langCode, - "displayName": cast(str, manifest["summary"]), - "description": cast(str, manifest["description"]), - } - if translatedChangelog is not None: - translation["changelog"] = translatedChangelog - addonData["translations"].append(translation) - - with open(filePath, "wt", encoding="utf-8") as f: - json.dump(addonData, f, indent="\t", ensure_ascii=False) - print(f"Wrote json file: {filePath}") - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument( - "--dir", - dest="parentDir", - help="Parent directory to regenerate the JSON files inside.", - required=True, - ) - parser.add_argument( - "--output", - dest="errorOutputFile", - help="The text file to output errors from the validation, if any.", - default=None, - ) - args = parser.parse_args() - errorFilePath: str | None = args.errorOutputFile - for addonJsonFile in glob.glob(f"{args.parentDir}/**/*.json"): - regenerateJsonFile(addonJsonFile, errorFilePath) - - -if __name__ == "__main__": - main() diff --git a/regenerateTranslations.bat b/regenerateJson.bat similarity index 74% rename from regenerateTranslations.bat rename to regenerateJson.bat index eefd38b..e4804b8 100644 --- a/regenerateTranslations.bat +++ b/regenerateJson.bat @@ -7,4 +7,4 @@ set unitTestsPath=%here%\tests set testOutput=%here%\testOutput md %testOutput% -call uv run --directory "%here%" python -m _validate.regenerateTranslations %* +call uv run --directory "%here%" python -m _validate.regenerateJson %*