1
|
# redMine - project management software
|
2
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
3
|
#
|
4
|
# This program is free software; you can redistribute it and/or
|
5
|
# modify it under the terms of the GNU General Public License
|
6
|
# as published by the Free Software Foundation; either version 2
|
7
|
# of the License, or (at your option) any later version.
|
8
|
#
|
9
|
# This program is distributed in the hope that it will be useful,
|
10
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
# GNU General Public License for more details.
|
13
|
#
|
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
|
16
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
|
|
18
|
require 'redmine/scm/adapters/visual_source_safe_adapter'
|
19
|
require 'redmine/scm/adapters/abstract_adapter'
|
20
|
|
21
|
class Repository::VisualSourceSafe < Repository
|
22
|
attr_protected :root_url
|
23
|
validates_presence_of :url
|
24
|
validates_format_of :url, :with => /^.*srcsafe\.ini/i
|
25
|
|
26
|
def scm_adapter
|
27
|
Redmine::Scm::Adapters::VisualSourceSafeAdapter
|
28
|
end
|
29
|
|
30
|
def self.scm_name
|
31
|
'VisualSourceSafe'
|
32
|
end
|
33
|
|
34
|
def fetch_changesets
|
35
|
#use like CVS
|
36
|
|
37
|
#not the preferred way with CVS. maybe we should introduce always a cron-job for this
|
38
|
last_commit = changesets.maximum(:committed_on)
|
39
|
|
40
|
# some nifty bits to introduce a commit-id with cvs
|
41
|
# natively cvs doesn't provide any kind of changesets, there is only a revision per file.
|
42
|
# we now take a guess using the author, the commitlog and the commit-date.
|
43
|
|
44
|
# last one is the next step to take. the commit-date is not equal for all
|
45
|
# commits in one changeset. cvs update the commit-date when the *,v file was touched. so
|
46
|
# we use a small delta here, to merge all changes belonging to _one_ changeset
|
47
|
#time_delta=10.seconds
|
48
|
|
49
|
time_delta=10.seconds
|
50
|
revisions = nil
|
51
|
transaction do
|
52
|
revisions = scm.revisions('', last_commit, nil, :with_paths => true)
|
53
|
revisions.each do |revision|
|
54
|
# only add the change to the database, if it doen't exists. the cvs log
|
55
|
# is not exclusive at all.
|
56
|
cs1 = changes.find_by_path_and_revision(scm.with_leading_slash(revision.paths[0][:path]), revision.paths[0][:revision])
|
57
|
unless cs1
|
58
|
revision
|
59
|
cs=Changeset.find(:first, :conditions=>{
|
60
|
:committed_on=>revision.time-time_delta..revision.time+time_delta,
|
61
|
:committer=>revision.author,
|
62
|
:comments=>revision.message
|
63
|
})
|
64
|
|
65
|
# create a new changeset....
|
66
|
unless cs
|
67
|
# we use a negative changeset-number here (just for inserting)
|
68
|
# later on, we calculate a continous positive number
|
69
|
next_rev = changesets.minimum(:revision)
|
70
|
next_rev = 0 if next_rev.nil? or next_rev > 0
|
71
|
next_rev = next_rev - 1
|
72
|
|
73
|
cs=Changeset.create(:repository => self,
|
74
|
:revision => next_rev,
|
75
|
:committer => revision.author,
|
76
|
:committed_on => revision.time,
|
77
|
:comments => revision.message)
|
78
|
end
|
79
|
|
80
|
#convert CVS-File-States to internal Action-abbrevations
|
81
|
#default action is (M)odified
|
82
|
action="M"
|
83
|
# if revision.paths[0][:action]=="Exp" && revision.paths[0][:revision]=="1.1"
|
84
|
# action="A" #add-action always at first revision (= 1.1)
|
85
|
# elsif revision.paths[0][:action]=="dead"
|
86
|
# action="D" #dead-state is similar to Delete
|
87
|
# end
|
88
|
act = revision.paths[0][:action]
|
89
|
#need check only 'Added' or 'Created' or 'Deleted'
|
90
|
if /^Added/ =~ act or /^Created/ =~ act or /^Recovered/ =~ act or /^Shared/ =~ act
|
91
|
action="A"
|
92
|
elsif /^Deleted/ =~ act
|
93
|
action="D"
|
94
|
end
|
95
|
Change.create(:changeset => cs,
|
96
|
:action => action,
|
97
|
:path => scm.with_leading_slash(revision.paths[0][:path]),
|
98
|
:revision => revision.paths[0][:revision],
|
99
|
:branch => revision.paths[0][:branch]
|
100
|
)
|
101
|
end
|
102
|
end
|
103
|
|
104
|
next_rev = [changesets.maximum(:revision) || 0, 0].max
|
105
|
changesets.find(:all, :conditions=>["revision < 0"], :order=>"committed_on ASC").each() do |changeset|
|
106
|
next_rev = next_rev + 1
|
107
|
changeset.revision = next_rev
|
108
|
changeset.save!
|
109
|
end
|
110
|
end
|
111
|
end
|
112
|
|
113
|
def diff(path, rev, rev_to, type2)
|
114
|
#convert rev to revision. CVS can't handle changesets here
|
115
|
diffx = Redmine::Scm::Adapters::DiffTableList.new([], type2)
|
116
|
changeset_from=changesets.find_by_revision(rev)
|
117
|
if rev_to.to_i > 0
|
118
|
changeset_to=changesets.find_by_revision(rev_to)
|
119
|
end
|
120
|
changeset_from.changes.each() do |change_from|
|
121
|
|
122
|
revision_from=nil
|
123
|
revision_to=nil
|
124
|
|
125
|
revision_from=change_from.revision if path.nil? || (change_from.path.starts_with? scm.with_leading_slash(path))
|
126
|
|
127
|
if revision_from
|
128
|
if changeset_to
|
129
|
changeset_to.changes.each() do |change_to|
|
130
|
revision_to=change_to.revision if change_to.path==change_from.path
|
131
|
end
|
132
|
end
|
133
|
unless revision_to
|
134
|
revision_to=scm.get_previous_revision(change_from.path, revision_from)
|
135
|
end
|
136
|
diff2 = scm.diff(change_from.path, revision_from, revision_to, type2)
|
137
|
diffx=diff2 if diff2
|
138
|
end
|
139
|
end
|
140
|
return diffx
|
141
|
end
|
142
|
|
143
|
end
|