Skip to content

Commit d66e8f8

Browse files
Matthew Ogilviegitster
authored andcommitted
cvsserver: Add version awareness to argsfromdir
Signed-off-by: Matthew Ogilvie <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent bfdafa0 commit d66e8f8

File tree

1 file changed

+198
-30
lines changed

1 file changed

+198
-30
lines changed

git-cvsserver.perl

Lines changed: 198 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2226,55 +2226,222 @@ sub argsplit
22262226
}
22272227
}
22282228

2229-
# This method uses $state->{directory} to populate $state->{args} with a list of filenames
2230-
sub argsfromdir
2229+
# Used by argsfromdir
2230+
sub expandArg
22312231
{
2232-
my $updater = shift;
2232+
my ($updater,$outNameMap,$outDirMap,$path,$isDir) = @_;
22332233

2234-
$state->{args} = [] if ( scalar(@{$state->{args}}) == 1 and $state->{args}[0] eq "." );
2234+
my $fullPath = filecleanup($path);
22352235

2236-
return if ( scalar ( @{$state->{args}} ) > 1 );
2236+
# Is it a directory?
2237+
if( defined($state->{dirMap}{$fullPath}) ||
2238+
defined($state->{dirMap}{"$fullPath/"}) )
2239+
{
2240+
# It is a directory in the user's sandbox.
2241+
$isDir=1;
22372242

2238-
my @gethead = @{$updater->gethead};
2243+
if(defined($state->{entries}{$fullPath}))
2244+
{
2245+
$log->fatal("Inconsistent file/dir type");
2246+
die "Inconsistent file/dir type";
2247+
}
2248+
}
2249+
elsif(defined($state->{entries}{$fullPath}))
2250+
{
2251+
# It is a file in the user's sandbox.
2252+
$isDir=0;
2253+
}
2254+
my($revDirMap,$otherRevDirMap);
2255+
if(!defined($isDir) || $isDir)
2256+
{
2257+
# Resolve version tree for sticky tag:
2258+
# (for now we only want list of files for the version, not
2259+
# particular versions of those files: assume it is a directory
2260+
# for the moment; ignore Entry's stick tag)
2261+
2262+
# Order of precedence of sticky tags:
2263+
# -A [head]
2264+
# -r /tag/
2265+
# [file entry sticky tag, but that is only relevant to files]
2266+
# [the tag specified in dir req_Sticky]
2267+
# [the tag specified in a parent dir req_Sticky]
2268+
# [head]
2269+
# Also, -r may appear twice (for diff).
2270+
#
2271+
# FUTURE: When/if -j (merges) are supported, we also
2272+
# need to add relevant files from one or two
2273+
# versions specified with -j.
2274+
2275+
if(exists($state->{opt}{A}))
2276+
{
2277+
$revDirMap=$updater->getRevisionDirMap();
2278+
}
2279+
elsif( defined($state->{opt}{r}) and
2280+
ref $state->{opt}{r} eq "ARRAY" )
2281+
{
2282+
$revDirMap=$updater->getRevisionDirMap($state->{opt}{r}[0]);
2283+
$otherRevDirMap=$updater->getRevisionDirMap($state->{opt}{r}[1]);
2284+
}
2285+
elsif(defined($state->{opt}{r}))
2286+
{
2287+
$revDirMap=$updater->getRevisionDirMap($state->{opt}{r});
2288+
}
2289+
else
2290+
{
2291+
my($sticky)=getDirStickyInfo($fullPath);
2292+
$revDirMap=$updater->getRevisionDirMap($sticky->{tag});
2293+
}
22392294

2240-
# push added files
2241-
foreach my $file (keys %{$state->{entries}}) {
2242-
if ( exists $state->{entries}{$file}{revision} &&
2243-
$state->{entries}{$file}{revision} eq '0' )
2244-
{
2245-
push @gethead, { name => $file, filehash => 'added' };
2246-
}
2295+
# Is it a directory?
2296+
if( defined($revDirMap->{$fullPath}) ||
2297+
defined($otherRevDirMap->{$fullPath}) )
2298+
{
2299+
$isDir=1;
2300+
}
22472301
}
22482302

2249-
if ( scalar(@{$state->{args}}) == 1 )
2303+
# What to do with it?
2304+
if(!$isDir)
22502305
{
2251-
my $arg = $state->{args}[0];
2252-
$arg .= $state->{prependdir} if ( defined ( $state->{prependdir} ) );
2253-
2254-
$log->info("Only one arg specified, checking for directory expansion on '$arg'");
2306+
$outNameMap->{$fullPath}=1;
2307+
}
2308+
else
2309+
{
2310+
$outDirMap->{$fullPath}=1;
22552311

2256-
foreach my $file ( @gethead )
2312+
if(defined($revDirMap->{$fullPath}))
22572313
{
2258-
next if ( $file->{filehash} eq "deleted" and not defined ( $state->{entries}{$file->{name}} ) );
2259-
next unless ( $file->{name} =~ /^$arg\// or $file->{name} eq $arg );
2260-
push @{$state->{args}}, $file->{name};
2314+
addDirMapFiles($updater,$outNameMap,$outDirMap,
2315+
$revDirMap->{$fullPath});
22612316
}
2317+
if( defined($otherRevDirMap) &&
2318+
defined($otherRevDirMap->{$fullPath}) )
2319+
{
2320+
addDirMapFiles($updater,$outNameMap,$outDirMap,
2321+
$otherRevDirMap->{$fullPath});
2322+
}
2323+
}
2324+
}
22622325

2263-
shift @{$state->{args}} if ( scalar(@{$state->{args}}) > 1 );
2264-
} else {
2265-
$log->info("Only one arg specified, populating file list automatically");
2326+
# Used by argsfromdir
2327+
# Add entries from dirMap to outNameMap. Also recurse into entries
2328+
# that are subdirectories.
2329+
sub addDirMapFiles
2330+
{
2331+
my($updater,$outNameMap,$outDirMap,$dirMap)=@_;
22662332

2267-
$state->{args} = [];
2333+
my($fullName);
2334+
foreach $fullName (keys(%$dirMap))
2335+
{
2336+
my $cleanName=$fullName;
2337+
if(defined($state->{prependdir}))
2338+
{
2339+
if(!($cleanName=~s/^\Q$state->{prependdir}\E//))
2340+
{
2341+
$log->fatal("internal error stripping prependdir");
2342+
die "internal error stripping prependdir";
2343+
}
2344+
}
22682345

2269-
foreach my $file ( @gethead )
2346+
if($dirMap->{$fullName} eq "F")
2347+
{
2348+
$outNameMap->{$cleanName}=1;
2349+
}
2350+
elsif($dirMap->{$fullName} eq "D")
2351+
{
2352+
if(!$state->{opt}{l})
2353+
{
2354+
expandArg($updater,$outNameMap,$outDirMap,$cleanName,1);
2355+
}
2356+
}
2357+
else
22702358
{
2271-
next if ( $file->{filehash} eq "deleted" and not defined ( $state->{entries}{$file->{name}} ) );
2272-
next unless ( $file->{name} =~ s/^$state->{prependdir}// );
2273-
push @{$state->{args}}, $file->{name};
2359+
$log->fatal("internal error in addDirMapFiles");
2360+
die "internal error in addDirMapFiles";
22742361
}
22752362
}
22762363
}
22772364

2365+
# This method replaces $state->{args} with a directory-expanded
2366+
# list of all relevant filenames (recursively unless -d), based
2367+
# on $state->{entries}, and the "current" list of files in
2368+
# each directory. "Current" files as determined by
2369+
# either the requested (-r/-A) or "req_Sticky" version of
2370+
# that directory.
2371+
# Both the input args and the new output args are relative
2372+
# to the cvs-client's CWD, although some of the internal
2373+
# computations are relative to the top of the project.
2374+
sub argsfromdir
2375+
{
2376+
my $updater = shift;
2377+
2378+
# Notes about requirements for specific callers:
2379+
# update # "standard" case (entries; a single -r/-A/default; -l)
2380+
# # Special case: -d for create missing directories.
2381+
# diff # 0 or 1 -r's: "standard" case.
2382+
# # 2 -r's: We could ignore entries (just use the two -r's),
2383+
# # but it doesn't really matter.
2384+
# annotate # "standard" case
2385+
# log # Punting: log -r has a more complex non-"standard"
2386+
# # meaning, and we don't currently try to support log'ing
2387+
# # branches at all (need a lot of work to
2388+
# # support CVS-consistent branch relative version
2389+
# # numbering).
2390+
#HERE: But we still want to expand directories. Maybe we should
2391+
# essentially force "-A".
2392+
# status # "standard", except that -r/-A/default are not possible.
2393+
# # Mostly only used to expand entries only)
2394+
#
2395+
# Don't use argsfromdir at all:
2396+
# add # Explicit arguments required. Directory args imply add
2397+
# # the directory itself, not the files in it.
2398+
# co # Obtain list directly.
2399+
# remove # HERE: TEST: MAYBE client does the recursion for us,
2400+
# # since it only makes sense to remove stuff already in
2401+
# # the sandobx?
2402+
# ci # HERE: Similar to remove...
2403+
# # Don't try to implement the confusing/weird
2404+
# # ci -r bug er.."feature".
2405+
2406+
if(scalar(@{$state->{args}})==0)
2407+
{
2408+
$state->{args} = [ "." ];
2409+
}
2410+
my %allArgs;
2411+
my %allDirs;
2412+
for my $file (@{$state->{args}})
2413+
{
2414+
expandArg($updater,\%allArgs,\%allDirs,$file);
2415+
}
2416+
2417+
# Include any entries from sandbox. Generally client won't
2418+
# send entries that shouldn't be used.
2419+
foreach my $file (keys %{$state->{entries}})
2420+
{
2421+
$allArgs{remove_prependdir($file)} = 1;
2422+
}
2423+
2424+
$state->{dirArgs} = \%allDirs;
2425+
$state->{args} = [
2426+
sort {
2427+
# Sort priority: by directory depth, then actual file name:
2428+
my @piecesA=split('/',$a);
2429+
my @piecesB=split('/',$b);
2430+
2431+
my $count=scalar(@piecesA);
2432+
my $tmp=scalar(@piecesB);
2433+
return $count<=>$tmp if($count!=$tmp);
2434+
2435+
for($tmp=0;$tmp<$count;$tmp++)
2436+
{
2437+
if($piecesA[$tmp] ne $piecesB[$tmp])
2438+
{
2439+
return $piecesA[$tmp] cmp $piecesB[$tmp]
2440+
}
2441+
}
2442+
return 0;
2443+
} keys(%allArgs) ];
2444+
}
22782445

22792446
## look up directory sticky tag, of either fullPath or a parent:
22802447
sub getDirStickyInfo
@@ -2383,6 +2550,7 @@ sub getStickyTagOrDate
23832550
sub statecleanup
23842551
{
23852552
$state->{files} = [];
2553+
$state->{dirArgs} = {};
23862554
$state->{args} = [];
23872555
$state->{arguments} = [];
23882556
$state->{entries} = {};

0 commit comments

Comments
 (0)