1919
2020class ExternalRuntime (AbstractRuntime ):
2121 '''Runtime to execute codes with external command.'''
22- def __init__ (self , name , command , runner_source , encoding = 'utf8' ):
22+ def __init__ (self , name , command , runner_source , encoding = 'utf8' , tempfile = False ):
2323 self ._name = name
2424 if isinstance (command , str ):
2525 command = [command ]
2626 self ._command = command
2727 self ._runner_source = runner_source
2828 self ._encoding = encoding
29+ self ._tempfile = tempfile
2930
3031 self ._available = self ._binary () is not None
3132
@@ -43,7 +44,7 @@ def is_available(self):
4344 return self ._available
4445
4546 def _compile (self , source , cwd = None ):
46- return self .Context (self , source , cwd = cwd )
47+ return self .Context (self , source , cwd = cwd , tempfile = tempfile )
4748
4849 def _binary (self ):
4950 if not hasattr (self , "_binary_cache" ):
@@ -53,10 +54,11 @@ def _binary(self):
5354 class Context (AbstractRuntimeContext ):
5455 # protected
5556
56- def __init__ (self , runtime , source = '' , cwd = None ):
57+ def __init__ (self , runtime , source = '' , cwd = None , tempfile = False ):
5758 self ._runtime = runtime
5859 self ._source = source
5960 self ._cwd = cwd
61+ self ._tempfile = tempfile
6062
6163 def is_available (self ):
6264 return self ._runtime .is_available ()
@@ -74,35 +76,53 @@ def _exec_(self, source):
7476 if self ._source :
7577 source = self ._source + '\n ' + source
7678
77- (fd , filename ) = tempfile .mkstemp (prefix = 'execjs' , suffix = '.js' )
78- os .close (fd )
79- try :
80- with io .open (filename , "w+" , encoding = self ._runtime ._encoding ) as fp :
81- fp .write (self ._compile (source ))
82- output = self ._execfile (filename )
83- finally :
84- os .remove (filename )
85-
79+ if self ._tempfile :
80+ output = self ._exec_with_tempfile (source )
81+ else :
82+ output = self ._exec_with_pipe (source )
8683 return self ._extract_result (output )
8784
8885 def _call (self , identifier , * args ):
8986 args = json .dumps (args )
90- return self .eval ("{identifier}.apply(this, {args})" .format (identifier = identifier , args = args ))
87+ return self ._eval ("{identifier}.apply(this, {args})" .format (identifier = identifier , args = args ))
9188
92- def _execfile (self , filename ):
93- cmd = self ._runtime ._binary () + [ filename ]
89+ def _exec_with_pipe (self , source ):
90+ cmd = self ._runtime ._binary ()
9491
9592 p = None
9693 try :
97- p = Popen (cmd , stdout = PIPE , stderr = PIPE , cwd = self ._cwd )
98- stdoutdata , stderrdata = p .communicate ()
94+ p = Popen (cmd , stdin = PIPE , stdout = PIPE , stderr = PIPE , cwd = self ._cwd , universal_newlines = True )
95+ stdoutdata , stderrdata = p .communicate (input = source )
9996 ret = p .wait ()
10097 finally :
10198 del p
10299
103- if ret == 0 :
100+ self ._fail_on_non_zero_status (ret , stdoutdata , stderrdata )
101+ return stdoutdata
102+
103+ def _exec_with_tempfile (self , source ):
104+ (fd , filename ) = tempfile .mkstemp (prefix = 'execjs' , suffix = '.js' )
105+ os .close (fd )
106+ try :
107+ with io .open (filename , "w+" , encoding = self ._runtime ._encoding ) as fp :
108+ fp .write (self ._compile (source ))
109+ cmd = self ._runtime ._binary () + [filename ]
110+
111+ p = None
112+ try :
113+ p = Popen (cmd , stdout = PIPE , stderr = PIPE , cwd = self ._cwd )
114+ stdoutdata , stderrdata = p .communicate ()
115+ ret = p .wait ()
116+ finally :
117+ del p
118+
119+ self ._fail_on_non_zero_status (ret , stdoutdata , stderrdata )
104120 return stdoutdata
105- else :
121+ finally :
122+ os .remove (filename )
123+
124+ def _fail_on_non_zero_status (self , status , stdoutdata , stderrdata ):
125+ if status != 0 :
106126 raise exceptions .RuntimeError ("stdout: {}, stderr: {}" .format (repr (stdoutdata ), repr (stderrdata )))
107127
108128 def _compile (self , source ):
0 commit comments