]> git.ipfire.org Git - thirdparty/autoconf.git/commitdiff
Make autoreconf --force --install overwrite existing files (#110371)
authorZack Weinberg <zackw@panix.com>
Mon, 30 Nov 2020 23:06:26 +0000 (18:06 -0500)
committerZack Weinberg <zackw@panix.com>
Mon, 30 Nov 2020 23:06:26 +0000 (18:06 -0500)
The new feature of autoreconf --install installing config.guess,
config.sub, and install-sh itself didn’t implement --force mode
correctly; existing files would not be overwritten.

The fix has two parts.  If --force is in effect, we try to install
everything that we can from the needed-auxfiles list *before* checking
which of them already exist.  But also, we don’t overwrite existing
files unconditionally, even with --force; we only do so if the file we
can install has a newer “timestamp” line than the copy at the
destination.  This is because Automake can also install all of the
files we can install.  Suppose someone is using autoconf 2.70 with a
newly released automake 1.17; automake 1.17 will presumably ship with
a newer config.guess than autoconf 2.70 did; that version should win.

Fixes bug #110371.

* bin/autoreconf.in (extract_time_stamp, our_aux_file_is_newer): New functions.
  (install_aux_file): If the destination exists, and our copy is not
  newer, do not overwrite it.
  (autoreconf_current_directory): When $force is true, attempt to
  install all needed aux files *before* scanning for missing aux files.
  (throughout): Remove extra \n from various error messages.

* tests/torture.at (Missing auxiliary files (--force)): New test.

bin/autoreconf.in
tests/torture.at

index e564d18c75175d3ae4d28a70b0eb521576ae8412..036c0657f4f7534f4082bfe120ef599a41fb292a 100644 (file)
@@ -310,6 +310,37 @@ sub can_install_aux_files
   return 1;
 }
 
+# extract_time_stamp ($fname)
+# ---------------------------
+# Extract a timestamp line from $fname.
+# This is hardwired to know what to look for in the files we currently install.
+sub extract_time_stamp
+{
+  my $fname = shift;
+  open my $fh, '<', $fname
+    or fatal "opening $fname: $!";
+  while (my $l = <$fh>)
+    {
+      if ($l =~ /^(?:scriptversion|timestamp)='?(\d\d\d\d-\d\d-\d\d(?:\.\d\d)?)/)
+        {
+          return $1;
+        }
+    }
+  fatal "no timestamp line found in $fname";
+}
+
+# our_aux_file_is_newer ($dest, $src)
+# -----------------------------------
+# True if our copy of an aux file ($src) has a newer 'timestamp' line
+# than the matching line in $dest.
+sub our_aux_file_is_newer
+{
+  my ($dest, $src) = @_;
+  my $dstamp = extract_time_stamp ($dest);
+  my $sstamp = extract_time_stamp ($src);
+  return $sstamp gt $dstamp;
+}
+
 # try_install_aux_files
 # ---------------------
 # Install each of the aux files listed in @$auxfiles, that we are able
@@ -341,6 +372,11 @@ sub install_aux_file
 {
   my ($destdir, $f, $src) = @_;
   my $dest = "${destdir}/$f";
+  if (-e $dest && ! our_aux_file_is_newer ($dest, $src))
+    {
+      return;
+    }
+
   if ($symlink)
     {
       if ($force || ! -l $dest || readlink $dest != $src)
@@ -348,11 +384,11 @@ sub install_aux_file
           if (-e $dest)
             {
               unlink $dest
-                or fatal "rm -f $dest: $!\n";
+                or fatal "rm -f $dest: $!";
             }
           verb "linking $dest to $src";
           symlink $src, $dest
-            or fatal "ln -s $src $dest: $!\n";
+            or fatal "ln -s $src $dest: $!";
         }
     }
   else
@@ -360,11 +396,11 @@ sub install_aux_file
       if (-e $dest && ! -f $dest)
         {
           unlink $dest
-            or fatal "rm -f $dest: $!\n";
+            or fatal "rm -f $dest: $!";
         }
       my ($temp, $tempname) = tempfile (UNLINK => 0, DIR => $destdir);
       copy ($src, $tempname)
-        or fatal "copying $src to $tempname: $!\n";
+        or fatal "copying $src to $tempname: $!";
       make_executable ($tempname) if -x $src;
       update_file ($tempname, $dest, $force);
     }
@@ -381,7 +417,7 @@ sub make_executable
   $perm |= 0010 if ($perm & 0040);
   $perm |= 0001 if ($perm & 0004);
   chmod $perm, $f
-    or fatal "chmod $f: $!\n";
+    or fatal "chmod $f: $!";
 }
 
 
@@ -772,10 +808,14 @@ sub autoreconf_current_directory ($)
   # ---------------------------------------------------- #
   # Installing aux files and checking for missing ones.  #
   # ---------------------------------------------------- #
+  try_install_aux_files (\@aux_files, $aux_dir || '.')
+    if $install && $force;
+
   my @missing_aux_files = find_missing_aux_files (\@aux_files, $aux_dir);
   if (@missing_aux_files)
     {
-      try_install_aux_files (\@missing_aux_files, $aux_dir || '.') if $install;
+      try_install_aux_files (\@missing_aux_files, $aux_dir || '.')
+        if $install && !$force;
 
       for (0 .. $#missing_aux_files)
         {
index 70763ba12e59ab38f60fa1d0e636b4069b84b96e..dd9eef9c66c8b3326ad5859f5eca532ba1658d2c 100644 (file)
@@ -2117,6 +2117,62 @@ touch build-aux/tap-driver.sh
 AT_CHECK([autoreconf])
 AT_CHECK_CONFIGURE
 
+AT_CLEANUP
+
+
+AT_SETUP([Missing auxiliary files (--force)])
+AT_KEYWORDS([autoreconf])
+
+# Aux files that already exist should not be overwritten, unless
+# --force is used, in which case they *should* be overwritten.
+# Additional wrinkle: in case automake got to the files we install
+# first, we need to *not* overwrite a newer copy supplied by them.
+
+# Prevent autoreconf from running aclocal, which might not exist,
+# or could barf over warnings in third-party macro files.
+AT_DATA([aclocal.m4])
+ACLOCAL=true
+export ACLOCAL
+
+AT_DATA([configure.ac],
+[[AC_INIT([GNU foo], [1.0])
+AC_CONFIG_AUX_DIR([build-aux])
+AC_CANONICAL_HOST
+AC_OUTPUT
+]])
+
+mkdir build-aux
+
+AT_DATA([build-aux/config.guess.old],
+[[#! /bin/sh
+timestamp='1970-01-01'
+printf '%s\n' 'frobozz-bogon-bogos1'
+]])
+
+AT_DATA([build-aux/config.sub.new],
+[[#! /bin/sh
+timestamp='9999-12-31'
+printf '%s\n' "$*"
+]])
+
+cp build-aux/config.guess.old build-aux/config.guess
+cp build-aux/config.sub.new build-aux/config.sub
+chmod +x build-aux/config.sub build-aux/config.guess
+
+# This pass should not change either file.
+AT_CHECK([autoreconf --install])
+AT_CMP([build-aux/config.guess.old], [build-aux/config.guess])
+AT_CMP([build-aux/config.sub.new], [build-aux/config.sub])
+
+# This pass should change only config.guess, not config.sub.
+AT_CHECK([autoreconf --install --force])
+AT_CHECK(
+  [if cmp build-aux/config.guess.old build-aux/config.guess > /dev/null 2>&1
+  then exit 1
+  fi])
+AT_CMP([build-aux/config.sub.new], [build-aux/config.sub])
+
+
 AT_CLEANUP
 
 ## ------------------------------ ##