0.5.3 setup stability, errors & retrying

This commit is contained in:
Jeffrey Morgan 2015-03-01 17:08:46 -05:00
Родитель bf0abc1d2c
Коммит 9b32a6a680
13 изменённых файлов: 169 добавлений и 60 удалений

Просмотреть файл

@ -1,6 +1,6 @@
{ {
"name": "Kitematic", "name": "Kitematic",
"version": "0.5.2", "version": "0.5.3",
"author": "Kitematic", "author": "Kitematic",
"description": "Simple Docker Container management for Mac OS X.", "description": "Simple Docker Container management for Mac OS X.",
"homepage": "https://kitematic.com/", "homepage": "https://kitematic.com/",

Просмотреть файл

@ -28,7 +28,7 @@ var ContainerDetail = React.createClass({
<div className="details"> <div className="details">
<ContainerDetailsHeader container={this.props.container}/> <ContainerDetailsHeader container={this.props.container}/>
<ContainerDetailsSubheader container={this.props.container} /> <ContainerDetailsSubheader container={this.props.container} />
<Router.RouteHandler container={this.props.container}/> <Router.RouteHandler container={this.props.container} error={this.props.error}/>
</div> </div>
); );
} }

Просмотреть файл

@ -8,7 +8,7 @@ var ContainerHomePreview = require('./ContainerHomePreview.react');
var ContainerHomeLogs = require('./ContainerHomeLogs.react'); var ContainerHomeLogs = require('./ContainerHomeLogs.react');
var ContainerHomeFolders = require('./ContainerHomeFolders.react'); var ContainerHomeFolders = require('./ContainerHomeFolders.react');
var ContainerUtil = require('./ContainerUtil'); var ContainerUtil = require('./ContainerUtil');
var webPorts = require('./Util').webPorts; var util = require('./Util');
var resizeWindow = function () { var resizeWindow = function () {
$('.left .wrapper').height(window.innerHeight - 240); $('.left .wrapper').height(window.innerHeight - 240);
@ -27,6 +27,9 @@ var ContainerHome = React.createClass({
handleResize: function () { handleResize: function () {
resizeWindow(); resizeWindow();
}, },
handleErrorClick: function () {
util.exec(['open', 'https://github.com/kitematic/kitematic/issues/new']);
},
componentWillReceiveProps: function () { componentWillReceiveProps: function () {
this.init(); this.init();
}, },
@ -52,7 +55,7 @@ var ContainerHome = React.createClass({
this.setState({ this.setState({
ports: ports, ports: ports,
defaultPort: _.find(_.keys(ports), function (port) { defaultPort: _.find(_.keys(ports), function (port) {
return webPorts.indexOf(port) !== -1; return util.webPorts.indexOf(port) !== -1;
}), }),
progress: ContainerStore.progress(this.getParams().name), progress: ContainerStore.progress(this.getParams().name),
blocked: ContainerStore.blocked(this.getParams().name) blocked: ContainerStore.blocked(this.getParams().name)
@ -68,7 +71,14 @@ var ContainerHome = React.createClass({
}, },
render: function () { render: function () {
var body; var body;
if (this.props.container && this.props.container.State.Downloading) { if (this.props.error) {
body = (
<div className="details-progress">
<h3>There was a problem connecting to the Docker Engine.<br/>Either the VirtualBox VM was removed, is not responding or Docker is not running inside of it. Try restarting Kitematic. If the issue persists, please <a onClick={this.handleErrorClick}>file a ticket on our GitHub repo.</a></h3>
<Radial progress={100} error={true} thick={true} transparent={true}/>
</div>
);
} else if (this.props.container && this.props.container.State.Downloading) {
if (this.state.progress) { if (this.state.progress) {
body = ( body = (
<div className="details-progress"> <div className="details-progress">

Просмотреть файл

@ -7,17 +7,20 @@ var docker = require('./Docker');
var metrics = require('./Metrics'); var metrics = require('./Metrics');
var registry = require('./Registry'); var registry = require('./Registry');
var LogStore = require('./LogStore'); var LogStore = require('./LogStore');
var bugsnag = require('bugsnag-js');
var _placeholders = {}; var _placeholders = {};
var _containers = {}; var _containers = {};
var _progress = {}; var _progress = {};
var _muted = {}; var _muted = {};
var _blocked = {}; var _blocked = {};
var _error = null;
var ContainerStore = assign(Object.create(EventEmitter.prototype), { var ContainerStore = assign(Object.create(EventEmitter.prototype), {
CLIENT_CONTAINER_EVENT: 'client_container_event', CLIENT_CONTAINER_EVENT: 'client_container_event',
SERVER_CONTAINER_EVENT: 'server_container_event', SERVER_CONTAINER_EVENT: 'server_container_event',
SERVER_PROGRESS_EVENT: 'server_progress_event', SERVER_PROGRESS_EVENT: 'server_progress_event',
SERVER_ERROR_EVENT: 'server_error_event',
_pullImage: function (repository, tag, callback, progressCallback, blockedCallback) { _pullImage: function (repository, tag, callback, progressCallback, blockedCallback) {
registry.layers(repository, tag, (err, layerSizes) => { registry.layers(repository, tag, (err, layerSizes) => {
@ -35,6 +38,10 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
var totalBytes = layersToDownload.map(function (s) { return s.size; }).reduce(function (pv, sv) { return pv + sv; }, 0); var totalBytes = layersToDownload.map(function (s) { return s.size; }).reduce(function (pv, sv) { return pv + sv; }, 0);
docker.client().pull(repository + ':' + tag, (err, stream) => { docker.client().pull(repository + ':' + tag, (err, stream) => {
if (err) {
callback(err);
return;
}
stream.setEncoding('utf8'); stream.setEncoding('utf8');
var layerProgress = layersToDownload.reduce(function (r, layer) { var layerProgress = layersToDownload.reduce(function (r, layer) {
@ -50,7 +57,7 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
var data = JSON.parse(str); var data = JSON.parse(str);
console.log(data); console.log(data);
if (data.status === 'Pulling dependent layers') { if (data.status === 'Pulling dependent layers' || data.status.indexOf('already being pulled by another client') !== -1) {
blockedCallback(); blockedCallback();
return; return;
} }
@ -153,7 +160,7 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
} }
} }
}, },
_resumePulling: function () { _resumePulling: function (callback) {
var downloading = _.filter(_.values(this.containers()), function (container) { var downloading = _.filter(_.values(this.containers()), function (container) {
return container.State.Downloading; return container.State.Downloading;
}); });
@ -163,12 +170,20 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
downloading.forEach(function (container) { downloading.forEach(function (container) {
_progress[container.Name] = 99; _progress[container.Name] = 99;
docker.client().pull(container.Config.Image, function (err, stream) { docker.client().pull(container.Config.Image, function (err, stream) {
if (err) {
callback(err);
return;
}
stream.setEncoding('utf8'); stream.setEncoding('utf8');
stream.on('data', function () {}); stream.on('data', function () {});
stream.on('end', function () { stream.on('end', function () {
delete _placeholders[container.Name]; delete _placeholders[container.Name];
localStorage.setItem('store.placeholders', JSON.stringify(_placeholders)); localStorage.setItem('store.placeholders', JSON.stringify(_placeholders));
self._createContainer(container.Name, {Image: container.Config.Image}, function () { self._createContainer(container.Name, {Image: container.Config.Image}, err => {
if (err) {
callback(err);
return;
}
self.emit(self.SERVER_PROGRESS_EVENT, container.Name); self.emit(self.SERVER_PROGRESS_EVENT, container.Name);
self.emit(self.CLIENT_CONTAINER_EVENT, container.Name); self.emit(self.CLIENT_CONTAINER_EVENT, container.Name);
}); });
@ -176,13 +191,17 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
}); });
}); });
}, },
_startListeningToEvents: function () { _startListeningToEvents: function (callback) {
docker.client().getEvents(function (err, stream) { docker.client().getEvents((err, stream) => {
if (err) {
callback(err);
return;
}
if (stream) { if (stream) {
stream.setEncoding('utf8'); stream.setEncoding('utf8');
stream.on('data', this._dockerEvent.bind(this)); stream.on('data', this._dockerEvent.bind(this));
} }
}.bind(this)); });
}, },
_dockerEvent: function (json) { _dockerEvent: function (json) {
var data = JSON.parse(json); var data = JSON.parse(json);
@ -200,7 +219,7 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
this.emit(this.SERVER_CONTAINER_EVENT, data.status); this.emit(this.SERVER_CONTAINER_EVENT, data.status);
} }
} else { } else {
this.fetchContainer(data.id, function (err) { this.fetchContainer(data.id, err => {
if (err) { if (err) {
return; return;
} }
@ -209,13 +228,16 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
return; return;
} }
this.emit(this.SERVER_CONTAINER_EVENT, container ? container.Name : null, data.status); this.emit(this.SERVER_CONTAINER_EVENT, container ? container.Name : null, data.status);
}.bind(this)); });
} }
}, },
init: function (callback) { init: function (callback) {
// TODO: Load cached data from db on loading // TODO: Load cached data from db on loading
this.fetchAllContainers(function (err) { this.fetchAllContainers(err => {
if (err) { if (err) {
_error = err;
this.emit(this.SERVER_ERROR_EVENT, err);
bugsnag.notify(err, 'Container Store failed to init', err);
callback(err); callback(err);
return; return;
} else { } else {
@ -227,12 +249,20 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
localStorage.setItem('store.placeholders', JSON.stringify(_placeholders)); localStorage.setItem('store.placeholders', JSON.stringify(_placeholders));
} }
this.emit(this.CLIENT_CONTAINER_EVENT); this.emit(this.CLIENT_CONTAINER_EVENT);
this._resumePulling(); this._resumePulling(err => {
this._startListeningToEvents(); _error = err;
}.bind(this)); this.emit(this.SERVER_ERROR_EVENT, err);
bugsnag.notify(err, 'Container Store failed to resume pulling', err);
});
this._startListeningToEvents(err => {
_error = err;
this.emit(this.SERVER_ERROR_EVENT, err);
bugsnag.notify(err, 'Container Store failed to listen to events', err);
});
});
}, },
fetchContainer: function (id, callback) { fetchContainer: function (id, callback) {
docker.client().getContainer(id).inspect(function (err, container) { docker.client().getContainer(id).inspect((err, container) => {
if (err) { if (err) {
callback(err); callback(err);
} else { } else {
@ -245,11 +275,10 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
_containers[container.Name] = container; _containers[container.Name] = container;
callback(null, container); callback(null, container);
} }
}.bind(this)); });
}, },
fetchAllContainers: function (callback) { fetchAllContainers: function (callback) {
var self = this; docker.client().listContainers({all: true}, (err, containers) => {
docker.client().listContainers({all: true}, function (err, containers) {
if (err) { if (err) {
callback(err); callback(err);
return; return;
@ -260,8 +289,8 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
delete _containers[name]; delete _containers[name];
} }
}); });
async.each(containers, function (container, callback) { async.each(containers, (container, callback) => {
self.fetchContainer(container.Id, function (err) { this.fetchContainer(container.Id, function (err) {
callback(err); callback(err);
}); });
}, function (err) { }, function (err) {
@ -289,14 +318,28 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
_muted[containerName] = true; _muted[containerName] = true;
_progress[containerName] = 0; _progress[containerName] = 0;
this._pullImage(repository, tag, () => { this._pullImage(repository, tag, err => {
if (err) {
_error = err;
this.emit(this.SERVER_ERROR_EVENT, err);
bugsnag.notify(err, 'Container Store failed to create container', err);
return;
}
_error = null;
_blocked[containerName] = false; _blocked[containerName] = false;
if (!_placeholders[containerName]) { if (!_placeholders[containerName]) {
return; return;
} }
delete _placeholders[containerName]; delete _placeholders[containerName];
localStorage.setItem('store.placeholders', JSON.stringify(_placeholders)); localStorage.setItem('store.placeholders', JSON.stringify(_placeholders));
this._createContainer(containerName, {Image: imageName}, () => { this._createContainer(containerName, {Image: imageName}, err => {
if (err) {
console.log(err);
_error = err;
this.emit(this.SERVER_ERROR_EVENT, err);
return;
}
_error = null;
metrics.track('Container Finished Creating'); metrics.track('Container Finished Creating');
delete _progress[containerName]; delete _progress[containerName];
_muted[containerName] = false; _muted[containerName] = false;
@ -321,10 +364,10 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
LogStore.rename(name, data.name); LogStore.rename(name, data.name);
} }
var fullData = assign(_containers[name], data); var fullData = assign(_containers[name], data);
this._createContainer(name, fullData, function (err) { this._createContainer(name, fullData, function () {
_muted[name] = false; _muted[name] = false;
this.emit(this.CLIENT_CONTAINER_EVENT, name); this.emit(this.CLIENT_CONTAINER_EVENT, name);
callback(err); callback();
}.bind(this)); }.bind(this));
}, },
rename: function (name, newName, callback) { rename: function (name, newName, callback) {
@ -417,6 +460,9 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
}, },
blocked: function (name) { blocked: function (name) {
return !!_blocked[name]; return !!_blocked[name];
},
error: function () {
return _error;
} }
}); });

Просмотреть файл

@ -20,11 +20,13 @@ var Containers = React.createClass({
containers: ContainerStore.containers(), containers: ContainerStore.containers(),
sorted: ContainerStore.sorted(), sorted: ContainerStore.sorted(),
updateAvailable: false, updateAvailable: false,
currentButtonLabel: '' currentButtonLabel: '',
error: ContainerStore.error()
}; };
}, },
componentDidMount: function () { componentDidMount: function () {
this.update(); this.update();
ContainerStore.on(ContainerStore.SERVER_ERROR_EVENT, this.updateError);
ContainerStore.on(ContainerStore.SERVER_CONTAINER_EVENT, this.update); ContainerStore.on(ContainerStore.SERVER_CONTAINER_EVENT, this.update);
ContainerStore.on(ContainerStore.CLIENT_CONTAINER_EVENT, this.updateFromClient); ContainerStore.on(ContainerStore.CLIENT_CONTAINER_EVENT, this.updateFromClient);
@ -52,6 +54,11 @@ var Containers = React.createClass({
this.transitionTo('containers'); this.transitionTo('containers');
} }
}, },
updateError: function (err) {
this.setState({
error: err
});
},
update: function (name, status) { update: function (name, status) {
this.setState({ this.setState({
containers: ContainerStore.containers(), containers: ContainerStore.containers(),
@ -175,7 +182,7 @@ var Containers = React.createClass({
<div className="sidebar-buttons-padding"></div> <div className="sidebar-buttons-padding"></div>
</section> </section>
</div> </div>
<Router.RouteHandler container={container}/> <Router.RouteHandler container={container} error={this.state.error}/>
</div> </div>
</div> </div>
); );

Просмотреть файл

@ -23,10 +23,7 @@ var ImageCard = React.createClass({
}, },
handleClick: function (name) { handleClick: function (name) {
metrics.track('Created Container'); metrics.track('Created Container');
ContainerStore.create(name, this.state.chosenTag, function (err) { ContainerStore.create(name, this.state.chosenTag, function () {
if (err) {
throw err;
}
$(document.body).find('.new-container-item').parent().fadeOut(); $(document.body).find('.new-container-item').parent().fadeOut();
}.bind(this)); }.bind(this));
}, },

Просмотреть файл

@ -6,13 +6,13 @@ var fs = require('fs');
var path = require('path'); var path = require('path');
var docker = require('./Docker'); var docker = require('./Docker');
var router = require('./Router'); var router = require('./Router');
var machine = require('./DockerMachine');
var ContainerStore = require('./ContainerStore'); var ContainerStore = require('./ContainerStore');
var SetupStore = require('./SetupStore'); var SetupStore = require('./SetupStore');
var metrics = require('./Metrics'); var metrics = require('./Metrics');
var template = require('./MenuTemplate'); var template = require('./MenuTemplate');
var util = require('./Util'); var util = require('./Util');
var Menu = remote.require('menu'); var Menu = remote.require('menu');
var bugsnag = require('bugsnag-js');
window.addEventListener('resize', function () { window.addEventListener('resize', function () {
fs.writeFileSync(path.join(util.supportDir(), 'size'), JSON.stringify({ fs.writeFileSync(path.join(util.supportDir(), 'size'), JSON.stringify({
@ -38,7 +38,6 @@ if (process.env.NODE_ENV === 'development') {
head.appendChild(script); head.appendChild(script);
} }
var bugsnag = require('bugsnag-js');
bugsnag.apiKey = settingsjson.bugsnag; bugsnag.apiKey = settingsjson.bugsnag;
bugsnag.autoNotify = true; bugsnag.autoNotify = true;
bugsnag.releaseStage = process.env.NODE_ENV === 'development' ? 'development' : 'production'; bugsnag.releaseStage = process.env.NODE_ENV === 'development' ? 'development' : 'production';
@ -81,18 +80,25 @@ setInterval(function () {
}, 14400000); }, 14400000);
router.run(Handler => React.render(<Handler/>, document.body)); router.run(Handler => React.render(<Handler/>, document.body));
SetupStore.run().then(machine.info).then(machine => { SetupStore.setup().then(machine => {
console.log('setup complete');
console.log(machine);
docker.setup(machine.url, machine.name); docker.setup(machine.url, machine.name);
Menu.setApplicationMenu(Menu.buildFromTemplate(template())); Menu.setApplicationMenu(Menu.buildFromTemplate(template()));
ContainerStore.on(ContainerStore.SERVER_ERROR_EVENT, (err) => {
bugsnag.notify(err);
});
ContainerStore.init(function (err) { ContainerStore.init(function (err) {
if (err) { if (err) {
console.log(err);
bugsnag.notify(err); bugsnag.notify(err);
} }
router.transitionTo('containers'); router.transitionTo('containers');
}); });
}).catch(err => { }).catch(err => {
metrics.track('Setup Failed', { metrics.track('Setup Failed', {
step: SetupStore.step(), step: 'catch',
message: err.message
}); });
bugsnag.notify(err); bugsnag.notify(err);
console.log(err); console.log(err);

Просмотреть файл

@ -3,7 +3,7 @@ var React = require('react/addons');
var Radial = React.createClass({ var Radial = React.createClass({
render: function () { render: function () {
var percentage; var percentage;
if ((this.props.progress !== null && this.props.progress !== undefined) && !this.props.spin) { if ((this.props.progress !== null && this.props.progress !== undefined) && !this.props.spin && !this.props.error) {
percentage = ( percentage = (
<div className="percentage"></div> <div className="percentage"></div>
); );

Просмотреть файл

@ -6,13 +6,15 @@ var RetinaImage = require('react-retina-image');
var Header = require('./Header.react'); var Header = require('./Header.react');
var Util = require('./Util'); var Util = require('./Util');
var metrics = require('./Metrics'); var metrics = require('./Metrics');
var machine = require('./DockerMachine');
var Setup = React.createClass({ var Setup = React.createClass({
mixins: [ Router.Navigation ], mixins: [ Router.Navigation ],
getInitialState: function () { getInitialState: function () {
return { return {
progress: 0, progress: 0,
name: '' name: '',
retrying: false
}; };
}, },
componentWillMount: function () { componentWillMount: function () {
@ -28,10 +30,26 @@ var Setup = React.createClass({
SetupStore.removeListener(SetupStore.STEP_EVENT, this.update); SetupStore.removeListener(SetupStore.STEP_EVENT, this.update);
SetupStore.removeListener(SetupStore.ERROR_EVENT, this.update); SetupStore.removeListener(SetupStore.ERROR_EVENT, this.update);
}, },
handleRetry: function () { handleCancelRetry: function () {
metrics.track('Setup Retried'); metrics.track('Setup Retried', {
from: 'cancel'
});
SetupStore.retry(); SetupStore.retry();
}, },
handleErrorRetry: function () {
this.setState({
retrying: true
});
metrics.track('Setup Retried', {
from: 'error'
});
machine.stop().finally(() => {
this.setState({
retrying: false
});
SetupStore.retry();
});
},
handleOpenWebsite: function () { handleOpenWebsite: function () {
Util.exec(['open', 'https://www.virtualbox.org/wiki/Downloads']); Util.exec(['open', 'https://www.virtualbox.org/wiki/Downloads']);
}, },
@ -110,21 +128,21 @@ var Setup = React.createClass({
<h1>We&#39;re Sorry!</h1> <h1>We&#39;re Sorry!</h1>
<p>There seems to have been an unexpected error with Kitematic:</p> <p>There seems to have been an unexpected error with Kitematic:</p>
<p className="error">{this.state.error}<br />{this.state.error.message}</p> <p className="error">{this.state.error}<br />{this.state.error.message}</p>
<p><button className="btn btn-action" disabled={this.state.retrying} onClick={this.handleErrorRetry}>Retry Setup</button></p>
</div> </div>
</div> </div>
</div> </div>
); );
}, },
render: function () { render: function () {
if (!SetupStore.step()) {
return false;
}
if (this.state.cancelled) { if (this.state.cancelled) {
return this.renderCancelled(); return this.renderCancelled();
} else if (this.state.error) { } else if (this.state.error) {
return this.renderError(); return this.renderError();
} else { } else if (SetupStore.step()) {
return this.renderStep(); return this.renderStep();
} else {
return false;
} }
} }
}); });

Просмотреть файл

@ -10,6 +10,7 @@ var util = require('./Util');
var assign = require('object-assign'); var assign = require('object-assign');
var metrics = require('./Metrics'); var metrics = require('./Metrics');
var bugsnag = require('bugsnag-js'); var bugsnag = require('bugsnag-js');
var rimraf = require('rimraf');
var _currentStep = null; var _currentStep = null;
var _error = null; var _error = null;
@ -59,26 +60,25 @@ var _steps = [{
message: 'To run Docker containers on your computer, Kitematic is starting a Linux virutal machine. This may take a minute...', message: 'To run Docker containers on your computer, Kitematic is starting a Linux virutal machine. This may take a minute...',
totalPercent: 60, totalPercent: 60,
percent: 0, percent: 0,
seconds: 52, seconds: 53,
run: Promise.coroutine(function* (progressCallback) { run: Promise.coroutine(function* (progressCallback) {
setupUtil.simulateProgress(this.seconds, progressCallback); setupUtil.simulateProgress(this.seconds, progressCallback);
yield virtualBox.vmdestroy('kitematic-vm'); yield virtualBox.vmdestroy('kitematic-vm');
var exists = yield machine.exists(); var exists = yield machine.exists();
if (!exists) { if (!exists || (yield machine.state()) === 'Error') {
yield machine.create();
return;
} else if ((yield machine.state()) === 'Error') {
try { try {
yield machine.rm(); yield machine.rm();
} catch (err) {} yield machine.create();
yield machine.create(); } catch (err) {
rimraf.sync(path.join(util.home(), '.docker', 'machine', 'machines', machine.name()));
yield machine.create();
}
return; return;
} }
var isoversion = machine.isoversion(); var isoversion = machine.isoversion();
var packagejson = util.packagejson(); var packagejson = util.packagejson();
if (!isoversion || setupUtil.compareVersions(isoversion, packagejson['docker-version']) < 0) { if (!isoversion || setupUtil.compareVersions(isoversion, packagejson['docker-version']) < 0) {
console.log('upgrading');
yield machine.stop(); yield machine.stop();
yield machine.upgrade(); yield machine.upgrade();
} }
@ -113,15 +113,21 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), {
error: function () { error: function () {
return _error; return _error;
}, },
setError: function (error) {
_error = error;
this.emit(this.ERROR_EVENT);
},
cancelled: function () { cancelled: function () {
return _cancelled; return _cancelled;
}, },
retry: function () { retry: function () {
_error = null; _error = null;
_cancelled = false; _cancelled = false;
_retryPromise.resolve(); if (_retryPromise) {
_retryPromise.resolve();
}
}, },
wait: function () { pause: function () {
_retryPromise = Promise.defer(); _retryPromise = Promise.defer();
return _retryPromise.promise; return _retryPromise.promise;
}, },
@ -141,7 +147,7 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), {
if (isoversion && setupUtil.compareVersions(isoversion, packagejson['docker-version']) < 0) { if (isoversion && setupUtil.compareVersions(isoversion, packagejson['docker-version']) < 0) {
this.steps().init.seconds = 33; this.steps().init.seconds = 33;
} else if (exists && (yield machine.state()) !== 'Error') { } else if (exists && (yield machine.state()) !== 'Error') {
this.steps().init.seconds = 13; this.steps().init.seconds = 23;
} }
_requiredSteps = _steps.filter(function (step) { _requiredSteps = _steps.filter(function (step) {
@ -196,12 +202,30 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), {
_cancelled = true; _cancelled = true;
this.emit(this.STEP_EVENT); this.emit(this.STEP_EVENT);
} }
yield this.wait(); yield this.pause();
} }
} }
} }
metrics.track('Finished Setup');
_currentStep = null; _currentStep = null;
return yield machine.info();
}),
setup: Promise.coroutine(function * () {
while (true) {
var info = yield this.run();
console.log(info);
if (!info.url) {
metrics.track('Setup Failed', {
step: 'done',
message: 'Machine URL not set'
});
bugsnag.notify('SetupError', 'Machine url was not set', machine);
SetupStore.setError('Could not reach the Docker Engine inside the VirtualBox VM');
yield this.pause();
} else {
metrics.track('Finished Setup');
return info;
}
}
}) })
}); });

Просмотреть файл

@ -9,7 +9,7 @@ module.exports = {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
exec(args, options, (stderr, stdout, code) => { exec(args, options, (stderr, stdout, code) => {
if (code) { if (code) {
reject(stderr); reject(stderr || args.join(' ').replace(this.home(), '') + 'returned non zero exit code');
} }
resolve(stdout); resolve(stdout);
}); });

Просмотреть файл

@ -122,7 +122,7 @@
.details-progress { .details-progress {
margin: 20% auto 0; margin: 20% auto 0;
text-align: center; text-align: center;
width: 300px; width: 400px;
h2 { h2 {
margin-bottom: 20px; margin-bottom: 20px;
} }

Просмотреть файл

@ -8,4 +8,5 @@ pkill VBox
rm -rf ~/Library/Application\ Support/Kitematic/ rm -rf ~/Library/Application\ Support/Kitematic/
rm -rf ~/.docker rm -rf ~/.docker
rm -rf ~/Library/VirtualBox/ rm -rf ~/Library/VirtualBox/
rm -rf ~/Kitematic
$DIR/VirtualBox_Uninstall.tool $DIR/VirtualBox_Uninstall.tool