blob: 70df3fc55fe9294cc92332a7b417b53c98cc5370 [file] [log] [blame]
"""Executable Python script for running Python actions.
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
"""
import os
import sys
import codecs
import traceback
sys.path.append('../actionProxy')
from actionproxy import ActionRunner, main, setRunner
class PythonRunner(ActionRunner):
def __init__(self):
ActionRunner.__init__(self, '/action/__main__.py')
self.fn = None
self.mainFn = 'main'
self.global_context = {}
def initCodeFromString(self, message):
# do nothing, defer to build step
return True
def build(self, message):
binary = message['binary'] if 'binary' in message else False
if not binary:
code = message['code']
filename = 'action'
elif os.path.isfile(self.source):
with codecs.open(self.source, 'r', 'utf-8') as m:
code = m.read()
workdir = os.path.dirname(self.source)
sys.path.insert(0, workdir)
os.chdir(workdir)
else:
sys.stderr.write('Zip file does not include ' + os.path.basename(self.source) + '\n')
return False
try:
filename = os.path.basename(self.source)
self.fn = compile(code, filename=filename, mode='exec')
if 'main' in message:
self.mainFn = message['main']
# if the directory 'virtualenv' is extracted out of a zip file
path_to_virtualenv = os.path.dirname(self.source) + '/virtualenv'
if os.path.isdir(path_to_virtualenv):
# activate the virtualenv using activate_this.py contained in the virtualenv
activate_this_file = path_to_virtualenv + '/bin/activate_this.py'
if os.path.exists(activate_this_file):
with open(activate_this_file) as f:
code = compile(f.read(), activate_this_file, 'exec')
exec(code, dict(__file__=activate_this_file))
else:
sys.stderr.write('Invalid virtualenv. Zip file does not include /virtualenv/bin/' + os.path.basename(activate_this_file) + '\n')
return False
exec(self.fn, self.global_context)
return True
except Exception:
traceback.print_exc(file=sys.stderr, limit=0)
return False
def verify(self):
return self.fn is not None
def run(self, args, env):
result = None
try:
os.environ = env
self.global_context['param'] = args
exec('fun = %s(param)' % self.mainFn, self.global_context)
result = self.global_context['fun']
except Exception:
traceback.print_exc(file=sys.stderr)
if result and isinstance(result, dict):
return (200, result)
else:
return (502, {'error': 'The action did not return a dictionary.'})
if __name__ == '__main__':
setRunner(PythonRunner())
main()