def readRangeMap(filename, srcRoot): rangeMap = {} 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 not rangeMap.has_key(filename): rangeMap[filename] = [] # Build unique identifier for symbol if kind == "package": packageName, forClass = info #key = "package "+packageName # ignore old name (unique identifier is filename) if forClass == "(file)": forClass = getTopLevelClassForFilename(filename) else: forClass = srglib.sourceName2Internal(forClass) # . -> / # 'forClass' is the class that is in this package; when the class is # remapped to a different package, this range should be updated key = "package "+forClass elif kind == "class": className, = info key = "class "+srglib.sourceName2Internal(className) elif kind == "field": className, fieldName = info key = "field "+srglib.sourceName2Internal(className)+"/"+fieldName elif kind == "method": if expectedOldText in ("super", "this"): continue # hack: avoid erroneously replacing super/this calls className, methodName, methodSignature = info key = "method "+srglib.sourceName2Internal(className)+"/"+methodName+" "+methodSignature elif kind == "param": className, methodName, methodSignature, parameterName, parameterIndex = info key = "param "+srglib.sourceName2Internal(className)+"/"+methodName+" "+methodSignature+" "+str(parameterIndex) # ignore old name (positional) elif kind == "localvar": className, methodName, methodSignature, variableName, variableIndex = info key = "localvar "+srglib.sourceName2Internal(className)+"/"+methodName+" "+methodSignature+" "+str(variableIndex) # ignore old name (positional) else: assert False, "Unknown kind: "+kind # Map to range rangeMap[filename].append((startRange, endRange, expectedOldText, key)) # Sort and check for filename in sorted(rangeMap.keys()): sortRangeList(rangeMap[filename], filename) return rangeMap
def readRangeMap(filename, srcRoot): rangeMap = {} 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 not rangeMap.has_key(filename): rangeMap[filename] = [] # Build unique identifier for symbol if kind == "package": packageName, forClass = info #key = "package "+packageName # ignore old name (unique identifier is filename) if forClass == "(file)": forClass = getTopLevelClassForFilename(filename) else: forClass = srglib.sourceName2Internal(forClass) # . -> / # 'forClass' is the class that is in this package; when the class is # remapped to a different package, this range should be updated key = "package "+forClass elif kind == "class": className, = info key = "class "+srglib.sourceName2Internal(className) elif kind == "field": className, fieldName = info key = "field "+srglib.sourceName2Internal(className)+"/"+fieldName elif kind == "method": if expectedOldText in ("super", "this"): continue # hack: avoid erroneously replacing super/this calls className, methodName, methodSignature = info key = "method "+srglib.sourceName2Internal(className)+"/"+methodName+" "+methodSignature elif kind == "param": className, methodName, methodSignature, parameterName, parameterIndex = info key = "param "+srglib.sourceName2Internal(className)+"/"+methodName+" "+methodSignature+" "+str(parameterIndex) # ignore old name (positional) elif kind == "localvar": className, methodName, methodSignature, variableName, variableIndex = info key = "localvar "+srglib.sourceName2Internal(className)+"/"+methodName+" "+methodSignature+" "+str(variableIndex) # ignore old name (positional) else: assert False, "Unknown kind: "+kind # Map to range rangeMap[filename].append((startRange, endRange, expectedOldText, key)) # Sort and check for filename in sorted(rangeMap.keys()): sortRangeList(rangeMap[filename], filename) return rangeMap
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 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 updateImports(data, newImports, importMap): lines = data.split("\n") # Parse the existing imports and find out where to add ours # This doesn't use Psi.. but the syntax is easy enough to parse here newLines = [] addedNewImports = False newImportLines = [] for imp in sorted(list(newImports)): newImportLines.append("import %s;" % (imp,)) for i, line in enumerate(lines): if line.startswith("import net.minecraft"): # Add our new imports first, before existing NMS imports if not addedNewImports: print "Adding %s imports" % (len(newImportLines)) newLines.extend(newImportLines) addedNewImports = True # If no import map, *remove* NMS imports (OBC rewritten with fully-qualified names) if len(importMap) == 0: continue # Rewrite NMS imports oldClass = line.replace("import ", "").replace(";", "") print oldClass if oldClass == "net.minecraft.server.*": # wildcard NMS imports (CraftWorld, CraftEntity, CraftPlayer).. bad idea continue else: newClass = importMap["class " + srglib.sourceName2Internal(oldClass)] newLine = "import %s;" % (newClass,) if newLine not in newImportLines: # if not already added newLines.append(newLine) else: newLines.append(line) if not addedNewImports: newLines = newLines[0:2] + newImportLines + newLines[2:] return "\n".join(newLines)
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 updateImports(data, newImports, importMap): lines = data.split("\n") # Parse the existing imports and find out where to add ours # This doesn't use Psi.. but the syntax is easy enough to parse here newLines = [] addedNewImports = False newImportLines = [] for imp in sorted(list(newImports)): newImportLines.append("import %s;" % (imp,)) sawImports = False for i, line in enumerate(lines): if line.startswith("import "): sawImports = True if line.startswith("import net.minecraft."): # If no import map, *remove* NMS imports (OBC rewritten with fully-qualified names) if len(importMap) == 0: continue # Rewrite NMS imports oldClass = line.replace("import ", "").replace(";", ""); print oldClass if oldClass == "net.minecraft.server.*": # wildcard NMS imports (CraftWorld, CraftEntity, CraftPlayer).. bad idea continue else: newClass = importMap["class "+srglib.sourceName2Internal(oldClass)] newLine = "import %s;" % (newClass,) if newLine not in newImportLines: # if not already added newLines.append(newLine) else: newLines.append(line) else: if sawImports and not addedNewImports: # Add our new imports right after the last import print "Adding %s imports" % (len(newImportLines,)) newLines.extend(newImportLines) addedNewImports = True newLines.append(line) if not addedNewImports: newLines = newLines[0:2] + newImportLines + newLines[2:] newData = "\n".join(newLines) # Warning: ugly hack ahead # The symbol range map extractor is supposed to emit package reference ranges, which we can # update with the correct new package names. However, it has a bug where the package ranges # are not always emitted on fully-qualified names. For example: (net.minecraft.server.X)Y - a # cast - will fail to recognize the net.minecraft.server package, so it won't be processed by us. # This leads to some qualified names in the original source to becoming "overqualified", that is, # net.minecraft.server.net.minecraft.X; the NMS class is replaced with its fully-qualified name # (in non-NMS source, where we want it to always be fully-qualified): original package name isn't replaced. # Occurs in OBC source which uses fully-qualified NMS names already, and NMS source which (unnecessarily) # uses fully-qualified NMS names, too. Attempted to fix this problem for longer than I should.. # maybe someone smarter can figure it out -- but until then, in the interest of expediency, I present # this ugly workaround, replacing the overqualified names after-the-fact. # Fortunately, this pattern is easy enough to reliably detect and replace textually! newData = newData.replace("net.minecraft.server.net", "net") # OBC overqualified symbols newData = newData.replace("net.minecraft.server.Block", "Block") # NMS overqualified symbols # ..and qualified inner classes, only one.... last ugly hack, I promise :P newData = newData.replace("net.minecraft.block.BlockSapling/*was:BlockSapling*/.net.minecraft.block.BlockSapling.TreeGenerator", "net.minecraft.block.BlockSapling.TreeGenerator") newData = newData.replace("net.minecraft.block.BlockSapling.net.minecraft.block.BlockSapling.TreeGenerator", "net.minecraft.block.BlockSapling.TreeGenerator") return newData
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)
def updateImports(data, newImports, importMap): lines = data.split("\n") # Parse the existing imports and find out where to add ours # This doesn't use Psi.. but the syntax is easy enough to parse here newLines = [] addedNewImports = False newImportLines = [] for imp in sorted(list(newImports)): newImportLines.append("import %s;" % (imp,)) sawImports = False for i, line in enumerate(lines): if line.startswith("import "): sawImports = True if line.startswith("import net.minecraft."): # If no import map, *remove* NMS imports (OBC rewritten with fully-qualified names) if len(importMap) == 0: continue # Rewrite NMS imports oldClass = line.replace("import ", "").replace(";", ""); print oldClass if oldClass == "net.minecraft.server.*": # wildcard NMS imports (CraftWorld, CraftEntity, CraftPlayer).. bad idea continue else: newClass = importMap["class "+srglib.sourceName2Internal(oldClass)] newLine = "import %s;" % (newClass,) if newLine not in newImportLines: # if not already added newLines.append(newLine) else: newLines.append(line) else: if sawImports and not addedNewImports: # Add our new imports right after the last import print "Adding %s imports" % (len(newImportLines,)) newLines.extend(newImportLines) addedNewImports = True newLines.append(line) if not addedNewImports: newLines = newLines[0:2] + newImportLines + newLines[2:] newData = "\n".join(newLines) # Warning: ugly hack ahead # The symbol range map extractor is supposed to emit package reference ranges, which we can # update with the correct new package names. However, it has a bug where the package ranges # are not always emitted on fully-qualified names. For example: (net.minecraft.server.X)Y - a # cast - will fail to recognize the net.minecraft.server package, so it won't be processed by us. # This leads to some qualified names in the original source to becoming "overqualified", that is, # net.minecraft.server.net.minecraft.X; the NMS class is replaced with its fully-qualified name # (in non-NMS source, where we want it to always be fully-qualified): original package name isn't replaced. # Occurs in OBC source which uses fully-qualified NMS names already, and NMS source which (unnecessarily) # uses fully-qualified NMS names, too. Attempted to fix this problem for longer than I should.. # maybe someone smarter can figure it out -- but until then, in the interest of expediency, I present # this ugly workaround, replacing the overqualified names after-the-fact. # Fortunately, this pattern is easy enough to reliably detect and replace textually! newData = newData.replace("net.minecraft.server.net", "net") # OBC overqualified symbols newData = newData.replace("net.minecraft.server.Block", "Block") # NMS overqualified symbols # ..and qualified inner classes, only one.... last ugly hack, I promise :P newData = newData.replace("net.minecraft.block.BlockSapling/*was:BlockSapling*/.net.minecraft.block.BlockSapling.TreeGenerator", "net.minecraft.block.BlockSapling.TreeGenerator") newData = newData.replace("net.minecraft.block.BlockSapling.net.minecraft.block.BlockSapling.TreeGenerator", "net.minecraft.block.BlockSapling.TreeGenerator") return newData
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)