blob: 1b62cb8afcee6efd1bc9054ec4bb8e8d24c595c5 [file] [log] [blame]
/*
* Copyright 2015-2016 IBM Corporation
*
* Licensed 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'),
open = require('open'),
path = require('path'),
spawn = require('child_process').spawn;
function compileIt(sourcePath, tmpDirPath, actionName) {
// console.log("COMPILEIT", sourcePath);
return new Promise((resolve, reject) => {
var spawnOpts = {
cwd: tmpDirPath,
stdio: ['inherit', 'inherit', 'inherit'],
env: process.env
};
try {
var executablePath = path.join(tmpDirPath, actionName);
var child = spawn('swiftc',
['-o', executablePath,
'-g',
sourcePath],
spawnOpts);
child.on('exit', (code) => {
if (code !== 0) {
reject(code);
} else {
resolve(executablePath);
}
});
} catch (err) {
console.error(err);
reject(err);
}
});
}
function debugIt(eventBus, executablePath) {
// console.log("DEBUGIT", executablePath);
return new Promise((resolve, reject) => {
try {
var spawnOpts = {
cwd: process.cwd(),
stdio: ['inherit', 'inherit', 'inherit'],
env: process.env
};
try {
var child = spawn('lldb',
['-s', path.join(process.cwd(), 'lib', 'helpers', 'lldb.run'),
executablePath],
spawnOpts);
child.on('exit', (code) => {
if (code !== 0 && code !== null) {
console.error('The Swift debugger exited abnormally with code ' + code + ' ' + (code === 'null'));
reject(code);
} else {
//executableCleanup();
resolve();
}
});
eventBus.on('invocation-done', () => child.kill());
} catch (e) {
console.error('Error spawning debugger', e);
console.error(e.stack);
reject(e);
}
} catch (e) {
console.error('Error spawning debugger', e);
console.error(e.stack);
reject(e);
}
});
}
/**
* Format a Swift Dictionary from a javascript struct
*
*/
function jsonToSwiftDictionary(params) {
var s = JSON.stringify(params)
.replace(/{/g, '[')
.replace(/}/g, ']');
if (s === '[]') {
return '[:]';
} else {
return s;
}
}
exports.debug = function debugSwift(message, ws, echoChamberNames, done, commandLineOptions, eventBus) {
try {
exports._debug(message, ws, echoChamberNames, done, commandLineOptions, eventBus);
} catch (e) {
console.error(e);
}
};
exports._debug = function debugSwift(message, ws, echoChamberNames, done, commandLineOptions, eventBus) {
var code = message.action.exec.code;
var r2 = new RegExp(/\[[\s]*String[\s]*:[\s]*Any[\s]*\]/);
var paramType = code.search(r2, startOfMethodBody);
code = code.substring(0, paramType) + ' inout ' + code.substring(paramType);
var r = new RegExp(/func main[\s]*\([^\)]*\)/);
var startOfMethodBody = code.search(r);
if (startOfMethodBody >= 0) {
var paren = code.indexOf('{', startOfMethodBody);
code = code.substring(0, paren + 1) + '\n // Hello from the OpenWhisk debugger. Welcome to your main method\n' + code.substring(paren + 1);
}
fs.readFile(path.join('lib', 'debug-bootstrap.swift'), (err, codeBuffer) => {
code += '\n\n//\n';
code += '// Welcome to the OpenWhisk debugger.\n';
code += '//\n';
code += '// To proceed with debugging, press the continue => button.\n';
code += '// The first breakpoint will be in your main method\n';
code += '//\n';
code += codeBuffer.toString('utf8');
code += '\nvar params: [String:Any] = ' + jsonToSwiftDictionary(message.actualParameters);
code += '\nbootstrap(key: "' + message.key + '", namespace: "' + message.action.namespace + '", triggerName: "' + echoChamberNames.trigger + '", main: main, actualParameters: &params);';
tmp.dir({ prefix: 'wskdb-', unsafeCleanup: true }, function onTempDirCreation(err, tmpDirPath, fd, tmpdirCleanupCallback) {
var tmpFilePath = path.join(tmpDirPath, message.action.name + '.swift');
console.log('TMP ' + tmpFilePath);
try {
fs.writeFile(tmpFilePath, code, 0, 'utf8', function onFileWriteCompletion(err, written, string) {
compileIt(tmpFilePath, tmpDirPath, message.action.name)
.then(debugIt.bind(undefined, eventBus))
.then(() => {
try { tmpdirCleanupCallback(); } catch (e) { }
done(); // we don't need to "ok" here, as the invoker will do that for us
});
});
} catch (err) {
console.error(err);
console.error(err.stack);
try { tmpdirCleanupCallback(); } catch (e) { }
done();
}
});
});
};