def getRenameMaps(srgFiles, mcpConfDir, lvRangeMapFile, dumpRenameMap, srcRoot, excFiles): maps = {} importMaps = {} # CB -> packaged MCP class/field/method _notReallyThePackageMap, classMap, fieldMap, methodMap, methodSigMap = srglib.readMultipleSrgs(srgFiles) for old,new in classMap.iteritems(): maps["class "+old]=srglib.splitBaseName(new) importMaps["class "+old]=srglib.internalName2Source(new) # when renaming class, need to import it, too for old,new in fieldMap.iteritems(): maps["field "+old]=srglib.splitBaseName(new) for old,new in methodMap.iteritems(): maps["method "+old]=srglib.splitBaseName(new) # CB class -> MCP package name for cbClass, mcpClass in classMap.iteritems(): cbFile = "src/main/java/"+cbClass+".java" mcpPackage = srglib.splitPackageName(mcpClass) maps["package "+cbClass] = srglib.internalName2Source(mcpPackage) # Read parameter map from MCP.. it comes from MCP with MCP namings, so have to remap to CB invMethodMap, invMethodSigMap = srglib.invertMethodMap(methodMap, methodSigMap) invClassMap = srglib.invertDict(classMap) if mcpConfDir is not None: mcpParamMap = srglib.readParameterMap(mcpConfDir, apply_map = False) cbParamMap, removedParamMap = srglib.remapParameterMap(mcpParamMap, invMethodMap, invMethodSigMap, invClassMap) if not excFiles is None: for file in excFiles: tmp = srglib.readParameterMap(mcpConfDir, file, apply_map = False) tmp_clean, _ = srglib.remapParameterMap(tmp, invMethodMap, invMethodSigMap, invClassMap, keep_missing=True) pprint(tmp_clean) cbParamMap.update(tmp_clean) # removedParamMap = methods in FML/MCP repackaged+joined but not CB = client-only methods else: # don't rename any parameters mcpParamMap = {} cbParamMap = {} removedParamMap = {} for old,new in cbParamMap.iteritems(): for i in range(0,len(new)): maps["param %s %s" % (old, i)] = new[i] # Local variable map - position in source -> name; derived from MCP rangemap if lvRangeMapFile is not None: readLocalVariableMap(lvRangeMapFile, maps, invClassMap, invMethodMap, invMethodSigMap, srcRoot) if dumpRenameMap: for key in sorted(maps.keys()): newName = maps[key] print "RENAME MAP: %s -> %s" % (key, newName) return maps, importMaps
def getRenameMaps(srgFiles, mcpConfDir, lvRangeMapFile, dumpRenameMap, srcRoot): maps = {} importMaps = {} # CB -> packaged MCP class/field/method _notReallyThePackageMap, classMap, fieldMap, methodMap, methodSigMap = srglib.readMultipleSrgs(srgFiles) for old,new in classMap.iteritems(): maps["class "+old]=srglib.splitBaseName(new) importMaps["class "+old]=srglib.internalName2Source(new) # when renaming class, need to import it, too for old,new in fieldMap.iteritems(): maps["field "+old]=srglib.splitBaseName(new) for old,new in methodMap.iteritems(): maps["method "+old]=srglib.splitBaseName(new) # CB class -> MCP package name for cbClass, mcpClass in classMap.iteritems(): cbFile = "src/main/java/"+cbClass+".java" mcpPackage = srglib.splitPackageName(mcpClass) maps["package "+cbClass] = srglib.internalName2Source(mcpPackage) # Read parameter map from MCP.. it comes from MCP with MCP namings, so have to remap to CB invMethodMap, invMethodSigMap = srglib.invertMethodMap(methodMap, methodSigMap) invClassMap = srglib.invertDict(classMap) if mcpConfDir is not None: mcpParamMap = srglib.readParameterMap(mcpConfDir) cbParamMap, removedParamMap = srglib.remapParameterMap(mcpParamMap, invMethodMap, invMethodSigMap, invClassMap) # removedParamMap = methods in FML/MCP repackaged+joined but not CB = client-only methods else: # don't rename any parameters mcpParamMap = {} cbParamMap = {} removedParamMap = {} for old,new in cbParamMap.iteritems(): for i in range(0,len(new)): maps["param %s %s" % (old, i)] = new[i] # Local variable map - position in source -> name; derived from MCP rangemap if lvRangeMapFile is not None: readLocalVariableMap(lvRangeMapFile, maps, invClassMap, invMethodMap, invMethodSigMap, srcRoot) if dumpRenameMap: for key in sorted(maps.keys()): newName = maps[key] print "RENAME MAP: %s -> %s" % (key, newName) return maps, importMaps
def getConstructor(key): tokens = key.split(" ", 2) # TODO: switch to non-conflicting separator..types can have spaces :( if tokens[0] != "method": return None print tokens kind, fullMethodName, methodSig = tokens if methodSig[-1] != "V": return None # constructors marked with 'V' return type signature in ApplySrg2Source and MCP fullClassName = srglib.splitPackageName(fullMethodName) methodName = srglib.splitBaseName(fullMethodName) packageName = srglib.splitPackageName(fullClassName) className = srglib.splitBaseName(fullClassName) if className == methodName: # constructor has same name as class return fullClassName else: return None
def getNewName(key, oldName, renameMap, shouldAnnotate): if key.startswith("localvar"): # Temporary hack to rename local variables without a mapping # This is not accurate.. variables are not always monotonic nor sequential # TODO: extract local variable map from MCP source with same tool, range map -> local var newName = "var%s" % ((int(key.split(" ")[-1]) + 1),) else: if not renameMap.has_key(key): constructorClassName = getConstructor(key) if constructorClassName is not None: # Constructors are not in the method map (from .srg, and can't be derived # exclusively from the class map since we don't know all the parameters).. so we # have to synthesize a rename from the class map here. Ugh..but, it works. print "FOUND CONSTR", key, constructorClassName if renameMap.has_key("class " + constructorClassName): # Rename constructor to new class name newName = srglib.splitBaseName(renameMap["class " + constructorClassName]) else: return None else: # Not renaming this return None else: newName = renameMap[key] if shouldAnnotate: newName = newName + "/*was:" + oldName + "*/" return newName
def readLocalVariableMap(filename, renameMaps, invClassMap, invMethodMap, invMethodSigMap, srcRoot): for line in file(filename).readlines(): tokens = line.strip().split("|") if tokens[0] != "@": continue absFilename, startRangeStr, endRangeStr, expectedOldText, kind = tokens[1:6] filename = getProjectRelativePath(absFilename, srcRoot) startRange = int(startRangeStr) endRange = int(endRangeStr) info = tokens[6:] if kind != "localvar": continue mcpClassName, mcpMethodName, mcpMethodSignature, variableName, variableIndex = info mcpClassName = srglib.sourceName2Internal(mcpClassName) # Range map has MCP names, but we need to map from CB if not invClassMap.has_key(mcpClassName): className = "net.minecraft.server." + srglib.splitBaseName(mcpClassName) # fake it, assuming CB mc-dev will choose similar name to MCP print "WARNING: readLocalVariableMap: no CB class name for MCP class name '%s', using %s" % (mcpClassName, className) else: className = invClassMap[mcpClassName] if mcpMethodName == "{}": # Initializer - no name methodName = className + "/{}" methodSignature = "" elif srglib.splitBaseName(mcpClassName) == mcpMethodName: # Constructor - same name as class methodName = className + "/" + srglib.splitBaseName(className) methodSignature = srglib.remapSig(mcpMethodSignature, invClassMap) else: # Normal method key = mcpClassName+"/"+mcpMethodName+" "+mcpMethodSignature if not invMethodMap.has_key(key): print "NOTICE: local variables available for %s but no inverse method map; skipping" % (key,) # probably a changed signature continue methodName = invMethodMap[key] methodSignature = invMethodSigMap[key] key = "localvar "+methodName+" "+methodSignature+" "+str(variableIndex) renameMaps[key] = expectedOldText # existing name
def main(): packageMap, classMap, fieldMap, methodMap, methodSigMap = srglib.readSrg(sys.argv[1]) oldNames = {} for oldFull, newFull in fieldMap.iteritems(): oldName = srglib.splitBaseName(oldFull) newName = srglib.splitBaseName(newFull) if oldName == newName: continue # skip un-renamed #print oldName,newName,oldFull,newFull if not oldNames.has_key(oldName): oldNames[oldName] = [] oldNames[oldName].append((newName,oldFull,newFull)) print for oldName, newNames in oldNames.iteritems(): obfNames = uniq([x for x,y,z in newNames]) print len(obfNames),oldName,[newNames]
def getRenameMaps(srgFiles, mcpConfDir, mcpRangeMapFile, dumpRenameMap, srcRoot): maps = {} importMaps = {} # CB -> packaged MCP class/field/method _notReallyThePackageMap, classMap, fieldMap, methodMap, methodSigMap = srglib.readMultipleSrgs(srgFiles) for old, new in classMap.iteritems(): maps["class " + old] = srglib.splitBaseName(new) importMaps["class " + old] = srglib.internalName2Source(new) # when renaming class, need to import it, too for old, new in fieldMap.iteritems(): maps["field " + old] = srglib.splitBaseName(new) for old, new in methodMap.iteritems(): maps["method " + old] = srglib.splitBaseName(new) # CB class -> MCP package name for cbClass, mcpClass in classMap.iteritems(): cbFile = "src/main/java/" + cbClass + ".java" mcpPackage = srglib.splitPackageName(mcpClass) maps["package " + cbClass] = srglib.internalName2Source(mcpPackage) # Read parameter map.. it comes from MCP with MCP namings, so have to remap to CB mcpParamMap = srglib.readParameterMap(mcpConfDir) invMethodMap, invMethodSigMap = srglib.invertMethodMap(methodMap, methodSigMap) invClassMap = srglib.invertDict(classMap) cbParamMap, removedParamMap = srglib.remapParameterMap(mcpParamMap, invMethodMap, invMethodSigMap, invClassMap) # removedParamMap = methods in FML/MCP repackaged+joined but not CB = client-only methods for old, new in cbParamMap.iteritems(): for i in range(0, len(new)): maps["param %s %s" % (old, i)] = new[i] # Local variable map - position in source -> name; derived from MCP rangemap readLocalVariableMap(mcpRangeMapFile, maps, invClassMap, invMethodMap, invMethodSigMap, srcRoot) if dumpRenameMap: for key in sorted(maps.keys()): newName = maps[key] print "RENAME MAP: %s -> %s" % (key, newName) return maps, importMaps
def main(): packageMap, classMap, fieldMap, methodMap, methodSigMap = srglib.readSrg( sys.argv[1]) oldNames = {} for oldFull, newFull in fieldMap.iteritems(): oldName = srglib.splitBaseName(oldFull) newName = srglib.splitBaseName(newFull) if oldName == newName: continue # skip un-renamed #print oldName,newName,oldFull,newFull if not oldNames.has_key(oldName): oldNames[oldName] = [] oldNames[oldName].append((newName, oldFull, newFull)) print for oldName, newNames in oldNames.iteritems(): obfNames = uniq([x for x, y, z in newNames]) print len(obfNames), oldName, [newNames]
def getNewName(key, oldName, renameMap, shouldAnnotate): if not renameMap.has_key(key): constructorClassName = getConstructor(key) if constructorClassName is not None: # Constructors are not in the method map (from .srg, and can't be derived # exclusively from the class map since we don't know all the parameters).. so we # have to synthesize a rename from the class map here. Ugh..but, it works. print "FOUND CONSTR",key,constructorClassName if renameMap.has_key("class "+constructorClassName): # Rename constructor to new class name newName = srglib.splitBaseName(renameMap["class "+constructorClassName]) else: return None else: # Not renaming this return None else: newName = renameMap[key] if shouldAnnotate: newName = newName+"/*was:"+oldName+"*/" return newName
def isUnmappedCB(s): return len(srglib.splitBaseName(s)) < 3
def processJavaSourceFile(srcRoot, filename, rangeList, renameMap, importMap, shouldAnnotate, options): path = os.path.join(options.srcRoot, filename) data = file(path).read() if "\r" in data: # BlockJukebox is the only file with CRLF line endings in NMS.. and.. IntelliJ IDEA treats offsets # as line endings being one character, whether LF or CR+LF. So remove the extraneous character or # offsets will be all off :. print "Warning: %s has CRLF line endings; consider switching to LF" % (filename,) data = data.replace("\r", "") importsToAdd = set() shift = 0 # Existing package/class name (with package, internal) derived from filename oldTopLevelClassFullName = getTopLevelClassForFilename(filename) oldTopLevelClassPackage = srglib.splitPackageName(oldTopLevelClassFullName) oldTopLevelClassName = srglib.splitBaseName(oldTopLevelClassFullName) # New package/class name through mapping newTopLevelClassPackage = srglib.sourceName2Internal(renameMap.get("package "+oldTopLevelClassFullName)) newTopLevelClassName = renameMap.get("class "+oldTopLevelClassFullName) if newTopLevelClassPackage is not None and newTopLevelClassName is None: assert False, "filename %s found package %s->%s but no class map for %s" % (filename, oldTopLevelClassPackage, newTopLevelClassPackage, newTopLevelClassName) if newTopLevelClassPackage is None and newTopLevelClassName is not None: assert False, "filename %s found class map %s->%s but no package map for %s" % (filename, oldTopLevelClassName, newTopLevelClassName, oldTopLevelClassPackage) for start,end,expectedOldText,key in rangeList: if renameMap.has_key(key) and len(renameMap[key]) == 0: # Replacing a symbol with no text = removing a symbol assert key.startswith("package "), "unable to remove non-package symbol %s" % (key,) # Remove that pesky extra period after qualified package names end += 1 expectedOldText += "." oldName = data[start+shift:end+shift] assert oldName == expectedOldText, "Rename sanity check failed: expected '%s' at [%s,%s] (shifted %s to [%s,%s]) in %s, but found '%s'\nRegenerate symbol map on latest sources or start with fresh source and try again" % ( expectedOldText, start, end, shift, start+shift, end+shift, filename, oldName) newName = getNewName(key, oldName, renameMap, shouldAnnotate) if newName is None: print "No rename for "+key continue print "Rename",key,[start+shift,end+shift],"::",oldName,"->",newName if importMap.has_key(key): # This rename requires adding an import, if it crosses packages importPackage = srglib.splitPackageName(srglib.sourceName2Internal(importMap[key])) if importPackage != newTopLevelClassPackage: importsToAdd.add(importMap[key]) # Rename algorithm: # 1. textually replace text at specified range with new text # 2. shift future ranges by difference in text length data = data[0:start+shift] + newName + data[end+shift:] shift += len(newName) - len(oldName) # Lastly, update imports - this is separate from symbol range manipulation above data = updateImports(data, importsToAdd, importMap) if options.rewriteFiles: print "Writing",filename file(path,"w").write(data) if options.renameFiles: if newTopLevelClassPackage is not None: # rename if package changed newFilename = os.path.join("src/main/java/", newTopLevelClassPackage, newTopLevelClassName + ".java") newPath = os.path.join(options.srcRoot, newFilename) print "Rename file",filename,"->",newFilename if filename != newFilename: # Create any missing directories in new path dirComponents = os.path.dirname(newPath).split(os.path.sep) for i in range(2,len(dirComponents)+1): intermediateDir = os.path.sep.join(dirComponents[0:i]) if not os.path.exists(intermediateDir): os.mkdir(intermediateDir) #os.rename(path, newPath) wd = os.getcwd() os.chdir(options.srcRoot) cmd = "git mv '%s' '%s'" % (filename, newFilename) # warning: if filename contains quotes.. status = os.system(cmd) assert status == 0, "Failed to execute rename command: %s" % (cmd,) os.chdir(wd)
def processJavaSourceFile(filename, rangeList, renameMap, importMap, renameLocalVars, shouldAnnotate): path = os.path.join(srcRoot, filename) data = file(path).read() if "\r" in data: # BlockJukebox is the only file with CRLF line endings in NMS.. and.. IntelliJ IDEA treats offsets # as line endings being one character, whether LF or CR+LF. So remove the extraneous character or # offsets will be all off :. print "Warning: %s has CRLF line endings; consider switching to LF" % (filename,) data = data.replace("\r", "") importsToAdd = set() shift = 0 # Existing package/class name (with package, internal) derived from filename oldTopLevelClassFullName = getTopLevelClassForFilename(filename) oldTopLevelClassPackage = srglib.splitPackageName(oldTopLevelClassFullName) oldTopLevelClassName = srglib.splitBaseName(oldTopLevelClassFullName) # New package/class name through mapping newTopLevelClassPackage = srglib.sourceName2Internal(renameMap.get("package " + oldTopLevelClassFullName)) newTopLevelClassName = renameMap.get("class " + oldTopLevelClassFullName) if newTopLevelClassPackage is not None and newTopLevelClassName is None: assert False, "filename %s found package %s->%s but no class map for %s" % ( filename, oldTopLevelClassPackage, newTopLevelClassPackage, newTopLevelClassName, ) if newTopLevelClassPackage is None and newTopLevelClassName is not None: assert False, "filename %s found class map %s->%s but no package map for %s" % ( filename, oldTopLevelClassName, newTopLevelClassName, oldTopLevelClassPackage, ) for start, end, expectedOldText, key in rangeList: if renameMap.has_key(key) and len(renameMap[key]) == 0: # Replacing a symbol with no text = removing a symbol assert key.startswith("package "), "unable to remove non-package symbol %s" % (key,) # Remove that pesky extra period after qualified package names end += 1 expectedOldText += "." if renameLocalVars == False and key.startswith("localvar"): # non-NMS, no need to rename local variables continue oldName = data[start + shift : end + shift] if oldName != expectedOldText: print "Rename sanity check failed: expected '%s' at [%s,%s] (shifted %s to [%s,%s]) in %s, but found '%s'" % ( expectedOldText, start, end, shift, start + shift, end + shift, filename, oldName, ) print "Regenerate symbol map on latest sources or start with fresh source and try again" # file("/tmp/a","w").write(data) raise SystemExit newName = getNewName(key, oldName, renameMap, shouldAnnotate) if newName is None: print "No rename for " + key continue print "Rename", key, [start + shift, end + shift], "::", oldName, "->", newName if importMap.has_key(key): # this rename requires adding an import importsToAdd.add(importMap[key]) # Rename algorithm: # 1. textually replace text at specified range with new text # 2. shift future ranges by difference in text length data = data[0 : start + shift] + newName + data[end + shift :] shift += len(newName) - len(oldName) # Lastly, update imports - this is separate from symbol range manipulation above data = updateImports(data, importsToAdd, importMap) if rewriteFiles: print "Writing", filename file(path, "w").write(data) if renameFiles: if newTopLevelClassPackage is not None: # rename if package changed newFilename = os.path.join( srcRoot, "src/main/java/", newTopLevelClassPackage, newTopLevelClassName + ".java" ) newPath = os.path.join(srcRoot, newFilename) print "Rename file", filename, "->", newFilename srglib.rename_path(path, newPath)
def processJavaSourceFile(srcRoot, filename, rangeList, renameMap, importMap, shouldAnnotate, options): path = os.path.join(options.srcRoot, filename) data = file(path).read() if "\r" in data: # BlockJukebox is the only file with CRLF line endings in NMS.. and.. IntelliJ IDEA treats offsets # as line endings being one character, whether LF or CR+LF. So remove the extraneous character or # offsets will be all off :. print "Warning: %s has CRLF line endings; consider switching to LF" % (filename,) data = data.replace("\r", "") importsToAdd = set() shift = 0 # Existing package/class name (with package, internal) derived from filename oldTopLevelClassFullName = getTopLevelClassForFilename(filename) oldTopLevelClassPackage = srglib.splitPackageName(oldTopLevelClassFullName) oldTopLevelClassName = srglib.splitBaseName(oldTopLevelClassFullName) # New package/class name through mapping newTopLevelClassPackage = srglib.sourceName2Internal(renameMap.get("package "+oldTopLevelClassFullName)) newTopLevelClassName = renameMap.get("class "+oldTopLevelClassFullName) if newTopLevelClassPackage is not None and newTopLevelClassName is None: assert False, "filename %s found package %s->%s but no class map for %s" % (filename, oldTopLevelClassPackage, newTopLevelClassPackage, newTopLevelClassName) if newTopLevelClassPackage is None and newTopLevelClassName is not None: assert False, "filename %s found class map %s->%s but no package map for %s" % (filename, oldTopLevelClassName, newTopLevelClassName, oldTopLevelClassPackage) for start,end,expectedOldText,key in rangeList: if renameMap.has_key(key) and len(renameMap[key]) == 0: # Replacing a symbol with no text = removing a symbol assert key.startswith("package "), "unable to remove non-package symbol %s" % (key,) # Remove that pesky extra period after qualified package names end += 1 expectedOldText += "." oldName = data[start+shift:end+shift] assert oldName == expectedOldText, "Rename sanity check failed: expected '%s' at [%s,%s] (shifted %s to [%s,%s]) in %s, but found '%s'\nRegenerate symbol map on latest sources or start with fresh source and try again" % ( expectedOldText, start, end, shift, start+shift, end+shift, filename, oldName) newName = getNewName(key, oldName, renameMap, shouldAnnotate) if newName is None: print "No rename for "+key continue print "Rename",key,[start+shift,end+shift],"::",oldName,"->",newName if importMap.has_key(key): # This rename requires adding an import, if it crosses packages importPackage = srglib.splitPackageName(srglib.sourceName2Internal(importMap[key])) if importPackage != newTopLevelClassPackage: importsToAdd.add(importMap[key]) # Rename algorithm: # 1. textually replace text at specified range with new text # 2. shift future ranges by difference in text length data = data[0:start+shift] + newName + data[end+shift:] shift += len(newName) - len(oldName) # Lastly, update imports - this is separate from symbol range manipulation above data = updateImports(data, importsToAdd, importMap) if options.rewriteFiles: print "Writing",filename file(path,"w").write(data) if options.renameFiles: if newTopLevelClassPackage is not None: # rename if package changed newFilename = os.path.join("src/main/java/", newTopLevelClassPackage, newTopLevelClassName + ".java") newPath = os.path.join(options.srcRoot, newFilename) print "Rename file",filename,"->",newFilename if filename != newFilename: # Create any missing directories in new path dirComponents = os.path.dirname(newPath).split(SEP) for i in range(2,len(dirComponents)+1): intermediateDir = os.path.sep.join(dirComponents[0:i]) if not os.path.exists(intermediateDir): os.mkdir(intermediateDir) #os.rename(path, newPath) wd = os.getcwd() os.chdir(options.srcRoot) cmd = "%s mv '%s' '%s'" % (options.git, filename, newFilename) # warning: if filename contains quotes.. status = os.system(cmd) assert status == 0, "Failed to execute rename command: %s" % (cmd,) os.chdir(wd)
#!/usr/bin/python # Filter srg removing names that didn't change import sys import srglib for line in sys.stdin.readlines(): line = line.strip() tokens = line.split(" ") kind = tokens[0] args = tokens[1:] if kind == "PK:": # package print line elif kind == "CL:": # class inName, outName = args if inName != outName: print kind, inName, outName elif kind == "FD:": # field inName, outName = args if srglib.splitBaseName(inName) != srglib.splitBaseName(outName): print kind, inName, outName elif kind == "MD:": # method inName, inSig, outName, outSig = args if srglib.splitBaseName(inName) != srglib.splitBaseName(outName): print kind, inName, inSig, outName, outSig else: print line