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