mirror of https://github.com/docker/docs.git
Implement Linux support
This commit is contained in:
parent
0ed907553b
commit
de0b2efd2a
20
Gruntfile.js
20
Gruntfile.js
|
|
@ -22,6 +22,7 @@ module.exports = function (grunt) {
|
|||
var BASENAME = 'Kitematic';
|
||||
var OSX_APPNAME = BASENAME + ' (Beta)';
|
||||
var WINDOWS_APPNAME = BASENAME + ' (Alpha)';
|
||||
var LINUX_APPNAME = BASENAME + ' (Alpha)';
|
||||
var OSX_OUT = './dist';
|
||||
var OSX_OUT_X64 = OSX_OUT + '/' + OSX_APPNAME + '-darwin-x64';
|
||||
var OSX_FILENAME = OSX_OUT_X64 + '/' + OSX_APPNAME + '.app';
|
||||
|
|
@ -57,6 +58,19 @@ module.exports = function (grunt) {
|
|||
'app-bundle-id': 'com.kitematic.kitematic',
|
||||
'app-version': packagejson.version
|
||||
}
|
||||
},
|
||||
linux: {
|
||||
options: {
|
||||
name: LINUX_APPNAME,
|
||||
dir: 'build/',
|
||||
out: 'dist/linux/',
|
||||
version: packagejson['electron-version'],
|
||||
platform: 'linux',
|
||||
arch: 'x64',
|
||||
asar: true,
|
||||
'app-bundle-id': 'com.kitematic.kitematic',
|
||||
'app-version': packagejson.version
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -243,7 +257,11 @@ module.exports = function (grunt) {
|
|||
});
|
||||
|
||||
grunt.registerTask('default', ['newer:babel', 'less', 'newer:copy:dev', 'shell:electron', 'watchChokidar']);
|
||||
grunt.registerTask('release', ['clean:release', 'babel', 'less', 'copy:dev', 'electron', 'copy:osx', 'shell:sign', 'shell:zip', 'copy:windows', 'rcedit:exes', 'compress']);
|
||||
if(process.platform === 'linux') {
|
||||
grunt.registerTask('release', ['clean:release', 'babel', 'less', 'copy:dev', 'electron:linux']);
|
||||
} else {
|
||||
grunt.registerTask('release', ['clean:release', 'babel', 'less', 'copy:dev', 'electron', 'copy:osx', 'shell:sign', 'shell:zip', 'copy:windows', 'rcedit:exes', 'compress']);
|
||||
}
|
||||
|
||||
process.on('SIGINT', function () {
|
||||
grunt.task.run(['shell:electron:kill']);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
[](https://kitematic.com)
|
||||
|
||||
Kitematic is a simple application for managing Docker containers on Mac and Windows.
|
||||
Kitematic is a simple application for managing Docker containers on Mac, Linux and Windows.
|
||||
|
||||

|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import Router from 'react-router';
|
|||
import routes from './routes';
|
||||
import routerContainer from './router';
|
||||
import repositoryActions from './actions/RepositoryActions';
|
||||
import util from './utils/Util';
|
||||
var app = remote.require('app');
|
||||
|
||||
hubUtil.init();
|
||||
|
|
@ -46,7 +47,8 @@ var router = Router.create({
|
|||
router.run(Handler => React.render(<Handler/>, document.body));
|
||||
routerContainer.set(router);
|
||||
|
||||
setupUtil.setup().then(() => {
|
||||
let setup = util.isLinux() ? setupUtil.nativeSetup : setupUtil.nonNativeSetup;
|
||||
setup().then(() => {
|
||||
Menu.setApplicationMenu(Menu.buildFromTemplate(template()));
|
||||
docker.init();
|
||||
if (!hub.prompted() && !hub.loggedin()) {
|
||||
|
|
|
|||
|
|
@ -35,10 +35,11 @@ var Preferences = React.createClass({
|
|||
});
|
||||
},
|
||||
render: function () {
|
||||
return (
|
||||
<div className="preferences">
|
||||
<div className="preferences-content">
|
||||
<a onClick={this.handleGoBackClick}>Go Back</a>
|
||||
var vmSettings;
|
||||
|
||||
if (process.platform !== 'linux') {
|
||||
vmSettings = (
|
||||
<div>
|
||||
<div className="title">VM Settings</div>
|
||||
<div className="option">
|
||||
<div className="option-name">
|
||||
|
|
@ -48,6 +49,15 @@ var Preferences = React.createClass({
|
|||
<input type="checkbox" checked={this.state.closeVMOnQuit} onChange={this.handleChangeCloseVMOnQuit}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="preferences">
|
||||
<div className="preferences-content">
|
||||
<a onClick={this.handleGoBackClick}>Go Back</a>
|
||||
{vmSettings}
|
||||
<div className="title">App Settings</div>
|
||||
<div className="option">
|
||||
<div className="option-name">
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ 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 metrics from '../utils/MetricsUtil';
|
||||
import setupStore from '../stores/SetupStore';
|
||||
import setupActions from '../actions/SetupActions';
|
||||
|
|
@ -43,6 +44,13 @@ var Setup = React.createClass({
|
|||
shell.openExternal('https://www.docker.com/docker-toolbox');
|
||||
},
|
||||
|
||||
handleLinuxDockerInstall: function () {
|
||||
metrics.track('Opening Linux Docker installation instructions', {
|
||||
from: 'setup'
|
||||
});
|
||||
shell.openExternal('http://docs.docker.com/linux/started/');
|
||||
},
|
||||
|
||||
renderContents: function () {
|
||||
return (
|
||||
<div className="contents">
|
||||
|
|
@ -74,6 +82,25 @@ var Setup = React.createClass({
|
|||
},
|
||||
|
||||
renderError: function () {
|
||||
let deleteVmAndRetry;
|
||||
|
||||
if (Util.isLinux()) {
|
||||
if (!this.state.started) {
|
||||
deleteVmAndRetry = (
|
||||
<button className="btn btn-action" onClick={this.handleLinuxDockerInstall}>Install Docker</button>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (this.state.started) {
|
||||
deleteVmAndRetry = (
|
||||
<button className="btn btn-action" onClick={this.handleErrorRemoveRetry}>Delete VM & Retry Setup</button>
|
||||
);
|
||||
} else {
|
||||
deleteVmAndRetry = (
|
||||
<button className="btn btn-action" onClick={this.handleToolBox}>Get Toolbox</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div className="setup">
|
||||
<Header hideLogin={true}/>
|
||||
|
|
@ -93,7 +120,7 @@ var Setup = React.createClass({
|
|||
<p className="error">{this.state.error.message || this.state.error}</p>
|
||||
<p className="setup-actions">
|
||||
<button className="btn btn-action" onClick={this.handleErrorRetry}>Retry Setup</button>
|
||||
{this.state.started ? <button className="btn btn-action" onClick={this.handleErrorRemoveRetry}>Delete VM & Retry Setup</button> : <button className="btn btn-action" onClick={this.handleToolBox}>Get Toolbox</button>}
|
||||
{{deleteVmAndRetry}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -151,6 +151,11 @@ var DockerMachine = {
|
|||
}
|
||||
});
|
||||
});
|
||||
} else if (util.isLinux()) {
|
||||
cmd = cmd || process.env.SHELL;
|
||||
var terminal = util.linuxTerminal();
|
||||
if (terminal)
|
||||
util.exec(terminal.concat([cmd])).then(() => {});
|
||||
} else {
|
||||
cmd = cmd || process.env.SHELL;
|
||||
this.url(machineName).then(machineUrl => {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import fs from 'fs';
|
|||
import path from 'path';
|
||||
import dockerode from 'dockerode';
|
||||
import _ from 'underscore';
|
||||
import child_process from 'child_process';
|
||||
import util from './Util';
|
||||
import hubUtil from './HubUtil';
|
||||
import metrics from '../utils/MetricsUtil';
|
||||
|
|
@ -20,20 +21,25 @@ export default {
|
|||
throw new Error('Falsy ip or name passed to docker client setup');
|
||||
}
|
||||
|
||||
let certDir = path.join(util.home(), '.docker/machine/machines/', name);
|
||||
if (!fs.existsSync(certDir)) {
|
||||
throw new Error('Certificate directory does not exist');
|
||||
}
|
||||
if (util.isLinux()) {
|
||||
this.host = 'localhost';
|
||||
this.client = new dockerode({socketPath: '/var/run/docker.sock'});
|
||||
} 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,
|
||||
port: 2376,
|
||||
ca: fs.readFileSync(path.join(certDir, 'ca.pem')),
|
||||
cert: fs.readFileSync(path.join(certDir, 'cert.pem')),
|
||||
key: fs.readFileSync(path.join(certDir, 'key.pem'))
|
||||
});
|
||||
this.host = ip;
|
||||
this.client = new dockerode({
|
||||
protocol: 'https',
|
||||
host: ip,
|
||||
port: 2376,
|
||||
ca: fs.readFileSync(path.join(certDir, 'ca.pem')),
|
||||
cert: fs.readFileSync(path.join(certDir, 'cert.pem')),
|
||||
key: fs.readFileSync(path.join(certDir, 'key.pem'))
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
init () {
|
||||
|
|
@ -66,6 +72,14 @@ export default {
|
|||
});
|
||||
},
|
||||
|
||||
isDockerRunning () {
|
||||
try {
|
||||
child_process.execSync('ps ax | grep "docker daemon" | grep -v grep');
|
||||
} catch (error) {
|
||||
throw new Error('Cannot connect to the Docker daemon. The daemon is not running.');
|
||||
}
|
||||
},
|
||||
|
||||
startContainer (name, containerData) {
|
||||
let startopts = {
|
||||
Binds: containerData.Binds || []
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import _ from 'underscore';
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import Promise from 'bluebird';
|
||||
import util from './Util';
|
||||
import bugsnag from 'bugsnag-js';
|
||||
import util from './Util';
|
||||
import virtualBox from './VirtualBoxUtil';
|
||||
import setupServerActions from '../actions/SetupServerActions';
|
||||
import metrics from './MetricsUtil';
|
||||
|
|
@ -51,7 +51,31 @@ export default {
|
|||
return _retryPromise.promise;
|
||||
},
|
||||
|
||||
async setup () {
|
||||
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();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async nonNativeSetup () {
|
||||
let virtualBoxVersion = null;
|
||||
let machineVersion = null;
|
||||
while (true) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import fs from 'fs';
|
|||
import path from 'path';
|
||||
import crypto from 'crypto';
|
||||
import remote from 'remote';
|
||||
var dialog = remote.require('dialog');
|
||||
var app = remote.require('app');
|
||||
|
||||
module.exports = {
|
||||
|
|
@ -34,6 +35,9 @@ module.exports = {
|
|||
isWindows: function () {
|
||||
return process.platform === 'win32';
|
||||
},
|
||||
isLinux: function () {
|
||||
return process.platform === 'linux';
|
||||
},
|
||||
binsPath: function () {
|
||||
return this.isWindows() ? path.join(this.home(), 'Kitematic-bins') : path.join('/usr/local/bin');
|
||||
},
|
||||
|
|
@ -156,5 +160,17 @@ module.exports = {
|
|||
linuxToWindowsPath: function (linuxAbsPath) {
|
||||
return linuxAbsPath.replace('/c', 'C:').split('/').join('\\');
|
||||
},
|
||||
linuxTerminal: function () {
|
||||
if (fs.existsSync('/usr/bin/x-terminal-emulator')) {
|
||||
return ['/usr/bin/x-terminal-emulator', '-e'];
|
||||
} else {
|
||||
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.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
},
|
||||
webPorts: ['80', '8000', '8080', '8888', '3000', '5000', '2368', '9200', '8983']
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@
|
|||
@color-box-button: lighten(@gray-lightest, 5%);
|
||||
@color-background: lighten(@gray-lightest, 4.5%);
|
||||
|
||||
@font-regular: "Helvetica Neue", Segoe UI, Arial, "Lucida Grande", sans-serif;
|
||||
@font-code: Menlo, Consolas;
|
||||
@font-regular: "Helvetica Neue", Segoe UI, "Ubuntu", Arial, "Lucida Grande", sans-serif;
|
||||
@font-code: Menlo, Consolas, "DejaVu Sans Mono";
|
||||
|
||||
@border-radius: 0.2rem;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue