diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 79ad0eb510..0000000000 --- a/appveyor.yml +++ /dev/null @@ -1,21 +0,0 @@ -# Test against this version of Node.js -environment: - nodejs_version: "0.10" - -# Install scripts. (runs after repo cloning) -install: - # Get the latest stable version of Node.js or io.js - - ps: Install-Product node $env:nodejs_version - # Updating NPM to avoid permission issues: http://www.appveyor.com/docs/lang/nodejs-iojs#locking-errors-eperm-eexist-tgz-lock - - npm -g install npm@2 - - set PATH=%APPDATA%\npm;%PATH% - # install modules - - npm install - -# Post-install test scripts. -test_script: - # Output useful info for debugging. - - node --version - - npm --version - # run tests - - npm test \ No newline at end of file diff --git a/src/components/ContainerDetailsSubheader.react.js b/src/components/ContainerDetailsSubheader.react.js index 6c1a52093c..2e02e28655 100644 --- a/src/components/ContainerDetailsSubheader.react.js +++ b/src/components/ContainerDetailsSubheader.react.js @@ -10,6 +10,7 @@ var machine = require('../utils/DockerMachineUtil'); var RetinaImage = require('react-retina-image'); var webPorts = require('../utils/Util').webPorts; var classNames = require('classnames'); +var resources = require('../utils/ResourcesUtil'); var ContainerDetailsSubheader = React.createClass({ contextTypes: { diff --git a/src/components/ContainerHome.react.js b/src/components/ContainerHome.react.js index 82e0c82ad2..d760bc5bd4 100644 --- a/src/components/ContainerHome.react.js +++ b/src/components/ContainerHome.react.js @@ -6,14 +6,9 @@ var Radial = require('./Radial.react'); var ContainerHomePreview = require('./ContainerHomePreview.react'); var ContainerHomeLogs = require('./ContainerHomeLogs.react'); var ContainerHomeFolders = require('./ContainerHomeFolders.react'); -<<<<<<< HEAD:src/ContainerHome.react.js -var ContainerUtil = require('./ContainerUtil'); -var util = require('./Util'); var shell = require('shell'); -======= var ContainerUtil = require('../utils/ContainerUtil'); var util = require('../utils/Util'); ->>>>>>> master:src/components/ContainerHome.react.js var resizeWindow = function () { $('.left .wrapper').height(window.innerHeight - 240); diff --git a/src/components/ContainerHomeFolders.react.js b/src/components/ContainerHomeFolders.react.js index e575278bcf..db5095f23e 100644 --- a/src/components/ContainerHomeFolders.react.js +++ b/src/components/ContainerHomeFolders.react.js @@ -28,12 +28,12 @@ var ContainerHomeFolder = React.createClass({ volumes[containerVolume] = newHostVolume; var binds = _.pairs(volumes).map(function (pair) { if(util.isWindows()) { - var home = util.home(); - home = home.charAt(0).toLowerCase() + home.slice(1); - home = '/' + home.replace(':', '').replace(/\\/g, '/'); - var fullPath = path.join(home, 'Kitematic', pair[1], pair[0]); - fullPath = fullPath.replace(/\\/g, '/'); - return fullPath + ':' + pair[0]; + var home = util.home(); + home = home.charAt(0).toLowerCase() + home.slice(1); + home = '/' + home.replace(':', '').replace(/\\/g, '/'); + var fullPath = path.join(home, 'Kitematic', pair[1], pair[0]); + fullPath = fullPath.replace(/\\/g, '/'); + return fullPath + ':' + pair[0]; } return pair[1] + ':' + pair[0]; }); diff --git a/src/components/ContainerSettingsVolumes.react.js b/src/components/ContainerSettingsVolumes.react.js index 79c2a87991..73c8ef95c0 100644 --- a/src/components/ContainerSettingsVolumes.react.js +++ b/src/components/ContainerSettingsVolumes.react.js @@ -2,9 +2,9 @@ var _ = require('underscore'); var React = require('react/addons'); var remote = require('remote'); var dialog = remote.require('dialog'); +var shell = require('shell'); var metrics = require('../utils/MetricsUtil'); var ContainerStore = require('../stores/ContainerStore'); -var util = require('../utils/Util'); var ContainerSettingsVolumes = React.createClass({ handleChooseVolumeClick: function (dockerVol) { @@ -48,7 +48,7 @@ var ContainerSettingsVolumes = React.createClass({ metrics.track('Opened Volume Directory', { from: 'settings' }); - util.showItemInFolder(path); + shell.showItemInFolder(path); }, render: function () { if (!this.props.container) { diff --git a/src/stores/SetupStore-test.js b/src/stores/SetupStore-test.js index 2ce667d079..5613d44aa5 100644 --- a/src/stores/SetupStore-test.js +++ b/src/stores/SetupStore-test.js @@ -11,7 +11,7 @@ describe('SetupStore', function () { pit('downloads virtualbox if it is not installed', function () { virtualBox.installed.mockReturnValue(false); setupUtil.download.mockReturnValue(Promise.resolve()); - setupUtil.virtualBoxFileName.mockReturnValue(''); + virtualBox.filename.mockReturnValue(''); util.supportDir.mockReturnValue(''); return setupStore.steps().download.run().then(() => { expect(setupUtil.download).toBeCalled(); @@ -23,7 +23,7 @@ describe('SetupStore', function () { virtualBox.version.mockReturnValue(Promise.resolve('4.3.16')); util.compareVersions.mockReturnValue(-1); setupUtil.download.mockReturnValue(Promise.resolve()); - setupUtil.virtualBoxFileName.mockReturnValue(''); + virtualBox.filename.mockReturnValue(''); util.supportDir.mockReturnValue(''); return setupStore.steps().download.run().then(() => { expect(setupUtil.download).toBeCalled(); @@ -33,7 +33,6 @@ describe('SetupStore', function () { describe('install step', function () { util.exec.mockReturnValue(Promise.resolve()); - util.execProper.mockReturnValue(Promise.resolve()); setupUtil.copyBinariesCmd.mockReturnValue(Promise.resolve()); setupUtil.fixBinariesCmd.mockReturnValue(Promise.resolve()); virtualBox.killall.mockReturnValue(Promise.resolve()); @@ -64,8 +63,6 @@ describe('SetupStore', function () { }); describe('init step', function () { - virtualBox.vmdestroy.mockReturnValue(Promise.resolve()); - pit('upgrades the vm if it exists and is out of date', function () { machine.exists.mockReturnValue(Promise.resolve(true)); machine.state.mockReturnValue(Promise.resolve('Stopped')); diff --git a/src/stores/SetupStore.js b/src/stores/SetupStore.js index 92b4a46dba..d4440f8801 100644 --- a/src/stores/SetupStore.js +++ b/src/stores/SetupStore.js @@ -25,7 +25,7 @@ var _steps = [{ totalPercent: 35, percent: 0, run: function (progressCallback) { - return setupUtil.download(setupUtil.virtualBoxUrl(), path.join(util.supportDir(), setupUtil.virtualBoxFileName()), setupUtil.virtualBoxChecksum(), percent => { + return setupUtil.download(virtualBox.url(), path.join(util.supportDir(), virtualBox.filename()), virtualBox.checksum(), percent => { progressCallback(percent); }); } @@ -37,20 +37,22 @@ var _steps = [{ percent: 0, seconds: 5, run: Promise.coroutine(function* (progressCallback) { - yield setupUtil.copyBinariesCmd(); - yield setupUtil.fixBinariesCmd(); + var cmd = ''; if (!virtualBox.installed()) { yield virtualBox.killall(); - try { - progressCallback(50); // TODO: detect when the installation has started so we can simulate progress - yield setupUtil.installVirtualBoxCmd(); - } catch (err) { - throw null; + cmd += ' && ' + setupUtil.installVirtualBoxCmd(); + } else { + if (!setupUtil.needsBinaryFix()) { + return; } } - - return; + try { + progressCallback(50); // TODO: detect when the installation has started so we can simulate progress + yield setupUtil.installVirtualBoxCmd(); + } catch (err) { + throw null; + } }) }, { name: 'init', @@ -70,23 +72,7 @@ var _steps = [{ let parts = home.split('\\').slice(0, -1); let usersDirName = parts[parts.length-1]; let usersDirPath = parts.join('\\'); - let shareName = driveLetter + "/" + usersDirName; - - yield machine.stop(); - yield virtualBox.mountSharedDir(machine.name(), shareName, usersDirPath); - yield machine.start(); - } - return; - } else if ((yield machine.state()) === 'Error') { - yield machine.rm(); - yield machine.create(); - if(util.isWindows()) { - let home = util.home(); - let driveLetter = home.charAt(0); - let parts = home.split('\\').slice(0, -1); - let usersDirName = parts[parts.length-1]; - let usersDirPath = parts.join('\\'); - let shareName = driveLetter + "/" + usersDirName; + let shareName = driveLetter + '/' + usersDirName; yield machine.stop(); yield virtualBox.mountSharedDir(machine.name(), shareName, usersDirPath); @@ -169,10 +155,10 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), { var packagejson = util.packagejson(); var isoversion = machine.isoversion(); var required = {}; - var vboxfile = path.join(util.supportDir(), setupUtil.virtualBoxFileName()); + var vboxfile = path.join(util.supportDir(), virtualBox.filename()); var vboxNeedsInstall = !virtualBox.installed(); - required.download = vboxNeedsInstall && (!fs.existsSync(vboxfile) || setupUtil.checksum(vboxfile) !== setupUtil.virtualBoxChecksum()); + required.download = vboxNeedsInstall && (!fs.existsSync(vboxfile) || setupUtil.checksum(vboxfile) !== virtualBox.checksum()); required.install = vboxNeedsInstall || setupUtil.needsBinaryFix(); required.init = required.install || !(yield machine.exists()) || (yield machine.state()) !== 'Running' || !isoversion || util.compareVersions(isoversion, packagejson['docker-version']) < 0; @@ -257,8 +243,6 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), { metrics.track('Setup Failed', { step: _currentStep, }); - console.log(err); - console.log(err.stack); bugsnag.notify('SetupError', err.message, { error: err, output: err.message diff --git a/src/utils/DockerMachineUtil.js b/src/utils/DockerMachineUtil.js index 479c3071dc..58f8d2644e 100644 --- a/src/utils/DockerMachineUtil.js +++ b/src/utils/DockerMachineUtil.js @@ -9,7 +9,7 @@ var NAME = 'dev'; var DockerMachine = { command: function () { - return resources.docker_machine(); + return resources.dockerMachine(); }, name: function () { return NAME; diff --git a/src/utils/SetupUtil.js b/src/utils/SetupUtil.js index 1a067f31ff..6336919a82 100644 --- a/src/utils/SetupUtil.js +++ b/src/utils/SetupUtil.js @@ -1,16 +1,19 @@ var _ = require('underscore'); var crypto = require('crypto'); -var fs = require('fs-promise'); +var fs = require('fs'); var path = require('path'); var request = require('request'); var progress = require('request-progress'); var Promise = require('bluebird'); var util = require('./Util'); var resources = require('./ResourcesUtil'); +var virtualBox = require ('./VirtualBoxUtil'); var SetupUtil = { needsBinaryFix() { - return !!(util.pathDoesNotExistOrDenied(util.binsPath()) || util.pathDoesNotExistOrDenied(util.dockerBinPath()) || util.pathDoesNotExistOrDenied(util.dockerMachineBinPath())); + return this.pathDoesNotExistOrDenied(util.binsPath()) || + this.pathDoesNotExistOrDenied(util.dockerBinPath()) || + this.pathDoesNotExistOrDenied(util.dockerMachineBinPath()); }, pathDoesNotExistOrDenied: function (path) { if(util.isWindows()) { @@ -19,49 +22,38 @@ var SetupUtil = { return (!fs.existsSync(path) || fs.statSync(path).gid !== 80 || fs.statSync(path).uid !== process.getuid()); } }, - escapePath(str) { - return str.replace(/ /g, '\\ ').replace(/\(/g, '\\(').replace(/\)/g, '\\)'); - }, - shouldUpdateBinaries() { + shouldUpdateBinaries: function () { return !fs.existsSync(util.dockerBinPath()) || !fs.existsSync(util.dockerMachineBinPath()) || this.checksum(util.dockerMachineBinPath()) !== this.checksum(resources.dockerMachine()) || this.checksum(util.dockerBinPath()) !== this.checksum(resources.docker()); - }, - copyBinariesCmd: Promise.coroutine(function* () { - yield fs.mkdirs(util.binsPath()); - yield fs.copy(resources.dockerMachine(), util.dockerMachineBinPath()); - yield fs.copy(resources.docker(), util.dockerBinPath()); - }), - fixBinariesCmd: Promise.coroutine(function* () { + copyBinariesCmd: function () { + var cmd = ['mkdir', '-p', '/usr/local/bin']; + cmd.push('&&'); + cmd.push.apply(cmd, this.copycmd(util.escapePath(resources.dockerMachine()), '/usr/local/bin/docker-machine')); + cmd.push('&&'); + cmd.push.apply(cmd, this.copycmd(util.escapePath(resources.docker()), '/usr/local/bin/docker')); + return cmd.join(' '); + }, + fixBinariesCmd: function () { + var cmd = []; + cmd.push.apply(cmd, ['chown', `${process.getuid()}:${80}`, path.join('/usr/local/bin')]); + cmd.push('&&'); + cmd.push.apply(cmd, ['chown', `${process.getuid()}:${80}`, path.join('/usr/local/bin', 'docker-machine')]); + cmd.push('&&'); + cmd.push.apply(cmd, ['chown', `${process.getuid()}:${80}`, path.join('/usr/local/bin', 'docker')]); + return cmd.join(' '); + }, + installVirtualBoxCmd: function () { if(util.isWindows()) { - return; - } - - yield fs.chown(util.binsPath(), process.getuid(), 80); - yield fs.chown(util.dockerBinPath(), process.getuid(), 80); - yield fs.chown(util.dockerMachineBinPath(), process.getuid(), 80); - return Promise.resolve(); - }), - installVirtualBoxCmd: Promise.coroutine(function* () { - if(util.isWindows()) { - yield util.execProper(`powershell.exe -ExecutionPolicy unrestricted -Command "Start-Process \\\"${path.join(util.supportDir(), this.virtualBoxFileName())}\\\" -ArgumentList \\\"--silent --msiparams REBOOT=ReallySuppress\\\" -Verb runAs -Wait"`); + return `powershell.exe -ExecutionPolicy unrestricted -Command "Start-Process \\\"${path.join(util.supportDir(), virtualBox.filename())}\\\" -ArgumentList \\\"--silent --msiparams REBOOT=ReallySuppress\\\" -Verb runAs -Wait"`; } else { - yield util.exec(this.macSudoCmd(`installer -pkg ${this.escapePath(path.join(util.supportDir(), this.virtualBoxFileName()))} -target /`)); - } - - return Promise.resolve(); - }), - virtualBoxUrl() { - if(util.isWindows()) { - return 'http://download.virtualbox.org/virtualbox/4.3.26/VirtualBox-4.3.26-98988-Win.exe'; - } else { - return `https://github.com/kitematic/virtualbox/releases/download/${util.packagejson()['virtualbox-version']}/${this.virtualBoxFileName()}`; + return `installer -pkg ${util.escapePath(path.join(util.supportDir(), virtualBox.filename()))} -target /`; } }, macSudoCmd(cmd) { - return `${this.escapePath(resources.macsudo())} -p "Kitematic requires administrative privileges to install." sh -c \"${cmd}\"`; + return `${util.escapePath(resources.macsudo())} -p "Kitematic requires administrative privileges to install." sh -c \"${cmd}\"`; }, simulateProgress(estimateSeconds, progress) { var times = _.range(0, estimateSeconds * 1000, 200); @@ -103,12 +95,6 @@ var SetupUtil = { resolve(); }); }); - }, - virtualBoxFileName() { - return util.isWindows() ? util.packagejson()['virtualbox-filename-win'] : util.packagejson()['virtualbox-filename']; - }, - virtualBoxChecksum() { - return util.isWindows() ? util.packagejson()['virtualbox-checksum-win'] : util.packagejson()['virtualbox-checksum']; } }; diff --git a/src/utils/Util.js b/src/utils/Util.js index a48ac4143e..b305a3aa49 100644 --- a/src/utils/Util.js +++ b/src/utils/Util.js @@ -1,10 +1,13 @@ var exec = require('exec'); var Promise = require('bluebird'); -var fs = require('fs'); +var fs = require('fs-promise'); var path = require('path'); module.exports = { exec: function (args, options) { + if (typeof args === 'string') { + args = args.split(' '); + } options = options || {}; return new Promise((resolve, reject) => { exec(args, options, (stderr, stdout, code) => { @@ -20,18 +23,6 @@ module.exports = { isWindows: function () { return process.platform === 'win32'; }, - home: function () { - return process.env[this.isWindows() ? 'USERPROFILE' : 'HOME']; - }, - supportDir: function () { - var acc = path.join(this.home(), 'Library', 'Application\ Support', 'Kitematic'); - fs.mkdirsSync(acc); - return acc; - }, - CommandOrCtrl: function () { - return this.isWindows() ? 'Ctrl' : 'Command'; - }, - binsPath: function () { return this.isWindows() ? path.join(this.home(), 'Kitematic-bins') : path.join('/usr/local/bin'); }, @@ -44,6 +35,20 @@ module.exports = { dockerMachineBinPath: function () { return path.join(this.binsPath(), 'docker-machine' + this.binsEnding()); }, + escapePath: function (str) { + return str.replace(/ /g, '\\ ').replace(/\(/g, '\\(').replace(/\)/g, '\\)'); + }, + home: function () { + return process.env[this.isWindows() ? 'USERPROFILE' : 'HOME']; + }, + supportDir: function () { + var acc = path.join(this.home(), 'Library', 'Application\ Support', 'Kitematic'); + fs.mkdirsSync(acc); + return acc; + }, + CommandOrCtrl: function () { + return this.isWindows() ? 'Ctrl' : 'Command'; + }, removeSensitiveData: function (str) { if (!str || str.length === 0 || typeof str !== 'string' ) { return str; diff --git a/src/utils/VirtualBoxUtil.js b/src/utils/VirtualBoxUtil.js index bf115ebb57..1c58d5f16e 100644 --- a/src/utils/VirtualBoxUtil.js +++ b/src/utils/VirtualBoxUtil.js @@ -4,22 +4,35 @@ var Promise = require('bluebird'); var VirtualBox = { command: function () { - if(util.isWindows()) { - return 'C:\\Program Files\\Oracle\\VirtualBox\\VBoxManage.exe'; - } else { - return '/usr/bin/VBoxManage'; - } + if(util.isWindows()) { + return 'C:\\Program Files\\Oracle\\VirtualBox\\VBoxManage.exe'; + } else { + return '/usr/bin/VBoxManage'; + } + }, + filename: function () { + return util.isWindows() ? util.packagejson()['virtualbox-filename-win'] : util.packagejson()['virtualbox-filename']; + }, + checksum: function () { + return util.isWindows() ? util.packagejson()['virtualbox-checksum-win'] : util.packagejson()['virtualbox-checksum']; + }, + url: function () { + if(util.isWindows()) { + return 'http://download.virtualbox.org/virtualbox/4.3.26/VirtualBox-4.3.26-98988-Win.exe'; + } else { + return `https://github.com/kitematic/virtualbox/releases/download/${util.packagejson()['virtualbox-version']}/${this.virtualBoxFileName()}`; + } }, installed: function () { if(util.isWindows()) { - return fs.existsSync('C:\\Program Files\\Oracle\\VirtualBox\\VBoxManage.exe') && fs.existsSync('C:\\Program Files\\Oracle\\VirtualBox\\VirtualBox.exe'); + return fs.existsSync('C:\\Program Files\\Oracle\\VirtualBox\\VBoxManage.exe') && fs.existsSync('C:\\Program Files\\Oracle\\VirtualBox\\VirtualBox.exe'); } else { - return fs.existsSync('/usr/bin/VBoxManage') && fs.existsSync('/Applications/VirtualBox.app'); + return fs.existsSync('/usr/bin/VBoxManage') && fs.existsSync('/Applications/VirtualBox.app'); } }, version: function () { return new Promise((resolve, reject) => { - util.exec([this.command(), '-v']).then(stdout => { + util.exec([this.command(), '-v']).then(stdout => { var match = stdout.match(/(\d+\.\d+\.\d+).*/); if (!match || match.length < 2) { reject('VBoxManage -v output format not recognized.'); @@ -38,28 +51,23 @@ var VirtualBox = { if (!this.installed()) { return Promise.reject('VirtualBox not installed.'); } - + return util.exec([this.command(), 'sharedfolder', 'add', vmName, '--name', pathName, '--hostpath', hostPath, '--automount']); }, killall: function () { - if(util.isWindows()) { - return this.poweroffall().then(() => { - return util.exec(['powershell.exe', '\"get-process VBox* | stop-process\"']); - }).catch(() => { + if(util.isWindows()) { + return this.poweroffall().then(() => { + return util.exec(['powershell.exe', '\"get-process VBox* | stop-process\"']); + }).catch(() => {}); + } else { + return this.poweroffall().then(() => { + return util.exec(['pkill', 'VirtualBox']); + }).then(() => { + return util.exec(['pkill', 'VBox']); + }).catch(() => { - }); - } else { - return this.poweroffall().then(() => { - return util.exec(['pkill', 'VirtualBox']); - }).then(() => { - return util.exec(['pkill', 'VBox']); - }).catch(() => { - - }); - } - }, - wake: function (name) { - return util.exec([this.command(), 'startvm', name, '--type', 'headless']); + }); + } }, vmstate: function (name) { return new Promise((resolve, reject) => { @@ -71,17 +79,6 @@ var VirtualBox = { resolve(match[1]); }).catch(reject); }); - }, - vmdestroy: function (name) { - return Promise.coroutine(function* () { - try { - var state = yield this.vmstate(name); - if (state === 'running') { - yield util.exec([this.command(), 'controlvm', name, 'poweroff']); - } - yield util.exec([this.command(), 'unregistervm', name, '--delete']); - } catch (err) {} - }.bind(this))(); } };