2005-02-24 22:10:44 +01:00
|
|
|
#
|
|
|
|
# $Id$
|
|
|
|
#
|
|
|
|
# This file contains class definitions and interface to the database
|
|
|
|
# itself while defining objects that the database will return.
|
|
|
|
#
|
|
|
|
|
2005-05-26 21:41:41 +02:00
|
|
|
import rcs, os
|
2005-03-18 00:42:28 +01:00
|
|
|
|
|
|
|
|
2005-02-24 22:10:44 +01:00
|
|
|
#
|
|
|
|
# The most generic exception that this library will raise.
|
|
|
|
#
|
|
|
|
class PVVDBError(Exception):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# PVVMember is the class that represents a record in the database.
|
2005-02-24 22:37:07 +01:00
|
|
|
# Its interface is like a dict with a few additional methods to
|
2005-02-24 22:10:44 +01:00
|
|
|
# talk to the database itself.
|
|
|
|
#
|
|
|
|
class PVVMember(dict):
|
|
|
|
|
|
|
|
def __init__(self, data, dbref):
|
|
|
|
# Populate the object with the fields and values provided in the
|
|
|
|
# `data' object. `dbref' is a pointer to the PVVDB instance that
|
|
|
|
# created the PVVMember instance.
|
2005-05-26 22:42:25 +02:00
|
|
|
dict.__init__(self, data)
|
|
|
|
self.dbref = dbref
|
2005-02-24 22:10:44 +01:00
|
|
|
|
|
|
|
def save(self):
|
|
|
|
# Synchronise the object to disk via the database interface.
|
2005-05-26 22:42:25 +02:00
|
|
|
self.dbref.save(self)
|
2005-02-24 22:10:44 +01:00
|
|
|
|
|
|
|
def load(self):
|
|
|
|
# Update the object with the data on disk.
|
2005-05-26 22:42:25 +02:00
|
|
|
o = self.dbref.load(data)
|
|
|
|
self.update(o)
|
2005-02-24 22:10:44 +01:00
|
|
|
|
|
|
|
def is_saved(self):
|
|
|
|
# Checks whether the objects need to be saved or loaded.
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# PVVDB is the class that interfaces to the directory structure and files.
|
|
|
|
# It also verifies the data read from the files and written to it.
|
|
|
|
#
|
|
|
|
class PVVDB:
|
|
|
|
|
|
|
|
def __init__(self, base):
|
|
|
|
# Find the record definition file, read it, verify it and
|
|
|
|
# set the legal set of fields.
|
2005-05-26 21:41:41 +02:00
|
|
|
self.base = base # base database directory
|
|
|
|
self.locks = [] # list of activated locks
|
|
|
|
self.rcs = rcs.RCS() # an RCS interface function
|
2005-05-26 23:09:08 +02:00
|
|
|
self.format = self.__format(
|
|
|
|
os.path.join(self.base, ".format"))
|
2005-02-24 22:10:44 +01:00
|
|
|
|
2005-02-24 22:23:55 +01:00
|
|
|
def __del__(self):
|
|
|
|
# clean up locks and such before being deleted.
|
2005-05-26 21:41:41 +02:00
|
|
|
for username in self.locks:
|
|
|
|
self.rcs.unlock(username)
|
|
|
|
|
|
|
|
def __filename(self, username):
|
|
|
|
# transform the username into a tuple with the full name of
|
|
|
|
# the databasefile and the latest revision number.
|
|
|
|
return self.rcs.rcsname(os.path.join(self.base, username))
|
2005-02-24 22:23:55 +01:00
|
|
|
|
2005-03-18 00:42:28 +01:00
|
|
|
def __format(self, file_path):
|
|
|
|
# parses and verifies the .format files for a database.
|
|
|
|
fh = file(file_path)
|
|
|
|
fmt = {}
|
|
|
|
for line in fh:
|
|
|
|
if line[0] == "#":
|
|
|
|
continue
|
2005-05-26 21:41:41 +02:00
|
|
|
name, value = line.strip().split(":", 1)
|
|
|
|
value = value.split("#", 1)[0].strip()
|
2005-03-18 00:49:12 +01:00
|
|
|
if not value in ['scalar', 'list']:
|
|
|
|
raise PVVDBError, "%s not legal .format datatype." % value
|
2005-03-18 00:42:28 +01:00
|
|
|
fmt[name] = value
|
|
|
|
return fmt
|
|
|
|
|
2005-05-26 21:41:41 +02:00
|
|
|
def lock(self, username, pedantic=False):
|
2005-02-24 22:10:44 +01:00
|
|
|
# Lock the record.
|
2005-05-26 21:41:41 +02:00
|
|
|
if username in self.locks and pedantic:
|
|
|
|
raise PVVDBError, "%s already locked." % `username`
|
|
|
|
self.rcs.lock(self.__filename(username))
|
|
|
|
self.locks.append(username)
|
|
|
|
|
2005-02-24 22:10:44 +01:00
|
|
|
|
2005-05-26 21:41:41 +02:00
|
|
|
def unlock(self, username, pedantic=False):
|
2005-02-24 22:10:44 +01:00
|
|
|
# Unlock the record.
|
2005-05-26 22:19:45 +02:00
|
|
|
if not username in self.locks and pedantic:
|
|
|
|
raise PVVDBError, "%s not locked." % `username`
|
|
|
|
self.rcs.unlock(self.__filename(username))
|
|
|
|
self.locks.remove(username)
|
2005-02-24 22:10:44 +01:00
|
|
|
|
|
|
|
def load(self, username, lock=False):
|
|
|
|
# Read the record from the database. Will do an automatic lock
|
|
|
|
# if `lock' is True.
|
2005-05-27 17:13:16 +02:00
|
|
|
cwd = os.getcwd()
|
|
|
|
os.chdir(self.base)
|
|
|
|
rv = self.rcs.checkout(username + ",v")
|
|
|
|
userfile = file(username)
|
|
|
|
os.chdir(cwd)
|
2005-05-26 22:19:45 +02:00
|
|
|
member = {}
|
|
|
|
for line in userfile:
|
|
|
|
key, value = line.strip().split(": ", 1)
|
|
|
|
if not key in self.format:
|
|
|
|
raise PVVDBError, "%s not a legal attribute." % `key`
|
|
|
|
v = None
|
|
|
|
# handle the list datatype
|
|
|
|
if self.format[key] == 'list':
|
|
|
|
v = []
|
|
|
|
# XXX: needs to respect escaping of field separators
|
|
|
|
for e in value.split(", "):
|
|
|
|
v.append(e)
|
|
|
|
elif self.format[key] == 'scalar':
|
|
|
|
v = value
|
|
|
|
else:
|
|
|
|
# we should not be here
|
|
|
|
raise PVVDBError, "%s not legal datatype." % `self.format[key]`
|
2005-05-27 17:13:16 +02:00
|
|
|
member[key] = v
|
2005-05-26 22:42:25 +02:00
|
|
|
return PVVMember(member, self)
|
2005-02-24 22:10:44 +01:00
|
|
|
|
|
|
|
def save(self, username, comment="", lock=False):
|
|
|
|
# Write the record to the database. Will automatically unlock
|
|
|
|
# the record if `lock' is True. A `comment' can be supplied that
|
|
|
|
# explains the changes made.
|
|
|
|
pass
|
2005-02-24 22:23:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Regular interface to the database.
|
|
|
|
#
|
2005-03-18 00:42:28 +01:00
|
|
|
|
|
|
|
pathmap = {}
|
|
|
|
|
2005-02-24 22:23:55 +01:00
|
|
|
def connect(path):
|
|
|
|
# returns a PVVDB instance to that path. If asked for another
|
|
|
|
# PVVDB instance with the same path as earlier, it will return
|
|
|
|
# the same object.
|
2005-03-18 00:42:28 +01:00
|
|
|
if not path in pathmap:
|
|
|
|
pathmap[path] = PVVDB(path)
|
|
|
|
return pathmap[path]
|
2005-02-24 22:23:55 +01:00
|
|
|
|
|
|
|
def disconnect(dbo):
|
|
|
|
# do not do anything, really. PVVDB objects will clean up
|
2005-03-18 00:42:28 +01:00
|
|
|
# automatically when deleted. is here for future database
|
|
|
|
# systems.
|
2005-02-24 22:23:55 +01:00
|
|
|
pass
|