diff --git a/__mocks__/remote.js b/__mocks__/remote.js new file mode 100644 index 0000000000..b2c2ab1348 --- /dev/null +++ b/__mocks__/remote.js @@ -0,0 +1,4 @@ +module.exports = { + require: jest.genMockFunction(), + match: jest.genMockFunction() +}; diff --git a/gulpfile.js b/gulpfile.js index b52142baa2..09b70a92b9 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -14,6 +14,9 @@ var plumber = require('gulp-plumber'); var runSequence = require('run-sequence'); var shell = require('gulp-shell'); var sourcemaps = require('gulp-sourcemaps'); +var execFile = require('child_process').execFile; +var request = require('request'); +var path = require('path'); var dependencies = Object.keys(packagejson.dependencies); var argv = require('minimist')(process.argv.slice(2)); @@ -175,16 +178,96 @@ gulp.task('settings', function () { string_src('settings.json', JSON.stringify(settings)).pipe(gulp.dest('dist/osx/' + options.appFilename.replace(' ', '\ ').replace('(','\(').replace(')','\)') + '/Contents/Resources/app')); }); -gulp.task('download-deps', function () { - if(process.platform === 'win32') { - return gulp.src('').pipe( - shell(['powershell.exe -ExecutionPolicy unrestricted -File util\\deps.ps1']) - ); - } else { - return gulp.src('').pipe( - shell(['./util/deps']) - ); +var version = function (str) { + var match = str.match(/(\d+\.\d+\.\d+)/); + if (match) { + return match[1]; + } else { + return null; + } +}; + +gulp.task('download-docker', function (cb) { + if (process.platform === 'win32' && fs.existsSync(path.join('resources', 'docker.exe'))) { + cb(); + return; + } + + execFile(path.join('resources', 'docker'), ['-v'], function (err, stdout, stderr) { + var currentVersion = version(stdout); + if (currentVersion && currentVersion === packagejson['docker-version']) { + cb(); + return; } + + gutil.log(gutil.colors.green('Downloading Docker')); + + if(process.platform === 'win32') { + request('https://master.dockerproject.com/windows/amd64/docker-1.7.0-dev.exe').pipe(fs.createWriteStream('./resources/docker.exe')).on('finish', cb); + } else { + request('https://get.docker.com/builds/Darwin/x86_64/docker-' + packagejson['docker-version']) + .pipe(fs.createWriteStream('./resources/docker')).on('finish', function () { + fs.chmodSync('./resources/docker', 755); + cb(); + }); + } + }); +}); + +gulp.task('download-docker-machine', function (cb) { + execFile(path.join('resources', 'docker-machine'), ['-v'], function (err, stdout, stderr) { + var currentVersion = version(stdout); + if (currentVersion && currentVersion === version(packagejson['docker-machine-version'])) { + cb(); + return; + } + + gutil.log(gutil.colors.green('Downloading Docker Machine')); + + if(process.platform === 'win32') { + request('https://github.com/docker/machine/releases/download/v' + packagejson['docker-machine-version'] + '/docker-machine_windows-amd64.exe') + .pipe(fs.createWriteStream('./resources/docker-machine.exe')).on('finish', function () {cb()}); + } else { + request('https://github.com/docker/machine/releases/download/v' + packagejson['docker-machine-version'] + '/docker-machine_darwin-amd64') + .pipe(fs.createWriteStream('./resources/docker-machine')).on('finish', function () { + fs.chmodSync('./resources/docker-machine', 755); + cb(); + }); + } + }); +}); + +gulp.task('download-docker-compose', function (cb) { + execFile(path.join('resources', 'docker-compose'), ['--version'], function (err, stdout, stderr) { + var currentVersion = version(stdout); + if (currentVersion && currentVersion === packagejson['docker-compose-version']) { + cb(); + return; + } + + if(process.platform === 'win32') { + // Todo: install windows version of compose + cb(); + } else { + gutil.log(gutil.colors.green('Downloading Docker Compose')); + request('https://github.com/docker/compose/releases/download/' + packagejson['docker-compose-version'] + '/docker-compose-Darwin-x86_64') + .pipe(fs.createWriteStream('./resources/docker-compose')).on('finish', function () { + fs.chmodSync('./resources/docker-compose', 755); + cb(); + }); + } + }); +}); + +gulp.task('download-boot2docker-iso', function (cb) { + var b2dFile = path.join('resources', 'boot2docker-' + packagejson['docker-version'] + '.iso'); + if (!fs.existsSync(b2dFile)) { + gutil.log(gutil.colors.green('Downloading Boot2Docker iso')); + request('https://github.com/boot2docker/boot2docker/releases/download/v' + packagejson['docker-version'] + '/boot2docker.iso') + .pipe(fs.createWriteStream(b2dFile)).on('finish', cb); + } else { + cb(); + } }); gulp.task('reset', function () { @@ -200,10 +283,10 @@ gulp.task('reset', function () { }); gulp.task('release', function () { - runSequence('download-deps', 'download', 'dist', ['copy', 'images', 'js', 'styles', 'settings'], 'sign', 'zip'); + runSequence('download-docker', 'download-docker-machine', 'download-docker-compose', 'download-boot2docker-iso', 'download', 'dist', ['copy', 'images', 'js', 'styles', 'settings'], 'sign', 'zip'); }); -gulp.task('default', ['download-deps', 'download', 'copy', 'js', 'images', 'styles'], function () { +gulp.task('default', ['download-docker', 'download-docker-machine', 'download-docker-compose', 'download-boot2docker-iso', 'download', 'copy', 'js', 'images', 'styles'], function () { gulp.watch('src/**/*.js', ['js']); gulp.watch('index.html', ['copy']); gulp.watch('styles/**/*.less', ['styles']); diff --git a/index.html b/index.html index 69fafdb727..699c7186f0 100644 --- a/index.html +++ b/index.html @@ -6,6 +6,6 @@ Kitematic - + diff --git a/jest-integration.json b/jest-integration.json index 1405f9045e..af08d8fd85 100644 --- a/jest-integration.json +++ b/jest-integration.json @@ -1,6 +1,6 @@ { "testDirectoryName": "__integration__", - "scriptPreprocessor": "/util/preprocessor.js", + "scriptPreprocessor": "/node_modules/babel-jest", "setupEnvScriptFile": "/util/testenv.js", "setupTestFrameworkScriptFile": "/util/prepare.js", "unmockedModulePathPatterns": [ diff --git a/jest-unit.json b/jest-unit.json index 0981c13ebf..bc91f0f679 100644 --- a/jest-unit.json +++ b/jest-unit.json @@ -1,5 +1,5 @@ { - "scriptPreprocessor": "/util/preprocessor.js", + "scriptPreprocessor": "/node_modules/babel-jest", "setupEnvScriptFile": "/util/testenv.js", "setupTestFrameworkScriptFile": "/util/prepare.js", "unmockedModulePathPatterns": [ @@ -9,10 +9,10 @@ "net", "crypto", "babel", - "/node_modules/.*JSONStream", - "/node_modules/object-assign", - "/node_modules/underscore", - "/node_modules/bluebird", - "/node_modules/source-map-support" + "bluebird", + "object-assign", + "underscore", + "source-map-support", + "/node_modules/.*JSONStream" ] } diff --git a/package.json b/package.json index 1d8db74abf..f33814e197 100644 --- a/package.json +++ b/package.json @@ -26,9 +26,9 @@ } ], "docker-version": "1.6.2", - "docker-machine-version": "0.2.0", + "docker-machine-version": "0.3.0-rc1", "docker-compose-version": "1.2.0", - "electron-version": "0.26.0", + "electron-version": "0.27.2", "virtualbox-version": "4.3.28", "virtualbox-filename": "VirtualBox-4.3.28.pkg", "virtualbox-filename-win": "VirtualBox-4.3.28.exe", @@ -57,7 +57,7 @@ "react": "^0.13.1", "react-bootstrap": "^0.20.3", "react-retina-image": "^1.1.2", - "react-router": "^0.13.2", + "react-router": "^0.13.3", "request": "^2.55.0", "request-progress": "^0.3.1", "rimraf": "^2.3.2", @@ -66,6 +66,7 @@ }, "devDependencies": { "babel": "^5.1.10", + "babel-jest": "^5.2.0", "gulp": "^3.8.11", "gulp-babel": "^5.1.0", "gulp-changed": "^1.2.1", diff --git a/src/components/ContainerHome.react.js b/src/components/ContainerHome.react.js index 6b63bab4b3..18d0f97ffc 100644 --- a/src/components/ContainerHome.react.js +++ b/src/components/ContainerHome.react.js @@ -45,7 +45,7 @@ var ContainerHome = React.createClass({ body = (

An error occurred:

-

{this.props.container.Error.message}

+

{this.props.container.Error}

If you feel that this error is invalid, please file a ticket on our GitHub repo.

diff --git a/src/components/ContainerHomeFolders.react.js b/src/components/ContainerHomeFolders.react.js index cc62cd6a87..4bd3ef8bd7 100644 --- a/src/components/ContainerHomeFolders.react.js +++ b/src/components/ContainerHomeFolders.react.js @@ -63,8 +63,9 @@ var ContainerHomeFolder = React.createClass({ return false; } - var folders = _.map(this.props.container.Volumes, (val, key) => { - var firstFolder = key.split(path.sep)[1]; + console.log(this.props.container.Volumes); + var folders = _.map(_.omit(this.props.container.Volumes, (v, k) => k.indexOf('/Users/') !== -1), (val, key) => { + var firstFolder = key.split('/')[1]; return (
diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000000..36c3352e9f --- /dev/null +++ b/src/main.js @@ -0,0 +1 @@ +import './app'; diff --git a/src/stores/SetupStore.js b/src/stores/SetupStore.js index f97a8e7cbb..ddedcb3545 100644 --- a/src/stores/SetupStore.js +++ b/src/stores/SetupStore.js @@ -41,7 +41,11 @@ var _steps = [{ yield virtualBox.killall(); progressCallback(50); // TODO: detect when the installation has started so we can simulate progress try { - yield util.exec(setupUtil.macSudoCmd(setupUtil.installVirtualBoxCmd())); + if (util.isWindows()) { + yield util.exec([path.join(util.supportDir(), virtualBox.filename())]); + } else { + yield util.exec(setupUtil.macSudoCmd(setupUtil.installVirtualBoxCmd())); + } } catch (err) { throw null; } diff --git a/src/utils/DockerMachineUtil.js b/src/utils/DockerMachineUtil.js index 49ac2b399d..0875882d5c 100644 --- a/src/utils/DockerMachineUtil.js +++ b/src/utils/DockerMachineUtil.js @@ -57,7 +57,11 @@ var DockerMachine = { }, create: function () { var dockerversion = util.packagejson()['docker-version']; - return util.exec([this.command(), '-D', 'create', '-d', 'virtualbox', '--virtualbox-boot2docker-url', path.join(process.cwd(), 'resources', 'boot2docker-' + dockerversion + '.iso'), '--virtualbox-memory', '2048', NAME]); + if (util.isWindows()) { + return util.exec([this.command(), '-D', 'create', '-d', 'virtualbox', '--virtualbox-memory', '2048', NAME]); + } else { + return util.exec([this.command(), '-D', 'create', '-d', 'virtualbox', '--virtualbox-boot2docker-url', path.join(process.cwd(), 'resources', 'boot2docker-' + dockerversion + '.iso'), '--virtualbox-memory', '2048', NAME]); + } }, start: function () { return util.exec([this.command(), '-D', 'start', NAME]); diff --git a/src/utils/Util.js b/src/utils/Util.js index 60554439ab..6a1ebdcdd4 100644 --- a/src/utils/Util.js +++ b/src/utils/Util.js @@ -3,6 +3,8 @@ var Promise = require('bluebird'); var fs = require('fs'); var path = require('path'); var crypto = require('crypto'); +var remote = require('remote'); +var app = remote.require('app'); module.exports = { exec: function (args, options) { @@ -37,21 +39,13 @@ module.exports = { return str.replace(/ /g, '\\ ').replace(/\(/g, '\\(').replace(/\)/g, '\\)'); }, home: function () { - return process.env[this.isWindows() ? 'USERPROFILE' : 'HOME']; + return app.getPath('home'); }, documents: function () { return this.isWindows() ? 'My\ Documents' : 'Documents'; }, supportDir: function () { - var dirs = ['Library', 'Application\ Support', 'Kitematic']; - var acc = this.home(); - dirs.forEach(function (d) { - acc = path.join(acc, d); - if (!fs.existsSync(acc)) { - fs.mkdirSync(acc); - } - }); - return acc; + return app.getPath('userData'); }, CommandOrCtrl: function () { return this.isWindows() ? 'Ctrl' : 'Command'; diff --git a/src/utils/VirtualBoxUtil.js b/src/utils/VirtualBoxUtil.js index 3bf33432f1..80705cbe78 100644 --- a/src/utils/VirtualBoxUtil.js +++ b/src/utils/VirtualBoxUtil.js @@ -17,11 +17,7 @@ var VirtualBox = { 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.filename()}`; - } + return `https://github.com/kitematic/virtualbox/releases/download/${util.packagejson()['virtualbox-version']}/${this.filename()}`; }, installed: function () { if(util.isWindows()) { diff --git a/styles/variables.less b/styles/variables.less index 83e17a8c3b..dc0624f59e 100644 --- a/styles/variables.less +++ b/styles/variables.less @@ -22,5 +22,5 @@ @color-divider: @gray-lightest; @color-background: #FCFCFC; -@font-regular: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; -@font-code: Menlo; +@font-regular: "Helvetica Neue", Segoe UI, Arial, "Lucida Grande", sans-serif; +@font-code: Menlo, Consolas; diff --git a/util/deps b/util/deps deleted file mode 100755 index a2f364c97a..0000000000 --- a/util/deps +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -BASE=$DIR/.. -DOCKER_VERSION=$(node -pe "JSON.parse(process.argv[1])['docker-version']" "$(cat $BASE/package.json)") -DOCKER_MACHINE_VERSION=$(node -pe "JSON.parse(process.argv[1])['docker-machine-version']" "$(cat $BASE/package.json)") -DOCKER_COMPOSE_VERSION=$(node -pe "JSON.parse(process.argv[1])['docker-compose-version']" "$(cat $BASE/package.json)") -CURRENT_DOCKER_VERSION=$($BASE/resources/docker -v | cut -d ',' -f1 | awk '{print $3}' | cut -d '-' -f1) -CURRENT_DOCKER_MACHINE_VERSION=$($BASE/resources/docker-machine -v | cut -d ',' -f1 | awk '{print $3}' | cut -d '-' -f1) -CURRENT_DOCKER_COMPOSE_VERSION=$($BASE/resources/docker-compose --version | cut -d ',' -f1 | awk '{print $2}' | cut -d '-' -f1) -BOOT2DOCKER_FILE=boot2docker-$DOCKER_VERSION.iso - -pushd $BASE/resources > /dev/null - -if [ "$DOCKER_VERSION" != "$CURRENT_DOCKER_VERSION" ]; then - echo "-----> Downloading Docker CLI..." - rm -rf docker - rm -rf docker-* - curl -L -o docker-$DOCKER_VERSION.tgz https://get.docker.com/builds/Darwin/x86_64/docker-$DOCKER_VERSION.tgz - tar xvzf docker-$DOCKER_VERSION.tgz --strip=3 - rm docker-$DOCKER_VERSION.tgz - chmod +x docker -fi - -if [ "$DOCKER_MACHINE_VERSION" != "$CURRENT_DOCKER_MACHINE_VERSION" ]; then - echo "-----> Downloading Docker Machine CLI..." - rm -rf docker-machine - rm -rf docker-machine-* - curl -L -o docker-machine https://github.com/docker/machine/releases/download/v$DOCKER_MACHINE_VERSION/docker-machine_darwin-amd64 - chmod +x docker-machine -fi - -if [ "$DOCKER_COMPOSE_VERSION" != "$CURRENT_DOCKER_COMPOSE_VERSION" ]; then - echo "-----> Downloading Docker Compose CLI..." - rm -rf docker-compose - curl -L -o docker-compose https://github.com/docker/compose/releases/download/$DOCKER_COMPOSE_VERSION/docker-compose-Darwin-x86_64 - chmod +x docker-compose -fi - -if [ ! -f $BOOT2DOCKER_FILE ]; then - echo "-----> Downloading Boot2Docker iso..." - rm -rf boot2docker-* - curl -L -o $BOOT2DOCKER_FILE https://github.com/boot2docker/boot2docker/releases/download/v$DOCKER_VERSION/boot2docker.iso -fi - - -popd > /dev/null diff --git a/util/deps.ps1 b/util/deps.ps1 deleted file mode 100644 index ba08d6c2ec..0000000000 --- a/util/deps.ps1 +++ /dev/null @@ -1,26 +0,0 @@ -$scriptpath = $MyInvocation.MyCommand.Path -$dir = Split-Path $scriptpath -$BasePath = $dir + '\..\' -$packageJson = get-content ($BasePath + 'package.json') -[System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") > $null -$serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer -$packageJsonContent = $serializer.DeserializeObject($packageJson) -$webclient = New-Object System.Net.WebClient - -$DOCKER_MACHINE_CLI_VERSION = $packageJsonContent['docker-machine-version'] -$DOCKER_CLI_VERSION = $packageJsonContent['docker-version'] - - -if(-Not (test-path ($BasePath + '\resources\docker'))) { - echo "-----> Downloading Docker CLI..." - $source = "https://master.dockerproject.com/windows/amd64/docker.exe" - $destination = $BasePath + "\resources\docker" - $webclient.DownloadFile($source, $destination) -} - -if(-Not (test-path ($BasePath + '\resources\docker-machine'))) { - echo "-----> Downloading Docker Machine CLI..." - $source = "https://github.com/docker/machine/releases/download/v" + $DOCKER_MACHINE_VERSION+ "/docker-machine_windows-amd64.exe" - $destination = $BasePath + "\resources\docker-machine" - $webclient.DownloadFile($source, $destination) -} diff --git a/util/prepare.js b/util/prepare.js index 2aa87fd0a3..d293d5d710 100644 --- a/util/prepare.js +++ b/util/prepare.js @@ -1,14 +1 @@ require.requireActual('babel/polyfill'); -require.requireActual('source-map-support').install({ - retrieveSourceMap: function(filename) { - if (filename.indexOf('node_modules') === -1) { - try { - return { - map: require.requireActual('fs').readFileSync('/tmp/' + require('crypto').createHash('md5').update(filename).digest('hex') + '.map', 'utf8') - }; - } catch (err) { - return undefined; - } - } - } -}); diff --git a/util/preprocessor.js b/util/preprocessor.js deleted file mode 100644 index a284c1eacc..0000000000 --- a/util/preprocessor.js +++ /dev/null @@ -1,14 +0,0 @@ -var babel = require('babel'); -var fs = require('fs'); -var crypto = require('crypto'); - -module.exports = { - process: function(src, filename) { - if (filename.indexOf('node_modules') !== -1) { - return src; - } - var compiled = babel.transform(src, {filename: filename, sourceMap: true}); - fs.writeFileSync('/tmp/' + crypto.createHash('md5').update(filename).digest('hex') + '.map', JSON.stringify(compiled.map)); - return compiled.code; - } -};