Overview
SHA1 Hash: | 72dac950c36d76f5e6b9b5d806a2c2eda1507444 |
---|---|
Date: | 2007-09-26 05:06:18 |
User: | aku |
Comment: | Continued work on the import of branches. Main principle now is to handle the branches vertically. First the trunk, then the branch starting with the first unprocessed changeset, and so forth. Looks more promising than the previous approach. Currently handles just a bit over half of the test projects (11 of 21 in 6 repositories). |
Timelines: | ancestors | descendants | both | trunk |
Other Links: | files | ZIP archive | manifest |
Tags And Properties
- branch=trunk inherited from [a28c83647d]
- sym-trunk inherited from [a28c83647d]
Changes
[hide diffs]Modified tools/lib/cvs.tcl from [e947a38eb8] to [ad0046436f].
@@ -11,10 +11,12 @@ package require vc::tools::trouble ; # Error handling package require vc::cvs::cmd ; # Access to cvs application. package require vc::cvs::ws::files ; # Scan CVS repository for relevant files. package require vc::cvs::ws::timeline ; # Manage timeline of all changes. package require vc::cvs::ws::csets ; # Manage the changesets found in the timeline +package require vc::cvs::ws::branch ; # Branch database +package require vc::cvs::ws::sig ; # Changeset file/rev signatures namespace eval ::vc::cvs::ws { vc::tools::log::system cvs namespace import ::vc::tools::log::write namespace import ::vc::rcs::parser::process @@ -213,11 +215,14 @@ set operation [Operation $rev $stat($rev)] NoteDeadRoots $f $rev $operation timeline::add $date($rev) $f $rev $operation $auth($rev) $cmsg($rev) incr n } - #B Extend branch management + + if {[info exists md(symbol)]} { + branch::def $f date $md(symbol) + } unset md unset date unset auth unset cmsg @@ -240,13 +245,14 @@ } return } proc ::vc::cvs::ws::Operation {rev state} { - if {$state eq "dead"} {return "R"} ; # Removed - if {$rev eq "1.1"} {return "A"} ; # Added - return "M" ; # Modified + if {$state eq "dead"} {return "R"} ; # Removed + if {$rev eq "1.1"} {return "A"} ; # Added + if {[string match *.1.1 $rev]} {return "A"} ; # Added on a branch + return "M" ; # Modified } proc ::vc::cvs::ws::MakeChangesets {} { write 0 cvs "Generating changesets from timeline" @@ -324,24 +330,16 @@ write 0 cvs "Found [NSIPL $t {trunk changeset}], [NSIPL [llength $remainder] {branch changeset}]" return $remainder } proc ::vc::cvs::ws::ProcessBranch {cslist} { - write 0 cvs "Processing the remaining changesets" + write 0 cvs "Processing the remaining [SIPL [llength $cslist] changeset "[llength $cslist] changesets"]" set base [lindex $cslist 0] set cslist [lrange $cslist 1 end] - set remainder {} - set t 0 - - ### ### ### ######### ######### ######### - ## Dump data of the unprocessing changeset - - puts /${base}/_________________ - array set cs [csets::get $base] - parray cs + csets::DUMP $base # Which branch does base belong to? # - It has to be the base of an unprocessed branch! # Otherwise it would have been on either the trunk # or an already processed branch. @@ -352,37 +350,42 @@ # versions we know the root versions of these files, and we # can determine the changesets they are in => Intersection # plus cap from previous contraint gives us the possible # candidates. - # ### ### ### ######### ######### ######### - exit - - set tag [FindBranch $base ..] - set root [FindRoot $tag ...] - + write 4 cvs "Branch base $base" + + ::foreach {tag rootsig} [branch::find [csets::get $base]] break + + write 4 cvs "Branch tag $tag" + write 4 cvs "Root sig $rootsig" + + set root [sig::find $base $rootsig] + + write 4 cvs "Branch root $root" + + write 0 cvs "Changeset $base, starting branch \"$tag\", rooted at $root" csets::setParentOf $base $root - foreach c $cslist { - if {[csets::sameBranch $c $base]} { + set remainder {} + set t 1 + + ::foreach c $cslist { + #csets::DUMP $c + if {[csets::sameBranch $c $base $tag]} { csets::setParentOf $c $base set base $c incr t lappend importable $c } else { lappend remainder $c } } - #write 0 cvs "Found [NSIPL $t {trunk changeset}], [NSIPL [llength $remainder] {branch changeset}]" + write 0 cvs "Found [NSIPL $t "$tag changeset"], [NSIPL [llength $remainder] changeset] outside" return $remainder } - -#TBD -#... FindBranch -#... FindRoot -#... SameBranch proc ::vc::cvs::ws::Checkout {f r} { variable base variable project
Added tools/lib/cvs_branch.tcl version [d6f60bec8c]
@@ -1,1 +1,313 @@ + + +namespace eval ::vc::cvs::ws::branch {} + +# Trivial storage of all branch data as a rectangular table. We can +# think up a better suited storage system later, when we know what +# type of queries are made to this module. + +proc ::vc::cvs::ws::branch::def {f dv deflist} { + upvar 1 $dv date + variable bra + foreach {tag rev} $deflist { + # ignore non-branch tags + if {[llength [split $rev .]] < 4} continue + + if 0 { + if { ($rev ne "1.1.1.1") && ![string match *.0.2 $rev] } { + # 1.1.1.1 is the base of vendor branches, usually. *.0.y + # is the base of regular branches where nothing is on the + # branch yet, only its root is marked. Everything else is + # noteworthy for now. + puts $f/$rev/$tag + } + } + + set root [revroot $rev] + lappend bra [list $date($root) $tag $f $rev] + } +} + +proc ::vc::cvs::ws::branch::revroot {rev} { + return [join [lrange [split $rev .] 0 end-2] .] +} + + + # ! Files in a branch can appear only after their root revision + # exists. This can be checked against the time of the cset which + # is our base. Branches which have no files yet can be eliminated + # from consideration. + + # ! All files noted by the base cset as added/modified have to be + # in the branch root. Branches which do not have such a file can + # be eliminated from consideration. + + # ! The versions of the added/modified files in the base have + # match the versions in the branch root. In the sense that they + # have to be equal or sucessors. The later implies identity in the + # upper parts (only the last 2 parts are relevant), and equal + # length. + + # This gives us the branch, and, due to the time information a + # signature for the root. + + #? Can search for the root based on this signature fail ? + # Yes. Because the signature may contain files which were not + # actually yet in the root, despite being able to. And which were + # not modified by the base, so the check 2 above still passes. + + # -> Search for the full signature first, then drop the youngest + # files, search again until match. Check the result against the + # base, that all needed files are present. + + # However - Can search for the root based on the cset data (needed + # files). Gives us another set of candidate roots. Intersect! + + +proc ::vc::cvs::ws::branch::find {csvalue} { + array set cs $csvalue + + #variable bra + #puts ___________________________________________ + #puts [join [lsort -index 0 [lsort -index 1 $bra]] \n] + + Signatures bd [TimeRelevant $cs(date)] + DropIncomplete bd [concat $cs(added) $cs(changed)] + + #puts ___________________________________________ + #parray bd + + if {[array size bd] < 1} { + puts "NO BRANCH" + # Deal how? + # - Abort + # - Ignore this changeset and try the next one + # (Which has higher probability of not matching as it might + # be the successor in the branch to this cset and not a base). + puts "" + parray cs + exit + } elseif {[array size bd] > 1} { + + # While we might have found several tag they may all refer to + # the same set of files. If that is so we consider them + # identical and take one as representative of all. + + set su {} + foreach {t s} [array get bd] { + lappend su [DictSort $s] + } + if {[llength [lsort -unique $su]] > 1} { + puts "AMBIGOUS. The following branches match:" + # Deal how? S.a. + puts \t[join [array names bd] \n\t] + puts "" + parray cs + exit + } + # Fall through ... + } + + set tg [lindex [array names bd] 0] + set rs [RootOf $bd($tg)] + + #puts "BRANCH = $tg" + #puts "ROOTSG = $rs" + + return [list $tg $rs] +} + + +proc ::vc::cvs::ws::branch::has {ts needed} { + #variable bra + #puts ___________________________________________ + #puts [join [lsort -index 0 [lsort -index 1 $bra]] \n] + + Signatures bd [TimeRelevant $ts] + DropIncomplete bd $needed + + #puts ___________________________________________ + #parray bd + + if {[array size bd] < 1} { + puts "NO BRANCH" + # Deal how? + # - Abort + # - Ignore this changeset and try the next one + # (Which has higher probability of not matching as it might + # be the successor in the branch to this cset and not a base). + exit + } elseif {[array size bd] > 1} { + puts "AMBIGOUS. Following branches match:" + # Deal how? S.a. + puts \t[join [array names bd] \n\t] + exit + } + + set tg [lindex [array names bd] 0] + + #puts "BRANCH = $tg" + + return $tg +} + + + +proc ::vc::cvs::ws::branch::RootOf {dict} { + set res {} + foreach {f r} $dict { + lappend res $f [revroot $r] + } + return $res +} + +proc ::vc::cvs::ws::branch::DictSort {dict} { + array set a $dict + set r {} + foreach k [lsort [array names a]] { + lappend r $k $a($k) + } + return $r +} + +proc ::vc::cvs::ws::branch::DropIncomplete {bv needed} { + upvar 1 $bv bdata + + # Check the needed files against the branch signature. If files + # are missing or not of a matching version drop the branch from + # further consideration. + + foreach {tag sig} [array get bdata] { + array set rev $sig + foreach {file rv} $needed { + if {![info exists rev($file)] || ![successor $rv $rev($file)]} { + # file in cset is not in the branch or is present, but + # not proper version (different lengths, not matching + # in upper 0..end-2 parts, not equal|successor). + unset bdata($tag) + break + } + continue + } + unset rev + } + return +} + +proc ::vc::cvs::ws::branch::successor {ra rb} { + # a successor-of b ? + + set la [split $ra .] + set lb [split $rb .] + if { + ([llength $la] != [llength $lb]) || + ([lrange $la 0 end-2] ne [lrange $lb 0 end-2]) || + ([package vcompare $ra $rb] < 0) + } { + return 0 + } else { + return 1 + } +} + +proc ::vc::cvs::ws::branch::Signatures {bv deflist} { + upvar 1 $bv bdata + # Sort branch data by symbolic name for the upcoming checks, and + # generate file revision signatures. + + array set bdata {} + foreach item $deflist { + # item = timestamp tag file revision + foreach {__ tag file rev} $item break + lappend bdata($tag) $file $rev + } + + #puts ___________________________________________ + #parray bdata + + return +} + +proc ::vc::cvs::ws::branch::TimeRelevant {date} { + variable bra + + # Retrieve the branch data which definitely comes before (in time) + # the candidate cset. Only this set is relevant to further checks + # and filters. + + set res {} + foreach item $bra { + # item = timestamp tag file revision + # 0 1 2 3 + if {[package vcompare [lindex $item 0] $date] > 0} continue + lappend res $item + } + + #puts ___________________________________________ + #puts [join [lsort -index 0 [lsort -index 1 $res]] \n] + return $res +} + + +namespace eval ::vc::cvs::ws::branch { + variable bra {} + + namespace export def find successor revroot has +} + +package provide vc::cvs::ws::branch 1.0 +return + + + + + # Queries ... + # - Get set of files and revs for branch B which can be in it by the time T + # - Check if a file referenced a/m instruction is in a set of files + # and revision, identical or proper sucessor. + # => Combination + # Can branch B match the cset file a/m at time T ? + # => Full combination + # Give me the list of branches which can match the cset file a/m + # at time T. + + # Branch DB organization => (Tag -> (Time -> (File -> Rev))) + # The full combination actually does not need a complex structure. + # We can simply scan a plain list of branch data. + # The only alternative is an inverted index. + # Time -> ((File -> Rev) -> Tag). Difficult to process. + # Linear scan: + # - Time after T => drop + # - File !in a/m => drop + # - Version !match => drop + # -- Collect tag + # Then lsort -unique for our result. + # NO - The file check is inverted - All files have to be in a/m for the base, not a/m in files + # == - This also breaks the issue for same-branch detection - + # future csets in the branch do not have that property. + + puts ___________________________________________ + # Show only branch data which definitely comes before the + # candidate cset + + array set n [concat $cs(added) $cs(changed)] + set xx {} + set bb {} + ::foreach x $bra { + ::foreach {ts tag f r} $x break + if {[package vcompare $ts $cs(date)] > 0} continue + if {![info exists n($f)]} continue + if { + ([llength [split $n($f) .]] != [llength [split $r .]]) || + ([lrange [split $n($f) .] 0 end-2] ne [lrange [split $r .] 0 end-2]) || + ([package vcompare $n($f) $r] < 0) + } continue + lappend xx $x + lappend bb $tag + } + puts [join [lsort -index 0 [lsort -index 1 $xx]] \n] + puts [join [lsort -unique $bb] \n] + +exit +
Modified tools/lib/cvs_csets.tcl from [c6beb0fbbb] to [4ade9049c6].
@@ -3,12 +3,16 @@ # ----------------------------------------------------------------------------- # Requirements package require Tcl 8.4 +package require vc::cvs::ws::sig ; # Changeset file/rev signatures namespace eval ::vc::cvs::ws::csets::Current {} +namespace eval ::vc::cvs::ws::csets::sig { + namespace import ::vc::cvs::ws::sig::* +} # ----------------------------------------------------------------------------- # API # vc::cvs::ws::csets::init - Initialize accumulator @@ -45,10 +49,18 @@ proc ::vc::cvs::ws::csets::get {id} { variable csets return $csets($id) } + +proc ::vc::cvs::ws::csets::DUMP {id} { + puts /${id}/_________________ + array set cs [get $id] + parray cs + return +} + proc ::vc::cvs::ws::csets::num {} { variable csets return [array size csets] } @@ -59,17 +71,26 @@ } proc ::vc::cvs::ws::csets::setParentOf {id parent} { variable csets lappend csets($id) parent $parent + + array set cs $csets($id) + sig::def $id $parent $cs(added) $cs(changed) $cs(removed) return } proc ::vc::cvs::ws::csets::parentOf {id} { variable csets array set cs $csets($id) return $cs(parent) +} + +proc ::vc::cvs::ws::csets::sameBranch {id parent tag} { + variable csets + array set cs $csets($id) + return [sig::next $parent $cs(added) $cs(changed) $cs(removed) $tag $cs(date)] } # ----------------------------------------------------------------------------- # Internal helper commands: Changeset inspection and construction. @@ -215,13 +236,13 @@ variable changed {} ; # file -> revision of modified files. variable files array set files {} ; # file -> revision } - namespace export init add done get num isTrunk setParentOf parentOf + namespace export init add done get num isTrunk setParentOf parentOf sameBranch } # ----------------------------------------------------------------------------- # Ready package provide vc::cvs::ws::csets 1.0 return
Added tools/lib/cvs_sig.tcl version [41da9ebbf9]
@@ -1,1 +1,144 @@ +package require struct::set +package require vc::cvs::ws::branch + +namespace eval ::vc::cvs::ws::sig::branch { + namespace import ::vc::cvs::ws::branch::* +} + +# Save the mapping from changesets to file/rev signatures, and further +# remember all the csets a specific file/rev combination belongs to. + +proc ::vc::cvs::ws::sig::def {id parent added changed removed} { + variable sig + variable csl + + array set new $sig($parent) + array set new $added + array set new $changed + foreach {f r} $removed {catch {unset new($f)}} + set sig($id) [DictSort [array get new]] + + foreach {f r} [array get new] { + lappend csl($f,$r) $id + } + return +} + +proc ::vc::cvs::ws::sig::next {id added changed removed tag ts} { + variable sig + array set rev $sig($id) + + foreach {f r} [concat $changed $removed] { + if {![info exists rev($f)] || ![branch::successor $r $rev($f)]} { + return 0 + } + } + + if {[llength $added]} { + # Check that added files belong to the branch too! + if {$tag ne [branch::has $ts $added]} { + return 0 + } + } + return 1 +} + + +proc ::vc::cvs::ws::sig::find {id sig} { + set cslist [Cut $id [Find $sig]] + + if {[llength $cslist] < 1} { + puts "NO ROOT" + # Deal how? + # - Abort + # - Ignore this changeset and try the next one + # (Which has higher probability of not matching as it might + # be the successor in the branch to this cset and not a base). + exit + } elseif {[llength $cslist] > 1} { + puts "AMBIGOUS. Following csets match root requirements:" + # Deal how? S.a. + puts \t[join $cslist \n\t] + exit + } + + set r [lindex $cslist 0] + #puts "ROOT = $r" + return $r +} + +proc ::vc::cvs::ws::sig::Cut {id cslist} { + # Changesets have to be before id! This makes for another + # intersection, programmatic. + + set res {} + foreach c $cslist { + if {$c >= $id} continue + lappend res $c + } + return $res +} + +proc ::vc::cvs::ws::sig::Find {sig} { + # Locate all changesets which contain the given signature. + variable csl + + set res {} + set first 1 + foreach {f r} $sig { + #puts $f/$r? + # Unknown file not used anywhere + if {![info exists csl($f,$r)]} {return {}} + puts $f/$r\t=\t($csl($f,$r))*($res)/$first + + if {$first} { + set res $csl($f,$r) + set first 0 + #puts F($res) + } else { + set new [struct::set intersect $res $csl($f,$r)] + set rv $r + while {![llength $new]} { + # Assume that the problem file was added and as such + # does not exist yet at the root revision. However its + # root should exist, and some point. + + set rv [branch::revroot $rv] + if {$rv eq ""} { + puts BREAK/\t($f\ $r) + exit + } + if {![info exists csl($f,$rv)]} {return {}} + #puts $f/$r\t=\t($csl($f,$rv)) + set new [struct::set intersect $res $csl($f,$rv)] + } + set res $new + #puts R($res) + #if {![llength $res]} {return {}} + } + } + return $res +} + +proc ::vc::cvs::ws::sig::DictSort {dict} { + array set a $dict + set r {} + foreach k [lsort [array names a]] { + lappend r $k $a($k) + } + return $r +} + + +namespace eval ::vc::cvs::ws::sig { + variable sig ; # cset id -> signature + array set sig {{} {}} + variable csl ; # file x rev -> list (cset id) + array set csl {} + + namespace export def find next +} + +package provide vc::cvs::ws::sig 1.0 +return
Modified tools/lib/pkgIndex.tcl from [48d829569b] to [fde05dafaa].
@@ -3,12 +3,14 @@ package ifneeded vc::cvs::cmd 1.0 [list source [file join $dir cvs_cmd.tcl]] package ifneeded vc::cvs::ws 1.0 [list source [file join $dir cvs.tcl]] package ifneeded vc::cvs::ws::files 1.0 [list source [file join $dir cvs_files.tcl]] package ifneeded vc::cvs::ws::timeline 1.0 [list source [file join $dir cvs_timeline.tcl]] package ifneeded vc::cvs::ws::csets 1.0 [list source [file join $dir cvs_csets.tcl]] +package ifneeded vc::cvs::ws::branch 1.0 [list source [file join $dir cvs_branch.tcl]] +package ifneeded vc::cvs::ws::sig 1.0 [list source [file join $dir cvs_sig.tcl]] package ifneeded vc::fossil::cmd 1.0 [list source [file join $dir fossil_cmd.tcl]] package ifneeded vc::fossil::ws 1.0 [list source [file join $dir fossil.tcl]] package ifneeded vc::fossil::import::cvs 1.0 [list source [file join $dir importcvs.tcl]] package ifneeded vc::fossil::import::stats 1.0 [list source [file join $dir import_statistics.tcl]] package ifneeded vc::fossil::import::map 1.0 [list source [file join $dir import_map.tcl]] package ifneeded vc::tools::log 1.0 [list source [file join $dir log.tcl]] package ifneeded vc::tools::trouble 1.0 [list source [file join $dir trouble.tcl]]