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