Check-in [cb70cf4ad6]
Not logged in
Overview

SHA1 Hash:cb70cf4ad69d891a24b9499cfbbd75f132954ba1
Date: 2007-10-13 05:39:00
User: aku
Comment:The basic work of setting up and linking revisions, tags, and branches is complete.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified tools/cvs2fossil/lib/c2f_file.tcl from [f38b4ceaf7] to [880ea7b085].

@@ -19,10 +19,12 @@
 package require Tcl 8.4                             ; # Required runtime.
 package require snit                                ; # OO system.
 package require struct::set                         ; # Set operations.
 package require vc::fossil::import::cvs::file::rev  ; # CVS per file revisions.
 package require vc::fossil::import::cvs::file::sym  ; # CVS per file symbols.
+package require vc::tools::trouble                  ; # Error reporting.
+package require vc::tools::misc                     ; # Text formatting
 
 # # ## ### ##### ######## ############# #####################
 ##
 
 snit::type ::vc::fossil::import::cvs::file {
@@ -97,11 +99,11 @@
     method admindone {} {
 	# We do nothing at the boundary of admin and revision data
     }
 
     method def {revnr date author state next branches} {
-	$self LookForUnlabeledBranches $branches
+	$self RecordBranchCommits $branches
 	$myproject author $author
 
 	if {[info exists myrev($revnr)]} {
 	    trouble fatal "File $mypath contains duplicate definitions for revision $revnr."
 	    return
@@ -112,10 +114,20 @@
 	RecordBasicDependencies $revnr $next
 	return
     }
 
     method defdone {} {
+	# This is all done after the revision tree has been extracted
+	# from the file, before the commit mesages and delta texts are
+	# processed.
+
+	ProcessPrimaryDependencies
+	ProcessBranchDependencies
+	SortBranches
+	ProcessTagDependencies
+	DetermineTheRootRevision
+	return
     }
 
     method setdesc {d} {# ignore}
 
     method extend {revnr commitmsg deltarange} {
@@ -146,11 +158,11 @@
 
 	$rev setcommitmsg $cm
 	$rev settext  $deltarange
 
 	if {![rev istrunkrevnr $revnr]} {
-	    $rev setbranch [[$self Rev2Branch $revnr] name]
+	    $rev setbranchname [[$self Rev2Branch $revnr] name]
 	}
 
 	# If this is revision 1.1, we have to determine whether the
 	# file seems to have been created through 'cvs add' instead of
 	# 'cvs import'. This can be done by looking at the un-
@@ -174,43 +186,68 @@
     method done {} {}
 
     # # ## ### ##### ######## #############
     ## State
 
-    variable mypath            {} ; # Path of rcs archive
-    variable myproject         {} ; # Project object the file belongs to.
-    variable myrev -array      {} ; # All revisions and their connections.
-    variable myrevisions       {} ; # Same as myrev, but a list, giving us the order
-    #                             ; # of revisions.
+    variable mypath            {} ; # Path of our rcs archive.
+    variable myproject         {} ; # Reference to the project object
+				    # the file belongs to.
+    variable myrev -array      {} ; # Maps revision number to the
+				    # associated revision object.
+    variable myrevisions       {} ; # Same as myrev, but a list,
+				    # giving us the order of
+				    # revisions.
     variable myhead            {} ; # Head revision (revision number)
-    variable myprincipal       {} ; # Principal branch (branch number)
-    #                             ; # Contrary to the name this is the default branch.
-    variable mydependencies    {} ; # Dictionary parent -> child, dependency recorder.
-    variable myimported        0  ; # Boolean flag. Set iff rev 1.1 of the file seemingly
-    #                             ; # was imported instead of added normally.
-    variable myroot            {} ; # Revision number of the root revision. Usually '1.1'.
-    #                             ; # Can be a different number, because of 'cvsadmin -o'.
-    variable mybranches -array {} ; # branch number   -> symbol object handling the branch
-    variable mytags     -array {} ; # revision number -> list of symbol object for the tags
-    #                             ; # associated with the revision.
-    variable mysymbols         {} ; # Set of symbol names found in this file.
+    variable myprincipal       {} ; # Principal branch (branch number).
+				    # Contrary to the name this is the
+				    # default branch.
+    variable mydependencies    {} ; # Dictionary parent -> child,
+				    # records primary dependencies.
+    variable myimported        0  ; # Boolean flag. Set if and only if
+				    # rev 1.1 of the file seemingly
+				    # was imported instead of added
+				    # normally.
+    variable myroot            {} ; # Reference to the revision object
+				    # holding the root revision.  Its
+				    # number usually is '1.1'. Can be
+				    # a different number, because of
+				    # gaps created via 'cvsadmin -o'.
+    variable mybranches -array {} ; # Maps branch number to the symbol
+				    # object handling the branch.
+    variable mytags     -array {} ; # Maps revision number to the list
+				    # of symbol objects for the tags
+				    # associated with the revision.
+    variable mysymbols         {} ; # Set of the symbol names found in
+				    # this file.
+
+    variable mybranchcnt 0 ; # Counter for branches, to record their
+			     # order of definition. This also defines
+			     # their order of creation, which is the
+			     # reverse of definition.  I.e. a smaller
+			     # number means 'Defined earlier', means
+			     # 'Created later'.
 
     ### TODO ###
     ### File flag - executable,
     ### RCS mode info (kb, kkb, ...)
 
     # # ## ### ##### ######## #############
     ## Internal methods
 
-    method LookForUnlabeledBranches {branches} {
+    method RecordBranchCommits {branches} {
 	foreach branchrevnr $branches {
 	    if {[catch {
 		set branch [$self Rev2Branch $branchrevnr]
 	    }]} {
 		set branch [$self AddUnlabeledBranch [rev 2branchnr $branchrevnr]]
 	    }
-	    # TODO $branch child $branchrevnr - when add-unlabeled has sensible return value
+
+	    # Record the commit, just as revision number for
+	    # now. ProcesBranchDependencies will extend that ito a
+	    # proper object reference.
+
+	    $branch setchildrevnr $branchrevnr
 	}
 	return
     }
 
     method Rev2Branch {revnr} {
@@ -229,10 +266,11 @@
 	    log write 1 file "In '$mypath': Branch '$branchnr' named '[$mybranches($branchnr) name]'"
 	    log write 1 file "Cannot have second name '$name', ignoring it"
 	    return
 	}
 	set branch [sym %AUTO% branch $branchnr [$myproject getsymbol $name]]
+	$branch setposition [incr mybranchcnt]
 	set mybranches($branchnr) $branch
 	return $branch
     }
 
     method AddTag {name revnr} {
@@ -271,10 +309,101 @@
 	    lappend mydependencies $revnr $next
 	}
 	return
     }
 
+    proc ProcessPrimaryDependencies {} {
+	upvar 1 mydependencies mydependencies myrev myrev
+
+	foreach {parentrevnr childrevnr} $mydependencies {
+	    set parent $myrev($parentrevnr)
+	    set child  $myrev($childrevnr)
+	    $parent setchild $child
+	    $child setparent $parent
+	}
+	return
+    }
+
+    proc ProcessBranchDependencies {} {
+	upvar 1 mybranches mybranches myrev myrev
+
+	foreach {branchnr branch} [array get mybranches] {
+	    set revnr [$branch parentrevnr]
+
+	    if {![info exists myrev($revnr)]} {
+		log write 1 file "In '$mypath': The branch '[$branch name]' references"
+		log write 1 file "the bogus revision '$revnr' and will be ignored."
+		$branch destroy
+		unset mybranches($branchnr)
+	    } else {
+		set rev $myrev($revnr)
+		$rev addbranch $branch
+
+		# If revisions were committed on the branch we store a
+		# reference to the branch there, and further declare
+		# the first child's parent to be branch's parent, and
+		# list this child in the parent revision.
+
+		if {[$branch haschild]} {
+		    set childrevnr [$branch childrevnr]
+		    set child $myrev($childrevnr)
+
+		    $child setparentbranch $branch
+		    $child setparent       $rev
+		    $rev addchildonbranch $child
+		}
+	    }
+	}
+	return
+    }
+
+    proc SortBranches {} {
+	upvar 1 myrev myrev
+
+	foreach {revnr rev} [array get myrev] {
+	    $rev sortbranches
+	}
+	return
+    }
+
+    proc ProcessTagDependencies {} {
+	upvar 1 mytags mytags myrev myrev
+
+	foreach {revnr taglist} [array get mytags] {
+	    if {![info exists myrev($revnr)]} {
+		set n [llength $taglist]
+		log write 1 file "In '$mypath': The following [nsp $n tag] reference"
+		log write 1 file "the bogus revision '$revnr' and will be ignored."
+		foreach tag $taglist {
+		    log write 1 file "    [$tag name]"
+		    $tag destroy
+		}
+		unset mytags($revnr)
+	    } else {
+		set rev $myrev($revnr)
+		foreach tag $taglist { $rev addtag $tag }
+	    }
+	}
+	return
+    }
+
+    proc DetermineTheRootRevision {} {
+	upvar 1 myrev myrev myroot myroot
+
+	# The root is the one revision which has no parent. By
+	# checking all revisions we ensure that we can detect and
+	# report the case of multiple roots. Without that we could
+	# simply take one revision and follow the parent links to
+	# their root (sic!).
+
+	foreach {revnr rev} [array get myrev] {
+	    if {[$rev hasparent]} continue
+	    if {$myroot ne ""} { trouble internal "Multiple root revisions found" }
+	    set myroot $rev
+	}
+	return
+    }
 
     # # ## ### ##### ######## #############
     ## Configuration
 
     pragma -hastypeinfo    no  ; # no type introspection
@@ -287,15 +416,17 @@
 
 namespace eval ::vc::fossil::import::cvs {
     namespace export file
     namespace eval file {
 	# Import not required, already a child namespace.
-	# namespace import vc::fossil::import::cvs::file::rev
-	# namespace import vc::fossil::import::cvs::file::sym
+	# namespace import ::vc::fossil::import::cvs::file::rev
+	# namespace import ::vc::fossil::import::cvs::file::sym
+	namespace import ::vc::tools::misc::*
+	namespace import ::vc::tools::trouble
     }
 }
 
 # # ## ### ##### ######## ############# #####################
 ## Ready
 
 package provide vc::fossil::import::cvs::file 1.0
 return

Modified tools/cvs2fossil/lib/c2f_frev.tcl from [867793964e] to [a8af3a8bac].

@@ -24,41 +24,115 @@
 snit::type ::vc::fossil::import::cvs::file::rev {
     # # ## ### ##### ######## #############
     ## Public API
 
     constructor {revnr date author state thefile} {
-	set myrevnr  $revnr
-	set mydate   $date
-	set myauthor $author
-	set mystate  $state
-	set myfile   $thefile
+	set myrevnr    $revnr
+	set mydate     $date
+	set myorigdate $date
+	set myauthor   $author
+	set mystate    $state
+	set myfile     $thefile
 	return
     }
+
+    # Basic pieces ________________________
 
     method hascommitmsg {} { return $myhascm }
 
-    method setcommitmsg {cm} {
-	set mycommitmsg $cm
-	set myhascm 1
+    method setcommitmsg  {cm}   { set mycommitmsg  $cm   ; set myhascm 1 ; return }
+    method settext       {text} { set mytext       $text ; return }
+    method setbranchname {name} { set mybranchname $name ; return }
+
+    method revnr {} { return $myrevnr }
+
+    # Basic parent/child linkage __________
+
+    method hasparent {} { return [expr {$myparent ne ""}] }
+    method haschild  {} { return [expr {$mychild  ne ""}] }
+
+    method setparent {parent} {
+	if {$myparent ne ""} { trouble internal "Parent already defined" }
+	set myparent $parent
+	return
+    }
+
+    method setchild {child} {
+	if {$mychild ne ""} { trouble internal "Child already defined" }
+	set mychild $child
+	return
+    }
+
+    method parent {} { return $myparent }
+    method child  {} { return $mychild  }
+
+    # Branch linkage ______________________
+
+    method setparentbranch {branch} {
+	if {$myparentbranch ne ""} { trouble internal "Branch parent already defined" }
+	set myparentbranch $branch
+	return
+    }
+
+    method addbranch {branch} {
+	lappend mybranches $branch
+	#sorted in ascending order by branch number?
+	return
+    }
+
+    method addchildonbranch {child} {
+	lappend mybranchchildren $child
 	return
     }
 
-    method settext {text} {
-	set mytext $text
+    # Tag linkage _________________________
+
+    method addtag {tag} {
+	lappend mytags $tag
 	return
     }
 
-    method setbranch {branchnr} {
-	set mybranchnr $branchnr
+    method sortbranches {} {
+	if {![llength $mybranches]} return
+
+	# Sort the branches spawned by this revision in creation
+	# order. To help in this our file gave all branches a position
+	# id, in order of their definition by the RCS archive.
+	#
+	# The creation order is (apparently) the reverse of the
+	# definition order. (If a branch is created then deleted, a
+	# later branch can be assigned the recycled branch number;
+	# therefore branch numbers are not an indication of creation
+	# order.)
+
+	set tmp {}
+	foreach branch $mybranches {
+	    lappend tmp [list $branch [$branch position]]
+	}
+
+	set mybranches {}
+	foreach item [lsort -index 1 -decreasing $tmp] {
+	    struct::list assign $item -> branch position
+	    lappend mybranches $branch
+	}
 	return
     }
 
     # # ## ### ##### ######## #############
     ## Type API
 
     typemethod istrunkrevnr {revnr} {
 	return [expr {[llength [split $revnr .]] == 2}]
+    }
+
+    typemethod isbranchrevnr {revnr _ bv} {
+	if {[regexp $mybranchpattern $revnr -> head tail]} {
+	    upvar 1 $bv branchnr
+	    set branchnr ${head}$tail
+	    return 1
+	}
+	return 0
     }
 
     typemethod 2branchnr {revnr} {
 	# Input is a branch revision number, i.e. a revision number
 	# with an even number of components; for example '2.9.2.1'
@@ -70,17 +144,13 @@
 	    return ""
 	}
 	return [join [lrange [split $revnr .] 0 end-1] .]
     }
 
-    typemethod isbranchrevnr {revnr _ bv} {
-	if {[regexp $mybranchpattern $revnr -> head tail]} {
-	    upvar 1 $bv branchnr
-	    set branchnr ${head}$tail
-	    return 1
-	}
-	return 0
+    typemethod 2branchparentrevnr {branchnr} {
+	# Chop the last segment off
+	return [join [lrange [split $branchnr .] 0 end-1] .]
     }
 
     # # ## ### ##### ######## #############
     ## State
 
@@ -89,22 +159,61 @@
     # CVS then sticks an extra 0 in here; RCS does not.
     # And the last digit group.
 
     variable myrevnr     {} ; # Revision number of the revision.
     variable mydate      {} ; # Timestamp of the revision, seconds since epoch
+    variable myorigdate  {} ; # Original unmodified timestamp.
     variable mystate     {} ; # State of the revision.
     variable myfile      {} ; # Ref to the file object the revision belongs to.
     variable myhascm     0  ; # Bool flag, set when the commit msg was set.
     variable mytext      {} ; # Range of the (delta) text for this revision in the file.
 
     # The meta data block used later to group revisions into changesets.
     # The project name factors into this as well, but is not stored
     # here. The name is acessible via myfile's project.
 
-    variable myauthor    {} ; # Name of the user who committed the revision.
-    variable mycommitmsg {} ; # The message entered as part of the commit.
-    variable mybranchnr  {} ; # The number of the branch the commit was done on.
+    variable myauthor     {} ; # Name of the user who committed the revision.
+    variable mycommitmsg  {} ; # The message entered as part of the commit.
+    variable mybranchname {} ; # The name of the branch the revision was committed on.
+
+    # Basic parent/child linkage (lines of development)
+
+    variable myparent {} ; # Ref to parent revision object. Link required because of
+    #                    ; # 'cvsadmin -o', which can create arbitrary gaps in the
+    #                    ; # numbering sequence. This is in the same line of development
+    #                    ; # Note: For the first revision on a branch the revision
+    #                    ; # it was spawned from is the parent. Only the root revision
+    #                    ; # of myfile's revision tree has nothing set here.
+    #                    ; #
+
+    variable mychild  {} ; # Ref to the primary child revision object, i.e. the next
+    #                    ; # revision in the same line of development.
+
+    # Branch linkage ____________________
+
+    variable mybranches     {} ; # List of the branches (objs) spawned by this revision.
+    variable myparentbranch {} ; # For the first revision on a branch the relevant
+    #                          ; # branch object. This also allows us to determine if
+    #                          ; # myparent is in the same LOD, or the revision the
+    #                          ; # branch spawned from.
+
+    # List of the revision objects of the first commits on any
+    # branches spawned by this revision on which commits occurred.
+    # This dependency is kept explicitly because otherwise a
+    # revision-only topological sort would miss the dependency that
+    # exists via -> mybranches.
+
+    variable mybranchchildren {} ; # List of the revisions (objs) which are the first
+    #                            ; # commits on any of the branches spawned from this
+    #                            ; # revision. The dependency is kept explicitly to
+    #                            ; # ensure that a revision-only topological sort will
+    #                            ; # not miss it, as it otherwise exists only via
+    #                            ; # mybranches.
+
+    # Tag linkage ________________________
+
+    variable mytags {} ; # List of tags (objs) associated with this revision.
 
     # # ## ### ##### ######## #############
     ## Internal methods
 
     # # ## ### ##### ######## #############

Modified tools/cvs2fossil/lib/c2f_fsym.tcl from [d0212d4c6d] to [f9d277d79e].

@@ -15,10 +15,12 @@
 # # ## ### ##### ######## ############# #####################
 ## Requirements
 
 package require Tcl 8.4                             ; # Required runtime.
 package require snit                                ; # OO system.
+package require vc::tools::trouble                  ; # Error reporting.
+package require vc::fossil::import::cvs::file::rev  ; # CVS per file revisions.
 
 # # ## ### ##### ######## ############# #####################
 ##
 
 snit::type ::vc::fossil::import::cvs::file::sym {
@@ -27,24 +29,86 @@
 
     constructor {symtype nr symbol} {
 	set mytype   $symtype
 	set mynr     $nr
 	set mysymbol $symbol
+
+	switch -exact -- $mytype {
+	    branch  { SetupBranch }
+	    tag     { }
+	    default { trouble internal "Bad symbol type '$mytype'" }
+	}
+	return
+    }
+
+    # Symbol acessor methods.
+
+    delegate method name to mysymbol
+
+    # Branch acessor methods.
+
+    method setchildrevnr  {revnr} {
+	if {$mybranchchildrevnr ne ""} { trouble internal "Child already defined" }
+	set mybranchchildrevnr $revnr
 	return
     }
 
-    delegate method name to mysymbol
+    method setposition {n} { set mybranchposition $n }
+
+    method branchnr    {} { return $mynr }
+    method parentrevnr {} { return $mybranchparentrevnr }
+    method childrevnr  {} { return $mybranchchildrevnr }
+
+    method haschild    {} { return [expr {$mybranchchildrevnr ne ""}] }
+    method child       {} { return $mybranchchild }
+
+    method position {} { return $mybranchposition }
+
+    # Tag acessor methods.
+
+    method tagrevnr {} { return $mynr }
 
     # # ## ### ##### ######## #############
     ## State
 
+    ## Basic, all symbols _________________
+
     variable mytype   {} ; # Symbol type, 'tag', or 'branch'.
-    variable mynr     {} ; # Revision number of a 'tag', branch number of a 'branch'.
-    variable mysymbol {} ; # Ref to symbol object at project level.
+    variable mynr     {} ; # Revision number of a 'tag', branch number
+			   # of a 'branch'.
+    variable mysymbol {} ; # Reference to the symbol object of this
+			   # symbol at the project level.
+
+    ## Branch symbols _____________________
+
+    variable mybranchparentrevnr {} ; # The number of the parent
+				      # revision, derived from our
+				      # branch number (mynr).
+    variable mybranchparent      {} ; # Reference to the revision
+				      # (object) which spawns the
+				      # branch.
+    variable mybranchchildrevnr  {} ; # Number of the first revision
+				      # committed on this branch.
+    variable mybranchchild       {} ; # Reference to the revision
+				      # (object) first committed on
+				      # this branch.
+    variable mybranchposition    {} ; # Relative id of the branch in
+				      # the file, to sort into
+				      # creation order.
+
+    ## Tag symbols ________________________
+
+    # ... nothing special ... (only mynr, see basic)
 
     # # ## ### ##### ######## #############
     ## Internal methods
+
+    proc SetupBranch {} {
+	upvar 1 mybranchparentrevnr mybranchparentrevnr mynr mynr
+	set mybranchparentrevnr [rev 2branchparentrevnr  $mynr]
+	return
+    }
 
     # # ## ### ##### ######## #############
     ## Configuration
 
     pragma -hastypeinfo    no  ; # no type introspection
@@ -54,12 +118,16 @@
     # # ## ### ##### ######## #############
 }
 
 namespace eval ::vc::fossil::import::cvs::file {
     namespace export sym
+    namespace eval sym {
+	namespace import ::vc::fossil::import::cvs::file::rev
+	namespace import ::vc::tools::trouble
+    }
 }
 
 # # ## ### ##### ######## ############# #####################
 ## Ready
 
 package provide vc::fossil::import::cvs::file::sym 1.0
 return