Ruwiki Deployment
Thursday, 2 September 2004
Posted by austin in: Ruby, Ruwiki, trackback
When Alan originally wrote Ruwiki, he wrote it as a single-user or small-group Wiki clone. When I first started hacking against Ruwiki, I kept it the same. There is increased interest in Ruwiki on large Ruby sites now, as well as interest in having Ruwiki delivered via RubyGems or RPA.
Ruwiki works extremely well under the “unpack and run” model that we’ve delivered it as so far. Unfortunately, when considering how to deliver Ruwiki as a RubyGem (as Mauricio and the RPA team will deliver Ruwiki as an RPA package), it was brought to my attention that the installation is in a central location, and this is not desirable: this means that you could only have one Wiki per machine1 and that the data would be in a location that is less than ideal (under RubyGems, it would be under ${prefix}/rubygems/gems/ruwiki-<em>version</em>/data), making it hard to have a private Wiki on a public server. Originally, I thought this would be a trivial thing to fix, but it isn’t, especially when the goal is to keep Ruwiki as simple as possible for the end user. Solving this installation problem, however, seems to solve other possible deployment scenarios.
The first step is to make it so that one doesn’t even need to have the main Ruwiki programs in the same directory as the Wiki. Some of this has been enabled for a long time, but I’ve never really tested this configuration. I determined that it would be beneficial to have the ability to keep a configuration file separate from the Ruby code.
The Flatfiles tagged format (section!item:value) was ideal for this2, and I generalised it to handle any two-level hash (e.g., { 'ruwiki' => { 'version' => 0.8.1 } }). This became Ruwiki::Exportable; I verified that my implementation was correct and complete by modifying Ruwiki::Backend::Flatfiles and Ruwiki::Page to use Ruwiki::Exportable, and then implemented it in Ruwiki::Config. This required one incompatible change: previously, storage options had been stored like @opts[:<em>type</em>][:<em>name</em>]. While the storage type is still referred to as a Symbol, the options for each storage type are now stored as strings. That is, what used to be @storage_options[:flatfiles][:data_path] is now @storage_options[:flatfiles]['data-path']. Note that the name has changed slightly, too.
The second step is initial deployment. This led me into a week-long diversion into Mauricio’s RPA::Package code, leading to the creation of my Tar module (based very heavily on Mauricio’s code, but also incorporating a number of changes); this will be released as a separate package with a limited tar/untar program at a later date. I now have the ability to pull Ruwiki data, templates, and executables from a central location. Because the feature was so easy to add, I have made it possible for users to package their wiki (into a .pkg file) and unpackage it elsewhere. I am completing the deployment command-line now. It used to be that one would do:
% tar xvfz ruwiki-0.8.0.tar.gz % cd ruwiki-0.8.0 % ruwiki_servlet
Now, one will do:
% gem install ruwiki % ruwiki install --to ruwiki # installs the data/ and templates/ to ruwiki/ % cd ruwiki % ruwiki_servlet # pulls from the stub installed by RubyGems
The third and final step for this is packaging. My packaging requirements have become far more complex, so I have to automate the packaging process. When I release Ruwiki, now, I will need to check out the codebase, create a default configuration file (ruwiki_servlet --save-config) for the current release, create the default deployment package for the current release, build the gem with those files, and then create the .tar.gz distribution. I also need to PGP/GPG sign the released files.
Those who have looked at my releases will have noted that I touch all of my released files to the date and time of the release; this will actually be easier to deal with using an automated packaging process, but this is part of the process.
1 Yes, you could copy the executable files (ruwiki.cgi or ruwiki_servlet) and modify those before running, but this is less than ideal for many things.
2 I didn’t use YAML because of various problems with YAML across versions of Ruby, including parts which still do not work with Ruby 1.8.2 preview2 on Windows–and I am not in a position to test post-preview2 code at the moment. I didn’t use XML because that would add another dependency to Ruwiki. Finally, I didn’t use Marshal because I wanted the files to be human editable.




Comments
Sorry, comments are closed for this entry