Source code for httk.core.template

#
#    The high-throughput toolkit (httk)
#    Copyright (C) 2012-2015 Rickard Armiento
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
import shlex, os, sys, shutil
from string import Template
from httk.core.basic import mkdir_p

if sys.version_info[0] == 3:
    from io import StringIO
else:
    from StringIO import StringIO

[docs]def apply_template(template, output, envglobals=None, envlocals=None): """ Simple Python template engine. The file 'template' is turned into a new file 'output' replacing the following: $name -> the value of the variable 'name' in the scope provided by locals and globals. $(python statement) -> result of evaluating the python statment. ${some python code} -> text on stdout from running that python code. Note: it is safe for the code inside the template to load the file it eventually will replace. """ if envlocals is None: envlocals = {} else: envlocals = envlocals.copy() if envglobals is None: envglobals = {} else: envglobals = envglobals.copy() # Read template and substitute $name entries template_file = open(template, 'r') ## shlex does not work with unicode, hence the .encode('ascii') to make sure the result is not unicode # Henrik added: These days it looks like we don't need the ascii encoding anymore. result_step1 = Template(Template(template_file.read()).safe_substitute( envlocals)).safe_substitute(envglobals)#.encode('ascii') template_file.close() # Substitute $(some python code) entries result_step2 = '' lexer = shlex.shlex(result_step1) lexer.whitespace = '' eval_nesting = 0 exec_nesting = 0 for token in lexer: if(eval_nesting == 0 and exec_nesting == 0): if(token == '\\'): token += lexer.get_token() if(token == '$'): token += lexer.get_token() if(token == '$('): # eval command eval_nesting = 1 command = '' continue if(token == '${'): # exec command exec_nesting = 1 command = '' continue if(token == '\\$'): # escaped $ -> send $ to output token = '$' result_step2 += token elif(exec_nesting != 0): if(token == '{'): exec_nesting += 1 if(token == '}'): exec_nesting -= 1 if(exec_nesting == 0): sys.stdout = StringIO() try: exec(command, envglobals, envlocals) except: print("Failed to execute:"+command) raise result_step2 += sys.stdout.getvalue() if result_step2.endswith('\n'): result_step2 = result_step2[:-1] sys.stdout = sys.__stdout__ continue command += token elif(eval_nesting != 0): if(token == '('): eval_nesting += 1 if(token == ')'): eval_nesting -= 1 if(eval_nesting == 0): try: result_step2 += str(eval(command, envglobals, envlocals)) except: print("Failed to eval:"+command) raise continue command += token # Write output, but first remove file if it already exists, this is done explicitly # to handle symlinks in a sane way; i.e., they are replaced by the instantiated template, # and the file the symlink is pointing at is NOT changed. if os.path.exists(output): os.remove(output) output_file = open(output, 'w') output_file.write(result_step2) output_file.close()
[docs]def apply_templates(inputpath, outpath, template_suffixes="template", envglobals=None, envlocals=None, mkdir=True): """ Apply one or a series of templates throughout directory tree. template_suffixes: string or list of strings that are the suffixes of templates that are to be applied. name: subdirectory in which to apply the template, defaults to last subrun created, or '.' if no subrun have been created. """ if not os.path.exists(inputpath): raise Exception("apply_templates: template does not exist") if mkdir: os.mkdir(outpath) # Make sure template_suffixies is a list so we can iterate over it if isinstance(template_suffixes, str): template_suffixes = [template_suffixes] # Loop over all files in the directory tree and run all templates that are found #main_path = os.getcwd() #print("Looping over",inputpath) for root, dirs, files in os.walk(inputpath): for filename in files: for suffix in template_suffixes: rp = os.path.relpath(root, inputpath) if rp == '.': rp = '' else: mkdir_p(os.path.join(outpath, rp)) if(filename.endswith("."+suffix)): newname = filename[:-len("."+suffix)] #os.chdir(os.path.join("./",outpath,root)) #mkdir_p(os.path.dirname(newname)) #apply_template("./"+filename,"./"+newname,locals,envglobals=None,envlocals=None) #os.chdir(path) apply_template(os.path.join(root, filename), os.path.join(outpath, rp, newname), envglobals=envglobals, envlocals=envlocals) shutil.copymode(os.path.join(root, filename), os.path.join(outpath, rp, newname)) #print("Instanceiate",os.path.join(root,filename),os.path.join(outpath,rp,newname)) else: #print("Copy",shutil.copyfile(os.path.join(root,filename),os.path.join(outpath,rp,filename)) ) shutil.copy(os.path.join(root, filename), os.path.join(outpath, rp, filename))
#os.chdir(main_path)