Project

General

Profile

Develop Plugin as a mountable Engine?

Added by Stefan Frank almost 12 years ago

Is it possible to develop a plugin as a Rails mountable engine? Is there anything special about the redmine-plugin that prevents a plugin to be developed a an engine?

I'm asking because this would have several advantages:

  • bring the plugin-mechanism in line with 3.2
  • install plugins by adding them to the gemfile; updates work by updating the gem
  • get a standard-way of testing plugins standalone and add them to Continuous Integration

For the project-structure for the plugin, this would turn things around: The redmine-installation would go into <engine-root>/test/redmine (currently rails generates a dummy app) and could be easily .gitignore'd, then the plugin would be a gem and could easily be checked into git, distributed etc.

Does this sound crazy or doable?! I'm just starting out here, but I'm looking for a convenient setup to be able to check in plugins into git, make them easily testable standalone, add them to Continuous Integration etc. - the current examples all use several variations of this theme, with custom scripts to checkout redmine, copy the plugin into the plugins-dir, run the tests etc. - I haven't yet found a blueprint for doing this efficiently.

Any ideas or pointers, where I can look for that are be highly appreciated...

Cheers
Stefan


Replies (6)

RE: Develop Plugin as a mountable Engine? - Added by Jean-Philippe Lang almost 12 years ago

Is it possible to develop a plugin as a Rails mountable engine?

You're not the first one who asks and until someone actually tries, I can't really say. I don't have much time for that right now but if you are able to experiment, I'd appreciate any feedback.

Is there anything special about the redmine-plugin that prevents a plugin to be developed a an engine?

Redmine offers some features for plugins located in /plugins (eg. autoloading, view paths, migrations...) but I guess that these mechanisms are handled by Engines pretty well. And the Redmine plugin API (eg. to extend menus, permissions...) can be used from anywhere. So I'd say no and I'd be happy to make the required changes to make it work if it's not the case.

RE: Develop Plugin as a mountable Engine? - Added by Stefan Frank almost 12 years ago

ok, I tried it:

I generated a mountable engine, unpacked redmine into the test-dir, added this engine as a gem into Gemfile.local:

gem "redmine_config", :path => "../../../redmine_config" 

and put the put the Redmine-configuration into an initializer:

puts "----------Configuring Plugin!!!!-------" 

Redmine::Plugin.register :redmine_configuration do
  name 'Redmine Custom Configuration'
  author 'Stefan Frank, s.frank@vierundsechzig.de'
  description 'This is a plugin for Redmine'
  version '0.0.1'
  url 'http://example.com/path/to/redmine_config'
  author_url 'http://www.vierundsechzig.de'

end

The initializer gets correctly called when redmine is started up, but I get:

/private/tmp/redmine_config/test/redmine/lib/redmine/menu_manager.rb:348:in `add_at': Child already added (RuntimeError)

(see below for the full stacktrace)

Googling around only brings up plugin-conflicts, but there are currently no other plugins configured, so this has have other reasons. So, unless you have a brilliantly quick idea where I can look, I guess I'll have to postpone this: I currently do not know enough about the plugin-mechanisms to debug this efficiently. But I will definitely get back to this: I'd really like to use the rails-engines-mechanisms for plugin-development...

cheers
Stefan

Full Stacktrace of the exception:

/private/tmp/redmine_config/test/redmine/lib/redmine/menu_manager.rb:348:in `add_at': Child already added (RuntimeError)
    from /private/tmp/redmine_config/test/redmine/lib/redmine/menu_manager.rb:365:in `add'
    from /private/tmp/redmine_config/test/redmine/lib/redmine/menu_manager.rb:283:in `push'
    from /private/tmp/redmine_config/test/redmine/lib/redmine.rb:154:in `block in <top (required)>'
    from /private/tmp/redmine_config/test/redmine/lib/redmine/menu_manager.rb:215:in `map'
    from /private/tmp/redmine_config/test/redmine/lib/redmine.rb:153:in `<top (required)>'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.2.5/lib/active_support/dependencies.rb:251:in `require'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.2.5/lib/active_support/dependencies.rb:251:in `block in require'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.2.5/lib/active_support/dependencies.rb:236:in `load_dependency'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.2.5/lib/active_support/dependencies.rb:251:in `require'
    from /private/tmp/redmine_config/test/redmine/config/initializers/30-redmine.rb:5:in `<top (required)>'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.2.5/lib/active_support/dependencies.rb:245:in `load'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.2.5/lib/active_support/dependencies.rb:245:in `block in load'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.2.5/lib/active_support/dependencies.rb:236:in `load_dependency'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.2.5/lib/active_support/dependencies.rb:245:in `load'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/engine.rb:588:in `block (2 levels) in <class:Engine>'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/engine.rb:587:in `each'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/engine.rb:587:in `block in <class:Engine>'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/initializable.rb:30:in `instance_exec'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/initializable.rb:30:in `run'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/initializable.rb:55:in `block in run_initializers'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/initializable.rb:54:in `each'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/initializable.rb:54:in `run_initializers'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/application.rb:136:in `initialize!'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/railtie/configurable.rb:30:in `method_missing'
    from /private/tmp/redmine_config/test/redmine/config/environment.rb:14:in `<top (required)>'
    from /private/tmp/redmine_config/test/redmine/config.ru:4:in `require'
    from /private/tmp/redmine_config/test/redmine/config.ru:4:in `block in <main>'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/rack-1.4.1/lib/rack/builder.rb:51:in `instance_eval'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/rack-1.4.1/lib/rack/builder.rb:51:in `initialize'
    from /private/tmp/redmine_config/test/redmine/config.ru:1:in `new'
    from /private/tmp/redmine_config/test/redmine/config.ru:1:in `<main>'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/rack-1.4.1/lib/rack/builder.rb:40:in `eval'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/rack-1.4.1/lib/rack/builder.rb:40:in `parse_file'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/rack-1.4.1/lib/rack/server.rb:200:in `app'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/commands/server.rb:46:in `app'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/rack-1.4.1/lib/rack/server.rb:301:in `wrapped_app'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/rack-1.4.1/lib/rack/server.rb:252:in `start'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/commands/server.rb:70:in `start'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/commands.rb:55:in `block in <top (required)>'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/commands.rb:50:in `tap'
    from /Users/sfrank/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.5/lib/rails/commands.rb:50:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'

RE: Develop Plugin as a mountable Engine? - Added by Jean-Philippe Lang almost 12 years ago

Thanks, I'll try to find some time do a few tests this evening.

RE: Develop Plugin as a mountable Engine? - Added by Stefan Frank almost 12 years ago

thank you! let me know if there is anything I can test or do to help.

RE: Develop Plugin as a mountable Engine? - Added by Jean-Philippe Lang almost 12 years ago

I was able to reproduce this error. Strange issue, lib/redmine.rb is loaded twice. I'll fix it later but you can apply this small patch to boot without errors for now:

Index: config/initializers/30-redmine.rb
===================================================================
--- config/initializers/30-redmine.rb    (revision 9794)
+++ config/initializers/30-redmine.rb    (working copy)
@@ -2,7 +2,7 @@
 # Adds fallback to default locale for untranslated strings
 I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)

-require 'redmine'
+require 'redmine' unless defined?(Redmine)

 # Load the secret token from the Redmine configuration file
 secret = Redmine::Configuration['secret_token']

I then just made a small test and was able to use the plugin API (eg. add an item to the Redmine menu).

RE: Develop Plugin as a mountable Engine? - Added by Etienne Massip almost 12 years ago

I think that's the Rails 3 way to go, with plugins/engines bundled into gems. Moreover, if pipeline is active then they can have their own /assets directories then they'll be handled by the application asset pipeline.

Still, what I don't get with this pipeline when configured with default production options, is that you'll have to precompile the plugin assets as well when installing it which is not very flexible. Or maybe are they supposed to be bundled into the gem?

    (1-6/6)