comparison app/models/repository/.svn/text-base/cvs.rb.svn-base @ 514:7eba09d624db live

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