From dac06537e539cf2e7612406f911dcb59a2e34f3e Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Wed, 2 May 2012 11:02:47 +0100 Subject: [PATCH] Added command handling The idea is that the same commands will work on the server or the client, and that the client will be able to remotely run commands on the server. Also includes abstraction of the version number of TW5. --- rabbithole/core/boot.js | 8 +- rabbithole/core/modules/commander.js | 93 +++++++++++++++++++++ rabbithole/core/modules/commands/version.js | 30 +++++++ rabbithole/core/modules/macros/version.js | 2 +- rabbithole/core/modules/startup.js | 15 +++- rabbithole/core/modules/utils.js | 58 +++++++++++++ rabbithole/core/modules/wiki.js | 15 ++++ rabbithole/core/version.txt | 1 + rabbithole/readme.md | 1 + rabbithole/tiddlywiki5.recipe | 2 + rabbithole/tiddlywiki5.template.html | 5 ++ rabbithole/tw5.com/store/HelloThere.tid | 2 +- 12 files changed, 228 insertions(+), 4 deletions(-) create mode 100644 rabbithole/core/modules/commander.js create mode 100644 rabbithole/core/modules/commands/version.js create mode 100644 rabbithole/core/version.txt diff --git a/rabbithole/core/boot.js b/rabbithole/core/boot.js index f58040e16..908f918d9 100644 --- a/rabbithole/core/boot.js +++ b/rabbithole/core/boot.js @@ -35,6 +35,9 @@ if(typeof(window) === "undefined" && !global.$tw) { global.$tw = {isBrowser: false}; } +// Boot information +$tw.boot = {}; + // Modules store registers all the modules the system has seen $tw.modules = $tw.modules || {}; $tw.modules.titles = $tw.modules.titles || {} // hashmap by module title of {fn:, exports:, moduleType:} @@ -523,6 +526,8 @@ var fs = require("fs"), path = require("path"), vm = require("vm"); +$tw.boot.bootPath = path.dirname(module.filename); + /* Load the tiddlers contained in a particular file (and optionally the accompanying .meta file) */ @@ -574,6 +579,7 @@ $tw.modules.execute = function(moduleName,moduleRoot) { module: module, exports: {}, console: console, + process: process, $tw: $tw, require: function(title) { return $tw.modules.execute(title,name); @@ -598,7 +604,7 @@ $tw.modules.execute = function(moduleName,moduleRoot) { } // Load plugins from the plugins directory -$tw.plugins.loadPlugins(path.resolve(path.dirname(module.filename),$tw.config.pluginSubDir)); +$tw.plugins.loadPlugins(path.resolve($tw.boot.bootPath,$tw.config.pluginSubDir)); // End of if(!$tw.isBrowser) } diff --git a/rabbithole/core/modules/commander.js b/rabbithole/core/modules/commander.js new file mode 100644 index 000000000..7f277f803 --- /dev/null +++ b/rabbithole/core/modules/commander.js @@ -0,0 +1,93 @@ +/*\ +title: $:/core/commander.js +type: application/javascript +module-type: global + +The $tw.Commander class is a command interpreter + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +"use strict"; + +/* +Parse a sequence of commands + commandTokens: an array of command string tokens + wiki: reference to the wiki store object + streams: {output:, error:}, each of which has a write(string) method + callback: a callback invoked as callback(err) where err is null if there was no error +*/ +var Commander = function(commandTokens,callback,wiki,streams) { + this.commandTokens = commandTokens; + this.nextToken = 0; + this.callback = callback; + this.wiki = wiki; + this.streams = streams; +}; + +/* +Execute the sequence of commands and invoke a callback on completion +*/ +Commander.prototype.execute = function() { + this.executeNextCommand(); +}; + +/* +Execute the next command in the sequence +*/ +Commander.prototype.executeNextCommand = function() { + // Invoke the callback if there are no more commands + if(this.nextToken >= this.commandTokens.length) { + this.callback(null); + } else { + // Get and check the command token + var commandName = this.commandTokens[this.nextToken++]; + if(commandName.substr(0,2) !== "--") { + this.callback("Missing command"); + } else { + commandName = commandName.substr(2); // Trim off the -- + // Accumulate the parameters to the command + var params = []; + while(this.nextToken < this.commandTokens.length && + this.commandTokens[this.nextToken].substr(0,2) !== "--") { + params.push(this.commandTokens[this.nextToken++]); + } + // Get the command info + var command = $tw.commands[commandName]; + if(!command) { + this.callback("Unknown command: " + commandName); + } else { + if(command.info.synchronous) { + var c = new command.Command(params,this); + c.execute(); + this.executeNextCommand(); + } + } + } + } +}; + +Commander.initCommands = function(moduleType) { + // Install the command modules + moduleType = moduleType || "command"; + $tw.commands = {}; + var modules = $tw.plugins.moduleTypes[moduleType], + n,m,f,c; + if(modules) { + for(n=0; n, minor: , revision: , alpha: , beta: } +*/ +exports.parseVersion = function(versionString) { + versionString = versionString || "0.0.0"; + var components = versionString.split("."), + version = { + major: components[0] ? parseInt(components[0],10) : null, + minor: components[1] ? parseInt(components[1],10) : null, + revision: components[2] ? parseInt(components[2],10) : null + }; + if(components[3]) { + if(components[3].charAt(0) === "a") { + version.alpha = parseInt(components[3].substr(1),10); + } else if(components[3].charAt(0) === "b") { + version.beta = parseInt(components[3].substr(1),10); + } + } + return version; +}; + +exports.getVersionString = function() { + return ($tw.version.major || "0") + "." + + ($tw.version.minor || "0") + "." + + ($tw.version.revision || "0") + + ($tw.version.alpha ? ".a" + $tw.version.alpha : "") + + ($tw.version.beta ? ".b" + $tw.version.beta : ""); +}; + +/* +Extract the version number from the meta tag or from the boot file +*/ + +if($tw.isBrowser) { + +// Browser version +exports.extractVersionInfo = function() { + var metatags = document.getElementsByTagName("meta"); + for(var t=0; t + + + diff --git a/rabbithole/tw5.com/store/HelloThere.tid b/rabbithole/tw5.com/store/HelloThere.tid index bdcdd6fc2..172887855 100644 --- a/rabbithole/tw5.com/store/HelloThere.tid +++ b/rabbithole/tw5.com/store/HelloThere.tid @@ -4,4 +4,4 @@ tags: Introduction Welcome to TiddlyWiki5, a reboot of TiddlyWiki, the venerable, reusable non-linear personal web notebook first released in 2004. It is a complete interactive wiki that can run from a single HTML file in the browser or as a powerful [[node.js application|What is node.js?]]. -TiddlyWiki5 is currently in early beta, which is to say that it is useful but incomplete. You can try out the prototype at http://tiddlywiki.com/tiddlywiki5, get involved in the [[development on GitHub|https://github.com/Jermolene/TiddlyWiki5]] or the discussions on [[the TiddlyWikiDev Google Group|http://groups.google.com/group/TiddlyWikiDev]]. +TiddlyWiki5 is currently at version <> and is under active development, which is to say that it is useful but incomplete. You can try out the prototype at http://tiddlywiki.com/tiddlywiki5, get involved in the [[development on GitHub|https://github.com/Jermolene/TiddlyWiki5]] or the discussions on [[the TiddlyWikiDev Google Group|http://groups.google.com/group/TiddlyWikiDev]].