forked from zeldaret/oot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
progress.py
executable file
·153 lines (119 loc) · 4.84 KB
/
progress.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
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env python3
import argparse
import json
import git
import os
import re
parser = argparse.ArgumentParser(description="Computes current progress throughout the whole project.")
parser.add_argument("format", nargs="?", default="text", choices=["text", "csv", "shield-json"])
parser.add_argument("-m", "--matching", dest='matching', action='store_true',
help="Output matching progress instead of decompilation progress")
args = parser.parse_args()
NON_MATCHING_PATTERN = r"#ifdef\s+NON_MATCHING.*?#pragma\s+GLOBAL_ASM\s*\(\s*\"(.*?)\"\s*\).*?#endif"
def GetNonMatchingFunctions(files):
functions = []
for file in files:
with open(file) as f:
functions += re.findall(NON_MATCHING_PATTERN, f.read(), re.DOTALL)
return functions
def ReadAllLines(fileName):
lineList = list()
with open(fileName) as f:
lineList = f.readlines()
return lineList
def GetFiles(path, ext):
files = []
for r, d, f in os.walk(path):
for file in f:
if file.endswith(ext):
files.append(os.path.join(r, file))
return files
nonMatchingFunctions = GetNonMatchingFunctions(GetFiles("src", ".c")) if not args.matching else []
def GetNonMatchingSize(path):
size = 0
asmFiles = GetFiles(path, ".s")
for asmFilePath in asmFiles:
if asmFilePath not in nonMatchingFunctions:
asmLines = ReadAllLines(asmFilePath)
for asmLine in asmLines:
if (asmLine.startswith("/*")):
size += 4
return size
def IsCFile(objfile):
srcfile = objfile.strip().replace("build/gc-eu-mq-dbg/", "").replace(".o", ".c")
return os.path.isfile(srcfile)
mapFile = ReadAllLines("build/gc-eu-mq-dbg/oot-gc-eu-mq-dbg.map")
curSegment = None
src = 0
code = 0
boot = 0
ovl = 0
for line in mapFile:
if "_codeSegmentStart" in line:
curSegment = "code"
elif "_bootSegmentStart" in line:
curSegment = "boot"
elif "_codeSegmentEnd" in line or "_bootSegmentEnd" in line:
curSegment = None
lineSplit = list(filter(None, line.split(" ")))
if (len(lineSplit) == 4 and lineSplit[0].startswith(".")):
section = lineSplit[0]
size = int(lineSplit[2], 16)
objFile = lineSplit[3]
if (section == ".text" and IsCFile(objFile)):
if objFile.startswith("build/gc-eu-mq-dbg/src"):
src += size
if curSegment == "code":
code += size
elif curSegment == "boot":
boot += size
else:
ovl += size
nonMatchingASM = GetNonMatchingSize("asm/non_matchings")
nonMatchingASMBoot = GetNonMatchingSize("asm/non_matchings/boot")
nonMatchingASMCode = GetNonMatchingSize("asm/non_matchings/code")
nonMatchingASMOvl = GetNonMatchingSize("asm/non_matchings/overlays")
src -= nonMatchingASM
code -= nonMatchingASMCode
boot -= nonMatchingASMBoot
ovl -= nonMatchingASMOvl
bootSize = 31408 # decompilable code only
codeSize = 999984 # decompilable code only
ovlSize = 2812000 # .text sections
total = src + nonMatchingASM
srcPct = 100 * src / total
codePct = 100 * code / codeSize
bootPct = 100 * boot / bootSize
ovlPct = 100 * ovl / ovlSize
bytesPerHeartPiece = total // 80
if args.format == 'csv':
csv_version = 2
git_object = git.Repo().head.object
timestamp = str(git_object.committed_date)
git_hash = git_object.hexsha
csv_list = [str(csv_version), timestamp, git_hash, str(src), str(total), str(code), str(codeSize), str(boot), str(bootSize), str(ovl), str(ovlSize), str(nonMatchingASM), str(len(nonMatchingFunctions))]
print(",".join(csv_list))
elif args.format == 'shield-json':
# https://shields.io/endpoint
print(json.dumps({
"schemaVersion": 1,
"label": "progress",
"message": f"{srcPct:.3g}%",
"color": 'yellow' if srcPct < 100 else 'brightgreen',
}))
elif args.format == 'text':
adjective = "decompiled" if not args.matching else "matched"
print(str(total) + " total bytes of decompilable code\n")
print(str(src) + " bytes " + adjective + " in src " + str(srcPct) + "%\n")
print(str(boot) + "/" + str(bootSize) + " bytes " + adjective + " in boot " + str(bootPct) + "%\n")
print(str(code) + "/" + str(codeSize) + " bytes " + adjective + " in code " + str(codePct) + "%\n")
print(str(ovl) + "/" + str(ovlSize) + " bytes " + adjective + " in overlays " + str(ovlPct) + "%\n")
print("------------------------------------\n")
heartPieces = int(src / bytesPerHeartPiece)
rupees = int(((src % bytesPerHeartPiece) * 100) / bytesPerHeartPiece)
if (rupees > 0):
print("You have " + str(heartPieces) + "/80 heart pieces and " + str(rupees) + " rupee(s).\n")
else:
print("You have " + str(heartPieces) + "/80 heart pieces.\n")
else:
print("Unknown format argument: " + args.format)