]> code.delx.au - pymsnt/blob - src/xdb.py
Use md5 hashes for spool dir. Moved avatar dir to root of spool dir.
[pymsnt] / src / xdb.py
1 # Copyright 2004-2005 James Bunton <james@delx.cjb.net>
2 # Licensed for distribution under the GPL version 2, check COPYING for details
3
4 from tlib import xmlw
5 from debug import LogEvent, INFO, WARN
6 import os
7 import os.path
8 import shutil
9 import md5
10 import config
11
12 X = os.path.sep
13 SPOOL_UMASK = 0077
14
15
16 def unmangle(file):
17 chunks = file.split("%")
18 end = chunks.pop()
19 file = "%s@%s" % ("%".join(chunks), end)
20 return file
21
22 def mangle(file):
23 return file.replace("@", "%")
24
25 def makeHash(file):
26 return md5.md5(file).hexdigest()[0:3]
27
28
29 class XDB:
30 """
31 Class for storage of data.
32
33 Create one instance of the class for each XDB 'folder' you want.
34 Call request()/set() with the xdbns argument you wish to retrieve
35 """
36 def __init__(self, name, mangle=False):
37 """ Creates an XDB object. If mangle is True then any '@' signs in filenames will be changed to '%' """
38 self.name = os.path.join(os.path.abspath(config.spooldir), name)
39 if not os.path.exists(self.name):
40 os.makedirs(self.name)
41 self.mangle = mangle
42
43 def __getFile(self, file):
44 if(self.mangle):
45 file = mangle(file)
46
47 hash = makeHash(file)
48 document = xmlw.parseFile(self.name + X + hash + X + file + ".xml")
49
50 return document
51
52 def __writeFile(self, file, text):
53 if(self.mangle):
54 file = mangle(file)
55
56 prev_umask = os.umask(SPOOL_UMASK)
57 hash = makeHash(file)
58 pre = self.name + X + hash + X
59 if not os.path.exists(pre):
60 os.makedirs(pre)
61 try:
62 f = open(pre + file + ".xml.new", "w")
63 f.write(text)
64 f.close()
65 shutil.move(pre + file + ".xml.new", pre + file + ".xml")
66 except IOError, e:
67 LogEvent(WARN, "", "IOError " + str(e))
68 raise
69 os.umask(prev_umask)
70
71 def files(self):
72 """ Returns a list containing the files in the current XDB database """
73 files = []
74 for dir in os.listdir(self.name):
75 if(os.path.isdir(self.name + X + dir)):
76 files.extend(os.listdir(self.name + X + dir))
77 if self.mangle:
78 files = [unmangle(x)[:-4] for x in files]
79 else:
80 files = [x[:-4] for x in files]
81
82 while files.count(''):
83 files.remove('')
84
85 return files
86
87 def request(self, file, xdbns):
88 """ Requests a specific xdb namespace from the XDB 'file' """
89 try:
90 document = self.__getFile(file)
91 for child in document.elements():
92 if(child.getAttribute("xdbns") == xdbns):
93 return child
94 except:
95 return None
96
97 def set(self, file, xdbns, element):
98 """ Sets a specific xdb namespace in the XDB 'file' to element """
99 try:
100 element.attributes["xdbns"] = xdbns
101 document = None
102 try:
103 document = self.__getFile(file)
104 except IOError:
105 pass
106 if(not document):
107 document = xmlw.Element((None, "xdb"))
108
109 # Remove the existing node (if any)
110 for child in document.elements():
111 if(child.getAttribute("xdbns") == xdbns):
112 document.children.remove(child)
113 # Add the new one
114 document.addChild(element)
115
116 self.__writeFile(file, document.toXml())
117 except IOError, e:
118 LogEvent(WARN, "", "IOError " + str(e))
119 raise
120
121 def remove(self, file):
122 """ Removes an XDB file """
123 file = self.name + X + file[0:2] + X + file + ".xml"
124 if(self.mangle):
125 file = mangle(file)
126 try:
127 os.remove(file)
128 except IOError, e:
129 LogEvent(WARN, "", "IOError " + str(e))
130 raise
131
132
133