Fossil SCM

Replaced the checks for self-referential changesets in the cycle breaker with a scheme in the changeset class doing checks when splitting a changeset, which is also called by the general changeset integrity code, after each pass. Extended log output at high verbosity levels. Thorough checking of the fragments a changeset is to be split into.

aku 2007-11-30 03:57 trunk
Commit b42cff97e319c2087208f98065f6c809ed560da4
--- tools/cvs2fossil/lib/c2f_cyclebreaker.tcl
+++ tools/cvs2fossil/lib/c2f_cyclebreaker.tcl
@@ -197,31 +197,10 @@
197197
foreach succ [$cset successors] {
198198
# Changesets may have dependencies outside of the
199199
# chosen set. These are ignored
200200
if {![$dg node exists $succ]} continue
201201
$dg arc insert $cset $succ
202
-
203
- # Check for changesets referencing themselves. Such a
204
- # loop shows that the changeset in question has
205
- # internal dependencies. Something which is supposed
206
- # to be not possible, as pass 5 (InitCsets) takes care
207
- # to transform internal into external dependencies by
208
- # breaking the relevant changesets apart. So having
209
- # one indicates big trouble in pass 5. We report them
210
- # and dump internal structures to make it easier to
211
- # trace the links causing the problem.
212
- if {$succ eq $cset} {
213
- log write 2 cyclebreaker "LOOP changeset [$cset str] __________________"
214
- array set nmap [$cset nextmap]
215
- foreach r [lsort -dict [array names nmap]] {
216
- foreach succrev $nmap($r) {
217
- log write 2 cyclebreaker \
218
- "LOOP * <$r> --> <$succrev> --> cs [[project::rev ofitem $succrev] str]"
219
- }
220
- }
221
- trouble fatal "Self-referencing changeset [$cset str]"
222
- }
223202
}
224203
}
225204
226205
if {$log} {
227206
log write 3 cyclebreaker "Has [nsp [llength [$dg arcs]] dependency dependencies]"
@@ -232,13 +211,10 @@
232211
233212
if {$log} { Mark $dg -start }
234213
MarkWatch $dg
235214
PreHook $dg
236215
MarkWatch $dg
237
-
238
- # This kills the application if loops (see above) were found.
239
- trouble abort?
240216
return $dg
241217
}
242218
243219
# Instead of searching the whole graph for the degree-0 nodes in
244220
# each iteration we compute the list once to start, and then only
@@ -440,21 +416,10 @@
440416
foreach succ [$cset successors] {
441417
# The new changesets may have dependencies outside of
442418
# the chosen set. These are ignored
443419
if {![$dg node exists $succ]} continue
444420
$dg arc insert $cset $succ
445
- if {$succ eq $cset} {
446
- log write 2 cyclebreaker "LOOP changeset [$cset str] __________________"
447
- array set nmap [$cset nextmap]
448
- foreach r [lsort -dict [array names nmap]] {
449
- foreach succrev $nmap($r) {
450
- log write 2 cyclebreaker \
451
- "LOOP * <$r> --> <$succrev> --> cs [[project::rev ofitem $succrev] str]"
452
- }
453
- }
454
- trouble internal "Self-referencing changeset [$cset str]"
455
- }
456421
}
457422
}
458423
foreach cset $pre {
459424
foreach succ [$cset successors] {
460425
# Note that the arc may already exist in the graph. If
461426
--- tools/cvs2fossil/lib/c2f_cyclebreaker.tcl
+++ tools/cvs2fossil/lib/c2f_cyclebreaker.tcl
@@ -197,31 +197,10 @@
197 foreach succ [$cset successors] {
198 # Changesets may have dependencies outside of the
199 # chosen set. These are ignored
200 if {![$dg node exists $succ]} continue
201 $dg arc insert $cset $succ
202
203 # Check for changesets referencing themselves. Such a
204 # loop shows that the changeset in question has
205 # internal dependencies. Something which is supposed
206 # to be not possible, as pass 5 (InitCsets) takes care
207 # to transform internal into external dependencies by
208 # breaking the relevant changesets apart. So having
209 # one indicates big trouble in pass 5. We report them
210 # and dump internal structures to make it easier to
211 # trace the links causing the problem.
212 if {$succ eq $cset} {
213 log write 2 cyclebreaker "LOOP changeset [$cset str] __________________"
214 array set nmap [$cset nextmap]
215 foreach r [lsort -dict [array names nmap]] {
216 foreach succrev $nmap($r) {
217 log write 2 cyclebreaker \
218 "LOOP * <$r> --> <$succrev> --> cs [[project::rev ofitem $succrev] str]"
219 }
220 }
221 trouble fatal "Self-referencing changeset [$cset str]"
222 }
223 }
224 }
225
226 if {$log} {
227 log write 3 cyclebreaker "Has [nsp [llength [$dg arcs]] dependency dependencies]"
@@ -232,13 +211,10 @@
232
233 if {$log} { Mark $dg -start }
234 MarkWatch $dg
235 PreHook $dg
236 MarkWatch $dg
237
238 # This kills the application if loops (see above) were found.
239 trouble abort?
240 return $dg
241 }
242
243 # Instead of searching the whole graph for the degree-0 nodes in
244 # each iteration we compute the list once to start, and then only
@@ -440,21 +416,10 @@
440 foreach succ [$cset successors] {
441 # The new changesets may have dependencies outside of
442 # the chosen set. These are ignored
443 if {![$dg node exists $succ]} continue
444 $dg arc insert $cset $succ
445 if {$succ eq $cset} {
446 log write 2 cyclebreaker "LOOP changeset [$cset str] __________________"
447 array set nmap [$cset nextmap]
448 foreach r [lsort -dict [array names nmap]] {
449 foreach succrev $nmap($r) {
450 log write 2 cyclebreaker \
451 "LOOP * <$r> --> <$succrev> --> cs [[project::rev ofitem $succrev] str]"
452 }
453 }
454 trouble internal "Self-referencing changeset [$cset str]"
455 }
456 }
457 }
458 foreach cset $pre {
459 foreach succ [$cset successors] {
460 # Note that the arc may already exist in the graph. If
461
--- tools/cvs2fossil/lib/c2f_cyclebreaker.tcl
+++ tools/cvs2fossil/lib/c2f_cyclebreaker.tcl
@@ -197,31 +197,10 @@
197 foreach succ [$cset successors] {
198 # Changesets may have dependencies outside of the
199 # chosen set. These are ignored
200 if {![$dg node exists $succ]} continue
201 $dg arc insert $cset $succ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202 }
203 }
204
205 if {$log} {
206 log write 3 cyclebreaker "Has [nsp [llength [$dg arcs]] dependency dependencies]"
@@ -232,13 +211,10 @@
211
212 if {$log} { Mark $dg -start }
213 MarkWatch $dg
214 PreHook $dg
215 MarkWatch $dg
 
 
 
216 return $dg
217 }
218
219 # Instead of searching the whole graph for the degree-0 nodes in
220 # each iteration we compute the list once to start, and then only
@@ -440,21 +416,10 @@
416 foreach succ [$cset successors] {
417 # The new changesets may have dependencies outside of
418 # the chosen set. These are ignored
419 if {![$dg node exists $succ]} continue
420 $dg arc insert $cset $succ
 
 
 
 
 
 
 
 
 
 
 
421 }
422 }
423 foreach cset $pre {
424 foreach succ [$cset successors] {
425 # Note that the arc may already exist in the graph. If
426
--- tools/cvs2fossil/lib/c2f_integrity.tcl
+++ tools/cvs2fossil/lib/c2f_integrity.tcl
@@ -51,17 +51,18 @@
5151
set n 0
5252
AllButMeta
5353
return
5454
}
5555
56
- typemethod changesets {} {
56
+ typemethod changesets {csets} {
5757
log write 4 integrity {Check database consistency}
5858
5959
set n 0
6060
RevisionChangesets
6161
TagChangesets
6262
BranchChangesets
63
+ Selfreferentiality $csets
6364
return
6465
}
6566
6667
# # ## ### ##### ######## #############
6768
## Internal methods
@@ -732,10 +733,21 @@
732733
GROUP BY V.cid) AS VV
733734
WHERE VV.cid = UU.cid
734735
AND UU.fcount < VV.rcount)
735736
AND T.tid = C.type
736737
}
738
+ return
739
+ }
740
+
741
+ proc Selfreferentiality {csets} {
742
+ log write 4 integrity {Checking changesets for self-references}
743
+
744
+ foreach cset $csets {
745
+ if {[$cset selfreferential]} {
746
+ trouble fatal "[$cset str] depends on itself"
747
+ }
748
+ }
737749
return
738750
}
739751
740752
proc ___UnusedChangesetChecks___ {} {
741753
# This code performs a number of paranoid checks of the
742754
--- tools/cvs2fossil/lib/c2f_integrity.tcl
+++ tools/cvs2fossil/lib/c2f_integrity.tcl
@@ -51,17 +51,18 @@
51 set n 0
52 AllButMeta
53 return
54 }
55
56 typemethod changesets {} {
57 log write 4 integrity {Check database consistency}
58
59 set n 0
60 RevisionChangesets
61 TagChangesets
62 BranchChangesets
 
63 return
64 }
65
66 # # ## ### ##### ######## #############
67 ## Internal methods
@@ -732,10 +733,21 @@
732 GROUP BY V.cid) AS VV
733 WHERE VV.cid = UU.cid
734 AND UU.fcount < VV.rcount)
735 AND T.tid = C.type
736 }
 
 
 
 
 
 
 
 
 
 
 
737 return
738 }
739
740 proc ___UnusedChangesetChecks___ {} {
741 # This code performs a number of paranoid checks of the
742
--- tools/cvs2fossil/lib/c2f_integrity.tcl
+++ tools/cvs2fossil/lib/c2f_integrity.tcl
@@ -51,17 +51,18 @@
51 set n 0
52 AllButMeta
53 return
54 }
55
56 typemethod changesets {csets} {
57 log write 4 integrity {Check database consistency}
58
59 set n 0
60 RevisionChangesets
61 TagChangesets
62 BranchChangesets
63 Selfreferentiality $csets
64 return
65 }
66
67 # # ## ### ##### ######## #############
68 ## Internal methods
@@ -732,10 +733,21 @@
733 GROUP BY V.cid) AS VV
734 WHERE VV.cid = UU.cid
735 AND UU.fcount < VV.rcount)
736 AND T.tid = C.type
737 }
738 return
739 }
740
741 proc Selfreferentiality {csets} {
742 log write 4 integrity {Checking changesets for self-references}
743
744 foreach cset $csets {
745 if {[$cset selfreferential]} {
746 trouble fatal "[$cset str] depends on itself"
747 }
748 }
749 return
750 }
751
752 proc ___UnusedChangesetChecks___ {} {
753 # This code performs a number of paranoid checks of the
754
--- tools/cvs2fossil/lib/c2f_pbreakacycle.tcl
+++ tools/cvs2fossil/lib/c2f_pbreakacycle.tcl
@@ -80,11 +80,11 @@
8080
LoadCommitOrder
8181
cyclebreaker run break-all [myproc Changesets]
8282
}
8383
8484
repository printcsetstatistics
85
- integrity changesets
85
+ integrity changesets [project::rev all]
8686
return
8787
}
8888
8989
typemethod discard {} {
9090
# Pass manager interface. Executed for all passes after the
9191
--- tools/cvs2fossil/lib/c2f_pbreakacycle.tcl
+++ tools/cvs2fossil/lib/c2f_pbreakacycle.tcl
@@ -80,11 +80,11 @@
80 LoadCommitOrder
81 cyclebreaker run break-all [myproc Changesets]
82 }
83
84 repository printcsetstatistics
85 integrity changesets
86 return
87 }
88
89 typemethod discard {} {
90 # Pass manager interface. Executed for all passes after the
91
--- tools/cvs2fossil/lib/c2f_pbreakacycle.tcl
+++ tools/cvs2fossil/lib/c2f_pbreakacycle.tcl
@@ -80,11 +80,11 @@
80 LoadCommitOrder
81 cyclebreaker run break-all [myproc Changesets]
82 }
83
84 repository printcsetstatistics
85 integrity changesets [project::rev all]
86 return
87 }
88
89 typemethod discard {} {
90 # Pass manager interface. Executed for all passes after the
91
--- tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl
+++ tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl
@@ -69,11 +69,11 @@
6969
state transaction {
7070
cyclebreaker run break-rev [myproc Changesets]
7171
}
7272
7373
repository printcsetstatistics
74
- integrity changesets
74
+ integrity changesets [project::rev all]
7575
return
7676
}
7777
7878
typemethod discard {} {
7979
# Pass manager interface. Executed for all passes after the
8080
--- tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl
+++ tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl
@@ -69,11 +69,11 @@
69 state transaction {
70 cyclebreaker run break-rev [myproc Changesets]
71 }
72
73 repository printcsetstatistics
74 integrity changesets
75 return
76 }
77
78 typemethod discard {} {
79 # Pass manager interface. Executed for all passes after the
80
--- tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl
+++ tools/cvs2fossil/lib/c2f_pbreakrcycle.tcl
@@ -69,11 +69,11 @@
69 state transaction {
70 cyclebreaker run break-rev [myproc Changesets]
71 }
72
73 repository printcsetstatistics
74 integrity changesets [project::rev all]
75 return
76 }
77
78 typemethod discard {} {
79 # Pass manager interface. Executed for all passes after the
80
--- tools/cvs2fossil/lib/c2f_pbreakscycle.tcl
+++ tools/cvs2fossil/lib/c2f_pbreakscycle.tcl
@@ -68,11 +68,11 @@
6868
state transaction {
6969
cyclebreaker run break-sym [myproc Changesets]
7070
}
7171
7272
repository printcsetstatistics
73
- integrity changesets
73
+ integrity changesets [project::rev all]
7474
return
7575
}
7676
7777
typemethod discard {} {
7878
# Pass manager interface. Executed for all passes after the
7979
--- tools/cvs2fossil/lib/c2f_pbreakscycle.tcl
+++ tools/cvs2fossil/lib/c2f_pbreakscycle.tcl
@@ -68,11 +68,11 @@
68 state transaction {
69 cyclebreaker run break-sym [myproc Changesets]
70 }
71
72 repository printcsetstatistics
73 integrity changesets
74 return
75 }
76
77 typemethod discard {} {
78 # Pass manager interface. Executed for all passes after the
79
--- tools/cvs2fossil/lib/c2f_pbreakscycle.tcl
+++ tools/cvs2fossil/lib/c2f_pbreakscycle.tcl
@@ -68,11 +68,11 @@
68 state transaction {
69 cyclebreaker run break-sym [myproc Changesets]
70 }
71
72 repository printcsetstatistics
73 integrity changesets [project::rev all]
74 return
75 }
76
77 typemethod discard {} {
78 # Pass manager interface. Executed for all passes after the
79
--- tools/cvs2fossil/lib/c2f_pinitcsets.tcl
+++ tools/cvs2fossil/lib/c2f_pinitcsets.tcl
@@ -142,11 +142,11 @@
142142
CreateSymbolChangesets ; # Create csets for tags and branches.
143143
PersistTheChangesets
144144
}
145145
146146
repository printcsetstatistics
147
- integrity changesets
147
+ integrity changesets [project::rev all]
148148
return
149149
}
150150
151151
typemethod discard {} {
152152
# Pass manager interface. Executed for all passes after the
153153
--- tools/cvs2fossil/lib/c2f_pinitcsets.tcl
+++ tools/cvs2fossil/lib/c2f_pinitcsets.tcl
@@ -142,11 +142,11 @@
142 CreateSymbolChangesets ; # Create csets for tags and branches.
143 PersistTheChangesets
144 }
145
146 repository printcsetstatistics
147 integrity changesets
148 return
149 }
150
151 typemethod discard {} {
152 # Pass manager interface. Executed for all passes after the
153
--- tools/cvs2fossil/lib/c2f_pinitcsets.tcl
+++ tools/cvs2fossil/lib/c2f_pinitcsets.tcl
@@ -142,11 +142,11 @@
142 CreateSymbolChangesets ; # Create csets for tags and branches.
143 PersistTheChangesets
144 }
145
146 repository printcsetstatistics
147 integrity changesets [project::rev all]
148 return
149 }
150
151 typemethod discard {} {
152 # Pass manager interface. Executed for all passes after the
153
--- tools/cvs2fossil/lib/c2f_prev.tcl
+++ tools/cvs2fossil/lib/c2f_prev.tcl
@@ -16,10 +16,11 @@
1616
# # ## ### ##### ######## ############# #####################
1717
## Requirements
1818
1919
package require Tcl 8.4 ; # Required runtime.
2020
package require snit ; # OO system.
21
+package require struct::set ; # Set operations.
2122
package require vc::tools::misc ; # Text formatting
2223
package require vc::tools::trouble ; # Error reporting.
2324
package require vc::tools::log ; # User feedback.
2425
package require vc::fossil::import::cvs::state ; # State storage.
2526
package require vc::fossil::import::cvs::integrity ; # State integrity checks.
@@ -36,11 +37,13 @@
3637
set myid $theid
3738
} else {
3839
set myid [incr mycounter]
3940
}
4041
41
- integrity assert {[info exists mycstype($cstype)]} {Bad changeset type '$cstype'.}
42
+ integrity assert {
43
+ [info exists mycstype($cstype)]
44
+ } {Bad changeset type '$cstype'.}
4245
4346
set myproject $project
4447
set mytype $cstype
4548
set mytypeobj ::vc::fossil::import::cvs::project::rev::${cstype}
4649
set mysrcid $srcid
@@ -53,10 +56,11 @@
5356
set myidmap($myid) $self
5457
foreach iid $items {
5558
set key [list $cstype $iid]
5659
set myitemmap($key) $self
5760
lappend mytitems $key
61
+ log write 8 csets {MAP+ item <$key> $self = [$self str]}
5862
}
5963
return
6064
}
6165
6266
method str {} {
@@ -243,10 +247,11 @@
243247
# thus never more than one reference in the list.
244248
245249
foreach iid $myitems {
246250
set key [list $mytype $iid]
247251
unset myitemmap($key)
252
+ log write 8 csets {MAP- item <$key> $self = [$self str]}
248253
}
249254
250255
# Create changesets for the fragments, reusing the current one
251256
# for the first fragment. We sort them in order to allow
252257
# checking for gaps and nice messages.
@@ -283,10 +288,11 @@
283288
284289
set myitems [lrange $myitems 0 $firste]
285290
foreach iid $myitems {
286291
set key [list $mytype $iid]
287292
set myitemmap($key) $self
293
+ log write 8 csets {MAP+ item <$key> $self = [$self str]}
288294
}
289295
290296
return 1
291297
}
292298
@@ -313,24 +319,57 @@
313319
}
314320
315321
method timerange {} { return [$mytypeobj timerange $myitems] }
316322
317323
method drop {} {
324
+ log write 8 csets {Dropping $self = [$self str]}
325
+
318326
state transaction {
319327
state run {
320328
DELETE FROM changeset WHERE cid = $myid;
321329
DELETE FROM csitem WHERE cid = $myid;
322330
}
323331
}
324332
foreach iid $myitems {
325333
set key [list $mytype $iid]
326334
unset myitemmap($key)
335
+ log write 8 csets {MAP- item <$key> $self = [$self str]}
327336
}
328337
set pos [lsearch -exact $mychangesets $self]
329338
set mychangesets [lreplace $mychangesets $pos $pos]
330339
return
331340
}
341
+
342
+ method selfreferential {} {
343
+ log write 9 csets {Checking [$self str] /[llength $myitems]}
344
+
345
+ if {![struct::set contains [$self successors] $self]} {
346
+ return 0
347
+ }
348
+ if {[log verbosity?] < 8} { return 1 }
349
+
350
+ # Print the detailed successor structure of the self-
351
+ # referential changeset, if the verbosity of the log is dialed
352
+ # high enough.
353
+
354
+ log write 8 csets [set hdr {Self-referential changeset [$self str] __________________}]
355
+ array set nmap [$self nextmap]
356
+ foreach item [lsort -dict [array names nmap]] {
357
+ foreach succitem $nmap($item) {
358
+ set succcs $myitemmap($succitem)
359
+ set hint [expr {($succcs eq $self)
360
+ ? "LOOP"
361
+ : " "}]
362
+ set i "<$item [$type itemstr $item]>"
363
+ set s "<$succitem [$type itemstr $succitem]>"
364
+ set scs [$succcs str]
365
+ log write 8 csets {$hint * $i --> $s --> cs $scs}
366
+ }
367
+ }
368
+ log write 8 csets [regsub -all {[^ ]} $hdr {_}]
369
+ return 1
370
+ }
332371
333372
typemethod split {cset args} {
334373
# As part of the creation of the new changesets specified in
335374
# ARGS as sets of items, all subsets of CSET's item set, CSET
336375
# will be dropped from all databases, in and out of memory,
@@ -337,26 +376,64 @@
337376
# and then destroyed.
338377
#
339378
# Note: The item lists found in args are tagged items. They
340379
# have to have the same type as the changeset, being subsets
341380
# of its items. This is checked in Untag1.
381
+
382
+ # Constraints: No fragment must be empty. All fragments have
383
+ # to be subsets of the cset. The union has to cover the
384
+ # original. All pairwise intersections have to be empty.
385
+
386
+ log write 8 csets {OLD: [lsort [$cset items]]}
387
+
388
+ set cover {}
389
+ foreach fragmentitems $args {
390
+ log write 8 csets {NEW: [lsort $fragmentitems]}
391
+
392
+ integrity assert {
393
+ ![struct::set empty $fragmentitems]
394
+ } {changeset fragment is empty}
395
+ integrity assert {
396
+ [struct::set subsetof $fragmentitems [$cset items]]
397
+ } {changeset fragment is not a subset}
398
+ struct::set add cover $fragmentitems
399
+ }
400
+ integrity assert {
401
+ [struct::set equal $cover [$cset items]]
402
+ } {The fragments do not cover the original changeset}
403
+ set i 1
404
+ foreach fia $args {
405
+ foreach fib [lrange $args $i end] {
406
+ integrity assert {
407
+ [struct::set empty [struct::set intersect $fia $fib]]
408
+ } {The fragments <$fia> and <$fib> overlap}
409
+ }
410
+ incr i
411
+ }
412
+
413
+ # All checks pass, actually perform the split.
342414
343415
struct::list assign [$cset data] project cstype cssrc
344416
345417
$cset drop
346418
$cset destroy
347419
348420
set newcsets {}
349421
foreach fragmentitems $args {
350
- integrity assert {
351
- [llength $fragmentitems]
352
- } {Attempted to create an empty changeset, i.e. without items}
353
- lappend newcsets [$type %AUTO% $project $cstype $cssrc \
354
- [Untag $fragmentitems $cstype]]
422
+ log write 8 csets {MAKE: [lsort $fragmentitems]}
423
+
424
+ set fragment [$type %AUTO% $project $cstype $cssrc \
425
+ [Untag $fragmentitems $cstype]]
426
+ lappend newcsets $fragment
427
+ $fragment persist
428
+
429
+ if {[$fragment selfreferential]} {
430
+ trouble fatal "[$fragment str] depends on itself"
431
+ }
355432
}
356433
357
- foreach c $newcsets { $c persist }
434
+ trouble abort?
358435
return $newcsets
359436
}
360437
361438
typemethod strlist {changesets} {
362439
return [join [struct::list map $changesets [myproc ID]]]
@@ -371,10 +448,15 @@
371448
proc Untag1 {cstype theitem} {
372449
struct::list assign $theitem t i
373450
integrity assert {$cstype eq $t} {Item $i's type is '$t', expected '$cstype'}
374451
return $i
375452
}
453
+
454
+ typemethod itemstr {item} {
455
+ struct::list assign $item itype iid
456
+ return [$itype str $iid]
457
+ }
376458
377459
# # ## ### ##### ######## #############
378460
## State
379461
380462
variable myid {} ; # Id of the cset for the persistent
@@ -673,10 +755,21 @@
673755
snit::type ::vc::fossil::import::cvs::project::rev::rev {
674756
typemethod byrevision {} { return 1 }
675757
typemethod bysymbol {} { return 0 }
676758
typemethod istag {} { return 0 }
677759
typemethod isbranch {} { return 0 }
760
+
761
+ typemethod str {revision} {
762
+ struct::list assign [state run {
763
+ SELECT R.rev, F.name, P.name
764
+ FROM revision R, file F, project P
765
+ WHERE R.rid = $revision
766
+ AND F.fid = R.fid
767
+ AND P.pid = F.pid
768
+ }] revnr fname pname
769
+ return "$pname/${revnr}::$fname"
770
+ }
678771
679772
# result = list (mintime, maxtime)
680773
typemethod timerange {items} {
681774
set theset ('[join $items {','}]')
682775
return [state run "
@@ -917,10 +1010,22 @@
9171010
snit::type ::vc::fossil::import::cvs::project::rev::sym::tag {
9181011
typemethod byrevision {} { return 0 }
9191012
typemethod bysymbol {} { return 1 }
9201013
typemethod istag {} { return 1 }
9211014
typemethod isbranch {} { return 0 }
1015
+
1016
+ typemethod str {tag} {
1017
+ struct::list assign [state run {
1018
+ SELECT S.name, F.name, P.name
1019
+ FROM tag T, symbol S, file F, project P
1020
+ WHERE T.tid = $tag
1021
+ AND F.fid = T.fid
1022
+ AND P.pid = F.pid
1023
+ AND S.sid = T.sid
1024
+ }] sname fname pname
1025
+ return "$pname/T'${sname}'::$fname"
1026
+ }
9221027
9231028
# result = list (mintime, maxtime)
9241029
typemethod timerange {tags} {
9251030
# The range is defined as the range of the revisions the tags
9261031
# are attached to.
@@ -985,10 +1090,22 @@
9851090
snit::type ::vc::fossil::import::cvs::project::rev::sym::branch {
9861091
typemethod byrevision {} { return 0 }
9871092
typemethod bysymbol {} { return 1 }
9881093
typemethod istag {} { return 0 }
9891094
typemethod isbranch {} { return 1 }
1095
+
1096
+ typemethod str {branch} {
1097
+ struct::list assign [state run {
1098
+ SELECT S.name, F.name, P.name
1099
+ FROM branch B, symbol S, file F, project P
1100
+ WHERE B.bid = $branch
1101
+ AND F.fid = B.fid
1102
+ AND P.pid = F.pid
1103
+ AND S.sid = B.sid
1104
+ }] sname fname pname
1105
+ return "$pname/B'${sname}'::$fname"
1106
+ }
9901107
9911108
# result = list (mintime, maxtime)
9921109
typemethod timerange {branches} {
9931110
# The range of a branch is defined as the range of the
9941111
# revisions the branches are spawned by. NOTE however that the
9951112
--- tools/cvs2fossil/lib/c2f_prev.tcl
+++ tools/cvs2fossil/lib/c2f_prev.tcl
@@ -16,10 +16,11 @@
16 # # ## ### ##### ######## ############# #####################
17 ## Requirements
18
19 package require Tcl 8.4 ; # Required runtime.
20 package require snit ; # OO system.
 
21 package require vc::tools::misc ; # Text formatting
22 package require vc::tools::trouble ; # Error reporting.
23 package require vc::tools::log ; # User feedback.
24 package require vc::fossil::import::cvs::state ; # State storage.
25 package require vc::fossil::import::cvs::integrity ; # State integrity checks.
@@ -36,11 +37,13 @@
36 set myid $theid
37 } else {
38 set myid [incr mycounter]
39 }
40
41 integrity assert {[info exists mycstype($cstype)]} {Bad changeset type '$cstype'.}
 
 
42
43 set myproject $project
44 set mytype $cstype
45 set mytypeobj ::vc::fossil::import::cvs::project::rev::${cstype}
46 set mysrcid $srcid
@@ -53,10 +56,11 @@
53 set myidmap($myid) $self
54 foreach iid $items {
55 set key [list $cstype $iid]
56 set myitemmap($key) $self
57 lappend mytitems $key
 
58 }
59 return
60 }
61
62 method str {} {
@@ -243,10 +247,11 @@
243 # thus never more than one reference in the list.
244
245 foreach iid $myitems {
246 set key [list $mytype $iid]
247 unset myitemmap($key)
 
248 }
249
250 # Create changesets for the fragments, reusing the current one
251 # for the first fragment. We sort them in order to allow
252 # checking for gaps and nice messages.
@@ -283,10 +288,11 @@
283
284 set myitems [lrange $myitems 0 $firste]
285 foreach iid $myitems {
286 set key [list $mytype $iid]
287 set myitemmap($key) $self
 
288 }
289
290 return 1
291 }
292
@@ -313,24 +319,57 @@
313 }
314
315 method timerange {} { return [$mytypeobj timerange $myitems] }
316
317 method drop {} {
 
 
318 state transaction {
319 state run {
320 DELETE FROM changeset WHERE cid = $myid;
321 DELETE FROM csitem WHERE cid = $myid;
322 }
323 }
324 foreach iid $myitems {
325 set key [list $mytype $iid]
326 unset myitemmap($key)
 
327 }
328 set pos [lsearch -exact $mychangesets $self]
329 set mychangesets [lreplace $mychangesets $pos $pos]
330 return
331 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
333 typemethod split {cset args} {
334 # As part of the creation of the new changesets specified in
335 # ARGS as sets of items, all subsets of CSET's item set, CSET
336 # will be dropped from all databases, in and out of memory,
@@ -337,26 +376,64 @@
337 # and then destroyed.
338 #
339 # Note: The item lists found in args are tagged items. They
340 # have to have the same type as the changeset, being subsets
341 # of its items. This is checked in Untag1.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
343 struct::list assign [$cset data] project cstype cssrc
344
345 $cset drop
346 $cset destroy
347
348 set newcsets {}
349 foreach fragmentitems $args {
350 integrity assert {
351 [llength $fragmentitems]
352 } {Attempted to create an empty changeset, i.e. without items}
353 lappend newcsets [$type %AUTO% $project $cstype $cssrc \
354 [Untag $fragmentitems $cstype]]
 
 
 
 
 
355 }
356
357 foreach c $newcsets { $c persist }
358 return $newcsets
359 }
360
361 typemethod strlist {changesets} {
362 return [join [struct::list map $changesets [myproc ID]]]
@@ -371,10 +448,15 @@
371 proc Untag1 {cstype theitem} {
372 struct::list assign $theitem t i
373 integrity assert {$cstype eq $t} {Item $i's type is '$t', expected '$cstype'}
374 return $i
375 }
 
 
 
 
 
376
377 # # ## ### ##### ######## #############
378 ## State
379
380 variable myid {} ; # Id of the cset for the persistent
@@ -673,10 +755,21 @@
673 snit::type ::vc::fossil::import::cvs::project::rev::rev {
674 typemethod byrevision {} { return 1 }
675 typemethod bysymbol {} { return 0 }
676 typemethod istag {} { return 0 }
677 typemethod isbranch {} { return 0 }
 
 
 
 
 
 
 
 
 
 
 
678
679 # result = list (mintime, maxtime)
680 typemethod timerange {items} {
681 set theset ('[join $items {','}]')
682 return [state run "
@@ -917,10 +1010,22 @@
917 snit::type ::vc::fossil::import::cvs::project::rev::sym::tag {
918 typemethod byrevision {} { return 0 }
919 typemethod bysymbol {} { return 1 }
920 typemethod istag {} { return 1 }
921 typemethod isbranch {} { return 0 }
 
 
 
 
 
 
 
 
 
 
 
 
922
923 # result = list (mintime, maxtime)
924 typemethod timerange {tags} {
925 # The range is defined as the range of the revisions the tags
926 # are attached to.
@@ -985,10 +1090,22 @@
985 snit::type ::vc::fossil::import::cvs::project::rev::sym::branch {
986 typemethod byrevision {} { return 0 }
987 typemethod bysymbol {} { return 1 }
988 typemethod istag {} { return 0 }
989 typemethod isbranch {} { return 1 }
 
 
 
 
 
 
 
 
 
 
 
 
990
991 # result = list (mintime, maxtime)
992 typemethod timerange {branches} {
993 # The range of a branch is defined as the range of the
994 # revisions the branches are spawned by. NOTE however that the
995
--- tools/cvs2fossil/lib/c2f_prev.tcl
+++ tools/cvs2fossil/lib/c2f_prev.tcl
@@ -16,10 +16,11 @@
16 # # ## ### ##### ######## ############# #####################
17 ## Requirements
18
19 package require Tcl 8.4 ; # Required runtime.
20 package require snit ; # OO system.
21 package require struct::set ; # Set operations.
22 package require vc::tools::misc ; # Text formatting
23 package require vc::tools::trouble ; # Error reporting.
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::integrity ; # State integrity checks.
@@ -36,11 +37,13 @@
37 set myid $theid
38 } else {
39 set myid [incr mycounter]
40 }
41
42 integrity assert {
43 [info exists mycstype($cstype)]
44 } {Bad changeset type '$cstype'.}
45
46 set myproject $project
47 set mytype $cstype
48 set mytypeobj ::vc::fossil::import::cvs::project::rev::${cstype}
49 set mysrcid $srcid
@@ -53,10 +56,11 @@
56 set myidmap($myid) $self
57 foreach iid $items {
58 set key [list $cstype $iid]
59 set myitemmap($key) $self
60 lappend mytitems $key
61 log write 8 csets {MAP+ item <$key> $self = [$self str]}
62 }
63 return
64 }
65
66 method str {} {
@@ -243,10 +247,11 @@
247 # thus never more than one reference in the list.
248
249 foreach iid $myitems {
250 set key [list $mytype $iid]
251 unset myitemmap($key)
252 log write 8 csets {MAP- item <$key> $self = [$self str]}
253 }
254
255 # Create changesets for the fragments, reusing the current one
256 # for the first fragment. We sort them in order to allow
257 # checking for gaps and nice messages.
@@ -283,10 +288,11 @@
288
289 set myitems [lrange $myitems 0 $firste]
290 foreach iid $myitems {
291 set key [list $mytype $iid]
292 set myitemmap($key) $self
293 log write 8 csets {MAP+ item <$key> $self = [$self str]}
294 }
295
296 return 1
297 }
298
@@ -313,24 +319,57 @@
319 }
320
321 method timerange {} { return [$mytypeobj timerange $myitems] }
322
323 method drop {} {
324 log write 8 csets {Dropping $self = [$self str]}
325
326 state transaction {
327 state run {
328 DELETE FROM changeset WHERE cid = $myid;
329 DELETE FROM csitem WHERE cid = $myid;
330 }
331 }
332 foreach iid $myitems {
333 set key [list $mytype $iid]
334 unset myitemmap($key)
335 log write 8 csets {MAP- item <$key> $self = [$self str]}
336 }
337 set pos [lsearch -exact $mychangesets $self]
338 set mychangesets [lreplace $mychangesets $pos $pos]
339 return
340 }
341
342 method selfreferential {} {
343 log write 9 csets {Checking [$self str] /[llength $myitems]}
344
345 if {![struct::set contains [$self successors] $self]} {
346 return 0
347 }
348 if {[log verbosity?] < 8} { return 1 }
349
350 # Print the detailed successor structure of the self-
351 # referential changeset, if the verbosity of the log is dialed
352 # high enough.
353
354 log write 8 csets [set hdr {Self-referential changeset [$self str] __________________}]
355 array set nmap [$self nextmap]
356 foreach item [lsort -dict [array names nmap]] {
357 foreach succitem $nmap($item) {
358 set succcs $myitemmap($succitem)
359 set hint [expr {($succcs eq $self)
360 ? "LOOP"
361 : " "}]
362 set i "<$item [$type itemstr $item]>"
363 set s "<$succitem [$type itemstr $succitem]>"
364 set scs [$succcs str]
365 log write 8 csets {$hint * $i --> $s --> cs $scs}
366 }
367 }
368 log write 8 csets [regsub -all {[^ ]} $hdr {_}]
369 return 1
370 }
371
372 typemethod split {cset args} {
373 # As part of the creation of the new changesets specified in
374 # ARGS as sets of items, all subsets of CSET's item set, CSET
375 # will be dropped from all databases, in and out of memory,
@@ -337,26 +376,64 @@
376 # and then destroyed.
377 #
378 # Note: The item lists found in args are tagged items. They
379 # have to have the same type as the changeset, being subsets
380 # of its items. This is checked in Untag1.
381
382 # Constraints: No fragment must be empty. All fragments have
383 # to be subsets of the cset. The union has to cover the
384 # original. All pairwise intersections have to be empty.
385
386 log write 8 csets {OLD: [lsort [$cset items]]}
387
388 set cover {}
389 foreach fragmentitems $args {
390 log write 8 csets {NEW: [lsort $fragmentitems]}
391
392 integrity assert {
393 ![struct::set empty $fragmentitems]
394 } {changeset fragment is empty}
395 integrity assert {
396 [struct::set subsetof $fragmentitems [$cset items]]
397 } {changeset fragment is not a subset}
398 struct::set add cover $fragmentitems
399 }
400 integrity assert {
401 [struct::set equal $cover [$cset items]]
402 } {The fragments do not cover the original changeset}
403 set i 1
404 foreach fia $args {
405 foreach fib [lrange $args $i end] {
406 integrity assert {
407 [struct::set empty [struct::set intersect $fia $fib]]
408 } {The fragments <$fia> and <$fib> overlap}
409 }
410 incr i
411 }
412
413 # All checks pass, actually perform the split.
414
415 struct::list assign [$cset data] project cstype cssrc
416
417 $cset drop
418 $cset destroy
419
420 set newcsets {}
421 foreach fragmentitems $args {
422 log write 8 csets {MAKE: [lsort $fragmentitems]}
423
424 set fragment [$type %AUTO% $project $cstype $cssrc \
425 [Untag $fragmentitems $cstype]]
426 lappend newcsets $fragment
427 $fragment persist
428
429 if {[$fragment selfreferential]} {
430 trouble fatal "[$fragment str] depends on itself"
431 }
432 }
433
434 trouble abort?
435 return $newcsets
436 }
437
438 typemethod strlist {changesets} {
439 return [join [struct::list map $changesets [myproc ID]]]
@@ -371,10 +448,15 @@
448 proc Untag1 {cstype theitem} {
449 struct::list assign $theitem t i
450 integrity assert {$cstype eq $t} {Item $i's type is '$t', expected '$cstype'}
451 return $i
452 }
453
454 typemethod itemstr {item} {
455 struct::list assign $item itype iid
456 return [$itype str $iid]
457 }
458
459 # # ## ### ##### ######## #############
460 ## State
461
462 variable myid {} ; # Id of the cset for the persistent
@@ -673,10 +755,21 @@
755 snit::type ::vc::fossil::import::cvs::project::rev::rev {
756 typemethod byrevision {} { return 1 }
757 typemethod bysymbol {} { return 0 }
758 typemethod istag {} { return 0 }
759 typemethod isbranch {} { return 0 }
760
761 typemethod str {revision} {
762 struct::list assign [state run {
763 SELECT R.rev, F.name, P.name
764 FROM revision R, file F, project P
765 WHERE R.rid = $revision
766 AND F.fid = R.fid
767 AND P.pid = F.pid
768 }] revnr fname pname
769 return "$pname/${revnr}::$fname"
770 }
771
772 # result = list (mintime, maxtime)
773 typemethod timerange {items} {
774 set theset ('[join $items {','}]')
775 return [state run "
@@ -917,10 +1010,22 @@
1010 snit::type ::vc::fossil::import::cvs::project::rev::sym::tag {
1011 typemethod byrevision {} { return 0 }
1012 typemethod bysymbol {} { return 1 }
1013 typemethod istag {} { return 1 }
1014 typemethod isbranch {} { return 0 }
1015
1016 typemethod str {tag} {
1017 struct::list assign [state run {
1018 SELECT S.name, F.name, P.name
1019 FROM tag T, symbol S, file F, project P
1020 WHERE T.tid = $tag
1021 AND F.fid = T.fid
1022 AND P.pid = F.pid
1023 AND S.sid = T.sid
1024 }] sname fname pname
1025 return "$pname/T'${sname}'::$fname"
1026 }
1027
1028 # result = list (mintime, maxtime)
1029 typemethod timerange {tags} {
1030 # The range is defined as the range of the revisions the tags
1031 # are attached to.
@@ -985,10 +1090,22 @@
1090 snit::type ::vc::fossil::import::cvs::project::rev::sym::branch {
1091 typemethod byrevision {} { return 0 }
1092 typemethod bysymbol {} { return 1 }
1093 typemethod istag {} { return 0 }
1094 typemethod isbranch {} { return 1 }
1095
1096 typemethod str {branch} {
1097 struct::list assign [state run {
1098 SELECT S.name, F.name, P.name
1099 FROM branch B, symbol S, file F, project P
1100 WHERE B.bid = $branch
1101 AND F.fid = B.fid
1102 AND P.pid = F.pid
1103 AND S.sid = B.sid
1104 }] sname fname pname
1105 return "$pname/B'${sname}'::$fname"
1106 }
1107
1108 # result = list (mintime, maxtime)
1109 typemethod timerange {branches} {
1110 # The range of a branch is defined as the range of the
1111 # revisions the branches are spawned by. NOTE however that the
1112

Keyboard Shortcuts

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