mirror of https://github.com/docker/docs.git
Promises, virtual box & boot2docker integration tests
This commit is contained in:
parent
3cadecef1d
commit
88d39d2505
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"curly": true,
|
||||||
|
"noempty": true,
|
||||||
|
"newcap": true,
|
||||||
|
"eqeqeq": true,
|
||||||
|
"eqnull": true,
|
||||||
|
"esnext": true,
|
||||||
|
"undef": true,
|
||||||
|
"unused": true,
|
||||||
|
"devel": true,
|
||||||
|
"node": true,
|
||||||
|
"browser": true,
|
||||||
|
"evil": false,
|
||||||
|
"latedef": true,
|
||||||
|
"nonew": true,
|
||||||
|
"trailing": true,
|
||||||
|
"immed": true,
|
||||||
|
"smarttabs": true,
|
||||||
|
"strict": false,
|
||||||
|
"quotmark": false,
|
||||||
|
"nonbsp": true,
|
||||||
|
"noempty": true,
|
||||||
|
"camelcase": false,
|
||||||
|
"jasmine": true,
|
||||||
|
"globals": {
|
||||||
|
"define": true
|
||||||
|
},
|
||||||
|
"predef": [ "-Promise" ]
|
||||||
|
}
|
|
@ -1,15 +1,10 @@
|
||||||
var child_process = require('child_process');
|
var app = require('app');
|
||||||
var net = require('net');
|
|
||||||
var os = require('os');
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var exec = require('exec');
|
var exec = require('exec');
|
||||||
|
|
||||||
var autoUpdater = require('auto-updater');
|
var autoUpdater = require('auto-updater');
|
||||||
var app = require('app');
|
|
||||||
var BrowserWindow = require('browser-window');
|
var BrowserWindow = require('browser-window');
|
||||||
var ipc = require('ipc');
|
var ipc = require('ipc');
|
||||||
|
|
||||||
var argv = require('minimist')(process.argv);
|
var argv = require('minimist')(process.argv);
|
||||||
var settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
|
var settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
|
||||||
|
|
||||||
|
@ -23,6 +18,9 @@ if (argv.integration) {
|
||||||
process.env.TEST_TYPE = 'test';
|
process.env.TEST_TYPE = 'test';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.commandLine.appendSwitch('js-flags', '--harmony');
|
||||||
|
|
||||||
|
var mainWindow = null;
|
||||||
app.on('activate-with-no-open-windows', function () {
|
app.on('activate-with-no-open-windows', function () {
|
||||||
if (mainWindow) {
|
if (mainWindow) {
|
||||||
mainWindow.show();
|
mainWindow.show();
|
||||||
|
@ -30,7 +28,7 @@ app.on('activate-with-no-open-windows', function () {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('ready', function() {
|
app.on('ready', function () {
|
||||||
mainWindow = new BrowserWindow({
|
mainWindow = new BrowserWindow({
|
||||||
width: 1000,
|
width: 1000,
|
||||||
height: 700,
|
height: 700,
|
||||||
|
@ -44,12 +42,12 @@ app.on('ready', function() {
|
||||||
var saveVMOnQuit = false;
|
var saveVMOnQuit = false;
|
||||||
|
|
||||||
if (argv.test) {
|
if (argv.test) {
|
||||||
mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, '..', 'tests/tests.html')));
|
mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, '..', 'build/tests.html')));
|
||||||
} else {
|
} else {
|
||||||
mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, '..', 'build/index.html')));
|
mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, '..', 'build/index.html')));
|
||||||
app.on('will-quit', function (e) {
|
app.on('will-quit', function () {
|
||||||
if (saveVMOnQuit) {
|
if (saveVMOnQuit) {
|
||||||
exec('VBoxManage controlvm boot2docker-vm savestate', function (stderr, stdout, code) {});
|
exec('VBoxManage controlvm boot2docker-vm savestate', function () {});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -69,7 +67,7 @@ app.on('ready', function() {
|
||||||
if (process.env.NODE_ENV !== 'development' && !argv.test) {
|
if (process.env.NODE_ENV !== 'development' && !argv.test) {
|
||||||
autoUpdater.setFeedUrl('https://updates.kitematic.com/releases/latest?version=' + app.getVersion() + '&beta=' + settingsjson.beta);
|
autoUpdater.setFeedUrl('https://updates.kitematic.com/releases/latest?version=' + app.getVersion() + '&beta=' + settingsjson.beta);
|
||||||
|
|
||||||
autoUpdater.on('checking-for-update', function (e) {
|
autoUpdater.on('checking-for-update', function () {
|
||||||
console.log('Checking for update...');
|
console.log('Checking for update...');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -78,11 +76,12 @@ app.on('ready', function() {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('update-not-available', function (e) {
|
autoUpdater.on('update-not-available', function () {
|
||||||
console.log('Update not available.');
|
console.log('Update not available.');
|
||||||
});
|
});
|
||||||
|
|
||||||
autoUpdater.on('update-downloaded', function (e, releaseNotes, releaseName, releaseDate, updateURL) {
|
autoUpdater.on('update-downloaded', function (e, releaseNotes, releaseName, releaseDate, updateURL) {
|
||||||
|
console.log(e, releaseNotes, releaseName, releaseDate, updateURL);
|
||||||
console.log('Update downloaded.');
|
console.log('Update downloaded.');
|
||||||
mainWindow.webContents.send('notify', 'window:update-available');
|
mainWindow.webContents.send('notify', 'window:update-available');
|
||||||
});
|
});
|
||||||
|
|
27
gulpfile.js
27
gulpfile.js
|
@ -5,18 +5,17 @@ var fs = require('fs');
|
||||||
var gulp = require('gulp');
|
var gulp = require('gulp');
|
||||||
var gulpif = require('gulp-if');
|
var gulpif = require('gulp-if');
|
||||||
var gutil = require('gulp-util');
|
var gutil = require('gulp-util');
|
||||||
var http = require('http');
|
|
||||||
var less = require('gulp-less');
|
var less = require('gulp-less');
|
||||||
var livereload = require('gulp-livereload');
|
var livereload = require('gulp-livereload');
|
||||||
var plumber = require('gulp-plumber');
|
var plumber = require('gulp-plumber');
|
||||||
var react = require('gulp-react');
|
var react = require('gulp-react');
|
||||||
|
var to5 = require('gulp-6to5');
|
||||||
var runSequence = require('run-sequence');
|
var runSequence = require('run-sequence');
|
||||||
var shell = require('gulp-shell');
|
var shell = require('gulp-shell');
|
||||||
var sourcemaps = require('gulp-sourcemaps');
|
var sourcemaps = require('gulp-sourcemaps');
|
||||||
var packagejson = require('./package.json');
|
var packagejson = require('./package.json');
|
||||||
|
|
||||||
var dependencies = Object.keys(packagejson.dependencies);
|
var dependencies = Object.keys(packagejson.dependencies);
|
||||||
var devDependencies = Object.keys(packagejson.devDependencies);
|
|
||||||
var isBeta = process.argv.indexOf('--beta') !== -1;
|
var isBeta = process.argv.indexOf('--beta') !== -1;
|
||||||
var options = {
|
var options = {
|
||||||
dev: process.argv.indexOf('release') === -1 && process.argv.indexOf('test') === -1,
|
dev: process.argv.indexOf('release') === -1 && process.argv.indexOf('test') === -1,
|
||||||
|
@ -35,11 +34,31 @@ gulp.task('js', function () {
|
||||||
// emit the end event, to properly end the task
|
// emit the end event, to properly end the task
|
||||||
this.emit('end');
|
this.emit('end');
|
||||||
}))
|
}))
|
||||||
|
.pipe(sourcemaps.init())
|
||||||
.pipe(react())
|
.pipe(react())
|
||||||
|
.pipe(to5({blacklist: ['regenerator']}))
|
||||||
|
.pipe(sourcemaps.write('.'))
|
||||||
.pipe(gulp.dest((options.dev || options.test) ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
|
.pipe(gulp.dest((options.dev || options.test) ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
|
||||||
.pipe(gulpif(options.dev, livereload()));
|
.pipe(gulpif(options.dev, livereload()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task('tests', function () {
|
||||||
|
gulp.src('tests/*.js')
|
||||||
|
.pipe(plumber(function(error) {
|
||||||
|
gutil.log(gutil.colors.red('Error (' + error.plugin + '): ' + error.message));
|
||||||
|
// emit the end event, to properly end the task
|
||||||
|
this.emit('end');
|
||||||
|
}))
|
||||||
|
.pipe(sourcemaps.init())
|
||||||
|
.pipe(react())
|
||||||
|
.pipe(to5())
|
||||||
|
.pipe(sourcemaps.write('.'))
|
||||||
|
.pipe(gulp.dest('./build'));
|
||||||
|
|
||||||
|
gulp.src('./tests/tests.html').pipe(gulp.dest('./build'));
|
||||||
|
gulp.src('./tests/jasmine-2.1.3/*').pipe(gulp.dest('./build/jasmine-2.1.3'));
|
||||||
|
});
|
||||||
|
|
||||||
gulp.task('images', function() {
|
gulp.task('images', function() {
|
||||||
return gulp.src('images/*')
|
return gulp.src('images/*')
|
||||||
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
|
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
|
||||||
|
@ -79,7 +98,7 @@ gulp.task('copy', function () {
|
||||||
.pipe(gulpif(options.dev, livereload()));
|
.pipe(gulpif(options.dev, livereload()));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('dist', function (cb) {
|
gulp.task('dist', function () {
|
||||||
var stream = gulp.src('').pipe(shell([
|
var stream = gulp.src('').pipe(shell([
|
||||||
'rm -Rf ./dist',
|
'rm -Rf ./dist',
|
||||||
'mkdir -p ./dist/osx',
|
'mkdir -p ./dist/osx',
|
||||||
|
@ -146,7 +165,7 @@ gulp.task('release', function () {
|
||||||
runSequence('download', 'dist', ['copy', 'images', 'js', 'styles'], 'sign', 'zip');
|
runSequence('download', 'dist', ['copy', 'images', 'js', 'styles'], 'sign', 'zip');
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('test', ['download', 'copy', 'js'], function () {
|
gulp.task('test', ['download', 'copy', 'js', 'tests'], function () {
|
||||||
var env = process.env;
|
var env = process.env;
|
||||||
env.NODE_ENV = 'test';
|
env.NODE_ENV = 'test';
|
||||||
if (options.integration) {
|
if (options.integration) {
|
||||||
|
|
|
@ -6,6 +6,6 @@
|
||||||
<title>Kitematic</title>
|
<title>Kitematic</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="Main.js"></script>
|
<script src="index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
16
package.json
16
package.json
|
@ -12,9 +12,9 @@
|
||||||
"bugs": "https://github.com/kitematic/kitematic/issues",
|
"bugs": "https://github.com/kitematic/kitematic/issues",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "gulp",
|
"start": "gulp",
|
||||||
"test": "gulp test --silent",
|
"test": "gulp test",
|
||||||
"test:integration": "gulp test --silent --integration",
|
"test:integration": "gulp test --integration",
|
||||||
"all-tests": "npm test && npm run integration-tests",
|
"test:all": "npm test && npm run test:integration",
|
||||||
"release": "gulp release",
|
"release": "gulp release",
|
||||||
"release:beta": "gulp release --beta",
|
"release:beta": "gulp release --beta",
|
||||||
"preinstall": "./deps"
|
"preinstall": "./deps"
|
||||||
|
@ -33,17 +33,17 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"boot2docker-version": "1.4.1",
|
"boot2docker-version": "1.4.1",
|
||||||
"atom-shell-version": "0.21.0",
|
"atom-shell-version": "0.21.1",
|
||||||
"virtualbox-version": "4.3.20",
|
"virtualbox-version": "4.3.20",
|
||||||
"virtualbox-filename": "VirtualBox-4.3.20-96996-OSX.dmg",
|
"virtualbox-filename": "VirtualBox-4.3.20-96996-OSX.dmg",
|
||||||
"virtualbox-required-version": "4.3.18",
|
"virtualbox-required-version": "4.3.18",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-to-html": "0.2.0",
|
"ansi-to-html": "0.2.0",
|
||||||
"async": "^0.9.0",
|
"async": "^0.9.0",
|
||||||
|
"bluebird": "^2.9.6",
|
||||||
"bugsnag-js": "git+https://git@github.com/bugsnag/bugsnag-js",
|
"bugsnag-js": "git+https://git@github.com/bugsnag/bugsnag-js",
|
||||||
"dockerode": "2.0.4",
|
"dockerode": "2.0.4",
|
||||||
"exec": "0.1.2",
|
"exec": "0.1.2",
|
||||||
"jest-cli": "^0.2.1",
|
|
||||||
"jquery": "^2.1.3",
|
"jquery": "^2.1.3",
|
||||||
"minimist": "^1.1.0",
|
"minimist": "^1.1.0",
|
||||||
"node-uuid": "1.4.1",
|
"node-uuid": "1.4.1",
|
||||||
|
@ -55,15 +55,17 @@
|
||||||
"react-router": "^0.11.6",
|
"react-router": "^0.11.6",
|
||||||
"request": "^2.51.0",
|
"request": "^2.51.0",
|
||||||
"request-progress": "0.3.1",
|
"request-progress": "0.3.1",
|
||||||
|
"request-promise": "^0.3.3",
|
||||||
"retina.js": "^1.1.0",
|
"retina.js": "^1.1.0",
|
||||||
"underscore": "^1.7.0",
|
"rimraf": "^2.2.8",
|
||||||
"rimraf": "^2.2.8"
|
"underscore": "^1.7.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"browserify": "^6.2.0",
|
"browserify": "^6.2.0",
|
||||||
"ecstatic": "^0.5.8",
|
"ecstatic": "^0.5.8",
|
||||||
"glob": "^4.0.6",
|
"glob": "^4.0.6",
|
||||||
"gulp": "^3.8.10",
|
"gulp": "^3.8.10",
|
||||||
|
"gulp-6to5": "^3.0.0",
|
||||||
"gulp-atom": "0.0.5",
|
"gulp-atom": "0.0.5",
|
||||||
"gulp-concat": "^2.3.4",
|
"gulp-concat": "^2.3.4",
|
||||||
"gulp-cssmin": "^0.1.6",
|
"gulp-cssmin": "^0.1.6",
|
||||||
|
|
|
@ -1,123 +1,87 @@
|
||||||
var exec = require('exec');
|
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var fs = require('fs');
|
var Promise = require('bluebird');
|
||||||
var path = require('path');
|
var _ = require('underscore');
|
||||||
var async = require('async');
|
var fs = Promise.promisifyAll(require('fs'));
|
||||||
|
var util = require('./Util');
|
||||||
var cmdExec = function (cmd, callback) {
|
|
||||||
exec(cmd, function (stderr, stdout, code) {
|
|
||||||
if (code !== 0) {
|
|
||||||
callback('Exit code ' + code + ': ' + stderr);
|
|
||||||
} else {
|
|
||||||
callback(null, stdout);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var homeDir = function () {
|
|
||||||
return process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];
|
|
||||||
};
|
|
||||||
|
|
||||||
var Boot2Docker = {
|
var Boot2Docker = {
|
||||||
version: function () {
|
version: function () {
|
||||||
return JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'))['boot2docker-version'];
|
return JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'))['boot2docker-version'];
|
||||||
},
|
},
|
||||||
cliVersion: function (callback) {
|
cliversion: function () {
|
||||||
cmdExec([Boot2Docker.command(), 'version'], function (err, out) {
|
return util.exec([Boot2Docker.command(), 'version']).then(stdout => {
|
||||||
if (err) {
|
var match = stdout.match(/version: v(\d+\.\d+\.\d+)/);
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var match = out.match(/version: v(\d+\.\d+\.\d+)/);
|
|
||||||
if (!match || match.length < 2) {
|
if (!match || match.length < 2) {
|
||||||
callback('Could not parse the boot2docker cli version.');
|
return Promise.reject('Could not parse the boot2docker cli version.');
|
||||||
} else {
|
} else {
|
||||||
callback(null, match[1]);
|
return Promise.resolve(match[1]);
|
||||||
}
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
return Promise.reject(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
isoVersion: function (callback) {
|
isoversion: function () {
|
||||||
fs.readFile(path.join(homeDir(), '.boot2docker', 'boot2docker.iso'), 'utf8', function (err, data) {
|
return fs.readFileAsync(path.join(util.home(), '.boot2docker', 'boot2docker.iso'), 'utf8').then(data => {
|
||||||
if (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var match = data.match(/Boot2Docker-v(\d+\.\d+\.\d+)/);
|
var match = data.match(/Boot2Docker-v(\d+\.\d+\.\d+)/);
|
||||||
if (!match) {
|
if (match) {
|
||||||
callback('Could not parse boot2docker iso version');
|
return Promise.resolve(match[1]);
|
||||||
return;
|
} else {
|
||||||
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
callback (null, match[1]);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
command: function () {
|
command: function () {
|
||||||
return path.join(process.cwd(), 'resources', 'boot2docker-' + this.version());
|
return path.join(process.cwd(), 'resources', 'boot2docker-' + this.version());
|
||||||
},
|
},
|
||||||
exists: function (callback) {
|
exists: function () {
|
||||||
cmdExec([Boot2Docker.command(), 'info'], function (err, out) {
|
return util.exec([Boot2Docker.command(), 'status']).then(() => {
|
||||||
if (err) {
|
return Promise.resolve(true);
|
||||||
callback(null, false);
|
}).catch(() => {
|
||||||
} else {
|
return Promise.resolve(false);
|
||||||
callback(null, true);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
status: function (callback) {
|
status: function () {
|
||||||
cmdExec([Boot2Docker.command(), 'status'], function (err, out) {
|
return util.exec([Boot2Docker.command(), 'status']).then(stdout => {
|
||||||
if (err) {
|
return Promise.resolve(stdout.trim());
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback(null, out.trim());
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
init: function (callback) {
|
init: function () {
|
||||||
cmdExec([Boot2Docker.command(), 'init'], callback);
|
return util.exec([Boot2Docker.command(), 'init']);
|
||||||
},
|
},
|
||||||
start: function (callback) {
|
start: function () {
|
||||||
cmdExec([Boot2Docker.command(), 'start'], callback);
|
return util.exec([Boot2Docker.command(), 'start']);
|
||||||
},
|
},
|
||||||
stop: function (callback) {
|
stop: function () {
|
||||||
cmdExec([Boot2Docker.command(), 'stop'], callback);
|
return util.exec([Boot2Docker.command(), 'stop']);
|
||||||
},
|
},
|
||||||
upgrade: function (callback) {
|
upgrade: function () {
|
||||||
cmdExec([Boot2Docker.command(), 'upgrade'], callback);
|
return util.exec([Boot2Docker.command(), 'upgrade']);
|
||||||
},
|
},
|
||||||
ip: function (callback) {
|
destroy: function () {
|
||||||
exec([Boot2Docker.command(), 'ip'], function (stderr, stdout, code) {
|
return util.exec([Boot2Docker.command(), 'destroy']);
|
||||||
if (code) {
|
},
|
||||||
callback(stderr);
|
ip: function () {
|
||||||
} else {
|
return util.exec([Boot2Docker.command(), 'ip']).then(stdout => {
|
||||||
callback(null, stdout.trim().replace('\n', ''));
|
return Promise.resolve(stdout.trim().replace('\n', ''));
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
erase: function (callback) {
|
erase: function () {
|
||||||
var VMFileLocation = path.join(homeDir(), 'VirtualBox\\ VMs/boot2docker-vm');
|
return util.exec(['rm', '-rf', path.join(util.home(), 'VirtualBox\\ VMs/boot2docker-vm')]);
|
||||||
cmdExec(['rm', '-rf', VMFileLocation], callback);
|
|
||||||
},
|
},
|
||||||
state: function (callback) {
|
state: function () {
|
||||||
cmdExec([Boot2Docker.command(), 'info'], function (err, out) {
|
util.exec([Boot2Docker.command(), 'info']).then(stdout => {
|
||||||
if (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
var info = JSON.parse(out);
|
var info = JSON.parse(stdout);
|
||||||
callback(null, info.State);
|
return Promise.resolve(info.State);
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
callback(e, null);
|
return Promise.reject(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
disk: function (callback) {
|
disk: function () {
|
||||||
cmdExec([Boot2Docker.command(), 'ssh', 'df'], function (err, out) {
|
return util.exec([Boot2Docker.command(), 'ssh', 'df']).then(stdout => {
|
||||||
if (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
var lines = out.split('\n');
|
var lines = stdout.split('\n');
|
||||||
var dataline = _.find(lines, function (line) {
|
var dataline = _.find(lines, function (line) {
|
||||||
return line.indexOf('/dev/sda1') !== -1;
|
return line.indexOf('/dev/sda1') !== -1;
|
||||||
});
|
});
|
||||||
|
@ -128,24 +92,20 @@ var Boot2Docker = {
|
||||||
var usedGb = parseInt(tokens[2], 10) / 1000000;
|
var usedGb = parseInt(tokens[2], 10) / 1000000;
|
||||||
var totalGb = parseInt(tokens[3], 10) / 1000000;
|
var totalGb = parseInt(tokens[3], 10) / 1000000;
|
||||||
var percent = parseInt(tokens[4].replace('%', ''), 10);
|
var percent = parseInt(tokens[4].replace('%', ''), 10);
|
||||||
callback(null, {
|
Promise.resolve({
|
||||||
used_gb: usedGb.toFixed(2),
|
used_gb: usedGb.toFixed(2),
|
||||||
total_gb: totalGb.toFixed(2),
|
total_gb: totalGb.toFixed(2),
|
||||||
percent: percent
|
percent: percent
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
callback(error, null);
|
return Promise.reject(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
memory: function (callback) {
|
memory: function () {
|
||||||
cmdExec([Boot2Docker.command(), 'ssh', 'free -m'], function (err, out) {
|
return util.exec([this.command(), 'ssh', 'free -m']).then(stdout => {
|
||||||
if (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
var lines = out.split('\n');
|
var lines = stdout.split('\n');
|
||||||
var dataline = _.find(lines, function (line) {
|
var dataline = _.find(lines, function (line) {
|
||||||
return line.indexOf('-/+ buffers') !== -1;
|
return line.indexOf('-/+ buffers') !== -1;
|
||||||
});
|
});
|
||||||
|
@ -157,74 +117,44 @@ var Boot2Docker = {
|
||||||
var freeGb = parseInt(tokens[3], 10) / 1000;
|
var freeGb = parseInt(tokens[3], 10) / 1000;
|
||||||
var totalGb = usedGb + freeGb;
|
var totalGb = usedGb + freeGb;
|
||||||
var percent = Math.round(usedGb / totalGb * 100);
|
var percent = Math.round(usedGb / totalGb * 100);
|
||||||
callback(null, {
|
return Promise.resolve({
|
||||||
used_gb: usedGb.toFixed(2),
|
used_gb: usedGb.toFixed(2),
|
||||||
total_gb: totalGb.toFixed(2),
|
total_gb: totalGb.toFixed(2),
|
||||||
free_gb: freeGb.toFixed(2),
|
free_gb: freeGb.toFixed(2),
|
||||||
percent: percent
|
percent: percent
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
callback(error);
|
return Promise.reject(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
createScratchImage: function (callback) {
|
stats: function () {
|
||||||
cmdExec([Boot2Docker.command(), 'ssh', 'tar cv --files-from /dev/null | docker import - scratch'], function (err, out) {
|
Boot2Docker.state().then(state => {
|
||||||
callback(err);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
stats: function (callback) {
|
|
||||||
var self = this;
|
|
||||||
self.state(function (err, state) {
|
|
||||||
if (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (state === 'poweroff') {
|
if (state === 'poweroff') {
|
||||||
callback(null, {state: state});
|
return Promise.resolve({state: state});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
self.memoryUsage(function (err, mem) {
|
var memory = Boot2Docker.memory();
|
||||||
if (err) {
|
var disk = Boot2Docker.disk();
|
||||||
callback(null, {state: state});
|
return Promise.all([memory, disk]).spread((memory, disk) => {
|
||||||
return;
|
return Promise.resolve({
|
||||||
}
|
state: state,
|
||||||
self.diskUsage(function (err, disk) {
|
memory: memory,
|
||||||
if (err) {
|
disk: disk
|
||||||
callback(null, {state: state, memory: mem});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback(null, {
|
|
||||||
state: state,
|
|
||||||
memory: mem,
|
|
||||||
disk: disk
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
sshKeyExists: function () {
|
haskeys: function () {
|
||||||
return fs.existsSync(path.join(homeDir(), '.ssh', 'id_boot2docker'));
|
return fs.existsSync(path.join(util.home(), '.ssh', 'id_boot2docker'));
|
||||||
},
|
},
|
||||||
|
waitstatus: Promise.coroutine(function* () {
|
||||||
// Todo: move me to setup
|
while (true) {
|
||||||
waitWhileStatus: function (status, callback) {
|
var current = yield Boot2Docker.status();
|
||||||
var current = status;
|
if (status !== current.trim()) {
|
||||||
async.whilst(function () {
|
return;
|
||||||
return current === status;
|
}
|
||||||
}, function (callback) {
|
}
|
||||||
Boot2Docker.status(function (err, vmStatus) {
|
})
|
||||||
if (err) {
|
|
||||||
callback(err);
|
|
||||||
} else {
|
|
||||||
current = vmStatus.trim();
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, function (err) {
|
|
||||||
callback(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Boot2Docker;
|
module.exports = Boot2Docker;
|
||||||
|
|
|
@ -206,6 +206,7 @@ var ContainerModal = React.createClass({
|
||||||
);
|
);
|
||||||
|
|
||||||
var tagData = self.state.tags[this.state.active];
|
var tagData = self.state.tags[this.state.active];
|
||||||
|
var tags;
|
||||||
if (tagData) {
|
if (tagData) {
|
||||||
var list = tagData.map(function (t) {
|
var list = tagData.map(function (t) {
|
||||||
return <li key={t.name} onClick={self.handleTagClick.bind(self, t.name, self.state.active)}>{t.name}</li>;
|
return <li key={t.name} onClick={self.handleTagClick.bind(self, t.name, self.state.active)}>{t.name}</li>;
|
||||||
|
|
68
src/Main.js
68
src/Main.js
|
@ -1,12 +1,6 @@
|
||||||
var module = require('module');
|
|
||||||
require.main.paths.splice(0, 0, process.env.NODE_PATH);
|
|
||||||
|
|
||||||
var remote = require('remote');
|
var remote = require('remote');
|
||||||
var app = remote.require('app');
|
var app = remote.require('app');
|
||||||
var ipc = require('ipc');
|
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var Router = require('react-router');
|
|
||||||
var RetinaImage = require('react-retina-image');
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var docker = require('./Docker');
|
var docker = require('./Docker');
|
||||||
|
@ -14,55 +8,43 @@ var router = require('./router');
|
||||||
var boot2docker = require('./boot2docker');
|
var boot2docker = require('./boot2docker');
|
||||||
var ContainerStore = require('./ContainerStore');
|
var ContainerStore = require('./ContainerStore');
|
||||||
var SetupStore = require('./ContainerStore');
|
var SetupStore = require('./ContainerStore');
|
||||||
var Menu = require('./Menu');
|
|
||||||
var Route = Router.Route;
|
|
||||||
var NotFoundRoute = Router.NotFoundRoute;
|
|
||||||
var DefaultRoute = Router.DefaultRoute;
|
|
||||||
var Link = Router.Link;
|
|
||||||
var RouteHandler = Router.RouteHandler;
|
|
||||||
var settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
|
var settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
var head = document.getElementsByTagName('head')[0];
|
||||||
var script = document.createElement('script');
|
var script = document.createElement('script');
|
||||||
script.type = 'text/javascript';
|
script.type = 'text/javascript';
|
||||||
script.src = 'http://localhost:35729/livereload.js';
|
script.src = 'http://localhost:35729/livereload.js';
|
||||||
var head = document.getElementsByTagName('head')[0];
|
|
||||||
head.appendChild(script);
|
head.appendChild(script);
|
||||||
} else {
|
|
||||||
var bugsnag = require('bugsnag-js');
|
|
||||||
bugsnag.apiKey = settingsjson.bugsnag;
|
|
||||||
bugsnag.autoNotify = true;
|
|
||||||
bugsnag.releaseStage = process.env.NODE_ENV === 'development' ? 'development' : 'production';
|
|
||||||
bugsnag.notifyReleaseStages = ['production'];
|
|
||||||
bugsnag.appVersion = app.getVersion();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bugsnag = require('bugsnag-js');
|
||||||
|
bugsnag.apiKey = settingsjson.bugsnag;
|
||||||
|
bugsnag.autoNotify = true;
|
||||||
|
bugsnag.releaseStage = process.env.NODE_ENV === 'development' ? 'development' : 'production';
|
||||||
|
bugsnag.notifyReleaseStages = ['production'];
|
||||||
|
bugsnag.appVersion = app.getVersion();
|
||||||
|
|
||||||
|
router.run(Handler => React.render(<Handler/>, document.body));
|
||||||
if (!window.location.hash.length || window.location.hash === '#/') {
|
if (!window.location.hash.length || window.location.hash === '#/') {
|
||||||
router.run(function (Handler) {
|
SetupStore.run().then(boot2docker.ip).then(ip => {
|
||||||
React.render(<Handler/>, document.body);
|
|
||||||
});
|
|
||||||
SetupStore.run(function (err) {
|
|
||||||
if (err) {
|
|
||||||
bugsnag.notify(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
boot2docker.ip(function (err, ip) {
|
|
||||||
if (err) console.log(err);
|
|
||||||
docker.setHost(ip);
|
|
||||||
ContainerStore.init(function (err) {
|
|
||||||
router.transitionTo('containers');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
router.run(function (Handler) {
|
|
||||||
React.render(<Handler/>, document.body);
|
|
||||||
});
|
|
||||||
boot2docker.ip(function (err, ip) {
|
|
||||||
if (err) console.log(err);
|
|
||||||
docker.setHost(ip);
|
docker.setHost(ip);
|
||||||
ContainerStore.init(function (err) {
|
ContainerStore.init(function (err) {
|
||||||
if (err) console.log(err);
|
if (err) { console.log(err); }
|
||||||
|
router.transitionTo('containers');
|
||||||
});
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
bugsnag.notify(err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('Skipping installer.');
|
||||||
|
router.transitionTo('containers');
|
||||||
|
boot2docker.ip().then(ip => {
|
||||||
|
docker.setHost(ip);
|
||||||
|
ContainerStore.init(function (err) {
|
||||||
|
if (err) { console.log(err); }
|
||||||
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
bugsnag.notify(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,7 @@ var routes = (
|
||||||
<Route name="preferences" path="/preferences" handler={Preferences}/>
|
<Route name="preferences" path="/preferences" handler={Preferences}/>
|
||||||
<DefaultRoute handler={NoContainers}/>
|
<DefaultRoute handler={NoContainers}/>
|
||||||
</Route>
|
</Route>
|
||||||
<Route name="setup" handler={Setup}></Route>
|
<DefaultRoute name="setup" handler={Setup}/>
|
||||||
<DefaultRoute handler={Setup}/>
|
|
||||||
</Route>
|
</Route>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
var React = require('react/addons');
|
var React = require('react/addons');
|
||||||
var Router = require('react-router');
|
var Router = require('react-router');
|
||||||
var Radial = require('./Radial.react.js');
|
var Radial = require('./Radial.react.js');
|
||||||
var async = require('async');
|
|
||||||
var assign = require('object-assign');
|
|
||||||
var fs = require('fs');
|
|
||||||
var path = require('path');
|
|
||||||
var virtualbox = require('./Virtualbox');
|
|
||||||
var SetupStore = require('./SetupStore');
|
var SetupStore = require('./SetupStore');
|
||||||
var RetinaImage = require('react-retina-image');
|
var RetinaImage = require('react-retina-image');
|
||||||
|
|
||||||
|
@ -27,8 +22,8 @@ var Setup = React.createClass({
|
||||||
},
|
},
|
||||||
update: function () {
|
update: function () {
|
||||||
this.setState({
|
this.setState({
|
||||||
progress: SetupStore.stepProgress(),
|
progress: SetupStore.percent(),
|
||||||
step: SetupStore.stepName(),
|
step: SetupStore.step(),
|
||||||
error: SetupStore.error()
|
error: SetupStore.error()
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -118,9 +113,9 @@ var Setup = React.createClass({
|
||||||
},
|
},
|
||||||
renderStep: function () {
|
renderStep: function () {
|
||||||
switch(this.state.step) {
|
switch(this.state.step) {
|
||||||
case 'downloading_virtualbox':
|
case 'download_virtualbox':
|
||||||
return this.renderDownloadingVirtualboxStep();
|
return this.renderDownloadingVirtualboxStep();
|
||||||
case 'installing_virtualbox':
|
case 'install_virtualbox':
|
||||||
return this.renderInstallingVirtualboxStep();
|
return this.renderInstallingVirtualboxStep();
|
||||||
case 'cleanup_kitematic':
|
case 'cleanup_kitematic':
|
||||||
return this.renderInitBoot2DockerStep();
|
return this.renderInitBoot2DockerStep();
|
||||||
|
@ -133,21 +128,11 @@ var Setup = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
var radial;
|
|
||||||
if (this.state.progress) {
|
|
||||||
radial = <Radial progress={this.state.progress}/>;
|
|
||||||
} else if (this.state.error) {
|
|
||||||
radial = <Radial error={true} spin="true" progress="100"/>;
|
|
||||||
} else {
|
|
||||||
radial = <Radial spin="true" progress="100"/>;
|
|
||||||
}
|
|
||||||
|
|
||||||
var step = this.renderStep();
|
var step = this.renderStep();
|
||||||
|
|
||||||
if (this.state.error) {
|
if (this.state.error) {
|
||||||
return (
|
return (
|
||||||
<div className="setup">
|
<div className="setup">
|
||||||
{radial}
|
<Radial error={true} spin="true" progress="100"/>;
|
||||||
<p className="error">Error: {this.state.error}</p>
|
<p className="error">Error: {this.state.error}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,210 +1,127 @@
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var assign = require('object-assign');
|
var assign = require('object-assign');
|
||||||
var async = require('async');
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var exec = require('exec');
|
var Promise = require('bluebird');
|
||||||
var boot2docker = require('./Boot2Docker');
|
var boot2docker = require('./Boot2Docker');
|
||||||
var virtualbox = require('./Virtualbox');
|
var virtualbox = require('./Virtualbox');
|
||||||
var setupUtil = require('./SetupUtil');
|
var setupUtil = require('./SetupUtil');
|
||||||
|
var util = require('./Util');
|
||||||
var packagejson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
var packagejson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
||||||
|
|
||||||
|
var _percent = 0;
|
||||||
var _currentStep = null;
|
var _currentStep = null;
|
||||||
var _progress = 0;
|
|
||||||
var _error = null;
|
var _error = null;
|
||||||
|
|
||||||
|
var VIRTUALBOX_FILE = `http://download.virtualbox.org/virtualbox/${packagejson['virtualbox-version']}/${packagejson['virtualbox-filename']}`;
|
||||||
|
var SUDO_PROMPT = 'Kitematic requires administrative privileges to install VirtualBox and copy itself to the Applications folder.';
|
||||||
|
|
||||||
var SetupStore = assign(EventEmitter.prototype, {
|
var SetupStore = assign(EventEmitter.prototype, {
|
||||||
PROGRESS_EVENT: 'setup_progress',
|
PROGRESS_EVENT: 'setup_progress',
|
||||||
STEP_EVENT: 'setup_step',
|
STEP_EVENT: 'setup_step',
|
||||||
ERROR_EVENT: 'setup_error',
|
ERROR_EVENT: 'setup_error',
|
||||||
downloadVirtualboxStep: {
|
downloadVirtualboxStep: Promise.coroutine(function* () {
|
||||||
_download: function (callback, progressCallback) {
|
if (virtualbox.installed()) {
|
||||||
setupUtil.virtualboxSHA256(packagejson['virtualbox-version'], packagejson['virtualbox-filename'], function (err, checksum) {
|
var version = yield virtualbox.version();
|
||||||
if (err) {
|
if (setupUtil.compareVersions(version, packagejson['virtualbox-required-version']) >= 0) {
|
||||||
callback(err);
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
var url = 'http://download.virtualbox.org/virtualbox/' + packagejson['virtualbox-version'] + '/' + packagejson['virtualbox-filename'];
|
|
||||||
var downloadPath = path.join(setupUtil.supportDir(), packagejson['virtualbox-filename']);
|
|
||||||
setupUtil.download(url, downloadPath, checksum, function (err) {
|
|
||||||
callback(err);
|
|
||||||
}, function (progress) {
|
|
||||||
progressCallback(progress);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
run: function (callback, progressCallback) {
|
|
||||||
if (virtualbox.installed()) {
|
|
||||||
virtualbox.version(function (err, version) {
|
|
||||||
if (err) {callback(err); return;}
|
|
||||||
if (setupUtil.compareVersions(version, packagejson['virtualbox-required-version']) < 0) {
|
|
||||||
this._download(callback, progressCallback);
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this._download(callback, progressCallback);
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
name: 'downloading_virtualbox',
|
var checksum = yield setupUtil.virtualboxSHA256(packagejson['virtualbox-version'], packagejson['virtualbox-filename']);
|
||||||
},
|
yield setupUtil.download(VIRTUALBOX_FILE, path.join(setupUtil.supportDir(), packagejson['virtualbox-filename']), checksum, percent => {
|
||||||
installVirtualboxStep: {
|
_percent = percent;
|
||||||
_install: function (callback) {
|
SetupStore.emit(SetupStore.PROGRESS_EVENT);
|
||||||
console.log('attaching');
|
});
|
||||||
exec(['hdiutil', 'attach', path.join(setupUtil.supportDir(), packagejson['virtualbox-filename'])], function (stderr, stdout, code) {
|
}),
|
||||||
if (code) {
|
installVirtualboxStep: Promise.coroutine(function* () {
|
||||||
callback(stderr);
|
if (virtualbox.installed()) {
|
||||||
return;
|
var version = yield virtualbox.version();
|
||||||
}
|
if (setupUtil.compareVersions(version, packagejson['virtualbox-required-version']) >= 0) {
|
||||||
console.log('Attached.');
|
return;
|
||||||
var iconPath = path.join(setupUtil.resourceDir(), 'kitematic.icns');
|
|
||||||
setupUtil.isSudo(function (err, isSudo) {
|
|
||||||
console.log(isSudo);
|
|
||||||
sudoCmd = isSudo ? ['sudo'] : [path.join(setupUtil.resourceDir(), 'cocoasudo'), '--icon=' + iconPath, '--prompt=Kitematic requires administrative privileges to install VirtualBox and copy itself to the Applications folder.'];
|
|
||||||
sudoCmd.push.apply(sudoCmd, ['installer', '-pkg', '/Volumes/VirtualBox/VirtualBox.pkg', '-target', '/']);
|
|
||||||
exec(sudoCmd, function (stderr, stdout, code) {
|
|
||||||
console.log(stdout);
|
|
||||||
console.log('Ran installer.');
|
|
||||||
if (code) {
|
|
||||||
console.log(stderr);
|
|
||||||
console.log(stdout);
|
|
||||||
callback('Could not install virtualbox.');
|
|
||||||
} else {
|
|
||||||
exec(['hdiutil', 'detach', '/Volumes/VirtualBox'], function(stderr, stdout, code) {
|
|
||||||
console.log('detaching');
|
|
||||||
if (code) {
|
|
||||||
callback(stderr);
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
run: function (callback) {
|
|
||||||
var self = this;
|
|
||||||
if (virtualbox.installed()) {
|
|
||||||
virtualbox.version(function (err, version) {
|
|
||||||
if (setupUtil.compareVersions(version, packagejson['virtualbox-required-version']) < 0) {
|
|
||||||
virtualbox.kill(function (err) {
|
|
||||||
if (err) {callback(err); return;}
|
|
||||||
self._install(function(err) {
|
|
||||||
callback(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
self._install(function(err) {
|
|
||||||
callback(err);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
yield virtualbox.kill();
|
||||||
name: 'installing_virtualbox',
|
}
|
||||||
|
yield util.exec(['hdiutil', 'attach', path.join(setupUtil.supportDir(), packagejson['virtualbox-filename'])]);
|
||||||
|
var isSudo = yield setupUtil.isSudo();
|
||||||
|
var iconPath = path.join(setupUtil.resourceDir(), 'kitematic.icns');
|
||||||
|
var sudoCmd = isSudo ? ['sudo'] : [path.join(setupUtil.resourceDir(), 'cocoasudo'), '--icon=' + iconPath, `--prompt=${SUDO_PROMPT}`];
|
||||||
|
sudoCmd.push.apply(sudoCmd, ['installer', '-pkg', '/Volumes/VirtualBox/VirtualBox.pkg', '-target', '/']);
|
||||||
|
yield util.exec(sudoCmd);
|
||||||
|
yield util.exec(['hdiutil', 'detach', '/Volumes/VirtualBox']);
|
||||||
|
}),
|
||||||
|
cleanupKitematicStep: function () {
|
||||||
|
return virtualbox.vmdestroy('kitematic-vm');
|
||||||
},
|
},
|
||||||
cleanupKitematicStep: {
|
initBoot2DockerStep: Promise.coroutine(function* () {
|
||||||
run: function (callback) {
|
var exists = yield boot2docker.exists();
|
||||||
virtualbox.vmdestroy('kitematic-vm', function (err, removed) {
|
if (!exists) {
|
||||||
if (err) {
|
yield boot2docker.init();
|
||||||
console.log(err);
|
return;
|
||||||
}
|
}
|
||||||
callback();
|
|
||||||
});
|
if (!boot2docker.haskeys()) {
|
||||||
},
|
throw new Error('Boot2Docker SSH key doesn\'t exist. Fix by removing the existing Boot2Docker VM and re-run the installer. This usually occurs because an old version of Boot2Docker is installed.');
|
||||||
name: 'cleanup_kitematic',
|
}
|
||||||
|
|
||||||
|
var isoversion = yield boot2docker.isoversion();
|
||||||
|
if (!isoversion || setupUtil.compareVersions(isoversion, boot2docker.version()) < 0) {
|
||||||
|
yield boot2docker.stop();
|
||||||
|
yield boot2docker.upgrade();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
startBoot2DockerStep: function () {
|
||||||
|
return boot2docker.waitstatus('saving').then(boot2docker.status).then(status => {
|
||||||
|
if (status !== 'running') {
|
||||||
|
return boot2docker.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
initBoot2DockerStep: {
|
step: function () {
|
||||||
run: function (callback) {
|
|
||||||
boot2docker.exists(function (err, exists) {
|
|
||||||
if (err) { callback(err); return; }
|
|
||||||
if (!exists) {
|
|
||||||
boot2docker.init(function (err) {
|
|
||||||
callback(err);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (!boot2docker.sshKeyExists()) {
|
|
||||||
callback('Boot2Docker SSH key doesn\'t exist. Fix by removing the existing Boot2Docker VM and re-run the installer. This usually occurs because an old version of Boot2Docker is installed.');
|
|
||||||
} else {
|
|
||||||
boot2docker.isoVersion(function (err, version) {
|
|
||||||
if (err || setupUtil.compareVersions(version, boot2docker.version()) < 0) {
|
|
||||||
boot2docker.stop(function(err) {
|
|
||||||
boot2docker.upgrade(function (err) {
|
|
||||||
callback(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
name: 'init_boot2docker',
|
|
||||||
},
|
|
||||||
startBoot2DockerStep: {
|
|
||||||
run: function (callback) {
|
|
||||||
boot2docker.waitWhileStatus('saving', function (err) {
|
|
||||||
boot2docker.status(function (err, status) {
|
|
||||||
if (err) {callback(err); return;}
|
|
||||||
if (status !== 'running') {
|
|
||||||
boot2docker.start(function (err) {
|
|
||||||
callback(err);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
name: 'start_boot2docker',
|
|
||||||
},
|
|
||||||
stepName: function () {
|
|
||||||
if (_currentStep) {
|
if (_currentStep) {
|
||||||
return _currentStep.name;
|
return _currentStep;
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
stepProgress: function () {
|
percent: function () {
|
||||||
return _progress;
|
return _percent;
|
||||||
},
|
},
|
||||||
error: function () {
|
error: function () {
|
||||||
return _error;
|
return _error;
|
||||||
},
|
},
|
||||||
run: function (callback) {
|
run: Promise.coroutine(function* () {
|
||||||
var self = this;
|
var steps = [{
|
||||||
var steps = [this.downloadVirtualboxStep, this.installVirtualboxStep, this.cleanupKitematicStep, this.initBoot2DockerStep, this.startBoot2DockerStep];
|
name: 'download_virtualbox',
|
||||||
async.eachSeries(steps, function (step, callback) {
|
run: this.downloadVirtualboxStep
|
||||||
_currentStep = step;
|
}, {
|
||||||
_progress = 0;
|
name: 'install_virtualbox',
|
||||||
self.emit(self.STEP_EVENT);
|
run: this.installVirtualboxStep
|
||||||
|
}, {
|
||||||
|
name: 'cleanup_kitematic',
|
||||||
|
run: this.cleanupKitematicStep
|
||||||
|
}, {
|
||||||
|
name: 'init_boot2docker',
|
||||||
|
run: this.initBoot2DockerStep
|
||||||
|
}, {
|
||||||
|
name: 'start_boot2docker',
|
||||||
|
run: this.startBoot2DockerStep
|
||||||
|
}];
|
||||||
|
|
||||||
step.run(function (err) {
|
_error = null;
|
||||||
if (err) {
|
for (let step of steps) {
|
||||||
callback(err);
|
console.log(step.name);
|
||||||
} else {
|
_currentStep = step.name;
|
||||||
callback();
|
_percent = 0;
|
||||||
}
|
this.emit(this.STEP_EVENT);
|
||||||
}, function (progress) {
|
try {
|
||||||
_progress = progress;
|
yield step.run();
|
||||||
self.emit(self.PROGRESS_EVENT, progress);
|
} catch (err) {
|
||||||
});
|
_error = err;
|
||||||
}, function (err) {
|
this.emit(this.ERROR_EVENT);
|
||||||
_error = err;
|
throw err;
|
||||||
if (err) {
|
|
||||||
self.emit(self.ERROR_EVENT);
|
|
||||||
callback(err);
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = SetupStore;
|
module.exports = SetupStore;
|
||||||
|
|
|
@ -4,9 +4,11 @@ var path = require('path');
|
||||||
var crypto = require('crypto');
|
var crypto = require('crypto');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var exec = require('exec');
|
var exec = require('exec');
|
||||||
|
var rp = require('request-promise');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
|
||||||
var SetupUtil = {
|
var SetupUtil = {
|
||||||
supportDir: function (callback) {
|
supportDir: function () {
|
||||||
var dirs = ['Library', 'Application\ Support', 'Kitematic'];
|
var dirs = ['Library', 'Application\ Support', 'Kitematic'];
|
||||||
var acc = process.env.HOME;
|
var acc = process.env.HOME;
|
||||||
dirs.forEach(function (d) {
|
dirs.forEach(function (d) {
|
||||||
|
@ -17,64 +19,53 @@ var SetupUtil = {
|
||||||
});
|
});
|
||||||
return acc;
|
return acc;
|
||||||
},
|
},
|
||||||
resourceDir: function (callback) {
|
resourceDir: function () {
|
||||||
return process.env.RESOURCES_PATH;
|
return process.env.RESOURCES_PATH;
|
||||||
},
|
},
|
||||||
isSudo: function (callback) {
|
isSudo: function () {
|
||||||
exec(['sudo', '-n', '-u', 'root', 'true'], function (stderr, stdout, code) {
|
return new Promise((resolve, reject) => {
|
||||||
if (code) {
|
exec(['sudo', '-n', '-u', 'root', 'true'], (stderr, stdout, code) => {
|
||||||
callback(stderr);
|
if (code) {
|
||||||
} else {
|
reject(stderr);
|
||||||
var isSudo = stderr.indexOf('a password is required') === -1;
|
}
|
||||||
callback(null, isSudo);
|
resolve(stderr.indexOf('a password is required') === -1);
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
download: function (url, filename, checksum, callback, progressCallback) {
|
download: function (url, filename, checksum, percentCallback) {
|
||||||
var doDownload = function () {
|
return new Promise((resolve, reject) => {
|
||||||
progress(request({
|
if (fs.existsSync(filename)) {
|
||||||
uri: url,
|
var existingChecksum = crypto.createHash('sha256').update(fs.readFileSync(filename), 'utf8').digest('hex');
|
||||||
rejectUnauthorized: false
|
if (existingChecksum === checksum) {
|
||||||
}), {
|
resolve();
|
||||||
throttle: 250
|
} else {
|
||||||
}).on('progress', function (state) {
|
fs.unlinkSync(filename);
|
||||||
progressCallback(state.percent);
|
}
|
||||||
}).on('error', function (err) {
|
}
|
||||||
callback(err);
|
|
||||||
}).pipe(fs.createWriteStream(filename)).on('error', function (err) {
|
|
||||||
callback(err);
|
|
||||||
}).on('close', function (err) {
|
|
||||||
callback(err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Compare checksum to see if it already exists first
|
progress(request({ uri: url, rejectUnauthorized: false }), { throttle: 250 }).on('progress', state => {
|
||||||
if (fs.existsSync(filename)) {
|
percentCallback(state.percent);
|
||||||
var existingChecksum = crypto.createHash('sha256').update(fs.readFileSync(filename), 'utf8').digest('hex');
|
}).on('error', err => {
|
||||||
if (existingChecksum !== checksum) {
|
reject(err);
|
||||||
fs.unlinkSync(filename);
|
}).pipe(fs.createWriteStream(filename)).on('error', err => {
|
||||||
doDownload();
|
reject(err);
|
||||||
} else {
|
}).on('close', err => {
|
||||||
callback();
|
if (err) {
|
||||||
}
|
reject(err);
|
||||||
} else {
|
}
|
||||||
doDownload();
|
resolve();
|
||||||
}
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
virtualboxSHA256: function (version, filename, callback) {
|
virtualboxSHA256: function (version, filename) {
|
||||||
var checksumUrl = 'http://dlc-cdn.sun.com/virtualbox/' + version + '/SHA256SUMS';
|
return rp(`http://dlc-cdn.sun.com/virtualbox/${version}/SHA256SUMS`).then((body) => {
|
||||||
request(checksumUrl, function (error, response, body) {
|
var checksums = body.split('\n').map(line => {
|
||||||
if (error) {
|
|
||||||
callback(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var checksums = body.split('\n').map(function (line) {
|
|
||||||
return line.split(' *');
|
return line.split(' *');
|
||||||
}).reduce(function (obj, pair) {
|
}).reduce((obj, pair) => {
|
||||||
obj[pair[1]] = pair[0];
|
obj[pair[1]] = pair[0];
|
||||||
return obj;
|
return obj;
|
||||||
}, {});
|
}, {});
|
||||||
callback(null, checksums[filename]);
|
return Promise.resolve(checksums[filename]);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
compareVersions: function (v1, v2, options) {
|
compareVersions: function (v1, v2, options) {
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
var exec = require('exec');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
exec: function (args) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
exec(args, (stderr, stdout, code) => {
|
||||||
|
if (code) {
|
||||||
|
reject(stderr);
|
||||||
|
}
|
||||||
|
resolve(stdout);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
home: function () {
|
||||||
|
return process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,7 +1,6 @@
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var exec = require('exec');
|
var util = require('./Util');
|
||||||
var path = require('path');
|
var Promise = require('bluebird');
|
||||||
var async = require('async');
|
|
||||||
|
|
||||||
var VirtualBox = {
|
var VirtualBox = {
|
||||||
command: function () {
|
command: function () {
|
||||||
|
@ -10,85 +9,57 @@ var VirtualBox = {
|
||||||
installed: function () {
|
installed: function () {
|
||||||
return fs.existsSync('/usr/bin/VBoxManage') && fs.existsSync('/Applications/VirtualBox.app/Contents/MacOS/VirtualBox');
|
return fs.existsSync('/usr/bin/VBoxManage') && fs.existsSync('/Applications/VirtualBox.app/Contents/MacOS/VirtualBox');
|
||||||
},
|
},
|
||||||
version: function (callback) {
|
version: function () {
|
||||||
if (!this.installed()) {
|
if (!this.installed()) {
|
||||||
callback('VirtualBox not installed.');
|
return Promise.reject('VirtualBox not installed.');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
exec([this.command(), '-v'], function (stderr, stdout, code) {
|
return new Promise((resolve, reject) => {
|
||||||
if (code) {
|
util.exec([this.command(), '-v']).then(stdout => {
|
||||||
callback(stderr);
|
var match = stdout.match(/(\d+\.\d+\.\d+).*/);
|
||||||
return;
|
if (!match || match.length < 2) {
|
||||||
}
|
reject('VBoxManage -v output format not recognized.');
|
||||||
// Output is x.x.xryyyyyy
|
}
|
||||||
var match = stdout.match(/(\d+\.\d+\.\d+).*/);
|
resolve(match[1]);
|
||||||
if (!match || match.length < 2) {
|
}).catch(reject);
|
||||||
callback('VBoxManage -v output format not recognized.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback(null, match[1]);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
poweroff: function (callback) {
|
poweroffall: function () {
|
||||||
if (!this.installed()) {
|
if (!this.installed()) {
|
||||||
callback('VirtualBox not installed.');
|
return Promise.reject('VirtualBox not installed.');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
exec(this.command() + ' list runningvms | sed -E \'s/.*\\{(.*)\\}/\\1/\' | xargs -L1 -I {} ' + this.command() + ' controlvm {} acpipowerbutton', function (stderr, stdout, code) {
|
return util.exec(this.command() + ' list runningvms | sed -E \'s/.*\\{(.*)\\}/\\1/\' | xargs -L1 -I {} ' + this.command() + ' controlvm {} poweroff');
|
||||||
if (code) {
|
},
|
||||||
callback(stderr);
|
kill: function () {
|
||||||
} else {
|
if (!this.installed()) {
|
||||||
callback();
|
return Promise.reject('VirtualBox not installed.');
|
||||||
}
|
}
|
||||||
|
return this.poweroffall().then(() => {
|
||||||
|
return util.exec(['pkill', 'VirtualBox']);
|
||||||
|
}).then(() => {
|
||||||
|
return util.exec(['pkill', 'VBox']);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
kill: function (callback) {
|
vmstate: function (name) {
|
||||||
this.poweroff(function (err) {
|
return new Promise((resolve, reject) => {
|
||||||
if (err) {callback(err); return;}
|
util.exec([this.command(), 'showvminfo', name, '--machinereadable']).then(stdout => {
|
||||||
exec('pkill VirtualBox', function (stderr, stdout, code) {
|
var match = stdout.match(/VMState="(\w+)"/);
|
||||||
if (code) {callback(stderr); return;}
|
if (!match) {
|
||||||
exec('pkill VBox', function (stderr, stdout, code) {
|
reject('Could not parse VMState');
|
||||||
if (code) {callback(stderr); return;}
|
}
|
||||||
callback();
|
resolve(match[1]);
|
||||||
});
|
}).catch(reject);
|
||||||
});
|
});
|
||||||
});
|
},
|
||||||
},
|
vmdestroy: function (name) {
|
||||||
vmstate: function (name, callback) {
|
if (!this.installed()) {
|
||||||
exec(this.command() + ' showvminfo ' + name + ' --machinereadable', function (stderr, stdout, code) {
|
throw Promise.reject('VirtualBox not installed.');
|
||||||
if (code) { callback(stderr); return; }
|
}
|
||||||
var match = stdout.match(/VMState="(\w+)"/);
|
return util.exec([this.command(), 'controlvm', name, 'poweroff']).then(() => {
|
||||||
if (!match) {
|
return util.exec([this.command(), 'unregistervm', name, '--delete']).then(() => {
|
||||||
callback('Could not parse VMState');
|
return true;
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback(null, match[1]);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
vmdestroy: function (name, callback) {
|
|
||||||
var self = this;
|
|
||||||
this.vmstate(name, function (err, state) {
|
|
||||||
// No VM found
|
|
||||||
if (err) { callback(null, false); return; }
|
|
||||||
exec('/usr/bin/VBoxManage controlvm ' + name + ' acpipowerbutton', function (stderr, stdout, code) {
|
|
||||||
if (code) { callback(stderr, false); return; }
|
|
||||||
var state = null;
|
|
||||||
|
|
||||||
async.until(function () {
|
|
||||||
return state === 'poweroff';
|
|
||||||
}, function (callback) {
|
|
||||||
self.vmstate(name, function (err, newState) {
|
|
||||||
if (err) { callback(err); return; }
|
|
||||||
state = newState;
|
|
||||||
setTimeout(callback, 250);
|
|
||||||
});
|
|
||||||
}, function (err) {
|
|
||||||
exec('/usr/bin/VBoxManage unregistervm ' + name + ' --delete', function (stderr, stdout, code) {
|
|
||||||
if (code) { callback(err); return; }
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
}).catch(() => {
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
require.main.paths.splice(0, 0, process.env.NODE_PATH);
|
||||||
|
require('./Main');
|
|
@ -0,0 +1,57 @@
|
||||||
|
var boot2docker = require('../build/Boot2Docker');
|
||||||
|
var path = require('path');
|
||||||
|
var fs = require('fs');
|
||||||
|
var packagejson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
||||||
|
|
||||||
|
describe('Boot2Docker', () => {
|
||||||
|
it('cli version is correct', done => {
|
||||||
|
boot2docker.cliversion().then(version => {
|
||||||
|
expect(version).toBe(packagejson['boot2docker-version']);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with an existing & running boot2docker vm', () => {
|
||||||
|
beforeAll(done => {
|
||||||
|
boot2docker.init().then(boot2docker.start).then(() => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates a vm', done => {
|
||||||
|
boot2docker.exists().then(exists => {
|
||||||
|
expect(exists).toBe(true);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('detects the correct state of running vm', done => {
|
||||||
|
boot2docker.status().then(status => {
|
||||||
|
expect(status).toBe('running');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('detects ssh keys', () => {
|
||||||
|
expect(boot2docker.haskeys()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('receives an ip address from the vm', done => {
|
||||||
|
boot2docker.ip().then(ip => {
|
||||||
|
expect(ip).toMatch(/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reads a version from the boot2docker iso file', done => {
|
||||||
|
boot2docker.isoversion().then(version => {
|
||||||
|
expect(version).toMatch(/\d+\.\d+\.\d+/);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(done => {
|
||||||
|
boot2docker.destroy().finally(done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -3,57 +3,12 @@ var SetupStore = require('../build/SetupStore');
|
||||||
var setupUtil = require('../build/SetupUtil');
|
var setupUtil = require('../build/SetupUtil');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var child_process = require('child_process');
|
var Promise = require('bluebird');
|
||||||
var exec = require('exec');
|
|
||||||
var rimraf = require('rimraf');
|
|
||||||
var packagejson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
var packagejson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
||||||
|
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 300000; // 5 minutes
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 300000; // 5 minutes for integration tests
|
||||||
|
|
||||||
describe('Setup', function () {
|
describe('Setup', function () {
|
||||||
describe('without virtualbox installed or downloaded', function () {
|
|
||||||
var virtualboxFile = path.join(setupUtil.supportDir(), packagejson['virtualbox-filename']);
|
|
||||||
beforeEach(function () {
|
|
||||||
if (fs.existsSync(virtualboxFile)) {
|
|
||||||
fs.unlinkSync(virtualboxFile);
|
|
||||||
}
|
|
||||||
spyOn(virtualbox, 'installed').and.returnValue(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('downloads virtualbox from the official website', function (done) {
|
|
||||||
SetupStore.downloadVirtualboxStep.run(function (err) {
|
|
||||||
expect(err).toBeFalsy();
|
|
||||||
expect(fs.existsSync(virtualboxFile)).toBe(true);
|
|
||||||
done();
|
|
||||||
}, function (progress) {
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('with virtualbox downloaded but not installed', function () {
|
|
||||||
beforeEach(function (done) {
|
|
||||||
// 5 minute timeout per test
|
|
||||||
|
|
||||||
SetupStore.downloadVirtualboxStep.run(function (err) {
|
|
||||||
if (virtualbox.installed()) {
|
|
||||||
virtualbox.kill(function (callback) {
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
}, function (progress) {});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does install virtualbox', function (done) {
|
|
||||||
SetupStore.installVirtualboxStep.run(function (err) {
|
|
||||||
expect(err).toBeFalsy();
|
|
||||||
expect(fs.existsSync(virtualbox.command())).toBe(true);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('with virtualbox installed', function () {
|
describe('with virtualbox installed', function () {
|
||||||
|
|
||||||
|
@ -96,4 +51,41 @@ describe('Setup', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*describe('with virtualbox downloaded', function () {
|
||||||
|
beforeEach(function (done) {
|
||||||
|
Promise.coroutine(SetupStore.downloadVirtualboxStep)().finally(function () {
|
||||||
|
if (virtualbox.installed()) {
|
||||||
|
virtualbox.kill().finally(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('install virtualbox succeeds', function (done) {
|
||||||
|
Promise.coroutine(SetupStore.installVirtualboxStep)().finally(function () {
|
||||||
|
expect(virtualbox.installed()).toBe(true);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});*/
|
||||||
|
|
||||||
|
/*describe('without virtualbox installed or downloaded', function () {
|
||||||
|
var virtualboxFile = path.join(setupUtil.supportDir(), packagejson['virtualbox-filename']);
|
||||||
|
beforeEach(function () {
|
||||||
|
if (fs.existsSync(virtualboxFile)) {
|
||||||
|
fs.unlinkSync(virtualboxFile);
|
||||||
|
}
|
||||||
|
spyOn(virtualbox, 'installed').and.returnValue(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('downloads virtualbox from the official website', function (done) {
|
||||||
|
Promise.coroutine(SetupStore.downloadVirtualboxStep)().finally(function () {
|
||||||
|
expect(fs.existsSync(virtualboxFile)).toBe(true);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});*/
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,7 @@ var setupUtil = require('../build/SetupUtil');
|
||||||
|
|
||||||
describe('SetupUtils', function() {
|
describe('SetupUtils', function() {
|
||||||
it('returns live sha256 checksum for a given virtualbox version & filename', function (done) {
|
it('returns live sha256 checksum for a given virtualbox version & filename', function (done) {
|
||||||
setupUtil.virtualboxSHA256('4.3.20', 'VirtualBox-4.3.20-96996-OSX.dmg', function (err, checksum) {
|
setupUtil.virtualboxSHA256('4.3.20', 'VirtualBox-4.3.20-96996-OSX.dmg').then(function (checksum) {
|
||||||
expect(checksum).toBe('744e77119a640a5974160213c9912568a3d88dbd06a2fc6b6970070941732705');
|
expect(checksum).toBe('744e77119a640a5974160213c9912568a3d88dbd06a2fc6b6970070941732705');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
var virtualbox = require('../build/Virtualbox');
|
||||||
|
var util = require('../build/Util');
|
||||||
|
|
||||||
|
describe('Virtualbox', function () {
|
||||||
|
beforeAll(function () {
|
||||||
|
// Make sure VirtualBox is installed
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with a running VM', function () {
|
||||||
|
beforeEach(function (done) {
|
||||||
|
return util.exec([virtualbox.command(), 'createvm', '--name', 'km-test', '--register']).finally(function () {
|
||||||
|
return util.exec([virtualbox.command(), 'startvm', 'km-test', '--type', 'headless']);
|
||||||
|
}).then(function() {
|
||||||
|
done();
|
||||||
|
}).catch(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('powers off all vms', function (done) {
|
||||||
|
virtualbox.poweroffall().then(function () {
|
||||||
|
return virtualbox.vmstate('km-test');
|
||||||
|
}).then(function (state) {
|
||||||
|
expect(state).toBe('poweroff');
|
||||||
|
done();
|
||||||
|
}).catch(function (err) {
|
||||||
|
expect(err).toBeFalsy();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('destroys a vm', function (done) {
|
||||||
|
virtualbox.vmdestroy('km-test').then(function () {
|
||||||
|
return util.exec([virtualbox.command(), 'showvminfo', 'km-test']).then(function () {
|
||||||
|
done();
|
||||||
|
}).catch(function (err) {
|
||||||
|
expect(err).toBeTruthy();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}).catch(function (err) {
|
||||||
|
console.log(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function (done) {
|
||||||
|
util.exec([virtualbox.command(), 'controlvm', 'km-test', 'poweroff']).finally(function () {
|
||||||
|
return util.exec([virtualbox.command(), 'unregistervm', 'km-test', '--delete']);
|
||||||
|
}).then(function () {
|
||||||
|
done();
|
||||||
|
}).catch(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,21 @@
|
||||||
|
var virtualbox = require('../build/Virtualbox');
|
||||||
|
var util = require('../build/Util');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
|
||||||
|
describe('Virtualbox', function () {
|
||||||
|
it('returns the right command', function () {
|
||||||
|
expect(virtualbox.command()).toBe('/usr/bin/VBoxManage');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('version 4.3.20r96996', function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
spyOn(util, 'exec').and.returnValue(Promise.resolve('4.3.20r96996'));
|
||||||
|
});
|
||||||
|
it('correctly parses virtualbox version', function (done) {
|
||||||
|
virtualbox.version().then(function (version) {
|
||||||
|
expect(version).toBe('4.3.20');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -7,6 +7,7 @@ var app = require('remote').require('app');
|
||||||
jasmine.getEnv().addReporter(new consoleReporter.ConsoleReporter()({
|
jasmine.getEnv().addReporter(new consoleReporter.ConsoleReporter()({
|
||||||
showColors: true,
|
showColors: true,
|
||||||
timer: new jasmine.Timer(),
|
timer: new jasmine.Timer(),
|
||||||
|
verbose: true,
|
||||||
print: function() {
|
print: function() {
|
||||||
process.stdout.write.apply(process.stdout, arguments);
|
process.stdout.write.apply(process.stdout, arguments);
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue