Project

General

Profile

Feature #2876 » wiki_concurrent_edition.patch

Wiki concurrent edition patch - Pierre Paysant-Le Roux, 2009-06-30 20:24

View differences:

app/controllers/wiki_controller.rb Sun Jun 28 14:12:27 2009 +0200 → app/controllers/wiki_controller.rb Tue Jun 30 20:21:43 2009 +0200
89 89
    end
90 90
  rescue ActiveRecord::StaleObjectError
91 91
    # Optimistic locking exception
92
    flash[:error] = l(:notice_locking_conflict)
92
    # Try to merge
93
    if @content.merge
94
      flash[:notice] = l(:notice_merged)
95
      redirect_to :action => 'index', :id => @project, :page => @page.title
96
    else
97
      flash[:error] = l(:notice_locking_conflict)
98
    end    
93 99
  end
94 100
  
95 101
  # rename a page
app/models/wiki_content.rb Sun Jun 28 14:12:27 2009 +0200 → app/models/wiki_content.rb Tue Jun 30 20:21:43 2009 +0200
92 92
                                              :conditions => ["wiki_content_id = ? AND version < ?", wiki_content_id, version])
93 93
    end
94 94
  end
95

  
96
  def merge
97
    transaction do 
98
      parent_version = versions.find_by_version(version)
99
      last_version = versions.last
100
      begin
101
        conflict, merged_text = Merger.merge(text, parent_version.text, last_version.text,
102
                                             l(:label_merge_my), 
103
                                             l(:label_merge_old), 
104
                                             l(:label_merge_other,
105
                                               :author_name => last_version.author.name))
106
        self.text = merged_text
107
        self.version = last_version.version
108
        return (!conflict and save)
109
      rescue Merger::DiffBinaryNotAvailable
110
        return false
111
      end
112
    end
113
  end
114

  
95 115
end
config/locales/en.yml Sun Jun 28 14:12:27 2009 +0200 → config/locales/en.yml Tue Jun 30 20:21:43 2009 +0200
121 121
  notice_successful_connection: Successful connection.
122 122
  notice_file_not_found: The page you were trying to access doesn't exist or has been removed.
123 123
  notice_locking_conflict: Data has been updated by another user.
124
  notice_merged: "Another user edited this page in the meantime. An automatic merge occured."
124 125
  notice_not_authorized: You are not authorized to access this page.
125 126
  notice_email_sent: "An email was sent to {{value}}"
126 127
  notice_email_error: "An error occurred while sending mail ({{value}})"
......
678 679
  label_date_from_to: From {{start}} to {{end}}
679 680
  label_wiki_content_added: Wiki page added
680 681
  label_wiki_content_updated: Wiki page updated
682
  label_merge_my: "My version"
683
  label_merge_old: "Previous version"
684
  label_merge_other: "{{author_name}}'s version"
681 685
  
682 686
  button_login: Login
683 687
  button_submit: Submit
config/locales/fr.yml Sun Jun 28 14:12:27 2009 +0200 → config/locales/fr.yml Tue Jun 30 20:21:43 2009 +0200
153 153
  notice_successful_connection: Connection réussie.
154 154
  notice_file_not_found: "La page à laquelle vous souhaitez accéder n'existe pas ou a été supprimée."
155 155
  notice_locking_conflict: Les données ont été mises à jour par un autre utilisateur. Mise à jour impossible.
156
  notice_merged: "Un autre utilisateur a modifié la page en même temps que vous. Un assemblage automatique a donc eu lieu."
156 157
  notice_not_authorized: "Vous n'êtes pas autorisés à accéder à cette page."
157 158
  notice_email_sent: "Un email a été envoyé à {{value}}"
158 159
  notice_email_error: "Erreur lors de l'envoi de l'email ({{value}})"
......
708 709
  label_date_from_to: Du {{start}} au {{end}}
709 710
  label_wiki_content_added: Page wiki ajoutée
710 711
  label_wiki_content_updated: Page wiki mise à jour
712
  label_merge_my: "Ma version"
713
  label_merge_old: "Version précédente"
714
  label_merge_other: "Version de {{author_name}}"
711 715
  
712 716
  button_login: Connexion
713 717
  button_submit: Soumettre
/dev/null Thu Jan 01 00:00:00 1970 +0000 → lib/merger.rb Tue Jun 30 20:21:43 2009 +0200
1
module Merger
2
  
3
  class DiffBinaryNotAvailable < Exception
4
  end
5

  
6

  
7
  class << self    
8
    private
9
    
10
    def shell_quote(str)
11
      if RUBY_PLATFORM =~ /mswin/
12
        '"' + str.gsub(/"/, '\\"') + '"'
13
      else
14
        "'" + str.gsub(/'/, "'\"'\"'") + "'"
15
      end
16
    end
17
    
18
    def diff3_command(*opts)
19
      command = format("diff3 %s",
20
                       opts.join(" "))
21
      output = nil
22
      IO.popen(command) do |io|
23
        output = io.read  
24
      end
25
      raise "diff3 exited with an error" if $?.exitstatus > 1
26
      return output
27
    end
28
    
29
    def tempfile(content, &block)
30
      Tempfile.open("redmine_wiki_merge") do |t_file|
31
        t_file << content
32
        t_file.open
33
        yield t_file
34
      end
35
    end
36
  end
37
  
38
  begin
39
    diff3_command('-v').blank?
40
    def self.merge(mine, old, other, mine_label, old_label, other_label)
41
      tempfile(mine) do |my_file|
42
        tempfile(old) do |old_file|
43
          tempfile(other) do |other_file|
44
            conflict = diff3_command("-a", "-x", shell_quote(my_file.path),
45
                                     shell_quote(old_file.path),
46
                                     shell_quote(other_file.path))
47
            return !conflict.blank?, diff3_command("-a", "-m", "-E", 
48
                                                   "-L #{shell_quote(mine_label)}",
49
                                                   "-L #{shell_quote(old_label)}",
50
                                                   "-L #{shell_quote(other_label)}",
51
                                                   shell_quote(my_file.path),
52
                                                   shell_quote(old_file.path),
53
                                                   shell_quote(other_file.path))
54
          end
55
        end
56
      end
57
    end
58
  rescue
59
    def self.merge(*args)
60
      raise "diff3 binary not found."
61
    end
62
  end
63
end
/dev/null Thu Jan 01 00:00:00 1970 +0000 → test/unit/merger_test.rb Tue Jun 30 20:21:43 2009 +0200
1
require File.dirname(__FILE__) + '/../test_helper'
2

  
3
class MergerTest < Test::Unit::TestCase
4

  
5
  def test_simple_merge
6
    assert_equal [false, "aa\n\nbb\n"], Merger.merge("a\n\nbb\n", "a\n\nb\n", "aa\n\nb\n",
7
                                                     "my", "old", "yours")
8
  end
9

  
10
end
    (1-1/1)