diff --git a/calculate/lib/cl_template.py b/calculate/lib/cl_template.py index 8ee09af..f71baf1 100644 --- a/calculate/lib/cl_template.py +++ b/calculate/lib/cl_template.py @@ -37,7 +37,7 @@ from operator import lt, le, eq, ne, ge, gt from utils.common import _error, _warning from utils.text import _toUNICODE, convertStrListDict -from utils.portage import isPkgInstalled +from utils.portage import isPkgInstalled,reVerSplitToPV from utils.content import PkgContents from utils.files import (getModeFile, listDirectory,removeDir, typeFile, scanDirectory, @@ -47,7 +47,28 @@ from datavars import DataVarsError from calculate.lib.cl_lang import setLocalTranslate setLocalTranslate('cl_lib3',sys.modules[__name__]) -class TemplatesError(Exception): +class TemplatesInterrupt(Exception): + """ + Interrupt templates appling + """ + EXIT,ABORT=1,2 + + def __init__(self,*args): + self.message = args[0] + self.args = args + + def __str__(self): + return str(self.message) + + def isExit(self): return self.isInterrupt() and self.args[1] == self.EXIT + + def isAbort(self): return self.isInterrupt() and self.args[1] == self.ABORT + + def status(self): return self.args[1] if self.isInterrupt() else 0 + + def isInterrupt(self): return len(self.args)>1 + +class TemplatesError(TemplatesInterrupt): """ Error on templates appling """ @@ -2186,7 +2207,7 @@ class _file(_error): except: try: if os.path.isdir(nameFileConfig): - self.setWarning(_("unable to open the directory as file:") + self.printWARNING(_("unable to open the directory as file:") + nameFileConfig) return False F_CONF = open(nameFileConfig, "w+") @@ -3016,6 +3037,101 @@ class templateFunction(_error, _warning, _shareTemplate, _shareTermsFunction): textTemplateTmp[resS.end():] return textTemplateTmp + def funcPrint(self,funArgv, resS, localVars, textTemplateTmp, nameTemp): + """ + Вывод успешного сообщения + """ + self.printSUCCESS(_(funArgv)) + textTemplateTmp = textTemplateTmp[:resS.start()] + \ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def funcWarning(self,funArgv, resS, localVars, textTemplateTmp, nameTemp): + """ + Вывод сообщения с предупреждением + """ + self.printWARNING(_(funArgv)) + textTemplateTmp = textTemplateTmp[:resS.start()] + \ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def funcError(self,funArgv, resS, localVars, textTemplateTmp, nameTemp): + """ + Вывод сообщения с ошибкой + """ + self.printERROR(_(funArgv)) + textTemplateTmp = textTemplateTmp[:resS.start()] + \ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def funcExit(self,funArgv, resS, localVars, textTemplateTmp, nameTemp): + """ + Вывод сообщения с ошибкой + """ + self.printSUCCESS(_(funArgv)) + raise TemplatesInterrupt(_("Applying was stop"),TemplatesInterrupt.EXIT) + + def funcBreak(self,funArgv, resS, localVars, textTemplateTmp, nameTemp): + """ + Вывод сообщения с ошибкой + """ + self.printERROR(_(funArgv)) + raise TemplatesInterrupt(_("Applying was interrupted"), + TemplatesInterrupt.ABORT) + + def getElogTimestamp(self): + # Получаем время модификации конфигурационного файла + curTime = self.getTimeFile(self.fileConfigIni) + nameLocVar = "update.timestamp" + if self.timeIni != curTime: + # читаем переменные из файла + self.prevDictIni = self.loadVarsIni(self.fileConfigIni) + self.currDictIni= {} + self.currDictIni.update(self.prevDictIni) + self.timeIni = self.getTimeFile(self.fileConfigIni) + if nameLocVar in self.currDictIni.keys(): + if self.currDictIni[nameLocVar] is None: + return 0 + else: + val = self.currDictIni[nameLocVar].encode("UTF-8") + if val.isdigit(): + return int(val) + return 0 + + def funcElog(self,funArgv, resS, localVars, textTemplateTmp, nameTemp): + """Function for work with emerge.log""" + funArgv = funArgv.strip() + rePkg = re.compile(r'completed emerge \(\d+ of \d+\) (\S+)\s',re.S) + logFile = '/var/log/emerge.log' + replace = "" + if funArgv: + lastTimestamp = self.getElogTimestamp() + skip = True + for line in reversed(list(readLinesFile(logFile))): + timestamp,op,info = line.partition(':') + if timestamp.isdigit() and lastTimestamp and \ + int(timestamp) < lastTimestamp: + break + match = rePkg.search(info) + if match and match.group(1).startswith(funArgv): + pkgInfo = reVerSplitToPV(match.group(1)) + if "{CATEGORY}/{PN}".format(**pkgInfo) == funArgv: + replace = pkgInfo['PVR'] + break + else: + # get last timestamp + replace = readFile(logFile).rpartition( + '\n')[2].lpartition(':')[0] + textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def funcConfirm(self,funArgv, resS, localVars, textTemplateTmp, nameTemp): + res = self.askConfirm(_(funArgv)) + textTemplateTmp = textTemplateTmp[:resS.start()] + res + \ + textTemplateTmp[resS.end():] + return textTemplateTmp + def loadVarsIni(self, iniFileName): """ Читает файл fileName создает и заполняет переменные на основе этого файла @@ -3274,9 +3390,9 @@ class templateFunction(_error, _warning, _shareTemplate, _shareTermsFunction): return textTemplateTmp def funcBelong(self, funArgv, resS, localVars, textTemplateTmp, nameTemp): - self.setWarning( - _("Function '{funcname}' used by {template} is deprecated and will be removed in the future").format( - funcname="belong",template=nameTemp)) + self.printWARNING(_("Function '{funcname}' used by {template} " + "is deprecated and will be removed in the future" + ).format(funcname="belong",template=nameTemp)) replace = "" return textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] @@ -3664,11 +3780,13 @@ class Template(_file,_terms,_warning,xmlShare,templateFormat,_shareTemplate): def __init__(self, objVar, servDir=False, dirsFilter=[], filesFilter=[], cltObj=True, cltFilter=True, printWarning=True, printSUCCESS=lambda x:x,printWARNING=lambda x:x, - printERROR=lambda x:x): + printERROR=lambda x:x,askConfirm=lambda x:x): self.changedFiles = ChangedFiles() self.printSUCCESS = printSUCCESS self.printERROR = printERROR self.printWARNING = printWARNING + self.askConfirm = askConfirm + self.stop = 0 self.cltObj = None self.functObj = None # Предупреждения @@ -3730,6 +3848,7 @@ re.M|re.S) self.functObj.printSUCCESS = self.printSUCCESS self.functObj.printWARNING = self.printWARNING self.functObj.printERROR = self.printERROR + self.functObj.askConfirm = self.askConfirm # Метод применения функций к шаблонам self.applyFuncTemplate = self.functObj.applyFuncTemplate # Объект для определения типа файла шаблона @@ -3741,7 +3860,8 @@ re.M|re.S) # Объект templateClt self.cltObj = templateClt(self.objVar,printSUCCESS=self.printSUCCESS, printERROR=self.printERROR, - printWARNING=self.printWARNING) + printWARNING=self.printWARNING, + askConfirm=self.askConfirm) elif cltObj: # Объект templateClt self.cltObj = cltObj @@ -3797,18 +3917,18 @@ gettext -d cl_template "$*" p.write(code) p.pipe.stdin.close() for line in p.readByLine(): - self.printSUCCESS(line) + self.printSUCCESS(line.strip()) p.pipe.wait() if p.success(): self.executedFiles.append((code,execPath)) if p.readerr(): for line in p.readerr().split('\n'): - self.printWARNING(line) + self.printWARNING(line.strip()) return True else: if p.readerr(): for line in p.readerr().split('\n'): - self.printERROR(line) + self.printERROR(line.strip()) return False def __octToInt(self, strOct): @@ -4129,11 +4249,7 @@ gettext -d cl_template "$*" if skipDirs or skipTemplates: # print warning from cl_print import color_print - printObj = color_print() - setWARNING = lambda x: self.setWarning(x) and\ - self.printWarning and\ - printObj.printWARNING(x) - setWARNING(_("No conditions for checking the value of variable" + self.printWARNING(_("No conditions for checking the value of variable" " 'cl_name'")) skipDirTemplates = [] for skipDir in skipDirs: @@ -4156,7 +4272,7 @@ gettext -d cl_template "$*" setWARNING("# Calculate cl_name==calculate-install") return skipDirs + skipTemplates - def applyTemplates(self,progress=True,execute=True): + def applyTemplates(self,progress=True,rerun=True): """Применяет шаблоны к конфигурационным файлам""" def createDictTemplates(path, prefix, dictTemplates): @@ -4245,8 +4361,8 @@ gettext -d cl_template "$*" for dirTemplate in dirsTemplatesExists: if self.scanningTemplates(dirTemplate, skipTemplates=skipTemplates) is False: - return False - if self.cltObj: + break + if self.cltObj and not self.stop: # Созданные директории self.cltObj.createdDirs = self.createdDirs # Примененные файлы @@ -4279,11 +4395,19 @@ gettext -d cl_template "$*" if not filename in self.cltObj.filterApplyTemplates: self.cltObj.filterApplyTemplates[filename] = [] self.cltObj.filterApplyTemplates[filename].append(pkg) - if not self.cltObj.applyTemplates(): - return False - if (self.objVar.Get('cl_merge_pkg') or \ + for filename,pkgs in self.changedFiles.data.items(): + if not filename in self.cltObj.filterApplyTemplates: + self.cltObj.filterApplyTemplates[filename] = [] + pkgs = filter(lambda x:not x in \ + self.cltObj.filterApplyTemplates[filename], + map(lambda x:x[0],pkgs)) + self.cltObj.filterApplyTemplates[filename].extend(pkgs) + + self.cltObj.applyTemplates() + self.stop = self.stop or self.cltObj.stop + if not self.stop and ((self.objVar.Get('cl_merge_pkg') or \ self.objVar.Get('cl_action') == "sync") and \ - self.objVar.Get('cl_merge_pkg_new'): + self.objVar.Get('cl_merge_pkg_new')): self.objVar.Set('cl_root_path', self.objVar.Get('cl_root_path_next'),force=True) self.recalculateBaseDir() @@ -4297,12 +4421,12 @@ gettext -d cl_template "$*" createdDirs = self.createdDirs filesApply = self.filesApply self.changeMergePackage(self.objVar.Get('cl_merge_pkg')) - self.applyTemplates(execute=False) + self.applyTemplates(rerun=False) createdDirs.extend(self.createdDirs) filesApply.extend(self.filesApply) self.filesApply = filesApply self.createdDirs = createdDirs - if execute: + if rerun and self.stop != TemplatesInterrupt.ABORT: if self.cltObj: self.queueExecute.extend(self.cltObj.queueExecute) for processor,text,nameTemplate in self.queueExecute: @@ -4372,8 +4496,12 @@ gettext -d cl_template "$*" optNextDir) if ret is False: break - except TemplatesError as e: - self.printWARNING(str(e)) + except TemplatesInterrupt as e: + if e.isInterrupt(): + self.stop = e.status() + return False + else: + self.printWARNING(str(e)) finally: self.objVar.defaultModule = prevModule self.functObj.currentBelong = prevBelong @@ -4428,8 +4556,8 @@ gettext -d cl_template "$*" if createdDirs: self.createdDirs += createdDirs if os.path.isfile(pathDir): - self.setWarning(_("{dirpath} is a file").format(dirpath=pathDir)) - self.setWarning(_("templates in {tempath} are skipped" + self.printWARNING(_("{dirpath} is a file").format(dirpath=pathDir)) + self.printWARNING(_("templates in {tempath} are skipped" ).format(tempath=path)) return None if objHeadDir: @@ -5636,12 +5764,17 @@ class scanDirectoryClt: self.filterApplyTemplates.keys() or self.hasBelong(absPath): prevDefault = self.objVar.defaultModule if not self.processingFile(absPath, prefix): - ret = False + return False self.objVar.defaultModule = prevDefault elif stat.S_ISDIR(statInfo): - ret = self.scanningTemplates(absPath, prefix, True) - except TemplatesError as e: - self.printWARNING(str(e)) + if not self.scanningTemplates(absPath, prefix, True): + return False + except TemplatesInterrupt as e: + if e.isInterrupt(): + self.stop = e.status() + return False + else: + self.printWARNING(str(e)) return True class templateClt(scanDirectoryClt, Template): @@ -5780,7 +5913,7 @@ class templateClt(scanDirectoryClt, Template): # Обрабатываем шаблоны for dirTemplate in dirsTemplates: if self.scanningTemplates(dirTemplate, self._chrootDir) is False: - return False + break return (self.createdDirs, self.filesApply) class iniParser(_error, templateFormat): diff --git a/calculate/lib/variables/__init__.py b/calculate/lib/variables/__init__.py index f1d80a8..ade7a61 100644 --- a/calculate/lib/variables/__init__.py +++ b/calculate/lib/variables/__init__.py @@ -25,4 +25,4 @@ class VariableClVer(ReadonlyVariable): """ Package version """ - value = "3.1.2" + value = "3.1.3"