3 # imports the API description and fills up a database with
4 # name relevance to modules, functions or web pages
9 # install mysqld, the python wrappers for mysql and libxml2, start mysqld
10 # Change the root passwd of mysql:
11 # mysqladmin -u root password new_password
12 # Create the new database xmlsoft
13 # mysqladmin -p create xmlsoft
14 # Create a database user 'veillard' and give him passord access
15 # change veillard and abcde with the right user name and passwd
18 # mysql> GRANT ALL PRIVILEGES ON xmlsoft TO veillard@localhost
19 # IDENTIFIED BY 'abcde' WITH GRANT OPTION;
21 # As the user check the access:
24 # Welcome to the MySQL monitor....
30 # Then run the script in the doc subdir, it will create the symbols and
31 # word tables and populate them with informations extracted from
32 # the libxml2-api.xml API description, and make then accessible read-only
33 # by nobody@loaclhost the user expected to be Apache's one
35 # On the Apache configuration, make sure you have php support enabled
45 # We are not interested in parsing errors here
47 def callback(ctx, str):
49 libxml2.registerErrorHandler(callback, None)
52 # The dictionary of tables required and the SQL command needed
56 "symbols" : """CREATE TABLE symbols (
57 name varchar(255) BINARY NOT NULL,
58 module varchar(255) BINARY NOT NULL,
59 type varchar(25) NOT NULL,
61 UNIQUE KEY name (name),
62 KEY module (module))""",
63 "words" : """CREATE TABLE words (
64 name varchar(50) BINARY NOT NULL,
65 symbol varchar(255) BINARY NOT NULL,
69 UNIQUE KEY ID (name, symbol))""",
70 "wordsHTML" : """CREATE TABLE wordsHTML (
71 name varchar(50) BINARY NOT NULL,
72 resource varchar(255) BINARY NOT NULL,
77 KEY resource (resource),
78 UNIQUE KEY ref (name, resource))""",
79 "wordsArchive" : """CREATE TABLE wordsArchive (
80 name varchar(50) BINARY NOT NULL,
84 UNIQUE KEY ref (name, ID))""",
85 "pages" : """CREATE TABLE pages (
86 resource varchar(255) BINARY NOT NULL,
87 title varchar(255) BINARY NOT NULL,
88 UNIQUE KEY name (resource))""",
89 "archives" : """CREATE TABLE archives (
90 ID int(11) NOT NULL auto_increment,
91 resource varchar(255) BINARY NOT NULL,
92 title varchar(255) BINARY NOT NULL,
93 UNIQUE KEY id (ID,resource(255)),
96 "Queries" : """CREATE TABLE Queries (
97 ID int(11) NOT NULL auto_increment,
98 Value varchar(50) NOT NULL,
99 Count int(11) NOT NULL,
100 UNIQUE KEY id (ID,Value(35)),
102 "AllQueries" : """CREATE TABLE AllQueries (
103 ID int(11) NOT NULL auto_increment,
104 Value varchar(50) NOT NULL,
105 Count int(11) NOT NULL,
106 UNIQUE KEY id (ID,Value(35)),
111 # The XML API description file to parse
113 API="libxml2-api.xml"
116 #########################################################################
118 # MySQL database interfaces #
120 #########################################################################
121 def createTable(db, name):
130 ret = c.execute("DROP TABLE IF EXISTS %s" % (name))
132 print "Removed table %s" % (name)
133 print "Creating table %s" % (name)
135 ret = c.execute(TABLES[name])
137 print "Failed to create table %s" % (name)
141 def checkTables(db, verbose = 1):
147 nbtables = c.execute("show tables")
149 print "Found %d tables" % (nbtables)
158 for table in TABLES.keys():
159 if not tables.has_key(table):
160 print "table %s missing" % (table)
161 createTable(db, table)
163 ret = c.execute("SELECT count(*) from %s" % table);
166 print "Table %s contains %d records" % (table, row[0])
168 print "Troubles with table %s : repairing" % (table)
169 ret = c.execute("repair table %s" % table);
170 print "repairing returned %d" % (ret)
171 ret = c.execute("SELECT count(*) from %s" % table);
173 print "Table %s contains %d records" % (table, row[0])
175 print "checkTables finished"
177 # make sure apache can access the tables read-only
179 ret = c.execute("GRANT SELECT ON xmlsoft.* TO nobody@localhost")
180 ret = c.execute("GRANT INSERT,SELECT,UPDATE ON xmlsoft.Queries TO nobody@localhost")
185 def openMySQL(db="xmlsoft", passwd=None, verbose = 1):
190 passwd = os.environ["MySQL_PASS"]
192 print "No password available, set environment MySQL_PASS"
195 DB = MySQLdb.connect(passwd=passwd, db=db)
198 ret = checkTables(DB, verbose)
201 def updateWord(name, symbol, relevance):
216 """INSERT INTO words (name, symbol, relevance) VALUES ('%s','%s', %d)""" %
217 (name, symbol, relevance))
221 """UPDATE words SET relevance = %d where name = '%s' and symbol = '%s'""" %
222 (relevance, name, symbol))
224 print "Update word (%s, %s, %s) failed command" % (name, symbol, relevance)
225 print "UPDATE words SET relevance = %d where name = '%s' and symbol = '%s'" % (relevance, name, symbol)
226 print sys.exc_type, sys.exc_value
231 def updateSymbol(name, module, type, desc):
234 updateWord(name, name, 50)
247 desc = string.replace(desc, "'", " ")
248 l = string.split(desc, ".")
257 """INSERT INTO symbols (name, module, type, descr) VALUES ('%s','%s', '%s', '%s')""" %
258 (name, module, type, desc))
262 """UPDATE symbols SET module='%s', type='%s', descr='%s' where name='%s'""" %
263 (module, type, desc, name))
265 print "Update symbol (%s, %s, %s) failed command" % (name, module, type)
266 print """UPDATE symbols SET module='%s', type='%s', descr='%s' where name='%s'""" % (module, type, desc, name)
267 print sys.exc_type, sys.exc_value
272 def addFunction(name, module, desc = ""):
273 return updateSymbol(name, module, 'function', desc)
275 def addMacro(name, module, desc = ""):
276 return updateSymbol(name, module, 'macro', desc)
278 def addEnum(name, module, desc = ""):
279 return updateSymbol(name, module, 'enum', desc)
281 def addStruct(name, module, desc = ""):
282 return updateSymbol(name, module, 'struct', desc)
284 def addConst(name, module, desc = ""):
285 return updateSymbol(name, module, 'const', desc)
287 def addType(name, module, desc = ""):
288 return updateSymbol(name, module, 'type', desc)
290 def addFunctype(name, module, desc = ""):
291 return updateSymbol(name, module, 'functype', desc)
293 def addPage(resource, title):
306 """INSERT INTO pages (resource, title) VALUES ('%s','%s')""" %
311 """UPDATE pages SET title='%s' WHERE resource='%s'""" %
314 print "Update symbol (%s, %s, %s) failed command" % (name, module, type)
315 print """UPDATE pages SET title='%s' WHERE resource='%s'""" % (title, resource)
316 print sys.exc_type, sys.exc_value
321 def updateWordHTML(name, resource, desc, id, relevance):
338 desc = string.replace(desc, "'", " ")
346 """INSERT INTO wordsHTML (name, resource, section, id, relevance) VALUES ('%s','%s', '%s', '%s', '%d')""" %
347 (name, resource, desc, id, relevance))
351 """UPDATE wordsHTML SET section='%s', id='%s', relevance='%d' where name='%s' and resource='%s'""" %
352 (desc, id, relevance, name, resource))
354 print "Update symbol (%s, %s, %d) failed command" % (name, resource, relevance)
355 print """UPDATE wordsHTML SET section='%s', id='%s', relevance='%d' where name='%s' and resource='%s'""" % (desc, id, relevance, name, resource)
356 print sys.exc_type, sys.exc_value
361 def checkXMLMsgArchive(url):
374 """SELECT ID FROM archives WHERE resource='%s'""" % (url))
383 def addXMLMsgArchive(url, title):
395 title = string.replace(title, "'", " ")
400 cmd = """INSERT INTO archives (resource, title) VALUES ('%s','%s')""" % (url, title)
402 cmd = """SELECT ID FROM archives WHERE resource='%s'""" % (url)
406 print "addXMLMsgArchive failed to get the ID: %s" % (url)
409 print "addXMLMsgArchive failed command: %s" % (cmd)
412 return((int)(row[0]))
414 def updateWordArchive(name, id, relevance):
429 """INSERT INTO wordsArchive (name, id, relevance) VALUES ('%s', '%d', '%d')""" %
430 (name, id, relevance))
434 """UPDATE wordsArchive SET relevance='%d' where name='%s' and ID='%d'""" %
435 (relevance, name, id))
437 print "Update word archive (%s, %d, %d) failed command" % (name, id, relevance)
438 print """UPDATE wordsArchive SET relevance='%d' where name='%s' and ID='%d'""" % (relevance, name, id)
439 print sys.exc_type, sys.exc_value
444 #########################################################################
446 # Word dictionary and analysis routines #
448 #########################################################################
451 # top 100 english word without the one len < 3 + own set
454 'the':0, 'this':0, 'can':0, 'man':0, 'had':0, 'him':0, 'only':0,
455 'and':0, 'not':0, 'been':0, 'other':0, 'even':0, 'are':0, 'was':0,
456 'new':0, 'most':0, 'but':0, 'when':0, 'some':0, 'made':0, 'from':0,
457 'who':0, 'could':0, 'after':0, 'that':0, 'will':0, 'time':0, 'also':0,
458 'have':0, 'more':0, 'these':0, 'did':0, 'was':0, 'two':0, 'many':0,
459 'they':0, 'may':0, 'before':0, 'for':0, 'which':0, 'out':0, 'then':0,
460 'must':0, 'one':0, 'through':0, 'with':0, 'you':0, 'said':0,
461 'first':0, 'back':0, 'were':0, 'what':0, 'any':0, 'years':0, 'his':0,
462 'her':0, 'where':0, 'all':0, 'its':0, 'now':0, 'much':0, 'she':0,
463 'about':0, 'such':0, 'your':0, 'there':0, 'into':0, 'like':0, 'may':0,
464 'would':0, 'than':0, 'our':0, 'well':0, 'their':0, 'them':0, 'over':0,
466 'net':0, 'www':0, 'bad':0, 'Okay':0, 'bin':0, 'cur':0,
471 wordsDictArchive = {}
473 def cleanupWordsString(str):
474 str = string.replace(str, ".", " ")
475 str = string.replace(str, "!", " ")
476 str = string.replace(str, "?", " ")
477 str = string.replace(str, ",", " ")
478 str = string.replace(str, "'", " ")
479 str = string.replace(str, '"', " ")
480 str = string.replace(str, ";", " ")
481 str = string.replace(str, "(", " ")
482 str = string.replace(str, ")", " ")
483 str = string.replace(str, "{", " ")
484 str = string.replace(str, "}", " ")
485 str = string.replace(str, "<", " ")
486 str = string.replace(str, ">", " ")
487 str = string.replace(str, "=", " ")
488 str = string.replace(str, "/", " ")
489 str = string.replace(str, "*", " ")
490 str = string.replace(str, ":", " ")
491 str = string.replace(str, "#", " ")
492 str = string.replace(str, "\\", " ")
493 str = string.replace(str, "\n", " ")
494 str = string.replace(str, "\r", " ")
495 str = string.replace(str, "\xc2", " ")
496 str = string.replace(str, "\xa0", " ")
499 def cleanupDescrString(str):
500 str = string.replace(str, "'", " ")
501 str = string.replace(str, "\n", " ")
502 str = string.replace(str, "\r", " ")
503 str = string.replace(str, "\xc2", " ")
504 str = string.replace(str, "\xa0", " ")
505 l = string.split(str)
506 str = string.join(str)
509 def splitIdentifier(str):
512 cur = string.lower(str[0])
514 if ((cur < 'a') or (cur > 'z')):
516 while (str != "") and (str[0] >= 'A') and (str[0] <= 'Z'):
517 cur = cur + string.lower(str[0])
519 while (str != "") and (str[0] >= 'a') and (str[0] <= 'z'):
522 while (str != "") and (str[0] >= '0') and (str[0] <= '9'):
527 def addWord(word, module, symbol, relevance):
530 if word == None or len(word) < 3:
532 if module == None or symbol == None:
534 if dropWords.has_key(word):
536 if ord(word[0]) > 0x80:
539 if wordsDict.has_key(word):
544 wordsDict[word] = None
547 relevance = relevance + d[(module, symbol)]
552 wordsDict[word][(module, symbol)] = relevance
555 def addString(str, module, symbol, relevance):
556 if str == None or len(str) < 3:
559 str = cleanupWordsString(str)
560 l = string.split(str)
563 ret = ret + addWord(word, module, symbol, 5)
567 def addWordHTML(word, resource, id, section, relevance):
570 if word == None or len(word) < 3:
572 if resource == None or section == None:
574 if dropWords.has_key(word):
576 if ord(word[0]) > 0x80:
579 section = cleanupDescrString(section)
581 if wordsDictHTML.has_key(word):
582 d = wordsDictHTML[word]
584 print "skipped %s" % (word)
587 (r,i,s) = d[resource]
592 relevance = relevance + r
596 wordsDictHTML[word] = {}
597 d = wordsDictHTML[word];
598 d[resource] = (relevance, id, section)
601 def addStringHTML(str, resource, id, section, relevance):
602 if str == None or len(str) < 3:
605 str = cleanupWordsString(str)
606 l = string.split(str)
610 r = addWordHTML(word, resource, id, section, relevance)
612 print "addWordHTML failed: %s %s" % (word, resource)
615 print "addWordHTML failed: %s %s %d" % (word, resource, relevance)
616 print sys.exc_type, sys.exc_value
620 def addWordArchive(word, id, relevance):
621 global wordsDictArchive
623 if word == None or len(word) < 3:
625 if id == None or id == -1:
627 if dropWords.has_key(word):
629 if ord(word[0]) > 0x80:
632 if wordsDictArchive.has_key(word):
633 d = wordsDictArchive[word]
635 print "skipped %s" % (word)
639 relevance = relevance + r
643 wordsDictArchive[word] = {}
644 d = wordsDictArchive[word];
648 def addStringArchive(str, id, relevance):
649 if str == None or len(str) < 3:
652 str = cleanupWordsString(str)
653 l = string.split(str)
658 r = addWordArchive(word, id, relevance)
660 print "addWordArchive failed: %s %s" % (word, id)
664 print "addWordArchive failed: %s %s %d" % (word, id, relevance)
665 print sys.exc_type, sys.exc_value
668 #########################################################################
670 # XML API description analysis #
672 #########################################################################
674 def loadAPI(filename):
675 doc = libxml2.parseFile(filename)
676 print "loaded %s" % (filename)
679 def foundExport(file, symbol):
684 addFunction(symbol, file)
685 l = splitIdentifier(symbol)
687 addWord(word, file, symbol, 10)
690 def analyzeAPIFile(top):
692 name = top.prop("name")
695 if cur.type == 'text':
698 if cur.name == "exports":
699 count = count + foundExport(name, cur.prop("symbol"))
701 print "unexpected element %s in API doc <file name='%s'>" % (name)
705 def analyzeAPIFiles(top):
710 if cur.type == 'text':
713 if cur.name == "file":
714 count = count + analyzeAPIFile(cur)
716 print "unexpected element %s in API doc <files>" % (cur.name)
720 def analyzeAPIEnum(top):
721 file = top.prop("file")
724 symbol = top.prop("name")
728 addEnum(symbol, file)
729 l = splitIdentifier(symbol)
731 addWord(word, file, symbol, 10)
735 def analyzeAPIConst(top):
736 file = top.prop("file")
739 symbol = top.prop("name")
743 addConst(symbol, file)
744 l = splitIdentifier(symbol)
746 addWord(word, file, symbol, 10)
750 def analyzeAPIType(top):
751 file = top.prop("file")
754 symbol = top.prop("name")
758 addType(symbol, file)
759 l = splitIdentifier(symbol)
761 addWord(word, file, symbol, 10)
764 def analyzeAPIFunctype(top):
765 file = top.prop("file")
768 symbol = top.prop("name")
772 addFunctype(symbol, file)
773 l = splitIdentifier(symbol)
775 addWord(word, file, symbol, 10)
778 def analyzeAPIStruct(top):
779 file = top.prop("file")
782 symbol = top.prop("name")
786 addStruct(symbol, file)
787 l = splitIdentifier(symbol)
789 addWord(word, file, symbol, 10)
791 info = top.prop("info")
793 info = string.replace(info, "'", " ")
794 info = string.strip(info)
795 l = string.split(info)
798 addWord(word, file, symbol, 5)
801 def analyzeAPIMacro(top):
802 file = top.prop("file")
805 symbol = top.prop("name")
808 symbol = string.replace(symbol, "'", " ")
809 symbol = string.strip(symbol)
814 if cur.type == 'text':
817 if cur.name == "info":
822 l = splitIdentifier(symbol)
824 addWord(word, file, symbol, 10)
827 addMacro(symbol, file)
828 print "Macro %s description has no <info>" % (symbol)
831 info = string.replace(info, "'", " ")
832 info = string.strip(info)
833 addMacro(symbol, file, info)
834 l = string.split(info)
837 addWord(word, file, symbol, 5)
840 def analyzeAPIFunction(top):
841 file = top.prop("file")
844 symbol = top.prop("name")
848 symbol = string.replace(symbol, "'", " ")
849 symbol = string.strip(symbol)
853 if cur.type == 'text':
856 if cur.name == "info":
858 elif cur.name == "return":
859 rinfo = cur.prop("info")
861 rinfo = string.replace(rinfo, "'", " ")
862 rinfo = string.strip(rinfo)
863 addString(rinfo, file, symbol, 7)
864 elif cur.name == "arg":
865 ainfo = cur.prop("info")
867 ainfo = string.replace(ainfo, "'", " ")
868 ainfo = string.strip(ainfo)
869 addString(ainfo, file, symbol, 5)
870 name = cur.prop("name")
872 name = string.replace(name, "'", " ")
873 name = string.strip(name)
874 addWord(name, file, symbol, 7)
877 print "Function %s description has no <info>" % (symbol)
878 addFunction(symbol, file, "")
880 info = string.replace(info, "'", " ")
881 info = string.strip(info)
882 addFunction(symbol, file, info)
883 addString(info, file, symbol, 5)
885 l = splitIdentifier(symbol)
887 addWord(word, file, symbol, 10)
891 def analyzeAPISymbols(top):
896 if cur.type == 'text':
899 if cur.name == "macro":
900 count = count + analyzeAPIMacro(cur)
901 elif cur.name == "function":
902 count = count + analyzeAPIFunction(cur)
903 elif cur.name == "const":
904 count = count + analyzeAPIConst(cur)
905 elif cur.name == "typedef":
906 count = count + analyzeAPIType(cur)
907 elif cur.name == "struct":
908 count = count + analyzeAPIStruct(cur)
909 elif cur.name == "enum":
910 count = count + analyzeAPIEnum(cur)
911 elif cur.name == "functype":
912 count = count + analyzeAPIFunctype(cur)
914 print "unexpected element %s in API doc <files>" % (cur.name)
922 root = doc.getRootElement()
923 if root.name != "api":
924 print "Unexpected root name"
928 if cur.type == 'text':
931 if cur.name == "files":
933 # count = count + analyzeAPIFiles(cur)
934 elif cur.name == "symbols":
935 count = count + analyzeAPISymbols(cur)
937 print "unexpected element %s in API doc" % (cur.name)
941 #########################################################################
943 # Web pages parsing and analysis #
945 #########################################################################
949 def analyzeHTMLText(doc, resource, p, section, id):
953 words = words + addStringHTML(content, resource, id, section, 5)
958 def analyzeHTMLPara(doc, resource, p, section, id):
962 words = words + addStringHTML(content, resource, id, section, 5)
967 def analyzeHTMLPre(doc, resource, p, section, id):
971 words = words + addStringHTML(content, resource, id, section, 5)
976 def analyzeHTML(doc, resource, p, section, id):
980 words = words + addStringHTML(content, resource, id, section, 5)
985 def analyzeHTML(doc, resource):
987 ctxt = doc.xpathNewContext()
989 res = ctxt.xpathEval("//head/title")
990 title = res[0].content
992 title = "Page %s" % (resource)
993 addPage(resource, title)
995 items = ctxt.xpathEval("//h1 | //h2 | //h3 | //text()")
999 if item.name == 'h1' or item.name == 'h2' or item.name == 'h3':
1000 section = item.content
1002 id = item.prop("id")
1003 elif item.prop("name"):
1004 id = item.prop("name")
1005 elif item.type == 'text':
1006 analyzeHTMLText(doc, resource, item, section, id)
1008 elif item.name == 'p':
1009 analyzeHTMLPara(doc, resource, item, section, id)
1011 elif item.name == 'pre':
1012 analyzeHTMLPre(doc, resource, item, section, id)
1015 print "Page %s, unexpected %s element" % (resource, item.name)
1017 print "Page %s: problem analyzing" % (resource)
1018 print sys.exc_type, sys.exc_value
1022 def analyzeHTMLPages():
1024 HTMLfiles = glob.glob("*.html") + glob.glob("tutorial/*.html")
1025 for html in HTMLfiles:
1026 if html[0:3] == "API":
1028 if html == "xml.html":
1031 doc = libxml2.parseFile(html)
1033 doc = libxml2.htmlParseFile(html, None)
1035 res = analyzeHTML(doc, html)
1036 print "Parsed %s : %d paragraphs" % (html, res)
1039 print "could not parse %s" % (html)
1042 #########################################################################
1044 # Mail archives parsing and analysis #
1046 #########################################################################
1050 def getXMLDateArchive(t = None):
1054 month = time.strftime("%B", T)
1056 url = "http://mail.gnome.org/archives/xml/%d-%s/date.html" % (year, month)
1059 def scanXMLMsgArchive(url, title, force = 0):
1060 if url == None or title == None:
1063 ID = checkXMLMsgArchive(url)
1064 if force == 0 and ID != -1:
1068 ID = addXMLMsgArchive(url, title)
1073 print "Loading %s" % (url)
1074 doc = libxml2.htmlParseFile(url, None);
1078 print "Failed to parse %s" % (url)
1081 addStringArchive(title, ID, 20)
1082 ctxt = doc.xpathNewContext()
1083 texts = ctxt.xpathEval("//pre//text()")
1085 addStringArchive(text.content, ID, 5)
1089 def scanXMLDateArchive(t = None, force = 0):
1090 global wordsDictArchive
1092 wordsDictArchive = {}
1094 url = getXMLDateArchive(t)
1095 print "loading %s" % (url)
1097 doc = libxml2.htmlParseFile(url, None);
1101 print "Failed to parse %s" % (url)
1103 ctxt = doc.xpathNewContext()
1104 anchors = ctxt.xpathEval("//a[@href]")
1107 for anchor in anchors:
1108 href = anchor.prop("href")
1109 if href == None or href[0:3] != "msg":
1114 msg = libxml2.buildURI(href, url)
1115 title = anchor.content
1116 if title != None and title[0:4] == 'Re: ':
1118 if title != None and title[0:6] == '[xml] ':
1120 newmsg = newmsg + scanXMLMsgArchive(msg, title, force)
1128 #########################################################################
1130 # Main code: open the DB, the API XML and analyze it #
1132 #########################################################################
1133 def analyzeArchives(t = None, force = 0):
1134 global wordsDictArchive
1136 ret = scanXMLDateArchive(t, force)
1137 print "Indexed %d words in %d archive pages" % (len(wordsDictArchive), ret)
1141 for word in wordsDictArchive.keys():
1142 refs = wordsDictArchive[word]
1144 skipped = skipped + 1
1146 for id in refs.keys():
1147 relevance = refs[id]
1148 updateWordArchive(word, id, relevance)
1151 print "Found %d associations in HTML pages" % (i)
1153 def analyzeHTMLTop():
1154 global wordsDictHTML
1156 ret = analyzeHTMLPages()
1157 print "Indexed %d words in %d HTML pages" % (len(wordsDictHTML), ret)
1161 for word in wordsDictHTML.keys():
1162 refs = wordsDictHTML[word]
1164 skipped = skipped + 1
1166 for resource in refs.keys():
1167 (relevance, id, section) = refs[resource]
1168 updateWordHTML(word, resource, section, id, relevance)
1171 print "Found %d associations in HTML pages" % (i)
1173 def analyzeAPITop():
1179 ret = analyzeAPI(doc)
1180 print "Analyzed %d blocs" % (ret)
1183 print "Failed to parse and analyze %s" % (API)
1184 print sys.exc_type, sys.exc_value
1187 print "Indexed %d words" % (len(wordsDict))
1190 for word in wordsDict.keys():
1191 refs = wordsDict[word]
1193 skipped = skipped + 1
1195 for (module, symbol) in refs.keys():
1196 updateWord(word, symbol, refs[(module, symbol)])
1199 print "Found %d associations, skipped %d words" % (i, skipped)
1202 print "Usage index.py [--force] [--archive] [--archive-year year] [--archive-month month] [--API] [--docs]"
1209 print "Failed to open the database"
1210 print sys.exc_type, sys.exc_value
1217 while i < len(args):
1218 if args[i] == '--force':
1220 elif args[i] == '--archive':
1221 analyzeArchives(None, force)
1222 elif args[i] == '--archive-year':
1225 months = ["January" , "February", "March", "April", "May",
1226 "June", "July", "August", "September", "October",
1227 "November", "December"];
1228 for month in months:
1230 str = "%s-%s" % (year, month)
1231 T = time.strptime(str, "%Y-%B")
1232 t = time.mktime(T) + 3600 * 24 * 10;
1233 analyzeArchives(t, force)
1235 print "Failed to index month archive:"
1236 print sys.exc_type, sys.exc_value
1237 elif args[i] == '--archive-month':
1241 T = time.strptime(month, "%Y-%B")
1242 t = time.mktime(T) + 3600 * 24 * 10;
1243 analyzeArchives(t, force)
1245 print "Failed to index month archive:"
1246 print sys.exc_type, sys.exc_value
1247 elif args[i] == '--API':
1249 elif args[i] == '--docs':
1257 if __name__ == "__main__":