mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
176 lines
5.1 KiB
JavaScript
176 lines
5.1 KiB
JavaScript
'use strict';
|
|
|
|
const SError = require('./Error'),
|
|
SCli = require('./utils/cli'),
|
|
BbPromise = require('bluebird'),
|
|
path = require('path'),
|
|
_ = require('lodash'),
|
|
spawnSync = require('child_process').spawnSync,
|
|
chalk = require('chalk'),
|
|
context = require('./utils/context'),
|
|
fs = BbPromise.promisifyAll(require('fs'));
|
|
|
|
module.exports = function(S) {
|
|
|
|
class RuntimePython27 extends S.classes.Runtime {
|
|
|
|
constructor() {
|
|
super();
|
|
}
|
|
|
|
static getName() {
|
|
return 'python2.7';
|
|
}
|
|
|
|
getName() {
|
|
return RuntimePython27.getName();
|
|
}
|
|
|
|
/**
|
|
* Scaffold
|
|
*/
|
|
|
|
scaffold(func) {
|
|
const handlerPath = path.join(S.getServerlessPath(), 'templates', 'python2.7', 'handler.py');
|
|
|
|
return fs.readFileAsync(handlerPath)
|
|
.then(handlerPy => BbPromise.all([
|
|
S.utils.writeFile(func.getRootPath('handler.py'), handlerPy),
|
|
S.utils.writeFile(func.getRootPath('event.json'), {})
|
|
]));
|
|
}
|
|
|
|
/**
|
|
* Run
|
|
*/
|
|
|
|
run(func, stage, region) {
|
|
|
|
return BbPromise.all([
|
|
S.utils.readFile(func.getRootPath('event.json')),
|
|
this.getEnvVars(func, stage, region)
|
|
])
|
|
.spread((functionEvent, env) => {
|
|
const handlerArr = func.handler.split('/').pop().split('.'),
|
|
functionFile = func.getRootPath(handlerArr[0] + '.py'),
|
|
functionHandler = handlerArr[1],
|
|
result = {};
|
|
|
|
const childArgs = [
|
|
'--event', JSON.stringify(functionEvent),
|
|
'--handler-path', functionFile,
|
|
'--handler-function', functionHandler
|
|
];
|
|
|
|
const child = spawnSync("serverless-run-python-handler", childArgs, {env: _.merge(env, process.env)});
|
|
|
|
SCli.log(`-----------------`);
|
|
var handler_result = JSON.parse(child.stdout);
|
|
if (child.status === 0 && handler_result.success) {
|
|
SCli.log(chalk.bold('Success! - This Response Was Returned:'));
|
|
SCli.log(JSON.stringify(handler_result.result));
|
|
result.status = 'success';
|
|
result.response = handler_result.result;
|
|
} else {
|
|
SCli.log(chalk.bold('Failed - This Error Was Returned:'));
|
|
SCli.log(child.stdout);
|
|
SCli.log(chalk.bold('Exception message from Python'));
|
|
SCli.log(handler_result.exception);
|
|
result.status = 'error';
|
|
result.response = handler_result.exception;
|
|
}
|
|
return result;
|
|
})
|
|
.catch((err) => {
|
|
SCli.log(chalk.bold('Failed - This Error Was Thrown:'));
|
|
SCli.log(err);
|
|
return {
|
|
status: 'error',
|
|
response: err.message,
|
|
error: err
|
|
};
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Build
|
|
* - Build the function in this runtime
|
|
*/
|
|
|
|
build(func, stage, region) {
|
|
|
|
// Validate
|
|
if (!func._class || func._class !== 'Function') return BbPromise.reject(new SError('A function instance is required'));
|
|
|
|
let pathDist;
|
|
|
|
return this.createDistDir(func.name)
|
|
.then(function (distDir) {
|
|
pathDist = distDir
|
|
})
|
|
.then(() => this.copyFunction(func, pathDist, stage, region))
|
|
.then(() => this._addEnvVarsInline(func, pathDist, stage, region))
|
|
.then(() => this.generatePaths(func, pathDist));
|
|
}
|
|
|
|
/**
|
|
* Get Handler
|
|
*/
|
|
|
|
getHandler(func) {
|
|
return path.join(path.dirname(func.handler), "_serverless_handler.handler").replace(/\\/g, '/');
|
|
}
|
|
|
|
/**
|
|
* Add ENV Vars In-line
|
|
* - Adds a new handler that loads in ENV vars before running the main handler
|
|
*/
|
|
|
|
_addEnvVarsInline(func, pathDist, stage, region) {
|
|
return this.getEnvVars(func, stage, region)
|
|
.then(envVars => {
|
|
|
|
const handlerArr = func.handler.split('.'),
|
|
handlerDir = path.dirname(func.handler),
|
|
handlerFile = handlerArr[0].split('/').pop(),
|
|
handlerMethod = handlerArr[1];
|
|
|
|
let loader = ['import os'];
|
|
loader = loader.concat(_.map(envVars, (value, key) => `os.environ['${key}'] = str('${value}')`));
|
|
loader.push(`from ${handlerFile} import ${handlerMethod}`);
|
|
|
|
return fs.writeFileAsync(path.join(pathDist, handlerDir, '_serverless_handler.py'), loader.join('\n'));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Install NPM Dependencies
|
|
*/
|
|
|
|
installDependencies(dir) {
|
|
SCli.log("Installing default python dependencies with pip...");
|
|
SCli.log(`-----------------`);
|
|
pipPrefixInstall(
|
|
S.getProject().getRootPath(dir, 'requirements.txt'),
|
|
S.getProject().getRootPath(dir, 'vendored')
|
|
);
|
|
SCli.log(`-----------------`);
|
|
}
|
|
}
|
|
|
|
return RuntimePython27;
|
|
|
|
};
|
|
|
|
/**
|
|
* Pip install using prefix strategy (not virtualenv), requires a modern `pip` version
|
|
*/
|
|
|
|
function pipPrefixInstall(requirements, dir) {
|
|
if (exec(`pip install -t "${dir}" -r "${requirements}"`, { silent: false }).code !== 0) {
|
|
throw new SError(`Error executing pip install on ${dir}`, SError.errorCodes.UNKNOWN);
|
|
}
|
|
|
|
process.chdir(process.cwd());
|
|
}
|