summaryrefslogtreecommitdiff
path: root/tools/cvs2fossil/lib/c2f_pinitcsets.tcl
diff options
context:
space:
mode:
authorcashmere <cashmere@autistici.org>2026-09-04 09:05:24 +0200
committercashmere <cashmere@autistici.org>2026-09-04 09:05:24 +0200
commit4f49b16079b27d7ce633619e4cddfdf2bffbc952 (patch)
treec296c1e7f3c3e2f6859c6d3a1b1b208779b89679 /tools/cvs2fossil/lib/c2f_pinitcsets.tcl
downloadrelic-master.tar.gz
initial commitHEADmaster
Diffstat (limited to 'tools/cvs2fossil/lib/c2f_pinitcsets.tcl')
-rw-r--r--tools/cvs2fossil/lib/c2f_pinitcsets.tcl379
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