Merge pull request #204 from kitematic/machine
Use Docker Machine to create VMs
|
@ -9,7 +9,6 @@ npm-debug.log
|
||||||
identity
|
identity
|
||||||
|
|
||||||
# Resources
|
# Resources
|
||||||
resources/boot2docker-*
|
|
||||||
resources/docker-*
|
resources/docker-*
|
||||||
|
|
||||||
# Cache
|
# Cache
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
jest.dontMock('../src/Boot2Docker');
|
|
||||||
var boot2docker = require('../src/Boot2Docker');
|
|
||||||
|
|
||||||
var fs = require('fs');
|
|
||||||
var util = require('../src/Util');
|
|
||||||
var Promise = require('bluebird');
|
|
||||||
|
|
||||||
describe('Boot2Docker', () => {
|
|
||||||
it('iso version parsed correctly', function () {
|
|
||||||
fs.readFileSync.mockReturnValueOnce('9adjaldijaslkjd123Boot2Docker-v1.4.1aisudhha82jj123');
|
|
||||||
expect(boot2docker.isoversion()).toBe('1.4.1');
|
|
||||||
});
|
|
||||||
|
|
||||||
pit('should exist if status command succeeds', function () {
|
|
||||||
util.exec.mockReturnValueOnce(Promise.resolve(true));
|
|
||||||
return boot2docker.exists().then(exists => {
|
|
||||||
expect(util.exec).toBeCalledWith([boot2docker.command(), 'status']);
|
|
||||||
expect(exists).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
pit('should not exist if status command fails', function () {
|
|
||||||
util.exec.mockReturnValueOnce(Promise.reject(false));
|
|
||||||
return boot2docker.exists().then(exists => {
|
|
||||||
expect(util.exec).toBeCalledWith([boot2docker.command(), 'status']);
|
|
||||||
expect(exists).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -2,7 +2,7 @@ jest.dontMock('../src/SetupStore');
|
||||||
var setupStore = require('../src/SetupStore');
|
var setupStore = require('../src/SetupStore');
|
||||||
var virtualBox = require('../src/VirtualBox');
|
var virtualBox = require('../src/VirtualBox');
|
||||||
var util = require('../src/Util');
|
var util = require('../src/Util');
|
||||||
var boot2docker = require('../src/Boot2Docker');
|
var machine = require('../src/DockerMachine');
|
||||||
var setupUtil = require('../src/SetupUtil');
|
var setupUtil = require('../src/SetupUtil');
|
||||||
var Promise = require('bluebird');
|
var Promise = require('bluebird');
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ describe('SetupStore', function () {
|
||||||
pit('downloads virtualbox if it is not installed', function () {
|
pit('downloads virtualbox if it is not installed', function () {
|
||||||
virtualBox.installed.mockReturnValue(false);
|
virtualBox.installed.mockReturnValue(false);
|
||||||
setupUtil.download.mockReturnValue(Promise.resolve());
|
setupUtil.download.mockReturnValue(Promise.resolve());
|
||||||
|
util.packagejson.mockReturnValue({'virtualbox-filename': ''});
|
||||||
|
util.supportDir.mockReturnValue('');
|
||||||
return setupStore.steps().download.run().then(() => {
|
return setupStore.steps().download.run().then(() => {
|
||||||
expect(setupUtil.download).toBeCalled();
|
expect(setupUtil.download).toBeCalled();
|
||||||
});
|
});
|
||||||
|
@ -22,6 +24,8 @@ describe('SetupStore', function () {
|
||||||
virtualBox.version.mockReturnValue(Promise.resolve('4.3.16'));
|
virtualBox.version.mockReturnValue(Promise.resolve('4.3.16'));
|
||||||
setupUtil.compareVersions.mockReturnValue(-1);
|
setupUtil.compareVersions.mockReturnValue(-1);
|
||||||
setupUtil.download.mockReturnValue(Promise.resolve());
|
setupUtil.download.mockReturnValue(Promise.resolve());
|
||||||
|
util.packagejson.mockReturnValue({'virtualbox-filename': ''});
|
||||||
|
util.supportDir.mockReturnValue('');
|
||||||
return setupStore.steps().download.run().then(() => {
|
return setupStore.steps().download.run().then(() => {
|
||||||
expect(setupUtil.download).toBeCalled();
|
expect(setupUtil.download).toBeCalled();
|
||||||
});
|
});
|
||||||
|
@ -30,8 +34,8 @@ describe('SetupStore', function () {
|
||||||
|
|
||||||
describe('install step', function () {
|
describe('install step', function () {
|
||||||
util.exec.mockReturnValue(Promise.resolve());
|
util.exec.mockReturnValue(Promise.resolve());
|
||||||
util.copyBinariesCmd.mockReturnValue('copycmd');
|
setupUtil.copyBinariesCmd.mockReturnValue('copycmd');
|
||||||
util.fixBinariesCmd.mockReturnValue('fixcmd');
|
setupUtil.fixBinariesCmd.mockReturnValue('fixcmd');
|
||||||
virtualBox.killall.mockReturnValue(Promise.resolve());
|
virtualBox.killall.mockReturnValue(Promise.resolve());
|
||||||
setupUtil.installVirtualBoxCmd.mockReturnValue('installvb');
|
setupUtil.installVirtualBoxCmd.mockReturnValue('installvb');
|
||||||
setupUtil.macSudoCmd.mockImplementation(cmd => 'macsudo ' + cmd);
|
setupUtil.macSudoCmd.mockImplementation(cmd => 'macsudo ' + cmd);
|
||||||
|
@ -45,17 +49,6 @@ describe('SetupStore', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('installs virtualbox if it is installed but has an outdated version', function () {
|
|
||||||
virtualBox.installed.mockReturnValue(true);
|
|
||||||
virtualBox.version.mockReturnValue(Promise.resolve('4.3.16'));
|
|
||||||
setupUtil.compareVersions.mockReturnValue(-1);
|
|
||||||
util.exec.mockReturnValue(Promise.resolve());
|
|
||||||
return setupStore.steps().install.run().then(() => {
|
|
||||||
expect(virtualBox.killall).toBeCalled();
|
|
||||||
expect(util.exec).toBeCalledWith('macsudo copycmd && fixcmd && installvbcmd');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
pit('only installs binaries if virtualbox is installed', function () {
|
pit('only installs binaries if virtualbox is installed', function () {
|
||||||
virtualBox.installed.mockReturnValue(true);
|
virtualBox.installed.mockReturnValue(true);
|
||||||
setupUtil.compareVersions.mockReturnValue(0);
|
setupUtil.compareVersions.mockReturnValue(0);
|
||||||
|
@ -69,35 +62,30 @@ describe('SetupStore', function () {
|
||||||
describe('init step', function () {
|
describe('init step', function () {
|
||||||
virtualBox.vmdestroy.mockReturnValue(Promise.resolve());
|
virtualBox.vmdestroy.mockReturnValue(Promise.resolve());
|
||||||
pit('inintializes the boot2docker vm if it does not exist', function () {
|
pit('inintializes the boot2docker vm if it does not exist', function () {
|
||||||
boot2docker.exists.mockReturnValue(Promise.resolve(false));
|
machine.exists.mockReturnValue(Promise.resolve(false));
|
||||||
boot2docker.init.mockReturnValue(Promise.resolve());
|
machine.create.mockReturnValue(Promise.resolve());
|
||||||
return setupStore.steps().init.run().then(() => {
|
return setupStore.steps().init.run().then(() => {
|
||||||
expect(boot2docker.init).toBeCalled();
|
expect(machine.create).toBeCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('upgrades the boot2docker vm if it exists and is out of date', function () {
|
pit('upgrades the vm if it exists and is out of date', function () {
|
||||||
boot2docker.exists.mockReturnValue(Promise.resolve(true));
|
machine.exists.mockReturnValue(Promise.resolve(true));
|
||||||
boot2docker.isoversion.mockReturnValue('1.0');
|
machine.state.mockReturnValue(Promise.resolve('Running'));
|
||||||
boot2docker.haskeys.mockReturnValue(true);
|
machine.isoversion.mockReturnValue('1.0');
|
||||||
boot2docker.stop.mockReturnValue(Promise.resolve());
|
machine.stop.mockReturnValue(Promise.resolve());
|
||||||
boot2docker.upgrade.mockReturnValue(Promise.resolve());
|
machine.start.mockReturnValue(Promise.resolve());
|
||||||
|
machine.upgrade.mockReturnValue(Promise.resolve());
|
||||||
setupUtil.compareVersions.mockReturnValue(-1);
|
setupUtil.compareVersions.mockReturnValue(-1);
|
||||||
return setupStore.steps().init.run().then(() => {
|
machine.create.mockClear();
|
||||||
boot2docker.init.mockClear();
|
machine.upgrade.mockClear();
|
||||||
expect(boot2docker.init).not.toBeCalled();
|
machine.stop.mockClear();
|
||||||
expect(boot2docker.upgrade).toBeCalled();
|
machine.start.mockClear();
|
||||||
});
|
return setupStore.steps().init.run(() => {}).then(() => {
|
||||||
});
|
expect(machine.create).not.toBeCalled();
|
||||||
});
|
expect(machine.stop).toBeCalled();
|
||||||
|
expect(machine.start).toBeCalled();
|
||||||
describe('start step', function () {
|
expect(machine.upgrade).toBeCalled();
|
||||||
pit('starts the boot2docker vm if it is not running', function () {
|
|
||||||
boot2docker.status.mockReturnValue(false);
|
|
||||||
boot2docker.waitstatus.mockReturnValue(Promise.resolve());
|
|
||||||
boot2docker.start.mockReturnValue(Promise.resolve());
|
|
||||||
return setupStore.steps().start.run().then(() => {
|
|
||||||
expect(boot2docker.start).toBeCalled();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
{"error":"Not Found"}
|
|
|
@ -26,7 +26,7 @@ var windowOptions = {
|
||||||
'min-height': 700,
|
'min-height': 700,
|
||||||
resizable: true,
|
resizable: true,
|
||||||
frame: false,
|
frame: false,
|
||||||
show: true
|
show: false
|
||||||
};
|
};
|
||||||
|
|
||||||
app.on('activate-with-no-open-windows', function () {
|
app.on('activate-with-no-open-windows', function () {
|
||||||
|
@ -38,14 +38,14 @@ app.on('activate-with-no-open-windows', function () {
|
||||||
|
|
||||||
app.on('ready', function() {
|
app.on('ready', function() {
|
||||||
mainWindow = new BrowserWindow(windowOptions);
|
mainWindow = new BrowserWindow(windowOptions);
|
||||||
var saveVMOnQuit = false;
|
var closeVMOnQuit = false;
|
||||||
if (argv.test) {
|
if (argv.test) {
|
||||||
mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, '..', 'build/tests.html')));
|
mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, '..', 'build/tests.html')));
|
||||||
} else {
|
} else {
|
||||||
mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, '..', 'build/index.html')));
|
mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, '..', 'build/index.html')));
|
||||||
app.on('will-quit', function () {
|
app.on('will-quit', function () {
|
||||||
if (saveVMOnQuit) {
|
if (closeVMOnQuit) {
|
||||||
exec('/usr/bin/VBoxManage controlvm boot2docker-vm savestate', function () {});
|
exec('/usr/bin/VBoxManage controlvm dev poweroff', function () {});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -97,14 +97,14 @@ app.on('ready', function() {
|
||||||
ipc.on('command', function (event, arg) {
|
ipc.on('command', function (event, arg) {
|
||||||
console.log('Command: ' + arg);
|
console.log('Command: ' + arg);
|
||||||
if (arg === 'application:quit-install') {
|
if (arg === 'application:quit-install') {
|
||||||
saveVMOnQuit = false;
|
closeVMOnQuit = false;
|
||||||
autoUpdater.quitAndInstall();
|
autoUpdater.quitAndInstall();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ipc.on('vm', function (event, arg) {
|
ipc.on('vm', function (event, arg) {
|
||||||
saveVMOnQuit = arg;
|
closeVMOnQuit = arg;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
37
gulpfile.js
|
@ -30,9 +30,11 @@ settings.beta = isBeta;
|
||||||
var options = {
|
var options = {
|
||||||
dev: process.argv.indexOf('release') === -1,
|
dev: process.argv.indexOf('release') === -1,
|
||||||
beta: isBeta,
|
beta: isBeta,
|
||||||
filename: isBeta ? 'Kitematic (Beta).app' : 'Kitematic.app',
|
appFilename: isBeta ? 'Kitematic (Beta).app' : 'Kitematic.app',
|
||||||
name: isBeta ? 'Kitematic (Beta)' : 'Kitematic',
|
appName: isBeta ? 'Kitematic (Beta)' : 'Kitematic',
|
||||||
icon: isBeta ? './util/kitematic-beta.icns' : './util/kitematic.icns'
|
name: 'Kitematic',
|
||||||
|
icon: isBeta ? './util/kitematic-beta.icns' : './util/kitematic.icns',
|
||||||
|
bundle: 'com.kitemaic.app'
|
||||||
};
|
};
|
||||||
|
|
||||||
gulp.task('js', function () {
|
gulp.task('js', function () {
|
||||||
|
@ -46,14 +48,14 @@ gulp.task('js', function () {
|
||||||
.pipe(react())
|
.pipe(react())
|
||||||
.pipe(babel({blacklist: ['regenerator']}))
|
.pipe(babel({blacklist: ['regenerator']}))
|
||||||
.pipe(gulpif(options.dev, sourcemaps.write('.')))
|
.pipe(gulpif(options.dev, sourcemaps.write('.')))
|
||||||
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
|
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.appFilename + '/Contents/Resources/app/build'))
|
||||||
.pipe(gulpif(options.dev, livereload()));
|
.pipe(gulpif(options.dev, livereload()));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('images', function() {
|
gulp.task('images', function() {
|
||||||
return gulp.src('images/*')
|
return gulp.src('images/*')
|
||||||
.pipe(gulpif(options.dev, changed('./build')))
|
.pipe(gulpif(options.dev, changed('./build')))
|
||||||
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
|
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.appFilename + '/Contents/Resources/app/build'))
|
||||||
.pipe(gulpif(options.dev, livereload()));
|
.pipe(gulpif(options.dev, livereload()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -68,7 +70,7 @@ gulp.task('styles', function () {
|
||||||
.pipe(gulpif(options.dev, sourcemaps.init()))
|
.pipe(gulpif(options.dev, sourcemaps.init()))
|
||||||
.pipe(less())
|
.pipe(less())
|
||||||
.pipe(gulpif(options.dev, sourcemaps.write()))
|
.pipe(gulpif(options.dev, sourcemaps.write()))
|
||||||
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
|
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.appFilename + '/Contents/Resources/app/build'))
|
||||||
.pipe(gulpif(!options.dev, cssmin()))
|
.pipe(gulpif(!options.dev, cssmin()))
|
||||||
.pipe(concat('main.css'))
|
.pipe(concat('main.css'))
|
||||||
.pipe(gulpif(options.dev, livereload()));
|
.pipe(gulpif(options.dev, livereload()));
|
||||||
|
@ -83,12 +85,12 @@ gulp.task('download', function (cb) {
|
||||||
|
|
||||||
gulp.task('copy', function () {
|
gulp.task('copy', function () {
|
||||||
gulp.src('index.html')
|
gulp.src('index.html')
|
||||||
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
|
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.appFilename + '/Contents/Resources/app/build'))
|
||||||
.pipe(gulpif(options.dev, livereload()));
|
.pipe(gulpif(options.dev, livereload()));
|
||||||
|
|
||||||
gulp.src('fonts/**')
|
gulp.src('fonts/**')
|
||||||
.pipe(gulpif(options.dev, changed('./build')))
|
.pipe(gulpif(options.dev, changed('./build')))
|
||||||
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
|
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.appFilename + '/Contents/Resources/app/build'))
|
||||||
.pipe(gulpif(options.dev, livereload()));
|
.pipe(gulpif(options.dev, livereload()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -112,10 +114,10 @@ gulp.task('dist', function () {
|
||||||
'/usr/libexec/PlistBuddy -c "Set :CFBundleExecutable <%= name %>" dist/osx/<%= filename %>/Contents/Info.plist'
|
'/usr/libexec/PlistBuddy -c "Set :CFBundleExecutable <%= name %>" dist/osx/<%= filename %>/Contents/Info.plist'
|
||||||
], {
|
], {
|
||||||
templateData: {
|
templateData: {
|
||||||
filename: options.filename.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)'),
|
filename: options.appFilename.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)'),
|
||||||
name: options.name.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)'),
|
name: options.appName.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)'),
|
||||||
version: packagejson.version,
|
version: packagejson.version,
|
||||||
bundle: 'com.kitematic.app',
|
bundle: options.bundle,
|
||||||
icon: options.icon
|
icon: options.icon
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -125,7 +127,7 @@ gulp.task('dist', function () {
|
||||||
'cp -R node_modules/' + d + ' dist/osx/<%= filename %>/Contents/Resources/app/node_modules/'
|
'cp -R node_modules/' + d + ' dist/osx/<%= filename %>/Contents/Resources/app/node_modules/'
|
||||||
], {
|
], {
|
||||||
templateData: {
|
templateData: {
|
||||||
filename: options.filename.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)')
|
filename: options.appFilename.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)')
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
@ -137,7 +139,7 @@ gulp.task('sign', function () {
|
||||||
try {
|
try {
|
||||||
var signing_identity = fs.readFileSync('./identity', 'utf8').trim();
|
var signing_identity = fs.readFileSync('./identity', 'utf8').trim();
|
||||||
return gulp.src('').pipe(shell([
|
return gulp.src('').pipe(shell([
|
||||||
'codesign --deep --force --verbose --sign "' + signing_identity + '" ' + options.filename.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)')
|
'codesign --deep --force --verbose --sign "' + signing_identity + '" ' + options.appFilename.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)')
|
||||||
], {
|
], {
|
||||||
cwd: './dist/osx/'
|
cwd: './dist/osx/'
|
||||||
}));
|
}));
|
||||||
|
@ -148,7 +150,7 @@ gulp.task('sign', function () {
|
||||||
|
|
||||||
gulp.task('zip', function () {
|
gulp.task('zip', function () {
|
||||||
return gulp.src('').pipe(shell([
|
return gulp.src('').pipe(shell([
|
||||||
'ditto -c -k --sequesterRsrc --keepParent ' + options.filename.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)') + ' ' + options.name.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)') + '-' + packagejson.version + '.zip'
|
'ditto -c -k --sequesterRsrc --keepParent ' + options.appFilename.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)') + ' ' + options.name.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)') + '-' + packagejson.version + '.zip'
|
||||||
], {
|
], {
|
||||||
cwd: './dist/osx/'
|
cwd: './dist/osx/'
|
||||||
}));
|
}));
|
||||||
|
@ -163,7 +165,7 @@ gulp.task('settings', function () {
|
||||||
};
|
};
|
||||||
return src;
|
return src;
|
||||||
};
|
};
|
||||||
string_src('settings.json', JSON.stringify(settings)).pipe(gulp.dest('dist/osx/' + options.filename.replace(' ', '\ ').replace('(','\(').replace(')','\)') + '/Contents/Resources/app'));
|
string_src('settings.json', JSON.stringify(settings)).pipe(gulp.dest('dist/osx/' + options.appFilename.replace(' ', '\ ').replace('(','\(').replace(')','\)') + '/Contents/Resources/app'));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('release', function () {
|
gulp.task('release', function () {
|
||||||
|
@ -171,12 +173,13 @@ gulp.task('release', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('default', ['download', 'copy', 'js', 'images', 'styles'], function () {
|
gulp.task('default', ['download', 'copy', 'js', 'images', 'styles'], function () {
|
||||||
livereload.listen();
|
gulp.watch('src/**/*.js', ['js']);
|
||||||
gulp.watch('src/**/*.js', ['js', function () {livereload();}]);
|
|
||||||
gulp.watch('index.html', ['copy']);
|
gulp.watch('index.html', ['copy']);
|
||||||
gulp.watch('styles/**/*.less', ['styles']);
|
gulp.watch('styles/**/*.less', ['styles']);
|
||||||
gulp.watch('images/**', ['images']);
|
gulp.watch('images/**', ['images']);
|
||||||
|
|
||||||
|
livereload.listen();
|
||||||
|
|
||||||
var env = process.env;
|
var env = process.env;
|
||||||
env.NODE_ENV = 'development';
|
env.NODE_ENV = 'development';
|
||||||
gulp.src('').pipe(shell(['./cache/Atom.app/Contents/MacOS/Atom .'], {
|
gulp.src('').pipe(shell(['./cache/Atom.app/Contents/MacOS/Atom .'], {
|
||||||
|
|
Двоичные данные
images/button-restart.png
До Ширина: | Высота: | Размер: 1.6 KiB После Ширина: | Высота: | Размер: 1.6 KiB |
Двоичные данные
images/button-restart@2x.png
До Ширина: | Высота: | Размер: 3.6 KiB После Ширина: | Высота: | Размер: 3.6 KiB |
Двоичные данные
images/button-terminal.png
До Ширина: | Высота: | Размер: 1.4 KiB После Ширина: | Высота: | Размер: 1.4 KiB |
Двоичные данные
images/button-terminal@2x.png
До Ширина: | Высота: | Размер: 3.2 KiB После Ширина: | Высота: | Размер: 3.2 KiB |
Двоичные данные
images/button-view.png
До Ширина: | Высота: | Размер: 1.7 KiB После Ширина: | Высота: | Размер: 1.7 KiB |
Двоичные данные
images/button-view@2x.png
До Ширина: | Высота: | Размер: 3.9 KiB После Ширина: | Высота: | Размер: 3.9 KiB |
36
package.json
|
@ -40,50 +40,50 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"docker-version": "1.5.0",
|
"docker-version": "1.5.0",
|
||||||
"boot2docker-version": "1.5.0",
|
"docker-machine-version": "0.1.0",
|
||||||
"atom-shell-version": "0.21.1",
|
"atom-shell-version": "0.21.2",
|
||||||
"virtualbox-version": "4.3.22",
|
"virtualbox-version": "4.3.22",
|
||||||
"virtualbox-filename": "VirtualBox-4.3.22.pkg",
|
"virtualbox-filename": "VirtualBox-4.3.22.pkg",
|
||||||
"virtualbox-checksum": "4a7dff25bdeef0d112e16ac11bee6d52e856d36bb412aa75576036ba560082eb",
|
"virtualbox-checksum": "4a7dff25bdeef0d112e16ac11bee6d52e856d36bb412aa75576036ba560082eb",
|
||||||
"virtualbox-required-version": "4.3.0",
|
"virtualbox-required-version": "4.3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-to-html": "0.2.0",
|
"ansi-to-html": "0.3.0",
|
||||||
"async": "^0.9.0",
|
"async": "^0.9.0",
|
||||||
"bluebird": "^2.9.6",
|
"bluebird": "^2.9.12",
|
||||||
"bugsnag-js": "^2.4.7",
|
"bugsnag-js": "^2.4.7",
|
||||||
"dockerode": "^2.0.7",
|
"dockerode": "^2.0.7",
|
||||||
"exec": "0.1.2",
|
"exec": "0.2.0",
|
||||||
"jquery": "^2.1.3",
|
"jquery": "^2.1.3",
|
||||||
"minimist": "^1.1.0",
|
"minimist": "^1.1.0",
|
||||||
"mixpanel": "0.0.20",
|
"mixpanel": "0.0.20",
|
||||||
"node-uuid": "^1.4.2",
|
"node-uuid": "^1.4.2",
|
||||||
"object-assign": "^2.0.0",
|
"object-assign": "^2.0.0",
|
||||||
"react": "^0.12.2",
|
"react": "^0.12.2",
|
||||||
"react-bootstrap": "^0.13.2",
|
"react-bootstrap": "^0.15.1",
|
||||||
"react-retina-image": "^1.1.2",
|
"react-retina-image": "^1.1.2",
|
||||||
"react-router": "^0.11.6",
|
"react-router": "^0.12.4",
|
||||||
"request": "^2.53.0",
|
"request": "^2.53.0",
|
||||||
"request-progress": "^0.3.1",
|
"request-progress": "^0.3.1",
|
||||||
"rimraf": "^2.2.8",
|
"rimraf": "^2.2.8",
|
||||||
"underscore": "^1.7.0"
|
"underscore": "^1.8.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel": "^4.0.1",
|
"babel": "^4.5.5",
|
||||||
"gulp": "^3.8.10",
|
"gulp": "^3.8.11",
|
||||||
"gulp-babel": "^4.0.0",
|
"gulp-babel": "^4.0.0",
|
||||||
"gulp-changed": "^1.1.1",
|
"gulp-changed": "^1.1.1",
|
||||||
"gulp-concat": "^2.3.4",
|
"gulp-concat": "^2.5.2",
|
||||||
"gulp-cssmin": "^0.1.6",
|
"gulp-cssmin": "^0.1.6",
|
||||||
"gulp-download-atom-shell": "0.0.4",
|
"gulp-download-atom-shell": "0.0.4",
|
||||||
"gulp-if": "^1.2.4",
|
"gulp-if": "^1.2.5",
|
||||||
"gulp-less": "^2.0.1",
|
"gulp-less": "^3.0.1",
|
||||||
"gulp-livereload": "^2.1.1",
|
"gulp-livereload": "^3.8.0",
|
||||||
"gulp-plumber": "^0.6.6",
|
"gulp-plumber": "^0.6.6",
|
||||||
"gulp-react": "^2.0.0",
|
"gulp-react": "^2.0.0",
|
||||||
"gulp-shell": "^0.2.11",
|
"gulp-shell": "^0.3.0",
|
||||||
"gulp-sourcemaps": "^1.2.8",
|
"gulp-sourcemaps": "^1.5.0",
|
||||||
"gulp-util": "^3.0.0",
|
"gulp-util": "^3.0.4",
|
||||||
"jest-cli": "^0.2.2",
|
"jest-cli": "^0.4.0",
|
||||||
"jsxhint": "^0.12.1",
|
"jsxhint": "^0.12.1",
|
||||||
"react-tools": "^0.12.2",
|
"react-tools": "^0.12.2",
|
||||||
"run-sequence": "^1.0.2"
|
"run-sequence": "^1.0.2"
|
||||||
|
|
|
@ -6,7 +6,7 @@ var path = require('path');
|
||||||
var metrics = require('./Metrics');
|
var metrics = require('./Metrics');
|
||||||
var ContainerStore = require('./ContainerStore');
|
var ContainerStore = require('./ContainerStore');
|
||||||
var ContainerUtil = require('./ContainerUtil');
|
var ContainerUtil = require('./ContainerUtil');
|
||||||
var boot2docker = require('./Boot2Docker');
|
var machine = require('./DockerMachine');
|
||||||
var RetinaImage = require('react-retina-image');
|
var RetinaImage = require('react-retina-image');
|
||||||
var Router = require('react-router');
|
var Router = require('react-router');
|
||||||
var webPorts = require('./Util').webPorts;
|
var webPorts = require('./Util').webPorts;
|
||||||
|
@ -105,11 +105,13 @@ var ContainerDetailsSubheader = React.createClass({
|
||||||
metrics.track('Terminaled Into Container');
|
metrics.track('Terminaled Into Container');
|
||||||
var container = this.props.container;
|
var container = this.props.container;
|
||||||
var terminal = path.join(process.cwd(), 'resources', 'terminal');
|
var terminal = path.join(process.cwd(), 'resources', 'terminal');
|
||||||
var cmd = [terminal, boot2docker.command().replace(/ /g, '\\\\\\\\ ').replace(/\(/g, '\\\\\\\\(').replace(/\)/g, '\\\\\\\\)'), 'ssh', '-t', 'sudo', 'docker', 'exec', '-i', '-t', container.Name, 'sh'];
|
machine.ip().then(ip => {
|
||||||
exec(cmd, function (stderr, stdout, code) {
|
var cmd = [terminal, 'ssh', '-o', 'UserKnownHostsFile=/dev/null', '-o', 'LogLevel=quiet', '-o', 'StrictHostKeyChecking=no', '-i', '~/.docker/machine/machines/' + machine.name() + '/id_rsa', 'docker@' + ip, '-t', 'docker', 'exec', '-i', '-t', container.Name, 'sh'];
|
||||||
if (code) {
|
exec(cmd, function (stderr, stdout, code) {
|
||||||
console.log(stderr);
|
if (code) {
|
||||||
}
|
console.log(stderr);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -119,10 +119,15 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
|
||||||
if (containerData.State && !containerData.State.Running) {
|
if (containerData.State && !containerData.State.Running) {
|
||||||
self.fetchContainer(containerData.name, callback);
|
self.fetchContainer(containerData.name, callback);
|
||||||
} else {
|
} else {
|
||||||
container.start({
|
var startopts = {
|
||||||
PublishAllPorts: true,
|
|
||||||
Binds: binds
|
Binds: binds
|
||||||
}, function (err) {
|
};
|
||||||
|
if (containerData.NetworkSettings && containerData.NetworkSettings.Ports) {
|
||||||
|
startopts.PortBindings = containerData.NetworkSettings.Ports;
|
||||||
|
} else{
|
||||||
|
startopts.PublishAllPorts = true;
|
||||||
|
}
|
||||||
|
container.start(startopts, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
|
@ -140,8 +145,7 @@ var ContainerStore = assign(Object.create(EventEmitter.prototype), {
|
||||||
var count = 1;
|
var count = 1;
|
||||||
var name = base;
|
var name = base;
|
||||||
while (true) {
|
while (true) {
|
||||||
var exists = _.findWhere(_.values(_containers), {Name: name}) || _.findWhere(_.values(_containers), {Name: name});
|
if (!this.containers()[name]) {
|
||||||
if (!exists) {
|
|
||||||
return name;
|
return name;
|
||||||
} else {
|
} else {
|
||||||
count++;
|
count++;
|
||||||
|
|
|
@ -17,7 +17,7 @@ var ContainerUtil = {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
var res = {};
|
var res = {};
|
||||||
var ip = docker.host;
|
var ip = docker.host();
|
||||||
_.each(container.NetworkSettings.Ports, function (value, key) {
|
_.each(container.NetworkSettings.Ports, function (value, key) {
|
||||||
var dockerPort = key.split('/')[0];
|
var dockerPort = key.split('/')[0];
|
||||||
var localUrl = null;
|
var localUrl = null;
|
||||||
|
|
|
@ -9,8 +9,7 @@ var remote = require('remote');
|
||||||
var metrics = require('./Metrics');
|
var metrics = require('./Metrics');
|
||||||
var autoUpdater = remote.require('auto-updater');
|
var autoUpdater = remote.require('auto-updater');
|
||||||
var RetinaImage = require('react-retina-image');
|
var RetinaImage = require('react-retina-image');
|
||||||
var path = require('path');
|
var machine = require('./DockerMachine');
|
||||||
var docker = require('./Docker');
|
|
||||||
var util = require('./Util');
|
var util = require('./Util');
|
||||||
|
|
||||||
var Containers = React.createClass({
|
var Containers = React.createClass({
|
||||||
|
@ -94,19 +93,26 @@ var Containers = React.createClass({
|
||||||
ipc.send('command', 'application:quit-install');
|
ipc.send('command', 'application:quit-install');
|
||||||
},
|
},
|
||||||
handleClickPreferences: function () {
|
handleClickPreferences: function () {
|
||||||
|
metrics.track('Opened Preferences', {
|
||||||
|
from: 'app'
|
||||||
|
});
|
||||||
this.transitionTo('preferences');
|
this.transitionTo('preferences');
|
||||||
},
|
},
|
||||||
handleClickDockerTerminal: function () {
|
handleClickDockerTerminal: function () {
|
||||||
var terminal = path.join(process.cwd(), 'resources', 'terminal');
|
metrics.track('Opened Docker Terminal', {
|
||||||
var cmd = [terminal, `DOCKER_HOST=${'tcp://' + docker.host + ':2376'} DOCKER_CERT_PATH=${path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], '.boot2docker/certs/boot2docker-vm')} DOCKER_TLS_VERIFY=1 $SHELL`];
|
from: 'app'
|
||||||
util.exec(cmd).then(() => {});
|
});
|
||||||
|
machine.dockerTerminal();
|
||||||
},
|
},
|
||||||
handleClickReportIssue: function () {
|
handleClickReportIssue: function () {
|
||||||
|
metrics.track('Opened Issue Reporter', {
|
||||||
|
from: 'app'
|
||||||
|
});
|
||||||
util.exec(['open', 'https://github.com/kitematic/kitematic/issues/new']);
|
util.exec(['open', 'https://github.com/kitematic/kitematic/issues/new']);
|
||||||
},
|
},
|
||||||
handleMouseEnterDockerTerminal: function () {
|
handleMouseEnterDockerTerminal: function () {
|
||||||
this.setState({
|
this.setState({
|
||||||
currentButtonLabel: 'Open terminal to use Docker CLI.'
|
currentButtonLabel: 'Open Docker-Ready Mac Terminal.'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleMouseLeaveDockerTerminal: function () {
|
handleMouseLeaveDockerTerminal: function () {
|
||||||
|
@ -116,7 +122,7 @@ var Containers = React.createClass({
|
||||||
},
|
},
|
||||||
handleMouseEnterReportIssue: function () {
|
handleMouseEnterReportIssue: function () {
|
||||||
this.setState({
|
this.setState({
|
||||||
currentButtonLabel: 'Report issues or suggest feedbacks.'
|
currentButtonLabel: 'Report an Issue'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleMouseLeaveReportIssue: function () {
|
handleMouseLeaveReportIssue: function () {
|
||||||
|
@ -126,7 +132,7 @@ var Containers = React.createClass({
|
||||||
},
|
},
|
||||||
handleMouseEnterPreferences: function () {
|
handleMouseEnterPreferences: function () {
|
||||||
this.setState({
|
this.setState({
|
||||||
currentButtonLabel: 'Change app preferences.'
|
currentButtonLabel: 'Change app Preferences.'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleMouseLeavePreferences: function () {
|
handleMouseLeavePreferences: function () {
|
||||||
|
|
|
@ -3,17 +3,20 @@ var path = require('path');
|
||||||
var dockerode = require('dockerode');
|
var dockerode = require('dockerode');
|
||||||
|
|
||||||
var Docker = {
|
var Docker = {
|
||||||
host: null,
|
_host: null,
|
||||||
_client: null,
|
_client: null,
|
||||||
setHost: function(host) {
|
setup: function(url, name) {
|
||||||
this.host = host;
|
var certDir = path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], '.docker/machine/machines', name);
|
||||||
var certDir = path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], '.boot2docker/certs/boot2docker-vm');
|
|
||||||
if (!fs.existsSync(certDir)) {
|
if (!fs.existsSync(certDir)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var ip = url.split(':')[1].replace('//', '');
|
||||||
|
var port = url.split(':')[2];
|
||||||
|
this._host = ip;
|
||||||
this._client = new dockerode({
|
this._client = new dockerode({
|
||||||
host: host,
|
protocol: 'https',
|
||||||
port: 2376,
|
host: ip,
|
||||||
|
port: port,
|
||||||
ca: fs.readFileSync(path.join(certDir, 'ca.pem')),
|
ca: fs.readFileSync(path.join(certDir, 'ca.pem')),
|
||||||
cert: fs.readFileSync(path.join(certDir, 'cert.pem')),
|
cert: fs.readFileSync(path.join(certDir, 'cert.pem')),
|
||||||
key: fs.readFileSync(path.join(certDir, 'key.pem'))
|
key: fs.readFileSync(path.join(certDir, 'key.pem'))
|
||||||
|
@ -21,6 +24,9 @@ var Docker = {
|
||||||
},
|
},
|
||||||
client: function () {
|
client: function () {
|
||||||
return this._client;
|
return this._client;
|
||||||
|
},
|
||||||
|
host: function () {
|
||||||
|
return this._host;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,20 +5,25 @@ var _ = require('underscore');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var util = require('./Util');
|
var util = require('./Util');
|
||||||
|
|
||||||
var Boot2Docker = {
|
var NAME = 'dev';
|
||||||
|
|
||||||
|
var DockerMachine = {
|
||||||
command: function () {
|
command: function () {
|
||||||
return path.join(process.cwd(), 'resources', 'boot2docker-' + this.version());
|
return path.join(process.cwd(), 'resources', 'docker-machine-' + this.version());
|
||||||
|
},
|
||||||
|
name: function () {
|
||||||
|
return NAME;
|
||||||
},
|
},
|
||||||
version: function () {
|
version: function () {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'))['boot2docker-version'];
|
return JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'))['docker-machine-version'];
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isoversion: function () {
|
isoversion: function () {
|
||||||
try {
|
try {
|
||||||
var data = fs.readFileSync(path.join(util.home(), '.boot2docker', 'boot2docker.iso'), 'utf8');
|
var data = fs.readFileSync(path.join(util.home(), '.docker', 'machine', 'machines', NAME, 'boot2docker.iso'), 'utf8');
|
||||||
var match = data.match(/Boot2Docker-v(\d+\.\d+\.\d+)/);
|
var match = data.match(/Boot2Docker-v(\d+\.\d+\.\d+)/);
|
||||||
if (match) {
|
if (match) {
|
||||||
return match[1];
|
return match[1];
|
||||||
|
@ -29,53 +34,62 @@ var Boot2Docker = {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
exists: function () {
|
info: function () {
|
||||||
return util.exec([Boot2Docker.command(), 'status']).then(() => {
|
return util.exec([DockerMachine.command(), 'ls']).then(stdout => {
|
||||||
return Promise.resolve(true);
|
var lines = stdout.trim().split('\n').filter(line => line.indexOf('time=') === -1);
|
||||||
}).catch(() => {
|
var machines = {};
|
||||||
return Promise.resolve(false);
|
lines.slice(1, lines.length).forEach(line => {
|
||||||
});
|
var tokens = line.trim().split(/[\s]+/).filter(token => token !== '*');
|
||||||
},
|
var machine = {
|
||||||
status: function () {
|
name: tokens[0],
|
||||||
return util.exec([Boot2Docker.command(), 'status']).then(stdout => {
|
driver: tokens[1],
|
||||||
return Promise.resolve(stdout.trim());
|
state: tokens[2],
|
||||||
});
|
url: tokens[3] || ''
|
||||||
},
|
};
|
||||||
init: function () {
|
machines[machine.name] = machine;
|
||||||
return util.exec([Boot2Docker.command(), 'init']);
|
});
|
||||||
},
|
if (machines[NAME]) {
|
||||||
start: function () {
|
return machines[NAME];
|
||||||
return util.exec([Boot2Docker.command(), 'start']);
|
} else {
|
||||||
},
|
throw new Error('Machine does not exist.');
|
||||||
stop: function () {
|
|
||||||
return util.exec([Boot2Docker.command(), 'stop']);
|
|
||||||
},
|
|
||||||
upgrade: function () {
|
|
||||||
return util.exec([Boot2Docker.command(), 'upgrade']);
|
|
||||||
},
|
|
||||||
destroy: function () {
|
|
||||||
return util.exec([Boot2Docker.command(), 'destroy']);
|
|
||||||
},
|
|
||||||
ip: function () {
|
|
||||||
return util.exec([Boot2Docker.command(), 'ip']).then(stdout => {
|
|
||||||
return Promise.resolve(stdout.trim().replace('\n', ''));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
erase: function () {
|
|
||||||
return util.exec(['rm', '-rf', path.join(util.home(), 'VirtualBox\\ VMs/boot2docker-vm')]);
|
|
||||||
},
|
|
||||||
state: function () {
|
|
||||||
util.exec([Boot2Docker.command(), 'info']).then(stdout => {
|
|
||||||
try {
|
|
||||||
var info = JSON.parse(stdout);
|
|
||||||
return Promise.resolve(info.State);
|
|
||||||
} catch (err) {
|
|
||||||
return Promise.reject(err);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
exists: function () {
|
||||||
|
return DockerMachine.info().then(() => {
|
||||||
|
return true;
|
||||||
|
}).catch(() => {
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
create: function () {
|
||||||
|
return util.exec([DockerMachine.command(), 'create', '-d', 'virtualbox', '--virtualbox-memory', '2048', NAME]);
|
||||||
|
},
|
||||||
|
start: function () {
|
||||||
|
return util.exec([DockerMachine.command(), 'start', NAME]);
|
||||||
|
},
|
||||||
|
stop: function () {
|
||||||
|
return util.exec([DockerMachine.command(), 'stop', NAME]);
|
||||||
|
},
|
||||||
|
upgrade: function () {
|
||||||
|
return util.exec([DockerMachine.command(), 'upgrade', NAME]);
|
||||||
|
},
|
||||||
|
rm: function () {
|
||||||
|
return util.exec([DockerMachine.command(), 'rm', '-f', NAME]);
|
||||||
|
},
|
||||||
|
ip: function () {
|
||||||
|
return util.exec([DockerMachine.command(), 'ip']).then(stdout => {
|
||||||
|
return Promise.resolve(stdout.trim().replace('\n', ''));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
state: function () {
|
||||||
|
return DockerMachine.info().then(info => {
|
||||||
|
return info ? info.state : null;
|
||||||
|
});
|
||||||
|
},
|
||||||
disk: function () {
|
disk: function () {
|
||||||
return util.exec([Boot2Docker.command(), 'ssh', 'df']).then(stdout => {
|
return util.exec([DockerMachine.command(), 'ssh', NAME, 'df']).then(stdout => {
|
||||||
try {
|
try {
|
||||||
var lines = stdout.split('\n');
|
var lines = stdout.split('\n');
|
||||||
var dataline = _.find(lines, function (line) {
|
var dataline = _.find(lines, function (line) {
|
||||||
|
@ -99,7 +113,7 @@ var Boot2Docker = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
memory: function () {
|
memory: function () {
|
||||||
return util.exec([this.command(), 'ssh', 'free -m']).then(stdout => {
|
return util.exec([this.command(), 'ssh', NAME, 'free -m']).then(stdout => {
|
||||||
try {
|
try {
|
||||||
var lines = stdout.split('\n');
|
var lines = stdout.split('\n');
|
||||||
var dataline = _.find(lines, function (line) {
|
var dataline = _.find(lines, function (line) {
|
||||||
|
@ -125,32 +139,35 @@ var Boot2Docker = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
stats: function () {
|
stats: function () {
|
||||||
Boot2Docker.state().then(state => {
|
DockerMachine.state().then(state => {
|
||||||
if (state === 'poweroff') {
|
if (state === 'Stopped') {
|
||||||
return Promise.resolve({state: state});
|
return Promise.resolve({state: state});
|
||||||
}
|
}
|
||||||
var memory = Boot2Docker.memory();
|
var memory = DockerMachine.memory();
|
||||||
var disk = Boot2Docker.disk();
|
var disk = DockerMachine.disk();
|
||||||
return Promise.all([memory, disk]).spread((memory, disk) => {
|
return Promise.all([memory, disk]).spread((memory, disk) => {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
state: state,
|
|
||||||
memory: memory,
|
memory: memory,
|
||||||
disk: disk
|
disk: disk
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
haskeys: function () {
|
waitWhileState: Promise.coroutine(function* (status) {
|
||||||
return fs.existsSync(path.join(util.home(), '.ssh', 'id_boot2docker'));
|
|
||||||
},
|
|
||||||
waitstatus: Promise.coroutine(function* () {
|
|
||||||
while (true) {
|
while (true) {
|
||||||
var current = yield Boot2Docker.status();
|
var current = yield DockerMachine.state();
|
||||||
if (status !== current.trim()) {
|
if (status !== current.trim()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
|
dockerTerminal: function () {
|
||||||
|
var terminal = path.join(process.cwd(), 'resources', 'terminal');
|
||||||
|
this.info().then(machine => {
|
||||||
|
var cmd = [terminal, `DOCKER_HOST=${machine.url} DOCKER_CERT_PATH=${path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], '.docker/machine/machines/' + machine.name)} DOCKER_TLS_VERIFY=1 $SHELL`];
|
||||||
|
util.exec(cmd).then(() => {});
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Boot2Docker;
|
module.exports = DockerMachine;
|
44
src/Main.js
|
@ -1,14 +1,4 @@
|
||||||
var remote = require('remote');
|
var remote = require('remote');
|
||||||
if (localStorage.getItem('settings.width') && localStorage.getItem('settings.height')) {
|
|
||||||
remote.getCurrentWindow().setSize(parseInt(localStorage.getItem('settings.width')), parseInt(localStorage.getItem('settings.height')));
|
|
||||||
remote.getCurrentWindow().center();
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('resize', function () {
|
|
||||||
localStorage.setItem('settings.width', window.innerWidth);
|
|
||||||
localStorage.setItem('settings.height', window.innerHeight);
|
|
||||||
});
|
|
||||||
|
|
||||||
require.main.paths.splice(0, 0, process.env.NODE_PATH);
|
require.main.paths.splice(0, 0, process.env.NODE_PATH);
|
||||||
var app = remote.require('app');
|
var app = remote.require('app');
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
|
@ -16,15 +6,24 @@ var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var docker = require('./Docker');
|
var docker = require('./Docker');
|
||||||
var router = require('./router');
|
var router = require('./router');
|
||||||
var boot2docker = require('./boot2docker');
|
var machine = require('./DockerMachine');
|
||||||
var ContainerStore = require('./ContainerStore');
|
var ContainerStore = require('./ContainerStore');
|
||||||
var SetupStore = require('./SetupStore');
|
var SetupStore = require('./SetupStore');
|
||||||
var metrics = require('./Metrics');
|
var metrics = require('./Metrics');
|
||||||
|
var template = require('./MenuTemplate');
|
||||||
var MenuTemplate = require('./MenuTemplate');
|
|
||||||
var Menu = remote.require('menu');
|
var Menu = remote.require('menu');
|
||||||
var menu = Menu.buildFromTemplate(MenuTemplate);
|
|
||||||
Menu.setApplicationMenu(menu);
|
if (localStorage.getItem('settings.width') && localStorage.getItem('settings.height')) {
|
||||||
|
remote.getCurrentWindow().setSize(parseInt(localStorage.getItem('settings.width')), parseInt(localStorage.getItem('settings.height')));
|
||||||
|
remote.getCurrentWindow().center();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', function () {
|
||||||
|
localStorage.setItem('settings.width', window.outerWidth);
|
||||||
|
localStorage.setItem('settings.height', window.outerHeight);
|
||||||
|
});
|
||||||
|
|
||||||
|
Menu.setApplicationMenu(Menu.buildFromTemplate(template()));
|
||||||
|
|
||||||
var settingsjson;
|
var settingsjson;
|
||||||
try {
|
try {
|
||||||
|
@ -52,12 +51,13 @@ bugsnag.metaData = {
|
||||||
};
|
};
|
||||||
|
|
||||||
bugsnag.beforeNotify = function(payload) {
|
bugsnag.beforeNotify = function(payload) {
|
||||||
var re = new RegExp(process.cwd().replace(' ', '\\s').replace('(','\\(').replace(')','\\)'), 'g');
|
var re = new RegExp(process.cwd().replace(/\s+/g, '\\s+').replace(/\(/g,'\\(').replace(/\)/g,'\\)').replace(/\//g, '\\/'), 'g');
|
||||||
payload.stacktrace = payload.stacktrace.replace(re, '<redacted codedir>');
|
payload.stacktrace = payload.stacktrace.replace(/%20/g, ' ').replace(re, '<redacted codedir>');
|
||||||
payload.context = payload.context.replace(re, '<redacted codedir>');
|
payload.context = payload.context.replace(/%20/g, ' ').replace(re, '<redacted codedir>');
|
||||||
payload.file = payload.file.replace(re, '<redacted codedir>');
|
payload.file = payload.file.replace(/%20/g, ' ').replace(re, '<redacted codedir>');
|
||||||
payload.url = '<redacted url>';
|
payload.url = '<redacted url>';
|
||||||
};
|
};
|
||||||
|
bugsnag.notify(new Error('test'));
|
||||||
|
|
||||||
document.onkeydown = function (e) {
|
document.onkeydown = function (e) {
|
||||||
e = e || window.event;
|
e = e || window.event;
|
||||||
|
@ -82,13 +82,15 @@ setInterval(function () {
|
||||||
}, 14400000);
|
}, 14400000);
|
||||||
|
|
||||||
router.run(Handler => React.render(<Handler/>, document.body));
|
router.run(Handler => React.render(<Handler/>, document.body));
|
||||||
SetupStore.run().then(boot2docker.ip).then(ip => {
|
SetupStore.run().then(machine.info).then(machine => {
|
||||||
docker.setHost(ip);
|
docker.setup(machine.url, machine.name);
|
||||||
|
Menu.setApplicationMenu(Menu.buildFromTemplate(template()));
|
||||||
ContainerStore.init(function (err) {
|
ContainerStore.init(function (err) {
|
||||||
if (err) { console.log(err); }
|
if (err) { console.log(err); }
|
||||||
router.transitionTo('containers');
|
router.transitionTo('containers');
|
||||||
});
|
});
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
console.log(err.stack);
|
||||||
bugsnag.notify(err);
|
bugsnag.notify(err);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,168 +1,177 @@
|
||||||
var remote = require('remote');
|
var remote = require('remote');
|
||||||
var app = remote.require('app');
|
var app = remote.require('app');
|
||||||
var path = require('path');
|
|
||||||
var docker = require('./Docker');
|
|
||||||
var router = require('./Router');
|
var router = require('./Router');
|
||||||
var util = require('./Util');
|
var util = require('./Util');
|
||||||
var metrics = require('./Metrics');
|
var metrics = require('./Metrics');
|
||||||
|
var machine = require('./DockerMachine');
|
||||||
|
var docker = require('./Docker');
|
||||||
|
|
||||||
// main.js
|
// main.js
|
||||||
var MenuTemplate = [
|
var MenuTemplate = function () {
|
||||||
{
|
return [
|
||||||
label: 'Kitematic',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'About Kitematic',
|
|
||||||
selector: 'orderFrontStandardAboutPanel:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Preferences',
|
|
||||||
accelerator: 'Command+,',
|
|
||||||
click: function () {
|
|
||||||
router.transitionTo('preferences');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Services',
|
|
||||||
submenu: []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Hide Kitematic',
|
|
||||||
accelerator: 'Command+H',
|
|
||||||
selector: 'hide:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Hide Others',
|
|
||||||
accelerator: 'Command+Shift+H',
|
|
||||||
selector: 'hideOtherApplications:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Show All',
|
|
||||||
selector: 'unhideAllApplications:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Quit',
|
|
||||||
accelerator: 'Command+Q',
|
|
||||||
click: function() {
|
|
||||||
app.quit();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'File',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
type: 'separator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Open Docker Terminal',
|
|
||||||
accelerator: 'Command+Shift+T',
|
|
||||||
click: function() {
|
|
||||||
metrics.track('Opened Docker Terminal');
|
|
||||||
var terminal = path.join(process.cwd(), 'resources', 'terminal');
|
|
||||||
var cmd = [terminal, `DOCKER_HOST=${'tcp://' + docker.host + ':2376'} DOCKER_CERT_PATH=${path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], '.boot2docker/certs/boot2docker-vm')} DOCKER_TLS_VERIFY=1 $SHELL`];
|
|
||||||
util.exec(cmd).then(() => {});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Edit',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Undo',
|
|
||||||
accelerator: 'Command+Z',
|
|
||||||
selector: 'undo:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Redo',
|
|
||||||
accelerator: 'Shift+Command+Z',
|
|
||||||
selector: 'redo:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Cut',
|
|
||||||
accelerator: 'Command+X',
|
|
||||||
selector: 'cut:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Copy',
|
|
||||||
accelerator: 'Command+C',
|
|
||||||
selector: 'copy:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Paste',
|
|
||||||
accelerator: 'Command+V',
|
|
||||||
selector: 'paste:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Select All',
|
|
||||||
accelerator: 'Command+A',
|
|
||||||
selector: 'selectAll:'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'View',
|
|
||||||
submenu: [
|
|
||||||
{
|
{
|
||||||
label: 'Toggle DevTools',
|
label: 'Kitematic',
|
||||||
accelerator: 'Alt+Command+I',
|
submenu: [
|
||||||
click: function() { remote.getCurrentWindow().toggleDevTools(); }
|
{
|
||||||
|
label: 'About Kitematic',
|
||||||
|
selector: 'orderFrontStandardAboutPanel:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Preferences',
|
||||||
|
accelerator: 'Command+,',
|
||||||
|
enabled: !!docker.host(),
|
||||||
|
click: function () {
|
||||||
|
metrics.track('Opened Preferences', {
|
||||||
|
from: 'menu'
|
||||||
|
});
|
||||||
|
router.transitionTo('preferences');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Services',
|
||||||
|
submenu: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hide Kitematic',
|
||||||
|
accelerator: 'Command+H',
|
||||||
|
selector: 'hide:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hide Others',
|
||||||
|
accelerator: 'Command+Shift+H',
|
||||||
|
selector: 'hideOtherApplications:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Show All',
|
||||||
|
selector: 'unhideAllApplications:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Quit',
|
||||||
|
accelerator: 'Command+Q',
|
||||||
|
click: function() {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Window',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Minimize',
|
|
||||||
accelerator: 'Command+M',
|
|
||||||
selector: 'performMiniaturize:'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Close',
|
|
||||||
accelerator: 'Command+W',
|
|
||||||
click: function () {
|
|
||||||
remote.getCurrentWindow().hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Bring All to Front',
|
|
||||||
selector: 'arrangeInFront:'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Help',
|
|
||||||
submenu: [
|
|
||||||
{
|
{
|
||||||
label: 'Report an Issue...',
|
label: 'File',
|
||||||
click: function () {
|
submenu: [
|
||||||
util.exec(['open', 'https://github.com/kitematic/kitematic/issues/new']);
|
{
|
||||||
}
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Open Docker Terminal',
|
||||||
|
accelerator: 'Command+Shift+T',
|
||||||
|
enabled: !!docker.host(),
|
||||||
|
click: function() {
|
||||||
|
metrics.track('Opened Docker Terminal', {
|
||||||
|
from: 'menu'
|
||||||
|
});
|
||||||
|
machine.dockerTerminal();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
},
|
},
|
||||||
]
|
{
|
||||||
},
|
label: 'Edit',
|
||||||
];
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'Undo',
|
||||||
|
accelerator: 'Command+Z',
|
||||||
|
selector: 'undo:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Redo',
|
||||||
|
accelerator: 'Shift+Command+Z',
|
||||||
|
selector: 'redo:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cut',
|
||||||
|
accelerator: 'Command+X',
|
||||||
|
selector: 'cut:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Copy',
|
||||||
|
accelerator: 'Command+C',
|
||||||
|
selector: 'copy:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Paste',
|
||||||
|
accelerator: 'Command+V',
|
||||||
|
selector: 'paste:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Select All',
|
||||||
|
accelerator: 'Command+A',
|
||||||
|
selector: 'selectAll:'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'View',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'Toggle DevTools',
|
||||||
|
accelerator: 'Alt+Command+I',
|
||||||
|
click: function() { remote.getCurrentWindow().toggleDevTools(); }
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Window',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'Minimize',
|
||||||
|
accelerator: 'Command+M',
|
||||||
|
selector: 'performMiniaturize:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Close',
|
||||||
|
accelerator: 'Command+W',
|
||||||
|
click: function () {
|
||||||
|
remote.getCurrentWindow().hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Bring All to Front',
|
||||||
|
selector: 'arrangeInFront:'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Help',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'Report an Issue...',
|
||||||
|
click: function () {
|
||||||
|
metrics.track('Opened Issue Reporter', {
|
||||||
|
from: 'menu'
|
||||||
|
});
|
||||||
|
util.exec(['open', 'https://github.com/kitematic/kitematic/issues/new']);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = MenuTemplate;
|
module.exports = MenuTemplate;
|
||||||
|
|
|
@ -3,7 +3,7 @@ var ipc = require('ipc');
|
||||||
var metrics = require('./Metrics');
|
var metrics = require('./Metrics');
|
||||||
var Router = require('react-router');
|
var Router = require('react-router');
|
||||||
|
|
||||||
if (localStorage.getItem('settings.saveVMOnQuit') === 'true') {
|
if (localStorage.getItem('settings.closeVMOnQuit') === 'true') {
|
||||||
ipc.send('vm', true);
|
ipc.send('vm', true);
|
||||||
} else {
|
} else {
|
||||||
ipc.send('vm', false);
|
ipc.send('vm', false);
|
||||||
|
@ -13,7 +13,7 @@ var Preferences = React.createClass({
|
||||||
mixins: [Router.Navigation],
|
mixins: [Router.Navigation],
|
||||||
getInitialState: function () {
|
getInitialState: function () {
|
||||||
return {
|
return {
|
||||||
saveVMOnQuit: localStorage.getItem('settings.saveVMOnQuit') === 'true',
|
closeVMOnQuit: localStorage.getItem('settings.closeVMOnQuit') === 'true',
|
||||||
metricsEnabled: metrics.enabled()
|
metricsEnabled: metrics.enabled()
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -21,14 +21,15 @@ var Preferences = React.createClass({
|
||||||
this.goBack();
|
this.goBack();
|
||||||
metrics.track('Went Back From Preferences');
|
metrics.track('Went Back From Preferences');
|
||||||
},
|
},
|
||||||
handleChangeSaveVMOnQuit: function (e) {
|
handleChangeCloseVMOnQuit: function (e) {
|
||||||
var checked = e.target.checked;
|
var checked = e.target.checked;
|
||||||
this.setState({
|
this.setState({
|
||||||
saveVMOnQuit: checked
|
closeVMOnQuit: checked
|
||||||
});
|
});
|
||||||
|
localStorage.setItem('settings.closeVMOnQuit', checked);
|
||||||
ipc.send('vm', checked);
|
ipc.send('vm', checked);
|
||||||
metrics.track('Toggled Save VM On Quit', {
|
metrics.track('Toggled Close VM On Quit', {
|
||||||
save: checked
|
close: checked
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleChangeMetricsEnabled: function (e) {
|
handleChangeMetricsEnabled: function (e) {
|
||||||
|
@ -49,10 +50,10 @@ var Preferences = React.createClass({
|
||||||
<div className="title">VM Settings</div>
|
<div className="title">VM Settings</div>
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<div className="option-name">
|
<div className="option-name">
|
||||||
Save Linux VM state on closing Kitematic
|
Shut Down Linux VM on closing Kitematic
|
||||||
</div>
|
</div>
|
||||||
<div className="option-value">
|
<div className="option-value">
|
||||||
<input type="checkbox" checked={this.state.saveVMOnQuit} onChange={this.handleChangeSaveVMOnQuit}/>
|
<input type="checkbox" checked={this.state.closeVMOnQuit} onChange={this.handleChangeCloseVMOnQuit}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="title">App Settings</div>
|
<div className="title">App Settings</div>
|
||||||
|
|
|
@ -27,13 +27,13 @@ var App = React.createClass({
|
||||||
var routes = (
|
var routes = (
|
||||||
<Route name="app" path="/" handler={App}>
|
<Route name="app" path="/" handler={App}>
|
||||||
<Route name="containers" handler={Containers}>
|
<Route name="containers" handler={Containers}>
|
||||||
<Route name="containerDetails" path="/containers/:name" handler={ContainerDetails}>
|
<Route name="containerDetails" path="containers/:name" handler={ContainerDetails}>
|
||||||
<Route name="containerHome" path="/containers/:name/home" handler={ContainerHome} />
|
<Route name="containerHome" path="containers/:name/home" handler={ContainerHome} />
|
||||||
<Route name="containerLogs" path="/containers/:name/logs" handler={ContainerLogs}/>
|
<Route name="containerLogs" path="containers/:name/logs" handler={ContainerLogs}/>
|
||||||
<Route name="containerSettings" path="/containers/:name/settings" handler={ContainerSettings}>
|
<Route name="containerSettings" path="containers/:name/settings" handler={ContainerSettings}>
|
||||||
<Route name="containerSettingsGeneral" path="/containers/:name/settings/general" handler={ContainerSettingsGeneral}/>
|
<Route name="containerSettingsGeneral" path="containers/:name/settings/general" handler={ContainerSettingsGeneral}/>
|
||||||
<Route name="containerSettingsPorts" path="/containers/:name/settings/ports" handler={ContainerSettingsPorts}/>
|
<Route name="containerSettingsPorts" path="containers/:name/settings/ports" handler={ContainerSettingsPorts}/>
|
||||||
<Route name="containerSettingsVolumes" path="/containers/:name/settings/volumes" handler={ContainerSettingsVolumes}/>
|
<Route name="containerSettingsVolumes" path="containers/:name/settings/volumes" handler={ContainerSettingsVolumes}/>
|
||||||
</Route>
|
</Route>
|
||||||
</Route>
|
</Route>
|
||||||
<Route name="preferences" path="/preferences" handler={Preferences}/>
|
<Route name="preferences" path="/preferences" handler={Preferences}/>
|
||||||
|
|
|
@ -3,7 +3,7 @@ var _ = require('underscore');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var Promise = require('bluebird');
|
var Promise = require('bluebird');
|
||||||
var boot2docker = require('./Boot2Docker');
|
var machine = require('./DockerMachine');
|
||||||
var virtualBox = require('./VirtualBox');
|
var virtualBox = require('./VirtualBox');
|
||||||
var setupUtil = require('./SetupUtil');
|
var setupUtil = require('./SetupUtil');
|
||||||
var util = require('./Util');
|
var util = require('./Util');
|
||||||
|
@ -36,9 +36,8 @@ var _steps = [{
|
||||||
percent: 0,
|
percent: 0,
|
||||||
seconds: 5,
|
seconds: 5,
|
||||||
run: Promise.coroutine(function* (progressCallback) {
|
run: Promise.coroutine(function* (progressCallback) {
|
||||||
var packagejson = util.packagejson();
|
var cmd = setupUtil.copyBinariesCmd() + ' && ' + setupUtil.fixBinariesCmd();
|
||||||
var cmd = util.copyBinariesCmd() + ' && ' + util.fixBinariesCmd();
|
if (!virtualBox.installed()) {
|
||||||
if (!virtualBox.installed() || setupUtil.compareVersions(yield virtualBox.version(), packagejson['virtualbox-required-version']) < 0) {
|
|
||||||
yield virtualBox.killall();
|
yield virtualBox.killall();
|
||||||
cmd += ' && ' + setupUtil.installVirtualBoxCmd();
|
cmd += ' && ' + setupUtil.installVirtualBoxCmd();
|
||||||
} else {
|
} else {
|
||||||
|
@ -55,45 +54,35 @@ var _steps = [{
|
||||||
})
|
})
|
||||||
}, {
|
}, {
|
||||||
name: 'init',
|
name: 'init',
|
||||||
title: 'Setting up Docker VM',
|
title: 'Starting Docker VM',
|
||||||
message: 'To run Docker containers on your computer, we are setting up a Linux virtual machine provided by boot2docker.',
|
message: 'To run Docker containers on your computer, Kitematic is starting a Linux virutal machine. This may take a minute...',
|
||||||
totalPercent: 15,
|
totalPercent: 60,
|
||||||
percent: 0,
|
percent: 0,
|
||||||
seconds: 11,
|
seconds: 52,
|
||||||
run: Promise.coroutine(function* (progressCallback) {
|
run: Promise.coroutine(function* (progressCallback) {
|
||||||
setupUtil.simulateProgress(this.seconds, progressCallback);
|
setupUtil.simulateProgress(this.seconds, progressCallback);
|
||||||
yield virtualBox.vmdestroy('kitematic-vm');
|
yield virtualBox.vmdestroy('kitematic-vm');
|
||||||
var exists = yield boot2docker.exists();
|
var exists = yield machine.exists();
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
yield boot2docker.init();
|
yield machine.create();
|
||||||
|
return;
|
||||||
|
} else if ((yield machine.state()) === 'Error') {
|
||||||
|
try {
|
||||||
|
yield machine.rm();
|
||||||
|
} catch (err) {}
|
||||||
|
yield machine.create();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!boot2docker.haskeys()) {
|
var isoversion = machine.isoversion();
|
||||||
throw new Error('Boot2Docker SSH keys do not exist. Fix this by removing the existing Boot2Docker VM setup and re-run the installer. This usually occurs because an old version of Boot2Docker is installed.');
|
var packagejson = util.packagejson();
|
||||||
}
|
if (!isoversion || setupUtil.compareVersions(isoversion, packagejson['docker-version']) < 0) {
|
||||||
|
console.log('upgrading');
|
||||||
var isoversion = boot2docker.isoversion();
|
yield machine.stop();
|
||||||
if (!isoversion || setupUtil.compareVersions(isoversion, boot2docker.version()) < 0) {
|
yield machine.upgrade();
|
||||||
yield boot2docker.stop();
|
|
||||||
yield boot2docker.upgrade();
|
|
||||||
}
|
}
|
||||||
|
yield machine.start();
|
||||||
})
|
})
|
||||||
}, {
|
|
||||||
name: 'start',
|
|
||||||
title: 'Starting Docker VM',
|
|
||||||
message: "Kitematic is starting the boot2docker VM. This may take about a minute.",
|
|
||||||
totalPercent: 45,
|
|
||||||
percent: 0,
|
|
||||||
seconds: 35,
|
|
||||||
run: function (progressCallback) {
|
|
||||||
setupUtil.simulateProgress(this.seconds, progressCallback);
|
|
||||||
return boot2docker.waitstatus('saving').then(boot2docker.status).then(status => {
|
|
||||||
if (status !== 'running') {
|
|
||||||
return boot2docker.start();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
var SetupStore = assign(Object.create(EventEmitter.prototype), {
|
var SetupStore = assign(Object.create(EventEmitter.prototype), {
|
||||||
|
@ -140,18 +129,18 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), {
|
||||||
return Promise.resolve(_requiredSteps);
|
return Promise.resolve(_requiredSteps);
|
||||||
}
|
}
|
||||||
var packagejson = util.packagejson();
|
var packagejson = util.packagejson();
|
||||||
var isoversion = boot2docker.isoversion();
|
var isoversion = machine.isoversion();
|
||||||
var required = {};
|
var required = {};
|
||||||
var vboxfile = path.join(util.supportDir(), packagejson['virtualbox-filename']);
|
var vboxfile = path.join(util.supportDir(), packagejson['virtualbox-filename']);
|
||||||
var vboxInstallRequired = virtualBox.installed() ? setupUtil.compareVersions(yield virtualBox.version(), packagejson['virtualbox-required-version']) < 0 : true;
|
required.download = !virtualBox.installed() && (!fs.existsSync(vboxfile) || setupUtil.checksum(vboxfile) !== packagejson['virtualbox-checksum']);
|
||||||
required.download = vboxInstallRequired && (!fs.existsSync(vboxfile) || setupUtil.checksum(vboxfile) !== packagejson['virtualbox-checksum']);
|
required.install = !virtualBox.installed() || setupUtil.needsBinaryFix();
|
||||||
required.install = vboxInstallRequired || setupUtil.needsBinaryFix();
|
required.init = !(yield machine.exists()) || (yield machine.state()) !== 'Running' || !isoversion || setupUtil.compareVersions(isoversion, packagejson['docker-version']) < 0;
|
||||||
required.init = !(yield boot2docker.exists()) || !isoversion || setupUtil.compareVersions(isoversion, boot2docker.version()) < 0;
|
|
||||||
required.start = required.install || required.init || (yield boot2docker.status()) !== 'running';
|
|
||||||
|
|
||||||
var exists = yield boot2docker.exists();
|
var exists = yield machine.exists();
|
||||||
if (exists) {
|
if (isoversion && setupUtil.compareVersions(isoversion, packagejson['docker-version']) < 0) {
|
||||||
this.steps().start.seconds = 13;
|
this.steps().init.seconds = 33;
|
||||||
|
} else if (exists && (yield machine.state()) !== 'Error') {
|
||||||
|
this.steps().init.seconds = 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
_requiredSteps = _steps.filter(function (step) {
|
_requiredSteps = _steps.filter(function (step) {
|
||||||
|
@ -164,7 +153,7 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
if (setupUtil.shouldUpdateBinaries()) {
|
if (setupUtil.shouldUpdateBinaries()) {
|
||||||
return util.exec(util.copyBinariesCmd());
|
return util.exec(setupUtil.copyBinariesCmd());
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
},
|
},
|
||||||
|
@ -194,9 +183,10 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), {
|
||||||
metrics.track('Setup Failed', {
|
metrics.track('Setup Failed', {
|
||||||
step: step.name
|
step: step.name
|
||||||
});
|
});
|
||||||
console.log('Setup encountered an error.');
|
|
||||||
console.log(err);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
|
console.log('Setup encountered an error.');
|
||||||
|
console.log(err);
|
||||||
|
console.log(err.stack);
|
||||||
_error = err;
|
_error = err;
|
||||||
this.emit(this.ERROR_EVENT);
|
this.emit(this.ERROR_EVENT);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -12,7 +12,7 @@ var SetupUtil = {
|
||||||
if (!fs.existsSync('/usr/local') || !fs.existsSync('/usr/local/bin')) {
|
if (!fs.existsSync('/usr/local') || !fs.existsSync('/usr/local/bin')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!fs.existsSync('/usr/local/bin/docker') && !fs.existsSync('/usr/local/bin/boot2docker')) {
|
if (!fs.existsSync('/usr/local/bin/docker') && !fs.existsSync('/usr/local/bin/docker-machine')) {
|
||||||
return fs.statSync('/usr/local/bin').gid !== 80 || fs.statSync('/usr/local/bin').uid !== process.getuid();
|
return fs.statSync('/usr/local/bin').gid !== 80 || fs.statSync('/usr/local/bin').uid !== process.getuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,28 +20,50 @@ var SetupUtil = {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fs.existsSync('/usr/local/bin/boot2docker') && (fs.statSync('/usr/local/bin/boot2docker').gid !== 80 || fs.statSync('/usr/local/bin/boot2docker').uid !== process.getuid())) {
|
if (fs.existsSync('/usr/local/bin/docker-machine') && (fs.statSync('/usr/local/bin/docker-machine').gid !== 80 || fs.statSync('/usr/local/bin/docker-machine').uid !== process.getuid())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
copycmd: function (src, dest) {
|
||||||
|
return ['rm', '-f', dest, '&&', 'cp', src, dest];
|
||||||
|
},
|
||||||
|
escapePath: function (str) {
|
||||||
|
return str.replace(/ /g, '\\ ').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
|
||||||
|
},
|
||||||
shouldUpdateBinaries: function () {
|
shouldUpdateBinaries: function () {
|
||||||
var packagejson = util.packagejson();
|
var packagejson = util.packagejson();
|
||||||
return !fs.existsSync('/usr/local/bin/docker') ||
|
return !fs.existsSync('/usr/local/bin/docker') ||
|
||||||
!fs.existsSync('/usr/local/bin/boot2docker') ||
|
!fs.existsSync('/usr/local/bin/docker-machine') ||
|
||||||
this.checksum('/usr/local/bin/boot2docker') !== this.checksum(path.join(util.resourceDir(), 'boot2docker-' + packagejson['boot2docker-version'])) ||
|
this.checksum('/usr/local/bin/docker-machine') !== this.checksum(path.join(util.resourceDir(), 'docker-machine-' + packagejson['docker-machine-version'])) ||
|
||||||
this.checksum('/usr/local/bin/docker') !== this.checksum(path.join(util.resourceDir(), 'docker-' + packagejson['docker-version']));
|
this.checksum('/usr/local/bin/docker') !== this.checksum(path.join(util.resourceDir(), 'docker-' + packagejson['docker-version']));
|
||||||
},
|
},
|
||||||
|
copyBinariesCmd: function () {
|
||||||
|
var packagejson = util.packagejson();
|
||||||
|
var cmd = ['mkdir', '-p', '/usr/local/bin'];
|
||||||
|
cmd.push('&&');
|
||||||
|
cmd.push.apply(cmd, this.copycmd(this.escapePath(path.join(util.resourceDir(), 'docker-machine-' + packagejson['docker-machine-version'])), '/usr/local/bin/docker-machine'));
|
||||||
|
cmd.push('&&');
|
||||||
|
cmd.push.apply(cmd, this.copycmd(this.escapePath(path.join(util.resourceDir(), 'docker-' + packagejson['docker-version'])), '/usr/local/bin/docker'));
|
||||||
|
return cmd.join(' ');
|
||||||
|
},
|
||||||
|
fixBinariesCmd: function () {
|
||||||
|
var cmd = [];
|
||||||
|
cmd.push.apply(cmd, ['chown', `${process.getuid()}:${80}`, this.escapePath(path.join('/usr/local/bin', 'docker-machine'))]);
|
||||||
|
cmd.push('&&');
|
||||||
|
cmd.push.apply(cmd, ['chown', `${process.getuid()}:${80}`, this.escapePath(path.join('/usr/local/bin', 'docker'))]);
|
||||||
|
return cmd.join(' ');
|
||||||
|
},
|
||||||
installVirtualBoxCmd: function () {
|
installVirtualBoxCmd: function () {
|
||||||
var packagejson = util.packagejson();
|
var packagejson = util.packagejson();
|
||||||
return `installer -pkg ${util.escapePath(path.join(util.supportDir(), packagejson['virtualbox-filename']))} -target /`;
|
return `installer -pkg ${this.escapePath(path.join(util.supportDir(), packagejson['virtualbox-filename']))} -target /`;
|
||||||
},
|
},
|
||||||
virtualBoxUrl: function () {
|
virtualBoxUrl: function () {
|
||||||
var packagejson = util.packagejson();
|
var packagejson = util.packagejson();
|
||||||
return `https://github.com/kitematic/virtualbox/releases/download/${packagejson['virtualbox-version']}/${packagejson['virtualbox-filename']}`;
|
return `https://github.com/kitematic/virtualbox/releases/download/${packagejson['virtualbox-version']}/${packagejson['virtualbox-filename']}`;
|
||||||
},
|
},
|
||||||
macSudoCmd: function (cmd) {
|
macSudoCmd: function (cmd) {
|
||||||
return `${util.escapePath(path.join(util.resourceDir(), 'macsudo'))} -p "Kitematic requires administrative privileges to install." sh -c \"${cmd}\"`;
|
return `${this.escapePath(path.join(util.resourceDir(), 'macsudo'))} -p "Kitematic requires administrative privileges to install." sh -c \"${cmd}\"`;
|
||||||
},
|
},
|
||||||
simulateProgress: function (estimateSeconds, progress) {
|
simulateProgress: function (estimateSeconds, progress) {
|
||||||
var times = _.range(0, estimateSeconds * 1000, 200);
|
var times = _.range(0, estimateSeconds * 1000, 200);
|
||||||
|
|
22
src/Util.js
|
@ -35,27 +35,5 @@ module.exports = {
|
||||||
packagejson: function () {
|
packagejson: function () {
|
||||||
return JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
return JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
||||||
},
|
},
|
||||||
copycmd: function (src, dest) {
|
|
||||||
return ['rm', '-f', dest, '&&', 'cp', src, dest];
|
|
||||||
},
|
|
||||||
copyBinariesCmd: function () {
|
|
||||||
var packagejson = this.packagejson();
|
|
||||||
var cmd = ['mkdir', '-p', '/usr/local/bin'];
|
|
||||||
cmd.push('&&');
|
|
||||||
cmd.push.apply(cmd, this.copycmd(this.escapePath(path.join(this.resourceDir(), 'boot2docker-' + packagejson['boot2docker-version'])), '/usr/local/bin/boot2docker'));
|
|
||||||
cmd.push('&&');
|
|
||||||
cmd.push.apply(cmd, this.copycmd(this.escapePath(path.join(this.resourceDir(), 'docker-' + packagejson['docker-version'])), '/usr/local/bin/docker'));
|
|
||||||
return cmd.join(' ');
|
|
||||||
},
|
|
||||||
fixBinariesCmd: function () {
|
|
||||||
var cmd = [];
|
|
||||||
cmd.push.apply(cmd, ['chown', `${process.getuid()}:${80}`, this.escapePath(path.join('/usr/local/bin', 'boot2docker'))]);
|
|
||||||
cmd.push('&&');
|
|
||||||
cmd.push.apply(cmd, ['chown', `${process.getuid()}:${80}`, this.escapePath(path.join('/usr/local/bin', 'docker'))]);
|
|
||||||
return cmd.join(' ');
|
|
||||||
},
|
|
||||||
escapePath: function (str) {
|
|
||||||
return str.replace(/ /g, '\\ ').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
|
|
||||||
},
|
|
||||||
webPorts: ['80', '8000', '8080', '3000', '5000', '2368', '9200', '8983']
|
webPorts: ['80', '8000', '8080', '3000', '5000', '2368', '9200', '8983']
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,6 +48,10 @@
|
||||||
background-color: @traffic-light-green;
|
background-color: @traffic-light-green;
|
||||||
border-color: @traffic-light-green-border;
|
border-color: @traffic-light-green-border;
|
||||||
}
|
}
|
||||||
|
&.button-fullscreenclose {
|
||||||
|
background-color: @traffic-light-green;
|
||||||
|
border-color: @traffic-light-green-border;
|
||||||
|
}
|
||||||
&.disabled {
|
&.disabled {
|
||||||
background-color: @traffic-light-gray;
|
background-color: @traffic-light-gray;
|
||||||
border-color: @traffic-light-gray-border;
|
border-color: @traffic-light-gray-border;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
@traffic-light-red-border: #E33E32;
|
@traffic-light-red-border: #E33E32;
|
||||||
@traffic-light-yellow: #FFBE05;
|
@traffic-light-yellow: #FFBE05;
|
||||||
@traffic-light-yellow-border: #E2A100;
|
@traffic-light-yellow-border: #E2A100;
|
||||||
@traffic-light-gray: #DDDDDD;
|
@traffic-light-gray: #E5E5E5;
|
||||||
@traffic-light-gray-border: #D3D3D3;
|
@traffic-light-gray-border: #D3D3D3;
|
||||||
|
|
||||||
@gray-darkest: #253237;
|
@gray-darkest: #253237;
|
||||||
|
|
14
util/deps
|
@ -1,18 +1,18 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
BASE=$DIR/..
|
BASE=$DIR/..
|
||||||
BOOT2DOCKER_CLI_VERSION=$(node -pe "JSON.parse(process.argv[1])['boot2docker-version']" "$(cat $BASE/package.json)")
|
DOCKER_MACHINE_CLI_VERSION=$(node -pe "JSON.parse(process.argv[1])['docker-machine-version']" "$(cat $BASE/package.json)")
|
||||||
BOOT2DOCKER_CLI_FILE=boot2docker-$BOOT2DOCKER_CLI_VERSION
|
DOCKER_MACHINE_CLI_FILE=docker-machine-$DOCKER_MACHINE_CLI_VERSION
|
||||||
DOCKER_CLI_VERSION=$(node -pe "JSON.parse(process.argv[1])['docker-version']" "$(cat $BASE/package.json)")
|
DOCKER_CLI_VERSION=$(node -pe "JSON.parse(process.argv[1])['docker-version']" "$(cat $BASE/package.json)")
|
||||||
DOCKER_CLI_FILE=docker-$DOCKER_CLI_VERSION
|
DOCKER_CLI_FILE=docker-$DOCKER_CLI_VERSION
|
||||||
|
|
||||||
pushd $BASE/resources > /dev/null
|
pushd $BASE/resources > /dev/null
|
||||||
|
|
||||||
if [ ! -f $BOOT2DOCKER_CLI_FILE ]; then
|
if [ ! -f $DOCKER_MACHINE_CLI_FILE ]; then
|
||||||
echo "-----> Downloading Boot2docker CLI..."
|
echo "-----> Downloading Docker Machine CLI..."
|
||||||
rm -rf boot2docker-*
|
rm -rf docker-machine*
|
||||||
curl -L -o $BOOT2DOCKER_CLI_FILE https://github.com/boot2docker/boot2docker-cli/releases/download/v$BOOT2DOCKER_CLI_VERSION/boot2docker-v$BOOT2DOCKER_CLI_VERSION-darwin-amd64
|
curl -L -o $DOCKER_MACHINE_CLI_FILE https://github.com/docker/machine/releases/download/v$DOCKER_MACHINE_CLI_VERSION/docker-machine_darwin-amd64
|
||||||
chmod +x $BOOT2DOCKER_CLI_FILE
|
chmod +x $DOCKER_MACHINE_CLI_FILE
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f $DOCKER_CLI_FILE ]; then
|
if [ ! -f $DOCKER_CLI_FILE ]; then
|
||||||
|
|
|
@ -2,12 +2,10 @@
|
||||||
|
|
||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
sudo rm -f /usr/local/bin/docker
|
sudo rm -f /usr/local/bin/docker*
|
||||||
sudo rm -f /usr/local/bin/boot2docker
|
|
||||||
pkill VirtualBox
|
pkill VirtualBox
|
||||||
pkill VBox
|
pkill VBox
|
||||||
rm -rf ~/Library/Application\ Support/Kitematic/
|
rm -rf ~/Library/Application\ Support/Kitematic/
|
||||||
rm -rf ~/.boot2docker
|
rm -rf ~/.docker
|
||||||
rm -rf ~/VirtualBox\ VMs/boot2docker-vm
|
|
||||||
rm -rf ~/Library/VirtualBox/
|
rm -rf ~/Library/VirtualBox/
|
||||||
$DIR/VirtualBox_Uninstall.tool
|
$DIR/VirtualBox_Uninstall.tool
|
||||||
|
|