mirror of https://github.com/docker/docs.git
Merge pull request #177 from kitematic/setup-cancel
Install docker and boot2docker with Kitematic
This commit is contained in:
commit
e8f87e1ebe
|
@ -1,3 +1,7 @@
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- 0.10
|
- 0.10
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- node_modules
|
||||||
|
- resources
|
||||||
|
|
|
@ -12,7 +12,7 @@ describe('SetupStore', function () {
|
||||||
pit('downloads virtualbox if it is not installed', function () {
|
pit('downloads virtualbox if it is not installed', function () {
|
||||||
virtualBox.installed.mockReturnValue(false);
|
virtualBox.installed.mockReturnValue(false);
|
||||||
setupUtil.download.mockReturnValue(Promise.resolve());
|
setupUtil.download.mockReturnValue(Promise.resolve());
|
||||||
return setupStore.steps().downloadVirtualBox.run().then(() => {
|
return setupStore.steps().download.run().then(() => {
|
||||||
// TODO: make sure download was called with the right args
|
// TODO: make sure download was called with the right args
|
||||||
expect(setupUtil.download).toBeCalled();
|
expect(setupUtil.download).toBeCalled();
|
||||||
});
|
});
|
||||||
|
@ -23,30 +23,18 @@ describe('SetupStore', function () {
|
||||||
virtualBox.version.mockReturnValue(Promise.resolve('4.3.16'));
|
virtualBox.version.mockReturnValue(Promise.resolve('4.3.16'));
|
||||||
setupUtil.compareVersions.mockReturnValue(-1);
|
setupUtil.compareVersions.mockReturnValue(-1);
|
||||||
setupUtil.download.mockReturnValue(Promise.resolve());
|
setupUtil.download.mockReturnValue(Promise.resolve());
|
||||||
return setupStore.steps().downloadVirtualBox.run().then(() => {
|
return setupStore.steps().download.run().then(() => {
|
||||||
expect(setupUtil.download).toBeCalled();
|
expect(setupUtil.download).toBeCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('skips download if virtualbox is already installed', function () {
|
|
||||||
virtualBox.installed.mockReturnValue(true);
|
|
||||||
virtualBox.version.mockReturnValue(Promise.resolve('4.3.20'));
|
|
||||||
setupUtil.download.mockClear();
|
|
||||||
setupUtil.download.mockReturnValue(Promise.resolve());
|
|
||||||
setupUtil.compareVersions.mockReturnValue(1);
|
|
||||||
return setupStore.steps().downloadVirtualBox.run().then(() => {
|
|
||||||
expect(setupUtil.download).not.toBeCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('install step', function () {
|
describe('install step', function () {
|
||||||
pit('installs virtualbox if it is not installed', function () {
|
pit('installs virtualbox if it is not installed', function () {
|
||||||
virtualBox.installed.mockReturnValue(false);
|
virtualBox.installed.mockReturnValue(false);
|
||||||
virtualBox.killall.mockReturnValue(Promise.resolve());
|
virtualBox.killall.mockReturnValue(Promise.resolve());
|
||||||
setupUtil.isSudo.mockReturnValue(Promise.resolve(false));
|
|
||||||
util.exec.mockReturnValue(Promise.resolve());
|
util.exec.mockReturnValue(Promise.resolve());
|
||||||
return setupStore.steps().installVirtualBox.run().then(() => {
|
return setupStore.steps().install.run().then(() => {
|
||||||
// TODO: make sure that the right install command was executed
|
// TODO: make sure that the right install command was executed
|
||||||
expect(util.exec).toBeCalled();
|
expect(util.exec).toBeCalled();
|
||||||
});
|
});
|
||||||
|
@ -56,29 +44,14 @@ describe('SetupStore', function () {
|
||||||
virtualBox.installed.mockReturnValue(true);
|
virtualBox.installed.mockReturnValue(true);
|
||||||
virtualBox.version.mockReturnValue(Promise.resolve('4.3.16'));
|
virtualBox.version.mockReturnValue(Promise.resolve('4.3.16'));
|
||||||
virtualBox.killall.mockReturnValue(Promise.resolve());
|
virtualBox.killall.mockReturnValue(Promise.resolve());
|
||||||
setupUtil.isSudo.mockReturnValue(Promise.resolve(false));
|
|
||||||
setupUtil.compareVersions.mockReturnValue(-1);
|
setupUtil.compareVersions.mockReturnValue(-1);
|
||||||
util.exec.mockReturnValue(Promise.resolve());
|
util.exec.mockReturnValue(Promise.resolve());
|
||||||
return setupStore.steps().installVirtualBox.run().then(() => {
|
return setupStore.steps().install.run().then(() => {
|
||||||
// TODO: make sure the right install command was executed
|
// TODO: make sure the right install command was executed
|
||||||
expect(virtualBox.killall).toBeCalled();
|
expect(virtualBox.killall).toBeCalled();
|
||||||
expect(util.exec).toBeCalled();
|
expect(util.exec).toBeCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('skips install if virtualbox is already installed', function () {
|
|
||||||
virtualBox.installed.mockReturnValue(true);
|
|
||||||
virtualBox.version.mockReturnValue(Promise.resolve('4.3.20'));
|
|
||||||
setupUtil.isSudo.mockReturnValue(Promise.resolve(false));
|
|
||||||
setupUtil.compareVersions.mockReturnValue(-1);
|
|
||||||
util.exec.mockReturnValue(Promise.resolve());
|
|
||||||
return setupStore.steps().installVirtualBox.run().then(() => {
|
|
||||||
virtualBox.killall.mockClear();
|
|
||||||
util.exec.mockClear();
|
|
||||||
expect(virtualBox.killall).not.toBeCalled();
|
|
||||||
expect(util.exec).not.toBeCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('init step', function () {
|
describe('init step', function () {
|
||||||
|
@ -86,7 +59,7 @@ describe('SetupStore', function () {
|
||||||
pit('inintializes the boot2docker vm if it does not exist', function () {
|
pit('inintializes the boot2docker vm if it does not exist', function () {
|
||||||
boot2docker.exists.mockReturnValue(Promise.resolve(false));
|
boot2docker.exists.mockReturnValue(Promise.resolve(false));
|
||||||
boot2docker.init.mockReturnValue(Promise.resolve());
|
boot2docker.init.mockReturnValue(Promise.resolve());
|
||||||
return setupStore.steps().initBoot2Docker.run().then(() => {
|
return setupStore.steps().init.run().then(() => {
|
||||||
expect(boot2docker.init).toBeCalled();
|
expect(boot2docker.init).toBeCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -98,7 +71,7 @@ describe('SetupStore', function () {
|
||||||
boot2docker.stop.mockReturnValue(Promise.resolve());
|
boot2docker.stop.mockReturnValue(Promise.resolve());
|
||||||
boot2docker.upgrade.mockReturnValue(Promise.resolve());
|
boot2docker.upgrade.mockReturnValue(Promise.resolve());
|
||||||
setupUtil.compareVersions.mockReturnValue(-1);
|
setupUtil.compareVersions.mockReturnValue(-1);
|
||||||
return setupStore.steps().initBoot2Docker.run().then(() => {
|
return setupStore.steps().init.run().then(() => {
|
||||||
boot2docker.init.mockClear();
|
boot2docker.init.mockClear();
|
||||||
expect(boot2docker.init).not.toBeCalled();
|
expect(boot2docker.init).not.toBeCalled();
|
||||||
expect(boot2docker.upgrade).toBeCalled();
|
expect(boot2docker.upgrade).toBeCalled();
|
||||||
|
@ -111,7 +84,7 @@ describe('SetupStore', function () {
|
||||||
boot2docker.status.mockReturnValue(false);
|
boot2docker.status.mockReturnValue(false);
|
||||||
boot2docker.waitstatus.mockReturnValue(Promise.resolve());
|
boot2docker.waitstatus.mockReturnValue(Promise.resolve());
|
||||||
boot2docker.start.mockReturnValue(Promise.resolve());
|
boot2docker.start.mockReturnValue(Promise.resolve());
|
||||||
return setupStore.steps().startBoot2Docker.run().then(() => {
|
return setupStore.steps().start.run().then(() => {
|
||||||
expect(boot2docker.start).toBeCalled();
|
expect(boot2docker.start).toBeCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,7 +17,7 @@ var _logs = {};
|
||||||
var _streams = {};
|
var _streams = {};
|
||||||
var _muted = {};
|
var _muted = {};
|
||||||
|
|
||||||
var ContainerStore = assign(EventEmitter.prototype, {
|
var ContainerStore = assign(Object.create(EventEmitter.prototype), {
|
||||||
CLIENT_CONTAINER_EVENT: 'client_container_event',
|
CLIENT_CONTAINER_EVENT: 'client_container_event',
|
||||||
CLIENT_RECOMMENDED_EVENT: 'client_recommended_event',
|
CLIENT_RECOMMENDED_EVENT: 'client_recommended_event',
|
||||||
SERVER_CONTAINER_EVENT: 'server_container_event',
|
SERVER_CONTAINER_EVENT: 'server_container_event',
|
||||||
|
|
|
@ -8,8 +8,10 @@ var docker = require('./Docker');
|
||||||
var router = require('./router');
|
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('./SetupStore');
|
||||||
var settingsjson;
|
var settingsjson;
|
||||||
|
var Menu = require('./Menu');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
|
settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -34,6 +36,7 @@ bugsnag.appVersion = app.getVersion();
|
||||||
router.run(Handler => React.render(<Handler/>, document.body));
|
router.run(Handler => React.render(<Handler/>, document.body));
|
||||||
if (!window.location.hash.length || window.location.hash === '#/') {
|
if (!window.location.hash.length || window.location.hash === '#/') {
|
||||||
SetupStore.run().then(boot2docker.ip).then(ip => {
|
SetupStore.run().then(boot2docker.ip).then(ip => {
|
||||||
|
console.log(ip);
|
||||||
docker.setHost(ip);
|
docker.setHost(ip);
|
||||||
ContainerStore.init(function (err) {
|
ContainerStore.init(function (err) {
|
||||||
if (err) { console.log(err); }
|
if (err) { console.log(err); }
|
||||||
|
|
25
src/Menu.js
25
src/Menu.js
|
@ -1,8 +1,11 @@
|
||||||
var remote = require('remote');
|
var remote = require('remote');
|
||||||
var app = remote.require('app');
|
var app = remote.require('app');
|
||||||
|
var path = require('path');
|
||||||
|
var docker = require('./Docker');
|
||||||
var Menu = remote.require('menu');
|
var Menu = remote.require('menu');
|
||||||
var BrowserWindow = remote.require('browser-window');
|
var BrowserWindow = remote.require('browser-window');
|
||||||
var router = require('./Router');
|
var router = require('./Router');
|
||||||
|
var util = require('./Util');
|
||||||
|
|
||||||
// main.js
|
// main.js
|
||||||
var template = [
|
var template = [
|
||||||
|
@ -59,6 +62,28 @@ var template = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'File',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'New Container',
|
||||||
|
accelerator: 'Command+N',
|
||||||
|
selector: 'undo:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Open Docker Terminal',
|
||||||
|
accelerator: 'Command+Shift+T',
|
||||||
|
click: function() {
|
||||||
|
var terminal = path.join(process.cwd(), 'resources', 'terminal');
|
||||||
|
var cmd = [terminal, `DOCKER_HOST=${'tcp://' + docker.host + ':2376'} DOCKER_CERT_PATH=${path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], '.boot2docker/certs/boot2docker-vm')} DOCKER_TLS_VERIFY=1 $SHELL`];
|
||||||
|
util.exec(cmd).then(() => {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Edit',
|
label: 'Edit',
|
||||||
submenu: [
|
submenu: [
|
||||||
|
|
|
@ -83,7 +83,7 @@ var Setup = React.createClass({
|
||||||
<div className="content">
|
<div className="content">
|
||||||
<h4>Installation Cancelled</h4>
|
<h4>Installation Cancelled</h4>
|
||||||
<h1>Couldn't Install VirtualBox</h1>
|
<h1>Couldn't Install VirtualBox</h1>
|
||||||
<p>Kitematic did not receive the administrative privileges required to install VirtualBox.</p>
|
<p>Kitematic did not receive the administrative privileges required to install VirtualBox & Docker.</p>
|
||||||
<p>Please retry or download & install VirutalBox manually from the <a onClick={this.handleOpenWebsite}>official Oracle website</a>.</p>
|
<p>Please retry or download & install VirutalBox manually from the <a onClick={this.handleOpenWebsite}>official Oracle website</a>.</p>
|
||||||
<button className="btn btn-action" onClick={this.handleRetry}>Retry</button>
|
<button className="btn btn-action" onClick={this.handleRetry}>Retry</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var assign = require('object-assign');
|
|
||||||
var _ = require('underscore');
|
var _ = require('underscore');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var Promise = require('bluebird');
|
var Promise = require('bluebird');
|
||||||
|
@ -7,70 +6,60 @@ 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 util = require('./Util');
|
||||||
|
var assign = require('object-assign');
|
||||||
|
|
||||||
var SUDO_PROMPT = 'Kitematic requires administrative privileges to install VirtualBox.';
|
|
||||||
var _currentStep = null;
|
var _currentStep = null;
|
||||||
var _error = null;
|
var _error = null;
|
||||||
var _cancelled = false;
|
var _cancelled = false;
|
||||||
var _retryPromise = null;
|
var _retryPromise = null;
|
||||||
|
var _requiredSteps = [];
|
||||||
|
|
||||||
var _steps = [{
|
var _steps = [{
|
||||||
name: 'downloadVirtualBox',
|
name: 'download',
|
||||||
title: 'Downloading VirtualBox',
|
title: 'Downloading VirtualBox',
|
||||||
message: 'VirtualBox is being downloaded. Kitematic requires VirtualBox to run containers.',
|
message: 'VirtualBox is being downloaded. Kitematic requires VirtualBox to run containers.',
|
||||||
totalPercent: 35,
|
totalPercent: 35,
|
||||||
percent: 0,
|
percent: 0,
|
||||||
run: Promise.coroutine(function* (progressCallback) {
|
run: Promise.coroutine(function* (progressCallback) {
|
||||||
var packagejson = util.packagejson();
|
var packagejson = util.packagejson();
|
||||||
if (virtualBox.installed()) {
|
|
||||||
var version = yield virtualBox.version();
|
|
||||||
if (setupUtil.compareVersions(version, packagejson['virtualbox-required-version']) >= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var virtualBoxFile = `https://github.com/kitematic/virtualbox/releases/download/${packagejson['virtualbox-version']}/${packagejson['virtualbox-filename']}`;
|
var virtualBoxFile = `https://github.com/kitematic/virtualbox/releases/download/${packagejson['virtualbox-version']}/${packagejson['virtualbox-filename']}`;
|
||||||
yield setupUtil.download(virtualBoxFile, path.join(setupUtil.supportDir(), packagejson['virtualbox-filename']), packagejson['virtualbox-checksum'], percent => {
|
yield setupUtil.download(virtualBoxFile, path.join(util.supportDir(), packagejson['virtualbox-filename']), packagejson['virtualbox-checksum'], percent => {
|
||||||
progressCallback(percent);
|
progressCallback(percent);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
}, {
|
}, {
|
||||||
name: 'installVirtualBox',
|
name: 'install',
|
||||||
title: 'Installing VirtualBox',
|
title: 'Installing Docker & VirtualBox',
|
||||||
message: "VirtualBox is being installed in the background. We may need you to type in your password to continue.",
|
message: 'VirtualBox is being installed in the background. We may need you to type in your password to continue.',
|
||||||
totalPercent: 5,
|
totalPercent: 5,
|
||||||
percent: 0,
|
percent: 0,
|
||||||
seconds: 5,
|
seconds: 5,
|
||||||
run: Promise.coroutine(function* () {
|
run: Promise.coroutine(function* () {
|
||||||
var packagejson = util.packagejson();
|
var packagejson = util.packagejson();
|
||||||
if (virtualBox.installed()) {
|
var base = util.copyBinariesCmd() + ' && ' + util.fixBinariesCmd();
|
||||||
var version = yield virtualBox.version();
|
if (!virtualBox.installed() || setupUtil.compareVersions(yield virtualBox.version(), packagejson['virtualbox-required-version']) < 0) {
|
||||||
if (setupUtil.compareVersions(version, packagejson['virtualbox-required-version']) >= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
yield virtualBox.killall();
|
yield virtualBox.killall();
|
||||||
|
base += ` && installer -pkg ${path.join(util.supportDir(), packagejson['virtualbox-filename'])} -target /`;
|
||||||
}
|
}
|
||||||
var isSudo = yield setupUtil.isSudo();
|
var cmd = `${util.escapePath(path.join(util.resourceDir(), 'cocoasudo'))} --prompt="Kitematic requires administrative privileges to install VirtualBox." bash -c \"${base}\"`;
|
||||||
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', path.join(setupUtil.supportDir(), packagejson['virtualbox-filename']), '-target', '/']);
|
|
||||||
try {
|
try {
|
||||||
yield util.exec(sudoCmd);
|
yield util.exec(cmd);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw null;
|
throw null;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, {
|
}, {
|
||||||
name: 'initBoot2Docker',
|
name: 'init',
|
||||||
title: 'Setting up Docker VM',
|
title: 'Setting up Docker VM',
|
||||||
message: "To run Docker containers on your computer, we are setting up a Linux virtual machine provided by boot2docker.",
|
message: 'To run Docker containers on your computer, we are setting up a Linux virtual machine provided by boot2docker.',
|
||||||
totalPercent: 15,
|
totalPercent: 15,
|
||||||
percent: 0,
|
percent: 0,
|
||||||
seconds: 11,
|
seconds: 11,
|
||||||
run: Promise.coroutine(function* (progressCallback) {
|
run: Promise.coroutine(function* (progressCallback) {
|
||||||
|
setupUtil.simulateProgress(this.seconds, progressCallback);
|
||||||
yield virtualBox.vmdestroy('kitematic-vm');
|
yield virtualBox.vmdestroy('kitematic-vm');
|
||||||
var exists = yield boot2docker.exists();
|
var exists = yield boot2docker.exists();
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
setupUtil.simulateProgress(this.seconds, progressCallback);
|
|
||||||
yield boot2docker.init();
|
yield boot2docker.init();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -81,21 +70,20 @@ var _steps = [{
|
||||||
|
|
||||||
var isoversion = boot2docker.isoversion();
|
var isoversion = boot2docker.isoversion();
|
||||||
if (!isoversion || setupUtil.compareVersions(isoversion, boot2docker.version()) < 0) {
|
if (!isoversion || setupUtil.compareVersions(isoversion, boot2docker.version()) < 0) {
|
||||||
setupUtil.simulateProgress(this.seconds, progressCallback);
|
|
||||||
yield boot2docker.stop();
|
yield boot2docker.stop();
|
||||||
yield boot2docker.upgrade();
|
yield boot2docker.upgrade();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, {
|
}, {
|
||||||
name: 'startBoot2Docker',
|
name: 'start',
|
||||||
title: 'Starting Docker VM',
|
title: 'Starting Docker VM',
|
||||||
message: "Kitematic is starting the boot2docker VM. This may take about a minute.",
|
message: "Kitematic is starting the boot2docker VM. This may take about a minute.",
|
||||||
totalPercent: 45,
|
totalPercent: 45,
|
||||||
percent: 0,
|
percent: 0,
|
||||||
seconds: 35,
|
seconds: 35,
|
||||||
run: function (progressCallback) {
|
run: function (progressCallback) {
|
||||||
|
setupUtil.simulateProgress(this.seconds, progressCallback);
|
||||||
return boot2docker.waitstatus('saving').then(boot2docker.status).then(status => {
|
return boot2docker.waitstatus('saving').then(boot2docker.status).then(status => {
|
||||||
setupUtil.simulateProgress(this.seconds, progressCallback);
|
|
||||||
if (status !== 'running') {
|
if (status !== 'running') {
|
||||||
return boot2docker.start();
|
return boot2docker.start();
|
||||||
}
|
}
|
||||||
|
@ -103,28 +91,29 @@ var _steps = [{
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
var SetupStore = assign(EventEmitter.prototype, {
|
var SetupStore = assign(Object.create(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',
|
||||||
step: function () {
|
step: function () {
|
||||||
return _currentStep || _steps[0];
|
return _currentStep;
|
||||||
},
|
},
|
||||||
steps: function () {
|
steps: function () {
|
||||||
return _.indexBy(_steps, 'name');
|
return _.indexBy(_steps, 'name');
|
||||||
},
|
},
|
||||||
stepCount: function () {
|
stepCount: function () {
|
||||||
return _steps.length;
|
return _requiredSteps.length;
|
||||||
},
|
},
|
||||||
number: function () {
|
number: function () {
|
||||||
return _.indexOf(_steps, _currentStep) + 1;
|
return _.indexOf(_requiredSteps, _currentStep) + 1;
|
||||||
},
|
},
|
||||||
percent: function () {
|
percent: function () {
|
||||||
var total = 0;
|
var sofar = 0;
|
||||||
_.each(_steps, step => {
|
var totalPercent = _requiredSteps.reduce((prev, step) => prev + step.totalPercent, 0);
|
||||||
total += step.totalPercent * step.percent / 100;
|
_.each(_requiredSteps, step => {
|
||||||
|
sofar += step.totalPercent * step.percent / 100;
|
||||||
});
|
});
|
||||||
return Math.min(Math.round(total), 99);
|
return Math.min(Math.round(100 * sofar / totalPercent), 99);
|
||||||
},
|
},
|
||||||
error: function () {
|
error: function () {
|
||||||
return _error;
|
return _error;
|
||||||
|
@ -141,13 +130,37 @@ var SetupStore = assign(EventEmitter.prototype, {
|
||||||
_retryPromise = Promise.defer();
|
_retryPromise = Promise.defer();
|
||||||
return _retryPromise.promise;
|
return _retryPromise.promise;
|
||||||
},
|
},
|
||||||
run: Promise.coroutine(function* () {
|
init: Promise.coroutine(function* () {
|
||||||
|
var packagejson = util.packagejson();
|
||||||
|
var isoversion = boot2docker.isoversion();
|
||||||
|
var required = {};
|
||||||
|
required.download = !virtualBox.installed() || setupUtil.compareVersions(yield virtualBox.version(), packagejson['virtualbox-required-version']) < 0;
|
||||||
|
required.install = required.download || setupUtil.needsBinaryFix();
|
||||||
|
required.init = !(yield boot2docker.exists()) || !isoversion || setupUtil.compareVersions(isoversion, boot2docker.version()) < 0;
|
||||||
|
required.start = required.init || (yield boot2docker.status()) !== 'running';
|
||||||
|
|
||||||
var exists = yield boot2docker.exists();
|
var exists = yield boot2docker.exists();
|
||||||
if (exists) {
|
if (exists) {
|
||||||
this.steps().startBoot2Docker.seconds = 13;
|
this.steps().start.seconds = 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let step of _steps) {
|
_requiredSteps = _steps.filter(function (step) {
|
||||||
|
return required[step.name];
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
updateBinaries: function () {
|
||||||
|
if (setupUtil.needsBinaryFix()) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
if (setupUtil.shouldUpdateBinaries()) {
|
||||||
|
return util.exec(util.copyBinariesCmd());
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
run: Promise.coroutine(function* () {
|
||||||
|
yield this.init();
|
||||||
|
yield this.updateBinaries();
|
||||||
|
for (let step of _requiredSteps) {
|
||||||
_currentStep = step;
|
_currentStep = step;
|
||||||
step.percent = 0;
|
step.percent = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -163,6 +176,7 @@ var SetupStore = assign(EventEmitter.prototype, {
|
||||||
break;
|
break;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
console.log(err.stack);
|
||||||
_error = err;
|
_error = err;
|
||||||
this.emit(this.ERROR_EVENT);
|
this.emit(this.ERROR_EVENT);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,36 +1,33 @@
|
||||||
var _ = require('underscore');
|
var _ = require('underscore');
|
||||||
var crypto = require('crypto');
|
var crypto = require('crypto');
|
||||||
var exec = require('exec');
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
var request = require('request');
|
var request = require('request');
|
||||||
var progress = require('request-progress');
|
var progress = require('request-progress');
|
||||||
var path = require('path');
|
|
||||||
var Promise = require('bluebird');
|
var Promise = require('bluebird');
|
||||||
|
var util = require('./Util');
|
||||||
|
|
||||||
var SetupUtil = {
|
var SetupUtil = {
|
||||||
supportDir: function () {
|
needsBinaryFix: function () {
|
||||||
var dirs = ['Library', 'Application\ Support', 'Kitematic'];
|
if (!fs.existsSync('/usr/local/bin/docker') && !fs.existsSync('/usr/local/bin/boot2docker')) {
|
||||||
var acc = process.env.HOME;
|
return fs.statSync('/usr/local/bin').gid !== 80 || fs.statSync('/usr/local/bin').uid !== process.getuid();
|
||||||
dirs.forEach(function (d) {
|
}
|
||||||
acc = path.join(acc, d);
|
|
||||||
if (!fs.existsSync(acc)) {
|
if (fs.existsSync('/usr/local/bin/docker') && (fs.statSync('/usr/local/bin/docker').gid !== 80 || fs.statSync('/usr/local/bin/docker').uid !== process.getuid())) {
|
||||||
fs.mkdirSync(acc);
|
return true;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
return acc;
|
if (fs.existsSync('/usr/local/bin/boot2docker') && (fs.statSync('/usr/local/bin/boot2docker').gid !== 80 || fs.statSync('/usr/local/bin/boot2docker').uid !== process.getuid())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
resourceDir: function () {
|
shouldUpdateBinaries: function () {
|
||||||
return process.env.RESOURCES_PATH;
|
var packagejson = util.packagejson();
|
||||||
},
|
return !fs.existsSync('/usr/local/bin/docker') ||
|
||||||
isSudo: function () {
|
!fs.existsSync('/usr/local/bin/boot2docker') ||
|
||||||
return new Promise((resolve, reject) => {
|
this.checksum('/usr/local/bin/boot2docker') !== this.checksum(path.join(util.resourceDir(), 'boot2docker-' + packagejson['boot2docker-version'])) ||
|
||||||
exec(['sudo', '-n', '-u', 'root', 'true'], (stderr, stdout, code) => {
|
this.checksum('/usr/local/bin/docker') !== this.checksum(path.join(util.resourceDir(), 'docker-' + packagejson['docker-version']));
|
||||||
if (code) {
|
|
||||||
reject(stderr);
|
|
||||||
}
|
|
||||||
resolve(stderr.indexOf('a password is required') === -1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
simulateProgress: function (estimateSeconds, progress) {
|
simulateProgress: function (estimateSeconds, progress) {
|
||||||
var times = _.range(0, estimateSeconds * 1000, 200);
|
var times = _.range(0, estimateSeconds * 1000, 200);
|
||||||
|
@ -42,10 +39,13 @@ var SetupUtil = {
|
||||||
timers.push(timer);
|
timers.push(timer);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
checksum: function (filename) {
|
||||||
|
return crypto.createHash('sha256').update(fs.readFileSync(filename), 'utf8').digest('hex');
|
||||||
|
},
|
||||||
download: function (url, filename, checksum, percentCallback) {
|
download: function (url, filename, checksum, percentCallback) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (fs.existsSync(filename)) {
|
if (fs.existsSync(filename)) {
|
||||||
var existingChecksum = crypto.createHash('sha256').update(fs.readFileSync(filename), 'utf8').digest('hex');
|
var existingChecksum = this.checksum(filename);
|
||||||
if (existingChecksum === checksum) {
|
if (existingChecksum === checksum) {
|
||||||
resolve();
|
resolve();
|
||||||
return;
|
return;
|
||||||
|
|
41
src/Util.js
41
src/Util.js
|
@ -4,9 +4,11 @@ var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
exec: function (args) {
|
exec: function (args, options) {
|
||||||
|
options = options || {};
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
exec(args, (stderr, stdout, code) => {
|
console.log(options);
|
||||||
|
exec(args, options, (stderr, stdout, code) => {
|
||||||
if (code) {
|
if (code) {
|
||||||
reject(stderr);
|
reject(stderr);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +19,42 @@ module.exports = {
|
||||||
home: function () {
|
home: function () {
|
||||||
return process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];
|
return process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];
|
||||||
},
|
},
|
||||||
|
supportDir: function () {
|
||||||
|
var dirs = ['Library', 'Application\ Support', 'Kitematic'];
|
||||||
|
var acc = process.env.HOME;
|
||||||
|
dirs.forEach(function (d) {
|
||||||
|
acc = path.join(acc, d);
|
||||||
|
if (!fs.existsSync(acc)) {
|
||||||
|
fs.mkdirSync(acc);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
resourceDir: function () {
|
||||||
|
return process.env.RESOURCES_PATH;
|
||||||
|
},
|
||||||
packagejson: function () {
|
packagejson: function () {
|
||||||
return JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
return JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
||||||
|
},
|
||||||
|
copycmd: function (src, dest) {
|
||||||
|
return ['rm', '-f', dest, '&&', 'cp', src, dest];
|
||||||
|
},
|
||||||
|
copyBinariesCmd: function () {
|
||||||
|
var packagejson = this.packagejson();
|
||||||
|
var cmd = [];
|
||||||
|
cmd.push.apply(cmd, this.copycmd(this.escapePath(path.join(this.resourceDir(), 'boot2docker-' + packagejson['boot2docker-version'])), '/usr/local/bin/boot2docker'));
|
||||||
|
cmd.push('&&');
|
||||||
|
cmd.push.apply(cmd, this.copycmd(this.escapePath(path.join(this.resourceDir(), 'docker-' + packagejson['docker-version'])), '/usr/local/bin/docker'));
|
||||||
|
return cmd.join(' ');
|
||||||
|
},
|
||||||
|
fixBinariesCmd: function () {
|
||||||
|
var cmd = [];
|
||||||
|
cmd.push.apply(cmd, ['chown', `${process.getuid()}:${80}`, this.escapePath(path.join('/usr/local/bin', 'boot2docker'))]);
|
||||||
|
cmd.push('&&');
|
||||||
|
cmd.push.apply(cmd, ['chown', `${process.getuid()}:${80}`, this.escapePath(path.join('/usr/local/bin', 'docker'))]);
|
||||||
|
return cmd.join(' ');
|
||||||
|
},
|
||||||
|
escapePath: function (str) {
|
||||||
|
return str.replace(/ /g, '\\ ').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,13 +27,12 @@ var VirtualBox = {
|
||||||
return util.exec(this.command() + ' list runningvms | sed -E \'s/.*\\{(.*)\\}/\\1/\' | xargs -L1 -I {} ' + this.command() + ' controlvm {} poweroff');
|
return util.exec(this.command() + ' list runningvms | sed -E \'s/.*\\{(.*)\\}/\\1/\' | xargs -L1 -I {} ' + this.command() + ' controlvm {} poweroff');
|
||||||
},
|
},
|
||||||
killall: function () {
|
killall: function () {
|
||||||
if (!this.installed()) {
|
|
||||||
return Promise.reject('VirtualBox not installed.');
|
|
||||||
}
|
|
||||||
return this.poweroffall().then(() => {
|
return this.poweroffall().then(() => {
|
||||||
return util.exec(['pkill', 'VirtualBox']);
|
return util.exec(['pkill', 'VirtualBox']);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
return util.exec(['pkill', 'VBox']);
|
return util.exec(['pkill', 'VBox']);
|
||||||
|
}).catch(err => {
|
||||||
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
vmstate: function (name) {
|
vmstate: function (name) {
|
||||||
|
|
Loading…
Reference in New Issue