##// END OF EJS Templates
scm: model: add method to switch revision graph support or not and set default false (#5501)...
Toshi MARUYAMA -
r7596:15795c438552
parent child
Show More
@@ -1,321 +1,325
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 def supports_revision_graph?
112 false
113 end
114
111 115 def entry(path=nil, identifier=nil)
112 116 scm.entry(path, identifier)
113 117 end
114 118
115 119 def entries(path=nil, identifier=nil)
116 120 scm.entries(path, identifier)
117 121 end
118 122
119 123 def branches
120 124 scm.branches
121 125 end
122 126
123 127 def tags
124 128 scm.tags
125 129 end
126 130
127 131 def default_branch
128 132 nil
129 133 end
130 134
131 135 def properties(path, identifier=nil)
132 136 scm.properties(path, identifier)
133 137 end
134 138
135 139 def cat(path, identifier=nil)
136 140 scm.cat(path, identifier)
137 141 end
138 142
139 143 def diff(path, rev, rev_to)
140 144 scm.diff(path, rev, rev_to)
141 145 end
142 146
143 147 def diff_format_revisions(cs, cs_to, sep=':')
144 148 text = ""
145 149 text << cs_to.format_identifier + sep if cs_to
146 150 text << cs.format_identifier if cs
147 151 text
148 152 end
149 153
150 154 # Returns a path relative to the url of the repository
151 155 def relative_path(path)
152 156 path
153 157 end
154 158
155 159 # Finds and returns a revision with a number or the beginning of a hash
156 160 def find_changeset_by_name(name)
157 161 return nil if name.blank?
158 162 changesets.find(:first, :conditions => (name.match(/^\d*$/) ?
159 163 ["revision = ?", name.to_s] : ["revision LIKE ?", name + '%']))
160 164 end
161 165
162 166 def latest_changeset
163 167 @latest_changeset ||= changesets.find(:first)
164 168 end
165 169
166 170 # Returns the latest changesets for +path+
167 171 # Default behaviour is to search in cached changesets
168 172 def latest_changesets(path, rev, limit=10)
169 173 if path.blank?
170 174 changesets.find(
171 175 :all,
172 176 :include => :user,
173 177 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
174 178 :limit => limit)
175 179 else
176 180 changes.find(
177 181 :all,
178 182 :include => {:changeset => :user},
179 183 :conditions => ["path = ?", path.with_leading_slash],
180 184 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
181 185 :limit => limit
182 186 ).collect(&:changeset)
183 187 end
184 188 end
185 189
186 190 def scan_changesets_for_issue_ids
187 191 self.changesets.each(&:scan_comment_for_issue_ids)
188 192 end
189 193
190 194 # Returns an array of committers usernames and associated user_id
191 195 def committers
192 196 @committers ||= Changeset.connection.select_rows(
193 197 "SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}")
194 198 end
195 199
196 200 # Maps committers username to a user ids
197 201 def committer_ids=(h)
198 202 if h.is_a?(Hash)
199 203 committers.each do |committer, user_id|
200 204 new_user_id = h[committer]
201 205 if new_user_id && (new_user_id.to_i != user_id.to_i)
202 206 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil)
203 207 Changeset.update_all(
204 208 "user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }",
205 209 ["repository_id = ? AND committer = ?", id, committer])
206 210 end
207 211 end
208 212 @committers = nil
209 213 @found_committer_users = nil
210 214 true
211 215 else
212 216 false
213 217 end
214 218 end
215 219
216 220 # Returns the Redmine User corresponding to the given +committer+
217 221 # It will return nil if the committer is not yet mapped and if no User
218 222 # with the same username or email was found
219 223 def find_committer_user(committer)
220 224 unless committer.blank?
221 225 @found_committer_users ||= {}
222 226 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
223 227
224 228 user = nil
225 229 c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user)
226 230 if c && c.user
227 231 user = c.user
228 232 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
229 233 username, email = $1.strip, $3
230 234 u = User.find_by_login(username)
231 235 u ||= User.find_by_mail(email) unless email.blank?
232 236 user = u
233 237 end
234 238 @found_committer_users[committer] = user
235 239 user
236 240 end
237 241 end
238 242
239 243 def repo_log_encoding
240 244 encoding = log_encoding.to_s.strip
241 245 encoding.blank? ? 'UTF-8' : encoding
242 246 end
243 247
244 248 # Fetches new changesets for all repositories of active projects
245 249 # Can be called periodically by an external script
246 250 # eg. ruby script/runner "Repository.fetch_changesets"
247 251 def self.fetch_changesets
248 252 Project.active.has_module(:repository).find(:all, :include => :repository).each do |project|
249 253 if project.repository
250 254 begin
251 255 project.repository.fetch_changesets
252 256 rescue Redmine::Scm::Adapters::CommandFailed => e
253 257 logger.error "scm: error during fetching changesets: #{e.message}"
254 258 end
255 259 end
256 260 end
257 261 end
258 262
259 263 # scan changeset comments to find related and fixed issues for all repositories
260 264 def self.scan_changesets_for_issue_ids
261 265 find(:all).each(&:scan_changesets_for_issue_ids)
262 266 end
263 267
264 268 def self.scm_name
265 269 'Abstract'
266 270 end
267 271
268 272 def self.available_scm
269 273 subclasses.collect {|klass| [klass.scm_name, klass.name]}
270 274 end
271 275
272 276 def self.factory(klass_name, *args)
273 277 klass = "Repository::#{klass_name}".constantize
274 278 klass.new(*args)
275 279 rescue
276 280 nil
277 281 end
278 282
279 283 def self.scm_adapter_class
280 284 nil
281 285 end
282 286
283 287 def self.scm_command
284 288 ret = ""
285 289 begin
286 290 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
287 291 rescue Exception => e
288 292 logger.error "scm: error during get command: #{e.message}"
289 293 end
290 294 ret
291 295 end
292 296
293 297 def self.scm_version_string
294 298 ret = ""
295 299 begin
296 300 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
297 301 rescue Exception => e
298 302 logger.error "scm: error during get version string: #{e.message}"
299 303 end
300 304 ret
301 305 end
302 306
303 307 def self.scm_available
304 308 ret = false
305 309 begin
306 310 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
307 311 rescue Exception => e
308 312 logger.error "scm: error during get scm available: #{e.message}"
309 313 end
310 314 ret
311 315 end
312 316
313 317 private
314 318
315 319 def clear_changesets
316 320 cs, ch, ci = Changeset.table_name, Change.table_name, "#{table_name_prefix}changesets_issues#{table_name_suffix}"
317 321 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
318 322 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
319 323 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
320 324 end
321 325 end
General Comments 0
You need to be logged in to leave comments. Login now