diff options
author | Zack Weinberg <zackw@panix.com> | 2020-11-30 18:06:26 -0500 |
---|---|---|
committer | Zack Weinberg <zackw@panix.com> | 2020-11-30 18:06:26 -0500 |
commit | 40fa9edce6ad1a05988e4743a7ca64c3a8b3208d (patch) | |
tree | 58eb08c6f9b6f7d7f1823069764414f91d670a1d | |
parent | f44695c56b65e29829da43b594c31c59de5766a6 (diff) | |
download | autoconf-40fa9edce6ad1a05988e4743a7ca64c3a8b3208d.tar.gz |
Make autoreconf --force --install overwrite existing files (#110371)
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.
-rw-r--r-- | bin/autoreconf.in | 52 | ||||
-rw-r--r-- | tests/torture.at | 56 |
2 files changed, 102 insertions, 6 deletions
diff --git a/bin/autoreconf.in b/bin/autoreconf.in index e564d18c..036c0657 100644 --- a/bin/autoreconf.in +++ b/bin/autoreconf.in @@ -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) { diff --git a/tests/torture.at b/tests/torture.at index 70763ba1..dd9eef9c 100644 --- a/tests/torture.at +++ b/tests/torture.at @@ -2119,6 +2119,62 @@ 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 + ## ------------------------------ ## ## Files clobbered by AC_OPENMP. ## ## ------------------------------ ## |