1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
|
#!/usr/bin/python
# sorts resources by their included name and version information
# usage: call from the directory containing the resources or
# call
# sortresources.py <path_to_seach_and_sort>
# use sortresources.py -h to get command line option help
from xml import sax
from xml.sax import handler
import string
import os.path
import os
import sys
import StringIO
# parse a resource xml file and fill in data property data strucure
def parseResource(filename, data):
# document parser class
class docHandler(handler.ContentHandler):
def __init__(self,data):
self.data = data
# fill in defaults
data.type = "unknown"
data.name = ""
data.version = "1.0"
data.author = "Anonymous"
data.category = ""
def startElement(self,name,attr):
# just parse the <map> tag and fill data
if name in("Resource","Map"):
# set type from tag name it is not already set
try: oldtype = self.data.type
except: self.data.type = name.lower()
# read values from file
if "name" in attr.getNames():
self.data.name = attr.getValue("name")
else:
return #invalid element
if "author" in attr.getNames():
self.data.author = attr.getValue("author")
else:
return #invalid element
if "type" in attr.getNames():
self.data.type = attr.getValue("type")
if "version" in attr.getNames():
self.data.version = attr.getValue("version")
if "category" in attr.getNames():
self.data.category = attr.getValue("category")
# rudimentary entity resolver
class entityResolver:
# initialize, storing a path and a data object
def __init__(self,path,data):
self.path = path
self.data = data
# return a stream for a given external entity
def resolveEntity(self,pubid,sysid):
path = self.path
# extract data type: the base name of the DTD
self.data.type = string.split(sysid,"-")[0]
# look in current and parent directories for dtds
while len(path) > 0:
fullfile = os.path.join(path, sysid)
try: return open( fullfile )
except: pass
# go to "parent" directory
path = os.path.split(path)[0]
# fallback: return empty stream, result: no dtd checking is done.
# Not horribly bad in this context
print "warning, could not find requested entity", sysid
return StringIO.StringIO("")
# parse: create parser...
parser = sax.make_parser()
# set it's content handler to extract the category data we want...
parser.setContentHandler( docHandler(data) )
# give it a dummy entity resolver that tries to find external entites in a
# half-assed way...
parser.setEntityResolver( entityResolver(os.path.split(filename)[0], data) )
# and go!
parser.parse( open(filename) )
# exception rule for the moment: Translate type = map to type = aamap.
try:
if data.type == "map":
data.type = "aamap"
except: pass
# take the parsed data and trandsform it into a filename
def getName(data):
return os.path.join(data.author, data.category, data.name) + "-" + data.version + "." + data.type + ".xml"
# determine the canonical name of a xml resource
def getCanonicalPath(path):
# trivial data class
class Data:
pass
# parse xml file and return name
data = Data()
parseResource(path, data)
return getName(data)
# scan for all XML files in the directory and rename them according to the rules
def scanDir(sourceDir, destinationDir, function):
def visitor( arg, dirname, names ):
for file in names:
if len(file) > 4 and file[-4:] == ".xml":
path = os.path.join(dirname,file)
newPath = getCanonicalPath(path)
# call the passed function
function(path, os.path.join(destinationDir, newPath), newPath)
os.path.walk(sourceDir, visitor, visitor )
# move file oldFile to newFile
def Move(oldFile, newFile, canonicalPath ):
if oldFile == newFile:
return False
Print( oldFile, newFile, canonicalPath )
# generate target directory
dir = os.path.split(newFile)[0]
if not os.path.exists(dir):
os.makedirs(dir)
# move file
os.rename(oldFile, newFile)
return True
# dummy replacement: just print
def Print(oldFile, newFile, canonicalPath ):
if oldFile == newFile:
return False
if doPrint:
print "renaming", oldFile, "->", newFile
# move file oldFile to newFile, setting apache rewrite rules to keep the file
# fetchable from its old position
def Redirect(oldFile, newFile, canonicalPath ):
# move the file
if Move( oldFile, newFile, canonicalPath ):
# determine full path
fullCanonicalPath = "/resource/" + canonicalPath
# file was really moved, see what directory it came from
oldPath = os.path.split( oldFile )
# determine filename of the .htaccess file
htaccessPath = os.path.join( oldPath[0], ".htaccess" )
# determine whether we need to add the RewriteEngine On line:
needEngine = True
try:
# open .htaccess file in the old directory for reading
accessFile = open(htaccessPath)
for line in accessFile:
splitLineLower = string.split(line.lower())
splitLine = string.split(line)
if splitLineLower[0] == "rewriteengine":
# rewriting is already mentioned; we don't have to enable it laster.
needEngine = False
# see if there already is a rewrite rule for our file
if splitLineLower[0] == "rewriterule" and splitLine[1] == oldPath[1]:
if splitLine[2] == fullCanonicalPath:
# nothing to do
return
else:
print "Warning: There already is a different RewriteRule for", oldFile, "in place."
except: pass
# open .htaccess file for appended writing
accessFile = open(htaccessPath, "a")
# enable rewriting
if needEngine:
accessFile.write("RewriteEngine On\n")
# add rewrite rule
accessFile.write( "RewriteRule " + oldPath[1] + " " + fullCanonicalPath + "\n");
# print usage message and exit.
def Options( ret ):
print
print "Usage: sortresources.py [OPTIONS] <source directory> <destination directory>"
print " Omitting the destination directory makes it equal to the source."
print " Omitting both directories makes them the current working directory."
print "Options: -r add apache rewrite rules"
print " -n don't do anything, just print what would be done"
print " -v print non-warning status messages"
print " -h print this message"
print
sys.exit( ret )
if __name__ == "__main__":
destinationDirectory = "."
sourceDirectory = "."
function = Move
global doPrint
doPrint = False
# parse arguments
for arg in sys.argv[1:]:
# parse options
if arg[0] == "-":
if len(arg) > 1:
if arg[1] == "h":
Options( 0 )
continue
if arg[1] == "n":
function = Print
doPrint = True
continue
if arg[1] == "r":
function = Redirect
continue
if arg[1] == "v":
doPrint = True
continue
print "\nUnknown option:", arg
Options(-1)
else:
Options(-1)
else:
# non-dashed argument gives the target and destination directory
if "." == destinationDirectory:
sourceDirectory = arg
destinationDirectory = arg
# print sourceDirectory, destinationDirectory
# do the work
scanDir(sourceDirectory, destinationDirectory, function)
|