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