##// END OF EJS Templates
Fixed: deleted files should not be shown when browsing a Darcs repository (#2385)....
Jean-Philippe Lang -
r2187:a7a4c9f84878
parent child
Show More
@@ -1,189 +1,196
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'redmine/scm/adapters/abstract_adapter'
19 19 require 'rexml/document'
20 20
21 21 module Redmine
22 22 module Scm
23 23 module Adapters
24 24 class DarcsAdapter < AbstractAdapter
25 25 # Darcs executable name
26 26 DARCS_BIN = "darcs"
27 27
28 28 class << self
29 29 def client_version
30 30 @@client_version ||= (darcs_binary_version || [])
31 31 end
32 32
33 33 def darcs_binary_version
34 34 cmd = "#{DARCS_BIN} --version"
35 35 version = nil
36 36 shellout(cmd) do |io|
37 37 # Read darcs version in first returned line
38 38 if m = io.gets.match(%r{((\d+\.)+\d+)})
39 39 version = m[0].scan(%r{\d+}).collect(&:to_i)
40 40 end
41 41 end
42 42 return nil if $? && $?.exitstatus != 0
43 43 version
44 44 end
45 45 end
46 46
47 47 def initialize(url, root_url=nil, login=nil, password=nil)
48 48 @url = url
49 49 @root_url = url
50 50 end
51 51
52 52 def supports_cat?
53 53 # cat supported in darcs 2.0.0 and higher
54 54 self.class.client_version_above?([2, 0, 0])
55 55 end
56 56
57 57 # Get info about the darcs repository
58 58 def info
59 59 rev = revisions(nil,nil,nil,{:limit => 1})
60 60 rev ? Info.new({:root_url => @url, :lastrev => rev.last}) : nil
61 61 end
62 62
63 63 # Returns an Entries collection
64 64 # or nil if the given path doesn't exist in the repository
65 65 def entries(path=nil, identifier=nil)
66 66 path_prefix = (path.blank? ? '' : "#{path}/")
67 67 path = '.' if path.blank?
68 68 entries = Entries.new
69 69 cmd = "#{DARCS_BIN} annotate --repodir #{@url} --xml-output"
70 70 cmd << " --match \"hash #{identifier}\"" if identifier
71 71 cmd << " #{path}"
72 72 shellout(cmd) do |io|
73 73 begin
74 74 doc = REXML::Document.new(io)
75 75 if doc.root.name == 'directory'
76 76 doc.elements.each('directory/*') do |element|
77 77 next unless ['file', 'directory'].include? element.name
78 78 entries << entry_from_xml(element, path_prefix)
79 79 end
80 80 elsif doc.root.name == 'file'
81 81 entries << entry_from_xml(doc.root, path_prefix)
82 82 end
83 83 rescue
84 84 end
85 85 end
86 86 return nil if $? && $?.exitstatus != 0
87 entries.sort_by_name
87 entries.compact.sort_by_name
88 88 end
89 89
90 90 def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
91 91 path = '.' if path.blank?
92 92 revisions = Revisions.new
93 93 cmd = "#{DARCS_BIN} changes --repodir #{@url} --xml-output"
94 94 cmd << " --from-match \"hash #{identifier_from}\"" if identifier_from
95 95 cmd << " --last #{options[:limit].to_i}" if options[:limit]
96 96 shellout(cmd) do |io|
97 97 begin
98 98 doc = REXML::Document.new(io)
99 99 doc.elements.each("changelog/patch") do |patch|
100 100 message = patch.elements['name'].text
101 101 message << "\n" + patch.elements['comment'].text.gsub(/\*\*\*END OF DESCRIPTION\*\*\*.*\z/m, '') if patch.elements['comment']
102 102 revisions << Revision.new({:identifier => nil,
103 103 :author => patch.attributes['author'],
104 104 :scmid => patch.attributes['hash'],
105 105 :time => Time.parse(patch.attributes['local_date']),
106 106 :message => message,
107 107 :paths => (options[:with_path] ? get_paths_for_patch(patch.attributes['hash']) : nil)
108 108 })
109 109 end
110 110 rescue
111 111 end
112 112 end
113 113 return nil if $? && $?.exitstatus != 0
114 114 revisions
115 115 end
116 116
117 117 def diff(path, identifier_from, identifier_to=nil)
118 118 path = '*' if path.blank?
119 119 cmd = "#{DARCS_BIN} diff --repodir #{@url}"
120 120 if identifier_to.nil?
121 121 cmd << " --match \"hash #{identifier_from}\""
122 122 else
123 123 cmd << " --to-match \"hash #{identifier_from}\""
124 124 cmd << " --from-match \"hash #{identifier_to}\""
125 125 end
126 126 cmd << " -u #{path}"
127 127 diff = []
128 128 shellout(cmd) do |io|
129 129 io.each_line do |line|
130 130 diff << line
131 131 end
132 132 end
133 133 return nil if $? && $?.exitstatus != 0
134 134 diff
135 135 end
136 136
137 137 def cat(path, identifier=nil)
138 138 cmd = "#{DARCS_BIN} show content --repodir #{@url}"
139 139 cmd << " --match \"hash #{identifier}\"" if identifier
140 140 cmd << " #{shell_quote path}"
141 141 cat = nil
142 142 shellout(cmd) do |io|
143 143 io.binmode
144 144 cat = io.read
145 145 end
146 146 return nil if $? && $?.exitstatus != 0
147 147 cat
148 148 end
149 149
150 150 private
151
151
152 # Returns an Entry from the given XML element
153 # or nil if the entry was deleted
152 154 def entry_from_xml(element, path_prefix)
155 modified_element = element.elements['modified']
156 if modified_element.elements['modified_how'].text.match(/removed/)
157 return nil
158 end
159
153 160 Entry.new({:name => element.attributes['name'],
154 161 :path => path_prefix + element.attributes['name'],
155 162 :kind => element.name == 'file' ? 'file' : 'dir',
156 163 :size => nil,
157 164 :lastrev => Revision.new({
158 165 :identifier => nil,
159 :scmid => element.elements['modified'].elements['patch'].attributes['hash']
166 :scmid => modified_element.elements['patch'].attributes['hash']
160 167 })
161 168 })
162 169 end
163 170
164 171 # Retrieve changed paths for a single patch
165 172 def get_paths_for_patch(hash)
166 173 cmd = "#{DARCS_BIN} annotate --repodir #{@url} --summary --xml-output"
167 174 cmd << " --match \"hash #{hash}\" "
168 175 paths = []
169 176 shellout(cmd) do |io|
170 177 begin
171 178 # Darcs xml output has multiple root elements in this case (tested with darcs 1.0.7)
172 179 # A root element is added so that REXML doesn't raise an error
173 180 doc = REXML::Document.new("<fake_root>" + io.read + "</fake_root>")
174 181 doc.elements.each('fake_root/summary/*') do |modif|
175 182 paths << {:action => modif.name[0,1].upcase,
176 183 :path => "/" + modif.text.chomp.gsub(/^\s*/, '')
177 184 }
178 185 end
179 186 rescue
180 187 end
181 188 end
182 189 paths
183 190 rescue CommandFailed
184 191 paths
185 192 end
186 193 end
187 194 end
188 195 end
189 196 end
@@ -1,62 +1,68
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2008 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.dirname(__FILE__) + '/../test_helper'
19 19
20 20 class RepositoryDarcsTest < Test::Unit::TestCase
21 21 fixtures :projects
22 22
23 23 # No '..' in the repository path
24 24 REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/darcs_repository'
25 25
26 26 def setup
27 27 @project = Project.find(1)
28 28 assert @repository = Repository::Darcs.create(:project => @project, :url => REPOSITORY_PATH)
29 29 end
30 30
31 31 if File.directory?(REPOSITORY_PATH)
32 32 def test_fetch_changesets_from_scratch
33 33 @repository.fetch_changesets
34 34 @repository.reload
35 35
36 36 assert_equal 6, @repository.changesets.count
37 37 assert_equal 13, @repository.changes.count
38 38 assert_equal "Initial commit.", @repository.changesets.find_by_revision('1').comments
39 39 end
40 40
41 41 def test_fetch_changesets_incremental
42 42 @repository.fetch_changesets
43 43 # Remove changesets with revision > 3
44 44 @repository.changesets.find(:all).each {|c| c.destroy if c.revision.to_i > 3}
45 45 @repository.reload
46 46 assert_equal 3, @repository.changesets.count
47 47
48 48 @repository.fetch_changesets
49 49 assert_equal 6, @repository.changesets.count
50 50 end
51 51
52 def test_deleted_files_should_not_be_listed
53 entries = @repository.entries('sources')
54 assert entries.detect {|e| e.name == 'watchers_controller.rb'}
55 assert_nil entries.detect {|e| e.name == 'welcome_controller.rb'}
56 end
57
52 58 def test_cat
53 59 @repository.fetch_changesets
54 60 cat = @repository.cat("sources/welcome_controller.rb", 2)
55 61 assert_not_nil cat
56 62 assert cat.include?('class WelcomeController < ApplicationController')
57 63 end
58 64 else
59 65 puts "Darcs test repository NOT FOUND. Skipping unit tests !!!"
60 66 def test_fake; assert true end
61 67 end
62 68 end
General Comments 0
You need to be logged in to leave comments. Login now