| #!/usr/bin/env python | 
 | # | 
 | # Copyright 2008 Google Inc. | 
 | # | 
 | # Licensed under the Apache License, Version 2.0 (the "License"); | 
 | # you may not use this file except in compliance with the License. | 
 | # You may obtain a copy of the License at | 
 | # | 
 | #     http://www.apache.org/licenses/LICENSE-2.0 | 
 | # | 
 | # Unless required by applicable law or agreed to in writing, software | 
 | # distributed under the License is distributed on an "AS IS" BASIS, | 
 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | # See the License for the specific language governing permissions and | 
 | # limitations under the License. | 
 | # | 
 |  | 
 | """drtool is for moving your wiki documents between googlecode projects. | 
 |  | 
 | drtool actually does three things: | 
 |   - copy all of your wiki documentation between googlecode projects. This is | 
 |     done via the "copy" command. References to a project will be changed during | 
 |     the move. | 
 |  | 
 |   - tell you what wiki pages are not referenced by your docreader-enabled | 
 |     TableOfContents page. Use "nothave" or "orphans" or "list-orphans" for | 
 |     this. | 
 |  | 
 |   - find all of the http references to your subversion repository in your wiki | 
 |     docs. "references" or "refs". | 
 |  | 
 | It's assumed that you have svn checkouts of both projects. | 
 | """ | 
 |  | 
 | import sys | 
 | import shutil | 
 | import re | 
 | import os.path | 
 | import glob | 
 | import TOCNode | 
 | from BuildGlobalTOC import BuildTOC | 
 |  | 
 | NOTHAVE = ["nothave", "orphans", "list-orphans"] | 
 | REFERENCES = ["references", "refs"] | 
 | COPY = ["copy"] | 
 |  | 
 | wikipatterns = {} | 
 | svnpatterns = {} | 
 |  | 
 | def getpattern(table, template, projectname): | 
 |   if table.has_key(projectname): | 
 |     return table[projectname] | 
 |   else: | 
 |     pattern = (template % projectname) | 
 |     compiled = re.compile(pattern) | 
 |     table[projectname] = compiled | 
 |     return compiled | 
 |  | 
 | def wikipattern(projectname): | 
 |   return getpattern(wikipatterns, | 
 |                     "http://code.google.com/p/(%s)/wiki/([^\s\]]+)", | 
 |                     projectname) | 
 |  | 
 | def svnpattern(projectname): | 
 |   return getpattern(svnpatterns, | 
 |                     "http://(%s).googlecode.com([^\s\]]+)", | 
 |                     projectname) | 
 |  | 
 | def change_ref(link, oldproject, newproject): | 
 |   return link.replace(oldproject, newproject) | 
 |  | 
 | def change_references(bytes, oldprojectname, newprojectname): | 
 |   """Returns the string that is the new text for the wiki page, with all | 
 |   of the references changed to point to the new project.""" | 
 |  | 
 |   svn = svnpattern(oldprojectname) | 
 |   wiki = wikipattern(oldprojectname) | 
 |  | 
 |   postsvn = "" | 
 |   postwiki = "" | 
 |   ## step one, do all the svn references. | 
 |   svnreferences = re.finditer(svn, bytes) | 
 |   append_start = 0 | 
 |  | 
 |   for match in svnreferences: | 
 |     matchstart, matchend = match.span() | 
 |  | 
 |     ## take all of the stuff from the end of the last match to the beginning | 
 |     ## of this one and append it to the output. | 
 |     postsvn += bytes[append_start:matchstart] | 
 |  | 
 |     ## append the version of this match with the project names replaced | 
 |     postsvn += change_ref(match.group(0), oldprojectname, newprojectname) | 
 |     append_start = matchend | 
 |   postsvn += bytes[append_start:] | 
 |  | 
 |   ## step two, do all the wiki references (should be rarer?) | 
 |   wikireferences = re.finditer(wiki, postsvn) | 
 |   append_start = 0 | 
 |  | 
 |   for match in wikireferences: | 
 |     matchstart, matchend = match.span() | 
 |  | 
 |     ## take all of the stuff from the end of the last match to the beginning | 
 |     ## of this one and append it to the output. | 
 |     postwiki += postsvn[append_start:matchstart] | 
 |  | 
 |     ## append the version of this match with the project names replaced | 
 |     postwiki += change_ref(match.group(0), | 
 |                            oldprojectname, | 
 |                            newprojectname) | 
 |     append_start = matchend | 
 |   postwiki += postsvn[append_start:] | 
 |  | 
 |   return postwiki | 
 |  | 
 | def find_references(bytes, projectname, fn): | 
 |   """Return a list of all the references to a given project in this string""" | 
 |   def find_refs(pattern): | 
 |     compiled = re.compile(pattern) | 
 |     refs  = re.findall(compiled, bytes) | 
 |     return refs | 
 |  | 
 |   svn = svnpattern(projectname) | 
 |   wiki = wikipattern(projectname) | 
 |  | 
 |   return find_refs(svn) + find_refs(wiki) | 
 |  | 
 | def print_references(bytes, projectname, fn): | 
 |   refs = find_references(bytes, projectname, fn) | 
 |   if refs: | 
 |     print ("** %s" % fn) | 
 |     for ref in refs: | 
 |       print ":::", ref | 
 |  | 
 | def usage(): | 
 |   commands = (", ").join(NOTHAVE + REFERENCES + COPY) | 
 |   print ("usage: %s <cmd> prj1 [prj2]" % sys.argv[0]) | 
 |   print "\tcmd is one of: ", commands  | 
 |   print "\tprj2 is required for 'copy' command" | 
 |  | 
 | def copy_into_target(source_project, target_project, source_path, | 
 |                      relative_filename, target_dir): | 
 |   """Copy one file into the target directory.""" | 
 |   target_path = os.path.join(target_dir, relative_filename) | 
 |  | 
 |   if relative_filename.endswith(".wiki"): | 
 |     infile = open(source_path) | 
 |     bytes = infile.read() | 
 |     changed = change_references(bytes, source_project, target_project) | 
 |  | 
 |     head,tail = os.path.split(target_path) | 
 |     if not os.path.isdir(head): | 
 |       os.makedirs(head) | 
 |  | 
 |     outfile = open(target_path, "w") | 
 |     outfile.write(changed) | 
 |     outfile.close() | 
 |  | 
 |     # print ("%s: changed references, wrote into %s." % | 
 |     #        (relative_filename, target_project) ) | 
 |   else: | 
 |     shutil.copyfile(source_path, target_path) | 
 |     # print ("%s: not a wiki file, copied into the new %s" % | 
 |     #        (relative_filename, target_project)) | 
 |  | 
 |   pass | 
 |  | 
 | def find_wikipath(target): | 
 |   normalized = os.path.normpath(target) | 
 |  | 
 |   if not normalized.endswith("/wiki"): | 
 |     normalized += "/wiki" | 
 |   return normalized | 
 |  | 
 | def all_wiki_docs(wikipath): | 
 |   """All of the .wiki files in our wiki directory, with paths, recursively.""" | 
 |   out = [] | 
 |   for root, dirs, fileshere in os.walk(wikipath): | 
 |     path_elements = root.split(os.sep) | 
 |     if ".svn" in path_elements: | 
 |       continue | 
 |  | 
 |     for fn in fileshere: | 
 |       if fn.endswith(".wiki"): | 
 |         whole_pathname = os.path.join(root, fn) | 
 |         out.append(whole_pathname) | 
 |   return out | 
 |  | 
 | def nothave(wikipath, projectname): | 
 |   toc_path = wikipath + os.path.sep + "TableOfContents.wiki" | 
 |   if not os.path.exists(toc_path): | 
 |     print "Could not find TableOfContents.wiki for that project." | 
 |     return | 
 |  | 
 |   listed = BuildTOC(toc_path, projectname) | 
 |   all_wiki_pages = all_wiki_docs(wikipath) | 
 |  | 
 |   ## run through every .wiki file (recursively under the wiki directory, and if | 
 |   ## it's not mentioned in the TOC, print it out. | 
 |  | 
 |   for wikipage in all_wiki_pages: | 
 |     basename = os.path.basename(wikipage) | 
 |     wikiword = basename[:-5] | 
 |     node = TOCNode.lookup(wikiword) | 
 |  | 
 |     if not node: | 
 |       print " ", wikipage | 
 |  | 
 | def file_references(fn, projectname): | 
 |   infile = open(fn) | 
 |   bytes = infile.read() | 
 |   print_references(bytes, projectname, fn) | 
 |  | 
 | def references(wikipath, projectname): | 
 |   wikipaths = all_wiki_docs(wikipath) | 
 |  | 
 |   for wikipath  in wikipaths: | 
 |     file_references(wikipath, projectname) | 
 |  | 
 | def wikicopy(source_dir, source_project, target_dir, target_project): | 
 |   print "Copying from", source_project, | 
 |   print "to", target_project, "and changing references...", | 
 |  | 
 |   ## Walk every file in source_dir. Skip .svn directories. | 
 |   for root, dirs, fileshere in os.walk(source_dir): | 
 |     path_elements = root.split(os.sep) | 
 |     if ".svn" in path_elements: | 
 |       continue | 
 |  | 
 |     for filename in fileshere: | 
 |       ## Find the part of the path after source_dir | 
 |       whole_pathname = os.path.join(root, filename) | 
 |       after_source_dir = whole_pathname[len(source_dir):] | 
 |       if after_source_dir.startswith("/"): | 
 |         after_source_dir = after_source_dir[1:] | 
 |  | 
 |       copy_into_target(source_project, target_project, whole_pathname, | 
 |                        after_source_dir, target_dir) | 
 |  | 
 |   print "OK!" | 
 |   ## Warn about wiki pages that are not referenced by TOC. | 
 |   print "Careful: these wiki pages aren't referenced in your TableOfContents:" | 
 |   nothave(source_dir, source_project) | 
 |   print "Done." | 
 |  | 
 | def main(argv): | 
 |   if len(argv) < 3: | 
 |     usage() | 
 |     return | 
 |  | 
 |   source_dir = find_wikipath(argv[2]) | 
 |   source_projectname = source_dir.split(os.path.sep)[-2] | 
 |  | 
 |   if len(argv) > 3: | 
 |     target_dir = find_wikipath(argv[3]) | 
 |     target_projectname = target_dir.split(os.path.sep)[-2] | 
 |  | 
 |   if argv[1] in NOTHAVE: | 
 |     nothave(source_dir, source_projectname) | 
 |   elif argv[1] in REFERENCES: | 
 |     references(source_dir, source_projectname) | 
 |   elif argv[1] in COPY: | 
 |     if not target_dir: | 
 |       usage() | 
 |       return | 
 |     wikicopy(source_dir, source_projectname, target_dir, target_projectname) | 
 |  | 
 | if __name__ == '__main__': | 
 |   main(sys.argv) |