diff options
author | Michael DeHaan <mdehaan@redhat.com> | 2007-03-23 12:25:11 -0400 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2007-03-23 12:25:11 -0400 |
commit | e639b419fb91246436d673569ccf7bced60c66e5 (patch) | |
tree | a67c60ec8986b6aa395d28f5c7f2aa806c69ab47 /cobbler | |
parent | 30c9135a720556af5210c5d9c16a6c732fb42afc (diff) | |
download | third_party-cobbler-e639b419fb91246436d673569ccf7bced60c66e5.tar.gz third_party-cobbler-e639b419fb91246436d673569ccf7bced60c66e5.tar.xz third_party-cobbler-e639b419fb91246436d673569ccf7bced60c66e5.zip |
This is release 0.4.4. I mean it this time :)
Diffstat (limited to 'cobbler')
-rw-r--r-- | cobbler/Cheetah/Compiler.py | 1975 | ||||
-rw-r--r-- | cobbler/action_import.py | 5 | ||||
-rw-r--r-- | cobbler/cobbler_msg.py | 2 |
3 files changed, 5 insertions, 1977 deletions
diff --git a/cobbler/Cheetah/Compiler.py b/cobbler/Cheetah/Compiler.py deleted file mode 100644 index a74267d..0000000 --- a/cobbler/Cheetah/Compiler.py +++ /dev/null @@ -1,1975 +0,0 @@ -#!/usr/bin/env python -# $Id: Compiler.py,v 1.148 2006/06/22 00:18:22 tavis_rudd Exp $ -"""Compiler classes for Cheetah: -ModuleCompiler aka 'Compiler' -ClassCompiler -MethodCompiler - -If you are trying to grok this code start with ModuleCompiler.__init__, -ModuleCompiler.compile, and ModuleCompiler.__getattr__. - -Meta-Data -================================================================================ -Author: Tavis Rudd <tavis@damnsimple.com> -Version: $Revision: 1.148 $ -Start Date: 2001/09/19 -Last Revision Date: $Date: 2006/06/22 00:18:22 $ -""" -__author__ = "Tavis Rudd <tavis@damnsimple.com>" -__revision__ = "$Revision: 1.148 $"[11:-2] - -import sys -import os -import os.path -from os.path import getmtime, exists -import re -import types -import time -import random -import warnings -import __builtin__ -import copy - -from Cheetah.Version import Version, VersionTuple -from Cheetah.SettingsManager import SettingsManager -from Cheetah.Parser import Parser, ParseError, specialVarRE, \ - STATIC_CACHE, REFRESH_CACHE, SET_LOCAL, SET_GLOBAL,SET_MODULE -from Cheetah.Utils.Indenter import indentize # an undocumented preprocessor -from Cheetah import ErrorCatchers -from Cheetah import NameMapper - -from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList -VFFSL=valueFromFrameOrSearchList -VFSL=valueFromSearchList -VFN=valueForName -currentTime=time.time - -class Error(Exception): pass - -DEFAULT_COMPILER_SETTINGS = { - ## controlling the handling of Cheetah $placeholders - 'useNameMapper': True, # Unified dotted notation and the searchList - 'useSearchList': True, # if false, assume the first - # portion of the $variable (before the first dot) is a global, - # builtin, or local var that doesn't need - # looking up in the searchlist BUT use - # namemapper on the rest of the lookup - 'allowSearchListAsMethArg': True, - 'useAutocalling': True, # detect and call callable()'s, requires NameMapper - 'useStackFrames': True, # use NameMapper.valueFromFrameOrSearchList - # rather than NameMapper.valueFromSearchList - 'useErrorCatcher':False, - 'alwaysFilterNone':True, # filter out None, before the filter is called - 'useFilters':True, # use str instead if =False - 'includeRawExprInFilterArgs':True, - - - #'lookForTransactionAttr':False, - 'autoAssignDummyTransactionToSelf':False, - 'useKWsDictArgForPassingTrans':True, - - ## controlling the aesthetic appearance / behaviour of generated code - 'commentOffset': 1, - # should shorter str constant chunks be printed using repr rather than ''' quotes - 'reprShortStrConstants': True, - 'reprNewlineThreshold':3, - 'outputRowColComments':True, - # should #block's be wrapped in a comment in the template's output - 'includeBlockMarkers': False, - 'blockMarkerStart':('\n<!-- START BLOCK: ',' -->\n'), - 'blockMarkerEnd':('\n<!-- END BLOCK: ',' -->\n'), - 'defDocStrMsg':'Autogenerated by CHEETAH: The Python-Powered Template Engine', - 'setup__str__method': False, - 'mainMethodName':'respond', - 'mainMethodNameForSubclasses':'writeBody', - 'indentationStep': ' '*4, - 'initialMethIndentLevel': 2, - 'monitorSrcFile':False, - 'outputMethodsBeforeAttributes': True, - - - ## customizing the #extends directive - 'autoImportForExtendsDirective':True, - 'handlerForExtendsDirective':None, # baseClassName = handler(compiler, baseClassName) - # a callback hook for customizing the - # #extends directive. It can manipulate - # the compiler's state if needed. - # also see allowExpressionsInExtendsDirective - - - # input filtering/restriction - # use lower case keys here!! - 'disabledDirectives':[], # list of directive keys, without the start token - 'enabledDirectives':[], # list of directive keys, without the start token - - 'disabledDirectiveHooks':[], # callable(parser, directiveKey) - 'preparseDirectiveHooks':[], # callable(parser, directiveKey) - 'postparseDirectiveHooks':[], # callable(parser, directiveKey) - 'preparsePlaceholderHooks':[], # callable(parser) - 'postparsePlaceholderHooks':[], # callable(parser) - # the above hooks don't need to return anything - - 'expressionFilterHooks':[], # callable(parser, expr, exprType, rawExpr=None, startPos=None) - # exprType is the name of the directive, 'psp', or 'placeholder'. all - # lowercase. The filters *must* return the expr or raise an exception. - # They can modify the expr if needed. - - 'templateMetaclass':None, # strictly optional. Only works with new-style baseclasses - - - 'i18NFunctionName':'self.i18n', - - ## These are used in the parser, but I've put them here for the time being to - ## facilitate separating the parser and compiler: - 'cheetahVarStartToken':'$', - 'commentStartToken':'##', - 'multiLineCommentStartToken':'#*', - 'multiLineCommentEndToken':'*#', - 'gobbleWhitespaceAroundMultiLineComments':True, - 'directiveStartToken':'#', - 'directiveEndToken':'#', - 'allowWhitespaceAfterDirectiveStartToken':False, - 'PSPStartToken':'<%', - 'PSPEndToken':'%>', - 'EOLSlurpToken':'#', - 'gettextTokens': ["_", "N_", "ngettext"], - 'allowExpressionsInExtendsDirective': False, # the default restricts it to - # accepting dotted names - 'allowEmptySingleLineMethods': False, - 'allowNestedDefScopes': True, - 'allowPlaceholderFilterArgs': True, - - ## See Parser.initDirectives() for the use of the next 3 - #'directiveNamesAndParsers':{} - #'endDirectiveNamesAndHandlers':{} - #'macroDirectives':{} - - } - - - -class GenUtils: - """An abstract baseclass for the Compiler classes that provides methods that - perform generic utility functions or generate pieces of output code from - information passed in by the Parser baseclass. These methods don't do any - parsing themselves. - """ - - def genTimeInterval(self, timeString): - ##@@ TR: need to add some error handling here - if timeString[-1] == 's': - interval = float(timeString[:-1]) - elif timeString[-1] == 'm': - interval = float(timeString[:-1])*60 - elif timeString[-1] == 'h': - interval = float(timeString[:-1])*60*60 - elif timeString[-1] == 'd': - interval = float(timeString[:-1])*60*60*24 - elif timeString[-1] == 'w': - interval = float(timeString[:-1])*60*60*24*7 - else: # default to minutes - interval = float(timeString)*60 - return interval - - def genCacheInfo(self, cacheTokenParts): - """Decipher a placeholder cachetoken - """ - cacheInfo = {} - if cacheTokenParts['REFRESH_CACHE']: - cacheInfo['type'] = REFRESH_CACHE - cacheInfo['interval'] = self.genTimeInterval(cacheTokenParts['interval']) - elif cacheTokenParts['STATIC_CACHE']: - cacheInfo['type'] = STATIC_CACHE - return cacheInfo # is empty if no cache - - def genCacheInfoFromArgList(self, argList): - cacheInfo = {'type':REFRESH_CACHE} - for key, val in argList: - if val[0] in '"\'': - val = val[1:-1] - - if key == 'timer': - key = 'interval' - val = self.genTimeInterval(val) - - cacheInfo[key] = val - return cacheInfo - - def genCheetahVar(self, nameChunks, plain=False): - if nameChunks[0][0] in self.setting('gettextTokens'): - self.addGetTextVar(nameChunks) - if self.setting('useNameMapper') and not plain: - return self.genNameMapperVar(nameChunks) - else: - return self.genPlainVar(nameChunks) - - def addGetTextVar(self, nameChunks): - """Output something that gettext can recognize. - - This is a harmless side effect necessary to make gettext work when it - is scanning compiled templates for strings marked for translation. - - @@TR: another marginally more efficient approach would be to put the - output in a dummy method that is never called. - """ - # @@TR: this should be in the compiler not here - self.addChunk("if False:") - self.indent() - self.addChunk(self.genPlainVar(nameChunks[:])) - self.dedent() - - def genPlainVar(self, nameChunks): - """Generate Python code for a Cheetah $var without using NameMapper - (Unified Dotted Notation with the SearchList). - """ - nameChunks.reverse() - chunk = nameChunks.pop() - pythonCode = chunk[0] + chunk[2] - while nameChunks: - chunk = nameChunks.pop() - pythonCode = (pythonCode + '.' + chunk[0] + chunk[2]) - return pythonCode - - def genNameMapperVar(self, nameChunks): - """Generate valid Python code for a Cheetah $var, using NameMapper - (Unified Dotted Notation with the SearchList). - - nameChunks = list of var subcomponents represented as tuples - [ (name,useAC,remainderOfExpr), - ] - where: - name = the dotted name base - useAC = where NameMapper should use autocalling on namemapperPart - remainderOfExpr = any arglist, index, or slice - - If remainderOfExpr contains a call arglist (e.g. '(1234)') then useAC - is False, otherwise it defaults to True. It is overridden by the global - setting 'useAutocalling' if this setting is False. - - EXAMPLE - ------------------------------------------------------------------------ - if the raw Cheetah Var is - $a.b.c[1].d().x.y.z - - nameChunks is the list - [ ('a.b.c',True,'[1]'), # A - ('d',False,'()'), # B - ('x.y.z',True,''), # C - ] - - When this method is fed the list above it returns - VFN(VFN(VFFSL(SL, 'a.b.c',True)[1], 'd',False)(), 'x.y.z',True) - which can be represented as - VFN(B`, name=C[0], executeCallables=(useAC and C[1]))C[2] - where: - VFN = NameMapper.valueForName - VFFSL = NameMapper.valueFromFrameOrSearchList - VFSL = NameMapper.valueFromSearchList # optionally used instead of VFFSL - SL = self.searchList() - useAC = self.setting('useAutocalling') # True in this example - - A = ('a.b.c',True,'[1]') - B = ('d',False,'()') - C = ('x.y.z',True,'') - - C` = VFN( VFN( VFFSL(SL, 'a.b.c',True)[1], - 'd',False)(), - 'x.y.z',True) - = VFN(B`, name='x.y.z', executeCallables=True) - - B` = VFN(A`, name=B[0], executeCallables=(useAC and B[1]))B[2] - A` = VFFSL(SL, name=A[0], executeCallables=(useAC and A[1]))A[2] - - - Note, if the compiler setting useStackFrames=False (default is true) - then - A` = VFSL([locals()]+SL+[globals(), __builtin__], name=A[0], executeCallables=(useAC and A[1]))A[2] - This option allows Cheetah to be used with Psyco, which doesn't support - stack frame introspection. - """ - defaultUseAC = self.setting('useAutocalling') - useSearchList = self.setting('useSearchList') - - nameChunks.reverse() - name, useAC, remainder = nameChunks.pop() - - if not useSearchList: - firstDotIdx = name.find('.') - if firstDotIdx != -1 and firstDotIdx < len(name): - beforeFirstDot, afterDot = name[:firstDotIdx], name[firstDotIdx+1:] - pythonCode = ('VFN(' + beforeFirstDot + - ',"' + afterDot + - '",' + repr(defaultUseAC and useAC) + ')' - + remainder) - else: - pythonCode = name+remainder - elif self.setting('useStackFrames'): - pythonCode = ('VFFSL(SL,' - '"'+ name + '",' - + repr(defaultUseAC and useAC) + ')' - + remainder) - else: - pythonCode = ('VFSL([locals()]+SL+[globals(), __builtin__],' - '"'+ name + '",' - + repr(defaultUseAC and useAC) + ')' - + remainder) - ## - while nameChunks: - name, useAC, remainder = nameChunks.pop() - pythonCode = ('VFN(' + pythonCode + - ',"' + name + - '",' + repr(defaultUseAC and useAC) + ')' - + remainder) - return pythonCode - -################################################## -## METHOD COMPILERS - -class MethodCompiler(GenUtils): - def __init__(self, methodName, classCompiler, - initialMethodComment=None, - decorator=None): - self._settingsManager = classCompiler - self._classCompiler = classCompiler - self._moduleCompiler = classCompiler._moduleCompiler - self._methodName = methodName - self._initialMethodComment = initialMethodComment - self._setupState() - self._decorator = decorator - - def setting(self, key): - return self._settingsManager.setting(key) - - def _setupState(self): - self._indent = self.setting('indentationStep') - self._indentLev = self.setting('initialMethIndentLevel') - self._pendingStrConstChunks = [] - self._methodSignature = None - self._methodDef = None - self._docStringLines = [] - self._methodBodyChunks = [] - - self._cacheRegionsStack = [] - self._callRegionsStack = [] - self._captureRegionsStack = [] - self._filterRegionsStack = [] - - self._isErrorCatcherOn = False - - self._hasReturnStatement = False - self._isGenerator = False - - - def cleanupState(self): - """Called by the containing class compiler instance - """ - pass - - def methodName(self): - return self._methodName - - def setMethodName(self, name): - self._methodName = name - - ## methods for managing indentation - - def indentation(self): - return self._indent * self._indentLev - - def indent(self): - self._indentLev +=1 - - def dedent(self): - if self._indentLev: - self._indentLev -=1 - else: - raise Error('Attempt to dedent when the indentLev is 0') - - ## methods for final code wrapping - - def methodDef(self): - if self._methodDef: - return self._methodDef - else: - return self.wrapCode() - - __str__ = methodDef - - def wrapCode(self): - self.commitStrConst() - methodDefChunks = ( - self.methodSignature(), - '\n', - self.docString(), - self.methodBody() ) - methodDef = ''.join(methodDefChunks) - self._methodDef = methodDef - return methodDef - - def methodSignature(self): - return self._indent + self._methodSignature + ':' - - def setMethodSignature(self, signature): - self._methodSignature = signature - - def methodBody(self): - return ''.join( self._methodBodyChunks ) - - def docString(self): - if not self._docStringLines: - return '' - - ind = self._indent*2 - docStr = (ind + '"""\n' + ind + - ('\n' + ind).join([ln.replace('"""',"'''") for ln in self._docStringLines]) + - '\n' + ind + '"""\n') - return docStr - - ## methods for adding code - def addMethDocString(self, line): - self._docStringLines.append(line.replace('%','%%')) - - def addChunk(self, chunk): - self.commitStrConst() - chunk = "\n" + self.indentation() + chunk - self._methodBodyChunks.append(chunk) - - def appendToPrevChunk(self, appendage): - self._methodBodyChunks[-1] = self._methodBodyChunks[-1] + appendage - - def addWriteChunk(self, chunk): - self.addChunk('write(' + chunk + ')') - - def addFilteredChunk(self, chunk, filterArgs=None, rawExpr=None, lineCol=None): - if filterArgs is None: - filterArgs = '' - if self.setting('includeRawExprInFilterArgs') and rawExpr: - filterArgs += ', rawExpr=%s'%repr(rawExpr) - - if self.setting('alwaysFilterNone'): - if rawExpr and rawExpr.find('\n')==-1 and rawExpr.find('\r')==-1: - self.addChunk("_v = %s # %r"%(chunk, rawExpr)) - if lineCol: - self.appendToPrevChunk(' on line %s, col %s'%lineCol) - else: - self.addChunk("_v = %s"%chunk) - - if self.setting('useFilters'): - self.addChunk("if _v is not None: write(_filter(_v%s))"%filterArgs) - else: - self.addChunk("if _v is not None: write(str(_v))") - else: - if self.setting('useFilters'): - self.addChunk("write(_filter(%s%s))"%(chunk,filterArgs)) - else: - self.addChunk("write(str(%s))"%chunk) - - def _appendToPrevStrConst(self, strConst): - if self._pendingStrConstChunks: - self._pendingStrConstChunks.append(strConst) - else: - self._pendingStrConstChunks = [strConst] - - def _unescapeCheetahVars(self, theString): - """Unescape any escaped Cheetah \$vars in the string. - """ - - token = self.setting('cheetahVarStartToken') - return theString.replace('\\' + token, token) - - def _unescapeDirectives(self, theString): - """Unescape any escaped Cheetah \$vars in the string. - """ - - token = self.setting('directiveStartToken') - return theString.replace('\\' + token, token) - - def commitStrConst(self): - """Add the code for outputting the pending strConst without chopping off - any whitespace from it. - """ - if self._pendingStrConstChunks: - strConst = self._unescapeCheetahVars(''.join(self._pendingStrConstChunks)) - strConst = self._unescapeDirectives(strConst) - self._pendingStrConstChunks = [] - if not strConst: - return - if self.setting('reprShortStrConstants') and \ - strConst.count('\n') < self.setting('reprNewlineThreshold'): - self.addWriteChunk( repr(strConst).replace('\\012','\\n')) - else: - strConst = strConst.replace('\\','\\\\').replace("'''","'\'\'\'") - if strConst[0] == "'": - strConst = '\\' + strConst - if strConst[-1] == "'": - strConst = strConst[:-1] + '\\' + strConst[-1] - - self.addWriteChunk("'''" + strConst + "'''" ) - - def handleWSBeforeDirective(self): - """Truncate the pending strCont to the beginning of the current line. - """ - if self._pendingStrConstChunks: - src = self._pendingStrConstChunks[-1] - BOL = max(src.rfind('\n')+1, src.rfind('\r')+1, 0) - if BOL < len(src): - self._pendingStrConstChunks[-1] = src[:BOL] - - - - def isErrorCatcherOn(self): - return self._isErrorCatcherOn - - def turnErrorCatcherOn(self): - self._isErrorCatcherOn = True - - def turnErrorCatcherOff(self): - self._isErrorCatcherOn = False - - # @@TR: consider merging the next two methods into one - def addStrConst(self, strConst): - self._appendToPrevStrConst(strConst) - - def addRawText(self, text): - self.addStrConst(text) - - def addMethComment(self, comm): - offSet = self.setting('commentOffset') - self.addChunk('#' + ' '*offSet + comm) - - def addPlaceholder(self, expr, filterArgs, rawPlaceholder, - cacheTokenParts, lineCol, - silentMode=False): - cacheInfo = self.genCacheInfo(cacheTokenParts) - if cacheInfo: - cacheInfo['ID'] = repr(rawPlaceholder)[1:-1] - self.startCacheRegion(cacheInfo, lineCol, rawPlaceholder=rawPlaceholder) - - if self.isErrorCatcherOn(): - methodName = self._classCompiler.addErrorCatcherCall( - expr, rawCode=rawPlaceholder, lineCol=lineCol) - expr = 'self.' + methodName + '(localsDict=locals())' - - if silentMode: - self.addChunk('try:') - self.indent() - self.addFilteredChunk(expr, filterArgs, rawPlaceholder, lineCol=lineCol) - self.dedent() - self.addChunk('except NotFound: pass') - else: - self.addFilteredChunk(expr, filterArgs, rawPlaceholder, lineCol=lineCol) - - if self.setting('outputRowColComments'): - self.appendToPrevChunk(' # from line %s, col %s' % lineCol + '.') - if cacheInfo: - self.endCacheRegion() - - def addSilent(self, expr): - self.addChunk( expr ) - - def addEcho(self, expr, rawExpr=None): - self.addFilteredChunk(expr, rawExpr=rawExpr) - - def addSet(self, expr, exprComponents, setStyle): - if setStyle is SET_GLOBAL: - (LVALUE, OP, RVALUE) = (exprComponents.LVALUE, - exprComponents.OP, - exprComponents.RVALUE) - # we need to split the LVALUE to deal with globalSetVars - splitPos1 = LVALUE.find('.') - splitPos2 = LVALUE.find('[') - if splitPos1 > 0 and splitPos2==-1: - splitPos = splitPos1 - elif splitPos1 > 0 and splitPos1 < max(splitPos2,0): - splitPos = splitPos1 - else: - splitPos = splitPos2 - - if splitPos >0: - primary = LVALUE[:splitPos] - secondary = LVALUE[splitPos:] - else: - primary = LVALUE - secondary = '' - LVALUE = 'self._CHEETAH__globalSetVars["' + primary + '"]' + secondary - expr = LVALUE + ' ' + OP + ' ' + RVALUE.strip() - - if setStyle is SET_MODULE: - self._moduleCompiler.addModuleGlobal(expr) - else: - self.addChunk(expr) - - def addInclude(self, sourceExpr, includeFrom, isRaw): - self.addChunk('self._handleCheetahInclude(' + sourceExpr + - ', trans=trans, ' + - 'includeFrom="' + includeFrom + '", raw=' + - repr(isRaw) + ')') - - def addWhile(self, expr, lineCol=None): - self.addIndentingDirective(expr, lineCol=lineCol) - - def addFor(self, expr, lineCol=None): - self.addIndentingDirective(expr, lineCol=lineCol) - - def addRepeat(self, expr, lineCol=None): - #the _repeatCount stuff here allows nesting of #repeat directives - self._repeatCount = getattr(self, "_repeatCount", -1) + 1 - self.addFor('for __i%s in range(%s)' % (self._repeatCount,expr), lineCol=lineCol) - - def addIndentingDirective(self, expr, lineCol=None): - if expr and not expr[-1] == ':': - expr = expr + ':' - self.addChunk( expr ) - if lineCol: - self.appendToPrevChunk(' # generated from line %s, col %s'%lineCol ) - self.indent() - - def addReIndentingDirective(self, expr, dedent=True, lineCol=None): - self.commitStrConst() - if dedent: - self.dedent() - if not expr[-1] == ':': - expr = expr + ':' - - self.addChunk( expr ) - if lineCol: - self.appendToPrevChunk(' # generated from line %s, col %s'%lineCol ) - self.indent() - - def addIf(self, expr, lineCol=None): - """For a full #if ... #end if directive - """ - self.addIndentingDirective(expr, lineCol=lineCol) - - def addOneLineIf(self, expr, lineCol=None): - """For a full #if ... #end if directive - """ - self.addIndentingDirective(expr, lineCol=lineCol) - - def addTernaryExpr(self, conditionExpr, trueExpr, falseExpr, lineCol=None): - """For a single-lie #if ... then .... else ... directive - <condition> then <trueExpr> else <falseExpr> - """ - self.addIndentingDirective(conditionExpr, lineCol=lineCol) - self.addFilteredChunk(trueExpr) - self.dedent() - self.addIndentingDirective('else') - self.addFilteredChunk(falseExpr) - self.dedent() - - def addElse(self, expr, dedent=True, lineCol=None): - expr = re.sub(r'else[ \f\t]+if','elif', expr) - self.addReIndentingDirective(expr, dedent=dedent, lineCol=lineCol) - - def addElif(self, expr, dedent=True, lineCol=None): - self.addElse(expr, dedent=dedent, lineCol=lineCol) - - def addUnless(self, expr, lineCol=None): - self.addIf('if not (' + expr + ')') - - def addClosure(self, functionName, argsList, parserComment): - argStringChunks = [] - for arg in argsList: - chunk = arg[0] - if not arg[1] == None: - chunk += '=' + arg[1] - argStringChunks.append(chunk) - signature = "def " + functionName + "(" + ','.join(argStringChunks) + "):" - self.addIndentingDirective(signature) - self.addChunk('#'+parserComment) - - def addTry(self, expr, lineCol=None): - self.addIndentingDirective(expr, lineCol=lineCol) - - def addExcept(self, expr, dedent=True, lineCol=None): - self.addReIndentingDirective(expr, dedent=dedent, lineCol=lineCol) - - def addFinally(self, expr, dedent=True, lineCol=None): - self.addReIndentingDirective(expr, dedent=dedent, lineCol=lineCol) - - def addReturn(self, expr): - assert not self._isGenerator - self.addChunk(expr) - self._hasReturnStatement = True - - def addYield(self, expr): - assert not self._hasReturnStatement - self._isGenerator = True - if expr.replace('yield','').strip(): - self.addChunk(expr) - else: - self.addChunk('if _dummyTrans:') - self.indent() - self.addChunk('yield trans.response().getvalue()') - self.addChunk('trans = DummyTransaction()') - self.addChunk('write = trans.response().write') - self.dedent() - self.addChunk('else:') - self.indent() - self.addChunk( - 'raise TypeError("This method cannot be called with a trans arg")') - self.dedent() - - - def addPass(self, expr): - self.addChunk(expr) - - def addDel(self, expr): - self.addChunk(expr) - - def addAssert(self, expr): - self.addChunk(expr) - - def addRaise(self, expr): - self.addChunk(expr) - - def addBreak(self, expr): - self.addChunk(expr) - - def addContinue(self, expr): - self.addChunk(expr) - - def addPSP(self, PSP): - self.commitStrConst() - autoIndent = False - if PSP[0] == '=': - PSP = PSP[1:] - if PSP: - self.addWriteChunk('_filter(' + PSP + ')') - return - - elif PSP.lower() == 'end': - self.dedent() - return - elif PSP[-1] == '$': - autoIndent = True - PSP = PSP[:-1] - elif PSP[-1] == ':': - autoIndent = True - - for line in PSP.splitlines(): - self.addChunk(line) - - if autoIndent: - self.indent() - - def nextCacheID(self): - return ('_'+str(random.randrange(100, 999)) - + str(random.randrange(10000, 99999))) - - def startCacheRegion(self, cacheInfo, lineCol, rawPlaceholder=None): - - # @@TR: we should add some runtime logging to this - - ID = self.nextCacheID() - interval = cacheInfo.get('interval',None) - test = cacheInfo.get('test',None) - customID = cacheInfo.get('id',None) - if customID: - ID = customID - varyBy = cacheInfo.get('varyBy', repr(ID)) - self._cacheRegionsStack.append(ID) # attrib of current methodCompiler - - # @@TR: add this to a special class var as well - self.addChunk('') - - self.addChunk('## START CACHE REGION: ID='+ID+ - '. line %s, col %s'%lineCol + ' in the source.') - - self.addChunk('_RECACHE_%(ID)s = False'%locals()) - self.addChunk('_cacheRegion_%(ID)s = self.getCacheRegion(regionID='%locals() - + repr(ID) - + ', cacheInfo=%r'%cacheInfo - + ')') - self.addChunk('if _cacheRegion_%(ID)s.isNew():'%locals()) - self.indent() - self.addChunk('_RECACHE_%(ID)s = True'%locals()) - self.dedent() - - self.addChunk('_cacheItem_%(ID)s = _cacheRegion_%(ID)s.getCacheItem('%locals() - +varyBy+')') - - self.addChunk('if _cacheItem_%(ID)s.hasExpired():'%locals()) - self.indent() - self.addChunk('_RECACHE_%(ID)s = True'%locals()) - self.dedent() - - if test: - self.addChunk('if ' + test + ':') - self.indent() - self.addChunk('_RECACHE_%(ID)s = True'%locals()) - self.dedent() - - self.addChunk('if (not _RECACHE_%(ID)s) and _cacheItem_%(ID)s.getRefreshTime():'%locals()) - self.indent() - #self.addChunk('print "DEBUG"+"-"*50') - self.addChunk('try:') - self.indent() - self.addChunk('_output = _cacheItem_%(ID)s.renderOutput()'%locals()) - self.dedent() - self.addChunk('except KeyError:') - self.indent() - self.addChunk('_RECACHE_%(ID)s = True'%locals()) - #self.addChunk('print "DEBUG"+"*"*50') - self.dedent() - self.addChunk('else:') - self.indent() - self.addWriteChunk('_output') - self.addChunk('del _output') - self.dedent() - - self.dedent() - - self.addChunk('if _RECACHE_%(ID)s or not _cacheItem_%(ID)s.getRefreshTime():'%locals()) - self.indent() - self.addChunk('_orig_trans%(ID)s = trans'%locals()) - self.addChunk('trans = _cacheCollector_%(ID)s = DummyTransaction()'%locals()) - self.addChunk('write = _cacheCollector_%(ID)s.response().write'%locals()) - if interval: - self.addChunk(("_cacheItem_%(ID)s.setExpiryTime(currentTime() +"%locals()) - + str(interval) + ")") - - def endCacheRegion(self): - ID = self._cacheRegionsStack.pop() - self.addChunk('trans = _orig_trans%(ID)s'%locals()) - self.addChunk('write = trans.response().write') - self.addChunk('_cacheData = _cacheCollector_%(ID)s.response().getvalue()'%locals()) - self.addChunk('_cacheItem_%(ID)s.setData(_cacheData)'%locals()) - self.addWriteChunk('_cacheData') - self.addChunk('del _cacheData') - self.addChunk('del _cacheCollector_%(ID)s'%locals()) - self.addChunk('del _orig_trans%(ID)s'%locals()) - self.dedent() - self.addChunk('## END CACHE REGION: '+ID) - self.addChunk('') - - def nextCallRegionID(self): - return self.nextCacheID() - - def startCallRegion(self, functionName, args, lineCol, regionTitle='CALL'): - class CallDetails: pass - callDetails = CallDetails() - callDetails.ID = ID = self.nextCallRegionID() - callDetails.functionName = functionName - callDetails.args = args - callDetails.lineCol = lineCol - callDetails.usesKeywordArgs = False - self._callRegionsStack.append((ID, callDetails)) # attrib of current methodCompiler - - self.addChunk('## START %(regionTitle)s REGION: '%locals() - +ID - +' of '+functionName - +' at line %s, col %s'%lineCol + ' in the source.') - self.addChunk('_orig_trans%(ID)s = trans'%locals()) - self.addChunk('_wasBuffering%(ID)s = self._CHEETAH__isBuffering'%locals()) - self.addChunk('self._CHEETAH__isBuffering = True') - self.addChunk('trans = _callCollector%(ID)s = DummyTransaction()'%locals()) - self.addChunk('write = _callCollector%(ID)s.response().write'%locals()) - - def setCallArg(self, argName, lineCol): - ID, callDetails = self._callRegionsStack[-1] - if callDetails.usesKeywordArgs: - self._endCallArg() - else: - callDetails.usesKeywordArgs = True - self.addChunk('_callKws%(ID)s = {}'%locals()) - self.addChunk('_currentCallArgname%(ID)s = %(argName)r'%locals()) - callDetails.currentArgname = argName - - def _endCallArg(self): - ID, callDetails = self._callRegionsStack[-1] - currCallArg = callDetails.currentArgname - self.addChunk(('_callKws%(ID)s[%(currCallArg)r] =' - ' _callCollector%(ID)s.response().getvalue()')%locals()) - self.addChunk('del _callCollector%(ID)s'%locals()) - self.addChunk('trans = _callCollector%(ID)s = DummyTransaction()'%locals()) - self.addChunk('write = _callCollector%(ID)s.response().write'%locals()) - - def endCallRegion(self, regionTitle='CALL'): - ID, callDetails = self._callRegionsStack[-1] - functionName, initialKwArgs, lineCol = ( - callDetails.functionName, callDetails.args, callDetails.lineCol) - - def reset(ID=ID): - self.addChunk('trans = _orig_trans%(ID)s'%locals()) - self.addChunk('write = trans.response().write') - self.addChunk('self._CHEETAH__isBuffering = _wasBuffering%(ID)s '%locals()) - self.addChunk('del _wasBuffering%(ID)s'%locals()) - self.addChunk('del _orig_trans%(ID)s'%locals()) - - if not callDetails.usesKeywordArgs: - reset() - self.addChunk('_callArgVal%(ID)s = _callCollector%(ID)s.response().getvalue()'%locals()) - self.addChunk('del _callCollector%(ID)s'%locals()) - if initialKwArgs: - initialKwArgs = ', '+initialKwArgs - self.addFilteredChunk('%(functionName)s(_callArgVal%(ID)s%(initialKwArgs)s)'%locals()) - self.addChunk('del _callArgVal%(ID)s'%locals()) - else: - if initialKwArgs: - initialKwArgs = initialKwArgs+', ' - self._endCallArg() - reset() - self.addFilteredChunk('%(functionName)s(%(initialKwArgs)s**_callKws%(ID)s)'%locals()) - self.addChunk('del _callKws%(ID)s'%locals()) - self.addChunk('## END %(regionTitle)s REGION: '%locals() - +ID - +' of '+functionName - +' at line %s, col %s'%lineCol + ' in the source.') - self.addChunk('') - self._callRegionsStack.pop() # attrib of current methodCompiler - - def nextCaptureRegionID(self): - return self.nextCacheID() - - def startCaptureRegion(self, assignTo, lineCol): - class CaptureDetails: pass - captureDetails = CaptureDetails() - captureDetails.ID = ID = self.nextCaptureRegionID() - captureDetails.assignTo = assignTo - captureDetails.lineCol = lineCol - - self._captureRegionsStack.append((ID,captureDetails)) # attrib of current methodCompiler - self.addChunk('## START CAPTURE REGION: '+ID - +' '+assignTo - +' at line %s, col %s'%lineCol + ' in the source.') - self.addChunk('_orig_trans%(ID)s = trans'%locals()) - self.addChunk('_wasBuffering%(ID)s = self._CHEETAH__isBuffering'%locals()) - self.addChunk('self._CHEETAH__isBuffering = True') - self.addChunk('trans = _captureCollector%(ID)s = DummyTransaction()'%locals()) - self.addChunk('write = _captureCollector%(ID)s.response().write'%locals()) - - def endCaptureRegion(self): - ID, captureDetails = self._captureRegionsStack.pop() - assignTo, lineCol = (captureDetails.assignTo, captureDetails.lineCol) - self.addChunk('trans = _orig_trans%(ID)s'%locals()) - self.addChunk('write = trans.response().write') - self.addChunk('self._CHEETAH__isBuffering = _wasBuffering%(ID)s '%locals()) - self.addChunk('%(assignTo)s = _captureCollector%(ID)s.response().getvalue()'%locals()) - self.addChunk('del _orig_trans%(ID)s'%locals()) - self.addChunk('del _captureCollector%(ID)s'%locals()) - self.addChunk('del _wasBuffering%(ID)s'%locals()) - - def setErrorCatcher(self, errorCatcherName): - self.turnErrorCatcherOn() - - self.addChunk('if self._CHEETAH__errorCatchers.has_key("' + errorCatcherName + '"):') - self.indent() - self.addChunk('self._CHEETAH__errorCatcher = self._CHEETAH__errorCatchers["' + - errorCatcherName + '"]') - self.dedent() - self.addChunk('else:') - self.indent() - self.addChunk('self._CHEETAH__errorCatcher = self._CHEETAH__errorCatchers["' - + errorCatcherName + '"] = ErrorCatchers.' - + errorCatcherName + '(self)' - ) - self.dedent() - - def nextFilterRegionID(self): - return self.nextCacheID() - - def setFilter(self, theFilter, isKlass): - class FilterDetails: pass - filterDetails = FilterDetails() - filterDetails.ID = ID = self.nextFilterRegionID() - filterDetails.theFilter = theFilter - filterDetails.isKlass = isKlass - self._filterRegionsStack.append((ID, filterDetails)) # attrib of current methodCompiler - - self.addChunk('_orig_filter%(ID)s = _filter'%locals()) - if isKlass: - self.addChunk('_filter = self._CHEETAH__currentFilter = ' + theFilter.strip() + - '(self).filter') - else: - if theFilter.lower() == 'none': - self.addChunk('_filter = self._CHEETAH__initialFilter') - else: - # is string representing the name of a builtin filter - self.addChunk('filterName = ' + repr(theFilter)) - self.addChunk('if self._CHEETAH__filters.has_key("' + theFilter + '"):') - self.indent() - self.addChunk('_filter = self._CHEETAH__currentFilter = self._CHEETAH__filters[filterName]') - self.dedent() - self.addChunk('else:') - self.indent() - self.addChunk('_filter = self._CHEETAH__currentFilter' - +' = \\\n\t\t\tself._CHEETAH__filters[filterName] = ' - + 'getattr(self._CHEETAH__filtersLib, filterName)(self).filter') - self.dedent() - - def closeFilterBlock(self): - ID, filterDetails = self._filterRegionsStack.pop() - #self.addChunk('_filter = self._CHEETAH__initialFilter') - self.addChunk('_filter = _orig_filter%(ID)s'%locals()) - -class AutoMethodCompiler(MethodCompiler): - - def _setupState(self): - MethodCompiler._setupState(self) - self._argStringList = [ ("self",None) ] - self._streamingEnabled = True - - def _useKWsDictArgForPassingTrans(self): - alreadyHasTransArg = [argname for argname,defval in self._argStringList - if argname=='trans'] - return (self.methodName()!='respond' - and not alreadyHasTransArg - and self.setting('useKWsDictArgForPassingTrans')) - - def cleanupState(self): - MethodCompiler.cleanupState(self) - self.commitStrConst() - if self._cacheRegionsStack: - self.endCacheRegion() - if self._callRegionsStack: - self.endCallRegion() - - if self._streamingEnabled: - kwargsName = None - positionalArgsListName = None - for argname,defval in self._argStringList: - if argname.strip().startswith('**'): - kwargsName = argname.strip().replace('**','') - break - elif argname.strip().startswith('*'): - positionalArgsListName = argname.strip().replace('*','') - - if not kwargsName and self._useKWsDictArgForPassingTrans(): - kwargsName = 'KWS' - self.addMethArg('**KWS', None) - self._kwargsName = kwargsName - - if not self._useKWsDictArgForPassingTrans(): - if not kwargsName and not positionalArgsListName: - self.addMethArg('trans', 'None') - else: - self._streamingEnabled = False - - self._indentLev = self.setting('initialMethIndentLevel') - mainBodyChunks = self._methodBodyChunks - self._methodBodyChunks = [] - self._addAutoSetupCode() - self._methodBodyChunks.extend(mainBodyChunks) - self._addAutoCleanupCode() - - def _addAutoSetupCode(self): - if self._initialMethodComment: - self.addChunk(self._initialMethodComment) - - if self._streamingEnabled: - if self._useKWsDictArgForPassingTrans() and self._kwargsName: - self.addChunk('trans = %s.get("trans")'%self._kwargsName) - self.addChunk('if (not trans and not self._CHEETAH__isBuffering' - ' and not callable(self.transaction)):') - self.indent() - self.addChunk('trans = self.transaction' - ' # is None unless self.awake() was called') - self.dedent() - self.addChunk('if not trans:') - self.indent() - self.addChunk('trans = DummyTransaction()') - if self.setting('autoAssignDummyTransactionToSelf'): - self.addChunk('self.transaction = trans') - self.addChunk('_dummyTrans = True') - self.dedent() - self.addChunk('else: _dummyTrans = False') - else: - self.addChunk('trans = DummyTransaction()') - self.addChunk('_dummyTrans = True') - self.addChunk('write = trans.response().write') - if self.setting('useNameMapper'): - argNames = [arg[0] for arg in self._argStringList] - allowSearchListAsMethArg = self.setting('allowSearchListAsMethArg') - if allowSearchListAsMethArg and 'SL' in argNames: - pass - elif allowSearchListAsMethArg and 'searchList' in argNames: - self.addChunk('SL = searchList') - else: - self.addChunk('SL = self._CHEETAH__searchList') - if self.setting('useFilters'): - self.addChunk('_filter = self._CHEETAH__currentFilter') - self.addChunk('') - self.addChunk("#" *40) - self.addChunk('## START - generated method body') - self.addChunk('') - - def _addAutoCleanupCode(self): - self.addChunk('') - self.addChunk("#" *40) - self.addChunk('## END - generated method body') - self.addChunk('') - - if not self._isGenerator: - self.addStop() - self.addChunk('') - - def addStop(self, expr=None): - self.addChunk('return _dummyTrans and trans.response().getvalue() or ""') - - def addMethArg(self, name, defVal=None): - self._argStringList.append( (name,defVal) ) - - def methodSignature(self): - argStringChunks = [] - for arg in self._argStringList: - chunk = arg[0] - if not arg[1] == None: - chunk += '=' + arg[1] - argStringChunks.append(chunk) - argString = (', ').join(argStringChunks) - - output = [] - if self._decorator: - output.append(self._indent + self._decorator+'\n') - output.append(self._indent + "def " - + self.methodName() + "(" + - argString + "):\n\n") - return ''.join(output) - - -################################################## -## CLASS COMPILERS - -_initMethod_initCheetah = """\ -if not self._CHEETAH__instanceInitialized: - cheetahKWArgs = {} - allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split() - for k,v in KWs.items(): - if k in allowedKWs: cheetahKWArgs[k] = v - self._initCheetahInstance(**cheetahKWArgs) -""".replace('\n','\n'+' '*8) - -class ClassCompiler(GenUtils): - methodCompilerClass = AutoMethodCompiler - methodCompilerClassForInit = MethodCompiler - - def __init__(self, className, mainMethodName='respond', - moduleCompiler=None, - fileName=None, - settingsManager=None): - - self._settingsManager = settingsManager - self._fileName = fileName - self._className = className - self._moduleCompiler = moduleCompiler - self._mainMethodName = mainMethodName - self._setupState() - methodCompiler = self._spawnMethodCompiler( - mainMethodName, - initialMethodComment='## CHEETAH: main method generated for this template') - - self._setActiveMethodCompiler(methodCompiler) - if fileName and self.setting('monitorSrcFile'): - self._addSourceFileMonitoring(fileName) - - def setting(self, key): - return self._settingsManager.setting(key) - - def __getattr__(self, name): - """Provide access to the methods and attributes of the MethodCompiler - at the top of the activeMethods stack: one-way namespace sharing - - - WARNING: Use .setMethods to assign the attributes of the MethodCompiler - from the methods of this class!!! or you will be assigning to attributes - of this object instead.""" - - if self.__dict__.has_key(name): - return self.__dict__[name] - elif hasattr(self.__class__, name): - return getattr(self.__class__, name) - elif self._activeMethodsList and hasattr(self._activeMethodsList[-1], name): - return getattr(self._activeMethodsList[-1], name) - else: - raise AttributeError, name - - def _setupState(self): - self._classDef = None - self._decoratorForNextMethod = None - self._activeMethodsList = [] # stack while parsing/generating - self._finishedMethodsList = [] # store by order - self._methodsIndex = {} # store by name - self._baseClass = 'Template' - self._classDocStringLines = [] - # printed after methods in the gen class def: - self._generatedAttribs = ['_CHEETAH__instanceInitialized = False'] - self._generatedAttribs.append('_CHEETAH_version = __CHEETAH_version__') - self._generatedAttribs.append( - '_CHEETAH_versionTuple = __CHEETAH_versionTuple__') - self._generatedAttribs.append('_CHEETAH_genTime = __CHEETAH_genTime__') - self._generatedAttribs.append('_CHEETAH_genTimestamp = __CHEETAH_genTimestamp__') - self._generatedAttribs.append('_CHEETAH_src = __CHEETAH_src__') - self._generatedAttribs.append( - '_CHEETAH_srcLastModified = __CHEETAH_srcLastModified__') - - if self.setting('templateMetaclass'): - self._generatedAttribs.append('__metaclass__ = '+self.setting('templateMetaclass')) - self._initMethChunks = [] - self._blockMetaData = {} - self._errorCatcherCount = 0 - self._placeholderToErrorCatcherMap = {} - - def cleanupState(self): - while self._activeMethodsList: - methCompiler = self._popActiveMethodCompiler() - self._swallowMethodCompiler(methCompiler) - self._setupInitMethod() - if self._mainMethodName == 'respond': - if self.setting('setup__str__method'): - self._generatedAttribs.append('def __str__(self): return self.respond()') - self.addAttribute('_mainCheetahMethod_for_' + self._className + - '= ' + repr(self._mainMethodName) ) - - def _setupInitMethod(self): - __init__ = self._spawnMethodCompiler('__init__', - klass=self.methodCompilerClassForInit) - __init__.setMethodSignature("def __init__(self, *args, **KWs)") - __init__.addChunk("%s.__init__(self, *args, **KWs)" % self._baseClass) - __init__.addChunk(_initMethod_initCheetah%{'className':self._className}) - for chunk in self._initMethChunks: - __init__.addChunk(chunk) - __init__.cleanupState() - self._swallowMethodCompiler(__init__, pos=0) - - def _addSourceFileMonitoring(self, fileName): - # @@TR: this stuff needs auditing for Cheetah 2.0 - # the first bit is added to init - self.addChunkToInit('self._filePath = ' + repr(fileName)) - self.addChunkToInit('self._fileMtime = ' + str(getmtime(fileName)) ) - - # the rest is added to the main output method of the class ('mainMethod') - self.addChunk('if exists(self._filePath) and ' + - 'getmtime(self._filePath) > self._fileMtime:') - self.indent() - self.addChunk('self._compile(file=self._filePath, moduleName='+className + ')') - self.addChunk( - 'write(getattr(self, self._mainCheetahMethod_for_' + self._className + - ')(trans=trans))') - self.addStop() - self.dedent() - - def setClassName(self, name): - self._className = name - - def className(self): - return self._className - - def setBaseClass(self, baseClassName): - self._baseClass = baseClassName - - def setMainMethodName(self, methodName): - if methodName == self._mainMethodName: - return - ## change the name in the methodCompiler and add new reference - mainMethod = self._methodsIndex[self._mainMethodName] - mainMethod.setMethodName(methodName) - self._methodsIndex[methodName] = mainMethod - - ## make sure that fileUpdate code still works properly: - chunkToChange = ('write(self.' + self._mainMethodName + '(trans=trans))') - chunks = mainMethod._methodBodyChunks - if chunkToChange in chunks: - for i in range(len(chunks)): - if chunks[i] == chunkToChange: - chunks[i] = ('write(self.' + methodName + '(trans=trans))') - ## get rid of the old reference and update self._mainMethodName - del self._methodsIndex[self._mainMethodName] - self._mainMethodName = methodName - - def setMainMethodArgs(self, argsList): - mainMethodCompiler = self._methodsIndex[self._mainMethodName] - for argName, defVal in argsList: - mainMethodCompiler.addMethArg(argName, defVal) - - - def _spawnMethodCompiler(self, methodName, klass=None, - initialMethodComment=None): - if klass is None: - klass = self.methodCompilerClass - - decorator = None - if self._decoratorForNextMethod: - decorator = self._decoratorForNextMethod - self._decoratorForNextMethod = None - methodCompiler = klass(methodName, classCompiler=self, - decorator=decorator, - initialMethodComment=initialMethodComment) - self._methodsIndex[methodName] = methodCompiler - return methodCompiler - - def _setActiveMethodCompiler(self, methodCompiler): - self._activeMethodsList.append(methodCompiler) - - def _getActiveMethodCompiler(self): - return self._activeMethodsList[-1] - - def _popActiveMethodCompiler(self): - return self._activeMethodsList.pop() - - def _swallowMethodCompiler(self, methodCompiler, pos=None): - methodCompiler.cleanupState() - if pos==None: - self._finishedMethodsList.append( methodCompiler ) - else: - self._finishedMethodsList.insert(pos, methodCompiler) - return methodCompiler - - def startMethodDef(self, methodName, argsList, parserComment): - methodCompiler = self._spawnMethodCompiler( - methodName, initialMethodComment=parserComment) - self._setActiveMethodCompiler(methodCompiler) - for argName, defVal in argsList: - methodCompiler.addMethArg(argName, defVal) - - def _finishedMethods(self): - return self._finishedMethodsList - - def addDecorator(self, decoratorExpr): - """Set the decorator to be used with the next method in the source. - - See _spawnMethodCompiler() and MethodCompiler for the details of how - this is used. - """ - self._decoratorForNextMethod = decoratorExpr - - def addClassDocString(self, line): - self._classDocStringLines.append( line.replace('%','%%')) - - def addChunkToInit(self,chunk): - self._initMethChunks.append(chunk) - - def addAttribute(self, attribExpr): - ## first test to make sure that the user hasn't used any fancy Cheetah syntax - # (placeholders, directives, etc.) inside the expression - if attribExpr.find('VFN(') != -1 or attribExpr.find('VFFSL(') != -1: - raise ParseError(self, - 'Invalid #attr directive.' + - ' It should only contain simple Python literals.') - ## now add the attribute - self._generatedAttribs.append(attribExpr) - - - def addErrorCatcherCall(self, codeChunk, rawCode='', lineCol=''): - if self._placeholderToErrorCatcherMap.has_key(rawCode): - methodName = self._placeholderToErrorCatcherMap[rawCode] - if not self.setting('outputRowColComments'): - self._methodsIndex[methodName].addMethDocString( - 'plus at line %s, col %s'%lineCol) - return methodName - - self._errorCatcherCount += 1 - methodName = '__errorCatcher' + str(self._errorCatcherCount) - self._placeholderToErrorCatcherMap[rawCode] = methodName - - catcherMeth = self._spawnMethodCompiler( - methodName, - klass=MethodCompiler, - initialMethodComment=('## CHEETAH: Generated from ' + rawCode + - ' at line %s, col %s'%lineCol + '.') - ) - catcherMeth.setMethodSignature('def ' + methodName + - '(self, localsDict={})') - # is this use of localsDict right? - catcherMeth.addChunk('try:') - catcherMeth.indent() - catcherMeth.addChunk("return eval('''" + codeChunk + - "''', globals(), localsDict)") - catcherMeth.dedent() - catcherMeth.addChunk('except self._CHEETAH__errorCatcher.exceptions(), e:') - catcherMeth.indent() - catcherMeth.addChunk("return self._CHEETAH__errorCatcher.warn(exc_val=e, code= " + - repr(codeChunk) + " , rawCode= " + - repr(rawCode) + " , lineCol=" + str(lineCol) +")") - - catcherMeth.cleanupState() - - self._swallowMethodCompiler(catcherMeth) - return methodName - - def closeDef(self): - self.commitStrConst() - methCompiler = self._popActiveMethodCompiler() - self._swallowMethodCompiler(methCompiler) - - def closeBlock(self): - self.commitStrConst() - methCompiler = self._popActiveMethodCompiler() - methodName = methCompiler.methodName() - if self.setting('includeBlockMarkers'): - endMarker = self.setting('blockMarkerEnd') - methCompiler.addStrConst(endMarker[0] + methodName + endMarker[1]) - self._swallowMethodCompiler(methCompiler) - - #metaData = self._blockMetaData[methodName] - #rawDirective = metaData['raw'] - #lineCol = metaData['lineCol'] - - ## insert the code to call the block, caching if #cache directive is on - codeChunk = 'self.' + methodName + '(trans=trans)' - self.addChunk(codeChunk) - - #self.appendToPrevChunk(' # generated from ' + repr(rawDirective) ) - #if self.setting('outputRowColComments'): - # self.appendToPrevChunk(' at line %s, col %s' % lineCol + '.') - - - ## code wrapping methods - - def classDef(self): - if self._classDef: - return self._classDef - else: - return self.wrapClassDef() - - __str__ = classDef - - def wrapClassDef(self): - ind = self.setting('indentationStep') - classDefChunks = [self.classSignature(), - self.classDocstring(), - ] - def addMethods(): - classDefChunks.extend([ - ind + '#'*50, - ind + '## CHEETAH GENERATED METHODS', - '\n', - self.methodDefs(), - ]) - def addAttributes(): - classDefChunks.extend([ - ind + '#'*50, - ind + '## CHEETAH GENERATED ATTRIBUTES', - '\n', - self.attributes(), - ]) - if self.setting('outputMethodsBeforeAttributes'): - addMethods() - addAttributes() - else: - addAttributes() - addMethods() - - classDef = '\n'.join(classDefChunks) - self._classDef = classDef - return classDef - - - def classSignature(self): - return "class %s(%s):" % (self.className(), self._baseClass) - - def classDocstring(self): - if not self._classDocStringLines: - return '' - ind = self.setting('indentationStep') - docStr = ('%(ind)s"""\n%(ind)s' + - '\n%(ind)s'.join(self._classDocStringLines) + - '\n%(ind)s"""\n' - ) % {'ind':ind} - return docStr - - def methodDefs(self): - methodDefs = [str(methGen) for methGen in self._finishedMethods() ] - return '\n\n'.join(methodDefs) - - def attributes(self): - attribs = [self.setting('indentationStep') + str(attrib) - for attrib in self._generatedAttribs ] - return '\n\n'.join(attribs) - -class AutoClassCompiler(ClassCompiler): - pass - -################################################## -## MODULE COMPILERS - -class ModuleCompiler(SettingsManager, GenUtils): - - parserClass = Parser - classCompilerClass = AutoClassCompiler - - def __init__(self, source=None, file=None, - moduleName='DynamicallyCompiledCheetahTemplate', - mainClassName=None, # string - mainMethodName=None, # string - baseclassName=None, # string - extraImportStatements=None, # list of strings - settings=None # dict - ): - SettingsManager.__init__(self) - if settings: - self.updateSettings(settings) - # disable useStackFrames if the C version of NameMapper isn't compiled - # it's painfully slow in the Python version and bites Windows users all - # the time: - if not NameMapper.C_VERSION: - # disable warning noise as Cobbler is noarch, hence no C version -- mdehaan - # - # if not sys.platform.startswith('java'): - # warnings.warn( - # "\nYou don't have the C version of NameMapper installed! " - # "I'm disabling Cheetah's useStackFrames option as it is " - # "painfully slow with the Python version of NameMapper. " - # "You should get a copy of Cheetah with the compiled C version of NameMapper." - # ) - self.setSetting('useStackFrames', False) - - self._compiled = False - self._moduleName = moduleName - if not mainClassName: - self._mainClassName = moduleName - else: - self._mainClassName = mainClassName - self._mainMethodNameArg = mainMethodName - if mainMethodName: - self.setSetting('mainMethodName', mainMethodName) - self._baseclassName = baseclassName - - self._filePath = None - self._fileMtime = None - - if source and file: - raise TypeError("Cannot compile from a source string AND file.") - elif isinstance(file, types.StringType) or isinstance(file, types.UnicodeType): # it's a filename. - - f = open(file) # Raises IOError. - source = f.read() - f.close() - self._filePath = file - self._fileMtime = os.path.getmtime(file) - elif hasattr(file, 'read'): - source = file.read() # Can't set filename or mtime--they're not accessible. - elif file: - raise TypeError("'file' argument must be a filename string or file-like object") - - - if self._filePath: - self._fileDirName, self._fileBaseName = os.path.split(self._filePath) - self._fileBaseNameRoot, self._fileBaseNameExt = \ - os.path.splitext(self._fileBaseName) - - if not (isinstance(source, str) or isinstance(source, unicode)): - source = str( source ) - # by converting to string here we allow objects such as other Templates - # to be passed in - - # Handle the #indent directive by converting it to other directives. - # (Over the long term we'll make it a real directive.) - if source == "": - warnings.warn("You supplied an empty string for the source!", ) - - if source.find('#indent') != -1: #@@TR: undocumented hack - source = indentize(source) - - self._parser = self.parserClass(source, filename=self._filePath, compiler=self) - self._setupCompilerState() - - def __getattr__(self, name): - """Provide one-way access to the methods and attributes of the - ClassCompiler, and thereby the MethodCompilers as well. - - WARNING: Use .setMethods to assign the attributes of the ClassCompiler - from the methods of this class!!! or you will be assigning to attributes - of this object instead. - """ - if self.__dict__.has_key(name): - return self.__dict__[name] - elif hasattr(self.__class__, name): - return getattr(self.__class__, name) - elif self._activeClassesList and hasattr(self._activeClassesList[-1], name): - return getattr(self._activeClassesList[-1], name) - else: - raise AttributeError, name - - def _initializeSettings(self): - self.updateSettings(copy.deepcopy(DEFAULT_COMPILER_SETTINGS)) - - def _setupCompilerState(self): - self._activeClassesList = [] - self._finishedClassesList = [] # listed by ordered - self._finishedClassIndex = {} # listed by name - self._moduleDef = None - self._moduleShBang = '#!/usr/bin/env python' - self._moduleEncoding = 'ascii' - self._moduleEncodingStr = '' - self._moduleHeaderLines = [] - self._moduleDocStringLines = [] - self._specialVars = {} - self._importStatements = [ - "import sys", - "import os", - "import os.path", - "from os.path import getmtime, exists", - "import time", - "import types", - "import __builtin__", - "from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion", - "from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple", - "from Cheetah.Template import Template", - "from Cheetah.DummyTransaction import DummyTransaction", - "from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList", - "from Cheetah.CacheRegion import CacheRegion", - "import Cheetah.Filters as Filters", - "import Cheetah.ErrorCatchers as ErrorCatchers", - ] - - self._importedVarNames = ['sys', - 'os', - 'os.path', - 'time', - 'types', - 'Template', - 'DummyTransaction', - 'NotFound', - 'Filters', - 'ErrorCatchers', - 'CacheRegion', - ] - - self._moduleConstants = [ - "try:", - " True, False", - "except NameError:", - " True, False = (1==1), (1==0)", - "VFFSL=valueFromFrameOrSearchList", - "VFSL=valueFromSearchList", - "VFN=valueForName", - "currentTime=time.time", - ] - - def compile(self): - classCompiler = self._spawnClassCompiler(self._mainClassName) - if self._baseclassName: - classCompiler.setBaseClass(self._baseclassName) - self._addActiveClassCompiler(classCompiler) - self._parser.parse() - self._swallowClassCompiler(self._popActiveClassCompiler()) - self._compiled = True - self._parser.cleanup() - - def _spawnClassCompiler(self, className, klass=None): - if klass is None: - klass = self.classCompilerClass - classCompiler = klass(className, - moduleCompiler=self, - mainMethodName=self.setting('mainMethodName'), - fileName=self._filePath, - settingsManager=self, - ) - return classCompiler - - def _addActiveClassCompiler(self, classCompiler): - self._activeClassesList.append(classCompiler) - - def _getActiveClassCompiler(self): - return self._activeClassesList[-1] - - def _popActiveClassCompiler(self): - return self._activeClassesList.pop() - - def _swallowClassCompiler(self, classCompiler): - classCompiler.cleanupState() - self._finishedClassesList.append( classCompiler ) - self._finishedClassIndex[classCompiler.className()] = classCompiler - return classCompiler - - def _finishedClasses(self): - return self._finishedClassesList - - def importedVarNames(self): - return self._importedVarNames - - def addImportedVarNames(self, varNames): - self._importedVarNames.extend(varNames) - - ## methods for adding stuff to the module and class definitions - - def setBaseClass(self, baseClassName): - if self._mainMethodNameArg: - self.setMainMethodName(self._mainMethodNameArg) - else: - self.setMainMethodName(self.setting('mainMethodNameForSubclasses')) - - if self.setting('handlerForExtendsDirective'): - handler = self.setting('handlerForExtendsDirective') - baseClassName = handler(compiler=self, baseClassName=baseClassName) - self._getActiveClassCompiler().setBaseClass(baseClassName) - elif (not self.setting('autoImportForExtendsDirective') - or baseClassName=='object' or baseClassName in self.importedVarNames()): - self._getActiveClassCompiler().setBaseClass(baseClassName) - # no need to import - else: - ################################################## - ## If the #extends directive contains a classname or modulename that isn't - # in self.importedVarNames() already, we assume that we need to add - # an implied 'from ModName import ClassName' where ModName == ClassName. - # - This is the case in WebKit servlet modules. - # - We also assume that the final . separates the classname from the - # module name. This might break if people do something really fancy - # with their dots and namespaces. - chunks = baseClassName.split('.') - if len(chunks)==1: - self._getActiveClassCompiler().setBaseClass(baseClassName) - if baseClassName not in self.importedVarNames(): - modName = baseClassName - # we assume the class name to be the module name - # and that it's not a builtin: - importStatement = "from %s import %s" % (modName, baseClassName) - self.addImportStatement(importStatement) - self.addImportedVarNames( [baseClassName,] ) - else: - needToAddImport = True - modName = chunks[0] - #print chunks, ':', self.importedVarNames() - for chunk in chunks[1:-1]: - if modName in self.importedVarNames(): - needToAddImport = False - finalBaseClassName = baseClassName.replace(modName+'.', '') - self._getActiveClassCompiler().setBaseClass(finalBaseClassName) - break - else: - modName += '.'+chunk - if needToAddImport: - modName, finalClassName = '.'.join(chunks[:-1]), chunks[-1] - #if finalClassName != chunks[:-1][-1]: - if finalClassName != chunks[-2]: - # we assume the class name to be the module name - modName = '.'.join(chunks) - self._getActiveClassCompiler().setBaseClass(finalClassName) - importStatement = "from %s import %s" % (modName, finalClassName) - self.addImportStatement(importStatement) - self.addImportedVarNames( [finalClassName,] ) - - def setCompilerSetting(self, key, valueExpr): - self.setSetting(key, eval(valueExpr) ) - self._parser.configureParser() - - def setCompilerSettings(self, keywords, settingsStr): - KWs = keywords - merge = True - if 'nomerge' in KWs: - merge = False - - if 'reset' in KWs: - # @@TR: this is actually caught by the parser at the moment. - # subject to change in the future - self._initializeSettings() - self._parser.configureParser() - return - elif 'python' in KWs: - settingsReader = self.updateSettingsFromPySrcStr - # this comes from SettingsManager - else: - # this comes from SettingsManager - settingsReader = self.updateSettingsFromConfigStr - - settingsReader(settingsStr) - self._parser.configureParser() - - def setShBang(self, shBang): - self._moduleShBang = shBang - - def setModuleEncoding(self, encoding): - self._moduleEncoding = encoding - self._moduleEncodingStr = '# -*- coding: %s -*-' %encoding - - def getModuleEncoding(self): - return self._moduleEncoding - - def addModuleHeader(self, line): - """Adds a header comment to the top of the generated module. - """ - self._moduleHeaderLines.append(line) - - def addModuleDocString(self, line): - """Adds a line to the generated module docstring. - """ - self._moduleDocStringLines.append(line) - - def addModuleGlobal(self, line): - """Adds a line of global module code. It is inserted after the import - statements and Cheetah default module constants. - """ - self._moduleConstants.append(line) - - def addSpecialVar(self, basename, contents, includeUnderscores=True): - """Adds module __specialConstant__ to the module globals. - """ - name = includeUnderscores and '__'+basename+'__' or basename - self._specialVars[name] = contents.strip() - - def addImportStatement(self, impStatement): - self._importStatements.append(impStatement) - - #@@TR 2005-01-01: there's almost certainly a cleaner way to do this! - importVarNames = impStatement[impStatement.find('import') + len('import'):].split(',') - importVarNames = [var.split()[-1] for var in importVarNames] # handles aliases - importVarNames = [var for var in importVarNames if var!='*'] - self.addImportedVarNames(importVarNames) #used by #extend for auto-imports - - def addAttribute(self, attribName, expr): - self._getActiveClassCompiler().addAttribute(attribName + ' =' + expr) - - def addComment(self, comm): - if re.match(r'#+$',comm): # skip bar comments - return - - specialVarMatch = specialVarRE.match(comm) - if specialVarMatch: - # @@TR: this is a bit hackish and is being replaced with - # #set module varName = ... - return self.addSpecialVar(specialVarMatch.group(1), - comm[specialVarMatch.end():]) - elif comm.startswith('doc:'): - addLine = self.addMethDocString - comm = comm[len('doc:'):].strip() - elif comm.startswith('doc-method:'): - addLine = self.addMethDocString - comm = comm[len('doc-method:'):].strip() - elif comm.startswith('doc-module:'): - addLine = self.addModuleDocString - comm = comm[len('doc-module:'):].strip() - elif comm.startswith('doc-class:'): - addLine = self.addClassDocString - comm = comm[len('doc-class:'):].strip() - elif comm.startswith('header:'): - addLine = self.addModuleHeader - comm = comm[len('header:'):].strip() - else: - addLine = self.addMethComment - - for line in comm.splitlines(): - addLine(line) - - ## methods for module code wrapping - - def getModuleCode(self): - if not self._compiled: - self.compile() - if self._moduleDef: - return self._moduleDef - else: - return self.wrapModuleDef() - - __str__ = getModuleCode - - def wrapModuleDef(self): - self.addSpecialVar('CHEETAH_docstring', self.setting('defDocStrMsg')) - self.addModuleGlobal('__CHEETAH_version__ = %r'%Version) - self.addModuleGlobal('__CHEETAH_versionTuple__ = %r'%(VersionTuple,)) - self.addModuleGlobal('__CHEETAH_genTime__ = %r'%time.time()) - self.addModuleGlobal('__CHEETAH_genTimestamp__ = %r'%self.timestamp()) - if self._filePath: - timestamp = self.timestamp(self._fileMtime) - self.addModuleGlobal('__CHEETAH_src__ = %r'%self._filePath) - self.addModuleGlobal('__CHEETAH_srcLastModified__ = %r'%timestamp) - else: - self.addModuleGlobal('__CHEETAH_src__ = None') - self.addModuleGlobal('__CHEETAH_srcLastModified__ = None') - - moduleDef = """%(header)s -%(docstring)s - -################################################## -## DEPENDENCIES -%(imports)s - -################################################## -## MODULE CONSTANTS -%(constants)s -%(specialVars)s - -if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple: - raise AssertionError( - 'This template was compiled with Cheetah version' - ' %%s. Templates compiled before version %%s must be recompiled.'%%( - __CHEETAH_version__, RequiredCheetahVersion)) - -################################################## -## CLASSES - -%(classes)s - -## END CLASS DEFINITION - -if not hasattr(%(mainClassName)s, '_initCheetahAttributes'): - templateAPIClass = getattr(%(mainClassName)s, '_CHEETAH_templateClass', Template) - templateAPIClass._addCheetahPlumbingCodeToClass(%(mainClassName)s) - -%(footer)s -""" % {'header':self.moduleHeader(), - 'docstring':self.moduleDocstring(), - 'specialVars':self.specialVars(), - 'imports':self.importStatements(), - 'constants':self.moduleConstants(), - 'classes':self.classDefs(), - 'footer':self.moduleFooter(), - 'mainClassName':self._mainClassName, - } - - self._moduleDef = moduleDef - return moduleDef - - def timestamp(self, theTime=None): - if not theTime: - theTime = time.time() - return time.asctime(time.localtime(theTime)) - - def moduleHeader(self): - header = self._moduleShBang + '\n' - header += self._moduleEncodingStr + '\n' - if self._moduleHeaderLines: - offSet = self.setting('commentOffset') - - header += ( - '#' + ' '*offSet + - ('\n#'+ ' '*offSet).join(self._moduleHeaderLines) + '\n') - - return header - - def moduleDocstring(self): - if not self._moduleDocStringLines: - return '' - - return ('"""' + - '\n'.join(self._moduleDocStringLines) + - '\n"""\n') - - def specialVars(self): - chunks = [] - theVars = self._specialVars - keys = theVars.keys() - keys.sort() - for key in keys: - chunks.append(key + ' = ' + repr(theVars[key]) ) - return '\n'.join(chunks) - - def importStatements(self): - return '\n'.join(self._importStatements) - - def moduleConstants(self): - return '\n'.join(self._moduleConstants) - - def classDefs(self): - classDefs = [str(klass) for klass in self._finishedClasses() ] - return '\n\n'.join(classDefs) - - def moduleFooter(self): - return """ -# CHEETAH was developed by Tavis Rudd and Mike Orr -# with code, advice and input from many other volunteers. -# For more information visit http://www.CheetahTemplate.org/ - -################################################## -## if run from command line: -if __name__ == '__main__': - from Cheetah.TemplateCmdLineIface import CmdLineIface - CmdLineIface(templateObj=%(className)s()).run() - -""" % {'className':self._mainClassName} - - -################################################## -## Make Compiler an alias for ModuleCompiler - -Compiler = ModuleCompiler diff --git a/cobbler/action_import.py b/cobbler/action_import.py index 8afbabd..f58bfd9 100644 --- a/cobbler/action_import.py +++ b/cobbler/action_import.py @@ -79,7 +79,10 @@ class Importer: os.path.walk(self.path, self.walker, None) - self.guess_kickstarts() + self.guess_kickstarts() + + self.api.sync() + return True # ---------------------------------------------------------------------- diff --git a/cobbler/cobbler_msg.py b/cobbler/cobbler_msg.py index 6396706..4212502 100644 --- a/cobbler/cobbler_msg.py +++ b/cobbler/cobbler_msg.py @@ -35,7 +35,7 @@ cobbler system add --name=<ip│mac│hostname|default> --profile=<string> cobbler import --name=<string> --mirror=rsync://<address> cobbler import --name=<string> --mirror=user@address:/path -cobbler import --path=<path> +cobbler import --name=<string> --mirror=<path> cobbler repo add --name=<string> --mirror=rsync://<address> [--local-file=name] cobbler repo add --name=<string> --mirror=user@address:/path [--local-file=name] |