@@ -18,10 +18,11 @@
18 18 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
19 19 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
package require Tcl 8.4 ; # Required runtime.
20 20 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
package require snit ; # OO system.
21 21 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
package require struct::graph ; # Graph handling.
22 22 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
package require struct::list ; # Higher order list operations.
23 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ package require vc::tools::dot ; # User feedback. DOT export.
23 24 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
package require vc::tools::log ; # User feedback.
24 25 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
package require vc::tools::misc ; # Text formatting.
25 26 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
package require vc::fossil::import::cvs::project::rev ; # Project level changesets
26 27 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
package require vc::fossil::import::cvs::project::revlink ; # Cycle links.
27 28 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
@@ -30,46 +31,40 @@
30 31 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
31 32 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
snit::type ::vc::fossil::import::cvs::cyclebreaker {
32 33 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# # ## ### ##### ######## #############
33 34 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
## Public API
34 35 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
35 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- typemethod run {changesets {savecmd {}}} {
36 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- ::variable save $savecmd
37 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- ::variable at 0
36 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ typemethod dotsto {path} {
37 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ::variable mydotdestination $path
38 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ return
39 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
40 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
41 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ typemethod dot {label changesets} {
42 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ::variable mydotprefix $label
43 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ::variable mydotid 0
44 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
45 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ set dg [Setup $changesets 0]
46 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Mark $dg
47 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ $dg destroy
48 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ return
49 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
50 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
51 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ typemethod run {label changesets {savecmd {}}} {
52 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ::variable mysave $savecmd
53 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ::variable myat 0
54 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ::variable mydotprefix $label
55 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ::variable mydotid 0
38 56 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
39 57 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# We create a graph of the revision changesets, using the file
40 58 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# level dependencies to construct a first approximation of the
41 59 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# dependencies at the project level. Then we look for cycles
42 60 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# in that graph and break them.
43 61 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
44 62 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# 1. Create nodes for all relevant changesets and a mapping
45 63 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# from the revisions to their changesets/nodes.
46 64 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
47 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- log write 3 cyclebreaker "Creating changeset graph, filling with nodes"
48 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- log write 3 cyclebreaker "Adding [nsp [llength $changesets] node]"
49 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
50 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- set dg [struct::graph dg]
51 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
52 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- foreach cset $changesets {
53 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- dg node insert $cset
54 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- dg node set $cset timerange [$cset timerange]
55 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- }
56 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
57 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # 2. Find for all relevant changeset their revisions and their
58 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # dependencies. Map the latter back to changesets and
59 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # construct the corresponding arcs.
60 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
61 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- log write 3 cyclebreaker {Setting up node dependencies}
62 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
63 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- foreach cset $changesets {
64 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- foreach succ [$cset successors] {
65 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # Changesets may have dependencies outside of the
66 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # chosen set. These are ignored
67 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- if {![dg node exists $succ]} continue
68 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- dg arc insert $cset $succ
69 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- }
70 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- }
65 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ set dg [Setup $changesets]
71 66 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
72 67 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# 3. Lastly we iterate the graph topologically. We mark off
73 68 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# the nodes which have no predecessors, in order from
74 69 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# oldest to youngest, saving and removing dependencies. If
75 70 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# we find no nodes without predecessors we have a cycle,
@@ -93,35 +88,68 @@
93 88 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return
94 89 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
95 90 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
96 91 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# # ## ### ##### ######## #############
97 92 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
## Internal methods
93 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
94 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ proc Setup {changesets {log 1}} {
95 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if {$log} {
96 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ log write 3 cyclebreaker "Creating changeset graph, filling with nodes"
97 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ log write 3 cyclebreaker "Adding [nsp [llength $changesets] node]"
98 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
99 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
100 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ set dg [struct::graph dg]
101 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
102 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ foreach cset $changesets {
103 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ $dg node insert $cset
104 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ $dg node set $cset timerange [$cset timerange]
105 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
106 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
107 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # 2. Find for all relevant changeset their revisions and their
108 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # dependencies. Map the latter back to changesets and
109 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # construct the corresponding arcs.
110 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
111 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if {$log} {
112 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ log write 3 cyclebreaker {Setting up node dependencies}
113 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
114 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
115 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ foreach cset $changesets {
116 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ foreach succ [$cset successors] {
117 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Changesets may have dependencies outside of the
118 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # chosen set. These are ignored
119 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if {![$dg node exists $succ]} continue
120 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ $dg arc insert $cset $succ
121 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
122 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
123 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
124 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ return $dg
125 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
98 126 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
99 127 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# Instead of searching the whole graph for the degree-0 nodes in
100 128 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# each iteration we compute the list once to start, and then only
101 129 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# update it incrementally based on the outgoing neighbours of the
102 130 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# node chosen for commit.
103 131 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
104 132 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
proc InitializeCandidates {dg} {
105 133 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# bottom = list (list (node, range min, range max))
106 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- ::variable bottom
134 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ::variable mybottom
107 135 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
foreach n [$dg nodes] {
108 136 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
if {[$dg node degree -in $n]} continue
109 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- lappend bottom [linsert [$dg node get $n timerange] 0 $n]
137 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ lappend mybottom [linsert [$dg node get $n timerange] 0 $n]
110 138 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
111 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- set bottom [lsort -index 1 -integer [lsort -index 2 -integer $bottom]]
139 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ set mybottom [lsort -index 1 -integer [lsort -index 2 -integer $mybottom]]
112 140 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return
113 141 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
114 142 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
115 143 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
proc WithoutPredecessor {dg nv} {
116 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- ::variable bottom
144 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ::variable mybottom
117 145 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
118 146 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
upvar 1 $nv n
119 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- if {![llength $bottom]} { return 0 }
147 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if {![llength $mybottom]} { return 0 }
120 148 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
121 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- set n [lindex [lindex $bottom 0] 0]
122 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- set bottom [lrange $bottom 1 end]
149 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ set n [lindex [lindex $mybottom 0] 0]
150 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ set mybottom [lrange $mybottom 1 end]
123 151 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
set changed 0
124 152 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
125 153 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# Update list of nodes without predecessor, based on the
126 154 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# outgoing neighbours of the chosen node. This should be
127 155 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# faster than iterating of the whole set of nodes, finding all
@@ -128,35 +156,35 @@
128 156 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# without predecessors, sorting them by time, etc. pp.
129 157 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
foreach out [$dg nodes -out $n] {
130 158 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
if {[$dg node degree -in $out] > 1} continue
131 159 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# Degree-1 neighbour, will have no predecessors after the
132 160 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# removal of n. Put on the list.
133 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- lappend bottom [linsert [$dg node get $out timerange] 0 $out]
161 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ lappend mybottom [linsert [$dg node get $out timerange] 0 $out]
134 162 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
set changed 1
135 163 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
136 164 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
if {$changed} {
137 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- set bottom [lsort -index 1 -integer [lsort -index 2 -integer $bottom]]
165 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ set mybottom [lsort -index 1 -integer [lsort -index 2 -integer $mybottom]]
138 166 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
139 167 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
140 168 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# We do not delete the node immediately, to allow the Save
141 169 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# procedure to save the dependencies as well (encoded in the
142 170 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# arcs).
143 171 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return 1
144 172 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
145 173 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
146 174 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
proc SaveAndRemove {dg n} {
147 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- ::variable at
148 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- ::variable save
175 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ::variable myat
176 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ::variable mysave
149 177 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
150 178 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# Give the user of the cycle breaker the opportunity to work
151 179 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# with the changeset before it is removed from the graph.
152 180 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
153 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- if {[llength $save]} {
154 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- uplevel #0 [linsert $save end $at $n]
181 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if {[llength $mysave]} {
182 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ uplevel #0 [linsert $mysave end $myat $n]
155 183 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
156 184 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
157 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- incr at
185 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ incr myat
158 186 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
$dg node delete $n
159 187 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return
160 188 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
161 189 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
162 190 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
proc FindCycle {dg} {
@@ -229,17 +257,27 @@
229 257 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
$link destroy
230 258 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
231 259 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
232 260 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
233 261 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
log write 5 breakrcycle "Breaking cycle ($cprint) by splitting changeset <[$bestnode id]>"
262 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ set ID [$bestnode id]
263 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Mark $dg -${ID}-before
234 264 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
235 265 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
set newcsets [$bestlink break]
236 266 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
$bestlink destroy
237 267 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
238 268 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# At this point the old changeset (BESTNODE) is gone
239 269 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# already. We remove it from the graph as well and then enter
240 270 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# the fragments generated for it.
271 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
272 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # NOTE. We have to get the list of incoming neighbours and
273 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # recompute their successors after the new nodes have been
274 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # inserted. Their outgoing arcs will now go to one or both of
275 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # the new nodes, and not redoing them may cause us to forget
276 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # circles, leaving them in, unbroken.
277 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
278 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ set pre [$dg nodes -in $bestnode]
241 279 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
242 280 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
$dg node delete $bestnode
243 281 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
244 282 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
foreach cset $newcsets {
245 283 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
$dg node insert $cset
@@ -252,16 +290,54 @@
252 290 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# the chosen set. These are ignored
253 291 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
if {![$dg node exists $succ]} continue
254 292 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
$dg arc insert $cset $succ
255 293 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
256 294 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
295 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ foreach cset $pre {
296 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ foreach succ [$cset successors] {
297 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Note that the arc may already exist in the graph. If
298 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # so ignore it. The new changesets may have
299 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # dependencies outside of the chosen set. These are
300 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ignored
301 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if {![$dg node exists $succ]} continue
302 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if {[HasArc $dg $cset $succ]} continue;# TODO should be graph method.
303 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ $dg arc insert $cset $succ
304 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
305 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
306 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
307 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Mark $dg -${ID}-after
308 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ return
309 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
310 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
311 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # TODO: This should be a graph method.
312 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ proc HasArc {dg a b} {
313 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ #8.5: return [expr {$b in [$dg nodes -out $a]}]
314 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if {[lsearch -exact [$dg nodes -out $a] $b] < 0} { return 0 }
315 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ return 1
316 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
317 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
318 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ proc Mark {dg {suffix {}}} {
319 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ::variable mydotdestination
320 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if {$mydotdestination eq ""} return
321 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ::variable mydotprefix
322 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ::variable mydotid
323 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ set fname $mydotdestination/${mydotprefix}${mydotid}${suffix}.dot
324 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ file mkdir [file dirname $fname]
325 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ dot write $dg $mydotprefix$suffix $fname
326 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ incr mydotid
327 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
328 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ log write 5 cyclebreaker ".dot export $fname"
257 329 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return
258 330 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
259 331 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
260 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- typevariable at 0 ; # Counter for commit ids for the changesets.
261 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- typevariable bottom {} ; # List of candidate nodes for committing.
262 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- typevariable save {} ; # The command to call for each processed node
332 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ typevariable myat 0 ; # Counter for commit ids for the changesets.
333 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ typevariable mybottom {} ; # List of candidate nodes for committing.
334 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ typevariable mysave {} ; # The command to call for each processed node
335 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
336 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ typevariable mydotdestination {} ; # Destination directory for .dot files.
337 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ typevariable mydotprefix {} ; # Prefix for dot files when exporting the graphs.
338 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ typevariable mydotid 0 ; # Counter for dot file name generation.
263 339 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
264 340 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# # ## ### ##### ######## #############
265 341 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
## Configuration
266 342 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
267 343 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
pragma -hasinstances no ; # singleton
@@ -278,14 +354,15 @@
278 354 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
namespace import ::vc::fossil::import::cvs::project::rev
279 355 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
namespace import ::vc::fossil::import::cvs::project::revlink
280 356 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
281 357 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
namespace import ::vc::tools::misc::*
282 358 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
namespace import ::vc::tools::log
359 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ namespace import ::vc::tools::dot
283 360 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
log register cyclebreaker
284 361 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
285 362 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
286 363 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
287 364 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
# # ## ### ##### ######## ############# #####################
288 365 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
## Ready
289 366 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
290 367 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
package provide vc::fossil::import::cvs::cyclebreaker 1.0
291 368 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return
292 369 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!