Subject: bug#8168: macros directory not created automatically

From: Ralf Wildenhues <[email-masked]>
Date: Fri, 1 Apr 2011 09:45:41 +0200

* Stefano Lattarini wrote on Mon, Mar 14, 2011 at 08:44:03PM CET:
>   <http://lists.gnu.org/archive/html/automake/2011-03/msg00000.html>
>   <http://lists.gnu.org/archive/html/bug-automake/2011-03/msg00004.html>

> Attached is a patch series (2 patches) that should address the issue.
> The series is based off of maint -- as I'm not yet sure whether it
> would be better to merge it to master only, or to maint too.

> Ralf, OK to apply?

I'm debating a couple of questions:

Patch 2:
- Should `--install -I foo/bar/m4' create intermediate directories, or
  would we suspect a typo?
- Should `--install -I $dir' also create an absolute $dir?  Does it with
  your patch?  (I think "no" with both questions, but it would be good
  to be sure.)

Patch 1:
- Should the warning/erroring bits differentiate between relative or
  absolute directory names?  I'm considering to not warn at all about
  absolute names, as we might not have any control over the tree there.
- For a relative directory, a warning seems appropriate; and verb is not
  the right function for that.  The most fitting category would be
  syntax, barring anything better?  (And yes, that means aclocal -Werror
  would then error out, but that could be considered a good thing).
  But it seems 'verb' would be appropriate for absolute directories.

What do you think?

> If yes, where (maint, or master only)?

Hmm, 1/2 can be seen as a bug fix, but I'd regard 2/2 as a new feature.
Maybe base both of them off maint, and merge 1/2 to maint when we're
done with the semantics?

Further, a couple of trivial nits inline.

Thanks,
Ralf

> Subject: [PATCH 1/2] aclocal: `-I' does not bail out on invalid directories.
> 
> Related to automake bug#8168.
> 
> * aclocal.in (scan_m4_dirs): If a user-specified "include
> directory" is unreadable or non-existent, do not issue a
> fatal error anymore, but simply issue a warning, and only
> when running in verbose mode.
> * NEWS: Update.
> * tests/aclocal-bad-dirlist-include-dir.test: New test.
> * tests/aclocal-bad-local-include-dir.test: Likewise.
> * tests/aclocal-bad-system-include-dir.test: Likewise.
> * tests/Makefile.am (TESTS): Update.
> * tests/.gitignore: Update.

> --- a/NEWS
> +++ b/NEWS
> @@ -5,6 +5,11 @@ New in 1.11.0a:
>    - The `lzma' compression scheme and associated automake option `dist-lzma'
>      is obsoleted by `xz' and `dist-xz' due to upstream changes.
>  
> +* Changes to aclocal:
> +
> +  - aclocal does not issue a fatal error anymore if one of the directories
> +    specified with `-I' does not exist, or is not readable.
> +
>  Bugs fixed in 1.11.0a:
>  
>  * Bugs introduced by 1.11:
> diff --git a/aclocal.in b/aclocal.in
> index 2210fe3..3b9beab 100644
> --- a/aclocal.in
> +++ b/aclocal.in
> @@ -312,7 +312,15 @@ sub scan_m4_dirs ($@)
>      {
>        if (! opendir (DIR, $m4dir))
>  	{
> -	  fatal "couldn't open directory `$m4dir': $!";
> +	  if ($type == FT_USER)
> +	    {
> +	      verb "cannot open directory `$m4dir': $!";
> +	      next;
> +	    }
> +	  else
> +	    {
> +	      fatal "couldn't open directory `$m4dir': $!";
> +	    }
>  	}
>  
>        # We reverse the directory contents so that foo2.m4 gets

> --- /dev/null
> +++ b/tests/aclocal-bad-dirlist-include-dir.test

Wouldn't "bad-dirlist-include" be a long-enough and precise-enough name?

> +# Check that `aclocal' errors out when passed a non-readable directory
> +# with the `dirlist' file.
> +
> +. ./defs || Exit 1
> +
> +set -e
> +
> +cat > configure.in <<END
> +AC_INIT([$me], [1.0])
> +END
> +
> +mkdir dirlist-test
> +chmod a-r dirlist-test
> +ls -l disrlist-test && Exit 77

Typo disrlist

> +$ACLOCAL 2>stderr && { cat stderr >&2; Exit 1; }

Please add a comment before this line:
  # See the m4/dirlist file in the source tree.

which I needed to understand why the test was working at all.

> +cat stderr >&2
> +grep " couldn't open directory .*dirlist-test" stderr

> --- /dev/null
> +++ b/tests/aclocal-bad-local-include-dir.test

> +# Check that `aclocal' does not bail out when passed a non-existent
> +# or non-readable directory with the `-I' option.  Also check that
> +# warns appropriately when `--verbose' is used.

The second sentence is missing a subject ('it'?).

> +cat > configure.in <<END
> +AC_INIT([$me], [1.0])
> +MY_MACRO
> +NOT_A_MACRO
> +END
> +
> +mkdir m4
> +cat > m4/my-defs.m4 <<END
> +AC_DEFUN([MY_MACRO], [my--macro--expansion])
> +END
> +
> +mkdir unreadable unopenable unopenable/sub private
> +
> +cat > unreadable/not-defs.m4 <<END
> +AC_DEFUN([NOT_A_MACRO], [invalid--expansion])
> +END
> +cp unreadable/not-defs.m4 unopenable/sub
> +cp unreadable/not-defs.m4 private
> +
> +chmod a-r unreadable
> +chmod a-x unopenable
> +chmod a-rwx private
> +
> +ls -l unreadable && Exit 77
> +ls -l unopenable/sub && Exit 77
> +ls -l private && Exit 77
> +
> +aclocal_call ()
> +{
> +  $ACLOCAL -I m4 \
> +           -I non-existent \
> +           -I "$cwd"/non-existent \
> +           -I unreadable \
> +           -I "$cwd"/unreadable \
> +           -I unopenable/sub \
> +           -I "$cwd"/unopenable/sub \
> +           -I private \
> +           -I "$cwd"/private \
> +           ${1+"$@"} >stdout 2>stderr
> +}
> +
> +cwd=`pwd` || Exit 99
> +
> +aclocal_call && test ! -s stdout && test ! -s stderr \
> +  || { cat stdout; cat stderr >&2; Exit 1; }
> +
> +$EGREP '(MY_MACRO|my-defs\.m4)' aclocal.m4
> +$EGREP '(NOT_A_MACRO|not-defs\.m4)' aclocal.m4 && Exit 1
> +
> +$AUTOCONF
> +
> +$FGREP MY_MACRO configure && Exit 1
> +$FGREP my--macro--expansion configure
> +$FGREP NOT_A_MACRO configure
> +$FGREP invalid--expansion configure && Exit 1
> +
> +aclocal_call --verbose || { cat stdout; cat stderr >&2; Exit 1; }
> +cat stdout
> +cat stderr >&2
> +
> +for d in non-existent unreadable unopenable/sub private; do
> +  grep " cannot open .*$d" stderr
> +  grep " cannot open .*$cwd/$d" stderr
> +done

> --- /dev/null
> +++ b/tests/aclocal-bad-system-include-dir.test

> +# Check that `aclocal' errors out when passed a non-existent or
> +# non-readable directory with the `dirlist' file.

> +cat > configure.in <<END
> +AC_INIT([$me], [1.0])
> +END
> +
> +mkdir fake-acdir
> +chmod a-r fake-acdir
> +ls -l fake-acdir && Exit 77
> +
> +$ACLOCAL --acdir fake-acdir 2>stderr && { cat stderr >&2; Exit 1; }
> +cat stderr >&2
> +grep " couldn't open directory .*fake-acdir" stderr

> Subject: [PATCH 2/2] aclocal: create local directory where to install m4 files

> Before this change, a call like `aclocal -I m4 --install' would
> fail if the `m4' directory wasn't pre-existing.  This could be
> particularly annoying when running in a checked-out version
> from a VCS like git, which doesn't allow empty directories to
> be tracked.
> 
> Closes automake bug#8168.
> 
> * aclocal.in (install_file): Change signature: take as second
> argument the destination directory rather than the destination
> file.  Crate the destination directory if it doesn't already
> exist.  In verbose mode, tell what is being copied where.
> (write_aclocal: Update.
> * NEWS: Update.
> * THANKS: Update.
> * tests/aclocal-install-fail.test: New test.
> * tests/aclocal-install-mkdir.test: Likewise.
> * tests/aclocal-no-install-no-mkdir.test: Likewise.
> * tests/aclocal-verbose-install.test: Likewise.
> * tests/Makefile.am (TESTS): Update.

> --- a/NEWS
> +++ b/NEWS
> @@ -10,6 +10,10 @@ New in 1.11.0a:
>    - aclocal does not issue a fatal error anymore if one of the directories
>      specified with `-I' does not exist, or is not readable.
>  
> +  - If `aclocal --install' is used, and the first directory specified with
> +    `-I' is non-existent, aclocal will now create it before trying to copy
> +    files in it.
> +
>  Bugs fixed in 1.11.0a:
>  
>  * Bugs introduced by 1.11:

> --- a/aclocal.in
> +++ b/aclocal.in
> @@ -207,12 +207,15 @@ sub reset_maps ()
>    undef &search;
>  }
>  
> -# install_file ($SRC, $DEST)
> +# install_file ($SRC, $DESTDIR)
>  sub install_file ($$)
>  {
> -  my ($src, $dest) = @_;
> +  my ($src, $destdir) = @_;
> +  my $dest = $destdir . "/" . basename $src;
>    my $diff_dest;
>  
> +  verb "installing $src to $dest";
> +
>    if ($force_output
>        || !exists $file_contents{$dest}
>        || $file_contents{$src} ne $file_contents{$dest})
> @@ -265,6 +268,8 @@ sub install_file ($$)
>  	}
>        elsif (!$dry_run)
>  	{
> +	  xsystem ('mkdir', $destdir)
> +            unless -d $destdir;

Perl has a mkdir function, there is no need for xsystem.

>  	  xsystem ('cp', $src, $dest);
>  	}
>      }
> @@ -778,9 +783,7 @@ sub write_aclocal ($@)
>  	      my $dest;
>  	      for my $ifile (@{$file_includes{$file}}, $file)
>  		{
> -		  $dest = "$user_includes[0]/" . basename $ifile;
> -		  verb "installing $ifile to $dest";
> -		  install_file ($ifile, $dest);
> +		  install_file ($ifile, $user_includes[0]);
>  		}
>  	      $installed = 1;
>  	    }

> --- /dev/null
> +++ b/tests/aclocal-install-fail.test

> +# Check that `aclocal --install' fails when it should.

This test should use required=ro-dir I think.

> +. ./defs || Exit 1
> +
> +set -e
> +
> +cat > configure.in <<END
> +AC_INIT([$me], [1.0])
> +MY_MACRO
> +END
> +
> +mkdir dirlist-test
> +cat > dirlist-test/my-defs.m4 <<END
> +AC_DEFUN([MY_MACRO], [:])
> +END
> +
> +: > a-regular-file
> +mkdir unwritable-dir
> +chmod a-w unwritable-dir
> +
> +ACLOCAL_TESTSUITE_FLAGS='-I a-regular-file' $ACLOCAL --install 2>stderr \
> +  && { cat stderr >&2; Exit 1; }
> +cat stderr >&2
> +grep 'mkdir:.*a-regular-file' stderr
> +
> +ACLOCAL_TESTSUITE_FLAGS='-I unwritable-dir/sub' $ACLOCAL --install \
> +  2>stderr && { cat stderr >&2; Exit 1; }
> +cat stderr >&2
> +grep 'mkdir:.*unwritable-dir/sub' stderr
> +
> +ACLOCAL_TESTSUITE_FLAGS='-I unwritable-dir' $ACLOCAL --install 2>stderr \
> +  && { cat stderr >&2; Exit 1; }
> +cat stderr >&2
> +grep 'cp:.*unwritable-dir' stderr

> --- /dev/null
> +++ b/tests/aclocal-install-mkdir.test

> +# Check that `aclocal --install' create the local m4 directory if
> +# necessary.
> +
> +. ./defs || Exit 1
> +
> +set -e
> +
> +cat > configure.in <<END
> +AC_INIT([$me], [1.0])
> +MY_MACRO
> +END
> +
> +mkdir dirlist-test
> +cat > dirlist-test/my-defs.m4 <<END
> +AC_DEFUN([MY_MACRO], [:])
> +END
> +
> +ACLOCAL_TESTSUITE_FLAGS='-I foo' $ACLOCAL --install
> +ls -l . foo
> +test -f foo/my-defs.m4
> +
> +cwd=`pwd`
> +case $pwd in
> +  *$sp*|*$tab*)
> +    : cannot run this check
> +    ;;
> +  *)
> +    ACLOCAL_TESTSUITE_FLAGS="-I $cwd/bar" $ACLOCAL --install
> +    ls -l . bar
> +    test -f bar/my-defs.m4
> +    ;;
> +esac
> +
> +mkdir zardoz
> +# What should happen:
> +#  * quux should be created, and required m4 files copied into there.
> +#  * zardoz shouldn't be preferred to quux, if if the former exists while
> +#    the latter does not.
> +#  * blah shouldn't be uselessly created.
> +ACLOCAL_TESTSUITE_FLAGS='-I quux -I zardoz -I blah' $ACLOCAL --install
> +ls -l . quux zardoz
> +grep MY_MACRO quux/my-defs.m4
> +ls zardoz | grep . && Exit 1
> +test -d blah || test -r blah && Exit 1

> --- /dev/null
> +++ b/tests/aclocal-no-install-no-mkdir.test
> @@ -0,0 +1,39 @@

> +# Check that `aclocal' do not create non-existent local m4 directory

s/do/does/
a non-existent

> +# if the `--install' option is not given.
> +
> +. ./defs || Exit 1
> +
> +set -e
> +
> +cat > configure.in <<END
> +AC_INIT([$me], [1.0])
> +MY_MACRO
> +END
> +
> +mkdir dirlist-test
> +cat > dirlist-test/my-defs.m4 <<END
> +AC_DEFUN([MY_MACRO], [:])
> +END
> +
> +# Ignore the exit status of aclocal; that is checked in other tests.

Why?  Can't hurt to also test that it fails, no?

> +ACLOCAL_TESTSUITE_FLAGS='-I foo' $ACLOCAL -I bar || :
> +test ! -d foo && test ! -r foo
> +test ! -d bar && test ! -r bar

> --- /dev/null
> +++ b/tests/aclocal-verbose-install.test

> +# Check verbose messages by `aclocal --install'.
> +
> +. ./defs || Exit 1
> +
> +set -e
> +
> +cat > configure.in <<END
> +AC_INIT([$me], [1.0])
> +MY_MACRO_BAR
> +MY_MACRO_QUUX
> +END
> +
> +mkdir dirlist-test
> +cat > dirlist-test/bar.m4 <<END
> +AC_DEFUN([MY_MACRO_BAR], [:])
> +END
> +cat > dirlist-test/quux.m4 <<END
> +AC_DEFUN([MY_MACRO_QUUX], [:])
> +END
> +
> +mkdir foodir
> +: > foodir/bar.m4
> +
> +ACLOCAL_TESTSUITE_FLAGS='-I foodir' $ACLOCAL --install --verbose 2>stderr \
> + || { cat stderr >&2; Exit 1; }
> +cat stderr >&2
> +grep ' installing .*dirlist-test/bar\.m4.* to .*foodir/bar\.m4' stderr
> +grep ' installing .*dirlist-test/quux\.m4.* to .*foodir/quux\.m4' stderr
> +grep ' overwriting .*foodir/bar\.m4.* with .*dirlist-test/bar\.m4' stderr
> +grep ' installing .*foodir/quux\.m4.* from .*dirlist-test/quux\.m4' stderr
> +
> +# Sanity checks.
> +ls -l foodir
> +grep MY_MACRO_BAR foodir/bar.m4
> +grep MY_MACRO_QUUX foodir/quux.m4