comparison app/models/.svn/text-base/repository.rb.svn-base @ 441:cbce1fd3b1b7 redmine-1.2

Update to Redmine 1.2-stable branch (Redmine SVN rev 6000)
author Chris Cannam
date Mon, 06 Jun 2011 14:24:13 +0100
parents 051f544170fe
children 753f1380d6bc 0c939c159af4
comparison
equal deleted inserted replaced
245:051f544170fe 441:cbce1fd3b1b7
1 # redMine - project management software 1 # Redmine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 # 3 #
4 # This program is free software; you can redistribute it and/or 4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License 5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2 6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version. 7 # of the License, or (at your option) any later version.
8 # 8 #
9 # This program is distributed in the hope that it will be useful, 9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details. 12 # GNU General Public License for more details.
13 # 13 #
14 # You should have received a copy of the GNU General Public License 14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software 15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 class Repository < ActiveRecord::Base 18 class Repository < ActiveRecord::Base
19 include Redmine::Ciphering 19 include Redmine::Ciphering
20 20
21 belongs_to :project 21 belongs_to :project
22 has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC" 22 has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
23 has_many :changes, :through => :changesets 23 has_many :changes, :through => :changesets
24 24
25 serialize :extra_info
26
25 # Raw SQL to delete changesets and changes in the database 27 # Raw SQL to delete changesets and changes in the database
26 # has_many :changesets, :dependent => :destroy is too slow for big repositories 28 # has_many :changesets, :dependent => :destroy is too slow for big repositories
27 before_destroy :clear_changesets 29 before_destroy :clear_changesets
28 30
29 validates_length_of :password, :maximum => 255, :allow_nil => true 31 validates_length_of :password, :maximum => 255, :allow_nil => true
30 # Checks if the SCM is enabled when creating a repository 32 # Checks if the SCM is enabled when creating a repository
31 validate_on_create { |r| r.errors.add(:type, :invalid) unless Setting.enabled_scm.include?(r.class.name.demodulize) } 33 validate_on_create { |r| r.errors.add(:type, :invalid) unless Setting.enabled_scm.include?(r.class.name.demodulize) }
32 34
35 def self.human_attribute_name(attribute_key_name)
36 attr_name = attribute_key_name
37 if attr_name == "log_encoding"
38 attr_name = "commit_logs_encoding"
39 end
40 super(attr_name)
41 end
42
33 # Removes leading and trailing whitespace 43 # Removes leading and trailing whitespace
34 def url=(arg) 44 def url=(arg)
35 write_attribute(:url, arg ? arg.to_s.strip : nil) 45 write_attribute(:url, arg ? arg.to_s.strip : nil)
36 end 46 end
37 47
38 # Removes leading and trailing whitespace 48 # Removes leading and trailing whitespace
39 def root_url=(arg) 49 def root_url=(arg)
40 write_attribute(:root_url, arg ? arg.to_s.strip : nil) 50 write_attribute(:root_url, arg ? arg.to_s.strip : nil)
41 end 51 end
42 52
43 def password 53 def password
44 read_ciphered_attribute(:password) 54 read_ciphered_attribute(:password)
45 end 55 end
46 56
47 def password=(arg) 57 def password=(arg)
48 write_ciphered_attribute(:password, arg) 58 write_ciphered_attribute(:password, arg)
49 end 59 end
50 60
51 def scm_adapter 61 def scm_adapter
61 71
62 def scm_name 72 def scm_name
63 self.class.scm_name 73 self.class.scm_name
64 end 74 end
65 75
76 def merge_extra_info(arg)
77 h = extra_info || {}
78 return h if arg.nil?
79 h.merge!(arg)
80 write_attribute(:extra_info, h)
81 end
82
83 def report_last_commit
84 true
85 end
86
66 def supports_cat? 87 def supports_cat?
67 scm.supports_cat? 88 scm.supports_cat?
68 end 89 end
69 90
70 def supports_annotate? 91 def supports_annotate?
71 scm.supports_annotate? 92 scm.supports_annotate?
72 end 93 end
73 94
95 def supports_all_revisions?
96 true
97 end
98
99 def supports_directory_revisions?
100 false
101 end
102
74 def entry(path=nil, identifier=nil) 103 def entry(path=nil, identifier=nil)
75 scm.entry(path, identifier) 104 scm.entry(path, identifier)
76 end 105 end
77 106
78 def entries(path=nil, identifier=nil) 107 def entries(path=nil, identifier=nil)
79 scm.entries(path, identifier) 108 scm.entries(path, identifier)
80 end 109 end
81 110
82 def branches 111 def branches
88 end 117 end
89 118
90 def default_branch 119 def default_branch
91 scm.default_branch 120 scm.default_branch
92 end 121 end
93 122
94 def properties(path, identifier=nil) 123 def properties(path, identifier=nil)
95 scm.properties(path, identifier) 124 scm.properties(path, identifier)
96 end 125 end
97 126
98 def cat(path, identifier=nil) 127 def cat(path, identifier=nil)
99 scm.cat(path, identifier) 128 scm.cat(path, identifier)
100 end 129 end
101 130
102 def diff(path, rev, rev_to) 131 def diff(path, rev, rev_to)
103 scm.diff(path, rev, rev_to) 132 scm.diff(path, rev, rev_to)
104 end 133 end
105 134
106 def diff_format_revisions(cs, cs_to, sep=':') 135 def diff_format_revisions(cs, cs_to, sep=':')
116 end 145 end
117 146
118 # Finds and returns a revision with a number or the beginning of a hash 147 # Finds and returns a revision with a number or the beginning of a hash
119 def find_changeset_by_name(name) 148 def find_changeset_by_name(name)
120 return nil if name.blank? 149 return nil if name.blank?
121 changesets.find(:first, :conditions => (name.match(/^\d*$/) ? ["revision = ?", name.to_s] : ["revision LIKE ?", name + '%'])) 150 changesets.find(:first, :conditions => (name.match(/^\d*$/) ?
151 ["revision = ?", name.to_s] : ["revision LIKE ?", name + '%']))
122 end 152 end
123 153
124 def latest_changeset 154 def latest_changeset
125 @latest_changeset ||= changesets.find(:first) 155 @latest_changeset ||= changesets.find(:first)
126 end 156 end
127 157
128 # Returns the latest changesets for +path+ 158 # Returns the latest changesets for +path+
129 # Default behaviour is to search in cached changesets 159 # Default behaviour is to search in cached changesets
130 def latest_changesets(path, rev, limit=10) 160 def latest_changesets(path, rev, limit=10)
131 if path.blank? 161 if path.blank?
132 changesets.find(:all, :include => :user, 162 changesets.find(
133 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC", 163 :all,
134 :limit => limit) 164 :include => :user,
165 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
166 :limit => limit)
135 else 167 else
136 changes.find(:all, :include => {:changeset => :user}, 168 changes.find(
137 :conditions => ["path = ?", path.with_leading_slash], 169 :all,
138 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC", 170 :include => {:changeset => :user},
139 :limit => limit).collect(&:changeset) 171 :conditions => ["path = ?", path.with_leading_slash],
140 end 172 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
141 end 173 :limit => limit
142 174 ).collect(&:changeset)
175 end
176 end
177
143 def scan_changesets_for_issue_ids 178 def scan_changesets_for_issue_ids
144 self.changesets.each(&:scan_comment_for_issue_ids) 179 self.changesets.each(&:scan_comment_for_issue_ids)
145 end 180 end
146 181
147 # Returns an array of committers usernames and associated user_id 182 # Returns an array of committers usernames and associated user_id
148 def committers 183 def committers
149 @committers ||= Changeset.connection.select_rows("SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}") 184 @committers ||= Changeset.connection.select_rows(
150 end 185 "SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}")
151 186 end
187
152 # Maps committers username to a user ids 188 # Maps committers username to a user ids
153 def committer_ids=(h) 189 def committer_ids=(h)
154 if h.is_a?(Hash) 190 if h.is_a?(Hash)
155 committers.each do |committer, user_id| 191 committers.each do |committer, user_id|
156 new_user_id = h[committer] 192 new_user_id = h[committer]
157 if new_user_id && (new_user_id.to_i != user_id.to_i) 193 if new_user_id && (new_user_id.to_i != user_id.to_i)
158 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil) 194 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil)
159 Changeset.update_all("user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }", ["repository_id = ? AND committer = ?", id, committer]) 195 Changeset.update_all(
196 "user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }",
197 ["repository_id = ? AND committer = ?", id, committer])
160 end 198 end
161 end 199 end
162 @committers = nil 200 @committers = nil
163 @found_committer_users = nil 201 @found_committer_users = nil
164 true 202 true
165 else 203 else
166 false 204 false
167 end 205 end
168 end 206 end
169 207
170 # Returns the Redmine User corresponding to the given +committer+ 208 # Returns the Redmine User corresponding to the given +committer+
171 # It will return nil if the committer is not yet mapped and if no User 209 # It will return nil if the committer is not yet mapped and if no User
172 # with the same username or email was found 210 # with the same username or email was found
173 def find_committer_user(committer) 211 def find_committer_user(committer)
174 unless committer.blank? 212 unless committer.blank?
175 @found_committer_users ||= {} 213 @found_committer_users ||= {}
176 return @found_committer_users[committer] if @found_committer_users.has_key?(committer) 214 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
177 215
178 user = nil 216 user = nil
179 c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user) 217 c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user)
180 if c && c.user 218 if c && c.user
181 user = c.user 219 user = c.user
182 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/ 220 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
216 end 254 end
217 255
218 def self.scm_name 256 def self.scm_name
219 'Abstract' 257 'Abstract'
220 end 258 end
221 259
222 def self.available_scm 260 def self.available_scm
223 subclasses.collect {|klass| [klass.scm_name, klass.name]} 261 subclasses.collect {|klass| [klass.scm_name, klass.name]}
224 end 262 end
225 263
226 def self.factory(klass_name, *args) 264 def self.factory(klass_name, *args)
236 274
237 def self.scm_command 275 def self.scm_command
238 ret = "" 276 ret = ""
239 begin 277 begin
240 ret = self.scm_adapter_class.client_command if self.scm_adapter_class 278 ret = self.scm_adapter_class.client_command if self.scm_adapter_class
241 rescue Redmine::Scm::Adapters::CommandFailed => e 279 rescue Exception => e
242 logger.error "scm: error during get command: #{e.message}" 280 logger.error "scm: error during get command: #{e.message}"
243 end 281 end
244 ret 282 ret
245 end 283 end
246 284
247 def self.scm_version_string 285 def self.scm_version_string
248 ret = "" 286 ret = ""
249 begin 287 begin
250 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class 288 ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class
251 rescue Redmine::Scm::Adapters::CommandFailed => e 289 rescue Exception => e
252 logger.error "scm: error during get version string: #{e.message}" 290 logger.error "scm: error during get version string: #{e.message}"
253 end 291 end
254 ret 292 ret
255 end 293 end
256 294
257 def self.scm_available 295 def self.scm_available
258 ret = false 296 ret = false
259 begin 297 begin
260 ret = self.scm_adapter_class.client_available if self.scm_adapter_class 298 ret = self.scm_adapter_class.client_available if self.scm_adapter_class
261 rescue Redmine::Scm::Adapters::CommandFailed => e 299 rescue Exception => e
262 logger.error "scm: error during get scm available: #{e.message}" 300 logger.error "scm: error during get scm available: #{e.message}"
263 end 301 end
264 ret 302 ret
265 end 303 end
266 304
270 # Strips url and root_url 308 # Strips url and root_url
271 url.strip! 309 url.strip!
272 root_url.strip! 310 root_url.strip!
273 true 311 true
274 end 312 end
275 313
276 def clear_changesets 314 def clear_changesets
277 cs, ch, ci = Changeset.table_name, Change.table_name, "#{table_name_prefix}changesets_issues#{table_name_suffix}" 315 cs, ch, ci = Changeset.table_name, Change.table_name, "#{table_name_prefix}changesets_issues#{table_name_suffix}"
278 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})") 316 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
279 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})") 317 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
280 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}") 318 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")