diff --git a/meteor/client/lib/docker.js b/meteor/client/lib/docker.js
index e959079d08..4759ab0a53 100644
--- a/meteor/client/lib/docker.js
+++ b/meteor/client/lib/docker.js
@@ -6,6 +6,9 @@ var path = require('path');
Docker = {};
Docker.DOCKER_HOST = '192.168.60.103';
+Docker.DEFAULT_IMAGES_FILENAME = 'base-images-0.0.2.tar.gz';
+Docker.DEFAULT_IMAGES_CHECKSUM = '67e7c7562991a4208c90007461ec14bc184a52ad6048e6bed3e8a8c2b306cee7'; // Sha256 Checksum
+
Docker.client = function () {
return new Dockerode({host: Docker.DOCKER_HOST, port: '2375'});
};
@@ -283,7 +286,7 @@ Docker.reloadDefaultContainers = function (callback) {
return;
}
console.log('Loading new Kitematic default images.');
- docker.loadImage(path.join(Util.getBinDir(), 'base-images.tar.gz'), {}, function (err) {
+ docker.loadImage(path.join(Util.getResourceDir(), Docker.DEFAULT_IMAGES_FILENAME), {}, function (err) {
if (err) {
callback(err);
return;
diff --git a/meteor/client/lib/installer.js b/meteor/client/lib/installer.js
index e99e9664f0..aa20d8bc52 100644
--- a/meteor/client/lib/installer.js
+++ b/meteor/client/lib/installer.js
@@ -22,26 +22,42 @@ Installer.isUpToDate = function () {
*/
Installer.steps = [
{
- run: function (callback) {
+ run: function (callback, progressCallback) {
var installed = VirtualBox.installed();
if (!installed) {
- VirtualBox.install(function (err) {
- callback(err);
+ Util.downloadFile(Installer.baseURL + VirtualBox.INSTALLER_FILENAME, path.join(Util.getResourceDir(), VirtualBox.INSTALLER_FILENAME), VirtualBox.INSTALLER_CHECKSUM, function (err) {
+ if (err) {callback(err); return;}
+ VirtualBox.install(function (err) {
+ if (!VirtualBox.installed()) {
+ callback('VirtualBox could not be installed. The installation either failed or was cancelled. Please try closing all VirtualBox instances and try again.');
+ } else {
+ callback(err);
+ }
+ });
+ }, function (progress) {
+ progressCallback(progress);
});
} else {
// Version 4.3.12 is required.
VirtualBox.version(function (err, installedVersion) {
- if (err) {
- callback(err);
- return;
- }
+ if (err) {callback(err); return;}
if (Util.compareVersions(installedVersion, VirtualBox.REQUIRED_VERSION) < 0) {
- VirtualBox.install(function (err) {
- if (Util.compareVersions(installedVersion, VirtualBox.REQUIRED_VERSION) < 0) {
- callback('VirtualBox could not be installed. The installation either failed or was cancelled. Please try closing all VirtualBox instances and try again.');
- } else {
- callback(err);
- }
+ // Download a newer version of Virtualbox
+ Util.downloadFile(Installer.baseURL + VirtualBox.INSTALLER_FILENAME, path.join(Util.getResourceDir(), VirtualBox.INSTALLER_FILENAME), VirtualBox.INSTALLER_CHECKSUM, function (err) {
+ if (err) {callback(err); return;}
+ VirtualBox.install(function (err) {
+ if (err) {callback(err); return;}
+ VirtualBox.version(function (err, installedVersion) {
+ if (err) {callback(err); return;}
+ if (Util.compareVersions(installedVersion, VirtualBox.REQUIRED_VERSION) < 0) {
+ callback('VirtualBox could not be installed. The installation either failed or was cancelled. Please try closing all VirtualBox instances and try again.');
+ } else {
+ callback(err);
+ }
+ });
+ }, function (progress) {
+ progressCallback(progress);
+ });
});
} else {
callback();
@@ -50,8 +66,8 @@ Installer.steps = [
}
},
pastMessage: 'VirtualBox installed',
- message: 'Installing VirtualBox',
- futureMessage: 'Install VirtualBox if necessary'
+ message: 'Downloading & Installing VirtualBox',
+ futureMessage: 'Download & Install VirtualBox if necessary'
},
// Initialize Boot2Docker if necessary.
@@ -78,9 +94,9 @@ Installer.steps = [
}
});
},
- pastMessage: 'Setup the Boot2Docker VM (if required)',
- message: 'Setting up the Boot2Docker VM',
- futureMessage: 'Set up the Boot2Docker VM(if required)'
+ pastMessage: 'Setup the Kitematic VM (if required)',
+ message: 'Setting up the Kitematic VM',
+ futureMessage: 'Set up the Kitematic VM(if required)'
},
{
@@ -89,9 +105,9 @@ Installer.steps = [
callback(err);
});
},
- pastMessage: 'Added custom host adapter to the Boot2Docker VM',
- message: 'Adding custom host adapter to the Boot2Docker VM',
- futureMessage: 'Add custom host adapter to the Boot2Docker VM'
+ pastMessage: 'Added custom host adapter to the Kitematic VM',
+ message: 'Adding custom host adapter to the Kitematic VM',
+ futureMessage: 'Add custom host adapter to the Kitematic VM'
},
// Start the Kitematic VM
@@ -111,8 +127,8 @@ Installer.steps = [
}
});
},
- pastMessage: 'Started the Boot2Docker VM',
- message: 'Starting the Boot2Docker VM',
+ pastMessage: 'Started the Kitematic VM',
+ message: 'Starting the Kitematic VM',
futureMessage: 'Start the Kitematic VM'
},
@@ -129,12 +145,16 @@ Installer.steps = [
// Set up the default Kitematic images
{
- run: function (callback) {
- Docker.reloadDefaultContainers(function (err) {
- callback(err);
+ run: function (callback, progressCallback) {
+ Util.downloadFile(Installer.baseURL + Docker.DEFAULT_IMAGES_FILENAME, path.join(Util.getResourceDir(), Docker.DEFAULT_IMAGES_FILENAME), Docker.DEFAULT_IMAGES_CHECKSUM, function (err) {
+ Docker.reloadDefaultContainers(function (err) {
+ callback(err);
+ });
+ }, function (progress) {
+ progressCallback(progress);
});
},
- pastMessage: 'Started the Boot2Docker VM',
+ pastMessage: 'Set up the default Kitematic images.',
message: 'Setting up the default Kitematic images...',
subMessage: '(This may take a few minutes)',
futureMessage: 'Set up the default Kitematic images'
@@ -147,6 +167,7 @@ Installer.run = function (callback) {
Session.set('numberOfInstallSteps', this.steps.length);
async.eachSeries(this.steps, function (step, callback) {
console.log('Performing step ' + currentStep);
+ Session.set('currentInstallStepProgress', 0);
step.run(function (err) {
if (err) {
callback(err);
@@ -155,6 +176,8 @@ Installer.run = function (callback) {
Session.set('currentInstallStep', currentStep);
callback();
}
+ }, function (progress) {
+ Session.set('currentInstallStepProgress', progress);
});
}, function (err) {
if (err) {
diff --git a/meteor/client/lib/util.js b/meteor/client/lib/util.js
index 2d46b711ee..29fcbf8b8c 100755
--- a/meteor/client/lib/util.js
+++ b/meteor/client/lib/util.js
@@ -1,6 +1,6 @@
var path = require('path');
var fs = require('fs');
-var https = require('https');
+var wget = require('wget');
var nodeCrypto = require('crypto');
Util = {};
@@ -95,25 +95,24 @@ Util.openTerminal = function (command) {
});
};
-Util.downloadFile = function (url, filename, checksum, progressCallback, callback) {
+Util.downloadFile = function (url, filename, checksum, callback, progressCallback) {
var doDownload = function () {
- var file = fs.createWriteStream(filename);
- https.get(url, function(res) {
- var len = 0;
- res.on('data', function(chunk) {
- file.write(chunk);
- len += chunk.length;
-
- // percentage downloaded is as follows
- var percent = (len / res.headers['content-length']) * 100;
- progressCallback(percent);
- });
- res.on('end', function() {
- file.close();
- });
- file.on('close', function() {
- callback();
- });
+ var percent = 0;
+ var interval = setInterval(function () {
+ progressCallback(percent);
+ }, 250);
+ var download = wget.download(url, filename);
+ download.on('error', function (err) {
+ console.log(err);
+ clearInterval(interval);
+ });
+ download.on('end', function (output) {
+ console.log(output);
+ callback();
+ clearInterval(interval);
+ });
+ download.on('progress', function (progress) {
+ percent = Math.round(progress * 100.0);
});
};
@@ -122,10 +121,13 @@ Util.downloadFile = function (url, filename, checksum, progressCallback, callbac
var existingChecksum = nodeCrypto.createHash('sha256').update(fs.readFileSync(filename), 'utf8').digest('hex');
console.log(existingChecksum);
if (existingChecksum !== checksum) {
+ fs.unlinkSync(filename);
doDownload();
} else {
callback();
}
+ } else {
+ doDownload();
}
};
diff --git a/meteor/client/lib/virtualbox.js b/meteor/client/lib/virtualbox.js
index 8eba0b2f4a..ee172fb1bb 100644
--- a/meteor/client/lib/virtualbox.js
+++ b/meteor/client/lib/virtualbox.js
@@ -8,7 +8,7 @@ VirtualBox = {};
VirtualBox.REQUIRED_VERSION = '4.3.14';
VirtualBox.INCLUDED_VERSION = '4.3.14';
VirtualBox.INSTALLER_FILENAME = 'virtualbox-4.3.14.pkg';
-VirtualBox.INSTALLER_CHECKSUM = '486348a5336539728ca20dcd9674cf3d37e5c7f32255d90f1edc7391b54bd5dd';
+VirtualBox.INSTALLER_CHECKSUM = '486348a5336539728ca20dcd9674cf3d37e5c7f32255d90f1edc7391b54bd5dd'; // Sha256 Checksum
// Info for the hostonly interface we add to the VM.
VirtualBox.HOSTONLY_HOSTIP = '192.168.60.3';
@@ -26,7 +26,7 @@ VirtualBox.exec = function (command, callback) {
VirtualBox.install = function (callback) {
// -W waits for the process to close before finishing.
- exec('open -W ' + path.join(Util.getResourceDir(), this.INSTALLER_FILENAME), function (error, stdout, stderr) {
+ exec('open -W ' + path.join(Util.getResourceDir(), this.INSTALLER_FILENAME).replace(' ', '\\ '), function (error, stdout, stderr) {
console.log(stdout);
console.log(stderr);
if (error) {
diff --git a/meteor/client/main.less b/meteor/client/main.less
index b0d775924d..80701a0b9f 100755
--- a/meteor/client/main.less
+++ b/meteor/client/main.less
@@ -9,3 +9,4 @@
@import "stylesheets/dashboard.import.less";
@import "stylesheets/setup.import.less";
@import "stylesheets/spinner.import.less";
+@import "stylesheets/radial-progress.import.less";
diff --git a/meteor/client/stylesheets/radial-progress.import.less b/meteor/client/stylesheets/radial-progress.import.less
new file mode 100644
index 0000000000..f522a827d0
--- /dev/null
+++ b/meteor/client/stylesheets/radial-progress.import.less
@@ -0,0 +1,91 @@
+.radial-progress {
+ @circle-size: 34px;
+ @circle-background: #d6dadc;
+ @circle-color: #3FD899;
+ @inset-size: 28px;
+ @inset-color: #fbfbfb;
+ @transition-length: 1s;
+ @shadow: 0px 1px 3px rgba(0,0,0,0.2);
+ @percentage-color: #3FD899;
+ @percentage-font-size: 11px;
+ @percentage-text-width: 57px;
+
+ width: @circle-size;
+ height: @circle-size;
+
+ background-color: @circle-background;
+ border-radius: 50%;
+ .circle {
+ .mask, .fill, .shadow {
+ width: @circle-size;
+ height: @circle-size;
+ position: absolute;
+ border-radius: 50%;
+ }
+ .shadow {
+ box-shadow: @shadow inset;
+ }
+ .mask, .fill {
+ -webkit-backface-visibility: hidden;
+ transition: -webkit-transform @transition-length;
+ transition: -ms-transform @transition-length;
+ transition: transform @transition-length;
+ border-radius: 50%;
+ }
+ .mask {
+ clip: rect(0px, @circle-size, @circle-size, @circle-size/2);
+ .fill {
+ clip: rect(0px, @circle-size/2, @circle-size, 0px);
+ background-color: @circle-color;
+ }
+ }
+ }
+ .inset {
+ width: @inset-size;
+ height: @inset-size;
+ position: absolute;
+ margin-left: (@circle-size - @inset-size)/2;
+ margin-top: (@circle-size - @inset-size)/2;
+
+ background-color: @inset-color;
+ border-radius: 50%;
+ box-shadow: @shadow;
+ .percentage {
+ width: @percentage-text-width;
+ position: absolute;
+ top: (@inset-size - @percentage-font-size) / 2;
+ left: (@inset-size - @percentage-text-width) / 2;
+
+ line-height: 1;
+ text-align: center;
+
+ color: @percentage-color;
+ font-weight: 800;
+ font-size: @percentage-font-size;
+ }
+ }
+
+ @i: 0;
+ @increment: 180deg / 100;
+ .loop (@i) when (@i <= 100) {
+ &[data-progress="@{i}"] {
+ .circle {
+ .mask.full, .fill {
+ -webkit-transform: rotate(@increment * @i);
+ -ms-transform: rotate(@increment * @i);
+ transform: rotate(@increment * @i);
+ }
+ .fill.fix {
+ -webkit-transform: rotate(@increment * @i * 2);
+ -ms-transform: rotate(@increment * @i * 2);
+ transform: rotate(@increment * @i * 2);
+ }
+ }
+ .inset .percentage:before {
+ content: "@{i}%"
+ }
+ }
+ .loop(@i + 1);
+ }
+ .loop(@i);
+}
\ No newline at end of file
diff --git a/meteor/client/views/dashboard/setup/setup-install.html b/meteor/client/views/dashboard/setup/setup-install.html
index a58b7c88b9..bb76f77e74 100644
--- a/meteor/client/views/dashboard/setup/setup-install.html
+++ b/meteor/client/views/dashboard/setup/setup-install.html
@@ -24,7 +24,11 @@
{{#if $eq this.index failedStep}}
{{else}}
- {{> spinner}}
+ {{#if currentInstallStepProgress}}
+ {{> radial_progress progress=currentInstallStepProgress}}
+ {{else}}
+ {{> spinner}}
+ {{/if}}
{{/if}}