mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-19 21:57:51 +00:00
Commit build directory
This commit is contained in:
parent
01d2edb819
commit
a4cc106890
1
.gitignore
vendored
1
.gitignore
vendored
@ -29,5 +29,4 @@ node_modules
|
||||
|
||||
bin/node
|
||||
|
||||
build/
|
||||
release/
|
||||
|
128
build/actions/app.js
Normal file
128
build/actions/app.js
Normal file
@ -0,0 +1,128 @@
|
||||
(function() {
|
||||
var _, async, commandOptions, resin, visuals;
|
||||
|
||||
_ = require('lodash-contrib');
|
||||
|
||||
async = require('async');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
commandOptions = require('./command-options');
|
||||
|
||||
exports.create = {
|
||||
signature: 'app create <name>',
|
||||
description: 'create an application',
|
||||
help: 'Use this command to create a new resin.io application.\n\nYou can specify the application type with the `--type` option.\nOtherwise, an interactive dropdown will be shown for you to select from.\n\nYou can see a list of supported device types with\n $ resin devices supported\n\nExamples:\n $ resin app create MyApp\n $ resin app create MyApp --type raspberry-pi',
|
||||
options: [
|
||||
{
|
||||
signature: 'type',
|
||||
parameter: 'type',
|
||||
description: 'application type',
|
||||
alias: 't'
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
if (options.type != null) {
|
||||
return callback(null, options.type);
|
||||
}
|
||||
return resin.models.device.getSupportedDeviceTypes(function(error, deviceTypes) {
|
||||
if (error != null) {
|
||||
return callback(error);
|
||||
}
|
||||
return visuals.widgets.select('Select a type', deviceTypes, callback);
|
||||
});
|
||||
}, function(type, callback) {
|
||||
return resin.models.application.create(params.name, type, callback);
|
||||
}
|
||||
], done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.list = {
|
||||
signature: 'apps',
|
||||
description: 'list all applications',
|
||||
help: 'Use this command to list all your applications.\n\nNotice this command only shows the most important bits of information for each app.\nIf you want detailed information, use resin app <id> instead.\n\nExamples:\n $ resin apps',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.application.getAll(function(error, applications) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.log(visuals.widgets.table.horizontal(applications, ['id', 'app_name', 'device_type', 'online_devices', 'devices_length']));
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.info = {
|
||||
signature: 'app <id>',
|
||||
description: 'list a single application',
|
||||
help: 'Use this command to show detailed information for a single application.\n\nExamples:\n $ resin app 91',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.application.get(params.id, function(error, application) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.log(visuals.widgets.table.vertical(application, ['id', 'app_name', 'device_type', 'git_repository', 'commit']));
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.restart = {
|
||||
signature: 'app restart <id>',
|
||||
description: 'restart an application',
|
||||
help: 'Use this command to restart all devices that belongs to a certain application.\n\nExamples:\n $ resin app restart 91',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.application.restart(params.id, done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.remove = {
|
||||
signature: 'app rm <id>',
|
||||
description: 'remove an application',
|
||||
help: 'Use this command to remove a resin.io application.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nExamples:\n $ resin app rm 91\n $ resin app rm 91 --yes',
|
||||
options: [commandOptions.yes],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return visuals.patterns.remove('application', options.yes, function(callback) {
|
||||
return resin.models.application.remove(params.id, callback);
|
||||
}, done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.init = {
|
||||
signature: 'init <id>',
|
||||
description: 'init an application',
|
||||
help: 'Use this command to associate a local project to an existing resin.io application.\n\nThe application should be a git repository before issuing this command.\nNotice this command adds a `resin` git remote to your application.\n\nExamples:\n $ cd myApp && resin init 91',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
var currentDirectory;
|
||||
currentDirectory = process.cwd();
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
return resin.vcs.isResinProject(currentDirectory, callback);
|
||||
}, function(isResinProject, callback) {
|
||||
var error;
|
||||
if (isResinProject) {
|
||||
error = new Error('Project is already a resin application.');
|
||||
return callback(error);
|
||||
}
|
||||
return callback();
|
||||
}, function(callback) {
|
||||
return resin.models.application.get(params.id, callback);
|
||||
}, function(application, callback) {
|
||||
return resin.vcs.initProjectWithApplication(application, currentDirectory, callback);
|
||||
}
|
||||
], done);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
134
build/actions/auth.js
Normal file
134
build/actions/auth.js
Normal file
@ -0,0 +1,134 @@
|
||||
(function() {
|
||||
var _, async, resin, url, visuals;
|
||||
|
||||
_ = require('lodash-contrib');
|
||||
|
||||
url = require('url');
|
||||
|
||||
async = require('async');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
exports.login = {
|
||||
signature: 'login',
|
||||
description: 'login to resin.io',
|
||||
help: 'Use this command to login to your resin.io account.\nYou need to login before you can use most of the commands this tool provides.\n\nYou can pass your credentials as `--username` and `--password` options, or you can omit the\ncredentials, in which case the tool will present you with an interactive login form.\n\nExamples:\n $ resin login --username <username> --password <password>\n $ resin login',
|
||||
options: [
|
||||
{
|
||||
signature: 'username',
|
||||
parameter: 'username',
|
||||
description: 'user name',
|
||||
alias: 'u'
|
||||
}, {
|
||||
signature: 'password',
|
||||
parameter: 'password',
|
||||
description: 'user password',
|
||||
alias: 'p'
|
||||
}
|
||||
],
|
||||
action: function(params, options, done) {
|
||||
var hasOptionCredentials;
|
||||
hasOptionCredentials = !_.isEmpty(options);
|
||||
if (hasOptionCredentials) {
|
||||
if (!options.username) {
|
||||
return done(new Error('Missing username'));
|
||||
}
|
||||
if (!options.password) {
|
||||
return done(new Error('Missing password'));
|
||||
}
|
||||
}
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
if (hasOptionCredentials) {
|
||||
return callback(null, options);
|
||||
} else {
|
||||
return visuals.widgets.login(callback);
|
||||
}
|
||||
}, function(credentials, callback) {
|
||||
return resin.auth.login(credentials, callback);
|
||||
}
|
||||
], done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.logout = {
|
||||
signature: 'logout',
|
||||
description: 'logout from resin.io',
|
||||
help: 'Use this command to logout from your resin.io account.o\n\nExamples:\n $ resin logout',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.auth.logout(done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.signup = {
|
||||
signature: 'signup',
|
||||
description: 'signup to resin.io',
|
||||
help: 'Use this command to signup for a resin.io account.\n\nIf signup is successful, you\'ll be logged in to your new user automatically.\n\nExamples:\n $ resin signup\n Email: me@mycompany.com\n Username: johndoe\n Password: ***********\n\n $ resin signup --email me@mycompany.com --username johndoe --password ***********\n\n $ resin whoami\n johndoe',
|
||||
options: [
|
||||
{
|
||||
signature: 'email',
|
||||
parameter: 'email',
|
||||
description: 'user email',
|
||||
alias: 'e'
|
||||
}, {
|
||||
signature: 'username',
|
||||
parameter: 'username',
|
||||
description: 'user name',
|
||||
alias: 'u'
|
||||
}, {
|
||||
signature: 'password',
|
||||
parameter: 'user password',
|
||||
description: 'user password',
|
||||
alias: 'p'
|
||||
}
|
||||
],
|
||||
action: function(params, options, done) {
|
||||
var hasOptionCredentials;
|
||||
hasOptionCredentials = !_.isEmpty(options);
|
||||
if (hasOptionCredentials) {
|
||||
if (options.email == null) {
|
||||
return done(new Error('Missing email'));
|
||||
}
|
||||
if (options.username == null) {
|
||||
return done(new Error('Missing username'));
|
||||
}
|
||||
if (options.password == null) {
|
||||
return done(new Error('Missing password'));
|
||||
}
|
||||
}
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
if (hasOptionCredentials) {
|
||||
return callback(null, options);
|
||||
}
|
||||
return visuals.widgets.register(callback);
|
||||
}, function(credentials, callback) {
|
||||
return resin.auth.register(credentials, function(error, token) {
|
||||
return callback(error, credentials);
|
||||
});
|
||||
}, function(credentials, callback) {
|
||||
return resin.auth.login(credentials, callback);
|
||||
}
|
||||
], done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.whoami = {
|
||||
signature: 'whoami',
|
||||
description: 'get current username',
|
||||
help: 'Use this command to find out the current logged in username.\n\nExamples:\n $ resin whoami',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.auth.whoami(function(error, username) {
|
||||
if (username == null) {
|
||||
return done(new Error('Username not found'));
|
||||
}
|
||||
return console.log(username);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
38
build/actions/command-options.js
Normal file
38
build/actions/command-options.js
Normal file
@ -0,0 +1,38 @@
|
||||
(function() {
|
||||
exports.yes = {
|
||||
signature: 'yes',
|
||||
description: 'confirm non interactively',
|
||||
boolean: true,
|
||||
alias: 'y'
|
||||
};
|
||||
|
||||
exports.application = {
|
||||
signature: 'application',
|
||||
parameter: 'application',
|
||||
description: 'application id',
|
||||
alias: ['a', 'app'],
|
||||
required: 'You have to specify an application'
|
||||
};
|
||||
|
||||
exports.network = {
|
||||
signature: 'network',
|
||||
parameter: 'network',
|
||||
description: 'network type',
|
||||
alias: 'n'
|
||||
};
|
||||
|
||||
exports.wifiSsid = {
|
||||
signature: 'ssid',
|
||||
parameter: 'ssid',
|
||||
description: 'wifi ssid, if network is wifi',
|
||||
alias: 's'
|
||||
};
|
||||
|
||||
exports.wifiKey = {
|
||||
signature: 'key',
|
||||
parameter: 'key',
|
||||
description: 'wifi key, if network is wifi',
|
||||
alias: 'k'
|
||||
};
|
||||
|
||||
}).call(this);
|
140
build/actions/device.js
Normal file
140
build/actions/device.js
Normal file
@ -0,0 +1,140 @@
|
||||
(function() {
|
||||
var _, async, commandOptions, osAction, path, resin, visuals;
|
||||
|
||||
_ = require('lodash-contrib');
|
||||
|
||||
path = require('path');
|
||||
|
||||
async = require('async');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
commandOptions = require('./command-options');
|
||||
|
||||
osAction = require('./os');
|
||||
|
||||
exports.list = {
|
||||
signature: 'devices',
|
||||
description: 'list all devices',
|
||||
help: 'Use this command to list all devices that belong to a certain application.\n\nExamples:\n $ resin devices --application 91',
|
||||
options: [commandOptions.application],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.device.getAllByApplication(options.application, function(error, devices) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.log(visuals.widgets.table.horizontal(devices, ['id', 'name', 'device_type', 'is_online', 'application_name', 'status', 'last_seen']));
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.info = {
|
||||
signature: 'device <id>',
|
||||
description: 'list a single device',
|
||||
help: 'Use this command to show information about a single device.\n\nExamples:\n $ resin device 317',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.device.get(params.id, function(error, device) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.log(visuals.widgets.table.vertical(device, ['id', 'name', 'device_type', 'is_online', 'ip_address', 'application_name', 'status', 'last_seen', 'uuid', 'commit', 'supervisor_version', 'is_web_accessible', 'note']));
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.remove = {
|
||||
signature: 'device rm <id>',
|
||||
description: 'remove a device',
|
||||
help: 'Use this command to remove a device from resin.io.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nExamples:\n $ resin device rm 317\n $ resin device rm 317 --yes',
|
||||
options: [commandOptions.yes],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return visuals.patterns.remove('device', options.yes, function(callback) {
|
||||
return resin.models.device.remove(params.id, callback);
|
||||
}, done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.identify = {
|
||||
signature: 'device identify <uuid>',
|
||||
description: 'identify a device with a UUID',
|
||||
help: 'Use this command to identify a device.\n\nIn the Raspberry Pi, the ACT led is blinked several times.\n\nExamples:\n $ resin device identify 23c73a12e3527df55c60b9ce647640c1b7da1b32d71e6a39849ac0f00db828',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.device.identify(params.uuid, done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.rename = {
|
||||
signature: 'device rename <id> [name]',
|
||||
description: 'rename a resin device',
|
||||
help: 'Use this command to rename a device.\n\nIf you omit the name, you\'ll get asked for it interactively.\n\nExamples:\n $ resin device rename 317 MyPi\n $ resin device rename 317',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
if (!_.isEmpty(params.name)) {
|
||||
return callback(null, params.name);
|
||||
}
|
||||
return visuals.widgets.ask('How do you want to name this device?', callback);
|
||||
}, function(name, callback) {
|
||||
return resin.models.device.rename(params.id, name, callback);
|
||||
}
|
||||
], done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.supported = {
|
||||
signature: 'devices supported',
|
||||
description: 'list all supported devices',
|
||||
help: 'Use this command to get the list of all supported devices\n\nExamples:\n $ resin devices supported',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.device.getSupportedDeviceTypes(function(error, devices) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
_.each(devices, _.unary(console.log));
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.init = {
|
||||
signature: 'device init [device]',
|
||||
description: 'initialise a device with resin os',
|
||||
help: 'Use this command to download the OS image of a certain application and write it to an SD Card.\n\nNote that this command requires admin privileges.\n\nIf `device` is omitted, you will be prompted to select a device interactively.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nYou can quiet the progress bar by passing the `--quiet` boolean option.\n\nYou may have to unmount the device before attempting this operation.\n\nYou need to configure the network type and other settings:\n\nEthernet:\n You can setup the device OS to use ethernet by setting the `--network` option to "ethernet".\n\nWifi:\n You can setup the device OS to use wifi by setting the `--network` option to "wifi".\n If you set "network" to "wifi", you will need to specify the `--ssid` and `--key` option as well.\n\nExamples:\n $ resin device init --application 91 --network ethernet\n $ resin device init /dev/disk2 --application 91 --network wifi --ssid MyNetwork --key secret',
|
||||
options: [commandOptions.application, commandOptions.network, commandOptions.wifiSsid, commandOptions.wifiKey],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
params.id = options.application;
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
if (params.device != null) {
|
||||
return callback(null, params.device);
|
||||
}
|
||||
return visuals.patterns.selectDrive(callback);
|
||||
}, function(device, callback) {
|
||||
params.device = device;
|
||||
return visuals.patterns.confirm(options.yes, "This will completely erase " + params.device + ". Are you sure you want to continue?", callback);
|
||||
}, function(confirmed, callback) {
|
||||
if (!confirmed) {
|
||||
return done();
|
||||
}
|
||||
options.yes = confirmed;
|
||||
return osAction.download.action(params, options, callback);
|
||||
}, function(outputFile, callback) {
|
||||
params.image = outputFile;
|
||||
return osAction.install.action(params, options, callback);
|
||||
}
|
||||
], done);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
33
build/actions/drive.js
Normal file
33
build/actions/drive.js
Normal file
@ -0,0 +1,33 @@
|
||||
(function() {
|
||||
var _, async, drivelist, visuals;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
async = require('async');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
drivelist = require('drivelist');
|
||||
|
||||
exports.list = {
|
||||
signature: 'drives',
|
||||
description: 'list available drives',
|
||||
help: 'Use this command to list all drives that are connected to your machine.\n\nExamples:\n $ resin drives',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return drivelist.list(function(error, drives) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
return async.reject(drives, drivelist.isSystem, function(removableDrives) {
|
||||
if (_.isEmpty(removableDrives)) {
|
||||
return done(new Error('No removable devices available'));
|
||||
}
|
||||
console.log(visuals.widgets.table.horizontal(removableDrives, ['device', 'description', 'size']));
|
||||
return done();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
81
build/actions/environment-variables.js
Normal file
81
build/actions/environment-variables.js
Normal file
@ -0,0 +1,81 @@
|
||||
(function() {
|
||||
var _, commandOptions, resin, visuals;
|
||||
|
||||
_ = require('lodash-contrib');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
commandOptions = require('./command-options');
|
||||
|
||||
exports.list = {
|
||||
signature: 'envs',
|
||||
description: 'list all environment variables',
|
||||
help: 'Use this command to list all environment variables for a particular application.\nNotice we will support per-device environment variables soon.\n\nThis command lists all custom environment variables set on the devices running\nthe application. If you want to see all environment variables, including private\nones used by resin, use the verbose option.\n\nExample:\n $ resin envs --application 91\n $ resin envs --application 91 --verbose',
|
||||
options: [
|
||||
commandOptions.application, {
|
||||
signature: 'verbose',
|
||||
description: 'show private environment variables',
|
||||
boolean: true,
|
||||
alias: 'v'
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.environmentVariables.getAllByApplication(options.application, function(error, environmentVariables) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
if (!options.verbose) {
|
||||
environmentVariables = _.reject(environmentVariables, resin.models.environmentVariables.isSystemVariable);
|
||||
}
|
||||
console.log(visuals.widgets.table.horizontal(environmentVariables, ['id', 'name', 'value']));
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.remove = {
|
||||
signature: 'env rm <id>',
|
||||
description: 'remove an environment variable',
|
||||
help: 'Use this command to remove an environment variable from an application.\n\nDon\'t remove resin specific variables, as things might not work as expected.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nExamples:\n $ resin env rm 215\n $ resin env rm 215 --yes',
|
||||
options: [commandOptions.yes],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return visuals.patterns.remove('environment variable', options.yes, function(callback) {
|
||||
return resin.models.environmentVariables.remove(params.id, callback);
|
||||
}, done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.add = {
|
||||
signature: 'env add <key> [value]',
|
||||
description: 'add an environment variable',
|
||||
help: 'Use this command to add an enviroment variable to an application.\n\nYou need to pass the `--application` option.\n\nIf value is omitted, the tool will attempt to use the variable\'s value\nas defined in your host machine.\n\nIf the value is grabbed from the environment, a warning message will be printed.\nUse `--quiet` to remove it.\n\nExamples:\n $ resin env add EDITOR vim -a 91\n $ resin env add TERM -a 91',
|
||||
options: [commandOptions.application],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
if (params.value == null) {
|
||||
params.value = process.env[params.key];
|
||||
if (params.value == null) {
|
||||
return done(new Error("Environment value not found for key: " + params.key));
|
||||
} else {
|
||||
console.info("Warning: using " + params.key + "=" + params.value + " from host environment");
|
||||
}
|
||||
}
|
||||
return resin.models.environmentVariables.create(options.application, params.key, params.value, done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.rename = {
|
||||
signature: 'env rename <id> <value>',
|
||||
description: 'rename an environment variable',
|
||||
help: 'Use this command to rename an enviroment variable from an application.\n\nExamples:\n $ resin env rename 376 emacs',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.environmentVariables.update(params.id, params.value, done);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
92
build/actions/examples.js
Normal file
92
build/actions/examples.js
Normal file
@ -0,0 +1,92 @@
|
||||
(function() {
|
||||
var _, async, examplesData, fs, gitCli, path, resin, visuals;
|
||||
|
||||
async = require('async');
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
path = require('path');
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
gitCli = require('git-cli');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
examplesData = require('../data/examples.json');
|
||||
|
||||
exports.list = {
|
||||
signature: 'examples',
|
||||
description: 'list all example applications',
|
||||
help: 'Use this command to list available example applications from resin.io\n\nExample:\n $ resin examples',
|
||||
permission: 'user',
|
||||
action: function() {
|
||||
examplesData = _.map(examplesData, function(example, index) {
|
||||
example.id = index + 1;
|
||||
return example;
|
||||
});
|
||||
examplesData = _.map(examplesData, function(example) {
|
||||
if (example.author == null) {
|
||||
example.author = 'Unknown';
|
||||
}
|
||||
return example;
|
||||
});
|
||||
return console.log(visuals.widgets.table.horizontal(examplesData, ['id', 'display_name', 'repository', 'author']));
|
||||
}
|
||||
};
|
||||
|
||||
exports.info = {
|
||||
signature: 'example <id>',
|
||||
description: 'list a single example application',
|
||||
help: 'Use this command to show information of a single example application\n\nExample:\n $ resin example 3',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
var example, id;
|
||||
id = params.id - 1;
|
||||
example = examplesData[id];
|
||||
if (example == null) {
|
||||
return done(new Error("Unknown example: " + id));
|
||||
}
|
||||
example.id = id;
|
||||
if (example.author == null) {
|
||||
example.author = 'Unknown';
|
||||
}
|
||||
console.log(visuals.widgets.table.vertical(example, ['id', 'display_name', 'description', 'author', 'repository']));
|
||||
return done();
|
||||
}
|
||||
};
|
||||
|
||||
exports.clone = {
|
||||
signature: 'example clone <id>',
|
||||
description: 'clone an example application',
|
||||
help: 'Use this command to clone an example application to the current directory\n\nThis command outputs information about the cloning process.\nUse `--quiet` to remove that output.\n\nExample:\n $ resin example clone 3',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
var example;
|
||||
example = examplesData[params.id - 1];
|
||||
if (example == null) {
|
||||
return done(new Error("Unknown example: " + id));
|
||||
}
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
var exampleAbsolutePath;
|
||||
exampleAbsolutePath = path.join(process.cwd(), example.name);
|
||||
return fs.exists(exampleAbsolutePath, function(exists) {
|
||||
var error;
|
||||
if (!exists) {
|
||||
return callback();
|
||||
}
|
||||
error = new Error("Directory exists: " + example.name);
|
||||
return callback(error);
|
||||
});
|
||||
}, function(callback) {
|
||||
console.info("Cloning " + example.display_name + " to " + example.name);
|
||||
return gitCli.Repository.clone(example.repository, example.name, callback);
|
||||
}
|
||||
], done);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
161
build/actions/help.js
Normal file
161
build/actions/help.js
Normal file
@ -0,0 +1,161 @@
|
||||
(function() {
|
||||
var PADDING_INITIAL, PADDING_MIDDLE, _, addAlias, addOptionPrefix, buildHelpString, buildOptionSignatureHelp, capitano, getCommandHelp, getFieldMaxLength, getOptionHelp, getOptionsParsedSignatures, resin;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
_.str = require('underscore.string');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
capitano = require('capitano');
|
||||
|
||||
PADDING_INITIAL = ' ';
|
||||
|
||||
PADDING_MIDDLE = '\t';
|
||||
|
||||
getFieldMaxLength = function(array, field) {
|
||||
return _.max(_.map(array, function(item) {
|
||||
return item[field].toString().length;
|
||||
}));
|
||||
};
|
||||
|
||||
buildHelpString = function(firstColumn, secondColumn) {
|
||||
var result;
|
||||
result = "" + PADDING_INITIAL + firstColumn;
|
||||
result += "" + PADDING_MIDDLE + secondColumn;
|
||||
return result;
|
||||
};
|
||||
|
||||
addOptionPrefix = function(option) {
|
||||
if (option.length <= 0) {
|
||||
return;
|
||||
}
|
||||
if (option.length === 1) {
|
||||
return "-" + option;
|
||||
} else {
|
||||
return "--" + option;
|
||||
}
|
||||
};
|
||||
|
||||
addAlias = function(alias) {
|
||||
return ", " + (addOptionPrefix(alias));
|
||||
};
|
||||
|
||||
buildOptionSignatureHelp = function(option) {
|
||||
var alias, i, len, ref, result;
|
||||
result = addOptionPrefix(option.signature.toString());
|
||||
if (_.isString(option.alias)) {
|
||||
result += addAlias(option.alias);
|
||||
} else if (_.isArray(option.alias)) {
|
||||
ref = option.alias;
|
||||
for (i = 0, len = ref.length; i < len; i++) {
|
||||
alias = ref[i];
|
||||
result += addAlias(alias);
|
||||
}
|
||||
}
|
||||
if (option.parameter != null) {
|
||||
result += " <" + option.parameter + ">";
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
getCommandHelp = function(command) {
|
||||
var commandSignature, maxSignatureLength;
|
||||
maxSignatureLength = getFieldMaxLength(capitano.state.commands, 'signature');
|
||||
commandSignature = _.str.rpad(command.signature.toString(), maxSignatureLength, ' ');
|
||||
return buildHelpString(commandSignature, command.description);
|
||||
};
|
||||
|
||||
getOptionsParsedSignatures = function(optionsHelp) {
|
||||
var maxLength;
|
||||
maxLength = _.max(_.map(optionsHelp, function(signature) {
|
||||
return signature.length;
|
||||
}));
|
||||
return _.map(optionsHelp, function(signature) {
|
||||
return _.str.rpad(signature, maxLength, ' ');
|
||||
});
|
||||
};
|
||||
|
||||
getOptionHelp = function(option, maxLength) {
|
||||
var result;
|
||||
result = PADDING_INITIAL;
|
||||
result += _.str.rpad(option.signature, maxLength, ' ');
|
||||
result += PADDING_MIDDLE;
|
||||
result += option.description;
|
||||
return result;
|
||||
};
|
||||
|
||||
exports.general = function() {
|
||||
var command, i, j, len, len1, option, optionSignatureMaxLength, options, ref;
|
||||
console.log('Usage: resin [COMMAND] [OPTIONS]\n');
|
||||
console.log('Commands:\n');
|
||||
ref = capitano.state.commands;
|
||||
for (i = 0, len = ref.length; i < len; i++) {
|
||||
command = ref[i];
|
||||
if (command.isWildcard()) {
|
||||
continue;
|
||||
}
|
||||
console.log(getCommandHelp(command));
|
||||
}
|
||||
console.log('\nGlobal Options:\n');
|
||||
options = _.map(capitano.state.globalOptions, function(option) {
|
||||
option.signature = buildOptionSignatureHelp(option);
|
||||
return option;
|
||||
});
|
||||
optionSignatureMaxLength = _.max(_.map(options, function(option) {
|
||||
return option.signature.length;
|
||||
}));
|
||||
for (j = 0, len1 = options.length; j < len1; j++) {
|
||||
option = options[j];
|
||||
console.log(getOptionHelp(option, optionSignatureMaxLength));
|
||||
}
|
||||
return console.log();
|
||||
};
|
||||
|
||||
exports.command = function(params, options, done) {
|
||||
return capitano.state.getMatchCommand(params.command, function(error, command) {
|
||||
var i, len, option, optionSignatureMaxLength;
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
if ((command == null) || command.isWildcard()) {
|
||||
return capitano.defaults.actions.commandNotFound(params.command);
|
||||
}
|
||||
console.log("Usage: " + command.signature);
|
||||
if (command.help != null) {
|
||||
console.log("\n" + command.help);
|
||||
} else if (command.description != null) {
|
||||
console.log("\n" + (_.str.humanize(command.description)));
|
||||
}
|
||||
if (!_.isEmpty(command.options)) {
|
||||
console.log('\nOptions:\n');
|
||||
options = _.map(command.options, function(option) {
|
||||
option.signature = buildOptionSignatureHelp(option);
|
||||
return option;
|
||||
});
|
||||
optionSignatureMaxLength = _.max(_.map(options, function(option) {
|
||||
return option.signature.toString().length;
|
||||
}));
|
||||
for (i = 0, len = options.length; i < len; i++) {
|
||||
option = options[i];
|
||||
console.log(getOptionHelp(option, optionSignatureMaxLength));
|
||||
}
|
||||
console.log();
|
||||
}
|
||||
return done();
|
||||
});
|
||||
};
|
||||
|
||||
exports.help = {
|
||||
signature: 'help [command...]',
|
||||
description: 'show help',
|
||||
action: function(params, options, done) {
|
||||
if (params.command != null) {
|
||||
return exports.command(params, options, done);
|
||||
} else {
|
||||
return exports.general(params, options, done);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
19
build/actions/index.js
Normal file
19
build/actions/index.js
Normal file
@ -0,0 +1,19 @@
|
||||
(function() {
|
||||
module.exports = {
|
||||
app: require('./app'),
|
||||
info: require('./info'),
|
||||
auth: require('./auth'),
|
||||
drive: require('./drive'),
|
||||
device: require('./device'),
|
||||
env: require('./environment-variables'),
|
||||
keys: require('./keys'),
|
||||
logs: require('./logs'),
|
||||
notes: require('./notes'),
|
||||
preferences: require('./preferences'),
|
||||
os: require('./os'),
|
||||
help: require('./help'),
|
||||
examples: require('./examples'),
|
||||
plugin: require('./plugin')
|
||||
};
|
||||
|
||||
}).call(this);
|
15
build/actions/info.js
Normal file
15
build/actions/info.js
Normal file
@ -0,0 +1,15 @@
|
||||
(function() {
|
||||
var packageJSON;
|
||||
|
||||
packageJSON = require('../../package.json');
|
||||
|
||||
exports.version = {
|
||||
signature: 'version',
|
||||
description: 'output the version number',
|
||||
action: function() {
|
||||
console.log(packageJSON.name + ": " + packageJSON.version);
|
||||
return console.log("node: " + process.version);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
92
build/actions/keys.js
Normal file
92
build/actions/keys.js
Normal file
@ -0,0 +1,92 @@
|
||||
(function() {
|
||||
var _, async, capitano, commandOptions, fs, resin, visuals;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
_.str = require('underscore.string');
|
||||
|
||||
async = require('async');
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
capitano = require('capitano');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
commandOptions = require('./command-options');
|
||||
|
||||
exports.list = {
|
||||
signature: 'keys',
|
||||
description: 'list all ssh keys',
|
||||
help: 'Use this command to list all your SSH keys.\n\nExamples:\n $ resin keys',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.key.getAll(function(error, keys) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.log(visuals.widgets.table.horizontal(keys, ['id', 'title']));
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.info = {
|
||||
signature: 'key <id>',
|
||||
description: 'list a single ssh key',
|
||||
help: 'Use this command to show information about a single SSH key.\n\nExamples:\n $ resin key 17',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.key.get(params.id, function(error, key) {
|
||||
var sshKeyWidth;
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
sshKeyWidth = resin.settings.get('sshKeyWidth');
|
||||
key.public_key = '\n' + visuals.helpers.chop(key.public_key, sshKeyWidth);
|
||||
console.log(visuals.widgets.table.vertical(key, ['id', 'title', 'public_key']));
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.remove = {
|
||||
signature: 'key rm <id>',
|
||||
description: 'remove a ssh key',
|
||||
help: 'Use this command to remove a SSH key from resin.io.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nExamples:\n $ resin key rm 17\n $ resin key rm 17 --yes',
|
||||
options: [commandOptions.yes],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return visuals.patterns.remove('key', options.yes, function(callback) {
|
||||
return resin.models.key.remove(params.id, callback);
|
||||
}, done);
|
||||
}
|
||||
};
|
||||
|
||||
exports.add = {
|
||||
signature: 'key add <name> [path]',
|
||||
description: 'add a SSH key to resin.io',
|
||||
help: 'Use this command to associate a new SSH key with your account.\n\nIf `path` is omitted, the command will attempt\nto read the SSH key from stdin.\n\nExamples:\n $ resin key add Main ~/.ssh/id_rsa.pub\n $ cat ~/.ssh/id_rsa.pub | resin key add Main',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
if (params.path != null) {
|
||||
return fs.readFile(params.path, {
|
||||
encoding: 'utf8'
|
||||
}, callback);
|
||||
} else {
|
||||
return capitano.utils.getStdin(function(data) {
|
||||
return callback(null, data);
|
||||
});
|
||||
}
|
||||
}, function(key, callback) {
|
||||
return resin.models.key.create(params.name, key, callback);
|
||||
}
|
||||
], done);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
48
build/actions/logs.js
Normal file
48
build/actions/logs.js
Normal file
@ -0,0 +1,48 @@
|
||||
(function() {
|
||||
var LOGS_HISTORY_COUNT, _, resin;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
LOGS_HISTORY_COUNT = 200;
|
||||
|
||||
exports.logs = {
|
||||
signature: 'logs <uuid>',
|
||||
description: 'show device logs',
|
||||
help: 'Use this command to show logs for a specific device.\n\nBy default, the command prints all log messages and exit.\n\nTo limit the output to the n last lines, use the `--num` option along with a number.\nThis is similar to doing `resin logs <uuid> | tail -n X`.\n\nTo continuously stream output, and see new logs in real time, use the `--tail` option.\n\nNote that for now you need to provide the whole UUID for this command to work correctly,\nand the tool won\'t notice if you\'re using an invalid UUID.\n\nThis is due to some technical limitations that we plan to address soon.\n\nExamples:\n $ resin logs 23c73a12e3527df55c60b9ce647640c1b7da1b32d71e6a39849ac0f00db828\n $ resin logs 23c73a12e3527df55c60b9ce647640c1b7da1b32d71e6a39849ac0f00db828 --num 20\n $ resin logs 23c73a12e3527df55c60b9ce647640c1b7da1b32d71e6a39849ac0f00db828 --tail',
|
||||
options: [
|
||||
{
|
||||
signature: 'num',
|
||||
parameter: 'num',
|
||||
description: 'number of lines to display',
|
||||
alias: 'n'
|
||||
}, {
|
||||
signature: 'tail',
|
||||
description: 'continuously stream output',
|
||||
boolean: true,
|
||||
alias: 't'
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.logs.subscribe(params.uuid, {
|
||||
history: options.num || LOGS_HISTORY_COUNT,
|
||||
tail: options.tail
|
||||
}, function(error, message) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
if (_.isArray(message)) {
|
||||
_.each(message, function(line) {
|
||||
return console.log(line);
|
||||
});
|
||||
} else {
|
||||
console.log(message);
|
||||
}
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
27
build/actions/notes.js
Normal file
27
build/actions/notes.js
Normal file
@ -0,0 +1,27 @@
|
||||
(function() {
|
||||
var async, resin;
|
||||
|
||||
async = require('async');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
exports.set = {
|
||||
signature: 'note <|note>',
|
||||
description: 'set a device note',
|
||||
help: 'Use this command to set or update a device note.\n\nIf note command isn\'t passed, the tool attempts to read from `stdin`.\n\nTo view the notes, use $ resin device <id>.\n\nExamples:\n $ resin note "My useful note" --device 317\n $ cat note.txt | resin note --device 317',
|
||||
options: [
|
||||
{
|
||||
signature: 'device',
|
||||
parameter: 'device',
|
||||
description: 'device id',
|
||||
alias: ['d', 'dev'],
|
||||
required: 'You have to specify a device'
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return resin.models.device.note(options.device, params.note, done);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
134
build/actions/os.js
Normal file
134
build/actions/os.js
Normal file
@ -0,0 +1,134 @@
|
||||
(function() {
|
||||
var _, async, commandOptions, diskio, fs, mkdirp, os, path, progressStream, resin, visuals;
|
||||
|
||||
_ = require('lodash-contrib');
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
os = require('os');
|
||||
|
||||
async = require('async');
|
||||
|
||||
path = require('path');
|
||||
|
||||
mkdirp = require('mkdirp');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
progressStream = require('progress-stream');
|
||||
|
||||
diskio = require('diskio');
|
||||
|
||||
commandOptions = require('./command-options');
|
||||
|
||||
exports.download = {
|
||||
signature: 'os download <id>',
|
||||
description: 'download device OS',
|
||||
help: 'Use this command to download the device OS configured to a specific network.\n\nEthernet:\n You can setup the device OS to use ethernet by setting the `--network` option to "ethernet".\n\nWifi:\n You can setup the device OS to use wifi by setting the `--network` option to "wifi".\n If you set "network" to "wifi", you will need to specify the `--ssid` and `--key` option as well.\n\nBy default, this command saved the downloaded image into a resin specific directory.\nYou can save it to a custom location by specifying the `--output` option.\n\nExamples:\n $ resin os download 91 --network ethernet\n $ resin os download 91 --network wifi --ssid MyNetwork --key secreykey123\n $ resin os download 91 --network ethernet --output ~/MyResinOS.zip',
|
||||
options: [
|
||||
commandOptions.network, commandOptions.wifiSsid, commandOptions.wifiKey, {
|
||||
signature: 'output',
|
||||
parameter: 'output',
|
||||
description: 'output file',
|
||||
alias: 'o'
|
||||
}
|
||||
],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
var fileName, osParams;
|
||||
osParams = {
|
||||
network: options.network,
|
||||
wifiSsid: options.ssid,
|
||||
wifiKey: options.key,
|
||||
appId: params.id
|
||||
};
|
||||
fileName = resin.models.os.generateCacheName(osParams);
|
||||
if (options.output == null) {
|
||||
options.output = path.join(resin.settings.get('directories.os'), fileName);
|
||||
}
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
return mkdirp(path.dirname(options.output), _.unary(callback));
|
||||
}, function(callback) {
|
||||
var bar;
|
||||
console.info("Destination file: " + options.output + "\n");
|
||||
bar = new visuals.widgets.Progress('Downloading Device OS');
|
||||
return resin.models.os.download(osParams, options.output, callback, function(state) {
|
||||
return bar.update(state);
|
||||
});
|
||||
}
|
||||
], function(error) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.info("\nFinished downloading " + options.output);
|
||||
return done(null, options.output);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.install = {
|
||||
signature: 'os install <image> [device]',
|
||||
description: 'write an operating system image to a device',
|
||||
help: 'Use this command to write an operating system image to a device.\n\nNote that this command requires admin privileges.\n\nIf `device` is omitted, you will be prompted to select a device interactively.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nYou can quiet the progress bar by passing the `--quiet` boolean option.\n\nYou may have to unmount the device before attempting this operation.\n\nSee the `drives` command to get a list of all connected devices to your machine and their respective ids.\n\nIn Mac OS X:\n $ sudo diskutil unmountDisk /dev/xxx\n\nIn GNU/Linux:\n $ sudo umount /dev/xxx\n\nExamples:\n $ resin os install rpi.iso /dev/disk2',
|
||||
options: [commandOptions.yes],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return async.waterfall([
|
||||
function(callback) {
|
||||
if (params.device != null) {
|
||||
return callback(null, params.device);
|
||||
}
|
||||
return visuals.patterns.selectDrive(function(error, device) {
|
||||
if (error != null) {
|
||||
return callback(error);
|
||||
}
|
||||
if (device == null) {
|
||||
return callback(new Error('No removable devices available'));
|
||||
}
|
||||
return callback(null, device);
|
||||
});
|
||||
}, function(device, callback) {
|
||||
var message;
|
||||
params.device = device;
|
||||
message = "This will completely erase " + params.device + ". Are you sure you want to continue?";
|
||||
return visuals.patterns.confirm(options.yes, message, callback);
|
||||
}, function(confirmed, callback) {
|
||||
var bar, error, imageFileSize, imageFileStream, progress;
|
||||
if (!confirmed) {
|
||||
return done();
|
||||
}
|
||||
imageFileSize = fs.statSync(params.image).size;
|
||||
if (imageFileSize === 0) {
|
||||
error = new Error("Invalid OS image: " + params.image + ". The image is 0 bytes.");
|
||||
return callback(error);
|
||||
}
|
||||
progress = progressStream({
|
||||
length: imageFileSize,
|
||||
time: 500
|
||||
});
|
||||
if (!options.quiet) {
|
||||
bar = new visuals.widgets.Progress('Writing Device OS');
|
||||
progress.on('progress', function(status) {
|
||||
return bar.update(status);
|
||||
});
|
||||
}
|
||||
imageFileStream = fs.createReadStream(params.image).pipe(progress);
|
||||
return diskio.writeStream(params.device, imageFileStream, callback);
|
||||
}
|
||||
], function(error) {
|
||||
var resinWritePath, windosu;
|
||||
if (os.platform() === 'win32' && (error != null) && (error.code === 'EPERM' || error.code === 'EACCES')) {
|
||||
windosu = require('windosu');
|
||||
resinWritePath = "\"" + (path.join(__dirname, '..', '..', 'bin', 'resin-write')) + "\"";
|
||||
return windosu.exec("node " + resinWritePath + " \"" + params.image + "\" \"" + params.device + "\"");
|
||||
} else {
|
||||
return done(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
67
build/actions/plugin.js
Normal file
67
build/actions/plugin.js
Normal file
@ -0,0 +1,67 @@
|
||||
(function() {
|
||||
var _, commandOptions, plugins, visuals;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
visuals = require('resin-cli-visuals');
|
||||
|
||||
commandOptions = require('./command-options');
|
||||
|
||||
plugins = require('../plugins');
|
||||
|
||||
exports.list = {
|
||||
signature: 'plugins',
|
||||
description: 'list all plugins',
|
||||
help: 'Use this command to list all the installed resin plugins.\n\nExamples:\n $ resin plugins',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return plugins.list(function(error, resinPlugins) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
if (_.isEmpty(resinPlugins)) {
|
||||
console.log('You don\'t have any plugins yet');
|
||||
return done();
|
||||
}
|
||||
console.log(visuals.widgets.table.horizontal(resinPlugins, ['name', 'version', 'description', 'license']));
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.install = {
|
||||
signature: 'plugin install <name>',
|
||||
description: 'install a plugin',
|
||||
help: 'Use this command to install a resin plugin\n\nExamples:\n $ resin plugin install hello',
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return plugins.install(params.name, function(error) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.info("Plugin installed: " + params.name);
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.remove = {
|
||||
signature: 'plugin rm <name>',
|
||||
description: 'remove a plugin',
|
||||
help: 'Use this command to remove a resin.io plugin.\n\nNotice this command asks for confirmation interactively.\nYou can avoid this by passing the `--yes` boolean option.\n\nExamples:\n $ resin plugin rm hello\n $ resin plugin rm hello --yes',
|
||||
options: [commandOptions.yes],
|
||||
permission: 'user',
|
||||
action: function(params, options, done) {
|
||||
return visuals.patterns.remove('plugin', options.yes, function(callback) {
|
||||
return plugins.remove(params.name, callback);
|
||||
}, function(error) {
|
||||
if (error != null) {
|
||||
return done(error);
|
||||
}
|
||||
console.info("Plugin removed: " + params.name);
|
||||
return done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
23
build/actions/preferences.js
Normal file
23
build/actions/preferences.js
Normal file
@ -0,0 +1,23 @@
|
||||
(function() {
|
||||
var open, resin, url;
|
||||
|
||||
open = require('open');
|
||||
|
||||
url = require('url');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
exports.preferences = {
|
||||
signature: 'preferences',
|
||||
description: 'open preferences form',
|
||||
help: 'Use this command to open the preferences form.\n\nIn the future, we will allow changing all preferences directly from the terminal.\nFor now, we open your default web browser and point it to the web based preferences form.\n\nExamples:\n $ resin preferences',
|
||||
permission: 'user',
|
||||
action: function() {
|
||||
var absUrl, preferencesUrl;
|
||||
preferencesUrl = resin.settings.get('urls.preferences');
|
||||
absUrl = url.resolve(resin.settings.get('remoteUrl'), preferencesUrl);
|
||||
return open(absUrl);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
162
build/app.js
Normal file
162
build/app.js
Normal file
@ -0,0 +1,162 @@
|
||||
(function() {
|
||||
var _, actions, async, capitano, changeProjectDirectory, errors, plugins, resin;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
async = require('async');
|
||||
|
||||
capitano = require('capitano');
|
||||
|
||||
resin = require('resin-sdk');
|
||||
|
||||
actions = require('./actions');
|
||||
|
||||
errors = require('./errors');
|
||||
|
||||
plugins = require('./plugins');
|
||||
|
||||
capitano.permission('user', function(done) {
|
||||
return resin.auth.isLoggedIn(function(isLoggedIn) {
|
||||
if (!isLoggedIn) {
|
||||
return done(new Error('You have to log in'));
|
||||
}
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
capitano.command({
|
||||
signature: '*',
|
||||
action: function() {
|
||||
return capitano.execute({
|
||||
command: 'help'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
capitano.globalOption({
|
||||
signature: 'quiet',
|
||||
description: 'quiet (no output)',
|
||||
boolean: true,
|
||||
alias: 'q'
|
||||
});
|
||||
|
||||
capitano.globalOption({
|
||||
signature: 'project',
|
||||
parameter: 'path',
|
||||
description: 'project path',
|
||||
alias: 'j'
|
||||
});
|
||||
|
||||
capitano.globalOption({
|
||||
signature: 'no-color',
|
||||
description: 'disable colour highlighting',
|
||||
boolean: true
|
||||
});
|
||||
|
||||
capitano.command(actions.info.version);
|
||||
|
||||
capitano.command(actions.help.help);
|
||||
|
||||
capitano.command(actions.auth.login);
|
||||
|
||||
capitano.command(actions.auth.logout);
|
||||
|
||||
capitano.command(actions.auth.signup);
|
||||
|
||||
capitano.command(actions.auth.whoami);
|
||||
|
||||
capitano.command(actions.app.create);
|
||||
|
||||
capitano.command(actions.app.list);
|
||||
|
||||
capitano.command(actions.app.info);
|
||||
|
||||
capitano.command(actions.app.remove);
|
||||
|
||||
capitano.command(actions.app.restart);
|
||||
|
||||
capitano.command(actions.app.init);
|
||||
|
||||
capitano.command(actions.device.list);
|
||||
|
||||
capitano.command(actions.device.supported);
|
||||
|
||||
capitano.command(actions.device.rename);
|
||||
|
||||
capitano.command(actions.device.init);
|
||||
|
||||
capitano.command(actions.device.info);
|
||||
|
||||
capitano.command(actions.device.remove);
|
||||
|
||||
capitano.command(actions.device.identify);
|
||||
|
||||
capitano.command(actions.drive.list);
|
||||
|
||||
capitano.command(actions.notes.set);
|
||||
|
||||
capitano.command(actions.preferences.preferences);
|
||||
|
||||
capitano.command(actions.keys.list);
|
||||
|
||||
capitano.command(actions.keys.add);
|
||||
|
||||
capitano.command(actions.keys.info);
|
||||
|
||||
capitano.command(actions.keys.remove);
|
||||
|
||||
capitano.command(actions.env.list);
|
||||
|
||||
capitano.command(actions.env.add);
|
||||
|
||||
capitano.command(actions.env.rename);
|
||||
|
||||
capitano.command(actions.env.remove);
|
||||
|
||||
capitano.command(actions.logs.logs);
|
||||
|
||||
capitano.command(actions.os.download);
|
||||
|
||||
capitano.command(actions.os.install);
|
||||
|
||||
capitano.command(actions.examples.list);
|
||||
|
||||
capitano.command(actions.examples.clone);
|
||||
|
||||
capitano.command(actions.examples.info);
|
||||
|
||||
capitano.command(actions.plugin.list);
|
||||
|
||||
capitano.command(actions.plugin.install);
|
||||
|
||||
capitano.command(actions.plugin.remove);
|
||||
|
||||
changeProjectDirectory = function(directory) {
|
||||
try {
|
||||
return process.chdir(directory);
|
||||
} catch (_error) {
|
||||
return errors.handle(new Error("Invalid project: " + directory));
|
||||
}
|
||||
};
|
||||
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
return plugins.register('resin-plugin-', callback);
|
||||
}, function(callback) {
|
||||
var dataPrefix;
|
||||
dataPrefix = resin.settings.get('dataPrefix');
|
||||
return resin.data.prefix.set(dataPrefix, callback);
|
||||
}, function(callback) {
|
||||
var cli;
|
||||
cli = capitano.parse(process.argv);
|
||||
if (cli.global.quiet) {
|
||||
console.info = _.noop;
|
||||
}
|
||||
if (cli.global.project != null) {
|
||||
changeProjectDirectory(cli.global.project);
|
||||
}
|
||||
return capitano.execute(cli, callback);
|
||||
}
|
||||
], errors.handle);
|
||||
|
||||
}).call(this);
|
96
build/data/examples.json
Normal file
96
build/data/examples.json
Normal file
@ -0,0 +1,96 @@
|
||||
[
|
||||
{
|
||||
"name": "basic-resin-node-project",
|
||||
"display_name": "Node.js Starter Project",
|
||||
"repository": "https://github.com/resin-io/basic-resin-node-project",
|
||||
"description": "This is a simple Hello, World project for node.js designed to act as a basis for future work. It demonstrates how to install native Linux packages and configure your application."
|
||||
},
|
||||
{
|
||||
"name": "cimon",
|
||||
"display_name": "Cimon",
|
||||
"repository": "https://bitbucket.org/efwe/cimon",
|
||||
"description": "A simple tool for reading temperatures from a USB-enabled thermometer. This project is used as the backend to efwe's awesome temperature visualisation at 123k.de.",
|
||||
"author": "efwe"
|
||||
},
|
||||
{
|
||||
"name": "firebaseDTL",
|
||||
"display_name": "Digital Temperature Logger",
|
||||
"repository": "https://github.com/shaunmulligan/firebaseDTL",
|
||||
"description": "A Firebase-backed Digital Temperature Logger allowing you to connect devices with multiple temperature sensors to a central cloud-based datastore.",
|
||||
"author": "Shaun Mulligan"
|
||||
},
|
||||
{
|
||||
"name": "digitiser",
|
||||
"display_name": "Digitiser",
|
||||
"repository": "https://github.com/shaunmulligan/digitiser",
|
||||
"description": "A tool for displaying integer values from a JSON endpoint on a MAX7219 7-segment display.",
|
||||
"author": "Shaun Mulligan"
|
||||
},
|
||||
{
|
||||
"name": "basic-gpio",
|
||||
"display_name": "Example Pi Pins Application",
|
||||
"repository": "https://github.com/shaunmulligan/basic-gpio",
|
||||
"description": "A simple application which demonstrates the use of the Pi Pins library to interface with GPIO.",
|
||||
"author": "Shaun Mulligan"
|
||||
},
|
||||
{
|
||||
"name": "coder",
|
||||
"display_name": "Google Coder",
|
||||
"repository": "https://github.com/resin-io/coder",
|
||||
"description": "Resin.io-enabled version of Google's excellent Coder project which makes it easy to develop web projects on your device."
|
||||
},
|
||||
{
|
||||
"name": "hoversnap",
|
||||
"display_name": "Hoversnap",
|
||||
"repository": "https://github.com/resin-io/hoversnap",
|
||||
"description": "A tool for controlling a camera using a foot switch in order to capture shots in which people appear to be flying."
|
||||
},
|
||||
{
|
||||
"name": "resin-piminer",
|
||||
"display_name": "Pi Miner",
|
||||
"repository": "https://github.com/csquared/resin-piminer",
|
||||
"description": "A bitcoin miner for the Raspberry Pi.",
|
||||
"author": "Chris Continanza"
|
||||
},
|
||||
{
|
||||
"name": "resin-cctv",
|
||||
"display_name": "Resin CCTV",
|
||||
"repository": "https://github.com/abresas/resin-cctv",
|
||||
"description": "A project which allows you to use your devices as a CCTV camera system which hooks into Dropbox.",
|
||||
"author": "Aleksis Brezas"
|
||||
},
|
||||
{
|
||||
"name": "resin_player",
|
||||
"display_name": "Resin Player",
|
||||
"repository": "https://bitbucket.org/lifeeth/resin_player/",
|
||||
"description": "A project which allows you to play squeezebox media through your devices.",
|
||||
"author": "Praneeth Bodduluri"
|
||||
},
|
||||
{
|
||||
"name": "salesforceTemp",
|
||||
"display_name": "Salesforce Temperature Probe",
|
||||
"repository": "https://github.com/shaunmulligan/salesforceTemp",
|
||||
"description": "Example application for interfacing with a temperature probe using Salesforce.com.",
|
||||
"author": "Shaun Mulligan"
|
||||
},
|
||||
{
|
||||
"name": "sms2speech",
|
||||
"display_name": "SMS to Speech",
|
||||
"repository": "https://github.com/alexandrosm/sms2speech",
|
||||
"description": "A simple tool which uses Twillio to read out incoming SMS messages.",
|
||||
"author": "Alexandros Marinos"
|
||||
},
|
||||
{
|
||||
"name": "resin-kiosk",
|
||||
"display_name": "Simple Digitiser Kiosk",
|
||||
"repository": "https://bitbucket.org/lifeeth/resin-kiosk",
|
||||
"description": "Displays values from a JSON endpoint on your browser in kiosk mode",
|
||||
"author": "Praneeth Bodduluri"
|
||||
},
|
||||
{
|
||||
"name": "text2speech",
|
||||
"display_name": "Text to Speech Converter",
|
||||
"repository": "https://github.com/resin-io/text2speech",
|
||||
"description": "A simple application that makes your device speak out loud."
|
||||
}
|
||||
]
|
45
build/errors.js
Normal file
45
build/errors.js
Normal file
@ -0,0 +1,45 @@
|
||||
(function() {
|
||||
var _, os;
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
os = require('os');
|
||||
|
||||
exports.handle = function(error, exit) {
|
||||
var errorCode, message;
|
||||
if (exit == null) {
|
||||
exit = true;
|
||||
}
|
||||
if ((error == null) || !(error instanceof Error)) {
|
||||
return;
|
||||
}
|
||||
if (process.env.DEBUG) {
|
||||
console.error(error.stack);
|
||||
} else {
|
||||
if (error.code === 'EISDIR') {
|
||||
console.error("File is a directory: " + error.path);
|
||||
} else if (error.code === 'ENOENT') {
|
||||
console.error("No such file or directory: " + error.path);
|
||||
} else if (error.code === 'EACCES' || error.code === 'EPERM') {
|
||||
message = 'You don\'t have enough privileges to run this operation.\n';
|
||||
if (os.platform() === 'win32') {
|
||||
message += 'Run a new Command Prompt as administrator and try running this command again.';
|
||||
} else {
|
||||
message += 'Try running this command again prefixing it with `sudo`.';
|
||||
}
|
||||
console.error(message);
|
||||
} else if (error.message != null) {
|
||||
console.error(error.message);
|
||||
}
|
||||
}
|
||||
if (_.isNumber(error.exitCode)) {
|
||||
errorCode = error.exitCode;
|
||||
} else {
|
||||
errorCode = 1;
|
||||
}
|
||||
if (exit) {
|
||||
return process.exit(errorCode);
|
||||
}
|
||||
};
|
||||
|
||||
}).call(this);
|
121
build/install-node.js
Normal file
121
build/install-node.js
Normal file
@ -0,0 +1,121 @@
|
||||
(function() {
|
||||
var DESTINATION, NODE_VERSION, RESIN_BUNDLE, async, binary, bundle, bundles, fs, getNodeName, i, len, nodeDownload, path;
|
||||
|
||||
async = require('async');
|
||||
|
||||
binary = require('node-binary');
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
path = require('path');
|
||||
|
||||
DESTINATION = process.argv[2];
|
||||
|
||||
if (DESTINATION == null) {
|
||||
console.error('Missing destination argument');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
NODE_VERSION = require('../package.json').bundled_engine;
|
||||
|
||||
RESIN_BUNDLE = process.env.RESIN_BUNDLE;
|
||||
|
||||
if ((RESIN_BUNDLE == null) || RESIN_BUNDLE === 'current') {
|
||||
bundles = [
|
||||
{
|
||||
os: process.platform,
|
||||
arch: process.arch,
|
||||
version: NODE_VERSION
|
||||
}
|
||||
];
|
||||
} else if (RESIN_BUNDLE === 'darwin') {
|
||||
bundles = [
|
||||
{
|
||||
os: 'darwin',
|
||||
arch: 'x86',
|
||||
version: NODE_VERSION
|
||||
}, {
|
||||
os: 'darwin',
|
||||
arch: 'x64',
|
||||
version: NODE_VERSION
|
||||
}
|
||||
];
|
||||
} else if (RESIN_BUNDLE === 'linux') {
|
||||
bundles = [
|
||||
{
|
||||
os: 'linux',
|
||||
arch: 'x86',
|
||||
version: NODE_VERSION
|
||||
}, {
|
||||
os: 'linux',
|
||||
arch: 'x64',
|
||||
version: NODE_VERSION
|
||||
}
|
||||
];
|
||||
} else if (RESIN_BUNDLE === 'win32') {
|
||||
bundles = [
|
||||
{
|
||||
os: 'win32',
|
||||
arch: 'x86',
|
||||
version: NODE_VERSION
|
||||
}, {
|
||||
os: 'win32',
|
||||
arch: 'x64',
|
||||
version: NODE_VERSION
|
||||
}
|
||||
];
|
||||
} else {
|
||||
console.error("Unknown RESIN_BUNDLE value: " + RESIN_BUNDLE);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
getNodeName = function(options) {
|
||||
var result;
|
||||
result = "node-" + options.os + "-" + options.arch;
|
||||
if (options.os === 'win32') {
|
||||
result += '.exe';
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
console.info('Installing the following NodeJS bundles:');
|
||||
|
||||
for (i = 0, len = bundles.length; i < len; i++) {
|
||||
bundle = bundles[i];
|
||||
console.info("- " + (getNodeName(bundle)));
|
||||
}
|
||||
|
||||
nodeDownload = function(destination, options, callback) {
|
||||
return binary.download(options, destination, function(error, binaryPath) {
|
||||
var output;
|
||||
if (error != null) {
|
||||
return callback(error);
|
||||
}
|
||||
output = path.join(destination, getNodeName(options));
|
||||
return fs.rename(binaryPath, output, function(error) {
|
||||
if (error != null) {
|
||||
return callback(error);
|
||||
}
|
||||
return callback(null, output);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
async.eachLimit(bundles, 2, function(bundle, callback) {
|
||||
console.info("Downloading: " + (getNodeName(bundle)) + " to " + DESTINATION);
|
||||
return nodeDownload(DESTINATION, bundle, function(error, output) {
|
||||
if (error != null) {
|
||||
return callback(error);
|
||||
}
|
||||
console.info("Downloaded: " + (getNodeName(bundle)) + " to " + output);
|
||||
return callback(null, output);
|
||||
});
|
||||
}, function(error) {
|
||||
if (error != null) {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
return console.info('All NodeJS bundles downloaded');
|
||||
});
|
||||
|
||||
}).call(this);
|
68
build/package.json
Normal file
68
build/package.json
Normal file
@ -0,0 +1,68 @@
|
||||
{
|
||||
"name": "resin-cli",
|
||||
"version": "0.0.1",
|
||||
"description": "Git Push to your devices",
|
||||
"main": "./lib/actions/index.coffee",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@bitbucket.org:rulemotion/resin-cli.git"
|
||||
},
|
||||
"preferGlobal": true,
|
||||
"bundled_engine": "v0.12.0",
|
||||
"man": [
|
||||
"./man/resin.1",
|
||||
"./man/resin-completion.1",
|
||||
"./man/resin-plugins.1"
|
||||
],
|
||||
"bin": {
|
||||
"resin": "./bin/resin"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish": "gulp build",
|
||||
"test": "gult test",
|
||||
"install": "coffee lib/install-node.coffee bin/node"
|
||||
},
|
||||
"keywords": [
|
||||
"resin",
|
||||
"git"
|
||||
],
|
||||
"author": "Juan Cruz Viotti <juanchiviotti@gmail.com>",
|
||||
"license": "MIT",
|
||||
"optionalDependencies": {
|
||||
"windosu": "^0.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "~1.9.2",
|
||||
"gulp": "~3.8.9",
|
||||
"gulp-coffee": "^2.2.0",
|
||||
"gulp-coffeelint": "~0.4.0",
|
||||
"gulp-marked-man": "~0.3.1",
|
||||
"gulp-mocha": "~1.1.1",
|
||||
"gulp-shell": "^0.2.11",
|
||||
"gulp-util": "~3.0.1",
|
||||
"mocha": "~2.0.1",
|
||||
"mocha-notifier-reporter": "~0.1.0",
|
||||
"run-sequence": "~1.0.2",
|
||||
"sinon": "~1.12.1",
|
||||
"sinon-chai": "~2.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "~0.9.0",
|
||||
"capitano": "~1.5.0",
|
||||
"coffee-script": "~1.8.0",
|
||||
"conf.js": "^0.1.1",
|
||||
"diskio": "^1.0.0",
|
||||
"drivelist": "^1.2.0",
|
||||
"git-cli": "~0.8.2",
|
||||
"lodash": "~2.4.1",
|
||||
"lodash-contrib": "~241.4.14",
|
||||
"mkdirp": "~0.5.0",
|
||||
"node-binary": "^1.0.1",
|
||||
"nplugm": "^2.0.0",
|
||||
"open": "0.0.5",
|
||||
"progress-stream": "^0.5.0",
|
||||
"resin-cli-visuals": "resin-io/resin-cli-visuals",
|
||||
"resin-sdk": "resin-io/resin-sdk",
|
||||
"underscore.string": "~2.4.0"
|
||||
}
|
||||
}
|
51
build/plugins.js
Normal file
51
build/plugins.js
Normal file
@ -0,0 +1,51 @@
|
||||
(function() {
|
||||
var Nplugm, _, capitano, nplugm, registerPlugin;
|
||||
|
||||
Nplugm = require('nplugm');
|
||||
|
||||
_ = require('lodash');
|
||||
|
||||
capitano = require('capitano');
|
||||
|
||||
nplugm = null;
|
||||
|
||||
registerPlugin = function(plugin) {
|
||||
if (!_.isArray(plugin)) {
|
||||
return capitano.command(plugin);
|
||||
}
|
||||
return _.each(plugin, capitano.command);
|
||||
};
|
||||
|
||||
exports.register = function(prefix, callback) {
|
||||
nplugm = new Nplugm(prefix);
|
||||
return nplugm.list(function(error, plugins) {
|
||||
var i, len, plugin;
|
||||
if (error != null) {
|
||||
return callback(error);
|
||||
}
|
||||
for (i = 0, len = plugins.length; i < len; i++) {
|
||||
plugin = plugins[i];
|
||||
try {
|
||||
registerPlugin(nplugm.require(plugin));
|
||||
} catch (_error) {
|
||||
error = _error;
|
||||
console.error(error.message);
|
||||
}
|
||||
}
|
||||
return callback();
|
||||
});
|
||||
};
|
||||
|
||||
exports.list = function() {
|
||||
return nplugm.list.apply(nplugm, arguments);
|
||||
};
|
||||
|
||||
exports.install = function() {
|
||||
return nplugm.install.apply(nplugm, arguments);
|
||||
};
|
||||
|
||||
exports.remove = function() {
|
||||
return nplugm.remove.apply(nplugm, arguments);
|
||||
};
|
||||
|
||||
}).call(this);
|
Loading…
Reference in New Issue
Block a user