mirror of https://github.com/docker/docs.git
commit
82551ae9d3
|
@ -2,6 +2,7 @@
|
||||||
.swp
|
.swp
|
||||||
build
|
build
|
||||||
dist
|
dist
|
||||||
|
installer
|
||||||
node_modules
|
node_modules
|
||||||
coverage
|
coverage
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
|
|
|
@ -0,0 +1,308 @@
|
||||||
|
var path = require('path');
|
||||||
|
var execFile = require('child_process').execFile;
|
||||||
|
var packagejson = require('./package.json');
|
||||||
|
var electron = require('electron-prebuilt');
|
||||||
|
|
||||||
|
var WINDOWS_DOCKER_URL = 'https://get.docker.com/builds/Windows/x86_64/docker-1.6.2.exe';
|
||||||
|
var DARWIN_DOCKER_URL = 'https://get.docker.com/builds/Darwin/x86_64/docker-' + packagejson['docker-version'];
|
||||||
|
var WINDOWS_DOCKER_MACHINE_URL = 'https://github.com/docker/machine/releases/download/v' + packagejson['docker-machine-version'] + '/docker-machine_windows-amd64.exe';
|
||||||
|
var DARWIN_DOCKER_MACHINE_URL = 'https://github.com/docker/machine/releases/download/v' + packagejson['docker-machine-version'] + '/docker-machine_darwin-amd64';
|
||||||
|
var DARWIN_COMPOSE_URL = 'https://github.com/docker/compose/releases/download/' + packagejson['docker-compose-version'] + '/docker-compose-Darwin-x86_64';
|
||||||
|
var BOOT2DOCKER_ISO_URL = 'https://github.com/boot2docker/boot2docker/releases/download/v' + packagejson['docker-version'] + '/boot2docker.iso';
|
||||||
|
|
||||||
|
module.exports = function (grunt) {
|
||||||
|
require('load-grunt-tasks')(grunt);
|
||||||
|
var target = grunt.option('target') || 'development';
|
||||||
|
var beta = grunt.option('beta') || false;
|
||||||
|
var env = process.env;
|
||||||
|
env.NODE_PATH = '..:' + env.NODE_PATH;
|
||||||
|
env.NODE_ENV = target;
|
||||||
|
|
||||||
|
var version = function (str) {
|
||||||
|
var match = str.match(/(\d+\.\d+\.\d+)/);
|
||||||
|
return match ? match[1] : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
grunt.registerMultiTask('download-binary', 'Downloads binary unless version up to date', function () {
|
||||||
|
var target = grunt.task.current.target;
|
||||||
|
var done = this.async();
|
||||||
|
var config = grunt.config('download-binary')[target];
|
||||||
|
execFile(config.binary, ['--version'], function (err, stdout) {
|
||||||
|
var currentVersion = version(stdout);
|
||||||
|
if (!currentVersion || currentVersion !== version(config.version)) {
|
||||||
|
grunt.task.run('curl:' + target);
|
||||||
|
grunt.task.run('chmod');
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var APPNAME = beta ? 'Kitematic (Beta)' : 'Kitematic';
|
||||||
|
var OSX_OUT = './dist/osx';
|
||||||
|
var OSX_FILENAME = OSX_OUT + '/' + APPNAME + '.app';
|
||||||
|
|
||||||
|
grunt.initConfig({
|
||||||
|
IDENTITY: 'Developer ID Application: Docker Inc',
|
||||||
|
APPNAME: APPNAME,
|
||||||
|
OSX_OUT: OSX_OUT,
|
||||||
|
OSX_FILENAME: OSX_FILENAME,
|
||||||
|
OSX_FILENAME_ESCAPED: OSX_FILENAME.replace(' ', '\\ ').replace('(','\\(').replace(')','\\)'),
|
||||||
|
|
||||||
|
// electron
|
||||||
|
electron: {
|
||||||
|
windows: {
|
||||||
|
options: {
|
||||||
|
name: '<%= APPNAME %>',
|
||||||
|
dir: 'build/',
|
||||||
|
out: 'dist/',
|
||||||
|
version: packagejson['electron-version'],
|
||||||
|
platform: 'win32',
|
||||||
|
arch: 'x64',
|
||||||
|
asar: true,
|
||||||
|
icon: 'util/kitematic.ico'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
osx: {
|
||||||
|
options: {
|
||||||
|
name: '<%= APPNAME %>',
|
||||||
|
dir: 'build/',
|
||||||
|
out: '<%= OSX_OUT %>',
|
||||||
|
version: packagejson['electron-version'],
|
||||||
|
platform: 'darwin',
|
||||||
|
arch: 'x64',
|
||||||
|
asar: true,
|
||||||
|
'app-bundle-id': 'com.kitematic.kitematic'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
rcedit: {
|
||||||
|
exes: {
|
||||||
|
files: [{
|
||||||
|
expand: true,
|
||||||
|
cwd: 'dist/Kitematic-win32',
|
||||||
|
src: ['Kitematic.exe']
|
||||||
|
}],
|
||||||
|
options: {
|
||||||
|
icon: 'util/kitematic.ico',
|
||||||
|
'file-version': packagejson.version,
|
||||||
|
'product-version': packagejson.version,
|
||||||
|
'version-string': {
|
||||||
|
'CompanyName': 'Docker, Inc',
|
||||||
|
'ProductVersion': packagejson.version,
|
||||||
|
'ProductName': 'Kitematic',
|
||||||
|
'FileDescription': 'Kitematic',
|
||||||
|
'InternalName': 'Kitematic.exe',
|
||||||
|
'OriginalFilename': 'Kitematic.exe',
|
||||||
|
'LegalCopyright': 'Copyright 2015 Docker Inc. All rights reserved.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
'create-windows-installer': {
|
||||||
|
appDirectory: 'dist/Kitematic-win32/',
|
||||||
|
authors: 'Docker Inc.',
|
||||||
|
loadingGif: 'util/loading.gif',
|
||||||
|
setupIcon: 'util/kitematic.ico',
|
||||||
|
description: 'Kitematic',
|
||||||
|
title: 'Kitematic',
|
||||||
|
version: packagejson.version
|
||||||
|
},
|
||||||
|
|
||||||
|
// docker binaries
|
||||||
|
'download-binary': {
|
||||||
|
docker: {
|
||||||
|
version: packagejson['docker-version'],
|
||||||
|
binary: path.join('resources', 'docker'),
|
||||||
|
download: 'curl:docker'
|
||||||
|
},
|
||||||
|
'docker-machine': {
|
||||||
|
version: packagejson['docker-machine-version'],
|
||||||
|
binary: path.join('resources', 'docker-machine'),
|
||||||
|
download: 'curl:docker-machine'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// images
|
||||||
|
copy: {
|
||||||
|
dev: {
|
||||||
|
files: [{
|
||||||
|
expand: true,
|
||||||
|
cwd: '.',
|
||||||
|
src: ['package.json', 'settings.json', 'index.html'],
|
||||||
|
dest: 'build/'
|
||||||
|
}, {
|
||||||
|
expand: true,
|
||||||
|
cwd: 'images/',
|
||||||
|
src: ['**/*'],
|
||||||
|
dest: 'build/'
|
||||||
|
}, {
|
||||||
|
expand: true,
|
||||||
|
cwd: 'fonts/',
|
||||||
|
src: ['**/*'],
|
||||||
|
dest: 'build/'
|
||||||
|
}, {
|
||||||
|
cwd: 'node_modules/',
|
||||||
|
src: Object.keys(packagejson.dependencies).map(function (dep) { return dep + '/**/*';}),
|
||||||
|
dest: 'build/node_modules/',
|
||||||
|
expand: true
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
windows: {
|
||||||
|
files: [{
|
||||||
|
expand: true,
|
||||||
|
cwd: 'resources',
|
||||||
|
src: ['docker*', 'boot2docker.iso', 'ssh.exe', 'OPENSSH_LICENSE', 'msys-*'],
|
||||||
|
dest: 'dist/Kitematic-win32/resources/resources/'
|
||||||
|
}],
|
||||||
|
options: {
|
||||||
|
mode: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
osx: {
|
||||||
|
files: [{
|
||||||
|
expand: true,
|
||||||
|
cwd: 'resources',
|
||||||
|
src: ['docker*', 'boot2docker.iso', 'macsudo', 'terminal'],
|
||||||
|
dest: '<%= OSX_FILENAME %>/Contents/Resources/resources/'
|
||||||
|
}, {
|
||||||
|
src: 'util/kitematic.icns',
|
||||||
|
dest: '<%= OSX_FILENAME %>/Contents/Resources/atom.icns'
|
||||||
|
}],
|
||||||
|
options: {
|
||||||
|
mode: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
rename: {
|
||||||
|
installer: {
|
||||||
|
src: 'installer/Setup.exe',
|
||||||
|
dest: 'installer/KitematicSetup-' + packagejson.version + '.exe'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// download binaries
|
||||||
|
curl: {
|
||||||
|
docker: {
|
||||||
|
src: process.platform === 'win32' ? WINDOWS_DOCKER_URL : DARWIN_DOCKER_URL,
|
||||||
|
dest: process.platform === 'win32' ? path.join('resources', 'docker.exe') : path.join('resources', 'docker')
|
||||||
|
},
|
||||||
|
'docker-machine': {
|
||||||
|
src: process.platform === 'win32' ? WINDOWS_DOCKER_MACHINE_URL : DARWIN_DOCKER_MACHINE_URL,
|
||||||
|
dest: process.platform === 'win32' ? path.join('resources', 'docker-machine.exe') : path.join('resources', 'docker-machine')
|
||||||
|
},
|
||||||
|
'docker-compose': {
|
||||||
|
src: DARWIN_COMPOSE_URL,
|
||||||
|
dest: 'resources/docker-compose'
|
||||||
|
},
|
||||||
|
'boot2docker-iso': {
|
||||||
|
src: BOOT2DOCKER_ISO_URL,
|
||||||
|
dest: path.join('resources', 'boot2docker-' + packagejson['docker-version'])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
chmod: {
|
||||||
|
binaries: {
|
||||||
|
options: {
|
||||||
|
mode: '755'
|
||||||
|
},
|
||||||
|
src: ['resources/docker*']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// styles
|
||||||
|
less: {
|
||||||
|
options: {
|
||||||
|
sourceMapFileInline: true
|
||||||
|
},
|
||||||
|
dist: {
|
||||||
|
files: {
|
||||||
|
'build/main.css': 'styles/main.less'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// javascript
|
||||||
|
babel: {
|
||||||
|
options: {
|
||||||
|
sourceMap: 'inline',
|
||||||
|
blacklist: 'regenerator'
|
||||||
|
},
|
||||||
|
dist: {
|
||||||
|
files: [{
|
||||||
|
expand: true,
|
||||||
|
cwd: 'src/',
|
||||||
|
src: ['**/*.js'],
|
||||||
|
dest: 'build/',
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
shell: {
|
||||||
|
electron: {
|
||||||
|
command: electron + ' ' + 'build',
|
||||||
|
options: {
|
||||||
|
async: true,
|
||||||
|
execOptions: {
|
||||||
|
env: env
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sign: {
|
||||||
|
options: {
|
||||||
|
failOnError: false,
|
||||||
|
},
|
||||||
|
command: [
|
||||||
|
'codesign --deep -v -f -s "<%= IDENTITY %>" <%= OSX_FILENAME_ESCAPED %>/Contents/Frameworks/*',
|
||||||
|
'codesign -v -f -s "<%= IDENTITY %>" <%= OSX_FILENAME_ESCAPED %>',
|
||||||
|
'codesign -vvv --display <%= OSX_FILENAME_ESCAPED %>',
|
||||||
|
'codesign -v --verify <%= OSX_FILENAME_ESCAPED %>',
|
||||||
|
].join(' && '),
|
||||||
|
},
|
||||||
|
zip: {
|
||||||
|
command: 'ditto -c -k --sequesterRsrc --keepParent <%= OSX_FILENAME_ESCAPED %> <%= OSX_OUT %>/Kitematic-' + packagejson.version + '.zip',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
clean: {
|
||||||
|
release: ['build/', 'dist/', 'installer/'],
|
||||||
|
},
|
||||||
|
|
||||||
|
// livereload
|
||||||
|
watchChokidar: {
|
||||||
|
options: {
|
||||||
|
spawn: true
|
||||||
|
},
|
||||||
|
livereload: {
|
||||||
|
options: {livereload: true},
|
||||||
|
files: ['build/**/*']
|
||||||
|
},
|
||||||
|
js: {
|
||||||
|
files: ['src/**/*.js'],
|
||||||
|
tasks: ['newer:babel']
|
||||||
|
},
|
||||||
|
less: {
|
||||||
|
files: ['styles/**/*.less'],
|
||||||
|
tasks: ['less']
|
||||||
|
},
|
||||||
|
copy: {
|
||||||
|
files: ['images/*', 'index.html', 'fonts/*'],
|
||||||
|
tasks: ['newer:copy:dev']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
grunt.registerTask('default', ['download-binary', 'newer:babel', 'less', 'newer:copy:dev', 'shell:electron', 'watchChokidar']);
|
||||||
|
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
grunt.registerTask('release', ['clean', 'download-binary', 'babel', 'less', 'copy:dev', 'electron:windows', 'copy:windows', 'rcedit:exes', 'create-windows-installer', 'rename:installer']);
|
||||||
|
} else {
|
||||||
|
grunt.registerTask('release', ['clean', 'download-binary', 'babel', 'less', 'copy:dev', 'electron:osx', 'copy:osx', 'shell:sign', 'shell:zip']);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on('SIGINT', function () {
|
||||||
|
grunt.task.run(['shell:electron:kill']);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
};
|
47
package.json
47
package.json
|
@ -1,23 +1,22 @@
|
||||||
{
|
{
|
||||||
"name": "Kitematic",
|
"name": "Kitematic",
|
||||||
"version": "0.6.6",
|
"version": "0.6.7",
|
||||||
"author": "Kitematic",
|
"author": "Kitematic",
|
||||||
"description": "Simple Docker Container management for Mac OS X.",
|
"description": "Simple Docker Container management for Mac OS X.",
|
||||||
"homepage": "https://kitematic.com/",
|
"homepage": "https://kitematic.com/",
|
||||||
"main": "build/browser.js",
|
"main": "browser.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git@github.com:kitematic/kitematic.git"
|
"url": "git@github.com:kitematic/kitematic.git"
|
||||||
},
|
},
|
||||||
"bugs": "https://github.com/kitematic/kitematic/issues",
|
"bugs": "https://github.com/kitematic/kitematic/issues",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "gulp",
|
"start": "grunt",
|
||||||
"test": "jest -c jest-unit.json",
|
"test": "jest -c jest-unit.json",
|
||||||
"integration": "jest -c jest-integration.json",
|
"integration": "jest -c jest-integration.json",
|
||||||
"release": "gulp release",
|
"release": "grunt release",
|
||||||
"release:beta": "gulp release --beta",
|
"release:beta": "grunt release --beta=true",
|
||||||
"lint": "jsxhint src",
|
"lint": "jsxhint src"
|
||||||
"reset": "gulp reset"
|
|
||||||
},
|
},
|
||||||
"licenses": [
|
"licenses": [
|
||||||
{
|
{
|
||||||
|
@ -67,25 +66,31 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel": "^5.1.10",
|
"babel": "^5.1.10",
|
||||||
"babel-jest": "^5.2.0",
|
"babel-jest": "^5.2.0",
|
||||||
"gulp": "^3.8.11",
|
"electron-prebuilt": "^0.27.3",
|
||||||
"gulp-babel": "^5.1.0",
|
"grunt": "^0.4.5",
|
||||||
"gulp-changed": "^1.2.1",
|
"grunt-babel": "^5.0.1",
|
||||||
"gulp-concat": "^2.5.2",
|
"grunt-chmod": "^1.0.3",
|
||||||
"gulp-cssmin": "^0.1.6",
|
"grunt-cli": "^0.1.13",
|
||||||
"gulp-download-electron": "^0.0.5",
|
"grunt-contrib-clean": "^0.6.0",
|
||||||
"gulp-if": "^1.2.5",
|
"grunt-contrib-copy": "^0.8.0",
|
||||||
"gulp-insert": "^0.4.0",
|
"grunt-contrib-less": "^1.0.1",
|
||||||
"gulp-less": "^3.0.2",
|
"grunt-contrib-watch-chokidar": "^1.0.0",
|
||||||
"gulp-livereload": "^3.8.0",
|
"grunt-curl": "^2.2.0",
|
||||||
"gulp-plumber": "^1.0.0",
|
"grunt-download-electron": "^2.1.1",
|
||||||
"gulp-shell": "^0.4.1",
|
"grunt-electron": "^1.0.0",
|
||||||
"gulp-sourcemaps": "^1.5.2",
|
"grunt-electron-installer": "^0.33.0",
|
||||||
"gulp-util": "^3.0.4",
|
"grunt-newer": "^1.1.1",
|
||||||
|
"grunt-rcedit": "^0.3.1",
|
||||||
|
"grunt-rename": "^0.1.4",
|
||||||
|
"grunt-shell": "^1.1.2",
|
||||||
|
"grunt-shell-spawn": "^0.3.8",
|
||||||
"jest-cli": "^0.4.5",
|
"jest-cli": "^0.4.5",
|
||||||
"jsxhint": "^0.14.0",
|
"jsxhint": "^0.14.0",
|
||||||
|
"load-grunt-tasks": "^3.2.0",
|
||||||
"minimist": "^1.1.1",
|
"minimist": "^1.1.1",
|
||||||
"react-tools": "^0.13.1",
|
"react-tools": "^0.13.1",
|
||||||
"run-sequence": "^1.0.2",
|
"run-sequence": "^1.0.2",
|
||||||
|
"shell-escape": "^0.2.0",
|
||||||
"source-map-support": "^0.2.10"
|
"source-map-support": "^0.2.10"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
Kitematic includes (but does not link to) various DLLs included with the msysgit Git-1.9.5-preview20150319 distribution. Included is the MSYS runtime license.
|
||||||
|
Source is available online at https://github.com/msysgit/git/tree/v1.9.5.msysgit.1
|
||||||
|
|
||||||
|
File: MSYS_LICENSE
|
||||||
|
Copyright (C): 2001, Earnie Boyd <earnie@users.sf.net>
|
||||||
|
File $Revision$
|
||||||
|
File Revision $Date$
|
||||||
|
MSYS Release: 1.0.2
|
||||||
|
MSYS Release Date: November 30th, 2001
|
||||||
|
|
||||||
|
The software, both source and binary forms, are covered via differing licenses.
|
||||||
|
Each license has it's own set of rules so please make sure you read them
|
||||||
|
carefully to see how it applies to you, particularly if you're going to
|
||||||
|
distribute the software.
|
||||||
|
|
||||||
|
The MSYS runtime software source can found in the winsup/cygwin directory. The
|
||||||
|
existing code portions of this source is covered by the CYGWIN_LICENSE which can
|
||||||
|
be found in this directory in a file by the name of CYGWIN_LICENSE. MSYS
|
||||||
|
specific software code added regardless of existing license is covered by the
|
||||||
|
ESPL which can be found in a file by the same name.
|
|
@ -0,0 +1,205 @@
|
||||||
|
Kitematic includes OpenSSH ssh.exe from the msysgit distribution version Git-1.9.5-preview20150319, available online at https://github.com/msysgit/git/tree/v1.9.5.msysgit.1
|
||||||
|
|
||||||
|
This file is part of the OpenSSH software.
|
||||||
|
|
||||||
|
The licences which components of this software fall under are as
|
||||||
|
follows. First, we will summarize and say that all components
|
||||||
|
are under a BSD licence, or a licence more free than that.
|
||||||
|
|
||||||
|
OpenSSH contains no GPL code.
|
||||||
|
|
||||||
|
1)
|
||||||
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
|
* All rights reserved
|
||||||
|
*
|
||||||
|
* As far as I am concerned, the code I have written for this software
|
||||||
|
* can be used freely for any purpose. Any derived versions of this
|
||||||
|
* software must be clearly marked as such, and if the derived work is
|
||||||
|
* incompatible with the protocol description in the RFC file, it must be
|
||||||
|
* called by a name other than "ssh" or "Secure Shell".
|
||||||
|
|
||||||
|
[Tatu continues]
|
||||||
|
* However, I am not implying to give any licenses to any patents or
|
||||||
|
* copyrights held by third parties, and the software includes parts that
|
||||||
|
* are not under my direct control. As far as I know, all included
|
||||||
|
* source code is used in accordance with the relevant license agreements
|
||||||
|
* and can be used freely for any purpose (the GNU license being the most
|
||||||
|
* restrictive); see below for details.
|
||||||
|
|
||||||
|
[However, none of that term is relevant at this point in time. All of
|
||||||
|
these restrictively licenced software components which he talks about
|
||||||
|
have been removed from OpenSSH, i.e.,
|
||||||
|
|
||||||
|
- RSA is no longer included, found in the OpenSSL library
|
||||||
|
- IDEA is no longer included, its use is deprecated
|
||||||
|
- DES is now external, in the OpenSSL library
|
||||||
|
- GMP is no longer used, and instead we call BN code from OpenSSL
|
||||||
|
- Zlib is now external, in a library
|
||||||
|
- The make-ssh-known-hosts script is no longer included
|
||||||
|
- TSS has been removed
|
||||||
|
- MD5 is now external, in the OpenSSL library
|
||||||
|
- RC4 support has been replaced with ARC4 support from OpenSSL
|
||||||
|
- Blowfish is now external, in the OpenSSL library
|
||||||
|
|
||||||
|
[The licence continues]
|
||||||
|
|
||||||
|
Note that any information and cryptographic algorithms used in this
|
||||||
|
software are publicly available on the Internet and at any major
|
||||||
|
bookstore, scientific library, and patent office worldwide. More
|
||||||
|
information can be found e.g. at "http://www.cs.hut.fi/crypto".
|
||||||
|
|
||||||
|
The legal status of this program is some combination of all these
|
||||||
|
permissions and restrictions. Use only at your own responsibility.
|
||||||
|
You will be responsible for any legal consequences yourself; I am not
|
||||||
|
making any claims whether possessing or using this is legal or not in
|
||||||
|
your country, and I am not taking any responsibility on your behalf.
|
||||||
|
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
2)
|
||||||
|
The 32-bit CRC compensation attack detector in deattack.c was
|
||||||
|
contributed by CORE SDI S.A. under a BSD-style license.
|
||||||
|
|
||||||
|
* Cryptographic attack detector for ssh - source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
|
||||||
|
*
|
||||||
|
* All rights reserved. Redistribution and use in source and binary
|
||||||
|
* forms, with or without modification, are permitted provided that
|
||||||
|
* this copyright notice is retained.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
|
||||||
|
* CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
* Ariel Futoransky <futo@core-sdi.com>
|
||||||
|
* <http://www.core-sdi.com>
|
||||||
|
|
||||||
|
3)
|
||||||
|
ssh-keyscan was contributed by David Mazieres under a BSD-style
|
||||||
|
license.
|
||||||
|
|
||||||
|
* Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
|
||||||
|
*
|
||||||
|
* Modification and redistribution in source and binary forms is
|
||||||
|
* permitted provided that due credit is given to the author and the
|
||||||
|
* OpenBSD project by leaving this copyright notice intact.
|
||||||
|
|
||||||
|
4)
|
||||||
|
The Rijndael implementation by Vincent Rijmen, Antoon Bosselaers
|
||||||
|
and Paulo Barreto is in the public domain and distributed
|
||||||
|
with the following license:
|
||||||
|
|
||||||
|
* @version 3.0 (December 2000)
|
||||||
|
*
|
||||||
|
* Optimised ANSI C code for the Rijndael cipher (now AES)
|
||||||
|
*
|
||||||
|
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
|
||||||
|
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
|
||||||
|
* @author Paulo Barreto <paulo.barreto@terra.com.br>
|
||||||
|
*
|
||||||
|
* This code is hereby placed in the public domain.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
|
||||||
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||||
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||||
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||||
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
5)
|
||||||
|
One component of the ssh source code is under a 3-clause BSD license,
|
||||||
|
held by the University of California, since we pulled these parts from
|
||||||
|
original Berkeley code.
|
||||||
|
|
||||||
|
* Copyright (c) 1983, 1990, 1992, 1993, 1995
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
|
||||||
|
6)
|
||||||
|
Remaining components of the software are provided under a standard
|
||||||
|
2-term BSD licence with the following names as copyright holders:
|
||||||
|
|
||||||
|
Markus Friedl
|
||||||
|
Theo de Raadt
|
||||||
|
Niels Provos
|
||||||
|
Dug Song
|
||||||
|
Aaron Campbell
|
||||||
|
Damien Miller
|
||||||
|
Kevin Steves
|
||||||
|
Daniel Kouril
|
||||||
|
Wesley Griffin
|
||||||
|
Per Allansson
|
||||||
|
Nils Nordman
|
||||||
|
Simon Wilkinson
|
||||||
|
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -28,9 +28,9 @@ class ContainerActions {
|
||||||
dockerUtil.restart(name);
|
dockerUtil.restart(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
update (name, containerOpts) {
|
update (name, container) {
|
||||||
this.dispatch({name, containerOpts});
|
this.dispatch({name, container});
|
||||||
dockerUtil.updateContainer(name, containerOpts);
|
dockerUtil.updateContainer(name, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearPending () {
|
clearPending () {
|
||||||
|
|
|
@ -2,12 +2,13 @@ var app = require('app');
|
||||||
var autoUpdater = require('auto-updater');
|
var autoUpdater = require('auto-updater');
|
||||||
var BrowserWindow = require('browser-window');
|
var BrowserWindow = require('browser-window');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
var os = require('os');
|
||||||
var ipc = require('ipc');
|
var ipc = require('ipc');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
var child_process = require('child_process');
|
||||||
|
|
||||||
process.env.NODE_PATH = path.join(__dirname, '/../node_modules');
|
process.env.NODE_PATH = path.join(__dirname, 'node_modules');
|
||||||
process.env.RESOURCES_PATH = path.join(__dirname, '/../resources');
|
process.env.RESOURCES_PATH = path.join(__dirname, '/../resources');
|
||||||
process.chdir(path.join(__dirname, '..'));
|
|
||||||
process.env.PATH = '/usr/local/bin:' + process.env.PATH;
|
process.env.PATH = '/usr/local/bin:' + process.env.PATH;
|
||||||
|
|
||||||
var size = {}, settingsjson = {};
|
var size = {}, settingsjson = {};
|
||||||
|
@ -15,9 +16,32 @@ try {
|
||||||
size = JSON.parse(fs.readFileSync(path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], 'Library', 'Application\ Support', 'Kitematic', 'size')));
|
size = JSON.parse(fs.readFileSync(path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], 'Library', 'Application\ Support', 'Kitematic', 'size')));
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
try {
|
try {
|
||||||
settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
|
settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, 'settings.json'), 'utf8'));
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
|
|
||||||
|
let updateCmd = (args, cb) => {
|
||||||
|
let updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe');
|
||||||
|
let child = child_process.spawn(updateExe, args, {detached: true});
|
||||||
|
child.on('close', cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
var squirrelCommand = process.argv[1];
|
||||||
|
let target = path.basename(process.execPath);
|
||||||
|
switch (squirrelCommand) {
|
||||||
|
case '--squirrel-install':
|
||||||
|
case '--squirrel-updated':
|
||||||
|
updateCmd(['--createShortcut', target], app.quit);
|
||||||
|
break;
|
||||||
|
case '--squirrel-uninstall':
|
||||||
|
updateCmd(['--removeShortcut', target], app.quit);
|
||||||
|
break;
|
||||||
|
case '--squirrel-obsolete':
|
||||||
|
app.quit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var openURL = null;
|
var openURL = null;
|
||||||
app.on('open-url', function (event, url) {
|
app.on('open-url', function (event, url) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -33,10 +57,10 @@ app.on('ready', function () {
|
||||||
'standard-window': false,
|
'standard-window': false,
|
||||||
resizable: true,
|
resizable: true,
|
||||||
frame: false,
|
frame: false,
|
||||||
show: false,
|
show: false
|
||||||
});
|
});
|
||||||
|
|
||||||
mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, '..', 'build/index.html')));
|
mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, 'index.html')));
|
||||||
|
|
||||||
app.on('activate-with-no-open-windows', function () {
|
app.on('activate-with-no-open-windows', function () {
|
||||||
if (mainWindow) {
|
if (mainWindow) {
|
||||||
|
@ -51,11 +75,21 @@ app.on('ready', function () {
|
||||||
autoUpdater.quitAndInstall();
|
autoUpdater.quitAndInstall();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('before-quit', function () {
|
if (os.platform() === 'win32') {
|
||||||
if (!updating) {
|
mainWindow.on('close', function () {
|
||||||
mainWindow.webContents.send('application:quitting');
|
mainWindow.webContents.send('application:quitting');
|
||||||
}
|
return true;
|
||||||
});
|
});
|
||||||
|
app.on('window-all-closed', function() {
|
||||||
|
app.quit();
|
||||||
|
});
|
||||||
|
} else if (os.platform() === 'darwin') {
|
||||||
|
app.on('before-quit', function () {
|
||||||
|
if (!updating) {
|
||||||
|
mainWindow.webContents.send('application:quitting');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
mainWindow.webContents.on('new-window', function (e) {
|
mainWindow.webContents.on('new-window', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -85,7 +119,7 @@ app.on('ready', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'development') {
|
if (process.env.NODE_ENV !== 'development') {
|
||||||
autoUpdater.setFeedUrl('https://updates.kitematic.com/releases/latest?version=' + app.getVersion() + '&beta=' + !!settingsjson.beta);
|
autoUpdater.setFeedUrl('https://updates.kitematic.com/releases/latest?version=' + app.getVersion() + '&beta=' + !!settingsjson.beta + '&platform=' + os.platform());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
|
var $ = require('jquery');
|
||||||
var _ = require('underscore');
|
var _ = require('underscore');
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var exec = require('exec');
|
var exec = require('exec');
|
||||||
var shell = require('shell');
|
var shell = require('shell');
|
||||||
var metrics = require('../utils/MetricsUtil');
|
var metrics = require('../utils/MetricsUtil');
|
||||||
var ContainerUtil = require('../utils/ContainerUtil');
|
var ContainerUtil = require('../utils/ContainerUtil');
|
||||||
|
var util = require('../utils/Util');
|
||||||
var machine = require('../utils/DockerMachineUtil');
|
var machine = require('../utils/DockerMachineUtil');
|
||||||
|
var RetinaImage = require('react-retina-image');
|
||||||
var classNames = require('classnames');
|
var classNames = require('classnames');
|
||||||
var resources = require('../utils/ResourcesUtil');
|
var resources = require('../utils/ResourcesUtil');
|
||||||
|
var dockerUtil = require('../utils/DockerUtil');
|
||||||
var containerActions = require('../actions/ContainerActions');
|
var containerActions = require('../actions/ContainerActions');
|
||||||
|
var dockerMachineUtil = require('../utils/DockerMachineUtil');
|
||||||
|
|
||||||
var ContainerDetailsSubheader = React.createClass({
|
var ContainerDetailsSubheader = React.createClass({
|
||||||
contextTypes: {
|
contextTypes: {
|
||||||
|
@ -101,15 +106,7 @@ var ContainerDetailsSubheader = React.createClass({
|
||||||
if(!shell) {
|
if(!shell) {
|
||||||
shell = 'sh';
|
shell = 'sh';
|
||||||
}
|
}
|
||||||
machine.ip().then(ip => {
|
dockerMachineUtil.dockerTerminal(`docker exec -it ${this.props.container.Name} ${shell}`);
|
||||||
var cmd = [resources.terminal(), 'ssh', '-p', '22', '-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, shell];
|
|
||||||
exec(cmd, function (stderr, stdout, code) {
|
|
||||||
if (code) {
|
|
||||||
console.log(stderr);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
|
|
|
@ -18,23 +18,18 @@ var ContainerHomeFolder = React.createClass({
|
||||||
from: 'home'
|
from: 'home'
|
||||||
});
|
});
|
||||||
|
|
||||||
if (hostVolume.indexOf(process.env.HOME) === -1) {
|
if (hostVolume.indexOf(util.windowsToLinuxPath(util.home())) === -1) {
|
||||||
dialog.showMessageBox({
|
dialog.showMessageBox({
|
||||||
message: 'Enable all volumes to edit files via Finder? This may not work with all database containers.',
|
message: 'Enable all volumes to edit files via Finder? This may not work with all database containers.',
|
||||||
buttons: ['Enable Volumes', 'Cancel']
|
buttons: ['Enable Volumes', 'Cancel']
|
||||||
}, (index) => {
|
}, (index) => {
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
var volumes = _.clone(this.props.container.Volumes);
|
var volumes = _.clone(this.props.container.Volumes);
|
||||||
var newHostVolume = path.join(util.home(), util.documents(), 'Kitematic', this.props.container.Name, containerVolume);
|
var newHostVolume = util.escapePath(path.join(util.home(), util.documents(), 'Kitematic', this.props.container.Name, containerVolume));
|
||||||
volumes[containerVolume] = newHostVolume;
|
volumes[containerVolume] = newHostVolume;
|
||||||
var binds = _.pairs(volumes).map(function (pair) {
|
var binds = _.pairs(volumes).map(function (pair) {
|
||||||
if(util.isWindows()) {
|
if(util.isWindows()) {
|
||||||
var home = util.home();
|
return util.windowsToLinuxPath(pair[1]) + ':' + pair[0];
|
||||||
home = home.charAt(0).toLowerCase() + home.slice(1);
|
|
||||||
home = '/' + home.replace(':', '').replace(/\\/g, '/');
|
|
||||||
var fullPath = path.join(home, 'Kitematic', pair[1], pair[0]);
|
|
||||||
fullPath = fullPath.replace(/\\/g, '/');
|
|
||||||
return fullPath + ':' + pair[0];
|
|
||||||
}
|
}
|
||||||
return pair[1] + ':' + pair[0];
|
return pair[1] + ':' + pair[0];
|
||||||
});
|
});
|
||||||
|
@ -49,7 +44,8 @@ var ContainerHomeFolder = React.createClass({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
shell.showItemInFolder(hostVolume);
|
let path = util.isWindows() ? util.linuxToWindowsPath(hostVolume) : hostVolume;
|
||||||
|
shell.showItemInFolder(path);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleClickChangeFolders: function () {
|
handleClickChangeFolders: function () {
|
||||||
|
|
|
@ -62,7 +62,7 @@ var ContainerHomePreview = React.createClass({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{frame}
|
{frame}
|
||||||
<div className="frame-overlay"></div>
|
<div onClick={this.handleClickPreview} className="frame-overlay"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -92,7 +92,7 @@ var ContainerHomePreview = React.createClass({
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>DOCKER PORT</th>
|
<th>DOCKER PORT</th>
|
||||||
<th>MAC PORT</th>
|
<th>ACCESS URL</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
|
@ -46,7 +46,7 @@ var ContainerSettingsPorts = React.createClass({
|
||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
if (!this.props.container) {
|
if (!this.props.container) {
|
||||||
return (<div></div>);
|
return false;
|
||||||
}
|
}
|
||||||
var ports = _.map(_.pairs(this.state.ports), pair => {
|
var ports = _.map(_.pairs(this.state.ports), pair => {
|
||||||
var key = pair[0];
|
var key = pair[0];
|
||||||
|
@ -66,7 +66,7 @@ var ContainerSettingsPorts = React.createClass({
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>DOCKER PORT</th>
|
<th>DOCKER PORT</th>
|
||||||
<th>MAC PORT</th>
|
<th>ACCESS URL</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
|
@ -3,58 +3,81 @@ var React = require('react/addons');
|
||||||
var remote = require('remote');
|
var remote = require('remote');
|
||||||
var dialog = remote.require('dialog');
|
var dialog = remote.require('dialog');
|
||||||
var shell = require('shell');
|
var shell = require('shell');
|
||||||
|
var util = require('../utils/Util');
|
||||||
var metrics = require('../utils/MetricsUtil');
|
var metrics = require('../utils/MetricsUtil');
|
||||||
var containerActions = require('../actions/ContainerActions');
|
var containerActions = require('../actions/ContainerActions');
|
||||||
|
|
||||||
var ContainerSettingsVolumes = React.createClass({
|
var ContainerSettingsVolumes = React.createClass({
|
||||||
handleChooseVolumeClick: function (dockerVol) {
|
handleChooseVolumeClick: function (dockerVol) {
|
||||||
var self = this;
|
|
||||||
dialog.showOpenDialog({properties: ['openDirectory', 'createDirectory']}, (filenames) => {
|
dialog.showOpenDialog({properties: ['openDirectory', 'createDirectory']}, (filenames) => {
|
||||||
if (!filenames) {
|
if (!filenames) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var directory = filenames[0];
|
|
||||||
if (directory) {
|
|
||||||
metrics.track('Chose Directory for Volume');
|
|
||||||
var volumes = _.clone(self.props.container.Volumes);
|
|
||||||
volumes[dockerVol] = directory;
|
|
||||||
var binds = _.pairs(volumes).map(function (pair) {
|
|
||||||
return pair[1] + ':' + pair[0];
|
|
||||||
});
|
|
||||||
|
|
||||||
containerActions.update(this.props.container.Name, {Binds: binds, Volumes: volumes});
|
var directory = filenames[0];
|
||||||
|
|
||||||
|
if (!directory || directory.indexOf(util.home()) === -1) {
|
||||||
|
dialog.showMessageBox({
|
||||||
|
type: 'warning',
|
||||||
|
buttons: ['OK'],
|
||||||
|
message: 'Invalid directory. Volume directories must be under your Users directory'
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
metrics.track('Choose Directory for Volume');
|
||||||
|
if(util.isWindows()) {
|
||||||
|
directory = util.escapePath(util.windowsToLinuxPath(directory));
|
||||||
|
}
|
||||||
|
var volumes = _.clone(this.props.container.Volumes);
|
||||||
|
volumes[dockerVol] = directory;
|
||||||
|
var binds = _.pairs(volumes).map(function (pair) {
|
||||||
|
return pair[1] + ':' + pair[0];
|
||||||
|
});
|
||||||
|
|
||||||
|
containerActions.update(this.props.container.Name, {Binds: binds, Volumes: volumes});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleRemoveVolumeClick: function (dockerVol) {
|
handleRemoveVolumeClick: function (dockerVol) {
|
||||||
metrics.track('Removed Volume Directory', {
|
metrics.track('Removed Volume Directory', {
|
||||||
from: 'settings'
|
from: 'settings'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var hostConfig = _.clone(this.props.container.HostConfig);
|
||||||
|
var binds = hostConfig.Binds;
|
||||||
var volumes = _.clone(this.props.container.Volumes);
|
var volumes = _.clone(this.props.container.Volumes);
|
||||||
delete volumes[dockerVol];
|
volumes[dockerVol] = null;
|
||||||
var binds = _.pairs(volumes).map(function (pair) {
|
var index = _.findIndex(binds, bind => bind.indexOf(`:${dockerVol}`) !== -1);
|
||||||
return pair[1] + ':' + pair[0];
|
if (index >= 0) {
|
||||||
});
|
binds.splice(index, 1);
|
||||||
containerActions.update(this.props.container.Name, {Binds: binds, Volumes: volumes});
|
}
|
||||||
|
containerActions.update(this.props.container.Name, {HostConfig: hostConfig, Binds: binds, Volumes: volumes});
|
||||||
},
|
},
|
||||||
handleOpenVolumeClick: function (path) {
|
handleOpenVolumeClick: function (path) {
|
||||||
metrics.track('Opened Volume Directory', {
|
metrics.track('Opened Volume Directory', {
|
||||||
from: 'settings'
|
from: 'settings'
|
||||||
});
|
});
|
||||||
shell.showItemInFolder(path);
|
if (util.isWindows()) {
|
||||||
|
shell.showItemInFolder(util.linuxToWindowsPath(path));
|
||||||
|
} else {
|
||||||
|
shell.showItemInFolder(path);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
if (!this.props.container) {
|
if (!this.props.container) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var homeDir = util.isWindows() ? util.windowsToLinuxPath(util.home()) : util.home();
|
||||||
var volumes = _.map(this.props.container.Volumes, (val, key) => {
|
var volumes = _.map(this.props.container.Volumes, (val, key) => {
|
||||||
if (!val || val.indexOf(process.env.HOME) === -1) {
|
if (!val || val.indexOf(homeDir) === -1) {
|
||||||
val = (
|
val = (
|
||||||
<span className="value-right">No Folder</span>
|
<span className="value-right">No Folder</span>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
let local = util.isWindows() ? util.linuxToWindowsPath(val) : val;
|
||||||
val = (
|
val = (
|
||||||
<a className="value-right" onClick={this.handleOpenVolumeClick.bind(this, val)}>{val.replace(process.env.HOME, '~')}</a>
|
<a className="value-right" onClick={this.handleOpenVolumeClick.bind(this, val)}>{local.replace(process.env.HOME, '~')}</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
@ -76,7 +99,7 @@ var ContainerSettingsVolumes = React.createClass({
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>DOCKER FOLDER</th>
|
<th>DOCKER FOLDER</th>
|
||||||
<th>MAC FOLDER</th>
|
<th>LOCAL FOLDER</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
|
@ -6,6 +6,7 @@ var containerStore = require('../stores/ContainerStore');
|
||||||
var ContainerList = require('./ContainerList.react');
|
var ContainerList = require('./ContainerList.react');
|
||||||
var Header = require('./Header.react');
|
var Header = require('./Header.react');
|
||||||
var metrics = require('../utils/MetricsUtil');
|
var metrics = require('../utils/MetricsUtil');
|
||||||
|
var RetinaImage = require('react-retina-image');
|
||||||
var shell = require('shell');
|
var shell = require('shell');
|
||||||
var machine = require('../utils/DockerMachineUtil');
|
var machine = require('../utils/DockerMachineUtil');
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ var RetinaImage = require('react-retina-image');
|
||||||
var remote = require('remote');
|
var remote = require('remote');
|
||||||
var ipc = require('ipc');
|
var ipc = require('ipc');
|
||||||
var autoUpdater = remote.require('auto-updater');
|
var autoUpdater = remote.require('auto-updater');
|
||||||
|
var util = require('../utils/Util');
|
||||||
var metrics = require('../utils/MetricsUtil');
|
var metrics = require('../utils/MetricsUtil');
|
||||||
var Menu = remote.require('menu');
|
var Menu = remote.require('menu');
|
||||||
var MenuItem = remote.require('menu-item');
|
var MenuItem = remote.require('menu-item');
|
||||||
|
@ -52,7 +53,11 @@ var Header = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleClose: function () {
|
handleClose: function () {
|
||||||
remote.getCurrentWindow().hide();
|
if (util.isWindows()) {
|
||||||
|
remote.getCurrentWindow().close();
|
||||||
|
} else {
|
||||||
|
remote.getCurrentWindow().hide();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleMinimize: function () {
|
handleMinimize: function () {
|
||||||
remote.getCurrentWindow().minimize();
|
remote.getCurrentWindow().minimize();
|
||||||
|
@ -94,22 +99,29 @@ var Header = React.createClass({
|
||||||
});
|
});
|
||||||
accountActions.verify();
|
accountActions.verify();
|
||||||
},
|
},
|
||||||
|
renderLogo: function () {
|
||||||
|
return (
|
||||||
|
<div className="logo">
|
||||||
|
<RetinaImage src="logo.png"/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
renderWindowButtons: function () {
|
renderWindowButtons: function () {
|
||||||
let buttons;
|
let buttons;
|
||||||
if (this.state.fullscreen) {
|
if (util.isWindows()) {
|
||||||
buttons = (
|
buttons = (
|
||||||
<div className="buttons">
|
<div className="windows-buttons">
|
||||||
<div className="button button-close disabled"></div>
|
<div className="windows-button button-minimize enabled" onClick={this.handleMinimize}><div className="icon"></div></div>
|
||||||
<div className="button button-minimize disabled"></div>
|
<div className={`windows-button ${this.state.fullscreen ? 'button-fullscreenclose' : 'button-fullscreen'} enabled`} onClick={this.handleFullscreen}><div className="icon"></div></div>
|
||||||
<div className="button button-fullscreenclose enabled" onClick={this.handleFullscreen}></div>
|
<div className="windows-button button-close enabled" onClick={this.handleClose}></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
buttons = (
|
buttons = (
|
||||||
<div className="buttons">
|
<div className="buttons">
|
||||||
<div className="button button-close enabled" onClick={this.handleClose}></div>
|
<div className="button button-close enabled" onClick={this.handleClose}></div>
|
||||||
<div className="button button-minimize enabled" onClick={this.handleMinimize}></div>
|
<div className="button button-minimize enabled" onClick={this.handleMinimize}></div>
|
||||||
<div className="button button-fullscreen enabled" onClick={this.handleFullscreen}></div>
|
<div className="button button-fullscreen enabled" onClick={this.handleFullscreen}></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -150,16 +162,14 @@ var Header = React.createClass({
|
||||||
return (
|
return (
|
||||||
<div className={headerClasses}>
|
<div className={headerClasses}>
|
||||||
<div className="left-header">
|
<div className="left-header">
|
||||||
{this.renderWindowButtons()}
|
{util.isWindows () ? this.renderLogo() : this.renderWindowButtons()}
|
||||||
{username}
|
{username}
|
||||||
</div>
|
</div>
|
||||||
<div className="right-header">
|
<div className="right-header">
|
||||||
<div className="updates">
|
<div className="updates">
|
||||||
{updateWidget}
|
{updateWidget}
|
||||||
</div>
|
</div>
|
||||||
<div className="logo">
|
{util.isWindows () ? this.renderWindowButtons() : this.renderLogo()}
|
||||||
<RetinaImage src="logo.png"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -173,9 +183,10 @@ var Header = React.createClass({
|
||||||
return (
|
return (
|
||||||
<div className={headerClasses}>
|
<div className={headerClasses}>
|
||||||
<div className="left-header">
|
<div className="left-header">
|
||||||
{this.renderWindowButtons()}
|
{util.isWindows () ? null : this.renderWindowButtons()}
|
||||||
</div>
|
</div>
|
||||||
<div className="right-header">
|
<div className="right-header">
|
||||||
|
{util.isWindows () ? this.renderWindowButtons() : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -74,7 +74,7 @@ class ContainerStore {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
deepExtend(containers[name], container);
|
_.extend(containers[name], container);
|
||||||
|
|
||||||
if (containers[name].State) {
|
if (containers[name].State) {
|
||||||
containers[name].State.Updating = true;
|
containers[name].State.Updating = true;
|
||||||
|
@ -89,7 +89,8 @@ class ContainerStore {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Trigger log update
|
// Trigger log update
|
||||||
LogStore.fetch(container.Name);
|
// TODO: fix this loading multiple times
|
||||||
|
// LogStore.fetch(container.Name);
|
||||||
|
|
||||||
containers[container.Name] = container;
|
containers[container.Name] = container;
|
||||||
|
|
||||||
|
|
|
@ -42,14 +42,14 @@ var _steps = [{
|
||||||
progressCallback(50); // TODO: detect when the installation has started so we can simulate progress
|
progressCallback(50); // TODO: detect when the installation has started so we can simulate progress
|
||||||
try {
|
try {
|
||||||
if (util.isWindows()) {
|
if (util.isWindows()) {
|
||||||
yield util.exec([path.join(util.supportDir(), virtualBox.filename())]);
|
yield util.exec([path.join(util.supportDir(), virtualBox.filename()), '-msiparams', 'REBOOT=ReallySuppress', 'LIMITUI=INSTALLUILEVEL_PROGRESSONLY']);
|
||||||
} else {
|
} else {
|
||||||
yield util.exec(setupUtil.macSudoCmd(setupUtil.installVirtualBoxCmd()));
|
yield util.exec(setupUtil.macSudoCmd(setupUtil.installVirtualBoxCmd()));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw null;
|
throw null;
|
||||||
}
|
}
|
||||||
} else if (!virtualBox.active()) {
|
} else if (!util.isWindows() && !virtualBox.active()) {
|
||||||
yield util.exec(setupUtil.macSudoCmd(util.escapePath('/Library/Application Support/VirtualBox/LaunchDaemons/VirtualBoxStartup.sh') + ' restart'));
|
yield util.exec(setupUtil.macSudoCmd(util.escapePath('/Library/Application Support/VirtualBox/LaunchDaemons/VirtualBoxStartup.sh') + ' restart'));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -59,7 +59,7 @@ var _steps = [{
|
||||||
message: 'To run Docker containers on your computer, Kitematic is starting a Linux virtual machine. This may take a minute...',
|
message: 'To run Docker containers on your computer, Kitematic is starting a Linux virtual machine. This may take a minute...',
|
||||||
totalPercent: 60,
|
totalPercent: 60,
|
||||||
percent: 0,
|
percent: 0,
|
||||||
seconds: 72,
|
seconds: 110,
|
||||||
run: Promise.coroutine(function* (progressCallback) {
|
run: Promise.coroutine(function* (progressCallback) {
|
||||||
setupUtil.simulateProgress(this.seconds, progressCallback);
|
setupUtil.simulateProgress(this.seconds, progressCallback);
|
||||||
var exists = yield machine.exists();
|
var exists = yield machine.exists();
|
||||||
|
@ -68,16 +68,6 @@ var _steps = [{
|
||||||
yield machine.rm();
|
yield machine.rm();
|
||||||
}
|
}
|
||||||
yield machine.create();
|
yield machine.create();
|
||||||
if(util.isWindows()) {
|
|
||||||
let home = util.home();
|
|
||||||
let driveLetter = home.charAt(0);
|
|
||||||
let parts = home.split('\\').slice(0, -1);
|
|
||||||
let usersDirName = parts[parts.length-1];
|
|
||||||
let usersDirPath = parts.join('\\');
|
|
||||||
let shareName = driveLetter + '/' + usersDirName;
|
|
||||||
yield virtualBox.mountSharedDir(machine.name(), shareName, usersDirPath);
|
|
||||||
yield machine.start();
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +149,7 @@ var SetupStore = assign(Object.create(EventEmitter.prototype), {
|
||||||
var vboxNeedsInstall = !virtualBox.installed();
|
var vboxNeedsInstall = !virtualBox.installed();
|
||||||
|
|
||||||
required.download = vboxNeedsInstall && (!fs.existsSync(vboxfile) || setupUtil.checksum(vboxfile) !== virtualBox.checksum());
|
required.download = vboxNeedsInstall && (!fs.existsSync(vboxfile) || setupUtil.checksum(vboxfile) !== virtualBox.checksum());
|
||||||
required.install = vboxNeedsInstall || !virtualBox.active();
|
required.install = vboxNeedsInstall || (!util.isWindows() && !virtualBox.active());
|
||||||
required.init = required.install || !(yield machine.exists()) || (yield machine.state()) !== 'Running' || !isoversion || util.compareVersions(isoversion, packagejson['docker-version']) < 0;
|
required.init = required.install || !(yield machine.exists()) || (yield machine.state()) !== 'Running' || !isoversion || util.compareVersions(isoversion, packagejson['docker-version']) < 0;
|
||||||
|
|
||||||
var exists = yield machine.exists();
|
var exists = yield machine.exists();
|
||||||
|
|
|
@ -5,7 +5,7 @@ var fs = require('fs');
|
||||||
var util = require('./Util');
|
var util = require('./Util');
|
||||||
var resources = require('./ResourcesUtil');
|
var resources = require('./ResourcesUtil');
|
||||||
|
|
||||||
var NAME = 'dev';
|
var NAME = util.isWindows () ? 'kitematic' : 'dev';
|
||||||
|
|
||||||
var DockerMachine = {
|
var DockerMachine = {
|
||||||
command: function () {
|
command: function () {
|
||||||
|
@ -60,7 +60,7 @@ var DockerMachine = {
|
||||||
if (util.isWindows()) {
|
if (util.isWindows()) {
|
||||||
return util.exec([this.command(), '-D', 'create', '-d', 'virtualbox', '--virtualbox-memory', '2048', NAME]);
|
return util.exec([this.command(), '-D', 'create', '-d', 'virtualbox', '--virtualbox-memory', '2048', NAME]);
|
||||||
} else {
|
} else {
|
||||||
return util.exec([this.command(), '-D', 'create', '-d', 'virtualbox', '--virtualbox-boot2docker-url', path.join(process.cwd(), 'resources', 'boot2docker-' + dockerversion + '.iso'), '--virtualbox-memory', '2048', NAME]);
|
return util.exec([this.command(), '-D', 'create', '-d', 'virtualbox' ,'--virtualbox-boot2docker-url', path.join(process.cwd(), 'resources', 'boot2docker-' + dockerversion + '.iso'), '--virtualbox-memory', '2048', NAME]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
start: function () {
|
start: function () {
|
||||||
|
@ -153,18 +153,25 @@ var DockerMachine = {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
dockerTerminal: function () {
|
dockerTerminal: function (cmd) {
|
||||||
if(util.isWindows()) {
|
if(util.isWindows()) {
|
||||||
|
cmd = cmd || '';
|
||||||
this.info().then(machine => {
|
this.info().then(machine => {
|
||||||
util.execProper(`start cmd.exe /k "SET DOCKER_HOST=${machine.url}&& SET DOCKER_CERT_PATH=${path.join(util.home(), '.docker/machine/machines/' + machine.name)}&& SET DOCKER_TLS_VERIFY=1`);
|
util.exec('start powershell.exe ' + cmd,
|
||||||
|
{env: {
|
||||||
|
'DOCKER_HOST' : machine.url,
|
||||||
|
'DOCKER_CERT_PATH' : path.join(util.home(), '.docker/machine/machines/' + machine.name),
|
||||||
|
'DOCKER_TLS_VERIFY': 1
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
cmd = cmd || process.env.SHELL;
|
||||||
this.info().then(machine => {
|
this.info().then(machine => {
|
||||||
var cmd = [resources.terminal(), `DOCKER_HOST=${machine.url} DOCKER_CERT_PATH=${path.join(util.home(), '.docker/machine/machines/' + machine.name)} DOCKER_TLS_VERIFY=1 $SHELL`];
|
util.exec([resources.terminal(), `DOCKER_HOST=${machine.url} DOCKER_CERT_PATH=${path.join(util.home(), '.docker/machine/machines/' + machine.name)} DOCKER_TLS_VERIFY=1 ${cmd}`]).then(() => {});
|
||||||
util.exec(cmd).then(() => {});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = DockerMachine;
|
module.exports = DockerMachine;
|
||||||
|
|
|
@ -25,8 +25,6 @@ export default {
|
||||||
throw new Error('Certificate directory does not exist');
|
throw new Error('Certificate directory does not exist');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(ip);
|
|
||||||
|
|
||||||
this.host = ip;
|
this.host = ip;
|
||||||
this.client = new dockerode({
|
this.client = new dockerode({
|
||||||
protocol: 'https',
|
protocol: 'https',
|
||||||
|
@ -369,13 +367,14 @@ export default {
|
||||||
let columns = {};
|
let columns = {};
|
||||||
columns.amount = 4; // arbitrary
|
columns.amount = 4; // arbitrary
|
||||||
columns.toFill = 0; // the current column index, waiting for layer IDs to be displayed
|
columns.toFill = 0; // the current column index, waiting for layer IDs to be displayed
|
||||||
|
let error = null;
|
||||||
|
|
||||||
// data is associated with one layer only (can be identified with id)
|
// data is associated with one layer only (can be identified with id)
|
||||||
stream.on('data', str => {
|
stream.on('data', str => {
|
||||||
var data = JSON.parse(str);
|
var data = JSON.parse(str);
|
||||||
|
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
callback(data.error);
|
error = data.error;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,7 +448,7 @@ export default {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
stream.on('end', function () {
|
stream.on('end', function () {
|
||||||
callback();
|
callback(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -74,11 +74,10 @@ module.exports = {
|
||||||
let data = JSON.parse(body);
|
let data = JSON.parse(body);
|
||||||
if (response.statusCode === 200 && data && data.token) {
|
if (response.statusCode === 200 && data && data.token) {
|
||||||
localStorage.setItem('auth.jwt', data.token);
|
localStorage.setItem('auth.jwt', data.token);
|
||||||
|
this.request(req, callback);
|
||||||
} else {
|
} else {
|
||||||
this.logout();
|
this.logout();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.request(req, callback);
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
callback(error, response, body);
|
callback(error, response, body);
|
||||||
|
|
|
@ -7,7 +7,7 @@ var util = require('./Util');
|
||||||
var settings;
|
var settings;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
settings = JSON.parse(fs.readFileSync(path.join(__dirname, '../..', 'settings.json'), 'utf8'));
|
settings = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
settings = {};
|
settings = {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ var util = require('../utils/Util');
|
||||||
var hubUtil = require('../utils/HubUtil');
|
var hubUtil = require('../utils/HubUtil');
|
||||||
var repositoryServerActions = require('../actions/RepositoryServerActions');
|
var repositoryServerActions = require('../actions/RepositoryServerActions');
|
||||||
var tagServerActions = require('../actions/TagServerActions');
|
var tagServerActions = require('../actions/TagServerActions');
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
|
||||||
let REGHUB2_ENDPOINT = process.env.REGHUB2_ENDPOINT || 'https://registry.hub.docker.com/v2';
|
let REGHUB2_ENDPOINT = process.env.REGHUB2_ENDPOINT || 'https://registry.hub.docker.com/v2';
|
||||||
let searchReq = null;
|
let searchReq = null;
|
||||||
|
@ -61,7 +62,7 @@ module.exports = {
|
||||||
let data = JSON.parse(body);
|
let data = JSON.parse(body);
|
||||||
let repos = data.repos;
|
let repos = data.repos;
|
||||||
async.map(repos, (repo, cb) => {
|
async.map(repos, (repo, cb) => {
|
||||||
var name = repo.repo;
|
let name = repo.repo;
|
||||||
if (util.isOfficialRepo(name)) {
|
if (util.isOfficialRepo(name)) {
|
||||||
name = 'library/' + name;
|
name = 'library/' + name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ var SetupUtil = {
|
||||||
},
|
},
|
||||||
copycmd: function (src, dest) {
|
copycmd: function (src, dest) {
|
||||||
return ['rm', '-f', dest, '&&', 'cp', src, dest];
|
return ['rm', '-f', dest, '&&', 'cp', src, dest];
|
||||||
},
|
},
|
||||||
copyBinariesCmd: function () {
|
copyBinariesCmd: function () {
|
||||||
var cmd = ['mkdir', '-p', '/usr/local/bin'];
|
var cmd = ['mkdir', '-p', '/usr/local/bin'];
|
||||||
cmd.push('&&');
|
cmd.push('&&');
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
var exec = require('exec');
|
var exec = require('exec');
|
||||||
|
var child_process = require('child_process');
|
||||||
var Promise = require('bluebird');
|
var Promise = require('bluebird');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
@ -9,11 +10,21 @@ var app = remote.require('app');
|
||||||
module.exports = {
|
module.exports = {
|
||||||
exec: function (args, options) {
|
exec: function (args, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
|
// Add resources dir to exec path for Windows
|
||||||
|
if (this.isWindows()) {
|
||||||
|
options.env = options.env || {};
|
||||||
|
if (!options.env.PATH) {
|
||||||
|
options.env.PATH = process.env.RESOURCES_PATH + ';' + process.env.PATH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let fn = Array.isArray(args) ? exec : child_process.exec;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
exec(args, options, (stderr, stdout, code) => {
|
fn(args, options, (stderr, stdout, code) => {
|
||||||
if (code) {
|
if (code) {
|
||||||
var cmd = Array.isArray(args) ? args.join(' ') : args;
|
var cmd = Array.isArray(args) ? args.join(' ') : args;
|
||||||
reject(new Error(cmd + ' returned non zero exit code.\n===== Stderr =====\n ' + stderr + '\n===== Stdout =====\n' + stdout));
|
reject(new Error(cmd + ' returned non zero exit code. Stderr: ' + stderr));
|
||||||
} else {
|
} else {
|
||||||
resolve(stdout);
|
resolve(stdout);
|
||||||
}
|
}
|
||||||
|
@ -45,7 +56,8 @@ module.exports = {
|
||||||
return app.getPath('home');
|
return app.getPath('home');
|
||||||
},
|
},
|
||||||
documents: function () {
|
documents: function () {
|
||||||
return this.isWindows() ? 'My\ Documents' : 'Documents';
|
// TODO: fix me for windows 7
|
||||||
|
return 'Documents';
|
||||||
},
|
},
|
||||||
supportDir: function () {
|
supportDir: function () {
|
||||||
return app.getPath('userData');
|
return app.getPath('userData');
|
||||||
|
@ -62,12 +74,12 @@ module.exports = {
|
||||||
.replace(/\/Users\/[^\/]*\//mg, '/Users/<redacted>/');
|
.replace(/\/Users\/[^\/]*\//mg, '/Users/<redacted>/');
|
||||||
},
|
},
|
||||||
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'));
|
||||||
},
|
},
|
||||||
settingsjson: function () {
|
settingsjson: function () {
|
||||||
var settingsjson = {};
|
var settingsjson = {};
|
||||||
try {
|
try {
|
||||||
settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '../..', 'settings.json'), 'utf8'));
|
settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8'));
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
return settingsjson;
|
return settingsjson;
|
||||||
},
|
},
|
||||||
|
@ -135,5 +147,15 @@ module.exports = {
|
||||||
randomId: function () {
|
randomId: function () {
|
||||||
return crypto.randomBytes(32).toString('hex');
|
return crypto.randomBytes(32).toString('hex');
|
||||||
},
|
},
|
||||||
|
windowsToLinuxPath: function(windowsAbsPath) {
|
||||||
|
var fullPath = windowsAbsPath.replace(':', '').split(path.sep).join('/');
|
||||||
|
if(fullPath.charAt(0) !== '/'){
|
||||||
|
fullPath = '/' + fullPath.charAt(0).toLowerCase() + fullPath.substring(1);
|
||||||
|
}
|
||||||
|
return fullPath;
|
||||||
|
},
|
||||||
|
linuxToWindowsPath: function (linuxAbsPath) {
|
||||||
|
return linuxAbsPath.replace('/c', 'C:').split('/').join('\\');
|
||||||
|
},
|
||||||
webPorts: ['80', '8000', '8080', '3000', '5000', '2368', '9200', '8983']
|
webPorts: ['80', '8000', '8080', '3000', '5000', '2368', '9200', '8983']
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,12 +12,12 @@
|
||||||
.no-drag {
|
.no-drag {
|
||||||
-webkit-app-region: no-drag;
|
-webkit-app-region: no-drag;
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-header {
|
.left-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-width: @sidebar-width + 1px;
|
min-width: @sidebar-width + 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right-header {
|
.right-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
@ -33,9 +33,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
padding: 0.9rem 1rem 0 0;
|
padding: 0.9rem 1rem 0 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-wrapper {
|
.login-wrapper {
|
||||||
flex: 1 auto;
|
flex: 1 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -65,6 +65,81 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.windows-buttons {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-end;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
margin-right: 7px;
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
|
||||||
|
.windows-button {
|
||||||
|
height: 25px;
|
||||||
|
margin-left: 1px;
|
||||||
|
-webkit-transition: -webkit-filter 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
-webkit-transition: -webkit-filter 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.button-minimize, &.button-fullscreen, &.button-fullscreenclose {
|
||||||
|
min-width: 34px;
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
-webkit-filter: brightness(0.3);
|
||||||
|
height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
-webkit-filter: brightness(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
-webkit-filter: brightness(0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.button-minimize {
|
||||||
|
.icon {
|
||||||
|
background-position: 50% 18px;
|
||||||
|
.at2x('windows-minimize.png', 14px, 2px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.button-fullscreen {
|
||||||
|
.icon {
|
||||||
|
background-position: center;
|
||||||
|
.at2x('windows-fullscreen.png', 14px, 2px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.button-fullscreenclose {
|
||||||
|
.icon {
|
||||||
|
background-position: center;
|
||||||
|
.at2x('windows-fullscreenclose.png', 14px, 2px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.button-close {
|
||||||
|
min-width: 58px;
|
||||||
|
background: #C75050;
|
||||||
|
.at2x('windows-close.png', 12px, 9px);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
box-shadow: inset 0 0 0 -1px rgba(255, 255, 255, 0.4);
|
||||||
|
&:hover {
|
||||||
|
-webkit-filter: saturate(120%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
-webkit-filter: brightness(0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.buttons {
|
.buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin: 0 1.5rem;
|
margin: 0 1.5rem;
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
||||||
flex: 1 auto;
|
flex: 1 auto;
|
||||||
|
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
|
|
||||||
.image {
|
.image {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1 auto;
|
flex: 1 auto;
|
||||||
|
@ -163,7 +163,7 @@
|
||||||
.btn-close {
|
.btn-close {
|
||||||
-webkit-app-region: no-drag;
|
-webkit-app-region: no-drag;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 16px;
|
bottom: 16px;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 9.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
Loading…
Reference in New Issue