diff --git a/CoTeTo/CLI.py b/CoTeTo/CLI.py index a45817b..738085d 100644 --- a/CoTeTo/CLI.py +++ b/CoTeTo/CLI.py @@ -82,24 +82,18 @@ def main(): elif args.data_source: # execute the generator - o = g.execute(args.data_source) - if len(o) == 1: - # single file output - ext = list(o.keys())[0] - if args.output: - outFile = open(args.output[0] + ext, 'w') - outFile.write(o[ext].read()) - outFile.close() - else: - sys.stdout.write(o[ext].read()) + if args.output: + # output to files: let the generator handle file saving + g.execute(args.data_source, args.output[0]) else: - # multi file output - if args.output: - for ext in o: - outFile = open(args.output[0] + ext, 'w') - outFile.write(o[ext].read()) - outFile.close() + # print to stdout + o = g.execute(args.data_source) + if len(o) == 1: + # single file output + ext = list(o.keys())[0] + sys.stdout.write(o[ext].read()) else: + # files separated by a line for ext in o: sys.stdout.write('### FILE: %s\n' % ext) sys.stdout.write(o[ext].read()) diff --git a/CoTeTo/GUI.py b/CoTeTo/GUI.py index 99fd615..b124315 100644 --- a/CoTeTo/GUI.py +++ b/CoTeTo/GUI.py @@ -266,15 +266,11 @@ def executeGenerator(self): self.outputInput.setText(outputBase) if not os.path.isabs(outputBase): outputBase = os.path.abspath(outputBase) - x = self.activeGenerator.execute(uriList) - for ext in x: - outputFile = outputBase + ext - o = open(outputFile, 'w') - o.write(x[ext].read()) - o.close() - if self.openOutputButton.isChecked(): - QtGui.QDesktopServices.openUrl(QtCore.QUrl.fromLocalFile(outputFile)) - + x = self.activeGenerator.execute(uriList, outputBase) + if self.openOutputButton.isChecked(): + for ext in x: + QtGui.QDesktopServices.openUrl(QtCore.QUrl.fromLocalFile(x[ext])) + def closeEvent(self, e): # first reset output streams to standard settings XStream.reset() diff --git a/CoTeTo/Generator.py b/CoTeTo/Generator.py index 303df3c..fa9ba2a 100644 --- a/CoTeTo/Generator.py +++ b/CoTeTo/Generator.py @@ -186,19 +186,41 @@ def executeFilter(self): function = getattr(module, functionName) function(self.data, self.controller.systemCfg, self.cfg, self.logger) - def executeTemplates(self): - """execeute all templates, return the output buffers and extensions""" + def executeTemplates(self, outputBasename=None): + """execeute all templates, return the output buffers and extensions - + if outputBasename is given, save file and return file names instead of the buffers""" tmpls = sorted([s for s in self.cfg.sections() if s.upper().startswith('TEMPLATE')]) - txt = {} + res = {} for tmpl in tmpls: ext = self.cfg[tmpl].get('ext', '') - if ext in txt: - while ext in txt: + if ext in res: + while ext in res: ext.append('X') self.logger.error('GEN | file extension already exists, using %s!' % ext) self.logger.debug('GEN | processing template setup ' + tmpl) - txt[ext] = self.executeTemplate(tmpl) - return txt + buf = self.executeTemplate(tmpl) + if outputBasename is None: + # return buffer + res[ext] = buf + if self.cfg[tmpl].get('postExec', ''): + self.logger.error('GEN | postExec defined but saving to buffer instead of file: skipping postExec in ' + tmpl) + else: + # save file and return file name + fname = outputBasename + ext + o = open(fname, 'w') + o.write(buf.read()) + o.close() + # buf.close() ? + res[ext] = fname + # post execution cmd? + cmd = self.cfg[tmpl].get('postExec', '') + if cmd: + self.logger.debug('GEN | starting postExec command: %s: ', cmd) + try: + exec(cmd, globals(), locals()) + except BaseException: + self.logger.exception('GEN | error during postExec: %s: ', cmd) + return res def executeTemplate(self, name): """execeute a single template with the data, return the output buffer""" @@ -230,7 +252,7 @@ def executeTemplate(self, name): else: raise Exception('Unknown template system: ' + tmplType) - def execute(self, uriList=[]): + def execute(self, uriList=[], outputBasename = None): if not self.loader: raise Exception('Generator is not valid - canceling execution!') # fill data model from the loader using the data URIs @@ -238,8 +260,9 @@ def execute(self, uriList=[]): # apply filter if self.cfg.has_section('FILTER'): self.executeFilter() - # handle data to template, return text buffer - return self.executeTemplates() + # handle data to templates, return text buffers or file names + return self.executeTemplates(outputBasename) + # make the generator executable __call__ = execute diff --git a/Generators/TestPostExec/Filters/Filter01.py b/Generators/TestPostExec/Filters/Filter01.py new file mode 100644 index 0000000..d426454 --- /dev/null +++ b/Generators/TestPostExec/Filters/Filter01.py @@ -0,0 +1,21 @@ +# a filter function is called with the following arguments: +# d - the data dictionary read from the loader +# systemCfg - system configuration +# generatorCfg - generator configuration +# logger - a logger instance + + +def filter01(d, systemCfg, generatorCfg, logger): + + # spread a message + logger.debug('hi there! This is a filter running from module: ' + __file__) + + x = d['dummy'] + + # manipulate some data + x['foo'] += 1 + + # add more data + x['bar'] = 2.0 * x['foo'] + + # no return needed - data is manipulated inplace diff --git a/Generators/TestPostExec/Package.inf b/Generators/TestPostExec/Package.inf new file mode 100644 index 0000000..f39e17f --- /dev/null +++ b/Generators/TestPostExec/Package.inf @@ -0,0 +1,22 @@ +[GENERATOR] +name = TestPostExec +version = 0.1 +description = test the post execution feature +author = Joerg Raedler jraedler@udk-berlin.de + +[LOADER] +name = TestDummy +minVer = 0.1 +maxVer = 2.0 + +[FILTER] +module = Filter01 +function = filter01 + +[TEMPLATE] +topFile = Main.mako +type = mako +# be VERY carefull with the postexec feature, it has complete access +# to the whole namespace and will run this code without checking! +# You can use "fname" to access the name of the generated file +postExec = os.system("dir "+fname) diff --git a/Generators/TestPostExec/Templates/Main.mako b/Generators/TestPostExec/Templates/Main.mako new file mode 100644 index 0000000..fed1400 --- /dev/null +++ b/Generators/TestPostExec/Templates/Main.mako @@ -0,0 +1,14 @@ +# +# CoTeTo +# Version: ${systemCfg['version']} +# Platform: ${systemCfg['platform']} +# Path: ${systemCfg['path']} +# Gen-Path: ${', '.join(systemCfg['generatorPath'])} +# +# Generator +# Name: ${generatorCfg['GENERATOR'].get('name')} +# Version: ${generatorCfg['GENERATOR'].get('version')} + +The value of foo is ${d['dummy']['foo']}. + +<%include file="Sub.mako"/> diff --git a/Generators/TestPostExec/Templates/Sub.mako b/Generators/TestPostExec/Templates/Sub.mako new file mode 100644 index 0000000..c082879 --- /dev/null +++ b/Generators/TestPostExec/Templates/Sub.mako @@ -0,0 +1,2 @@ +Hello, I'm a sub template! +bar = ${d['dummy']['bar']}