Check-in [177a0cc55c]
Not logged in
Overview

SHA1 Hash:177a0cc55c3da003fae4aac6b4800ff73bd08cfa
Date: 2007-10-17 03:15:12
User: aku
Comment:Fix setting of myimported, wrong condition. Fix item assignment when sorting branches. Fix parent/child linkage when setting up branch dependencies. Completed processes on non-trunk default branch revisions. Added skeleton code for the deletion of superfluous revisions.
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 [6a3824b872] to [952128b4cc].

@@ -20,10 +20,11 @@
 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::log                      ; # User feedback
 package require vc::tools::misc                     ; # Text formatting
 
 # # ## ### ##### ######## ############# #####################
 ##
 
@@ -175,11 +176,11 @@
 	# message for the latter, i.e. "Initial revision\n", no
 	# period.  (This fact also helps us when the time comes to
 	# determine whether this file might have had a default branch
 	# in the past.)
 
-	if {$revnr eq ""} {
+	if {$revnr eq "1.1"} {
 	    set myimported [expr {$commitmsg eq "Initial revision\n"}]
 	}
 
 	# Here we also keep track of the order in which the revisions
 	# were added to the file.
@@ -193,12 +194,17 @@
 	# looking for a non-trunk default branch, marking its members
 	# and linking them into the trunk.
 
 	DetermineRevisionOperations
 	DetermineLinesOfDevelopment
-
-	# list of roots ... first only one, later can become more.
+	HandleNonTrunkDefaultBranch
+	RemoveIrrelevantDeletions
+	RemoveInitialBranchDeletions
+
+	if {[$myproject trunkonly]} {
+	    ExcludeNonTrunkInformation
+	}
 	return
     }
 
     # # ## ### ##### ######## #############
     ## State
@@ -246,10 +252,14 @@
 			     # reverse of definition.  I.e. a smaller
 			     # number means 'Defined earlier', means
 			     # 'Created later'.
 
     variable mytrunk {} ; # Direct reference to myproject -> trunk.
+    variable myroots {} ; # List of roots in the forest of
+			  # lod's. Object references to revisions and
+			  # branches. The latter can appear when they
+			  # are severed from their parent.
 
     # # ## ### ##### ######## #############
     ## Internal methods
 
     method RecordBranchCommits {branches} {
@@ -364,10 +374,11 @@
 		# list this child in the parent revision.
 
 		if {[$branch haschild]} {
 		    set childrevnr [$branch childrevnr]
 		    set child $myrev($childrevnr)
+		    $branch setchild $child
 
 		    $child setparentbranch $branch
 		    $child setparent       $rev
 		    $rev addchildonbranch $child
 		}
@@ -421,10 +432,14 @@
 	foreach {revnr rev} [array get myrev] {
 	    if {[$rev hasparent]} continue
 	    if {$myroot ne ""} { trouble internal "Multiple root revisions found" }
 	    set myroot $rev
 	}
+
+	# In the future we also need a list, as branches can become
+	# severed from their parent, making them their own root.
+	set myroots [list $myroot]
 	return
     }
 
     proc DetermineRevisionOperations {} {
 	upvar 1 myrevisions myrevisions
@@ -458,10 +473,259 @@
 	    upvar 1 self self
 	    return [$self Rev2Branch $revnr]
 	}
     }
 
+    proc HandleNonTrunkDefaultBranch {} {
+	upvar 1 myprincipal myprincipal myroot myroot mybranches mybranches myimported myimported myroots myroots myrev myrev
+
+	set revlist [NonTrunkDefaultRevisions]
+	if {![llength $revlist]} return
+
+	AdjustNonTrunkDefaultBranch $revlist
+	CheckLODs
+	return
+    }
+
+    proc NonTrunkDefaultRevisions {} {
+	# From cvs2svn the following explanation (with modifications
+	# for our algorithm):
+
+	# Determine whether there are any non-trunk default branch
+	# revisions.
+
+	# If a non-trunk default branch is determined to have existed,
+	# return a list of objects for all revisions that were once
+	# non-trunk default revisions, in dependency order (i.e. root
+	# first).
+
+	# There are two cases to handle:
+
+	# One case is simple.  The RCS file lists a default branch
+	# explicitly in its header, such as '1.1.1'.  In this case, we
+	# know that every revision on the vendor branch is to be
+	# treated as head of trunk at that point in time.
+
+	# But there's also a degenerate case.  The RCS file does not
+	# currently have a default branch, yet we can deduce that for
+	# some period in the past it probably *did* have one.  For
+	# example, the file has vendor revisions 1.1.1.1 -> 1.1.1.96,
+	# all of which are dated before 1.2, and then it has 1.1.1.97
+	# -> 1.1.1.100 dated after 1.2.  In this case, we should
+	# record 1.1.1.96 as the last vendor revision to have been the
+	# head of the default branch.
+
+	upvar 1 myprincipal myprincipal myroot myroot mybranches mybranches myimported myimported
+
+	if {$myprincipal ne ""} {
+	    # There is still a default branch; that means that all
+	    # revisions on that branch get marked.
+
+	    log write 5 file "Found explicitly marked NTDB"
+
+	    set rnext [$myroot child]
+	    if {$rnext ne ""} {
+		trouble fatal "File with default branch $myprincipal also has revision [$rnext revnr]"
+		return
+	    }
+
+	    set rev [$mybranches($myprincipal) child]
+	    set res {}
+
+	    while {$rev ne ""} {
+		lappend res $rev
+		set rev [$rev child]
+	    }
+
+	    return $res
+
+	} elseif {$myimported} {
+	    # No default branch, but the file appears to have been
+	    # imported.  So our educated guess is that all revisions
+	    # on the '1.1.1' branch with timestamps prior to the
+	    # timestamp of '1.2' were non-trunk default branch
+	    # revisions.
+
+	    # This really only processes standard '1.1.1.*'-style
+	    # vendor revisions.  One could conceivably have a file
+	    # whose default branch is 1.1.3 or whatever, or was that
+	    # at some point in time, with vendor revisions 1.1.3.1,
+	    # 1.1.3.2, etc.  But with the default branch gone now,
+	    # we'd have no basis for assuming that the non-standard
+	    # vendor branch had ever been the default branch anyway.
+
+	    # Note that we rely on comparisons between the timestamps
+	    # of the revisions on the vendor branch and that of
+	    # revision 1.2, even though the timestamps might be
+	    # incorrect due to clock skew.  We could do a slightly
+	    # better job if we used the changeset timestamps, as it is
+	    # possible that the dependencies that went into
+	    # determining those timestamps are more accurate.  But
+	    # that would require an extra pass or two.
+
+	    if {![info exists mybranches(1.1.1)]} { return {} }
+
+	    log write 5 file "Deduced existence of NTDB"
+
+	    set rev  [$mybranches(1.1.1) child]
+	    set res  {}
+	    set stop [$myroot child]
+
+	    if {$stop eq ""} {
+		# Get everything on the branch
+		while {$rev ne ""} {
+		    lappend res $rev
+		    set rev [$rev child]
+		}
+	    } else {
+		# Collect everything on the branch which seems to have
+		# been committed before the first primary child of the
+		# root revision.
+		set stopdate [$stop date]
+		while {$rev ne ""} {
+		    if {[$rev date] >= $stopdate} break
+		    lappend res $rev
+		    set rev [$rev child]
+		}
+	    }
+
+	    return $res
+
+	} else {
+	    return {}
+	}
+    }
+
+    proc AdjustNonTrunkDefaultBranch {revlist} {
+	upvar 1 myroot myroot myimported myimported myroots myroots myrev myrev mybranches mybranches
+	set stop [$myroot child] ;# rev '1.2'
+
+	log write 5 file "Adjusting NTDB containing [nsp [llength $revlist] revision]"
+
+	# From cvs2svn the following explanation (with modifications
+	# for our algorithm):
+
+	# Adjust the non-trunk default branch revisions found in the
+	# 'revlist'.
+
+	# 'myimported' is a boolean flag indicating whether this file
+	# appears to have been imported, which also means that
+	# revision 1.1 has a generated log message that need not be
+	# preserved.  'revlist' is a list of object references for the
+	# revisions that have been determined to be non-trunk default
+	# branch revisions.
+
+	# Note that the first revision on the default branch is
+	# handled strangely by CVS.  If a file is imported (as opposed
+	# to being added), CVS creates a 1.1 revision, then creates a
+	# vendor branch 1.1.1 based on 1.1, then creates a 1.1.1.1
+	# revision that is identical to the 1.1 revision (i.e., its
+	# deltatext is empty).  The log message that the user typed
+	# when importing is stored with the 1.1.1.1 revision.  The 1.1
+	# revision always contains a standard, generated log message,
+	# 'Initial revision\n'.
+
+	# When we detect a straightforward import like this, we want
+	# to handle it by deleting the 1.1 revision (which doesn't
+	# contain any useful information) and making 1.1.1.1 into an
+	# independent root in the file's dependency tree.  In SVN,
+	# 1.1.1.1 will be added directly to the vendor branch with its
+	# initial content.  Then in a special 'post-commit', the
+	# 1.1.1.1 revision is copied back to trunk.
+
+	# If the user imports again to the same vendor branch, then CVS
+	# creates revisions 1.1.1.2, 1.1.1.3, etc. on the vendor branch,
+	# *without* counterparts in trunk (even though these revisions
+	# effectively play the role of trunk revisions).  So after we add
+	# such revisions to the vendor branch, we also copy them back to
+	# trunk in post-commits.
+
+	# We mark the revisions found in 'revlist' as default branch
+	# revisions.  Also, if the root revision has a primary child
+	# we set that revision to depend on the last non-trunk default
+	# branch revision and possibly adjust its type accordingly.
+
+	set first [lindex $revlist 0]
+
+	log write 6 file "<[$first revnr]> [expr {$myimported ? "imported" : "not imported"}], [$first operation], [expr {[$first hastext] ? "has text" : "no text"}]"
+
+	if {$myimported &&
+	    [$first revnr] eq "1.1.1.1" &&
+	    [$first operation] eq "change" &&
+	    ![$first hastext]} {
+
+	    set rev11 [$first parent] ; # Assert: Should be myroot.
+	    log write 3 file "Removing irrelevant revision [$rev11 revnr]"
+
+	    # Cut out the old myroot revision.
+
+	    ldelete myroots $rev11 ; # Not a root any longer.
+	    unset myrev([$rev11 revnr])
+
+	    $first cutfromparent ; # Sever revision from parent revision.
+	    if {$stop ne ""} {
+		$stop cutfromparent
+		lappend myroots $stop ; # New root, after vendor branch
+	    }
+
+	    # Cut out the vendor branch symbol
+
+	    set vendor [$first parentbranch]
+	    if {$vendor eq ""} { trouble internal "First NTDB revision has no branch" }
+	    if {[$vendor parent] eq $rev11} {
+		unset mybranches([$vendor branchnr])
+		$rev11 removebranch        $vendor
+		$rev11 removechildonbranch $first
+		$first cutfromparentbranch
+		lappend myroots $first
+	    }
+
+	    # Change the type of first (typically from Change to Add):
+	    $first retype add
+
+	    # Move any tags and branches from the old to the new root.
+	    $rev11 movesymbolsto $first
+	}
+
+	# Mark all the special revisions as such
+	foreach rev $revlist {
+	    log write 3 file "Revision on default branch: [$rev revnr]"
+	    $rev isondefaultbranch
+	}
+
+	if {$stop ne ""} {
+	    # Revision 1.2 logically follows the imported revisions,
+	    # not 1.1.  Accordingly, connect it to the last NTDBR and
+	    # possibly change its type.
+
+	    set last [lindex $revlist end]
+	    $stop setdefaultbranchparent $last ; # Retypes the revision too.
+	    $last setdefaultbranchchild  $stop
+	}
+	return
+    }
+
+    proc CheckLODs {} {
+	upvar 1 mybranches mybranches mytags mytags
+
+	foreach {_ branch} [array get mybranches] { $branch checklod }
+
+	foreach {_ taglist} [array get mytags] {
+	    foreach tag $taglist { $tag checklod }
+	}
+	return
+    }
+
+    proc RemoveIrrelevantDeletions {} {
+    }
+
+    proc RemoveInitialBranchDeletions {} {
+    }
+
+    proc ExcludeNonTrunkInformation {} {
+    }
+
     # # ## ### ##### ######## #############
     ## Configuration
 
     pragma -hastypeinfo    no  ; # no type introspection
     pragma -hasinfo        no  ; # no object introspection
@@ -477,13 +741,14 @@
 	# 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::tools::misc::*
 	namespace import ::vc::tools::trouble
+	namespace import ::vc::tools::log
     }
 }
 
 # # ## ### ##### ######## ############# #####################
 ## Ready
 
 package provide vc::fossil::import::cvs::file 1.0
 return

Modified tools/cvs2fossil/lib/c2f_frev.tcl from [00508f634d] to [89b7595516].

@@ -15,10 +15,11 @@
 # # ## ### ##### ######## ############# #####################
 ## Requirements
 
 package require Tcl 8.4                             ; # Required runtime.
 package require snit                                ; # OO system.
+package require vc::tools::misc                     ; # Text formatting
 
 # # ## ### ##### ######## ############# #####################
 ##
 
 snit::type ::vc::fossil::import::cvs::file::rev {
@@ -34,18 +35,24 @@
 	return
     }
 
     # Basic pieces ________________________
 
-    method hasmeta {}     { return [expr {$mymetaid ne ""}] }
+    method hasmeta {} { return [expr {$mymetaid ne ""}] }
+    method hastext {} {
+	struct::list assign $mytext s e
+	return [expr {$s <= $e}]
+    }
+
     method setmeta {meta} { set mymetaid $meta ; return }
     method settext {text} { set mytext   $text ; return }
     method setlod  {lod}  { set mylod    $lod  ; return }
 
     method revnr {} { return $myrevnr }
     method state {} { return $mystate }
     method lod   {} { return $mylod   }
+    method date  {} { return $mydate  }
 
     # Basic parent/child linkage __________
 
     method hasparent {} { return [expr {$myparent ne ""}] }
     method haschild  {} { return [expr {$mychild  ne ""}] }
@@ -53,10 +60,13 @@
     method setparent {parent} {
 	if {$myparent ne ""} { trouble internal "Parent already defined" }
 	set myparent $parent
 	return
     }
+
+    method cutfromparent {} { set myparent "" ; return }
+    method cutfromchild  {} { set mychild  "" ; return }
 
     method setchild {child} {
 	if {$mychild ne ""} { trouble internal "Child already defined" }
 	set mychild $child
 	return
@@ -71,25 +81,31 @@
 	if {$myparentbranch ne ""} { trouble internal "Branch parent already defined" }
 	set myparentbranch $branch
 	return
     }
 
+    method parentbranch {} { return $myparentbranch }
+
     method addbranch {branch} {
 	lappend mybranches $branch
-	#sorted in ascending order by branch number?
 	return
     }
 
     method addchildonbranch {child} {
 	lappend mybranchchildren $child
 	return
     }
 
-    # Tag linkage _________________________
-
-    method addtag {tag} {
-	lappend mytags $tag
+    method cutfromparentbranch {} { set myparentbranch "" ; return }
+
+    method removebranch {branch} {
+	ldelete mybranches $branch
+	return
+    }
+
+    method removechildonbranch {rev} {
+	ldelete mybranchchildren $rev
 	return
     }
 
     method sortbranches {} {
 	if {![llength $mybranches]} return
@@ -109,15 +125,63 @@
 	    lappend tmp [list $branch [$branch position]]
 	}
 
 	set mybranches {}
 	foreach item [lsort -index 1 -decreasing $tmp] {
-	    struct::list assign $item -> branch position
+	    struct::list assign $item branch position
 	    lappend mybranches $branch
 	}
 	return
     }
+
+    method movebranchesto {rev} {
+	set revlod [$rev lod]
+	foreach branch $mybranches {
+	    $rev addbranch $branch
+	    $branch setparent $rev
+	    $branch setlod $revlod
+	}
+	foreach branchrev $mybranchchildren {
+	    $rev addchildonbranch $branchrev
+	    $branchrev cutfromparent
+	    $branchrev setparent $rev
+	}
+	set mybranches       {}
+	set mybranchchildren {}
+	return
+    }
+
+    # Tag linkage _________________________
+
+    method addtag {tag} {
+	lappend mytags $tag
+	return
+    }
+
+    method movetagsto {rev} {
+	set revlod [$rev lod]
+	foreach tag $mytags {
+	    $rev addtag $tag
+	    $tag settagrev $rev
+	    $tag setlod $revlod
+	}
+	set mytags {}
+	return
+    }
+
+    # general symbol operations ___________
+
+    method movesymbolsto {rev} {
+	# Move the tags and branches attached to this revision to the
+	# destination and fix all pointers.
+
+	$self movetagsto     $rev
+	$self movebranchesto $rev
+	return
+    }
+
+    # Derived stuff _______________________
 
     method determineoperation {} {
 	# Look at the state of both this revision and its parent to
 	# determine the type opf operation which was performed (add,
 	# modify, delete, none).
@@ -126,10 +190,27 @@
 	# giving rise to four possible types.
 
 	set sdead [expr {$mystate eq "dead"}]
 	set pdead [expr {$myparent eq "" || [$myparent state] eq "dead"}]
 
+	set myoperation $myopstate([list $pdead $sdead])
+	return
+    }
+
+    method operation {} { return $myoperation }
+    method retype {x} { set myoperation $x ; return }
+
+    method isondefaultbranch {} { set myisondefaultbranch 1 ; return }
+
+    method setdefaultbranchchild  {rev} { set mydbchild $rev ; return }
+    method setdefaultbranchparent {rev} {
+	set mydbparent $rev
+
+	# Retype the revision (may change from 'add' to 'change').
+
+	set sdead [expr {$myoperation     ne "change"}]
+	set pdead [expr {[$rev operation] ne "change"}]
 	set myoperation $myopstate([list $pdead $sdead])
 	return
     }
 
     # # ## ### ##### ######## #############
@@ -234,13 +315,25 @@
 
     variable mytags {} ; # List of tags (objs) associated with this revision.
 
     # More derived data
 
-    variable myoperation {} ; # One of 'add', 'change', 'delete', or
-			      # 'nothing'. Derived from our and its
-			      # parent's state.
+    variable myoperation        {} ; # One of 'add', 'change', 'delete', or
+			             # 'nothing'. Derived from our and
+			             # its parent's state.
+    variable myisondefaultbranch 0 ; # Boolean flag, set if the
+				     # revision is on the non-trunk
+				     # default branch, aka vendor
+				     # branch.
+    variable mydbparent         {} ; # Reference to the last revision
+				     # on the vendor branch if this is
+				     # the primary child of the
+				     # regular root.
+    variable mydbchild          {} ; # Reference to the primary child
+				     # of the regular root if this is
+				     # the last revision on the vendor
+				     # branch.
 
     # dead(self) x dead(parent) -> operation
     typevariable myopstate -array {
 	{0 0} change
 	{0 1} delete
@@ -261,12 +354,15 @@
     # # ## ### ##### ######## #############
 }
 
 namespace eval ::vc::fossil::import::cvs::file {
     namespace export rev
+    namespace eval rev {
+	namespace import ::vc::tools::misc::*
+    }
 }
 
 # # ## ### ##### ######## ############# #####################
 ## Ready
 
 package provide vc::fossil::import::cvs::file::rev 1.0
 return

Modified tools/cvs2fossil/lib/c2f_fsym.tcl from [85589454df] to [211201a643].

@@ -53,17 +53,20 @@
 	return
     }
 
     method setposition {n}   { set mybranchposition $n ; return }
     method setparent   {rev} { set mybranchparent $rev ; return }
+    method setchild    {rev} { set mybranchchild  $rev ; return }
 
     method branchnr    {} { return $mynr }
     method parentrevnr {} { return $mybranchparentrevnr }
     method childrevnr  {} { return $mybranchchildrevnr }
     method haschild    {} { return [expr {$mybranchchildrevnr ne ""}] }
+    method parent      {} { return $mybranchparent }
     method child       {} { return $mybranchchild }
     method position    {} { return $mybranchposition }
+
 
     # Tag acessor methods.
 
     method tagrevnr  {}    { return $mynr }
     method settagrev {rev} {set mytagrev $rev ; return }
@@ -72,22 +75,26 @@
 
     method lod {} { return $mylod }
 
     method setlod {lod} {
 	set mylod $lod
-
-	# Consistency check integrated. The symbol's
-	# line-of-development has to be same as the
-	# line-of-development of its source.
+	$self checklod
+	return
+    }
+
+    method checklod {} {
+	# Consistency check. The symbol's line-of-development has to
+	# be same as the line-of-development of its source (parent
+	# revision of a branch, revision of a tag itself).
 
 	switch -exact -- $mytype {
 	    branch  { set slod [$mybranchparent lod] }
 	    tag     { set slod [$mytagrev       lod] }
 	}
 
 	if {$mylod ne $slod} {
-	    trouble fatal "For [$mysymbol name]: LOD conflict with source, '[$mylod name]' vs. '[$slod name]'"
+	    trouble fatal "For $mytype [$mysymbol name]: LOD conflict with source, '[$mylod name]' vs. '[$slod name]'"
 	    return
 	}
 	return
     }
 
@@ -103,11 +110,12 @@
 			   # symbol at the project level.
     variable mylod    {} ; # Reference to the line-of-development
 			   # object the symbol belongs to. An
 			   # alternative idiom would be to call it the
 			   # branch the symbol is on. This reference
-			   # is to a project-level symbol object.
+			   # is to a project-level object (symbol or
+			   # trunk).
 
     ## Branch symbols _____________________
 
     variable mybranchparentrevnr {} ; # The number of the parent
 				      # revision, derived from our