mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 21:34:08 -07:00
It doesn't properly handle mixins / special templates
On python 3.8+, XML elements are no longer sorted and this fails
validation against entity.rng
mixins are not properly applied because the | split is incorrect (3
max items instead of 2)
merge="" is not supported
Parents aren't always passed when they should be.
on windows it is incorrectly assumed that the encoding is 1252
Patch by: @baco
Tweaks by: @Stan
Based on a patch by: @wraitii
Differential Revision: https://code.wildfiregames.com/D4698
This was SVN commit r27161.
116 lines
4.1 KiB
Python
116 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
import argparse
|
|
import logging
|
|
from pathlib import Path
|
|
import shutil
|
|
from subprocess import run, CalledProcessError
|
|
import sys
|
|
from typing import Sequence
|
|
|
|
from xml.etree import ElementTree
|
|
|
|
from scriptlib import SimulTemplateEntity, find_files
|
|
|
|
SIMUL_TEMPLATES_PATH = Path("simulation/templates")
|
|
ENTITY_RELAXNG_FNAME = "entity.rng"
|
|
RELAXNG_SCHEMA_ERROR_MSG = """Relax NG schema non existant.
|
|
Please create the file: {}
|
|
You can do that by running 'pyrogenesis -dumpSchema' in the 'system' directory
|
|
"""
|
|
XMLLINT_ERROR_MSG = ("xmllint not found in your PATH, please install it "
|
|
"(usually in libxml2 package)")
|
|
|
|
class SingleLevelFilter(logging.Filter):
|
|
def __init__(self, passlevel, reject):
|
|
self.passlevel = passlevel
|
|
self.reject = reject
|
|
|
|
def filter(self, record):
|
|
if self.reject:
|
|
return (record.levelno != self.passlevel)
|
|
else:
|
|
return (record.levelno == self.passlevel)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
logger.setLevel(logging.INFO)
|
|
# create a console handler, seems nicer to Windows and for future uses
|
|
ch = logging.StreamHandler(sys.stdout)
|
|
ch.setLevel(logging.INFO)
|
|
ch.setFormatter(logging.Formatter('%(levelname)s - %(message)s'))
|
|
f1 = SingleLevelFilter(logging.INFO, False)
|
|
ch.addFilter(f1)
|
|
logger.addHandler(ch)
|
|
errorch =logging. StreamHandler(sys.stderr)
|
|
errorch.setLevel(logging.WARNING)
|
|
errorch.setFormatter(logging.Formatter('%(levelname)s - %(message)s'))
|
|
logger.addHandler(errorch)
|
|
|
|
def main(argv: Sequence[str] | None = None) -> int:
|
|
parser = argparse.ArgumentParser(description="Validate templates")
|
|
parser.add_argument("-m", "--mod-name", required=True,
|
|
help="The name of the mod to validate.")
|
|
parser.add_argument("-r", "--root", dest="vfs_root", default=Path(),
|
|
type=Path, help="The path to mod's root location.")
|
|
parser.add_argument("-s", "--relaxng-schema",
|
|
default=Path() / ENTITY_RELAXNG_FNAME, type=Path,
|
|
help="The path to mod's root location.")
|
|
parser.add_argument("-t", "--templates", nargs="*",
|
|
help="Optionally, a list of templates to validate.")
|
|
parser.add_argument("-v", "--verbose",
|
|
help="Be verbose about the output.", default=False)
|
|
|
|
args = parser.parse_args(argv)
|
|
|
|
if not args.relaxng_schema.exists():
|
|
logging.error(RELAXNG_SCHEMA_ERROR_MSG.format(args.relaxng_schema))
|
|
return 1
|
|
|
|
if not shutil.which("xmllint"):
|
|
logging.error(XMLLINT_ERROR_MSG)
|
|
return 2
|
|
|
|
if args.templates:
|
|
templates = sorted([(Path(t), None) for t in args.templates])
|
|
else:
|
|
templates = sorted(find_files(args.vfs_root, [args.mod_name],
|
|
SIMUL_TEMPLATES_PATH.as_posix(), "xml"))
|
|
|
|
simul_template_entity = SimulTemplateEntity(args.vfs_root, logger)
|
|
count, failed = 0, 0
|
|
for fp, _ in templates:
|
|
if fp.stem.startswith("template_"):
|
|
continue
|
|
|
|
path = fp.as_posix()
|
|
if (path.startswith(f"{SIMUL_TEMPLATES_PATH.as_posix()}/mixins/")
|
|
or path.startswith(
|
|
f"{SIMUL_TEMPLATES_PATH.as_posix()}/special/")):
|
|
continue
|
|
|
|
if (args.verbose):
|
|
logger.info(f"Parsing {fp}...")
|
|
count += 1
|
|
entity = simul_template_entity.load_inherited(
|
|
SIMUL_TEMPLATES_PATH,
|
|
str(fp.relative_to(SIMUL_TEMPLATES_PATH)),
|
|
[args.mod_name]
|
|
)
|
|
xmlcontent = ElementTree.tostring(entity, encoding="unicode")
|
|
try:
|
|
run(["xmllint", "--relaxng",
|
|
str(args.relaxng_schema.resolve()), "-"],
|
|
input=xmlcontent, encoding="utf-8", capture_output=True, text=True, check=True)
|
|
except CalledProcessError as e:
|
|
failed += 1
|
|
if (e.stderr):
|
|
logger.error(e.stderr)
|
|
if (e.stdout):
|
|
logger.info(e.stdout)
|
|
|
|
logger.info(f"Total: {count}; failed: {failed}")
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|