1
0
forked from 0ad/0ad

Replace use of os.path with pathlib

This commit is contained in:
Dunedan 2024-08-25 17:08:09 +02:00
parent 4b77d7bb74
commit 75949e1f5a
Signed by untrusted user: Dunedan
GPG Key ID: 885B16854284E0B2

View File

@ -5,9 +5,9 @@ from argparse import ArgumentParser
from io import BytesIO from io import BytesIO
from json import load, loads from json import load, loads
from logging import INFO, WARNING, Filter, Formatter, StreamHandler, getLogger from logging import INFO, WARNING, Filter, Formatter, StreamHandler, getLogger
from os.path import basename, exists, sep
from pathlib import Path from pathlib import Path
from struct import calcsize, unpack from struct import calcsize, unpack
from typing import List, Tuple
from xml.etree import ElementTree as ET from xml.etree import ElementTree as ET
from scriptlib import SimulTemplateEntity, find_files from scriptlib import SimulTemplateEntity, find_files
@ -26,12 +26,9 @@ class SingleLevelFilter(Filter):
class CheckRefs: class CheckRefs:
def __init__(self): def __init__(self):
# list of relative root file:str self.files: List[Path] = []
self.files = [] self.roots: List[Path] = []
# list of relative file:str self.deps: List[Tuple[Path, Path]] = []
self.roots = []
# list of tuple (parent_file:str, dep_file:str)
self.deps = []
self.vfs_root = Path(__file__).resolve().parents[3] / "binaries" / "data" / "mods" self.vfs_root = Path(__file__).resolve().parents[3] / "binaries" / "data" / "mods"
self.supportedTextureFormats = ("dds", "png") self.supportedTextureFormats = ("dds", "png")
self.supportedMeshesFormats = ("pmd", "dae") self.supportedMeshesFormats = ("pmd", "dae")
@ -151,7 +148,7 @@ class CheckRefs:
modjsondeps = [] modjsondeps = []
for mod in mods: for mod in mods:
mod_json_path = self.vfs_root / mod / "mod.json" mod_json_path = self.vfs_root / mod / "mod.json"
if not exists(mod_json_path): if not mod_json_path.exists():
self.logger.warning('Failed to find the mod.json for "%s"', mod) self.logger.warning('Failed to find the mod.json for "%s"', mod)
continue continue
@ -185,8 +182,8 @@ class CheckRefs:
actor_prefix = "actor|" actor_prefix = "actor|"
resource_prefix = "resource|" resource_prefix = "resource|"
for fp, ffp in sorted(mapfiles): for fp, ffp in sorted(mapfiles):
self.files.append(str(fp)) self.files.append(fp)
self.roots.append(str(fp)) self.roots.append(fp)
et_map = ET.parse(ffp).getroot() et_map = ET.parse(ffp).getroot()
entities = et_map.find("Entities") entities = et_map.find("Entities")
used = ( used = (
@ -196,18 +193,18 @@ class CheckRefs:
) )
for template in used: for template in used:
if template.startswith(actor_prefix): if template.startswith(actor_prefix):
self.deps.append((str(fp), f"art/actors/{template[len(actor_prefix):]}")) self.deps.append((fp, Path(f"art/actors/{template[len(actor_prefix) :]}")))
elif template.startswith(resource_prefix): elif template.startswith(resource_prefix):
self.deps.append( self.deps.append(
(str(fp), f"simulation/templates/{template[len(resource_prefix):]}.xml") (fp, Path(f"simulation/templates/{template[len(resource_prefix):]}.xml"))
) )
else: else:
self.deps.append((str(fp), f"simulation/templates/{template}.xml")) self.deps.append((fp, Path(f"simulation/templates/{template}.xml")))
# Map previews # Map previews
settings = loads(et_map.find("ScriptSettings").text) settings = loads(et_map.find("ScriptSettings").text)
if settings.get("Preview"): if settings.get("Preview"):
self.deps.append( self.deps.append(
(str(fp), f'art/textures/ui/session/icons/mappreview/{settings["Preview"]}') (fp, Path(f"art/textures/ui/session/icons/mappreview/{settings['Preview']}"))
) )
def add_maps_pmp(self): def add_maps_pmp(self):
@ -230,8 +227,8 @@ class CheckRefs:
mapfiles = self.find_files("maps/scenarios", "pmp") mapfiles = self.find_files("maps/scenarios", "pmp")
mapfiles.extend(self.find_files("maps/skirmishes", "pmp")) mapfiles.extend(self.find_files("maps/skirmishes", "pmp"))
for fp, ffp in sorted(mapfiles): for fp, ffp in sorted(mapfiles):
self.files.append(str(fp)) self.files.append(fp)
self.roots.append(str(fp)) self.roots.append(fp)
with open(ffp, "rb") as f: with open(ffp, "rb") as f:
expected_header = b"PSMP" expected_header = b"PSMP"
header = f.read(len(expected_header)) header = f.read(len(expected_header))
@ -251,8 +248,12 @@ class CheckRefs:
terrain_name = f.read(length).decode("ascii") # suppose ascii encoding terrain_name = f.read(length).decode("ascii") # suppose ascii encoding
self.deps.append( self.deps.append(
( (
str(fp), fp,
terrains.get(terrain_name, f"art/terrains/(unknown)/{terrain_name}"), Path(
terrains.get(
terrain_name, f"art/terrains/(unknown)/{terrain_name}"
)
),
) )
) )
@ -274,9 +275,9 @@ class CheckRefs:
path_str = str(fp) path_str = str(fp)
if "phase" in path_str: if "phase" in path_str:
# Get the last part of the phase tech name. # Get the last part of the phase tech name.
if basename(path_str).split("_")[-1].split(".")[0] in existing_civs: if Path(path_str).stem.split("_")[-1] in existing_civs:
custom_phase_techs.append( custom_phase_techs.append(
str(fp.relative_to("simulation/data/technologies")).replace(sep, "/") fp.relative_to("simulation/data/technologies").as_posix()
) )
return custom_phase_techs return custom_phase_techs
@ -289,15 +290,15 @@ class CheckRefs:
simul_template_entity = SimulTemplateEntity(self.vfs_root, self.logger) simul_template_entity = SimulTemplateEntity(self.vfs_root, self.logger)
custom_phase_techs = self.get_custom_phase_techs() custom_phase_techs = self.get_custom_phase_techs()
for fp, _ in sorted(self.find_files(simul_templates_path, "xml")): for fp, _ in sorted(self.find_files(simul_templates_path, "xml")):
self.files.append(str(fp)) self.files.append(fp)
entity = simul_template_entity.load_inherited( entity = simul_template_entity.load_inherited(
simul_templates_path, str(fp.relative_to(simul_templates_path)), self.mods simul_templates_path, str(fp.relative_to(simul_templates_path)), self.mods
) )
if entity.get("parent"): if entity.get("parent"):
for parent in entity.get("parent").split("|"): for parent in entity.get("parent").split("|"):
self.deps.append((str(fp), str(simul_templates_path / (parent + ".xml")))) self.deps.append((fp, simul_templates_path / (parent + ".xml")))
if not str(fp).startswith("template_"): if not str(fp).startswith("template_"):
self.roots.append(str(fp)) self.roots.append(fp)
if ( if (
entity.find("VisualActor") is not None entity.find("VisualActor") is not None
and entity.find("VisualActor").find("Actor") is not None and entity.find("VisualActor").find("Actor") is not None
@ -315,13 +316,13 @@ class CheckRefs:
# See simulation2/components/CCmpVisualActor.cpp and Identity.js # See simulation2/components/CCmpVisualActor.cpp and Identity.js
# for explanation. # for explanation.
actor_path = actor.text.replace("{phenotype}", phenotype) actor_path = actor.text.replace("{phenotype}", phenotype)
self.deps.append((str(fp), f"art/actors/{actor_path}")) self.deps.append((fp, Path(f"art/actors/{actor_path}")))
else: else:
actor_path = actor.text actor_path = actor.text
self.deps.append((str(fp), f"art/actors/{actor_path}")) self.deps.append((fp, Path(f"art/actors/{actor_path}")))
foundation_actor = entity.find("VisualActor").find("FoundationActor") foundation_actor = entity.find("VisualActor").find("FoundationActor")
if foundation_actor is not None: if foundation_actor is not None:
self.deps.append((str(fp), f"art/actors/{foundation_actor.text}")) self.deps.append((fp, Path(f"art/actors/{foundation_actor.text}")))
if entity.find("Sound") is not None: if entity.find("Sound") is not None:
phenotype_tag = entity.find("Identity").find("Phenotype") phenotype_tag = entity.find("Identity").find("Phenotype")
phenotypes = ( phenotypes = (
@ -342,20 +343,20 @@ class CheckRefs:
sound_path = sound_group.text.replace( sound_path = sound_group.text.replace(
"{phenotype}", phenotype "{phenotype}", phenotype
).replace("{lang}", lang) ).replace("{lang}", lang)
self.deps.append((str(fp), f"audio/{sound_path}")) self.deps.append((fp, Path(f"audio/{sound_path}")))
else: else:
sound_path = sound_group.text.replace("{lang}", lang) sound_path = sound_group.text.replace("{lang}", lang)
self.deps.append((str(fp), f"audio/{sound_path}")) self.deps.append((fp, Path(f"audio/{sound_path}")))
if entity.find("Identity") is not None: if entity.find("Identity") is not None:
icon = entity.find("Identity").find("Icon") icon = entity.find("Identity").find("Icon")
if icon is not None and icon.text: if icon is not None and icon.text:
if entity.find("Formation") is not None: if entity.find("Formation") is not None:
self.deps.append( self.deps.append(
(str(fp), f"art/textures/ui/session/icons/{icon.text}") (fp, Path(f"art/textures/ui/session/icons/{icon.text}"))
) )
else: else:
self.deps.append( self.deps.append(
(str(fp), f"art/textures/ui/session/portraits/{icon.text}") (fp, Path(f"art/textures/ui/session/portraits/{icon.text}"))
) )
if ( if (
entity.find("Heal") is not None entity.find("Heal") is not None
@ -365,7 +366,7 @@ class CheckRefs:
for tag in ("LineTexture", "LineTextureMask"): for tag in ("LineTexture", "LineTextureMask"):
elem = range_overlay.find(tag) elem = range_overlay.find(tag)
if elem is not None and elem.text: if elem is not None and elem.text:
self.deps.append((str(fp), f"art/textures/selection/{elem.text}")) self.deps.append((fp, Path(f"art/textures/selection/{elem.text}")))
if ( if (
entity.find("Selectable") is not None entity.find("Selectable") is not None
and entity.find("Selectable").find("Overlay") is not None and entity.find("Selectable").find("Overlay") is not None
@ -375,11 +376,11 @@ class CheckRefs:
for tag in ("MainTexture", "MainTextureMask"): for tag in ("MainTexture", "MainTextureMask"):
elem = texture.find(tag) elem = texture.find(tag)
if elem is not None and elem.text: if elem is not None and elem.text:
self.deps.append((str(fp), f"art/textures/selection/{elem.text}")) self.deps.append((fp, Path(f"art/textures/selection/{elem.text}")))
if entity.find("Formation") is not None: if entity.find("Formation") is not None:
icon = entity.find("Formation").find("Icon") icon = entity.find("Formation").find("Icon")
if icon is not None and icon.text: if icon is not None and icon.text:
self.deps.append((str(fp), f"art/textures/ui/session/icons/{icon.text}")) self.deps.append((fp, Path(f"art/textures/ui/session/icons/{icon.text}")))
cmp_auras = entity.find("Auras") cmp_auras = entity.find("Auras")
if cmp_auras is not None: if cmp_auras is not None:
@ -389,7 +390,7 @@ class CheckRefs:
continue continue
if aura.startswith("-"): if aura.startswith("-"):
continue continue
self.deps.append((str(fp), f"simulation/data/auras/{aura}.json")) self.deps.append((fp, Path(f"simulation/data/auras/{aura}.json")))
cmp_identity = entity.find("Identity") cmp_identity = entity.find("Identity")
if cmp_identity is not None: if cmp_identity is not None:
@ -401,7 +402,7 @@ class CheckRefs:
if techsTag is not None: if techsTag is not None:
for techTag in techsTag.text.split(): for techTag in techsTag.text.split():
self.deps.append( self.deps.append(
(str(fp), f"simulation/data/technologies/{techTag}.json") (fp, Path(f"simulation/data/technologies/{techTag}.json"))
) )
if recursionDepth > 0: if recursionDepth > 0:
@ -441,7 +442,7 @@ class CheckRefs:
civ = "generic" civ = "generic"
tech = tech.replace("{civ}", civ) tech = tech.replace("{civ}", civ)
self.deps.append( self.deps.append(
(str(fp), f"simulation/data/technologies/{tech}.json") (fp, Path(f"simulation/data/technologies/{tech}.json"))
) )
def append_variant_dependencies(self, variant, fp): def append_variant_dependencies(self, variant, fp):
@ -464,17 +465,17 @@ class CheckRefs:
else [] else []
) )
if variant_file: if variant_file:
self.deps.append((str(fp), f"art/variants/{variant_file}")) self.deps.append((fp, Path(f"art/variants/{variant_file}")))
if mesh is not None and mesh.text: if mesh is not None and mesh.text:
self.deps.append((str(fp), f"art/meshes/{mesh.text}")) self.deps.append((fp, Path(f"art/meshes/{mesh.text}")))
if particles is not None and particles.get("file"): if particles is not None and particles.get("file"):
self.deps.append((str(fp), f'art/particles/{particles.get("file")}')) self.deps.append((fp, Path(f"art/particles/{particles.get('file')}")))
for texture_file in [x for x in texture_files if x]: for texture_file in [x for x in texture_files if x]:
self.deps.append((str(fp), f"art/textures/skins/{texture_file}")) self.deps.append((fp, Path(f"art/textures/skins/{texture_file}")))
for prop_actor in [x for x in prop_actors if x]: for prop_actor in [x for x in prop_actors if x]:
self.deps.append((str(fp), f"art/actors/{prop_actor}")) self.deps.append((fp, Path(f"art/actors/{prop_actor}")))
for animation_file in [x for x in animation_files if x]: for animation_file in [x for x in animation_files if x]:
self.deps.append((str(fp), f"art/animation/{animation_file}")) self.deps.append((fp, Path(f"art/animation/{animation_file}")))
def append_actor_dependencies(self, actor, fp): def append_actor_dependencies(self, actor, fp):
for group in actor.findall("group"): for group in actor.findall("group"):
@ -482,13 +483,13 @@ class CheckRefs:
self.append_variant_dependencies(variant, fp) self.append_variant_dependencies(variant, fp)
material = actor.find("material") material = actor.find("material")
if material is not None and material.text: if material is not None and material.text:
self.deps.append((str(fp), f"art/materials/{material.text}")) self.deps.append((fp, Path(f"art/materials/{material.text}")))
def add_actors(self): def add_actors(self):
self.logger.info("Loading actors...") self.logger.info("Loading actors...")
for fp, ffp in sorted(self.find_files("art/actors", "xml")): for fp, ffp in sorted(self.find_files("art/actors", "xml")):
self.files.append(str(fp)) self.files.append(fp)
self.roots.append(str(fp)) self.roots.append(fp)
root = ET.parse(ffp).getroot() root = ET.parse(ffp).getroot()
if root.tag == "actor": if root.tag == "actor":
self.append_actor_dependencies(root, fp) self.append_actor_dependencies(root, fp)
@ -504,8 +505,8 @@ class CheckRefs:
def add_variants(self): def add_variants(self):
self.logger.info("Loading variants...") self.logger.info("Loading variants...")
for fp, ffp in sorted(self.find_files("art/variants", "xml")): for fp, ffp in sorted(self.find_files("art/variants", "xml")):
self.files.append(str(fp)) self.files.append(fp)
self.roots.append(str(fp)) self.roots.append(fp)
variant = ET.parse(ffp).getroot() variant = ET.parse(ffp).getroot()
self.append_variant_dependencies(variant, fp) self.append_variant_dependencies(variant, fp)
@ -513,7 +514,7 @@ class CheckRefs:
self.logger.info("Loading art files...") self.logger.info("Loading art files...")
self.files.extend( self.files.extend(
[ [
str(fp) fp
for (fp, ffp) in self.find_files( for (fp, ffp) in self.find_files(
"art/textures/particles", *self.supportedTextureFormats "art/textures/particles", *self.supportedTextureFormats
) )
@ -521,7 +522,7 @@ class CheckRefs:
) )
self.files.extend( self.files.extend(
[ [
str(fp) fp
for (fp, ffp) in self.find_files( for (fp, ffp) in self.find_files(
"art/textures/terrain", *self.supportedTextureFormats "art/textures/terrain", *self.supportedTextureFormats
) )
@ -529,56 +530,53 @@ class CheckRefs:
) )
self.files.extend( self.files.extend(
[ [
str(fp) fp
for (fp, ffp) in self.find_files( for (fp, ffp) in self.find_files(
"art/textures/skins", *self.supportedTextureFormats "art/textures/skins", *self.supportedTextureFormats
) )
] ]
) )
self.files.extend( self.files.extend(
[str(fp) for (fp, ffp) in self.find_files("art/meshes", *self.supportedMeshesFormats)] [fp for (fp, ffp) in self.find_files("art/meshes", *self.supportedMeshesFormats)]
) )
self.files.extend( self.files.extend(
[ [fp for (fp, ffp) in self.find_files("art/animation", *self.supportedAnimationFormats)]
str(fp)
for (fp, ffp) in self.find_files("art/animation", *self.supportedAnimationFormats)
]
) )
def add_materials(self): def add_materials(self):
self.logger.info("Loading materials...") self.logger.info("Loading materials...")
for fp, ffp in sorted(self.find_files("art/materials", "xml")): for fp, ffp in sorted(self.find_files("art/materials", "xml")):
self.files.append(str(fp)) self.files.append(fp)
material_elem = ET.parse(ffp).getroot() material_elem = ET.parse(ffp).getroot()
for alternative in material_elem.findall("alternative"): for alternative in material_elem.findall("alternative"):
material = alternative.get("material") material = alternative.get("material")
if material is not None: if material is not None:
self.deps.append((str(fp), f"art/materials/{material}")) self.deps.append((fp, Path(f"art/materials/{material}")))
def add_particles(self): def add_particles(self):
self.logger.info("Loading particles...") self.logger.info("Loading particles...")
for fp, ffp in sorted(self.find_files("art/particles", "xml")): for fp, ffp in sorted(self.find_files("art/particles", "xml")):
self.files.append(str(fp)) self.files.append(fp)
self.roots.append(str(fp)) self.roots.append(fp)
particle = ET.parse(ffp).getroot() particle = ET.parse(ffp).getroot()
texture = particle.find("texture") texture = particle.find("texture")
if texture is not None: if texture is not None:
self.deps.append((str(fp), texture.text)) self.deps.append((fp, Path(texture.text)))
def add_soundgroups(self): def add_soundgroups(self):
self.logger.info("Loading sound groups...") self.logger.info("Loading sound groups...")
for fp, ffp in sorted(self.find_files("audio", "xml")): for fp, ffp in sorted(self.find_files("audio", "xml")):
self.files.append(str(fp)) self.files.append(fp)
self.roots.append(str(fp)) self.roots.append(fp)
sound_group = ET.parse(ffp).getroot() sound_group = ET.parse(ffp).getroot()
path = sound_group.find("Path").text.rstrip("/") path = sound_group.find("Path").text.rstrip("/")
for sound in sound_group.findall("Sound"): for sound in sound_group.findall("Sound"):
self.deps.append((str(fp), f"{path}/{sound.text}")) self.deps.append((fp, Path(f"{path}/{sound.text}")))
def add_audio(self): def add_audio(self):
self.logger.info("Loading audio files...") self.logger.info("Loading audio files...")
self.files.extend( self.files.extend(
[str(fp) for (fp, ffp) in self.find_files("audio/", self.supportedAudioFormats)] [fp for (fp, ffp) in self.find_files("audio/", self.supportedAudioFormats)]
) )
def add_gui_object_repeat(self, obj, fp): def add_gui_object_repeat(self, obj, fp):
@ -596,7 +594,7 @@ class CheckRefs:
for include in obj.findall("include"): for include in obj.findall("include"):
included_file = include.get("file") included_file = include.get("file")
if included_file: if included_file:
self.deps.append((str(fp), f"{included_file}")) self.deps.append((fp, Path(included_file)))
def add_gui_object(self, parent, fp): def add_gui_object(self, parent, fp):
if parent is None: if parent is None:
@ -617,38 +615,38 @@ class CheckRefs:
self.logger.info("Loading GUI XML...") self.logger.info("Loading GUI XML...")
gui_page_regex = re.compile(r".*[\\\/]page(_[^.\/\\]+)?\.xml$") gui_page_regex = re.compile(r".*[\\\/]page(_[^.\/\\]+)?\.xml$")
for fp, ffp in sorted(self.find_files("gui", "xml")): for fp, ffp in sorted(self.find_files("gui", "xml")):
self.files.append(str(fp)) self.files.append(fp)
# GUI page definitions are assumed to be named page_[something].xml and alone in that. # GUI page definitions are assumed to be named page_[something].xml and alone in that.
if gui_page_regex.match(str(fp)): if gui_page_regex.match(str(fp)):
self.roots.append(str(fp)) self.roots.append(fp)
root_xml = ET.parse(ffp).getroot() root_xml = ET.parse(ffp).getroot()
for include in root_xml.findall("include"): for include in root_xml.findall("include"):
# If including an entire directory, find all the *.xml files # If including an entire directory, find all the *.xml files
if include.text.endswith("/"): if include.text.endswith("/"):
self.deps.extend( self.deps.extend(
[ [
(str(fp), str(sub_fp)) (fp, sub_fp)
for (sub_fp, sub_ffp) in self.find_files( for (sub_fp, sub_ffp) in self.find_files(
f"gui/{include.text}", "xml" f"gui/{include.text}", "xml"
) )
] ]
) )
else: else:
self.deps.append((str(fp), f"gui/{include.text}")) self.deps.append((fp, Path(f"gui/{include.text}")))
else: else:
xml = ET.parse(ffp) xml = ET.parse(ffp)
root_xml = xml.getroot() root_xml = xml.getroot()
name = root_xml.tag name = root_xml.tag
self.roots.append(str(fp)) self.roots.append(fp)
if name in ("objects", "object"): if name in ("objects", "object"):
for script in root_xml.findall("script"): for script in root_xml.findall("script"):
if script.get("file"): if script.get("file"):
self.deps.append((str(fp), script.get("file"))) self.deps.append((fp, Path(script.get("file"))))
if script.get("directory"): if script.get("directory"):
# If including an entire directory, find all the *.js files # If including an entire directory, find all the *.js files
self.deps.extend( self.deps.extend(
[ [
(str(fp), str(sub_fp)) (fp, sub_fp)
for (sub_fp, sub_ffp) in self.find_files( for (sub_fp, sub_ffp) in self.find_files(
script.get("directory"), "js" script.get("directory"), "js"
) )
@ -661,20 +659,20 @@ class CheckRefs:
elif name == "styles": elif name == "styles":
for style in root_xml.findall("style"): for style in root_xml.findall("style"):
if style.get("sound_opened"): if style.get("sound_opened"):
self.deps.append((str(fp), f"{style.get('sound_opened')}")) self.deps.append((fp, Path(f"{style.get('sound_opened')}")))
if style.get("sound_closed"): if style.get("sound_closed"):
self.deps.append((str(fp), f"{style.get('sound_closed')}")) self.deps.append((fp, Path(f"{style.get('sound_closed')}")))
if style.get("sound_selected"): if style.get("sound_selected"):
self.deps.append((str(fp), f"{style.get('sound_selected')}")) self.deps.append((fp, Path(f"{style.get('sound_selected')}")))
if style.get("sound_disabled"): if style.get("sound_disabled"):
self.deps.append((str(fp), f"{style.get('sound_disabled')}")) self.deps.append((fp, Path(f"{style.get('sound_disabled')}")))
# TODO: look at sprites, styles, etc # TODO: look at sprites, styles, etc
elif name == "sprites": elif name == "sprites":
for sprite in root_xml.findall("sprite"): for sprite in root_xml.findall("sprite"):
for image in sprite.findall("image"): for image in sprite.findall("image"):
if image.get("texture"): if image.get("texture"):
self.deps.append( self.deps.append(
(str(fp), f"art/textures/ui/{image.get('texture')}") (fp, Path(f"art/textures/ui/{image.get('texture')}"))
) )
else: else:
bio = BytesIO() bio = BytesIO()
@ -686,19 +684,16 @@ class CheckRefs:
def add_gui_data(self): def add_gui_data(self):
self.logger.info("Loading GUI data...") self.logger.info("Loading GUI data...")
self.files.extend([str(fp) for (fp, ffp) in self.find_files("gui", "js")]) self.files.extend([fp for (fp, ffp) in self.find_files("gui", "js")])
self.files.extend([str(fp) for (fp, ffp) in self.find_files("gamesettings", "js")]) self.files.extend([fp for (fp, ffp) in self.find_files("gamesettings", "js")])
self.files.extend([str(fp) for (fp, ffp) in self.find_files("autostart", "js")]) self.files.extend([fp for (fp, ffp) in self.find_files("autostart", "js")])
self.roots.extend([str(fp) for (fp, ffp) in self.find_files("autostart", "js")]) self.roots.extend([fp for (fp, ffp) in self.find_files("autostart", "js")])
self.files.extend( self.files.extend(
[ [fp for (fp, ffp) in self.find_files("art/textures/ui", *self.supportedTextureFormats)]
str(fp)
for (fp, ffp) in self.find_files("art/textures/ui", *self.supportedTextureFormats)
]
) )
self.files.extend( self.files.extend(
[ [
str(fp) fp
for (fp, ffp) in self.find_files( for (fp, ffp) in self.find_files(
"art/textures/selection", *self.supportedTextureFormats "art/textures/selection", *self.supportedTextureFormats
) )
@ -708,65 +703,59 @@ class CheckRefs:
def add_civs(self): def add_civs(self):
self.logger.info("Loading civs...") self.logger.info("Loading civs...")
for fp, ffp in sorted(self.find_files("simulation/data/civs", "json")): for fp, ffp in sorted(self.find_files("simulation/data/civs", "json")):
self.files.append(str(fp)) self.files.append(fp)
self.roots.append(str(fp)) self.roots.append(fp)
with open(ffp, encoding="utf-8") as f: with open(ffp, encoding="utf-8") as f:
civ = load(f) civ = load(f)
for music in civ.get("Music", []): for music in civ.get("Music", []):
self.deps.append((str(fp), f"audio/music/{music['File']}")) self.deps.append((fp, Path(f"audio/music/{music['File']}")))
def add_tips(self): def add_tips(self):
self.logger.info("Loading tips...") self.logger.info("Loading tips...")
for fp, _ffp in sorted(self.find_files("gui/text/tips", "txt")): for fp, _ffp in sorted(self.find_files("gui/text/tips", "txt")):
relative_path = str(fp) self.files.append(fp)
self.files.append(relative_path) self.roots.append(fp)
self.roots.append(relative_path) self.deps.append((fp, Path(f"art/textures/ui/loading/tips/{fp.stem}.png")))
self.deps.append(
(
relative_path,
f"art/textures/ui/loading/tips/{basename(relative_path).split('.')[0]}.png",
)
)
def add_rms(self): def add_rms(self):
self.logger.info("Loading random maps...") self.logger.info("Loading random maps...")
self.files.extend([str(fp) for (fp, ffp) in self.find_files("maps/random", "js")]) self.files.extend([fp for (fp, ffp) in self.find_files("maps/random", "js")])
for fp, ffp in sorted(self.find_files("maps/random", "json")): for fp, ffp in sorted(self.find_files("maps/random", "json")):
if str(fp).startswith("maps/random/rmbiome"): if str(fp).startswith("maps/random/rmbiome"):
continue continue
self.files.append(str(fp)) self.files.append(fp)
self.roots.append(str(fp)) self.roots.append(fp)
with open(ffp, encoding="utf-8") as f: with open(ffp, encoding="utf-8") as f:
randmap = load(f) randmap = load(f)
settings = randmap.get("settings", {}) settings = randmap.get("settings", {})
if settings.get("Script"): if settings.get("Script"):
self.deps.append((str(fp), f"maps/random/{settings['Script']}")) self.deps.append((fp, Path(f"maps/random/{settings['Script']}")))
# Map previews # Map previews
if settings.get("Preview"): if settings.get("Preview"):
self.deps.append( self.deps.append(
(str(fp), f'art/textures/ui/session/icons/mappreview/{settings["Preview"]}') (fp, Path(f"art/textures/ui/session/icons/mappreview/{settings['Preview']}"))
) )
def add_techs(self): def add_techs(self):
self.logger.info("Loading techs...") self.logger.info("Loading techs...")
for fp, ffp in sorted(self.find_files("simulation/data/technologies", "json")): for fp, ffp in sorted(self.find_files("simulation/data/technologies", "json")):
self.files.append(str(fp)) self.files.append(fp)
with open(ffp, encoding="utf-8") as f: with open(ffp, encoding="utf-8") as f:
tech = load(f) tech = load(f)
if tech.get("autoResearch"): if tech.get("autoResearch"):
self.roots.append(str(fp)) self.roots.append(fp)
if tech.get("icon"): if tech.get("icon"):
self.deps.append( self.deps.append(
(str(fp), f"art/textures/ui/session/portraits/technologies/{tech['icon']}") (fp, Path(f"art/textures/ui/session/portraits/technologies/{tech['icon']}"))
) )
if tech.get("supersedes"): if tech.get("supersedes"):
self.deps.append( self.deps.append(
(str(fp), f"simulation/data/technologies/{tech['supersedes']}.json") (fp, Path(f"simulation/data/technologies/{tech['supersedes']}.json"))
) )
if tech.get("top"): if tech.get("top"):
self.deps.append((str(fp), f"simulation/data/technologies/{tech['top']}.json")) self.deps.append((fp, Path(f"simulation/data/technologies/{tech['top']}.json")))
if tech.get("bottom"): if tech.get("bottom"):
self.deps.append((str(fp), f"simulation/data/technologies/{tech['bottom']}.json")) self.deps.append((fp, Path(f"simulation/data/technologies/{tech['bottom']}.json")))
def add_terrains(self): def add_terrains(self):
self.logger.info("Loading terrains...") self.logger.info("Loading terrains...")
@ -774,43 +763,40 @@ class CheckRefs:
# ignore terrains.xml # ignore terrains.xml
if str(fp).endswith("terrains.xml"): if str(fp).endswith("terrains.xml"):
continue continue
self.files.append(str(fp)) self.files.append(fp)
self.roots.append(str(fp)) self.roots.append(fp)
terrain = ET.parse(ffp).getroot() terrain = ET.parse(ffp).getroot()
for texture in terrain.find("textures").findall("texture"): for texture in terrain.find("textures").findall("texture"):
if texture.get("file"): if texture.get("file"):
self.deps.append((str(fp), f"art/textures/terrain/{texture.get('file')}")) self.deps.append((fp, Path(f"art/textures/terrain/{texture.get('file')}")))
if terrain.find("material") is not None: if terrain.find("material") is not None:
material = terrain.find("material").text material = terrain.find("material").text
self.deps.append((str(fp), f"art/materials/{material}")) self.deps.append((fp, Path(f"art/materials/{material}")))
def add_auras(self): def add_auras(self):
self.logger.info("Loading auras...") self.logger.info("Loading auras...")
for fp, ffp in sorted(self.find_files("simulation/data/auras", "json")): for fp, ffp in sorted(self.find_files("simulation/data/auras", "json")):
self.files.append(str(fp)) self.files.append(fp)
with open(ffp, encoding="utf-8") as f: with open(ffp, encoding="utf-8") as f:
aura = load(f) aura = load(f)
if aura.get("overlayIcon"): if aura.get("overlayIcon"):
self.deps.append((str(fp), aura["overlayIcon"])) self.deps.append((fp, Path(aura["overlayIcon"])))
range_overlay = aura.get("rangeOverlay", {}) range_overlay = aura.get("rangeOverlay", {})
for prop in ("lineTexture", "lineTextureMask"): for prop in ("lineTexture", "lineTextureMask"):
if range_overlay.get(prop): if range_overlay.get(prop):
self.deps.append((str(fp), f"art/textures/selection/{range_overlay[prop]}")) self.deps.append((fp, Path(f"art/textures/selection/{range_overlay[prop]}")))
def check_deps(self): def check_deps(self):
self.logger.info("Looking for missing files...") self.logger.info("Looking for missing files...")
uniq_files = set(self.files) uniq_files = set(self.files)
uniq_files = [r.replace(sep, "/") for r in uniq_files] uniq_files = [r.as_posix() for r in uniq_files]
lower_case_files = {f.lower(): f for f in uniq_files} lower_case_files = {f.lower(): f for f in uniq_files}
reverse_deps = {} reverse_deps = {}
for parent, dep in self.deps: for parent, dep in self.deps:
if sep != "/":
parent = parent.replace(sep, "/")
dep = dep.replace(sep, "/")
if dep not in reverse_deps: if dep not in reverse_deps:
reverse_deps[dep] = {parent} reverse_deps[dep.as_posix()] = {parent.as_posix()}
else: else:
reverse_deps[dep].add(parent) reverse_deps[dep.as_posix()].add(parent.as_posix())
for dep in sorted(reverse_deps.keys()): for dep in sorted(reverse_deps.keys()):
if "simulation/templates" in dep and ( if "simulation/templates" in dep and (
@ -836,19 +822,15 @@ class CheckRefs:
self.logger.info("Looking for unused files...") self.logger.info("Looking for unused files...")
deps = {} deps = {}
for parent, dep in self.deps: for parent, dep in self.deps:
if sep != "/":
parent = parent.replace(sep, "/")
dep = dep.replace(sep, "/")
if parent not in deps: if parent not in deps:
deps[parent] = {dep} deps[parent.as_posix()] = {dep.as_posix()}
else: else:
deps[parent].add(dep) deps[parent.as_posix()].add(dep.as_posix())
uniq_files = set(self.files) uniq_files = set(self.files)
uniq_files = [r.replace(sep, "/") for r in uniq_files] uniq_files = [r.as_posix() for r in uniq_files]
reachable = list(set(self.roots)) reachable = list(set(self.roots))
reachable = [r.replace(sep, "/") for r in reachable] reachable = [r.as_posix() for r in reachable]
while True: while True:
new_reachable = [] new_reachable = []
for r in reachable: for r in reachable: