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>
This commit is contained in:
Matthew Ogilvie 2012-10-13 23:42:28 -06:00 коммит произвёл Junio C Hamano
Родитель 658b57ad52
Коммит eb5dcb2c02
1 изменённых файлов: 169 добавлений и 2 удалений

Просмотреть файл

@ -60,6 +60,7 @@ my $methods = {
'Valid-responses' => \&req_Validresponses,
'valid-requests' => \&req_validrequests,
'Directory' => \&req_Directory,
'Sticky' => \&req_Sticky,
'Entry' => \&req_Entry,
'Modified' => \&req_Modified,
'Unchanged' => \&req_Unchanged,
@ -470,11 +471,19 @@ sub req_Directory
{
$log->info("Setting prepend to '$state->{path}'");
$state->{prependdir} = $state->{path};
my %entries;
foreach my $entry ( keys %{$state->{entries}} )
{
$state->{entries}{$state->{prependdir} . $entry} = $state->{entries}{$entry};
delete $state->{entries}{$entry};
$entries{$state->{prependdir} . $entry} = $state->{entries}{$entry};
}
$state->{entries}=\%entries;
my %dirMap;
foreach my $dir ( keys %{$state->{dirMap}} )
{
$dirMap{$state->{prependdir} . $dir} = $state->{dirMap}{$dir};
}
$state->{dirMap}=\%dirMap;
}
if ( defined ( $state->{prependdir} ) )
@ -482,9 +491,60 @@ sub req_Directory
$log->debug("Prepending '$state->{prependdir}' to state|directory");
$state->{directory} = $state->{prependdir} . $state->{directory}
}
if ( ! defined($state->{dirMap}{$state->{directory}}) )
{
$state->{dirMap}{$state->{directory}} =
{
'names' => {}
#'tagspec' => undef
};
}
$log->debug("req_Directory : localdir=$data repository=$repository path=$state->{path} directory=$state->{directory} module=$state->{module}");
}
# Sticky tagspec \n
# Response expected: no. Tell the server that the directory most
# recently specified with Directory has a sticky tag or date
# tagspec. The first character of tagspec is T for a tag, D for
# a date, or some other character supplied by a Set-sticky
# response from a previous request to the server. The remainder
# of tagspec contains the actual tag or date, again as supplied
# by Set-sticky.
# The server should remember Static-directory and Sticky requests
# for a particular directory; the client need not resend them each
# time it sends a Directory request for a given directory. However,
# the server is not obliged to remember them beyond the context
# of a single command.
sub req_Sticky
{
my ( $cmd, $tagspec ) = @_;
my ( $stickyInfo );
if($tagspec eq "")
{
# nothing
}
elsif($tagspec=~/^T([^ ]+)\s*$/)
{
$stickyInfo = { 'tag' => $1 };
}
elsif($tagspec=~/^D([0-9.]+)\s*$/)
{
$stickyInfo= { 'date' => $1 };
}
else
{
die "Unknown tag_or_date format\n";
}
$state->{dirMap}{$state->{directory}}{stickyInfo}=$stickyInfo;
$log->debug("req_Sticky : tagspec=$tagspec repository=$state->{repository}"
. " path=$state->{path} directory=$state->{directory}"
. " module=$state->{module}");
}
# Entry entry-line \n
# Response expected: no. Tell the server what version of a file is on the
# local machine. The name in entry-line is a name relative to the directory
@ -511,6 +571,8 @@ sub req_Entry
tag_or_date => $data[5],
};
$state->{dirMap}{$state->{directory}}{names}{$data[1]} = 'F';
$log->info("Received entry line '$data' => '" . $state->{directory} . $data[1] . "'");
}
@ -2213,6 +2275,110 @@ sub argsfromdir
}
}
## look up directory sticky tag, of either fullPath or a parent:
sub getDirStickyInfo
{
my($fullPath)=@_;
$fullPath=~s%/+$%%;
while($fullPath ne "" && !defined($state->{dirMap}{"$fullPath/"}))
{
$fullPath=~s%/?[^/]*$%%;
}
if( !defined($state->{dirMap}{"$fullPath/"}) &&
( $fullPath eq "" ||
$fullPath eq "." ) )
{
return $state->{dirMap}{""}{stickyInfo};
}
else
{
return $state->{dirMap}{"$fullPath/"}{stickyInfo};
}
}
# Resolve precedence of various ways of specifying which version of
# a file you want. Returns undef (for default head), or a ref to a hash
# that contains "tag" and/or "date" keys.
sub resolveStickyInfo
{
my($filename,$stickyTag,$stickyDate,$reset) = @_;
# Order of precedence of sticky tags:
# -A [head]
# -r /tag/
# [file entry sticky tag]
# [the tag specified in dir req_Sticky]
# [the tag specified in a parent dir req_Sticky]
# [head]
my $result;
if($reset)
{
# $result=undef;
}
elsif( defined($stickyTag) && $stickyTag ne "" )
# || ( defined($stickyDate) && $stickyDate ne "" ) # TODO
{
$result={ 'tag' => (defined($stickyTag)?$stickyTag:undef) };
# TODO: Convert -D value into the form 2011.04.10.04.46.57,
# similar to an entry line's sticky date, without the D prefix.
# It sometimes (always?) arrives as something more like
# '10 Apr 2011 04:46:57 -0000'...
# $result={ 'date' => (defined($stickyDate)?$stickyDate:undef) };
}
elsif( defined($state->{entries}{$filename}) &&
defined($state->{entries}{$filename}{tag_or_date}) &&
$state->{entries}{$filename}{tag_or_date} ne "" )
{
my($tagOrDate)=$state->{entries}{$filename}{tag_or_date};
if($tagOrDate=~/^T([^ ]+)\s*$/)
{
$result = { 'tag' => $1 };
}
elsif($tagOrDate=~/^D([0-9.]+)\s*$/)
{
$result= { 'date' => $1 };
}
else
{
die "Unknown tag_or_date format\n";
}
}
else
{
$result=getDirStickyInfo($filename);
}
return $result;
}
# Convert a stickyInfo (ref to a hash) as returned by resolveStickyInfo into
# a form appropriate for the sticky tag field of an Entries
# line (field index 5, 0-based).
sub getStickyTagOrDate
{
my($stickyInfo)=@_;
my $result;
if(defined($stickyInfo) && defined($stickyInfo->{tag}))
{
$result="T$stickyInfo->{tag}";
}
# TODO: When/if we actually pick versions by {date} properly,
# also handle it here:
# "D$stickyInfo->{date}" (example: "D2011.04.13.20.37.07").
else
{
$result="";
}
return $result;
}
# This method cleans up the $state variable after a command that uses arguments has run
sub statecleanup
{
@ -2220,6 +2386,7 @@ sub statecleanup
$state->{args} = [];
$state->{arguments} = [];
$state->{entries} = {};
$state->{dirMap} = {};
}
# Return working directory CVS revision "1.X" out