| 1 |
#!/usr/bin/env python |
|---|
| 2 |
|
|---|
| 3 |
import sys |
|---|
| 4 |
import os |
|---|
| 5 |
import zipfile |
|---|
| 6 |
import md5 |
|---|
| 7 |
import xml.dom.minidom |
|---|
| 8 |
import xml.dom.ext |
|---|
| 9 |
|
|---|
| 10 |
# |
|---|
| 11 |
# Add-ons description file generator for OpenDict |
|---|
| 12 |
# Copyright (c) 2005 Martynas Jocius <mjoc@akl.lt> |
|---|
| 13 |
# |
|---|
| 14 |
# Fast code, dirty code |
|---|
| 15 |
# |
|---|
| 16 |
|
|---|
| 17 |
def parsePluginConfig(xmlData): |
|---|
| 18 |
"""Parse plugin configuration""" |
|---|
| 19 |
|
|---|
| 20 |
doc = xml.dom.minidom.parseString(xmlData) |
|---|
| 21 |
|
|---|
| 22 |
name = None |
|---|
| 23 |
version = None |
|---|
| 24 |
authors = [] |
|---|
| 25 |
description = None |
|---|
| 26 |
|
|---|
| 27 |
pluginElement = doc.getElementsByTagName('plugin')[0] |
|---|
| 28 |
pluginType = pluginElement.getAttribute('type') |
|---|
| 29 |
|
|---|
| 30 |
if pluginType != 'dictionary': |
|---|
| 31 |
raise Exception, "Plugin is not dictionary plugin" |
|---|
| 32 |
|
|---|
| 33 |
# Get name |
|---|
| 34 |
for nameElement in doc.getElementsByTagName('name'): |
|---|
| 35 |
for node in nameElement.childNodes: |
|---|
| 36 |
if node.nodeType == node.TEXT_NODE: |
|---|
| 37 |
name = node.data |
|---|
| 38 |
|
|---|
| 39 |
# Get version |
|---|
| 40 |
for versionElement in doc.getElementsByTagName('version'): |
|---|
| 41 |
for node in versionElement.childNodes: |
|---|
| 42 |
if node.nodeType == node.TEXT_NODE: |
|---|
| 43 |
version = node.data |
|---|
| 44 |
|
|---|
| 45 |
# Get authors |
|---|
| 46 |
for authorElement in doc.getElementsByTagName('author'): |
|---|
| 47 |
authorName = authorElement.getAttribute('name') |
|---|
| 48 |
authorEMail = authorElement.getAttribute('email') |
|---|
| 49 |
authors.append({'name': authorName, 'email': authorEMail}) |
|---|
| 50 |
|
|---|
| 51 |
# Get description |
|---|
| 52 |
for descElement in doc.getElementsByTagName('description'): |
|---|
| 53 |
for node in descElement.childNodes: |
|---|
| 54 |
if node.nodeType == node.TEXT_NODE: |
|---|
| 55 |
description = node.data |
|---|
| 56 |
|
|---|
| 57 |
|
|---|
| 58 |
|
|---|
| 59 |
result = {} |
|---|
| 60 |
result['name'] = name |
|---|
| 61 |
result['version'] = version |
|---|
| 62 |
result['authors'] = authors |
|---|
| 63 |
result['description'] = description |
|---|
| 64 |
|
|---|
| 65 |
return result |
|---|
| 66 |
|
|---|
| 67 |
|
|---|
| 68 |
def parsePlainConfig(xmlData): |
|---|
| 69 |
"""Parse plain dict configuration""" |
|---|
| 70 |
|
|---|
| 71 |
doc = xml.dom.minidom.parseString(xmlData) |
|---|
| 72 |
name = None |
|---|
| 73 |
version = None |
|---|
| 74 |
authors = [] |
|---|
| 75 |
description = None |
|---|
| 76 |
|
|---|
| 77 |
registers = doc.getElementsByTagName('plain-dictionary') |
|---|
| 78 |
if len(registers) == 0: |
|---|
| 79 |
raise "Invalid configuration" |
|---|
| 80 |
|
|---|
| 81 |
registerElement = registers[0] |
|---|
| 82 |
|
|---|
| 83 |
for nameElement in registerElement.getElementsByTagName('name'): |
|---|
| 84 |
for node in nameElement.childNodes: |
|---|
| 85 |
name = node.data |
|---|
| 86 |
|
|---|
| 87 |
for versionElement in registerElement.getElementsByTagName('version'): |
|---|
| 88 |
for node in versionElement.childNodes: |
|---|
| 89 |
version = node.data.strip() |
|---|
| 90 |
|
|---|
| 91 |
for authorElement in registerElement.getElementsByTagName('author'): |
|---|
| 92 |
authors.append({'name': authorElement.getAttribute('name'), |
|---|
| 93 |
'email': authorElement.getAttribute('email')}) |
|---|
| 94 |
|
|---|
| 95 |
for descElement in \ |
|---|
| 96 |
registerElement.getElementsByTagName('description'): |
|---|
| 97 |
for node in descElement.childNodes: |
|---|
| 98 |
description = (description or '') + node.data.strip() |
|---|
| 99 |
|
|---|
| 100 |
result = {} |
|---|
| 101 |
result['name'] = name |
|---|
| 102 |
result['version'] = version |
|---|
| 103 |
result['authors'] = authors |
|---|
| 104 |
result['description'] = description |
|---|
| 105 |
|
|---|
| 106 |
return result |
|---|
| 107 |
|
|---|
| 108 |
|
|---|
| 109 |
def generateElement(**args): |
|---|
| 110 |
"""Generate add-on XML DOM elemente""" |
|---|
| 111 |
|
|---|
| 112 |
doc = xml.dom.minidom.Document() |
|---|
| 113 |
|
|---|
| 114 |
addonElement = doc.createElement('add-on') |
|---|
| 115 |
addonElement.setAttribute('type', args.get('type')) |
|---|
| 116 |
|
|---|
| 117 |
# Name element |
|---|
| 118 |
nameElement = doc.createElement('name') |
|---|
| 119 |
addonElement.appendChild(nameElement) |
|---|
| 120 |
nameElement.appendChild(doc.createTextNode(args.get('name'))) |
|---|
| 121 |
|
|---|
| 122 |
# Version element |
|---|
| 123 |
versionElement = doc.createElement('version') |
|---|
| 124 |
addonElement.appendChild(versionElement) |
|---|
| 125 |
versionElement.appendChild(doc.createTextNode(args.get('version'))) |
|---|
| 126 |
|
|---|
| 127 |
# Authors element |
|---|
| 128 |
authorsElement = doc.createElement('authors') |
|---|
| 129 |
addonElement.appendChild(authorsElement) |
|---|
| 130 |
for author in (args.get('authors') or []): |
|---|
| 131 |
authorElement = doc.createElement('author') |
|---|
| 132 |
authorsElement.appendChild(authorElement) |
|---|
| 133 |
authorElement.setAttribute('name', author.get('name')) |
|---|
| 134 |
authorElement.setAttribute('email', author.get('email')) |
|---|
| 135 |
|
|---|
| 136 |
# Description element |
|---|
| 137 |
descElement = doc.createElement('description') |
|---|
| 138 |
addonElement.appendChild(descElement) |
|---|
| 139 |
descEscaped = "%s" % args.get('description', '') |
|---|
| 140 |
descElement.appendChild(doc.createTextNode(descEscaped)) |
|---|
| 141 |
|
|---|
| 142 |
# MD5 element |
|---|
| 143 |
md5Element = doc.createElement('md5') |
|---|
| 144 |
addonElement.appendChild(md5Element) |
|---|
| 145 |
md5Element.appendChild(doc.createTextNode(args.get('md5sum'))) |
|---|
| 146 |
|
|---|
| 147 |
# URL element |
|---|
| 148 |
urlElement = doc.createElement('url') |
|---|
| 149 |
addonElement.appendChild(urlElement) |
|---|
| 150 |
urlElement.appendChild(doc.createTextNode(args.get('url'))) |
|---|
| 151 |
|
|---|
| 152 |
# Size element |
|---|
| 153 |
sizeElement = doc.createElement('size') |
|---|
| 154 |
addonElement.appendChild(sizeElement) |
|---|
| 155 |
sizeElement.appendChild(doc.createTextNode(str(args.get('size')))) |
|---|
| 156 |
|
|---|
| 157 |
return addonElement |
|---|
| 158 |
|
|---|
| 159 |
|
|---|
| 160 |
def listFiles(start, followLinks, myDepth, maxDepth): |
|---|
| 161 |
"""Return file list""" |
|---|
| 162 |
|
|---|
| 163 |
files = [] |
|---|
| 164 |
|
|---|
| 165 |
try: |
|---|
| 166 |
dirList = os.listdir(start) |
|---|
| 167 |
except: |
|---|
| 168 |
if os.path.isdir(start): |
|---|
| 169 |
print 'ERROR: Cannot list directory %s' % start |
|---|
| 170 |
return files |
|---|
| 171 |
|
|---|
| 172 |
for item in dirList: |
|---|
| 173 |
path = os.path.join(start, item) |
|---|
| 174 |
|
|---|
| 175 |
if os.path.isdir(path) and (followLinks or \ |
|---|
| 176 |
(not followLinks and not islink(path))): |
|---|
| 177 |
files.extend(listFiles(path, followLinks, |
|---|
| 178 |
myDepth + 1, |
|---|
| 179 |
maxDepth)) |
|---|
| 180 |
else: |
|---|
| 181 |
files.append(path) |
|---|
| 182 |
|
|---|
| 183 |
return files |
|---|
| 184 |
|
|---|
| 185 |
|
|---|
| 186 |
def makeDocument(addons): |
|---|
| 187 |
"""Connect add-on elements to one XML document""" |
|---|
| 188 |
|
|---|
| 189 |
doc = xml.dom.minidom.Document() |
|---|
| 190 |
addonsElement = doc.createElement('opendict-add-ons') |
|---|
| 191 |
doc.appendChild(addonsElement) |
|---|
| 192 |
|
|---|
| 193 |
for addon in addons: |
|---|
| 194 |
addonsElement.appendChild(addon) |
|---|
| 195 |
|
|---|
| 196 |
return doc |
|---|
| 197 |
|
|---|
| 198 |
|
|---|
| 199 |
def main(): |
|---|
| 200 |
"""Main procedure""" |
|---|
| 201 |
|
|---|
| 202 |
if len(sys.argv) < 3: |
|---|
| 203 |
print "Usage: %s <directory> <base URL>" % sys.argv[0] |
|---|
| 204 |
print "(Example: '%s . http://xxx.yyy.net/dicts')" % sys.argv[0] |
|---|
| 205 |
sys.exit(1) |
|---|
| 206 |
|
|---|
| 207 |
d = sys.argv[1] |
|---|
| 208 |
baseURL = sys.argv[2] |
|---|
| 209 |
xmlElements = [] |
|---|
| 210 |
|
|---|
| 211 |
for filePath in listFiles(d, True, 0, None): |
|---|
| 212 |
|
|---|
| 213 |
try: |
|---|
| 214 |
zipFile = zipfile.ZipFile(filePath, 'r') |
|---|
| 215 |
except Exception, e: |
|---|
| 216 |
print "ERROR: %s: %s" % (filePath, e) |
|---|
| 217 |
continue |
|---|
| 218 |
|
|---|
| 219 |
# Test CRC |
|---|
| 220 |
if zipFile.testzip(): |
|---|
| 221 |
raise Exception, _("Dictionary plugin file is corrupted") |
|---|
| 222 |
|
|---|
| 223 |
# Check if empty |
|---|
| 224 |
try: |
|---|
| 225 |
topDirectory = zipFile.namelist()[0] |
|---|
| 226 |
except Exception, e: |
|---|
| 227 |
raise Exception, _("Plugin file is empty (%s)" % e) |
|---|
| 228 |
|
|---|
| 229 |
# Check for validity |
|---|
| 230 |
for fileInZip in zipFile.namelist(): |
|---|
| 231 |
dirName = os.path.dirname(fileInZip) |
|---|
| 232 |
fileName = os.path.basename(fileInZip) |
|---|
| 233 |
|
|---|
| 234 |
topDir = zipFile.namelist()[0] |
|---|
| 235 |
|
|---|
| 236 |
plainConfigPath = os.path.join(topDir, 'conf', 'config.xml') |
|---|
| 237 |
pluginConfigPath = os.path.join(topDir, 'plugin.xml') |
|---|
| 238 |
|
|---|
| 239 |
info = {} |
|---|
| 240 |
|
|---|
| 241 |
if plainConfigPath in zipFile.namelist(): |
|---|
| 242 |
info.update(parsePlainConfig(zipFile.read(plainConfigPath))) |
|---|
| 243 |
info['type'] = 'plain-dictionary' |
|---|
| 244 |
elif pluginConfigPath in zipFile.namelist(): |
|---|
| 245 |
info.update(parsePluginConfig(zipFile.read(pluginConfigPath))) |
|---|
| 246 |
info['type'] = 'plugin-dictionary' |
|---|
| 247 |
|
|---|
| 248 |
sz = os.stat(filePath)[6] / 1000 |
|---|
| 249 |
|
|---|
| 250 |
fd = open(filePath) |
|---|
| 251 |
m = md5.new(fd.read()) |
|---|
| 252 |
fd.close() |
|---|
| 253 |
checksum = m.hexdigest() |
|---|
| 254 |
|
|---|
| 255 |
location = baseURL + '/' + filePath |
|---|
| 256 |
|
|---|
| 257 |
xmlElements.append(generateElement(type=info.get('type'), |
|---|
| 258 |
name=info.get('name'), |
|---|
| 259 |
version=info.get('version'), |
|---|
| 260 |
authors=info.get('authors'), |
|---|
| 261 |
description=info.get('description'), |
|---|
| 262 |
url=location, |
|---|
| 263 |
md5sum=checksum, |
|---|
| 264 |
size=sz)) |
|---|
| 265 |
|
|---|
| 266 |
print "* %s" % filePath |
|---|
| 267 |
|
|---|
| 268 |
doc = makeDocument(xmlElements) |
|---|
| 269 |
fd = open('opendict-add-ons.xml', 'w') |
|---|
| 270 |
xml.dom.ext.PrettyPrint(doc, fd) |
|---|
| 271 |
fd.close() |
|---|
| 272 |
|
|---|
| 273 |
|
|---|
| 274 |
if __name__ == "__main__": |
|---|
| 275 |
main() |
|---|
| 276 |
|
|---|