Merge remote-tracking branch 'xo-cli/master'
This commit is contained in:
commit
a703ecc7e1
12
packages/xo-cli/.editorconfig
Normal file
12
packages/xo-cli/.editorconfig
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# EditorConfig is awesome: http://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespaces = true
|
1
packages/xo-cli/.gitignore
vendored
Normal file
1
packages/xo-cli/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/node_modules/
|
90
packages/xo-cli/.jshintrc
Normal file
90
packages/xo-cli/.jshintrc
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
{
|
||||||
|
// Julien Fontanet JSHint configuration
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
// See http://jshint.com/docs/ for more details
|
||||||
|
|
||||||
|
"maxerr" : 50, // {int} Maximum error before stopping
|
||||||
|
|
||||||
|
// 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
|
||||||
|
"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
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// Custom Globals
|
||||||
|
"globals" : {} // additional predefined global variables
|
||||||
|
}
|
9
packages/xo-cli/.travis.yml
Normal file
9
packages/xo-cli/.travis.yml
Normal file
@ -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
|
130
packages/xo-cli/README.md
Normal file
130
packages/xo-cli/README.md
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
# XO-CLI
|
||||||
|
[](http://travis-ci.org/vatesfr/xo-cli)
|
||||||
|
[](https://david-dm.org/vatesfr/xo-cli)
|
||||||
|
[](https://david-dm.org/vatesfr/xo-cli#info=devDependencies)
|
||||||
|
|
||||||
|
> Basic CLI for Xen-Orchestra
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
#### [npm](https://npmjs.org/package/xo-cli)
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install -g xo-cli
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
> xo-cli --help
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
xo-cli --register [<XO-Server URL>] [<username>] [<password>]
|
||||||
|
Registers the XO instance to use.
|
||||||
|
|
||||||
|
xo-cli --unregister
|
||||||
|
Remove stored credentials.
|
||||||
|
|
||||||
|
xo-cli --list-commands [--json] [<pattern>]...
|
||||||
|
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 [--<property>]… [<property>=<value>]...
|
||||||
|
Returns a list of XO objects.
|
||||||
|
|
||||||
|
--<property>
|
||||||
|
Restricts displayed properties to those listed.
|
||||||
|
|
||||||
|
<property>=<value>
|
||||||
|
Restricted displayed objects to those matching the patterns.
|
||||||
|
|
||||||
|
xo-cli <command> [<name>=<value>]...
|
||||||
|
Executes a command on the current XO instance.
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Register your XO instance
|
||||||
|
|
||||||
|
```
|
||||||
|
> 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.
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
|
||||||
|
```
|
||||||
|
> 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 <command> <param
|
||||||
|
name>=<value>...`
|
||||||
|
|
||||||
|
E.g., adding a new server:
|
||||||
|
|
||||||
|
```
|
||||||
|
> xo-cli server.add host=my.server.net username=root password=secret-password
|
||||||
|
42
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
```
|
||||||
|
> 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
|
||||||
|
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).
|
54
packages/xo-cli/config.js
Normal file
54
packages/xo-cli/config.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
|
var promisify = require('bluebird').promisify
|
||||||
|
|
||||||
|
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 configPath = xdgBasedir.config + '/xo-cli'
|
||||||
|
var configFile = configPath + '/config.json'
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
|
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(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)
|
||||||
|
})
|
||||||
|
}
|
397
packages/xo-cli/index.js
Executable file
397
packages/xo-cli/index.js
Executable file
@ -0,0 +1,397 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
var Bluebird = require('bluebird')
|
||||||
|
Bluebird.longStackTraces()
|
||||||
|
|
||||||
|
var createReadStream = require('fs').createReadStream
|
||||||
|
var createWriteStream = require('fs').createWriteStream
|
||||||
|
var resolveUrl = require('url').resolve
|
||||||
|
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 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')
|
||||||
|
var nicePipe = require('nice-pipe')
|
||||||
|
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').default
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
var config = require('./config')
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
|
function connect () {
|
||||||
|
return config.load().bind({}).then(function (config) {
|
||||||
|
if (!config.server) {
|
||||||
|
throw new Error('no server to connect to!')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.token) {
|
||||||
|
throw new Error('no token available')
|
||||||
|
}
|
||||||
|
|
||||||
|
var xo = new Xo({ url: config.server })
|
||||||
|
|
||||||
|
return xo.open().then(function () {
|
||||||
|
return xo.signIn({ token: config.token })
|
||||||
|
}).then(function () {
|
||||||
|
return xo
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = {}
|
||||||
|
forEach(args, function (arg) {
|
||||||
|
var matches
|
||||||
|
if (!(matches = arg.match(PARAM_RE))) {
|
||||||
|
throw new Error('invalid arg: ' + arg)
|
||||||
|
}
|
||||||
|
var name = matches[1]
|
||||||
|
var value = matches[2]
|
||||||
|
|
||||||
|
if (_startsWith(value, 'json:')) {
|
||||||
|
value = JSON.parse(value.slice(5))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === '@') {
|
||||||
|
params['@'] = value
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === 'true') {
|
||||||
|
value = true
|
||||||
|
} else if (value === 'false') {
|
||||||
|
value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
params[name] = value
|
||||||
|
})
|
||||||
|
|
||||||
|
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, humanFormatOpts),
|
||||||
|
humanFormat(progress.speed, humanFormatOpts),
|
||||||
|
prettyMs(progress.eta * 1e3)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
console.warn('%s @ %s/s',
|
||||||
|
humanFormat(progress.transferred, humanFormatOpts),
|
||||||
|
humanFormat(progress.speed, humanFormatOpts)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function wrap (val) {
|
||||||
|
return function wrappedValue () {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
|
var help = wrap((function (pkg) {
|
||||||
|
return multiline.stripIndent(function () { /*
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
$name --register [<XO-Server URL>] [<username>] [<password>]
|
||||||
|
Registers the XO instance to use.
|
||||||
|
|
||||||
|
$name --unregister
|
||||||
|
Remove stored credentials.
|
||||||
|
|
||||||
|
$name --list-commands [--json] [<pattern>]...
|
||||||
|
Returns the list of available commands on the current XO instance.
|
||||||
|
|
||||||
|
The patterns can be used to filter on command names.
|
||||||
|
|
||||||
|
$name --list-objects [--<property>]… [<property>=<value>]...
|
||||||
|
Returns a list of XO objects.
|
||||||
|
|
||||||
|
--<property>
|
||||||
|
Restricts displayed properties to those listed.
|
||||||
|
|
||||||
|
<property>=<value>
|
||||||
|
Restricted displayed objects to those matching the patterns.
|
||||||
|
|
||||||
|
$name <command> [<name>=<value>]...
|
||||||
|
Executes a command on the current XO instance.
|
||||||
|
|
||||||
|
$name v$version
|
||||||
|
*/ }).replace(/<([^>]+)>|\$(\w+)/g, function (_, arg, key) {
|
||||||
|
if (arg) {
|
||||||
|
return '<' + chalk.yellow(arg) + '>'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key === 'name') {
|
||||||
|
return chalk.bold(pkg[key])
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkg[key]
|
||||||
|
})
|
||||||
|
})(require('./package')))
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
function main (args) {
|
||||||
|
if (!args || !args.length || args[0] === '-h') {
|
||||||
|
return help()
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
exports = module.exports = main
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
exports.help = help
|
||||||
|
|
||||||
|
function register (args) {
|
||||||
|
var xo = new Xo({ url: args[0] })
|
||||||
|
return xo.open().then(function () {
|
||||||
|
return xo.signIn({
|
||||||
|
email: args[1],
|
||||||
|
password: args[2]
|
||||||
|
})
|
||||||
|
}).then(function () {
|
||||||
|
console.log('Successfully logged with', xo.user.email)
|
||||||
|
|
||||||
|
return xo.call('token.create')
|
||||||
|
}).then(function (token) {
|
||||||
|
return config.set({
|
||||||
|
server: args[0],
|
||||||
|
token: token
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
exports.register = register
|
||||||
|
|
||||||
|
function unregister () {
|
||||||
|
return config.unset([
|
||||||
|
'server',
|
||||||
|
'token'
|
||||||
|
])
|
||||||
|
}
|
||||||
|
exports.unregister = unregister
|
||||||
|
|
||||||
|
function listCommands (args) {
|
||||||
|
return connect().then(function getMethodsInfo (xo) {
|
||||||
|
return xo.call('system.getMethodsInfo')
|
||||||
|
}).then(function formatMethodsInfo (methods) {
|
||||||
|
var json = false
|
||||||
|
var patterns = []
|
||||||
|
forEach(args, function (arg) {
|
||||||
|
if (arg === '--json') {
|
||||||
|
json = true
|
||||||
|
} else {
|
||||||
|
patterns.push(arg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (patterns.length) {
|
||||||
|
methods = pick(methods, micromatch(Object.keys(methods), patterns))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json) {
|
||||||
|
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 = []
|
||||||
|
forEach(methods, function (method) {
|
||||||
|
var name = method[0]
|
||||||
|
var info = method[1]
|
||||||
|
str.push(chalk.bold.blue(name))
|
||||||
|
forEach(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('')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
exports.listCommands = listCommands
|
||||||
|
|
||||||
|
function listObjects (args) {
|
||||||
|
var properties = getKeys(extractFlags(args))
|
||||||
|
var filterProperties = properties.length
|
||||||
|
? function (object) {
|
||||||
|
return pick(object, properties)
|
||||||
|
}
|
||||||
|
: identity
|
||||||
|
|
||||||
|
var sieve = args.length ? parseParameters(args) : null
|
||||||
|
|
||||||
|
return connect().then(function getXoObjects (xo) {
|
||||||
|
return xo.call('xo.getAllObjects')
|
||||||
|
}).then(function filterObjects (objects) {
|
||||||
|
objects = filter(objects, sieve)
|
||||||
|
|
||||||
|
const stdout = process.stdout
|
||||||
|
stdout.write('[\n')
|
||||||
|
for (var i = 0, n = objects.length; i < n;) {
|
||||||
|
stdout.write(JSON.stringify(filterProperties(objects[i]), null, 2))
|
||||||
|
stdout.write(++i < n ? ',\n' : '\n')
|
||||||
|
}
|
||||||
|
stdout.write(']')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
exports.listObjects = listObjects
|
||||||
|
|
||||||
|
function call (args) {
|
||||||
|
if (!args.length) {
|
||||||
|
throw new Error('missing command name')
|
||||||
|
}
|
||||||
|
|
||||||
|
var method = args.shift()
|
||||||
|
var params = parseParameters(args)
|
||||||
|
|
||||||
|
var file = params['@']
|
||||||
|
delete params['@']
|
||||||
|
|
||||||
|
var baseUrl
|
||||||
|
return connect().then(function (xo) {
|
||||||
|
// FIXME: do not use private properties.
|
||||||
|
baseUrl = xo._url.replace(/^ws/, 'http')
|
||||||
|
|
||||||
|
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])
|
||||||
|
var output = createWriteStream(file)
|
||||||
|
|
||||||
|
var progress = progressStream({ time: 1e3 }, printProgress)
|
||||||
|
|
||||||
|
return eventToPromise(nicePipe([
|
||||||
|
got.stream(url).on('response', function (response) {
|
||||||
|
var length = response.headers['content-length']
|
||||||
|
if (length) {
|
||||||
|
progress.length(length)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
progress,
|
||||||
|
output
|
||||||
|
]), 'finish')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key === '$sendTo') {
|
||||||
|
url = resolveUrl(baseUrl, result[key])
|
||||||
|
|
||||||
|
return stat(file).then(function (stats) {
|
||||||
|
var length = stats.size
|
||||||
|
|
||||||
|
var input = nicePipe([
|
||||||
|
createReadStream(file),
|
||||||
|
progressStream({
|
||||||
|
length: length,
|
||||||
|
time: 1e3
|
||||||
|
}, printProgress)
|
||||||
|
])
|
||||||
|
|
||||||
|
return got.post(url, {
|
||||||
|
body: input,
|
||||||
|
headers: {
|
||||||
|
'content-length': length
|
||||||
|
},
|
||||||
|
method: 'POST'
|
||||||
|
}).then(function (response) {
|
||||||
|
return response.body
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
exports.call = call
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
|
if (!module.parent) {
|
||||||
|
require('exec-promise')(exports)
|
||||||
|
}
|
57
packages/xo-cli/package.json
Normal file
57
packages/xo-cli/package.json
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"name": "xo-cli",
|
||||||
|
"version": "0.8.2",
|
||||||
|
"license": "AGPL-3.0",
|
||||||
|
"description": "Basic CLI for Xen-Orchestra",
|
||||||
|
"keywords": [
|
||||||
|
"xo",
|
||||||
|
"xen-orchestra",
|
||||||
|
"xen",
|
||||||
|
"orchestra"
|
||||||
|
],
|
||||||
|
"homepage": "https://github.com/vatesfr/xo-cli",
|
||||||
|
"bugs": "https://github.com/vatesfr/xo-cli/issues",
|
||||||
|
"author": "Julien Fontanet <julien.fontanet@vates.fr>",
|
||||||
|
"preferGlobal": true,
|
||||||
|
"bin": {
|
||||||
|
"xo-cli": "index.js"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"*.js"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/vatesfr/xo-cli"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"bluebird": "^3.4.6",
|
||||||
|
"chalk": "^1.1.1",
|
||||||
|
"event-to-promise": "^0.7.0",
|
||||||
|
"exec-promise": "^0.6.1",
|
||||||
|
"fs-promise": "^1.0.0",
|
||||||
|
"got": "^6.5.0",
|
||||||
|
"human-format": "^0.7.0",
|
||||||
|
"l33teral": "^3.0.2",
|
||||||
|
"lodash": "^4.16.4",
|
||||||
|
"micromatch": "^2.2.0",
|
||||||
|
"mkdirp": "^0.5.0",
|
||||||
|
"multiline": "^1.0.2",
|
||||||
|
"nice-pipe": "0.0.0",
|
||||||
|
"pretty-ms": "^2.1.0",
|
||||||
|
"progress-stream": "^1.1.1",
|
||||||
|
"xdg-basedir": "^2.0.0",
|
||||||
|
"xo-lib": "^0.8.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"standard": "^8.1.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"lint": "standard",
|
||||||
|
"posttest": "npm run lint"
|
||||||
|
},
|
||||||
|
"greenkeeper": {
|
||||||
|
"ignore": [
|
||||||
|
"nice-pipe"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user