-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.py
143 lines (127 loc) · 4.56 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import json
import os
import pathlib
import sys
import time
import shutil
from threading import Lock, Timer
import traceback
from typing import Set
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from MrubyDecompiler import compileFile
from NierDocs.tools.pakScriptTools.xmlToYax import xmlToYax
from NierDocs.tools.pakScriptTools.pakRepacker import repackPak
from nier2blender2nier.exportDat import export_dat
from nier2blender2nier.util import importContentsFileFromFolder
from pakWarningsChecker import checkWarningsInFolder
watchDir: str = None
datFile: str = None
mutex = Lock()
def backupFile(file: str):
# copy the original file to <file>.bak the first time
backupFile = file + ".bak"
if not os.path.exists(backupFile):
shutil.copy(file, backupFile)
def debounce(wait):
"""
https://gist.github.com/walkermatt/2871026
Decorator that will postpone a functions
execution until after wait seconds
have elapsed since the last time it was invoked.
"""
def decorator(fn):
def debounced(*args, **kwargs):
def call_it():
try:
fn(*args, **kwargs)
except:
print("Error in debounced function")
traceback.print_exc()
if mutex.locked():
mutex.release()
try:
debounced.t.cancel()
except AttributeError:
pass
debounced.t = Timer(wait, call_it)
debounced.t.start()
return debounced
return decorator
class FileChangeHandler(FileSystemEventHandler):
pendingFiles: Set[str]
def __init__(self):
self.pendingFiles = set()
def on_modified(self, event):
if event.is_directory:
return
mutex.acquire()
self.pendingFiles.add(event.src_path)
mutex.release()
self.handlePendingFiles()
@debounce(0.15)
def handlePendingFiles(self):
mutex.acquire()
hasDatChanged = False
changedPakDirs = set()
for file in self.pendingFiles:
fileName = os.path.basename(file)
if file.endswith(".xml"):
# check if file is in pakInfo.json
infoPath = os.path.join(os.path.dirname(file), "pakInfo.json")
if not os.path.exists(infoPath):
continue
with open(infoPath, "r") as f:
pakInfo = json.load(f)
yaxFile = file[:-4] + ".yax"
yaxFileName = os.path.basename(yaxFile)
if not any(yaxFileName in file["name"] for file in pakInfo["files"]):
continue
# convert xml to yax
print(f"Converting {fileName} to yax")
xmlToYax(file, yaxFile)
dirName = os.path.dirname(file)
if dirName.endswith(".pak"):
changedPakDirs.add(dirName)
elif file.endswith("pakInfo.json"):
changedPakDirs.add(os.path.dirname(file))
elif file.endswith(".rb"):
mrbBinFile = file[:-3]
print(f"Compiling {fileName}")
backupFile(mrbBinFile)
compileFile(file, mrbBinFile)
hasDatChanged = True
for dirName in changedPakDirs:
pakFileName = pathlib.Path(dirName).parts[-1]
pakFile = str(pathlib.Path(dirName).parent.parent / pakFileName)
print(f"Repacking {pakFile}")
backupFile(pakFile)
repackPak(dirName)
hasDatChanged = True
if len(changedPakDirs) > 0:
checkWarningsInFolder(watchDir)
if datFile is not None and hasDatChanged:
# todo: Should probably check for file extensions
#Extensions bigger than 4 characters may mess things up
export_dat(datFile, importContentsFileFromFolder(watchDir))
self.pendingFiles.clear()
mutex.release()
if __name__ == '__main__':
if len(sys.argv) < 2:
print("Usage: python main.py <directory> [<out_dat>]")
sys.exit(1)
watchDir = sys.argv[1]
if len(sys.argv) > 2:
datFile = sys.argv[2]
handler = FileChangeHandler()
observer = Observer()
checkWarningsInFolder(watchDir)
observer.schedule(handler, watchDir, recursive=True)
observer.start()
print(f"Watching {watchDir}")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()