github.com/iDigitalFlame/xmt@v0.5.4/tools/crypt_generator.py (about) 1 #!/usr/bin/python3 2 # Copyright (C) 2020 - 2023 iDigitalFlame 3 # 4 # This program is free software: you can redistribute it and/or modify 5 # it under the terms of the GNU General Public License as published by 6 # the Free Software Foundation, either version 3 of the License, or 7 # any later version. 8 # 9 # This program is distributed in the hope that it will be useful, 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 # GNU General Public License for more details. 13 # 14 # You should have received a copy of the GNU General Public License 15 # along with this program. If not, see <https://www.gnu.org/licenses/>. 16 # 17 18 from glob import glob 19 from json import dumps 20 from os.path import join 21 from sys import argv, exit 22 23 OS_ARCH_TAGS = [ 24 "386", 25 "aix", 26 "amd64", 27 "amd64p32", 28 "android", 29 "arm", 30 "arm64", 31 "darwin", 32 "dragonfly", 33 "freebsd", 34 "illumos", 35 "ios", 36 "js", 37 "linux", 38 "loong64", 39 "mips", 40 "mips64", 41 "mips64le", 42 "mipsle", 43 "nacl", 44 "netbsd", 45 "openbsd", 46 "plan9", 47 "ppc64", 48 "ppc64le", 49 "riscv64", 50 "s390x", 51 "solaris", 52 "wasm", 53 "windows", 54 ] 55 56 57 def _make_tags(v): 58 s = v.strip() 59 if s == "crypt": 60 return None 61 e = s.split(" ") 62 if len(e) == 0: 63 return None 64 if len(e) == 1 and e[0] == "crypt": 65 return None 66 r = list() 67 for i in e: 68 # Remove operators and any go version tags 69 if i == "||" or i == "&&" or i == "crypt" or "go1." in i: 70 continue 71 r.append(i.replace("(", "").replace(")", "")) 72 r.sort() 73 return r 74 75 76 def _merge_tags(one, two): 77 if one is None or two is None: 78 return None 79 if len(one) == 0 or len(two) == 0: 80 return None 81 if one == two: 82 return one 83 y, z = False, False 84 for i in one: 85 if len(i) == 0: 86 continue 87 if i[0] != "!": 88 break 89 z = True 90 for i in two: 91 if len(i) == 0: 92 continue 93 if i[0] != "!": 94 break 95 y = True 96 r = one.copy() 97 for i in two: 98 if i[0] == "!": # We have a negate 99 if i[1:] in r: # We have a negative but theres a positive in the list 100 r.remove(i[1:]) # Remove the positive 101 continue # Skip the negative 102 if i in r: # Already exists 103 continue 104 if y and not z: # Only add if "two" is all negative and "one" is not. 105 r.append(i) # Add it since we don't care. 106 continue 107 # It's a positive 108 if f"!{i}" in r: # Is a negative of that in the current? 109 r.remove(f"!{i}") # Remove it 110 continue # Skip the positive, so we can have both 111 if i in r: # Already exists 112 continue 113 # Skip if we are all negatives and its an OS/ARCH name. 114 if z and i in OS_ARCH_TAGS: 115 continue 116 r.append(i) 117 if len(r) == 0: 118 return None 119 return r 120 121 122 class CryptGenerator(object): 123 __slots__ = ("text", "_count") 124 125 def __init__(self): 126 self.text = dict() 127 self._count = list() 128 129 def _add(self, value, tags): 130 t = _make_tags(tags) 131 if "\\n" in value: 132 value = value.replace("\\n", "\n") 133 if value in self.text: 134 n = self.text[value] 135 n[1] = _merge_tags(n[1], t) 136 return n[0] 137 i = str(len(self._count)) 138 self._count.append((i)) 139 self.text[value] = [i, t] 140 return i 141 142 def _index(self, p, d, tags): 143 if "crypt.Get(" not in d: 144 return None 145 s = d.find("crypt.Get(") 146 if s <= 0: 147 raise ValueError(f'{p}: Invalid crypt entry "{d.strip()}"') 148 e = d.find(")", s + 1) 149 if e <= s: 150 raise ValueError(f'{p}: Invalid crypt entry "{d.strip()}"') 151 c = d.find(" // ") 152 if c <= e: 153 raise ValueError(f'{p}: Crypt entry lacks comment entry "{d.strip()}"') 154 return ( 155 d[:s] 156 + "crypt.Get(" 157 + self._add(d[c + 3 :].strip(), tags) 158 + ")" 159 + d[e + 1 :] 160 ) 161 162 def start(self, out, path=""): 163 m = list() 164 for i in glob(join(path, "**/**.go"), recursive=True): 165 if i.startswith("unit_tests") or i.endswith(".test"): 166 continue 167 with open(i) as f: 168 d = f.read() 169 if len(d) == 0: 170 continue 171 if "package main\n" in d: 172 continue 173 if 'xmt/util/crypt"' not in d: 174 continue 175 if "crypt.Get(" not in d: 176 continue 177 m.append((i, d, d.split("\n"))) 178 if len(m) == 0: 179 return 180 print(f"Examining {len(m)} files..") 181 for i in m: 182 r, t = False, None 183 f = open(i[0], "w") 184 for x in range(0, len(i[2])): 185 if t is None and i[2][x].startswith("//go:build"): 186 t = i[2][x][10:].strip().lower() 187 o = self._index(i[0], i[2][x], t) 188 if o is not None: 189 r = o != i[2][x] 190 f.write(o) 191 else: 192 f.write(i[2][x]) 193 if len(i[2][x]) == 0 and x + 1 >= len(i[2]): 194 continue 195 f.write("\n") 196 del o 197 f.close() 198 if not r: 199 continue 200 print(f'Reformatted "{i[0]}"') 201 del m 202 z = dict() 203 for k, v in self.text.items(): 204 z[v[0]] = {"value": k} 205 if v[1] is not None and len(v[1]) > 0: 206 z[v[0]]["tags"] = v[1] 207 with open(out, "w") as f: 208 f.write(dumps(z, indent=4, sort_keys=False)) 209 del z 210 211 212 if __name__ == "__main__": 213 if len(argv) < 2: 214 print(f"{argv[0]} <json> [dir]") 215 exit(1) 216 217 d = "" 218 if len(argv) == 3: 219 d = argv[2] 220 221 v = CryptGenerator() 222 v.start(argv[1], d) 223 del d, v