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