2
# Copyright (C) Thom May 2002
5
#Redistribution and use in source and binary forms, with or without
6
#modification, are permitted provided that the following conditions
8
#1. Redistributions of source code must retain the above copyright
9
# notice, this list of conditions and the following disclaimer.
10
#2. Redistributions in binary form must reproduce the above copyright
11
# notice, this list of conditions and the following disclaimer in the
12
# documentation and/or other materials provided with the distribution.
14
#THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15
#IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16
#OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
#IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18
#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19
#NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
#DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21
#THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23
#THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
#TODO: add --force option
27
import shelve, textwrap
29
__all__ = ["ModHandler", "ModHandlerException", "ModuleAlreadyExists", "NoSuchModule"]
31
class ModHandlerException(Exception):
34
class ModuleAlreadyExists(ModHandlerException):
35
def __init__(self, name):
39
class NoSuchModule(ModHandlerException):
40
def __init__(self, name):
45
def __init__(self, db):
46
self.registry = shelve.open(db,"c",writeback=True)
47
self.revision = "$LastChangedRevision: 19 $"
49
def add(self,module,sequence=99,*dependencies):
50
"""add(module[, sequence, *dependencies])
52
Add a module into the registry ready for enabling.
53
module is the name of the module
54
sequence is the sequence number of the module. The default is 99
55
any further arguments define dependencies for the module"""
57
if __debug__: print "The module is", module, "and the sequence number is",sequence,"\n"
59
#now we create a tuple
60
# name, sequence, state, [dependencies]
61
if len(dependencies) > 0:
62
entry = module, sequence, state, 0, dependencies
64
entry = module, sequence, state, 0
66
if self.registry.has_key(module):
67
raise ModuleAlreadyExists(module)
69
self.registry[module] = entry
73
"""dolist (no arguments)
74
lists all the current elements in the database."""
76
for key in self.registry.keys():
77
print textwrap.fill("The name of the key is %s and the data in the key is: %s" % (key , self.registry[key][:3]))
78
if len(self.registry[key]) > 4:
79
print textwrap.fill("The dependencies for %s are: %s\n" % (key , self.registry[key][4]))
80
if self.registry[key][3] > 0:
81
print textwrap.fill("%s is in use %s times\n" % (key, self.registry[key][3]))
84
def remove(self,module):
85
if __debug__: print "Plotting to remove",module,"\n"
88
del self.registry[module]
89
if __debug__: print "Removed",module
91
raise NoSuchModule(module)
94
def enable(self,module,isdependency=False,*dependseq):
95
"""enable(module,[dependseq])
97
enable takes one or two arguments. in normal opperation, just the module
98
name is passed. When being run recursively to fix dependencies, the
99
dependency sequence of the depending module is also passed"""
102
data = self.registry[module]
104
raise NoSuchModule(module)
106
#now, we check to see if our sequence number is higher than the module that's depending on us
107
#if so, we bump our sequence number down to one less than the depending module
110
if __debug__: print module+": seqnum "+str(seqnum)
111
if len(dependseq) > 0:
112
if __debug__: print module+": dependseq "+str(dependseq[0])
113
if int(seqnum) > int(dependseq[0]):
115
seqnum = int(dependseq[0])
118
print module +": punting old seqnum:",str(oldseqnum)," to new seqnum:",str(seqnum)
119
print "new seqnum:",str(seqnum)
120
#changedseqnum = True
122
changedseqnum = False
124
#next, we need to load any dependencies.
125
#this is complicated by the need to get the sequence right.
127
dependencies = data[4]
128
if __debug__: print dependencies
129
for dependency in dependencies:
130
if __debug__: print dependency
131
returncode = self.enable(dependency,True,seqnum)
132
if __debug__: print returncode
134
#now, we check whether the module is loaded already
135
if data[2] == "enabled" and changedseqnum == False:
139
self.switchon(module,seqnum)
145
#ok, nothing has broken. Only now do we update the module's status.
146
#it would be nice to provide some semblance of atomicity to the
149
newstatus = module, seqnum, "enabled", refcount
151
newstatus = module, seqnum, "enabled", refcount, dependencies
153
self.registry[module] = newstatus
155
def disable(self,module):
156
"""disable(module) marks a module as disabled"""
158
#this might require some form of refcounting so we can work out if any
159
#unneeded dependencies can be unloaded as well, for example with mod_dav
160
#and its providers, such as dav_fs or dav_svn - but not till the basic
161
#functionality works ;-)
165
data = self.registry[module]
167
raise NoSuchModule(module)
168
if data[2] == "disabled":
171
if __debug__: print "shutting",module,"down\n"
174
self.switchoff(module,data[1])
177
newstatus = module, data[1], "disabled"
179
newstatus = module, data[1], "disabled", data[3]
181
self.registry[module] = newstatus
183
def version(self, versionnum):
185
print "The version of the client is",versionnum
186
print "The revision number of ModHandler is %s" % self.revision.strip('$').split(':')[1].strip()
188
def switchon(self,module,seqnum): pass
190
def switchoff(self,module): pass