Chuckmove: a tool for reorganizing Python source trees
diff --git a/xos/tools/chuckmove b/xos/tools/chuckmove
new file mode 100755
index 0000000..09d9f4e
--- /dev/null
+++ b/xos/tools/chuckmove
@@ -0,0 +1,76 @@
+#!/usr/bin/python
+
+from pyparsing import *
+from optparse import OptionParser
+import os
+from os.path import join,exists
+from shutil import copy
+
+usage = "usage: %prog --old <old namespace> --new <new namespace> <directory root>"
+
+parser = OptionParser(usage=usage)
+
+parser.add_option("-q", "--quiet",
+ action="store_false", dest="verbose",
+ help="be vewwy quiet (I'm hunting wabbits)")
+
+parser.add_option("-o", "--old",
+ metavar="old", help="Old namespace")
+
+parser.add_option("-n", "--new",
+ default="new", help="New namespace")
+
+(options, args) = parser.parse_args()
+
+old_ns = options.old
+new_ns = options.new
+
+# grammar
+
+comment = '#' + SkipTo(lineEnd)
+
+module_ns = Word(alphanums + '-' + '_' + '.')
+old_module_ns = Combine(old_ns + Optional(module_ns))
+end_of_python_line = Or([lineEnd,comment])
+
+as_suffix = 'as' + module_ns
+
+import_pure = 'import' + old_module_ns
+import_pure_line = import_pure + Optional(as_suffix) + end_of_python_line
+
+import_from = 'from' + old_module_ns + 'import' + module_ns
+import_from_line = import_from + Optional(as_suffix) + end_of_python_line
+
+import_line = Or([import_pure_line, import_from_line])
+
+# Make a list of Python files to deal with
+
+try:
+ f = args[0]
+except IndexError:
+ print 'Specify a directory root'
+ exit(1)
+
+for root, dirs, files in os.walk(f):
+ for n in files:
+ if (n.endswith('.py')):
+ full_path = '/'.join([root,n])
+ orig_path = full_path + '.orig'
+ print 'Working on %s:'%full_path
+ if (not os.path.exists(orig_path)):
+ print 'Copying %s->%s:'%(full_path,orig_path)
+ copy(full_path, orig_path)
+ f_contents = open(orig_path).read()
+ new_contents = []
+ for l in f_contents.splitlines():
+ try:
+ match = import_line.parseString(l)
+ l = l.replace(old_ns, new_ns)
+ except ParseException:
+ pass
+ new_contents.append(l)
+
+ new_file = '\n'.join(new_contents)
+ if (f_contents.endswith('\n')):
+ new_file+='\n'
+ open(full_path,'w').write(new_file)
diff --git a/xos/tools/chuckmove.README b/xos/tools/chuckmove.README
new file mode 100644
index 0000000..5039548
--- /dev/null
+++ b/xos/tools/chuckmove.README
@@ -0,0 +1,27 @@
+Hi,
+
+I've written a tool called 'chuckmove' for helping move Python modules around in a source tree. You use it as follows. Lets say you want to relocate a module to a different location in the tree, and also rename it. So for instance, x is to become y.z. The syntax you use is:
+
+chuckmove -o x -n y.z <root directory>
+
+Invoking this command makes the tool recursively descend into the root directory, make a backup copy of each file (adding the prefix '.orig') and rewrite the imports in it, so that "import x" gets turned into "import y.z"
+
+It recognizes Python grammar, so it works with all of these forms:
+
+from x import a
+from x.b import c
+import x.d.e.f as foo # Comments are also handled
+
+...with the nit that lines with syntax/grammatical errors are left as is.
+
+For example, for the observer/synchronizer changes, I just had to do the following:
+
+chuckmove -o observer -n synchronizers.base xos
+
+...and then to generate a patch with the changes:
+
+gendiff xos .orig
+
+It's checked into the xos repository under tools (with a README file!).
+
+Sapan