Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
#! perl
2
########################################################################
3
# Copyright (C) 1998-2004 ERG Limited, All rights reserved
4
#
5
# Module name   : cache_dpkg
6
# Module type   : Makefile system
7
# Compiler(s)   : n/a
8
# Environment(s): jats
9
#
10
# Description:
335 dpurdie 11
#       Maintain a local cache of dpkg_Archive
227 dpurdie 12
#
13
# Notes:
335 dpurdie 14
#       Stopped using the JATS "cp.exe" utility as there was a weird problem under
227 dpurdie 15
#       windows. The package orahops-ssw-install/1.0.1000.ssw could not be installed
335 dpurdie 16
#       correctly. It appears that the 'cp' could not process the subdir pair
227 dpurdie 17
#       "DBMGR/DBMGR". Change the name it was OK.
18
#
19
#       Solution: Avoid system functions
20
#
21
#......................................................................#
22
 
23
use strict;
24
use warnings;
25
use JatsError;
26
use FileUtils;
27
use File::Find;
28
use File::Path;
29
use File::Copy;
30
 
31
use Getopt::Long;
32
use Pod::Usage;                             # required for help support
33
 
34
my $VERSION = "1.4.0";
35
 
36
 
37
#
38
#   Options
39
#
40
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
41
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
42
my $opt_help = 0;
43
my $opt_clear;
44
my $opt_flush;
45
my $opt_refresh;
46
my $opt_refresh_all;
47
my $opt_list;
48
my $opt_list_short;
49
my $opt_export;
50
my $opt_quiet;
51
my $opt_update_all;
52
my $opt_age;
361 dpurdie 53
my $opt_test;
227 dpurdie 54
 
55
#
56
#   Global Variables
57
#
58
my $GBE_DPKG        = $ENV{'GBE_DPKG'};                     # The Master repository
59
my $GBE_DPKG_CACHE  = $ENV{'GBE_DPKG_CACHE'} || "";         # Caches
60
my $GBE_DPKG_LOCAL  = $ENV{'GBE_DPKG_LOCAL'} || "";         # Local scratch
61
my $GBE_DPKG_STORE  = $ENV{'GBE_DPKG_STORE'} || "";         # Global Store
62
my $GBE_BIN         = $ENV{'GBE_BIN'};
63
 
64
my $gstore;
65
my $archive;
66
my $cache;
67
my $parchive;
68
my $local = '';
69
my $local_pkg;
70
my @package_list;
71
my @refresh_list;
72
#
73
#   Globals for recursive copy
74
#
75
my $copyFind_dst;
76
my $copyFind_src;
77
my $copyFind_src_len;
78
 
79
#
80
#   Globals for error recovery
81
#
82
my  $remove_on_error;
83
 
84
#-------------------------------------------------------------------------------
85
# Function        : Mainline Entry Point
86
#
87
# Description     :
88
#
89
# Inputs          :
90
#
91
my $result = GetOptions (
337 dpurdie 92
                "help|h:+"                  => \$opt_help,
93
                "manual:3"                  => \$opt_help,
94
                "verbose:+"                 => \$opt_verbose,           # flag, multiple use allowed
95
                "debug:+"                   => \$opt_debug,             # flag, multiple use allowed
227 dpurdie 96
                "flush"                     => \$opt_flush,             # flag
97
                "clear"                     => \$opt_clear,             # flag
98
                "refresh!"                  => \$opt_refresh,           # flag
99
                "refresh_all|refresh-all"   => \$opt_refresh_all,       # flag
100
                "update_all|update-all"     => \$opt_update_all,        # flag
101
                "list"                      => \$opt_list,              # flag
102
                "dir"                       => \$opt_list_short,        # flag
103
                "export"                    => \$opt_export,            # flag
104
                "quiet"                     => \$opt_quiet,             # flag
105
                "age=i"                     => \$opt_age,               # integer
361 dpurdie 106
                "test"                      => \$opt_test,              # flag
227 dpurdie 107
                );
108
 
109
                #
110
                #   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
111
                #
112
 
113
#
114
#   Process help and manual options
115
#
116
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
117
pod2usage(-verbose => 1)  if ($opt_help == 2 );
337 dpurdie 118
pod2usage(-verbose => 2)  if ($opt_help > 2);
227 dpurdie 119
 
120
#
121
#   Configure the error reporting process now that we have the user options
122
#
123
ErrorConfig( 'name'    =>'CACHE',
124
             'verbose' => $opt_verbose,
125
             'debug'   => $opt_debug );
126
 
127
#
128
#   Validate user options
129
#
130
Error( "GBE_BIN not defined in the environment" ) unless ( defined($GBE_BIN) );
131
Error( "GBE_DPKG not defined in the environment" ) unless ( defined($GBE_DPKG) );
132
 
133
#
134
#   No cache - nothing to do
135
#   Generate a status message and exit
136
#
137
unless ( defined($GBE_DPKG_CACHE) )
138
{
139
    Warning ( "GBE_DPKG_CACHE not defined in the environment" );
140
    return 0;
141
}
142
 
143
 
144
$opt_refresh = 1
145
    if ( $opt_refresh_all );
146
 
147
#
148
#   Locate the archive cache
149
#
150
#   Determine the archive to work on
151
#   Search the cache archive list for one with the keyword "_cache"
152
#   or use the last one.
153
#
154
$GBE_DPKG =~ tr~\\/~/~s;
155
$GBE_DPKG =~ s~/$~~;
156
 
157
my @pkg_list = split ( ';', $GBE_DPKG_CACHE );
158
for (@pkg_list)
159
{
160
    $cache = $_
161
        if ( m/_cache/ );
162
}
163
$cache = pop @pkg_list unless ( $cache );
164
$archive = $GBE_DPKG;
165
$local = $GBE_DPKG_LOCAL;
166
$gstore = $GBE_DPKG_STORE;
167
 
168
Error ("No dpkg_archive_cache found") unless ( $cache );
169
Error ("dpkg_archive_cache is the main archive") if ( $cache eq $archive );
170
Error ("main archive is local archive" )         if ( $local && $local eq $archive );
171
Warning  ("dpkg_archive_cache is local_archive" )   if ( $local && $local eq $cache );
172
 
173
#
174
#   Export the list of cache entries
175
#
176
if ( $opt_export or $opt_refresh_all or $opt_list_short or $opt_update_all )
177
{
178
    opendir (DIR, $cache) || die "Cannot open $cache\n";
179
    my @dir_list = readdir(DIR);
180
    closedir DIR;
181
 
182
    for my $fn ( @dir_list)
183
    {
184
        my $count = 0;
185
        next if ( $fn =~ m/^\./ );
186
        next unless ( -d "$cache/$fn" );
187
 
188
        opendir( DIR, "$cache/$fn" ) || die "Cannot open $cache/$fn\n";
189
        while ( my $fn1 = readdir(DIR) )
190
        {
191
            next if ( $fn1 =~ m/^\./ );
192
            push @package_list, "$fn/$fn1";
193
        }
194
        closedir DIR;
195
    }
196
 
197
    if ( $opt_refresh_all or $opt_update_all )
198
    {
199
        @refresh_list = @package_list
200
    }
201
 
202
    #
203
    #   Simply export a list of packages in the cache
204
    #   Used by other programs
205
    #
206
    if ( $opt_export )
207
    {
208
        print join ' ', @package_list;
209
        exit 0;
210
    }
211
}
212
 
213
#
214
#   Display cache information
215
#   This is done AFTER the export - since the export command does not
216
#   need this header.
217
if ( $opt_verbose || $#ARGV < 0 )
218
{
219
    print  "dpkg_store        : $gstore\n" if ($gstore);
220
    print  "dpkg_archive      : $archive\n";
221
    print  "dpkg_archive cache: $cache\n";
222
    print  "dpkg_archive local: $local\n";
223
    Verbose ("args:               @ARGV");
224
}
225
 
226
#
227
#   List the contents of the cache
228
#
229
if ( $opt_list_short )
230
{
231
    print join "\n", @package_list;
232
}
233
 
234
if ( $opt_list )
235
{
236
    #
237
    #   Process user commands
238
    #   List: A nice pretty display of the cache
239
    #
240
    opendir (DIR, $cache) || die "Cannot open $cache\n";
241
    my @dir_list = readdir(DIR);
242
    closedir DIR;
243
 
244
    #
245
    #   Determine max length of a name so that the display is nicely aligned
246
    #
247
    my $nl = 10;
248
    for my $fn ( @dir_list)
249
    {
250
        my $ns = length($fn);
251
        $nl = $ns if ( $ns > $nl )
252
    }
253
 
254
    #
255
    #   Display information by package
256
    #   A nicely formatted list with line wrapping
257
    #
258
    for my $fn ( @dir_list)
259
    {
260
        my $count = 0;
261
        next if ( $fn =~ m/^\./ );
262
        next unless ( -d "$cache/$fn" );
263
 
264
        opendir( DIR, "$cache/$fn" ) || die "Cannot open $cache/$fn\n";
265
        printf "%-*s :", $nl, $fn;
266
        while ( my $fn1 = readdir(DIR) )
267
        {
268
            next if ( $fn1 =~ m/^\./ );
269
            if ( $count++ >= 4 )
270
            {
271
                $count = 1;
272
                printf "\n%*s  ", $nl, "";
273
            }
274
            printf " %14.14s", $fn1;
275
        }
276
        closedir DIR;
277
        print "\n";
278
    }
279
}
280
 
281
#
282
#   Clear the cache
283
#
284
if ( $opt_clear )
285
{
286
    Warning   ( "Deleting the ENTIRE cache");
287
    rmtree( $cache, $opt_debug );
288
    mkpath( $cache, $opt_debug, 0777);
289
}
290
 
291
#
292
#   Perform cache aging
293
#
294
if ( $opt_age )
295
{
296
    Error ("Age parameter cannot be negative") if ( $opt_age < 0 );
297
    age_the_cache();
298
}
299
 
300
#
301
#   Process the command line arguments
302
#   These MUST be of the form
303
#       packagename
304
#       packagename/version
305
#
306
 
307
for (@ARGV, @refresh_list)
308
{
309
    $remove_on_error = undef;
310
    if ( $opt_flush )
311
    {
312
        unless ( -d "$cache/$_" )
313
        {
314
            Warning ("Package not in cache: $_")
315
                unless ( $opt_quiet );
316
        }
317
        else
318
        {
319
            rmtree( "$cache/$_", $opt_debug );
320
            print "Package removed: $_\n"
321
                unless ( $opt_quiet );
322
        }
323
    }
324
    else
325
    {
326
        #
327
        #   Speed up - for remote access
328
        #   If the package is found in the local archive and we aren't doing
329
        #   anything fancy then don't access the remote archive
330
        #
331
        my $local_pkg = ( -d "$local/$_" || -f "$local/$_.lnk" );
332
        if ( $local_pkg )
333
        {
334
            if ( !$opt_refresh )
335
            {
336
                print "Cache SkipLocal: $_ Local copy found\n";
337
 
338
                #
339
                # Delete the cache copy
340
                # The user is playing with local copy
341
                #
342
                if ( -d "$cache/$_" )
343
                {
344
                    print  "Cache SkipLocalDelete: $_ -> $cache\n";
345
                    Verbose ( "Remove: $_" );
346
                    rmtree( "$cache/$_", $opt_debug );
347
                    Verbose ( "Remove Complete: $_" );
348
                }
349
                next;
350
            }
351
        }
352
 
353
        #
354
        #   Locate package.
355
        #   It may be in GBE_DPKG or GBE_DPKG_STORE
356
        #
357
        $parchive = "$archive/$_";
358
        unless ( -d $parchive )
359
        {
360
            $parchive = "$gstore/$_";
361
            unless ( $gstore && -d $parchive )
362
            {
363
                Warning ("Package not in archive: $_")
364
                    unless ( $opt_quiet );
365
                next;
366
            }
367
        }
368
 
369
        ########################################################################
370
        #   We have a package to process
371
        #
372
 
373
        my $dir_found = ( -d "$cache/$_" ) ;
374
        my $force_update = 0;
375
        my $opr = "Update";
376
 
377
 
378
        #
379
        #   Setup error recovery
335 dpurdie 380
        #       1) Tag the directory to be deleted on error
227 dpurdie 381
        #
382
        $remove_on_error = "$cache/$_";
383
        ErrorConfig( 'on_exit' => \&error_recovery );
384
 
385
        #
335 dpurdie 386
        #   Not a forced refresh. Ensure that the cached copy is
227 dpurdie 387
        #   up to date. Examine descpkg
388
        #
389
        if ( $dir_found )
390
        {
391
            if ( -f "$cache/$_/built.cache" )
392
            {
393
                $force_update = 1;
394
                $opr = "Incomplete";
395
                Verbose ("Cache Copy Incomplete: $_");
396
            }
397
            elsif ( FileIsNewer( "$parchive/descpkg", "$cache/$_/descpkg" ) )
398
            {
399
                $force_update = 1;
400
                $opr = "OutOfDate";
401
                Verbose ("Cache out-of-date: $_");
402
            }
403
        }
404
 
405
        #
406
        #   If we need to refresh the cache copy - delete it first
407
        #
408
        if ( ($opt_refresh || $force_update) && $dir_found )
409
        {
410
            print  "Cache $opr: $_ -> $cache\n";
411
            Verbose ( "Remove: $_" );
412
            rmtree( "$cache/$_", $opt_debug );
413
            Verbose ( "Remove Complete: $_" );
229 dpurdie 414
 
415
            #
416
            #   Force transfer, but without the status message
417
            #
227 dpurdie 418
            $dir_found = 0;
229 dpurdie 419
            $opr = '';
227 dpurdie 420
        }
421
 
422
        #
423
        #   If its not in the cache then copy it in
424
        #
425
        unless ( $dir_found )
426
        {
229 dpurdie 427
            print "Cache $opr: $_ -> $cache\n" if $opr;
227 dpurdie 428
            mkpath( "$cache/$_", $opt_debug, 0777);
429
            TouchFile ( "$cache/$_/built.cache", "Marks the cache copy as incomplete");
430
            Verbose ( "Copy in: $_" );
431
            $copyFind_dst = "$cache/$_";
432
            $copyFind_src = $parchive;
433
            $copyFind_src_len = length( $copyFind_src );
434
            File::Find::find( \&copyFind, $parchive );
435
            rmtree( "$cache/$_/built.cache", $opt_debug );  # Works on files too !!
436
        }
437
        else
438
        {
439
            $opr = "Skip";
440
            print "Cache $opr: $_ -> $cache\n";
441
        }
442
    }
443
}
444
 
445
#-------------------------------------------------------------------------------
446
# Function        : copyFind
447
#
448
# Description     : File:Find:find callback function to transfer files
449
#
450
# Inputs          : None
451
#                   Global: $copyFind_dst       : Target directory
452
#                   Global: $copyFind_src       : Source directory
453
#                   Global: $copyFind_src_len   : Length of Source dir
454
#
455
# Returns         : 
456
#
457
 
458
sub copyFind
459
{
460
    my $item = $File::Find::name;
461
 
462
    #
463
    #   Calculate the target directory name
464
    #
465
    my $target = $copyFind_dst . substr($item, $copyFind_src_len );
466
    if ( -d $item )
467
    {
468
        #
469
        #   Directories are handled differently
470
        #       - Directories are created with nice permissions
471
        #
472
        if ( ! -d $target )
473
        {
474
            mkpath( $target, $opt_debug, 0755);
475
        }
476
    }
477
    else
478
    {
479
        #
480
        #   File copy
481
        #
482
        #
483
        #   Copy file to destination
484
        #   If the file is a link, then duplicate the link contents
485
        #   Use: Unix libraries are created as two files:
486
        #        lib.xxxx.so -> libxxxx.so.vv.vv.vv
487
        #
488
        if ( -l $item )
489
        {
490
            Debug("Clone Link: $target");
491
            my $link = readlink $item;
492
            Debug( "Link: $item, $link");
493
            symlink ($link, $target );
494
            unless ( $link && -l $target )
495
            {
496
                Error("Failed to copy link [$item] to [$target]: $!");
497
            }
498
        }
499
        elsif (File::Copy::copy($item, $target))
500
        {
501
            Debug("Copying File: $target");
502
 
503
            #   Make the file ReadOnly
504
            my $perm = (stat $item)[2] & 07777;
505
            CORE::chmod $perm & 0555, $target;
506
        }
507
        else
508
        {
509
            Error("Failed to copy file [$item] to [$target]: $!");
510
        }
511
    }
512
}
513
 
514
#-------------------------------------------------------------------------------
515
# Function        : error_recovery
516
#
517
# Description     : Error recovery routine
518
#                   Delete the cached entry
519
#
520
# Inputs          :  Globals
521
#
522
# Returns         : None
523
#
524
sub error_recovery
525
{
526
    if ( $remove_on_error )
527
    {
345 dpurdie 528
        ReportError ("Error cleanup. Delete cache entry: $remove_on_error");
227 dpurdie 529
        rmtree( $remove_on_error, $opt_debug );
530
        $remove_on_error = undef;
531
    }
532
}
533
 
534
 
535
#-------------------------------------------------------------------------------
536
# Function        : age_the_cache
537
#
538
# Description     : Age cache entries
539
#                   Determine the age by:
540
#                       Use used.cache file if present
541
#                       Use descpkg file
542
#                       Not a proper entry - delete
543
#
544
# Inputs          : opt_age         - Delete packages older than XX days
545
#
546
# Returns         : Nothing
547
#
548
sub age_the_cache
549
{
550
    my $now = time;
551
 
552
    opendir (DIR, $cache) || die "Cannot open $cache\n";
553
    my @dir_list = readdir(DIR);
554
    closedir DIR;
555
 
556
    for my $fn ( @dir_list)
557
    {
558
        my $keep_dir = 0;
559
        next if ( $fn =~ m/^\./ );
560
        next unless ( -d "$cache/$fn" );
361 dpurdie 561
        next if ( $fn eq "core_devl" );
227 dpurdie 562
 
563
        opendir( DIR, "$cache/$fn" ) || die "Cannot open $cache/$fn\n";
564
        while ( my $fn1 = readdir(DIR) )
565
        {
566
            next if ( $fn1 =~ m/^\./ );
567
            my $dir = "$cache/$fn/$fn1";
568
            my $file = "$dir/used.cache" ;
569
            $file = "$dir/descpkg" unless ( -f $file );
570
 
571
            if ( ! -f $file )
572
            {
573
                #
574
                #   No descpkg file
575
                #   This is a badly formed entry - so delete it
576
                #
361 dpurdie 577
                if ( $opt_test )
578
                {
579
                    Message("Would Purge: $fn/$fn1" );
580
                    $keep_dir = 1;
581
                }
582
                else
583
                {
584
                    Message("Purging: $fn/$fn1" );
585
                    rmtree( $dir, $opt_debug );
586
                }
227 dpurdie 587
            }
588
            else
589
            {
590
                #
591
                #   used.cache or descpkg file found
592
                #   How old is it
593
                #
594
                my $timestamp = (stat($file))[9] || 0;
595
                my $age = int( ($now - $timestamp) / (60 * 60 * 24));
596
 
597
                if ( $age > $opt_age )
598
                {
361 dpurdie 599
                    if ( $opt_test )
600
                    {
601
                        Message("Could Age: $fn/$fn1, $age" );
602
                        $keep_dir = 1;
603
                    } else {
604
                        Message("Aging: $fn/$fn1, $age" );
605
                        rmtree( $dir, $opt_debug );
606
                    }
227 dpurdie 607
                }
608
                else
609
                {
610
                    Verbose("Age of: $fn/$fn1, $age" );
611
                    $keep_dir = 1;
612
                }
613
            }
614
        }
615
        closedir DIR;
616
 
617
        #
618
        #   Delete the entire directory if is is empty
619
        #
620
        unless ( $keep_dir )
621
        {
622
            Message("Remove Empty Dir: $cache/$fn"  );
623
            rmtree( "$cache/$fn", $opt_debug );
624
        }
625
    }
626
}
627
 
628
#-------------------------------------------------------------------------------
629
#   Documentation
630
#
631
 
632
=pod
633
 
361 dpurdie 634
=for htmltoc    SYSUTIL::
635
 
227 dpurdie 636
=head1 NAME
637
 
638
cache_dpkg - Maintain a local cache of packages
639
 
640
=head1 SYNOPSIS
641
 
642
 jats cache_dpkg.pl [options] package/version ...
643
 
644
 Options:
645
    -help              - brief help message
646
    -help -help        - Detailed help message
647
    -man               - Full documentation
648
    -clear             - Delete the entire cache
649
    -flush             - Flush all named packages
650
    -[no]refresh       - Refresh package in cache
651
    -list              - List cache contents with nice format
652
    -dir               - List cache contents
653
    -export            - Generate a list of cached packages
654
    -refresh_all       - Refresh all packages within the cache
655
    -update_all        - Update all packages within the cache as required
656
    -quiet             - Suppress warnings
361 dpurdie 657
    -age=nn            - Remove all packages older than nn days
658
    -test              - Use with -age to report ages
227 dpurdie 659
 
660
=head1 OPTIONS
661
 
662
=over 8
663
 
664
=item B<-help>
665
 
666
Print a brief help message and exits.
667
 
668
=item B<-help -help>
669
 
670
Print a detailed help message with an explanation for each option.
671
 
672
=item B<-man>
673
 
674
Prints the manual page and exits.
675
 
676
=item B<-clear>
677
 
678
Delete the B<entire> contents of the dpkg_archive cache. This will occur before
679
any new packages are copied into the cache.
680
 
681
=item B<-flush>
682
 
683
If set then the utility will delete the named packages from the cache. All named
684
packaged will be deleted. This option affects all named packages. It is not
685
possible to flush and copy packages with the same command.
686
 
687
=item B<-[no]refresh>
688
 
689
If the B<refresh> option has been specified then packages will be deleted, from
690
the cache and then a new copy will be copied in. If not specified then no copy
691
will occur if the package is present in the cache.
692
 
693
=item B<-list>
694
 
695
Display a list of all packages in the cache. A formatted display is generated.
696
 
697
This will be done before any packages are transferred.
698
 
699
=item B<-dir>
700
 
701
Display a list of all packages in the cache. This is a raw directory like
702
listing of the cache.
703
 
704
This will be done before any packages are transferred.
705
 
706
=item B<-export>
707
 
708
Generate a space separated list of cached packages as a single line. This is
709
intended to allow a list be exported for later import.
710
 
711
=item B<-refresh_all>
712
 
713
This option will force the program to refresh all the packages in the cache.
714
This forces a B<-refresh> and may be combined with other packages specified
715
on the command line.
716
 
717
=item B<-update_all>
718
 
719
This option will force the program to examine all packages within the cache and
720
refresh packages that are out of date. This option may be combined with other
721
packages specified on the command line.
722
 
723
A package is deemed to be out-of-date if the modification time of the package's
335 dpurdie 724
descpkg file in the cache is older than the one in the archive.
227 dpurdie 725
 
726
=item B<-quiet>
727
 
728
This option will suppress almost all of the progress messages, except for a single
729
copy message. It is intended to be used when the program is called from another
730
script.
731
 
732
=item B<-age=nn>
733
 
734
This option will delete all package versions that are older than the nn days.
735
The age of a package is calculated from the timestamp of the descpkg file.
736
 
361 dpurdie 737
=item B<-test>
738
 
739
This option modifies the operation of the B<-age=nn> option such that it will not
740
delete old package-versions. It will simply report what would be deleted.
741
 
227 dpurdie 742
=back
743
 
744
=head1 DESCRIPTION
745
 
746
This program simplifies the operation of maintaining a local copy of
747
used packages from the maintaining dpkg_archive store. The cache should be
748
stored on your local disk for speed.
749
 
750
The local cache and the master cache are both determined from the environment
751
variable GBE_DPKG.
752
 
753
=head2 Location of the cache
754
 
755
The local cache is located by examining the paths specified in GBE_DPKG. The
756
local cache is taken to be the last directory with the keys string B<_cache> in it.
757
 
758
The local cache cannot be the same as the main cache.
759
 
760
The suggested named for the cache is: F<dpkg_archive_cache>
761
 
762
=head2 Location of the maintaining archive
763
 
764
The main cache is located by examining the paths specified in GBE_DPKG. The
765
main cache is taken to be the last directory with list.
766
 
767
=head2 Interaction with local_dpkg_archive
768
 
769
If a package is located in the users local_dpkg_archive and we are doing a
770
simple cache update then the package will be deleted from the cache. This is
771
done to speed use on slow remote links and ensure cache consistency.
772
 
773
=head1 EXAMPLE
774
 
775
=head2 jats dpkg_cache -list
776
 
777
This will list the current contents of the cache.
778
 
779
=head2 jats dpkg_cache -refresh crc/1.0.4.cr
780
 
781
This will delete any cached copy of the package crc/1.0.4.cr, if one exists,
782
and then copy in a new version.
783
 
784
=head2 jats dpkg_cache crc
785
 
786
This will copy in all versions of the crc package. This may not be desirable.
787
 
788
=head2 jats dpkg_cache -update_all
789
 
790
This will examine all packages in the cache and refresh those packages that are
791
out of date.
792
 
793
=cut
794