##// END OF EJS Templates
scm: set supporting directory revisions or not at scm level....
Toshi MARUYAMA -
r5024:bae1763a09ae
parent child
Show More
@@ -1,286 +1,290
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 class Repository < ActiveRecord::Base
19 19 include Redmine::Ciphering
20 20
21 21 belongs_to :project
22 22 has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
23 23 has_many :changes, :through => :changesets
24 24
25 25 # Raw SQL to delete changesets and changes in the database
26 26 # has_many :changesets, :dependent => :destroy is too slow for big repositories
27 27 before_destroy :clear_changesets
28 28
29 29 validates_length_of :password, :maximum => 255, :allow_nil => true
30 30 # Checks if the SCM is enabled when creating a repository
31 31 validate_on_create { |r| r.errors.add(:type, :invalid) unless Setting.enabled_scm.include?(r.class.name.demodulize) }
32 32
33 33 # Removes leading and trailing whitespace
34 34 def url=(arg)
35 35 write_attribute(:url, arg ? arg.to_s.strip : nil)
36 36 end
37 37
38 38 # Removes leading and trailing whitespace
39 39 def root_url=(arg)
40 40 write_attribute(:root_url, arg ? arg.to_s.strip : nil)
41 41 end
42 42
43 43 def password
44 44 read_ciphered_attribute(:password)
45 45 end
46 46
47 47 def password=(arg)
48 48 write_ciphered_attribute(:password, arg)
49 49 end
50 50
51 51 def scm_adapter
52 52 self.class.scm_adapter_class
53 53 end
54 54
55 55 def scm
56 56 @scm ||= self.scm_adapter.new(url, root_url,
57 57 login, password, path_encoding)
58 58 update_attribute(:root_url, @scm.root_url) if root_url.blank?
59 59 @scm
60 60 end
61 61
62 62 def scm_name
63 63 self.class.scm_name
64 64 end
65 65
66 66 def supports_cat?
67 67 scm.supports_cat?
68 68 end
69 69
70 70 def supports_annotate?
71 71 scm.supports_annotate?
72 72 end
73 73
74 74 def supports_all_revisions?
75 75 true
76 76 end
77 77
78 def supports_directory_revisions?
79 false
80 end
81
78 82 def entry(path=nil, identifier=nil)
79 83 scm.entry(path, identifier)
80 84 end
81 85
82 86 def entries(path=nil, identifier=nil)
83 87 scm.entries(path, identifier)
84 88 end
85 89
86 90 def branches
87 91 scm.branches
88 92 end
89 93
90 94 def tags
91 95 scm.tags
92 96 end
93 97
94 98 def default_branch
95 99 scm.default_branch
96 100 end
97 101
98 102 def properties(path, identifier=nil)
99 103 scm.properties(path, identifier)
100 104 end
101 105
102 106 def cat(path, identifier=nil)
103 107 scm.cat(path, identifier)
104 108 end
105 109
106 110 def diff(path, rev, rev_to)
107 111 scm.diff(path, rev, rev_to)
108 112 end
109 113
110 114 def diff_format_revisions(cs, cs_to, sep=':')
111 115 text = ""
112 116 text << cs_to.format_identifier + sep if cs_to
113 117 text << cs.format_identifier if cs
114 118 text
115 119 end
116 120
117 121 # Returns a path relative to the url of the repository
118 122 def relative_path(path)
119 123 path
120 124 end
121 125
122 126 # Finds and returns a revision with a number or the beginning of a hash
123 127 def find_changeset_by_name(name)
124 128 return nil if name.blank?
125 129 changesets.find(:first, :conditions => (name.match(/^\d*$/) ? ["revision = ?", name.to_s] : ["revision LIKE ?", name + '%']))
126 130 end
127 131
128 132 def latest_changeset
129 133 @latest_changeset ||= changesets.find(:first)
130 134 end
131 135
132 136 # Returns the latest changesets for +path+
133 137 # Default behaviour is to search in cached changesets
134 138 def latest_changesets(path, rev, limit=10)
135 139 if path.blank?
136 140 changesets.find(:all, :include => :user,
137 141 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
138 142 :limit => limit)
139 143 else
140 144 changes.find(:all, :include => {:changeset => :user},
141 145 :conditions => ["path = ?", path.with_leading_slash],
142 146 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
143 147 :limit => limit).collect(&:changeset)
144 148 end
145 149 end
146 150
147 151 def scan_changesets_for_issue_ids
148 152 self.changesets.each(&:scan_comment_for_issue_ids)
149 153 end
150 154
151 155 # Returns an array of committers usernames and associated user_id
152 156 def committers
153 157 @committers ||= Changeset.connection.select_rows("SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}")
154 158 end
155 159
156 160 # Maps committers username to a user ids
157 161 def committer_ids=(h)
158 162 if h.is_a?(Hash)
159 163 committers.each do |committer, user_id|
160 164 new_user_id = h[committer]
161 165 if new_user_id && (new_user_id.to_i != user_id.to_i)
162 166 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil)
163 167 Changeset.update_all("user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }", ["repository_id = ? AND committer = ?", id, committer])
164 168 end
165 169 end
166 170 @committers = nil
167 171 @found_committer_users = nil
168 172 true
169 173 else
170 174 false
171 175 end
172 176 end
173 177
174 178 # Returns the Redmine User corresponding to the given +committer+
175 179 # It will return nil if the committer is not yet mapped and if no User
176 180 # with the same username or email was found
177 181 def find_committer_user(committer)
178 182 unless committer.blank?
179 183 @found_committer_users ||= {}
180 184 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
181 185
182 186 user = nil
183 187 c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user)
184 188 if c && c.user
185 189 user = c.user
186 190 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
187 191 username, email = $1.strip, $3
188 192 u = User.find_by_login(username)
189 193 u ||= User.find_by_mail(email) unless email.blank?
190 194 user = u
191 195 end
192 196 @found_committer_users[committer] = user
193 197 user
194 198 end
195 199 end
196 200
197 201 def repo_log_encoding
198 202 encoding = log_encoding.to_s.strip
199 203 encoding.blank? ? 'UTF-8' : encoding
200 204 end
201 205
202 206 # Fetches new changesets for all repositories of active projects
203 207 # Can be called periodically by an external script
204 208 # eg. ruby script/runner "Repository.fetch_changesets"
205 209 def self.fetch_changesets
206 210 Project.active.has_module(:repository).find(:all, :include => :repository).each do |project|
207 211 if project.repository
208 212 begin
209 213 project.repository.fetch_changesets
210 214 rescue Redmine::Scm::Adapters::CommandFailed => e
211 215 logger.error "scm: error during fetching changesets: #{e.message}"
212 216 end
213 217 end
214 218 end
215 219 end
216 220
217 221 # scan changeset comments to find related and fixed issues for all repositories
218 222 def self.scan_changesets_for_issue_ids
219 223 find(:all).each(&:scan_changesets_for_issue_ids)
220 224 end
221 225
222 226 def self.scm_name
223 227 'Abstract'
224 228 end
225 229
226 230 def self.available_scm
227 231 subclasses.collect {|klass| [klass.scm_name, klass.name]}
228 232 end
229 233
230 234 def self.factory(klass_name, *args)
231 235 klass = "Repository::#{klass_name}".constantize
232 236 klass.new(*args)
233 237 rescue
234 238 nil
235 239 end
236 240
237 241 def self.scm_adapter_class
238 242 nil
239 243 end
240 244
241 245 def self.scm_command
242 246 ret = ""
243 247 begin
244 248 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
245 249 rescue Redmine::Scm::Adapters::CommandFailed => e
246 250 logger.error "scm: error during get command: #{e.message}"
247 251 end
248 252 ret
249 253 end
250 254
251 255 def self.scm_version_string
252 256 ret = ""
253 257 begin
254 258 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
255 259 rescue Redmine::Scm::Adapters::CommandFailed => e
256 260 logger.error "scm: error during get version string: #{e.message}"
257 261 end
258 262 ret
259 263 end
260 264
261 265 def self.scm_available
262 266 ret = false
263 267 begin
264 268 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
265 269 rescue Redmine::Scm::Adapters::CommandFailed => e
266 270 logger.error "scm: error during get scm available: #{e.message}"
267 271 end
268 272 ret
269 273 end
270 274
271 275 private
272 276
273 277 def before_save
274 278 # Strips url and root_url
275 279 url.strip!
276 280 root_url.strip!
277 281 true
278 282 end
279 283
280 284 def clear_changesets
281 285 cs, ch, ci = Changeset.table_name, Change.table_name, "#{table_name_prefix}changesets_issues#{table_name_suffix}"
282 286 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
283 287 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
284 288 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
285 289 end
286 290 end
@@ -1,130 +1,134
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 # Copyright (C) 2007 Patrick Aljord patcito@Ε‹mail.com
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/git_adapter'
19 19
20 20 class Repository::Git < Repository
21 21 attr_protected :root_url
22 22 validates_presence_of :url
23 23
24 24 ATTRIBUTE_KEY_NAMES = {
25 25 "url" => "Path to repository",
26 26 }
27 27 def self.human_attribute_name(attribute_key_name)
28 28 ATTRIBUTE_KEY_NAMES[attribute_key_name] || super
29 29 end
30 30
31 31 def self.scm_adapter_class
32 32 Redmine::Scm::Adapters::GitAdapter
33 33 end
34 34
35 35 def self.scm_name
36 36 'Git'
37 37 end
38 38
39 def supports_directory_revisions?
40 true
41 end
42
39 43 def repo_log_encoding
40 44 'UTF-8'
41 45 end
42 46
43 47 # Returns the identifier for the given git changeset
44 48 def self.changeset_identifier(changeset)
45 49 changeset.scmid
46 50 end
47 51
48 52 # Returns the readable identifier for the given git changeset
49 53 def self.format_changeset_identifier(changeset)
50 54 changeset.revision[0, 8]
51 55 end
52 56
53 57 def branches
54 58 scm.branches
55 59 end
56 60
57 61 def tags
58 62 scm.tags
59 63 end
60 64
61 65 def find_changeset_by_name(name)
62 66 return nil if name.nil? || name.empty?
63 67 e = changesets.find(:first, :conditions => ['revision = ?', name.to_s])
64 68 return e if e
65 69 changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"])
66 70 end
67 71
68 72 # With SCM's that have a sequential commit numbering, redmine is able to be
69 73 # clever and only fetch changesets going forward from the most recent one
70 74 # it knows about. However, with git, you never know if people have merged
71 75 # commits into the middle of the repository history, so we should parse
72 76 # the entire log. Since it's way too slow for large repositories, we only
73 77 # parse 1 week before the last known commit.
74 78 # The repository can still be fully reloaded by calling #clear_changesets
75 79 # before fetching changesets (eg. for offline resync)
76 80 def fetch_changesets
77 81 c = changesets.find(:first, :order => 'committed_on DESC')
78 82 since = (c ? c.committed_on - 7.days : nil)
79 83
80 84 revisions = scm.revisions('', nil, nil, {:all => true, :since => since, :reverse => true})
81 85 return if revisions.nil? || revisions.empty?
82 86
83 87 recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since])
84 88
85 89 # Clean out revisions that are no longer in git
86 90 recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }}
87 91
88 92 # Subtract revisions that redmine already knows about
89 93 recent_revisions = recent_changesets.map{|c| c.scmid}
90 94 revisions.reject!{|r| recent_revisions.include?(r.scmid)}
91 95
92 96 # Save the remaining ones to the database
93 97 unless revisions.nil?
94 98 revisions.each do |rev|
95 99 transaction do
96 100 changeset = Changeset.new(
97 101 :repository => self,
98 102 :revision => rev.identifier,
99 103 :scmid => rev.scmid,
100 104 :committer => rev.author,
101 105 :committed_on => rev.time,
102 106 :comments => rev.message)
103 107
104 108 if changeset.save
105 109 rev.paths.each do |file|
106 110 Change.create(
107 111 :changeset => changeset,
108 112 :action => file[:action],
109 113 :path => file[:path])
110 114 end
111 115 end
112 116 end
113 117 end
114 118 end
115 119 end
116 120
117 121 def latest_changesets(path,rev,limit=10)
118 122 revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
119 123 return [] if revisions.nil? || revisions.empty?
120 124
121 125 changesets.find(
122 126 :all,
123 127 :conditions => [
124 128 "scmid IN (?)",
125 129 revisions.map!{|c| c.scmid}
126 130 ],
127 131 :order => 'committed_on DESC'
128 132 )
129 133 end
130 134 end
@@ -1,138 +1,142
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/mercurial_adapter'
19 19
20 20 class Repository::Mercurial < Repository
21 21 # sort changesets by revision number
22 22 has_many :changesets, :order => "#{Changeset.table_name}.id DESC", :foreign_key => 'repository_id'
23 23
24 24 attr_protected :root_url
25 25 validates_presence_of :url
26 26
27 27 FETCH_AT_ONCE = 100 # number of changesets to fetch at once
28 28
29 29 ATTRIBUTE_KEY_NAMES = {
30 30 "url" => "Root directory",
31 31 }
32 32 def self.human_attribute_name(attribute_key_name)
33 33 ATTRIBUTE_KEY_NAMES[attribute_key_name] || super
34 34 end
35 35
36 36 def self.scm_adapter_class
37 37 Redmine::Scm::Adapters::MercurialAdapter
38 38 end
39 39
40 40 def self.scm_name
41 41 'Mercurial'
42 42 end
43 43
44 def supports_directory_revisions?
45 true
46 end
47
44 48 def repo_log_encoding
45 49 'UTF-8'
46 50 end
47 51
48 52 # Returns the readable identifier for the given mercurial changeset
49 53 def self.format_changeset_identifier(changeset)
50 54 "#{changeset.revision}:#{changeset.scmid}"
51 55 end
52 56
53 57 # Returns the identifier for the given Mercurial changeset
54 58 def self.changeset_identifier(changeset)
55 59 changeset.scmid
56 60 end
57 61
58 62 def diff_format_revisions(cs, cs_to, sep=':')
59 63 super(cs, cs_to, ' ')
60 64 end
61 65
62 66 # Finds and returns a revision with a number or the beginning of a hash
63 67 def find_changeset_by_name(name)
64 68 return nil if name.nil? || name.empty?
65 69 if /[^\d]/ =~ name or name.to_s.size > 8
66 70 e = changesets.find(:first, :conditions => ['scmid = ?', name.to_s])
67 71 else
68 72 e = changesets.find(:first, :conditions => ['revision = ?', name.to_s])
69 73 end
70 74 return e if e
71 75 changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"]) # last ditch
72 76 end
73 77
74 78 # Returns the latest changesets for +path+; sorted by revision number
75 79 #
76 80 # Because :order => 'id DESC' is defined at 'has_many',
77 81 # there is no need to set 'order'.
78 82 # But, MySQL test fails.
79 83 # Sqlite3 and PostgreSQL pass.
80 84 # Is this MySQL bug?
81 85 def latest_changesets(path, rev, limit=10)
82 86 changesets.find(:all, :include => :user,
83 87 :conditions => latest_changesets_cond(path, rev, limit),
84 88 :limit => limit, :order => "#{Changeset.table_name}.id DESC")
85 89 end
86 90
87 91 def latest_changesets_cond(path, rev, limit)
88 92 cond, args = [], []
89 93 if scm.branchmap.member? rev
90 94 # Mercurial named branch is *stable* in each revision.
91 95 # So, named branch can be stored in database.
92 96 # Mercurial provides *bookmark* which is equivalent with git branch.
93 97 # But, bookmark is not implemented.
94 98 cond << "#{Changeset.table_name}.scmid IN (?)"
95 99 # Revisions in root directory and sub directory are not equal.
96 100 # So, in order to get correct limit, we need to get all revisions.
97 101 # But, it is very heavy.
98 102 args << scm.nodes_in_branch(rev, :limit => limit)
99 103 elsif last = rev ? find_changeset_by_name(scm.tagmap[rev] || rev) : nil
100 104 cond << "#{Changeset.table_name}.id <= ?"
101 105 args << last.id
102 106 end
103 107
104 108 unless path.blank?
105 109 cond << "EXISTS (SELECT * FROM #{Change.table_name}
106 110 WHERE #{Change.table_name}.changeset_id = #{Changeset.table_name}.id
107 111 AND (#{Change.table_name}.path = ?
108 112 OR #{Change.table_name}.path LIKE ? ESCAPE ?))"
109 113 args << path.with_leading_slash
110 114 args << "#{path.with_leading_slash.gsub(/[%_\\]/) { |s| "\\#{s}" }}/%" << '\\'
111 115 end
112 116
113 117 [cond.join(' AND '), *args] unless cond.empty?
114 118 end
115 119 private :latest_changesets_cond
116 120
117 121 def fetch_changesets
118 122 scm_rev = scm.info.lastrev.revision.to_i
119 123 db_rev = latest_changeset ? latest_changeset.revision.to_i : -1
120 124 return unless db_rev < scm_rev # already up-to-date
121 125
122 126 logger.debug "Fetching changesets for repository #{url}" if logger
123 127 (db_rev + 1).step(scm_rev, FETCH_AT_ONCE) do |i|
124 128 transaction do
125 129 scm.each_revision('', i, [i + FETCH_AT_ONCE - 1, scm_rev].min) do |re|
126 130 cs = Changeset.create(:repository => self,
127 131 :revision => re.revision,
128 132 :scmid => re.scmid,
129 133 :committer => re.author,
130 134 :committed_on => re.time,
131 135 :comments => re.message)
132 136 re.paths.each { |e| cs.create_change(e) }
133 137 end
134 138 end
135 139 end
136 140 self
137 141 end
138 142 end
@@ -1,89 +1,93
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/subversion_adapter'
19 19
20 20 class Repository::Subversion < Repository
21 21 attr_protected :root_url
22 22 validates_presence_of :url
23 23 validates_format_of :url, :with => /^(http|https|svn(\+[^\s:\/\\]+)?|file):\/\/.+/i
24 24
25 25 def self.scm_adapter_class
26 26 Redmine::Scm::Adapters::SubversionAdapter
27 27 end
28 28
29 29 def self.scm_name
30 30 'Subversion'
31 31 end
32 32
33 def supports_directory_revisions?
34 true
35 end
36
33 37 def repo_log_encoding
34 38 'UTF-8'
35 39 end
36 40
37 41 def latest_changesets(path, rev, limit=10)
38 42 revisions = scm.revisions(path, rev, nil, :limit => limit)
39 43 revisions ? changesets.find_all_by_revision(revisions.collect(&:identifier), :order => "committed_on DESC", :include => :user) : []
40 44 end
41 45
42 46 # Returns a path relative to the url of the repository
43 47 def relative_path(path)
44 48 path.gsub(Regexp.new("^\/?#{Regexp.escape(relative_url)}"), '')
45 49 end
46 50
47 51 def fetch_changesets
48 52 scm_info = scm.info
49 53 if scm_info
50 54 # latest revision found in database
51 55 db_revision = latest_changeset ? latest_changeset.revision.to_i : 0
52 56 # latest revision in the repository
53 57 scm_revision = scm_info.lastrev.identifier.to_i
54 58 if db_revision < scm_revision
55 59 logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug?
56 60 identifier_from = db_revision + 1
57 61 while (identifier_from <= scm_revision)
58 62 # loads changesets by batches of 200
59 63 identifier_to = [identifier_from + 199, scm_revision].min
60 64 revisions = scm.revisions('', identifier_to, identifier_from, :with_paths => true)
61 65 revisions.reverse_each do |revision|
62 66 transaction do
63 67 changeset = Changeset.create(:repository => self,
64 68 :revision => revision.identifier,
65 69 :committer => revision.author,
66 70 :committed_on => revision.time,
67 71 :comments => revision.message)
68 72
69 73 revision.paths.each do |change|
70 74 changeset.create_change(change)
71 75 end unless changeset.new_record?
72 76 end
73 77 end unless revisions.nil?
74 78 identifier_from = identifier_to + 1
75 79 end
76 80 end
77 81 end
78 82 end
79 83
80 84 private
81 85
82 86 # Returns the relative url of the repository
83 87 # Eg: root_url = file:///var/svn/foo
84 88 # url = file:///var/svn/foo/bar
85 89 # => returns /bar
86 90 def relative_url
87 91 @relative_url ||= url.gsub(Regexp.new("^#{Regexp.escape(root_url || scm.root_url)}", Regexp::IGNORECASE), '')
88 92 end
89 93 end
General Comments 0
You need to be logged in to leave comments. Login now