Fixing case

This commit is contained in:
Jeffrey Morgan 2015-01-30 15:21:55 -05:00
parent 5f164ccca9
commit ba6fb4f657
18 changed files with 539 additions and 24 deletions

View File

@ -6,7 +6,7 @@
<title>Kitematic</title> <title>Kitematic</title>
</head> </head>
<body> <body>
<script src="main.js"></script> <script src="Main.js"></script>
<script src="http://localhost:35729/livereload.js"></script> <script src="http://localhost:35729/livereload.js"></script>
</body> </body>
</html> </html>

View File

@ -11,7 +11,7 @@
}, },
"bugs": "https://github.com/kitematic/kitematic/issues", "bugs": "https://github.com/kitematic/kitematic/issues",
"scripts": { "scripts": {
"start": "rsync ./index.html ./build/ && rsync ./fonts/* ./build/ && rsync ./images/* ./build && jsx --watch src/ build/ & wess -w -m -i ./styles/main.less -o ./build/main.css & wiper -w ./build/**/*.* & ./cache/Atom.app/Contents/MacOS/Atom .", "start": "rsync ./index.html ./build/ && rsync ./fonts/* ./build/ && rsync ./images/* ./build && jsx --watch src/ build/ & wess -w -m -i ./styles/main.less -o ./build/main.css & wiper -w ./build/**/*.* & ./cache/Atom.app/Contents/MacOS/Atom . && kill $(pgrep node)",
"preinstall": "./deps", "preinstall": "./deps",
"test": "jest", "test": "jest",
"release": "./release" "release": "./release"
@ -33,7 +33,7 @@
"dependencies": { "dependencies": {
"ansi-to-html": "0.2.0", "ansi-to-html": "0.2.0",
"async": "^0.9.0", "async": "^0.9.0",
"bugsnag-js": "git+https://git@github.com/bugsnag/bugsnag-js", "bugsnag-js": "^2.4.6",
"dockerode": "2.0.4", "dockerode": "2.0.4",
"exec": "0.1.2", "exec": "0.1.2",
"gulp-react": "^2.0.0", "gulp-react": "^2.0.0",

224
src/Boot2Docker.js Normal file
View File

@ -0,0 +1,224 @@
var exec = require('exec');
var path = require('path');
var fs = require('fs');
var path = require('path');
var async = require('async');
var cmdExec = function (cmd, callback) {
exec(cmd, function (stderr, stdout, code) {
if (code !== 0) {
callback('Exit code ' + code + ': ' + stderr);
} else {
callback(null, stdout);
}
});
};
var homeDir = function () {
return process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'];
};
var Boot2Docker = {
version: function () {
return JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'))['boot2docker-version'];
},
cliVersion: function (callback) {
cmdExec([Boot2Docker.command(), 'version'], function (err, out) {
if (err) {
callback(err);
return;
}
var match = out.match(/version: v(\d+\.\d+\.\d+)/);
if (!match || match.length < 2) {
callback('Could not parse the boot2docker cli version.');
} else {
callback(null, match[1]);
}
});
},
isoVersion: function (callback) {
fs.readFile(path.join(homeDir(), '.boot2docker', 'boot2docker.iso'), 'utf8', function (err, data) {
if (err) {
callback(err);
return;
}
var match = data.match(/Boot2Docker-v(\d+\.\d+\.\d+)/);
if (!match) {
callback('Could not parse boot2docker iso version');
return;
}
callback (null, match[1]);
});
},
command: function () {
return path.join(process.cwd(), 'resources', 'boot2docker-' + this.version());
},
exists: function (callback) {
cmdExec([Boot2Docker.command(), 'info'], function (err, out) {
if (err) {
callback(null, false);
} else {
callback(null, true);
}
});
},
status: function (callback) {
cmdExec([Boot2Docker.command(), 'status'], function (err, out) {
if (err) {
callback(err);
return;
}
callback(null, out.trim());
});
},
init: function (callback) {
cmdExec([Boot2Docker.command(), 'init'], callback);
},
start: function (callback) {
cmdExec([Boot2Docker.command(), 'start'], callback);
},
stop: function (callback) {
cmdExec([Boot2Docker.command(), 'stop'], callback);
},
upgrade: function (callback) {
cmdExec([Boot2Docker.command(), 'upgrade'], callback);
},
ip: function (callback) {
cmdExec([Boot2Docker.command(), 'ip'], callback);
},
erase: function (callback) {
var VMFileLocation = path.join(homeDir(), 'VirtualBox\\ VMs/boot2docker-vm');
cmdExec(['rm', '-rf', VMFileLocation], callback);
},
state: function (callback) {
cmdExec([Boot2Docker.command(), 'info'], function (err, out) {
if (err) {
callback(err);
return;
}
try {
var info = JSON.parse(out);
callback(null, info.State);
} catch (e) {
callback(e, null);
}
});
},
disk: function (callback) {
cmdExec([Boot2Docker.command(), 'ssh', 'df'], function (err, out) {
if (err) {
callback(err);
return;
}
try {
var lines = out.split('\n');
var dataline = _.find(lines, function (line) {
return line.indexOf('/dev/sda1') !== -1;
});
var tokens = dataline.split(' ');
tokens = tokens.filter(function (token) {
return token !== '';
});
var usedGb = parseInt(tokens[2], 10) / 1000000;
var totalGb = parseInt(tokens[3], 10) / 1000000;
var percent = parseInt(tokens[4].replace('%', ''), 10);
callback(null, {
used_gb: usedGb.toFixed(2),
total_gb: totalGb.toFixed(2),
percent: percent
});
} catch (error) {
callback(error, null);
}
});
},
memory: function (callback) {
cmdExec([Boot2Docker.command(), 'ssh', 'free -m'], function (err, out) {
if (err) {
callback(err);
return;
}
try {
var lines = out.split('\n');
var dataline = _.find(lines, function (line) {
return line.indexOf('-/+ buffers') !== -1;
});
var tokens = dataline.split(' ');
tokens = tokens.filter(function(token) {
return token !== '';
});
var usedGb = parseInt(tokens[2], 10) / 1000;
var freeGb = parseInt(tokens[3], 10) / 1000;
var totalGb = usedGb + freeGb;
var percent = Math.round(usedGb / totalGb * 100);
callback(null, {
used_gb: usedGb.toFixed(2),
total_gb: totalGb.toFixed(2),
free_gb: freeGb.toFixed(2),
percent: percent
});
} catch (error) {
callback(error);
}
});
},
createScratchImage: function (callback) {
cmdExec([Boot2Docker.command(), 'ssh', 'tar cv --files-from /dev/null | docker import - scratch'], function (err, out) {
callback(err);
});
},
stats: function (callback) {
var self = this;
self.state(function (err, state) {
if (err) {
callback(err);
return;
}
if (state === 'poweroff') {
callback(null, {state: state});
return;
}
self.memoryUsage(function (err, mem) {
if (err) {
callback(null, {state: state});
return;
}
self.diskUsage(function (err, disk) {
if (err) {
callback(null, {state: state, memory: mem});
return;
}
callback(null, {
state: state,
memory: mem,
disk: disk
});
});
});
});
},
sshKeyExists: function () {
return fs.existsSync(path.join(homeDir(), '.ssh', 'id_boot2docker'));
},
// Todo: move me to setup
waitWhileStatus: function (status, callback) {
var current = status;
async.whilst(function () {
return current === status;
}, function (callback) {
Boot2Docker.status(function (err, vmStatus) {
if (err) {
callback(err);
} else {
current = vmStatus.trim();
callback();
}
});
}, function (err) {
callback(err);
});
}
};
module.exports = Boot2Docker;

View File

@ -9,8 +9,8 @@ var remote = require('remote');
var dialog = remote.require('dialog'); var dialog = remote.require('dialog');
var ContainerStore = require('./ContainerStore'); var ContainerStore = require('./ContainerStore');
var ContainerUtil = require('./ContainerUtil'); var ContainerUtil = require('./ContainerUtil');
var docker = require('./docker'); var docker = require('./Docker');
var boot2docker = require('./boot2docker'); var boot2docker = require('./Boot2Docker');
var ProgressBar = require('react-bootstrap/ProgressBar'); var ProgressBar = require('react-bootstrap/ProgressBar');
var Popover = require('react-bootstrap/Popover'); var Popover = require('react-bootstrap/Popover');

View File

@ -8,7 +8,7 @@ var RetinaImage = require('react-retina-image');
var ModalTrigger = require('react-bootstrap/ModalTrigger'); var ModalTrigger = require('react-bootstrap/ModalTrigger');
var ContainerModal = require('./ContainerModal.react'); var ContainerModal = require('./ContainerModal.react');
var Header = require('./Header.react'); var Header = require('./Header.react');
var docker = require('./docker'); var docker = require('./Docker');
var ContainerList = React.createClass({ var ContainerList = React.createClass({
componentWillMount: function () { componentWillMount: function () {

View File

@ -1,14 +1,14 @@
var $ = require('jquery');
var _ = require('underscore');
var EventEmitter = require('events').EventEmitter; var EventEmitter = require('events').EventEmitter;
var async = require('async'); var async = require('async');
var path = require('path'); var path = require('path');
var assign = require('object-assign'); var assign = require('object-assign');
var Stream = require('stream'); var Stream = require('stream');
var Convert = require('ansi-to-html'); var Convert = require('ansi-to-html');
var docker = require('./docker'); var docker = require('./Docker');
var registry = require('./registry'); var registry = require('./Registry');
var ContainerUtil = require('./ContainerUtil'); var ContainerUtil = require('./ContainerUtil');
var $ = require('jquery');
var _ = require('underscore');
var convert = new Convert(); var convert = new Convert();

View File

@ -1,5 +1,5 @@
var _ = require('underscore'); var _ = require('underscore');
var docker = require('./docker'); var docker = require('./Docker');
var ContainerUtil = { var ContainerUtil = {
env: function (container) { env: function (container) {

View File

@ -1,3 +1,6 @@
var async = require('async');
var _ = require('underscore');
var $ = require('jquery');
var React = require('react/addons'); var React = require('react/addons');
var Router = require('react-router'); var Router = require('react-router');
var RetinaImage = require('react-retina-image'); var RetinaImage = require('react-retina-image');
@ -6,11 +9,7 @@ var ContainerModal = require('./ContainerModal.react');
var ContainerStore = require('./ContainerStore'); var ContainerStore = require('./ContainerStore');
var ContainerList = require('./ContainerList.react'); var ContainerList = require('./ContainerList.react');
var Header = require('./Header.react'); var Header = require('./Header.react');
var async = require('async'); var docker = require('./Docker');
var _ = require('underscore');
var docker = require('./docker');
var $ = require('jquery');
var Containers = React.createClass({ var Containers = React.createClass({
mixins: [Router.Navigation, Router.State], mixins: [Router.Navigation, Router.State],
getInitialState: function () { getInitialState: function () {

28
src/Docker.js Normal file
View File

@ -0,0 +1,28 @@
var fs = require('fs');
var path = require('path');
var dockerode = require('dockerode');
var Docker = {
host: null,
_client: null,
setHost: function(host) {
this.host = host;
var certDir = path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], '.boot2docker/certs/boot2docker-vm');
if (!fs.existsSync(certDir)) {
return;
}
this._client = new dockerode({
protocol: 'https',
host: this.host,
port: 2376,
ca: fs.readFileSync(path.join(certDir, 'ca.pem')),
cert: fs.readFileSync(path.join(certDir, 'cert.pem')),
key: fs.readFileSync(path.join(certDir, 'key.pem'))
});
},
client: function () {
return this._client;
}
};
module.exports = Docker;

44
src/Main.js Normal file
View File

@ -0,0 +1,44 @@
var module = require('module');
require.main.paths.splice(0, 0, process.env.NODE_PATH);
var Bugsnag = require('bugsnag-js');
var React = require('react');
var Router = require('react-router');
var RetinaImage = require('react-retina-image');
var async = require('async');
var docker = require('./docker');
var router = require('./router');
var boot2docker = require('./boot2docker');
var ContainerStore = require('./ContainerStore');
var Menu = require('./Menu');
var remote = require('remote');
var app = remote.require('app');
var ipc = require('ipc');
var Route = Router.Route;
var NotFoundRoute = Router.NotFoundRoute;
var DefaultRoute = Router.DefaultRoute;
var Link = Router.Link;
var RouteHandler = Router.RouteHandler;
Bugsnag.apiKey = 'fc51aab02ce9dd1bb6ebc9fe2f4d43d7';
Bugsnag.autoNotify = true;
Bugsnag.releaseStage = process.env.NODE_ENV === 'development' ? 'development' : 'production';
Bugsnag.notifyReleaseStages = [];
Bugsnag.appVersion = app.getVersion();
if (!window.location.hash.length || window.location.hash === '#/') {
router.run(function (Handler) {
React.render(<Handler/>, document.body);
});
} else {
boot2docker.ip(function (err, ip) {
docker.setHost(ip);
ContainerStore.init(function () {
router.run(function (Handler) {
React.render(<Handler/>, document.body);
});
});
});
}

View File

@ -3,7 +3,7 @@ var app = remote.require('app');
var Menu = remote.require('menu'); var Menu = remote.require('menu');
var MenuItem = remote.require('menu-item'); var MenuItem = remote.require('menu-item');
var BrowserWindow = remote.require('browser-window'); var BrowserWindow = remote.require('browser-window');
var router = require('./router'); var router = require('./Router');
// main.js // main.js
var template = [ var template = [

84
src/Registry.js Normal file
View File

@ -0,0 +1,84 @@
var async = require('async');
var $ = require('jquery');
var Registry = {
token: function(repository, callback) {
$.ajax({
url: 'https://registry.hub.docker.com/v1/repositories/' + repository + '/images',
headers: {
'X-Docker-Token': true,
},
success: function (res, status, xhr) {
callback(null, xhr.getResponseHeader('X-Docker-Token'));
},
error: function (err) {
callback(err);
}
});
},
ancestry: function (imageId, token, callback) {
$.ajax({
url: 'https://registry-1.docker.io/v1/images/' + imageId + '/ancestry',
headers: {
Authorization: 'Token ' + token
},
success: function (layers, status, xhr) {
callback(null, layers);
},
error: function (err) {
callback(err);
}
});
},
imageId: function (repository, tag, token, callback) {
$.ajax({
url: 'https://registry-1.docker.io/v1/repositories/' + repository + '/tags/' + tag,
headers: {
Authorization: 'Token ' + token
},
success: function (res, status, xhr) {
callback(null, res);
},
error: function (err) {
callback(err);
}
});
},
// Returns an array [{Id: <12 character image ID, size: size of layer in bytes}]
layers: function (repository, tag, callback) {
var self = this;
this.token(repository, function (err, token) {
self.imageId(repository, tag, token, function (err, imageId) {
self.ancestry(imageId, token, function (err, layers) {
async.map(layers, function (layer, callback) {
$.ajax({
url: 'https://registry-1.docker.io/v1/images/' + layer + '/json',
headers: {
Authorization: 'Token ' + token
},
success: function (res, status, xhr) {
var size = xhr.getResponseHeader('X-Docker-Size');
callback(null, {
Id: layer.slice(0, 12),
size: parseInt(size, 10)
});
},
error: function (err) {
callback(err);
}
});
}, function (err, results) {
if (err) {
callback('Could not sum' + err);
return;
}
callback(null, results);
});
});
});
});
}
};
module.exports = Registry;

33
src/Routes.js Normal file
View File

@ -0,0 +1,33 @@
var React = require('react/addons');
var Setup = require('./Setup.react');
var Containers = require('./Containers.react');
var ContainerDetails = require('./ContainerDetails.react');
var Preferences = require('./Preferences.react');
var NoContainers = require('./NoContainers.react');
var Router = require('react-router');
var Route = Router.Route;
var DefaultRoute = Router.DefaultRoute;
var RouteHandler = Router.RouteHandler;
var App = React.createClass({
render: function () {
return (
<RouteHandler/>
);
}
});
var routes = (
<Route name="app" path="/" handler={App}>
<Route name="containers" handler={Containers}>
<Route name="container" path="/containers/:name" handler={ContainerDetails}/>
<Route name="preferences" path="/preferences" handler={Preferences}/>
<DefaultRoute handler={NoContainers}/>
</Route>
<Route name="setup" handler={Setup}></Route>
<DefaultRoute handler={Setup}/>
</Route>
);
module.exports = routes;

View File

@ -5,11 +5,11 @@ var async = require('async');
var assign = require('object-assign'); var assign = require('object-assign');
var fs = require('fs'); var fs = require('fs');
var path = require('path'); var path = require('path');
var boot2docker = require('./boot2docker.js'); var boot2docker = require('./Boot2Docker');
var virtualbox = require('./virtualbox.js'); var virtualbox = require('./Virtualbox');
var util = require('./util.js'); var util = require('./Util');
var docker = require('./docker.js'); var docker = require('./Docker');
var ContainerStore = require('./ContainerStore.js'); var ContainerStore = require('./ContainerStore');
var setupSteps = [ var setupSteps = [
{ {

103
src/Util.js Normal file
View File

@ -0,0 +1,103 @@
var path = require('path');
var fs = require('fs');
var nodeCrypto = require('crypto');
var request = require('request');
var progress = require('request-progress');
var exec = require('exec');
var Util = {
supportDir: function (callback) {
var dirs = ['Application\ Support', 'Kitematic'];
var acc = process.env.HOME;
dirs.forEach(function (d) {
acc = path.join(acc, d);
if (!fs.existsSync(acc)) {
fs.mkdirSync(acc);
}
});
return acc;
},
download: function (url, filename, checksum, callback, progressCallback) {
var doDownload = function () {
progress(request({
uri: url,
rejectUnauthorized: false
}), {
throttle: 250
}).on('progress', function (state) {
progressCallback(state.percent);
}).on('error', function (err) {
callback(err);
}).pipe(fs.createWriteStream(filename)).on('error', function (err) {
callback(err);
}).on('close', function (err) {
callback(err);
});
};
// Compare checksum to see if it already exists first
if (fs.existsSync(filename)) {
var existingChecksum = nodeCrypto.createHash('sha256').update(fs.readFileSync(filename), 'utf8').digest('hex');
console.log(existingChecksum);
if (existingChecksum !== checksum) {
fs.unlinkSync(filename);
doDownload();
} else {
callback();
}
} else {
doDownload();
}
},
compareVersions: function (v1, v2, options) {
var lexicographical = options && options.lexicographical,
zeroExtend = options && options.zeroExtend,
v1parts = v1.split('.'),
v2parts = v2.split('.');
function isValidPart(x) {
return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x);
}
if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) {
return NaN;
}
if (zeroExtend) {
while (v1parts.length < v2parts.length) {
v1parts.push('0');
}
while (v2parts.length < v1parts.length) {
v2parts.push('0');
}
}
if (!lexicographical) {
v1parts = v1parts.map(Number);
v2parts = v2parts.map(Number);
}
for (var i = 0; i < v1parts.length; ++i) {
if (v2parts.length === i) {
return 1;
}
if (v1parts[i] === v2parts[i]) {
continue;
}
else if (v1parts[i] > v2parts[i]) {
return 1;
}
else {
return -1;
}
}
if (v1parts.length !== v2parts.length) {
return -1;
}
return 0;
}
};
module.exports = Util;

View File

@ -1,5 +1,5 @@
var Router = require('react-router'); var Router = require('react-router');
var routes = require('./routes'); var routes = require('./Routes');
var router = Router.create({ var router = Router.create({
routes: routes routes: routes

View File

@ -2,7 +2,7 @@ var fs = require('fs');
var exec = require('exec'); var exec = require('exec');
var path = require('path'); var path = require('path');
var async = require('async'); var async = require('async');
var util = require('./util'); var util = require('./Util');
var VirtualBox = { var VirtualBox = {
REQUIRED_VERSION: '4.3.18', REQUIRED_VERSION: '4.3.18',