index a043e5a3d4cdeb77b307e3f3f16ec9387a80bd1f..89193822f499a5be15aacfbdd4082f98087052f7 100755 (executable)
-from roundup import hyperdb, date, password, roundupdb
+from roundup import hyperdb, date, password, roundupdb, security
import metakit
+from sessions import Sessions
import re, marshal, os, sys, weakref, time, calendar
-from roundup import indexer
+from roundup import indexer
+import locking
-class Database(hyperdb.Database):
+_dbs = {}
+
+def Database(config, journaltag=None):
+ db = _dbs.get(config.DATABASE, None)
+ if db is None or db._db is None:
+ db = _Database(config, journaltag)
+ _dbs[config.DATABASE] = db
+ else:
+ db.journaltag = journaltag
+ try:
+ delattr(db, 'curuserid')
+ except AttributeError:
+ pass
+ return db
+
+class _Database(hyperdb.Database):
def __init__(self, config, journaltag=None):
self.config = config
self.journaltag = journaltag
self.classes = {}
- self._classes = []
self.dirty = 0
+ self.lockfile = None
self._db = self.__open()
self.indexer = Indexer(self.config.DATABASE, self._db)
+ self.sessions = Sessions(self.config)
+ self.security = security.Security(self)
+
os.umask(0002)
def post_init(self):
if self.indexer.should_reindex():
self.reindex()
def reindex(self):
- print "Reindexing!!!"
for klass in self.classes.values():
for nodeid in klass.list():
klass.index(nodeid)
except KeyError:
x = 0
return x
+ elif classname == 'transactions':
+ return self.dirty
return self.getclass(classname)
def getclass(self, classname):
return self.classes[classname]
for cl in self.classes.values():
cl._clear()
def hasnode(self, classname, nodeid):
- return self.getclass(clasname).hasnode(nodeid)
+ return self.getclass(classname).hasnode(nodeid)
def pack(self, pack_before):
pass
def addclass(self, cl):
self.classes[cl.classname] = cl
- if self.tables.find(name=cl.classname) < 0:
- self.tables.append(name=cl.classname)
+ if self.tables.find(name=cl.classname) < 0:
+ self.tables.append(name=cl.classname)
def addjournal(self, tablenm, nodeid, action, params):
tblid = self.tables.find(name=tablenm)
if tblid == -1:
for cl in self.classes.values():
cl.db = None
self._db = None
+ locking.release_lock(self.lockfile)
+ del _dbs[self.config.DATABASE]
+ self.lockfile.close()
self.classes = {}
self.indexer = None
# --- internal
def __open(self):
self.dbnm = db = os.path.join(self.config.DATABASE, 'tracker.mk4')
+ lockfilenm = db[:-3]+'lck'
+ self.lockfile = locking.acquire_lock(lockfilenm)
+ self.lockfile.write(str(os.getpid()))
+ self.lockfile.flush()
self.fastopen = 0
if os.path.exists(db):
dbtm = os.path.getmtime(db)
class Class:
privateprops = None
def __init__(self, db, classname, **properties):
- self.db = weakref.proxy(db)
+ #self.db = weakref.proxy(db)
+ self.db = db
self.classname = classname
self.keyname = None
self.ruprops = properties
if not isnew:
self.fireAuditors('set', nodeid, propvalues)
if not propvalues:
- return
+ return propvalues
if propvalues.has_key('id'):
raise KeyError, '"id" is reserved'
if self.db.journaltag is None:
# do stuff based on the prop type
if isinstance(prop, hyperdb.Link):
link_class = prop.classname
+ # must be a string or None
+ if value is not None and not isinstance(value, type('')):
+ raise ValueError, 'property "%s" link value be a string'%(
+ propname)
+ # Roundup sets to "unselected" by passing None
+ if value is None:
+ value = 0
# if it isn't a number, it's a key
- if type(value) != _STRINGTYPE:
- raise ValueError, 'link value must be String'
try:
int(value)
except ValueError:
raise IndexError, 'new property "%s": %s not a %s'%(
key, value, prop.classname)
- if not self.db.getclass(link_class).hasnode(value):
+ if (value is not None and
+ not self.db.getclass(link_class).hasnode(value)):
raise IndexError, '%s has no node %s'%(link_class, value)
setattr(row, key, int(value))
if self.do_journal and prop.do_journal:
# register the unlink with the old linked node
if oldvalue:
- self.db.addjournal(link_class, value, _UNLINK, (self.classname, str(row.id), key))
+ self.db.addjournal(link_class, value, _UNLINK,
+ (self.classname, str(row.id), key))
# register the link with the newly linked node
if value:
- self.db.addjournal(link_class, value, _LINK, (self.classname, str(row.id), key))
+ self.db.addjournal(link_class, value, _LINK,
+ (self.classname, str(row.id), key))
elif isinstance(prop, hyperdb.Multilink):
if type(value) != _LISTTYPE:
for id in adds:
sv.append(fid=int(id))
changes[key] = oldvalue
+ if not rmvd and not adds:
+ del propvalues[key]
elif isinstance(prop, hyperdb.String):
# nothing to do?
if not propvalues:
- return
+ return propvalues
if not propvalues.has_key('activity'):
row.activity = int(time.time())
if isnew:
self.db.addjournal(self.classname, nodeid, _SET, changes)
self.fireReactors('set', nodeid, oldnode)
+ return propvalues
+
def retire(self, nodeid):
self.fireAuditors('retire', nodeid, None)
view = self.getview(1)
row._isdel = 1
if self.do_journal:
self.db.addjournal(self.classname, nodeid, _RETIRE, {})
- iv = self.getindexview(1)
- ndx = iv.find(k=getattr(row, self.keyname),i=row.id)
- if ndx > -1:
- iv.delete(ndx)
+ if self.keyname:
+ iv = self.getindexview(1)
+ ndx = iv.find(k=getattr(row, self.keyname),i=row.id)
+ if ndx > -1:
+ iv.delete(ndx)
self.db.dirty = 1
self.fireReactors('retire', nodeid, None)
def history(self, nodeid):
# search_matches is None or a set (dict of {nodeid: {propname:[nodeid,...]}})
# filterspec is a dict {propname:value}
# sort and group are lists of propnames
-
+ # sort and group are (dir, prop) where dir is '+', '-' or None
+ # and prop is a prop name or None
+
where = {'_isdel':0}
mlcriteria = {}
regexes = {}
if sort or group:
sortspec = []
rev = []
- for propname in group + sort:
+ for dir, propname in group, sort:
+ if propname is None: continue
isreversed = 0
- if propname[0] == '-':
- propname = propname[1:]
+ if dir == '-':
isreversed = 1
try:
prop = getattr(v, propname)
except AttributeError:
+ print "MK has no property %s" % propname
continue
+ propclass = self.ruprops.get(propname, None)
+ if propclass is None:
+ propclass = self.privateprops.get(propname, None)
+ if propclass is None:
+ print "Schema has no property %s" % propname
+ continue
+ if isinstance(propclass, hyperdb.Link):
+ linkclass = self.db.getclass(propclass.classname)
+ lv = linkclass.getview()
+ lv = lv.rename('id', propname)
+ v = v.join(lv, prop, 1)
+ if linkclass.getprops().has_key('order'):
+ propname = 'order'
+ else:
+ propname = linkclass.labelprop()
+ prop = getattr(v, propname)
if isreversed:
rev.append(prop)
sortspec.append(prop)
else:
mkprop = None
if mkprop is None:
- print "%s missing prop %s (%s)" % (self.classname, nm, rutyp.__class__.__name__)
break
if _typmap[rutyp.__class__] != mkprop.type:
- print "%s - prop %s (%s) has wrong mktyp (%s)" % (self.classname, nm, rutyp.__class__.__name__, mkprop.type)
break
else:
return view.ordered(1)
newid = Class.create(self, **propvalues)
if not content:
return newid
- if content.startswith('/tracker/download.php?'):
- self.set(newid, content='http://sourceforge.net'+content)
- return newid
nm = bnm = '%s%s' % (self.classname, newid)
sd = str(int(int(newid) / 1000))
d = os.path.join(self.db.config.DATABASE, 'files', self.classname, sd)
if not properties.has_key('files'):
properties['files'] = hyperdb.Multilink("file")
if not properties.has_key('nosy'):
- properties['nosy'] = hyperdb.Multilink("user")
+ # note: journalling is turned off as it really just wastes
+ # space. this behaviour may be overridden in an instance
+ properties['nosy'] = hyperdb.Multilink("user", do_journal="no")
if not properties.has_key('superseder'):
properties['superseder'] = hyperdb.Multilink(classname)
Class.__init__(self, db, classname, **properties)
if self.changed:
self.db.commit()
self.changed = 0
-
-
-
-