|  | #!/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) |