Mercurial > hg > soundsoftware-site
comparison app/models/.svn/text-base/repository.rb.svn-base @ 0:513646585e45
* Import Redmine trunk SVN rev 3859
author | Chris Cannam |
---|---|
date | Fri, 23 Jul 2010 15:52:44 +0100 |
parents | |
children | af80e5618e9b 8661b858af72 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:513646585e45 |
---|---|
1 # redMine - project management software | |
2 # Copyright (C) 2006-2007 Jean-Philippe Lang | |
3 # | |
4 # This program is free software; you can redistribute it and/or | |
5 # modify it under the terms of the GNU General Public License | |
6 # as published by the Free Software Foundation; either version 2 | |
7 # of the License, or (at your option) any later version. | |
8 # | |
9 # This program is distributed in the hope that it will be useful, | |
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 # GNU General Public License for more details. | |
13 # | |
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 | |
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 | |
18 class Repository < ActiveRecord::Base | |
19 belongs_to :project | |
20 has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC" | |
21 has_many :changes, :through => :changesets | |
22 | |
23 # Raw SQL to delete changesets and changes in the database | |
24 # has_many :changesets, :dependent => :destroy is too slow for big repositories | |
25 before_destroy :clear_changesets | |
26 | |
27 # Checks if the SCM is enabled when creating a repository | |
28 validate_on_create { |r| r.errors.add(:type, :invalid) unless Setting.enabled_scm.include?(r.class.name.demodulize) } | |
29 | |
30 # Removes leading and trailing whitespace | |
31 def url=(arg) | |
32 write_attribute(:url, arg ? arg.to_s.strip : nil) | |
33 end | |
34 | |
35 # Removes leading and trailing whitespace | |
36 def root_url=(arg) | |
37 write_attribute(:root_url, arg ? arg.to_s.strip : nil) | |
38 end | |
39 | |
40 def scm | |
41 @scm ||= self.scm_adapter.new url, root_url, login, password | |
42 update_attribute(:root_url, @scm.root_url) if root_url.blank? | |
43 @scm | |
44 end | |
45 | |
46 def scm_name | |
47 self.class.scm_name | |
48 end | |
49 | |
50 def supports_cat? | |
51 scm.supports_cat? | |
52 end | |
53 | |
54 def supports_annotate? | |
55 scm.supports_annotate? | |
56 end | |
57 | |
58 def entry(path=nil, identifier=nil) | |
59 scm.entry(path, identifier) | |
60 end | |
61 | |
62 def entries(path=nil, identifier=nil) | |
63 scm.entries(path, identifier) | |
64 end | |
65 | |
66 def branches | |
67 scm.branches | |
68 end | |
69 | |
70 def tags | |
71 scm.tags | |
72 end | |
73 | |
74 def default_branch | |
75 scm.default_branch | |
76 end | |
77 | |
78 def properties(path, identifier=nil) | |
79 scm.properties(path, identifier) | |
80 end | |
81 | |
82 def cat(path, identifier=nil) | |
83 scm.cat(path, identifier) | |
84 end | |
85 | |
86 def diff(path, rev, rev_to) | |
87 scm.diff(path, rev, rev_to) | |
88 end | |
89 | |
90 # Returns a path relative to the url of the repository | |
91 def relative_path(path) | |
92 path | |
93 end | |
94 | |
95 # Finds and returns a revision with a number or the beginning of a hash | |
96 def find_changeset_by_name(name) | |
97 changesets.find(:first, :conditions => (name.match(/^\d*$/) ? ["revision = ?", name.to_s] : ["revision LIKE ?", name + '%'])) | |
98 end | |
99 | |
100 def latest_changeset | |
101 @latest_changeset ||= changesets.find(:first) | |
102 end | |
103 | |
104 # Returns the latest changesets for +path+ | |
105 # Default behaviour is to search in cached changesets | |
106 def latest_changesets(path, rev, limit=10) | |
107 if path.blank? | |
108 changesets.find(:all, :include => :user, | |
109 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC", | |
110 :limit => limit) | |
111 else | |
112 changes.find(:all, :include => {:changeset => :user}, | |
113 :conditions => ["path = ?", path.with_leading_slash], | |
114 :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC", | |
115 :limit => limit).collect(&:changeset) | |
116 end | |
117 end | |
118 | |
119 def scan_changesets_for_issue_ids | |
120 self.changesets.each(&:scan_comment_for_issue_ids) | |
121 end | |
122 | |
123 # Returns an array of committers usernames and associated user_id | |
124 def committers | |
125 @committers ||= Changeset.connection.select_rows("SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}") | |
126 end | |
127 | |
128 # Maps committers username to a user ids | |
129 def committer_ids=(h) | |
130 if h.is_a?(Hash) | |
131 committers.each do |committer, user_id| | |
132 new_user_id = h[committer] | |
133 if new_user_id && (new_user_id.to_i != user_id.to_i) | |
134 new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil) | |
135 Changeset.update_all("user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }", ["repository_id = ? AND committer = ?", id, committer]) | |
136 end | |
137 end | |
138 @committers = nil | |
139 @found_committer_users = nil | |
140 true | |
141 else | |
142 false | |
143 end | |
144 end | |
145 | |
146 # Returns the Redmine User corresponding to the given +committer+ | |
147 # It will return nil if the committer is not yet mapped and if no User | |
148 # with the same username or email was found | |
149 def find_committer_user(committer) | |
150 unless committer.blank? | |
151 @found_committer_users ||= {} | |
152 return @found_committer_users[committer] if @found_committer_users.has_key?(committer) | |
153 | |
154 user = nil | |
155 c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user) | |
156 if c && c.user | |
157 user = c.user | |
158 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/ | |
159 username, email = $1.strip, $3 | |
160 u = User.find_by_login(username) | |
161 u ||= User.find_by_mail(email) unless email.blank? | |
162 user = u | |
163 end | |
164 @found_committer_users[committer] = user | |
165 user | |
166 end | |
167 end | |
168 | |
169 # Fetches new changesets for all repositories of active projects | |
170 # Can be called periodically by an external script | |
171 # eg. ruby script/runner "Repository.fetch_changesets" | |
172 def self.fetch_changesets | |
173 Project.active.has_module(:repository).find(:all, :include => :repository).each do |project| | |
174 if project.repository | |
175 project.repository.fetch_changesets | |
176 end | |
177 end | |
178 end | |
179 | |
180 # scan changeset comments to find related and fixed issues for all repositories | |
181 def self.scan_changesets_for_issue_ids | |
182 find(:all).each(&:scan_changesets_for_issue_ids) | |
183 end | |
184 | |
185 def self.scm_name | |
186 'Abstract' | |
187 end | |
188 | |
189 def self.available_scm | |
190 subclasses.collect {|klass| [klass.scm_name, klass.name]} | |
191 end | |
192 | |
193 def self.factory(klass_name, *args) | |
194 klass = "Repository::#{klass_name}".constantize | |
195 klass.new(*args) | |
196 rescue | |
197 nil | |
198 end | |
199 | |
200 private | |
201 | |
202 def before_save | |
203 # Strips url and root_url | |
204 url.strip! | |
205 root_url.strip! | |
206 true | |
207 end | |
208 | |
209 def clear_changesets | |
210 cs, ch, ci = Changeset.table_name, Change.table_name, "#{table_name_prefix}changesets_issues#{table_name_suffix}" | |
211 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})") | |
212 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})") | |
213 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}") | |
214 end | |
215 end |