Defect #1754

Redmine not compatible with RedCloth >= 3.301

Added by Simone Carletti about 9 years ago. Updated about 9 years ago.

Status:ClosedStart date:2008-08-05
Priority:HighDue date:
Assignee:Jean-Philippe Lang% Done:

0%

Category:Wiki
Target version:0.8
Resolution:Fixed Affected version:0.7.3

Description

After a couple of year the new version of RedCloth has been released at the end of July.

Although a middle release was already available (called RedCloth 3.301 and available via --source http://code.whytheluckystiff.net) this is the first release > 3.0.4 available from RubyForge.
It means every new user that will install RedCloth will have this release by default.

Redmine 0.7.3 is not compatible with RedCloth > 3.0.4.
This is because in Redmine extends RedCloth and assumes that RedCloth provides a hard_breaks accessor method but:

  • RedCloth 3.301 doesn't provide hard_breaks method
  • RedCloth 4.x does but the main class is no longer RedCloth but RedCloth::TextileDoc

redcloth-rename.patch Magnifier - rename of the included modified redcloth library (75.7 KB) Gerrit Kaiser, 2008-08-26 03:01


Related issues

Related to Redmine - Defect #1714: Phusion Passenger and RailsSpawnMethod Closed 2008-07-30

Associated revisions

Revision 1800
Added by Jean-Philippe Lang about 9 years ago

Renames bundled RedCloth to RedCloth3 to avoid RedCloth 4 to be loaded instead (#1754).

Revision 1836
Added by Nicolas Chuche about 9 years ago

r18536@gaspard (orig r1800): jplang | 2008-09-11 19:19:26 +0200
Renames bundled RedCloth to RedCloth3 to avoid RedCloth 4 to be loaded instead (#1754).

History

#1 Updated by Simone Carletti about 9 years ago

I just noticed RedCloth lib is included in the lib folder.
For some reason (I guess because Rails loads it if available), the one installed in the server seems to take precedence thus Redmine is going to ignore the lib/RedCloth if an other release is installed.

ActionView::TemplateError (undefined method `hard_breaks=' for "Tagged release 0.9.1":Redmine::WikiFormatting::TextileFormatter) on line #21 of repositories/_revisions.rhtml:
18: <td class="checkbox"><%= radio_button_tag('rev_to', changeset.revision, (line_num==2), :id => "cbto-#{line_num}", :onclick => "if ($('cb-#{line_num}').checked==true) {$('cb-#{line_num-1}').checked=true;}") if show_diff && (line_num > 1) %></td>
19: <td class="committed_on"><%= format_time(changeset.committed_on) %></td>
20: <td class="author"><%=h changeset.committer.to_s.split('<').first %></td>
21: <td class="comments"><%= textilizable(changeset.comments) %></td>
22: </tr>
23: <% line_num += 1 %>
24: <% end %>

    /home/redmine/releases/0.7.3/lib/redmine/wiki_formatting.rb:33:in `initialize'
    /home/redmine/releases/0.7.3/lib/redmine/wiki_formatting.rb:168:in `new'
    /home/redmine/releases/0.7.3/lib/redmine/wiki_formatting.rb:168:in `to_html'
    /home/redmine/releases/0.7.3/app/helpers/application_helper.rb:226:in `textilizable'
    /home/redmine/releases/0.7.3/app/views/repositories/_revisions.rhtml:21:in `_run_erb_47app47views47repositories47_revisions46rhtml'
    /home/redmine/releases/0.7.3/app/views/repositories/_revisions.rhtml:14:in `each'
    /home/redmine/releases/0.7.3/app/views/repositories/_revisions.rhtml:14:in `_run_erb_47app47views47repositories47_revisions46rhtml'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/helpers/capture_helper.rb:142:in `call'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/helpers/capture_helper.rb:142:in `capture_erb_with_buffer'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/helpers/capture_helper.rb:44:in `capture'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/helpers/form_tag_helper.rb:417:in `form_tag_in_block'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/helpers/form_tag_helper.rb:39:in `form_tag'
    /home/redmine/releases/0.7.3/app/views/repositories/_revisions.rhtml:1:in `_run_erb_47app47views47repositories47_revisions46rhtml'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/base.rb:637:in `send'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/base.rb:637:in `compile_and_render_template'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/base.rb:365:in `render_template'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/base.rb:316:in `render_file'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/base.rb:331:in `render'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/partials.rb:120:in `render_partial'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/base.rb:352:in `render'
    /home/redmine/releases/0.7.3/app/views/repositories/show.rhtml:14:in `_run_erb_47app47views47repositories47show46rhtml'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/base.rb:637:in `send'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/base.rb:637:in `compile_and_render_template'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/base.rb:365:in `render_template'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_view/base.rb:316:in `render_file'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/base.rb:1100:in `render_for_file'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/base.rb:836:in `render_with_no_layout'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/layout.rb:262:in `render_without_benchmark'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/benchmarking.rb:51:in `render'
    /usr/lib/ruby/1.8/benchmark.rb:293:in `measure'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/benchmarking.rb:51:in `render'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/base.rb:1153:in `default_render'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/base.rb:1159:in `perform_action_without_filters'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/filters.rb:697:in `call_filters'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/filters.rb:689:in `perform_action_without_benchmark'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'
    /usr/lib/ruby/1.8/benchmark.rb:293:in `measure'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/rescue.rb:199:in `perform_action_without_caching'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/caching.rb:678:in `passenger_orig_perform_action'
    /usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/connection_adapters/abstract/query_cache.rb:33:in `cache'
    /usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/query_cache.rb:8:in `cache'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/caching.rb:677:in `passenger_orig_perform_action'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/railz/request_handler.rb:53:in `perform_action'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/base.rb:524:in `send'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/base.rb:524:in `process_without_filters'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/filters.rb:685:in `process_without_session_management_support'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/session_management.rb:123:in `process'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/base.rb:388:in `process'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/dispatcher.rb:171:in `handle_request'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/dispatcher.rb:115:in `dispatch'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/dispatcher.rb:126:in `dispatch_cgi'
    /usr/lib/ruby/gems/1.8/gems/actionpack-2.0.2/lib/action_controller/dispatcher.rb:9:in `dispatch'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/railz/request_handler.rb:38:in `process_request'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_request_handler.rb:163:in `main_loop'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/railz/application_spawner.rb:307:in `start_request_handler'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/railz/application_spawner.rb:276:in `handle_spawn_application'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/utils.rb:165:in `safe_fork'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/utils.rb:163:in `fork'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/utils.rb:163:in `safe_fork'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/railz/application_spawner.rb:274:in `handle_spawn_application'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/utils.rb:165:in `safe_fork'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/utils.rb:163:in `fork'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/utils.rb:163:in `safe_fork'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/railz/application_spawner.rb:273:in `handle_spawn_application'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:317:in `__send__'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:317:in `main_loop'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:168:in `start_synchronously'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:135:in `start'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:112:in `fork'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:112:in `start'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/railz/application_spawner.rb:177:in `start'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/railz/framework_spawner.rb:270:in `handle_spawn_application'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/railz/framework_spawner.rb:263:in `synchronize'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/railz/framework_spawner.rb:263:in `handle_spawn_application'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:317:in `__send__'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:317:in `main_loop'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:168:in `start_synchronously'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:135:in `start'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:112:in `fork'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:112:in `start'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/railz/framework_spawner.rb:87:in `start'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/spawn_manager.rb:224:in `spawn_rails_application'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/spawn_manager.rb:219:in `synchronize'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/spawn_manager.rb:219:in `spawn_rails_application'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/spawn_manager.rb:122:in `spawn_application'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/spawn_manager.rb:253:in `handle_spawn_application'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:317:in `__send__'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:317:in `main_loop'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/lib/passenger/abstract_server.rb:168:in `start_synchronously'
    /usr/lib/ruby/gems/1.8/gems/passenger-2.0.2/bin/passenger-spawn-server:46

Rendering /home/redmine/releases/0.7.3/public/500.html (500 Internal Server Error)

#2 Updated by Ignacio Carrera about 9 years ago

I just added

require 'rubygems'
gem 'RedCloth', '3.0.4'

in config/environment.rb, just after Rails' bootstrap, to make it work.

-- nachokb

#3 Updated by Simone Carletti about 9 years ago

Ignacio Carrera wrote:

I just added

[...]

in config/environment.rb, just after Rails' bootstrap, to make it work.

-- nachokb

I don't like this approach: it forces you to require an outdated library.
It can be used as a temporary workaround (I preferred the other way, I changed the base class extended by wiki formatter) but I would not suggest this as the final solution.

Additionally, it is prone to some side effects.
Because Rails loads RedCloth at initialization time before you require it, if you try to require it when the gem has alredy being loaded you may find yourself to deal with a "GEM alredy loaded" error.

#4 Updated by Jean-Philippe Lang about 9 years ago

I think I should move the included and modified RedCloth to Redmine::RedCloth to prevent this kind of problem.
What do you think ?

#5 Updated by Simone Carletti about 9 years ago

Jean-Philippe Lang wrote:

I think I should move the included and modified RedCloth to Redmine::RedCloth to prevent this kind of problem.
What do you think ?

That would be a possibile solution, even if I don't really like it but just because RedCloth has beed completely rewritten from scratch with a C parser and the new release it's now 30 times faster!

I started to work on a patch that was able to support both <= 3.3, ~> 3.3 and >= 4.x but I found a small problem trying to integrate special functions inline_auto_link, inline_auto_mailto.
My idea was to try to use RedCloth as an external instance (as Rails does) instead of extending it. This solution limits compatibility issues because libraries tends to change internally but preserving API access.

I was basically working on an unique initializer

      def initialize(string)
        @redcloth = RedCloth.new(args, [:filter_html, :no_span_caps])         # != 3.301 ignores restrictions
        @redcloth.hard_breaks = true if @redcloth.respond_to?("hard_breaks=") # != 3.301
      end

and some Modules to be mixed into TextileFormatter depending on RedCloth version.
For instance, RedCloth >= 3.3 Module would include the hard_break patch

      # Patch for RedCloth.  Fixed in RedCloth r128 but _why hasn't released it yet.
      # <a href="http://code.whytheluckystiff.net/redcloth/changeset/128">http://code.whytheluckystiff.net/redcloth/changeset/128</a>
      def hard_break( text ) 
        text.gsub!( /(.)\n(?!\n|\Z|>| *(>? *[#*=]+(\s|$)|[{|]))/, "\\1<br />\n" ) if hard_breaks 
      end

but not those for RedCloth >= 3.3.

However, because I don't really know the full Redmine structure, I stopped just to learn more about how Redmine calls WikiFormatter before taking bad design ways.

#6 Updated by Gerrit Kaiser about 9 years ago

We worked around the problem by simply renaming the included RedCloth (Patch against r1764 attached). That way at least Redmine can be run on systems with the RedCloth 4 gem installed.

#7 Updated by Dmitry Shaposhnik about 9 years ago

I can confirm - after renaming it works well (with RubyEE and mod_passenger).

#8 Updated by Simone Carletti about 9 years ago

I just want to let you know Rails 2.1.1 includes a nice change that could probably (partially) contribute to fix this issue.

  • Add the gem load paths before the framework is loaded, so certain gems like RedCloth and BlueCloth can be frozen.

In other words, as soon as Redmine will support Rails 2.1 (if I'm not wrong Redmine 0.8 should be compatible with Rails 2.1), RedCloth GEM could be frozen within Redcloth distribution.
I would suggest to consider to upgrade support at least to RedCloth 4.0 that is exceptionally faster than the previous major release.

#9 Updated by Babar O'Cap about 9 years ago

Just to say that JRuby is also not compatible with RedCloth > 3.0.4. for the moment.

#10 Updated by Jean-Philippe Lang about 9 years ago

  • Status changed from New to Closed
  • Target version set to 0.8
  • Resolution set to Fixed

For now, I've renamed the bundled RedCloth to RedCloth3 as proposed by Gerrit.

Moving to RedCloth 4 is not planned yet. It would require some work to port the changes/improvements done on the bundled RedCloth. I have made a few tests, the performance improvement on an average ticket page is not so big. An alternative and considerably faster solution would be to cache the textile output.

Also available in: Atom PDF