#!/usr/bin/env python # -*- coding: iso-8859-15 -*- ''' /* Copyright 2007, Jose Rodriguez (a.k.a. Boriel), http://www.boriel.com ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 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 General Public License for more details. ** ** You can read it at: http://www.gnu.org/copyleft/gpl.html or ** write to the Free Software Foundation, Inc., 59 Temple Place, ** Suite 330, Boston, MA 02111-1307 USA */ ''' import tempfile, os from subprocess import Popen, PIPE from types import * # Dictionary containing PERL5LIB path for each function __PERL5LIB = {} # Default PERL include PATH __DEFAULT_PERL5LIB = '.' # Executes system command and captures output def sys_exec(cmd, shell = True, env = None): if env is None: env = os.environ a = Popen(cmd, shell = shell, stdout = PIPE, stderr = PIPE, env = env) a.wait() # Wait process to terminate if a.returncode: # Not 0 => Error raise a.communicate()[1] return a.communicate()[0] # Perl path PERL = sys_exec('which perl').strip(' \t\n\r') # Set to True to leave the tmp file (for debug) DEBUG = False def perlargs(*args): def perl_elem(x): if x is None: return 'undef' t = type(x) if t == StringType or t == UnicodeType: return "'%s'" % str(x).replace("'", "\\'") return str(x) def perl_vector(vec): sep = result = '' for i in vec: t = type(i) result += sep if t == ListType: result += '[' + perl_vector(i) + ']' elif t == DictType: result += '{' + perl_dict(i) + '}' else: result += perl_elem(i) sep = ', ' return result def perl_dict(vec): sep = result = '' for i in vec.keys(): t = type(vec[i]) result += sep + str(i) + ' => ' if t == ListType: result += '[' + perl_vector(i) + ']' elif t == DictType: result += '{' + perl_dict(i) + '}' else: result += perl_elem(i) sep = ', ' return result sep = '' result = '(' for i in args: t = type(i) result += sep if t == DictType: result += '(' + perl_dict(i) + ')' elif t == ListType: result += '(' + perl_vector(i) + ')' else: result += perl_elem(i) sep = ', ' result += ')' return result # Decorator which allows to call a perl function from python def perlfunc(fn): def new(*args): # tmppipe, pipename = tempfile.mkstemp('.pipe', 'tmp_', '/tmp', True) os.close(tmppipe) tmpfile, tmpname = tempfile.mkstemp('.pl', 'tmp_', '/tmp', True) os.write(tmpfile, fn.func_doc) # Writes the perl code os.write(tmpfile, r''' { my @rst; my $len; my $i; open(DAT, ">''' + pipename + '''") || die("Cannot Open File for communication"); @rst = (%s%s); if (defined(@rst)) { $len = @rst; } else { $len = 0; print DAT 'None'; } if ($len > 1) { print DAT '['; } for ($i = 0; $i < $len; $i++) { if ($i) { print DAT ', '; } $rst[$i] =~ s/\'/\\\'/g; print DAT "'" . $rst[$i] . "'"; } if ($len > 1) { print DAT ']'; } close(DAT); } ''' % (fn.func_name, perlargs(*args))) os.close(tmpfile) try: env = os.environ # Get OS environment vars env['PERL5LIB'] = __PERL5LIB[fn.func_name] # Adds our PERL5LIB if defined except KeyError: env = os.environ env['PERL5LIB'] = __DEFAULT_PERL5LIB # Eval perl code result_stdout = sys_exec([PERL] + [tmpname], False, env = env) print 'STDOUT:', result_stdout pipe = open(pipename, 'r') result_str = pipe.read() pipe.close() try: result = eval(result_str) except: result = result_str # Erases tmp file if not DEBUG: os.unlink(tmpname) os.unlink(pipename) return result return new # Decorated function # Decorator which adds perl includes def perlreq(*modules): def require_inc(fn): def new(*args): return fn(*args) new.func_name = fn.func_name new.func_doc = fn.func_doc if new.func_doc is None: new.func_doc = '' for i in modules: new.func_doc = 'require(\'%s\');\n' % i + new.func_doc return new return require_inc # Decorator which changes perl includepath def perl5lib(*paths): def include_fun(fn): global __PERL5LIB def new(*args): return fn(*args) new.func_name = fn.func_name new.func_doc = fn.func_doc try: PATH = __PERL5LIB[fn.func_name] + ':' except KeyError: # Not defined in __PERL5LIB yet PATH = '' __PERL5LIB[fn.func_name] = PATH + ':'.join(paths) return new return include_fun