diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/plugins/contrib.mdwn | 13 | ||||
-rw-r--r-- | doc/plugins/write.mdwn | 39 | ||||
-rw-r--r-- | doc/plugins/write/external.mdwn | 88 | ||||
-rw-r--r-- | doc/todo/support_for_plugins_written_in_other_languages.mdwn | 43 | ||||
-rw-r--r-- | doc/usage.mdwn | 7 |
5 files changed, 146 insertions, 44 deletions
diff --git a/doc/plugins/contrib.mdwn b/doc/plugins/contrib.mdwn index dc8b90771..abdf1bd4e 100644 --- a/doc/plugins/contrib.mdwn +++ b/doc/plugins/contrib.mdwn @@ -6,10 +6,10 @@ rootpage="plugins/contrib" postformtext="Add a new plugin named:" show=0]] # Installing third party plugins -Plugins are perl modules and should be installed somewhere in the perl -module search path. See the @INC list at the end of the output of `perl -V` -for a list of the directories in that path. All plugins are in the -IkiWiki::Plugin namespace, so they go in a IkiWiki/Plugin subdirectory +Most ikiwiki plugins are perl modules and should be installed somewhere in +the perl module search path. See the @INC list at the end of the output of +`perl -V` for a list of the directories in that path. All plugins are in +the IkiWiki::Plugin namespace, so they go in a IkiWiki/Plugin subdirectory inside the perl search path. For example, if your perl looks in `/usr/local/lib/site_perl` for modules, you can locally install ikiwiki plugins to `/usr/local/lib/site_perl/IkiWiki/Plugin` @@ -17,3 +17,8 @@ plugins to `/usr/local/lib/site_perl/IkiWiki/Plugin` You can use the `libdir` configuration option to add a directory to the search path. For example, if you set `libdir` to `/home/you/.ikiwiki/`, then ikiwiki will look for plugins in `/home/you/.ikiwiki/IkiWiki/Plugins`. + +Ikiwiki also supports plugins that are external programs. These are +typically written in some other language than perl. Ikiwiki searches for +these in /usr/lib/ikiwiki/plugins by default. If `libdir` is set, it will +also look in that directory, for example in `/home/you/.ikiwiki/plugins`. diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index 416f1b86e..016746abb 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -1,8 +1,26 @@ -ikiwiki [[plugins]] are written in perl. Each plugin is a perl module, in -the `IkiWiki::Plugin` namespace. The name of the plugin is typically in -lowercase, such as `IkiWiki::Plugin::inline`. Ikiwiki includes a -`IkiWiki::Plugin::skeleton` that can be fleshed out to make a useful -plugin. `IkiWiki::Plugin::pagecount` is another simple example. +Most ikiwiki [[plugins]] are written in perl, like ikiwiki. This gives the +plugin full access to ikiwiki's internals, and is the most efficient. +However, plugins can actually be written in any language that supports XML +RPC. These are called [[external]] plugins. + +A plugin written in perl is a perl module, in the `IkiWiki::Plugin` +namespace. The name of the plugin is typically in lowercase, such as +`IkiWiki::Plugin::inline`. Ikiwiki includes a `IkiWiki::Plugin::skeleton` +that can be fleshed out to make a useful plugin. +`IkiWiki::Plugin::pagecount` is another simple example. All perl plugins +should `use IkiWiki` to import the ikiwiki plugin interface. It's a good +idea to include the version number of the plugin interface that your plugin +expects: `use IkiWiki 2.00`. + +An external plugin is an executable program. It can be written in any +language. Its interface to ikiwiki is via XML RPC, which it reads from +ikiwiki on its standard input, and writes to ikiwiki on its standard +output. For more details on writing external plugins, see [[external]]. + +Despite these two types of plugins having such different interfaces, +they're the same as far as how they hook into ikiwiki. This document will +explain how to write both sorts of plugins, albeit with an emphasis on perl +plugins. [[toc levels=2]] @@ -19,18 +37,13 @@ being edited. ## Registering plugins -All plugins should `use IkiWiki` to import the ikiwiki plugin interface. -It's a good idea to include the version number of the plugin interface that -your plugin expects: `use IkiWiki 2.00` - Plugins should, when imported, call `hook()` to hook into ikiwiki's processing. The function uses named parameters, and use varies depending on the type of hook being registered -- see below. Note that a plugin can call the function more than once to register multiple hooks. All calls to `hook()` should be passed a "type" parameter, which gives the type of hook, a "id" paramter, which should be a unique string for this plugin, and -a "call" parameter, which is a reference to a function to call for the -hook. +a "call" parameter, which tells what function to call for the hook. An optional "last" parameter, if set to a true value, makes the hook run after all other hooks of its type. Useful if the hook depends on some other @@ -272,7 +285,7 @@ namespace. These variables and functions are the ones most plugins need, and a special effort will be made to avoid changing them in incompatible ways, and to document any changes that have to be made in the future. -Note that IkiWiki also provides other variables functions that are not +Note that IkiWiki also provides other variables and functions that are not exported by default. No guarantee is made about these in the future, so if it's not exported, the wise choice is to not use it. @@ -287,7 +300,7 @@ hash. The best way to understand the contents of the hash is to look at If your plugin needs to access data about other pages in the wiki. It can use the following hashes, using a page name as the key: -* `links` lists the names of each page that a page links to, in an array +* `%links` lists the names of each page that a page links to, in an array reference. * `%destsources` contains the name of the source file used to create each destination file. diff --git a/doc/plugins/write/external.mdwn b/doc/plugins/write/external.mdwn new file mode 100644 index 000000000..735f7a20e --- /dev/null +++ b/doc/plugins/write/external.mdwn @@ -0,0 +1,88 @@ +External plugins are standalone, executable programs, that can be written +in any language. When ikiwiki starts up, it runs the program, and +communicates with it using XML RPC. If you want to [[write]] an external +plugin, read on.. + +ikiwiki contains one sample external plugin, named `externaldemo`. This is +written in perl, but is intended to be an example of how to write an +external plugin in your favorite programming language. Wow us at how much +easier you can do the same thing in your favorite language. ;-) + +## How external plugins use XML RPC + +While XML RPC is typically used over http, ikiwiki doesn't do that. +Instead, the external plugin reads XML RPC data from stdin, and writes it +to stdout. To ease parsing, each separate XML RPC request or response must +start at the beginning of a line, and end with a newline. When outputting +XML RPC to stdout, be _sure_ to flush stdout. Failure to do so will result +in deadlock! + +An external plugin should operate in a loop. First, read a command from +stdin, using XML RPC. Dispatch the command, and return its result to +stdout, also using XML RPC. After reading a command, and before returning +the result, the plugin can output XML RPC requests of its own, calling +functions in ikiwiki. Note: *Never* make an XML RPC request at any other +time. Ikiwiki won't be listening for it, and you will deadlock. + +When ikiwiki starts up an external plugin, the first RPC it will make +is to call the plugin's `import()` function. That function typically makes +an RPC to ikiwiki's `hook()` function, registering a callback. + +An external plugin can use XML RPC to call any of the exported functions +documented in the [[plugin_interface_documentation|write]]. It can also +actually call any non-exported IkiWiki function, but doing so is a good way +to break your plugin when ikiwiki changes. There is currently no versioned +interface like there is for perl plugins, but external plugins were first +supported in ikiwiki version 2.6. + +## Accessing data structures + +Ikiwiki has a few global data structures such as `%config`, which holds +its configuration. External plugins can use the `getvar` and `setvar` RPCs +to access any such global hash. To get the "url" configuration value, +call `getvar("config", "url")`. To set it, call +`setvar("config", "url", "http://example.com/)`. + +## Notes on function parameters + +The [[plugin_interface_documentation|write]] talks about functions that take +"named parameters". When such a function is called over XML RPC, such named +parameters look like a list of keys and values: + + page, foo, destpage, bar, magnify, 1 + +If a name is repeated in the list, the later value overrides the earlier +one: + + name, Bob, age, 20, name, Sally, gender, female + +In perl, boiling this down to an associative array of named parameters is +very easy: + + sub foo { + my %params=@list; + +Other languages might not find it so easy. If not, it might be a good idea +to convert these named parameters into something more natural for the +language as part of their XML RPC interface. + +## Function injection + +Some parts of ikiwiki are extensible by adding functions. For example, the +RCS interface relies on plugins providing several IkiWiki::rcs_* functions. +It's actually possible to do this from an external plugin too. + +To make your external plugin provide an `IkiWiki::rcs_update` function, for +example, make an RPC call to `inject`. Pass it named parameters "name" and +"call", where "name" is the name of the function to inject into perl (here +"Ikiwiki::rcs_update" and "call" is the RPC call ikiwiki will make whenever +that function is run. + +## Limitations of XML RPC + +Since XML RPC can't pass around references to objects, it can't be used +with functions that take or return such references. That means you can't +use XML RPC for `cgi` or `formbuilder` hooks (which are passed CGI and +FormBuilder perl objects), or use it to call `template()` (which returns a +perl HTML::Template object). + diff --git a/doc/todo/support_for_plugins_written_in_other_languages.mdwn b/doc/todo/support_for_plugins_written_in_other_languages.mdwn index 33378a4fe..8476d1b44 100644 --- a/doc/todo/support_for_plugins_written_in_other_languages.mdwn +++ b/doc/todo/support_for_plugins_written_in_other_languages.mdwn @@ -1,5 +1,7 @@ ikiwiki should support writing plugins in other languages +> [[done]] !! + While it should be possible to call ikiwiki from C, doing the callbacks in C is probably hard. And accessing perl at all from C is ugly. It also doesn't make it very easy to write plugins in an interpreted language, since that @@ -11,46 +13,39 @@ child process that it can spawn. The child could then be any program, written in any language. It could talk XML RPC via stdio. (This assumes that most languages allow easily serialising XML::RPC calls and responses to a file descriptor. Some XML RPC implementations may be hardcoded to use -http..) +http..) For ease of implementation, each rpc request sent via stio should +end with a newline, and begin with "<?xml ..>". Here's how it would basically look, not showing the actual XML RPC used to pass values. - -> import - <- 1 - <- hook type => preprocess, id => foo - -> 1 - <- done 1 - -> 1 - - -> callback type => preprocess, id => foo, page => bar - <- 1 - <- getconfig url - -> "http://example.com", ... - <- debug "foo" - -> 1 - <- done "my return value" - -> 1 + -> call import + <- call hook type => preprocess, id => foo, call => plugin_preprocess + -> result 1 + <- result 1 + + -> call plugin_preprocess page => bar + <- call getconfig url + -> result "http://example.com", ... + <- call debug "foo" + -> result 1 + <- result done "my return value" From ikiwiki's POV: * ikiwiki always initiates each conversation with a command * After sending a command, ikiwiki reads commands, dispatches them, and - returns the results, in a loop. -* The loop continues until the plugin calls the "done" command, with a value - that is the return value for the command that initiated the conversation. + returns the results, in a loop, until it gets a result for the command it + called. From the plugin's POV: * It's probably sitting in an XML::RPC loop. * Get a command from ikiwiki. -* Disaptch the command to the appropriate function. The main commands seem - to be "import" and "callback"; callback can call any function that the - plugin has registered a hook for. Others commands might include - "rcs_*" for RCS plugins.. +* Dispatch the command to the appropriate function. * The function can use XML::RPC to communicate with ikiwiki to get things like config values; and to call ikiwiki functions. -* When the callback returns, use XML::RPC to send a "done" command to ikiwiki. +* Send the function's return value back to ikiwiki. Simple enough, really. ikiwiki would need to add accessor functions for all important variables, such as "getconfig" and "setconfig". It would diff --git a/doc/usage.mdwn b/doc/usage.mdwn index 7f556cc95..aba213f21 100644 --- a/doc/usage.mdwn +++ b/doc/usage.mdwn @@ -231,9 +231,10 @@ configuration options of their own. * --libdir directory - Makes ikiwiki look in the specified directory first, before the regular perl - library directories. For example, if you set libdir to "/home/you/.ikiwiki/", - you can install plugins in "/home/you/.ikiwiki/IkiWiki/Plugin/". + Makes ikiwiki look in the specified directory first, before the regular + locations when loading library files and plugins. For example, if you set + libdir to "/home/you/.ikiwiki/", you can install a Foo.pm plugin as + "/home/you/.ikiwiki/IkiWiki/Plugin/Foo.pm". * --discussion, --no-discussion |