Differences From:
File
tools/lib/cvs.tcl
part of check-in
[10e3b3ed76]
- Fixed bug in the new code setting up the timeline, forgot to clean up loop state,
causing data from previous iterations to bleed into the current one, causing the
use of bogus data and ultimatively a bogus timeline. Note! Incidentially a bug
in the old code was fixed by the new one, the use of mismatching revisions and
commit messages. That caused the generation of extra changesets in the old code.
by
aku on
2007-09-17 04:14:18.
[view]
To:
File
tools/lib/cvs.tcl
part of check-in
[ae54e928c2]
- Further work on the CVS frontend. The main parts for doing the extraction and management of changesets are now in a separate package.
by
aku on
2007-09-17 07:05:01.
[view]
@@ -10,8 +10,9 @@
package require vc::tools::log ; # User feedback
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 struct::tree
namespace eval ::vc::cvs::ws {
vc::tools::log::system cvs
@@ -73,11 +74,11 @@
if {![check $src msg]} { return -code error $msg }
DefBase $src
MakeTimeline [ScanArchives [files::find [RootPath]]]
-
- # OLD api calls ... TODO rework for more structure ...
- csets ; # Group changes into sets
+ MakeChangesets
+
+ # OLD api calls ... TODO rework for more structure ...
rtree ; # Build revision tree (trunk only right now).
return [MakeWorkspace]
}
@@ -93,9 +94,8 @@
uplevel 1 [list ::vc::cvs::ws::foreach_cset $cv 0 $script]
}
proc ::vc::cvs::ws::ncsets {args} {
- variable ncs
variable ntrunk
if {[llength $args] > 1} {
return -code error "wrong#args: Expected ?-import?"
@@ -106,9 +106,9 @@
return $ntrunk
}
}
- return $ncs
+ return [csets::num]
}
proc ::vc::cvs::ws::isadmin {path} {
# Check if path is a CVS admin file.
@@ -117,14 +117,28 @@
return 0
}
proc ::vc::cvs::ws::checkout {id} {
- variable workspace ; cd $workspace
- wssetup $id ; # OLD api ... TODO inline
+ variable workspace
+ cd $workspace
+
+ array set cs [csets::get $id]
+
+ write 1 cvs "@ $cs(date)"
+ ::foreach l [split [string trim $cs(cmsg)] \n] {
+ write 1 cvs "| $l"
+ }
+
+ ::foreach {f r} $cs(removed) { write 2 cvs "R $f $r" ; Remove $f $r }
+ ::foreach {f r} $cs(added) { write 2 cvs "A $f $r" ; Checkout $f $r }
+ ::foreach {f r} $cs(changed) { write 2 cvs "M $f $r" ; Checkout $f $r }
+
+ # Provide metadata about the changeset the backend may wish to have
+ return [list $cs(author) $cs(date) $cs(cmsg)]
}
# -----------------------------------------------------------------------------
-# Internals - Old API for now.
+# Internals
proc ::vc::cvs::ws::DefBase {path} {
variable project
variable base
@@ -149,11 +163,8 @@
} else {
return $base/$project
}
}
-
-# Scan repository, collect archives, parse them, and collect revision
-# information (file, revision -> date, author, commit message)
proc ::vc::cvs::ws::ScanArchives {files} {
write 0 cvs "Scanning archives ..."
@@ -197,9 +208,9 @@
unset cmsg
unset stat
}
- write 0 cvs "Generated [NSIPL $n entry entries]"
+ write 0 cvs "Timeline has [NSIPL $n entry entries]"
return
}
proc ::vc::cvs::ws::NoteDeadRoots {f rev operation} {
@@ -220,8 +231,21 @@
if {$rev eq "1.1"} {return "A"} ; # Added
return "M" ; # Modified
}
+proc ::vc::cvs::ws::MakeChangesets {} {
+ write 0 cvs "Generating changesets from timeline"
+
+ csets::init
+ timeline::foreach date file revision operation author cmsg {
+ csets::add $date $file $revision $operation $author $cmsg
+ }
+ csets::done
+
+ write 0 cvs "Found [NSIPL [csets::num] changeset]"
+ return
+}
+
proc ::vc::cvs::ws::MakeWorkspace {} {
variable project
variable workspace [fileutil::tempfile importF_cvs_ws_]
@@ -234,55 +258,13 @@
write 0 cvs "Workspace: $workspace"
return $w
}
-
-# Group single changes into changesets
-
-proc ::vc::cvs::ws::csets {} {
- variable timeline
- variable csets
- variable ncs
- variable cmap
-
- array unset csets * ; array set csets {}
- array unset cmap * ; array set cmap {}
- set ncs 0
-
- write 0 cvs "Generating changesets from timeline"
-
- CSClear
- timeline::foreach date file revision operation author cmsg {
- # API adaption
- set entry [list $operation $date $author $revision $file $cmsg]
-
- if {![CSNone] && [CSNew $entry]} {
- CSSave
- CSClear
- }
- CSAdd $entry
- }
-
- write 0 cvs "Found [NSIPL [array size csets] changeset]"
- return
-}
-
-
-namespace eval ::vc::cvs::ws {
- # Changeset data:
- # ncs: Counter-based id generation
- # csets: id -> (user commit start end depth (file -> (op rev)))
-
- variable ncs ; set ncs 0 ; # Counter for changesets
- variable csets ; array set csets {} ; # Changeset data
-}
-
# Building the revision tree from the changesets.
# Limitation: Currently only trunk csets is handled.
# Limitation: Dead files are not removed, i.e. no 'R' actions right now.
proc ::vc::cvs::ws::rtree {} {
- variable csets
variable rtree {}
variable ntrunk 0
write 0 cvs "Extracting the trunk"
@@ -295,13 +277,12 @@
# Extracting the trunk is easy, simply by looking at the involved
# version numbers.
- ::foreach c [lrange [lsort -integer [array names csets]] 1 end] {
- ::foreach {u cm s e rd f} $csets($c) break
-
+ for {set c 1} {$c < [csets::num]} {incr c} {
+ array set cs [csets::get $c]
# Ignore branch changes, just count them for the statistics.
- if {$rd != 2} {
+ if {$cs(lastd) != 2} {
incr b
continue
}
@@ -321,76 +302,8 @@
# Node names are cset id's.
variable rtree {}
variable ntrunk 0
-}
-
-proc ::vc::cvs::ws::wssetup {c} {
- variable csets
- variable base
- variable project
-
- # pwd = workspace
-
- ::foreach {u cm s e rd fs} $csets($c) break
-
- write 1 cvs "@ $s"
-
- ::foreach l [split [string trim $cm] \n] {
- write 1 cvs "| $l"
- }
-
- ::foreach {f or} $fs {
- ::foreach {op r} $or break
- write 2 cvs "$op $f $r"
-
- if {$op eq "R"} {
- # Remove file from workspace. Prune empty directories.
- #
- # NOTE: A dead-first file (rev 1.1 dead) will never have
- # existed.
- #
- # NOTE: Logically empty directories still physically
- # contain the CVS admin directory, hence the check for ==
- # 1, not == 0. There might also be hidden files, we count
- # them as well. Always hidden are . and .. and they do not
- # count as user file.
-
- file delete $f
- set fd [file dirname $f]
- if {
- ([llength [glob -nocomplain -directory $fd *]] == 1) &&
- ([llength [glob -nocomplain -directory -type hidden $fd *]] == 2)
- } {
- file delete -force $fd
- }
- } else {
- # Added or modified, put the requested version of the file
- # into the workspace.
-
- if {$project ne ""} {set f $project/$f}
- if {[catch {
- dova -d $base co -r $r $f
- } msg]} {
- if {[string match {*invalid change text*} $msg]} {
- # The archive of the file is corrupted and the
- # chosen version not accessible due to that. We
- # report the problem, but otherwise ignore it. As
- # a consequence the destination repository will not
- # contain the full history of the named file. By
- # ignoring the problem we however get as much as
- # is possible.
-
- write 0 cvs "EE Corrupted archive file. Inaccessible revision."
- continue
- }
- return -code error $msg
- }
- }
- }
-
- # Provide metadata about the changeset the backend may wish to have
- return [list $u $s $cm]
}
proc ::vc::cvs::ws::foreach_cset {cv node script} {
upvar 1 $cv c
@@ -422,96 +335,56 @@
}
return
}
-# -----------------------------------------------------------------------------
-# Internal helper commands: Changeset inspection and construction.
-
-proc ::vc::cvs::ws::CSClear {} {
- upvar 1 start start end end cm cm user user files files lastd lastd
+proc ::vc::cvs::ws::Checkout {f r} {
+ variable base
+ variable project
+
+ # Added or modified, put the requested version of the file into
+ # the workspace.
+
+ if {$project ne ""} {set f $project/$f}
+ if {[catch {
+ dova -d $base co -r $r $f
+ } msg]} {
+ if {[string match {*invalid change text*} $msg]} {
+
+ # The archive of the file is corrupted and the chosen
+ # version not accessible due to that. We report the
+ # problem, but otherwise ignore it. As a consequence the
+ # destination repository will not contain the full history
+ # of the named file. By ignoring the problem we however
+ # get as much as is possible.
- set start {}
- set end {}
- set cm {}
- set user {}
- set lastd {}
- array unset files *
- array set files {}
+ write 0 cvs "EE Corrupted archive file. Inaccessible revision."
+ return
+ }
+ return -code error $msg
+ }
return
}
-proc ::vc::cvs::ws::CSNone {} {
- upvar 1 start start
- return [expr {$start eq ""}]
-}
-
-proc ::vc::cvs::ws::CSNew {entry} {
- upvar 1 start start end end cm cm user user files files lastd lastd reason reason
+proc ::vc::cvs::ws::Remove {f r} {
+ # Remove file from workspace. Prune empty directories.
+ # NOTE: A dead-first file (rev 1.1 dead) will never have existed.
- #puts -nonewline stdout . ; flush stdout
-
- ::foreach {op ts a rev f ecm} $entry break
-
- # User change
- if {$a ne $user} {set reason user ; return 1}
-
- # File already in current cset
- if {[info exists files($f)]} {set reason file ; return 1}
-
- # Current cset trunk/branch different from entry.
- set depth [llength [split $rev .]]
- if {($lastd == 2) != ($depth == 2)} {set reason depth/$lastd/$depth/($rev)/$f ; return 1}
-
- # Commit message changed
- if {$cm ne $ecm} {set reason cmsg\ <<$ecm>> ; return 1}
-
- # Everything is good, still the same cset
- return 0
+ file delete $f
+ Prune [file dirname $f]
+ return
}
-proc ::vc::cvs::ws::CSSave {} {
- variable cmap
- variable csets
- variable ncs
- upvar 1 start start end end cm cm user user files files lastd lastd
+proc ::vc::cvs::ws::Prune {path} {
+ # NOTE: Logically empty directories still physically contain the
+ # CVS admin directory, hence the check for == 1, not == 0. There
+ # might also be hidden files, we count them as well. Always hidden
+ # are . and .. and they do not count as user file.
- set csets($ncs) [list $user $cm $start $end $lastd [array get files]]
-
- # Record which revisions of a file are in what csets
- ::foreach {f or} [array get files] {
- ::foreach {_ rev} $or break
- set cmap([list $f $rev]) $ncs
- }
-
- #CSDump $ncs
-
- incr ncs
- return
-}
-
-proc ::vc::cvs::ws::CSAdd {entry} {
- upvar 1 start start end end cm cm user user files files lastd lastd
-
- ::foreach {op ts a rev f ecm} $entry break
-
- if {$start eq ""} {set start $ts}
- set end $ts
- set cm $ecm
- set user $a
- set files($f) [list $op $rev]
- set lastd [llength [split $rev .]]
- return
-}
-
-proc ::vc::cvs::ws::CSDump {c} {
- variable csets
- ::foreach {u cm s e rd f} $csets($c) break
-
- puts "$u $s"; regsub -all {.} $u { } b
- puts "$b $e"
- ::foreach {f or} $f {
- ::foreach {o r} $or break
- puts "$b $o $f $r"
+ if {
+ ([llength [glob -nocomplain -directory $path *]] == 1) &&
+ ([llength [glob -nocomplain -directory -type hidden $path *]] == 2)
+ } {
+ file delete -force $path
}
return
}