# - Autoconf
# - Automake >= 1.13
# - Wget
-# - Git
# - XZ Utils
-#
-# By default, it fetches Gnulib as a git submodule. If you already
-# have a local copy of Gnulib, you can avoid extra network traffic by
-# setting the GNULIB_SRCDIR environment variable pointing to the path.
+# If not used from a released tarball, it also requires either
+# - the GNULIB_SRCDIR environment variable pointing to a gnulib checkout, or
+# - a preceding invocation of './gitsub.sh pull'.
#
# In addition, it fetches the archive.dir.tar.gz file, which contains
# data files used by the autopoint program. If you already have the
# file, place it under gettext-tools/misc, before running this script.
#
-# Usage: ./autogen.sh [--skip-gnulib] [--no-git]
-#
-# Usage after a git clone: ./autogen.sh
-# Usage from a released tarball: ./autogen.sh --skip-gnulib
-# This does not use a gnulib checkout.
+# Usage: ./autogen.sh [--skip-gnulib]
# Nuisances.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
skip_gnulib=false
-# Use git to update gnulib sources
-use_git=true
-
while :; do
case "$1" in
--skip-gnulib) skip_gnulib=true; shift;;
- --no-git) use_git=false; shift;;
*) break ;;
esac
done
-if ! $use_git && ! test -d "$GNULIB_SRCDIR"; then
- echo "error: --no-git requires GNULIB_SRCDIR to be set" 1>&2
- exit 1
-fi
-
-cleanup_gnulib() {
- status=$?
- rm -fr "$gnulib_path"
- exit $status
-}
-
-git_modules_config () {
- test -f .gitmodules && git config --file .gitmodules "$@"
-}
-
-gnulib_path=$(git_modules_config submodule.gnulib.path)
-test -z "$gnulib_path" && gnulib_path=gnulib
-
# The tests in gettext-tools/tests are not meant to be executable, because
# they have a TESTS_ENVIRONMENT that specifies the shell explicitly.
if ! $skip_gnulib; then
- # Get gnulib files.
- case ${GNULIB_SRCDIR--} in
- -)
- if git_modules_config submodule.gnulib.url >/dev/null; then
- echo "$0: getting gnulib files..."
- git submodule init || exit $?
- git submodule update || exit $?
-
- elif [ ! -d "$gnulib_path" ]; then
- echo "$0: getting gnulib files..."
-
- trap cleanup_gnulib 1 2 13 15
-
- shallow=
- git clone -h 2>&1 | grep -- --depth > /dev/null && shallow='--depth 2'
- git clone $shallow git://git.sv.gnu.org/gnulib "$gnulib_path" ||
- cleanup_gnulib
-
- trap - 1 2 13 15
- fi
- GNULIB_SRCDIR=$gnulib_path
- ;;
- *)
- # Use GNULIB_SRCDIR as a reference.
- if $use_git && test -d "$GNULIB_SRCDIR"/.git && \
- git_modules_config submodule.gnulib.url >/dev/null; then
- echo "$0: getting gnulib files..."
- if git submodule -h | grep -- --reference > /dev/null; then
- # Prefer the one-liner available in git 1.6.4 or newer.
- git submodule update --init --reference "$GNULIB_SRCDIR" \
- "$gnulib_path" || exit $?
- else
- # This fallback allows at least git 1.5.5.
- if test -f "$gnulib_path"/gnulib-tool; then
- # Since file already exists, assume submodule init already complete.
- git submodule update || exit $?
- else
- # Older git can't clone into an empty directory.
- rmdir "$gnulib_path" 2>/dev/null
- git clone --reference "$GNULIB_SRCDIR" \
- "$(git_modules_config submodule.gnulib.url)" "$gnulib_path" \
- && git submodule init && git submodule update \
- || exit $?
- fi
- fi
- GNULIB_SRCDIR=$gnulib_path
- fi
- ;;
- esac
- # Now it should contain a gnulib-tool.
- if test -f "$GNULIB_SRCDIR"/gnulib-tool; then
- GNULIB_TOOL="$GNULIB_SRCDIR"/gnulib-tool
+ if test -n "$GNULIB_SRCDIR"; then
+ test -d "$GNULIB_SRCDIR" || {
+ echo "*** GNULIB_SRCDIR is set but does not point to an existing directory." 1>&2
+ exit 1
+ }
else
- echo "** warning: gnulib-tool not found" 1>&2
- fi
- # Skip the gnulib-tool step if gnulib-tool was not found.
- if test -n "$GNULIB_TOOL"; then
- # In gettext-runtime:
- GNULIB_MODULES_RUNTIME_FOR_SRC='
- atexit
- basename
- binary-io
- closeout
- error
- getopt-gnu
- gettext-h
- havelib
- memmove
- progname
- propername
- relocatable-prog
- setlocale
- sigpipe
- stdbool
- stdio
- stdlib
- strtoul
- unistd
- unlocked-io
- xalloc
- '
- GNULIB_MODULES_RUNTIME_OTHER='
- gettext-runtime-misc
- ansi-c++-opt
- csharpcomp-script
- java
- javacomp-script
- '
- $GNULIB_TOOL --dir=gettext-runtime --lib=libgrt --source-base=gnulib-lib --m4-base=gnulib-m4 --no-libtool --local-dir=gnulib-local --local-symlink \
- --import $GNULIB_MODULES_RUNTIME_FOR_SRC $GNULIB_MODULES_RUNTIME_OTHER || exit $?
- # In gettext-runtime/libasprintf:
- GNULIB_MODULES_LIBASPRINTF='
- alloca
- errno
- verify
- xsize
- '
- GNULIB_MODULES_LIBASPRINTF_OTHER='
- '
- $GNULIB_TOOL --dir=gettext-runtime/libasprintf --source-base=. --m4-base=gnulib-m4 --lgpl=2 --makefile-name=Makefile.gnulib --libtool --local-dir=gnulib-local --local-symlink \
- --import $GNULIB_MODULES_LIBASPRINTF $GNULIB_MODULES_LIBASPRINTF_OTHER || exit $?
- $GNULIB_TOOL --copy-file m4/intmax_t.m4 gettext-runtime/libasprintf/gnulib-m4/intmax_t.m4 || exit $?
- $GNULIB_TOOL --copy-file m4/wchar_t.m4 gettext-runtime/libasprintf/gnulib-m4/wchar_t.m4 || exit $?
- $GNULIB_TOOL --copy-file m4/wint_t.m4 gettext-runtime/libasprintf/gnulib-m4/wint_t.m4 || exit $?
- # In gettext-tools:
- GNULIB_MODULES_TOOLS_FOR_SRC='
- alloca-opt
- atexit
- backupfile
- basename
- binary-io
- bison-i18n
- byteswap
- c-ctype
- c-strcase
- c-strcasestr
- c-strstr
- clean-temp
- closedir
- closeout
- copy-file
- csharpcomp
- csharpexec
- error
- error-progname
- execute
- fd-ostream
- file-ostream
- filename
- findprog
- fnmatch
- fopen
- fstrcmp
- full-write
- fwriteerror
- gcd
- getline
- getopt-gnu
- gettext
- gettext-h
- hash
- html-styled-ostream
- iconv
- javacomp
- javaexec
- libunistring-optional
- localcharset
- locale
- localename
- lock
- memchr
- memmove
- memset
- minmax
- mkdir
- obstack
- open
- opendir
- openmp
- ostream
- pipe-filter-ii
- progname
- propername
- read-file
- readdir
- relocatable-prog
- relocatable-script
- setlocale
- sh-quote
- sigpipe
- sigprocmask
- spawn-pipe
- stdbool
- stdio
- stdlib
- stpcpy
- stpncpy
- strchrnul
- strcspn
- strerror
- strpbrk
- strtol
- strtoul
- styled-ostream
- sys_select
- sys_stat
- sys_time
- term-styled-ostream
- trim
- unictype/ctype-space
- unilbrk/ulc-width-linebreaks
- uniname/uniname
- unistd
- unistr/u8-check
- unistr/u8-mbtouc
- unistr/u8-mbtoucr
- unistr/u8-uctomb
- unistr/u16-mbtouc
- uniwidth/width
- unlocked-io
- vasprintf
- wait-process
- write
- xalloc
- xconcat-filename
- xerror
- xmalloca
- xmemdup0
- xsetenv
- xstriconv
- xstriconveh
- xvasprintf
- '
- # Common dependencies of GNULIB_MODULES_TOOLS_FOR_SRC and GNULIB_MODULES_TOOLS_FOR_LIBGREP.
- GNULIB_MODULES_TOOLS_FOR_SRC_COMMON_DEPENDENCIES='
- alloca-opt
- extensions
- gettext-h
- include_next
- locale
- localcharset
- malloc-posix
- mbrtowc
- mbsinit
- multiarch
- snippet/arg-nonnull
- snippet/c++defs
- snippet/warn-on-use
- ssize_t
- stdbool
- stddef
- stdint
- stdlib
- streq
- unistd
- verify
- wchar
- wctype-h
- '
- GNULIB_MODULES_TOOLS_OTHER='
- gettext-tools-misc
- ansi-c++-opt
- csharpcomp-script
- csharpexec-script
- java
- javacomp-script
- javaexec-script
- stdint
- '
- GNULIB_MODULES_TOOLS_LIBUNISTRING_TESTS='
- unilbrk/u8-possible-linebreaks-tests
- unilbrk/ulc-width-linebreaks-tests
- unistr/u8-mbtouc-tests
- unistr/u8-mbtouc-unsafe-tests
- uniwidth/width-tests
- '
- $GNULIB_TOOL --dir=gettext-tools --lib=libgettextlib --source-base=gnulib-lib --m4-base=gnulib-m4 --tests-base=gnulib-tests --makefile-name=Makefile.gnulib --libtool --with-tests --local-dir=gnulib-local --local-symlink \
- --import --avoid=hash-tests --avoid=fdutimensat-tests --avoid=futimens-tests --avoid=utime-tests --avoid=utimens-tests --avoid=utimensat-tests \
- `for m in $GNULIB_MODULES_TOOLS_LIBUNISTRING_TESTS; do echo --avoid=$m; done` $GNULIB_MODULES_TOOLS_FOR_SRC $GNULIB_MODULES_TOOLS_FOR_SRC_COMMON_DEPENDENCIES $GNULIB_MODULES_TOOLS_OTHER || exit $?
- # In gettext-tools/libgrep:
- GNULIB_MODULES_TOOLS_FOR_LIBGREP='
- mbrlen
- regex
- '
- $GNULIB_TOOL --dir=gettext-tools --macro-prefix=grgl --lib=libgrep --source-base=libgrep --m4-base=libgrep/gnulib-m4 --witness-c-macro=IN_GETTEXT_TOOLS_LIBGREP --makefile-name=Makefile.gnulib --local-dir=gnulib-local --local-symlink \
- --import `for m in $GNULIB_MODULES_TOOLS_FOR_SRC_COMMON_DEPENDENCIES; do if test \`$GNULIB_TOOL --extract-applicability $m\` != all; then echo --avoid=$m; fi; done` $GNULIB_MODULES_TOOLS_FOR_LIBGREP || exit $?
- # In gettext-tools/libgettextpo:
- # This is a subset of the GNULIB_MODULES_FOR_SRC.
- GNULIB_MODULES_LIBGETTEXTPO='
- basename
- close
- c-ctype
- c-strcase
- c-strstr
- error
- error-progname
- file-ostream
- filename
- fopen
- fstrcmp
- fwriteerror
- gcd
- getline
- gettext-h
- hash
- iconv
- libunistring-optional
- markup
- minmax
- open
- ostream
- progname
- relocatable-lib
- sigpipe
- stdbool
- stdio
- stdlib
- stpcpy
- stpncpy
- strchrnul
- strerror
- unictype/ctype-space
- unilbrk/ulc-width-linebreaks
- unistr/u8-mbtouc
- unistr/u8-mbtoucr
- unistr/u8-uctomb
- unistr/u16-mbtouc
- uniwidth/width
- unlocked-io
- vasprintf
- xalloc
- xconcat-filename
- xmalloca
- xerror
- xstriconv
- xvasprintf
- '
- # Module 'realloc-posix' is enabled in gettext-tools/config.status, because
- # it occurs as dependency of some module ('read-file') in
- # GNULIB_MODULES_TOOLS_FOR_SRC. Therefore on mingw, libgettextpo/stdlib.h
- # contains '#define realloc rpl_realloc'. Therefore we need to include
- # realloc.lo in libgettextpo.la.
- GNULIB_MODULES_LIBGETTEXTPO_OTHER='
- realloc-posix
- '
- $GNULIB_TOOL --dir=gettext-tools --source-base=libgettextpo --m4-base=libgettextpo/gnulib-m4 --macro-prefix=gtpo --makefile-name=Makefile.gnulib --libtool --local-dir=gnulib-local --local-symlink \
- --import $GNULIB_MODULES_LIBGETTEXTPO $GNULIB_MODULES_LIBGETTEXTPO_OTHER || exit $?
- # Overwrite older versions of .m4 files with the up-to-date version.
- cp gettext-runtime/m4/gettext.m4 gettext-tools/gnulib-m4/gettext.m4
- cp gettext-runtime/m4/intl.m4 gettext-tools/gnulib-m4/intl.m4
- # Import build tools. We use --copy-file to avoid directory creation.
- $GNULIB_TOOL --copy-file tests/init.sh gettext-tools || exit $?
- $GNULIB_TOOL --copy-file build-aux/git-version-gen || exit $?
- $GNULIB_TOOL --copy-file build-aux/gitlog-to-changelog || exit $?
- $GNULIB_TOOL --copy-file build-aux/update-copyright || exit $?
- $GNULIB_TOOL --copy-file build-aux/useless-if-before-free || exit $?
- $GNULIB_TOOL --copy-file build-aux/vc-list-files || exit $?
- $GNULIB_TOOL --copy-file top/GNUmakefile . || exit $?
- $GNULIB_TOOL --copy-file top/maint.mk . || exit $?
+ GNULIB_SRCDIR=`pwd`/gnulib
+ test -d "$GNULIB_SRCDIR" || {
+ echo "*** Subdirectory 'gnulib' does not yet exist. Use './gitsub.sh pull' to create it, or set the environment variable GNULIB_SRCDIR." 1>&2
+ exit 1
+ }
fi
+ # Now it should contain a gnulib-tool.
+ GNULIB_TOOL="$GNULIB_SRCDIR/gnulib-tool"
+ test -f "$GNULIB_TOOL" || {
+ echo "*** gnulib-tool not found." 1>&2
+ exit 1
+ }
+ # In gettext-runtime:
+ GNULIB_MODULES_RUNTIME_FOR_SRC='
+ atexit
+ basename
+ binary-io
+ closeout
+ error
+ getopt-gnu
+ gettext-h
+ havelib
+ memmove
+ progname
+ propername
+ relocatable-prog
+ setlocale
+ sigpipe
+ stdbool
+ stdio
+ stdlib
+ strtoul
+ unistd
+ unlocked-io
+ xalloc
+ '
+ GNULIB_MODULES_RUNTIME_OTHER='
+ gettext-runtime-misc
+ ansi-c++-opt
+ csharpcomp-script
+ java
+ javacomp-script
+ '
+ $GNULIB_TOOL --dir=gettext-runtime --lib=libgrt --source-base=gnulib-lib --m4-base=gnulib-m4 --no-libtool --local-dir=gnulib-local --local-symlink \
+ --import $GNULIB_MODULES_RUNTIME_FOR_SRC $GNULIB_MODULES_RUNTIME_OTHER || exit $?
+ # In gettext-runtime/libasprintf:
+ GNULIB_MODULES_LIBASPRINTF='
+ alloca
+ errno
+ verify
+ xsize
+ '
+ GNULIB_MODULES_LIBASPRINTF_OTHER='
+ '
+ $GNULIB_TOOL --dir=gettext-runtime/libasprintf --source-base=. --m4-base=gnulib-m4 --lgpl=2 --makefile-name=Makefile.gnulib --libtool --local-dir=gnulib-local --local-symlink \
+ --import $GNULIB_MODULES_LIBASPRINTF $GNULIB_MODULES_LIBASPRINTF_OTHER || exit $?
+ $GNULIB_TOOL --copy-file m4/intmax_t.m4 gettext-runtime/libasprintf/gnulib-m4/intmax_t.m4 || exit $?
+ $GNULIB_TOOL --copy-file m4/wchar_t.m4 gettext-runtime/libasprintf/gnulib-m4/wchar_t.m4 || exit $?
+ $GNULIB_TOOL --copy-file m4/wint_t.m4 gettext-runtime/libasprintf/gnulib-m4/wint_t.m4 || exit $?
+ # In gettext-tools:
+ GNULIB_MODULES_TOOLS_FOR_SRC='
+ alloca-opt
+ atexit
+ backupfile
+ basename
+ binary-io
+ bison-i18n
+ byteswap
+ c-ctype
+ c-strcase
+ c-strcasestr
+ c-strstr
+ clean-temp
+ closedir
+ closeout
+ copy-file
+ csharpcomp
+ csharpexec
+ error
+ error-progname
+ execute
+ fd-ostream
+ file-ostream
+ filename
+ findprog
+ fnmatch
+ fopen
+ fstrcmp
+ full-write
+ fwriteerror
+ gcd
+ getline
+ getopt-gnu
+ gettext
+ gettext-h
+ hash
+ html-styled-ostream
+ iconv
+ javacomp
+ javaexec
+ libunistring-optional
+ localcharset
+ locale
+ localename
+ lock
+ memchr
+ memmove
+ memset
+ minmax
+ mkdir
+ obstack
+ open
+ opendir
+ openmp
+ ostream
+ pipe-filter-ii
+ progname
+ propername
+ read-file
+ readdir
+ relocatable-prog
+ relocatable-script
+ setlocale
+ sh-quote
+ sigpipe
+ sigprocmask
+ spawn-pipe
+ stdbool
+ stdio
+ stdlib
+ stpcpy
+ stpncpy
+ strchrnul
+ strcspn
+ strerror
+ strpbrk
+ strtol
+ strtoul
+ styled-ostream
+ sys_select
+ sys_stat
+ sys_time
+ term-styled-ostream
+ trim
+ unictype/ctype-space
+ unilbrk/ulc-width-linebreaks
+ uniname/uniname
+ unistd
+ unistr/u8-check
+ unistr/u8-mbtouc
+ unistr/u8-mbtoucr
+ unistr/u8-uctomb
+ unistr/u16-mbtouc
+ uniwidth/width
+ unlocked-io
+ vasprintf
+ wait-process
+ write
+ xalloc
+ xconcat-filename
+ xerror
+ xmalloca
+ xmemdup0
+ xsetenv
+ xstriconv
+ xstriconveh
+ xvasprintf
+ '
+ # Common dependencies of GNULIB_MODULES_TOOLS_FOR_SRC and GNULIB_MODULES_TOOLS_FOR_LIBGREP.
+ GNULIB_MODULES_TOOLS_FOR_SRC_COMMON_DEPENDENCIES='
+ alloca-opt
+ extensions
+ gettext-h
+ include_next
+ locale
+ localcharset
+ malloc-posix
+ mbrtowc
+ mbsinit
+ multiarch
+ snippet/arg-nonnull
+ snippet/c++defs
+ snippet/warn-on-use
+ ssize_t
+ stdbool
+ stddef
+ stdint
+ stdlib
+ streq
+ unistd
+ verify
+ wchar
+ wctype-h
+ '
+ GNULIB_MODULES_TOOLS_OTHER='
+ gettext-tools-misc
+ ansi-c++-opt
+ csharpcomp-script
+ csharpexec-script
+ java
+ javacomp-script
+ javaexec-script
+ stdint
+ '
+ GNULIB_MODULES_TOOLS_LIBUNISTRING_TESTS='
+ unilbrk/u8-possible-linebreaks-tests
+ unilbrk/ulc-width-linebreaks-tests
+ unistr/u8-mbtouc-tests
+ unistr/u8-mbtouc-unsafe-tests
+ uniwidth/width-tests
+ '
+ $GNULIB_TOOL --dir=gettext-tools --lib=libgettextlib --source-base=gnulib-lib --m4-base=gnulib-m4 --tests-base=gnulib-tests --makefile-name=Makefile.gnulib --libtool --with-tests --local-dir=gnulib-local --local-symlink \
+ --import --avoid=hash-tests --avoid=fdutimensat-tests --avoid=futimens-tests --avoid=utime-tests --avoid=utimens-tests --avoid=utimensat-tests \
+ `for m in $GNULIB_MODULES_TOOLS_LIBUNISTRING_TESTS; do echo --avoid=$m; done` $GNULIB_MODULES_TOOLS_FOR_SRC $GNULIB_MODULES_TOOLS_FOR_SRC_COMMON_DEPENDENCIES $GNULIB_MODULES_TOOLS_OTHER || exit $?
+ # In gettext-tools/libgrep:
+ GNULIB_MODULES_TOOLS_FOR_LIBGREP='
+ mbrlen
+ regex
+ '
+ $GNULIB_TOOL --dir=gettext-tools --macro-prefix=grgl --lib=libgrep --source-base=libgrep --m4-base=libgrep/gnulib-m4 --witness-c-macro=IN_GETTEXT_TOOLS_LIBGREP --makefile-name=Makefile.gnulib --local-dir=gnulib-local --local-symlink \
+ --import `for m in $GNULIB_MODULES_TOOLS_FOR_SRC_COMMON_DEPENDENCIES; do if test \`$GNULIB_TOOL --extract-applicability $m\` != all; then echo --avoid=$m; fi; done` $GNULIB_MODULES_TOOLS_FOR_LIBGREP || exit $?
+ # In gettext-tools/libgettextpo:
+ # This is a subset of the GNULIB_MODULES_FOR_SRC.
+ GNULIB_MODULES_LIBGETTEXTPO='
+ basename
+ close
+ c-ctype
+ c-strcase
+ c-strstr
+ error
+ error-progname
+ file-ostream
+ filename
+ fopen
+ fstrcmp
+ fwriteerror
+ gcd
+ getline
+ gettext-h
+ hash
+ iconv
+ libunistring-optional
+ markup
+ minmax
+ open
+ ostream
+ progname
+ relocatable-lib
+ sigpipe
+ stdbool
+ stdio
+ stdlib
+ stpcpy
+ stpncpy
+ strchrnul
+ strerror
+ unictype/ctype-space
+ unilbrk/ulc-width-linebreaks
+ unistr/u8-mbtouc
+ unistr/u8-mbtoucr
+ unistr/u8-uctomb
+ unistr/u16-mbtouc
+ uniwidth/width
+ unlocked-io
+ vasprintf
+ xalloc
+ xconcat-filename
+ xmalloca
+ xerror
+ xstriconv
+ xvasprintf
+ '
+ # Module 'realloc-posix' is enabled in gettext-tools/config.status, because
+ # it occurs as dependency of some module ('read-file') in
+ # GNULIB_MODULES_TOOLS_FOR_SRC. Therefore on mingw, libgettextpo/stdlib.h
+ # contains '#define realloc rpl_realloc'. Therefore we need to include
+ # realloc.lo in libgettextpo.la.
+ GNULIB_MODULES_LIBGETTEXTPO_OTHER='
+ realloc-posix
+ '
+ $GNULIB_TOOL --dir=gettext-tools --source-base=libgettextpo --m4-base=libgettextpo/gnulib-m4 --macro-prefix=gtpo --makefile-name=Makefile.gnulib --libtool --local-dir=gnulib-local --local-symlink \
+ --import $GNULIB_MODULES_LIBGETTEXTPO $GNULIB_MODULES_LIBGETTEXTPO_OTHER || exit $?
+ # Overwrite older versions of .m4 files with the up-to-date version.
+ cp gettext-runtime/m4/gettext.m4 gettext-tools/gnulib-m4/gettext.m4
+ cp gettext-runtime/m4/intl.m4 gettext-tools/gnulib-m4/intl.m4
+ # Import build tools. We use --copy-file to avoid directory creation.
+ $GNULIB_TOOL --copy-file tests/init.sh gettext-tools || exit $?
+ $GNULIB_TOOL --copy-file build-aux/git-version-gen || exit $?
+ $GNULIB_TOOL --copy-file build-aux/gitlog-to-changelog || exit $?
+ $GNULIB_TOOL --copy-file build-aux/update-copyright || exit $?
+ $GNULIB_TOOL --copy-file build-aux/useless-if-before-free || exit $?
+ $GNULIB_TOOL --copy-file build-aux/vc-list-files || exit $?
+ $GNULIB_TOOL --copy-file top/GNUmakefile . || exit $?
+ $GNULIB_TOOL --copy-file top/maint.mk . || exit $?
fi
# Fetch config.guess, config.sub.
--- /dev/null
+#! /bin/sh
+#
+# Copyright (C) 2019 Free Software Foundation, Inc.
+# Written by Bruno Haible <bruno@clisp.org>, 2019.
+#
+# 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/>.
+
+# Program that manages the subdirectories of a git checkout of a package
+# that come from other packages (called "dependency packages").
+#
+# This program is similar in spirit to 'git submodule', with three
+# essential differences:
+#
+# 1) Its options are easy to remember, and do not require knowledge of
+# 'git submodule'.
+#
+# 2) The developer may choose to work on a different checkout for each
+# dependency package. This is important when the developer is
+# preparing simultaneous changes to the package and the dependency
+# package, or is using the dependency package in several packages.
+#
+# The developer indicates this different checkout by setting the
+# environment variable <SUBDIR>_SRCDIR (e.g. GNULIB_SRCDIR) to point to it.
+#
+# 3) The package maintainer may choose to use or not use git submodules.
+#
+# The advantages of management through a git submodule are:
+# - Changes to the dependency package cannot suddenly break your package.
+# In other words, when there is an incompatible change that will cause
+# a breakage, you can fix things at your pace; you are not forced to
+# cope with such breakages in an emergency.
+# - When you need to make a change as a response to a change in the
+# dependency package, your co-developers cannot accidentally mix things
+# up (for example, use a combination of your newest change with an
+# older version of the dependency package).
+#
+# The advantages of management without a git submodule (just as a plain
+# subdirectory, let's call it a "subcheckout") are:
+# - The simplicity: you are conceptually always using the newest revision
+# of the dependency package.
+# - You don't have to remember to periodially upgrade the dependency.
+# Upgrading the dependency is an implicit operation.
+
+# This program is meant to be copied to the top-level directory of the package,
+# together with a configuration file. The configuration is supposed to be
+# named '.gitmodules' and to define:
+# * The git submodules, as described in "man 5 gitmodules" or
+# <https://git-scm.com/docs/gitmodules>. For example:
+#
+# [submodule "gnulib"]
+# url = git://git.savannah.gnu.org/gnulib.git
+# path = gnulib
+#
+# You don't add this piece of configuration to .gitmodules manually. Instead,
+# you would invoke
+# $ git submodule add --name "gnulib" -- git://git.savannah.gnu.org/gnulib.git gnulib
+#
+# * The subdirectories that are not git submodules, in a similar syntax. For
+# example:
+#
+# [subcheckout "gnulib"]
+# url = git://git.savannah.gnu.org/gnulib.git
+# path = gnulib
+#
+# Here the URL is the one used for anonymous checkouts of the dependency
+# package. If the developer needs a checkout with write access, they can
+# either set the GNULIB_SRCDIR environment variable to point to that checkout
+# or modify the gnulib/.git/config file to enter a different URL.
+
+scriptname="$0"
+scriptversion='2019-04-01'
+nl='
+'
+IFS=" "" $nl"
+
+# func_usage
+# outputs to stdout the --help usage message.
+func_usage ()
+{
+ echo "\
+Usage: gitsub.sh pull [SUBDIR]
+ gitsub.sh upgrade [SUBDIR]
+ gitsub.sh checkout SUBDIR REVISION
+
+Operations:
+
+gitsub.sh pull [SUBDIR]
+ You should perform this operation after 'git clone ...' and after
+ every 'git pull'.
+ It brings your checkout in sync with what the other developers of
+ your package have committed and pushed.
+ If an environment variable <SUBDIR>_SRCDIR is set, with a non-empty
+ value, nothing is done for this SUBDIR.
+ If no SUBDIR is specified, the operation applies to all dependencies.
+
+gitsub.sh upgrade [SUBDIR]
+ You should perform this operation periodically, to ensure currency
+ of the dependency package revisions that you use.
+ This operation pulls and checks out the changes that the developers
+ of the dependency package have committed and pushed.
+ If an environment variable <SUBDIR>_SRCDIR is set, with a non-empty
+ value, nothing is done for this SUBDIR.
+ If no SUBDIR is specified, the operation applies to all dependencies.
+
+gitsub.sh checkout SUBDIR REVISION
+ Checks out a specific revision for a dependency package.
+ If an environment variable <SUBDIR>_SRCDIR is set, with a non-empty
+ value, this operation fails.
+
+This script requires the git program in the PATH and an internet connection.
+"
+}
+
+# func_version
+# outputs to stdout the --version message.
+func_version ()
+{
+ year=`echo "$scriptversion" | sed -e 's/^\(....\)-.*/\1/'`
+ echo "\
+gitsub.sh (GNU gnulib) $scriptversion
+Copyright (C) 2019-$year Free Software Foundation, Inc.
+License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.
+"
+ printf "Written by %s.\n" "Bruno Haible"
+}
+
+# func_fatal_error message
+# outputs to stderr a fatal error message, and terminates the program.
+# Input:
+# - scriptname name of this program
+func_fatal_error ()
+{
+ echo "$scriptname: *** $1" 1>&2
+ echo "$scriptname: *** Stop." 1>&2
+ exit 1
+}
+
+# func_warning message
+# Outputs to stderr a warning message,
+func_warning ()
+{
+ echo "gitsub.sh: warning: $1" 1>&2
+}
+
+# func_note message
+# Outputs to stdout a note message,
+func_note ()
+{
+ echo "gitsub.sh: note: $1"
+}
+
+# Unset CDPATH. Otherwise, output from 'cd dir' can surprise callers.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Command-line option processing.
+mode=
+while test $# -gt 0; do
+ case "$1" in
+ --help | --hel | --he | --h )
+ func_usage
+ exit $? ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v )
+ func_version
+ exit $? ;;
+ -- )
+ # Stop option processing
+ shift
+ break ;;
+ -* )
+ echo "gitsub.sh: unknown option $1" 1>&2
+ echo "Try 'gitsub.sh --help' for more information." 1>&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+if test $# = 0; then
+ echo "gitsub.sh: missing operation argument" 1>&2
+ echo "Try 'gitsub.sh --help' for more information." 1>&2
+ exit 1
+fi
+case "$1" in
+ pull | upgrade | checkout )
+ mode="$1"
+ shift ;;
+ *)
+ echo "gitsub.sh: unknown operation '$1'" 1>&2
+ echo "Try 'gitsub.sh --help' for more information." 1>&2
+ exit 1 ;;
+esac
+if test $# = 2 && test $mode != checkout || test $# -gt 2; then
+ echo "gitsub.sh: too many arguments in '$mode' mode" 1>&2
+ echo "Try 'gitsub.sh --help' for more information." 1>&2
+ exit 1
+fi
+if test $# = 0 && test $mode = checkout; then
+ echo "gitsub.sh: too few arguments in '$mode' mode" 1>&2
+ echo "Try 'gitsub.sh --help' for more information." 1>&2
+ exit 1
+fi
+
+# Read the configuration.
+# Output:
+# - subcheckout_names space-separated list of subcheckout names
+# - submodule_names space-separated list of submodule names
+if test -f .gitmodules; then
+ subcheckout_names=`git config --file .gitmodules --get-regexp --name-only 'subcheckout\..*\.url' | sed -e 's/^subcheckout\.//' -e 's/\.url$//' | tr -d '\r' | tr '\n' ' '`
+ submodule_names=`git config --file .gitmodules --get-regexp --name-only 'submodule\..*\.url' | sed -e 's/^submodule\.//' -e 's/\.url$//' | tr -d '\r' | tr '\n' ' '`
+else
+ subcheckout_names=
+ submodule_names=
+fi
+
+# func_validate SUBDIR
+# Verifies that the state on the file system is in sync with the declarations
+# in the configuration file.
+# Input:
+# - subcheckout_names space-separated list of subcheckout names
+# - submodule_names space-separated list of submodule names
+# Output:
+# - srcdirvar Environment that the user can set
+# - srcdir Value of the environment variable
+# - path if $srcdir = "": relative path of the subdirectory
+# - needs_init if $srcdir = "" and $path is not yet initialized:
+# true
+# - url if $srcdir = "" and $path is not yet initialized:
+# the repository URL
+func_validate ()
+{
+ srcdirvar=`echo "$1" | LC_ALL=C sed -e 's/[^a-zA-Z0-9]/_/g' | LC_ALL=C tr '[a-z]' '[A-Z]'`"_SRCDIR"
+ eval 'srcdir=$'"$srcdirvar"
+ path=
+ url=
+ if test -n "$srcdir"; then
+ func_note "Ignoring '$1' because $srcdirvar is set."
+ else
+ found=false
+ needs_init=
+ case " $subcheckout_names " in *" $1 "*)
+ found=true
+ # It ought to be a subcheckout.
+ path=`git config --file .gitmodules "subcheckout.$1.path"`
+ if test -z "$path"; then
+ path="$1"
+ fi
+ if test -d "$path"; then
+ if test -d "$path/.git"; then
+ # It's a plain checkout.
+ :
+ else
+ if test -f "$path/.git"; then
+ # It's a submodule.
+ func_fatal_error "Subdirectory '$path' is supposed to be a plain checkout, but it is a submodule."
+ else
+ func_warning "Ignoring '$path' because it exists but is not a git checkout."
+ fi
+ fi
+ else
+ # The subdir does not yet exist.
+ needs_init=true
+ url=`git config --file .gitmodules "subcheckout.$1.url"`
+ if test -z "$url"; then
+ func_fatal_error "Property subcheckout.$1.url is not defined in .gitmodules"
+ fi
+ fi
+ ;;
+ esac
+ case " $submodule_names " in *" $1 "*)
+ found=true
+ # It ought to be a submodule.
+ path=`git config --file .gitmodules "submodule.$1.path"`
+ if test -z "$path"; then
+ path="$1"
+ fi
+ if test -d "$path"; then
+ if test -d "$path/.git" || test -f "$path/.git"; then
+ # It's likely a submodule.
+ :
+ else
+ path_if_empty=`find "$path" -prune -empty 2>/dev/null`
+ if test -n "$path_if_empty"; then
+ # The subdir is empty.
+ needs_init=true
+ else
+ # The subdir is not empty.
+ # It is important to report an error, because we don't want to erase
+ # the user's files and 'git submodule update gnulib' sometimes reports
+ # "fatal: destination path '$path' already exists and is not an empty directory."
+ # but sometimes does not.
+ func_fatal_error "Subdir '$path' exists but is not a git checkout."
+ fi
+ fi
+ else
+ # The subdir does not yet exist.
+ needs_init=true
+ fi
+ # Another way to determine needs_init could be:
+ # if git submodule status "$path" | grep '^-' > /dev/null; then
+ # needs_init=true
+ # fi
+ if test -n "$needs_init"; then
+ url=`git config --file .gitmodules "submodule.$1.url"`
+ if test -z "$url"; then
+ func_fatal_error "Property submodule.$1.url is not defined in .gitmodules"
+ fi
+ fi
+ ;;
+ esac
+ if ! $found; then
+ func_fatal_error "Subdir '$1' is not configured as a subcheckout or a submodule in .gitmodules"
+ fi
+ fi
+}
+
+# func_cleanup_current_git_clone
+# Cleans up the current 'git clone' operation.
+# Input:
+# - path
+func_cleanup_current_git_clone ()
+{
+ rm -rf "$path"
+ func_fatal_error "git clone failed"
+}
+
+# func_pull SUBDIR
+# Implements the 'pull' operation.
+func_pull ()
+{
+ func_validate "$1"
+ if test -z "$srcdir"; then
+ case " $subcheckout_names " in *" $1 "*)
+ # It's a subcheckout.
+ if test -d "$path"; then
+ if test -d "$path/.git"; then
+ (cd "$path" && git pull) || func_fatal_error "git operation failed"
+ fi
+ else
+ # The subdir does not yet exist. Create a plain checkout.
+ trap func_cleanup_current_git_clone 1 2 13 15
+ git clone "$url" "$path" || func_cleanup_current_git_clone
+ trap - 1 2 13 15
+ fi
+ ;;
+ esac
+ case " $submodule_names " in *" $1 "*)
+ # It's a submodule.
+ if test -n "$needs_init"; then
+ # Create a submodule checkout.
+ git submodule init -- "$path" && git submodule update -- "$path" || func_fatal_error "git operation failed"
+ else
+ # See https://stackoverflow.com/questions/1030169/easy-way-to-pull-latest-of-all-git-submodules
+ # https://stackoverflow.com/questions/4611512/is-there-a-way-to-make-git-pull-automatically-update-submodules
+ git submodule update "$path" || func_fatal_error "git operation failed"
+ fi
+ ;;
+ esac
+ fi
+}
+
+# func_upgrade SUBDIR
+# Implements the 'upgrade' operation.
+func_upgrade ()
+{
+ func_validate "$1"
+ if test -z "$srcdir"; then
+ if test -d "$path"; then
+ case " $subcheckout_names " in *" $1 "*)
+ # It's a subcheckout.
+ if test -d "$path/.git"; then
+ (cd "$path" && git pull) || func_fatal_error "git operation failed"
+ fi
+ ;;
+ esac
+ case " $submodule_names " in *" $1 "*)
+ # It's a submodule.
+ if test -z "$needs_init"; then
+ (cd "$path" && git fetch && git merge origin/master) || func_fatal_error "git operation failed"
+ fi
+ ;;
+ esac
+ else
+ # The subdir does not yet exist.
+ func_fatal_error "Subdirectory '$path' does not exist yet. Use 'gitsub.sh pull' to create it."
+ fi
+ fi
+}
+
+# func_checkout SUBDIR REVISION
+# Implements the 'checkout' operation.
+func_checkout ()
+{
+ func_validate "$1"
+ if test -z "$srcdir"; then
+ if test -d "$path"; then
+ case " $subcheckout_names " in *" $1 "*)
+ # It's a subcheckout.
+ if test -d "$path/.git"; then
+ (cd "$path" && git checkout "$2") || func_fatal_error "git operation failed"
+ fi
+ ;;
+ esac
+ case " $submodule_names " in *" $1 "*)
+ # It's a submodule.
+ if test -z "$needs_init"; then
+ (cd "$path" && git checkout "$2") || func_fatal_error "git operation failed"
+ fi
+ ;;
+ esac
+ else
+ # The subdir does not yet exist.
+ func_fatal_error "Subdirectory '$path' does not exist yet. Use 'gitsub.sh pull' to create it."
+ fi
+ fi
+}
+
+case "$mode" in
+ pull )
+ if test $# = 0; then
+ for sub in $subcheckout_names $submodule_names; do
+ func_pull "$sub"
+ done
+ else
+ valid=false
+ for sub in $subcheckout_names $submodule_names; do
+ if test "$sub" = "$1"; then
+ valid=true
+ fi
+ done
+ if $valid; then
+ func_pull "$1"
+ else
+ func_fatal_error "Subdir '$1' is not configured as a subcheckout or a submodule in .gitmodules"
+ fi
+ fi
+ ;;
+
+ upgrade )
+ if test $# = 0; then
+ for sub in $subcheckout_names $submodule_names; do
+ func_upgrade "$sub"
+ done
+ else
+ valid=false
+ for sub in $subcheckout_names $submodule_names; do
+ if test "$sub" = "$1"; then
+ valid=true
+ fi
+ done
+ if $valid; then
+ func_upgrade "$1"
+ else
+ func_fatal_error "Subdir '$1' is not configured as a subcheckout or a submodule in .gitmodules"
+ fi
+ fi
+ ;;
+
+ checkout )
+ valid=false
+ for sub in $subcheckout_names $submodule_names; do
+ if test "$sub" = "$1"; then
+ valid=true
+ fi
+ done
+ if $valid; then
+ func_checkout "$1" "$2"
+ else
+ func_fatal_error "Subdir '$1' is not configured as a subcheckout or a submodule in .gitmodules"
+ fi
+ ;;
+esac