Overview
SHA1 Hash: | adf168e23e3d3812bb7c49d385a1bfd797e23a36 |
---|---|
Date: | 2007-10-24 08:01:01 |
User: | aku |
Comment: | Extended handling of id's for files so that we have them for backreferences from symbols and revisions. Completed persistence of revisions and symbols at file-level and fixed small problem with left-over links to branches. |
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/cvs2fossil/lib/c2f_file.tcl from [f06eb21d1d] to [bd5c5d46d2].
@@ -19,10 +19,11 @@ 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::fossil::import::cvs::state ; # State storage. package require vc::tools::trouble ; # Error reporting. package require vc::tools::log ; # User feedback package require vc::tools::misc ; # Text formatting # # ## ### ##### ######## ############# ##################### @@ -30,19 +31,27 @@ snit::type ::vc::fossil::import::cvs::file { # # ## ### ##### ######## ############# ## Public API - constructor {path usrpath executable project} { + constructor {id path usrpath executable project} { + set myid $id set mypath $path set myusrpath $usrpath set myexecutable $executable set myproject $project set mytrunk [$myproject trunk] return } + method setid {id} { + if {$myid ne ""} { trouble internal "File '$mypath' already has an id, '$myid'" } + set myid $id + return + } + + method id {} { return $myid } method path {} { return $mypath } method usrpath {} { return $myusrpath } method project {} { return $myproject } delegate method commitmessageof to myproject @@ -64,10 +73,30 @@ # # ## ### ##### ######## ############# ## Persistence (pass II) method persist {} { + # First collect the reachable revisions and symbols, then + # assign id's to all. They are sorted so that we will have ids + # which sort in order of creation. Then we can save them. This + # is done bottom up. Revisions, then symbols. __NOTE__ This + # works only because sqlite is not checking foreign key + # references during insert. This allows to have dangling + # references which are fixed later. The longest dangling + # references are for the project level symbols, these we do + # not save here, but at the end of the pass. What we need are + # the ids, hence the two phases. + + struct::list assign [$self Active] revisions symbols + foreach rev $revisions { $rev defid } + foreach sym $symbols { $sym defid } + + state transaction { + foreach rev $revisions { $rev persist } + foreach sym $symbols { $sym persist } + } + return } method drop {} { foreach {_ rev} [array get myrev] { $rev destroy } foreach {_ branch} [array get mybranches] { $branch destroy } @@ -220,10 +249,11 @@ } # # ## ### ##### ######## ############# ## State + variable myid {} ; # File id in the persistent state. variable mypath {} ; # Path of the file's rcs archive. variable myusrpath {} ; # Path of the file as seen by users. variable myexecutable 0 ; # Boolean flag 'file executable'. variable myproject {} ; # Reference to the project object # the file belongs to. @@ -308,18 +338,18 @@ if {[info exists mybranches($branchnr)]} { 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]] + set branch [sym %AUTO% branch $branchnr [$myproject getsymbol $name] $self] $branch setposition [incr mybranchcnt] set mybranches($branchnr) $branch return $branch } method AddTag {name revnr} { - set tag [sym %AUTO% tag $revnr [$myproject getsymbol $name]] + set tag [sym %AUTO% tag $revnr [$myproject getsymbol $name] $self] lappend mytags($revnr) $tag return $tag } method RecordBasicDependencies {revnr next} { @@ -378,11 +408,11 @@ # 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]} { + if {[$branch haschildrev]} { set childrevnr [$branch childrevnr] set child $myrev($childrevnr) $branch setchild $child $child setparentbranch $branch @@ -670,10 +700,11 @@ set vendor [$first parentbranch] if {$vendor eq ""} { trouble internal "First NTDB revision has no branch" } if {[$vendor parent] eq $rev11} { $rev11 removebranch $vendor $rev11 removechildonbranch $first + $vendor cutchild $first cutfromparentbranch lappend myroots $first } # Change the type of first (typically from Change to Add): @@ -726,11 +757,11 @@ set child [$root child] $child cutfromparent lappend myroots $child } - # Remove the branches spawned by the revision to be + # Cut out the branches spawned by the revision to be # deleted. If the branch has revisions they should already # use operation 'add', no need to change that. The first # revision on each branch becomes a new and disconnected # root. @@ -737,10 +768,11 @@ foreach branch [$root branches] { if {![$branch haschild]} continue set first [$branch child] $first cutfromparentbranch $first cutfromparent + $branch cutchild lappend myroots $first } $root removeallbranches # Tagging a dead revision doesn't do anything, so remove @@ -779,11 +811,13 @@ set child [$root child] ldelete myroots $root lappend myroots $child + $branch cutchild $child cutfromparent + $parent removebranch $branch $parent removechildonbranch $root } return } @@ -971,10 +1005,29 @@ } return } + method Active {} { + set revisions {} + set symbols {} + + foreach root [$self LinesOfDevelopment] { + if {[$root hasparentbranch]} { lappend symbols [$root parentbranch] } + while {$root ne ""} { + lappend revisions $root + foreach tag [$root tags] { lappend symbols $tag } + foreach branch [$root branches] { lappend symbols $branch } + set lod [$root lod] + if {![$lod istrunk]} { lappend symbols $lod } + set root [$root child] + } + } + + return [list [lsort -unique -dict $revisions] [lsort -unique -dict $symbols]] + } + # # ## ### ##### ######## ############# ## Configuration pragma -hastypeinfo no ; # no type introspection pragma -hasinfo no ; # no object introspection @@ -990,13 +1043,14 @@ # 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 + namespace import ::vc::fossil::import::cvs::state } } # # ## ### ##### ######## ############# ##################### ## Ready package provide vc::fossil::import::cvs::file 1.0 return
Modified tools/cvs2fossil/lib/c2f_frev.tcl from [2e41dc7df6] to [8b070e3579].
@@ -16,10 +16,11 @@ ## Requirements package require Tcl 8.4 ; # Required runtime. package require snit ; # OO system. package require vc::tools::misc ; # Text formatting +package require vc::fossil::import::cvs::state ; # State storage. # # ## ### ##### ######## ############# ##################### ## snit::type ::vc::fossil::import::cvs::file::rev { @@ -32,10 +33,17 @@ set myorigdate $date set mystate $state set myfile $thefile return } + + method defid {} { + set myid [incr myidcounter] + return + } + + method id {} { return $myid } # Basic pieces ________________________ method hasmeta {} { return [expr {$mymetaid ne ""}] } method hastext {} { @@ -332,16 +340,64 @@ # Chop the last segment off return [join [lrange [split $branchnr .] 0 end-1] .] } # # ## ### ##### ######## ############# + + method persist {} { + set fid [$myfile id] + set op $myopcode($myoperation) + set idb $myisondefaultbranch + + struct::list assign $mytext cs cl + set cl [expr {$cl - $cs}] + + lappend map @L@ [expr { [$mylod istrunk] ? "NULL" : [$mylod id] }] + lappend map @P@ [expr { ($myparent eq "") ? "NULL" : [$myparent id] }] + lappend map @C@ [expr { ($mychild eq "") ? "NULL" : [$mychild id] }] + lappend map @DP [expr { ($mydbparent eq "") ? "NULL" : [$mydbparent id] }] + lappend map @DC [expr { ($mydbchild eq "") ? "NULL" : [$mydbchild id] }] + lappend map @BP [expr { ($myparentbranch eq "") ? "NULL" : [$myparentbranch id] }] + + set cmd { + INSERT INTO revision ( rid, fid, lod, rev, date, state, mid, cs, cl, op, isdefault, parent, child, dbparent, dbchild, bparent) + VALUES ($myid, $fid, @L@, $myrevnr, $mydate, $mystate, $mymetaid, $cs, $cl, $op, $idb, @P@, @C@, @DP, @DC, @BP); + } + + state transaction { + state run [string map $map $cmd] + } + return + } + + # # ## ### ##### ######## ############# ## State + + # Persistent: myid - revision.rid + # myfile - revision.fid + # mylod - revision.lod + # myrevnr - revision.rev + # mydate - revision.date + # mystate - revision.state + # mymetaid - revision.mid + # mytext - revision.{cs,cl} + # myparent - revision.parent + # mychild - revision.child + # myparentbranch - revision.bparent + # myoperation - revision.op + # myisondefaultbranch - revision.isdefault + # mydbparent - revision.dbparent + # mydbchild - revision.dbchild + typevariable mybranchpattern {^((?:\d+\.\d+\.)+)(?:0\.)?(\d+)$} # First a nonzero even number of digit groups with trailing dot # CVS then sticks an extra 0 in here; RCS does not. # And the last digit group. + + typevariable myidcounter 0 ; # Counter for revision ids. + variable myid {} ; # Revision id. 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. @@ -424,10 +480,16 @@ {0 0} change {0 1} delete {1 0} add {1 1} nothing } + typevariable myopcode -array { + change 2 + delete -1 + add 1 + nothing 0 + } # # ## ### ##### ######## ############# ## Internal methods # # ## ### ##### ######## ############# @@ -442,13 +504,14 @@ namespace eval ::vc::fossil::import::cvs::file { namespace export rev namespace eval rev { namespace import ::vc::tools::misc::* + namespace import ::vc::fossil::import::cvs::state } } # # ## ### ##### ######## ############# ##################### ## Ready package provide vc::fossil::import::cvs::file::rev 1.0 return
Modified tools/cvs2fossil/lib/c2f_fsym.tcl from [0f3cff0586] to [0342b00fc2].
@@ -17,19 +17,21 @@ 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. +package require vc::fossil::import::cvs::state ; # State storage. # # ## ### ##### ######## ############# ##################### ## snit::type ::vc::fossil::import::cvs::file::sym { # # ## ### ##### ######## ############# ## Public API - constructor {symtype nr symbol} { + constructor {symtype nr symbol file} { + set myfile $file set mytype $symtype set mynr $nr set mysymbol $symbol switch -exact -- $mytype { @@ -37,10 +39,17 @@ tag { } default { trouble internal "Bad symbol type '$mytype'" } } return } + + method defid {} { + set myid [incr myidcounter] + return + } + + method fid {} { return $myid } # Symbol acessor methods. delegate method name to mysymbol delegate method id to mysymbol @@ -56,15 +65,17 @@ } method setposition {n} { set mybranchposition $n ; return } method setparent {rev} { set mybranchparent $rev ; return } method setchild {rev} { set mybranchchild $rev ; return } + method cutchild {} { set mybranchchild "" ; return } method branchnr {} { return $mynr } method parentrevnr {} { return $mybranchparentrevnr } method childrevnr {} { return $mybranchchildrevnr } - method haschild {} { return [expr {$mybranchchildrevnr ne ""}] } + method haschildrev {} { return [expr {$mybranchchildrevnr ne ""}] } + method haschild {} { return [expr {$mybranchchild ne ""}] } method parent {} { return $mybranchparent } method child {} { return $mybranchchild } method position {} { return $mybranchposition } @@ -99,14 +110,73 @@ } return } # # ## ### ##### ######## ############# + + method persist {} { + # Save the information we need after the collection pass. + + # NOTE: mybranchposition is currently not saved. This can + # likely be figured out later from the id itself. If yes, we + # can also get rid of 'sortbranches' (cvs::file) and the + # associated information. + + set fid [$myfile id] + set sid [$mysymbol id] + + lappend map @L@ [expr { [$mylod istrunk] ? "NULL" : [$mylod id] }] + + switch -exact -- $mytype { + tag { + set rid [$mytagrev id] + set cmd { + INSERT INTO tag ( tid, fid, lod, sid, rev) + VALUES ($myid, $fid, @L@, $sid, $rid); + } + } + branch { + lappend map @F@ [expr { ($mybranchchild eq "") ? "NULL" : [$mybranchchild id] }] + + set rid [$mybranchparent id] + set cmd { + INSERT INTO branch ( bid, fid, lod, sid, root, first, bra ) + VALUES ($myid, $fid, @L@, $sid, $rid, @F@, $mynr); + } + } + } + + state transaction { + state run [string map $map $cmd] + } + return + } + + # # ## ### ##### ######## ############# ## State + + # Persistent: + # Tag: myid - tag.tid + # myfile - tag.fid + # mylod - tag.lod + # mysymbol - tag.sid + # mytagrev - tag.rev + # + # Branch: myid - branch.bid + # myfile - branch.fid + # mylod - branch.lod + # mysymbol - branch.sid + # mybranchparent - branch.root + # mybranchchild - branch.first + # mynr - branch.bra + + typevariable myidcounter 0 ; # Counter for symbol ids. + variable myid {} ; # Symbol id. ## Basic, all symbols _________________ + variable myfile {} ; # Reference to the file the symbol is in. variable mytype {} ; # Symbol type, 'tag', or 'branch'. 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. @@ -162,14 +232,15 @@ namespace eval ::vc::fossil::import::cvs::file { namespace export sym namespace eval sym { namespace import ::vc::fossil::import::cvs::file::rev + namespace import ::vc::fossil::import::cvs::state namespace import ::vc::tools::trouble } } # # ## ### ##### ######## ############# ##################### ## Ready package provide vc::fossil::import::cvs::file::sym 1.0 return
Modified tools/cvs2fossil/lib/c2f_pcollrev.tcl from [38ef86c838] to [a41e2628dd].
@@ -56,57 +56,64 @@ # revisions and symbols. The latter can be further separated # into tags and branches. At project level the per-file # symbols information is merged. # File level ... - # Event, Revision, Symbol, Branch, Tag + # Revisions, Branches, Tags # - # Tag <- Symbol <- Event - # Branch <- Symbol <- Event - # Revision <- Event - # - # Head revision, Principal branch, Comment - - state writing rcs { - fid INTEGER NOT NULL REFERENCES file, -- RCS inherit from FILE - head INTEGER NOT NULL REFERENCES revision, - principal INTEGER NOT NULL REFERENCES branch, - comment TEXT NOT NULL - } - - state writing item { - iid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - type INTEGER NOT NULL, -- enum { tag = 1, branch, revision } - fid INTEGER NOT NULL REFERENCES file -- File the item belongs to - } + # Pseudo class hierarchy + # Tag <- Symbol <- Event + # Branch <- Symbol <- Event + # Revision <- Event state writing revision { - iid INTEGER NOT NULL REFERENCES item, -- REVISION inherit from ITEM - lod INTEGER NOT NULL REFERENCES symbol, -- Line of development + rid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + fid INTEGER NOT NULL REFERENCES file, -- File the item belongs to + lod INTEGER REFERENCES symbol, -- Line of development (NULL => Trunk) -- The tags and branches belonging to a revision can be -- determined by selecting on the backreferences in the -- tag and branch tables. - rev TEXT NOT NULL, -- revision number - date INTEGER NOT NULL, -- date of entry, seconds since epoch - state TEXT NOT NULL, -- state of revision - mid INTEGER NOT NULL REFERENCES meta, -- meta data (author, commit message) - next INTEGER NOT NULL REFERENCES revision, -- next in chain of revisions. - cs INTEGER NOT NULL, -- Revision content as offset and length - cl INTEGER NOT NULL -- into the archive file. + rev TEXT NOT NULL, -- revision number + date INTEGER NOT NULL, -- date of entry, seconds since epoch + state TEXT NOT NULL, -- state of revision + mid INTEGER NOT NULL REFERENCES meta, -- meta data (author, commit message) + cs INTEGER NOT NULL, -- Revision content as offset and + cl INTEGER NOT NULL, -- length into the archive file. + + -- Derived information, and links + -- Basic: Parent/Child + -- NTDB: DefaultParent/DefaultChild + -- Branches: Branch parent revision + + op INTEGER NOT NULL, + isdefault INTEGER NOT NULL, + parent INTEGER REFERENCES revision, + child INTEGER REFERENCES revision, + dbparent INTEGER REFERENCES revision, + dbchild INTEGER REFERENCES revision, + bparent INTEGER REFERENCES symbol } state writing tag { - iid INTEGER NOT NULL REFERENCES item, -- TAG inherit from ITEM - sid INTEGER NOT NULL REFERENCES symbol, -- Symbol capturing the tag - rev INTEGER NOT NULL REFERENCES revision -- The revision being tagged. + tid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + fid INTEGER NOT NULL REFERENCES file, -- File the item belongs to + lod INTEGER REFERENCES symbol, -- Line of development (NULL => Trunk) + + sid INTEGER NOT NULL REFERENCES symbol, -- Symbol capturing the tag + + rev INTEGER NOT NULL REFERENCES revision -- The revision being tagged. } state writing branch { - iid INTEGER NOT NULL REFERENCES item, -- BRANCH inherit from ITEM + bid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + fid INTEGER NOT NULL REFERENCES file, -- File the item belongs to + lod INTEGER REFERENCES symbol, -- Line of development (NULL => Trunk) + sid INTEGER NOT NULL REFERENCES symbol, -- Symbol capturing the branch + root INTEGER NOT NULL REFERENCES revision, -- Revision the branch sprouts from first INTEGER REFERENCES revision, -- First revision committed to the branch bra TEXT NOT NULL -- branch number } @@ -207,21 +214,23 @@ trouble fatal "$path is not a valid RCS archive ($msg)" } else { global errorInfo trouble internal $errorInfo } + } else { + # We persist the core of the data collected about + # each file immediately after it has been parsed + # and wrangled into shape, and then drop it from + # memory. This is done to keep the amount of + # required memory within sensible limits. Without + # doing it this way we would easily gobble up 1G + # of RAM or more with all the objects (revisions + # and file-level symbols). + + $file persist } - # We persist the core of the data collected about each - # file immediately after it has been parsed and - # wrangled into shape, and then drop it from - # memory. This is done to keep the memory requirements - # within limits, i.e. without doing it this way it is - # easy to blow 1G of RAM with all the objects - # (revisions and file-level symbols). - - $file persist $file drop } } repository printrevstatistics @@ -234,12 +243,10 @@ 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 rcs - state discard item state discard revision state discard tag state discard branch state discard symbol state discard blocker
Modified tools/cvs2fossil/lib/c2f_project.tcl from [69ed821c29] to [cfcc67163f].
@@ -45,12 +45,12 @@ return $mybase } method setid {id} { set myid $id ; return } - method addfile {rcs usr executable} { - set myfiles($rcs) [list $usr $executable] + method addfile {rcs usr executable {fid {}}} { + set myfiles($rcs) [list $usr $executable $fid] return } method filenames {} { return [lsort -dict [array names myfiles]] @@ -77,10 +77,12 @@ return $mysymbols($name) } # pass I persistence method persist {} { + TheFiles ; # Force id assignment. + state transaction { # Project data first. Required so that we have its id # ready for the files. state run { @@ -90,28 +92,32 @@ set myid [state id] # Then all files, with proper backreference to their # project. - foreach {rcs item} [array get myfiles] { - struct::list assign $item usr executable + foreach rcs [lsort -dict [array names myfiles]] { + struct::list assign $myfiles($rcs) usr executable _fid_ state run { INSERT INTO file (fid, pid, name, visible, exec) VALUES (NULL, $myid, $rcs, $usr, $executable); } + $myfmap($rcs) setid [state id] } } return } # pass II persistence method persistrev {} { + # Note: The per file information (incl. revisions and symbols) + # has already been saved and dropped, immediately after + # processing it, to keep out use of memory under control. Now + # we just have to save the remaining project level parts to + # fix the left-over dangling references. + state transaction { # TODO: per project persistence (symbols, meta data) - foreach f [TheFiles] { - $f persist - } } return } # # ## ### ##### ######## ############# @@ -122,31 +128,34 @@ variable mytrunk {} ; # Reference to the main line of # development for the project. variable myfiles -array {} ; # Maps the rcs archive paths to # their user-visible files. variable myfobj {} ; # File objects for the rcs archives + variable myfmap -array {} ; # Map rcs archive to their object. variable myrepository {} ; # Repository the prject belongs to. variable mysymbols -array {} ; # Map symbol names to project-level # symbol objects. # # ## ### ##### ######## ############# ## Internal methods proc TheFiles {} { - upvar 1 myfiles myfiles myfobj myfobj self self + upvar 1 myfiles myfiles myfobj myfobj self self myfmap myfmap if {![llength $myfobj]} { set myfobj [EmptyFiles myfiles] } return $myfobj } proc EmptyFiles {fv} { - upvar 1 $fv myfiles self self + upvar 1 $fv myfiles self self myfmap myfmap set res {} foreach rcs [lsort -dict [array names myfiles]] { - struct::list assign $myfiles($rcs) f executable - lappend res [file %AUTO% $rcs $f $executable $self] + struct::list assign $myfiles($rcs) f executable fid + set file [file %AUTO% $fid $rcs $f $executable $self] + lappend res $file + set myfmap($rcs) $file } return $res } # # ## ### ##### ######## #############
Modified tools/cvs2fossil/lib/c2f_repository.tcl from [2bc22e9971] to [e30942cde8].
@@ -150,11 +150,11 @@ $pr($pid) setid $pid } foreach {fid pid name visible exec} [state run { SELECT fid, pid, name, visible, exec FROM file ; }] { - $pr($pid) addfile $name $visible $exec + $pr($pid) addfile $name $visible $exec $fid } } return }