##// END OF EJS Templates
scm: subversion: code clean up model....
Toshi MARUYAMA -
r5633:fa5f4ff77a7c
parent child
Show More
@@ -1,205 +1,205
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 require 'redmine/scm/adapters/cvs_adapter'
18 require 'redmine/scm/adapters/cvs_adapter'
19 require 'digest/sha1'
19 require 'digest/sha1'
20
20
21 class Repository::Cvs < Repository
21 class Repository::Cvs < Repository
22 validates_presence_of :url, :root_url, :log_encoding
22 validates_presence_of :url, :root_url, :log_encoding
23
23
24 def self.human_attribute_name(attribute_key_name)
24 def self.human_attribute_name(attribute_key_name)
25 attr_name = attribute_key_name
25 attr_name = attribute_key_name
26 if attr_name == "root_url"
26 if attr_name == "root_url"
27 attr_name = "cvsroot"
27 attr_name = "cvsroot"
28 elsif attr_name == "url"
28 elsif attr_name == "url"
29 attr_name = "cvs_module"
29 attr_name = "cvs_module"
30 end
30 end
31 super(attr_name)
31 super(attr_name)
32 end
32 end
33
33
34 def self.scm_adapter_class
34 def self.scm_adapter_class
35 Redmine::Scm::Adapters::CvsAdapter
35 Redmine::Scm::Adapters::CvsAdapter
36 end
36 end
37
37
38 def self.scm_name
38 def self.scm_name
39 'CVS'
39 'CVS'
40 end
40 end
41
41
42 def entry(path=nil, identifier=nil)
42 def entry(path=nil, identifier=nil)
43 rev = identifier.nil? ? nil : changesets.find_by_revision(identifier)
43 rev = identifier.nil? ? nil : changesets.find_by_revision(identifier)
44 scm.entry(path, rev.nil? ? nil : rev.committed_on)
44 scm.entry(path, rev.nil? ? nil : rev.committed_on)
45 end
45 end
46
46
47 def entries(path=nil, identifier=nil)
47 def entries(path=nil, identifier=nil)
48 rev = nil
48 rev = nil
49 if ! identifier.nil?
49 if ! identifier.nil?
50 rev = changesets.find_by_revision(identifier)
50 rev = changesets.find_by_revision(identifier)
51 return nil if rev.nil?
51 return nil if rev.nil?
52 end
52 end
53 entries = scm.entries(path, rev.nil? ? nil : rev.committed_on)
53 entries = scm.entries(path, rev.nil? ? nil : rev.committed_on)
54 if entries
54 if entries
55 entries.each() do |entry|
55 entries.each() do |entry|
56 if ( ! entry.lastrev.nil? ) && ( ! entry.lastrev.revision.nil? )
56 if ( ! entry.lastrev.nil? ) && ( ! entry.lastrev.revision.nil? )
57 change=changes.find_by_revision_and_path(
57 change=changes.find_by_revision_and_path(
58 entry.lastrev.revision,
58 entry.lastrev.revision,
59 scm.with_leading_slash(entry.path) )
59 scm.with_leading_slash(entry.path) )
60 if change
60 if change
61 entry.lastrev.identifier = change.changeset.revision
61 entry.lastrev.identifier = change.changeset.revision
62 entry.lastrev.revision = change.changeset.revision
62 entry.lastrev.revision = change.changeset.revision
63 entry.lastrev.author = change.changeset.committer
63 entry.lastrev.author = change.changeset.committer
64 # entry.lastrev.branch = change.branch
64 # entry.lastrev.branch = change.branch
65 end
65 end
66 end
66 end
67 end
67 end
68 end
68 end
69 entries
69 entries
70 end
70 end
71
71
72 def cat(path, identifier=nil)
72 def cat(path, identifier=nil)
73 rev = nil
73 rev = nil
74 if ! identifier.nil?
74 if ! identifier.nil?
75 rev = changesets.find_by_revision(identifier)
75 rev = changesets.find_by_revision(identifier)
76 return nil if rev.nil?
76 return nil if rev.nil?
77 end
77 end
78 scm.cat(path, rev.nil? ? nil : rev.committed_on)
78 scm.cat(path, rev.nil? ? nil : rev.committed_on)
79 end
79 end
80
80
81 def annotate(path, identifier=nil)
81 def annotate(path, identifier=nil)
82 rev = nil
82 rev = nil
83 if ! identifier.nil?
83 if ! identifier.nil?
84 rev = changesets.find_by_revision(identifier)
84 rev = changesets.find_by_revision(identifier)
85 return nil if rev.nil?
85 return nil if rev.nil?
86 end
86 end
87 scm.annotate(path, rev.nil? ? nil : rev.committed_on)
87 scm.annotate(path, rev.nil? ? nil : rev.committed_on)
88 end
88 end
89
89
90 def diff(path, rev, rev_to)
90 def diff(path, rev, rev_to)
91 # convert rev to revision. CVS can't handle changesets here
91 # convert rev to revision. CVS can't handle changesets here
92 diff=[]
92 diff=[]
93 changeset_from = changesets.find_by_revision(rev)
93 changeset_from = changesets.find_by_revision(rev)
94 if rev_to.to_i > 0
94 if rev_to.to_i > 0
95 changeset_to = changesets.find_by_revision(rev_to)
95 changeset_to = changesets.find_by_revision(rev_to)
96 end
96 end
97 changeset_from.changes.each() do |change_from|
97 changeset_from.changes.each() do |change_from|
98 revision_from = nil
98 revision_from = nil
99 revision_to = nil
99 revision_to = nil
100 if path.nil? || (change_from.path.starts_with? scm.with_leading_slash(path))
100 if path.nil? || (change_from.path.starts_with? scm.with_leading_slash(path))
101 revision_from = change_from.revision
101 revision_from = change_from.revision
102 end
102 end
103 if revision_from
103 if revision_from
104 if changeset_to
104 if changeset_to
105 changeset_to.changes.each() do |change_to|
105 changeset_to.changes.each() do |change_to|
106 revision_to=change_to.revision if change_to.path==change_from.path
106 revision_to = change_to.revision if change_to.path == change_from.path
107 end
107 end
108 end
108 end
109 unless revision_to
109 unless revision_to
110 revision_to=scm.get_previous_revision(revision_from)
110 revision_to = scm.get_previous_revision(revision_from)
111 end
111 end
112 file_diff = scm.diff(change_from.path, revision_from, revision_to)
112 file_diff = scm.diff(change_from.path, revision_from, revision_to)
113 diff = diff + file_diff unless file_diff.nil?
113 diff = diff + file_diff unless file_diff.nil?
114 end
114 end
115 end
115 end
116 return diff
116 return diff
117 end
117 end
118
118
119 def fetch_changesets
119 def fetch_changesets
120 # some nifty bits to introduce a commit-id with cvs
120 # some nifty bits to introduce a commit-id with cvs
121 # natively cvs doesn't provide any kind of changesets,
121 # natively cvs doesn't provide any kind of changesets,
122 # there is only a revision per file.
122 # there is only a revision per file.
123 # we now take a guess using the author, the commitlog and the commit-date.
123 # we now take a guess using the author, the commitlog and the commit-date.
124
124
125 # last one is the next step to take. the commit-date is not equal for all
125 # last one is the next step to take. the commit-date is not equal for all
126 # commits in one changeset. cvs update the commit-date when the *,v file was touched. so
126 # commits in one changeset. cvs update the commit-date when the *,v file was touched. so
127 # we use a small delta here, to merge all changes belonging to _one_ changeset
127 # we use a small delta here, to merge all changes belonging to _one_ changeset
128 time_delta = 10.seconds
128 time_delta = 10.seconds
129 fetch_since = latest_changeset ? latest_changeset.committed_on : nil
129 fetch_since = latest_changeset ? latest_changeset.committed_on : nil
130 transaction do
130 transaction do
131 tmp_rev_num = 1
131 tmp_rev_num = 1
132 scm.revisions('', fetch_since, nil, :log_encoding => repo_log_encoding) do |revision|
132 scm.revisions('', fetch_since, nil, :log_encoding => repo_log_encoding) do |revision|
133 # only add the change to the database, if it doen't exists. the cvs log
133 # only add the change to the database, if it doen't exists. the cvs log
134 # is not exclusive at all.
134 # is not exclusive at all.
135 tmp_time = revision.time.clone
135 tmp_time = revision.time.clone
136 unless changes.find_by_path_and_revision(
136 unless changes.find_by_path_and_revision(
137 scm.with_leading_slash(revision.paths[0][:path]),
137 scm.with_leading_slash(revision.paths[0][:path]),
138 revision.paths[0][:revision]
138 revision.paths[0][:revision]
139 )
139 )
140 cmt = Changeset.normalize_comments(revision.message, repo_log_encoding)
140 cmt = Changeset.normalize_comments(revision.message, repo_log_encoding)
141 author_utf8 = Changeset.to_utf8(revision.author, repo_log_encoding)
141 author_utf8 = Changeset.to_utf8(revision.author, repo_log_encoding)
142 cs = changesets.find(
142 cs = changesets.find(
143 :first,
143 :first,
144 :conditions => {
144 :conditions => {
145 :committed_on => tmp_time - time_delta .. tmp_time + time_delta,
145 :committed_on => tmp_time - time_delta .. tmp_time + time_delta,
146 :committer => author_utf8,
146 :committer => author_utf8,
147 :comments => cmt
147 :comments => cmt
148 }
148 }
149 )
149 )
150 # create a new changeset....
150 # create a new changeset....
151 unless cs
151 unless cs
152 # we use a temporaray revision number here (just for inserting)
152 # we use a temporaray revision number here (just for inserting)
153 # later on, we calculate a continous positive number
153 # later on, we calculate a continous positive number
154 tmp_time2 = tmp_time.clone.gmtime
154 tmp_time2 = tmp_time.clone.gmtime
155 branch = revision.paths[0][:branch]
155 branch = revision.paths[0][:branch]
156 scmid = branch + "-" + tmp_time2.strftime("%Y%m%d-%H%M%S")
156 scmid = branch + "-" + tmp_time2.strftime("%Y%m%d-%H%M%S")
157 cs = Changeset.create(:repository => self,
157 cs = Changeset.create(:repository => self,
158 :revision => "tmp#{tmp_rev_num}",
158 :revision => "tmp#{tmp_rev_num}",
159 :scmid => scmid,
159 :scmid => scmid,
160 :committer => revision.author,
160 :committer => revision.author,
161 :committed_on => tmp_time,
161 :committed_on => tmp_time,
162 :comments => revision.message)
162 :comments => revision.message)
163 tmp_rev_num += 1
163 tmp_rev_num += 1
164 end
164 end
165 # convert CVS-File-States to internal Action-abbrevations
165 # convert CVS-File-States to internal Action-abbrevations
166 # default action is (M)odified
166 # default action is (M)odified
167 action = "M"
167 action = "M"
168 if revision.paths[0][:action] == "Exp" && revision.paths[0][:revision] == "1.1"
168 if revision.paths[0][:action] == "Exp" && revision.paths[0][:revision] == "1.1"
169 action = "A" # add-action always at first revision (= 1.1)
169 action = "A" # add-action always at first revision (= 1.1)
170 elsif revision.paths[0][:action] == "dead"
170 elsif revision.paths[0][:action] == "dead"
171 action = "D" # dead-state is similar to Delete
171 action = "D" # dead-state is similar to Delete
172 end
172 end
173 Change.create(
173 Change.create(
174 :changeset => cs,
174 :changeset => cs,
175 :action => action,
175 :action => action,
176 :path => scm.with_leading_slash(revision.paths[0][:path]),
176 :path => scm.with_leading_slash(revision.paths[0][:path]),
177 :revision => revision.paths[0][:revision],
177 :revision => revision.paths[0][:revision],
178 :branch => revision.paths[0][:branch]
178 :branch => revision.paths[0][:branch]
179 )
179 )
180 end
180 end
181 end
181 end
182
182
183 # Renumber new changesets in chronological order
183 # Renumber new changesets in chronological order
184 changesets.find(
184 changesets.find(
185 :all,
185 :all,
186 :order => 'committed_on ASC, id ASC',
186 :order => 'committed_on ASC, id ASC',
187 :conditions => "revision LIKE 'tmp%'"
187 :conditions => "revision LIKE 'tmp%'"
188 ).each do |changeset|
188 ).each do |changeset|
189 changeset.update_attribute :revision, next_revision_number
189 changeset.update_attribute :revision, next_revision_number
190 end
190 end
191 end # transaction
191 end # transaction
192 @current_revision_number = nil
192 @current_revision_number = nil
193 end
193 end
194
194
195 private
195 private
196
196
197 # Returns the next revision number to assign to a CVS changeset
197 # Returns the next revision number to assign to a CVS changeset
198 def next_revision_number
198 def next_revision_number
199 # Need to retrieve existing revision numbers to sort them as integers
199 # Need to retrieve existing revision numbers to sort them as integers
200 sql = "SELECT revision FROM #{Changeset.table_name} "
200 sql = "SELECT revision FROM #{Changeset.table_name} "
201 sql << "WHERE repository_id = #{id} AND revision NOT LIKE 'tmp%'"
201 sql << "WHERE repository_id = #{id} AND revision NOT LIKE 'tmp%'"
202 @current_revision_number ||= (connection.select_values(sql).collect(&:to_i).max || 0)
202 @current_revision_number ||= (connection.select_values(sql).collect(&:to_i).max || 0)
203 @current_revision_number += 1
203 @current_revision_number += 1
204 end
204 end
205 end
205 end
General Comments 0
You need to be logged in to leave comments. Login now