Initial commit.

This commit is contained in:
Julien Fontanet 2014-03-24 17:44:06 +01:00
commit b526067eeb
10 changed files with 556 additions and 0 deletions

View File

@ -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

1
packages/xo-cli/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/node_modules/

126
packages/xo-cli/.jshintrc Normal file
View File

@ -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 <julien.fontanet@isonoe.net>
// @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
}
}

20
packages/xo-cli/README.md Normal file
View File

@ -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
```

7
packages/xo-cli/bin/xo-cli Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env node
'use strict';
//====================================================================
require('../')(process.argv.slice(2));

187
packages/xo-cli/cli.js Normal file
View File

@ -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);
};

11
packages/xo-cli/config.js Normal file
View File

@ -0,0 +1,11 @@
'use strict';
//====================================================================
var xdg = require('xdg').basedir;
//====================================================================
var Config = function () {
this.data =
};

View File

@ -0,0 +1,34 @@
{
"name": "xo-cli",
"version": "0.1.0",
"description": "Basic CLI for Xen-Orchestra",
"author": "Julien Fontanet <julien.fontanet@vates.fr>",
"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"
}

32
packages/xo-cli/prompt.js Normal file
View File

@ -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');
};

123
packages/xo-cli/xo.js Normal file
View File

@ -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;