X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/055179cb4cc9b8bc9b204e1a9f83b1f59e13824e..7824ee0535f68b206cf34930712498a53e82998a:/doc/plugins/write/external.mdwn diff --git a/doc/plugins/write/external.mdwn b/doc/plugins/write/external.mdwn index a1a3811dc..a3fbe8a2c 100644 --- a/doc/plugins/write/external.mdwn +++ b/doc/plugins/write/external.mdwn @@ -1,7 +1,9 @@ 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.. +communicates with it using [XML RPC][xmlrpc]. If you want to [[write]] an +external plugin, read on.. + +[xmlrpc]: http://www.xmlrpc.com/ 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 @@ -9,10 +11,9 @@ external plugin in your favorite programming language. Wow us at how much easier you can do the same thing in your favorite language. ;-) There's now a second external plugin, the [[rst]] plugin, written in -python. (Could someone convert it into a python library that can be used by -other plugins?) +python. It uses a `proxy.py`, a helper library for ikiwiki python plugins. -[[toc ]] +[[!toc ]] ## How external plugins use XML RPC @@ -28,7 +29,7 @@ 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. +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 @@ -43,7 +44,7 @@ supported in ikiwiki version 2.6. ## Accessing data structures -Ikiwiki has a few global data structures such as `%config`, which holds +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 @@ -54,6 +55,9 @@ it, external plugins can use the `getstate` and `setstate` RPCs. To access stored state, call `getstate("page", "id", "key")`, and to store state, call `setstate("page", "id", "key", "value")`. +To access ikiwiki's ARGV array, call `getargv()`. To change its ARGV, call +`setargv(array)`. + ## Notes on function parameters The [[plugin_interface_documentation|write]] talks about functions that take @@ -77,16 +81,28 @@ 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. +## undef + +XML RPC has a limitation that it does not have a way to pass +undef/NULL/None. There is an extension to the protocol that supports this, +but it is not yet available in all versions of the [[!cpan XML::RPC]] library +used by ikiwiki. + +Until the extension is available, ikiwiki allows undef to be communicated +over XML RPC by passing a sentinal value, a hash with a single key "null" +with a value of an empty string. External plugins that need to communicate +null values to or from ikiwiki will have to translate between undef and +the sentinal. + ## Function injection -Some parts of ikiwiki are extensible by adding functions. For example, the -RCS interface relies on plugins providing several IkiWiki::rcs_* functions. +Some parts of ikiwiki are extensible by adding or overriding 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 +To make your external plugin override the `IkiWiki::formattime` 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 +"Ikiwiki::formattime" and "call" is the RPC call ikiwiki will make whenever that function is run. If the RPC call is memoizable, you can also pass a "memoize" parameter, set @@ -100,9 +116,6 @@ with functions that take or return such references. That means you can't FormBuilder perl objects), or use it to call `template()` (which returns a perl HTML::Template object). -Also. the `getopt` hook doesn't work, as ARGV is not available to the external -plugin. - ## Performance issues Since each external plugin is a separate process, when ikiwiki is @@ -120,12 +133,12 @@ large quantity of data conversion going on. In contrast, `preprocess` hooks are called generally rarely, and pass around minimal data. External plugins should avoid making RPC calls unnecessarily (ie, in a loop). -Memoizing the results of appropriate RPC calls is one good way to minimise the +Memoizing the results of appropriate RPC calls is one good way to minimize the number of calls. Injecting a replacement for a commonly called ikiwiki function could result in a lot more RPC calls than expected and slow -eveything down. `pagetitle`, for instance, is called about 100 times +everything down. `pagetitle`, for instance, is called about 100 times per page build. Whenever possible, you should tell ikiwiki to memoize injected functions.