0ad/source/tools/xmlvalidator/validator.py
vladislavbelov c5deda556c Adds a skip for invalid files in the validator
Reviewed By: Itms
Differential Revision: https://code.wildfiregames.com/D1140
This was SVN commit r20648.
2017-12-12 20:23:26 +00:00

157 lines
6.2 KiB
Python

#!/usr/bin/env python
import argparse
import os
import re
import sys
import time
import xml.etree.ElementTree
class Actor:
def __init__(self, mod_name, vfs_path):
self.mod_name = mod_name
self.vfs_path = vfs_path
self.name = os.path.basename(vfs_path)
self.textures = []
self.material = ''
def read(self, physical_path):
try:
tree = xml.etree.ElementTree.parse(physical_path)
except xml.etree.ElementTree.ParseError as err:
sys.stderr.write('Error in "%s": %s\n' % (physical_path, err.msg))
return False
root = tree.getroot()
for element in root.findall('.//material'):
self.material = element.text
for element in root.findall('.//texture'):
self.textures.append(element.get('name'))
return True
class Material:
def __init__(self, mod_name, vfs_path):
self.mod_name = mod_name
self.vfs_path = vfs_path
self.name = os.path.basename(vfs_path)
self.required_textures = []
def read(self, physical_path):
try:
root = xml.etree.ElementTree.parse(physical_path).getroot()
except xml.etree.ElementTree.ParseError as err:
sys.stderr.write('Error in "%s": %s\n' % (physical_path, err.msg))
return False
for element in root.findall('.//required_texture'):
texture_name = element.get('name')
self.required_textures.append(texture_name)
return True
class Validator:
def __init__(self, vfs_root, mods=None):
if mods is None:
mods = ['mod', 'public']
self.vfs_root = vfs_root
self.mods = mods
self.materials = {}
self.invalid_materials = {}
self.actors = []
def get_physical_path(self, mod_name, vfs_path):
return os.path.realpath(os.path.join(self.vfs_root, mod_name, vfs_path))
def find_mod_files(self, mod_name, vfs_path, pattern):
physical_path = self.get_physical_path(mod_name, vfs_path)
result = []
if not os.path.isdir(physical_path):
return result
for file_name in os.listdir(physical_path):
if file_name == '.git' or file_name == '.svn':
continue
vfs_file_path = os.path.join(vfs_path, file_name)
physical_file_path = os.path.join(physical_path, file_name)
if os.path.isdir(physical_file_path):
result += self.find_mod_files(mod_name, vfs_file_path, pattern)
elif os.path.isfile(physical_file_path) and pattern.match(file_name):
result.append({
'mod_name': mod_name,
'vfs_path': vfs_file_path
})
return result
def find_all_mods_files(self, vfs_path, pattern):
result = []
for mod_name in reversed(self.mods):
result += self.find_mod_files(mod_name, vfs_path, pattern)
return result
def find_materials(self, vfs_path):
material_files = self.find_all_mods_files(vfs_path, re.compile(r'.*\.xml'))
for material_file in material_files:
material_name = os.path.basename(material_file['vfs_path'])
if material_name in self.materials:
continue
material = Material(material_file['mod_name'], material_file['vfs_path'])
if material.read(self.get_physical_path(material_file['mod_name'], material_file['vfs_path'])):
self.materials[material_name] = material
else:
self.invalid_materials[material_name] = material
def find_actors(self, vfs_path):
actor_files = self.find_all_mods_files(vfs_path, re.compile(r'.*\.xml'))
for actor_file in actor_files:
actor = Actor(actor_file['mod_name'], actor_file['vfs_path'])
if actor.read(self.get_physical_path(actor_file['mod_name'], actor_file['vfs_path'])):
self.actors.append(actor)
def run(self):
start_time = time.time()
sys.stdout.write('Collecting list of files to check\n')
self.find_materials(os.path.join('art', 'materials'))
self.find_actors(os.path.join('art', 'actors'))
for actor in self.actors:
if not actor.material:
continue
if actor.material not in self.materials and actor.material not in self.invalid_materials:
sys.stderr.write('Error in "%s": unknown material "%s"' % (
self.get_physical_path(actor.mod_name, actor.vfs_path),
actor.material
))
if actor.material not in self.materials:
continue
material = self.materials[actor.material]
for required_texture in material.required_textures:
if required_texture in actor.textures:
continue
sys.stderr.write('Error in "%s": actor does not contain required texture "%s" from "%s"\n' % (
self.get_physical_path(actor.mod_name, actor.vfs_path),
required_texture,
material.name
))
for texture in actor.textures:
if texture in material.required_textures:
continue
sys.stderr.write('Warning in "%s": actor contains unnecessary texture "%s" from "%s"\n' % (
self.get_physical_path(actor.mod_name, actor.vfs_path),
texture,
material.name
))
finish_time = time.time()
sys.stdout.write('Total execution time: %.3f seconds.\n' % (finish_time - start_time))
if __name__ == '__main__':
script_dir = os.path.dirname(os.path.realpath(__file__))
default_root = os.path.join(script_dir, '..', '..', '..', 'binaries', 'data', 'mods')
parser = argparse.ArgumentParser(description='Actors/materials validator.')
parser.add_argument('-r', '--root', action='store', dest='root', default=default_root)
parser.add_argument('-m', '--mods', action='store', dest='mods', default='mod,public')
args = parser.parse_args()
validator = Validator(args.root, args.mods.split(','))
validator.run()