#!/usr/bin/python # Small routine to repackage java sets. # Will change package titles, replace import statements. # Will NOT replace partial package expressions in code # i.e. new package.class () # # Other problems # filename<==>package name at top level # partial hierarchies need some sort of root->newroot # # Should split into # repackage for a single dir # import os import os.path import re import getopt import xreadlines, sys import string dryrun=0 excludes = [] usage="""usage: repackage -P [-R val] [-nhv] [files..dirs] -P change toplevel package name to -n dryrun .. do not change files -h print this message -v print version -R 0 or 1 recurse on directories(default recurse:1) -X [regexp] Exclude any file/dirs matching regexp -r Restore files from previous rewrite """ def normalize_path(name): from os.path import abspath from os.path import expanduser from os.path import expandvars return abspath(expanduser(expandvars (name))) class EditableFile: def __init__(self, name): self.lines = [] self.filename = name self.oplog = [] if name: self.open (name) def open(self, path): try: self.filename = path path = normalize_path(path) tfile = open (path) self.lines = tfile.readlines() tfile.close(); except IOError: print "Unable to open file" + path def save(self, path = ""): if len(self.lines) > 0: if path == "": path = self.filename path = normalize_path(path) #readname,readext = os.path.splitext(path) os.rename(path, path + ".bak") tfile = open (path, "w") tfile.writelines(self.lines) tfile.close(); return path def log(self, str): self.oplog.append (str) # Edit operation def findline(self, key): return self.lines.index(key) def insertline(self, pos, line): return self.lines.insert(pos, line) def appendline(self, line): return self.lines.append(line) def deleteline(self, pos): return self.lines.pop(pos) def countlines(self): return len(self.lines) def findre (self, pattern, begin =0, end = -1): regexp = re.compile (pattern) if end == -1: end = len(self.lines) for l in range(begin,end): if regexp.match(self.lines[l]): return l return None class Javafile(EditableFile): def __init__(self, filename): EditableFile.__init__(self, filename) # self.log("opened " + filename) def replace_package (self, packagename): "Replace the package title of the java file" line = self.findre (r'^package ([^;]*);') if line: self.deleteline(line) self.insertline(line, "package " + packagename +";\n") self.log (self.filename + " changed to " + packagename); return 1 line = self.findre ('^import ([^;]*);') if line: self.insertline (line, "package " + packagename +";\n") self.log (self.filename + " changed to " + packagename); return 1 line = self.findre (r'^(public)? *(abstract|final)? *(class|interface) .*') if line: self.insertline (line, "package " + packagename +";\n") self.log (self.filename + " changed to " + packagename); return 1 return 0 def replace_imports(self,packagemap): "replace the local import statements of the package hierarchy" packages = packagemap.keys() packages.sort() line = self.findre ('^import ([^;]*);') while line: for p in packages: aline = self.lines[line] aline = string.replace(aline, p, packagemap[p]) if aline != self.lines[line]: self.lines[line] = aline self.log ("changed import to " + packagemap[p]) break line = self.findre ('^import ([^;]*);', line+1) return def repackage (self, packagename,packmap): r = self.replace_package(packagename) self.replace_imports( packmap) return r class Repackager: def __init__(self, packagename, packagemap, excludelist): self.packagename = packagename self.excludes = [] self.packmap = packagemap self.recursive = 1 for rex in excludelist: print "excluding: ", rex self.excludes.append (re.compile (rex)) def match_excludes(self,name): for rex in self.excludes: if rex.match (name): return 1 return 0 def repackage_file(self, filename, packagename): if self.match_excludes(filename): return jf = Javafile(filename) if jf.repackage(packagename, self.packmap): if dryrun: print "Repackaged %s to %s" % (filename,packagename) print jf.oplog return jf.save() def recurse (self, dirname, packagename): for f in os.listdir(dirname): if self.match_excludes(f): print "Skipping ", f continue fname = dirname + '/' + f if os.path.isdir(fname) : # packmap[dirname+'.'+f] = packagename+'.'+f self.recurse(fname, packagename+'.'+f) if os.path.splitext(fname)[1] == ".java": self.repackage_file(fname, packagename) def create_packmap (self, dirname, packname, packmap): """ Preprocess a set of directory to determine a new set of package names. This will allow the import statements to be remapped in a sensible way""" for f in os.listdir(dirname): fname = dirname + '/' + f if os.path.isdir(fname) : packmap[dirname+'.'+f] = packname+'.'+f self.create_packmap(fname, packname+'.'+f, packmap) def restore(dirname): """Recurse through the directories replacing the new file with the backup files""" for f in os.listdir(dirname): fname = dirname +'/'+f if os.path.isdir(fname): print "recursing in ",f restore (fname) else: parts=os.path.splitext(fname) if parts[1]==".bak": print "renaming %s to %s" % (fname, parts[0]) os.rename(fname, parts[0]) if __name__ == '__main__': packagename = "" packmap = {} recursive = 1 options, args =getopt.getopt(sys.argv[1:], 'P:R:nhvX:r') arg_restore = 0 for option in options: if option[0] == "-P": packagename = option[1] elif option[0] == "-R": recursive = option[1] elif option[0] == "-n": dryrun = 1 elif option[0] == "-v": print >>sys.stderr, "repackage version 0.9" elif option[0] == "-h": print >> sys.stderr, usage elif option[0] == "-X": excludes.append(option[1]) elif option[0] == "-r": arg_restore=1 if arg_restore: for filename in args: restore(filename) sys.exit(0) if not packagename: print >>sys.stderr, "Please give me package name" print >>sys.stderr, usage sys.exit(0) rp = Repackager(packagename, packmap, excludes) for filename in args: if os.path.isdir (filename) : if recursive: packmap = { filename : packagename } rp.create_packmap (filename, packagename, packmap) rp.packmap = packmap rp.recurse(filename, packagename) continue if os.path.splitext(filename)[1] == ".java": rp.repackage_file(filename, packagename)