#-*- coding: utf-8 -*- #Copyright 2008 Calculate Pack, http://www.calculate-linux.ru # # 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. Version = "calculate-server 0.0.1" import sys sys.path.append('/var/tmp/calculate2/calculate-lib/trunk/pym') import cStringIO import cl_base import struct import termios import fcntl import cl_utils import cl_profile import ldap class ldapFun(cl_profile._error): '''Объект для работы с LDAP сервером подключение к серверу и поиск данных ''' def __init__(self, dnUser, password, host="localhost"): self.conLdap = False # Получаем соединение с LDAP try: self.conLdap = self.__ldapConnect(dnUser, password, host) except ldap.LDAPError, e: self.setError(e[0]['desc']) def __ldapConnect(self, dnUser, password, host): """Соединение с LDAP сервером""" conLdap = ldap.initialize('ldap://%s'%host) conLdap.simple_bind_s(dnUser, password) return conLdap def ldapSearch(self,baseDN, searchScope, searchFilter, retrieveAttributes): try: ldap_result_id = self.conLdap.search(baseDN, searchScope, searchFilter, retrieveAttributes) result_set = [] while 1: result_type, result_data = self.conLdap.result(ldap_result_id, 0) if (result_data == []): break else: if result_type == ldap.RES_SEARCH_ENTRY: result_set.append(result_data) except ldap.NO_SUCH_OBJECT: return [] except: return False return result_set pcs = cl_utils.prettyColumnStr class cl_help: """Объект для работы со справкой, и обработкой параметров. Конструктор __init__ должен определить следующие переменные: self.chapter список разделов справки, каждый элементы состоит из имени раздела, флаг видимый/скрытый, кол-во переводов строк после названия раздела, количество строк после раздела, тип раздела Пример: [("Copyright",False,0,2),"options"] self.relService словарь связей сервисов и действующих опций ключ - название сервиса, значение - список отображаемых разделов отмеченных как "options" Пример: {"samba":[_("Common options"), _("Service Samba options")]} self.relOptions словарь связей длинных опций помощи и выводимых разделов помощи с опциями ключ - параметр справки, значение список отображаемых разделов справки Пример: {"help-ldap":[_("Common options"), _("Service LDAP options)]} self.progName словарь имена используемых программ и их номера для доступа к переменным Пример: {'cl-groupadd':0, 'cl-groupdel':1} self.data список данных для справки, каждый элемент словарь: progAccess: список номеров программ отображающих Пример: {'progAccess':(0,), 'shortOption':"g", 'longOption':"gid", 'optVal':"GID", 'helpChapter':_("Options"), 'help':_("use GID for the new group") }, после заполнения параметров необходимо выполнить self._cl_help__setParamHelp() для заполнения справки """ def __init__(self, cmdName): # ширина консоли взята за 80 # -1 чтобы компенсировать расстрояние между колонками self.consolewidth = 79 self.column_width = 32 self.cmdName = cmdName #короткие опции командной строки self.shortOpt = [] #длинные опции командной строки self.longOpt = [] # массив разделов (заполняется в __setParamHelp) self.chapterBloc = [] #optEnd = "" #if "user" in self.cmdName and not "mod" in self.cmdName: #optEnd = _("user") #elif "group" in self.cmdName and not "mod" in self.cmdName: #optEnd = _("group") #self.__setParamHelp() def getChapterNumber(self,NameChapter): """Получить номер раздела по имени""" num = 0 for i in self.chapter: if i[0] == NameChapter: return num num += 1 return False def __setParamHelp(self): """Внутренняя функция формирования справки по данным Перебирает все элементы списка data, проверяет их на доступность данной программы, разбирает опции на среди data и формирует для по ним справку. """ # сформировать нужное количество блоков раздела self.chapterBloc = [""]*len(self.chapter) # sp = {} i = 0 # перебираем все элементы справки собираем элементы опции # так же формируем разделы не опции for par in self.data: # перебираем только те опции, которые принадлежат команде if self.access(par): # есть короткая (возможно есть и длинная) if par.has_key("shortOption"): sp[par["shortOption"]+":"+par["helpChapter"]] = i # есть только длинная опция elif par.has_key("longOption"): sp[par["longOption"]+":"+par["helpChapter"]] = i # формирование разделов не опций else: helpTxt = par['help'] numChapter = self.getChapterNumber(par['helpChapter']) self.addChapterHelp(numChapter,helpTxt) i += 1 # перебираем все "собранные" опции # опции перебираются по порядку в списке date # для сортировки по ключам следует применить код: # for index in sorted(sp.keys()): # par = self.data[sp[index]] for index in sorted(sp.values()): par = self.data[index] numChapter = self.getChapterNumber(par['helpChapter']) # если есть и короткая и длинная if "shortOption" in par and "longOption" in par: paraminfo = "-%s, --%s "%(par["shortOption"],par["longOption"]) # если есть только короткая elif "shortOption" in par: paraminfo = "-%s "%par["shortOption"] # если только длинная else: paraminfo = "--%s "%par["longOption"] # если указан параметр для опции if "optVal" in par: optVal = par["optVal"] else: optVal = "" # вывод вида: " [-o, ][--option] [PARAM]" "helpstring" helpTxt = pcs(" "+paraminfo+optVal, self.column_width, \ par['help'], self.consolewidth-self.column_width) # добавить строку в нужный раздел self.addChapterHelp(numChapter,helpTxt) def getHelp(self, optionsChapters=False): """Выдать справку. Выдает справку в случае если указан optionsChapters, то фильтрует по типу разделов. Параметры: optionsChapters Flase или список опциональных разделов для отображения Возвращаемые параметры: Строка со справкой. """ # Выдать справку help = "" # перебираем все элементы справочных блоков iterChapterBloc = iter(self.chapterBloc) # перебираем все разделы по параметрам for (nameChapter, visibleChapter, beforeStrChapter, \ afterStrChapter, typeChapter) in self.chapter: # получаем следующий блок (т.о. textChapterBloc соответ, chapter) textChapterBloc = iterChapterBloc.next() # если тип раздела опциональный if optionsChapters and typeChapter=="options": # проверяем нужно ли его отображать if not (nameChapter in optionsChapters): continue bef = "\n"*beforeStrChapter aft = "\n"*afterStrChapter # если блок не пустой и раздел отображаемый if len(textChapterBloc) > 0: if visibleChapter: help += nameChapter + ": " + bef help += textChapterBloc + aft help = help.rstrip()+"\n" return help def addChapterHelp(self, numChapter, helpTxt): """Добавить в раздел помощи numChapteк тектстовую строку helpTxt Параметры: numChapter номер раздела в который нужно добавить данные справки helpTxt строка, содержащая данные """ self.chapterBloc[numChapter] += helpTxt return True def addData(self,dataHash): # На будущее (добавляет опции) self.data.append(dataHash) return True def handleCheckAccess(self,dataHash): """Замещаемый дополнительный обработчик проверки доступности опции. Входные параметры: dataHash элементы списка данных справки (self.data) """ return True def access(self,dataHash): """Доступна ли опция вызывающей программе Параметры: dataHash словарь элемент типа self.data Возвращаемые параметры: True/False доступна/недоступна """ # доступна ли опция вызывающей программе # опция без progAccess доступна numProg = self.progName[self.cmdName] if 'progAccess' in dataHash: if numProg in dataHash['progAccess']: # вызов дополнительной проверки доступа к опции return self.handleCheckAccess(dataHash) else: return False else: # вызов дополнительной проверки доступа к опции return self.handleCheckAccess(dataHash) def getTypeChapter(self, nameChapter): """Получить тип раздела по его имени Параметры: nameChapter название раздела Возвращаемые параметры: строка тип раздела Flase(Boolean) такой раздел отсутствует """ # фильтруем список по имени раздела, помещаем в список тип раздела filtered = [typeChapter for name, na, na, na, typeChapter \ in self.chapter if name == nameChapter] # если среди фильтрованных есть хоть один элемент if len(filtered) > 0: # возвращаем - он запрашиваемый return filtered[0] else: # такой раздел отсутствует return False def clearAllOpt(self): """Очистить все опции, полученные посредством getAllOpt""" if len(self.shortOpt) > 0: self.shortOpt = [] if len(self.longOpt) > 0: self.longOpt = [] return True def getAllOpt(self,typeOpt="all", optionsChapters=False): """Получить все доступные опции Параметры: typeOpt 'short'/'long'/'all', вернуть короткие или длинные опции или все (возвращаются кортежем) optionsChapters фильтр для опций по типам разделов (список,кортеж) Возвращаемые параметры: строка коротки или список строк длинных опций ('hb:c:wg:G:k:ms:u:') """ # Выдать все действующие опции if typeOpt=="short" or typeOpt=="all": if len(self.shortOpt) == 0: for par in self.data: if optionsChapters and\ self.getTypeChapter(par['helpChapter'])=="options": if not (par['helpChapter'] in optionsChapters): continue if par.has_key("shortOption") and self.access(par): if par.has_key("optVal"): self.shortOpt.append(par["shortOption"]+':') else: self.shortOpt.append(par["shortOption"]) if typeOpt=="long" or typeOpt=="all": if len(self.longOpt) == 0: for par in self.data: if optionsChapters and\ self.getTypeChapter(par['helpChapter'])=="options": #print par["longOption"] if not (par['helpChapter'] in optionsChapters): continue if par.has_key("longOption") and self.access(par): if par.has_key("optVal"): self.longOpt.append(par["longOption"]+'=') else: self.longOpt.append(par["longOption"]) if typeOpt=="short": return "".join(self.shortOpt) elif typeOpt=="long": return self.longOpt elif typeOpt=="all": return ("".join(self.shortOpt),self.longOpt) def getShortOpt(self,option): """Из любой опции получить короткую опцию. Фильтрация также происходит и по названию команды. Параметры: option запрашиваемая опция Возвращаемые параметры: короткая опция, если же для длинной опции нет короткой, возвращается пустая строка. """ # Из любой опции получаем короткую опцию for par in self.data: if par.has_key("shortOption") and self.access(par): if (par.has_key("longOption") and\ par["longOption"] == option) or \ par["shortOption"] == option: return par["shortOption"] break return "" class cl_smartcon(object): def getconsolewidth(self): """Получить ширину текущей консоли""" s = struct.pack("HHHH", 0, 0, 0, 0) fd_stdout = sys.stdout.fileno() try: x = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s) except IOError: # если ошибка то ширина 80 символов return 80 #(rows, cols, x pixels, y pixels) return struct.unpack("HHHH", x)[1] def printRight(self, offsetLeft, offsetRight): """Добавляет необходимое количество пробелов: количество пробелов = (ширина консоли - offsetLeft - offsetRight) """ cols = self.getconsolewidth() for i in range(cols - offsetLeft - offsetRight): sys.stdout.write(" ") def colorPrint(self,attr,fg,bg,string): """Раскрашивает выводимое сообщение Параметры: attr - это атрибут fg - цвет символа bg - цвет фона в случае если параметр равен "" то он не изменяется attr может принимать следующие значения: 0 сбросить все атрибуты (вернуться в нормальный режим) 1 яркий (обычно включает толстый шрифт) 2 тусклый 3 подчёркнутый 5 мигающий 7 реверсный 8 невидимый fg может принимать следующие значения: 30 чёрный 31 красный 32 зелёный 33 жёлтый 34 синий 35 фиолетовый 36 голубой 37 белый bg может принимать следующие значения: 40 чёрный 41 красный 42 зелёный 43 жёлтый 44 синий 45 фиолетовый 46 голубой 47 белый """ lst = [] if attr: lst.append(attr) if fg: lst.append(fg) if bg: lst.append(bg) sys.stdout.write("\033[%sm%s\033[0m" %(";".join(lst),string)) def redBrightPrint(self, string): """Печатает яркое красное сообщение""" self.colorPrint("1","31","",string) def greenBrightPrint(self, string): """Печатает яркое зеленое сообщение""" self.colorPrint("1","32","",string) def yellowBrightPrint(self, string): """Печатает яркое желтое сообщение""" self.colorPrint("1","33","",string) def blueBrightPrint(self, string): """Печатает яркое cинее сообщение""" self.colorPrint("1","34","",string) def lenString(self, string): """Получаем длинну строки""" stringUnicode = cl_utils._toUNICODE(string) lenString = len(stringUnicode) return lenString def defaultPrint(self, string): sys.stdout.write(string) sys.stdout.flush() def printLine(self, argL, argR): """Печатает справа и слева консоли цветные сообщения""" #Допустимые цвета colorDict = {\ # цвет по умолчанию '':self.defaultPrint, # ярко зеленый 'greenBr':self.greenBrightPrint, # ярко голубой 'blueBr':self.blueBrightPrint, # ярко красный 'redBr':self.redBrightPrint, # ярко желтый 'yellowBr':self.yellowBrightPrint, } # cмещение от левого края консоли offsetL = 0 for color,leftString in argL: offsetL += self.lenString(leftString) if colorDict.has_key(color): # печатаем и считаем смещение colorDict[color](leftString) else: colorDict[''](leftString) # cмещение от правого края консоли offsetR = 0 for color,rightString in argR: offsetR += self.lenString(rightString) # Добавляем пробелы self.printRight(offsetL, offsetR) for color,rightString in argR: if colorDict.has_key(color): # печатаем и считаем смещение colorDict[color](rightString) else: colorDict[''](rightString) print "" def printNotOK(self, string): """Вывод на печать в случае сбоя""" self.printLine((('greenBr',' * '), ('',string), ), (('blueBr','['), ('redBr',' !! '), ('blueBr',']'), ) ) def printOK(self, string): """Вывод на печать в случае успеха""" self.printLine((('greenBr',' * '), ('',string), ), (('blueBr','['), ('greenBr',' ok '), ('blueBr',']'), ) ) def printWARNING(self, string): """Вывод на печать предупреждения""" self.printLine((('yellowBr',' * '), ('',string), ), (('',''), ) ) def printERROR(self, string): """Вывод на печать предупреждения""" self.printLine((('redBr',' * '), ('',string), ), (('',''), ) ) def printSUCCESS(self, string): """Вывод на печать в случае успеха без [ok] справа""" self.printLine((('greenBr',' * '), ('',string), ), (('',''), ) )