comparison app/models/repository/.svn/text-base/cvs.rb.svn-base @ 441:cbce1fd3b1b7 redmine-1.2

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