This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
glasnost/shared/common/tools_new.py

465 lines
13 KiB
Python

# -*- coding: iso-8859-15 -*-
# Glasnost
# By: Odile Bénassy <obenassy@entrouvert.com>
# Romain Chantereau <rchantereau@entrouvert.com>
# Nicolas Clapiès <nclapies@easter-eggs.org>
# Pierre-Antoine Dejace <padejace@entrouvert.be>
# Thierry Dulieu <tdulieu@easter-eggs.com>
# Florent Monnier <monnier@codelutin.com>
# Cédric Musso <cmusso@easter-eggs.org>
# Frédéric Péters <fpeters@entrouvert.be>
# Benjamin Poussin <poussin@codelutin.com>
# Emmanuel Raviart <eraviart@entrouvert.com>
# Sébastien Régnier <regnier@codelutin.com>
# Emmanuel Saracco <esaracco@easter-eggs.com>
#
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
# Emmanuel Saracco & Théridion
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
# Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
# Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
# Régnier, Emmanuel Saracco, Théridion & Vecam
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
__doc__ = """Glasnost Common Tools"""
__version__ = '$Revision$'[11:-2]
try:
import glasnost
except ImportError:
class G:
applicationName = 'glasnost'
glasnost = G()
import ConfigParser
import gettext
import random
import context
config = None
configFile = '/etc/%s/config' % glasnost.applicationName
def buildPython22ClassLinearization(aClass, baseClasses):
if aClass in baseClasses:
baseClasses.remove(aClass)
baseClasses.append(aClass)
for baseClass in aClass.__bases__:
buildPython22ClassLinearization(baseClass, baseClasses)
def createMultiId(listIds):
"""Create new Id, with list of Id
Keyword arguments:
==================
*list*:
list with len >= 1
Return:
=======
one Id. This Id can be splited with splitSubId.
"""
return ':'.join(listIds)
def extractDispatcherId(id):
"""Return the dispatcher ID string from an server ID string
Keyword argument:
=================
*id*:
The server ID string.
Exception:
==========
*AssertionError*:
The server ID doesn't begin by 'glasnost://'.
*Standard Exception*:
The server ID folowing the protocol specifier is not valid.
"""
try:
assert id.startswith('glasnost://')
splittedApplicationId = id[11:].split('/', 1)
return 'glasnost://%s' % splittedApplicationId[0]
except (AssertionError, IndexError):
raise Exception('Malformed id or application id = "%s"' % str(id))
def extractLocalId(id):
try:
assert id.startswith('glasnost://')
splittedId = id[11:].split('/', 2)
if len(splittedId) <= 2:
return ''
else:
return splittedId[2]
except (AssertionError, IndexError):
raise Exception('Malformed id = "%s"' % str(id))
def extractRole(id):
try:
assert id.startswith('glasnost://')
splittedApplicationId = id[11:].split('/', 2)
if len(splittedApplicationId) == 1:
return ''
else:
return splittedApplicationId[1]
except (AssertionError, IndexError):
raise Exception('Malformed id or application id = "%s"' % str(id))
def extractServerId(id):
"""Extract the server ID from an object ID.
Keyword argument:
=================
*id*:
The object ID.
Return the server ID.
Exception:
==========
*AssertionError*:
The object ID string is not a glasnost service ('glasnost://').
*IndexError*:
The given object ID is incomplete.
"""
try:
assert id.startswith('glasnost://')
splittedId = id[11:].split('/', 2)
if len(splittedId) == 1 or not splittedId[1]:
# Id is a dispacherId.
return 'glasnost://%s' % splittedId[0]
else:
return 'glasnost://%s/%s' % (splittedId[0], splittedId[1])
except (AssertionError, IndexError):
raise Exception('Malformed id or application id = "%s"' % str(id))
def getAllThingClasses():
thingClasses = context.getVar('thingClasses')
return thingClasses.getAll()
def getC3ClassLinearization(c):
# An implementation of the C3 class hierarchy Linearization.
# Cf. http://www.webcom.com/haahr/dylan/linearization-oopsla96.html
linearization = [c]
if c.__bases__:
basesByPrecedenceOrder = list(c.__bases__)
basesByPrecedenceOrder.reverse()
remainingInputs = [getC3ClassLinearization(base)
for base in c.__bases__] + [basesByPrecedenceOrder]
while remainingInputs:
# The first class which is not in the tail of each remaining input
# is the next class to append to the linearization.
for remainingInput in remainingInputs:
candidate = remainingInput[0]
for remainingInput2 in remainingInputs:
if candidate in remainingInput2[1:]:
break
else:
break
else:
raise Exception(
'Inconsistent class hierarchy for class %s' % c)
# A good candidate has been found.
# Add it to the partial linearization and remove it from the
# remaining inputs.
linearization.append(candidate)
newRemainingInputs = []
for remainingInput in remainingInputs:
if remainingInput[0] == candidate:
del remainingInput[0]
if not remainingInput:
continue
newRemainingInputs.append(remainingInput)
remainingInputs = newRemainingInputs
return linearization
def getConfig(section, value, default = None, vars = None, raw = 0):
"""Retrieve values from the Glasnost config file.
Keyword arguments:
==================
*section*:
The section string in the config file where the attribute is.
*value*:
The attribute name string to get value.
*default*:
The default value to set if the attribute is not found.
*vars*:
A dictionnary used to override the set "%" attributes of the config
file.
*raw*:
If true, the vars dictionnary is not used.
Return:
=======
+ Return the wanted value
+ The default value if no attribute was found.
+ None if no attribute was found and no default value given.
"""
global config
if config is None:
config = ConfigParser.ConfigParser()
config.readfp(open(configFile))
return getConfig(section, value, default = default, vars = vars,
raw = raw)
else:
try:
return config.get(section, value, vars = vars, raw = raw)
except ConfigParser.NoOptionError:
return default
except ConfigParser.NoSectionError:
return default
def getConfigNoCache(section, value, default = None, vars = None, raw = 0):
conf = ConfigParser.ConfigParser()
conf.readfp(open(configFile))
try:
return conf.get(section, value, vars = None, raw = raw)
except ConfigParser.NoOptionError:
return default
except ConfigParser.NoSectionError:
return default
### FIXME: To remove ASAP.
def getSlotPath(slot):
if slot is None:
return 'self'
else:
return slot.getPath()
def getThingClass(thingCategory, thingName):
"""Return the class of a thing."""
thingClasses = context.getVar('thingClasses')
thingClass = thingClasses.get(thingCategory, thingName)
return thingClass
def importThing(thingImport, parentSlot = None):
thing = newThing(
thingImport['__thingCategory__'], thingImport['__thingName__'])
thing.importFromXmlRpc(thingImport, parentSlot = parentSlot)
return thing
def makeApplicationId(id, role):
"""Compute the application ID string.
Keyword arguments:
==================
*id*:
The server ID string.
*role*:
The server role String
Return the application ID string. Formaly, it is the dispatcher address
folowed by the given role.
Exception:
==========
*AssertionError*:
The server ID doesn't begin by 'glasnost://'.
*Standard Exception*:
The application ID folowing the protocol specifier is not valid.
"""
if role:
return '%s/%s' % (extractDispatcherId(id), role)
else:
return extractDispatcherId(id)
def makeHttpHostNameAndPort(httpHostName, httpPort):
if httpHostName is None and httpPort is None:
return None
elif httpPort is None:
return httpHostName
elif httpHostName is None:
return 'localhost:%s' % httpPort
else:
return '%s:%s' % (httpHostName, httpPort)
def makeHttpPathAndQuery(httpPath, httpQuery):
if httpPath is None and httpQuery is None:
return None
elif httpQuery is None:
return httpPath
elif httpPath is None:
return '/?%s' % httpQuery
else:
return '%s?%s' % (httpPath, httpQuery)
def makeHttpScriptDirectoryPath(httpScriptPath):
if httpScriptPath is None:
return '/'
splittedPath = httpScriptPath.split('/')
del splittedPath[-1]
path = '/'.join(splittedPath)
if not path or path[0] != '/':
path = '/' + path
if not path[-1] == '/':
path += '/'
return path
def makepassword(
length = 8,
allowChar = 'ABCDEFGHIJKLMNPQRSTUVWXYabcdefghijmnopqrstuvwxyz0123456789'):
"""Generate a random password.
@param length: length of the result string
@type length: int
@param CARAC: allowed charactere for the result string
@type allowChar: String
"""
g = random.Random()
result = ''
for i in range(length):
result += allowChar[g.randrange(len(allowChar))]
return result
def newThing(thingCategory, thingName, *arguments, **keywords):
"""Instantiate a new thing.
This is a generic method designed to instantiate any kind of thing.
Keyword arguments:
==================
*thingCategory*:
The category name of the class to instantiate (i.e.: 'object').
*thingName*:
The class name to instantiate (i.e.: 'AdminPeople'). The class name is
linked to a category. Same class names could be used in differents
categories.
*\*arguments*:
The arguments sequence to pass to the class constructor.
*\*\*keywords*:
The keyword dictionnary to pass to the class contructor.
Return the wanted thing instance (category + class name).
"""
return getThingClass(thingCategory, thingName)(*arguments, **keywords)
def splitMultiId(id):
"""Return list of sub id
Keyword arguments:
==================
*id*:
The id to split
example: glasnost://host.tld/serverName/id0:id1:id2:id3
become: [glasnost://host.tld/serverName/id0, id1, id2, id3]
Return:
=======
list of all sub id, this list have one or more component.
"""
try:
assert id.startswith('glasnost://')
splittedId = id[11:].split('/',2)
assert len(splittedId) == 3
applicationHostNameAndPort, applicationRole, localId = splittedId
result = localId.split(':')
result[0] = 'glasnost://%s/%s/%s' % (applicationHostNameAndPort,
applicationRole, result[0])
except IndexError:
raise Exception('Malformed id = %s' % str(id))
except AssertionError:
raise Exception('Malformed id = %s' % str(id))
return result
def translation(domains, languages = None):
localeDirectoryPath = context.getVar('localeDirectoryPath')
translation = gettext.NullTranslations()
for domain in domains:
try:
trans = gettext.translation(domain, localeDirectoryPath, languages)
except IOError:
continue
if not hasattr(trans, '_catalog'):
continue
if translation.__class__.__name__ == 'NullTranslations':
translation = trans
continue
translation._catalog.update(trans._catalog)
return translation