var fs = require('fs'); var exec = require('exec'); var path = require('path'); var async = require('async'); VirtualBox = {}; VirtualBox.REQUIRED_VERSION = '4.3.18'; VirtualBox.INCLUDED_VERSION = '4.3.18'; VirtualBox.INSTALLER_FILENAME = 'virtualbox-4.3.18.pkg'; VirtualBox.INSTALLER_CHECKSUM = '5836c94481c460c648b9216386591a2915293ac86b9bb6c57746637796af6af2'; // Sha256 Checksum VirtualBox.installed = function () { return fs.existsSync('/usr/bin/VBoxManage') && fs.existsSync('/Applications/VirtualBox.app/Contents/MacOS/VirtualBox'); }; VirtualBox.exec = function (command, callback) { exec(['/usr/bin/VBoxManage', command], function (stderr, stdout, code) { callback(stderr, stdout, code); }); }; VirtualBox.install = function (callback) { // -W waits for the process to close before finishing. exec('open -W ' + path.join(Util.getResourceDir(), this.INSTALLER_FILENAME).replace(' ', '\\ '), function (stderr, stdout, code) { if (code) { callback(stderr); return; } callback(null); }); }; VirtualBox.version = function (callback) { if (!this.installed()) { callback('VirtualBox not installed.'); return; } this.exec('-v', function (stderr, stdout, code) { if (code) { callback(stderr); return; } // Output is x.x.xryyyyyy var match = stdout.match(/(\d+\.\d+\.\d+).*/); if (!match || match.length < 2) { callback('VBoxManage -v output format not recognized.'); return; } callback(null, match[1]); }); }; VirtualBox.saveRunningVMs = function (callback) { if (!this.installed()) { callback('VirtualBox not installed.'); return; } this.exec('list runningvms | sed -E \'s/.*\\{(.*)\\}/\\1/\' | xargs -L1 -I {} VBoxManage controlvm {} savestate', function (stderr, stdout, code) { if (code) { callback(stderr); } else { callback(); } }); }; VirtualBox.killAllProcesses = function (callback) { this.saveRunningVMs(function (err) { if (err) {callback(err); return;} exec('pkill VirtualBox', function (stderr, stdout, code) { if (code) {callback(stderr); return;} exec('pkill VBox', function (stderr, stdout, code) { if (code) {callback(stderr); return;} callback(); }); }); }); }; VirtualBox.vmState = function (name, callback) { VirtualBox.exec('showvminfo ' + name + ' --machinereadable', function (stderr, stdout, code) { if (code) { callback(stderr); return; } var match = stdout.match(/VMState="(\w+)"/); if (!match) { callback('Could not parse VMState'); return; } callback(null, match[1]); }); }; VirtualBox.shutdownVM = function (name, callback) { VirtualBox.vmState(name, function (err, state) { // No VM found if (err) { callback(null, false); return; } VirtualBox.exec('controlvm ' + name + ' acpipowerbutton', function (stderr, stdout, code) { if (code) { callback(stderr, false); return; } var state = null; async.until(function () { return state === 'poweroff'; }, function (callback) { VirtualBox.vmState(name, function (err, newState) { if (err) { callback(err); return; } state = newState; setTimeout(callback, 250); }); }, function (err) { VirtualBox.exec('unregistervm ' + name + ' --delete', function (stderr, stdout, code) { if (code) { callback(err); return; } callback(); }); }); }); }); };