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