add support for redmine > v2.0

This commit is contained in:
mkinski 2012-08-02 12:09:00 +02:00
parent d31a74b204
commit 069cddd1c4
6 changed files with 58 additions and 53 deletions

View File

@ -20,38 +20,33 @@ ones is typically as easy as adding several lines in plugin config file.
Installation
============
** NOTE works only on Redmine > v2.0 **
1. It's recommended (but not required) to install
[popen4](http://popen4.rubyforge.org/) library first as without it plugin is
unable to capture stderr output of external command, so it might be hard to debug
it if things go wrong.
2. Get sources from [github](http://github.com/ndl/wiki_external_filter).
2. Get sources from [github](http://github.com/mkinski/wiki_external_filter).
3. See [Installing a plugin](http://www.redmine.org/wiki/redmine/Plugins) on
Redmine site.
4. Copy wiki_external_filter.yml from config folder of plugin
directory to the config folder of your redmine installation.
5. After installation it's **strongly recommended** to go to plugin settings and
configure caching: Administration -> Plugins -> Wiki External Filter Plugin: Configure and follow instructions. Note that RoR file-based caching suggested by default does
not implement proper cache expiration: you should either setup a cron task to
clean cache or do it manually from time to time.
configure caching: Administration -> Plugins -> Wiki External Filter Plugin: Configure and follow instructions.
6. To successfully use macros with argument expressions, it's necessary
to patch wiki formatting routine so that it preserves macros arguments.
**Redmine 1.0.2:** apply [this patch](http://www.ndl.kiev.ua/downloads/redmine-1.0.2-macros-escaping.patch) to the Redmine core and go to step 7, there's no need to patch individual wiki formatters anymore.
Graphviz will not work until modification MACRO_RE see ungoing [Issue 3061](http://www.redmine.org/issues/3061)
under app/helper/application_helper.rb
MACROS_RE = /
(!)? # escaping
(
\{\{ # opening tag
([\w]+) # macro name
(\((.*)\))? # optional arguments
\}\} # closing tag
)
/
**Redmine 0.9.x:** if you use Markdown Extra, switch to the following fork of [redmine_markdown_extra_formatter](http://github.com/ndl/redmine_markdown_extra_formatter) that contains all necessary changes. [This patch](http://www.ndl.kiev.ua/downloads/redmine_markdown_extra_formatter_fixes.patch.gz) is for older Markdown Extra formatter version and should not be used for new installations.
**Note**: if you install Markdown Extra formatter - you should enable it in Administration -> Settings -> General -> Text formatting.
If you use wiki formatter other than Markdown Extra (including default Textile formatter) **you will have to change your wiki formatter yourselves** as follows:
* [Change MACROS_RE](http://www.redmine.org/issues/3061) regexp not to stop
too early - in the issue description Textile wiki formatter is mentioned,
but in fact this change should be done for whatever wiki formatter you use.
* [Change arguments parsing](http://www.redmine.org/boards/3/topics/4987#message-9854) - again,
should be done for whatever wiki formatter you use.
* For some of the formatters escaping should be avoided for
macro arguments, see how it is done for Markdown Extra wiki formatter.
[Preliminary version of patch](http://www.redmine.org/boards/3/topics/10649#message-15222) for Textile support was made available by Yuya Nishihara, according to the author "It works but really messy" but I haven't tested it so cannot comment on it.
Do not use commas in macro because it would be splited in different arguments and therefore plugin will not work.
7. To allow passing attachments names as macros arguments Redmine core should be patched accordingly: here's [the patch for Redmine 1.0.2](http://www.ndl.kiev.ua/downloads/redmine-1.0.2-attachments.patch) and here is [the patch for Redmine 0.9.x](http://www.ndl.kiev.ua/downloads/redmine-attachments-in-macros.patch.gz).
@ -109,7 +104,7 @@ Example of usage:
{{graphviz(
digraph finite_state_machine {
rankdir=LR;
size="8,5"
size="8.5"
node [shape = doublecircle]; LR_0 LR_3 LR_4 LR_8;
node [shape = circle];
LR_0 -> LR_2 [ label = "SS(B)" ];

View File

@ -10,7 +10,9 @@ class WikiExternalFilterController < ApplicationController
filename = params[:filename] ? params[:filename] : name
config = load_config
cache_key = self.construct_cache_key(macro, name)
content = read_fragment cache_key
content = Rails.cache.read cache_key
Rails.logger.debug "Config:#{config} Key: #{cache_key} Content: #{content}"
if (content)
send_data content[index], :type => config[macro]['outputs'][index]['content_type'], :disposition => 'inline', :filename => filename

View File

@ -1,14 +1,15 @@
require 'digest/sha2'
include Redmine::WikiFormatting::Macros::Definitions
module WikiExternalFilterHelper
def load_config
unless @config
config_file = "#{RAILS_ROOT}/config/wiki_external_filter.yml"
config_file = "#{Rails.root}/plugins/wiki_external_filter/config/wiki_external_filter.yml"
unless File.exists?(config_file)
raise "Config not found: #{config_file}"
end
@config = YAML.load_file(config_file)[RAILS_ENV]
@config = YAML.load_file(config_file)[Rails.env]
end
@config
end
@ -26,7 +27,7 @@ module WikiExternalFilterHelper
def build(text, attachments, macro, info)
name = Digest::SHA256.hexdigest(text)
name = Digest::SHA256.hexdigest(text.to_s)
result = {}
content = nil
cache_key = nil
@ -41,27 +42,29 @@ module WikiExternalFilterHelper
if expires > 0
cache_key = self.construct_cache_key(macro, name)
begin
content = read_fragment cache_key, :expires_in => expires.seconds
content = Rails.cache.read cache_key, :expires_in => expires.seconds
rescue
RAILS_DEFAULT_LOGGER.error "Failed to load cache: #{cache_key}, error: $!"
Rails.logger.error "Failed to load cache: #{cache_key}, error: $! #{error} #{$@}"
end
end
if content
result[:source] = text
result[:source] = text.to_s
result[:content] = content
RAILS_DEFAULT_LOGGER.debug "from cache: #{cache_key}"
Rails.logger.debug "from cache: #{cache_key}"
else
result = self.build_forced(text, attachments, info)
if result[:status]
if expires > 0
begin
write_fragment cache_key, result[:content], :expires_in => expires.seconds
RAILS_DEFAULT_LOGGER.debug "cache saved: #{cache_key}"
Rails.cache.write cache_key, result[:content], :expires_in => expires.seconds
Rails.logger.debug "cache saved: #{cache_key} expires #{expires.seconds}"
rescue
RAILS_DEFAULT_LOGGER.error "Failed to save cache: #{cache_key}, error: $!"
end
end
Rails.logger.error "Failed to save cache: #{cache_key}, result content #{result[:content]}, error: $!"
end
else
raise "please set expires time under plugins settings"
end
else
raise "Error applying external filter: stdout is #{result[:content]}, stderr is #{result[:errors]}"
end
@ -79,7 +82,7 @@ module WikiExternalFilterHelper
if info['replace_attachments'] and attachments
attachments.each do |att|
text.gsub!(/#{att.filename.downcase}/i, att.diskfile)
text.to_s.gsub!(/#{att.filename.downcase}/i, att.diskfile)
end
end
@ -87,8 +90,11 @@ module WikiExternalFilterHelper
content = []
errors = ""
text = text.first.to_s.gsub("<br />", "\n")
Rails.logger.debug "\n Text #{text} \n"
info['outputs'].each do |out|
RAILS_DEFAULT_LOGGER.info "executing command: #{out['command']}"
Rails.logger.info "executing command: #{out['command']}"
c = nil
e = nil
@ -100,7 +106,7 @@ module WikiExternalFilterHelper
Open4::popen4(out['command']) { |pid, fin, fout, ferr|
fin.write out['prolog'] if out.key?('prolog')
fin.write CGI.unescapeHTML(text)
fin.write text
fin.write out['epilog'] if out.key?('epilog')
fin.close
c, e = [fout.read, ferr.read]
@ -108,14 +114,14 @@ module WikiExternalFilterHelper
rescue LoadError
IO.popen(out['command'], 'r+b') { |f|
f.write out['prolog'] if out.key?('prolog')
f.write CGI.unescapeHTML(text)
f.write text
f.write out['epilog'] if out.key?('epilog')
f.close_write
c = f.read
}
}
end
RAILS_DEFAULT_LOGGER.debug("child status: sig=#{$?.termsig}, exit=#{$?.exitstatus}")
Rails.logger.debug("child status: sig=#{$?.termsig}, exit=#{$?.exitstatus}")
content << c
errors += e if e

View File

@ -10,7 +10,7 @@
Configuration example for ActiveSupport::Cache::FileStore, config/environments/production.rb file:<br/>
<br/>
...<br/>
config.action_controller.cache_store = :file_store, &quot;#{RAILS_ROOT}/cache&quot;<br/>
config.action_controller.cache_store = :file_store, &quot;#{Rails.root}/cache&quot;<br/>
...
</p>
<p>
@ -18,8 +18,8 @@
</p>
<p>
Current cache settings are:<br/>
ActionController::Base.cache_configured? = <%= h ActionController::Base.cache_configured? ? "true" : "false" %><br/>
<% cache_store = ActionController::Base.respond_to?('fragment_cache_store=') ? ActionController::Base.fragment_cache_store : ActionController::Base.cache_store %>
<%= h ActionController::Base.perform_caching ? "true" : "false" %><br/>
<% cache_store = ActionController::Base.respond_to?('cache_store=') ? ActionController::Base.cache_store : ActionController::Base.cache_store %>
ActionController::Base.cache_store = <%= h cache_store.inspect %>
</p>
</fieldset>

View File

@ -1,4 +1,3 @@
ActionController::Routing::Routes.draw do |map|
map.connect 'wiki_external_filter/:filename', :controller => 'wiki_external_filter', :action => 'filter', :macro => 'video', :index => '1', :requirements => { :filename => /video\.flv/ }
map.connect 'wiki_external_filter/:filename', :controller => 'wiki_external_filter', :action => 'filter', :macro => 'video_url', :index => '1', :requirements => { :filename => /video_url\.flv/ }
end
match 'wiki_external_filter/:filename', :controller => 'wiki_external_filter', :action => 'filter', :macro => 'video', :index => '1', :requirements => { :filename => /video\.flv/ }
match 'wiki_external_filter/:filename', :controller => 'wiki_external_filter', :action => 'filter', :macro => 'video_url', :index => '1', :requirements => { :filename => /video_url\.flv/ }
match '/wiki_external_filter', :to => 'wiki_external_filter#filter', :via => [:get, :post]

13
init.rb
View File

@ -1,6 +1,7 @@
require 'redmine'
require "#{Rails.root}/plugins/wiki_external_filter/app/helpers/wiki_external_filter_helper"
RAILS_DEFAULT_LOGGER.info 'Starting wiki_external_filter plugin for Redmine'
Rails.logger.info 'Starting wiki_external_filter plugin for Redmin'
Redmine::Plugin.register :wiki_external_filter do
name 'Wiki External Filter Plugin'
@ -8,19 +9,21 @@ Redmine::Plugin.register :wiki_external_filter do
description 'Processes given text using external command and renders its output'
author_url 'http://www.ndl.kiev.ua'
version '0.0.2'
requires_redmine :version_or_higher => '2.0.0'
settings :default => {'cache_seconds' => '0'}, :partial => 'wiki_external_filter/settings'
config = WikiExternalFilterHelper.load_config
RAILS_DEFAULT_LOGGER.debug "Config: #{config.inspect}"
Rails.logger.debug "Config: #{config.inspect}"
config.keys.each do |name|
RAILS_DEFAULT_LOGGER.info "Registering #{name} macro with wiki_external_filter"
Rails.logger.info "Registering #{name} macro with wiki_external_filter"
Redmine::WikiFormatting::Macros.register do
info = config[name]
desc info['description']
macro name do |obj, args|
m = WikiExternalFilterHelper::Macro.new(self, args.to_s, obj.respond_to?('page') ? obj.page.attachments : nil, name, info)
m.render
m = WikiExternalFilterHelper::Macro.new(self, args, obj.respond_to?('page') ? obj.page.attachments : nil, name, info)
m.render
end
# code borrowed from wiki latex plugin