mirror of https://github.com/docker/docs.git
Ported kitematic setup
This commit is contained in:
parent
be51f26065
commit
13cd6ed0b4
|
@ -0,0 +1,15 @@
|
||||||
|
var React = require('react');
|
||||||
|
var Router = require('react-router');
|
||||||
|
var Route = Router.Route;
|
||||||
|
var NotFoundRoute = Router.NotFoundRoute;
|
||||||
|
var DefaultRoute = Router.DefaultRoute;
|
||||||
|
var Link = Router.Link;
|
||||||
|
var RouteHandler = Router.RouteHandler;
|
||||||
|
|
||||||
|
var Container = React.createClass({
|
||||||
|
render: function () {
|
||||||
|
return <p>Hello</p>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = Container;
|
|
@ -0,0 +1,69 @@
|
||||||
|
var React = require('react');
|
||||||
|
var Router = require('react-router');
|
||||||
|
var Route = Router.Route;
|
||||||
|
var NotFoundRoute = Router.NotFoundRoute;
|
||||||
|
var DefaultRoute = Router.DefaultRoute;
|
||||||
|
var Link = Router.Link;
|
||||||
|
var RouteHandler = Router.RouteHandler;
|
||||||
|
var Navigation= Router.Navigation;
|
||||||
|
|
||||||
|
var async = require('async');
|
||||||
|
var docker = require('./docker.js');
|
||||||
|
|
||||||
|
var ContainerList = React.createClass({
|
||||||
|
render: function () {
|
||||||
|
var containers = this.props.containers.map(function (container) {
|
||||||
|
return <li key={container.Id}><Link to="container" params={container}>{container.Name.replace('/', '')}</Link></li>
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<ul>
|
||||||
|
{containers}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var Containers = React.createClass({
|
||||||
|
mixins: [Navigation],
|
||||||
|
getInitialState: function() {
|
||||||
|
return {containers: []};
|
||||||
|
},
|
||||||
|
update: function () {
|
||||||
|
var self = this;
|
||||||
|
docker.client().listContainers({all: true}, function (err, containers) {
|
||||||
|
async.map(containers, function(container, callback) {
|
||||||
|
docker.client().getContainer(container.Id).inspect(function (err, data) {
|
||||||
|
callback(null, data);
|
||||||
|
});
|
||||||
|
}, function (err, results) {
|
||||||
|
if (results.length > 0) {
|
||||||
|
self.transitionTo('container', {Id: results[0].Id})
|
||||||
|
}
|
||||||
|
self.setState({containers: results});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
componentDidMount: function () {
|
||||||
|
this.update();
|
||||||
|
var self = this;
|
||||||
|
docker.client().getEvents(function (err, stream) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
stream.setEncoding('utf8');
|
||||||
|
stream.on('data', function (data) {
|
||||||
|
self.update();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
render: function () {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ContainerList containers={this.state.containers}/>
|
||||||
|
<RouteHandler/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = Containers;
|
|
@ -0,0 +1,37 @@
|
||||||
|
var React = require('react/addons');
|
||||||
|
|
||||||
|
var Radial = React.createClass({
|
||||||
|
render: function () {
|
||||||
|
var percentage;
|
||||||
|
if (this.props.progress && !this.props.spin) {
|
||||||
|
percentage = (
|
||||||
|
<div className="percentage"></div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
percentage = <div></div>;
|
||||||
|
}
|
||||||
|
var classes = React.addons.classSet({
|
||||||
|
'radial-progress': true,
|
||||||
|
'radial-spinner': this.props.spin
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<div className={classes} data-progress={this.props.progress}>
|
||||||
|
<div className="circle">
|
||||||
|
<div className="mask full">
|
||||||
|
<div className="fill"></div>
|
||||||
|
</div>
|
||||||
|
<div className="mask half">
|
||||||
|
<div className="fill"></div>
|
||||||
|
<div className="fill fix"></div>
|
||||||
|
</div>
|
||||||
|
<div className="shadow"></div>
|
||||||
|
</div>
|
||||||
|
<div className="inset">
|
||||||
|
{percentage}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = Radial;
|
|
@ -0,0 +1,195 @@
|
||||||
|
var React = require('react');
|
||||||
|
var Router = require('react-router');
|
||||||
|
var Radial = require('./Radial.react.js');
|
||||||
|
var async = require('async');
|
||||||
|
var assign = require('object-assign');
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
var boot2docker = require('./boot2docker.js');
|
||||||
|
var virtualbox = require('./virtualbox.js');
|
||||||
|
var util = require('./util.js');
|
||||||
|
var docker = require('./docker.js');
|
||||||
|
|
||||||
|
var setupSteps = [
|
||||||
|
{
|
||||||
|
run: function (callback, progressCallback) {
|
||||||
|
var installed = virtualbox.installed();
|
||||||
|
if (!installed) {
|
||||||
|
util.download('https://s3.amazonaws.com/kite-installer/' + virtualbox.INSTALLER_FILENAME, path.join(process.cwd(), 'resources', virtualbox.INSTALLER_FILENAME), virtualbox.INSTALLER_CHECKSUM, function (err) {
|
||||||
|
if (err) {callback(err); return;}
|
||||||
|
virtualbox.install(function (err) {
|
||||||
|
if (!virtualbox.installed()) {
|
||||||
|
callback('VirtualBox could not be installed. The installation either failed or was cancelled. Please try closing all VirtualBox instances and try again.');
|
||||||
|
} else {
|
||||||
|
callback(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, function (progress) {
|
||||||
|
progressCallback(progress);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
virtualbox.version(function (err, installedVersion) {
|
||||||
|
if (err) {callback(err); return;}
|
||||||
|
if (util.compareVersions(installedVersion, virtualbox.REQUIRED_VERSION) < 0) {
|
||||||
|
// Download a newer version of Virtualbox
|
||||||
|
util.downloadFile(Setup.BASE_URL + virtualbox.INSTALLER_FILENAME, path.join(util.getResourceDir(), virtualbox.INSTALLER_FILENAME), virtualbox.INSTALLER_CHECKSUM, function (err) {
|
||||||
|
if (err) {callback(err); return;}
|
||||||
|
virtualbox.kill(function (err) {
|
||||||
|
if (err) {callback(err); return;}
|
||||||
|
virtualbox.install(function (err) {
|
||||||
|
if (err) {callback(err); return;}
|
||||||
|
virtualbox.version(function (err, installedVersion) {
|
||||||
|
if (err) {callback(err); return;}
|
||||||
|
if (util.compareVersions(installedVersion, virtualbox.REQUIRED_VERSION) < 0) {
|
||||||
|
callback('VirtualBox could not be installed. The installation either failed or was cancelled. Please try closing all VirtualBox instances and try again.');
|
||||||
|
} else {
|
||||||
|
callback(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, function (progress) {
|
||||||
|
progressCallback(progress);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
message: 'Downloading VirtualBox...'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
run: function (callback) {
|
||||||
|
virtualbox.deleteVM('kitematic-vm', function (err, removed) {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
message: 'Cleaning up existing Docker VM...'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Initialize Boot2Docker if necessary.
|
||||||
|
{
|
||||||
|
run: function (callback) {
|
||||||
|
boot2docker.exists(function (err, exists) {
|
||||||
|
if (err) { callback(err); return; }
|
||||||
|
if (!exists) {
|
||||||
|
boot2docker.init(function (err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (!boot2docker.sshKeyExists()) {
|
||||||
|
callback('Boot2Docker SSH key doesn\'t exist. Fix by removing the existing Boot2Docker VM and re-run the installer. This usually occurs because an old version of Boot2Docker is installed.');
|
||||||
|
} else {
|
||||||
|
boot2docker.isoVersion(function (err, version) {
|
||||||
|
if (err || util.compareVersions(version, boot2docker.version()) < 0) {
|
||||||
|
boot2docker.stop(function(err) {
|
||||||
|
boot2docker.upgrade(function (err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
message: 'Setting up the Docker VM...'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
run: function (callback) {
|
||||||
|
boot2docker.waitWhileStatus('saving', function (err) {
|
||||||
|
boot2docker.status(function (err, status) {
|
||||||
|
if (err) {callback(err); return;}
|
||||||
|
if (status !== 'running') {
|
||||||
|
boot2docker.start(function (err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
message: 'Starting the Docker VM...'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
run: function (callback) {
|
||||||
|
boot2docker.ip(function (err, ip) {
|
||||||
|
if (err) {callback(err); return;}
|
||||||
|
console.log('Setting host IP to: ' + ip);
|
||||||
|
// Docker.setHost(ip);
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
message: 'Detecting Docker VM...'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
var Setup = React.createClass({
|
||||||
|
mixins: [ Router.Navigation ],
|
||||||
|
render: function () {
|
||||||
|
var radial;
|
||||||
|
if (this.state.progress) {
|
||||||
|
radial = <Radial progress={this.state.progress}/>;
|
||||||
|
} else {
|
||||||
|
radial = <Radial spin="true" progress="92"/>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="setup">
|
||||||
|
{radial}
|
||||||
|
<p>{this.state.message}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
componentWillMount: function () {
|
||||||
|
this.setState({});
|
||||||
|
},
|
||||||
|
componentDidMount: function () {
|
||||||
|
var self = this;
|
||||||
|
this.setup(function (err) {
|
||||||
|
boot2docker.ip(function (err, ip) {
|
||||||
|
docker.setHost(ip);
|
||||||
|
self.transitionTo('containers');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setup: function (callback) {
|
||||||
|
var self = this;
|
||||||
|
var currentStep = 0;
|
||||||
|
async.eachSeries(setupSteps, function (step, callback) {
|
||||||
|
console.log('Performing step ' + currentStep);
|
||||||
|
self.setState({progress: 0});
|
||||||
|
self.setState({message: step.message});
|
||||||
|
step.run(function (err) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
} else {
|
||||||
|
currentStep += 1;
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}, function (progress) {
|
||||||
|
self.setState({progress: progress});
|
||||||
|
});
|
||||||
|
}, function (err) {
|
||||||
|
if (err) {
|
||||||
|
// if any of the steps fail
|
||||||
|
console.log('Kitematic setup failed at step ' + currentStep);
|
||||||
|
console.log(err);
|
||||||
|
self.setState({error: err});
|
||||||
|
callback(err);
|
||||||
|
} else {
|
||||||
|
// Setup Finished
|
||||||
|
console.log('Setup finished.');
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = Setup;
|
18
app/Store.js
18
app/Store.js
|
@ -1,18 +0,0 @@
|
||||||
var flux = require('flux-react');
|
|
||||||
var actions = require('./actions.js');
|
|
||||||
|
|
||||||
module.exports = flux.createStore({
|
|
||||||
messages: [],
|
|
||||||
actions: [
|
|
||||||
actions.addMessage
|
|
||||||
],
|
|
||||||
addMessage: function (message) {
|
|
||||||
this.messages.push(message);
|
|
||||||
this.emitChange();
|
|
||||||
},
|
|
||||||
exports: {
|
|
||||||
getMessages: function () {
|
|
||||||
return this.messages;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,5 +0,0 @@
|
||||||
var flux = require('flux-react');
|
|
||||||
|
|
||||||
module.exports = flux.createActions([
|
|
||||||
'addMessage'
|
|
||||||
]);
|
|
|
@ -6,7 +6,6 @@ var async = require('async');
|
||||||
|
|
||||||
var cmdExec = function (cmd, callback) {
|
var cmdExec = function (cmd, callback) {
|
||||||
exec(cmd, function (stderr, stdout, code) {
|
exec(cmd, function (stderr, stdout, code) {
|
||||||
console.log(stderr, stdout, code);
|
|
||||||
if (code) {
|
if (code) {
|
||||||
callback('Exit code ' + code + ': ' + stderr);
|
callback('Exit code ' + code + ': ' + stderr);
|
||||||
} else {
|
} else {
|
||||||
|
@ -21,12 +20,10 @@ var homeDir = function () {
|
||||||
|
|
||||||
var Boot2Docker = {
|
var Boot2Docker = {
|
||||||
version: function () {
|
version: function () {
|
||||||
var packagejson = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8'));
|
return JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8'))['boot2docker-version'];
|
||||||
return packagejson['boot2docker-version'];
|
|
||||||
},
|
},
|
||||||
cliVersion: function (callback) {
|
cliVersion: function (callback) {
|
||||||
cmdExec([Boot2Docker.command(), 'version'], function (err, out) {
|
cmdExec([Boot2Docker.command(), 'version'], function (err, out) {
|
||||||
console.log(err, out);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
|
@ -61,7 +58,6 @@ var Boot2Docker = {
|
||||||
},
|
},
|
||||||
status: function (callback) {
|
status: function (callback) {
|
||||||
cmdExec([Boot2Docker.command(), 'status'], function (err, out) {
|
cmdExec([Boot2Docker.command(), 'status'], function (err, out) {
|
||||||
console.log(err, out);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
|
@ -192,13 +188,10 @@ var Boot2Docker = {
|
||||||
},
|
},
|
||||||
sshKeyExists: function () {
|
sshKeyExists: function () {
|
||||||
return fs.existsSync(path.join(homeDir(), '.ssh', 'id_boot2docker'));
|
return fs.existsSync(path.join(homeDir(), '.ssh', 'id_boot2docker'));
|
||||||
}
|
},
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = Boot2Docker;
|
// Todo: move me to setup
|
||||||
|
waitWhileStatus: function (status, callback) {
|
||||||
//TODO: move me to setup
|
|
||||||
Boot2Docker.waitWhileStatus = function (status, callback) {
|
|
||||||
var current = status;
|
var current = status;
|
||||||
async.whilst(function () {
|
async.whilst(function () {
|
||||||
return current === status;
|
return current === status;
|
||||||
|
@ -214,4 +207,7 @@ Boot2Docker.waitWhileStatus = function (status, callback) {
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports = Boot2Docker;
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
var dockerode = require('dockerode');
|
||||||
|
|
||||||
|
var Docker = {
|
||||||
|
host: null,
|
||||||
|
setHost: function(host) {
|
||||||
|
this.host = host;
|
||||||
|
},
|
||||||
|
client: function () {
|
||||||
|
var certDir = path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], '.boot2docker/certs/boot2docker-vm');
|
||||||
|
if (!fs.existsSync(certDir)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return 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'))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Docker;
|
|
@ -4,14 +4,8 @@
|
||||||
<link rel="stylesheet" href="main.css"/>
|
<link rel="stylesheet" href="main.css"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<script src="main.js"></script>
|
||||||
<script src="https://cdn.ravenjs.com/1.1.15/jquery,native/raven.min.js"></script>
|
<script src="https://cdn.ravenjs.com/1.1.15/jquery,native/raven.min.js"></script>
|
||||||
<script src="http://localhost:35729/livereload.js"></script>
|
<script src="http://localhost:35729/livereload.js"></script>
|
||||||
<script>
|
|
||||||
Raven.config('https://0a5f032d745d4acaae94ce46f762c586@app.getsentry.com/35057', {
|
|
||||||
// we highly recommend restricting exceptions to a domain in order to filter out clutter
|
|
||||||
// whitelistUrls: ['example.com/scripts/']
|
|
||||||
}).install();
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
79
app/main.js
79
app/main.js
|
@ -1,12 +1,29 @@
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var Router = require('react-router');
|
var Router = require('react-router');
|
||||||
|
var RetinaImage = require('react-retina-image');
|
||||||
var Route = Router.Route;
|
var Route = Router.Route;
|
||||||
var NotFoundRoute = Router.NotFoundRoute;
|
var NotFoundRoute = Router.NotFoundRoute;
|
||||||
var DefaultRoute = Router.DefaultRoute;
|
var DefaultRoute = Router.DefaultRoute;
|
||||||
var Link = Router.Link;
|
var Link = Router.Link;
|
||||||
var RouteHandler = Router.RouteHandler;
|
var RouteHandler = Router.RouteHandler;
|
||||||
|
|
||||||
|
var async = require('async');
|
||||||
|
var docker = require('./docker.js');
|
||||||
var boot2docker = require('./boot2docker.js');
|
var boot2docker = require('./boot2docker.js');
|
||||||
|
var Setup = require('./Setup.react');
|
||||||
|
var Containers = require('./Containers.react');
|
||||||
|
var Container = require('./Container.react');
|
||||||
|
var Radial = require('./Radial.react');
|
||||||
|
|
||||||
|
var NoContainers = React.createClass({
|
||||||
|
render: function () {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Radial spin="true" progress="92"/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var App = React.createClass({
|
var App = React.createClass({
|
||||||
render: function () {
|
render: function () {
|
||||||
|
@ -16,67 +33,27 @@ var App = React.createClass({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var Setup = React.createClass({
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<p>Hello!</p>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
componentWillMount: function () {
|
|
||||||
|
|
||||||
},
|
|
||||||
setup: function () {
|
|
||||||
|
|
||||||
},
|
|
||||||
steps: [
|
|
||||||
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
var Containers = React.createClass({
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<ContainerList/>
|
|
||||||
<RouteHandler/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var ContainerList = React.createClass({
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<ul>
|
|
||||||
<li>Container 1</li>
|
|
||||||
<li>Container 2</li>
|
|
||||||
<li>Container 3</li>
|
|
||||||
<li>Container 4</li>
|
|
||||||
<li>Container 5</li>
|
|
||||||
</ul>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var NoContainers = React.createClass({
|
|
||||||
render: function () {
|
|
||||||
return (
|
|
||||||
<p>No containers</p>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var routes = (
|
var routes = (
|
||||||
<Route name="app" path="/" handler={App}>
|
<Route name="app" path="/" handler={App}>
|
||||||
<DefaultRoute handler={Setup}/>
|
|
||||||
<Route name="containers" handler={Containers}>
|
<Route name="containers" handler={Containers}>
|
||||||
|
<Route name="container" path=":Id" handler={Container}>
|
||||||
|
</Route>
|
||||||
<DefaultRoute handler={NoContainers}/>
|
<DefaultRoute handler={NoContainers}/>
|
||||||
</Route>
|
</Route>
|
||||||
|
<DefaultRoute handler={Setup}/>
|
||||||
<Route name="setup" handler={Setup}>
|
<Route name="setup" handler={Setup}>
|
||||||
</Route>
|
</Route>
|
||||||
</Route>
|
</Route>
|
||||||
);
|
);
|
||||||
|
|
||||||
Router.run(routes, function (Handler) {
|
Router.run(routes, function (Handler) {
|
||||||
|
boot2docker.ip(function (err, ip) {
|
||||||
|
docker.setHost(ip);
|
||||||
React.render(<Handler/>, document.body);
|
React.render(<Handler/>, document.body);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== 'development') {
|
||||||
|
Raven.config('https://0a5f032d745d4acaae94ce46f762c586@app.getsentry.com/35057', {
|
||||||
|
}).install();
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
@import "bootstrap/bootstrap.less";
|
@import "bootstrap/bootstrap.less";
|
||||||
|
@import "setup.less";
|
||||||
|
@import "radial.less";
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background: white;
|
background: white;
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
@import "variables.less";
|
||||||
|
|
||||||
|
@-webkit-keyframes rotating {
|
||||||
|
from{
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to{
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.radial-progress {
|
||||||
|
|
||||||
|
&.radial-spinner {
|
||||||
|
-webkit-animation: rotating 1.2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@circle-size: 96px;
|
||||||
|
@circle-background: transparent;
|
||||||
|
@inset-size: 92px;
|
||||||
|
@inset-color: white;
|
||||||
|
@transition-length: 1s;
|
||||||
|
// @percentage-color: #3FD899;
|
||||||
|
@percentage-font-size: 14px;
|
||||||
|
@percentage-text-width: 57px;
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
width: @circle-size;
|
||||||
|
height: @circle-size;
|
||||||
|
|
||||||
|
background-color: @circle-background;
|
||||||
|
border-radius: 100%;
|
||||||
|
.circle {
|
||||||
|
.mask, .fill, .shadow {
|
||||||
|
width: @circle-size;
|
||||||
|
height: @circle-size;
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
|
.mask, .fill {
|
||||||
|
-webkit-backface-visibility: hidden;
|
||||||
|
transition: -webkit-transform @transition-length;
|
||||||
|
transition: -ms-transform @transition-length;
|
||||||
|
transition: transform @transition-length;
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
|
.mask {
|
||||||
|
clip: rect(0px, @circle-size, @circle-size, @circle-size/2.0);
|
||||||
|
.fill {
|
||||||
|
clip: rect(0px, @circle-size/2.0, @circle-size, 0px);
|
||||||
|
background-color: @brand-action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.inset {
|
||||||
|
width: @inset-size;
|
||||||
|
height: @inset-size;
|
||||||
|
position: absolute;
|
||||||
|
margin-left: (@circle-size - @inset-size) / 2.0;
|
||||||
|
margin-top: (@circle-size - @inset-size) / 2.0;
|
||||||
|
|
||||||
|
background-color: @inset-color;
|
||||||
|
border-radius: 100%;
|
||||||
|
.percentage {
|
||||||
|
width: @percentage-text-width;
|
||||||
|
position: absolute;
|
||||||
|
top: (@inset-size - @percentage-font-size) / 2.0;
|
||||||
|
left: (@inset-size - @percentage-text-width) / 2.0;
|
||||||
|
|
||||||
|
line-height: 1;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
// color: @percentage-color;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: @percentage-font-size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
&.radial-negative .circle .mask .fill {
|
||||||
|
background-color: @brand-negative;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.radial-positive .circle .mask .fill {
|
||||||
|
background-color: @brand-positive;
|
||||||
|
}
|
||||||
|
|
||||||
|
@i: 0;
|
||||||
|
@increment: 180deg / 100;
|
||||||
|
.loop (@i) when (@i <= 100) {
|
||||||
|
&[data-progress="@{i}"] {
|
||||||
|
.circle {
|
||||||
|
.mask.full, .fill {
|
||||||
|
-webkit-transform: rotate(@increment * @i);
|
||||||
|
-ms-transform: rotate(@increment * @i);
|
||||||
|
transform: rotate(@increment * @i);
|
||||||
|
}
|
||||||
|
.fill.fix {
|
||||||
|
-webkit-transform: rotate(@increment * @i * 2);
|
||||||
|
-ms-transform: rotate(@increment * @i * 2);
|
||||||
|
transform: rotate(@increment * @i * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.inset .percentage:before {
|
||||||
|
content: "@{i}%"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.loop(@i + 1);
|
||||||
|
}
|
||||||
|
.loop(@i);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
.setup {
|
||||||
|
margin-top: 25%;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
@brand-action: #4A9AEC;
|
||||||
|
@brand-positive: #3AD86D;
|
||||||
|
@brand-negative: #F74B1F;
|
|
@ -0,0 +1,90 @@
|
||||||
|
var path = require('path');
|
||||||
|
var fs = require('fs');
|
||||||
|
var nodeCrypto = require('crypto');
|
||||||
|
var request = require('request');
|
||||||
|
var progress = require('request-progress');
|
||||||
|
var ncp = require('ncp').ncp;
|
||||||
|
var exec = require('exec');
|
||||||
|
|
||||||
|
var Util = {
|
||||||
|
download: function (url, filename, checksum, callback, progressCallback) {
|
||||||
|
var doDownload = function () {
|
||||||
|
progress(request(url), {
|
||||||
|
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;
|
|
@ -0,0 +1,109 @@
|
||||||
|
var fs = require('fs');
|
||||||
|
var exec = require('exec');
|
||||||
|
var path = require('path');
|
||||||
|
var async = require('async');
|
||||||
|
|
||||||
|
var VirtualBox = {
|
||||||
|
REQUIRED_VERSION: '4.3.18',
|
||||||
|
INCLUDED_VERSION: '4.3.18',
|
||||||
|
INSTALLER_FILENAME: 'virtualbox-4.3.18.pkg',
|
||||||
|
INSTALLER_CHECKSUM: '5836c94481c460c648b9216386591a2915293ac86b9bb6c57746637796af6af2',
|
||||||
|
command: function () {
|
||||||
|
return '/usr/bin/VBoxManage';
|
||||||
|
},
|
||||||
|
installed: function () {
|
||||||
|
return fs.existsSync('/usr/bin/VBoxManage') && fs.existsSync('/Applications/VirtualBox.app/Contents/MacOS/VirtualBox');
|
||||||
|
},
|
||||||
|
install: function (callback) {
|
||||||
|
// -W waits for the process to close before finishing.
|
||||||
|
exec('open -W ' + path.join(process.cwd(), 'resources', this.INSTALLER_FILENAME).replace(' ', '\\ '), function (stderr, stdout, code) {
|
||||||
|
if (code) {
|
||||||
|
callback(stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback(null);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
version: function (callback) {
|
||||||
|
if (!this.installed()) {
|
||||||
|
callback('VirtualBox not installed.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
exec('/usr/bin/VBoxManage -v', function (stderr, stdout, code) {
|
||||||
|
if (code) {
|
||||||
|
callback(stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Output is x.x.xryyyyyy
|
||||||
|
var match = stdout.match(/(\d+\.\d+\.\d+).*/);
|
||||||
|
if (!match || match.length < 2) {
|
||||||
|
callback('VBoxManage -v output format not recognized.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback(null, match[1]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
saveVMs: function (callback) {
|
||||||
|
if (!this.installed()) {
|
||||||
|
callback('VirtualBox not installed.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
exec('list runningvms | sed -E \'s/.*\\{(.*)\\}/\\1/\' | xargs -L1 -I {} VBoxManage controlvm {} savestate', function (stderr, stdout, code) {
|
||||||
|
if (code) {
|
||||||
|
callback(stderr);
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
kill: function (callback) {
|
||||||
|
this.saveRunningVMs(function (err) {
|
||||||
|
if (err) {callback(err); return;}
|
||||||
|
exec('pkill VirtualBox', function (stderr, stdout, code) {
|
||||||
|
if (code) {callback(stderr); return;}
|
||||||
|
exec('pkill VBox', function (stderr, stdout, code) {
|
||||||
|
if (code) {callback(stderr); return;}
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
vmState: function (name, callback) {
|
||||||
|
exec(this.command() + ' showvminfo ' + name + ' --machinereadable', function (stderr, stdout, code) {
|
||||||
|
if (code) { callback(stderr); return; }
|
||||||
|
var match = stdout.match(/VMState="(\w+)"/);
|
||||||
|
if (!match) {
|
||||||
|
callback('Could not parse VMState');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback(null, match[1]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteVM:function (name, callback) {
|
||||||
|
VirtualBox.vmState(name, function (err, state) {
|
||||||
|
// No VM found
|
||||||
|
if (err) { callback(null, false); return; }
|
||||||
|
VirtualBox.exec('controlvm ' + name + ' acpipowerbutton', function (stderr, stdout, code) {
|
||||||
|
if (code) { callback(stderr, false); return; }
|
||||||
|
var state = null;
|
||||||
|
|
||||||
|
async.until(function () {
|
||||||
|
return state === 'poweroff';
|
||||||
|
}, function (callback) {
|
||||||
|
VirtualBox.vmState(name, function (err, newState) {
|
||||||
|
if (err) { callback(err); return; }
|
||||||
|
state = newState;
|
||||||
|
setTimeout(callback, 250);
|
||||||
|
});
|
||||||
|
}, function (err) {
|
||||||
|
VirtualBox.exec('unregistervm ' + name + ' --delete', function (stderr, stdout, code) {
|
||||||
|
if (code) { callback(err); return; }
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = VirtualBox;
|
|
@ -10,7 +10,11 @@ var app = require('app');
|
||||||
var BrowserWindow = require('browser-window');
|
var BrowserWindow = require('browser-window');
|
||||||
var ipc = require('ipc');
|
var ipc = require('ipc');
|
||||||
|
|
||||||
var argv = require('minimist')(process.argv.slice(2));
|
var argv = require('minimist')(process.argv);
|
||||||
|
|
||||||
|
if (argv.test) {
|
||||||
|
console.log('Running tests');
|
||||||
|
}
|
||||||
|
|
||||||
app.on('activate-with-no-open-windows', function () {
|
app.on('activate-with-no-open-windows', function () {
|
||||||
if (mainWindow) {
|
if (mainWindow) {
|
||||||
|
@ -22,17 +26,22 @@ app.on('activate-with-no-open-windows', function () {
|
||||||
app.on('ready', function() {
|
app.on('ready', function() {
|
||||||
// Create the browser window.
|
// Create the browser window.
|
||||||
var windowOptions = {
|
var windowOptions = {
|
||||||
width: 960,
|
width: 1200,
|
||||||
height: 640,
|
height: 800,
|
||||||
resizable: true,
|
resizable: true,
|
||||||
frame: false,
|
frame: true,
|
||||||
'web-preferences': {
|
'web-preferences': {
|
||||||
'web-security': false
|
'web-security': false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mainWindow = new BrowserWindow(windowOptions);
|
mainWindow = new BrowserWindow(windowOptions);
|
||||||
mainWindow.hide();
|
mainWindow.hide();
|
||||||
|
|
||||||
|
if (argv.test) {
|
||||||
|
mainWindow.loadUrl('file://' + __dirname + '/../build/specs.html');
|
||||||
|
} else{
|
||||||
mainWindow.loadUrl('file://' + __dirname + '/../build/index.html');
|
mainWindow.loadUrl('file://' + __dirname + '/../build/index.html');
|
||||||
|
}
|
||||||
|
|
||||||
process.on('uncaughtException', app.quit);
|
process.on('uncaughtException', app.quit);
|
||||||
|
|
||||||
|
@ -51,6 +60,8 @@ app.on('ready', function() {
|
||||||
mainWindow.show();
|
mainWindow.show();
|
||||||
mainWindow.focus();
|
mainWindow.focus();
|
||||||
|
|
||||||
|
mainWindow.setTitle('');
|
||||||
|
|
||||||
// Auto Updates
|
// Auto Updates
|
||||||
autoUpdater.setFeedUrl('https://updates.kitematic.com/releases/latest?version=' + app.getVersion());
|
autoUpdater.setFeedUrl('https://updates.kitematic.com/releases/latest?version=' + app.getVersion());
|
||||||
|
|
||||||
|
|
49
gulpfile.js
49
gulpfile.js
|
@ -24,8 +24,10 @@ var packagejson = require('./package.json');
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
|
|
||||||
var dependencies = Object.keys(packagejson.dependencies);
|
var dependencies = Object.keys(packagejson.dependencies);
|
||||||
|
var devDependencies = Object.keys(packagejson.devDependencies);
|
||||||
var options = {
|
var options = {
|
||||||
dev: process.argv.indexOf('release') === -1,
|
dev: process.argv.indexOf('release') === -1,
|
||||||
|
test: process.argv.indexOf('test') !== -1,
|
||||||
filename: 'Kitematic.app',
|
filename: 'Kitematic.app',
|
||||||
name: 'Kitematic',
|
name: 'Kitematic',
|
||||||
signing_identity: process.env.XCODE_SIGNING_IDENTITY
|
signing_identity: process.env.XCODE_SIGNING_IDENTITY
|
||||||
|
@ -36,7 +38,11 @@ gulp.task('js', function () {
|
||||||
entries: ['./app/main.js'], // Only need initial file, browserify finds the rest
|
entries: ['./app/main.js'], // Only need initial file, browserify finds the rest
|
||||||
transform: [reactify], // We want to convert JSX to normal javascript
|
transform: [reactify], // We want to convert JSX to normal javascript
|
||||||
debug: options.dev, // Gives us sourcemapping
|
debug: options.dev, // Gives us sourcemapping
|
||||||
ignoreMissing: true,
|
builtins: false,
|
||||||
|
commondir: false,
|
||||||
|
insertGlobals: false,
|
||||||
|
detectGlobals: false,
|
||||||
|
bundleExternal: false,
|
||||||
cache: {}, packageCache: {}, fullPaths: options.dev // Requirement of watchify
|
cache: {}, packageCache: {}, fullPaths: options.dev // Requirement of watchify
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -45,6 +51,10 @@ gulp.task('js', function () {
|
||||||
bundler.external(dep);
|
bundler.external(dep);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
devDependencies.forEach(function (dep) {
|
||||||
|
bundler.external(dep);
|
||||||
|
});
|
||||||
|
|
||||||
bundler.external('./app');
|
bundler.external('./app');
|
||||||
|
|
||||||
var bundle = function () {
|
var bundle = function () {
|
||||||
|
@ -53,7 +63,7 @@ gulp.task('js', function () {
|
||||||
.pipe(source('main.js'))
|
.pipe(source('main.js'))
|
||||||
.pipe(gulpif(!options.dev, streamify(uglify())))
|
.pipe(gulpif(!options.dev, streamify(uglify())))
|
||||||
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
|
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
|
||||||
.pipe(gulpif(options.dev, livereload()));
|
.pipe(gulpif(options.dev && !options.test, livereload()));
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options.dev) {
|
if (options.dev) {
|
||||||
|
@ -76,25 +86,30 @@ gulp.task('specs', function () {
|
||||||
bundler.external(dep);
|
bundler.external(dep);
|
||||||
});
|
});
|
||||||
|
|
||||||
var bundle = function () {
|
devDependencies.forEach(function (dep) {
|
||||||
|
bundler.external(dep);
|
||||||
|
});
|
||||||
|
|
||||||
|
bundler.external('./app');
|
||||||
|
|
||||||
bundler.bundle()
|
bundler.bundle()
|
||||||
.on('error', gutil.log)
|
.on('error', gutil.log)
|
||||||
.pipe(source('specs.js'))
|
.pipe(source('specs.js'))
|
||||||
.pipe(gulp.dest('./build'));
|
.pipe(gulp.dest('./build'));
|
||||||
};
|
|
||||||
|
|
||||||
bundle();
|
gulp.src('./specs/specs.html')
|
||||||
|
.pipe(gulp.dest('./build'));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('images', function() {
|
gulp.task('images', function() {
|
||||||
return gulp.src('./app/images/**')
|
return gulp.src('./app/images/*')
|
||||||
.pipe(imagemin({
|
.pipe(imagemin({
|
||||||
progressive: true,
|
progressive: true,
|
||||||
interlaced: true,
|
interlaced: true,
|
||||||
svgoPlugins: [{removeViewBox: false}]
|
svgoPlugins: [{removeViewBox: false}]
|
||||||
}))
|
}))
|
||||||
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
|
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
|
||||||
.pipe(gulpif(options.dev, livereload()));
|
.pipe(gulpif(options.dev && !options.test, livereload()));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('styles', function () {
|
gulp.task('styles', function () {
|
||||||
|
@ -106,7 +121,7 @@ gulp.task('styles', function () {
|
||||||
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/Contents/Resources/app/build'))
|
.pipe(gulp.dest(options.dev ? './build' : './dist/osx/' + options.filename + '/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 && !options.test, livereload()));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('download', function (cb) {
|
gulp.task('download', function (cb) {
|
||||||
|
@ -119,7 +134,7 @@ gulp.task('download', function (cb) {
|
||||||
gulp.task('copy', function () {
|
gulp.task('copy', function () {
|
||||||
gulp.src('./app/index.html')
|
gulp.src('./app/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.filename + '/Contents/Resources/app/build'))
|
||||||
.pipe(gulpif(options.dev, livereload()));
|
.pipe(gulpif(options.dev && !options.test, livereload()));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('dist', function (cb) {
|
gulp.task('dist', function (cb) {
|
||||||
|
@ -144,7 +159,7 @@ gulp.task('dist', function (cb) {
|
||||||
filename: options.filename,
|
filename: options.filename,
|
||||||
name: options.name,
|
name: options.name,
|
||||||
version: packagejson.version,
|
version: packagejson.version,
|
||||||
bundle: 'com.kitematic.kitematic'
|
bundle: 'com.kitematic.app'
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -181,10 +196,18 @@ gulp.task('release', function () {
|
||||||
runSequence('download', 'dist', ['copy', 'images', 'js', 'styles'], 'sign', 'zip');
|
runSequence('download', 'dist', ['copy', 'images', 'js', 'styles'], 'sign', 'zip');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task('test', ['download', 'copy', 'js', 'images', 'styles', 'specs'], function () {
|
||||||
|
var env = process.env;
|
||||||
|
env.NODE_ENV = 'development';
|
||||||
|
gulp.src('').pipe(shell(['./cache/Atom.app/Contents/MacOS/Atom . --test'], {
|
||||||
|
env: env
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
gulp.task('default', ['download', 'copy', 'js', 'images', 'styles'], function () {
|
gulp.task('default', ['download', 'copy', 'js', 'images', 'styles'], function () {
|
||||||
gulp.watch('./app/**/*.html', ['copy']);
|
gulp.watch('./app/**/*.html', ['copy']);
|
||||||
gulp.watch('./app/images/**', ['images']);
|
gulp.watch('./app/images/**', ['images']);
|
||||||
gulp.watch('./app/styles/**/*.less', ['styles']);
|
gulp.watch('./app/styles/**', ['styles']);
|
||||||
|
|
||||||
livereload.listen();
|
livereload.listen();
|
||||||
|
|
||||||
|
@ -194,7 +217,3 @@ gulp.task('default', ['download', 'copy', 'js', 'images', 'styles'], function ()
|
||||||
env: env
|
env: env
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('test', function () {
|
|
||||||
return gulp.src('./app/__tests__').pipe(jest());
|
|
||||||
});
|
|
||||||
|
|
|
@ -37,7 +37,8 @@
|
||||||
"react": "^0.12.1",
|
"react": "^0.12.1",
|
||||||
"request": "2.42.0",
|
"request": "2.42.0",
|
||||||
"request-progress": "0.3.1",
|
"request-progress": "0.3.1",
|
||||||
"tar": "0.1.20"
|
"tar": "0.1.20",
|
||||||
|
"retina.js": "^1.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"browserify": "^6.2.0",
|
"browserify": "^6.2.0",
|
||||||
|
@ -60,6 +61,7 @@
|
||||||
"gulp-uglify": "^0.3.1",
|
"gulp-uglify": "^0.3.1",
|
||||||
"gulp-util": "^3.0.0",
|
"gulp-util": "^3.0.0",
|
||||||
"jasmine-tagged": "^1.1.2",
|
"jasmine-tagged": "^1.1.2",
|
||||||
|
"object-assign": "^2.0.0",
|
||||||
"reactify": "^0.15.2",
|
"reactify": "^0.15.2",
|
||||||
"run-sequence": "^1.0.2",
|
"run-sequence": "^1.0.2",
|
||||||
"vinyl-source-stream": "^0.1.1",
|
"vinyl-source-stream": "^0.1.1",
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
source $DIR/env
|
||||||
|
|
||||||
|
gulp test
|
|
@ -1,11 +1,11 @@
|
||||||
var App = require('./../app/App.js');
|
var Containers = require('./../app/Containers.react.js');
|
||||||
var TestUtils = require('react/addons').TestUtils;
|
var TestUtils = require('react/addons').TestUtils;
|
||||||
|
var jasmine = require('jasmine-node');
|
||||||
|
|
||||||
describe("App", function() {
|
describe('Containers', function() {
|
||||||
|
it('should be wrapped with a div', function() {
|
||||||
it("should be wrapped with a div", function() {
|
// var app = TestUtils.renderIntoDocument(App());
|
||||||
var app = TestUtils.renderIntoDocument(App());
|
expect(true).toEqual(true);
|
||||||
expect(app.getDOMNode().tagName).toEqual('DIV');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="main.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="specs.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue