Files
2024-07-04 15:26:35 -04:00

107 lines
4.0 KiB
Python

import subprocess
import sys
import os
import hashlib
import argparse
import common as c
# List of Ninja build targets
NINJA_BUILD_TARGETS = [ ['src/data/bin1', 'out/forest_1st.arc', 'dump/forest_1st.arc'], ['src/data/bin2', 'out/forest_2nd.arc', 'dump/forest_2nd.arc'] ]
def calculate_directory_hash(path, hash_func):
if not os.path.isdir(path):
raise NotADirectoryError(f"{path} is not a directory")
hasher = hash_func()
for root, dirs, files in os.walk(path):
for names in files:
filepath = os.path.join(root, names)
try:
with open(filepath, 'rb') as f:
while True:
data = f.read(65536) # Read in chunks to handle large files
if not data:
break
hasher.update(data)
except IOError:
# Handle errors as needed
pass
return hasher.hexdigest()
def directory_changed(path, build_dir, hash_func=hashlib.md5):
hash_file = os.path.join(build_dir, f'{os.path.basename(os.path.normpath(path))}.dirhash')
current_hash = calculate_directory_hash(path, hash_func)
try:
with open(hash_file, 'r') as f:
stored_hash = f.read()
except FileNotFoundError:
stored_hash = None
if current_hash != stored_hash:
os.makedirs(build_dir, exist_ok=True)
with open(hash_file, 'w') as f:
f.write(current_hash)
return True
return False
def run_ninja_build(target):
try:
subprocess.run(['ninja', '-v', target], check=True)
except subprocess.CalledProcessError as e:
print(f"Error running Ninja build for target {target}: {e}")
sys.exit(1)
def check_and_dump_arc(target, dump, verbose=False):
if not os.path.exists(target):
assert os.path.exists(dump), f"Please add missing file: {dump}"
print(f'Dumping {dump}')
try:
if verbose:
subprocess.run(['python3', 'tools/arc_tool.py', dump, os.path.dirname(target)])
else:
subprocess.run(['python3', 'tools/arc_tool.py', '-v', dump, os.path.dirname(target)])
except subprocess.CalledProcessError as e:
print(f"Error running arc_tool")
sys.exit(1)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Build Animal Crossing')
parser.add_argument('--clean', help='Cleans all build artifacts', required=False, action='store_true')
parser.add_argument('-v', help='Enable verbose logging', required=False, action='store_true')
args = parser.parse_args()
if args.clean:
for target in NINJA_BUILD_TARGETS:
rel_path = f'{os.path.basename(os.path.normpath(target[0]))}.dirhash'
path = os.path.join('build', rel_path)
if os.path.exists(path):
os.remove(path)
try:
subprocess.run(['ninja', '-t', 'clean'], check=True)
except subprocess.CalledProcessError as e:
print(f"Error running ninja -t clean")
sys.exit(1)
else:
for target in NINJA_BUILD_TARGETS:
check_and_dump_arc(target[0], target[2], args.v)
if directory_changed(target[0], 'build'):
if os.path.exists(target[1]):
os.remove(target[1])
run_ninja_build(target[1])
else:
print(f"No changes in {target[0]}, skipping build.")
try:
if args.v:
subprocess.run(['ninja', '-v'], check=True)
else:
subprocess.run(['ninja'], check=True)
# Compress foresta.rel
if os.path.exists(c.REL_OUT):
print("Compressing foresta.rel to foresta.rel.szs")
subprocess.call([f'./{c.ORTHRUS}', 'ncompress', 'yaz0', '-c', c.REL_OUT, c.REL_SZS_OUT])
except subprocess.CalledProcessError as e:
print(f"Error running Ninja build")
sys.exit(1)