diff --git a/Gruntfile.js b/Gruntfile.js index 735dc33004..e03a31ecb3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -91,7 +91,7 @@ module.exports = function (grunt) { 'FileDescription': WINDOWS_APPNAME, 'InternalName': BASENAME + '.exe', 'OriginalFilename': BASENAME + '.exe', - 'LegalCopyright': 'Copyright 2015 Docker Inc. All rights reserved.' + 'LegalCopyright': 'Copyright 2015-2016 Docker Inc. All rights reserved.' } } } diff --git a/LICENSE b/LICENSE index dfed3fbe9e..498341cd9a 100644 --- a/LICENSE +++ b/LICENSE @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2014-2015 Docker, Inc. + Copyright 2014-2016 Docker, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Makefile b/Makefile index 01e2c56e4c..2ec5ecf027 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,11 @@ run: npm install npm run +# Get the IP ADDRESS +DOCKER_IP=$(shell python -c "import urlparse ; print urlparse.urlparse('$(DOCKER_HOST)').hostname or ''") +HUGO_BASE_URL=$(shell test -z "$(DOCKER_IP)" && echo localhost || echo "$(DOCKER_IP)") +HUGO_BIND_IP=0.0.0.0 + # import the existing docs build cmds from docker/docker DOCS_MOUNT := $(if $(DOCSDIR),-v $(CURDIR)/$(DOCSDIR):/$(DOCSDIR)) DOCSPORT := 8000 @@ -13,7 +18,9 @@ DOCKER_DOCS_IMAGE := kitematic-docs$(if $(GIT_BRANCH),:$(GIT_BRANCH)) DOCKER_RUN_DOCS := docker run --rm -it $(DOCS_MOUNT) docs: docs-build - $(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" mkdocs serve + $(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" \ + hugo server \ + --port=$(DOCSPORT) --baseUrl=$(HUGO_BASE_URL) --bind=$(HUGO_BIND_IP) docs-shell: docs-build $(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" bash diff --git a/circle.yml b/circle.yml index 24d27b74da..59f1a78674 100644 --- a/circle.yml +++ b/circle.yml @@ -11,5 +11,5 @@ deployment: tag: /v.*/ owner: docker commands: - - github-release upload --user docker --repo kitematic --tag $CIRCLE_TAG --file release/Kitematic-Mac.zip --name Kitematic-Mac.zip - - github-release upload --user docker --repo kitematic --tag $CIRCLE_TAG --file release/Kitematic-Windows.zip --name Kitematic-Windows.zip + - github-release upload --user docker --repo kitematic --tag $CIRCLE_TAG --file release/Kitematic-Mac.zip --name Kitematic-$(echo $CIRCLE_TAG | cut -c2-)-Mac.zip + - github-release upload --user docker --repo kitematic --tag $CIRCLE_TAG --file release/Kitematic-Windows.zip --name Kitematic-$(echo $CIRCLE_TAG | cut -c2-)-Windows.zip diff --git a/docs/Dockerfile b/docs/Dockerfile index b42ddbd82d..da11b2de13 100644 --- a/docs/Dockerfile +++ b/docs/Dockerfile @@ -5,9 +5,10 @@ RUN svn checkout https://github.com/docker/compose/trunk/docs /docs/content/comp RUN svn checkout https://github.com/docker/docker/trunk/docs /docs/content/docker RUN svn checkout https://github.com/docker/swarm/trunk/docs /docs/content/swarm RUN svn checkout https://github.com/docker/distribution/trunk/docs /docs/content/registry -RUN svn checkout https://github.com/docker/tutorials/trunk/docs /docs/content +RUN svn checkout https://github.com/docker/notary/trunk/docs /docs/content/notary RUN svn checkout https://github.com/docker/opensource/trunk/docs /docs/content/opensource RUN svn checkout https://github.com/docker/machine/trunk/docs /docs/content/machine +RUN svn checkout https://github.com/docker/toolbox/trunk/docs /docs/content/toolbox ENV PROJECT=kitematic # To get the git info for this repo diff --git a/docs/faq.md b/docs/faq.md index 3b9cd4cfc5..8a0a840e2f 100755 --- a/docs/faq.md +++ b/docs/faq.md @@ -4,7 +4,7 @@ title = "Frequently Asked Questions" description = "Documentation covering common questions users have about Kitematic" keywords = ["docker, documentation, about, technology, kitematic, gui"] [menu.main] -parent="smn_workw_kitematic" +parent="toolbox_kitematic" weight=5 +++ diff --git a/docs/index.md b/docs/index.md index 9190f56478..7cf9ec44ac 100755 --- a/docs/index.md +++ b/docs/index.md @@ -4,7 +4,8 @@ title = "Kitematic" description = "Documentation that provides an overview of Kitematic and installation instructions" keywords = ["docker, documentation, about, technology, kitematic, gui"] [menu.main] -parent="mn_install" +identifier="toolbox_kitematic" +parent="workw_toolbox" weight=2 +++ diff --git a/docs/known-issues.md b/docs/known-issues.md index a12c9bbe1b..b69b1c5ac9 100755 --- a/docs/known-issues.md +++ b/docs/known-issues.md @@ -4,7 +4,7 @@ title = "Known Issues" description = "Information about known issues in Kitematic" keywords = ["docker, documentation, about, technology, kitematic, gui"] [menu.main] -parent="smn_workw_kitematic" +parent="toolbox_kitematic" weight=5 +++ diff --git a/docs/minecraft-server.md b/docs/minecraft-server.md index 2c4d089bae..433b0f0dbe 100755 --- a/docs/minecraft-server.md +++ b/docs/minecraft-server.md @@ -4,7 +4,7 @@ title = "Set up a Minecraft Server" description = "Tutorial demonstrating the setup of a Minecraft server using Docker and Kitematic" keywords = ["docker, documentation, about, technology, kitematic, gui, minecraft, tutorial"] [menu.main] -parent="smn_workw_kitematic" +parent="toolbox_kitematic" weight=2 +++ diff --git a/docs/nginx-web-server.md b/docs/nginx-web-server.md index 7121c4fd6f..7c1199a579 100755 --- a/docs/nginx-web-server.md +++ b/docs/nginx-web-server.md @@ -4,7 +4,7 @@ title = "Set up an Nginx web server" description = "Tutorial demonstrating the setup of an Nginx web server using Docker and Kitematic" keywords = ["docker, documentation, about, technology, kitematic, gui, nginx, tutorial"] [menu.main] -parent="smn_workw_kitematic" +parent="toolbox_kitematic" weight=1 +++ diff --git a/docs/rethinkdb-dev-database.md b/docs/rethinkdb-dev-database.md index 620cb8f189..d571a121bb 100755 --- a/docs/rethinkdb-dev-database.md +++ b/docs/rethinkdb-dev-database.md @@ -4,7 +4,7 @@ title = "Creating a Local RethinkDB Database for Development" description = "Tutorial demonstrating the setup of an RethinkDB database for development" keywords = ["docker, documentation, about, technology, kitematic, gui, rethink, tutorial"] [menu.main] -parent="smn_workw_kitematic" +parent="toolbox_kitematic" weight=3 +++ diff --git a/docs/userguide.md b/docs/userguide.md index 4943e45562..01792cc58c 100755 --- a/docs/userguide.md +++ b/docs/userguide.md @@ -4,7 +4,7 @@ title = "Kitematic User Guide: Intro & Overview" description = "Documentation that provides an overview of Kitematic and installation instructions" keywords = ["docker, documentation, about, technology, kitematic, gui"] [menu.main] -parent="smn_workw_kitematic" +parent="toolbox_kitematic" +++ diff --git a/jest-unit.json b/jest-unit.json index bc91f0f679..19685d46ae 100644 --- a/jest-unit.json +++ b/jest-unit.json @@ -13,6 +13,7 @@ "object-assign", "underscore", "source-map-support", - "/node_modules/.*JSONStream" + "/node_modules/.*JSONStream", + "/node_modules/core-js" ] } diff --git a/package.json b/package.json index c61c40a67f..c4890e6ad9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Kitematic", - "version": "0.9.5", + "version": "0.10.0", "author": "Kitematic", "description": "Simple Docker Container management for Mac OS X.", "homepage": "https://kitematic.com/", @@ -16,13 +16,11 @@ "test": "jest -c jest-unit.json", "integration": "jest -c jest-integration.json", "release": "grunt release", - "release-mac": "grunt release-mac", "lint": "jsxhint src" }, "license": "Apache-2.0", "electron-version": "0.35.4", "dependencies": { - "JSONStream": "^1.0.7", "alt": "^0.16.2", "ansi-to-html": "0.3.0", "any-promise": "^0.1.0", @@ -35,6 +33,7 @@ "dockerode": "^2.2.7", "install": "^0.1.8", "jquery": "^2.1.3", + "JSONStream": "^1.0.7", "mixpanel": "kitematic/mixpanel-node", "mkdirp": "^0.5.0", "node-uuid": "^1.4.3", diff --git a/resources/terminal b/resources/terminal index ea55c18810..38e1d9896d 100755 --- a/resources/terminal +++ b/resources/terminal @@ -15,22 +15,49 @@ EOF` function open_iterm () { osascript > /dev/null < /dev/null < -

We're sorry. There seem to be an error:

+

We're sorry. There seems to be an error:

{this.props.container.Error}

If this error is invalid, please file a ticket on our Github repo.

File Ticket diff --git a/src/components/ContainerHomeFolders.react.js b/src/components/ContainerHomeFolders.react.js index cab35902df..fbbc704bf0 100644 --- a/src/components/ContainerHomeFolders.react.js +++ b/src/components/ContainerHomeFolders.react.js @@ -32,6 +32,7 @@ var ContainerHomeFolder = React.createClass({ mounts.forEach(m => { if (m.Destination === destination) { m.Source = util.windowsToLinuxPath(newSource); + m.Driver = null; } }); diff --git a/src/components/ContainerListItem.react.js b/src/components/ContainerListItem.react.js index 2791ca9d22..1e6af7a9a7 100644 --- a/src/components/ContainerListItem.react.js +++ b/src/components/ContainerListItem.react.js @@ -97,7 +97,7 @@ var ContainerListItem = React.createClass({ return ( -
  • +
  • {state}
    diff --git a/src/components/ContainerSettingsVolumes.react.js b/src/components/ContainerSettingsVolumes.react.js index 914fa57494..7462db8c04 100644 --- a/src/components/ContainerSettingsVolumes.react.js +++ b/src/components/ContainerSettingsVolumes.react.js @@ -28,7 +28,7 @@ var ContainerSettingsVolumes = React.createClass({ metrics.track('Choose Directory for Volume'); - var mounts = _.clone(this.props.container.Mounts); + let mounts = _.clone(this.props.container.Mounts); _.each(mounts, m => { if (m.Destination === dockerVol) { m.Source = util.windowsToLinuxPath(directory); @@ -36,7 +36,7 @@ var ContainerSettingsVolumes = React.createClass({ } }); - var binds = mounts.map(m => { + let binds = mounts.map(m => { return m.Source + ':' + m.Destination; }); @@ -50,7 +50,7 @@ var ContainerSettingsVolumes = React.createClass({ from: 'settings' }); - var mounts = _.clone(this.props.container.Mounts); + let mounts = _.clone(this.props.container.Mounts); _.each(mounts, m => { if (m.Destination === dockerVol) { m.Source = null; diff --git a/src/components/Containers.react.js b/src/components/Containers.react.js index d7b611168f..130557f15f 100644 --- a/src/components/Containers.react.js +++ b/src/components/Containers.react.js @@ -26,7 +26,7 @@ var Containers = React.createClass({ containerStore.listen(this.update); }, - componentDidUnmount: function () { + componentWillUnmount: function () { containerStore.unlisten(this.update); }, @@ -106,43 +106,7 @@ var Containers = React.createClass({ metrics.track('Opened Issue Reporter', { from: 'app' }); - shell.openExternal('https://github.com/kitematic/kitematic/issues/new'); - }, - - handleMouseEnterDockerTerminal: function () { - this.setState({ - currentButtonLabel: 'Open terminal to use Docker command line.' - }); - }, - - handleMouseLeaveDockerTerminal: function () { - this.setState({ - currentButtonLabel: '' - }); - }, - - handleMouseEnterReportIssue: function () { - this.setState({ - currentButtonLabel: 'Report an issue or suggest feedback.' - }); - }, - - handleMouseLeaveReportIssue: function () { - this.setState({ - currentButtonLabel: '' - }); - }, - - handleMouseEnterPreferences: function () { - this.setState({ - currentButtonLabel: 'Change app preferences.' - }); - }, - - handleMouseLeavePreferences: function () { - this.setState({ - currentButtonLabel: '' - }); + shell.openExternal('https://github.com/docker/kitematic/issues/new'); }, render: function () { @@ -169,9 +133,9 @@ var Containers = React.createClass({
    - DOCKER CLI - - + DOCKER CLI + +
    diff --git a/src/components/ImageCard.react.js b/src/components/ImageCard.react.js index a18420b16c..fe979c9ef1 100644 --- a/src/components/ImageCard.react.js +++ b/src/components/ImageCard.react.js @@ -76,11 +76,11 @@ var ImageCard = React.createClass({ $tagOverlay.fadeOut(300); }, handleRepoClick: function () { - var repoUri = 'https://registry.hub.docker.com/'; + var repoUri = 'https://hub.docker.com/'; if (this.props.image.namespace === 'library') { repoUri = repoUri + '_/' + this.props.image.name; } else { - repoUri = repoUri + 'u/' + this.props.image.namespace + '/' + this.props.image.name; + repoUri = repoUri + 'r/' + this.props.image.namespace + '/' + this.props.image.name; } shell.openExternal(repoUri); }, @@ -105,6 +105,8 @@ var ImageCard = React.createClass({ var description; if (this.props.image.description) { description = this.props.image.description; + } else if(this.props.image.short_description){ + description = this.props.image.short_description; } else { description = "No description."; } diff --git a/src/components/NewContainerSearch.react.js b/src/components/NewContainerSearch.react.js index 06b72dc946..410b4e43ff 100644 --- a/src/components/NewContainerSearch.react.js +++ b/src/components/NewContainerSearch.react.js @@ -73,7 +73,6 @@ module.exports = React.createClass({ nextPage = (page + 1 > this.state.totalPage) ? this.state.totalPage : page + 1; totalPage = this.state.totalPage; } - this.setState({ query: query, loading: true, diff --git a/src/components/Setup.react.js b/src/components/Setup.react.js index 741322e174..3635092cee 100644 --- a/src/components/Setup.react.js +++ b/src/components/Setup.react.js @@ -3,12 +3,13 @@ import Router from 'react-router'; import Radial from './Radial.react.js'; import RetinaImage from 'react-retina-image'; import Header from './Header.react'; -import Util from '../utils/Util'; +import util from '../utils/Util'; import metrics from '../utils/MetricsUtil'; import setupStore from '../stores/SetupStore'; import setupActions from '../actions/SetupActions'; import shell from 'shell'; + var Setup = React.createClass({ mixins: [Router.Navigation], @@ -20,7 +21,7 @@ var Setup = React.createClass({ setupStore.listen(this.update); }, - componentDidUnmount: function () { + componentWillUnmount: function () { setupStore.unlisten(this.update); }, @@ -32,6 +33,10 @@ var Setup = React.createClass({ setupActions.retry(false); }, + handleUseVbox: function () { + setupActions.useVbox(); + }, + handleErrorRemoveRetry: function () { console.log('Deleting VM and trying again.' ); setupActions.retry(true); @@ -63,6 +68,12 @@ var Setup = React.createClass({ }, renderProgress: function () { + let title = 'Starting Docker VM'; + let descr = 'To run Docker containers on your computer, Kitematic is starting a Linux virtual machine. This may take a minute...'; + if (util.isNative()) { + title = 'Checking Docker'; + descr = 'To run Docker containers on your computer, Kitematic is checking the Docker connection.'; + } return (
    @@ -72,8 +83,8 @@ var Setup = React.createClass({
    -

    Starting Docker VM

    -

    To run Docker containers on your computer, Kitematic is starting a Linux virtual machine. This may take a minute...

    +

    {title}

    +

    {descr}

    @@ -84,22 +95,24 @@ var Setup = React.createClass({ renderError: function () { let deleteVmAndRetry; - if (Util.isLinux()) { + if (util.isLinux()) { if (!this.state.started) { deleteVmAndRetry = ( ); } + } else if (util.isNative()) { + deleteVmAndRetry = ( + + ); + } else if (this.state.started) { + deleteVmAndRetry = ( + + ); } else { - if (this.state.started) { - deleteVmAndRetry = ( - - ); - } else { - deleteVmAndRetry = ( - - ); - } + deleteVmAndRetry = ( + + ); } return (
    diff --git a/src/utils/DockerMachineUtil.js b/src/utils/DockerMachineUtil.js index 49886372c4..8cd949f88c 100644 --- a/src/utils/DockerMachineUtil.js +++ b/src/utils/DockerMachineUtil.js @@ -158,11 +158,12 @@ var DockerMachine = { } }); }); - } else if (util.isLinux()) { + } else if (util.isNative()) { cmd = cmd || process.env.SHELL; - var terminal = util.linuxTerminal(); - if (terminal) - util.execFile(terminal.concat([cmd])).then(() => {}); + var terminal = util.isLinux() ? util.linuxTerminal() : path.join(process.env.RESOURCES_PATH, 'terminal'); + if (terminal) { + util.execFile([terminal, cmd]).then(() => {}); + } } else { cmd = cmd || process.env.SHELL; this.url(machineName).then(machineUrl => { diff --git a/src/utils/DockerUtil.js b/src/utils/DockerUtil.js index 7796016b8d..1942791936 100644 --- a/src/utils/DockerUtil.js +++ b/src/utils/DockerUtil.js @@ -11,6 +11,9 @@ import containerServerActions from '../actions/ContainerServerActions'; import rimraf from 'rimraf'; import stream from 'stream'; import JSONStream from 'JSONStream'; +import Promise from 'bluebird'; + + export default { host: null, @@ -20,20 +23,23 @@ export default { activeContainerName: null, setup (ip, name) { - if (!ip || !name) { + if (!ip && !name) { throw new Error('Falsy ip or name passed to docker client setup'); } + this.host = ip; - if (util.isLinux()) { - this.host = 'localhost'; - this.client = new dockerode({socketPath: '/var/run/docker.sock'}); + if (ip.indexOf('local') !== -1) { + try { + this.client = new dockerode({socketPath: '/var/run/docker.sock'}); + } catch (error) { + throw new Error('Cannot connect to the Docker daemon. Is the daemon running?'); + } } else { let certDir = path.join(util.home(), '.docker/machine/machines/', name); if (!fs.existsSync(certDir)) { throw new Error('Certificate directory does not exist'); } - this.host = ip; this.client = new dockerode({ protocol: 'https', host: ip, @@ -45,6 +51,28 @@ export default { } }, + async version () { + let version = null; + let maxRetries = 10; + let retries = 0; + let error_message = ""; + while (version == null && retries < maxRetries) { + this.client.version((error,data) => { + if (!error) { + version = data.Version; + } else { + error_message = error; + } + retries++; + }); + await Promise.delay(1000); + } + if (version == null) { + throw new Error(error_message); + } + return version; + }, + init () { this.placeholders = JSON.parse(localStorage.getItem('placeholders')) || {}; this.fetchAllContainers(); @@ -88,6 +116,7 @@ export default { container.start((error) => { if (error) { containerServerActions.error({name, error}); + console.log('error starting: %o - %o', name, error); return; } containerServerActions.started({name, error}); @@ -118,7 +147,12 @@ export default { containerData.PublishAllPorts = true; } - containerData.Cmd = image.Config.Cmd || image.Config.Entrypoint || 'bash'; + if (image.Config.Cmd) { + containerData.Cmd = image.Config.Cmd; + } else if (!image.Config.Entrypoint) { + containerData.Cmd = 'bash'; + } + let existing = this.client.getContainer(name); existing.kill(() => { existing.remove(() => { @@ -151,6 +185,7 @@ export default { fetchAllContainers () { this.client.listContainers({all: true}, (err, containers) => { if (err) { + console.error(err); return; } async.map(containers, (container, callback) => { @@ -166,6 +201,7 @@ export default { containers = containers.filter(c => c !== null); if (err) { // TODO: add a global error handler for this + console.error(err); return; } containerServerActions.allUpdated({containers: _.indexBy(containers.concat(_.values(this.placeholders)), 'Name')}); @@ -362,6 +398,8 @@ export default { timestamps: 1 }, (err, logStream) => { if (err) { + // socket hang up can be captured + console.error(err); return; } @@ -388,6 +426,8 @@ export default { timestamps: 1 }, (err, logStream) => { if (err) { + // Socket hang up also can be found here + console.error(err); return; } diff --git a/src/utils/SetupUtil.js b/src/utils/SetupUtil.js index 02faddafb8..2e55a8eab1 100644 --- a/src/utils/SetupUtil.js +++ b/src/utils/SetupUtil.js @@ -11,8 +11,14 @@ import machine from './DockerMachineUtil'; import docker from './DockerUtil'; import router from '../router'; +// Docker Machine exits with 3 to differentiate pre-create check failures (e.g. +// virtualization isn't enabled) from normal errors during create (exit code +// 1). +const precreateCheckExitCode = 3; + let _retryPromise = null; let _timers = []; +let useNative = util.isNative() ? util.isNative() : true; export default { simulateProgress (estimateSeconds) { @@ -31,12 +37,21 @@ export default { _timers = []; }, + async useVbox () { + metrics.track('Retried Setup with VBox'); + localStorage.setItem('settings.useNative', false); + router.get().transitionTo('loading'); + setupServerActions.error({ error: { message: null }}); + _retryPromise.resolve(); + }, + retry (removeVM) { metrics.track('Retried Setup', { removeVM }); router.get().transitionTo('loading'); + setupServerActions.error({ error: { message: null }}); if (removeVM) { machine.rm().finally(() => { _retryPromise.resolve(); @@ -51,30 +66,44 @@ export default { return _retryPromise.promise; }, - setup() { - return util.isLinux() ? this.nativeSetup() : this.nonNativeSetup(); + async setup () { + while (true) { + try { + if (util.isNative()) { + localStorage.setItem('setting.useNative', true); + let stats = fs.statSync('/var/run/docker.sock'); + if (stats.isSocket()) { + await this.nativeSetup(); + } else { + throw new Error('File found is not a socket'); + } + } else { + await this.nonNativeSetup(); + } + return; + } catch (error) { + metrics.track('Native Setup Failed'); + setupServerActions.error({error}); + + bugsnag.notify('Native Setup Failed', error.message, { + 'Docker Error': error.message + }, 'info'); + this.clearTimers(); + await this.pause(); + } + } }, async nativeSetup () { while (true) { try { - docker.setup('localhost', machine.name()); - docker.isDockerRunning(); - - break; - } catch (error) { router.get().transitionTo('setup'); - metrics.track('Native Setup Failed'); - setupServerActions.error({error}); - - let message = error.message.split('\n'); - let lastLine = message.length > 1 ? message[message.length - 2] : 'Docker Machine encountered an error.'; - bugsnag.notify('Native Setup Failed', lastLine, { - 'Docker Machine Logs': error.message - }, 'info'); - - this.clearTimers(); - await this.pause(); + docker.setup(util.isLinux() ? 'localhost':'docker.local'); + setupServerActions.started({started: true}); + this.simulateProgress(20); + return docker.version(); + } catch (error) { + throw new Error(error); } } }, @@ -86,7 +115,7 @@ export default { try { setupServerActions.started({started: false}); - // Make sure virtulBox and docker-machine are installed + // Make sure virtualBox and docker-machine are installed let virtualBoxInstalled = virtualBox.installed(); let machineInstalled = machine.installed(); if (!virtualBoxInstalled || !machineInstalled) { @@ -122,13 +151,16 @@ export default { } else { let state = await machine.status(); if (state !== 'Running') { + router.get().transitionTo('setup'); + setupServerActions.started({started: true}); if (state === 'Saved') { - router.get().transitionTo('setup'); this.simulateProgress(10); } else if (state === 'Stopped') { - router.get().transitionTo('setup'); this.simulateProgress(25); + } else { + this.simulateProgress(40); } + await machine.start(); } } @@ -146,6 +178,7 @@ export default { if (ip) { docker.setup(ip, machine.name()); + await docker.version(); } else { throw new Error('Could not determine IP from docker-machine.'); } @@ -154,11 +187,17 @@ export default { } catch (error) { router.get().transitionTo('setup'); - let novtx = error.message.indexOf('This computer doesn\'t have VT-X/AMD-v enabled') !== -1; - metrics.track(novtx ? 'Setup Halted' : 'Setup Failed', { - virtualBoxVersion, - machineVersion - }); + if (error.code === precreateCheckExitCode) { + metrics.track('Setup Halted', { + virtualBoxVersion, + machineVersion + }); + } else { + metrics.track('Setup Failed', { + virtualBoxVersion, + machineVersion + }); + } let message = error.message.split('\n'); let lastLine = message.length > 1 ? message[message.length - 2] : 'Docker Machine encountered an error.'; diff --git a/src/utils/Util.js b/src/utils/Util.js index c8e376021d..f383506ac9 100644 --- a/src/utils/Util.js +++ b/src/utils/Util.js @@ -13,7 +13,7 @@ module.exports = { return new Promise((resolve, reject) => { child_process.execFile(args[0], args.slice(1), options, (error, stdout) => { if (error) { - reject(new Error('Encountered an error: ' + error)); + reject(error); } else { resolve(stdout); } @@ -37,6 +37,24 @@ module.exports = { isLinux: function () { return process.platform === 'linux'; }, + isNative: function () { + // let native = JSON.parse(localStorage.getItem('settings.useNative')); + let native = null; + if (native === null) { + try { + // Check if file exists + fs.statSync('/var/run/docker.sock'); + native = true; + } catch (e) { + if (this.isLinux()) { + native = true; + } else { + native = false; + } + } + } + return native; + }, binsPath: function () { return this.isWindows() ? path.join(this.home(), 'Kitematic-bins') : path.join('/usr/local/bin'); }, @@ -62,9 +80,6 @@ module.exports = { // TODO: fix me for windows 7 return 'Documents'; }, - supportDir: function () { - return app.getPath('userData'); - }, CommandOrCtrl: function () { return this.isWindows() ? 'Ctrl' : 'Command'; }, @@ -95,7 +110,7 @@ module.exports = { // An official repo is alphanumeric characters separated by dashes or // underscores. // Examples: myrepo, my-docker-repo, my_docker_repo - // Non-exapmles: mynamespace/myrepo, my%!repo + // Non-examples: mynamespace/myrepo, my%!repo var repoRegexp = /^[a-z0-9]+(?:[._-][a-z0-9]+)*$/; return repoRegexp.test(name); }, @@ -166,9 +181,9 @@ module.exports = { dialog.showMessageBox({ type: 'warning', buttons: ['OK'], - message: 'The terminal emulator symbolic link doesn\'t exists. Please read the Wiki at https://github.com/kitematic/kitematic/wiki/Common-Issues-and-Fixes#early-linux-support-from-zedtux.' + message: 'The terminal emulator symbolic link doesn\'t exists. Please read the Wiki at https://github.com/docker/kitematic/wiki/Early-Linux-Support.' }); - return; + return false; } }, webPorts: ['80', '8000', '8080', '8888', '3000', '5000', '2368', '9200', '8983'] diff --git a/src/utils/VirtualBoxUtil.js b/src/utils/VirtualBoxUtil.js index 1d9bae104f..48d40b26e7 100644 --- a/src/utils/VirtualBoxUtil.js +++ b/src/utils/VirtualBoxUtil.js @@ -39,9 +39,9 @@ var VirtualBox = { return util.execFile([this.command(), 'sharedfolder', 'add', vmName, '--name', pathName, '--hostpath', hostPath, '--automount']); }, vmExists: function (name) { - return util.execFile([this.command(), 'showvminfo', name]).then(() => { - return true; - }).catch((err) => { + return util.execFile([this.command(), 'list', 'vms']).then(out => { + return out.indexOf('"' + name + '"') !== -1; + }).catch(() => { return false; }); } diff --git a/src/utils/WebUtil.js b/src/utils/WebUtil.js index 2d774fe013..f726d57ca1 100644 --- a/src/utils/WebUtil.js +++ b/src/utils/WebUtil.js @@ -10,7 +10,7 @@ import metrics from './MetricsUtil'; var WebUtil = { addWindowSizeSaving: function () { window.addEventListener('resize', function () { - fs.writeFileSync(path.join(util.supportDir(), 'size'), JSON.stringify({ + fs.writeFileSync(path.join(app.getPath('userData'), 'size'), JSON.stringify({ width: window.outerWidth, height: window.outerHeight }));