Fossil SCM

Continued work on pass 6. Completed creation of changeset graph (nodes, dependencies), started on topological iteration and breaking cycles. Basic iteration is complete, fiding a cycle ditto. Not yet done is to actually break a found cycle. Extended the changeset class with the necessary accessor methods (getting cset type, successors, time range). Note: Looking at my code it may be that my decision to save the cset order caused this pass to subsume the RevisionTopologicalSortPass of cvs2svn. Check again when I am done. Note 2: The test case (tcl repository, tcl project) had no cycles.

aku 2007-11-13 07:22 trunk
Commit 85bd219d0b2eca43bad0d4e03ed6c04ea4bfdd02
--- tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl
+++ tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl
@@ -17,11 +17,15 @@
1717
# # ## ### ##### ######## ############# #####################
1818
## Requirements
1919
2020
package require Tcl 8.4 ; # Required runtime.
2121
package require snit ; # OO system.
22
+package require struct::graph ; # Graph handling.
23
+package require struct::list ; # Higher order list operations.
2224
package require vc::tools::log ; # User feedback.
25
+package require vc::fossil::import::cvs::state ; # State storage.
26
+package require vc::fossil::import::cvs::project::rev ; # Project level changesets
2327
2428
# # ## ### ##### ######## ############# #####################
2529
## Register the pass with the management
2630
2731
vc::fossil::import::cvs::pass define \
@@ -37,10 +41,19 @@
3741
## Public API
3842
3943
typemethod setup {} {
4044
# Define the names and structure of the persistent state of
4145
# this pass.
46
+
47
+ state writing csorder {
48
+ -- Commit order of changesets based on their dependencies
49
+ cid INTEGER NOT NULL REFERENCES changeset,
50
+ pos INTEGER NOT NULL,
51
+ UNIQUE (cid),
52
+ UNIQUE (pos)
53
+ }
54
+
4255
return
4356
}
4457
4558
typemethod load {} {
4659
# Pass manager interface. Executed to load data computed by
@@ -50,23 +63,187 @@
5063
}
5164
5265
typemethod run {} {
5366
# Pass manager interface. Executed to perform the
5467
# functionality of the pass.
68
+
69
+ state reading revision
70
+
71
+ # We create a graph of the revision changesets, using the file
72
+ # level dependencies to construct a first approximation of
73
+ # them at the project level. Then look for cycles in that
74
+ # graph and break them.
75
+
76
+ # 1. Create nodes for all relevant changesets and a mapping
77
+ # from the revisions to their changesets/nodes.
78
+
79
+ log write 3 brkrcycle {Creating changeset graph, filling with nodes}
80
+
81
+ set dg [struct::graph dg]
82
+
83
+ state transaction {
84
+ foreach cset [project::rev all] {
85
+ if {[$cset bysymbol]} continue
86
+ dg node insert $cset
87
+ dg node set $cset timerange [$cset timerange]
88
+ }
89
+ }
90
+
91
+ # 2. Find for all relevant changeset their revisions and their
92
+ # dependencies. Map the latter back to changesets and
93
+ # construct the corresponding arcs.
94
+
95
+ log write 3 brkrcycle {Setting up node dependencies}
96
+
97
+ state transaction {
98
+ foreach cset [project::rev all] {
99
+ if {[$cset bysymbol]} continue
100
+ foreach succ [$cset successors] {
101
+ dg arc insert $cset $succ
102
+ }
103
+ }
104
+ }
105
+
106
+ # 3. Lastly we iterate the graph topologically. We mark off
107
+ # the nodes which have no predecessors, in order from
108
+ # oldest to youngest, saving and removing dependencies. If
109
+ # we find no nodes without predecessors we have a cycle,
110
+ # and work on breaking it.
111
+
112
+ log write 3 brkrcycle {Computing changeset order, breaking cycles}
113
+
114
+ InitializeCandidates $dg
115
+ state transaction {
116
+ while {1} {
117
+ while {[WithoutPredecessor $dg n]} {
118
+ SaveAndRemove $dg $n
119
+ }
120
+ if {![llength [dg nodes]]} break
121
+ set cycle [FindCycle $dg]
122
+ BreakCycle $dg $cycle
123
+ }
124
+ }
125
+
55126
return
56127
}
57128
58129
typemethod discard {} {
59130
# Pass manager interface. Executed for all passes after the
60131
# run passes, to remove all data of this pass from the state,
61132
# as being out of date.
133
+
134
+ state discard csorder
62135
return
63136
}
64137
65138
# # ## ### ##### ######## #############
66139
## Internal methods
67140
141
+ # Instead of searching the whole graph for the degree-0 nodes in
142
+ # each iteration we compute the list once to start, and then only
143
+ # update it incrementally based on the outgoing neighbours of the
144
+ # node chosen for commit.
145
+
146
+ proc InitializeCandidates {dg} {
147
+ # bottom = list (list (node, range min, range max))
148
+ ::variable bottom
149
+ foreach n [$dg nodes] {
150
+ if {[$dg node degree -in $n]} continue
151
+ lappend bottom [linsert [$dg node get $n timerange] 0 $n]
152
+ }
153
+ set bottom [lsort -index 1 -integer [lsort -index 2 -integer $bottom]]
154
+ return
155
+ }
156
+
157
+ proc WithoutPredecessor {dg nv} {
158
+ ::variable bottom
159
+
160
+ upvar 1 $nv n
161
+ if {![llength $bottom]} { return 0 }
162
+
163
+ set n [lindex [lindex $bottom 0] 0]
164
+ set bottom [lrange $bottom 1 end]
165
+ set changed 0
166
+
167
+ # Update list of nodes without predecessor, based on the
168
+ # outgoing neighbours of the chosen node. This should be
169
+ # faster than iterating of the whole set of nodes, finding all
170
+ # without predecessors, sorting them by time, etc. pp.
171
+ foreach out [$dg nodes -out $n] {
172
+ if {[$dg node degree -in $out] > 1} continue
173
+ # Degree-1 neighbour, will have no predecessors after the
174
+ # removal of n. Put on the list.
175
+ lappend bottom [linsert [$dg node get $out timerange] 0 $out]
176
+ set changed 1
177
+ }
178
+ if {$changed} {
179
+ set bottom [lsort -index 1 -integer [lsort -index 2 -integer $bottom]]
180
+ }
181
+
182
+ # We do not delete the node immediately, to allow the Save
183
+ # procedure to save the dependencies as well (encoded in the
184
+ # arcs).
185
+ return 1
186
+ }
187
+
188
+ proc SaveAndRemove {dg n} {
189
+ ::variable at
190
+ set cid [$n id]
191
+
192
+ log write 4 breakrcycle "Comitting @ $at: <$cid>"
193
+ state run {
194
+ INSERT INTO csorder (cid, pos)
195
+ VALUES ($cid, $at)
196
+ }
197
+ # TODO: Write the project level changeset dependencies as well.
198
+ incr at
199
+ $dg node delete $n
200
+ return
201
+ }
202
+
203
+ proc FindCycle {dg} {
204
+ # This procedure is run if and only the graph is not empty and
205
+ # all nodes have predecessors. This means that each node is
206
+ # either part of a cycle or (indirectly) depending on a node
207
+ # in a cycle. We can start at an arbitrary node, follow its
208
+ # incoming edges to its predecessors until we see a node a
209
+ # second time. That node closes the cycle and the beginning is
210
+ # its first occurence. Note that we can choose an arbitrary
211
+ # predecessor of each node as well, we do not have to search.
212
+
213
+ # We record for each node the index of the first appearance in
214
+ # the path, making it easy at the end to cut the cycle from
215
+ # it.
216
+
217
+ # Choose arbitrary node to start our search at.
218
+ set start [lindex [$dg nodes] 0]
219
+
220
+ # Initialize state, path of seen nodes, and when seen.
221
+ set path {}
222
+ array set seen {}
223
+
224
+ while {1} {
225
+ # Stop searching when we have seen the current node
226
+ # already, the circle has been closed.
227
+ if {[info exists seen($start)]} break
228
+ lappend path $start
229
+ set seen($start) [llength $path]
230
+ # Choose arbitrary predecessor
231
+ set start [lindex [$dg nodes -in $start] 0]
232
+ }
233
+
234
+ return [struct::list reverse [lrange $path $seen($start) end]]
235
+ }
236
+
237
+ proc BreakCycle {dg cycle} {
238
+ trouble internal "Break cycle <$cycle>"
239
+ return
240
+ }
241
+
242
+ typevariable at 0 ; # Counter for commit ids for the changesets.
243
+ typevariable bottom {} ; # List of candidate nodes for committing.
244
+
68245
# # ## ### ##### ######## #############
69246
## Configuration
70247
71248
pragma -hasinstances no ; # singleton
72249
pragma -hastypeinfo no ; # no introspection
@@ -74,12 +251,16 @@
74251
75252
# # ## ### ##### ######## #############
76253
}
77254
78255
namespace eval ::vc::fossil::import::cvs::pass {
79
- namespace export initcsets
80
- namespace eval initcsets {
256
+ namespace export breakrcycle
257
+ namespace eval breakrcycle {
258
+ namespace import ::vc::fossil::import::cvs::state
259
+ namespace eval project {
260
+ namespace import ::vc::fossil::import::cvs::project::rev
261
+ }
81262
namespace import ::vc::tools::log
82263
log register brkrcycle
83264
}
84265
}
85266
86267
--- tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl
+++ tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl
@@ -17,11 +17,15 @@
17 # # ## ### ##### ######## ############# #####################
18 ## Requirements
19
20 package require Tcl 8.4 ; # Required runtime.
21 package require snit ; # OO system.
 
 
22 package require vc::tools::log ; # User feedback.
 
 
23
24 # # ## ### ##### ######## ############# #####################
25 ## Register the pass with the management
26
27 vc::fossil::import::cvs::pass define \
@@ -37,10 +41,19 @@
37 ## Public API
38
39 typemethod setup {} {
40 # Define the names and structure of the persistent state of
41 # this pass.
 
 
 
 
 
 
 
 
 
42 return
43 }
44
45 typemethod load {} {
46 # Pass manager interface. Executed to load data computed by
@@ -50,23 +63,187 @@
50 }
51
52 typemethod run {} {
53 # Pass manager interface. Executed to perform the
54 # functionality of the pass.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55 return
56 }
57
58 typemethod discard {} {
59 # Pass manager interface. Executed for all passes after the
60 # run passes, to remove all data of this pass from the state,
61 # as being out of date.
 
 
62 return
63 }
64
65 # # ## ### ##### ######## #############
66 ## Internal methods
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68 # # ## ### ##### ######## #############
69 ## Configuration
70
71 pragma -hasinstances no ; # singleton
72 pragma -hastypeinfo no ; # no introspection
@@ -74,12 +251,16 @@
74
75 # # ## ### ##### ######## #############
76 }
77
78 namespace eval ::vc::fossil::import::cvs::pass {
79 namespace export initcsets
80 namespace eval initcsets {
 
 
 
 
81 namespace import ::vc::tools::log
82 log register brkrcycle
83 }
84 }
85
86
--- tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl
+++ tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl
@@ -17,11 +17,15 @@
17 # # ## ### ##### ######## ############# #####################
18 ## Requirements
19
20 package require Tcl 8.4 ; # Required runtime.
21 package require snit ; # OO system.
22 package require struct::graph ; # Graph handling.
23 package require struct::list ; # Higher order list operations.
24 package require vc::tools::log ; # User feedback.
25 package require vc::fossil::import::cvs::state ; # State storage.
26 package require vc::fossil::import::cvs::project::rev ; # Project level changesets
27
28 # # ## ### ##### ######## ############# #####################
29 ## Register the pass with the management
30
31 vc::fossil::import::cvs::pass define \
@@ -37,10 +41,19 @@
41 ## Public API
42
43 typemethod setup {} {
44 # Define the names and structure of the persistent state of
45 # this pass.
46
47 state writing csorder {
48 -- Commit order of changesets based on their dependencies
49 cid INTEGER NOT NULL REFERENCES changeset,
50 pos INTEGER NOT NULL,
51 UNIQUE (cid),
52 UNIQUE (pos)
53 }
54
55 return
56 }
57
58 typemethod load {} {
59 # Pass manager interface. Executed to load data computed by
@@ -50,23 +63,187 @@
63 }
64
65 typemethod run {} {
66 # Pass manager interface. Executed to perform the
67 # functionality of the pass.
68
69 state reading revision
70
71 # We create a graph of the revision changesets, using the file
72 # level dependencies to construct a first approximation of
73 # them at the project level. Then look for cycles in that
74 # graph and break them.
75
76 # 1. Create nodes for all relevant changesets and a mapping
77 # from the revisions to their changesets/nodes.
78
79 log write 3 brkrcycle {Creating changeset graph, filling with nodes}
80
81 set dg [struct::graph dg]
82
83 state transaction {
84 foreach cset [project::rev all] {
85 if {[$cset bysymbol]} continue
86 dg node insert $cset
87 dg node set $cset timerange [$cset timerange]
88 }
89 }
90
91 # 2. Find for all relevant changeset their revisions and their
92 # dependencies. Map the latter back to changesets and
93 # construct the corresponding arcs.
94
95 log write 3 brkrcycle {Setting up node dependencies}
96
97 state transaction {
98 foreach cset [project::rev all] {
99 if {[$cset bysymbol]} continue
100 foreach succ [$cset successors] {
101 dg arc insert $cset $succ
102 }
103 }
104 }
105
106 # 3. Lastly we iterate the graph topologically. We mark off
107 # the nodes which have no predecessors, in order from
108 # oldest to youngest, saving and removing dependencies. If
109 # we find no nodes without predecessors we have a cycle,
110 # and work on breaking it.
111
112 log write 3 brkrcycle {Computing changeset order, breaking cycles}
113
114 InitializeCandidates $dg
115 state transaction {
116 while {1} {
117 while {[WithoutPredecessor $dg n]} {
118 SaveAndRemove $dg $n
119 }
120 if {![llength [dg nodes]]} break
121 set cycle [FindCycle $dg]
122 BreakCycle $dg $cycle
123 }
124 }
125
126 return
127 }
128
129 typemethod discard {} {
130 # Pass manager interface. Executed for all passes after the
131 # run passes, to remove all data of this pass from the state,
132 # as being out of date.
133
134 state discard csorder
135 return
136 }
137
138 # # ## ### ##### ######## #############
139 ## Internal methods
140
141 # Instead of searching the whole graph for the degree-0 nodes in
142 # each iteration we compute the list once to start, and then only
143 # update it incrementally based on the outgoing neighbours of the
144 # node chosen for commit.
145
146 proc InitializeCandidates {dg} {
147 # bottom = list (list (node, range min, range max))
148 ::variable bottom
149 foreach n [$dg nodes] {
150 if {[$dg node degree -in $n]} continue
151 lappend bottom [linsert [$dg node get $n timerange] 0 $n]
152 }
153 set bottom [lsort -index 1 -integer [lsort -index 2 -integer $bottom]]
154 return
155 }
156
157 proc WithoutPredecessor {dg nv} {
158 ::variable bottom
159
160 upvar 1 $nv n
161 if {![llength $bottom]} { return 0 }
162
163 set n [lindex [lindex $bottom 0] 0]
164 set bottom [lrange $bottom 1 end]
165 set changed 0
166
167 # Update list of nodes without predecessor, based on the
168 # outgoing neighbours of the chosen node. This should be
169 # faster than iterating of the whole set of nodes, finding all
170 # without predecessors, sorting them by time, etc. pp.
171 foreach out [$dg nodes -out $n] {
172 if {[$dg node degree -in $out] > 1} continue
173 # Degree-1 neighbour, will have no predecessors after the
174 # removal of n. Put on the list.
175 lappend bottom [linsert [$dg node get $out timerange] 0 $out]
176 set changed 1
177 }
178 if {$changed} {
179 set bottom [lsort -index 1 -integer [lsort -index 2 -integer $bottom]]
180 }
181
182 # We do not delete the node immediately, to allow the Save
183 # procedure to save the dependencies as well (encoded in the
184 # arcs).
185 return 1
186 }
187
188 proc SaveAndRemove {dg n} {
189 ::variable at
190 set cid [$n id]
191
192 log write 4 breakrcycle "Comitting @ $at: <$cid>"
193 state run {
194 INSERT INTO csorder (cid, pos)
195 VALUES ($cid, $at)
196 }
197 # TODO: Write the project level changeset dependencies as well.
198 incr at
199 $dg node delete $n
200 return
201 }
202
203 proc FindCycle {dg} {
204 # This procedure is run if and only the graph is not empty and
205 # all nodes have predecessors. This means that each node is
206 # either part of a cycle or (indirectly) depending on a node
207 # in a cycle. We can start at an arbitrary node, follow its
208 # incoming edges to its predecessors until we see a node a
209 # second time. That node closes the cycle and the beginning is
210 # its first occurence. Note that we can choose an arbitrary
211 # predecessor of each node as well, we do not have to search.
212
213 # We record for each node the index of the first appearance in
214 # the path, making it easy at the end to cut the cycle from
215 # it.
216
217 # Choose arbitrary node to start our search at.
218 set start [lindex [$dg nodes] 0]
219
220 # Initialize state, path of seen nodes, and when seen.
221 set path {}
222 array set seen {}
223
224 while {1} {
225 # Stop searching when we have seen the current node
226 # already, the circle has been closed.
227 if {[info exists seen($start)]} break
228 lappend path $start
229 set seen($start) [llength $path]
230 # Choose arbitrary predecessor
231 set start [lindex [$dg nodes -in $start] 0]
232 }
233
234 return [struct::list reverse [lrange $path $seen($start) end]]
235 }
236
237 proc BreakCycle {dg cycle} {
238 trouble internal "Break cycle <$cycle>"
239 return
240 }
241
242 typevariable at 0 ; # Counter for commit ids for the changesets.
243 typevariable bottom {} ; # List of candidate nodes for committing.
244
245 # # ## ### ##### ######## #############
246 ## Configuration
247
248 pragma -hasinstances no ; # singleton
249 pragma -hastypeinfo no ; # no introspection
@@ -74,12 +251,16 @@
251
252 # # ## ### ##### ######## #############
253 }
254
255 namespace eval ::vc::fossil::import::cvs::pass {
256 namespace export breakrcycle
257 namespace eval breakrcycle {
258 namespace import ::vc::fossil::import::cvs::state
259 namespace eval project {
260 namespace import ::vc::fossil::import::cvs::project::rev
261 }
262 namespace import ::vc::tools::log
263 log register brkrcycle
264 }
265 }
266
267
--- tools/cvs2fossil/lib/c2f_prev.tcl
+++ tools/cvs2fossil/lib/c2f_prev.tcl
@@ -35,17 +35,35 @@
3535
set myproject $project
3636
set mytype $cstype
3737
set mysrcid $srcid
3838
set myrevisions $revisions
3939
40
- # Keep track of the generated changesets.
40
+ # Keep track of the generated changesets and of the inverse
41
+ # mapping from revisions to them.
4142
lappend mychangesets $self
43
+ foreach r $revisions { set myrevmap($r) $self }
4244
return
4345
}
4446
45
- method id {} { return $myid }
47
+ method id {} { return $myid }
48
+ method revisions {} { return $myrevisions }
49
+
4650
method setid {id} { set myid $id ; return }
51
+
52
+ method bysymbol {} { return [expr {$mytype eq "sym"}] }
53
+ method byrevision {} { return [expr {$mytype eq "rev"}] }
54
+
55
+ method successors {} {
56
+ # NOTE / FUTURE: Possible bottleneck.
57
+ array set dependencies {}
58
+ PullSuccessorRevisions dependencies $myrevisions
59
+ set csets {}
60
+ foreach {_ child} [array get dependencies] {
61
+ lappend csets $myrevmap($child)
62
+ }
63
+ return [lsort -unique $csets]
64
+ }
4765
4866
method breakinternaldependencies {} {
4967
# This method inspects the changesets for internal
5068
# dependencies. Nothing is done if there are no
5169
# such. Otherwise the changeset is split into a set of
@@ -66,11 +84,11 @@
6684
6785
# Array of dependencies (parent -> child). This is pulled from
6886
# the state, and limited to successors within the changeset.
6987
7088
array set dependencies {}
71
- PullInternalDependencies dependencies $myrevisions
89
+ PullSuccessorRevisions dependencies $myrevisions
7290
if {![array size dependencies]} {return 0} ; # Nothing to break.
7391
7492
log write 6 csets ...<$myid>.......................................................
7593
7694
# We have internal dependencies to break. We now iterate over
@@ -204,10 +222,19 @@
204222
incr pos
205223
}
206224
}
207225
return
208226
}
227
+
228
+ method timerange {} {
229
+ set theset ('[join $myrevisions {','}]')
230
+ return [state run "
231
+ SELECT MIN(R.date), MAX(R.date)
232
+ FROM revision R
233
+ WHERE R.rid IN $theset
234
+ "]
235
+ }
209236
210237
# # ## ### ##### ######## #############
211238
## State
212239
213240
variable myid ; # Id of the cset for the persistent state.
@@ -227,11 +254,11 @@
227254
SELECT tid, name FROM cstype;
228255
}] { set mycstype($name) $tid }
229256
return
230257
}
231258
232
- proc PullInternalDependencies {dv revisions} {
259
+ proc PullSuccessorRevisions {dv revisions} {
233260
upvar 1 $dv dependencies
234261
set theset ('[join $revisions {','}]')
235262
236263
foreach {rid child} [state run "
237264
-- Primary children
@@ -291,11 +318,11 @@
291318
# to ensure that the following loop runs correctly.
292319
#
293320
# Note 2: start == end is not possible. It indicates a
294321
# self-dependency due to the uniqueness of positions,
295322
# and that is something we have ruled out already, see
296
- # PullInternalDependencies.
323
+ # PullSuccessorRevisions.
297324
298325
foreach {rid child} [array get dependencies] {
299326
set dkey [list $rid $child]
300327
set start $pos($rid)
301328
set end $pos($child)
@@ -470,11 +497,12 @@
470497
return
471498
}
472499
473500
# # ## ### ##### ######## #############
474501
475
- typevariable mychangesets {} ; # List of all known changesets.
502
+ typevariable mychangesets {} ; # List of all known changesets.
503
+ typevariable myrevmap -array {} ; # Map from revisions to their changeset.
476504
477505
typemethod all {} {
478506
return $mychangesets
479507
}
480508
481509
--- tools/cvs2fossil/lib/c2f_prev.tcl
+++ tools/cvs2fossil/lib/c2f_prev.tcl
@@ -35,17 +35,35 @@
35 set myproject $project
36 set mytype $cstype
37 set mysrcid $srcid
38 set myrevisions $revisions
39
40 # Keep track of the generated changesets.
 
41 lappend mychangesets $self
 
42 return
43 }
44
45 method id {} { return $myid }
 
 
46 method setid {id} { set myid $id ; return }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
48 method breakinternaldependencies {} {
49 # This method inspects the changesets for internal
50 # dependencies. Nothing is done if there are no
51 # such. Otherwise the changeset is split into a set of
@@ -66,11 +84,11 @@
66
67 # Array of dependencies (parent -> child). This is pulled from
68 # the state, and limited to successors within the changeset.
69
70 array set dependencies {}
71 PullInternalDependencies dependencies $myrevisions
72 if {![array size dependencies]} {return 0} ; # Nothing to break.
73
74 log write 6 csets ...<$myid>.......................................................
75
76 # We have internal dependencies to break. We now iterate over
@@ -204,10 +222,19 @@
204 incr pos
205 }
206 }
207 return
208 }
 
 
 
 
 
 
 
 
 
209
210 # # ## ### ##### ######## #############
211 ## State
212
213 variable myid ; # Id of the cset for the persistent state.
@@ -227,11 +254,11 @@
227 SELECT tid, name FROM cstype;
228 }] { set mycstype($name) $tid }
229 return
230 }
231
232 proc PullInternalDependencies {dv revisions} {
233 upvar 1 $dv dependencies
234 set theset ('[join $revisions {','}]')
235
236 foreach {rid child} [state run "
237 -- Primary children
@@ -291,11 +318,11 @@
291 # to ensure that the following loop runs correctly.
292 #
293 # Note 2: start == end is not possible. It indicates a
294 # self-dependency due to the uniqueness of positions,
295 # and that is something we have ruled out already, see
296 # PullInternalDependencies.
297
298 foreach {rid child} [array get dependencies] {
299 set dkey [list $rid $child]
300 set start $pos($rid)
301 set end $pos($child)
@@ -470,11 +497,12 @@
470 return
471 }
472
473 # # ## ### ##### ######## #############
474
475 typevariable mychangesets {} ; # List of all known changesets.
 
476
477 typemethod all {} {
478 return $mychangesets
479 }
480
481
--- tools/cvs2fossil/lib/c2f_prev.tcl
+++ tools/cvs2fossil/lib/c2f_prev.tcl
@@ -35,17 +35,35 @@
35 set myproject $project
36 set mytype $cstype
37 set mysrcid $srcid
38 set myrevisions $revisions
39
40 # Keep track of the generated changesets and of the inverse
41 # mapping from revisions to them.
42 lappend mychangesets $self
43 foreach r $revisions { set myrevmap($r) $self }
44 return
45 }
46
47 method id {} { return $myid }
48 method revisions {} { return $myrevisions }
49
50 method setid {id} { set myid $id ; return }
51
52 method bysymbol {} { return [expr {$mytype eq "sym"}] }
53 method byrevision {} { return [expr {$mytype eq "rev"}] }
54
55 method successors {} {
56 # NOTE / FUTURE: Possible bottleneck.
57 array set dependencies {}
58 PullSuccessorRevisions dependencies $myrevisions
59 set csets {}
60 foreach {_ child} [array get dependencies] {
61 lappend csets $myrevmap($child)
62 }
63 return [lsort -unique $csets]
64 }
65
66 method breakinternaldependencies {} {
67 # This method inspects the changesets for internal
68 # dependencies. Nothing is done if there are no
69 # such. Otherwise the changeset is split into a set of
@@ -66,11 +84,11 @@
84
85 # Array of dependencies (parent -> child). This is pulled from
86 # the state, and limited to successors within the changeset.
87
88 array set dependencies {}
89 PullSuccessorRevisions dependencies $myrevisions
90 if {![array size dependencies]} {return 0} ; # Nothing to break.
91
92 log write 6 csets ...<$myid>.......................................................
93
94 # We have internal dependencies to break. We now iterate over
@@ -204,10 +222,19 @@
222 incr pos
223 }
224 }
225 return
226 }
227
228 method timerange {} {
229 set theset ('[join $myrevisions {','}]')
230 return [state run "
231 SELECT MIN(R.date), MAX(R.date)
232 FROM revision R
233 WHERE R.rid IN $theset
234 "]
235 }
236
237 # # ## ### ##### ######## #############
238 ## State
239
240 variable myid ; # Id of the cset for the persistent state.
@@ -227,11 +254,11 @@
254 SELECT tid, name FROM cstype;
255 }] { set mycstype($name) $tid }
256 return
257 }
258
259 proc PullSuccessorRevisions {dv revisions} {
260 upvar 1 $dv dependencies
261 set theset ('[join $revisions {','}]')
262
263 foreach {rid child} [state run "
264 -- Primary children
@@ -291,11 +318,11 @@
318 # to ensure that the following loop runs correctly.
319 #
320 # Note 2: start == end is not possible. It indicates a
321 # self-dependency due to the uniqueness of positions,
322 # and that is something we have ruled out already, see
323 # PullSuccessorRevisions.
324
325 foreach {rid child} [array get dependencies] {
326 set dkey [list $rid $child]
327 set start $pos($rid)
328 set end $pos($child)
@@ -470,11 +497,12 @@
497 return
498 }
499
500 # # ## ### ##### ######## #############
501
502 typevariable mychangesets {} ; # List of all known changesets.
503 typevariable myrevmap -array {} ; # Map from revisions to their changeset.
504
505 typemethod all {} {
506 return $mychangesets
507 }
508
509

Keyboard Shortcuts

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