blob: e1689c8a5a6fdf94e98d66f167b566817acd83ec [file] [log] [blame]
/*
* 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.
*/
var fs = require('fs'),
ok_ = require('./repl-messages').ok_,
tmp = require('tmp'),
diff = require('./diff'),
kill = require('tree-kill'),
open = require('open'),
path = require('path'),
spawn = require('child_process').spawn,
options = require('./options').options;
exports.debug = function debug(message, ws, echoChamberNames, done, commandLineOptions, eventBus) {
try {
exports._debug(message, ws, echoChamberNames, done, commandLineOptions, eventBus);
} catch (e) {
console.error(e);
}
};
exports._debug = function debug(message, ws, echoChamberNames, done, commandLineOptions, eventBus) {
var code = message.action.exec.code;
var r = new RegExp(/def main[\s]*\([^\)]*\):/);
var startOfMethodBody = code.search(r);
if (startOfMethodBody >= 0) {
var colon = code.indexOf(':', startOfMethodBody);
code =
code.substring(0, colon + 1)
+ '\n # Welcome to your main method\n'
+ ' from pdb import set_trace as debugger\n'
+ ' debugger()\n'
+ code.substring(colon + 1);
}
code += '\n\n\nfrom bootstrap import bootstrap\n';
code += 'try:\n';
code += ' bootstrap(\'' + message.key + '\', \'' + message.action.namespace + '\', \'' + echoChamberNames.trigger + '\', main, ' + JSON.stringify(message.actualParameters || {}) + ');\n';
code += 'except:\n';
code += ' pass\n';
code += 'finally:\n';
code += ' sys.exit(0)\n';
tmp.dir({ prefix: 'wskdb-', unsafeCleanup: true}, function onTempDirCreation(err, tmpDirPath, tmpdirCleanupCallback) {
var tmpdirPathRegExp = new RegExp(tmpDirPath + '/');
var tmpFilePath = path.join(tmpDirPath, message.action.name + '.py');
try {
fs.writeFile(tmpFilePath, code, 0, 'utf8', function onFileWriteCompletion(err, written, string) {
// we need to update the NODE_PATH env var, to add our local modules
var env = Object.assign({}, process.env);
env.PYTHONPATH = path.join(__dirname, '..', 'lib', 'debug-bootstrap', 'python');
env.PYTHONUNBUFFERED = '1';
function spawnWithCLI() {
try {
var spawnOpts = {
cwd: process.cwd(),
stdio: ['inherit', 'pipe', 'pipe'],
env: env
};
var child = spawn('python',
['-u',
'-m', 'pdb',
tmpFilePath],
spawnOpts);
//
// the activation that we are debugging has
// finished. kill the child debugger process
// SIGKILL is required to avoid killing wskdb, too
eventBus.on('invocation-done', () => child.kill('SIGKILL'));
child.stderr.on('data', message => console.error(message.toString().red));
var baked = false, raw = true, first = true;
child.stdout.on('data', function(message) {
try {
if (raw) {
raw = false;
console.log();
console.log('Hello from the Python debugger. Enter '
+ 'c'.red + ' or ' + 'continue'.red + ' to enter your main method.');
console.log('Hint: enter ' + 'l'.red + ' or ' + 'list'.red + ' to see a longer program listing');
console.log();
}
if (!baked) {
if (message.indexOf('The program exited via sys.exit') >= 0) {
baked = true;
} else {
process.stdout.write(message.toString().replace(tmpdirPathRegExp, '').blue.dim);
}
}
} catch (err) {
console.error(err);
}
});
//
// the child debugger process has terminated, clean things up
//
child.on('exit', code => {
//if (code !== 0) {
//console.error('The Python debugger exited abnormally with code ' + code);
//}
//try { tmpdirCleanupCallback(); } catch (e) { }
done(); // we don't need to "ok" here, as the invoker will do that for us
});
} catch (e) {
console.error('Error spawning debugger', e);
console.error(e.stack);
done();
}
}
spawnWithCLI();
});
} catch (e) {
console.error(e);
console.error(e.stack);
//try { tmpdirCleanupCallback(); } catch (e) { }
done();
}
});
};