Fossil SCM

fossil-scm / tools / cvs2fossil / lib / c2f_prevlink.tcl
Blame History Raw 241 lines
1
## -*- tcl -*-
2
# # ## ### ##### ######## ############# #####################
3
## Copyright (c) 2007 Andreas Kupries.
4
#
5
# This software is licensed as described in the file LICENSE, which
6
# you should have received as part of this distribution.
7
#
8
# This software consists of voluntary contributions made by many
9
# individuals. For exact contribution history, see the revision
10
# history and logs, available at http://fossil-scm.hwaci.com/fossil
11
# # ## ### ##### ######## ############# #####################
12
13
## Helper class for the pass 6 cycle breaker. Each instance refers to
14
## three changesets A, B, and C, with A a predecessor of B, and B
15
## predecessor of C, and the whole part of a dependency cycle.
16
17
## Instances analyse the file level dependencies which gave rise to
18
## the changeset dependencies of A, B, and C, with the results used by
19
## the cycle breaker algorithm to find a good location where to at
20
## least weaken and at best fully break the cycle.
21
22
# # ## ### ##### ######## ############# #####################
23
## Requirements
24
25
package require Tcl 8.4 ; # Required runtime.
26
package require snit ; # OO system.
27
package require vc::tools::misc ; # Text formatting
28
package require vc::tools::trouble ; # Error reporting.
29
package require vc::tools::log ; # User feedback.
30
package require vc::fossil::import::cvs::state ; # State storage.
31
package require vc::fossil::import::cvs::integrity ; # State integrity checks.
32
package require vc::fossil::import::cvs::project::rev ; # Project level changesets
33
34
# # ## ### ##### ######## ############# #####################
35
##
36
37
snit::type ::vc::fossil::import::cvs::project::revlink {
38
# # ## ### ##### ######## #############
39
## Public API
40
41
constructor {prev cset next} {
42
set myprev $prev
43
set mycset $cset
44
set mynext $next
45
46
# We perform the bulk of the analysis during construction. The
47
# file revisions held by the changeset CSET can be sorted into
48
# four categories.
49
50
# 1. Revisions whose predecessors are not in PREV, nor are
51
# their successors found in NEXT. These revisions do not
52
# count, as they did not induce any of the two dependencies
53
# under consideration. They can be ignored.
54
55
# 2. Revisions which have predecessors in PREV and successors
56
# in NEXT. They are called 'passthrough' in cvs2svn. They
57
# induce both dependencies under consideration and are thus
58
# critical in the creation of the cycle. As such they are
59
# also unbreakable :(
60
61
# 3. Revisions which have predecessor in PREVE, but no
62
# successors in NEXT. As such they induced the incoming
63
# dependency, but not the outgoing one.
64
65
# 4. Revisions which have no predecessors in PREVE, but their
66
# successors are in NEXT. As such they induced the outgoing
67
# dependency, but not the incoming one.
68
69
# If we have no passthrough revisions then splitting the
70
# changeset between categories 3 and 4, with category 1 going
71
# wherever, will break the cycle. If category 2 revisions are
72
# present we can still perform the split, this will however
73
# not break the cycle, only weaken it.
74
75
# NOTE: This is the only remaining user of 'nextmap'. Look
76
# into the possibility of performing the relevant counting
77
# within the database.
78
79
array set csetprevmap [Invert [$myprev nextmap]]
80
array set csetnextmap [$mycset nextmap]
81
82
set prevrev [$myprev items]
83
set nextrev [$mynext items]
84
85
foreach item [$mycset items] {
86
set rt [RT $item]
87
incr mycount($rt)
88
lappend mycategory($rt) $item
89
}
90
return
91
}
92
93
# Result is TRUE if and only breaking myset will do some good.
94
method breakable {} { expr {$mycount(prev) || $mycount(next)} }
95
method passcount {} { return $mycount(pass) }
96
97
method linkstomove {} {
98
# Return the number of revisions that would be moved should we
99
# split the changeset.
100
101
set n [min2 $mycount(prev) $mycount(next)]
102
if {$n > 0 } { return $n }
103
return [max2 $mycount(prev) $mycount(next)]
104
}
105
106
method betterthan {other} {
107
set sbreak [$self breakable]
108
set obreak [$other breakable]
109
110
if {$sbreak && !$obreak} { return 1 } ; # self is better.
111
if {!$sbreak && $obreak} { return 0 } ; # self is worse.
112
113
# Equality. Look at the counters.
114
# - Whichever has the lesser number of passthrough revisions
115
# is better, as more can be split off, weakening the cycle
116
# more.
117
# - Whichever has less links to move is better.
118
119
set opass [$other passcount]
120
if {$mycount(pass) < $opass} { return 1 } ; # self is better.
121
if {$mycount(pass) > $opass} { return 0 } ; # self is worse.
122
123
set smove [$self linkstomove]
124
set omove [$other linkstomove]
125
126
if {$smove < $omove} { return 1 } ; # self is better.
127
128
return 0 ; # Self is worse or equal, i.e. not better.
129
}
130
131
method break {} {
132
integrity assert {[$self breakable]} {Changeset [$mycset str] is not breakable.}
133
134
# One thing to choose when splitting CSET is where the
135
# revision in categories 1 and 2 (none and passthrough
136
# respectively) are moved to. This is done using the counters.
137
138
if {!$mycount(prev)} {
139
# Nothing in category 3 => 1,2 go there, 4 the other.
140
set mycategory(prev) [concat $mycategory(none) $mycategory(pass)]
141
} elseif {!$mycount(next)} {
142
# Nothing in category 4 => 1,2 go there, 3 the other.
143
set mycategory(next) [concat $mycategory(none) $mycategory(pass)]
144
} elseif {$mycount(prev) < $mycount(next)} {
145
# Less predecessors than successors => 1,2 go to the
146
# sucessors.
147
set mycategory(next) [concat $mycategory(next) $mycategory(none) \
148
$mycategory(pass)]
149
} else {
150
# Less successors than predecessors => 1,2 go to the
151
# predecessors.
152
set mycategory(next) [concat $mycategory(next) $mycategory(none) \
153
$mycategory(pass)]
154
}
155
156
# We now have the revisions for the two fragments to be in the
157
# (prev|next) elements of mycategory.
158
159
return [project::rev split $mycset $mycategory(prev) $mycategory(next)]
160
}
161
162
# # ## ### ##### ######## #############
163
## State
164
165
variable myprev {} ; # Reference to predecessor changeset in the link.
166
variable mycset {} ; # Reference to the main changeset of the link.
167
variable mynext {} ; # Reference to the successor changeset in the link.
168
169
# Counters for the revision categories.
170
variable mycount -array {
171
none 0
172
prev 0
173
next 0
174
pass 0
175
}
176
# Lists of revisions for the various categories
177
variable mycategory -array {
178
none {}
179
prev {}
180
next {}
181
pass {}
182
}
183
184
# # ## ### ##### ######## #############
185
## Internal methods
186
187
proc RT {r} {
188
upvar 1 csetprevmap csetprevmap csetnextmap csetnextmap prevrev prevrev nextrev nextrev
189
190
set inc [expr {[info exists csetprevmap($r)]
191
? [struct::set size [struct::set intersect $csetprevmap($r) $prevrev]]
192
: 0}]
193
set out [expr {[info exists csetnextmap($r)]
194
? [struct::set size [struct::set intersect $csetnextmap($r) $nextrev]]
195
: 0}]
196
197
if {$inc && $out} { return pass }
198
if {$inc} { return prev }
199
if {$out} { return next }
200
return none
201
}
202
203
proc Invert {dict} {
204
array set tmp {}
205
foreach {k values} $dict {
206
foreach v $values { lappend tmp($v) $k }
207
}
208
return [array get tmp]
209
}
210
211
# # ## ### ##### ######## #############
212
## Configuration
213
214
pragma -hastypeinfo no ; # no type introspection
215
pragma -hasinfo no ; # no object introspection
216
pragma -simpledispatch yes ; # simple fast dispatch
217
218
# # ## ### ##### ######## #############
219
}
220
221
namespace eval ::vc::fossil::import::cvs::project {
222
namespace export revlink
223
namespace eval revlink {
224
namespace import ::vc::fossil::import::cvs::state
225
namespace import ::vc::fossil::import::cvs::integrity
226
namespace import ::vc::tools::misc::*
227
namespace import ::vc::tools::trouble
228
namespace eval project {
229
namespace import ::vc::fossil::import::cvs::project::rev
230
}
231
namespace import ::vc::tools::log
232
log register csets
233
}
234
}
235
236
# # ## ### ##### ######## ############# #####################
237
## Ready
238
239
package provide vc::fossil::import::cvs::project::revlink 1.0
240
return
241

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button