Refactor quickstart

- Use promises.
- Move some logic to `helpers`.
- Inline `device await` command.
This commit is contained in:
Juan Cruz Viotti 2015-08-27 10:01:33 -04:00
parent d10d4ce185
commit a090e6c21d
10 changed files with 169 additions and 264 deletions

View File

@ -95,6 +95,7 @@
action: function(params, options, done) { action: function(params, options, done) {
var currentDirectory; var currentDirectory;
currentDirectory = process.cwd(); currentDirectory = process.cwd();
console.info("Associating " + params.name + " with " + currentDirectory);
return resin.models.application.has(params.name).then(function(hasApplication) { return resin.models.application.has(params.name).then(function(hasApplication) {
if (!hasApplication) { if (!hasApplication) {
throw new Error("Invalid application: " + params.name); throw new Error("Invalid application: " + params.name);

View File

@ -109,40 +109,6 @@
} }
}; };
exports.await = {
signature: 'device await <uuid>',
description: 'await for a device to become online',
help: 'Use this command to await for a device to become online.\n\nThe process will exit when the device becomes online.\n\nNotice that there is no time limit for this command, so it might run forever.\n\nYou can configure the poll interval with the --interval option (defaults to 3000ms).\n\nExamples:\n\n $ resin device await 7cf02a62a3a84440b1bb5579a3d57469148943278630b17e7fc6c4f7b465c9\n $ resin device await 7cf02a62a3a84440b1bb5579a3d57469148943278630b17e7fc6c4f7b465c9 --interval 1000',
options: [
{
signature: 'interval',
parameter: 'interval',
description: 'poll interval',
alias: 'i'
}
],
permission: 'user',
action: function(params, options, done) {
var poll, spinner;
if (options.interval == null) {
options.interval = 3000;
}
spinner = new visuals.Spinner("Awaiting device: " + params.uuid);
poll = function() {
return resin.models.device.isOnline(params.uuid).then(function(isOnline) {
if (isOnline) {
spinner.stop();
console.info("Device became online: " + params.uuid);
} else {
spinner.start();
return Promise.delay(options.interval).then(poll);
}
});
};
return poll().nodeify(done);
}
};
exports.init = { exports.init = {
signature: 'device init [device]', signature: 'device init [device]',
description: 'initialise a device with resin os', description: 'initialise a device with resin os',

View File

@ -1,22 +1,18 @@
(function() { (function() {
var Promise, _, async, capitano, form, mkdirp, resin, visuals; var Promise, capitano, form, helpers, mkdirp, resin;
_ = require('lodash');
Promise = require('bluebird'); Promise = require('bluebird');
capitano = Promise.promisifyAll(require('capitano')); capitano = Promise.promisifyAll(require('capitano'));
mkdirp = require('mkdirp'); mkdirp = Promise.promisify(require('mkdirp'));
visuals = require('resin-cli-visuals');
async = require('async');
resin = require('resin-sdk'); resin = require('resin-sdk');
form = require('resin-cli-form'); form = require('resin-cli-form');
helpers = require('../utils/helpers');
exports.wizard = { exports.wizard = {
signature: 'quickstart [name]', signature: 'quickstart [name]',
description: 'getting started with resin.io', description: 'getting started with resin.io',
@ -24,84 +20,27 @@
root: true, root: true,
permission: 'user', permission: 'user',
action: function(params, options, done) { action: function(params, options, done) {
return async.waterfall([ return Promise["try"](function() {
function(callback) { if (params.name != null) {
if (params.name != null) { return;
return callback();
}
return async.waterfall([
function(callback) {
return resin.models.application.hasAny().nodeify(callback);
}, function(hasAnyApplications, callback) {
if (!hasAnyApplications) {
return callback(null, null);
}
return async.waterfall([
function(callback) {
return resin.models.application.getAll().nodeify(callback);
}, function(applications, callback) {
applications = _.pluck(applications, 'app_name');
applications.unshift({
name: 'Create a new application',
value: null
});
return form.ask({
message: 'Select an application',
type: 'list',
choices: applications
}).nodeify(callback);
}
], callback);
}, function(application, callback) {
if (application != null) {
return callback(null, application);
}
return form.ask({
message: 'Choose a Name for your new application',
type: 'input'
}).then(function(applicationName) {
return capitano.runAsync("app create " + applicationName)["return"](applicationName);
}).nodeify(callback);
}, function(applicationName, callback) {
params.name = applicationName;
return callback();
}
], callback);
}, function(callback) {
return capitano.run("device init --application " + params.name, callback);
}, function(deviceUuid, callback) {
params.uuid = deviceUuid;
return resin.models.device.getName(params.uuid).then(function(deviceName) {
params.deviceName = deviceName;
console.log("Waiting for " + params.deviceName + " to connect to resin...");
return capitano.runAsync("device await " + params.uuid)["return"](callback);
}).nodeify(callback);
}, function(callback) {
console.log("The device " + params.deviceName + " successfully connected to resin!");
console.log('');
return capitano.run("device " + params.uuid, callback);
}, function(callback) {
console.log('Your device is ready, lets start pushing some code!');
return resin.settings.get('projectsDirectory').then(function(projectsDirectory) {
return form.ask({
message: 'Please choose a directory for your code',
type: 'input',
"default": projectsDirectory
});
}).nodeify(callback);
}, function(directoryName, callback) {
params.directory = directoryName;
return mkdirp(directoryName, callback);
}, function(made, callback) {
console.log("Associating " + params.name + " with " + params.directory + "...");
process.chdir(params.directory);
return capitano.run("app associate " + params.name, callback);
}, function(remoteUrl, callback) {
console.log("Resin git remote added: " + remoteUrl);
console.log("Please type:\n\n $ cd " + params.directory + " && git push resin master\n\nTo push your project to resin.io.");
return callback();
} }
], done); return helpers.selectApplication().tap(function(applicationName) {
return capitano.runAsync("app create " + applicationName);
}).then(function(applicationName) {
return params.name = applicationName;
});
}).then(function() {
return capitano.runAsync("device init --application " + params.name);
}).tap(helpers.awaitDevice).then(function(uuid) {
return capitano.runAsync("device " + uuid);
}).tap(function() {
return console.log('Your device is ready, lets start pushing some code!');
}).then(helpers.selectProjectDirectory).tap(mkdirp).tap(process.chdir).then(function() {
return capitano.runAsync("app associate " + params.name);
}).then(function(remoteUrl) {
console.log("Resin git remote added: " + remoteUrl);
return console.log("Please type:\n\n $ cd " + (process.cwd()) + " && git push resin master\n\nTo push your project to resin.io.");
}).nodeify(done);
} }
}; };

View File

@ -66,8 +66,6 @@
capitano.command(actions.device.init); capitano.command(actions.device.init);
capitano.command(actions.device.await);
capitano.command(actions.device.info); capitano.command(actions.device.info);
capitano.command(actions.device.remove); capitano.command(actions.device.remove);

View File

@ -1,10 +1,16 @@
(function() { (function() {
var Promise, form; var Promise, _, form, resin, visuals;
_ = require('lodash');
Promise = require('bluebird'); Promise = require('bluebird');
form = require('resin-cli-form'); form = require('resin-cli-form');
visuals = require('resin-cli-visuals');
resin = require('resin-sdk');
exports.selectDeviceType = function() { exports.selectDeviceType = function() {
return form.ask({ return form.ask({
message: 'Device Type', message: 'Device Type',
@ -30,4 +36,62 @@
}); });
}; };
exports.selectApplication = function() {
return resin.models.application.hasAny().then(function(hasAnyApplications) {
if (!hasAnyApplications) {
return;
}
return resin.models.application.getAll().then(function(applications) {
applications = _.pluck(applications, 'app_name');
applications.unshift({
name: 'Create a new application',
value: null
});
return form.ask({
message: 'Select an application',
type: 'list',
choices: applications
});
});
}).then(function(application) {
if (application != null) {
return application;
}
return form.ask({
message: 'Choose a Name for your new application',
type: 'input'
});
});
};
exports.selectProjectDirectory = function() {
return resin.settings.get('projectsDirectory').then(function(projectsDirectory) {
return form.ask({
message: 'Please choose a directory for your code',
type: 'input',
"default": projectsDirectory
});
});
};
exports.awaitDevice = function(uuid) {
var poll, spinner;
spinner = new visuals.Spinner("Awaiting device: " + uuid);
poll = function() {
return resin.models.device.isOnline(uuid).then(function(isOnline) {
if (isOnline) {
spinner.stop();
console.info("Device became online: " + uuid);
} else {
spinner.start();
return Promise.delay(3000).then(poll);
}
});
};
return resin.models.device.getName(uuid).then(function(deviceName) {
console.info("Waiting for " + deviceName + " to connect to resin...");
return poll()["return"](uuid);
});
};
}).call(this); }).call(this);

View File

@ -148,6 +148,7 @@ exports.associate =
permission: 'user' permission: 'user'
action: (params, options, done) -> action: (params, options, done) ->
currentDirectory = process.cwd() currentDirectory = process.cwd()
console.info("Associating #{params.name} with #{currentDirectory}")
resin.models.application.has(params.name).then (hasApplication) -> resin.models.application.has(params.name).then (hasApplication) ->
if not hasApplication if not hasApplication

View File

@ -150,50 +150,6 @@ exports.rename =
.then(_.partial(resin.models.device.rename, params.uuid)) .then(_.partial(resin.models.device.rename, params.uuid))
.nodeify(done) .nodeify(done)
exports.await =
signature: 'device await <uuid>'
description: 'await for a device to become online'
help: '''
Use this command to await for a device to become online.
The process will exit when the device becomes online.
Notice that there is no time limit for this command, so it might run forever.
You can configure the poll interval with the --interval option (defaults to 3000ms).
Examples:
$ resin device await 7cf02a62a3a84440b1bb5579a3d57469148943278630b17e7fc6c4f7b465c9
$ resin device await 7cf02a62a3a84440b1bb5579a3d57469148943278630b17e7fc6c4f7b465c9 --interval 1000
'''
options: [
signature: 'interval'
parameter: 'interval'
description: 'poll interval'
alias: 'i'
]
permission: 'user'
action: (params, options, done) ->
options.interval ?= 3000
spinner = new visuals.Spinner("Awaiting device: #{params.uuid}")
poll = ->
resin.models.device.isOnline(params.uuid).then (isOnline) ->
if isOnline
spinner.stop()
console.info("Device became online: #{params.uuid}")
return
else
# Spinner implementation is smart enough to
# not start again if it was already started
spinner.start()
return Promise.delay(options.interval).then(poll)
poll().nodeify(done)
exports.init = exports.init =
signature: 'device init [device]' signature: 'device init [device]'
description: 'initialise a device with resin os' description: 'initialise a device with resin os'

View File

@ -1,11 +1,9 @@
_ = require('lodash')
Promise = require('bluebird') Promise = require('bluebird')
capitano = Promise.promisifyAll(require('capitano')) capitano = Promise.promisifyAll(require('capitano'))
mkdirp = require('mkdirp') mkdirp = Promise.promisify(require('mkdirp'))
visuals = require('resin-cli-visuals')
async = require('async')
resin = require('resin-sdk') resin = require('resin-sdk')
form = require('resin-cli-form') form = require('resin-cli-form')
helpers = require('../utils/helpers')
exports.wizard = exports.wizard =
signature: 'quickstart [name]' signature: 'quickstart [name]'
@ -28,98 +26,31 @@ exports.wizard =
root: true root: true
permission: 'user' permission: 'user'
action: (params, options, done) -> action: (params, options, done) ->
async.waterfall [ Promise.try ->
return if params.name?
helpers.selectApplication().tap (applicationName) ->
capitano.runAsync("app create #{applicationName}")
.then (applicationName) ->
params.name = applicationName
.then ->
return capitano.runAsync("device init --application #{params.name}")
.tap(helpers.awaitDevice)
.then (uuid) ->
return capitano.runAsync("device #{uuid}")
.tap ->
console.log('Your device is ready, lets start pushing some code!')
.then(helpers.selectProjectDirectory)
.tap(mkdirp)
.tap(process.chdir)
.then ->
return capitano.runAsync("app associate #{params.name}")
.then (remoteUrl) ->
console.log("Resin git remote added: #{remoteUrl}")
console.log """
Please type:
(callback) -> $ cd #{process.cwd()} && git push resin master
return callback() if params.name?
# TODO: Move this whole routine to Resin CLI Visuals To push your project to resin.io.
async.waterfall [ """
.nodeify(done)
(callback) ->
resin.models.application.hasAny().nodeify(callback)
(hasAnyApplications, callback) ->
return callback(null, null) if not hasAnyApplications
async.waterfall [
(callback) ->
resin.models.application.getAll().nodeify(callback)
(applications, callback) ->
applications = _.pluck(applications, 'app_name')
applications.unshift
name: 'Create a new application'
value: null
form.ask
message: 'Select an application'
type: 'list'
choices: applications
.nodeify(callback)
], callback
(application, callback) ->
return callback(null, application) if application?
form.ask
message: 'Choose a Name for your new application'
type: 'input'
.then (applicationName) ->
capitano.runAsync("app create #{applicationName}").return(applicationName)
.nodeify(callback)
(applicationName, callback) ->
params.name = applicationName
return callback()
], callback
(callback) ->
capitano.run("device init --application #{params.name}", callback)
(deviceUuid, callback) ->
params.uuid = deviceUuid
resin.models.device.getName(params.uuid).then (deviceName) ->
params.deviceName = deviceName
console.log("Waiting for #{params.deviceName} to connect to resin...")
capitano.runAsync("device await #{params.uuid}").return(callback)
.nodeify(callback)
(callback) ->
console.log("The device #{params.deviceName} successfully connected to resin!")
console.log('')
capitano.run("device #{params.uuid}", callback)
(callback) ->
console.log('Your device is ready, lets start pushing some code!')
resin.settings.get('projectsDirectory').then (projectsDirectory) ->
form.ask
message: 'Please choose a directory for your code'
type: 'input'
default: projectsDirectory
.nodeify(callback)
(directoryName, callback) ->
params.directory = directoryName
mkdirp(directoryName, callback)
(made, callback) ->
console.log("Associating #{params.name} with #{params.directory}...")
process.chdir(params.directory)
capitano.run("app associate #{params.name}", callback)
(remoteUrl, callback) ->
console.log("Resin git remote added: #{remoteUrl}")
console.log """
Please type:
$ cd #{params.directory} && git push resin master
To push your project to resin.io.
"""
return callback()
], done

View File

@ -45,7 +45,6 @@ capitano.command(actions.app.info)
capitano.command(actions.device.list) capitano.command(actions.device.list)
capitano.command(actions.device.rename) capitano.command(actions.device.rename)
capitano.command(actions.device.init) capitano.command(actions.device.init)
capitano.command(actions.device.await)
capitano.command(actions.device.info) capitano.command(actions.device.info)
capitano.command(actions.device.remove) capitano.command(actions.device.remove)
capitano.command(actions.device.identify) capitano.command(actions.device.identify)

View File

@ -1,5 +1,8 @@
_ = require('lodash')
Promise = require('bluebird') Promise = require('bluebird')
form = require('resin-cli-form') form = require('resin-cli-form')
visuals = require('resin-cli-visuals')
resin = require('resin-sdk')
exports.selectDeviceType = -> exports.selectDeviceType = ->
return form.ask return form.ask
@ -24,3 +27,50 @@ exports.confirm = (yesOption, message) ->
.then (confirmed) -> .then (confirmed) ->
if not confirmed if not confirmed
throw new Error('Aborted') throw new Error('Aborted')
exports.selectApplication = ->
resin.models.application.hasAny().then (hasAnyApplications) ->
return if not hasAnyApplications
resin.models.application.getAll().then (applications) ->
applications = _.pluck(applications, 'app_name')
applications.unshift
name: 'Create a new application'
value: null
return form.ask
message: 'Select an application'
type: 'list'
choices: applications
.then (application) ->
return application if application?
form.ask
message: 'Choose a Name for your new application'
type: 'input'
exports.selectProjectDirectory = ->
resin.settings.get('projectsDirectory').then (projectsDirectory) ->
return form.ask
message: 'Please choose a directory for your code'
type: 'input'
default: projectsDirectory
exports.awaitDevice = (uuid) ->
spinner = new visuals.Spinner("Awaiting device: #{uuid}")
poll = ->
resin.models.device.isOnline(uuid).then (isOnline) ->
if isOnline
spinner.stop()
console.info("Device became online: #{uuid}")
return
else
# Spinner implementation is smart enough to
# not start again if it was already started
spinner.start()
return Promise.delay(3000).then(poll)
resin.models.device.getName(uuid).then (deviceName) ->
console.info("Waiting for #{deviceName} to connect to resin...")
poll().return(uuid)