Managing Plugins with Piston
(Mon Jan 22, 2007) [/Rails] #
For all the same reasons I'm not keen on using Subversion externals to manage versions of Rails, I'd rather not rely on a remote Subversion repository to manage Rails plugins my applications use. Actually, it's even more important with plugins. There's nothing worse than not being able to deploy because Fred's plugin server took a long vacation. Again, it pays to be selfish when it comes to your application's dependencies.
Enter Piston. It lets you manage your external dependencies in a similar manner to a Subversion external link—it pulls changes from a third-party Subversion repository—but it actually checks the changes into your local repository. And when you're ready to step up to a new revision of Fred's plugin, it makes it drop-dead easy to update your local repository with the remote repository. Indeed, it's all the goodness of svn:externals without all the downsides of remote repository access.
And judging by the number of passionate emails from happy Piston users, I figured it deserved a write-up...
Fits Like a Piston
Say you want to use the resource_feeder plugin to serve up RSS and Atom feeds from your Rails application. How do you manage the plugin with Piston?
1. Install Piston
$ gem install piston
2. Convert or Import
You have two choices for checking the plugin in to your Subversion repository. If you already have an external link to a remote repository, you can convert it to a Piston-managed folder of your repository. Alternatively, you can import the plugin into your repository straight from the remote repository.
Convert an Existing External
If you're currently using an svn:externals link, you can inspect it by typing
$ cd my_rails_app $ svn proplist --verbose vendor/plugins Properties on 'vendor/plugins': svn:externals : resource_feeder http://dev.rubyonrails.com/svn/rails/plugins/resource_feeder
To convert it to a Piston-managed folder of your Subversion repository, type
$ piston convert Importing 'http://dev.rubyonrails.com/svn/rails/plugins/resource_feeder' to vendor/plugins/resource_feeder (-r 5719) Exported r5719 from 'http://dev.rubyonrails.com/svn/rails/plugins/resource_feeder' to 'vendor/plugins/resource_feeder' Done converting existing svn:externals to Piston
Then check the changes into your Subversion repository:
$ svn commit vendor/plugins
Import a Non-Existing Plugin
To import the plugin straight into your Subversion repository, type
$ piston import http://dev.rubyonrails.com/svn/rails/plugins/resource_feeder \
vendor/plugins/resource_feeder
Then check the changes into your Subversion repository:
$ svn commit vendor/plugins
3. Check the Status
To check the status of each Piston-managed directory, type
$ piston status vendor/plugins/resource_feeder (http://dev.rubyonrails.com/svn/rails/plugins/resource_feeder)
4. Update the Plugin(s)
When you're ready to snag the latest changes from the remote repository, type
$ piston update vendor/plugins/resource_feeder/ Processing 'vendor/plugins/resource_feeder'... Fetching remote repository's latest revision and UUID Updated to r5719 (2 changes)
Updating is where Piston really shines. If you had simply copied a revision of the plugin into your repository, it would be inconvenient to sync up with future revisions of the plugin. But piston update updates the plugin in your repository to the latest revision in the remote repository, merging in any local changes you've made.
And how do you know when a plugin in a remote repository has been updated? Easy. Use Subtlety to get an RSS feed of changes.
To update all Piston-managed directories, simply type
$ piston update
5. Lock a Revision
If you want to lock the plugin to the current revision to avoid unexpected (unwanted) updates, type
$ piston lock vendor/plugins/resource_feeder/ 'vendor/plugins/resource_feeder/' locked at revision 5719
6. Unlock and Update
Then when you're ready to live on the bleeding edge again, unlock the plugin by typing
$ piston unlock vendor/plugins/resource_feeder/ Unlocked 'vendor/plugins/resource_feeder/'
Then run piston update to update again.
Advantages
-
Checkouts and updates are faster than hitting a remote repository each time you run
svn updateorsvn checkout. And plugins generally don't change often enough to warrant frequent remote queries. - You get control over when you update to new revisions, and can prevent inadvertent updates by locking to a specific revision.
- You can deploy without the nail-biting fear of a remote plugin repository being offline.
- You can modify plugins locally and your changes will be preserved when you update to a more recent revision.
- Not everyone on your team needs to have Piston installed. Once you've imported or converted a plugin to a Piston-managed folder, folks without Piston installed can happily check out and update those plugins.
Disadvantages
- Your repository grows in size more rapidly.
- Merging can be slow, as described in the caveats.
- Piston doesn't preserve change history from the remote repository. Rather, Piston will grab the current revision, or differences between what you currently have and the latest revision, and merge those changes into your checked out copy. However, you can examine the changes before committing them to your local repository.
Managing Rails Versions
Clearly you could also use Piston to manage the contents of your vendor/rails directory. It's simply a matter of typing
$ piston import http://dev.rubyonrails.org/svn/rails/trunk vendor/rails
or
$ piston convert vendor/rails
Frankly, I'm currently on the fence about doing this. Piston seems ideal for merging in relatively small chunks of code at a time, such as Rails plugins. I'm not yet comfortable enough with Piston to put all the Rails bits under its control in every Rails application. I have no reason not to trust it, I'm just preferring this approach for now. Your mileage may vary, of course.
Thanks to Graeme Mathieson and everyone else who wrote in with suggestions!
