Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## v1.0.6
- Adds `-s` functionality to all commands for silent mode while scripting - commands will error with non-zero status code instead of waiting for prompt if not enough information supplied
- `delete-site` command as a convenience method for removing a site from hosting. Site shows up as 'Site Not Found' as if never deployed to

## v1.0.5
- Gracefully handles error caused by symlinks in public directory until [isaacs/fstream#16](https://github.com/isaacs/fstream/pull/16) fix

## v1.0.4
- NPM artifact fix

## v1.0.3
- Allows command line params in `firebase deploy` to override `firebase.json` settings

## v1.0.2
- Enforces node 0.10.x and above after shown not to work on previous versions

## v1.0.1
- Fixes bug with `firebase bootstrap` on windows
- Adds 'ignore' to `firebase.json` to allow files to be ignored on deploy
- Prioritizes `--email` and `--password` command line arguments over current auth token if both passed
5 changes: 5 additions & 0 deletions bin/firebase
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ var argv = require('optimist')
.alias('m', 'message')
.alias('p', 'public')
.alias('r', 'rules')
.alias('s', 'silent')
.alias('t', 'template')
.alias('v', 'version')
.boolean('d')
.boolean('s')
.argv,
prompt = require('prompt'),
firebase = require('../lib/firebase'),
Expand Down Expand Up @@ -69,6 +71,9 @@ if (argv._.length === 0) {
case 'deploy':
app.deploy(argv);
break;
case 'delete-site':
app.deleteSite(argv);
break;
case 'open':
app.open(argv);
break;
Expand Down
154 changes: 114 additions & 40 deletions lib/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,60 @@ var defaultSettings = {

temp.track();

function getPrompt(schema, onComplete, idx, results) {
function getPrompt(argv, schema, onComplete, index, results) {
if (!Array.isArray(schema)) {
console.log(chalk.red('An error occurred'));
process.exit(1);
}
onComplete = typeof onComplete !== 'function' ? function() {} : onComplete;
idx = typeof idx !== 'number' ? 0 : idx;
index = typeof index !== 'number' ? 0 : index;
results = typeof results !== 'object' ? {} : results;
var item = schema[idx];
var item = schema[index];
if (argv.silent) {
if (!prompt.override[item.name] || (item.pattern && !item.pattern.test(prompt.override[item.name]))) {
console.log(chalk.red('Input Error') + ' - Not enough or invalid parameters specified while in silent mode');
console.log('Required ' + chalk.bold(item.name) + ' parameter missing or invalid');
process.exit(1);
}
}
if (typeof item.beforeValue === 'function') {
item.beforeValue(results);
}
prompt.get(schema[idx], function (error, result) {
prompt.get(schema[index], function (error, result) {
if (error) {
console.log(chalk.red('Input Error'));
process.exit(1);
}
results[item.name] = result[item.name];
if (++idx < schema.length) {
getPrompt(schema, onComplete, idx, results);
if (++index < schema.length) {
getPrompt(argv, schema, onComplete, index, results);
} else {
onComplete(results);
}
});
}

function getSettings(argv) {
var settingsFile = path.resolve('./firebase.json');
var settingsJSON, settings;
if (!fs.existsSync(settingsFile)) {
console.log(chalk.red('Initialization Error') + ' - Directory not ' +
'initialized');
process.exit(1);
}
try {
settingsJSON = fs.readFileSync(settingsFile);
settings = JSON.parse(settingsJSON);
} catch (err) {
console.log(chalk.red('Initialization Error') +' - Could not read ' +
'firebase.json settings file');
process.exit(1);
}
util._extend(settings, argv);

return settings;
}

module.exports = {
init: function(argv) {
auth.listFirebases(argv).then(function(res) {
Expand Down Expand Up @@ -110,7 +138,7 @@ module.exports = {
}
}];

getPrompt(schema, function(results) {
getPrompt(argv, schema, function(results) {
if (path.relative('.', results['public']).match(/^\./)) {
console.log(chalk.red('init cancelled - the public directory must be within the current working directory'));
process.exit(1);
Expand Down Expand Up @@ -200,7 +228,7 @@ module.exports = {
type: 'string'
}];

getPrompt(schema, function(results) {
getPrompt(argv, schema, function(results) {
var firebase = results.firebase;
var dir = firebase;
var projectDir = path.resolve(dir);
Expand Down Expand Up @@ -334,22 +362,7 @@ module.exports = {
console.log(chalk.red('Login Error'));
process.exit(1);
}
var settingsFile = path.resolve('./firebase.json');
var settingsJSON, settings;
if (!fs.existsSync(settingsFile)) {
console.log(chalk.red('Initialization Error') + ' - Directory not ' +
'initialized');
process.exit(1);
}
try {
settingsJSON = fs.readFileSync(settingsFile);
settings = JSON.parse(settingsJSON);
} catch (err) {
console.log(chalk.red('Initialization Error') +' - Could not read ' +
'firebase.json settings file');
process.exit(1);
}
util._extend(settings, argv);
var settings = getSettings(argv);
if (typeof(settings.firebase) !== 'string') {
console.log(chalk.red('Initialization Error') +' - Could not read ' +
'firebase.json settings file');
Expand Down Expand Up @@ -440,7 +453,7 @@ module.exports = {
message = argv.message;
}

upload.send(settings.firebase, settings['public'], settings.ignore || defaultSettings.ignore, directoryRef.name(), message, function(err, directory) {
upload.send(settings.firebase, settings['public'], settings.ignore, directoryRef.name(), message, function(err, directory) {
if (err) {
console.log(chalk.red('Deploy Error') + ' - Couldn\'t upload app');
console.log(err);
Expand All @@ -451,22 +464,83 @@ module.exports = {
});
});
},
deleteSite: function(argv) {
auth.requireLogin(argv, function(err) {
if (err) {
console.log(chalk.red('Login Error'));
process.exit(1);
}
var settings = getSettings(argv);
if (typeof(settings.firebase) !== 'string') {
console.log(chalk.red('Initialization Error') +' - Could not read ' +
'firebase.json settings file');
process.exit(1);
}
auth.checkCanAccess(settings.firebase, function(err, tokens) {
if (err) {
console.log(chalk.red('Permission Error') + ' - You do not have ' +
'permission to use this Firebase');
process.exit(1);
}
var firebaseRef = new Firebase(api.realtimeUrl.replace(/\/\//, '//firebase.'));
firebaseRef.auth(tokens.firebaseToken, function(error, result) {
if (error) {
console.log('Firebase authentication failed!');
process.exit(1);
}
});
var directoryRef = firebaseRef
.child('hosting/versions')
.child(settings.firebase)
.push();
var bar = null;
var total = 0;
directoryRef.on('value', function(snapshot) {
var status = snapshot.child('status').val();
if (status === 'deploying') {
if (!bar && snapshot.hasChild('fileCount')) {
total = snapshot.child('fileCount').val();
bar = new ProgressBar(chalk.yellow('progress: :percent'), {
total: total
});
}
if (bar) {
var uploadedCount = snapshot.hasChild('uploadedCount') ? snapshot.child('uploadedCount').val() : 0;
bar.update(uploadedCount / total);
}
} else if (status === 'removed') {
console.log(chalk.green('Sucessfully removed'));
process.exit(0);
} else if (status === 'failed') {
if (bar) {
bar.terminate();
}
var message = chalk.red('Deploy Failed');
if (snapshot.hasChild('statusMessage')) {
message += ' - ' + snapshot.child('statusMessage').val();
}
console.log(message);
process.exit(1);
}
});

var message = null;
if (argv.message && (typeof(argv.message) === 'string')) {
message = argv.message;
}

upload.deleteSite(settings.firebase, directoryRef.name(), message, function(err, directory) {
if (err) {
console.log(chalk.red('Deploy Error') + ' - Couldn\'t upload app');
console.log(err);
process.exit(1);
}
});
});
});
},
open: function(argv) {
var settingsFile = path.resolve('./firebase.json');
var settingsJSON, settings;
if (!fs.existsSync(settingsFile)) {
console.log(chalk.red('Initialization Error') + ' - Directory not ' +
'initialized');
process.exit(1);
}
try {
settingsJSON = fs.readFileSync(settingsFile);
settings = JSON.parse(settingsJSON);
} catch (err) {
console.log(chalk.red('Initialization Error') +' - Could not read ' +
'firebase.json settings file');
process.exit(1);
}
var settings = getSettings(argv);
if (typeof(settings.firebase) !== 'string') {
console.log(chalk.red('Initialization Error') +' - Could not read ' +
'firebase.json settings file');
Expand Down
48 changes: 31 additions & 17 deletions lib/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ var auth = {
var that = this;

if (argv.email && argv.password) {
this._attemptLogin(this.maxRetries, callback);
this._attemptLogin(argv, this.maxRetries, callback);
} else if ((this.email.length === 0) || (this.token.length === 0)) {
console.log('Please sign into your Firebase account to continue...');
this._attemptLogin(this.maxRetries, callback);
this._attemptLogin(argv, this.maxRetries, callback);
} else {
this._validate(function(err) {
if (err) {
console.log('Please sign into your Firebase account to continue...');
that._attemptLogin(that.maxRetries, callback);
that._attemptLogin(argv, that.maxRetries, callback);
} else {
setTimeout(callback, 0, null, that.email, that.token);
}
Expand Down Expand Up @@ -55,20 +55,24 @@ var auth = {
}
);
},
login: function(callback) {
this._attemptLogin(this.maxRetries, callback);
login: function(argv, callback) {
this._attemptLogin(argv, this.maxRetries, callback);
},
_attemptLogin: function(tries, callback) {
_attemptLogin: function(argv, tries, callback) {
var that = this;
if (tries > 0) {
if (tries !== this.maxRetries) {
if (argv.silent) {
console.log(chalk.red('Input Error') + ' - Email or password incorrect');
process.exit(1);
}
console.log('Email or password incorrect, please try again');
delete prompt.override.email;
delete prompt.override.password;
}
this._loginRequest(function(err, email, token) {
this._loginRequest(argv, function(err, email, token) {
if (err) {
that._attemptLogin(tries - 1, callback);
that._attemptLogin(argv, tries - 1, callback);
} else {
setTimeout(callback, 0, null, email, token);
}
Expand All @@ -78,28 +82,38 @@ var auth = {
process.exit(1);
}
},
_loginRequest: function(callback) {
_loginRequest: function(argv, callback) {
var that = this,
schema = {
properties: {
email: {
schema = [
{
name: 'email',
description: 'Email:',
pattern: /@/,
message: 'Must be a valid email address',
required: true,
type: 'string'
},
password: {
},{
name: 'password',
description: 'Password:',
hidden: true,
required: true,
type: 'string'
}
}
};
];

if (this.email.length > 0) {
schema.properties.email.default = this.email;
schema[0].default = this.email;
}

if (argv.silent) {
for (var i in schema) {
var item = schema[i];
if (!prompt.override[item.name] || (item.pattern && !item.pattern.test(prompt.override[item.name]))) {
console.log(chalk.red('Input Error') + ' - Not enough or invalid parameters specified while in silent mode');
console.log('Required ' + chalk.bold(item.name) + ' parameter missing or invalid');
process.exit(1);
}
}
}

prompt.get(schema, function(err, result) {
Expand Down
2 changes: 1 addition & 1 deletion lib/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ var auth = require('./auth'),

module.exports = {
login: function(argv) {
auth.login(function(err) {
auth.login(argv, function(err) {
if (err) {
console.log(chalk.red('Login Unsuccessful'));
process.exit(1);
Expand Down
Loading