From b526067eeb314e9965c4b2dae55ab79d0f519d17 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 24 Mar 2014 17:44:06 +0100 Subject: [PATCH 01/81] Initial commit. --- packages/xo-cli/.editorconfig | 15 +++ packages/xo-cli/.gitignore | 1 + packages/xo-cli/.jshintrc | 126 +++++++++++++++++++++++ packages/xo-cli/README.md | 20 ++++ packages/xo-cli/bin/xo-cli | 7 ++ packages/xo-cli/cli.js | 187 ++++++++++++++++++++++++++++++++++ packages/xo-cli/config.js | 11 ++ packages/xo-cli/package.json | 34 +++++++ packages/xo-cli/prompt.js | 32 ++++++ packages/xo-cli/xo.js | 123 ++++++++++++++++++++++ 10 files changed, 556 insertions(+) create mode 100644 packages/xo-cli/.editorconfig create mode 100644 packages/xo-cli/.gitignore create mode 100644 packages/xo-cli/.jshintrc create mode 100644 packages/xo-cli/README.md create mode 100755 packages/xo-cli/bin/xo-cli create mode 100644 packages/xo-cli/cli.js create mode 100644 packages/xo-cli/config.js create mode 100644 packages/xo-cli/package.json create mode 100644 packages/xo-cli/prompt.js create mode 100644 packages/xo-cli/xo.js diff --git a/packages/xo-cli/.editorconfig b/packages/xo-cli/.editorconfig new file mode 100644 index 000000000..d30e0c40a --- /dev/null +++ b/packages/xo-cli/.editorconfig @@ -0,0 +1,15 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +# +# Tab indentation (size of 2 spaces) +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespaces = true diff --git a/packages/xo-cli/.gitignore b/packages/xo-cli/.gitignore new file mode 100644 index 000000000..2ccbe4656 --- /dev/null +++ b/packages/xo-cli/.gitignore @@ -0,0 +1 @@ +/node_modules/ diff --git a/packages/xo-cli/.jshintrc b/packages/xo-cli/.jshintrc new file mode 100644 index 000000000..2b873faf5 --- /dev/null +++ b/packages/xo-cli/.jshintrc @@ -0,0 +1,126 @@ +{ + // -------------------------------------------------------------------- + // JSHint Configuration, Node.js Edition + // -------------------------------------------------------------------- + // + // This is an options template for [JSHint][1], forked from + // haschek's [JSHint template][2]: + // + // * the environment has been changed to `node`; + // * recent options were added; + // * coding style has been adapted to node (e.g. 2 spaces + // indenting, global use strict). + // + // [1]: http://www.jshint.com/ + // [2]: https://gist.github.com/haschek/2595796 + // + // @author Julien Fontanet + // @license http://unlicense.org/ + + // == Enforcing Options =============================================== + // + // These options tell JSHint to be more strict towards your code. Use + // them if you want to allow only a safe subset of JavaScript, very + // useful when your codebase is shared with a big number of developers + // with different skill levels. + + "bitwise" : true, // Prohibit bitwise operators (&, |, ^, etc.). + "camelcase" : true, // Require variable names to use either camelCase or UPPER_CASE styles. + "curly" : true, // Require {} for every new block or scope. + "eqeqeq" : true, // Require triple equals i.e. `===`. + "forin" : true, // Tolerate `for in` loops without `hasOwnPrototype`. + "freeze" : true, // Prohibit modification of native objects' prototypes. + "immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` + "indent" : 2, // Specify indentation spacing + "latedef" : true, // Prohibit variable use before definition. + "newcap" : true, // Require capitalization of all constructor functions e.g. `new F()`. + "noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`. + "noempty" : true, // Prohibit use of empty blocks. + "nonew" : true, // Prohibit use of constructors for side-effects. + "plusplus" : false, // Prohibit the use of `++` & `--`. + "quotmark" : "'", // Require single quotes. + "undef" : true, // Require all non-global variables be declared before they are used. + "unused" : true, // Prohibit unused variables. + "strict" : true, // Require `use strict` pragma in every function. + "trailing" : true, // Prohibit trailing whitespaces. + "maxparams" : 4, // Prohibit more than 4 parameters per function definition. + "maxdepth" : 3, // Prohibit nesting more than 3 control blocks. + "maxstatements" : 20, // Prohibit more than 20 statements per function. + "maxcomplexity" : 7, // Prohibit having to much branches in your code. + "maxlen" : 80, // Prohibit line with more than 80 characters. + + // == Relaxing Options ================================================ + // + // These options allow you to suppress certain types of warnings. Use + // them only if you are absolutely positive that you know what you are + // doing. + + "asi" : false, // Tolerate Automatic Semicolon Insertion (no semicolons). + "boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments. + "debug" : false, // Allow debugger statements e.g. browser breakpoints. + "eqnull" : false, // Tolerate use of `== null`. + "es5" : false, // Allow EcmaScript 5 syntax. + "esnext" : false, // Allow ES.next specific features such as `const` and `let`. + "evil" : false, // Tolerate use of `eval`. + "expr" : true, // Tolerate `ExpressionStatement` as Programs. (Allowed for Mocha.) + "funcscope" : false, // Tolerate declarations of variables inside of control structures while accessing them later from the outside. + "gcl" : false, // Makes JSHint compatible with Google Closure Compiler. + "globalstrict" : true, // Allow global "use strict" (also enables 'strict'). + "iterator" : false, // Allow usage of __iterator__ property. + "lastsemic" : false, // Tolerat missing semicolons when the it is omitted for the last statement in a one-line block. + "laxbreak" : false, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons. + "laxcomma" : false, // Suppress warnings about comma-first coding style. + "loopfunc" : false, // Allow functions to be defined within loops. + "maxerr" : 50, // Maximum errors before stopping. + "moz" : false, // Tolerate Mozilla JavaScript extensions. + "notypeof" : false, // Tolerate invalid typeof values. + "multistr" : false, // Tolerate multi-line strings. + "proto" : false, // Tolerate __proto__ property. This property is deprecated. + "scripturl" : false, // Tolerate script-targeted URLs. + "smarttabs" : false, // Tolerate mixed tabs and spaces when the latter are used for alignmnent only. + "shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`. + "sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`. + "supernew" : false, // Tolerate `new function () { ... };` and `new Object;`. + "validthis" : false, // Tolerate strict violations when the code is running in strict mode and you use this in a non-constructor function. + + // == Environments ==================================================== + // + // These options pre-define global variables that are exposed by + // popular JavaScript libraries and runtime environments—such as + // browser or node.js. + + "browser" : true, // Standard browser globals e.g. `window`, `document`. + "couch" : false, // Enable globals exposed by CouchDB. + "devel" : false, // Allow development statements e.g. `console.log();`. + "dojo" : false, // Enable globals exposed by Dojo Toolkit. + "jquery" : false, // Enable globals exposed by jQuery JavaScript library. + "mootools" : false, // Enable globals exposed by MooTools JavaScript framework. + "node" : true, // Enable globals available when code is running inside of the NodeJS runtime environment. + "nonstandard" : false, // Define non-standard but widely adopted globals such as escape and unescape. + "phantom" : false, // Enable globals exposed by PhantomJS. + "prototypejs" : false, // Enable globals exposed by Prototype JavaScript framework. + "rhino" : false, // Enable globals available when your code is running inside of the Rhino runtime environment. + "worker" : false, // Enable globals exposed when running inside a Web Worker. + "wsh" : false, // Enable globals available when your code is running as a script for the Windows Script Host. + "yui" : false, // Enable globals exposed by YUI. + + // == JSLint Legacy =================================================== + // + // These options are legacy from JSLint. Aside from bug fixes they will + // not be improved in any way and might be removed at any point. + + "nomen" : false, // Prohibit use of initial or trailing underbars in names. + "onevar" : false, // Allow only one `var` statement per function. + "passfail" : false, // Stop on first error. + "white" : false, // Check against strict whitespace and indentation rules. + + "globals": { + // Mocha. + "after" : false, + "afterEach" : false, + "before" : false, + "beforeEach" : false, + "describe" : false, + "it" : false + } +} diff --git a/packages/xo-cli/README.md b/packages/xo-cli/README.md new file mode 100644 index 000000000..aa2ed7f39 --- /dev/null +++ b/packages/xo-cli/README.md @@ -0,0 +1,20 @@ +# XO CLI +[![Build Status](https://img.shields.io/travis/vatesfr/xo-cli/master.svg)](http://travis-ci.org/vatesfr/xo-cli) +[![Dependency Status](https://david-dm.org/vatesfr/xo-cli/status.svg?theme=shields.io)](https://david-dm.org/vatesfr/xo-cli) +[![devDependency Status](https://david-dm.org/vatesfr/xo-cli/dev-status.svg?theme=shields.io)](https://david-dm.org/vatesfr/xo-cli#info=devDependencies) + +> Basic CLI for Xen-Orchestra + +## Installation + +#### [npm](https://npmjs.org/package/xo-cli) + +``` +npm install -f xo-cli +``` + +## Usage + +``` +xo-cli add-server +``` diff --git a/packages/xo-cli/bin/xo-cli b/packages/xo-cli/bin/xo-cli new file mode 100755 index 000000000..77127e56d --- /dev/null +++ b/packages/xo-cli/bin/xo-cli @@ -0,0 +1,7 @@ +#!/usr/bin/env node + +'use strict'; + +//==================================================================== + +require('../')(process.argv.slice(2)); diff --git a/packages/xo-cli/cli.js b/packages/xo-cli/cli.js new file mode 100644 index 000000000..b93525f61 --- /dev/null +++ b/packages/xo-cli/cli.js @@ -0,0 +1,187 @@ +'use strict'; + +//==================================================================== + +var _ = require('lodash'); +var nomnom = require('nomnom'); +var Promise = require('bluebird'); + +//-------------------------------------------------------------------- + +var prompt = require('./prompt'); +var Xo = require('./xo'); + +//==================================================================== + +// Handles a promise in a CLI environment. +var handlePromise = function (promise) { + promise.then(function (value) { + if (_.isString(value)) + { + console.log(value); + } + + process.exit(0); + }).catch(function (error) { + if (_.isString(error)) + { + console.error(error); + } + else if (_.isNumber(error)) + { + process.exit(error); + } + + process.exit(1); + }); +}; + +//-------------------------------------------------------------------- + +var connect = function (opts) { + var config, xo; + + return Promise.try(function () { + opts || (opts = {}); + + // TODO: reads the configuration file. + config = { + server: 'ws://localhost:9000/api/', + }; + + if (!config.server) + { + throw 'no server to connect to!'; + } + + xo = new Xo(config.server); + + if (config.token && !opts.noAutoSignIn) + { + return xo.send('session.signInWithToken', { + token: config.token, + }); + } + }); +}; + +//-------------------------------------------------------------------- + +var addServer = function (host, username, password) { + return connect().then(function (connection) { + return connection.send('server.add', { + host: host, + username: username, + password: password, + }); + }).return('ok'); +}; + +var register = function (url, email, password) { + var xo; + return Promise.try(function () { + xo = new Xo(url); + + return xo.send('session.signInWithPassword', { + email: email, + password: password, + }); + }).then(function (user) { + console.log('Successfully logged with', user.email); + + return xo.send('token.create'); + }).then(function (token) { + return getConfig().set({ + server: url, + token: token, + }); + }); +}; + +//==================================================================== + +module.exports = function (argv) { + nomnom.command('register') + .help('signs in XO using email/password') + .options({ + url: { + help: 'URL of the API endpoint', + }, + email: { + help: 'email to use to connect', + }, + password: { + help: 'password to use to connect', + }, + }) + .callback(function (opts) { + Promise.try(function () { + if (opts.url) + { + return prompt.input('URL').then(function (url) { + opts.url = url; + }); + } + }).then(function () { + if (!opts.email) + { + return prompt.input('Email').then(function (email) { + opts.email = email; + }); + } + }).then(function () { + if (!opts.password) + { + return prompt.password('Password').then(function (password) { + opts.password = password; + }); + } + }).then(function () { + return register(opts.url, opts.email, opts.password); + }); + }) + ; + + nomnom.command('add-server') + .help('adds a new server') + .options({ + host: { + help: 'hostname or ip of the server', + }, + username: { + help: 'username to use to connect', + }, + password: { + help: 'password to use to connect', + }, + }) + .callback(function (opts) { + Promise.try(function () { + if (opts.host) + { + return prompt.input('Hostname or ip').then(function (host) { + opts.host = host; + }); + } + }).then(function () { + if (!opts.username) + { + return prompt.input('Username').then(function (username) { + opts.username = username; + }); + } + }).then(function () { + if (!opts.password) + { + return prompt.password('Password').then(function (password) { + opts.password = password; + }); + } + }).then(function () { + return addServer(opts.host, opts.username, opts.password); + }); + }) + ; + + nomnom.parse(argv); +}; diff --git a/packages/xo-cli/config.js b/packages/xo-cli/config.js new file mode 100644 index 000000000..f3f4a5b9a --- /dev/null +++ b/packages/xo-cli/config.js @@ -0,0 +1,11 @@ +'use strict'; + +//==================================================================== + +var xdg = require('xdg').basedir; + +//==================================================================== + +var Config = function () { + this.data = +}; diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json new file mode 100644 index 000000000..d03bd4aae --- /dev/null +++ b/packages/xo-cli/package.json @@ -0,0 +1,34 @@ +{ + "name": "xo-cli", + "version": "0.1.0", + "description": "Basic CLI for Xen-Orchestra", + "author": "Julien Fontanet ", + "homepage": "https://github.com/vatesfr/xo-cli", + "bugs": "https://github.com/vatesfr/xo-cli", + "repository": { + "type": "git", + "url": "https://github.com/vatesfr/xo-cli" + }, + "dependencies": { + "bluebird": "^1.1.0", + "chalk": "^0.4.0", + "inquirer": "^0.4.1", + "lodash": "^2.4.1", + "nomnom": "^1.6.2", + "ws": "^0.4.31", + "xdg": "^0.1.1" + }, + "devDependencies": { + "chai": "^1.9.0", + "mocha": "^1.18.0", + "mocha-promise": "0.0.1" + }, + "scripts": { + "test": "mocha cli.spec.js" + }, + "main": "cli.js", + "bin": { + "xo-cli": "bin/xo-cli" + }, + "license": "AGPL3" +} diff --git a/packages/xo-cli/prompt.js b/packages/xo-cli/prompt.js new file mode 100644 index 000000000..b3499cd6c --- /dev/null +++ b/packages/xo-cli/prompt.js @@ -0,0 +1,32 @@ +'use strict'; + +//==================================================================== + +var inquirer = require('inquirer'); +var Promise = require('bluebird'); + +//==================================================================== + +var prompts = module.exports = function (prompts) { + var deferred = Promise.defer(); + + inquirer.prompt(prompts, deferred.resolve.bind(deferred)); + + return deferred.promise; +}; + +exports.input = function (message) { + return prompts({ + type: 'input', + name: 'question', + message: message, + }).get('question'); +}; + +exports.password = function (message) { + return prompts({ + type: 'password', + name: 'question', + message: message, + }).get('question'); +}; diff --git a/packages/xo-cli/xo.js b/packages/xo-cli/xo.js new file mode 100644 index 000000000..65a561523 --- /dev/null +++ b/packages/xo-cli/xo.js @@ -0,0 +1,123 @@ +'use strict'; + +//==================================================================== + +var _ = require('lodash'); + +var Promise = require('bluebird'); + +// Supports browsers. +// FIXME: wraps in an anonymous function. +var WebSocket = 'WebSocket' in window ? window.WebSocket : require('ws'); + +//==================================================================== + +var Xo = function (url) { + this._url = url; + + // Identifier of the next request. + this._nextId = 0; + + // Promises linked to the requests. + this._deferreds = {}; + + // Current WebSocket. + this._socket = null; + + // Current status which may be: + // - disconnected + // - connecting + // - connected + this.status = 'disconnected'; +}; + +_.extend(Xo.prototype, { + connect: function () { + if (this.status === 'connected') + { + return Promise.cast(); + } + + var deferred = Promise.defer(); + + this.status = 'connecting'; + + var socket = this._socket = new WebSocket(this._url); + + // When the socket opens, send any queued requests. + socket.on('open', function () { + this.status = 'connected'; + + // Reopens accesses. + delete this.send; + }.bind(this)); + + socket.on('message', function (event) { + // TODO: Wraps in a promise to prevent releasing the Zalgo. + var response = JSON.parse(event.data); + + var id = response.id; + + var deferred = this._deferreds[id]; + if (!deferred) + { + // Response already handled. + return; + } + delete this._deferreds[id]; + + if ('error' in response) + { + return deferred.reject(response.error); + } + + if ('result' in response) + { + return deferred.resolve(response.result); + } + + deferred.reject({ + message: 'invalid response received', + object: response, + }); + }); + + socket.on('close', function () { + // Closes accesses. + this.send = function () { + throw new Error('not connected'); + }; + + // Fails all waiting requests. + _.each(this._deferreds, function (deferred) { + deferred.reject('not connected'); + }); + this._deferreds = {}; + }.bind(this)); + + return deferred.promise; + }, + + send: function (method, params) { + return this.connect().then(function () { + var socket = this._socket; + + var id = this._nextId++; + + socket.send(JSON.stringify({ + jsonrpc: '2.0', + id: id, + method: method, + params: params || [], + })); + + var deferred = this._deferreds[id] = Promise.defer(); + + return deferred.promise; + }); + }, +}); + +//==================================================================== + +module.exports = Xo; From d9e615e69632e6876d286bbf938fdc3c9ad38da7 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Tue, 25 Mar 2014 15:33:16 +0100 Subject: [PATCH 02/81] First working version. --- packages/xo-cli/README.md | 15 +- packages/xo-cli/cli.js | 322 ++++++++++++++++++----------------- packages/xo-cli/config.js | 43 ++++- packages/xo-cli/package.json | 3 + packages/xo-cli/prompt.js | 4 +- packages/xo-cli/xo.js | 35 +++- 6 files changed, 254 insertions(+), 168 deletions(-) diff --git a/packages/xo-cli/README.md b/packages/xo-cli/README.md index aa2ed7f39..c441d30af 100644 --- a/packages/xo-cli/README.md +++ b/packages/xo-cli/README.md @@ -10,11 +10,22 @@ #### [npm](https://npmjs.org/package/xo-cli) ``` -npm install -f xo-cli +npm install -g xo-cli ``` ## Usage +#### Register your XO instance + ``` -xo-cli add-server +xo-cli register --host xo.my-company.net --email admin@admin.net --password admin +``` + +Note: only a token will be saved in the configuration file. + +#### Adds a new Xen server + + +``` +xo-cli add-server --host xen1.my-company.net --user root --password secure%password ``` diff --git a/packages/xo-cli/cli.js b/packages/xo-cli/cli.js index b93525f61..9b7657607 100644 --- a/packages/xo-cli/cli.js +++ b/packages/xo-cli/cli.js @@ -8,14 +8,171 @@ var Promise = require('bluebird'); //-------------------------------------------------------------------- +var config = require('./config'); var prompt = require('./prompt'); var Xo = require('./xo'); //==================================================================== -// Handles a promise in a CLI environment. -var handlePromise = function (promise) { - promise.then(function (value) { +var connect = function () { + return config.load().bind({}).then(function (config) { + if (!config.server) + { + throw 'no server to connect to!'; + } + + if (!config.token) + { + throw 'no token available'; + } + + this.xo = new Xo(config.server); + + return this.xo.send('session.signInWithToken', { + token: config.token, + }); + }).then(function () { + return this.xo; + }).bind(); +}; + +//==================================================================== + +module.exports = function (argv) { + var command; + var commandName; + var commandOpts; + + var registerCommand = function (name, def, fn) { + var cmdParser = nomnom.command(name); + + if (def.description) + { + cmdParser.help(def.description); + } + + if (def.args) + { + var interactive = process.stdout.isTTY; + + _.each(def.args, function (def, name) { + cmdParser.option(name, { + abbr: def.abbr, + flag: (def.type === 'boolean'), + help: def.description, + + // Do not mark options as required if the program is run in + // interactive mode, they will be asked. + required: !interactive && def.required, + }); + }); + + // TODO: alters `fn` to prompt for each missing argument. + fn = (function (fn, args) { + return function (opts) { + var prompts = []; + + _.each(args, function (def, name) { + if (!(name in opts)) + { + prompts.push({ + name: name, + message: def.prompt || def.description, + type: def.promptType || 'input', + }); + } + }); + + if (prompts.length) + { + return prompt(prompts).then(function (answers) { + return fn(_.extend(opts, answers)); + }); + } + + return fn(opts); + }; + })(fn, def.args); + } + + cmdParser.callback(function (opts) { + command = fn; + commandName = name; + commandOpts = opts; + }); + }; + + registerCommand('register', { + description: 'registers the XO instance', + args: { + host: { + description: 'host/ip optionally followed by `:port` if not 80', + required: true, + }, + email: { + description: 'email to use to connect', + required: true, + }, + password: { + description: 'password to use to connect', + promptType: 'password', + required: true, + }, + } + }, function (opts) { + return Promise.bind({opts: opts || {}}).then(function () { + this.xo = new Xo(opts.host); + + return this.xo.send('session.signInWithPassword', { + email: this.opts.email, + password: this.opts.password, + }); + }).then(function (user) { + console.log('Successfully logged with', user.email); + + return this.xo.send('token.create'); + }).then(function (token) { + console.log('Token created:', token); + + return config.set({ + server: this.opts.host, + token: token, + }); + }).bind(); + }); + + registerCommand('add-server', { + description: 'adds a new Xen server', + args: { + host: { + description: 'host of the server', + required: true, + }, + username: { + description: 'username to use to connect', + required: true, + }, + password: { + description: 'password to use to connect', + promptType: 'password', + required: true, + }, + }, + }, function (opts) { + return connect().then(function (connection) { + return connection.send('server.add', { + host: opts.host, + username: opts.username, + password: opts.password, + }); + }).return('ok'); + }); + + // TODO: handle global `--config FILE` option. + nomnom.parse(argv); + + // Executes the selected command. + Promise.try(command, [commandOpts]).then(function (value) { if (_.isString(value)) { console.log(value); @@ -23,165 +180,20 @@ var handlePromise = function (promise) { process.exit(0); }).catch(function (error) { - if (_.isString(error)) + if (error === undefined) { - console.error(error); + // Nothing to do. + undefined; } else if (_.isNumber(error)) { process.exit(error); } + else + { + console.error(error.stack || error); + } process.exit(1); }); }; - -//-------------------------------------------------------------------- - -var connect = function (opts) { - var config, xo; - - return Promise.try(function () { - opts || (opts = {}); - - // TODO: reads the configuration file. - config = { - server: 'ws://localhost:9000/api/', - }; - - if (!config.server) - { - throw 'no server to connect to!'; - } - - xo = new Xo(config.server); - - if (config.token && !opts.noAutoSignIn) - { - return xo.send('session.signInWithToken', { - token: config.token, - }); - } - }); -}; - -//-------------------------------------------------------------------- - -var addServer = function (host, username, password) { - return connect().then(function (connection) { - return connection.send('server.add', { - host: host, - username: username, - password: password, - }); - }).return('ok'); -}; - -var register = function (url, email, password) { - var xo; - return Promise.try(function () { - xo = new Xo(url); - - return xo.send('session.signInWithPassword', { - email: email, - password: password, - }); - }).then(function (user) { - console.log('Successfully logged with', user.email); - - return xo.send('token.create'); - }).then(function (token) { - return getConfig().set({ - server: url, - token: token, - }); - }); -}; - -//==================================================================== - -module.exports = function (argv) { - nomnom.command('register') - .help('signs in XO using email/password') - .options({ - url: { - help: 'URL of the API endpoint', - }, - email: { - help: 'email to use to connect', - }, - password: { - help: 'password to use to connect', - }, - }) - .callback(function (opts) { - Promise.try(function () { - if (opts.url) - { - return prompt.input('URL').then(function (url) { - opts.url = url; - }); - } - }).then(function () { - if (!opts.email) - { - return prompt.input('Email').then(function (email) { - opts.email = email; - }); - } - }).then(function () { - if (!opts.password) - { - return prompt.password('Password').then(function (password) { - opts.password = password; - }); - } - }).then(function () { - return register(opts.url, opts.email, opts.password); - }); - }) - ; - - nomnom.command('add-server') - .help('adds a new server') - .options({ - host: { - help: 'hostname or ip of the server', - }, - username: { - help: 'username to use to connect', - }, - password: { - help: 'password to use to connect', - }, - }) - .callback(function (opts) { - Promise.try(function () { - if (opts.host) - { - return prompt.input('Hostname or ip').then(function (host) { - opts.host = host; - }); - } - }).then(function () { - if (!opts.username) - { - return prompt.input('Username').then(function (username) { - opts.username = username; - }); - } - }).then(function () { - if (!opts.password) - { - return prompt.password('Password').then(function (password) { - opts.password = password; - }); - } - }).then(function () { - return addServer(opts.host, opts.username, opts.password); - }); - }) - ; - - nomnom.parse(argv); -}; diff --git a/packages/xo-cli/config.js b/packages/xo-cli/config.js index f3f4a5b9a..2bba89430 100644 --- a/packages/xo-cli/config.js +++ b/packages/xo-cli/config.js @@ -2,10 +2,47 @@ //==================================================================== -var xdg = require('xdg').basedir; +var fs = require('fs'); + +//-------------------------------------------------------------------- + +var _ = require('lodash'); +var l33t = require('l33teral'); +var mkdirp = require('mkdirp'); +var Promise = require('bluebird'); +var xdg = require('xdg'); //==================================================================== -var Config = function () { - this.data = +var configPath = xdg.basedir.configPath('xo-cli'); +var configFile = configPath +'/config.json'; + +var mkdirp = Promise.promisify(mkdirp); +var readFile = Promise.promisify(fs.readFile); +var writeFile = Promise.promisify(fs.writeFile); + +//==================================================================== + +var load = exports.load = function () { + return readFile(configFile).then(JSON.parse).catch(function () { + return {}; + }); +}; + +exports.get = function (path) { + return load().then(function (config) { + return l33t(config).tap(path); + }); +}; + +var save = exports.save = function (config) { + return mkdirp(configPath).then(function () { + return writeFile(configFile, JSON.stringify(config)); + }); +}; + +exports.set = function (data) { + return load().then(function (config) { + return save(_.extend(config, data)); + }); }; diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index d03bd4aae..0d1aad7aa 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -13,7 +13,9 @@ "bluebird": "^1.1.0", "chalk": "^0.4.0", "inquirer": "^0.4.1", + "l33teral": "^2.0.3", "lodash": "^2.4.1", + "mkdirp": "^0.3.5", "nomnom": "^1.6.2", "ws": "^0.4.31", "xdg": "^0.1.1" @@ -30,5 +32,6 @@ "bin": { "xo-cli": "bin/xo-cli" }, + "preferGlobal": true, "license": "AGPL3" } diff --git a/packages/xo-cli/prompt.js b/packages/xo-cli/prompt.js index b3499cd6c..f26e02b16 100644 --- a/packages/xo-cli/prompt.js +++ b/packages/xo-cli/prompt.js @@ -15,7 +15,7 @@ var prompts = module.exports = function (prompts) { return deferred.promise; }; -exports.input = function (message) { +prompts.input = function (message) { return prompts({ type: 'input', name: 'question', @@ -23,7 +23,7 @@ exports.input = function (message) { }).get('question'); }; -exports.password = function (message) { +prompts.password = function (message) { return prompts({ type: 'password', name: 'question', diff --git a/packages/xo-cli/xo.js b/packages/xo-cli/xo.js index 65a561523..290bdd3ab 100644 --- a/packages/xo-cli/xo.js +++ b/packages/xo-cli/xo.js @@ -8,7 +8,9 @@ var Promise = require('bluebird'); // Supports browsers. // FIXME: wraps in an anonymous function. -var WebSocket = 'WebSocket' in window ? window.WebSocket : require('ws'); +// jshint ignore: start +var WebSocket = (this && 'WebSocket' in this) ? this.WebSocket : require('ws'); +// jshint ignore: end //==================================================================== @@ -32,6 +34,13 @@ var Xo = function (url) { }; _.extend(Xo.prototype, { + close: function () { + if (this._socket) + { + this._socket.close(); + } + }, + connect: function () { if (this.status === 'connected') { @@ -48,13 +57,22 @@ _.extend(Xo.prototype, { socket.on('open', function () { this.status = 'connected'; - // Reopens accesses. + // (Re)Opens accesses. delete this.send; + + // Resolves the promise. + deferred.resolve(); }.bind(this)); - socket.on('message', function (event) { + socket.on('message', function (data) { + // `ws` API is lightly different from standard API. + if (data.data) + { + data = data.data; + } + // TODO: Wraps in a promise to prevent releasing the Zalgo. - var response = JSON.parse(event.data); + var response = JSON.parse(data); var id = response.id; @@ -80,7 +98,7 @@ _.extend(Xo.prototype, { message: 'invalid response received', object: response, }); - }); + }.bind(this)); socket.on('close', function () { // Closes accesses. @@ -95,6 +113,11 @@ _.extend(Xo.prototype, { this._deferreds = {}; }.bind(this)); + socket.on('error', function (error) { + // Fails the connect promise if possible. + deferred.reject(error); + }); + return deferred.promise; }, @@ -114,7 +137,7 @@ _.extend(Xo.prototype, { var deferred = this._deferreds[id] = Promise.defer(); return deferred.promise; - }); + }.bind(this)); }, }); From 313f7e817341a508b595e5f8d55e0365e9277fce Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Tue, 25 Mar 2014 17:17:51 +0100 Subject: [PATCH 03/81] Minor fixes and new command: `whoami`. --- packages/xo-cli/cli.js | 71 ++++++++++++++++++++++-------------- packages/xo-cli/package.json | 6 ++- 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/packages/xo-cli/cli.js b/packages/xo-cli/cli.js index 9b7657607..502e1d945 100644 --- a/packages/xo-cli/cli.js +++ b/packages/xo-cli/cli.js @@ -53,7 +53,7 @@ module.exports = function (argv) { if (def.args) { - var interactive = process.stdout.isTTY; + var interactive = process.stdin.isTTY; _.each(def.args, function (def, name) { cmdParser.option(name, { @@ -67,7 +67,6 @@ module.exports = function (argv) { }); }); - // TODO: alters `fn` to prompt for each missing argument. fn = (function (fn, args) { return function (opts) { var prompts = []; @@ -102,6 +101,33 @@ module.exports = function (argv) { }); }; + registerCommand('add-server', { + description: 'adds a new Xen server', + args: { + host: { + description: 'host of the server', + required: true, + }, + username: { + description: 'username to use to connect', + required: true, + }, + password: { + description: 'password to use to connect', + promptType: 'password', + required: true, + }, + }, + }, function (opts) { + return connect().then(function (connection) { + return connection.send('server.add', { + host: opts.host, + username: opts.username, + password: opts.password, + }); + }).return('ok'); + }); + registerCommand('register', { description: 'registers the XO instance', args: { @@ -141,31 +167,22 @@ module.exports = function (argv) { }).bind(); }); - registerCommand('add-server', { - description: 'adds a new Xen server', - args: { - host: { - description: 'host of the server', - required: true, - }, - username: { - description: 'username to use to connect', - required: true, - }, - password: { - description: 'password to use to connect', - promptType: 'password', - required: true, - }, - }, - }, function (opts) { - return connect().then(function (connection) { - return connection.send('server.add', { - host: opts.host, - username: opts.username, - password: opts.password, - }); - }).return('ok'); + registerCommand('whoami', { + description: 'displays information about the current user', + }, function () { + return connect().then(function (xo) { + return xo.send('session.getUser'); + }).then(function (user) { + if (user) + { + console.log('You are signed in as', user.email); + console.log('Your global permission is', user.permission); + } + else + { + console.log('Your are not signed in.'); + } + }); }); // TODO: handle global `--config FILE` option. diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 0d1aad7aa..5bfc92e04 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,10 +1,12 @@ { "name": "xo-cli", - "version": "0.1.0", + "version": "0.1.1", "description": "Basic CLI for Xen-Orchestra", "author": "Julien Fontanet ", "homepage": "https://github.com/vatesfr/xo-cli", - "bugs": "https://github.com/vatesfr/xo-cli", + "bugs": { + "url": "https://github.com/vatesfr/xo-cli" + }, "repository": { "type": "git", "url": "https://github.com/vatesfr/xo-cli" From 8b65a752358d92da6156d9249862dd71e7d7b04d Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Fri, 28 Mar 2014 15:19:53 +0100 Subject: [PATCH 04/81] Fixes register in README. --- packages/xo-cli/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/README.md b/packages/xo-cli/README.md index c441d30af..ac3ecdf9a 100644 --- a/packages/xo-cli/README.md +++ b/packages/xo-cli/README.md @@ -18,7 +18,7 @@ npm install -g xo-cli #### Register your XO instance ``` -xo-cli register --host xo.my-company.net --email admin@admin.net --password admin +xo-cli register --host http://xo.my-company.net/api/ --email admin@admin.net --password admin ``` Note: only a token will be saved in the configuration file. From 29398b98697192296c94a16f3658af43c1f8fe1c Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Thu, 3 Apr 2014 10:19:31 +0200 Subject: [PATCH 05/81] Various updates. --- packages/xo-cli/package.json | 26 +++++++++++++++---------- packages/xo-cli/{ => src}/cli.js | 30 +++++++++++++++++++++++++++-- packages/xo-cli/{ => src}/config.js | 0 packages/xo-cli/{ => src}/prompt.js | 0 packages/xo-cli/{ => src}/xo.js | 0 5 files changed, 44 insertions(+), 12 deletions(-) rename packages/xo-cli/{ => src}/cli.js (87%) rename packages/xo-cli/{ => src}/config.js (100%) rename packages/xo-cli/{ => src}/prompt.js (100%) rename packages/xo-cli/{ => src}/xo.js (100%) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 5bfc92e04..7c2f8a9db 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,11 +1,22 @@ { "name": "xo-cli", "version": "0.1.1", + "license": "AGPL3", "description": "Basic CLI for Xen-Orchestra", - "author": "Julien Fontanet ", + "keywords": [ + "xo", + "xen-orchestra", + "xen", + "orchestra" + ], "homepage": "https://github.com/vatesfr/xo-cli", - "bugs": { - "url": "https://github.com/vatesfr/xo-cli" + "bugs": "https://github.com/vatesfr/xo-cli/issues", + "author": "Julien Fontanet ", + "preferGlobal": true, + "main": "./src/cli.js", + "directories": { + "bin": "./bin", + "man": "./man" }, "repository": { "type": "git", @@ -24,16 +35,11 @@ }, "devDependencies": { "chai": "^1.9.0", + "human-format": "^0.1.0", "mocha": "^1.18.0", "mocha-promise": "0.0.1" }, "scripts": { "test": "mocha cli.spec.js" - }, - "main": "cli.js", - "bin": { - "xo-cli": "bin/xo-cli" - }, - "preferGlobal": true, - "license": "AGPL3" + } } diff --git a/packages/xo-cli/cli.js b/packages/xo-cli/src/cli.js similarity index 87% rename from packages/xo-cli/cli.js rename to packages/xo-cli/src/cli.js index 502e1d945..192c707e4 100644 --- a/packages/xo-cli/cli.js +++ b/packages/xo-cli/src/cli.js @@ -76,7 +76,7 @@ module.exports = function (argv) { { prompts.push({ name: name, - message: def.prompt || def.description, + message: def.prompt || def.description || name, type: def.promptType || 'input', }); } @@ -167,6 +167,23 @@ module.exports = function (argv) { }).bind(); }); + registerCommand('list-commands', {}, function () { + return connect().then(function (xo) { + return xo.send('system.listMethods').then(JSON.stringify); + }); + }); + registerCommand('show-command', { + args: { + name: { + required: true, + }, + }, + }, function (opts) { + return connect().then(function (xo) { + return xo.send('system.methodSignature', {name: opts.name}).then(console.log); + }); + }); + registerCommand('whoami', { description: 'displays information about the current user', }, function () { @@ -186,7 +203,16 @@ module.exports = function (argv) { }); // TODO: handle global `--config FILE` option. - nomnom.parse(argv); + nomnom + .option('version', { + flag: true, + help: 'prints the current version of xo-cli', + callback: function () { + return 'xo-cli version '+ require('../package').version; + }, + }) + .parse(argv) + ; // Executes the selected command. Promise.try(command, [commandOpts]).then(function (value) { diff --git a/packages/xo-cli/config.js b/packages/xo-cli/src/config.js similarity index 100% rename from packages/xo-cli/config.js rename to packages/xo-cli/src/config.js diff --git a/packages/xo-cli/prompt.js b/packages/xo-cli/src/prompt.js similarity index 100% rename from packages/xo-cli/prompt.js rename to packages/xo-cli/src/prompt.js diff --git a/packages/xo-cli/xo.js b/packages/xo-cli/src/xo.js similarity index 100% rename from packages/xo-cli/xo.js rename to packages/xo-cli/src/xo.js From 301cc22985b8904d9a581cbe068ed72388e5ea92 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 14 Apr 2014 16:38:29 +0200 Subject: [PATCH 06/81] Various updates. --- packages/xo-cli/.editorconfig | 3 - packages/xo-cli/.jshintrc | 222 ++++++++++++++++------------------ packages/xo-cli/package.json | 15 ++- 3 files changed, 114 insertions(+), 126 deletions(-) diff --git a/packages/xo-cli/.editorconfig b/packages/xo-cli/.editorconfig index d30e0c40a..e35119a31 100644 --- a/packages/xo-cli/.editorconfig +++ b/packages/xo-cli/.editorconfig @@ -3,9 +3,6 @@ # top-most EditorConfig file root = true -# Unix-style newlines with a newline ending every file -# -# Tab indentation (size of 2 spaces) [*] charset = utf-8 end_of_line = lf diff --git a/packages/xo-cli/.jshintrc b/packages/xo-cli/.jshintrc index 2b873faf5..dbd61b9e2 100644 --- a/packages/xo-cli/.jshintrc +++ b/packages/xo-cli/.jshintrc @@ -1,126 +1,118 @@ { - // -------------------------------------------------------------------- - // JSHint Configuration, Node.js Edition - // -------------------------------------------------------------------- - // - // This is an options template for [JSHint][1], forked from - // haschek's [JSHint template][2]: - // - // * the environment has been changed to `node`; - // * recent options were added; - // * coding style has been adapted to node (e.g. 2 spaces - // indenting, global use strict). - // - // [1]: http://www.jshint.com/ - // [2]: https://gist.github.com/haschek/2595796 - // - // @author Julien Fontanet - // @license http://unlicense.org/ + // -------------------------------------------------------------------- + // JSHint Configuration, Node.js Edition + // -------------------------------------------------------------------- + // + // This is an options template for [JSHint][1], forked from + // haschek's [JSHint template][2]: + // + // * the environment has been changed to `node`; + // * recent options were added; + // * coding style has been adapted to node (e.g. 2 spaces + // indenting, global use strict). + // + // [1]: http://www.jshint.com/ + // [2]: https://gist.github.com/haschek/2595796 + // + // @author Julien Fontanet + // @license http://unlicense.org/ - // == Enforcing Options =============================================== - // - // These options tell JSHint to be more strict towards your code. Use - // them if you want to allow only a safe subset of JavaScript, very - // useful when your codebase is shared with a big number of developers - // with different skill levels. + // == Enforcing Options =============================================== + // + // These options tell JSHint to be more strict towards your code. Use + // them if you want to allow only a safe subset of JavaScript, very + // useful when your codebase is shared with a big number of developers + // with different skill levels. - "bitwise" : true, // Prohibit bitwise operators (&, |, ^, etc.). - "camelcase" : true, // Require variable names to use either camelCase or UPPER_CASE styles. - "curly" : true, // Require {} for every new block or scope. - "eqeqeq" : true, // Require triple equals i.e. `===`. - "forin" : true, // Tolerate `for in` loops without `hasOwnPrototype`. - "freeze" : true, // Prohibit modification of native objects' prototypes. - "immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` - "indent" : 2, // Specify indentation spacing - "latedef" : true, // Prohibit variable use before definition. - "newcap" : true, // Require capitalization of all constructor functions e.g. `new F()`. - "noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`. - "noempty" : true, // Prohibit use of empty blocks. - "nonew" : true, // Prohibit use of constructors for side-effects. - "plusplus" : false, // Prohibit the use of `++` & `--`. - "quotmark" : "'", // Require single quotes. - "undef" : true, // Require all non-global variables be declared before they are used. - "unused" : true, // Prohibit unused variables. - "strict" : true, // Require `use strict` pragma in every function. - "trailing" : true, // Prohibit trailing whitespaces. - "maxparams" : 4, // Prohibit more than 4 parameters per function definition. - "maxdepth" : 3, // Prohibit nesting more than 3 control blocks. - "maxstatements" : 20, // Prohibit more than 20 statements per function. - "maxcomplexity" : 7, // Prohibit having to much branches in your code. - "maxlen" : 80, // Prohibit line with more than 80 characters. + "bitwise" : true, // Prohibit bitwise operators (&, |, ^, etc.). + "camelcase" : true, // Require variable names to use either camelCase or UPPER_CASE styles. + "curly" : true, // Require {} for every new block or scope. + "eqeqeq" : true, // Require triple equals i.e. `===`. + "forin" : true, // Tolerate `for in` loops without `hasOwnPrototype`. + "freeze" : true, // Prohibit modification of native objects' prototypes. + "immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` + "indent" : 2, // Specify indentation spacing + "latedef" : true, // Prohibit variable use before definition. + "newcap" : true, // Require capitalization of all constructor functions e.g. `new F()`. + "noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`. + "noempty" : true, // Prohibit use of empty blocks. + "nonew" : true, // Prohibit use of constructors for side-effects. + "plusplus" : false, // Prohibit the use of `++` & `--`. + "quotmark" : "'", // Require single quotes. + "undef" : true, // Require all non-global variables be declared before they are used. + "unused" : true, // Prohibit unused variables. + "strict" : true, // Require `use strict` pragma in every function. + "trailing" : true, // Prohibit trailing whitespaces. + "maxparams" : 4, // Prohibit more than 4 parameters per function definition. + "maxdepth" : 3, // Prohibit nesting more than 3 control blocks. + "maxstatements" : 20, // Prohibit more than 20 statements per function. + "maxcomplexity" : 7, // Prohibit having to much branches in your code. + "maxlen" : 80, // Prohibit line with more than 80 characters. - // == Relaxing Options ================================================ - // - // These options allow you to suppress certain types of warnings. Use - // them only if you are absolutely positive that you know what you are - // doing. + // == Relaxing Options ================================================ + // + // These options allow you to suppress certain types of warnings. Use + // them only if you are absolutely positive that you know what you are + // doing. - "asi" : false, // Tolerate Automatic Semicolon Insertion (no semicolons). - "boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments. - "debug" : false, // Allow debugger statements e.g. browser breakpoints. - "eqnull" : false, // Tolerate use of `== null`. - "es5" : false, // Allow EcmaScript 5 syntax. - "esnext" : false, // Allow ES.next specific features such as `const` and `let`. - "evil" : false, // Tolerate use of `eval`. - "expr" : true, // Tolerate `ExpressionStatement` as Programs. (Allowed for Mocha.) - "funcscope" : false, // Tolerate declarations of variables inside of control structures while accessing them later from the outside. - "gcl" : false, // Makes JSHint compatible with Google Closure Compiler. - "globalstrict" : true, // Allow global "use strict" (also enables 'strict'). - "iterator" : false, // Allow usage of __iterator__ property. - "lastsemic" : false, // Tolerat missing semicolons when the it is omitted for the last statement in a one-line block. - "laxbreak" : false, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons. - "laxcomma" : false, // Suppress warnings about comma-first coding style. - "loopfunc" : false, // Allow functions to be defined within loops. - "maxerr" : 50, // Maximum errors before stopping. - "moz" : false, // Tolerate Mozilla JavaScript extensions. - "notypeof" : false, // Tolerate invalid typeof values. - "multistr" : false, // Tolerate multi-line strings. - "proto" : false, // Tolerate __proto__ property. This property is deprecated. - "scripturl" : false, // Tolerate script-targeted URLs. - "smarttabs" : false, // Tolerate mixed tabs and spaces when the latter are used for alignmnent only. - "shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`. - "sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`. - "supernew" : false, // Tolerate `new function () { ... };` and `new Object;`. - "validthis" : false, // Tolerate strict violations when the code is running in strict mode and you use this in a non-constructor function. + "asi" : false, // Tolerate Automatic Semicolon Insertion (no semicolons). + "boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments. + "debug" : false, // Allow debugger statements e.g. browser breakpoints. + "eqnull" : false, // Tolerate use of `== null`. + "esnext" : false, // Allow ES.next specific features such as `const` and `let`. + "evil" : false, // Tolerate use of `eval`. + "expr" : true, // Tolerate `ExpressionStatement` as Programs. (Allowed for Mocha.) + "funcscope" : false, // Tolerate declarations of variables inside of control structures while accessing them later from the outside. + "gcl" : false, // Makes JSHint compatible with Google Closure Compiler. + "globalstrict" : true, // Allow global "use strict" (also enables 'strict'). + "iterator" : false, // Allow usage of __iterator__ property. + "lastsemic" : false, // Tolerate missing semicolons when the it is omitted for the last statement in a one-line block. + "laxbreak" : false, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons. + "laxcomma" : false, // Suppress warnings about comma-first coding style. + "loopfunc" : false, // Allow functions to be defined within loops. + "maxerr" : 50, // Maximum errors before stopping. + "moz" : false, // Tolerate Mozilla JavaScript extensions. + "notypeof" : false, // Tolerate invalid typeof values. + "multistr" : false, // Tolerate multi-line strings. + "proto" : false, // Tolerate __proto__ property. This property is deprecated. + "scripturl" : false, // Tolerate script-targeted URLs. + "smarttabs" : false, // Tolerate mixed tabs and spaces when the latter are used for alignment only. + "shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`. + "sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`. + "supernew" : false, // Tolerate `new function () { ... };` and `new Object;`. + "validthis" : false, // Tolerate strict violations when the code is running in strict mode and you use this in a non-constructor function. - // == Environments ==================================================== - // - // These options pre-define global variables that are exposed by - // popular JavaScript libraries and runtime environments—such as - // browser or node.js. + // == Environments ==================================================== + // + // These options pre-define global variables that are exposed by + // popular JavaScript libraries and runtime environments—such as + // browser or node.js. - "browser" : true, // Standard browser globals e.g. `window`, `document`. - "couch" : false, // Enable globals exposed by CouchDB. - "devel" : false, // Allow development statements e.g. `console.log();`. - "dojo" : false, // Enable globals exposed by Dojo Toolkit. - "jquery" : false, // Enable globals exposed by jQuery JavaScript library. - "mootools" : false, // Enable globals exposed by MooTools JavaScript framework. - "node" : true, // Enable globals available when code is running inside of the NodeJS runtime environment. - "nonstandard" : false, // Define non-standard but widely adopted globals such as escape and unescape. - "phantom" : false, // Enable globals exposed by PhantomJS. - "prototypejs" : false, // Enable globals exposed by Prototype JavaScript framework. - "rhino" : false, // Enable globals available when your code is running inside of the Rhino runtime environment. - "worker" : false, // Enable globals exposed when running inside a Web Worker. - "wsh" : false, // Enable globals available when your code is running as a script for the Windows Script Host. - "yui" : false, // Enable globals exposed by YUI. + "browser" : true, // Standard browser globals e.g. `window`, `document`. + "couch" : false, // Enable globals exposed by CouchDB. + "devel" : false, // Allow development statements e.g. `console.log();`. + "dojo" : false, // Enable globals exposed by Dojo Toolkit. + "jquery" : false, // Enable globals exposed by jQuery JavaScript library. + "mocha" : true, // Enable globals exposed by the mocha test runner. + "mootools" : false, // Enable globals exposed by MooTools JavaScript framework. + "node" : true, // Enable globals available when code is running inside of the NodeJS runtime environment. + "nonstandard" : false, // Define non-standard but widely adopted globals such as escape and unescape. + "phantom" : false, // Enable globals exposed by PhantomJS. + "prototypejs" : false, // Enable globals exposed by Prototype JavaScript framework. + "rhino" : false, // Enable globals available when your code is running inside of the Rhino runtime environment. + "worker" : false, // Enable globals exposed when running inside a Web Worker. + "wsh" : false, // Enable globals available when your code is running as a script for the Windows Script Host. + "yui" : false, // Enable globals exposed by YUI. - // == JSLint Legacy =================================================== - // - // These options are legacy from JSLint. Aside from bug fixes they will - // not be improved in any way and might be removed at any point. + // == JSLint Legacy =================================================== + // + // These options are legacy from JSLint. Aside from bug fixes they will + // not be improved in any way and might be removed at any point. - "nomen" : false, // Prohibit use of initial or trailing underbars in names. - "onevar" : false, // Allow only one `var` statement per function. - "passfail" : false, // Stop on first error. - "white" : false, // Check against strict whitespace and indentation rules. + "nomen" : false, // Prohibit use of initial or trailing underbars in names. + "onevar" : false, // Allow only one `var` statement per function. + "passfail" : false, // Stop on first error. + "white" : false, // Check against strict whitespace and indentation rules. - "globals": { - // Mocha. - "after" : false, - "afterEach" : false, - "before" : false, - "beforeEach" : false, - "describe" : false, - "it" : false - } + "globals": {} } diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 5bfc92e04..1424c01ee 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -5,17 +5,17 @@ "author": "Julien Fontanet ", "homepage": "https://github.com/vatesfr/xo-cli", "bugs": { - "url": "https://github.com/vatesfr/xo-cli" + "url": "https://github.com/vatesfr/xo-cli/issues" }, "repository": { "type": "git", "url": "https://github.com/vatesfr/xo-cli" }, "dependencies": { - "bluebird": "^1.1.0", + "bluebird": "^1.2.2", "chalk": "^0.4.0", "inquirer": "^0.4.1", - "l33teral": "^2.0.3", + "l33teral": "^2.0.4", "lodash": "^2.4.1", "mkdirp": "^0.3.5", "nomnom": "^1.6.2", @@ -23,16 +23,15 @@ "xdg": "^0.1.1" }, "devDependencies": { - "chai": "^1.9.0", - "mocha": "^1.18.0", - "mocha-promise": "0.0.1" + "chai": "^1.9.1", + "mocha": "^1.18.2" }, "scripts": { "test": "mocha cli.spec.js" }, "main": "cli.js", - "bin": { - "xo-cli": "bin/xo-cli" + "directories": { + "bin": "./bin" }, "preferGlobal": true, "license": "AGPL3" From 84e6228f9020bc098402ea1967d1ca5e70d7bf8b Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Sat, 24 May 2014 17:09:10 +0200 Subject: [PATCH 07/81] Various updates. --- packages/xo-cli/bin/xo-cli | 2 +- packages/xo-cli/package.json | 15 ++++++----- packages/xo-cli/src/cli.js | 50 +++++++++++++++--------------------- 3 files changed, 29 insertions(+), 38 deletions(-) diff --git a/packages/xo-cli/bin/xo-cli b/packages/xo-cli/bin/xo-cli index 77127e56d..bfe13c7d4 100755 --- a/packages/xo-cli/bin/xo-cli +++ b/packages/xo-cli/bin/xo-cli @@ -4,4 +4,4 @@ //==================================================================== -require('../')(process.argv.slice(2)); +require('exec-promise')(require('..')); diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 7c2f8a9db..1a571b498 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -23,20 +23,21 @@ "url": "https://github.com/vatesfr/xo-cli" }, "dependencies": { - "bluebird": "^1.1.0", + "bluebird": "^1.2.4", "chalk": "^0.4.0", - "inquirer": "^0.4.1", - "l33teral": "^2.0.3", + "exec-promise": "^0.2.4", + "inquirer": "^0.5.0", + "l33teral": "^2.0.4", "lodash": "^2.4.1", - "mkdirp": "^0.3.5", + "mkdirp": "^0.5.0", "nomnom": "^1.6.2", "ws": "^0.4.31", "xdg": "^0.1.1" }, "devDependencies": { - "chai": "^1.9.0", - "human-format": "^0.1.0", - "mocha": "^1.18.0", + "chai": "^1.9.1", + "human-format": "^0.1.3", + "mocha": "^1.19.0", "mocha-promise": "0.0.1" }, "scripts": { diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 192c707e4..d2992b6a1 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -3,7 +3,7 @@ //==================================================================== var _ = require('lodash'); -var nomnom = require('nomnom'); +var nomnom = require('nomnom')(); var Promise = require('bluebird'); //-------------------------------------------------------------------- @@ -14,6 +14,15 @@ var Xo = require('./xo'); //==================================================================== +//`nomnom.print()` version which does not use `process.exit()`. +nomnom.print = function (str, code) { + throw ''+ str; + + // TODO: handles code. +}; + +//==================================================================== + var connect = function () { return config.load().bind({}).then(function (config) { if (!config.server) @@ -180,7 +189,9 @@ module.exports = function (argv) { }, }, function (opts) { return connect().then(function (xo) { - return xo.send('system.methodSignature', {name: opts.name}).then(console.log); + return xo.send('system.methodSignature', { + name: opts.name + }).then(console.log); }); }); @@ -203,40 +214,19 @@ module.exports = function (argv) { }); // TODO: handle global `--config FILE` option. - nomnom + var opts = nomnom .option('version', { flag: true, help: 'prints the current version of xo-cli', - callback: function () { - return 'xo-cli version '+ require('../package').version; - }, }) .parse(argv) ; + if (opts.version) + { + return 'xo-cli version '+ require('../package').version; + } + // Executes the selected command. - Promise.try(command, [commandOpts]).then(function (value) { - if (_.isString(value)) - { - console.log(value); - } - - process.exit(0); - }).catch(function (error) { - if (error === undefined) - { - // Nothing to do. - undefined; - } - else if (_.isNumber(error)) - { - process.exit(error); - } - else - { - console.error(error.stack || error); - } - - process.exit(1); - }); + return command(commandOpts); }; From 061d8dc94f00d92625570f389fe58cf2dd17f94e Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 26 May 2014 13:33:56 +0200 Subject: [PATCH 08/81] Use API introspection. --- packages/xo-cli/package.json | 2 +- packages/xo-cli/src/cli.js | 300 +++++++++++++---------------------- packages/xo-cli/src/xo.js | 12 +- 3 files changed, 118 insertions(+), 196 deletions(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 1a571b498..9be374ea3 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -30,7 +30,7 @@ "l33teral": "^2.0.4", "lodash": "^2.4.1", "mkdirp": "^0.5.0", - "nomnom": "^1.6.2", + "multiline": "^0.3.4", "ws": "^0.4.31", "xdg": "^0.1.1" }, diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index d2992b6a1..8f92fdc2e 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -3,8 +3,9 @@ //==================================================================== var _ = require('lodash'); -var nomnom = require('nomnom')(); var Promise = require('bluebird'); +var multiline = require('multiline'); +var chalk = require('chalk'); //-------------------------------------------------------------------- @@ -14,15 +15,6 @@ var Xo = require('./xo'); //==================================================================== -//`nomnom.print()` version which does not use `process.exit()`. -nomnom.print = function (str, code) { - throw ''+ str; - - // TODO: handles code. -}; - -//==================================================================== - var connect = function () { return config.load().bind({}).then(function (config) { if (!config.server) @@ -37,7 +29,7 @@ var connect = function () { this.xo = new Xo(config.server); - return this.xo.send('session.signInWithToken', { + return this.xo.call('session.signInWithToken', { token: config.token, }); }).then(function () { @@ -45,188 +37,114 @@ var connect = function () { }).bind(); }; +var wrap = function (val) { + return function () { + return val; + }; +}; + //==================================================================== -module.exports = function (argv) { - var command; - var commandName; - var commandOpts; - - var registerCommand = function (name, def, fn) { - var cmdParser = nomnom.command(name); - - if (def.description) - { - cmdParser.help(def.description); - } - - if (def.args) - { - var interactive = process.stdin.isTTY; - - _.each(def.args, function (def, name) { - cmdParser.option(name, { - abbr: def.abbr, - flag: (def.type === 'boolean'), - help: def.description, - - // Do not mark options as required if the program is run in - // interactive mode, they will be asked. - required: !interactive && def.required, - }); - }); - - fn = (function (fn, args) { - return function (opts) { - var prompts = []; - - _.each(args, function (def, name) { - if (!(name in opts)) - { - prompts.push({ - name: name, - message: def.prompt || def.description || name, - type: def.promptType || 'input', - }); - } - }); - - if (prompts.length) - { - return prompt(prompts).then(function (answers) { - return fn(_.extend(opts, answers)); - }); - } - - return fn(opts); - }; - })(fn, def.args); - } - - cmdParser.callback(function (opts) { - command = fn; - commandName = name; - commandOpts = opts; - }); - }; - - registerCommand('add-server', { - description: 'adds a new Xen server', - args: { - host: { - description: 'host of the server', - required: true, - }, - username: { - description: 'username to use to connect', - required: true, - }, - password: { - description: 'password to use to connect', - promptType: 'password', - required: true, - }, - }, - }, function (opts) { - return connect().then(function (connection) { - return connection.send('server.add', { - host: opts.host, - username: opts.username, - password: opts.password, - }); - }).return('ok'); - }); - - registerCommand('register', { - description: 'registers the XO instance', - args: { - host: { - description: 'host/ip optionally followed by `:port` if not 80', - required: true, - }, - email: { - description: 'email to use to connect', - required: true, - }, - password: { - description: 'password to use to connect', - promptType: 'password', - required: true, - }, - } - }, function (opts) { - return Promise.bind({opts: opts || {}}).then(function () { - this.xo = new Xo(opts.host); - - return this.xo.send('session.signInWithPassword', { - email: this.opts.email, - password: this.opts.password, - }); - }).then(function (user) { - console.log('Successfully logged with', user.email); - - return this.xo.send('token.create'); - }).then(function (token) { - console.log('Token created:', token); - - return config.set({ - server: this.opts.host, - token: token, - }); - }).bind(); - }); - - registerCommand('list-commands', {}, function () { - return connect().then(function (xo) { - return xo.send('system.listMethods').then(JSON.stringify); - }); - }); - registerCommand('show-command', { - args: { - name: { - required: true, - }, - }, - }, function (opts) { - return connect().then(function (xo) { - return xo.send('system.methodSignature', { - name: opts.name - }).then(console.log); - }); - }); - - registerCommand('whoami', { - description: 'displays information about the current user', - }, function () { - return connect().then(function (xo) { - return xo.send('session.getUser'); - }).then(function (user) { - if (user) - { - console.log('You are signed in as', user.email); - console.log('Your global permission is', user.permission); - } - else - { - console.log('Your are not signed in.'); - } - }); - }); - - // TODO: handle global `--config FILE` option. - var opts = nomnom - .option('version', { - flag: true, - help: 'prints the current version of xo-cli', - }) - .parse(argv) - ; - - if (opts.version) - { - return 'xo-cli version '+ require('../package').version; +exports = module.exports = function (args) { + if (!args || !args.length) { + return help(); } - // Executes the selected command. - return command(commandOpts); + var fnName = args[0].replace(/^--|-\w/g, function (match) { + if (match === '--') + { + return ''; + } + + return match[1].toUpperCase(); + }); + if (fnName in exports) { + return exports[fnName](args.slice(1)); + } + + return exports.call(args); +}; + +//-------------------------------------------------------------------- + +var help = exports.help = wrap(multiline.stripIndent(function () {/* + Usage: + + xo-cli --register [] [] [] + Registers the XO instance to use. + + xo-cli --list-commands [--json] + Returns the list of available commands on the current XO instance. + + xo-cli [=]... + Executes a command on the current XO instance. +*/})); + +exports.version = wrap('xo-cli v'+ require('../package').version); + +exports.register = function (args) { +}; + +exports.listCommands = function (args) { + return connect().then(function (xo) { + return xo.call('system.getMethodsInfo'); + }).then(function (methods) { + if (args.indexOf('--json') !== -1) + { + return methods; + } + + methods = _.pairs(methods); + methods.sort(function (a, b) { + a = a[0]; + b = b[0]; + if (a < b) { + return -1; + } + return +(a > b); + }); + + var str = []; + methods.forEach(function (method) { + var name = method[0]; + var info = method[1]; + str.push(chalk.bold.blue(name)); + _.each(info.params || [], function (info, name) { + str.push(' '); + if (info.optional) { + str.push('['); + } + str.push(name, '=<', info.type || 'unknown', '>'); + if (info.optional) { + str.push(']'); + } + }); + str.push('\n'); + if (info.description) { + str.push(' ', info.description, '\n'); + } + }); + return str.join(''); + }); +}; + +var PARAM_RE = /^([^=]+)=(.*)$/; +exports.call = function (args) { + if (!args.length) { + throw 'missing command name'; + } + + var method = args.shift(); + var params = {}; + args.forEach(function (arg) { + var matches; + if (!(matches = arg.match(PARAM_RE))) { + throw 'invalid arg: '+arg; + } + params[matches[1]] = matches[2]; + }); + + return connect().then(function (xo) { + return xo.call(method, params); + }); }; diff --git a/packages/xo-cli/src/xo.js b/packages/xo-cli/src/xo.js index 290bdd3ab..678a68689 100644 --- a/packages/xo-cli/src/xo.js +++ b/packages/xo-cli/src/xo.js @@ -14,6 +14,12 @@ var WebSocket = (this && 'WebSocket' in this) ? this.WebSocket : require('ws'); //==================================================================== +var notConnected = function () { + throw new Error('not connected'); +}; + +//==================================================================== + var Xo = function (url) { this._url = url; @@ -102,9 +108,7 @@ _.extend(Xo.prototype, { socket.on('close', function () { // Closes accesses. - this.send = function () { - throw new Error('not connected'); - }; + this.send = notConnected; // Fails all waiting requests. _.each(this._deferreds, function (deferred) { @@ -121,7 +125,7 @@ _.extend(Xo.prototype, { return deferred.promise; }, - send: function (method, params) { + call: function (method, params) { return this.connect().then(function () { var socket = this._socket; From e7620025600c42b29f9777a00e715dcf2de0fae3 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 26 May 2014 13:42:36 +0200 Subject: [PATCH 09/81] Remove unused deps. --- packages/xo-cli/package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 9be374ea3..307808081 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -36,9 +36,7 @@ }, "devDependencies": { "chai": "^1.9.1", - "human-format": "^0.1.3", - "mocha": "^1.19.0", - "mocha-promise": "0.0.1" + "mocha": "^1.19.0" }, "scripts": { "test": "mocha cli.spec.js" From 3981c772a26902133557b952c8abff72dc6fc8e4 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 26 May 2014 13:57:18 +0200 Subject: [PATCH 10/81] --register and --unregister. --- packages/xo-cli/src/cli.js | 25 +++++++++++++++++++++++++ packages/xo-cli/src/config.js | 10 ++++++++++ 2 files changed, 35 insertions(+) diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 8f92fdc2e..0ceab90a6 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -83,8 +83,33 @@ var help = exports.help = wrap(multiline.stripIndent(function () {/* exports.version = wrap('xo-cli v'+ require('../package').version); exports.register = function (args) { + var xo; + return Promise.try(function () { + xo = new Xo(args[0]); + + return xo.call('session.signInWithPassword', { + email: args[1], + password: args[2], + }); + }).then(function (user) { + console.log('Successfully logged with', user.email); + + return xo.call('token.create'); + }).then(function (token) { + return config.set({ + server: args[0], + token: token, + }); + }); }; +exports.unregister = function () { + return config.unset([ + 'server', + 'token', + ]); +} + exports.listCommands = function (args) { return connect().then(function (xo) { return xo.call('system.getMethodsInfo'); diff --git a/packages/xo-cli/src/config.js b/packages/xo-cli/src/config.js index 2bba89430..47129eade 100644 --- a/packages/xo-cli/src/config.js +++ b/packages/xo-cli/src/config.js @@ -46,3 +46,13 @@ exports.set = function (data) { return save(_.extend(config, data)); }); }; + +exports.unset = function (paths) { + return load().then(function (config) { + var l33tConfig = l33t(config); + [].concat(paths).forEach(function (path) { + l33tConfig.purge(path, true); + }); + return save(config); + }); +}; From 97ad0483ecbbb1f363636f2823c5b659f74b1bb3 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 26 May 2014 14:01:55 +0200 Subject: [PATCH 11/81] Minor change. --- packages/xo-cli/src/cli.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 0ceab90a6..397939ed4 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -27,14 +27,12 @@ var connect = function () { throw 'no token available'; } - this.xo = new Xo(config.server); + var xo = new Xo(config.server); - return this.xo.call('session.signInWithToken', { + return xo.call('session.signInWithToken', { token: config.token, - }); - }).then(function () { - return this.xo; - }).bind(); + }).return(xo); + }); }; var wrap = function (val) { From e30a7b3849a4bb1aa478b89d624502d797d532e5 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 26 May 2014 14:22:08 +0200 Subject: [PATCH 12/81] README update. --- packages/xo-cli/README.md | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/packages/xo-cli/README.md b/packages/xo-cli/README.md index ac3ecdf9a..68b1059f3 100644 --- a/packages/xo-cli/README.md +++ b/packages/xo-cli/README.md @@ -1,4 +1,4 @@ -# XO CLI +# XO-CLI [![Build Status](https://img.shields.io/travis/vatesfr/xo-cli/master.svg)](http://travis-ci.org/vatesfr/xo-cli) [![Dependency Status](https://david-dm.org/vatesfr/xo-cli/status.svg?theme=shields.io)](https://david-dm.org/vatesfr/xo-cli) [![devDependency Status](https://david-dm.org/vatesfr/xo-cli/dev-status.svg?theme=shields.io)](https://david-dm.org/vatesfr/xo-cli#info=devDependencies) @@ -18,14 +18,43 @@ npm install -g xo-cli #### Register your XO instance ``` -xo-cli register --host http://xo.my-company.net/api/ --email admin@admin.net --password admin +xo-cli --register http://xo.my-company.net/api/admin@admin.net admin ``` Note: only a token will be saved in the configuration file. -#### Adds a new Xen server - +#### List available commands ``` -xo-cli add-server --host xen1.my-company.net --user root --password secure%password +xo-cli --list-commands ``` + +#### Execute a command + +The same syntax is used for all commands: `xo-cli =...` + +E.g., adding a new server: + +``` +xo-cli server.add my.server.net root secret-password +42 +``` + +The return value is the identifier of this new server in XO. + +## Contributing + +Contributions are *very* welcome, either on the documentation or on +the code. + +You may: + +- report any [issue](https://github.com/vatesfr/xo-cli/issues) + you've encountered; +- fork and create a pull request. + +## License + +XO-CLI is released under the [AGPL +v3](http://www.gnu.org/licenses/agpl-3.0-standalone.html). From c3ef051657fd7f2b19d1dac805f731a4aee4003e Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 26 May 2014 14:26:55 +0200 Subject: [PATCH 13/81] 0.2.0 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 307808081..9b43b5db5 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.1.1", + "version": "0.2.0", "license": "AGPL3", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From 7ed9adaf493a5d25b3363f40da36f3e625ec5dc7 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Tue, 27 May 2014 18:55:25 +0100 Subject: [PATCH 14/81] Allows connection to incorrect SSL certificates. --- packages/xo-cli/src/cli.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 397939ed4..436191fc9 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -57,6 +57,7 @@ exports = module.exports = function (args) { return match[1].toUpperCase(); }); if (fnName in exports) { + process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0; return exports[fnName](args.slice(1)); } From 99c28a184fc6bce02d4d1c466db78ff52d0c9075 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Tue, 27 May 2014 18:55:33 +0100 Subject: [PATCH 15/81] 0.2.1 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 9b43b5db5..be6476e97 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.2.0", + "version": "0.2.1", "license": "AGPL3", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From b17e6058d114052d61be2d674306a4972af6ad0c Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Tue, 27 May 2014 19:17:47 +0100 Subject: [PATCH 16/81] Minor fixes. --- packages/xo-cli/src/cli.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 436191fc9..28b00869f 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -48,6 +48,8 @@ exports = module.exports = function (args) { return help(); } + process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0; + var fnName = args[0].replace(/^--|-\w/g, function (match) { if (match === '--') { @@ -57,7 +59,6 @@ exports = module.exports = function (args) { return match[1].toUpperCase(); }); if (fnName in exports) { - process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0; return exports[fnName](args.slice(1)); } @@ -107,7 +108,7 @@ exports.unregister = function () { 'server', 'token', ]); -} +}; exports.listCommands = function (args) { return connect().then(function (xo) { From be4511d95b59526a411bf35bac008c2cff827421 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Tue, 27 May 2014 19:17:53 +0100 Subject: [PATCH 17/81] 0.2.2 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index be6476e97..23a1fa787 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.2.1", + "version": "0.2.2", "license": "AGPL3", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From 62df78f3290a075b8717c304e8b314e5e3855952 Mon Sep 17 00:00:00 2001 From: Olivier Lambert Date: Tue, 3 Jun 2014 15:11:39 +0200 Subject: [PATCH 18/81] fix error in doc --- packages/xo-cli/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/README.md b/packages/xo-cli/README.md index 68b1059f3..71f7f07a1 100644 --- a/packages/xo-cli/README.md +++ b/packages/xo-cli/README.md @@ -18,7 +18,7 @@ npm install -g xo-cli #### Register your XO instance ``` -xo-cli --register http://xo.my-company.net/api/admin@admin.net admin +xo-cli --register http://xo.my-company.net/api/ admin@admin.net admin ``` Note: only a token will be saved in the configuration file. From 7f739a1371472768eab0c76adffea2de6ac13710 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 9 Jun 2014 15:36:17 +0200 Subject: [PATCH 19/81] Update deps. --- packages/xo-cli/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 23a1fa787..744027399 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -23,10 +23,10 @@ "url": "https://github.com/vatesfr/xo-cli" }, "dependencies": { - "bluebird": "^1.2.4", + "bluebird": "^2.0.7", "chalk": "^0.4.0", - "exec-promise": "^0.2.4", - "inquirer": "^0.5.0", + "exec-promise": "^0.3.0", + "inquirer": "^0.5.1", "l33teral": "^2.0.4", "lodash": "^2.4.1", "mkdirp": "^0.5.0", @@ -36,7 +36,7 @@ }, "devDependencies": { "chai": "^1.9.1", - "mocha": "^1.19.0" + "mocha": "^1.20.1" }, "scripts": { "test": "mocha cli.spec.js" From a35c9d2d9e32825b270e74aac99dfd7ff359961e Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 9 Jun 2014 15:36:44 +0200 Subject: [PATCH 20/81] 0.2.3 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 744027399..532df7ca0 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.2.2", + "version": "0.2.3", "license": "AGPL3", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From 7840d601e16a95d88478ccc4e90fb045de616afa Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Sat, 26 Jul 2014 10:19:32 +0200 Subject: [PATCH 21/81] Use xo-lib. --- packages/xo-cli/package.json | 4 +- packages/xo-cli/src/cli.js | 2 +- packages/xo-cli/src/xo.js | 150 ----------------------------------- 3 files changed, 3 insertions(+), 153 deletions(-) delete mode 100644 packages/xo-cli/src/xo.js diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 532df7ca0..d117afcf6 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -31,8 +31,8 @@ "lodash": "^2.4.1", "mkdirp": "^0.5.0", "multiline": "^0.3.4", - "ws": "^0.4.31", - "xdg": "^0.1.1" + "xdg": "^0.1.1", + "xo-lib": "^0.1.0" }, "devDependencies": { "chai": "^1.9.1", diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 28b00869f..6fa4377f4 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -6,12 +6,12 @@ var _ = require('lodash'); var Promise = require('bluebird'); var multiline = require('multiline'); var chalk = require('chalk'); +var Xo = require('xo-lib'); //-------------------------------------------------------------------- var config = require('./config'); var prompt = require('./prompt'); -var Xo = require('./xo'); //==================================================================== diff --git a/packages/xo-cli/src/xo.js b/packages/xo-cli/src/xo.js deleted file mode 100644 index 678a68689..000000000 --- a/packages/xo-cli/src/xo.js +++ /dev/null @@ -1,150 +0,0 @@ -'use strict'; - -//==================================================================== - -var _ = require('lodash'); - -var Promise = require('bluebird'); - -// Supports browsers. -// FIXME: wraps in an anonymous function. -// jshint ignore: start -var WebSocket = (this && 'WebSocket' in this) ? this.WebSocket : require('ws'); -// jshint ignore: end - -//==================================================================== - -var notConnected = function () { - throw new Error('not connected'); -}; - -//==================================================================== - -var Xo = function (url) { - this._url = url; - - // Identifier of the next request. - this._nextId = 0; - - // Promises linked to the requests. - this._deferreds = {}; - - // Current WebSocket. - this._socket = null; - - // Current status which may be: - // - disconnected - // - connecting - // - connected - this.status = 'disconnected'; -}; - -_.extend(Xo.prototype, { - close: function () { - if (this._socket) - { - this._socket.close(); - } - }, - - connect: function () { - if (this.status === 'connected') - { - return Promise.cast(); - } - - var deferred = Promise.defer(); - - this.status = 'connecting'; - - var socket = this._socket = new WebSocket(this._url); - - // When the socket opens, send any queued requests. - socket.on('open', function () { - this.status = 'connected'; - - // (Re)Opens accesses. - delete this.send; - - // Resolves the promise. - deferred.resolve(); - }.bind(this)); - - socket.on('message', function (data) { - // `ws` API is lightly different from standard API. - if (data.data) - { - data = data.data; - } - - // TODO: Wraps in a promise to prevent releasing the Zalgo. - var response = JSON.parse(data); - - var id = response.id; - - var deferred = this._deferreds[id]; - if (!deferred) - { - // Response already handled. - return; - } - delete this._deferreds[id]; - - if ('error' in response) - { - return deferred.reject(response.error); - } - - if ('result' in response) - { - return deferred.resolve(response.result); - } - - deferred.reject({ - message: 'invalid response received', - object: response, - }); - }.bind(this)); - - socket.on('close', function () { - // Closes accesses. - this.send = notConnected; - - // Fails all waiting requests. - _.each(this._deferreds, function (deferred) { - deferred.reject('not connected'); - }); - this._deferreds = {}; - }.bind(this)); - - socket.on('error', function (error) { - // Fails the connect promise if possible. - deferred.reject(error); - }); - - return deferred.promise; - }, - - call: function (method, params) { - return this.connect().then(function () { - var socket = this._socket; - - var id = this._nextId++; - - socket.send(JSON.stringify({ - jsonrpc: '2.0', - id: id, - method: method, - params: params || [], - })); - - var deferred = this._deferreds[id] = Promise.defer(); - - return deferred.promise; - }.bind(this)); - }, -}); - -//==================================================================== - -module.exports = Xo; From a2bcadeb7c4da3273857ec87dfad71aa9702c42d Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Sat, 26 Jul 2014 23:51:23 +0200 Subject: [PATCH 22/81] Remove now useless code & Update deps. --- packages/xo-cli/package.json | 8 ++++---- packages/xo-cli/src/cli.js | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index d117afcf6..a72caf3db 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -23,8 +23,8 @@ "url": "https://github.com/vatesfr/xo-cli" }, "dependencies": { - "bluebird": "^2.0.7", - "chalk": "^0.4.0", + "bluebird": "^2.2.2", + "chalk": "^0.5.1", "exec-promise": "^0.3.0", "inquirer": "^0.5.1", "l33teral": "^2.0.4", @@ -32,11 +32,11 @@ "mkdirp": "^0.5.0", "multiline": "^0.3.4", "xdg": "^0.1.1", - "xo-lib": "^0.1.0" + "xo-lib": "^0.1.1" }, "devDependencies": { "chai": "^1.9.1", - "mocha": "^1.20.1" + "mocha": "^1.21.0" }, "scripts": { "test": "mocha cli.spec.js" diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 6fa4377f4..f49c7c2b5 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -48,8 +48,6 @@ exports = module.exports = function (args) { return help(); } - process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0; - var fnName = args[0].replace(/^--|-\w/g, function (match) { if (match === '--') { From 4e0b2e4f777ae020d8f238f201ce4eae0131d596 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 28 Jul 2014 12:41:45 +0200 Subject: [PATCH 23/81] Update deps. --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index a72caf3db..f57a7f2c9 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -36,7 +36,7 @@ }, "devDependencies": { "chai": "^1.9.1", - "mocha": "^1.21.0" + "mocha": "^1.21.3" }, "scripts": { "test": "mocha cli.spec.js" From bb18586484a564e521758f06417470bb3bf38186 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 28 Jul 2014 13:35:05 +0200 Subject: [PATCH 24/81] Update JSHint config. --- packages/xo-cli/.jshintrc | 190 ++++++++++++++++---------------------- 1 file changed, 81 insertions(+), 109 deletions(-) diff --git a/packages/xo-cli/.jshintrc b/packages/xo-cli/.jshintrc index dbd61b9e2..97fda4de7 100644 --- a/packages/xo-cli/.jshintrc +++ b/packages/xo-cli/.jshintrc @@ -1,118 +1,90 @@ { - // -------------------------------------------------------------------- - // JSHint Configuration, Node.js Edition - // -------------------------------------------------------------------- + // Julien Fontanet JSHint configuration // - // This is an options template for [JSHint][1], forked from - // haschek's [JSHint template][2]: + // Changes from defaults: + // - all enforcing options (except `++` & `--`) enabled + // - single quotes + // - indentation set to 2 instead of 4 + // - almost all relaxing options disabled + // - allow expression statements (necessary for chai.expect()) + // - allow global strict (most of my devs are in Node.js or Browserify) + // - environments are set to Browserify, mocha & Node.js // - // * the environment has been changed to `node`; - // * recent options were added; - // * coding style has been adapted to node (e.g. 2 spaces - // indenting, global use strict). - // - // [1]: http://www.jshint.com/ - // [2]: https://gist.github.com/haschek/2595796 - // - // @author Julien Fontanet - // @license http://unlicense.org/ + // See http://jshint.com/docs/ for more details - // == Enforcing Options =============================================== - // - // These options tell JSHint to be more strict towards your code. Use - // them if you want to allow only a safe subset of JavaScript, very - // useful when your codebase is shared with a big number of developers - // with different skill levels. + "maxerr" : 50, // {int} Maximum error before stopping - "bitwise" : true, // Prohibit bitwise operators (&, |, ^, etc.). - "camelcase" : true, // Require variable names to use either camelCase or UPPER_CASE styles. - "curly" : true, // Require {} for every new block or scope. - "eqeqeq" : true, // Require triple equals i.e. `===`. - "forin" : true, // Tolerate `for in` loops without `hasOwnPrototype`. - "freeze" : true, // Prohibit modification of native objects' prototypes. - "immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` - "indent" : 2, // Specify indentation spacing - "latedef" : true, // Prohibit variable use before definition. - "newcap" : true, // Require capitalization of all constructor functions e.g. `new F()`. - "noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`. - "noempty" : true, // Prohibit use of empty blocks. - "nonew" : true, // Prohibit use of constructors for side-effects. - "plusplus" : false, // Prohibit the use of `++` & `--`. - "quotmark" : "'", // Require single quotes. - "undef" : true, // Require all non-global variables be declared before they are used. - "unused" : true, // Prohibit unused variables. - "strict" : true, // Require `use strict` pragma in every function. - "trailing" : true, // Prohibit trailing whitespaces. - "maxparams" : 4, // Prohibit more than 4 parameters per function definition. - "maxdepth" : 3, // Prohibit nesting more than 3 control blocks. - "maxstatements" : 20, // Prohibit more than 20 statements per function. - "maxcomplexity" : 7, // Prohibit having to much branches in your code. - "maxlen" : 80, // Prohibit line with more than 80 characters. + // Enforcing + "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) + "camelcase" : true, // true: Identifiers must be in camelCase + "curly" : true, // true: Require {} for every new block or scope + "eqeqeq" : true, // true: Require triple equals (===) for comparison + "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() + "immed" : true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` + "indent" : 2, // {int} Number of spaces to use for indentation + "latedef" : true, // true: Require variables/functions to be defined before being used + "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()` + "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` + "noempty" : true, // true: Prohibit use of empty blocks + "nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment) + "plusplus" : false, // true: Prohibit use of `++` & `--` + "quotmark" : "single", // Quotation mark consistency: + // false : do nothing (default) + // true : ensure whatever is used is consistent + // "single" : require single quotes + // "double" : require double quotes + "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) + "unused" : true, // true: Require all defined variables be used + "strict" : true, // true: Requires all functions run in ES5 Strict Mode + "maxparams" : 4, // {int} Max number of formal params allowed per function + "maxdepth" : 3, // {int} Max depth of nested blocks (within functions) + "maxstatements" : 20, // {int} Max number statements per function + "maxcomplexity" : 7, // {int} Max cyclomatic complexity per function + "maxlen" : 80, // {int} Max number of characters per line - // == Relaxing Options ================================================ - // - // These options allow you to suppress certain types of warnings. Use - // them only if you are absolutely positive that you know what you are - // doing. + // Relaxing + "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) + "boss" : false, // true: Tolerate assignments where comparisons would be expected + "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. + "eqnull" : false, // true: Tolerate use of `== null` + "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) + "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`) + "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) + // (ex: `for each`, multiple try/catch, function expression…) + "evil" : false, // true: Tolerate use of `eval` and `new Function()` + "expr" : true, // true: Tolerate `ExpressionStatement` as Programs + "funcscope" : false, // true: Tolerate defining variables inside control statements + "globalstrict" : true, // true: Allow global "use strict" (also enables 'strict') + "iterator" : false, // true: Tolerate using the `__iterator__` property + "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block + "laxbreak" : false, // true: Tolerate possibly unsafe line breakings + "laxcomma" : false, // true: Tolerate comma-first style coding + "loopfunc" : false, // true: Tolerate functions being defined in loops + "multistr" : false, // true: Tolerate multi-line strings + "proto" : false, // true: Tolerate using the `__proto__` property + "scripturl" : false, // true: Tolerate script-targeted URLs + "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` + "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation + "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` + "validthis" : false, // true: Tolerate using this in a non-constructor function - "asi" : false, // Tolerate Automatic Semicolon Insertion (no semicolons). - "boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments. - "debug" : false, // Allow debugger statements e.g. browser breakpoints. - "eqnull" : false, // Tolerate use of `== null`. - "esnext" : false, // Allow ES.next specific features such as `const` and `let`. - "evil" : false, // Tolerate use of `eval`. - "expr" : true, // Tolerate `ExpressionStatement` as Programs. (Allowed for Mocha.) - "funcscope" : false, // Tolerate declarations of variables inside of control structures while accessing them later from the outside. - "gcl" : false, // Makes JSHint compatible with Google Closure Compiler. - "globalstrict" : true, // Allow global "use strict" (also enables 'strict'). - "iterator" : false, // Allow usage of __iterator__ property. - "lastsemic" : false, // Tolerate missing semicolons when the it is omitted for the last statement in a one-line block. - "laxbreak" : false, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons. - "laxcomma" : false, // Suppress warnings about comma-first coding style. - "loopfunc" : false, // Allow functions to be defined within loops. - "maxerr" : 50, // Maximum errors before stopping. - "moz" : false, // Tolerate Mozilla JavaScript extensions. - "notypeof" : false, // Tolerate invalid typeof values. - "multistr" : false, // Tolerate multi-line strings. - "proto" : false, // Tolerate __proto__ property. This property is deprecated. - "scripturl" : false, // Tolerate script-targeted URLs. - "smarttabs" : false, // Tolerate mixed tabs and spaces when the latter are used for alignment only. - "shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`. - "sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`. - "supernew" : false, // Tolerate `new function () { ... };` and `new Object;`. - "validthis" : false, // Tolerate strict violations when the code is running in strict mode and you use this in a non-constructor function. + // Environments + "browser" : false, // Web Browser (window, document, etc) + "browserify" : true, // Browserify (node.js code in the browser) + "couch" : false, // CouchDB + "devel" : true, // Development/debugging (alert, confirm, etc) + "dojo" : false, // Dojo Toolkit + "jquery" : false, // jQuery + "mocha" : true, // mocha + "mootools" : false, // MooTools + "node" : true, // Node.js + "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) + "prototypejs" : false, // Prototype and Scriptaculous + "rhino" : false, // Rhino + "worker" : false, // Web Workers + "wsh" : false, // Windows Scripting Host + "yui" : false, // Yahoo User Interface - // == Environments ==================================================== - // - // These options pre-define global variables that are exposed by - // popular JavaScript libraries and runtime environments—such as - // browser or node.js. - - "browser" : true, // Standard browser globals e.g. `window`, `document`. - "couch" : false, // Enable globals exposed by CouchDB. - "devel" : false, // Allow development statements e.g. `console.log();`. - "dojo" : false, // Enable globals exposed by Dojo Toolkit. - "jquery" : false, // Enable globals exposed by jQuery JavaScript library. - "mocha" : true, // Enable globals exposed by the mocha test runner. - "mootools" : false, // Enable globals exposed by MooTools JavaScript framework. - "node" : true, // Enable globals available when code is running inside of the NodeJS runtime environment. - "nonstandard" : false, // Define non-standard but widely adopted globals such as escape and unescape. - "phantom" : false, // Enable globals exposed by PhantomJS. - "prototypejs" : false, // Enable globals exposed by Prototype JavaScript framework. - "rhino" : false, // Enable globals available when your code is running inside of the Rhino runtime environment. - "worker" : false, // Enable globals exposed when running inside a Web Worker. - "wsh" : false, // Enable globals available when your code is running as a script for the Windows Script Host. - "yui" : false, // Enable globals exposed by YUI. - - // == JSLint Legacy =================================================== - // - // These options are legacy from JSLint. Aside from bug fixes they will - // not be improved in any way and might be removed at any point. - - "nomen" : false, // Prohibit use of initial or trailing underbars in names. - "onevar" : false, // Allow only one `var` statement per function. - "passfail" : false, // Stop on first error. - "white" : false, // Check against strict whitespace and indentation rules. - - "globals": {} + // Custom Globals + "globals" : {} // additional predefined global variables } From 6939e4964310b2626e29740dbe374bcc9133480d Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 28 Jul 2014 13:35:19 +0200 Subject: [PATCH 25/81] Enable async long traces. --- packages/xo-cli/src/cli.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index f49c7c2b5..682a00bb7 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -4,6 +4,7 @@ var _ = require('lodash'); var Promise = require('bluebird'); +Promise.longStackTraces(); var multiline = require('multiline'); var chalk = require('chalk'); var Xo = require('xo-lib'); From e64a95d1d7a7db778e789e449c884514d7ec0e31 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 28 Jul 2014 13:35:30 +0200 Subject: [PATCH 26/81] Handle boolean params. --- packages/xo-cli/src/cli.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 682a00bb7..af0175f34 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -165,7 +165,15 @@ exports.call = function (args) { if (!(matches = arg.match(PARAM_RE))) { throw 'invalid arg: '+arg; } - params[matches[1]] = matches[2]; + var value = matches[2]; + if (value === 'true') { + value = true; + } + else if (value === 'false') { + value = false; + } + + params[matches[1]] = value; }); return connect().then(function (xo) { From a06403ab7c3e855ca78f43e3f961f2369a2c11cd Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 28 Jul 2014 13:37:07 +0200 Subject: [PATCH 27/81] Update to latest xo-lib. --- packages/xo-cli/package.json | 2 +- packages/xo-cli/src/cli.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index f57a7f2c9..b57fde6e4 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -32,7 +32,7 @@ "mkdirp": "^0.5.0", "multiline": "^0.3.4", "xdg": "^0.1.1", - "xo-lib": "^0.1.1" + "xo-lib": "^0.2.0" }, "devDependencies": { "chai": "^1.9.1", diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index af0175f34..6ba5a9aa8 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -96,7 +96,7 @@ exports.register = function (args) { return xo.call('token.create'); }).then(function (token) { return config.set({ - server: args[0], + server: xo._url, token: token, }); }); From f6b9b4cc19535340a2e87164292ce0614e8e385f Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 28 Jul 2014 14:47:08 +0200 Subject: [PATCH 28/81] 0.3.0 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index b57fde6e4..8957bae23 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.2.3", + "version": "0.3.0", "license": "AGPL3", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From 291570dfd76f83f7927f4b9ca6a96412a60c5ee1 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 28 Jul 2014 15:06:15 +0200 Subject: [PATCH 29/81] Add colors to the help message. --- packages/xo-cli/src/cli.js | 44 ++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 6ba5a9aa8..bdb0f5001 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -44,6 +44,35 @@ var wrap = function (val) { //==================================================================== +var help = wrap((function (pkg) { + return multiline.stripIndent(function () {/* + Usage: + + $name --register [] [] [] + Registers the XO instance to use. + + $name --list-commands [--json] + Returns the list of available commands on the current XO instance. + + $name [=]... + Executes a command on the current XO instance. + + $name v$version + */}).replace(/<([^>]+)>|\$(\w+)/g, function (_, arg, key) { + if (arg) { + return '<'+ chalk.yellow(arg) +'>'; + } + + if ('name' === key) { + return chalk.bold(pkg[key]); + } + + return pkg[key]; + }); +})(require('../package'))); + +//-------------------------------------------------------------------- + exports = module.exports = function (args) { if (!args || !args.length) { return help(); @@ -66,20 +95,7 @@ exports = module.exports = function (args) { //-------------------------------------------------------------------- -var help = exports.help = wrap(multiline.stripIndent(function () {/* - Usage: - - xo-cli --register [] [] [] - Registers the XO instance to use. - - xo-cli --list-commands [--json] - Returns the list of available commands on the current XO instance. - - xo-cli [=]... - Executes a command on the current XO instance. -*/})); - -exports.version = wrap('xo-cli v'+ require('../package').version); +exports.help = help; exports.register = function (args) { var xo; From 8c0811885f9dd5985d0a4ea8987c3ab8559c3ce9 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 28 Jul 2014 15:09:00 +0200 Subject: [PATCH 30/81] Handle -h as an alias for --help. --- packages/xo-cli/src/cli.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index bdb0f5001..4dac994fb 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -74,7 +74,7 @@ var help = wrap((function (pkg) { //-------------------------------------------------------------------- exports = module.exports = function (args) { - if (!args || !args.length) { + if (!args || !args.length || '-h' === args[0]) { return help(); } From 54c5659496ec222346363947207feeff4e1ebddc Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 28 Jul 2014 15:09:12 +0200 Subject: [PATCH 31/81] 0.3.1 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 8957bae23..5bf7cf551 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.3.0", + "version": "0.3.1", "license": "AGPL3", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From ab7fd3d019a80645e20668eade6572aee67fdd2e Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 28 Jul 2014 15:32:55 +0200 Subject: [PATCH 32/81] README update. --- packages/xo-cli/README.md | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/xo-cli/README.md b/packages/xo-cli/README.md index 71f7f07a1..c782268a1 100644 --- a/packages/xo-cli/README.md +++ b/packages/xo-cli/README.md @@ -15,10 +15,25 @@ npm install -g xo-cli ## Usage +``` +> xo-cli --help +Usage: + + xo-cli --register [] [] [] + Registers the XO instance to use. + + xo-cli --list-commands [--json] + Returns the list of available commands on the current XO instance. + + xo-cli [=]... + Executes a command on the current XO instance. +``` + #### Register your XO instance ``` -xo-cli --register http://xo.my-company.net/api/ admin@admin.net admin +> xo-cli --register http://xo.my-company.net admin@admin.net admin +Successfully logged with admin@admin.net ``` Note: only a token will be saved in the configuration file. @@ -26,7 +41,7 @@ Note: only a token will be saved in the configuration file. #### List available commands ``` -xo-cli --list-commands +> xo-cli --list-commands ``` #### Execute a command @@ -37,7 +52,7 @@ name>=...` E.g., adding a new server: ``` -xo-cli server.add my.server.net root secret-password +> xo-cli server.add host=my.server.net username=root password=secret-password 42 ``` From 2974a96e9679a090e5608de0f865d208878c95c9 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 28 Jul 2014 15:34:19 +0200 Subject: [PATCH 33/81] 0.3.2 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 5bf7cf551..317c89c69 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.3.1", + "version": "0.3.2", "license": "AGPL3", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From 4b338c56b5183b1181551c04b155d30c9aa86888 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 22 Sep 2014 15:11:04 +0200 Subject: [PATCH 34/81] Remove dead code. --- packages/xo-cli/package.json | 1 - packages/xo-cli/src/cli.js | 1 - packages/xo-cli/src/prompt.js | 32 -------------------------------- 3 files changed, 34 deletions(-) delete mode 100644 packages/xo-cli/src/prompt.js diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 317c89c69..0bba10635 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -26,7 +26,6 @@ "bluebird": "^2.2.2", "chalk": "^0.5.1", "exec-promise": "^0.3.0", - "inquirer": "^0.5.1", "l33teral": "^2.0.4", "lodash": "^2.4.1", "mkdirp": "^0.5.0", diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 4dac994fb..d232f49c1 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -12,7 +12,6 @@ var Xo = require('xo-lib'); //-------------------------------------------------------------------- var config = require('./config'); -var prompt = require('./prompt'); //==================================================================== diff --git a/packages/xo-cli/src/prompt.js b/packages/xo-cli/src/prompt.js deleted file mode 100644 index f26e02b16..000000000 --- a/packages/xo-cli/src/prompt.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -//==================================================================== - -var inquirer = require('inquirer'); -var Promise = require('bluebird'); - -//==================================================================== - -var prompts = module.exports = function (prompts) { - var deferred = Promise.defer(); - - inquirer.prompt(prompts, deferred.resolve.bind(deferred)); - - return deferred.promise; -}; - -prompts.input = function (message) { - return prompts({ - type: 'input', - name: 'question', - message: message, - }).get('question'); -}; - -prompts.password = function (message) { - return prompts({ - type: 'password', - name: 'question', - message: message, - }).get('question'); -}; From e9706d605ad50f30259236e5002a9deccf5668a1 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 22 Sep 2014 15:12:14 +0200 Subject: [PATCH 35/81] `Promise` is already defined in ES6. --- packages/xo-cli/src/cli.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index d232f49c1..a68eb448c 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -3,8 +3,9 @@ //==================================================================== var _ = require('lodash'); -var Promise = require('bluebird'); -Promise.longStackTraces(); +var Bluebird = require('bluebird'); +Bluebird.longStackTraces(); + var multiline = require('multiline'); var chalk = require('chalk'); var Xo = require('xo-lib'); @@ -98,7 +99,7 @@ exports.help = help; exports.register = function (args) { var xo; - return Promise.try(function () { + return Bluebird.try(function () { xo = new Xo(args[0]); return xo.call('session.signInWithPassword', { From b8cf5a23475c112065635d59c3485c3cff968a8a Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 22 Sep 2014 15:29:28 +0200 Subject: [PATCH 36/81] Use per function lodash modules. --- packages/xo-cli/package.json | 3 ++- packages/xo-cli/src/cli.js | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 0bba10635..9112287db 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -27,7 +27,8 @@ "chalk": "^0.5.1", "exec-promise": "^0.3.0", "l33teral": "^2.0.4", - "lodash": "^2.4.1", + "lodash.foreach": "^2.4.1", + "lodash.pairs": "^2.4.1", "mkdirp": "^0.5.0", "multiline": "^0.3.4", "xdg": "^0.1.1", diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index a68eb448c..60914ab04 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -2,12 +2,13 @@ //==================================================================== -var _ = require('lodash'); var Bluebird = require('bluebird'); Bluebird.longStackTraces(); var multiline = require('multiline'); var chalk = require('chalk'); +var forEach = require('lodash.foreach'); +var pairs = require('lodash.pairs'); var Xo = require('xo-lib'); //-------------------------------------------------------------------- @@ -134,7 +135,7 @@ exports.listCommands = function (args) { return methods; } - methods = _.pairs(methods); + methods = pairs(methods); methods.sort(function (a, b) { a = a[0]; b = b[0]; @@ -145,11 +146,11 @@ exports.listCommands = function (args) { }); var str = []; - methods.forEach(function (method) { + forEach(methods, function (method) { var name = method[0]; var info = method[1]; str.push(chalk.bold.blue(name)); - _.each(info.params || [], function (info, name) { + forEach(info.params || [], function (info, name) { str.push(' '); if (info.optional) { str.push('['); @@ -176,7 +177,7 @@ exports.call = function (args) { var method = args.shift(); var params = {}; - args.forEach(function (arg) { + forEach(args, function (arg) { var matches; if (!(matches = arg.match(PARAM_RE))) { throw 'invalid arg: '+arg; From 1080562d96bcb9ceb94056311789733998a642d0 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 22 Sep 2014 15:29:45 +0200 Subject: [PATCH 37/81] Sort requires. --- packages/xo-cli/src/cli.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 60914ab04..e02f4b711 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -5,9 +5,9 @@ var Bluebird = require('bluebird'); Bluebird.longStackTraces(); -var multiline = require('multiline'); var chalk = require('chalk'); var forEach = require('lodash.foreach'); +var multiline = require('multiline'); var pairs = require('lodash.pairs'); var Xo = require('xo-lib'); From a7dea95f9058446059a2413070de9d1dc1740e76 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 22 Sep 2014 15:35:12 +0200 Subject: [PATCH 38/81] Named functions for better stack traces. --- packages/xo-cli/src/cli.js | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index e02f4b711..53b4fee94 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -17,7 +17,7 @@ var config = require('./config'); //==================================================================== -var connect = function () { +function connect() { return config.load().bind({}).then(function (config) { if (!config.server) { @@ -35,13 +35,13 @@ var connect = function () { token: config.token, }).return(xo); }); -}; +} -var wrap = function (val) { - return function () { +function wrap(val) { + return function wrappedValue() { return val; }; -}; +} //==================================================================== @@ -74,7 +74,7 @@ var help = wrap((function (pkg) { //-------------------------------------------------------------------- -exports = module.exports = function (args) { +function main(args) { if (!args || !args.length || '-h' === args[0]) { return help(); } @@ -92,13 +92,14 @@ exports = module.exports = function (args) { } return exports.call(args); -}; +} +exports = module.exports = main; //-------------------------------------------------------------------- exports.help = help; -exports.register = function (args) { +function register(args) { var xo; return Bluebird.try(function () { xo = new Xo(args[0]); @@ -117,19 +118,21 @@ exports.register = function (args) { token: token, }); }); -}; +} +exports.register = register; -exports.unregister = function () { +function unregister() { return config.unset([ 'server', 'token', ]); -}; +} +exports.unregister = unregister; -exports.listCommands = function (args) { - return connect().then(function (xo) { +function listCommands(args) { + return connect().then(function getMethodsInfo(xo) { return xo.call('system.getMethodsInfo'); - }).then(function (methods) { + }).then(function formatMethodsInfo(methods) { if (args.indexOf('--json') !== -1) { return methods; @@ -167,10 +170,11 @@ exports.listCommands = function (args) { }); return str.join(''); }); -}; +} +exports.listCommands = listCommands; var PARAM_RE = /^([^=]+)=(.*)$/; -exports.call = function (args) { +function call(args) { if (!args.length) { throw 'missing command name'; } @@ -197,3 +201,4 @@ exports.call = function (args) { return xo.call(method, params); }); }; +exports.call = call; From 578f842eedeb799ef78f2e3ec76676e1cb313996 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Tue, 23 Sep 2014 17:31:29 +0200 Subject: [PATCH 39/81] vm.export. --- packages/xo-cli/README.md | 12 +++++ packages/xo-cli/package.json | 10 ++++- packages/xo-cli/src/cli.js | 82 ++++++++++++++++++++++++++++++++++- packages/xo-cli/src/config.js | 16 +++---- 4 files changed, 107 insertions(+), 13 deletions(-) diff --git a/packages/xo-cli/README.md b/packages/xo-cli/README.md index c782268a1..87b96eedb 100644 --- a/packages/xo-cli/README.md +++ b/packages/xo-cli/README.md @@ -58,6 +58,18 @@ E.g., adding a new server: The return value is the identifier of this new server in XO. +##### VM export + +``` +> xo-cli vm.export vm=a01667e0-8e29-49fc-a550-17be4226783c > vm.xva +``` + +##### VM import + + ``` +> xo-cli vm.import host=60a6939e-8b0a-4352-9954-5bde44bcdf7d < vm.xva +``` + ## Contributing Contributions are *very* welcome, either on the documentation or on diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 9112287db..9c4c982da 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -25,12 +25,20 @@ "dependencies": { "bluebird": "^2.2.2", "chalk": "^0.5.1", - "exec-promise": "^0.3.0", + "event-to-promise": "^0.3.1", + "exec-promise": "^0.5.0", + "got": "^1.2.0", + "human-format": "^0.1.3", "l33teral": "^2.0.4", + "lodash.assign": "^2.4.1", "lodash.foreach": "^2.4.1", + "lodash.isobject": "^2.4.1", + "lodash.keys": "^2.4.1", "lodash.pairs": "^2.4.1", "mkdirp": "^0.5.0", "multiline": "^0.3.4", + "progress-stream": "^0.5.0", + "sent": "^1.1.0", "xdg": "^0.1.1", "xo-lib": "^0.2.0" }, diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 53b4fee94..bb528228b 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -2,13 +2,24 @@ //==================================================================== +require('superstack'); + var Bluebird = require('bluebird'); Bluebird.longStackTraces(); +var resolveUrl = require('url').resolve; + var chalk = require('chalk'); +var eventToPromise = require('event-to-promise'); var forEach = require('lodash.foreach'); +var getKeys = require('lodash.keys'); +var got = require('got'); +var humanFormat = require('human-format'); +var isObject = require('lodash.isobject'); var multiline = require('multiline'); var pairs = require('lodash.pairs'); +var progressStream = require('progress-stream'); +var sent = require('sent'); var Xo = require('xo-lib'); //-------------------------------------------------------------------- @@ -37,6 +48,35 @@ function connect() { }); } +function pipeWithErrors(streams) { + var current; + + forEach(streams, function (stream) { + if (!stream) { + return; + } + + if (current) { + current.on('error', function forwardError(error) { + stream.emit('error', error); + }); + current = current.pipe(stream); + } + else { + current = stream; + } + }); + + return current; +} + +function printProgress(progress) { + console.warn('%s downloaded at %s/s', + humanFormat(progress.transferred), + humanFormat(progress.speed) + ); +} + function wrap(val) { return function wrappedValue() { return val; @@ -186,7 +226,9 @@ function call(args) { if (!(matches = arg.match(PARAM_RE))) { throw 'invalid arg: '+arg; } + var name = matches[1]; var value = matches[2]; + if (value === 'true') { value = true; } @@ -194,11 +236,47 @@ function call(args) { value = false; } - params[matches[1]] = value; + params[name] = value; }); + var baseUrl; return connect().then(function (xo) { + baseUrl = xo._url; return xo.call(method, params); + }).then(function handleResult(result) { + var keys, key, url; + if (( + isObject(result) && + (keys = getKeys(result)).length === 1 + )) { + key = keys[0]; + + if (key === '$getFrom') { + url = resolveUrl(baseUrl, result[key]); + + return eventToPromise(pipeWithErrors([ + got(url), + progressStream({ time: 1e3 }, printProgress), + process.stdout, + ]), 'finish'); + } + + if (key === '$sendTo') { + url = resolveUrl(baseUrl, result[key]); + + return new Bluebird(function (resolve, reject) { + sent(url, process.stdin, function (error, result) { + if (error) { + reject(error); + return; + } + resolve(result); + }); + }); + } + } + + return result; }); -}; +} exports.call = call; diff --git a/packages/xo-cli/src/config.js b/packages/xo-cli/src/config.js index 47129eade..1e3f41294 100644 --- a/packages/xo-cli/src/config.js +++ b/packages/xo-cli/src/config.js @@ -2,14 +2,14 @@ //==================================================================== -var fs = require('fs'); +var promisify = require('bluebird').promisify; -//-------------------------------------------------------------------- +var readFile = promisify(require('fs').readFile); +var writeFile = promisify(require('fs').writeFile); -var _ = require('lodash'); +var assign = require('lodash.assign'); var l33t = require('l33teral'); -var mkdirp = require('mkdirp'); -var Promise = require('bluebird'); +var mkdirp = promisify(require('mkdirp')); var xdg = require('xdg'); //==================================================================== @@ -17,10 +17,6 @@ var xdg = require('xdg'); var configPath = xdg.basedir.configPath('xo-cli'); var configFile = configPath +'/config.json'; -var mkdirp = Promise.promisify(mkdirp); -var readFile = Promise.promisify(fs.readFile); -var writeFile = Promise.promisify(fs.writeFile); - //==================================================================== var load = exports.load = function () { @@ -43,7 +39,7 @@ var save = exports.save = function (config) { exports.set = function (data) { return load().then(function (config) { - return save(_.extend(config, data)); + return save(assign(config, data)); }); }; From ae1a68500c857f627f19a9dd855b2ed436dfe874 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Tue, 23 Sep 2014 17:57:04 +0200 Subject: [PATCH 40/81] Remove erroneous require. --- packages/xo-cli/src/cli.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index bb528228b..1b88f5f3e 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -2,8 +2,6 @@ //==================================================================== -require('superstack'); - var Bluebird = require('bluebird'); Bluebird.longStackTraces(); From 38683a7fea67e782b0a96568a02d6d38e509ac16 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Tue, 23 Sep 2014 19:16:11 +0200 Subject: [PATCH 41/81] Syntax update. --- packages/xo-cli/README.md | 4 ++-- packages/xo-cli/src/cli.js | 34 ++++++++++++++++++++++++---------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/packages/xo-cli/README.md b/packages/xo-cli/README.md index 87b96eedb..ab2b7e019 100644 --- a/packages/xo-cli/README.md +++ b/packages/xo-cli/README.md @@ -61,13 +61,13 @@ The return value is the identifier of this new server in XO. ##### VM export ``` -> xo-cli vm.export vm=a01667e0-8e29-49fc-a550-17be4226783c > vm.xva +> xo-cli vm.export vm=a01667e0-8e29-49fc-a550-17be4226783c @=vm.xva ``` ##### VM import ``` -> xo-cli vm.import host=60a6939e-8b0a-4352-9954-5bde44bcdf7d < vm.xva +> xo-cli vm.import host=60a6939e-8b0a-4352-9954-5bde44bcdf7d @=vm.xva ``` ## Contributing diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 1b88f5f3e..9e76da762 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -4,8 +4,12 @@ var Bluebird = require('bluebird'); Bluebird.longStackTraces(); +var promisify = Bluebird.promisify; +var createReadStream = require('fs').createReadStream; +var createWriteStream = require('fs').createWriteStream; var resolveUrl = require('url').resolve; +var stat = promisify(require('fs').stat); var chalk = require('chalk'); var eventToPromise = require('event-to-promise'); @@ -17,7 +21,7 @@ var isObject = require('lodash.isobject'); var multiline = require('multiline'); var pairs = require('lodash.pairs'); var progressStream = require('progress-stream'); -var sent = require('sent'); +var sent = promisify(require('sent')); var Xo = require('xo-lib'); //-------------------------------------------------------------------- @@ -219,6 +223,7 @@ function call(args) { var method = args.shift(); var params = {}; + var file; forEach(args, function (arg) { var matches; if (!(matches = arg.match(PARAM_RE))) { @@ -227,6 +232,11 @@ function call(args) { var name = matches[1]; var value = matches[2]; + if (name === '@') { + file = value; + return; + } + if (value === 'true') { value = true; } @@ -251,25 +261,29 @@ function call(args) { if (key === '$getFrom') { url = resolveUrl(baseUrl, result[key]); + var output = createWriteStream(file); return eventToPromise(pipeWithErrors([ got(url), progressStream({ time: 1e3 }, printProgress), - process.stdout, + output, ]), 'finish'); } if (key === '$sendTo') { url = resolveUrl(baseUrl, result[key]); - return new Bluebird(function (resolve, reject) { - sent(url, process.stdin, function (error, result) { - if (error) { - reject(error); - return; - } - resolve(result); - }); + return stat(file).then(function (stats) { + var input = pipeWithErrors([ + createReadStream(file), + progressStream({ time: 1e3 }, printProgress), + ]) && createReadStream(file); + + return sent(url, input, { + headers: { + // 'content-length': stats.size, + }, + }).get(0); }); } } From 70bedaf8ddb0690caeae0899ea3058c42841ba01 Mon Sep 17 00:00:00 2001 From: Olivier Lambert Date: Wed, 24 Sep 2014 17:09:59 +0200 Subject: [PATCH 42/81] fix by using PUT instead of POST --- packages/xo-cli/src/cli.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 9e76da762..17993d8b2 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -277,12 +277,13 @@ function call(args) { var input = pipeWithErrors([ createReadStream(file), progressStream({ time: 1e3 }, printProgress), - ]) && createReadStream(file); + ]); return sent(url, input, { headers: { - // 'content-length': stats.size, + 'content-length': stats.size, }, + method: 'PUT' }).get(0); }); } From 42bb3b5aca17b0ac43b94a5ff3e08b3896260917 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Wed, 24 Sep 2014 17:22:44 +0200 Subject: [PATCH 43/81] Always use the POST method. --- packages/xo-cli/src/cli.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index 17993d8b2..e9ab3efad 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -283,7 +283,7 @@ function call(args) { headers: { 'content-length': stats.size, }, - method: 'PUT' + method: 'POST' }).get(0); }); } From 99985f4fab322c8e9ee72afdbde69830b46c8608 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Wed, 24 Sep 2014 18:18:17 +0200 Subject: [PATCH 44/81] Better progress stats. --- packages/xo-cli/package.json | 1 + packages/xo-cli/src/cli.js | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 9c4c982da..ed80ba13d 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -37,6 +37,7 @@ "lodash.pairs": "^2.4.1", "mkdirp": "^0.5.0", "multiline": "^0.3.4", + "pretty-ms": "^1.0.0", "progress-stream": "^0.5.0", "sent": "^1.1.0", "xdg": "^0.1.1", diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/src/cli.js index e9ab3efad..392392a4d 100644 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/src/cli.js @@ -20,6 +20,7 @@ var humanFormat = require('human-format'); var isObject = require('lodash.isobject'); var multiline = require('multiline'); var pairs = require('lodash.pairs'); +var prettyMs = require('pretty-ms'); var progressStream = require('progress-stream'); var sent = promisify(require('sent')); var Xo = require('xo-lib'); @@ -73,10 +74,19 @@ function pipeWithErrors(streams) { } function printProgress(progress) { - console.warn('%s downloaded at %s/s', - humanFormat(progress.transferred), - humanFormat(progress.speed) - ); + if (progress.length) { + console.warn('%s% of %s @ %s/s - ETA %s', + Math.round(progress.percentage), + humanFormat(progress.length), + humanFormat(progress.speed), + prettyMs(progress.eta * 1e3) + ); + } else { + console.warn('%s @ %s/s', + humanFormat(progress.transferred), + humanFormat(progress.speed) + ); + } } function wrap(val) { @@ -274,14 +284,19 @@ function call(args) { url = resolveUrl(baseUrl, result[key]); return stat(file).then(function (stats) { + var length = stats.size; + var input = pipeWithErrors([ createReadStream(file), - progressStream({ time: 1e3 }, printProgress), + progressStream({ + length: length, + time: 1e3, + }, printProgress), ]); return sent(url, input, { headers: { - 'content-length': stats.size, + 'content-length': length, }, method: 'POST' }).get(0); From 4742cd4a03c6db060843c5d111f9532c4d8b5cc1 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Thu, 25 Sep 2014 14:59:54 +0200 Subject: [PATCH 45/81] 0.4.0 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index ed80ba13d..acefafddb 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.3.2", + "version": "0.4.0", "license": "AGPL3", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From 5564e4daa22b20189f9c9fd7fb3c175bf4b698ae Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Thu, 25 Sep 2014 15:23:53 +0200 Subject: [PATCH 46/81] Minor update. --- packages/xo-cli/bin/xo-cli | 7 ------- packages/xo-cli/{src => }/config.js | 0 packages/xo-cli/{src/cli.js => index.js} | 10 +++++++++- packages/xo-cli/package.json | 16 +++++----------- 4 files changed, 14 insertions(+), 19 deletions(-) delete mode 100755 packages/xo-cli/bin/xo-cli rename packages/xo-cli/{src => }/config.js (100%) rename packages/xo-cli/{src/cli.js => index.js} (97%) mode change 100644 => 100755 diff --git a/packages/xo-cli/bin/xo-cli b/packages/xo-cli/bin/xo-cli deleted file mode 100755 index bfe13c7d4..000000000 --- a/packages/xo-cli/bin/xo-cli +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env node - -'use strict'; - -//==================================================================== - -require('exec-promise')(require('..')); diff --git a/packages/xo-cli/src/config.js b/packages/xo-cli/config.js similarity index 100% rename from packages/xo-cli/src/config.js rename to packages/xo-cli/config.js diff --git a/packages/xo-cli/src/cli.js b/packages/xo-cli/index.js old mode 100644 new mode 100755 similarity index 97% rename from packages/xo-cli/src/cli.js rename to packages/xo-cli/index.js index 392392a4d..9fde2d5b9 --- a/packages/xo-cli/src/cli.js +++ b/packages/xo-cli/index.js @@ -1,3 +1,5 @@ +#!/usr/bin/env node + 'use strict'; //==================================================================== @@ -122,7 +124,7 @@ var help = wrap((function (pkg) { return pkg[key]; }); -})(require('../package'))); +})(require('./package'))); //-------------------------------------------------------------------- @@ -308,3 +310,9 @@ function call(args) { }); } exports.call = call; + +//==================================================================== + +if (!module.parent) { + require('exec-promise')(exports); +} diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index acefafddb..259910988 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -13,11 +13,12 @@ "bugs": "https://github.com/vatesfr/xo-cli/issues", "author": "Julien Fontanet ", "preferGlobal": true, - "main": "./src/cli.js", - "directories": { - "bin": "./bin", - "man": "./man" + "bin": { + "xo-cli": "index.js" }, + "files": [ + "*.js" + ], "repository": { "type": "git", "url": "https://github.com/vatesfr/xo-cli" @@ -42,12 +43,5 @@ "sent": "^1.1.0", "xdg": "^0.1.1", "xo-lib": "^0.2.0" - }, - "devDependencies": { - "chai": "^1.9.1", - "mocha": "^1.21.3" - }, - "scripts": { - "test": "mocha cli.spec.js" } } From e88d0579b0e5b5a0a89b5ffba66a733b912aad12 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 29 Sep 2014 14:53:11 +0200 Subject: [PATCH 47/81] Use nice-pipe instead of own code. --- packages/xo-cli/index.js | 27 +++------------------------ packages/xo-cli/package.json | 1 + 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index 9fde2d5b9..cdd4e71f8 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -21,6 +21,7 @@ var got = require('got'); var humanFormat = require('human-format'); var isObject = require('lodash.isobject'); var multiline = require('multiline'); +var nicePipe = require('nice-pipe'); var pairs = require('lodash.pairs'); var prettyMs = require('pretty-ms'); var progressStream = require('progress-stream'); @@ -53,28 +54,6 @@ function connect() { }); } -function pipeWithErrors(streams) { - var current; - - forEach(streams, function (stream) { - if (!stream) { - return; - } - - if (current) { - current.on('error', function forwardError(error) { - stream.emit('error', error); - }); - current = current.pipe(stream); - } - else { - current = stream; - } - }); - - return current; -} - function printProgress(progress) { if (progress.length) { console.warn('%s% of %s @ %s/s - ETA %s', @@ -275,7 +254,7 @@ function call(args) { url = resolveUrl(baseUrl, result[key]); var output = createWriteStream(file); - return eventToPromise(pipeWithErrors([ + return eventToPromise(nicePipe([ got(url), progressStream({ time: 1e3 }, printProgress), output, @@ -288,7 +267,7 @@ function call(args) { return stat(file).then(function (stats) { var length = stats.size; - var input = pipeWithErrors([ + var input = nicePipe([ createReadStream(file), progressStream({ length: length, diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 259910988..cd6985368 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -38,6 +38,7 @@ "lodash.pairs": "^2.4.1", "mkdirp": "^0.5.0", "multiline": "^0.3.4", + "nice-pipe": "0.0.0", "pretty-ms": "^1.0.0", "progress-stream": "^0.5.0", "sent": "^1.1.0", From de05139dfc188fc58b94569a48a5a506bc47474e Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Wed, 8 Oct 2014 09:50:34 +0200 Subject: [PATCH 48/81] Use xdg-basedir instead of xdg. --- packages/xo-cli/config.js | 4 ++-- packages/xo-cli/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/xo-cli/config.js b/packages/xo-cli/config.js index 1e3f41294..d76587c78 100644 --- a/packages/xo-cli/config.js +++ b/packages/xo-cli/config.js @@ -10,11 +10,11 @@ var writeFile = promisify(require('fs').writeFile); var assign = require('lodash.assign'); var l33t = require('l33teral'); var mkdirp = promisify(require('mkdirp')); -var xdg = require('xdg'); +var xdgBasedir = require('xdg-basedir'); //==================================================================== -var configPath = xdg.basedir.configPath('xo-cli'); +var configPath = xdgBasedir.config +'/xo-cli'; var configFile = configPath +'/config.json'; //==================================================================== diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index cd6985368..37d67e7b0 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -42,7 +42,7 @@ "pretty-ms": "^1.0.0", "progress-stream": "^0.5.0", "sent": "^1.1.0", - "xdg": "^0.1.1", + "xdg-basedir": "^1.0.0", "xo-lib": "^0.2.0" } } From 1fbe7d92ebe9fdcebe3d85f0675ed30aaa312b0e Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 21 Sep 2015 18:13:04 +0200 Subject: [PATCH 49/81] Add --list-objects (fix #8 and fix #9). --- packages/xo-cli/index.js | 71 ++++++++++++++++++++++++------------ packages/xo-cli/package.json | 1 + 2 files changed, 49 insertions(+), 23 deletions(-) diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index cdd4e71f8..09d8767b2 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -15,6 +15,7 @@ var stat = promisify(require('fs').stat); var chalk = require('chalk'); var eventToPromise = require('event-to-promise'); +var filter = require('lodash.filter'); var forEach = require('lodash.foreach'); var getKeys = require('lodash.keys'); var got = require('got'); @@ -54,6 +55,34 @@ function connect() { }); } +function parseParameters (args) { + var params = {}; + forEach(args, function (arg) { + var matches; + if (!(matches = arg.match(PARAM_RE))) { + throw 'invalid arg: '+arg; + } + var name = matches[1]; + var value = matches[2]; + + if (name === '@') { + params['@'] = value; + return; + } + + if (value === 'true') { + value = true; + } + else if (value === 'false') { + value = false; + } + + params[name] = value; + }); + + return params +} + function printProgress(progress) { if (progress.length) { console.warn('%s% of %s @ %s/s - ETA %s', @@ -88,6 +117,9 @@ var help = wrap((function (pkg) { $name --list-commands [--json] Returns the list of available commands on the current XO instance. + $name --list-objects [=]... + Returns a list of XO objects. + $name [=]... Executes a command on the current XO instance. @@ -206,6 +238,19 @@ function listCommands(args) { } exports.listCommands = listCommands; +function listObjects(args) { + var sieve = args.length + ? parseParameters(args) + : null + + return connect().then(function getXoObjects(xo) { + return xo.call('xo.getAllObjects') + }).then(function filterObjects (objects) { + return filter(objects, sieve) + }) +} +exports.listObjects = listObjects + var PARAM_RE = /^([^=]+)=(.*)$/; function call(args) { if (!args.length) { @@ -213,30 +258,10 @@ function call(args) { } var method = args.shift(); - var params = {}; - var file; - forEach(args, function (arg) { - var matches; - if (!(matches = arg.match(PARAM_RE))) { - throw 'invalid arg: '+arg; - } - var name = matches[1]; - var value = matches[2]; + var params = parseParameters(args); - if (name === '@') { - file = value; - return; - } - - if (value === 'true') { - value = true; - } - else if (value === 'false') { - value = false; - } - - params[name] = value; - }); + var file = params['@']; + delete params['@']; var baseUrl; return connect().then(function (xo) { diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 37d67e7b0..045b7b872 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -32,6 +32,7 @@ "human-format": "^0.1.3", "l33teral": "^2.0.4", "lodash.assign": "^2.4.1", + "lodash.filter": "^3.1.1", "lodash.foreach": "^2.4.1", "lodash.isobject": "^2.4.1", "lodash.keys": "^2.4.1", From a2f5f1cb0e79c54f5cbf1260112a2d0dfae93475 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 21 Sep 2015 18:13:13 +0200 Subject: [PATCH 50/81] 0.5.0 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 045b7b872..41ef2e324 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.4.0", + "version": "0.5.0", "license": "AGPL3", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From b1ee4bdc09defc0e17e84847b0a16abc5db41eca Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Tue, 27 Oct 2015 12:27:57 +0100 Subject: [PATCH 51/81] Standard coding style. --- packages/xo-cli/config.js | 64 ++++---- packages/xo-cli/index.js | 309 +++++++++++++++++------------------ packages/xo-cli/package.json | 7 + 3 files changed, 190 insertions(+), 190 deletions(-) diff --git a/packages/xo-cli/config.js b/packages/xo-cli/config.js index d76587c78..3a75ba42b 100644 --- a/packages/xo-cli/config.js +++ b/packages/xo-cli/config.js @@ -1,54 +1,54 @@ -'use strict'; +'use strict' -//==================================================================== +// =================================================================== -var promisify = require('bluebird').promisify; +var promisify = require('bluebird').promisify -var readFile = promisify(require('fs').readFile); -var writeFile = promisify(require('fs').writeFile); +var readFile = promisify(require('fs').readFile) +var writeFile = promisify(require('fs').writeFile) -var assign = require('lodash.assign'); -var l33t = require('l33teral'); -var mkdirp = promisify(require('mkdirp')); -var xdgBasedir = require('xdg-basedir'); +var assign = require('lodash.assign') +var l33t = require('l33teral') +var mkdirp = promisify(require('mkdirp')) +var xdgBasedir = require('xdg-basedir') -//==================================================================== +// =================================================================== -var configPath = xdgBasedir.config +'/xo-cli'; -var configFile = configPath +'/config.json'; +var configPath = xdgBasedir.config + '/xo-cli' +var configFile = configPath + '/config.json' -//==================================================================== +// =================================================================== var load = exports.load = function () { return readFile(configFile).then(JSON.parse).catch(function () { - return {}; - }); -}; + return {} + }) +} exports.get = function (path) { return load().then(function (config) { - return l33t(config).tap(path); - }); -}; + return l33t(config).tap(path) + }) +} var save = exports.save = function (config) { return mkdirp(configPath).then(function () { - return writeFile(configFile, JSON.stringify(config)); - }); -}; + return writeFile(configFile, JSON.stringify(config)) + }) +} exports.set = function (data) { return load().then(function (config) { - return save(assign(config, data)); - }); -}; + return save(assign(config, data)) + }) +} exports.unset = function (paths) { return load().then(function (config) { - var l33tConfig = l33t(config); - [].concat(paths).forEach(function (path) { - l33tConfig.purge(path, true); - }); - return save(config); - }); -}; + var l33tConfig = l33t(config) + ;[].concat(paths).forEach(function (path) { + l33tConfig.purge(path, true) + }) + return save(config) + }) +} diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index 09d8767b2..7c38e4b6b 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -1,114 +1,109 @@ #!/usr/bin/env node -'use strict'; +'use strict' -//==================================================================== +var Bluebird = require('bluebird') +Bluebird.longStackTraces() +var promisify = Bluebird.promisify -var Bluebird = require('bluebird'); -Bluebird.longStackTraces(); -var promisify = Bluebird.promisify; +var createReadStream = require('fs').createReadStream +var createWriteStream = require('fs').createWriteStream +var resolveUrl = require('url').resolve +var stat = promisify(require('fs').stat) -var createReadStream = require('fs').createReadStream; -var createWriteStream = require('fs').createWriteStream; -var resolveUrl = require('url').resolve; -var stat = promisify(require('fs').stat); +var chalk = require('chalk') +var eventToPromise = require('event-to-promise') +var filter = require('lodash.filter') +var forEach = require('lodash.foreach') +var getKeys = require('lodash.keys') +var got = require('got') +var humanFormat = require('human-format') +var isObject = require('lodash.isobject') +var multiline = require('multiline') +var nicePipe = require('nice-pipe') +var pairs = require('lodash.pairs') +var prettyMs = require('pretty-ms') +var progressStream = require('progress-stream') +var sent = promisify(require('sent')) +var Xo = require('xo-lib') -var chalk = require('chalk'); -var eventToPromise = require('event-to-promise'); -var filter = require('lodash.filter'); -var forEach = require('lodash.foreach'); -var getKeys = require('lodash.keys'); -var got = require('got'); -var humanFormat = require('human-format'); -var isObject = require('lodash.isobject'); -var multiline = require('multiline'); -var nicePipe = require('nice-pipe'); -var pairs = require('lodash.pairs'); -var prettyMs = require('pretty-ms'); -var progressStream = require('progress-stream'); -var sent = promisify(require('sent')); -var Xo = require('xo-lib'); +// ------------------------------------------------------------------- -//-------------------------------------------------------------------- +var config = require('./config') -var config = require('./config'); +// =================================================================== -//==================================================================== - -function connect() { +function connect () { return config.load().bind({}).then(function (config) { - if (!config.server) - { - throw 'no server to connect to!'; + if (!config.server) { + throw new Error('no server to connect to!') } - if (!config.token) - { - throw 'no token available'; + if (!config.token) { + throw new Error('no token available') } - var xo = new Xo(config.server); + var xo = new Xo(config.server) return xo.call('session.signInWithToken', { - token: config.token, - }).return(xo); - }); + token: config.token + }).return(xo) + }) } function parseParameters (args) { - var params = {}; + var params = {} forEach(args, function (arg) { - var matches; + var matches if (!(matches = arg.match(PARAM_RE))) { - throw 'invalid arg: '+arg; + throw new Error('invalid arg: ' + arg) } - var name = matches[1]; - var value = matches[2]; + var name = matches[1] + var value = matches[2] if (name === '@') { - params['@'] = value; - return; + params['@'] = value + return } if (value === 'true') { - value = true; - } - else if (value === 'false') { - value = false; + value = true + } else if (value === 'false') { + value = false } - params[name] = value; - }); + params[name] = value + }) return params } -function printProgress(progress) { +function printProgress (progress) { if (progress.length) { console.warn('%s% of %s @ %s/s - ETA %s', Math.round(progress.percentage), humanFormat(progress.length), humanFormat(progress.speed), prettyMs(progress.eta * 1e3) - ); + ) } else { console.warn('%s @ %s/s', humanFormat(progress.transferred), humanFormat(progress.speed) - ); + ) } } -function wrap(val) { - return function wrappedValue() { - return val; - }; +function wrap (val) { + return function wrappedValue () { + return val + } } -//==================================================================== +// =================================================================== var help = wrap((function (pkg) { - return multiline.stripIndent(function () {/* + return multiline.stripIndent(function () { /* Usage: $name --register [] [] [] @@ -126,124 +121,122 @@ var help = wrap((function (pkg) { $name v$version */}).replace(/<([^>]+)>|\$(\w+)/g, function (_, arg, key) { if (arg) { - return '<'+ chalk.yellow(arg) +'>'; + return '<' + chalk.yellow(arg) + '>' } - if ('name' === key) { - return chalk.bold(pkg[key]); + if (key === 'name') { + return chalk.bold(pkg[key]) } - return pkg[key]; - }); -})(require('./package'))); + return pkg[key] + }) +})(require('./package'))) -//-------------------------------------------------------------------- +// ------------------------------------------------------------------- -function main(args) { - if (!args || !args.length || '-h' === args[0]) { - return help(); +function main (args) { + if (!args || !args.length || args[0] === '-h') { + return help() } var fnName = args[0].replace(/^--|-\w/g, function (match) { - if (match === '--') - { - return ''; + if (match === '--') { + return '' } - return match[1].toUpperCase(); - }); + return match[1].toUpperCase() + }) if (fnName in exports) { - return exports[fnName](args.slice(1)); + return exports[fnName](args.slice(1)) } - return exports.call(args); + return exports.call(args) } -exports = module.exports = main; +exports = module.exports = main -//-------------------------------------------------------------------- +// ------------------------------------------------------------------- -exports.help = help; +exports.help = help -function register(args) { - var xo; +function register (args) { + var xo return Bluebird.try(function () { - xo = new Xo(args[0]); + xo = new Xo(args[0]) return xo.call('session.signInWithPassword', { email: args[1], - password: args[2], - }); + password: args[2] + }) }).then(function (user) { - console.log('Successfully logged with', user.email); + console.log('Successfully logged with', user.email) - return xo.call('token.create'); + return xo.call('token.create') }).then(function (token) { return config.set({ server: xo._url, - token: token, - }); - }); + token: token + }) + }) } -exports.register = register; +exports.register = register -function unregister() { +function unregister () { return config.unset([ 'server', - 'token', - ]); + 'token' + ]) } -exports.unregister = unregister; +exports.unregister = unregister -function listCommands(args) { - return connect().then(function getMethodsInfo(xo) { - return xo.call('system.getMethodsInfo'); - }).then(function formatMethodsInfo(methods) { - if (args.indexOf('--json') !== -1) - { - return methods; +function listCommands (args) { + return connect().then(function getMethodsInfo (xo) { + return xo.call('system.getMethodsInfo') + }).then(function formatMethodsInfo (methods) { + if (args.indexOf('--json') !== -1) { + return methods } - methods = pairs(methods); + methods = pairs(methods) methods.sort(function (a, b) { - a = a[0]; - b = b[0]; + a = a[0] + b = b[0] if (a < b) { - return -1; + return -1 } - return +(a > b); - }); + return +(a > b) + }) - var str = []; + var str = [] forEach(methods, function (method) { - var name = method[0]; - var info = method[1]; - str.push(chalk.bold.blue(name)); + var name = method[0] + var info = method[1] + str.push(chalk.bold.blue(name)) forEach(info.params || [], function (info, name) { - str.push(' '); + str.push(' ') if (info.optional) { - str.push('['); + str.push('[') } - str.push(name, '=<', info.type || 'unknown', '>'); + str.push(name, '=<', info.type || 'unknown', '>') if (info.optional) { - str.push(']'); + str.push(']') } - }); - str.push('\n'); + }) + str.push('\n') if (info.description) { - str.push(' ', info.description, '\n'); + str.push(' ', info.description, '\n') } - }); - return str.join(''); - }); + }) + return str.join('') + }) } -exports.listCommands = listCommands; +exports.listCommands = listCommands -function listObjects(args) { +function listObjects (args) { var sieve = args.length ? parseParameters(args) : null - return connect().then(function getXoObjects(xo) { + return connect().then(function getXoObjects (xo) { return xo.call('xo.getAllObjects') }).then(function filterObjects (objects) { return filter(objects, sieve) @@ -251,72 +244,72 @@ function listObjects(args) { } exports.listObjects = listObjects -var PARAM_RE = /^([^=]+)=(.*)$/; -function call(args) { +var PARAM_RE = /^([^=]+)=(.*)$/ +function call (args) { if (!args.length) { - throw 'missing command name'; + throw new Error('missing command name') } - var method = args.shift(); - var params = parseParameters(args); + var method = args.shift() + var params = parseParameters(args) - var file = params['@']; - delete params['@']; + var file = params['@'] + delete params['@'] - var baseUrl; + var baseUrl return connect().then(function (xo) { - baseUrl = xo._url; - return xo.call(method, params); - }).then(function handleResult(result) { - var keys, key, url; - if (( + baseUrl = xo._url + return xo.call(method, params) + }).then(function handleResult (result) { + var keys, key, url + if ( isObject(result) && (keys = getKeys(result)).length === 1 - )) { - key = keys[0]; + ) { + key = keys[0] if (key === '$getFrom') { - url = resolveUrl(baseUrl, result[key]); - var output = createWriteStream(file); + url = resolveUrl(baseUrl, result[key]) + var output = createWriteStream(file) return eventToPromise(nicePipe([ got(url), progressStream({ time: 1e3 }, printProgress), - output, - ]), 'finish'); + output + ]), 'finish') } if (key === '$sendTo') { - url = resolveUrl(baseUrl, result[key]); + url = resolveUrl(baseUrl, result[key]) return stat(file).then(function (stats) { - var length = stats.size; + var length = stats.size var input = nicePipe([ createReadStream(file), progressStream({ length: length, - time: 1e3, - }, printProgress), - ]); + time: 1e3 + }, printProgress) + ]) return sent(url, input, { headers: { - 'content-length': length, + 'content-length': length }, method: 'POST' - }).get(0); - }); + }).get(0) + }) } } - return result; - }); + return result + }) } -exports.call = call; +exports.call = call -//==================================================================== +// =================================================================== if (!module.parent) { - require('exec-promise')(exports); + require('exec-promise')(exports) } diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 41ef2e324..b780aecd9 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -45,5 +45,12 @@ "sent": "^1.1.0", "xdg-basedir": "^1.0.0", "xo-lib": "^0.2.0" + }, + "devDependencies": { + "standard": "^5.3.1" + }, + "scripts": { + "lint": "standard", + "posttest": "npm run lint" } } From 80d8388eb6b3aac2adefd5083dc82f08df5be330 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Tue, 27 Oct 2015 16:12:09 +0100 Subject: [PATCH 52/81] Update deps. --- packages/xo-cli/index.js | 46 ++++++++++++++++++++++-------------- packages/xo-cli/package.json | 32 ++++++++++++------------- 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index 7c38e4b6b..53d358f21 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -4,12 +4,11 @@ var Bluebird = require('bluebird') Bluebird.longStackTraces() -var promisify = Bluebird.promisify var createReadStream = require('fs').createReadStream var createWriteStream = require('fs').createWriteStream var resolveUrl = require('url').resolve -var stat = promisify(require('fs').stat) +var stat = require('fs-promise').stat var chalk = require('chalk') var eventToPromise = require('event-to-promise') @@ -24,8 +23,7 @@ var nicePipe = require('nice-pipe') var pairs = require('lodash.pairs') var prettyMs = require('pretty-ms') var progressStream = require('progress-stream') -var sent = promisify(require('sent')) -var Xo = require('xo-lib') +var Xo = require('xo-lib').Xo // ------------------------------------------------------------------- @@ -45,9 +43,11 @@ function connect () { var xo = new Xo(config.server) - return xo.call('session.signInWithToken', { + return xo.signIn({ token: config.token - }).return(xo) + }).then(function () { + return xo + }) }) } @@ -78,18 +78,23 @@ function parseParameters (args) { return params } +var humanFormatOpts = { + unit: 'B', + scale: 'binary' +} + function printProgress (progress) { if (progress.length) { console.warn('%s% of %s @ %s/s - ETA %s', Math.round(progress.percentage), - humanFormat(progress.length), - humanFormat(progress.speed), + humanFormat(progress.length, humanFormatOpts), + humanFormat(progress.speed, humanFormatOpts), prettyMs(progress.eta * 1e3) ) } else { console.warn('%s @ %s/s', - humanFormat(progress.transferred), - humanFormat(progress.speed) + humanFormat(progress.transferred, humanFormatOpts), + humanFormat(progress.speed, humanFormatOpts) ) } } @@ -163,17 +168,17 @@ function register (args) { return Bluebird.try(function () { xo = new Xo(args[0]) - return xo.call('session.signInWithPassword', { + return xo.signIn({ email: args[1], password: args[2] }) - }).then(function (user) { - console.log('Successfully logged with', user.email) + }).then(function () { + console.log('Successfully logged with', xo.user.email) return xo.call('token.create') }).then(function (token) { return config.set({ - server: xo._url, + server: args[0], token: token }) }) @@ -258,7 +263,9 @@ function call (args) { var baseUrl return connect().then(function (xo) { - baseUrl = xo._url + // FIXME: do not use private properties. + baseUrl = xo._api._url.replace(/^ws/, 'http') + return xo.call(method, params) }).then(function handleResult (result) { var keys, key, url @@ -273,7 +280,7 @@ function call (args) { var output = createWriteStream(file) return eventToPromise(nicePipe([ - got(url), + got.stream(url), progressStream({ time: 1e3 }, printProgress), output ]), 'finish') @@ -293,12 +300,15 @@ function call (args) { }, printProgress) ]) - return sent(url, input, { + return got.post(url, { + body: input, headers: { 'content-length': length }, method: 'POST' - }).get(0) + }).then(function (response) { + return response.body + }) }) } } diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index b780aecd9..68eb02663 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,7 +1,7 @@ { "name": "xo-cli", "version": "0.5.0", - "license": "AGPL3", + "license": "AGPL-3.0", "description": "Basic CLI for Xen-Orchestra", "keywords": [ "xo", @@ -25,26 +25,26 @@ }, "dependencies": { "bluebird": "^2.2.2", - "chalk": "^0.5.1", - "event-to-promise": "^0.3.1", + "chalk": "^1.1.1", + "event-to-promise": "^0.4.0", "exec-promise": "^0.5.0", - "got": "^1.2.0", - "human-format": "^0.1.3", + "fs-promise": "^0.3.1", + "got": "^5.0.0", + "human-format": "^0.5.0", "l33teral": "^2.0.4", - "lodash.assign": "^2.4.1", + "lodash.assign": "^3.2.0", "lodash.filter": "^3.1.1", - "lodash.foreach": "^2.4.1", - "lodash.isobject": "^2.4.1", - "lodash.keys": "^2.4.1", - "lodash.pairs": "^2.4.1", + "lodash.foreach": "^3.0.3", + "lodash.isobject": "^3.0.2", + "lodash.keys": "^3.1.2", + "lodash.pairs": "^3.0.1", "mkdirp": "^0.5.0", - "multiline": "^0.3.4", + "multiline": "^1.0.2", "nice-pipe": "0.0.0", - "pretty-ms": "^1.0.0", - "progress-stream": "^0.5.0", - "sent": "^1.1.0", - "xdg-basedir": "^1.0.0", - "xo-lib": "^0.2.0" + "pretty-ms": "^2.1.0", + "progress-stream": "^1.1.1", + "xdg-basedir": "^2.0.0", + "xo-lib": "^0.7.3" }, "devDependencies": { "standard": "^5.3.1" From c6657b9619d9b113124363bdef282d6eb6f99ac4 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Tue, 27 Oct 2015 18:47:44 +0100 Subject: [PATCH 53/81] Sets the length when/if known on download. --- packages/xo-cli/index.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index 53d358f21..367903ce9 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -279,9 +279,16 @@ function call (args) { url = resolveUrl(baseUrl, result[key]) var output = createWriteStream(file) + var progress = progressStream({ time: 1e3 }, printProgress) + return eventToPromise(nicePipe([ - got.stream(url), - progressStream({ time: 1e3 }, printProgress), + got.stream(url).on('response', function (response) { + var length = response.headers['content-length'] + if (length) { + progress.length(length) + } + }), + progress, output ]), 'finish') } From d58add18fc62491b708b6a2a5ee3deb73675bdc9 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Wed, 28 Oct 2015 14:47:24 +0100 Subject: [PATCH 54/81] Document --list-objects --- packages/xo-cli/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/xo-cli/README.md b/packages/xo-cli/README.md index ab2b7e019..b415a61ff 100644 --- a/packages/xo-cli/README.md +++ b/packages/xo-cli/README.md @@ -25,6 +25,9 @@ Usage: xo-cli --list-commands [--json] Returns the list of available commands on the current XO instance. + xo-cli --list-objects [=]... + Returns a list of XO objects. + xo-cli [=]... Executes a command on the current XO instance. ``` @@ -38,6 +41,21 @@ Successfully logged with admin@admin.net Note: only a token will be saved in the configuration file. +#### List available objects + +Prints all objects: + +``` +> xo-cli --list-objects +``` + +It is possible to filter on object properties, for instance to prints +all VM templates: + +``` +> xo-cli --list-objects type=VM-template +``` + #### List available commands ``` From 0f03208aa19782d31175686965a219b360d075c7 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Fri, 30 Oct 2015 11:30:22 +0100 Subject: [PATCH 55/81] Commands filtering. --- packages/xo-cli/README.md | 10 +++++++++- packages/xo-cli/index.js | 22 ++++++++++++++++++++-- packages/xo-cli/package.json | 2 ++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/packages/xo-cli/README.md b/packages/xo-cli/README.md index b415a61ff..49fcd65e4 100644 --- a/packages/xo-cli/README.md +++ b/packages/xo-cli/README.md @@ -22,9 +22,11 @@ Usage: xo-cli --register [] [] [] Registers the XO instance to use. - xo-cli --list-commands [--json] + xo-cli --list-commands [--json] []... Returns the list of available commands on the current XO instance. + The patterns can be used to filter on command names. + xo-cli --list-objects [=]... Returns a list of XO objects. @@ -62,6 +64,12 @@ all VM templates: > xo-cli --list-commands ``` +Commands can be filtered using patterns: + +``` +> xo-cli --list-commands '{user,group}.*' +``` + #### Execute a command The same syntax is used for all commands: `xo-cli ] [] [] Registers the XO instance to use. - $name --list-commands [--json] + $name --list-commands [--json] []... Returns the list of available commands on the current XO instance. + The patterns can be used to filter on command names. + $name --list-objects [=]... Returns a list of XO objects. @@ -197,7 +201,21 @@ function listCommands (args) { return connect().then(function getMethodsInfo (xo) { return xo.call('system.getMethodsInfo') }).then(function formatMethodsInfo (methods) { - if (args.indexOf('--json') !== -1) { + var json = false + var patterns = [] + forEach(args, function (arg) { + if (arg === -'--json') { + json = true + } + + patterns.push(arg) + }) + + if (patterns.length) { + methods = pick(methods, micromatch(Object.keys(methods), patterns)) + } + + if (json) { return methods } diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 68eb02663..e2762cd63 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -38,6 +38,8 @@ "lodash.isobject": "^3.0.2", "lodash.keys": "^3.1.2", "lodash.pairs": "^3.0.1", + "lodash.pick": "^3.1.0", + "micromatch": "^2.2.0", "mkdirp": "^0.5.0", "multiline": "^1.0.2", "nice-pipe": "0.0.0", From ea0db57388547d845cd5aaa6e27d65314738683f Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Tue, 5 Jan 2016 18:03:58 +0100 Subject: [PATCH 56/81] 0.6.0 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index e2762cd63..7f1fa551c 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.5.0", + "version": "0.6.0", "license": "AGPL-3.0", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From 74d8eff6d88adc1ff56572496e2836aa70fbc999 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 14 Mar 2016 10:20:15 +0100 Subject: [PATCH 57/81] Add support for JSON encoded values. --- packages/xo-cli/index.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index 9ee8d824c..4b706fe26 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -53,6 +53,10 @@ function connect () { }) } +function _startsWith (string, search) { + return string.lastIndexOf(search, 0) === 0 +} + function parseParameters (args) { var params = {} forEach(args, function (arg) { @@ -63,6 +67,10 @@ function parseParameters (args) { var name = matches[1] var value = matches[2] + if (_startsWith(value, 'json:')) { + value = JSON.parse(value.slice(5)) + } + if (name === '@') { params['@'] = value return From 934e67d146bc876c43a0328a3902a70d0920dacf Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Wed, 11 May 2016 12:57:53 +0200 Subject: [PATCH 58/81] Document JSON syntax --- packages/xo-cli/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/xo-cli/README.md b/packages/xo-cli/README.md index 49fcd65e4..240640037 100644 --- a/packages/xo-cli/README.md +++ b/packages/xo-cli/README.md @@ -84,6 +84,14 @@ E.g., adding a new server: The return value is the identifier of this new server in XO. +Parameters (except `true` and `false` which are correctly parsed as +booleans) are assumed to be strings, for other types, you may use JSON +encoding by prefixing with `json:`: + +``` +> xo-cli foo.bar baz='json:[1, 2, 3]' +``` + ##### VM export ``` From 4d4a2897a5b4b3b82b9fa523e9f8c55774948710 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Wed, 11 May 2016 12:59:14 +0200 Subject: [PATCH 59/81] 0.7.0 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 7f1fa551c..b48d4f5bb 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.6.0", + "version": "0.7.0", "license": "AGPL-3.0", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From 16dde5c772cd53dc78fe739756ce8afbbc2f9290 Mon Sep 17 00:00:00 2001 From: Greenkeeper Date: Sun, 18 Sep 2016 05:17:03 +0200 Subject: [PATCH 60/81] chore(package): update standard to version 8.1.0 (#12) https://greenkeeper.io/ --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index b48d4f5bb..b77d77376 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -49,7 +49,7 @@ "xo-lib": "^0.7.3" }, "devDependencies": { - "standard": "^5.3.1" + "standard": "^8.1.0" }, "scripts": { "lint": "standard", From 7aa591ffbdffb55cd79079614045ff8cd4d951b5 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 24 Oct 2016 15:33:40 +0200 Subject: [PATCH 61/81] fix(package): handle multiline params --- packages/xo-cli/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index 4b706fe26..d42e18ae1 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -57,6 +57,7 @@ function _startsWith (string, search) { return string.lastIndexOf(search, 0) === 0 } +var PARAM_RE = /^([^=]+)=([^]*)$/ function parseParameters (args) { var params = {} forEach(args, function (arg) { @@ -275,7 +276,6 @@ function listObjects (args) { } exports.listObjects = listObjects -var PARAM_RE = /^([^=]+)=(.*)$/ function call (args) { if (!args.length) { throw new Error('missing command name') From fbbd9ae249971f7df5dc4b884717cd5735486fcb Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 24 Oct 2016 15:55:01 +0200 Subject: [PATCH 62/81] chore(package): update (almost) all dependencies --- packages/xo-cli/index.js | 2 +- packages/xo-cli/package.json | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index d42e18ae1..b6ffe8c41 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -137,7 +137,7 @@ var help = wrap((function (pkg) { Executes a command on the current XO instance. $name v$version - */}).replace(/<([^>]+)>|\$(\w+)/g, function (_, arg, key) { + */ }).replace(/<([^>]+)>|\$(\w+)/g, function (_, arg, key) { if (arg) { return '<' + chalk.yellow(arg) + '>' } diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index b77d77376..f251ded35 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -24,25 +24,25 @@ "url": "https://github.com/vatesfr/xo-cli" }, "dependencies": { - "bluebird": "^2.2.2", + "bluebird": "^3.4.6", "chalk": "^1.1.1", - "event-to-promise": "^0.4.0", - "exec-promise": "^0.5.0", - "fs-promise": "^0.3.1", - "got": "^5.0.0", - "human-format": "^0.5.0", - "l33teral": "^2.0.4", - "lodash.assign": "^3.2.0", - "lodash.filter": "^3.1.1", - "lodash.foreach": "^3.0.3", + "event-to-promise": "^0.7.0", + "exec-promise": "^0.6.1", + "fs-promise": "^0.5.0", + "got": "^6.5.0", + "human-format": "^0.7.0", + "l33teral": "^3.0.2", + "lodash.assign": "^4.2.0", + "lodash.filter": "^4.6.0", + "lodash.foreach": "^4.5.0", "lodash.isobject": "^3.0.2", - "lodash.keys": "^3.1.2", + "lodash.keys": "^4.2.0", "lodash.pairs": "^3.0.1", - "lodash.pick": "^3.1.0", + "lodash.pick": "^4.4.0", "micromatch": "^2.2.0", "mkdirp": "^0.5.0", "multiline": "^1.0.2", - "nice-pipe": "0.0.0", + "nice-pipe": "0.3.4", "pretty-ms": "^2.1.0", "progress-stream": "^1.1.1", "xdg-basedir": "^2.0.0", From 207aef7cb3ee7c9640e91a9cdae6b58fd7ade066 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 24 Oct 2016 15:55:22 +0200 Subject: [PATCH 63/81] fix(--list-commands): fix --json flag --- packages/xo-cli/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index b6ffe8c41..085ee7b25 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -213,11 +213,11 @@ function listCommands (args) { var json = false var patterns = [] forEach(args, function (arg) { - if (arg === -'--json') { + if (arg === '--json') { json = true + } else { + patterns.push(arg) } - - patterns.push(arg) }) if (patterns.length) { From c3a5e0592d18312bd22f71b43e5510237565a84e Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 24 Oct 2016 15:58:14 +0200 Subject: [PATCH 64/81] chore(package): add --unregister doc --- packages/xo-cli/README.md | 3 +++ packages/xo-cli/index.js | 3 +++ 2 files changed, 6 insertions(+) diff --git a/packages/xo-cli/README.md b/packages/xo-cli/README.md index 240640037..c1f9422c3 100644 --- a/packages/xo-cli/README.md +++ b/packages/xo-cli/README.md @@ -22,6 +22,9 @@ Usage: xo-cli --register [] [] [] Registers the XO instance to use. + xo-cli --unregister + Remove stored credentials. + xo-cli --list-commands [--json] []... Returns the list of available commands on the current XO instance. diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index 085ee7b25..8cd0bf492 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -125,6 +125,9 @@ var help = wrap((function (pkg) { $name --register [] [] [] Registers the XO instance to use. + $name --unregister + Remove stored credentials. + $name --list-commands [--json] []... Returns the list of available commands on the current XO instance. From 4d50eae3c9b509ff0d62227f5eb431a62672fede Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 24 Oct 2016 15:58:32 +0200 Subject: [PATCH 65/81] 0.7.1 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index f251ded35..5420cee89 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.7.0", + "version": "0.7.1", "license": "AGPL-3.0", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From 7b928c4d412363d77fe1dd8290a90284c5a5ff51 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 24 Oct 2016 16:03:04 +0200 Subject: [PATCH 66/81] chore(package): add Travis CI conf --- packages/xo-cli/.travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 packages/xo-cli/.travis.yml diff --git a/packages/xo-cli/.travis.yml b/packages/xo-cli/.travis.yml new file mode 100644 index 000000000..ae52e87e6 --- /dev/null +++ b/packages/xo-cli/.travis.yml @@ -0,0 +1,9 @@ +language: node_js +node_js: + - 'stable' + - '6' + - '4' + +# Use containers. +# http://docs.travis-ci.com/user/workers/container-based-infrastructure/ +sudo: false From c24a4009c8e2428445bb510a82b3dce5b4d071af Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 24 Oct 2016 17:29:34 +0200 Subject: [PATCH 67/81] chore(package): use full lodash package --- packages/xo-cli/config.js | 2 +- packages/xo-cli/index.js | 12 ++++++------ packages/xo-cli/package.json | 8 +------- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/packages/xo-cli/config.js b/packages/xo-cli/config.js index 3a75ba42b..f93f9d091 100644 --- a/packages/xo-cli/config.js +++ b/packages/xo-cli/config.js @@ -7,7 +7,7 @@ var promisify = require('bluebird').promisify var readFile = promisify(require('fs').readFile) var writeFile = promisify(require('fs').writeFile) -var assign = require('lodash.assign') +var assign = require('lodash/assign') var l33t = require('l33teral') var mkdirp = promisify(require('mkdirp')) var xdgBasedir = require('xdg-basedir') diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index 8cd0bf492..52ab0171d 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -12,17 +12,17 @@ var stat = require('fs-promise').stat var chalk = require('chalk') var eventToPromise = require('event-to-promise') -var filter = require('lodash.filter') -var forEach = require('lodash.foreach') -var getKeys = require('lodash.keys') +var filter = require('lodash/filter') +var forEach = require('lodash/forEach') +var getKeys = require('lodash/keys') var got = require('got') var humanFormat = require('human-format') -var isObject = require('lodash.isobject') +var isObject = require('lodash/isObject') var micromatch = require('micromatch') var multiline = require('multiline') var nicePipe = require('nice-pipe') -var pairs = require('lodash.pairs') -var pick = require('lodash.pick') +var pairs = require('lodash/toPairs') +var pick = require('lodash/pick') var prettyMs = require('pretty-ms') var progressStream = require('progress-stream') var Xo = require('xo-lib').Xo diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 5420cee89..9e7291ef2 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -32,13 +32,7 @@ "got": "^6.5.0", "human-format": "^0.7.0", "l33teral": "^3.0.2", - "lodash.assign": "^4.2.0", - "lodash.filter": "^4.6.0", - "lodash.foreach": "^4.5.0", - "lodash.isobject": "^3.0.2", - "lodash.keys": "^4.2.0", - "lodash.pairs": "^3.0.1", - "lodash.pick": "^4.4.0", + "lodash": "^4.16.4", "micromatch": "^2.2.0", "mkdirp": "^0.5.0", "multiline": "^1.0.2", From 9aa9d4452c14f67aa0a20d49983de917360adeb1 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 2 Nov 2016 09:30:20 +0100 Subject: [PATCH 68/81] chore(package): update dependencies (#16) https://greenkeeper.io/ --- packages/xo-cli/index.js | 16 +++++++--------- packages/xo-cli/package.json | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index 52ab0171d..f74d51783 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -25,7 +25,7 @@ var pairs = require('lodash/toPairs') var pick = require('lodash/pick') var prettyMs = require('pretty-ms') var progressStream = require('progress-stream') -var Xo = require('xo-lib').Xo +var Xo = require('xo-lib').default // ------------------------------------------------------------------- @@ -43,10 +43,10 @@ function connect () { throw new Error('no token available') } - var xo = new Xo(config.server) + var xo = new Xo({ url: config.server }) - return xo.signIn({ - token: config.token + return xo.open().then(function () { + return xo.signIn({ token: config.token }) }).then(function () { return xo }) @@ -180,10 +180,8 @@ exports = module.exports = main exports.help = help function register (args) { - var xo - return Bluebird.try(function () { - xo = new Xo(args[0]) - + var xo = new Xo({ url: args[0] }) + return xo.open().then(function () { return xo.signIn({ email: args[1], password: args[2] @@ -293,7 +291,7 @@ function call (args) { var baseUrl return connect().then(function (xo) { // FIXME: do not use private properties. - baseUrl = xo._api._url.replace(/^ws/, 'http') + baseUrl = xo._url.replace(/^ws/, 'http') return xo.call(method, params) }).then(function handleResult (result) { diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 9e7291ef2..4266c7e4d 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -40,7 +40,7 @@ "pretty-ms": "^2.1.0", "progress-stream": "^1.1.1", "xdg-basedir": "^2.0.0", - "xo-lib": "^0.7.3" + "xo-lib": "^0.8.0" }, "devDependencies": { "standard": "^8.1.0" From baf5f7491d5830acefd8f69fec0777eeab78eca5 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Fri, 4 Nov 2016 17:24:00 +0100 Subject: [PATCH 69/81] 0.7.2 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 4266c7e4d..7fa05033c 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.7.1", + "version": "0.7.2", "license": "AGPL-3.0", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From 7c8194307e36c486ff6d17f08cf1b924c165cb5f Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Thu, 10 Nov 2016 08:56:51 +0100 Subject: [PATCH 70/81] fix(package): update fs-promise to version 1.0.0 (#17) https://greenkeeper.io/ --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 7fa05033c..7209079c2 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -28,7 +28,7 @@ "chalk": "^1.1.1", "event-to-promise": "^0.7.0", "exec-promise": "^0.6.1", - "fs-promise": "^0.5.0", + "fs-promise": "^1.0.0", "got": "^6.5.0", "human-format": "^0.7.0", "l33teral": "^3.0.2", From fee3f7a7160358e22732e0566396f2224bfabf59 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Thu, 17 Nov 2016 14:56:43 +0100 Subject: [PATCH 71/81] fix(list objects): writes one objects at a time Fixes vatesfr/xo-web#1356 --- packages/xo-cli/index.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index f74d51783..b6bf9afe4 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -272,7 +272,15 @@ function listObjects (args) { return connect().then(function getXoObjects (xo) { return xo.call('xo.getAllObjects') }).then(function filterObjects (objects) { - return filter(objects, sieve) + objects = filter(objects, sieve) + + const stdout = process.stdout + stdout.write('[\n') + for (var i = 0, n = objects.length; i < n;) { + stdout.write(JSON.stringify(objects[i], null, 2)) + stdout.write(++i < n ? ',\n' : '\n') + } + stdout.write(']') }) } exports.listObjects = listObjects From b36ef9fdb1c73a16871b89960821d5eea5e34395 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Thu, 17 Nov 2016 15:40:29 +0100 Subject: [PATCH 72/81] 0.7.3 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 7209079c2..24a59ee8b 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.7.2", + "version": "0.7.3", "license": "AGPL-3.0", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From 815bdf345445f93eb5c257593464b0bb62d137f9 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Thu, 17 Nov 2016 17:33:04 +0100 Subject: [PATCH 73/81] fix(package): downgrade nice-pipe to 0.0.0 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 24a59ee8b..3fb936fd0 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -36,7 +36,7 @@ "micromatch": "^2.2.0", "mkdirp": "^0.5.0", "multiline": "^1.0.2", - "nice-pipe": "0.3.4", + "nice-pipe": "0.0.0", "pretty-ms": "^2.1.0", "progress-stream": "^1.1.1", "xdg-basedir": "^2.0.0", From 731e2dc4c4e36bb92ab33f1ba2642015e81b483e Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Thu, 17 Nov 2016 17:33:08 +0100 Subject: [PATCH 74/81] 0.7.4 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 3fb936fd0..ca64675e4 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.7.3", + "version": "0.7.4", "license": "AGPL-3.0", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From a67b6130f8cc4e60312eed6f5592c8778603e5f5 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Thu, 24 Nov 2016 12:33:24 +0100 Subject: [PATCH 75/81] feat(list objects): ability to select displayed properties Fixes #18 --- packages/xo-cli/index.js | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index b6bf9afe4..8a37b376f 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -17,6 +17,7 @@ var forEach = require('lodash/forEach') var getKeys = require('lodash/keys') var got = require('got') var humanFormat = require('human-format') +var identity = require('lodash/identity') var isObject = require('lodash/isObject') var micromatch = require('micromatch') var multiline = require('multiline') @@ -57,6 +58,24 @@ function _startsWith (string, search) { return string.lastIndexOf(search, 0) === 0 } +var FLAG_RE = /^--([^=]+)(?:=([^]*))?$/ +function extractFlags (args) { + var flags = {} + + var i = 0 + var n = args.length + var matches + while (i < n && (matches = args[i].match(FLAG_RE))) { + var value = matches[2] + + flags[matches[1]] = value === undefined ? true : value + ++i + } + args.splice(0, i) + + return flags +} + var PARAM_RE = /^([^=]+)=([^]*)$/ function parseParameters (args) { var params = {} @@ -133,9 +152,15 @@ var help = wrap((function (pkg) { The patterns can be used to filter on command names. - $name --list-objects [=]... + $name --list-objects [--]… [=]... Returns a list of XO objects. + -- + Restricts displayed properties to those listed. + + = + Restricted displayed objects to those matching the patterns. + $name [=]... Executes a command on the current XO instance. @@ -265,9 +290,14 @@ function listCommands (args) { exports.listCommands = listCommands function listObjects (args) { - var sieve = args.length - ? parseParameters(args) - : null + var properties = getKeys(extractFlags(args)) + var filterProperties = properties.length + ? function (object) { + return pick(object, properties) + } + : identity + + var sieve = args.length && parseParameters(args) return connect().then(function getXoObjects (xo) { return xo.call('xo.getAllObjects') @@ -277,7 +307,7 @@ function listObjects (args) { const stdout = process.stdout stdout.write('[\n') for (var i = 0, n = objects.length; i < n;) { - stdout.write(JSON.stringify(objects[i], null, 2)) + stdout.write(JSON.stringify(filterProperties(objects[i]), null, 2)) stdout.write(++i < n ? ',\n' : '\n') } stdout.write(']') From 82489b36c84896ffba5f7ab3a428011f7060ffba Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Thu, 24 Nov 2016 12:34:04 +0100 Subject: [PATCH 76/81] 0.8.0 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index ca64675e4..9261133f9 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.7.4", + "version": "0.8.0", "license": "AGPL-3.0", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From 18ca950cd2117e484afbbfe90695622ed96e7f0c Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Thu, 24 Nov 2016 12:35:02 +0100 Subject: [PATCH 77/81] 0.8.1 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 9261133f9..46c038477 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.8.0", + "version": "0.8.1", "license": "AGPL-3.0", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From ab48d069677dc1993e8315375a95cf765fdab667 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Thu, 24 Nov 2016 12:39:14 +0100 Subject: [PATCH 78/81] feat(README): update usage --- packages/xo-cli/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/xo-cli/README.md b/packages/xo-cli/README.md index c1f9422c3..3b297b984 100644 --- a/packages/xo-cli/README.md +++ b/packages/xo-cli/README.md @@ -30,9 +30,15 @@ Usage: The patterns can be used to filter on command names. - xo-cli --list-objects [=]... + xo-cli --list-objects [--]… [=]... Returns a list of XO objects. + -- + Restricts displayed properties to those listed. + + = + Restricted displayed objects to those matching the patterns. + xo-cli [=]... Executes a command on the current XO instance. ``` From 729dbe16c0ecdc0823cb6286328069a1f0e4d9db Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Fri, 25 Nov 2016 11:49:28 +0100 Subject: [PATCH 79/81] fix(list objects): fix without filtering Fixes #19 --- packages/xo-cli/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/index.js b/packages/xo-cli/index.js index 8a37b376f..4ab7e8076 100755 --- a/packages/xo-cli/index.js +++ b/packages/xo-cli/index.js @@ -297,7 +297,7 @@ function listObjects (args) { } : identity - var sieve = args.length && parseParameters(args) + var sieve = args.length ? parseParameters(args) : null return connect().then(function getXoObjects (xo) { return xo.call('xo.getAllObjects') From 04e7d54620e86144811220962361c29a09d0f3d4 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Fri, 25 Nov 2016 11:50:31 +0100 Subject: [PATCH 80/81] v0.8.2 --- packages/xo-cli/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 46c038477..22d06a256 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -1,6 +1,6 @@ { "name": "xo-cli", - "version": "0.8.1", + "version": "0.8.2", "license": "AGPL-3.0", "description": "Basic CLI for Xen-Orchestra", "keywords": [ From b25f4184115a0dc5494fa998dfbd5026b56de9e5 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Tue, 29 Nov 2016 13:41:32 +0100 Subject: [PATCH 81/81] chore(package): update dependencies (#20) https://greenkeeper.io/ --- packages/xo-cli/package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/xo-cli/package.json b/packages/xo-cli/package.json index 22d06a256..5322e050f 100644 --- a/packages/xo-cli/package.json +++ b/packages/xo-cli/package.json @@ -48,5 +48,10 @@ "scripts": { "lint": "standard", "posttest": "npm run lint" + }, + "greenkeeper": { + "ignore": [ + "nice-pipe" + ] } }