Daily checkpoint. Implement list command and before filters.

This commit is contained in:
Michael Bleigh
2015-07-14 19:09:41 -07:00
committed by Michael Bleigh
parent 67a6cc81ca
commit a09855b99e
13 changed files with 124 additions and 35 deletions

View File

@@ -13,6 +13,14 @@ var path = require('path');
var logFilename = path.join(process.cwd(), '/firebase-debug.log');
process.on('exit', function(code) {
code = process.exitCode || code;
if (code < 2 && fs.existsSync(logFilename)) {
fs.unlinkSync(logFilename);
}
});
require('exit-code');
logger.add(winston.transports.Console, {
level: process.env.DEBUG ? 'debug' : 'info',
showLevel: true,
@@ -32,7 +40,8 @@ try {
if (err.name !== 'FirebaseError') {
err = new FirebaseError('An unexpected error has occurred. Please contact support', {
status: 500,
original: e
original: err,
exit: 2
});
}
errorOut(client, err);
@@ -41,11 +50,3 @@ try {
if (!process.argv.slice(2).length) {
client.cli.help();
}
process.on('exit', function(code) {
code = process.exitCode || code;
if (code < 2 && fs.existsSync(logFilename)) {
fs.unlinkSync(logFilename);
}
});
require('exit-code');

View File

@@ -8,6 +8,7 @@ module.exports = function(client) {
};
client.init = loadCommand('init');
client.list = loadCommand('list');
client.login = loadCommand('login');
client.logout = loadCommand('logout');
client.serve = loadCommand('serve');

View File

@@ -6,12 +6,29 @@ var path = require('path');
var defaultConfig = require('../templates/firebase.json');
var _ = require('lodash');
var logger = require('../lib/logger');
var homeDir = require('user-home');
module.exports = new Command('init')
.description('setup a Firebase app in the current directory')
.option('-f, --firebase <firebase>', 'the name of the firebase to use')
.option('-p, --public <dir>', 'the name of your app\'s public directory')
.action(function(options, resolve) {
var cwd = process.cwd();
if (path.relative(homeDir, cwd).match(/^\.\./)) {
logger.warn('Initializing outside your home directory');
}
if (cwd === homeDir) {
logger.warn('Initializing directly at your home directory');
}
var emptyDir = fs.readdirSync(cwd).length === 0;
if (!emptyDir) {
logger.warn('Initializing in a non-empty directory');
}
if (fs.existsSync(path.join(cwd, 'firebase.json'))) {
logger.warn('firebase.json already present, will be overwritten by this command');
}
prompt(options, [
{
type: 'input',
@@ -30,13 +47,13 @@ module.exports = new Command('init')
message: 'What directory should be your public dir?',
'default': '.',
validate: function(answer) {
if (!fs.existsSync(path.resolve(process.cwd(), answer))) {
if (!fs.existsSync(path.resolve(cwd, answer))) {
return 'Public directory must already exist';
}
return true;
},
filter: function(input) {
input = path.relative(process.cwd(), input);
input = path.relative(cwd, input);
if (input === '') { input = '.'; }
return input;
}
@@ -46,7 +63,7 @@ module.exports = new Command('init')
firebase: options.firebase,
'public': options.public
}), undefined, 2);
fs.writeFileSync(path.join(process.cwd(), 'firebase.json'), config);
fs.writeFileSync(path.join(cwd, 'firebase.json'), config);
logger.info('Firebase initialized, configuration written to firebase.json');
resolve();
});

21
commands/list.js Normal file
View File

@@ -0,0 +1,21 @@
'use strict';
var Command = require('../lib/command');
var api = require('../lib/api');
var requireAuth = require('../lib/requireAuth');
var logList = require('../lib/logList');
module.exports = new Command('list')
.description('list the Firebases to which you have access')
.before(requireAuth)
.action(function(options, resolve, reject) {
api.request('GET', '/account', {}, true, function(statusCode, response) {
if (response.firebases) {
var list = Object.keys(response.firebases).sort();
logList('info', 'Firebases for your account', list);
resolve(response.firebases);
} else {
reject('uh oh');
}
});
});

View File

@@ -13,7 +13,7 @@ var ticketsRef = new Firebase('https://gauth.firebaseio.com/tickets');
module.exports = new Command('login')
.description('sign in to your Google account')
.action(function(options, resolve) {
.action(function(options, resolve, reject) {
var user = configstore.get('user');
if (user) {
logger.info('Already logged in as', chalk.bold(user.google.email));
@@ -21,9 +21,8 @@ module.exports = new Command('login')
} else {
var ticket = uuid.v4();
var url = 'https://gauth.firebaseapp.com/?ticket=' + ticket;
// allow 5 minutes to consume the ticket
var ticketRef = ticketsRef.child(ticket);
ticketRef.set({
createdAt: Firebase.ServerValue.TIMESTAMP
}, function(err) {

View File

@@ -1,12 +1,12 @@
'use strict';
var prompt = require('prompt');
var prompt = require('./prompt');
var fs = require('fs');
var path = require('path');
var api = require('./api');
var util = require('util');
var chalk = require('chalk');
var _when = require('when');
var RSVP = require('RSVP');
var FirebaseError = require('./error');
var auth = {
@@ -17,7 +17,7 @@ var auth = {
maxRetries: 3,
requireLogin: function(argv, callback) {
var that = this;
if (argv.email && argv.password) {
this._attemptLogin(argv, this.maxRetries, callback);
} else if ((this.email.length === 0) || (this.token.length === 0)) {
@@ -281,7 +281,7 @@ var auth = {
return config;
},
listFirebases: function(argv) {
return _when.promise(function(resolve, reject) {
return new RSVP.Promise(function(resolve, reject) {
auth.requireLogin(argv, function(err) {
if (err) {
var error = new FirebaseError('Login Unsuccessful', {

View File

@@ -9,6 +9,7 @@ var Command = function(name) {
this._description = null;
this._options = [];
this._action = null;
this._befores = [];
};
Command.prototype.description = function(description) {
@@ -21,13 +22,13 @@ Command.prototype.option = function() {
return this;
};
Command.prototype.before = function(fn) {
this._befores.push(fn);
return this;
};
Command.prototype.action = function(fn) {
this._action = function(options) {
options = options || {};
return new RSVP.Promise(function(resolve, reject) {
fn(options, resolve, reject);
});
};
this._action = fn;
return this;
};
@@ -41,13 +42,20 @@ Command.prototype.register = function(client) {
var self = this;
cmd.action(function(options) {
self._action(options).then(function() {
logger.info(chalk.bold(self.name), 'completed successfully');
var tasks = self._befores.concat(self._action);
tasks.reduce(function(cur, next) {
return cur.then(function() {
return new RSVP.Promise(function(resolve, reject) {
next(options, resolve, reject);
});
});
}, RSVP.resolve()).then(function() {
logger.info(chalk.green('✔ '), chalk.bold(self.name), 'completed successfully');
process.exit();
}, client.errorOut);
});
return cmd;
return cmd;
});
};
module.exports = Command;

View File

@@ -9,6 +9,7 @@ var FirebaseError = function(message, options) {
this.status = options.status || 500;
this.exit = options.exit || 1;
this.stack = (new Error()).stack;
this.original = options.original;
};
FirebaseError.prototype = Object.create(Error.prototype);

View File

@@ -7,5 +7,5 @@ module.exports = function(client, error) {
process.exitCode = error.exit || 2;
setTimeout(function() {
process.exit();
}, 1000);
}, 250);
};

View File

@@ -14,10 +14,7 @@ module.exports = function(error) {
logger.error(out);
});
} else {
if (error.original) {
var o = error.original;
logger.verbose(o.name + ': ' + o.message);
}
if (error.original) { logger.debug(error.original); }
logger.error(error.message);
}
};

14
lib/logList.js Normal file
View File

@@ -0,0 +1,14 @@
'use strict';
var chalk = require('chalk');
var _ = require('lodash');
var logger = require('./logger');
module.exports = function(level, title, list, color) {
color = color || chalk.bold;
logger.log(level, color(title));
logger.log(level, color(_.repeat('=', title.length)));
list.forEach(function(item) {
logger.log(level, item);
});
};

View File

@@ -2,7 +2,19 @@
var winston = require('winston');
var logger = new (winston.Logger)();
function expandErrors(logger) {
var oldLogFunc = logger.log;
logger.log = function() {
var args = Array.prototype.slice.call(arguments, 0);
if (args.length >= 2 && args[1] instanceof Error) {
args[1] = args[1].stack;
}
return oldLogFunc.apply(this, args);
};
return logger;
}
var logger = expandErrors(new winston.Logger());
logger.exitOnError = false;
module.exports = logger;

18
lib/requireAuth.js Normal file
View File

@@ -0,0 +1,18 @@
'use strict';
var RSVP = require('rsvp');
var configstore = require('./configstore');
var FirebaseError = require('./error');
var chalk = require('chalk');
module.exports = function(options, resolve, reject) {
if (configstore.get('user')) {
options.user = configstore.get('user');
resolve(options);
} else {
reject(new FirebaseError('Command requires authentication, please run ' + chalk.bold('firebase login'), {
status: 401,
exit: 1
}));
}
};