From: Scott Baker <smbaker@gmail.com> Date: Tue, 8 Jul 2014 04:54:35 +0000 (-0700) Subject: xoslib wip X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=95d6c5cb91712cc881691f1754fc2f77a73003f7;p=plstackapi.git xoslib wip --- diff --git a/planetstack/core/xoslib/dashboards/sliverListTest.html b/planetstack/core/xoslib/dashboards/sliverListTest.html index 7a5b2d4..61c54cf 100644 --- a/planetstack/core/xoslib/dashboards/sliverListTest.html +++ b/planetstack/core/xoslib/dashboards/sliverListTest.html @@ -3,7 +3,6 @@ <script src="{{ STATIC_URL }}/js/underscore-min.js"></script> <script src="{{ STATIC_URL }}/js/backbone-min.js"></script> -<script src="{{ STATIC_URL }}/js/xxbackbone-tastypie.js"></script> <script src="{{ STATIC_URL }}/js/ICanHaz.min.js"></script> <script src="{{ STATIC_URL }}/js/xos-backbone.js"></script> diff --git a/planetstack/core/xoslib/dashboards/xsh.html b/planetstack/core/xoslib/dashboards/xsh.html new file mode 100644 index 0000000..6e5103a --- /dev/null +++ b/planetstack/core/xoslib/dashboards/xsh.html @@ -0,0 +1,21 @@ + <div id="terminal"> + <p class="response">XSH - The XOS Shell</p> + <br /> + <p id="terminal_help1" style="display: none;">type "help" for help</p> + <p id="terminal_help2" style="display: none;">type "tutorial" to start the tutorial</p> + + </div> + <link rel="stylesheet" type="text/css" href="{% static 'shell/opencloud_shell.css' %}" media="all"> + <script src="{{ STATIC_URL }}/js/underscore-min.js"></script> + <script src="{{ STATIC_URL }}/js/backbone-min.js"></script> + <script src="{{ STATIC_URL }}/js/ICanHaz.min.js"></script> + <script src="{{ STATIC_URL }}/js/xos-backbone.js"></script> + <script src="{% static 'xsh/xsh.js' %}"></script> + <script src="{% static 'xsh/object_id.js' %}"></script> + <script src="{% static 'xsh/constants.js' %}"></script> + <script src="{% static 'xsh/utils.js' %}"></script> + <script src="{% static 'xsh/shell_utils.js' %}"></script> + <script src="{% static 'xsh/tokens.js' %}"></script> + + + diff --git a/planetstack/core/xoslib/static/js/sliverListTest.js b/planetstack/core/xoslib/static/js/sliverListTest.js index 2365aa2..59970d8 100644 --- a/planetstack/core/xoslib/static/js/sliverListTest.js +++ b/planetstack/core/xoslib/static/js/sliverListTest.js @@ -110,7 +110,7 @@ window.Router = Backbone.Router.extend({ $(function(){ window.app = window.app || {}; app.router = new Router(); - app.slivers = XOSLib.slivers; //new XOSLib.slivers(); + app.slivers = xos.slivers; //new XOSLib.slivers(); app.list = new ListApp({ el: $("#app"), collection: app.slivers diff --git a/planetstack/core/xoslib/static/js/xos-backbone.js b/planetstack/core/xoslib/static/js/xos-backbone.js index 1633768..c4f1a33 100644 --- a/planetstack/core/xoslib/static/js/xos-backbone.js +++ b/planetstack/core/xoslib/static/js/xos-backbone.js @@ -1,4 +1,5 @@ SLIVER_API = "/plstackapi/slivers/"; +SLICE_API = "/plstackapi/slices/"; XOSModel = Backbone.Model.extend({ /* from backbone-tastypie.js */ @@ -93,6 +94,11 @@ function xoslib() { this.sliverCollection = XOSCollection.extend({ urlRoot: SLIVER_API, model: this.sliver}); this.slivers = new this.sliverCollection(); + + this.slice = XOSModel.extend({ urlRoot: SLICE_API }); + this.sliceCollection = XOSCollection.extend({ urlRoot: SLICE_API, + model: this.slice}); + this.slices = new this.sliceCollection(); }; -XOSLib = new xoslib(); +xos = new xoslib(); diff --git a/planetstack/core/xoslib/static/xsh/constants.js b/planetstack/core/xoslib/static/xsh/constants.js new file mode 100644 index 0000000..97b690a --- /dev/null +++ b/planetstack/core/xoslib/static/xsh/constants.js @@ -0,0 +1,39 @@ +// TryMongo +// +// Copyright (c) 2009 Kyle Banker +// Licensed under the MIT Licence. +// http://www.opensource.org/licenses/mit-license.php + +var DefaultInputHtml = function(stack) { + var linePrompt = ""; + if(stack == 0) { + linePrompt += "<span class='prompt'> ></span>"; + } + else { + for(var i=0; i <= stack; i++) { + linePrompt += "<span class='prompt'>.</span>"; + } + } + return "<div class='terminal_line'>" + + linePrompt + + "<input type='text' class='readLine active' />" + + "</div>"; +} + +var EnterKeyCode = 13; +var UpArrowKeyCode = 38; +var DownArrowKeyCode = 40; + +var PTAG = function(str) { + return '<pre class="terminal_help">' + str + '</pre>'; +} + +var BR = function() { + return "<br/>"; +} + +var JavascriptKeywords = ['abstract', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'double', 'else', 'enum', 'export', 'extends', 'false', 'final', 'finally', 'float', 'for', 'function', 'goto', 'if', 'implements', 'import', 'in', 'instanceof', 'int', 'interface', 'long', 'native', 'new', 'null', 'package', 'private', 'protected', 'public', 'return', 'short', 'static', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient', 'true', 'try', 'typeof', 'var', 'void', 'volatile', 'while', 'with', 'alert', 'date', 'eval']; + +var JavascriptClassNames = ['Array', 'String', 'Object'] + +var MongoKeywords = ['help','tutorial','next','back','t0','t1','t2','t3','t4']; diff --git a/planetstack/core/xoslib/static/xsh/object_id.js b/planetstack/core/xoslib/static/xsh/object_id.js new file mode 100644 index 0000000..15cbbb9 --- /dev/null +++ b/planetstack/core/xoslib/static/xsh/object_id.js @@ -0,0 +1,12 @@ +var ObjectIdCounter = 0; + +var ObjectId = function() { + this.counter = (ObjectIdCounter += 1); + this.str = this.counter; + this.initialize(); + return this.counter; +}; + +ObjectId.prototype.initialize = function() { + return this.counter; +} diff --git a/planetstack/core/xoslib/static/xsh/shell_utils.js b/planetstack/core/xoslib/static/xsh/shell_utils.js new file mode 100644 index 0000000..8ed5f4f --- /dev/null +++ b/planetstack/core/xoslib/static/xsh/shell_utils.js @@ -0,0 +1,548 @@ +DB = function() { +} + +print = function(msg) { + //console.log(msg); +} + + +friendlyEqual = function( a , b ){ + if ( a == b ) + return true; + + if ( tojson( a ) == tojson( b ) ) + return true; + + return false; +} + + +doassert = function( msg ){ + print( "assert: " + msg ); + throw msg; +} + +assert = function( b , msg ){ + if ( assert._debug && msg ) print( "in assert for: " + msg ); + + if ( b ) + return; + + doassert( "assert failed : " + msg ); +} + +assert.eq = function( a , b , msg ){ + if ( assert._debug && msg ) print( "in assert for: " + msg ); + + if ( a == b ) + return; + + if ( ( a != null && b != null ) && friendlyEqual( a , b ) ) + return; + + doassert( "[" + tojson( a ) + "] != [" + tojson( b ) + "] are not equal : " + msg ); +} + +assert.neq = function( a , b , msg ){ + if ( assert._debug && msg ) print( "in assert for: " + msg ); + if ( a != b ) + return; + + doassert( "[" + a + "] != [" + b + "] are equal : " + msg ); +} + +assert.soon = function( f, msg, timeout, interval ) { + if ( assert._debug && msg ) print( "in assert for: " + msg ); + + var start = new Date(); + timeout = timeout || 30000; + interval = interval || 200; + var last; + while( 1 ) { + + if ( typeof( f ) == "string" ){ + if ( eval( f ) ) + return; + } + else { + if ( f() ) + return; + } + + if ( ( new Date() ).getTime() - start.getTime() > timeout ) + doassert( "assert.soon failed: " + f + ", msg:" + msg ); + sleep( interval ); + } +} + +assert.throws = function( func , params , msg ){ + if ( assert._debug && msg ) print( "in assert for: " + msg ); + try { + func.apply( null , params ); + } + catch ( e ){ + return e; + } + + doassert( "did not throw exception: " + msg ); +} + +assert.commandWorked = function( res , msg ){ + if ( assert._debug && msg ) print( "in assert for: " + msg ); + + if ( res.ok == 1 ) + return; + + doassert( "command failed: " + tojson( res ) + " : " + msg ); +} + +assert.commandFailed = function( res , msg ){ + if ( assert._debug && msg ) print( "in assert for: " + msg ); + + if ( res.ok == 0 ) + return; + + doassert( "command worked when it should have failed: " + tojson( res ) + " : " + msg ); +} + +assert.isnull = function( what , msg ){ + if ( assert._debug && msg ) print( "in assert for: " + msg ); + + if ( what == null ) + return; + + doassert( "supposed to null (" + ( msg || "" ) + ") was: " + tojson( what ) ); +} + +assert.lt = function( a , b , msg ){ + if ( assert._debug && msg ) print( "in assert for: " + msg ); + + if ( a < b ) + return; + doassert( a + " is not less than " + b + " : " + msg ); +} + +assert.gt = function( a , b , msg ){ + if ( assert._debug && msg ) print( "in assert for: " + msg ); + + if ( a > b ) + return; + doassert( a + " is not greater than " + b + " : " + msg ); +} + +Object.extend = function( dst , src , deep ){ + for ( var k in src ){ + var v = src[k]; + if ( deep && typeof(v) == "object" ){ + v = Object.extend( typeof ( v.length ) == "number" ? [] : {} , v , true ); + } + dst[k] = v; + } + return dst; +} + +argumentsToArray = function( a ){ + var arr = []; + for ( var i=0; i<a.length; i++ ) + arr[i] = a[i]; + return arr; +} + +isString = function( x ){ + return typeof( x ) == "string"; +} + +isNumber = function(x){ + return typeof( x ) == "number"; +} + +isObject = function( x ){ + return typeof( x ) == "object"; +} + +String.prototype.trim = function() { + return this.replace(/^\s+|\s+$/g,""); +} +String.prototype.ltrim = function() { + return this.replace(/^\s+/,""); +} +String.prototype.rtrim = function() { + return this.replace(/\s+$/,""); +} + +Date.timeFunc = function( theFunc , numTimes ){ + + var start = new Date(); + + numTimes = numTimes || 1; + for ( var i=0; i<numTimes; i++ ){ + theFunc.apply( null , argumentsToArray( arguments ).slice( 2 ) ); + } + + return (new Date()).getTime() - start.getTime(); +} + +Date.prototype.tojson = function(){ + return "\"" + this.toString() + "\""; +} + +RegExp.prototype.tojson = RegExp.prototype.toString; + +Array.contains = function( a , x ){ + for ( var i=0; i<a.length; i++ ){ + if ( a[i] == x ) + return true; + } + return false; +} + +Array.unique = function( a ){ + var u = []; + for ( var i=0; i<a.length; i++){ + var o = a[i]; + if ( ! Array.contains( u , o ) ){ + u.push( o ); + } + } + return u; +} + +Array.shuffle = function( arr ){ + for ( var i=0; i<arr.length-1; i++ ){ + var pos = i+Math.floor(Math.random()*(arr.length-i)); + var save = arr[i]; + arr[i] = arr[pos]; + arr[pos] = save; + } + return arr; +} + + +Array.tojson = function( a , indent , x , html){ + if (!indent) + indent = ""; + var spacer = ""; + if(html) { + spacer = "<br/>"; + indent = " " + } + + var s = spacer + "[ " + spacer; + indent += " "; + for ( var i=0; i<a.length; i++){ + s += indent + tojson( a[i], indent ); + if ( i < a.length - 1 ){ + s += "," + spacer; + } + } + if ( a.length == 0 ) { + s += indent; + } + + indent = indent.substring(1); + s += spacer + " "+"]"; + return s; +} + +Array.fetchRefs = function( arr , coll ){ + var n = []; + for ( var i=0; i<arr.length; i ++){ + var z = arr[i]; + if ( coll && coll != z.getCollection() ) + continue; + n.push( z.fetch() ); + } + + return n; +} + +Array.sum = function( arr ){ + if ( arr.length == 0 ) + return null; + var s = arr[0]; + for ( var i=1; i<arr.length; i++ ) + s += arr[i]; + return s; +} + +Array.avg = function( arr ){ + if ( arr.length == 0 ) + return null; + return Array.sum( arr ) / arr.length; +} + +Array.stdDev = function( arr ){ + var avg = Array.avg( arr ); + var sum = 0; + + for ( var i=0; i<arr.length; i++ ){ + sum += Math.pow( arr[i] - avg , 2 ); + } + + return Math.sqrt( sum / arr.length ); +} + +if ( ! ObjectId.prototype ) + ObjectId.prototype = {} + +ObjectId.prototype.toString = function(){ + return this.str; +} + +ObjectId.prototype.tojson = function(){ + return "ObjectId(\"" + this.str + "\")"; +} + +ObjectId.prototype.isObjectId = true; + +tojson = function( x, indent , nolint , html){ + if ( x == null ) + return "null"; + + if ( x == undefined ) + return "undefined"; + + if (!indent) + indent = ""; + + switch ( typeof x ){ + + case "string": { + var s = "\""; + for ( var i=0; i<x.length; i++ ){ + if ( x[i] == '"' ){ + s += "\\\""; + } + else + s += x[i]; + } + return s + "\""; + } + + case "number": + case "boolean": + return "" + x; + + case "object":{ + var s = tojsonObject( x, indent , nolint , html); + if ( ( nolint == null || nolint == true ) && s.length < 80 && ( indent == null || indent.length == 0 ) ){ + s = s.replace( /[\s\r\n ]+/gm , " " ); + } + return s; + } + + case "function": + return x.toString(); + + + default: + throw "tojson can't handle type " + ( typeof x ); + } + +} + +tojsonObject = function( x, indent , nolint , html){ + if(html) { + var lineEnding = "<br/>"; + var tabSpace = " "; + } + else { + var lineEnding = nolint ? " " : "\n"; + var tabSpace = nolint ? "" : "\t"; + } + + assert.eq( ( typeof x ) , "object" , "tojsonObject needs object, not [" + ( typeof x ) + "]" ); + + if (!indent) + indent = ""; + + if ( x.hasOwnProperty("__str__")) { + return x.__str__(); + } + + if ( typeof( x.tojson ) == "function" && x.tojson != tojson ) { + return x.tojson(indent,nolint,html); + } + + if ( typeof( x.constructor.tojson ) == "function" && x.constructor.tojson != tojson ) { + return x.constructor.tojson( x, indent , nolint, html ); + } + + if ( x.toString() == "[object MaxKey]" ) + return "{ $maxKey : 1 }"; + if ( x.toString() == "[object MinKey]" ) + return "{ $minKey : 1 }"; + + var s = "{" + lineEnding; + + // push one level of indent + indent += tabSpace; + + var total = 0; + for ( var k in x ) total++; + if ( total == 0 ) { + s += indent + lineEnding; + } + + var keys = x; + if ( typeof( x._simpleKeys ) == "function" ) + keys = x._simpleKeys(); + var num = 1; + for ( var k in keys ){ + var val = x[k]; + + s += indent + "\"" + k + "\" : " + tojson( val, indent , nolint ); + if (num != total) { + s += ","; + num++; + } + s += lineEnding; + } + + // pop one level of indent + indent = indent.substring(1); + return s + indent + "}"; +} + +shellPrint = function( x ){ + it = x; + if ( x != undefined ) + shellPrintHelper( x ); +} + +printjson = function(x){ + print( tojson( x ) ); +} + +shellPrintHelper = function( x ){ + + if ( typeof( x ) == "undefined" ){ + + return; + } + + if ( x == null ){ + print( "null" ); + return; + } + + if ( typeof x != "object" ) + return print( x ); + + var p = x.shellPrint; + if ( typeof p == "function" ) + return x.shellPrint(); + + var p = x.tojson; + if ( typeof p == "function" ) + print( x.tojson() ); + else + print( tojson( x ) ); +} + +shellHelper = function( command , rest , shouldPrint ){ + command = command.trim(); + var args = rest.trim().replace(/;$/,"").split( "\s+" ); + + if ( ! shellHelper[command] ) + throw "no command [" + command + "]"; + + var res = shellHelper[command].apply( null , args ); + if ( shouldPrint ){ + shellPrintHelper( res ); + } + return res; +} + +help = shellHelper.help = function(){ + print( "HELP" ); + print( "\t" + "show dbs show database names"); + print( "\t" + "show collections show collections in current database"); + print( "\t" + "show users show users in current database"); + print( "\t" + "show profile show most recent system.profile entries with time >= 1ms"); + print( "\t" + "use <db name> set curent database to <db name>" ); + print( "\t" + "db.help() help on DB methods"); + print( "\t" + "db.foo.help() help on collection methods"); + print( "\t" + "db.foo.find() list objects in collection foo" ); + print( "\t" + "db.foo.find( { a : 1 } ) list objects in foo where a == 1" ); + print( "\t" + "it result of the last line evaluated; use to further iterate"); +} + +if ( typeof( Map ) == "undefined" ){ + Map = function(){ + this._data = {}; + } +} + +Map.hash = function( val ){ + if ( ! val ) + return val; + + switch ( typeof( val ) ){ + case 'string': + case 'number': + case 'date': + return val.toString(); + case 'object': + case 'array': + var s = ""; + for ( var k in val ){ + s += k + val[k]; + } + return s; + } + + throw "can't hash : " + typeof( val ); +} + +Map.prototype.put = function( key , value ){ + var o = this._get( key ); + var old = o.value; + o.value = value; + return old; +} + +Map.prototype.get = function( key ){ + return this._get( key ).value; +} + +Map.prototype._get = function( key ){ + var h = Map.hash( key ); + var a = this._data[h]; + if ( ! a ){ + a = []; + this._data[h] = a; + } + + for ( var i=0; i<a.length; i++ ){ + if ( friendlyEqual( key , a[i].key ) ){ + return a[i]; + } + } + var o = { key : key , value : null }; + a.push( o ); + return o; +} + +Map.prototype.values = function(){ + var all = []; + for ( var k in this._data ){ + this._data[k].forEach( function(z){ all.push( z.value ); } ); + } + return all; +} + +if ( typeof( gc ) == "undefined" ){ + gc = function(){ + } +} + + +Math.sigFig = function( x , N ){ + if ( ! N ){ + N = 3; + } + var p = Math.pow( 10, N - Math.ceil( Math.log( Math.abs(x) ) / Math.log( 10 )) ); + return Math.round(x*p)/p; +} + diff --git a/planetstack/core/xoslib/static/xsh/tokens.js b/planetstack/core/xoslib/static/xsh/tokens.js new file mode 100644 index 0000000..49c246e --- /dev/null +++ b/planetstack/core/xoslib/static/xsh/tokens.js @@ -0,0 +1,268 @@ +// tokens.js +// 2009-05-17 + +// (c) 2006 Douglas Crockford + +// Produce an array of simple token objects from a string. +// A simple token object contains these members: +// type: 'name', 'string', 'number', 'operator' +// value: string or number value of the token +// from: index of first character of the token +// to: index of the last character + 1 + +// Comments of the // type are ignored. + +// Operators are by default single characters. Multicharacter +// operators can be made by supplying a string of prefix and +// suffix characters. +// characters. For example, +// '<>+-&', '=>&:' +// will match any of these: +// <= >> >>> <> >= +: -: &: &&: && + + + +String.prototype.tokens = function (prefix, suffix) { + var c; // The current character. + var from; // The index of the start of the token. + var i = 0; // The index of the current character. + var length = this.length; + var n; // The number value. + var q; // The quote character. + var str; // The string value. + + var result = []; // An array to hold the results. + + var make = function (type, value) { + +// Make a token object. + + return { + type: type, + value: value, + from: from, + to: i + }; + }; + +// Begin tokenization. If the source string is empty, return nothing. + + if (!this) { + return; + } + +// If prefix and suffix strings are not provided, supply defaults. + + if (typeof prefix !== 'string') { + prefix = '<>+-&'; + } + if (typeof suffix !== 'string') { + suffix = '=>&:'; + } + + +// Loop through this text, one character at a time. + + c = this.charAt(i); + while (c) { + from = i; + +// Ignore whitespace. + + if (c <= ' ') { + i += 1; + c = this.charAt(i); + +// name. + + } else if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') { + str = c; + i += 1; + for (;;) { + c = this.charAt(i); + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || c === '_') { + str += c; + i += 1; + } else { + break; + } + } + result.push(make('name', str)); + +// number. + +// A number cannot start with a decimal point. It must start with a digit, +// possibly '0'. + + } else if (c >= '0' && c <= '9') { + str = c; + i += 1; + +// Look for more digits. + + for (;;) { + c = this.charAt(i); + if (c < '0' || c > '9') { + break; + } + i += 1; + str += c; + } + +// Look for a decimal fraction part. + + if (c === '.') { + i += 1; + str += c; + for (;;) { + c = this.charAt(i); + if (c < '0' || c > '9') { + break; + } + i += 1; + str += c; + } + } + +// Look for an exponent part. + + if (c === 'e' || c === 'E') { + i += 1; + str += c; + c = this.charAt(i); + if (c === '-' || c === '+') { + i += 1; + str += c; + c = this.charAt(i); + } + if (c < '0' || c > '9') { + make('number', str).error("Bad exponent"); + } + do { + i += 1; + str += c; + c = this.charAt(i); + } while (c >= '0' && c <= '9'); + } + +// Make sure the next character is not a letter. + + if (c >= 'a' && c <= 'z') { + str += c; + i += 1; + make('number', str).error("Bad number"); + } + +// Convert the string value to a number. If it is finite, then it is a good +// token. + + n = +str; + if (isFinite(n)) { + result.push(make('number', n)); + } else { + make('number', str).error("Bad number"); + } + +// string + + } else if (c === '\'' || c === '"') { + str = ''; + q = c; + i += 1; + for (;;) { + c = this.charAt(i); + if (c < ' ') { + make('string', str).error(c === '\n' || c === '\r' || c === '' ? + "Unterminated string." : + "Control character in string.", make('', str)); + } + +// Look for the closing quote. + + if (c === q) { + break; + } + +// Look for escapement. + + if (c === '\\') { + i += 1; + if (i >= length) { + make('string', str).error("Unterminated string"); + } + c = this.charAt(i); + switch (c) { + case 'b': + c = '\b'; + break; + case 'f': + c = '\f'; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'u': + if (i >= length) { + make('string', str).error("Unterminated string"); + } + c = parseInt(this.substr(i + 1, 4), 16); + if (!isFinite(c) || c < 0) { + make('string', str).error("Unterminated string"); + } + c = String.fromCharCode(c); + i += 4; + break; + } + } + str += c; + i += 1; + } + i += 1; + result.push(make('string', str)); + c = this.charAt(i); + +// comment. + + } else if (c === '/' && this.charAt(i + 1) === '/') { + i += 1; + for (;;) { + c = this.charAt(i); + if (c === '\n' || c === '\r' || c === '') { + break; + } + i += 1; + } + +// combining + + } else if (prefix.indexOf(c) >= 0) { + str = c; + i += 1; + while (i < length) { + c = this.charAt(i); + if (suffix.indexOf(c) < 0) { + break; + } + str += c; + i += 1; + } + result.push(make('operator', str)); + +// single-character operator + + } else { + i += 1; + result.push(make('operator', c)); + c = this.charAt(i); + } + } + return result; +}; + diff --git a/planetstack/core/xoslib/static/xsh/utils.js b/planetstack/core/xoslib/static/xsh/utils.js new file mode 100644 index 0000000..1ded27e --- /dev/null +++ b/planetstack/core/xoslib/static/xsh/utils.js @@ -0,0 +1,81 @@ +// Try Mongo +// +// Copyright (c) 2009 Kyle Banker +// Licensed under the MIT licence. +// http://www.opensource.org/licenses/mit-license.php + +// extending array like this is breaking datatables + +/*Array.prototype.include = function(value) { + for(var i=0; i < this.length; i++) { + if(this[i] == value) { + return this[i]; + } + } + return false; +}; + +Array.prototype.empty = function() { + return (this.length == 0); +};*/ + +function ArrayInclude(arr,value) { + for(var i=0; i < arr.length; i++) { + if(arr[i] == value) { + return arr[i]; + } + } + return false; +}; + +Function.prototype.bind = function() { + var __method = this, object = arguments[0], args = []; + + for(i = 1; i < arguments.length; i++) { + args.push(arguments[i]); + } + + return function() { + return __method.apply(object, args); + }; +}; + +String.prototype.trim = function() { + return this.replace(/^\s+|\s+$/g,""); +}; + +// Prints javascript types as readable strings. +Inspect = function(obj) { + if(typeof(obj) != 'object') { + return obj; + } + + else if (obj instanceof Array) { + var objRep = []; + for(var prop in obj) { + if(obj.hasOwnProperty(prop)) { + objRep.push(obj[prop]); + } + } + return '[' + objRep.join(', ') + ']'; + } + + else { + var objRep = []; + for(var prop in obj) { + if(obj.hasOwnProperty(prop)) { + objRep.push(prop + ': ' + ((typeof(obj[prop]) == 'object') ? Inspect(obj[prop]) : obj[prop])); + } + } + return '{' + objRep.join(', ') + '}'; + } +}; + +// Prints an array of javascript objects. +CollectionInspect = function(coll) { + var str = ''; + for(var i=0; i<coll.length; i++) { + str += Inspect(coll[i]) + '<br />'; + } + return str; +}; diff --git a/planetstack/core/xoslib/static/xsh/xsh.js b/planetstack/core/xoslib/static/xsh/xsh.js new file mode 100644 index 0000000..c2073e4 --- /dev/null +++ b/planetstack/core/xoslib/static/xsh/xsh.js @@ -0,0 +1,405 @@ +// TryMongo +// +// Copyright (c) 2009 Kyle Banker +// Licensed under the MIT Licence. +// http://www.opensource.org/licenses/mit-license.php + +// Readline class to handle line input. +var ReadLine = function(options) { + this.options = options || {}; + this.htmlForInput = this.options.htmlForInput; + this.inputHandler = this.options.handler || this.mockHandler; + this.scoper = this.options.scoper; + this.terminal = $(this.options.terminalId || "#terminal"); + this.lineClass = this.options.lineClass || '.readLine'; + this.history = []; + this.historyPtr = 0; + + this.initialize(); +}; + +ReadLine.prototype = { + + initialize: function() { + this.addInputLine(); + }, + + // Enter a new input line with proper behavior. + addInputLine: function(stackLevel) { + stackLevel = stackLevel || 0; + this.terminal.append(this.htmlForInput(stackLevel)); + var ctx = this; + ctx.activeLine = $(this.lineClass + '.active'); + + // Bind key events for entering and navigting history. + ctx.activeLine.bind("keydown", function(ev) { + switch (ev.keyCode) { + case EnterKeyCode: + ctx.processInput(this.value); + break; + case UpArrowKeyCode: + ctx.getCommand('previous'); + break; + case DownArrowKeyCode: + ctx.getCommand('next'); + break; + } + }); + + this.activeLine.focus(); + }, + + // Returns the 'next' or 'previous' command in this history. + getCommand: function(direction) { + if(this.history.length === 0) { + return; + } + this.adjustHistoryPointer(direction); + this.activeLine[0].value = this.history[this.historyPtr]; + $(this.activeLine[0]).focus(); + //this.activeLine[0].value = this.activeLine[0].value; + }, + + // Moves the history pointer to the 'next' or 'previous' position. + adjustHistoryPointer: function(direction) { + if(direction == 'previous') { + if(this.historyPtr - 1 >= 0) { + this.historyPtr -= 1; + } + } + else { + if(this.historyPtr + 1 < this.history.length) { + this.historyPtr += 1; + } + } + }, + + // Return the handler's response. + processInput: function(value) { + var response = this.inputHandler.apply(this.scoper, [value]); + this.insertResponse(response.result); + + // Save to the command history... + if((lineValue = value.trim()) !== "") { + this.history.push(lineValue); + this.historyPtr = this.history.length; + } + + // deactivate the line... + this.activeLine.value = ""; + this.activeLine.attr({disabled: true}); + this.activeLine.removeClass('active'); + + // and add add a new command line. + this.addInputLine(response.stack); + }, + + insertResponse: function(response) { + if((response.length < 1) || (response=='"donotprintme"') || (response=='donotprintme')) { + this.activeLine.parent().append("<p class='response'></p>"); + } + else { + this.activeLine.parent().append("<p class='response'>" + response + "</p>"); + } + }, + + // Simply return the entered string if the user hasn't specified a smarter handler. + mockHandler: function(inputString) { + return function() { + this._process = function() { return inputString; }; + }; + } +}; + +var MongoHandler = function() { + this._currentCommand = ""; + this._rawCommand = ""; + this._commandStack = 0; + this._tutorialPtr = 0; + this._tutorialMax = 4; + + this._mongo = {}; + this._mongo.test = []; + this.collections = []; +}; + +MongoHandler.prototype = { + + _process: function(inputString, errorCheck) { + this._rawCommand += ' ' + inputString; + + try { + inputString += ' '; // fixes certain bugs with the tokenizer. + var tokens = inputString.tokens(); + var mongoFunc = this._getCommand(tokens); + if(this._commandStack === 0 && inputString.match(/^\s*$/)) { + return {stack: 0, result: ''}; + } + else if(this._commandStack === 0 && mongoFunc) { + this._resetCurrentCommand(); + return {stack: 0, result: mongoFunc.apply(this, [tokens])}; + } + else { + return this._evaluator(tokens); + } + } + + catch(err) { + this._resetCurrentCommand(); + console.trace(); + return {stack: 0, result: "JS Error: " + err}; + } + }, + + // Calls eval on the input string when ready. + _evaluator: function(tokens) { + isAssignment = tokens.length>=2 && tokens[0].type=="name" && tokens[1].type=="operator" && tokens[1].value=="="; + + this._currentCommand += " " + this._massageTokens(tokens); + if(this._shouldEvaluateCommand(tokens)) { + print = this.print; + + // So this eval statement is the heart of the REPL. + var result = eval(this._currentCommand.trim()); + if(result === undefined) { + throw('result is undefined'); + } else if (typeof(result) === 'function') { + throw('result is a function. did you mean to call it?'); + } else { + result = $htmlFormat(result); + } + this._resetCurrentCommand(); + if (isAssignment) { + return {stack: this._commandStack, result: ""}; + } else { + return {stack: this._commandStack, result: result}; + } + } + + else { + return {stack: this._commandStack, result: ""}; + } + }, + + _resetCurrentCommand: function() { + this._currentCommand = ''; + this._rawCommand = ''; + }, + + // Evaluate only when we've exited any blocks. + _shouldEvaluateCommand: function(tokens) { + for(var i=0; i < tokens.length; i++) { + var token = tokens[i]; + if(token.type == 'operator') { + if(token.value == '(' || token.value == '{') { + this._commandStack += 1; + } + else if(token.value == ')' || token.value == '}') { + this._commandStack -= 1; + } + } + } + + if(this._commandStack === 0) { + return true; + } + else { + return false; + } + }, + + _massageTokens: function(tokens) { + for(var i=0; i < tokens.length; i++) { + if(tokens[i].type == 'name') { + if(tokens[i].value == 'var') { + tokens[i].value = ''; + } + } + } + return this._collectTokens(tokens); + }, + + // Collects tokens into a string, placing spaces between variables. + // This methods is called after we scope the vars. + _collectTokens: function(tokens) { + var result = ""; + for(var i=0; i < tokens.length; i++) { + if(tokens[i].type == "name" && tokens[i+1] && tokens[i+1].type == 'name') { + result += tokens[i].value + ' '; + } + else if (tokens[i].type == 'string') { + result += "'" + tokens[i].value + "'"; + } + else { + result += tokens[i].value; + } + } + return result; + }, + + // print output to the screen, e.g., in a loop + // TODO: remove dependency here + print: function() { + $('.readLine.active').parent().append('<p>' + JSON.stringify(arguments[0]) + '</p>'); + return "donotprintme"; + }, + + /* MongoDB */ + /* ________________________________________ */ + + // help command + _help: function() { + return PTAG('HELP') + + PTAG('xos list xos API object types') + + PTAG('xos.slices list methods to can call on slices') + + PTAG('xos.slices.all() get all slices') + + PTAG('xos.slices.filter({key: "value"}) filter using dictionary') + + PTAG('xos.slices.get({key: "value"}) get using dictionary') + + }, + + _tutorial: function() { + this._tutorialPtr = 0; + return PTAG("This is a self-guided tutorial on the xos shell.") + + PTAG("The tutorial is simple, more or less a few basic commands to try.") + + PTAG("To go directly to any part tutorial, enter one of the commands t0, t1, t2...t10") + + PTAG("Otherwise, use 'next' and 'back'. Start by typing 'next' and pressing enter."); + }, + + // go to the next step in the tutorial. + _next: function() { + if(this._tutorialPtr < this._tutorialMax) { + return this['_t' + (this._tutorialPtr + 1)](); + } + else { + return "You've reached the end of the tutorial. To go to the beginning, type 'tutorial'"; + } + }, + + // go to the previous step in the tutorial. + _back: function() { + if(this._tutorialPtr > 1) { + return this['_t' + (this._tutorialPtr - 1)](); + } + else { + return this._tutorial(); + } + }, + + _t1: function() { + this._tutorialPtr = 1; + return PTAG('1. JavaScript Shell') + + PTAG('The first thing to notice is that the MongoDB shell is JavaScript-based.') + + PTAG('So you can do things like:') + + PTAG(' a = 5; ') + + PTAG(' a * 10; ') + + PTAG(' print(a); ') + + PTAG(" for(i=0; i<10; i++) { print('hello'); }; ") + + PTAG("Try a few JS commands; when you're ready to move on, enter 'next'"); + + }, + + _t2: function() { + this._tutorialPtr = 2; + return PTAG('2. The API is asynchronous') + + PTAG('Try these:') + + PTAG(' xos.slices.fetch();') + + PTAG(' // wait a second or two...') + + PTAG(' xos.slices.objects();'); + + }, + + _t3: function() { + this._tutorialPtr = 3; + return PTAG('3. Filter some objects') + + PTAG('Try these:'); + + }, + + _t4: function() { + this._tutorialPtr = 4; + return PTAG('4. Available xos objects and methods') + + PTAG('Try these:') + + PTAG(' xos;') + + PTAG(' xos.slices;'); + + }, + + _getCommand: function(tokens) { + if(tokens[0] && ArrayInclude(MongoKeywords,(tokens[0].value + '').toLowerCase())) { + switch(tokens[0].value.toLowerCase()) { + case 'help': + return this._help; + + case 'tutorial': + return this._tutorial; + case 'next': + return this._next; + case 'back': + return this._back; + case 't0': + return this._tutorial; + case 't1': + return this._t1; + case 't2': + return this._t2; + case 't3': + return this._t3; + case 't4': + return this._t4; + } + } + } +}; + +function replaceAll(find, replace, str) { + return str.replace(new RegExp(find, 'g'), replace); +} + +/* stackoverflow: http://stackoverflow.com/questions/4810841/how-can-i-pretty-print-json-using-javascript */ +function syntaxHighlight(json) { + if ( json.hasOwnProperty("__str__")) { + return syntaxHighlight(json.__str__()); + } + if (typeof json != 'string') { + json = JSON.stringify(json, undefined, "\t"); + } + json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); + return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) { + var cls = 'terminal_number'; + if (/^"/.test(match)) { + if (/:$/.test(match)) { + cls = 'terminal_key'; + } else { + cls = 'terminal_string'; + } + } else if (/true|false/.test(match)) { + cls = 'terminal_boolean'; + } else if (/null/.test(match)) { + cls = 'terminal_null'; + } + return '<span class="' + cls + '">' + match + '</span>'; + }); +} + +$htmlFormat = function(obj) { + //JSON.stringify(obj,undefined,2) + result=replaceAll("\t"," ",replaceAll("\n","<br>",syntaxHighlight(obj))); //tojson(obj, ' ', ' ', true); + return result; +} + +function startTerminal() { + var mongo = new MongoHandler(); + var terminal = new ReadLine({htmlForInput: DefaultInputHtml, + handler: mongo._process, + scoper: mongo}); + $("#terminal_help1").show(); + $("#terminal_help2").show(); + $("#terminal_wait").hide(); + + $("#terminal").bind('click', function() { $(".readLine.active").focus(); }); +}; + +$(document).ready(function() { + startTerminal(); +}); diff --git a/planetstack/core/xoslib/up.sh b/planetstack/core/xoslib/up.sh index 1121892..bc2d469 100755 --- a/planetstack/core/xoslib/up.sh +++ b/planetstack/core/xoslib/up.sh @@ -1,3 +1,4 @@ scp static/js/*.js princeton_planetstack@node43.princeton.vicci.org:/opt/planetstack/core/xoslib/static/js/ scp templates/mustache/*.mustache princeton_planetstack@node43.princeton.vicci.org:/opt/planetstack/core/xoslib/templates/mustache/ +scp static/xsh/*.js princeton_planetstack@node43.princeton.vicci.org:/opt/planetstack/core/xoslib/static/xsh/ scp dashboards/*.html princeton_planetstack@node43.princeton.vicci.org:/opt/planetstack/templates/admin/dashboard/