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