mirror of
https://https.git.savannah.gnu.org/git/gnulib.git
synced 2026-04-28 06:33:36 +00:00
325 lines
12 KiB
Bash
Executable File
325 lines
12 KiB
Bash
Executable File
#! /bin/sh
|
||
#
|
||
# Copyright (C) 2002-2026 Free Software Foundation, Inc.
|
||
#
|
||
# This program is free software: you can redistribute it and/or modify
|
||
# it under the terms of the GNU General Public License as published by
|
||
# the Free Software Foundation, either version 3 of the License, or
|
||
# (at your option) any later version.
|
||
#
|
||
# This program is distributed in the hope that it will be useful,
|
||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
# GNU General Public License for more details.
|
||
#
|
||
# You should have received a copy of the GNU General Public License
|
||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
#
|
||
|
||
# This program dispatches among
|
||
# - the shell implementation and
|
||
# - the Python implementation
|
||
# of gnulib-tool, according to the environment variable GNULIB_TOOL_IMPL.
|
||
|
||
# The environment variable GNULIB_TOOL_IMPL can have four possible values:
|
||
# - GNULIB_TOOL_IMPL=sh chooses the shell implementation.
|
||
# - GNULIB_TOOL_IMPL=py chooses the Python implementation.
|
||
# - GNULIB_TOOL_IMPL= chooses the default (the Python implementation
|
||
# if a suitable Python version is found, the shell
|
||
# implementation otherwise).
|
||
# - GNULIB_TOOL_IMPL=sh+py runs both implementations and compares the
|
||
# results.
|
||
|
||
progname=$0
|
||
|
||
# func_exit STATUS
|
||
# exits with a given status.
|
||
# This function needs to be used, rather than 'exit', when a 'trap' handler is
|
||
# in effect that refers to $?.
|
||
func_exit ()
|
||
{
|
||
(exit $1); exit $1
|
||
}
|
||
|
||
# func_fatal_error message
|
||
# outputs to stderr a fatal error message, and terminates the program.
|
||
# Input:
|
||
# - progname name of this program
|
||
func_fatal_error ()
|
||
{
|
||
echo "$progname: *** $1" 1>&2
|
||
echo "$progname: *** Stop." 1>&2
|
||
func_exit 1
|
||
}
|
||
|
||
# func_readlink SYMLINK
|
||
# outputs the target of the given symlink.
|
||
if (type readlink) > /dev/null 2>&1; then
|
||
func_readlink ()
|
||
{
|
||
# Use the readlink program from GNU coreutils.
|
||
readlink "$1"
|
||
}
|
||
else
|
||
func_readlink ()
|
||
{
|
||
# Use two sed invocations. A single sed -n -e 's,^.* -> \(.*\)$,\1,p'
|
||
# would do the wrong thing if the link target contains " -> ".
|
||
LC_ALL=C ls -l "$1" | sed -e 's, -> ,#%%#,' | sed -n -e 's,^.*#%%#\(.*\)$,\1,p'
|
||
}
|
||
fi
|
||
|
||
# func_gnulib_dir
|
||
# locates the directory where the gnulib repository lives
|
||
# Input:
|
||
# - progname name of this program
|
||
# Sets variables
|
||
# - self_abspathname absolute pathname of gnulib-tool
|
||
# - gnulib_dir absolute pathname of gnulib repository
|
||
func_gnulib_dir ()
|
||
{
|
||
case "$progname" in
|
||
/* | ?:*) self_abspathname="$progname" ;;
|
||
*/*) self_abspathname=`pwd`/"$progname" ;;
|
||
*)
|
||
# Look in $PATH.
|
||
# Iterate through the elements of $PATH.
|
||
# We use IFS=: instead of
|
||
# for d in `echo ":$PATH:" | sed -e 's/:::*/:.:/g' | sed -e 's/:/ /g'`
|
||
# because the latter does not work when some PATH element contains spaces.
|
||
# We use a canonicalized $pathx instead of $PATH, because empty PATH
|
||
# elements are by definition equivalent to '.', however field splitting
|
||
# according to IFS=: loses empty fields in many shells:
|
||
# - /bin/sh on Solaris loses all empty fields (at the beginning, at
|
||
# the end, and in the middle),
|
||
# - GNU bash, /bin/sh on AIX and HP-UX, and /bin/ksh on AIX, HP-UX,
|
||
# Solaris lose empty fields at the end.
|
||
# The 'case' statement is an optimization, to avoid evaluating the
|
||
# explicit canonicalization command when $PATH contains no empty fields.
|
||
self_abspathname=
|
||
if test "$PATH_SEPARATOR" = ";"; then
|
||
# On Windows, programs are searched in "." before $PATH.
|
||
pathx=".;$PATH"
|
||
else
|
||
# On Unix, we have to convert empty PATH elements to ".".
|
||
pathx="$PATH"
|
||
case :$PATH: in
|
||
*::*)
|
||
pathx=`echo ":$PATH:" | sed -e 's/:::*/:.:/g' -e 's/^://' -e 's/:\$//'`
|
||
;;
|
||
esac
|
||
fi
|
||
saved_IFS="$IFS"
|
||
IFS="$PATH_SEPARATOR"
|
||
for d in $pathx; do
|
||
IFS="$saved_IFS"
|
||
test -z "$d" && d=.
|
||
if test -x "$d/$progname" && test ! -d "$d/$progname"; then
|
||
self_abspathname="$d/$progname"
|
||
break
|
||
fi
|
||
done
|
||
IFS="$saved_IFS"
|
||
if test -z "$self_abspathname"; then
|
||
func_fatal_error "could not locate the gnulib-tool program - how did you invoke it?"
|
||
fi
|
||
;;
|
||
esac
|
||
while test -h "$self_abspathname"; do
|
||
# Resolve symbolic link.
|
||
linkval=`func_readlink "$self_abspathname"`
|
||
test -n "$linkval" || break
|
||
case "$linkval" in
|
||
/* | ?:* ) self_abspathname="$linkval" ;;
|
||
* ) self_abspathname=`echo "$self_abspathname" | sed -e 's,/[^/]*$,,'`/"$linkval" ;;
|
||
esac
|
||
done
|
||
gnulib_dir=`echo "$self_abspathname" | sed -e 's,/[^/]*$,,'`
|
||
}
|
||
|
||
# If $progname contains '/' and is not a symlink, it suffices for $prog to be
|
||
# the same as $progname with except with basename 'gnulib-tool’; this
|
||
# speeds startup and might avoid problems in oddball development environments.
|
||
# Otherwise, $prog is the absolute name of the gnulib-tool executable.
|
||
if case $progname in
|
||
*/*) test -h "$0" ;;
|
||
esac
|
||
then
|
||
func_gnulib_dir
|
||
prog=$gnulib_dir/gnulib-tool
|
||
else
|
||
prog=${progname%/*}/gnulib-tool
|
||
fi
|
||
|
||
case "$GNULIB_TOOL_IMPL" in
|
||
'')
|
||
# Use the Python implementation if a suitable Python version is found
|
||
# in $PATH. This is the same Python version test as in gnulib-tool.py.
|
||
if (python3 -c 'import sys; sys.exit(not sys.version_info >= (3,7))') 2>/dev/null; then
|
||
exec "$prog.py" "$@"
|
||
else
|
||
echo "gnulib-tool: warning: python3 not found or too old, using the slow shell-based implementation" 1>&2
|
||
exec "$prog.sh" "$@"
|
||
fi
|
||
;;
|
||
sh)
|
||
exec "$prog.sh" "$@" ;;
|
||
py)
|
||
exec "$prog.py" "$@" ;;
|
||
sh+py)
|
||
case " $* " in
|
||
*" --import"* | *" --add-import"* | *" --remove-import"* | *" --update"* | *" --copy-file"*)
|
||
# A gnulib-tool invocation that produces files in the current directory.
|
||
# Create a temporary directory in the parent directory.
|
||
tmpdir=`cd .. && pwd`
|
||
{
|
||
# Use the mktemp program if available. If not available, hide the error
|
||
# message.
|
||
tmp=`(umask 077 && mktemp -d "$tmpdir/glpyXXXXXX") 2>/dev/null` &&
|
||
test -n "$tmp" && test -d "$tmp"
|
||
} ||
|
||
{
|
||
# Use a simple mkdir command. It is guaranteed to fail if the directory
|
||
# already exists.
|
||
tmp=$tmpdir/glpy$$
|
||
(umask 077 && mkdir "$tmp")
|
||
} ||
|
||
{
|
||
echo "$progname: cannot create a temporary directory in $tmpdir" >&2
|
||
func_exit 1
|
||
}
|
||
# Copy the current directory into the the temporary directory.
|
||
{ tar cf - . | (cd "$tmp" && tar xf -); } ||
|
||
{
|
||
echo "$progname: failed to clone the current directory" >&2
|
||
func_exit 1
|
||
}
|
||
# Execute gnulib-tool.py in the clone directory.
|
||
case $prog in
|
||
/*) absprog=$prog ;;
|
||
*) absprog=$PWD/prog ;;
|
||
esac
|
||
(cd "$tmp" && "$absprog.py" "$@" >"$tmp-py-out" 2>"$tmp-py-err")
|
||
pyrc=$?
|
||
# Execute gnulib-tool.sh in the current directory.
|
||
"$prog.sh" "$@" >"$tmp-sh-out" 2>"$tmp-sh-err"
|
||
shrc=$?
|
||
if test $shrc != 0; then
|
||
if test $pyrc = 0; then
|
||
func_fatal_error "gnulib-tool.sh failed but gnulib-tool.py succeeded! Inspect $tmp-sh-err and $tmp-py-err."
|
||
else
|
||
cat "$tmp-sh-out"
|
||
cat "$tmp-sh-err" >&2
|
||
rm -rf "$tmp" "$tmp-sh-out" "$tmp-sh-err" "$tmp-py-out" "$tmp-py-err"
|
||
exit $shrc
|
||
fi
|
||
fi
|
||
if test $pyrc != 0; then
|
||
func_fatal_error "gnulib-tool.sh succeeded but gnulib-tool.py failed! Inspect $tmp/ and $tmp-py-err."
|
||
fi
|
||
# Compare the two results on the file system.
|
||
# GNU diffutils 3.3 or newer support option --no-dereference. This
|
||
# option avoids errors on dangling links.
|
||
if LC_ALL=C diff --help 2>/dev/null | grep no-dereference >/dev/null; then
|
||
diff_options='--no-dereference'
|
||
else
|
||
diff_options=
|
||
fi
|
||
diff -r $diff_options --exclude=__pycache__ --exclude=autom4te.cache -q . "$tmp" >/dev/null ||
|
||
func_fatal_error "gnulib-tool.py produced different files than gnulib-tool.sh! Compare `pwd` and $tmp."
|
||
# Compare the two outputs.
|
||
diff -q "$tmp-sh-out" "$tmp-py-out" >/dev/null ||
|
||
func_fatal_error "gnulib-tool.py produced different output than gnulib-tool.sh! Compare $tmp-sh-out and $tmp-py-out."
|
||
# Same results.
|
||
cat "$tmp-sh-out"
|
||
cat "$tmp-sh-err" >&2
|
||
rm -rf "$tmp" "$tmp-sh-out" "$tmp-sh-err" "$tmp-py-out" "$tmp-py-err"
|
||
exit 0
|
||
;;
|
||
*" --create-testdir"* | *" --create-megatestdir"*)
|
||
# A gnulib-tool invocation that produces a new directory with files.
|
||
# Extract the --dir value.
|
||
dir=`echo " $* " | sed -n -e 's/^.* --dir=//p' | sed -e 's/ .*//'`
|
||
if test -z "$dir"; then
|
||
dir=`echo " $* " | sed -n -e 's/^.* --dir *//p' | sed -e 's/ .*//'`
|
||
if test -z "$dir"; then
|
||
func_fatal_error "could not extract --dir value"
|
||
fi
|
||
fi
|
||
# Find another directory name.
|
||
tmp="$dir-glpy$$"
|
||
# Execute gnulib-tool.py, creating a different directory.
|
||
"$prog.py" "$@" --dir="$tmp" >"$tmp-py-out" 2>"$tmp-py-err"
|
||
pyrc=$?
|
||
# Execute gnulib-tool.sh, creating the intended directory.
|
||
"$prog.sh" "$@" >"$tmp-sh-out" 2>"$tmp-sh-err"
|
||
shrc=$?
|
||
if test $shrc != 0; then
|
||
if test $pyrc = 0; then
|
||
func_fatal_error "gnulib-tool.sh failed but gnulib-tool.py succeeded! Inspect $tmp-sh-err and $tmp-py-err."
|
||
else
|
||
cat "$tmp-sh-out"
|
||
cat "$tmp-sh-err" >&2
|
||
rm -rf "$tmp" "$tmp-sh-out" "$tmp-sh-err" "$tmp-py-out" "$tmp-py-err"
|
||
exit $shrc
|
||
fi
|
||
fi
|
||
if test $pyrc != 0; then
|
||
func_fatal_error "gnulib-tool.sh succeeded but gnulib-tool.py failed! Inspect $tmp/ and $tmp-py-err."
|
||
fi
|
||
# Compare the two results on the file system.
|
||
# GNU diffutils 3.3 or newer support option --no-dereference. This
|
||
# option avoids errors on dangling links.
|
||
if LC_ALL=C diff --help 2>/dev/null | grep no-dereference >/dev/null; then
|
||
diff_options='--no-dereference'
|
||
else
|
||
diff_options=
|
||
fi
|
||
diff -r $diff_options -q "$dir" "$tmp" >/dev/null ||
|
||
func_fatal_error "gnulib-tool.py produced different files than gnulib-tool.sh! Compare $dir and $tmp."
|
||
# Compare the two outputs.
|
||
diff -q "$tmp-sh-out" "$tmp-py-out" >/dev/null ||
|
||
func_fatal_error "gnulib-tool.py produced different output than gnulib-tool.sh! Compare $tmp-sh-out and $tmp-py-out."
|
||
# Same results.
|
||
cat "$tmp-sh-out"
|
||
cat "$tmp-sh-err" >&2
|
||
rm -rf "$tmp" "$tmp-sh-out" "$tmp-sh-err" "$tmp-py-out" "$tmp-py-err"
|
||
exit 0
|
||
;;
|
||
*)
|
||
# A gnulib-tool invocation that produces only output, no files.
|
||
tmp="glpy$$"
|
||
# Execute gnulib-tool.py.
|
||
"$prog.py" "$@" >"$tmp-py-out" 2>"$tmp-py-err"
|
||
pyrc=$?
|
||
# Execute gnulib-tool.sh.
|
||
"$prog.sh" "$@" >"$tmp-sh-out" 2>"$tmp-sh-err"
|
||
shrc=$?
|
||
if test $shrc != 0; then
|
||
if test $pyrc = 0; then
|
||
func_fatal_error "gnulib-tool.sh failed but gnulib-tool.py succeeded! Inspect $tmp-sh-err and $tmp-py-err."
|
||
else
|
||
cat "$tmp-sh-out"
|
||
cat "$tmp-sh-err" >&2
|
||
rm -rf "$tmp-sh-out" "$tmp-sh-err" "$tmp-py-out" "$tmp-py-err"
|
||
exit $shrc
|
||
fi
|
||
fi
|
||
if test $pyrc != 0; then
|
||
func_fatal_error "gnulib-tool.sh succeeded but gnulib-tool.py failed! Inspect $tmp-py-err."
|
||
fi
|
||
# Compare the two outputs.
|
||
diff -q "$tmp-sh-out" "$tmp-py-out" >/dev/null ||
|
||
func_fatal_error "gnulib-tool.py produced different output than gnulib-tool.sh! Compare $tmp-sh-out and $tmp-py-out."
|
||
# Same results.
|
||
cat "$tmp-sh-out"
|
||
cat "$tmp-sh-err" >&2
|
||
rm -rf "$tmp-sh-out" "$tmp-sh-err" "$tmp-py-out" "$tmp-py-err"
|
||
exit 0
|
||
;;
|
||
esac
|
||
;;
|
||
*)
|
||
func_fatal_error "invalid value of GNULIB_TOOL_IMPL: $GNULIB_TOOL_IMPL" ;;
|
||
esac
|