| 1 | #!/usr/bin/python |
| 2 | # |
| 3 | # Check/update default wiki pages from the Trac project website. |
| 4 | # |
| 5 | # Note: This is a development tool used in Trac packaging/QA, not something |
| 6 | # particularly useful for end-users. |
| 7 | # |
| 8 | # Author: Daniel Lundin <daniel@edgewall.com> |
| 9 | |
| 10 | import httplib |
| 11 | import re |
| 12 | import sys |
| 13 | import getopt |
| 14 | |
| 15 | # Pages to include in distribution |
| 16 | wiki_pages = [ |
| 17 | "CamelCase", |
| 18 | "RecentChanges", |
| 19 | "TitleIndex", |
| 20 | "TracAccessibility", |
| 21 | "TracAdmin", |
| 22 | "TracBackup", |
| 23 | "TracBrowser", |
| 24 | "TracCgi", |
| 25 | "TracChangeset", |
| 26 | "TracEnvironment", |
| 27 | "TracFastCgi", |
| 28 | "TracGuide", |
| 29 | "TracImport", |
| 30 | "TracIni", |
| 31 | "TracInstall", |
| 32 | "TracInterfaceCustomization", |
| 33 | "TracLinks", |
| 34 | "TracLogging", |
| 35 | "TracModPython", |
| 36 | "TracNotification", |
| 37 | "TracPermissions", |
| 38 | "TracPlugins", |
| 39 | "TracQuery", |
| 40 | "TracReports", |
| 41 | "TracRoadmap", |
| 42 | "TracRss", |
| 43 | "TracSearch", |
| 44 | "TracStandalone", |
| 45 | "TracSupport", |
| 46 | "TracSyntaxColoring", |
| 47 | "TracTickets", |
| 48 | "TracTicketsCustomFields", |
| 49 | "TracTimeline", |
| 50 | "TracUnicode", |
| 51 | "TracUpgrade", |
| 52 | "TracWiki", |
| 53 | "WikiDeletePage", |
| 54 | "WikiFormatting", |
| 55 | "WikiHtml", |
| 56 | "WikiMacros", |
| 57 | "WikiNewPage", |
| 58 | "WikiPageNames", |
| 59 | "WikiProcessors", |
| 60 | "WikiRestructuredText", |
| 61 | "WikiRestructuredTextLinks" |
| 62 | ] |
| 63 | |
| 64 | def get_page_from_file (pname): |
| 65 | d = '' |
| 66 | try: |
| 67 | f = open(pname ,'r') |
| 68 | d = f.read() |
| 69 | f.close() |
| 70 | except: |
| 71 | print "Missing page: %s" % pname |
| 72 | return d |
| 73 | |
| 74 | def get_page_from_web (pname): |
| 75 | host = "projects.edgewall.com" |
| 76 | rfile = "/trac/wiki/%s?format=txt" % pname |
| 77 | c = httplib.HTTPConnection(host) |
| 78 | c.request("GET", rfile) |
| 79 | r = c.getresponse() |
| 80 | d = r.read() |
| 81 | if r.status != 200 or d == ("describe %s here\n" % pname): |
| 82 | c.close() |
| 83 | print "Missing page: %s" % pname |
| 84 | c.close() |
| 85 | f = open(pname, 'w+') |
| 86 | f.write(d) |
| 87 | f.close() |
| 88 | return d |
| 89 | |
| 90 | def check_links (data): |
| 91 | def get_refs(t, refs=[]): |
| 92 | r = "(?P<wikilink>(^|(?<=[^A-Za-z]))[!]?[A-Z][a-z/]+(?:[A-Z][a-z/]+)+)" |
| 93 | m = re.search (r, t) |
| 94 | if not m: |
| 95 | refs.sort() |
| 96 | result = [] |
| 97 | orf = None |
| 98 | for rf in refs: |
| 99 | if rf != orf: |
| 100 | result.append(rf) |
| 101 | orf = rf |
| 102 | return result |
| 103 | refs.append(m.group()) |
| 104 | return get_refs( t[m.end():], refs) |
| 105 | for p in data.keys(): |
| 106 | links = get_refs(data[p], []) |
| 107 | for l in links: |
| 108 | if l not in data.keys(): |
| 109 | print "Broken link: %s -> %s" % (p, l) |
| 110 | |
| 111 | if __name__ == '__main__': |
| 112 | try: |
| 113 | opts, args = getopt.getopt(sys.argv[1:], "ds") |
| 114 | except getopt.GetoptError: |
| 115 | # print help information and exit: |
| 116 | print "%s [-d]" % sys.argv[0] |
| 117 | print "\t-d -- Download pages from the main project wiki." |
| 118 | sys.exit() |
| 119 | get_page = get_page_from_file |
| 120 | for o,a in opts: |
| 121 | if o == '-d': |
| 122 | get_page = get_page_from_web |
| 123 | data = {} |
| 124 | for p in wiki_pages: |
| 125 | data[p] = get_page (p) |
| 126 | check_links(data) |
| 127 | |