6060 ' Valid-responses' => \&req_Validresponses,
6161 ' valid-requests' => \&req_validrequests,
6262 ' Directory' => \&req_Directory,
63+ ' Sticky' => \&req_Sticky,
6364 ' Entry' => \&req_Entry,
6465 ' Modified' => \&req_Modified,
6566 ' Unchanged' => \&req_Unchanged,
@@ -470,21 +471,80 @@ sub req_Directory
470471 {
471472 $log -> info(" Setting prepend to '$state ->{path}'" );
472473 $state -> {prependdir } = $state -> {path };
474+ my %entries ;
473475 foreach my $entry ( keys %{$state -> {entries }} )
474476 {
475- $state -> {entries }{$state -> {prependdir } . $entry } = $state -> {entries }{$entry };
476- delete $state -> {entries }{$entry };
477+ $entries {$state -> {prependdir } . $entry } = $state -> {entries }{$entry };
477478 }
479+ $state -> {entries }=\%entries ;
480+
481+ my %dirMap ;
482+ foreach my $dir ( keys %{$state -> {dirMap }} )
483+ {
484+ $dirMap {$state -> {prependdir } . $dir } = $state -> {dirMap }{$dir };
485+ }
486+ $state -> {dirMap }=\%dirMap ;
478487 }
479488
480489 if ( defined ( $state -> {prependdir } ) )
481490 {
482491 $log -> debug(" Prepending '$state ->{prependdir}' to state|directory" );
483492 $state -> {directory } = $state -> {prependdir } . $state -> {directory }
484493 }
494+
495+ if ( ! defined ($state -> {dirMap }{$state -> {directory }}) )
496+ {
497+ $state -> {dirMap }{$state -> {directory }} =
498+ {
499+ ' names' => {}
500+ # 'tagspec' => undef
501+ };
502+ }
503+
485504 $log -> debug(" req_Directory : localdir=$data repository=$repository path=$state ->{path} directory=$state ->{directory} module=$state ->{module}" );
486505}
487506
507+ # Sticky tagspec \n
508+ # Response expected: no. Tell the server that the directory most
509+ # recently specified with Directory has a sticky tag or date
510+ # tagspec. The first character of tagspec is T for a tag, D for
511+ # a date, or some other character supplied by a Set-sticky
512+ # response from a previous request to the server. The remainder
513+ # of tagspec contains the actual tag or date, again as supplied
514+ # by Set-sticky.
515+ # The server should remember Static-directory and Sticky requests
516+ # for a particular directory; the client need not resend them each
517+ # time it sends a Directory request for a given directory. However,
518+ # the server is not obliged to remember them beyond the context
519+ # of a single command.
520+ sub req_Sticky
521+ {
522+ my ( $cmd , $tagspec ) = @_ ;
523+
524+ my ( $stickyInfo );
525+ if ($tagspec eq " " )
526+ {
527+ # nothing
528+ }
529+ elsif ($tagspec =~/ ^T([^ ]+)\s *$ / )
530+ {
531+ $stickyInfo = { ' tag' => $1 };
532+ }
533+ elsif ($tagspec =~/ ^D([0-9.]+)\s *$ / )
534+ {
535+ $stickyInfo = { ' date' => $1 };
536+ }
537+ else
538+ {
539+ die " Unknown tag_or_date format\n " ;
540+ }
541+ $state -> {dirMap }{$state -> {directory }}{stickyInfo }=$stickyInfo ;
542+
543+ $log -> debug(" req_Sticky : tagspec=$tagspec repository=$state ->{repository}"
544+ . " path=$state ->{path} directory=$state ->{directory}"
545+ . " module=$state ->{module}" );
546+ }
547+
488548# Entry entry-line \n
489549# Response expected: no. Tell the server what version of a file is on the
490550# local machine. The name in entry-line is a name relative to the directory
@@ -511,6 +571,8 @@ sub req_Entry
511571 tag_or_date => $data [5],
512572 };
513573
574+ $state -> {dirMap }{$state -> {directory }}{names }{$data [1]} = ' F' ;
575+
514576 $log -> info(" Received entry line '$data ' => '" . $state -> {directory } . $data [1] . " '" );
515577}
516578
@@ -2213,13 +2275,118 @@ sub argsfromdir
22132275 }
22142276}
22152277
2278+
2279+ # # look up directory sticky tag, of either fullPath or a parent:
2280+ sub getDirStickyInfo
2281+ {
2282+ my ($fullPath )=@_ ;
2283+
2284+ $fullPath =~s % /+$%% ;
2285+ while ($fullPath ne " " && !defined ($state -> {dirMap }{" $fullPath /" }))
2286+ {
2287+ $fullPath =~s % /?[^/]*$%% ;
2288+ }
2289+
2290+ if ( !defined ($state -> {dirMap }{" $fullPath /" }) &&
2291+ ( $fullPath eq " " ||
2292+ $fullPath eq " ." ) )
2293+ {
2294+ return $state -> {dirMap }{" " }{stickyInfo };
2295+ }
2296+ else
2297+ {
2298+ return $state -> {dirMap }{" $fullPath /" }{stickyInfo };
2299+ }
2300+ }
2301+
2302+ # Resolve precedence of various ways of specifying which version of
2303+ # a file you want. Returns undef (for default head), or a ref to a hash
2304+ # that contains "tag" and/or "date" keys.
2305+ sub resolveStickyInfo
2306+ {
2307+ my ($filename ,$stickyTag ,$stickyDate ,$reset ) = @_ ;
2308+
2309+ # Order of precedence of sticky tags:
2310+ # -A [head]
2311+ # -r /tag/
2312+ # [file entry sticky tag]
2313+ # [the tag specified in dir req_Sticky]
2314+ # [the tag specified in a parent dir req_Sticky]
2315+ # [head]
2316+
2317+ my $result ;
2318+ if ($reset )
2319+ {
2320+ # $result=undef;
2321+ }
2322+ elsif ( defined ($stickyTag ) && $stickyTag ne " " )
2323+ # || ( defined($stickyDate) && $stickyDate ne "" ) # TODO
2324+ {
2325+ $result ={ ' tag' => (defined ($stickyTag )?$stickyTag :undef ) };
2326+
2327+ # TODO: Convert -D value into the form 2011.04.10.04.46.57,
2328+ # similar to an entry line's sticky date, without the D prefix.
2329+ # It sometimes (always?) arrives as something more like
2330+ # '10 Apr 2011 04:46:57 -0000'...
2331+ # $result={ 'date' => (defined($stickyDate)?$stickyDate:undef) };
2332+ }
2333+ elsif ( defined ($state -> {entries }{$filename }) &&
2334+ defined ($state -> {entries }{$filename }{tag_or_date }) &&
2335+ $state -> {entries }{$filename }{tag_or_date } ne " " )
2336+ {
2337+ my ($tagOrDate )=$state -> {entries }{$filename }{tag_or_date };
2338+ if ($tagOrDate =~/ ^T([^ ]+)\s *$ / )
2339+ {
2340+ $result = { ' tag' => $1 };
2341+ }
2342+ elsif ($tagOrDate =~/ ^D([0-9.]+)\s *$ / )
2343+ {
2344+ $result = { ' date' => $1 };
2345+ }
2346+ else
2347+ {
2348+ die " Unknown tag_or_date format\n " ;
2349+ }
2350+ }
2351+ else
2352+ {
2353+ $result =getDirStickyInfo($filename );
2354+ }
2355+
2356+ return $result ;
2357+ }
2358+
2359+ # Convert a stickyInfo (ref to a hash) as returned by resolveStickyInfo into
2360+ # a form appropriate for the sticky tag field of an Entries
2361+ # line (field index 5, 0-based).
2362+ sub getStickyTagOrDate
2363+ {
2364+ my ($stickyInfo )=@_ ;
2365+
2366+ my $result ;
2367+ if (defined ($stickyInfo ) && defined ($stickyInfo -> {tag }))
2368+ {
2369+ $result =" T$stickyInfo ->{tag}" ;
2370+ }
2371+ # TODO: When/if we actually pick versions by {date} properly,
2372+ # also handle it here:
2373+ # "D$stickyInfo->{date}" (example: "D2011.04.13.20.37.07").
2374+ else
2375+ {
2376+ $result =" " ;
2377+ }
2378+
2379+ return $result ;
2380+ }
2381+
22162382# This method cleans up the $state variable after a command that uses arguments has run
22172383sub statecleanup
22182384{
22192385 $state -> {files } = [];
22202386 $state -> {args } = [];
22212387 $state -> {arguments } = [];
22222388 $state -> {entries } = {};
2389+ $state -> {dirMap } = {};
22232390}
22242391
22252392# Return working directory CVS revision "1.X" out
0 commit comments