--- ./lib/CPAN.pm-pre	Thu Jul 31 13:56:22 2003
+++ ./lib/CPAN.pm	Sun Sep 21 19:46:24 2003
@@ -259,7 +259,7 @@ package CPAN::Complete;
 ) unless @CPAN::Complete::COMMANDS;
 
 package CPAN::Index;
-use vars qw($LAST_TIME $DATE_OF_02 $DATE_OF_03);
+use vars qw($LAST_TIME $DATE_OF_02 $DATE_OF_03 $BUILD_DIRS);
 @CPAN::Index::ISA = qw(CPAN::Debug);
 $LAST_TIME ||= 0;
 $DATE_OF_03 ||= 0;
@@ -807,6 +807,10 @@ sub cleanup {
 	  $subroutine eq '(eval)';
   }
   return if $ineval && !$End;
+  if ($CPAN::Index::BUILD_DIRS and $CPAN::Index::BUILD_DIRS->{'*new*'}) {
+    CPAN::Index->write_metadata_cache();
+    $CPAN::Frontend->mywarn("List of tested dirs updated.\n");
+  }
   return unless defined $META->{LOCK};
   return unless -f $META->{LOCK};
   $META->savehist;
@@ -842,8 +846,9 @@ sub savehist {
     close $fh;
 }
 
+# Actually, this means: tested, but not installed...
 sub is_tested {
-    my($self,$what) = @_;
+    my($self,$what,) = @_;
     $self->{is_tested}{$what} = 1;
 }
 
@@ -860,8 +865,14 @@ sub set_perl5lib {
     $env = $ENV{PERLLIB} unless defined $env;
     my @env;
     push @env, $env if defined $env and length $env;
-    my @dirs = map {("$_/blib/arch", "$_/blib/lib")} keys %{$self->{is_tested}};
-    $CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
+    my @dirs = map {("$_/blib/arch", "$_/blib/lib")} sort keys %{$self->{is_tested}};
+    if (@dirs < 15) {
+       $CPAN::Frontend->myprint("Prepending @dirs to PERL5LIB.\n");
+    } else {
+       my @d = map {s/^\Q$CPAN::Config->{'build_dir'}/%BUILDDIR%/; $_ }
+	 sort keys %{$self->{is_tested}};
+       $CPAN::Frontend->myprint("Prepending blib/arch and blib/lib subdirs of @d to PERL5LIB; %BUILDDIR%=$CPAN::Config->{'build_dir'}.\n");
+    }
     $ENV{PERL5LIB} = join $Config::Config{path_sep}, @dirs, @env;
 }
 
@@ -1285,7 +1296,7 @@ sub missing_config_data {
          "pager",
          "makepl_arg", "make_arg", "make_install_arg", "urllist",
          "inhibit_startup_message", "ftp_proxy", "http_proxy", "no_proxy",
-         "prerequisites_policy",
+         "prerequisites_policy", "expire_old_builds",
          "cache_metadata",
         ) {
 	push @miss, $_ unless defined $CPAN::Config->{$_};
@@ -1493,13 +1504,14 @@ sub o {
 	    $CPAN::Frontend->myprint(":\n");
 	    for $k (sort keys %CPAN::Config::can) {
 		$v = $CPAN::Config::can{$k};
-		$CPAN::Frontend->myprint(sprintf "    %-18s %s\n", $k, $v);
+		# use distinctive whitespace to make the commands stand out
+		$CPAN::Frontend->myprint(sprintf "      %-10s %s\n", $k, $v);
 	    }
 	    $CPAN::Frontend->myprint("\n");
 	    for $k (sort keys %$CPAN::Config) {
                 CPAN::Config->prettyprint($k);
 	    }
-	    $CPAN::Frontend->myprint("\n");
+	    # $CPAN::Frontend->myprint("\n");	# Why second empty line?
 	} elsif (!CPAN::Config->edit(@o_what)) {
 	    $CPAN::Frontend->myprint(qq{Type 'o conf' to view configuration }.
                                      qq{edit options\n\n});
@@ -3411,6 +3423,11 @@ sub write_metadata_cache {
     $cache->{last_time} = $LAST_TIME;
     $cache->{DATE_OF_02} = $DATE_OF_02;
     $cache->{PROTOCOL} = PROTOCOL;
+    if ($BUILD_DIRS) {
+	$cache->{'CPAN-sitearchexp'} = $Config::Config{sitearchexp};
+	delete $CPAN::Index::BUILD_DIRS->{'*new*'};
+        $cache->{'CPAN-tested-dirs'} = $BUILD_DIRS;
+    }
     $CPAN::Frontend->myprint("Going to write $metadata_file\n");
     eval { Storable::nstore($cache, $metadata_file) };
     $CPAN::Frontend->mywarn($@) if $@; # ?? missing "\n" after $@ in mywarn ??
@@ -3471,6 +3488,12 @@ sub read_metadata_cache {
                             # does initialize to some protocol
     $LAST_TIME = $cache->{last_time};
     $DATE_OF_02 = $cache->{DATE_OF_02};
+    # Do not trust build directories of different version of Perl:
+    delete $cache->{'CPAN-tested-dirs'}
+	if exists $cache->{'CPAN-sitearchexp'}
+	    and $cache->{'CPAN-sitearchexp'} ne $Config::Config{sitearchexp};
+    $BUILD_DIRS = $cache->{'CPAN-tested-dirs'}
+	if exists $cache->{'CPAN-tested-dirs'};
     $CPAN::Frontend->myprint("  Database was generated on $DATE_OF_02\n")
 	if defined $DATE_OF_02; # An old cache may not contain DATE_OF_02
     return;
@@ -4486,6 +4509,8 @@ or
 #	$switch = "-MExtUtils::MakeMaker ".
 #	    "-Mops=:default,:filesys_read,:filesys_open,require,chdir"
 #	    if $] > 5.00310;
+	local $ENV{PERL5LIB} = $ENV{PERL5LIB} || $ENV{PERLLIB} || "";
+	$CPAN::META->set_perl5lib;
 	$system = "$perl $switch Makefile.PL $CPAN::Config->{makepl_arg}";
     }
     unless (exists $self->{writemakefile}) {
@@ -4547,6 +4572,8 @@ or
       return 1 if $self->follow_prereqs(@prereq); # signal success to the queuerunner
     }
     $system = join " ", $CPAN::Config->{'make'}, $CPAN::Config->{make_arg};
+    local $ENV{PERL5LIB} = $ENV{PERL5LIB} || $ENV{PERLLIB} || "";
+    $CPAN::META->set_perl5lib;
     if (system($system) == 0) {
 	 $CPAN::Frontend->myprint("  $system -- OK\n");
 	 $self->{'make'} = "YES";
@@ -4682,9 +4709,65 @@ sub prereq_pm {
   return $self->{prereq_pm} = \%p;
 }
 
+#-> sub CPAN::Distribution::tested_ok ;
+sub tested_ok {
+  my($self) = @_;
+  return unless $CPAN::Index::BUILD_DIRS and $CPAN::Config->{expire_old_builds};
+  my $dir = $CPAN::Index::BUILD_DIRS->{$self->id};
+  return unless $dir and -d $dir;
+  my $cpan_test_ok = File::Spec->catfile($dir, '.cpantok');
+  return unless -f $cpan_test_ok;
+  return if $CPAN::Config->{expire_old_builds} > 0
+	    and -M $cpan_test_ok > $CPAN::Config->{expire_old_builds};
+  local *T;
+  open T, $cpan_test_ok and <T> eq "$Config::Config{sitearchexp}\n" and close T
+    or return;
+  my $date = -M $cpan_test_ok;
+  eval { File::Find::find sub {
+	  -M $_ >= $date
+	    or warn("File `$File::Find::name' newer than $cpan_test_ok: "
+		    . (-M _) . " days vs. $date days\n"),
+	       die 'update'
+	}, $dir ; 1} and return $dir;
+  warn "error scanning $dir: $@" unless $@ =~ /^update\b/;
+  return;
+}
+
+#-> sub CPAN::Distribution::mark_tested_ok ;
+sub mark_tested_ok {
+  my($self) = @_;
+  my $dir = $self->{build_dir};
+  return unless -d $dir;
+  my $cpan_test_ok = File::Spec->catfile($dir, '.cpantok');
+  local *T;
+  open T, "> $cpan_test_ok" or warn("error touching $cpan_test_ok: $!\n"), return;
+  # Something very build-specific
+  print T "$Config::Config{sitearchexp}\n";
+  close T or warn("error touching $cpan_test_ok: $!\n"), return;
+  $CPAN::Index::BUILD_DIRS ||= {};
+  $CPAN::Index::BUILD_DIRS->{'*new*'} ||= 0;
+  $CPAN::Index::BUILD_DIRS->{'*new*'}++
+    unless exists $CPAN::Index::BUILD_DIRS->{$self->id}
+      and $CPAN::Index::BUILD_DIRS->{$self->id} eq $dir;
+  $CPAN::Index::BUILD_DIRS->{$self->id} = $dir;
+  return 1;
+}
+
 #-> sub CPAN::Distribution::test ;
 sub test {
     my($self) = @_;
+    my $tested_dir = $self->tested_ok;
+    if ($tested_dir) {
+	 $self->{'build_dir'} = $tested_dir;
+	 $CPAN::Frontend->myprint("Skipping test for " . $self->id . ": test was successful in $tested_dir\n");
+	 $CPAN::META->is_tested($self->{'build_dir'});
+	 $self->{make_test} = "YES";
+	 chdir $self->{'build_dir'} or
+	    Carp::croak("Couldn't chdir to $self->{'build_dir'}");
+	 $self->debug("Changed directory to $self->{'build_dir'}")
+	    if $CPAN::DEBUG;
+	 return;
+    }
     $self->make;
     if ($CPAN::Signal){
       delete $self->{force_update};
@@ -4723,13 +4806,14 @@ sub test {
         return;
     }
 
-    local $ENV{PERL5LIB} = $ENV{PERL5LIB} || "";
+    local $ENV{PERL5LIB} = $ENV{PERL5LIB} || $ENV{PERLLIB} || "";
     $CPAN::META->set_perl5lib;
     my $system = join " ", $CPAN::Config->{'make'}, "test";
     if (system($system) == 0) {
 	 $CPAN::Frontend->myprint("  $system -- OK\n");
 	 $CPAN::META->is_tested($self->{'build_dir'});
 	 $self->{make_test} = "YES";
+	 $self->mark_tested_ok();
     } else {
 	 $self->{make_test} = "NO";
          $self->{badtestcnt}++;
@@ -6751,6 +6835,9 @@ defined:
   cpan_home          local directory reserved for this package
   dontload_hash      anonymous hash: modules in the keys will not be
                      loaded by the CPAN::has_inst() routine
+  expire_old_builds  Timeout in days; after this time the module is rebuild
+		     even if it was successfully build, and the build directory
+		     is still present.  -1 means 'never rebuild'.
   gzip		     location of external program gzip
   histfile           file to maintain history between sessions
   histsize           maximum number of lines to keep in histfile
--- ./lib/CPAN/FirstTime.pm-pre	Tue Jul 29 09:48:00 2003
+++ ./lib/CPAN/FirstTime.pm	Thu Sep 18 01:26:24 2003
@@ -384,6 +384,19 @@ Typical frequently used setting:
 Your choice: ",$default);
 
     #
+    # Should we trust old builds?
+    #
+
+    $default = exists $CPAN::Config->{expire_old_builds} ?
+		exists $CPAN::Config->{expire_old_builds} : -1 ;
+    $CPAN::Config->{expire_old_builds} =
+	prompt("When should we expire old successfully tested builds?
+The value is in days; the value of -1 means 'never rebuild'; the value of 0
+means 'rebuild each time the distribution is tested'.
+
+Your choice: ",$default);
+
+    #
     # Alarm period
     #
 
