Skip to content

Commit

Permalink
[api] More work on app and snapshot commands
Browse files Browse the repository at this point in the history
  • Loading branch information
indexzero committed Mar 7, 2011
1 parent a183338 commit d51860b
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 42 deletions.
16 changes: 14 additions & 2 deletions lib/jitsu/api/apps.js
Expand Up @@ -46,6 +46,18 @@ Apps.prototype.create = function (app, callback) {
});
};

//
// ### function view (name, callback)
// #### @name {string} Name of the application to view
// #### @callback {function} Continuation to pass control to when complete
// Views the application specified by `name`.
//
Apps.prototype.view = function (name, callback) {
this._request('GET', ['apps', jitsu.config.username, name], callback, function (res, result) {
callback(null, result.app);
});
};

//
// ### function update (name, attrs, callback)
// #### @name {string} Name of the application to update
Expand All @@ -54,8 +66,8 @@ Apps.prototype.create = function (app, callback) {
// Updates the application with `name` with the specified attributes in `attrs`
//
Apps.prototype.update = function (name, attrs, callback) {
this._request('PUT', ['apps', name], attrs, callback, function (res, result) {

this._request('PUT', ['apps', jitsu.config.username, name], attrs, callback, function (res, result) {
callback();
});
};

Expand Down
119 changes: 89 additions & 30 deletions lib/jitsu/commands/apps.js
Expand Up @@ -5,11 +5,49 @@
*
*/

var winston = require('winston'),
var eyes = require('eyes'),
winston = require('winston'),
jitsu = require('jitsu');

var apps = exports;

//
// ### function list (callback)
// #### @name {string} **optional** Name of the application to create
// #### @callback {function} Continuation to pass control to when complete.
// Creates an application for the package.json in the current directory
// using `name` if supplied and falling back to `package.name`.
//
apps.create = function (name, callback) {
jitsu.utils.readPackage(process.cwd(), function (err, pkg) {
if (!callback) {
callback = name;
name = null;
}

pkg.name = name || pkg.name;
jitsu.apps.list(function (err, apps) {
var existing = apps.filter(function (a) { return a.name === pkg.name });
if (existing.length > 0) {
return winston.warn('Cannot create duplicate application ' + pkg.name.magenta);
}

//
// TODO (indexzero): Configure this default value in nodejitsu APIs
//
pkg.state = 'stopped';
winston.info('Validating package.json for ' + pkg.name.magenta);
jitsu.prompt.addProperties(pkg, ['subdomain'], function (updated) {
winston.info('Creating app ' + pkg.name.magenta);
jitsu.apps.create(updated, function (err, res, result) {
winston.silly('Done creating app ' + pkg.name.magenta);
return err ? callback(err) : callback();
});
});
});
});
};

//
// ### function list (callback)
// #### @callback {function} Continuation to pass control to when complete.
Expand Down Expand Up @@ -40,41 +78,38 @@ apps.list = function (callback) {
};

//
// ### function list (callback)
// #### @name {string} **optional** Name of the application to create
// ### function view (name, callback)
// #### @name {string} **optional** Name of the application to view
// #### @callback {function} Continuation to pass control to when complete.
// Creates an application for the package.json in the current directory
// using `name` if supplied and falling back to `package.name`.
// Views the application with the specfied `name` for the authenticated user.
// If no name is supplied this will view the application in the current directory.
//
apps.create = function (name, callback) {
jitsu.utils.readPackage(process.cwd(), function (err, pkg) {
if (!callback) {
callback = name;
name = null;
}

pkg.name = name || pkg.name;
jitsu.apps.list(function (err, apps) {
var existing = apps.filter(function (a) { return a.name === pkg.name });
if (existing.length > 0) {
return winston.warn('Cannot create duplicate application ' + pkg.name.magenta);
apps.view = function (name, callback) {
if (!callback) {
callback = name;
return jitsu.utils.readPackage(process.cwd(), function (err, package) {
name = package.name;
executeView();
});
}


function executeView() {
jitsu.apps.view(name, function (err, app) {
if (err) {
return callback(err);
}

//
// TODO (indexzero): Configure this default value in nodejitsu APIs
// TODO (indexzero): Better object inspection
//
pkg.state = 'stopped';
winston.info('Validating package.json for ' + pkg.name.magenta);
jitsu.prompt.addProperties(pkg, ['subdomain'], function (updated) {
winston.info('Creating app ' + pkg.name.magenta);
jitsu.apps.create(updated, function (err, res, result) {
winston.silly('Done creating app ' + pkg.name.magenta);
return err ? callback(err) : callback();
});
});
eyes.inspect(app);
callback();
});
});
};
}

executeView();
}

//
// ### function list (callback)
Expand All @@ -85,9 +120,33 @@ apps.create = function (name, callback) {
apps.update = function (name, callback) {
if (!callback) {
callback = name;
name = null;
}


winston.silly('Reading package.json in ' + process.cwd());
jitsu.utils.readPackage(process.cwd(), function (err, pkg) {
if (err) {
return callback(err);
}

name = name || pkg.name;
jitsu.apps.view(name, function (err, app) {
if (err) {
return callback(err);
}

var diff = jitsu.utils.objectDiff(app, pkg);
if (!diff) {
winston.warn('No changes found to your package.json for ' + name.magenta);
return callback();
}

winston.info('Updating application ' + name.magenta + ' with:');
eyes.inspect(diff);

jitsu.apps.update(name, diff, callback);
});
});
};

//
Expand Down
30 changes: 20 additions & 10 deletions lib/jitsu/commands/snapshots.js
Expand Up @@ -28,18 +28,28 @@ snapshots.list = function (name, callback) {

function executeList () {
jitsu.snapshots.list(name, function (err, snapshots) {
var rows = [['filename', 'created', 'md5']],
colors = ['underline', 'yellow', 'grey'];
if (err) {
return callback(err);
}

if (snapshots && snapshots.length > 0) {
var rows = [['filename', 'created', 'md5']],
colors = ['underline', 'yellow', 'grey'];

snapshots.forEach(function (snap) {
rows.push([
snap.filename,
jitsu.utils.snapshotTime(snap.filename),
snap.md5
]);
});
snapshots.forEach(function (snap) {
rows.push([
snap.filename,
jitsu.utils.snapshotTime(snap.filename),
snap.md5
]);
});

jitsu.log.logRows('data', rows, colors);
jitsu.log.logRows('data', rows, colors);
}
else {
winston.warn('No snapshots for application ' + name.magenta);
}

callback();
});
}
Expand Down
80 changes: 80 additions & 0 deletions lib/jitsu/utils/index.js
Expand Up @@ -7,6 +7,7 @@

var jitsu = require('jitsu'),
util = require('util'),
eyes = require('eyes'),
spawn = require('child_process').spawn,
fs = require('fs'),
path = require('path');
Expand Down Expand Up @@ -105,4 +106,83 @@ utils.createPackage = function (dir, callback) {
callback(null, pkg, tarball);
});
});
};

//
// ### function missingKeys (source, target)
// #### @source {Array} List of keys for the current object
// #### @target {Array} List of keys for the new object
// Returns the complement of the intersection of the two arrays.
//
// e.g. [1,2,3,5], [1,2,3,4,5] => [4]
//
utils.missingKeys = function (source, target) {
var missing = [];

source.forEach(function (key) {
if (target.indexOf(key) === -1) {
missing.push(key);
}
});

return missing;
};

//
// ### function objectDiff (current, update, level)
// #### @current {Object} Current representation of the object.
// #### @update {Object} Updated representation of the object.
// #### @level {Number} Level in the object we are diffing.
// Returns an incremental diff of the `current` object
// against the updated representation `update`
//
// e.g. { foo: 1, bar: 2 }, { foo: 2, bar: 2 } => { foo: 2 }
//
utils.objectDiff = function (current, update, level) {
var ckeys = Object.keys(current),
ukeys = Object.keys(update),
diff = {};

//
// Ignore changes on the first level of the object.
//
level = level || 0;
if (level > 0) {
utils.missingKeys(ckeys, ukeys).forEach(function (key) {
diff[key] = undefined;
});
}

ukeys.forEach(function (key) {
var nested;

if (!current[key]) {
diff[key] = update[key];
}
else if (Array.isArray(update[key])) {
if (update[key].length !== current[key].length) {
diff[key] = update[key];
}
else {
for (var i = 0; i < update[key]; i++) {
if (current[key].indexOf(update[key][i]) === -1) {
diff[key] = update[key];
break;
}
}
}
}
else if (typeof update[key] === 'object') {
if ((nested = utils.objectDiff(current[key], update[key], level + 1))) {
diff[key] = update[key];
}
}
else {
if (current[key] !== update[key]) {
diff[key] = update[key];
}
}
});

return Object.keys(diff).length > 0 ? diff : null;
};

0 comments on commit d51860b

Please sign in to comment.