diff options
| author | cashmere <cashmere@autistici.org> | 2026-09-04 09:05:24 +0200 |
|---|---|---|
| committer | cashmere <cashmere@autistici.org> | 2026-09-04 09:05:24 +0200 |
| commit | 4f49b16079b27d7ce633619e4cddfdf2bffbc952 (patch) | |
| tree | c296c1e7f3c3e2f6859c6d3a1b1b208779b89679 /tools/cvs2fossil/lib/c2f_pinitcsets.tcl | |
| download | relic-master.tar.gz | |
Diffstat (limited to 'tools/cvs2fossil/lib/c2f_pinitcsets.tcl')
| -rw-r--r-- | tools/cvs2fossil/lib/c2f_pinitcsets.tcl | 379 |
1 files changed, 379 insertions, 0 deletions
diff --git a/tools/cvs2fossil/lib/c2f_pinitcsets.tcl b/tools/cvs2fossil/lib/c2f_pinitcsets.tcl new file mode 100644 index 0000000..cd4cafb --- /dev/null +++ b/tools/cvs2fossil/lib/c2f_pinitcsets.tcl @@ -0,0 +1,379 @@ +## -*- tcl -*- +# # ## ### ##### ######## ############# ##################### +## Copyright (c) 2007-2008 Andreas Kupries. +# +# This software is licensed as described in the file LICENSE, which +# you should have received as part of this distribution. +# +# This software consists of voluntary contributions made by many +# individuals. For exact contribution history, see the revision +# history and logs, available at http://fossil-scm.hwaci.com/fossil +# # ## ### ##### ######## ############# ##################### + +## Pass V. This pass creates the initial set of project level +## revisions, aka changesets. Later passes will refine them, puts them +## into proper order, set their dependencies, etc. + +# # ## ### ##### ######## ############# ##################### +## Requirements + +package require Tcl 8.4 ; # Required runtime. +package require snit ; # OO system. +package require vc::tools::misc ; # Text formatting. +package require vc::tools::log ; # User feedback. +package require vc::tools::mem ; # Memory tracking. +package require vc::fossil::import::cvs::repository ; # Repository management. +package require vc::fossil::import::cvs::state ; # State storage. +package require vc::fossil::import::cvs::integrity ; # State integrity checks. +package require vc::fossil::import::cvs::project::rev ; # Project level changesets + +# # ## ### ##### ######## ############# ##################### +## Register the pass with the management + +vc::fossil::import::cvs::pass define \ + InitCsets \ + {Initialize ChangeSets} \ + ::vc::fossil::import::cvs::pass::initcsets + +# # ## ### ##### ######## ############# ##################### +## + +snit::type ::vc::fossil::import::cvs::pass::initcsets { + # # ## ### ##### ######## ############# + ## Public API + + typemethod setup {} { + # Define the names and structure of the persistent state of + # this pass. + + state use project + state use file + state use revision + state use revisionbranchchildren + state use branch + state use tag + state use symbol + state use meta + + # Data per changeset, namely the project it belongs to, how it + # was induced (revision or symbol), plus reference to the + # primary entry causing it (meta entry or symbol). An adjunct + # table translates the type id's into human readable labels. + + state extend changeset { + cid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + pid INTEGER NOT NULL REFERENCES project, + type INTEGER NOT NULL REFERENCES cstype, + src INTEGER NOT NULL -- REFERENCES meta|symbol (type dependent) + } + state extend cstype { + tid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + UNIQUE (name) + } + # Note: Keep the labels used here in sync with the names for + # singleton helper classes for 'project::rev'. They are + # the valid type names for changesets and also hardwired + # in some code. + state run { + INSERT INTO cstype VALUES (0,'rev'); + INSERT INTO cstype VALUES (1,'sym::tag'); + INSERT INTO cstype VALUES (2,'sym::branch'); + } + + # Map from changesets to the (file level) revisions, tags, or + # branches they contain. The pos'ition provides an order of + # the items within a changeset. They are unique within the + # changeset. The items are in principle unique, if we were + # looking only at relevant changesets. However as they come + # from disparate sources the same id may have different + # meaning, be in different changesets and so is formally not + # unique. So we can only say that it is unique within the + # changeset. The integrity module has stronger checks. + + state extend csitem { + cid INTEGER NOT NULL REFERENCES changeset, + pos INTEGER NOT NULL, + iid INTEGER NOT NULL, -- REFERENCES revision|tag|branch + UNIQUE (cid, pos), + UNIQUE (cid, iid) + } { iid } + # Index on: iid (successor/predecessor retrieval) + + project::rev getcstypes + return + } + + typemethod load {} { + # Pass manager interface. Executed to load data computed by + # this pass into memory when this pass is skipped instead of + # executed. + + state use changeset + state use csitem + state use cstype + + # Need the types first, the constructor used inside of the + # 'load' below uses them to assert the correctness of type + # names. + project::rev getcstypes + project::rev load ::vc::fossil::import::cvs::repository + project::rev loadcounter + return + } + + typemethod run {} { + # Pass manager interface. Executed to perform the + # functionality of the pass. + + state transaction { + CreateRevisionChangesets ; # Group file revisions into + # preliminary csets and split + # them based on internal + # conflicts. + CreateSymbolChangesets ; # Create csets for tags and + # branches. + } + + repository printcsetstatistics + integrity changesets + + # Load the changesets for use by the next passes. + project::rev load ::vc::fossil::import::cvs::repository + project::rev loadcounter + return + } + + typemethod discard {} { + # Pass manager interface. Executed for all passes after the + # run passes, to remove all data of this pass from the state, + # as being out of date. + + state discard changeset + state discard cstype + state discard csitem + return + } + + # # ## ### ##### ######## ############# + ## Internal methods + + proc CreateRevisionChangesets {} { + log write 3 initcsets {Create changesets based on revisions} + + # To get the initial of changesets we first group all file + # level revisions using the same meta data entry together. As + # the meta data encodes not only author and log message, but + # also line of development and project we can be sure that + # revisions in different project and lines of development are + # not grouped together. In contrast to cvs2svn we do __not__ + # use distance in time between revisions to break them + # apart. We have seen CVS repositories (from SF) where a + # single commit contained revisions several hours apart, + # likely due to trouble on the server hosting the repository. + + # We order the revisions here by time, this will help the + # later passes (avoids joins later to get at the ordering + # info). + + # The changesets made from these groups are immediately + # inspected for internal conflicts and any such are broken by + # splitting the problematic changeset into multiple + # fragments. The results are changesets which have no internal + # dependencies, only external ones. + + set n 0 + set nx 0 + + set lastmeta {} + set lastproject {} + set revisions {} + + # Note: We could have written this loop to create the csets + # early, extending them with all their revisions. This + # however would mean lots of (slow) method invokations + # on the csets. Doing it like this, late creation, means + # less such calls. None, but the creation itself. + + log write 14 initcsets meta_begin + mem::mark + state foreachrow { + SELECT M.mid AS xmid, + R.rid AS xrid, + M.pid AS xpid + FROM revision R, + meta M -- R ==> M, using PK index of M. + WHERE R.mid = M.mid + ORDER BY M.mid, R.date + } { + log write 14 initcsets meta_next + + if {$lastmeta != $xmid} { + if {[llength $revisions]} { + incr n + set p [repository projectof $lastproject] + log write 14 initcsets meta_cset_begin + mem::mark + set cset [project::rev %AUTO% $p rev $lastmeta $revisions] + log write 14 initcsets meta_cset_done + set spawned [$cset breakinternaldependencies nx] + $cset persist + $cset destroy + foreach cset $spawned { $cset persist ; $cset destroy } + mem::mark + set revisions {} + } + set lastmeta $xmid + set lastproject $xpid + } + lappend revisions $xrid + } + + if {[llength $revisions]} { + incr n + set p [repository projectof $lastproject] + log write 14 initcsets meta_cset_begin + mem::mark + set cset [project::rev %AUTO% $p rev $lastmeta $revisions] + log write 14 initcsets meta_cset_done + set spawned [$cset breakinternaldependencies nx] + $cset persist + $cset destroy + foreach cset $spawned { $cset persist ; $cset destroy } + mem::mark + } + + log write 14 initcsets meta_done + mem::mark + + log write 4 initcsets "Created and saved [nsp $n {revision changeset}]" + log write 4 initcsets "Created and saved [nsp $nx {additional revision changeset}]" + + mem::mark + log write 4 initcsets Ok. + return + } + + proc CreateSymbolChangesets {} { + log write 3 initcsets {Create changesets based on symbols} + mem::mark + + # Tags and branches induce changesets as well, containing the + # revisions they are attached to (tags), or spawned from + # (branches). + + set n 0 + + # First process the tags, then the branches. We know that + # their ids do not overlap with each other. + + set lastsymbol {} + set lastproject {} + set tags {} + + state foreachrow { + SELECT S.sid AS xsid, + T.tid AS xtid, + S.pid AS xpid + FROM tag T, + symbol S -- T ==> R/S, using PK indices of R, S. + WHERE T.sid = S.sid + ORDER BY S.sid, T.tid + } { + if {$lastsymbol != $xsid} { + if {[llength $tags]} { + incr n + set p [repository projectof $lastproject] + set cset [project::rev %AUTO% $p sym::tag $lastsymbol $tags] + set tags {} + $cset persist + $cset destroy + } + set lastsymbol $xsid + set lastproject $xpid + } + lappend tags $xtid + } + + if {[llength $tags]} { + incr n + set p [repository projectof $lastproject] + set cset [project::rev %AUTO% $p sym::tag $lastsymbol $tags] + $cset persist + $cset destroy + } + + set lastsymbol {} + set lasproject {} + set branches {} + + state foreachrow { + SELECT S.sid AS xsid, + B.bid AS xbid, + S.pid AS xpid + FROM branch B, + symbol S -- B ==> R/S, using PK indices of R, S. + WHERE B.sid = S.sid + ORDER BY S.sid, B.bid + } { + if {$lastsymbol != $xsid} { + if {[llength $branches]} { + incr n + set p [repository projectof $lastproject] + set cset [project::rev %AUTO% $p sym::branch $lastsymbol $branches] + set branches {} + $cset persist + $cset destroy + } + set lastsymbol $xsid + set lastproject $xpid + } + lappend branches $xbid + } + + if {[llength $branches]} { + incr n + set p [repository projectof $lastproject] + set cset [project::rev %AUTO% $p sym::branch $lastsymbol $branches] + $cset persist + $cset destroy + } + + log write 4 initcsets "Created and saved [nsp $n {symbol changeset}]" + mem::mark + return + } + + # # ## ### ##### ######## ############# + ## Configuration + + pragma -hasinstances no ; # singleton + pragma -hastypeinfo no ; # no introspection + pragma -hastypedestroy no ; # immortal + + # # ## ### ##### ######## ############# +} + +namespace eval ::vc::fossil::import::cvs::pass { + namespace export initcsets + namespace eval initcsets { + namespace import ::vc::fossil::import::cvs::repository + namespace import ::vc::fossil::import::cvs::state + namespace import ::vc::fossil::import::cvs::integrity + namespace eval project { + namespace import ::vc::fossil::import::cvs::project::rev + } + namespace eval mem { + namespace import ::vc::tools::mem::mark + } + namespace import ::vc::tools::misc::* + namespace import ::vc::tools::log + log register initcsets + } +} + +# # ## ### ##### ######## ############# ##################### +## Ready + +package provide vc::fossil::import::cvs::pass::initcsets 1.0 +return |
