language namespace for plugins separated

plugin interface changed ("prepareForm" removed)
plugins do not raise exceptions anymore
first part of the partitioning plugin
device-specific stuff moved to CryptoBoxTools
This commit is contained in:
lars 2006-09-14 12:33:01 +00:00
parent f2a7ceb61c
commit de3280806f
26 changed files with 622 additions and 309 deletions

View file

@ -18,6 +18,7 @@ import CryptoBoxContainer
from CryptoBoxExceptions import *
import re
import os
import CryptoBoxTools
@ -112,10 +113,16 @@ class CryptoBoxProps(CryptoBox):
def __init__(self, config_file=None):
'''read config and fill class variables'''
CryptoBox.__init__(self, config_file)
self.__reReadContainerList()
def __reReadContainerList(self):
self.containers = []
for device in self.__getAvailablePartitions():
for device in CryptoBoxTools.getAvailablePartitions():
if self.isDeviceAllowed(device):
self.containers.append(CryptoBoxContainer.CryptoBoxContainer(device, self))
## sort by container name
self.containers.sort(cmp = lambda x,y: x.getName() < y.getName() and -1 or 1)
def isDeviceAllowed(self, devicename):
@ -185,9 +192,22 @@ class CryptoBoxProps(CryptoBox):
"assign a name to a uuid in the ContainerNameDatabase"
used_uuid = self.getUUIDForName(name)
"first remove potential conflicting uuid/name combination"
if used_uuid: del self.prefs.nameDB[used_uuid]
if used_uuid:
## remember the container which name was overriden
for e in self.containers:
if e.getName() == name:
forcedRename = e
break
del self.prefs.nameDB[used_uuid]
self.prefs.nameDB[uuid] = name
self.prefs.nameDB.write()
## rename the container that lost its name (necessary while we use cherrypy)
if used_uuid:
## this is surely not the best way to regenerate the name
dev = e.getDevice()
old_index = self.containers.index(e)
self.containers.remove(e)
self.containers.insert(old_index, CryptoBoxContainer.CryptoBoxContainer(dev,self))
def getNameForUUID(self, uuid):
@ -244,102 +264,6 @@ class CryptoBoxProps(CryptoBox):
return []
""" ************ internal stuff starts here *********** """
def __getAvailablePartitions(self):
"retrieve a list of all available containers"
ret_list = []
try:
"the following reads all lines of /proc/partitions and adds the mentioned devices"
fpart = open("/proc/partitions", "r")
try:
line = fpart.readline()
while line:
p_details = line.split()
if (len(p_details) == 4):
"the following code prevents double entries like /dev/hda and /dev/hda1"
(p_major, p_minor, p_size, p_device) = p_details
if re.search('^[0-9]*$', p_major) and re.search('^[0-9]*$', p_minor):
p_parent = re.sub('[1-9]?[0-9]$', '', p_device)
if p_parent == p_device:
if [e for e in ret_list if re.search('^' + p_parent + '[1-9]?[0-9]$', e)]:
"major partition - its children are already in the list"
pass
else:
"major partition - but there are no children for now"
ret_list.append(p_device)
else:
"minor partition - remove parent if necessary"
if p_parent in ret_list: ret_list.remove(p_parent)
ret_list.append(p_device)
line = fpart.readline()
finally:
fpart.close()
return [self.__getAbsoluteDeviceName(e) for e in ret_list]
except IOError:
self.log.warning("Could not read /proc/partitions")
return []
def __getAbsoluteDeviceName(self, shortname):
""" returns the absolute file name of a device (e.g.: "hda1" -> "/dev/hda1")
this does also work for device mapper devices
if the result is non-unique, one arbitrary value is returned"""
if re.search('^/', shortname): return shortname
default = os.path.join("/dev", shortname)
if os.path.exists(default): return default
result = self.__findMajorMinorOfDevice(shortname)
"if no valid major/minor was found -> exit"
if not result: return default
(major, minor) = result
"for device-mapper devices (major == 254) ..."
if major == 254:
result = self.__findMajorMinorDeviceName("/dev/mapper", major, minor)
if result: return result[0]
"now check all files in /dev"
result = self.__findMajorMinorDeviceName("/dev", major, minor)
if result: return result[0]
return default
def __findMajorMinorOfDevice(self, device):
"return the major/minor numbers of a block device by querying /sys/block/?/dev"
if not os.path.exists(os.path.join("/sys/block", device)): return None
blockdev_info_file = os.path.join(os.path.join("/sys/block", device), "dev")
try:
f_blockdev_info = open(blockdev_info_file, "r")
blockdev_info = f_blockdev_info.read()
f_blockdev_info.close()
(str_major, str_minor) = blockdev_info.split(":")
"numeric conversion"
try:
major = int(str_major)
minor = int(str_minor)
return (major, minor)
except ValueError:
"unknown device numbers -> stop guessing"
return None
except IOError:
pass
def __findMajorMinorDeviceName(self, dir, major, minor):
"returns the names of devices with the specified major and minor number"
collected = []
try:
subdirs = [os.path.join(dir, e) for e in os.listdir(dir) if (not os.path.islink(os.path.join(dir, e))) and os.path.isdir(os.path.join(dir, e))]
"do a recursive call to parse the directory tree"
for dirs in subdirs:
collected.extend(self.__findMajorMinorDeviceName(dirs, major, minor))
"filter all device inodes in this directory"
collected.extend([os.path.realpath(os.path.join(dir, e)) for e in os.listdir(dir) if (os.major(os.stat(os.path.join(dir, e)).st_rdev) == major) and (os.minor(os.stat(os.path.join(dir, e)).st_rdev) == minor)])
result = []
for e in collected:
if e not in result: result.append(e)
return collected
except OSError:
return []
if __name__ == "__main__":
cb = CryptoBox()

View file

@ -205,6 +205,7 @@ class CryptoBoxContainer:
def __getUUID(self):
"""return UUID for luks partitions, ext2/3 and vfat filesystems"""
emergency_default = self.device.replace(os.path.sep, "_")
devnull = None
try:
devnull = open(os.devnull, "w")
@ -214,7 +215,7 @@ class CryptoBoxContainer:
shell=False,
stdin=None,
stdout=subprocess.PIPE,
stderr=devnull,
stderr=subprocess.PIPE,
args=[self.Progs["blkid"],
"-s", "UUID",
"-o", "value",
@ -225,10 +226,10 @@ class CryptoBoxContainer:
result = proc.stdout.read().strip()
if proc.returncode != 0:
self.log.warn("retrieving of partition type via 'blkid' failed: %s" % (proc.stderr.read().strip(), ))
return None
return emergency_default
devnull.close()
if result: return result
return self.device.replace(os.path.sep, "_")
return emergency_default
def __getTypeOfPartition(self):

View file

@ -0,0 +1,117 @@
import logging
import os
import re
logger = logging.getLogger("CryptoBox")
def getAvailablePartitions():
"retrieve a list of all available containers"
ret_list = []
try:
"the following reads all lines of /proc/partitions and adds the mentioned devices"
fpart = open("/proc/partitions", "r")
try:
line = fpart.readline()
while line:
p_details = line.split()
if (len(p_details) == 4):
"the following code prevents double entries like /dev/hda and /dev/hda1"
(p_major, p_minor, p_size, p_device) = p_details
if re.search('^[0-9]*$', p_major) and re.search('^[0-9]*$', p_minor):
p_parent = re.sub('[1-9]?[0-9]$', '', p_device)
if p_parent == p_device:
if [e for e in ret_list if re.search('^' + p_parent + '[1-9]?[0-9]$', e)]:
"major partition - its children are already in the list"
pass
else:
"major partition - but there are no children for now"
ret_list.append(p_device)
else:
"minor partition - remove parent if necessary"
if p_parent in ret_list: ret_list.remove(p_parent)
ret_list.append(p_device)
line = fpart.readline()
finally:
fpart.close()
return map(getAbsoluteDeviceName, ret_list)
except IOError:
logger.warning("Could not read /proc/partitions")
return []
def getAbsoluteDeviceName(shortname):
""" returns the absolute file name of a device (e.g.: "hda1" -> "/dev/hda1")
this does also work for device mapper devices
if the result is non-unique, one arbitrary value is returned"""
if re.search('^/', shortname): return shortname
default = os.path.join("/dev", shortname)
if os.path.exists(default): return default
result = findMajorMinorOfDevice(shortname)
"if no valid major/minor was found -> exit"
if not result: return default
(major, minor) = result
"for device-mapper devices (major == 254) ..."
if major == 254:
result = findMajorMinorDeviceName("/dev/mapper", major, minor)
if result: return result[0]
"now check all files in /dev"
result = findMajorMinorDeviceName("/dev", major, minor)
if result: return result[0]
return default
def findMajorMinorOfDevice(device):
"return the major/minor numbers of a block device by querying /sys/block/?/dev"
if not os.path.exists(os.path.join(os.path.sep,"sys","block",device)): return None
blockdev_info_file = os.path.join(os.path.join(os.path.sep,"sys","block", device), "dev")
try:
f_blockdev_info = open(blockdev_info_file, "r")
blockdev_info = f_blockdev_info.read()
f_blockdev_info.close()
(str_major, str_minor) = blockdev_info.split(":")
"numeric conversion"
try:
major = int(str_major)
minor = int(str_minor)
return (major, minor)
except ValueError:
"unknown device numbers -> stop guessing"
return None
except IOError:
pass
def findMajorMinorDeviceName(dir, major, minor):
"returns the names of devices with the specified major and minor number"
collected = []
try:
subdirs = [os.path.join(dir, e) for e in os.listdir(dir) if (not os.path.islink(os.path.join(dir, e))) and os.path.isdir(os.path.join(dir, e))]
"do a recursive call to parse the directory tree"
for dirs in subdirs:
collected.extend(findMajorMinorDeviceName(dirs, major, minor))
"filter all device inodes in this directory"
collected.extend([os.path.realpath(os.path.join(dir, e)) for e in os.listdir(dir) if (os.major(os.stat(os.path.join(dir, e)).st_rdev) == major) and (os.minor(os.stat(os.path.join(dir, e)).st_rdev) == minor)])
## remove double entries
result = []
for e in collected:
if e not in result: result.append(e)
return result
except OSError:
return []
def getParentBlockDevices():
devs = []
for line in file("/proc/partitions"):
p_details = line.split()
## we expect four values - otherwise continue with next iteration
if len(p_details) != 4: continue
(p_major, p_minor, p_size, p_device) = p_details
## we expect numeric values in the first two columns
if re.search(u'\D',p_major) or re.search(u'\D',p_minor): continue
## now let us check, if it is a (parent) block device or a partition
if not os.path.isdir(os.path.join(os.path.sep, "sys", "block", p_device)): continue
devs.append(p_device)
return map(getAbsoluteDeviceName, devs)

View file

@ -44,14 +44,19 @@ class PluginManager:
def loadLanguageData(self, hdf, lang="en"):
import neo_cgi, neo_util
for plfile in self.__getPluginFiles():
plname = os.path.basename(plfile)[:-3]
langdir = os.path.join(os.path.dirname(plfile), "lang")
selected_langfile = os.path.join(langdir, lang + ".hdf")
default_langfile = os.path.join(langdir, "en.hdf")
for langfile in (selected_langfile, default_langfile):
if os.access(langfile, os.R_OK):
self.log.debug("Loading plugin language file: %s" % langfile)
hdf.readFile(langfile)
lang_hdf = neo_util.HDF()
lang_hdf.readFile(langfile)
## add the language data below "Lang.Plugins.PLUGINNAME"
hdf.copy("Lang.Plugins." + plname, lang_hdf)
break
else:
self.log.debug("Couldn't find a plugin language file (%s)" % default_langfile)

View file

@ -18,7 +18,7 @@ class WebInterfaceDataset(dict):
def setPluginState(self, plugins):
for pl in plugins.allPlugins():
self["Data.Status.Modules." + pl] = plugins.getPlugin(pl).getStatus(self.cbox)
self["Data.Status.Plugins." + pl] = plugins.getPlugin(pl).getStatus(self.cbox)
def setCurrentDiskState(self, device):
@ -48,6 +48,7 @@ class WebInterfaceDataset(dict):
self["Settings.Stylesheet"] = self.prefs["WebSettings"]["Stylesheet"]
self["Settings.Language"] = self.prefs["WebSettings"]["Language"]
self["Settings.DocLang"] = self.prefs["WebSettings"]["DocLanguage"]
self["Settings.PluginDir"] = self.prefs["Locations"]["PluginDir"]
def __setCryptoBoxState(self):

View file

@ -1,9 +1,21 @@
import CryptoBox
import WebInterfaceDataset
import re
from Plugins import PluginManager
import Plugins
from CryptoBoxExceptions import *
class WebInterfacePlugins:
def __init__(self, log, plugins, handler_func):
for plname in plugins.allPlugins():
log.info("Plugin '%s' loaded" % plname)
## this should be the "easiest" way to expose all plugins as URLs
setattr(self, plname, handler_func(plname))
setattr(getattr(self, plname), "exposed", True)
class WebInterfaceSites:
'''
url2func = {'index':'show_status','doc':'show_doc','logs':'show_log'}
@ -16,17 +28,10 @@ class WebInterfaceSites:
self.log = logging.getLogger("CryptoBox")
self.prefs = self.cbox.prefs
self.__resetDataset()
self.plugins = PluginManager(self.prefs["Locations"]["PluginDir"])
self.__exposePlugins()
self.pluginList = Plugins.PluginManager(self.prefs["Locations"]["PluginDir"])
self.plugins = WebInterfacePlugins(self.log, self.pluginList, self.return_plugin_action)
self.plugins.index = self.system
def __exposePlugins(self):
for plname in self.plugins.allPlugins():
self.log.info("Plugin '%s' loaded" % plname)
## this should be the "easiest" way to expose all modules as URLs
setattr(self, "module_" + plname, self.return_module_action(plname))
setattr(getattr(self, "module_" + plname), "exposed", True)
def __resetDataset(self):
self.dataset = WebInterfaceDataset.WebInterfaceDataset(self.cbox, self.prefs)
@ -134,8 +139,8 @@ class WebInterfaceSites:
try:
container.setName(volume_name)
# TODO: specify the possible exceptions
except Exception:
self.log.warn("failed to rename the volume '%s' to '%s'" % (device, volume_name))
except Exception, errMsg:
self.log.warn("failed to rename the volume '%s' to '%s: %s'" % (device, volume_name, errMsg))
self.dataset["Data.Warning"] = "SetVolumeNameFailed"
else:
self.log.info("successfully renamed volume '%s' to '%s'" % (device, volume_name))
@ -311,7 +316,7 @@ class WebInterfaceSites:
return self.__render("show_volume")
def return_module_action(self, module):
def return_plugin_action(self, plugin_name):
def handler(**args):
self.__resetDataset()
try:
@ -319,15 +324,9 @@ class WebInterfaceSites:
del args["weblang"]
except KeyError:
pass
plugin = self.plugins.getPlugin(module)
try:
nextTemplate = plugin.doAction(self.cbox, **args)
except CBPluginActionError, errMsg:
self.log.debug(errMsg)
self.dataset["Data.Warning"] = errMsg
nextTemplate = "empty"
plugin.prepareForm(self.dataset, self.cbox)
return self.__render(nextTemplate, module)
plugin = self.pluginList.getPlugin(plugin_name)
nextTemplate = plugin.doAction(self.dataset, self.cbox, **args)
return self.__render(nextTemplate, plugin_name)
return handler
@ -418,7 +417,7 @@ class WebInterfaceSites:
return False
def __render(self, template, module=None):
def __render(self, template, plugin=None):
'''renders from clearsilver templates and returns the resulting html
Gets a dictionary with all settings, nessessary for rendering.
@ -430,16 +429,16 @@ class WebInterfaceSites:
try:
import neo_cgi, neo_util, neo_cs
except ImportError:
errorMsg = "Could not import clearsilver modules. Try 'apt-get install python-clearsilver'."
errorMsg = "Could not import clearsilver module. Try 'apt-get install python-clearsilver'."
self.log.error(errorMsg)
sys.stderr.write(errorMsg)
raise ImportError, errorMsg
module_cs_file = False
if module:
module_cs_file = self.plugins.getTemplateFileName(module, template)
plugin_cs_file = False
if plugin:
plugin_cs_file = self.pluginList.getTemplateFileName(plugin, template)
default_cs_file = os.path.join(self.prefs["Locations"]["TemplateDir"], template + ".cs")
self.dataset["Data.TemplateFile"] = module_cs_file or default_cs_file
self.dataset["Data.TemplateFile"] = plugin_cs_file or default_cs_file
self.log.info("rendering site: " + template)
cs_path = os.path.join(self.prefs["Locations"]["TemplateDir"], "main.cs")
@ -454,7 +453,7 @@ class WebInterfaceSites:
return "Couldn't read language file: %s" % hdf_path
## add the current state of the plugins to the hdf dataset
self.dataset.setPluginState(self.plugins)
self.dataset.setPluginState(self.pluginList)
hdf = neo_util.HDF()
hdf.readFile(hdf_path)
@ -462,7 +461,7 @@ class WebInterfaceSites:
for key in self.dataset.keys():
hdf.setValue(key,str(self.dataset[key]))
## load languaga data of plugins
self.plugins.loadLanguageData(hdf, lang=self.dataset["Settings.Language"])
self.pluginList.loadLanguageData(hdf, lang=self.dataset["Settings.Language"])
cs = neo_cs.CS(hdf)
cs.parseFile(cs_path)
return cs.render()