#-*- coding: utf-8 -*- # Copyright 2008-2010 Mir Calculate. http://www.calculate-linux.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import filecmp import string from random import choice from re import search, compile, S import os import types import subprocess def getdirlist(s_path): #Получить список директорий по указаному пути fdir=filecmp.dircmp(s_path, s_path) dir_list=fdir.common_dirs return dir_list def prettyColumnStr(*cols): '''Функция преобразования строк в текстовые колонки. Если указанный текст не помещается в колонку, то строка переносится на следующую этой же колонки перенос текста идет по словам, и текст выравнивается по ширине колонки за счет дополнительных пробелов между словами. Если в строке используется перенос строки, то текст переносится не просто на следующую строку, а также на следующую строку колонки, причем если используется \r текст выравнива- ется по ширине, а если \n, то просто перевод строки. Параметры: cols множестово пар: текст, ширина колонки, причем, если у последней колонки не указывать ширину, то она будет выведена вся. Возвращаемые параметры: строка, которую можно использовать для вывода на экран Пример: columnWrite( "Some text", 10, "Next column", 20 ) ''' # шаблон поиска переводов строк wherenr = compile( '[\n\r]', S ) retstr = "" # перевести кортеж в список, т.к. изменяется cols = list(cols) # перевести текст в юникод, заодно перевести числа в строку noconvert = False space = u' ' nospace = u'' for i in xrange(0,len(cols),2): cols[i] = _toUNICODE(cols[i]) # флаг "есть еще текст для вывода" repeat = True while repeat: # сбросить итератор на первый элемент q = 0 repeat = False # пока не закончили перебирать параметры (перебираем по парам) while q < len(cols): # если это последний параметр, и для него не указана ширина if q == len(cols)-1: # выводим его полностью не смотря на ширину окна retstr += cols[q] + " " cols[q] = '' else: # вывести часть строки не больше указанной ширины колонки partstr = cols[q][:cols[q+1]] # искать перевод строки с полученной части brfind = wherenr.search(partstr) # если это не последняя колонка if q + 2 < len(cols): # добавить разделитель между колонками cellspacing = space else: # разделитель не нужен cellspacing = nospace # если перевод строки найден, то if brfind != None: # для текущего вывода в колонку # берем часть строки до перевода partstr = partstr[:brfind.start()] # остальная часть идет в остаток (без перевода) cols[q] = cols[q][brfind.start()+1:] # # если используется перевод каретки # if brfind.group() == '\r': # # то выравниваем по ширине колонки # partstr = partstr.ljust(cols[q+1], ' ') # else: # # добавить отступы чтобы закончить колонку partstr = partstr.ljust(cols[q+1], ' ') # если взята часть строки elif len(partstr) == cols[q+1] and partstr != cols[q]: # если взята часть строки (разрыв в слове) if cols[q][cols[q+1]] != ' ': # ищем ближайший пробел справа spacepos = partstr.rfind(' ') # если пробел найти не удалось if spacepos == -1: # то на вывод идет часть строки равной ширине cols[q] = cols[q][cols[q+1]:] # если пробел найден else: # обрезаем строку до найденного пробела partstr = partstr[:spacepos] cols[q] = cols[q][spacepos+1:] # если взята часть строки (разрыв на пробеле) else: # ислючить переносной пробел cols[q] = cols[q][cols[q+1]+1:] # выровнить текст по ширине колонки partstr = partstr.ljust(cols[q+1], ' ') #partstr = justify(partstr, cols[q+1]) # остатки строки else: # добавить отступы чтобы закончить колонку partstr = partstr.ljust(cols[q+1], ' ') cols[q] = '' retstr+= partstr + cellspacing # остальную часть строки оставить на следующую итерацию # если от строки что то осаталось if len(cols[q]) > 0: # отметить запуск еще одной итерации по параметрам repeat = True # следующая пара q += 2 # колонки отображены retstr += "\n" return retstr.encode('utf8') def columnStr(*cols): '''Вывод данных по колонкам, причем, если данные не вмещаются в указнаную колонку, то они переносятся на следующую строку в нужную колонку. В строку. Параметры: cols множестово пар: текст, ширина колонки, причем, если у последней колонки не указывать ширину, то она будет выведена вся. Возвращаемые параметры: строка, которую можно использовать для вывода на экран Пример: columnWrite( "Some text", 10, "Next column", 20 ) ''' retstr = "" # перевести кортеж в список, т.к. изменяется cols = list(cols) # перевести текст в юникод, заодно перевести числа в строку for i in xrange(0,len(cols),2): cols[i] = (str(cols[i])).decode('utf8') # флаг "есть еще текст для вывода" repeat = True while repeat: # сбросить итератор на первый элемент q = 0 repeat = False # пока не закончили перебирать параметры (перебираем по парам) while q < len(cols): # если это последний параметр, и для него не указана ширина if q == len(cols)-1: # выводим его полностью не смотря на ширину окна retstr += cols[q] + " " cols[q] = '' else: # вывести часть строки не больше указанной ширины колонки retstr+=(cols[q][:cols[q+1]].ljust(cols[q+1])).encode('utf8') \ + " " # остальную часть строки оставить на следующую итерацию cols[q] = cols[q][cols[q+1]:] # если от строки что то осаталось if len(cols[q]) > 0: # отметить запуск еще одной итерации по параметрам repeat = True # следующая пара q += 2 # колонки отображены retstr += "\n" return retstr def columnWrite(*cols): '''Вывод данных по колонкам, причем, если данные не вмещаются в указнаную колонку, то они переносятся на следующую строку в нужную колонку. Параметры: cols множестово пар: текст, ширина колонки, причем, если у последней колонки не указывать ширину, то она будет выведена вся. Пример: columnWrite( "Some text", 10, "Next column", 20 ) ''' # перевести кортеж в список, т.к. изменяется cols = list(cols) # перевести текст в юникод, заодно перевести числа в строку for i in xrange(0,len(cols),2): cols[i] = (str(cols[i])).decode('utf8') # флаг "есть еще текст для вывода" repeat = True while repeat: # сбросить итератор на первый элемент q = 0 repeat = False # пока не закончили перебирать параметры (перебираем по парам) while q < len(cols): # если это последний параметр, и для него не указана ширина if q == len(cols)-1: # выводим его полностью не смотря на ширину окна print cols[q].encode('utf8'), cols[q] = '' else: # вывести часть строки не больше указанной ширины колонки print (cols[q][:cols[q+1]].ljust(cols[q+1])).encode('utf8'), # остальную часть строки оставить на следующую итерацию cols[q] = cols[q][cols[q+1]:] # если от строки что то осаталось if len(cols[q]) > 0: # отметить запуск еще одной итерации по параметрам repeat = True # следующая пара q += 2 # колонки отображены print def justify(s,width): '''Выровнить текст по ширине Параметры: s выводимая строка width ширина на которую надо выровнить строку Возвращаямые параметры: Выровненная строка ''' # если подана строка без пробелов - прекратить обработку if s.find(' ') == -1: return s pos = 0 # переводим в юникод для правильного вычисления длины try: s = s.decode( 'utf-8' ) # пропуск если это не utf-8 except UnicodeEncodeError: pass # пока длина строки меньше указанной while len(s) < width: # находим очередной пробел pos = s.find( ' ', pos ) # если не найден искать сначала if pos == -1: pos = s.find(' ') # вставить в позицию еще один пробел s = s[:pos] +' ' +s[pos:] # оставить удвоенный пробел pos += 3 # вернуть строку в utf8 если она пришла в utf8 return s.encode('utf-8') def runOsCommand(cmd, inStr=None, ret_first=None, env_dict=None): """Выполняет внешнюю программу Параметры: cmd внешняя программа inStr данные передаваемые программе на страндартный вход. ret_first вернуть только первую строку env_dict словарь переменных окружения Возвращаемые параметры: строка/строки которую выведет внешняя программа Возвращает код возврата, stdout+stderr """ pipe = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env_dict, close_fds=True, shell=True) fout, fin, ferr = (pipe.stdout, pipe.stdin, pipe.stderr) # если есть данные на вход, передать их if inStr: fin.write(inStr) fin.close() # Код возврата retcode = pipe.wait() res = fout.readlines() fout.close() res += ferr.readlines() ferr.close() if res: if len(res) == 1 or ret_first: return retcode, res[0].strip() else: return retcode, res return retcode, None def genpassword(passlen=9): '''Вернуть случайный пассворд указанной длины Параметры: passlen длина пароля который нужно сгенерировать Возвращаемые параметры: Сгенерированный пароль указанной длины ''' res=''.join([choice(string.ascii_letters+string.digits)\ for i in xrange(passlen)]) return res def fillstr(char, width): '''Заполнить строку указанным числом символов. Псеводоним символ*кол-во''' return str(char) * width #вернуть пути для запуска утилит def getpathenv(): bindir=['/sbin','/bin','/usr/sbin','/usr/bin'] env=os.environ if env and env.has_key('PATH'): lpath=env['PATH'].split(":") npath=[] for dirname in bindir: if os.path.exists(dirname) and dirname not in lpath: npath.append(dirname) lpath=npath+lpath return ":".join(lpath) #класс для работы с установленными пакетами class pakages: #путь к директории установленнх пакетов pkgdir="/var/db/pkg/" #список установленных пакетов pkglist={} #Объект содержащий параметры пакета class pakage(object): #имя пакета с версией fullname="" #имя пакета name="" #версия ver="" #тип пакета в портежах portdir="" def __init__(self, **args): for atname,atvalue in args.items(): setattr(self,atname, atvalue) def __init__(self): self.pkglist=self.__getpkglist() #разбить имя пакета на тип и имя def __getpkgver(self, fname): res=search('^(.+)\-([0-9]+.*)$',fname) if res: return res.groups() else: return (None,None) #собрать установленные в системе пакеты def __getpkglist(self): portageDirs=[] instaledPkg={} #проверим на существование директории с установленными пакетами if os.path.exists(self.pkgdir): #получим список типов пакетов portageDirs=getdirlist(self.pkgdir) if len(portageDirs)>0: #обрабатываем содержимое каждого из типов for portageDir in portageDirs: pkgList=getdirlist(self.pkgdir+portageDir) for pkg in pkgList: fullname=pkg pkgName,pkgVer= self.__getpkgver(pkg) pobj=self.pakage(fullname=fullname, name=pkgName, \ ver=pkgVer,\ portdir=portageDir) fpkg=portageDir+"/"+pkgName if instaledPkg.has_key(fpkg): instaledPkg[fpkg].append(pobj) else: instaledPkg[fpkg]=[pobj] return instaledPkg #разбить pkgname на составляющие имени пакета def __partname(self, pkgname): if not pkgname.strip(): return False res=search('^(.+\/)?(.+)',pkgname) tname=None if res.group(1): tname=res.group(1) if res.group(2): res2=search('^(.+)(\-[0-9]+.+$)',res.group(2)) if res2: name=res2.group(1) ver=res2.group(2) else: name=res.group(2) ver=None if res: if name and name[-1:]=='-': name=name[:-1] if tname and tname[-1:]=='/': tname=tname[:-1] if ver and ver[0]=='-': ver=ver[1:] return [tname, name, ver] #проверить установленн ли пакет #isinstalled('dev-db/postgresql') def isinstalled(self, pkgname): res=self.getinstpkg(pkgname) if len(res)>0: return True else: return False #вернуть список объектов pakage() соответствующих pkgname #getinstpkg('dev-db/postgresql') #в случае отсутствия пакетов возвращает пустой список def getinstpkg(self, pkgname): pinfo=self.__partname(pkgname) if pinfo: ret=[] if pinfo[0] and pinfo[1] and pinfo[2]: if not self.pkglist.has_key(pinfo[0]+'/'+pinfo[1]): return [] fpkg=self.pkglist[pinfo[0]+'/'+pinfo[1]] ret=[] for i in fpkg: if i.ver==pinfo[2]: ret.append(i) return ret elif pinfo[0] and pinfo[1]: if not self.pkglist.has_key(pinfo[0]+'/'+pinfo[1]): return [] return self.pkglist[pinfo[0]+'/'+pinfo[1]] elif pinfo[1] and pinfo[2]: for i in self.pkglist.keys(): if search('^.+\/%s$'%(pinfo[1]),i): for el in self.pkglist[i]: if el.ver==pinfo[2]: ret.append(el) return ret elif pinfo[1]: for i in self.pkglist.keys(): if search('^.+\/%s$'%(pinfo[1]),i): ret+=self.pkglist[i] return ret return [] def getListPkg(self): return self.pkglist def list2str(list): '''Функция переводит список в строку''' return '['+','.join(list)+']' def str2list(s): '''Функция переводит строку в список''' return s[1:-1].split(',') def dict2str(dict): '''Функция перводит словарь в строку''' return '{'+','.join(["%s:%s" % (str(k),str(v)) \ for (k,v) in dict.items()])+'}' #: def str2dict(s): '''Функция переводит строку в словарь''' dict = {} for i in s[1:-1].split(','): k,v = i.split(':') dict[k] = v return dict def convertStrListDict(val): '''Функция определеяется что на входе (строка, список, словарь) и переводит их в строку и обратно''' # если подан список if type(val) == types.ListType: return list2str(val) # если подан словарь elif type(val) == types.DictType: return dict2str(val) # если подана строка else: # если поданная строка содержит словарь if ':' in val and '{' in val: return str2dict(val) # если поданная строка содержит список elif ',' in val and '[' in val: return str2list(val) # если это просто строка else: return val def _toUNICODE(val): """перевод текста в юникод""" if type(val) == types.UnicodeType: return val else: return str(val).decode('UTF-8')