#-*- coding: utf-8 -*- # Copyright 2008-2010 Mir Calculate Ltd. 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 getopt import sys from cl_string import prettyColumnStr pcs = prettyColumnStr class opt: def __init__(self,shortOpt,longOpt = []): """ Длинные и короткие опции командной строки допустимые в программе a - короткая опция >program -a a: - короткая опциия со значением >program -a 10 a:: - короткая опциия у которой может быть или не быть значение >program -a >program -a 15 "ha:" - значение параметра shortOpt две опции h - без значения, a - со значением help - длинная опция без значения test= - длинная опция со значением ["help","test="] - значение парамера longOpt >program -a две опции help - без значения, test - со значением """ self.shortOpt = shortOpt self.longOpt = longOpt self.sysArgv = sys.argv[1:] def getopt(self): try: opts, args = getopt.getopt(self.sysArgv,self.shortOpt,self.longOpt) except getopt.GetoptError: self.handlerErrOpt() sys.exit(1) for option, value in opts: if len(option) == 2: option = option[1:] else: option = option[2:] self.handlerOpt(option,value) for param in args: self.handlerParam(param) def handlerErrOpt(self): # Обработчик в случае неправильных параметров pass def handlerOpt(self,option,value): # Обработчик (параметр значение) pass def handlerParam(self,param): # Обработчик хвостов (значение) pass 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"] return ""