index 670a0aff0267b61202f62a0d22b85b4e3686c257..d2897addf497c0f019d6cd5bbae4bf8edf6d6eff 100644 (file)
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-#$Id: back_anydbm.py,v 1.119 2003-04-20 11:58:45 kedder Exp $
+#$Id: back_anydbm.py,v 1.131 2003-11-14 00:11:18 richard Exp $
'''
This module defines a backend that saves the hyperdatabase in a database
chosen by anydbm. It is guaranteed to always be available in python
serious bugs, and is not available)
'''
-import whichdb, anydbm, os, marshal, re, weakref, string, copy
+try:
+ import anydbm, sys
+ # dumbdbm only works in python 2.1.2+
+ if sys.version_info < (2,1,2):
+ import dumbdbm
+ assert anydbm._defaultmod != dumbdbm
+ del dumbdbm
+except AssertionError:
+ print "WARNING: you should upgrade to python 2.1.3"
+
+import whichdb, os, marshal, re, weakref, string, copy
from roundup import hyperdb, date, password, roundupdb, security
from blobfiles import FileStorage
from sessions import Sessions, OneTimeKeys
if self.indexer.should_reindex():
self.reindex()
- # figure the "curuserid"
- if self.journaltag is None:
- self.curuserid = None
- elif self.journaltag == 'admin':
- # admin user may not exist, but always has ID 1
- self.curuserid = '1'
- else:
- self.curuserid = self.user.lookup(self.journaltag)
+ def refresh_database(self):
+ "Rebuild the database"
+ self.reindex()
def reindex(self):
for klass in self.classes.values():
# add in the "calculated" properties (dupe so we don't affect
# calling code's node assumptions)
node = node.copy()
- node['creator'] = self.curuserid
+ node['creator'] = self.getuid()
node['creation'] = node['activity'] = date.Date()
self.newnodes.setdefault(classname, {})[nodeid] = 1
def getnode(self, classname, nodeid, db=None, cache=1):
''' get a node from the database
+
+ Note the "cache" parameter is not used, and exists purely for
+ backward compatibility!
'''
if __debug__:
print >>hyperdb.DEBUG, 'getnode', (self, classname, nodeid, db)
- if cache:
- # try the cache
- cache_dict = self.cache.setdefault(classname, {})
- if cache_dict.has_key(nodeid):
- if __debug__:
- print >>hyperdb.TRACE, 'get %s %s cached'%(classname,
- nodeid)
- return cache_dict[nodeid]
+
+ # try the cache
+ cache_dict = self.cache.setdefault(classname, {})
+ if cache_dict.has_key(nodeid):
+ if __debug__:
+ print >>hyperdb.TRACE, 'get %s %s cached'%(classname,
+ nodeid)
+ return cache_dict[nodeid]
if __debug__:
print >>hyperdb.TRACE, 'get %s %s'%(classname, nodeid)
cache_creator, cache_creation) = args
if cache_classname == classname and cache_nodeid == nodeid:
if not cache_creator:
- cache_creator = self.curuserid
+ cache_creator = self.getuid()
if not cache_creation:
cache_creation = date.Date()
res.append((cache_nodeid, cache_creation, cache_creator,
if str(error) == "need 'c' or 'n' flag to open new db":
raise IndexError, 'no such %s %s'%(classname, nodeid)
elif error.args[0] != 2:
+ # this isn't a "not found" error, be alarmed!
raise
+ if res:
+ # we have unsaved journal entries, return them
+ return res
raise IndexError, 'no such %s %s'%(classname, nodeid)
try:
journal = marshal.loads(db[nodeid])
# keep a handle to all the database files opened
self.databases = {}
- # now, do all the transactions
- reindex = {}
- for method, args in self.transactions:
- reindex[method(*args)] = 1
-
- # now close all the database files
- for db in self.databases.values():
- db.close()
- del self.databases
+ try:
+ # now, do all the transactions
+ reindex = {}
+ for method, args in self.transactions:
+ reindex[method(*args)] = 1
+ finally:
+ # make sure we close all the database files
+ for db in self.databases.values():
+ db.close()
+ del self.databases
# reindex the nodes that request it
for classname, nodeid in filter(None, reindex.keys()):
if creator:
journaltag = creator
else:
- journaltag = self.curuserid
+ journaltag = self.getuid()
if creation:
journaldate = creation.serialise()
else:
l.append(repr(value))
# append retired flag
- l.append(self.is_retired(nodeid))
+ l.append(repr(self.is_retired(nodeid)))
return l
d[self.db.RETIRED_FLAG] = 1
continue
elif value is None:
- # don't set Nones
+ d[propname] = None
continue
prop = properties[propname]
IndexError is raised. 'propname' must be the name of a property
of this class or a KeyError is raised.
- 'cache' indicates whether the transaction cache should be queried
- for the node. If the node has been modified and you need to
- determine what its values prior to modification are, you need to
- set cache=0.
+ 'cache' exists for backward compatibility, and is not used.
Attempts to get the "creation" or "activity" properties should
do the right thing.
return nodeid
# get the node's dict
- d = self.db.getnode(self.classname, nodeid, cache=cache)
+ d = self.db.getnode(self.classname, nodeid)
# check for one of the special props
if propname == 'creation':
# user's been retired, return admin
return '1'
else:
- return self.db.curuserid
+ return self.db.getuid()
# get the property (raises KeyErorr if invalid)
prop = self.properties[propname]
'nodeid' must be the id of an existing node of this class or an
IndexError is raised.
- 'cache' indicates whether the transaction cache should be queried
- for the node. If the node has been modified and you need to
- determine what its values prior to modification are, you need to
- set cache=0.
+ 'cache' exists for backwards compatibility, and is not used.
'''
- return Node(self, nodeid, cache=cache)
+ return Node(self, nodeid)
def set(self, nodeid, **propvalues):
'''Modify a property on an existing node of this class.
self.fireAuditors('set', nodeid, propvalues)
# Take a copy of the node dict so that the subsequent set
# operation doesn't modify the oldvalues structure.
- try:
- # try not using the cache initially
- oldvalues = copy.deepcopy(self.db.getnode(self.classname, nodeid,
- cache=0))
- except IndexError:
- # this will be needed if somone does a create() and set()
- # with no intervening commit()
- oldvalues = copy.deepcopy(self.db.getnode(self.classname, nodeid))
+ oldvalues = copy.deepcopy(self.db.getnode(self.classname, nodeid))
node = self.db.getnode(self.classname, nodeid)
if node.has_key(self.db.RETIRED_FLAG):
u.sort()
l.append((MULTILINK, k, u))
elif isinstance(propclass, String) and k != 'id':
- # simple glob searching
- v = re.sub(r'([\|\{\}\\\.\+\[\]\(\)])', r'\\\1', v)
- v = v.replace('?', '.')
- v = v.replace('*', '.*?')
- l.append((STRING, k, re.compile(v, re.I)))
+ if type(v) is not type([]):
+ v = [v]
+ m = []
+ for v in v:
+ # simple glob searching
+ v = re.sub(r'([\|\{\}\\\.\+\[\]\(\)])', r'\\\1', v)
+ v = v.replace('?', '.')
+ v = v.replace('*', '.*?')
+ m.append(v)
+ m = re.compile('(%s)'%('|'.join(m)), re.I)
+ l.append((STRING, k, m))
elif isinstance(propclass, Date):
try:
date_rng = Range(v, date.Date, offset=timezone)
continue
break
elif t == STRING:
+ if node[k] is None:
+ break
# RE search
- if node[k] is None or not v.search(node[k]):
+ if not v.search(node[k]):
break
elif t == DATE or t == INTERVAL:
- if node[k] is None: break
+ if node[k] is None:
+ break
if v.to_value:
- if not (v.from_value < node[k] and v.to_value > node[k]):
+ if not (v.from_value <= node[k] and v.to_value >= node[k]):
break
else:
- if not (v.from_value < node[k]):
+ if not (v.from_value <= node[k]):
break
elif t == OTHER:
# straight value comparison for the other types
r = cmp(bv, av)
if r != 0: return r
- # Multilink properties are sorted according to how many
- # links are present.
- elif isinstance(propclass, Multilink):
- r = cmp(len(av), len(bv))
- if r == 0:
- # Compare contents of multilink property if lenghts is
- # equal
- r = cmp ('.'.join(av), '.'.join(bv))
- if r:
- if dir == '+':
- return r
- else:
- return -r
-
else:
# all other types just compare
if dir == '+':
return newid
def get(self, nodeid, propname, default=_marker, cache=1):
- ''' trap the content propname and get it from the file
+ ''' Trap the content propname and get it from the file
+
+ 'cache' exists for backwards compatibility, and is not used.
'''
poss_msg = 'Possibly an access right configuration problem.'
if propname == 'content':
return 'ERROR reading file: %s%s\n%s\n%s'%(
self.classname, nodeid, poss_msg, strerror)
if default is not _marker:
- return Class.get(self, nodeid, propname, default, cache=cache)
+ return Class.get(self, nodeid, propname, default)
else:
- return Class.get(self, nodeid, propname, cache=cache)
+ return Class.get(self, nodeid, propname)
def getprops(self, protected=1):
''' In addition to the actual properties on the node, these methods