# -*- coding: UTF-8 -*-# Copyright (c) 2010 - 2011, Pascal Volk# See COPYING for distribution information.""" VirtualMailManager.common ~~~~~~~~~~~~~~~~~~~~~~~~~ Some common functions"""importlocaleimportosimportreimportstatfromVirtualMailManagerimportENCODINGfromVirtualMailManager.constantsimportNOT_EXECUTABLE,NO_SUCH_BINARYfromVirtualMailManager.errorsimportVMMErrorVERSION_RE=re.compile(r'^(\d+)\.(\d+)\.(?:(\d+)|(alpha|beta|rc)(\d+))$')_version_level=dict(alpha=0xA,beta=0xB,rc=0xC)_version_cache={}_=lambdamsg:msgdefexpand_path(path):"""Expands paths, starting with ``.`` or ``~``, to an absolute path."""ifpath.startswith('.'):returnos.path.abspath(path)ifpath.startswith('~'):returnos.path.expanduser(path)returnpathdefget_unicode(string):"""Converts `string` to `unicode`, if necessary."""ifisinstance(string,unicode):returnstringreturnunicode(string,ENCODING,'replace')deflisdir(path):"""Checks if `path` is a directory. Doesn't follow symbolic links. Returns bool. """try:lstat=os.lstat(path)exceptOSError:returnFalsereturnstat.S_ISDIR(lstat.st_mode)defexec_ok(binary):"""Checks if the `binary` exists and if it is executable. Throws a `VMMError` if the `binary` isn't a file or is not executable. """binary=expand_path(binary)ifnotos.path.isfile(binary):raiseVMMError(_(u"No such file: '%s'")%get_unicode(binary),NO_SUCH_BINARY)ifnotos.access(binary,os.X_OK):raiseVMMError(_(u"File is not executable: '%s'")%get_unicode(binary),NOT_EXECUTABLE)returnbinarydefhuman_size(size):"""Converts the `size` in bytes in human readable format."""ifnotisinstance(size,(long,int)):try:size=long(size)exceptValueError:raiseTypeError("'size' must be a positive long or int.")ifsize<0:raiseValueError("'size' must be a positive long or int.")ifsize<1024:returnstr(size)prefix_multiply=((_(u'TiB'),1<<40),(_(u'GiB'),1<<30),(_(u'MiB'),1<<20),(_(u'KiB'),1<<10))forprefix,multiplyinprefix_multiply:ifsize>=multiply:# TP: e.g.: '%(size)s %(prefix)s' -> '118.30 MiB'return_(u'%(size)s%(prefix)s')%{'size':locale.format('%.2f',float(size)/multiply,True),'prefix':prefix}defsize_in_bytes(size):"""Converts the string `size` to a long (size in bytes). The string `size` can be suffixed with *b* (bytes), *k* (kilobytes), *M* (megabytes) or *G* (gigabytes). """ifnotisinstance(size,basestring)ornotsize:raiseTypeError('size must be a non empty string.')ifsize[-1].upper()in('B','K','M','G'):try:num=int(size[:-1])exceptValueError:raiseValueError('Not a valid integer value: %r'%size[:-1])unit=size[-1].upper()ifunit=='B':returnnumelifunit=='K':returnnum<<10Lelifunit=='M':returnnum<<20Lelse:returnnum<<30Lelse:try:num=int(size)exceptValueError:raiseValueError('Not a valid size value: %r'%size)returnnumdefversion_hex(version_string):"""Converts a Dovecot version, e.g.: '1.2.3' or '2.0.beta4', to an int. Raises a `ValueError` if the *version_string* has the wrong™ format. version_hex('1.2.3') -> 270548736 hex(version_hex('1.2.3')) -> '0x10203f00' """global_version_cacheifversion_stringin_version_cache:return_version_cache[version_string]version=0version_mo=VERSION_RE.match(version_string)ifnotversion_mo:raiseValueError('Invalid version string: %r'%version_string)major,minor,patch,level,serial=version_mo.groups()major=int(major)minor=int(minor)ifpatch:patch=int(patch)ifserial:serial=int(serial)ifmajor>0xFForminor>0xFFor \patchandpatch>0xFForserialandserial>0xFF:raiseValueError('Invalid version string: %r'%version_string)version+=major<<28version+=minor<<20ifpatch:version+=patch<<12version+=_version_level.get(level,0xF)<<8ifserial:version+=serial_version_cache[version_string]=versionreturnversiondefversion_str(version):"""Converts a Dovecot version previously converted with version_hex back to a string. Raises a `TypeError` if *version* is not an int/long. Raises a `ValueError` if *version* is an incorrect int version. """global_version_cacheifversionin_version_cache:return_version_cache[version]ifnotisinstance(version,(int,long)):raiseTypeError('Argument is not a int/long: %r',version)major=(version>>28)&0xFFminor=(version>>20)&0xFFpatch=(version>>12)&0xFFlevel=(version>>8)&0x0Fserial=version&0xFFlevels=dict(zip(_version_level.values(),_version_level.keys()))iflevel==0xFandnotserial:version_string='%u.%u.%u'%(major,minor,patch)eliflevelinlevelsandnotpatch:version_string='%u.%u.%s%u'%(major,minor,levels[level],serial)else:raiseValueError('Invalid version: %r'%hex(version))_version_cache[version]=version_stringreturnversion_stringdel_