cvsserver: implement req_Sticky and related utilities

Nothing sets sticky yet, or uses the values set by this, but soon... Signed-off-by: Matthew Ogilvie <mmogilvi_git@miniinfo.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Matthew Ogilvie committed Oct 13, 2012 at 23:42 UTC eb5dcb2c0290aa0cdbbd3f6c9ddfa77f251deacf
1 file changed +169 -2
git-cvsserver.perl
+169 -2
@@ -60,6 +60,7 @@ my $methods = {
60 'Valid-responses' => \&req_Validresponses,
61 'valid-requests' => \&req_validrequests,
62 'Directory' => \&req_Directory,
63 + 'Sticky' => \&req_Sticky,
64 'Entry' => \&req_Entry,
65 'Modified' => \&req_Modified,
66 'Unchanged' => \&req_Unchanged,
@@ -470,11 +471,19 @@ sub req_Directory
471 {
472 $log->info("Setting prepend to '$state->{path}'");
473 $state->{prependdir} = $state->{path};
474 + my %entries;
475 foreach my $entry ( keys %{$state->{entries}} )
476 {
475 - $state->{entries}{$state->{prependdir} . $entry} = $state->{entries}{$entry};
476 - delete $state->{entries}{$entry};
477 + $entries{$state->{prependdir} . $entry} = $state->{entries}{$entry};
478 }
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;
487 }
488
489 if ( defined ( $state->{prependdir} ) )
@@ -482,9 +491,60 @@ sub req_Directory
491 $log->debug("Prepending '$state->{prependdir}' to state|directory");
492 $state->{directory} = $state->{prependdir} . $state->{directory}
493 }
494 +
495 + if ( ! defined($state->{dirMap}{$state->{directory}}) )
496 + {
497 + $state->{dirMap}{$state->{directory}} =
498 + {
499 + 'names' => {}
500 + #'tagspec' => undef
501 + };
502 + }
503 +
504 $log->debug("req_Directory : localdir=$data repository=$repository path=$state->{path} directory=$state->{directory} module=$state->{module}");
505 }
506
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 +
548 # Entry entry-line \n
549 # Response expected: no. Tell the server what version of a file is on the
550 # local machine. The name in entry-line is a name relative to the directory
@@ -511,6 +571,8 @@ sub req_Entry
571 tag_or_date => $data[5],
572 };
573
574 + $state->{dirMap}{$state->{directory}}{names}{$data[1]} = 'F';
575 +
576 $log->info("Received entry line '$data' => '" . $state->{directory} . $data[1] . "'");
577 }
578
@@ -2213,6 +2275,110 @@ sub argsfromdir
2275 }
2276 }
2277
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 +
2382 # This method cleans up the $state variable after a command that uses arguments has run
2383 sub statecleanup
2384 {
@@ -2220,6 +2386,7 @@ sub statecleanup
2386 $state->{args} = [];
2387 $state->{arguments} = [];
2388 $state->{entries} = {};
2389 + $state->{dirMap} = {};
2390 }
2391
2392 # Return working directory CVS revision "1.X" out