##// END OF EJS Templates
scm: remove before_save() because of duplicate at url=(arg) and root_url=(arg)....
Toshi MARUYAMA -
r6708:93b838c3f768
parent child
Show More
@@ -1,328 +1,321
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 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 ScmFetchError < Exception; end
19 19
20 20 class Repository < ActiveRecord::Base
21 21 include Redmine::Ciphering
22 22
23 23 belongs_to :project
24 24 has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
25 25 has_many :changes, :through => :changesets
26 26
27 27 serialize :extra_info
28 28
29 29 # Raw SQL to delete changesets and changes in the database
30 30 # has_many :changesets, :dependent => :destroy is too slow for big repositories
31 31 before_destroy :clear_changesets
32 32
33 33 validates_length_of :password, :maximum => 255, :allow_nil => true
34 34 # Checks if the SCM is enabled when creating a repository
35 35 validate :repo_create_validation, :on => :create
36 36
37 37 def repo_create_validation
38 38 unless Setting.enabled_scm.include?(self.class.name.demodulize)
39 39 errors.add(:type, :invalid)
40 40 end
41 41 end
42 42
43 43 def self.human_attribute_name(attribute_key_name)
44 44 attr_name = attribute_key_name
45 45 if attr_name == "log_encoding"
46 46 attr_name = "commit_logs_encoding"
47 47 end
48 48 super(attr_name)
49 49 end
50 50
51 51 # Removes leading and trailing whitespace
52 52 def url=(arg)
53 53 write_attribute(:url, arg ? arg.to_s.strip : nil)
54 54 end
55 55
56 56 # Removes leading and trailing whitespace
57 57 def root_url=(arg)
58 58 write_attribute(:root_url, arg ? arg.to_s.strip : nil)
59 59 end
60 60
61 61 def password
62 62 read_ciphered_attribute(:password)
63 63 end
64 64
65 65 def password=(arg)
66 66 write_ciphered_attribute(:password, arg)
67 67 end
68 68
69 69 def scm_adapter
70 70 self.class.scm_adapter_class
71 71 end
72 72
73 73 def scm
74 74 @scm ||= self.scm_adapter.new(url, root_url,
75 75 login, password, path_encoding)
76 76 update_attribute(:root_url, @scm.root_url) if root_url.blank?
77 77 @scm
78 78 end
79 79
80 80 def scm_name
81 81 self.class.scm_name
82 82 end
83 83
84 84 def merge_extra_info(arg)
85 85 h = extra_info || {}
86 86 return h if arg.nil?
87 87 h.merge!(arg)
88 88 write_attribute(:extra_info, h)
89 89 end
90 90
91 91 def report_last_commit
92 92 true
93 93 end
94 94
95 95 def supports_cat?
96 96 scm.supports_cat?
97 97 end
98 98
99 99 def supports_annotate?
100 100 scm.supports_annotate?
101 101 end
102 102
103 103 def supports_all_revisions?
104 104 true
105 105 end
106 106
107 107 def supports_directory_revisions?
108 108 false
109 109 end
110 110
111 111 def entry(path=nil, identifier=nil)
112 112 scm.entry(path, identifier)
113 113 end
114 114
115 115 def entries(path=nil, identifier=nil)
116 116 scm.entries(path, identifier)
117 117 end
118 118
119 119 def branches
120 120 scm.branches
121 121 end
122 122
123 123 def tags
124 124 scm.tags
125 125 end
126 126
127 127 def default_branch
128 128 nil
129 129 end
130 130
131 131 def properties(path, identifier=nil)
132 132 scm.properties(path, identifier)
133 133 end
134 134
135 135 def cat(path, identifier=nil)
136 136 scm.cat(path, identifier)
137 137 end
138 138
139 139 def diff(path, rev, rev_to)
140 140 scm.diff(path, rev, rev_to)
141 141 end
142 142
143 143 def diff_format_revisions(cs, cs_to, sep=':')
144 144 text = ""
145 145 text << cs_to.format_identifier + sep if cs_to
146 146 text << cs.format_identifier if cs
147 147 text
148 148 end
149 149
150 150 # Returns a path relative to the url of the repository
151 151 def relative_path(path)
152 152 path
153 153 end
154 154
155 155 # Finds and returns a revision with a number or the beginning of a hash
156 156 def find_changeset_by_name(name)
157 157 return nil if name.blank?
158 158 changesets.find(:first, :conditions => (name.match(/^\d*$/) ?
159 159 ["revision = ?", name.to_s] : ["revision LIKE ?", name + '%']))
160 160 end
161 161
162 162 def latest_changeset
163 163 @latest_changeset ||= changesets.find(:first)
164 164 end
165 165
166 166 # Returns the latest changesets for +path+
167 167 # Default behaviour is to search in cached changesets
168 168 def latest_changesets(path, rev, limit=10)
169 169 if path.blank?
170 170 changesets.find(
171 171 :all,
172 172 :include => :user,
173 173 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
174 174 :limit => limit)
175 175 else
176 176 changes.find(
177 177 :all,
178 178 :include => {:changeset => :user},
179 179 :conditions => ["path = ?", path.with_leading_slash],
180 180 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
181 181 :limit => limit
182 182 ).collect(&:changeset)
183 183 end
184 184 end
185 185
186 186 def scan_changesets_for_issue_ids
187 187 self.changesets.each(&:scan_comment_for_issue_ids)
188 188 end
189 189
190 190 # Returns an array of committers usernames and associated user_id
191 191 def committers
192 192 @committers ||= Changeset.connection.select_rows(
193 193 "SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}")
194 194 end
195 195
196 196 # Maps committers username to a user ids
197 197 def committer_ids=(h)
198 198 if h.is_a?(Hash)
199 199 committers.each do |committer, user_id|
200 200 new_user_id = h[committer]
201 201 if new_user_id && (new_user_id.to_i != user_id.to_i)
202 202 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil)
203 203 Changeset.update_all(
204 204 "user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }",
205 205 ["repository_id = ? AND committer = ?", id, committer])
206 206 end
207 207 end
208 208 @committers = nil
209 209 @found_committer_users = nil
210 210 true
211 211 else
212 212 false
213 213 end
214 214 end
215 215
216 216 # Returns the Redmine User corresponding to the given +committer+
217 217 # It will return nil if the committer is not yet mapped and if no User
218 218 # with the same username or email was found
219 219 def find_committer_user(committer)
220 220 unless committer.blank?
221 221 @found_committer_users ||= {}
222 222 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
223 223
224 224 user = nil
225 225 c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user)
226 226 if c && c.user
227 227 user = c.user
228 228 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
229 229 username, email = $1.strip, $3
230 230 u = User.find_by_login(username)
231 231 u ||= User.find_by_mail(email) unless email.blank?
232 232 user = u
233 233 end
234 234 @found_committer_users[committer] = user
235 235 user
236 236 end
237 237 end
238 238
239 239 def repo_log_encoding
240 240 encoding = log_encoding.to_s.strip
241 241 encoding.blank? ? 'UTF-8' : encoding
242 242 end
243 243
244 244 # Fetches new changesets for all repositories of active projects
245 245 # Can be called periodically by an external script
246 246 # eg. ruby script/runner "Repository.fetch_changesets"
247 247 def self.fetch_changesets
248 248 Project.active.has_module(:repository).find(:all, :include => :repository).each do |project|
249 249 if project.repository
250 250 begin
251 251 project.repository.fetch_changesets
252 252 rescue Redmine::Scm::Adapters::CommandFailed => e
253 253 logger.error "scm: error during fetching changesets: #{e.message}"
254 254 end
255 255 end
256 256 end
257 257 end
258 258
259 259 # scan changeset comments to find related and fixed issues for all repositories
260 260 def self.scan_changesets_for_issue_ids
261 261 find(:all).each(&:scan_changesets_for_issue_ids)
262 262 end
263 263
264 264 def self.scm_name
265 265 'Abstract'
266 266 end
267 267
268 268 def self.available_scm
269 269 subclasses.collect {|klass| [klass.scm_name, klass.name]}
270 270 end
271 271
272 272 def self.factory(klass_name, *args)
273 273 klass = "Repository::#{klass_name}".constantize
274 274 klass.new(*args)
275 275 rescue
276 276 nil
277 277 end
278 278
279 279 def self.scm_adapter_class
280 280 nil
281 281 end
282 282
283 283 def self.scm_command
284 284 ret = ""
285 285 begin
286 286 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
287 287 rescue Exception => e
288 288 logger.error "scm: error during get command: #{e.message}"
289 289 end
290 290 ret
291 291 end
292 292
293 293 def self.scm_version_string
294 294 ret = ""
295 295 begin
296 296 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
297 297 rescue Exception => e
298 298 logger.error "scm: error during get version string: #{e.message}"
299 299 end
300 300 ret
301 301 end
302 302
303 303 def self.scm_available
304 304 ret = false
305 305 begin
306 306 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
307 307 rescue Exception => e
308 308 logger.error "scm: error during get scm available: #{e.message}"
309 309 end
310 310 ret
311 311 end
312 312
313 313 private
314 314
315 def before_save
316 # Strips url and root_url
317 url.strip!
318 root_url.strip!
319 true
320 end
321
322 315 def clear_changesets
323 316 cs, ch, ci = Changeset.table_name, Change.table_name, "#{table_name_prefix}changesets_issues#{table_name_suffix}"
324 317 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
325 318 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
326 319 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
327 320 end
328 321 end
General Comments 0
You need to be logged in to leave comments. Login now