@@ -2226,55 +2226,222 @@ sub argsplit
2226
2226
}
2227
2227
}
2228
2228
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
2231
2231
{
2232
- my $updater = shift ;
2232
+ my ( $updater , $outNameMap , $outDirMap , $path , $isDir ) = @_ ;
2233
2233
2234
- $state -> { args } = [] if ( scalar (@{ $state -> { args }}) == 1 and $state -> { args }[0] eq " . " );
2234
+ my $fullPath = filecleanup( $path );
2235
2235
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;
2237
2242
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
+ }
2239
2294
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
+ }
2247
2301
}
2248
2302
2249
- if ( scalar (@{$state -> {args }}) == 1 )
2303
+ # What to do with it?
2304
+ if (!$isDir )
2250
2305
{
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;
2255
2311
2256
- foreach my $file ( @gethead )
2312
+ if ( defined ( $revDirMap -> { $fullPath }) )
2257
2313
{
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 });
2261
2316
}
2317
+ if ( defined ($otherRevDirMap ) &&
2318
+ defined ($otherRevDirMap -> {$fullPath }) )
2319
+ {
2320
+ addDirMapFiles($updater ,$outNameMap ,$outDirMap ,
2321
+ $otherRevDirMap -> {$fullPath });
2322
+ }
2323
+ }
2324
+ }
2262
2325
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 )=@_ ;
2266
2332
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
+ }
2268
2345
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
2270
2358
{
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" ;
2274
2361
}
2275
2362
}
2276
2363
}
2277
2364
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
+ }
2278
2445
2279
2446
# # look up directory sticky tag, of either fullPath or a parent:
2280
2447
sub getDirStickyInfo
@@ -2383,6 +2550,7 @@ sub getStickyTagOrDate
2383
2550
sub statecleanup
2384
2551
{
2385
2552
$state -> {files } = [];
2553
+ $state -> {dirArgs } = {};
2386
2554
$state -> {args } = [];
2387
2555
$state -> {arguments } = [];
2388
2556
$state -> {entries } = {};
0 commit comments