Also implement both HTTP Authentication and Basic Authentication (for BASIC only) (HTC-7 #work 1h)
261 lines
11 KiB
Python
Executable file
261 lines
11 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# encoding: utf-8
|
|
"""
|
|
Utility script to import doxygen docs into confluence
|
|
|
|
Original Author(s): Richard Bateman
|
|
Created: 18 October 2009
|
|
License: Dual license model; choose one of two:
|
|
New BSD License
|
|
http://www.opensource.org/licenses/bsd-license.php
|
|
- or -
|
|
GNU Lesser General Public License, version 2.1
|
|
http://www.gnu.org/licenses/lgpl-2.1.html
|
|
|
|
Copyright 2009 the Firebreath development team
|
|
"""
|
|
import os, sys, SOAPpy
|
|
from xml.dom import minidom
|
|
from itertools import izip
|
|
|
|
nameCount = {}
|
|
|
|
class Doxygen2Confluence:
|
|
nameCount = {}
|
|
inputHtmlPath = os.path.join("docs", "html")
|
|
outputHtmlPath = os.path.join("docs", "patched")
|
|
inputList = {}
|
|
pathMap = {}
|
|
baseUrl = "/confluence/display/HTC/%s"
|
|
classDocsUrl = "http://wiki.my-ho.st/"
|
|
url = "http://wiki.my-ho.st/confluence/rpc/soap-axis/confluenceservice-v2?wsdl"
|
|
server = SOAPpy.SOAPProxy(url)
|
|
rpc = SOAPpy.WSDL.Proxy(url)
|
|
token = ""
|
|
space = "HTC"
|
|
topPages = {
|
|
"class" : "7012748",
|
|
"struct" : "7012750",
|
|
"namespace" : "7012752",
|
|
"file" : "7012754",
|
|
"typedef": "7012756",
|
|
"function": "7012760",
|
|
"enum": "7012758",
|
|
"example": "7012762",
|
|
}
|
|
parents = {}
|
|
createdPages = []
|
|
username = ""
|
|
password = ""
|
|
|
|
def login(self):
|
|
self.token = self.rpc.login(self.username, self.password)
|
|
|
|
def __init__(self, username, password):
|
|
SOAPpy.Parser._parseSOAP = self.confluence_soap_parser
|
|
self.username = username
|
|
self.password = password
|
|
self.login()
|
|
|
|
def getName(self, name):
|
|
count = 1
|
|
retVal = name.replace("::", " ")
|
|
if name in self.nameCount:
|
|
count = self.nameCount[name]
|
|
count = count + 1
|
|
retVal = "%s (%s)" % (name, count)
|
|
|
|
self.nameCount[name] = count
|
|
return retVal.replace("<", "(").replace(">", ")").replace("/", " ")
|
|
|
|
def makeFirstPageInConfluence(self, pageId, targetPageId):
|
|
children = self.rpc.getChildren(self.token, SOAPpy.Types.longType(long(pageId)))
|
|
if len(children) and children[0]["id"] != targetPageId:
|
|
print "Moving %s to before %s" % (targetPageId, children[0]["id"])
|
|
self.rpc.movePage(self.token, SOAPpy.Types.longType(long(targetPageId)), SOAPpy.Types.longType(long(children[0]["id"])), "above")
|
|
|
|
def exportToConfluence(self, refId, pageName, kind):
|
|
try:
|
|
page = self.rpc.getPage(self.token, self.space, pageName)
|
|
except:
|
|
try:
|
|
self.login()
|
|
page = self.rpc.getPage(self.token, self.space, pageName)
|
|
except:
|
|
page = {"space": self.space, "title": pageName}
|
|
|
|
if kind == "file":
|
|
filename = "%s_source.html" % refId
|
|
else:
|
|
filename = "%s.html" % refId
|
|
|
|
npage = {
|
|
"content": "{doxygen-init}{html-include:url=http://wiki.my-ho.st/doco/%s/%s}" % (self.space, filename),
|
|
"space": page["space"],
|
|
"title": page["title"],
|
|
}
|
|
|
|
if hasattr(page, 'id'):
|
|
npage["id"] = SOAPpy.Types.longType(long(page["id"]))
|
|
npage["parentId"] = SOAPpy.Types.longType(long(self.parents[refId]))
|
|
npage["version"] = SOAPpy.Types.intType(int(page["version"]))
|
|
|
|
n = 0
|
|
while n < 10:
|
|
try:
|
|
npage["content"] = self.rpc.convertWikiToStorageFormat(self.token, npage['content'])
|
|
npage = self.rpc.storePage(self.token, npage)
|
|
self.createdPages.append(npage["id"])
|
|
self.rpc.setContentPermissions(self.token, SOAPpy.Types.longType(long(npage["id"])), "Edit", [ {'groupName': 'confluence-administrators', 'type': 'Edit'} ])
|
|
break;
|
|
except Exception as ex:
|
|
self.login()
|
|
print type(ex)
|
|
print ex.args
|
|
print ex
|
|
pass
|
|
|
|
return npage["id"]
|
|
|
|
def cleanConfluence(self):
|
|
for kind, id in self.topPages.items():
|
|
print "Scanning pages for %s (id %s)" % (kind, id)
|
|
pages = self.rpc.getDescendents(self.token, SOAPpy.Types.longType(long(id)))
|
|
for page in pages:
|
|
if (page["id"] not in self.createdPages) and (page["id"] not in self.topPages.values()):
|
|
print "Removing defunct page: %s (%s)" % (page["title"], page["id"])
|
|
self.rpc.removePage(self.token, SOAPpy.Types.longType(long(page["id"])))
|
|
|
|
def processDirectory(self, path):
|
|
xml = minidom.parse("docs/xml/index.xml")
|
|
|
|
compounds = xml.documentElement.getElementsByTagName("compound")
|
|
refidMap = {}
|
|
Info = {}
|
|
for com in compounds:
|
|
refid = com.getAttribute("refid")
|
|
kind = com.getAttribute("kind")
|
|
compoundName = com.getElementsByTagName("name")[0].firstChild.wholeText
|
|
realName = self.getName("%s %s" % (kind, compoundName.replace("::", " ")))
|
|
if os.path.exists(os.path.join(path, "%s-members.html" % refid)):
|
|
refidMap["%s-members.html" % refid] = self.baseUrl % (realName + " Members")
|
|
filename = "%s.html" % refid
|
|
if kind == "file":
|
|
filename = "%s_source.html" % refid
|
|
if os.path.exists(os.path.join(path, filename)):
|
|
Info[refid] = {}
|
|
Info[refid]["kind"] = kind
|
|
Info[refid]["name"] = realName
|
|
Info[refid]["members"] = {}
|
|
refidMap[filename] = self.baseUrl % realName
|
|
if kind == "file":
|
|
print "%s => %s" % (filename, self.baseUrl % realName)
|
|
continue
|
|
for mem in com.getElementsByTagName("member"):
|
|
memName = mem.getElementsByTagName("name")[0].firstChild.wholeText
|
|
memRefId = mem.getAttribute("refid")
|
|
memRefId = memRefId[0:memRefId.rindex("_")]
|
|
memKind = mem.getAttribute("kind")
|
|
if memKind == "enumvalue":
|
|
continue
|
|
|
|
if (os.path.exists(os.path.join(path, memRefId + ".html"))):
|
|
if kind == "namespace":
|
|
localName = self.getName("%s %s %s" % (memKind, compoundName, memName))
|
|
else:
|
|
localName = self.getName(Info[refid]["name"] + " " + memName)
|
|
refidMap["%s.html" % memRefId] = self.baseUrl % localName
|
|
Info[refid]["members"][memRefId] = {}
|
|
Info[refid]["members"][memRefId]["kind"] = memKind
|
|
Info[refid]["members"][memRefId]["name"] = localName
|
|
self.inputList = Info
|
|
self.pathMap = refidMap
|
|
|
|
def processFile(self, filename, inPath, outPath):
|
|
f = open(os.path.join(inPath, filename), "r")
|
|
fileText = f.read()
|
|
f.close()
|
|
|
|
for id, url in izip(self.pathMap.keys(), self.pathMap.values()):
|
|
print "Changing %s to %s" % (id, url)
|
|
try:
|
|
fileText = fileText.replace(id, url)
|
|
except UnicodeDecodeError:
|
|
fileText = fileText.replace(id.encode('utf8'), url.encode('utf8'))
|
|
fileText = fileText.replace(r'img src="', r'img src="http://wiki.my-ho.st/doco/%s/' % self.space)
|
|
fileText = fileText.replace(r'img class="footer" src="', r'img class="footer" src="http://wiki.my-ho.st/doco/')
|
|
nf = open(os.path.join(outPath, filename), "w")
|
|
nf.write(fileText)
|
|
nf.close()
|
|
|
|
def writeNewFiles(self, inPath, outPath):
|
|
if not os.path.exists(outPath):
|
|
os.mkdir(outPath)
|
|
|
|
self.processFile("annotated.html", inPath, outPath)
|
|
self.processFile("hierarchy.html", inPath, outPath)
|
|
self.processFile("files.html", inPath, outPath)
|
|
self.processFile("namespaces.html", inPath, outPath)
|
|
self.processFile("classes.html", inPath, outPath)
|
|
self.processFile("index.html", inPath, outPath)
|
|
self.processFile("examples.html", inPath, outPath)
|
|
self.processFile("functions.html", inPath, outPath)
|
|
# Now we're going to load the files, process them, and write them to the output directory
|
|
for refid, item in self.inputList.items():
|
|
filename = "%s.html" % refid
|
|
if item["kind"] == "file":
|
|
filename = "%s_source.html" % refid
|
|
if os.path.exists(os.path.join(inPath, "%s-members.html" % refid)):
|
|
self.processFile("%s-members.html" % refid, inPath, outPath)
|
|
#print "Opening file %s" % filename
|
|
self.processFile(filename, inPath, outPath)
|
|
for memid, mem in item["members"].items():
|
|
#print "Member: %s" % memid
|
|
self.processFile("%s.html" % memid, inPath, outPath)
|
|
|
|
|
|
def begin(self):
|
|
self.processDirectory(self.inputHtmlPath)
|
|
self.writeNewFiles(self.inputHtmlPath, self.outputHtmlPath)
|
|
|
|
for refid, item in self.inputList.items():
|
|
parentId = None
|
|
if item["kind"] in self.topPages:
|
|
parentId = self.topPages[item["kind"]]
|
|
else:
|
|
print "Could not find %s in " % item["kind"], self.topPages
|
|
continue
|
|
self.parents[refid] = parentId
|
|
print "Exporting %s to confluence..." % item["name"]
|
|
pageId = self.exportToConfluence(refid, item["name"], item["kind"])
|
|
for memid, mem in item["members"].items():
|
|
#print "Exporting %s to confluence..." % mem["name"]
|
|
if item["kind"] == "namespace" and mem["kind"] in self.topPages:
|
|
self.parents[memid] = self.topPages[mem["kind"]]
|
|
else:
|
|
self.parents[memid] = pageId
|
|
self.exportToConfluence(memid, mem["name"], mem["kind"])
|
|
if os.path.exists(os.path.join(self.inputHtmlPath, "%s-members.html" % refid)):
|
|
self.parents["%s-members" % refid] = pageId
|
|
membersPageId = self.exportToConfluence("%s-members" % refid, "%s Members" % item["name"], "members")
|
|
self.makeFirstPageInConfluence(pageId, membersPageId)
|
|
self.cleanConfluence()
|
|
|
|
# This parser is due to this bug https://jira.atlassian.com/browse/CONF-6720
|
|
# once that bug is fixed this parser can be retired
|
|
def confluence_soap_parser(self, xml_str, rules=None, parser=SOAPpy.Parser._parseSOAP):
|
|
attribute = 'xsi:type="soapenc:Array"'
|
|
xml_str = xml_str.replace('%s %s' % (attribute, attribute), attribute)
|
|
return parser(xml_str, rules=rules)
|
|
|
|
|
|
def Main():
|
|
"""
|
|
Parse the commandline and execute the appropriate actions.
|
|
"""
|
|
a = Doxygen2Confluence(sys.argv[1], sys.argv[2])
|
|
a.begin()
|
|
|
|
if __name__ == "__main__":
|
|
Main()
|
|
|