]> Savannah Git Hosting - gnulib.git/commitdiff
gnulib-tool.py: Reorganize code.
authorBruno Haible <bruno@clisp.org>
Mon, 26 Feb 2024 22:44:01 +0000 (23:44 +0100)
committerBruno Haible <bruno@clisp.org>
Mon, 26 Feb 2024 22:44:01 +0000 (23:44 +0100)
* pygnulib/main.py: New file, moved here from gnulib-tool.py.
* pygnulib/constants.py: Change the way APP['name'] and DIRS['root'] are
computed.
* gnulib-tool.py: New file, based on gnulib-tool.

ChangeLog
gnulib-tool.py
pygnulib/constants.py
pygnulib/main.py [new file with mode: 0644]

index 270b8cb0aac0054c167a2b8e8616bab594add266..af84986424215738146b0586f32250643c5f8c01 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2024-02-26  Bruno Haible  <bruno@clisp.org>
+
+       gnulib-tool.py: Reorganize code.
+       * pygnulib/main.py: New file, moved here from gnulib-tool.py.
+       * pygnulib/constants.py: Change the way APP['name'] and DIRS['root'] are
+       computed.
+       * gnulib-tool.py: New file, based on gnulib-tool.
+
 2024-02-25  Bruno Haible  <bruno@clisp.org>
 
        bitset: Don't access errno when it's not set.
index 1df790c49667ca8ee1756ed78c282468b78228ef..9773736e6db0970b056ff47e47fea157ec8dfd4a 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+#! /bin/sh
 #
 # Copyright (C) 2002-2024 Free Software Foundation, Inc.
 #
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #
 
-# This program is meant for authors or maintainers which want to import
-# modules from gnulib into their packages.
-
-# CODING STYLE for this file and its companions:
-# Like PEP 8 <https://peps.python.org/pep-0008/>, except
-# - Line length is not limited to 79 characters.
-# - Line breaking before or after binary operators? Better before, like in GNU.
-# - Place line breaks to help reading the code:
-#   Avoid line breaks inside expressions, if they can be avoided.
-#   Do use line breaks to separate the parts of [ ... for ... ] iterations.
-# You can use this command to check the style:
-#   $ pycodestyle --max-line-length=136 --ignore=E265,W503,E241,E711,E712,E201,E202,E221 gnulib-tool.py pygnulib/*.py
-
-# You can use this command to check for mistakes:
-#   $ pylint --disable=C0103,C0114,C0121,C0209,C0301,C0302,R0902,R0912,R0913,R0914,R0915,R1705,R1702,R1720 gnulib-tool.py pygnulib/*.py
-
-
-#===============================================================================
-# Define global imports
-#===============================================================================
-import os
-import re
-import sys
-import codecs
-import random
-import argparse
-import subprocess as sp
-import shlex
-from tempfile import mktemp
-from pygnulib import constants
-from pygnulib import classes
-
-
-#===============================================================================
-# Define global constants
-#===============================================================================
-APP = constants.APP
-DIRS = constants.DIRS
-ENCS = constants.ENCS
-UTILS = constants.UTILS
-MODES = constants.MODES
-TESTS = constants.TESTS
-joinpath = constants.joinpath
-copyfile = constants.copyfile
-isabs = os.path.isabs
-isdir = os.path.isdir
-isfile = os.path.isfile
-
-
-#===============================================================================
-# Define main part
-#===============================================================================
-def main():
-    info = classes.GLInfo()
-    parser = argparse.ArgumentParser(
-        prog=constants.APP['name'],
-        usage='gnulib-tool.py --help',
-        add_help=False)
-
-    # Here we list the options in the order they are listed in the --help output.
-
-    # list
-    parser.add_argument('--list',
-                        dest='mode_list',
-                        default=None,
-                        action='store_true')
-    # find
-    parser.add_argument('--find',
-                        dest='mode_find',
-                        default=None,
-                        action='store_true')
-    # import
-    parser.add_argument('--import',
-                        dest='mode_import',
-                        default=None,
-                        action='store_true')
-    # add-import
-    parser.add_argument('--add-import',
-                        dest='mode_add_import',
-                        default=None,
-                        action='store_true')
-    # remove-import
-    parser.add_argument('--remove-import',
-                        dest='mode_remove_import',
-                        default=None,
-                        action='store_true')
-    # update
-    parser.add_argument('--update',
-                        dest='mode_update',
-                        default=None,
-                        action='store_true')
-    # create-testdir
-    parser.add_argument('--create-testdir',
-                        dest='mode_create_testdir',
-                        default=None,
-                        action='store_true')
-    # create-megatestdir
-    parser.add_argument('--create-megatestdir',
-                        dest='mode_create_megatestdir',
-                        default=None,
-                        action='store_true')
-    # test
-    parser.add_argument('--test',
-                        dest='mode_test',
-                        default=None,
-                        action='store_true')
-    # megatest
-    parser.add_argument('--megatest',
-                        dest='mode_megatest',
-                        default=None,
-                        action='store_true')
-    # extract-*
-    parser.add_argument('--extract-description',
-                        dest='mode_xdescription',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--extract-comment',
-                        dest='mode_xcomment',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--extract-status',
-                        dest='mode_xstatus',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--extract-notice',
-                        dest='mode_xnotice',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--extract-applicability',
-                        dest='mode_xapplicability',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--extract-filelist',
-                        dest='mode_xfilelist',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--extract-dependencies',
-                        dest='mode_xdependencies',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--extract-autoconf-snippet',
-                        dest='mode_xautoconf',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--extract-automake-snippet',
-                        dest='mode_xautomake',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--extract-include-directive',
-                        dest='mode_xinclude',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--extract-link-directive',
-                        dest='mode_xlink',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--extract-license',
-                        dest='mode_xlicense',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--extract-maintainer',
-                        dest='mode_xmaintainer',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--extract-tests-module',
-                        dest='mode_xtests',
-                        default=None,
-                        action='store_true')
-    # copy-file
-    parser.add_argument('--copy-file',
-                        dest='mode_copy_file',
-                        default=None,
-                        action='store_true')
-    # help
-    parser.add_argument('--help', '--hel', '--he', '--h',
-                        dest='help',
-                        default=None,
-                        action='store_true')
-    # version
-    parser.add_argument('--version', '--versio', '--versi', '--vers',
-                        dest='version',
-                        default=None,
-                        action='store_true')
-    # no-changelog: a no-op for backward compatibility
-    parser.add_argument('--no-changelog',
-                        dest='changelog',
-                        default=None,
-                        action='store_false')
-    # destdir
-    parser.add_argument('--dir',
-                        dest='destdir',
-                        default=None,
-                        nargs=1)
-    # localpath
-    parser.add_argument('--local-dir',
-                        action='append',
-                        dest='localpath',
-                        default=None,
-                        nargs=1)
-    # cache-modules: a no-op for backward compatibility
-    parser.add_argument('--cache-modules',
-                        dest='cache_modules',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--no-cache-modules',
-                        dest='cache_modules',
-                        default=None,
-                        action='store_false')
-    # verbose
-    parser.add_argument('--verbose',
-                        default=0,
-                        action='count')
-    # quiet
-    parser.add_argument('--quiet',
-                        default=0,
-                        action='count')
-    # dryrun
-    parser.add_argument('--dry-run',
-                        dest='dryrun',
-                        default=None,
-                        action='store_true')
-    # inctests
-    parser.add_argument('--with-tests',
-                        dest='inctests',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--without-tests',
-                        dest='inctests',
-                        default=None,
-                        action='store_false')
-    # obsolete
-    parser.add_argument('--with-obsolete',
-                        dest='obsolete',
-                        default=None,
-                        action='store_true')
-    # c++-tests
-    parser.add_argument('--with-c++-tests',
-                        dest='inc_cxx_tests',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--without-c++-tests',
-                        dest='excl_cxx_tests',
-                        default=None,
-                        action='store_true')
-    # longrunning-tests
-    parser.add_argument('--with-longrunning-tests',
-                        dest='inc_longrunning_tests',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--without-longrunning-tests',
-                        dest='excl_longrunning_tests',
-                        default=None,
-                        action='store_true')
-    # privileged-tests
-    parser.add_argument('--with-privileged-tests',
-                        dest='inc_privileged_tests',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--without-privileged-tests',
-                        dest='excl_privileged_tests',
-                        default=None,
-                        action='store_true')
-    # unportable-tests
-    parser.add_argument('--with-unportable-tests',
-                        dest='inc_unportable_tests',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--without-unportable-tests',
-                        dest='excl_unportable_tests',
-                        default=None,
-                        action='store_true')
-    # all-tests
-    parser.add_argument('--with-all-tests',
-                        dest='alltests',
-                        default=None,
-                        action='store_true')
-    # avoids
-    parser.add_argument('--avoid',
-                        dest='avoids',
-                        default=None,
-                        action='append',
-                        nargs=1)
-    # conditional-dependencies
-    parser.add_argument('--conditional-dependencies',
-                        dest='cond_dependencies',
-                        default=None,
-                        action="store_true")
-    parser.add_argument('--no-conditional-dependencies',
-                        dest='cond_dependencies',
-                        default=None,
-                        action="store_false")
-    # libtool
-    parser.add_argument('--libtool',
-                        dest='libtool',
-                        default=None,
-                        action="store_true")
-    parser.add_argument('--no-libtool',
-                        dest='libtool',
-                        default=None,
-                        action="store_false")
-    # libname
-    parser.add_argument('--lib',
-                        dest='libname',
-                        default=None,
-                        nargs=1)
-    # sourcebase
-    parser.add_argument('--source-base',
-                        dest='sourcebase',
-                        default=None,
-                        nargs=1)
-    # m4base
-    parser.add_argument('--m4-base',
-                        dest='m4base',
-                        default=None,
-                        nargs=1)
-    # pobase
-    parser.add_argument('--po-base',
-                        dest='pobase',
-                        default=None,
-                        nargs=1)
-    # docbase
-    parser.add_argument('--doc-base',
-                        dest='docbase',
-                        default=None,
-                        nargs=1)
-    # testsbase
-    parser.add_argument('--tests-base',
-                        dest='testsbase',
-                        default=None,
-                        nargs=1)
-    # auxdir
-    parser.add_argument('--aux-dir',
-                        dest='auxdir',
-                        default=None,
-                        nargs=1)
-    # lgpl
-    parser.add_argument('--lgpl',
-                        dest='lgpl',
-                        default=None,
-                        action='append',
-                        choices=['2', '3orGPLv2', '3'],
-                        nargs='?')
-    # gnu-make
-    parser.add_argument('--gnu-make',
-                        dest='gnu_make',
-                        default=None,
-                        action='store_true')
-    # makefile-name
-    parser.add_argument('--makefile-name',
-                        dest='makefile_name',
-                        default=None,
-                        nargs=1)
-    # macro-prefix
-    parser.add_argument('--macro-prefix',
-                        dest='macro_prefix',
-                        default=None,
-                        nargs=1)
-    # po-domain
-    parser.add_argument('--po-domain',
-                        dest='podomain',
-                        default=None,
-                        nargs=1)
-    # witness-c-macro
-    parser.add_argument('--witness-c-macro',
-                        dest='witness_c_macro',
-                        default=None,
-                        nargs=1)
-    # vc-files
-    parser.add_argument('--vc-files',
-                        dest='vc_files',
-                        default=None,
-                        action='store_true')
-    parser.add_argument('--no-vc-files',
-                        dest='vc_files',
-                        default=None,
-                        action='store_false')
-    # single-configure
-    parser.add_argument('--single-configure',
-                        dest='single_configure',
-                        default=None,
-                        action='store_true')
-    # symlink
-    parser.add_argument('-s', '--symbolic', '--symlink',
-                        dest='symlink',
-                        default=None,
-                        action='store_true')
-    # local-symlink
-    parser.add_argument('--local-symlink',
-                        dest='lsymlink',
-                        default=None,
-                        action='store_true')
-    # All other arguments are collected.
-    parser.add_argument("non_option_arguments",
-                        nargs='*')
-
-    # Parse the given arguments. Don't signal an error if non-option arguments
-    # occur between or after options.
-    cmdargs, unhandled = parser.parse_known_args()
-
-    # Handle --help and --version, ignoring all other options.
-    if cmdargs.help != None:
-        print(info.usage())
-        sys.exit(0)
-    if cmdargs.version != None:
-        version = info.version()
-        if version != '':
-            version = ' ' + version
-        message = '''gnulib-tool (%s %s)%s\n%s\n%s\n\nWritten by %s.''' \
-            % (info.package(), info.date(), version, info.copyright(),
-               info.license(), info.authors())
-        print(message)
-        sys.exit(0)
-
-    # Report unhandled arguments.
-    for arg in unhandled:
-        if arg.startswith('-'):
-            message = '%s: Unrecognized option \'%s\'.\n' % (constants.APP['name'], arg)
-            message += 'Try \'gnulib-tool --help\' for more information.\n'
-            sys.stderr.write(message)
-            sys.exit(1)
-    # By now, all unhandled arguments were non-options.
-    cmdargs.non_option_arguments += unhandled
-
-    # Determine when user tries to combine modes.
-    args = [
-        cmdargs.mode_list,
-        cmdargs.mode_find,
-        cmdargs.mode_import,
-        cmdargs.mode_add_import,
-        cmdargs.mode_remove_import,
-        cmdargs.mode_update,
-        cmdargs.mode_create_testdir,
-        cmdargs.mode_create_megatestdir,
-        cmdargs.mode_test,
-        cmdargs.mode_megatest,
-        cmdargs.mode_xdescription,
-        cmdargs.mode_xcomment,
-        cmdargs.mode_xstatus,
-        cmdargs.mode_xnotice,
-        cmdargs.mode_xapplicability,
-        cmdargs.mode_xfilelist,
-        cmdargs.mode_xdependencies,
-        cmdargs.mode_xautoconf,
-        cmdargs.mode_xautomake,
-        cmdargs.mode_xinclude,
-        cmdargs.mode_xlink,
-        cmdargs.mode_xlicense,
-        cmdargs.mode_xmaintainer,
-        cmdargs.mode_xtests,
-        cmdargs.mode_copy_file,
-    ]
-    overflow = [ arg
-                 for arg in args
-                 if arg != None ]
-    if len(overflow) > 1:
-        message = '%s: Unable to combine different modes of work.\n' % constants.APP['name']
-        message += 'Try \'gnulib-tool --help\' for more information.\n'
-        sys.stderr.write(message)
-        sys.exit(1)
-
-    # Determine selected mode.
-    mode = None
-    modules = None
-    files = None
-    if cmdargs.mode_list != None:
-        mode = 'list'
-    if cmdargs.mode_find != None:
-        mode = 'find'
-        files = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_import != None:
-        mode = 'import'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_add_import != None:
-        mode = 'add-import'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_remove_import != None:
-        mode = 'remove-import'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_update != None:
-        mode = 'update'
-        if len(cmdargs.non_option_arguments) > 0:
-            message = '%s: too many arguments in \'update\' mode\n'
-            message += 'Try \'gnulib-tool --help\' for more information.\n'
-            message += 'If you really want to modify the gnulib configuration of your project,\n'
-            message += 'you need to use \'gnulib-tool --import\' - at your own risk!\n'
-            sys.stderr.write(message)
-            sys.exit(1)
-    if cmdargs.mode_create_testdir != None:
-        mode = 'create-testdir'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_create_megatestdir != None:
-        mode = 'create-megatestdir'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_test != None:
-        mode = 'test'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_megatest != None:
-        mode = 'megatest'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_xdescription != None:
-        mode = 'extract-description'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_xcomment != None:
-        mode = 'extract-comment'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_xstatus != None:
-        mode = 'extract-status'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_xnotice != None:
-        mode = 'extract-notice'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_xapplicability != None:
-        mode = 'extract-applicability'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_xfilelist != None:
-        mode = 'extract-filelist'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_xautoconf != None:
-        mode = 'extract-autoconf-snippet'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_xautomake != None:
-        mode = 'extract-automake-snippet'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_xdependencies != None:
-        mode = 'extract-dependencies'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_xinclude != None:
-        mode = 'extract-include-directive'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_xlink != None:
-        mode = 'extract-link-directive'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_xlicense != None:
-        mode = 'extract-license'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_xmaintainer != None:
-        mode = 'extract-maintainer'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_xtests != None:
-        mode = 'extract-tests-module'
-        modules = list(cmdargs.non_option_arguments)
-    if cmdargs.mode_copy_file != None:
-        mode = 'copy-file'
-        if len(cmdargs.non_option_arguments) < 1 or len(cmdargs.non_option_arguments) > 2:
-            message = '%s: *** ' % constants.APP['name']
-            message += 'invalid number of arguments for --%s\n' % mode
-            message += 'Try \'gnulib-tool --help\' for more information.\n'
-            message += '%s: *** Stop.\n' % constants.APP['name']
-            sys.stderr.write(message)
-            sys.exit(1)
-        files = list(cmdargs.non_option_arguments)
-
-    if ((mode in ['import', 'add-import', 'remove-import']
-         and (cmdargs.excl_cxx_tests or cmdargs.excl_longrunning_tests
-              or cmdargs.excl_privileged_tests or cmdargs.excl_unportable_tests
-              or cmdargs.single_configure))
-        or (mode == 'update'
-            and (cmdargs.localpath != None or cmdargs.libname != None
-                 or cmdargs.sourcebase != None or cmdargs.m4base != None
-                 or cmdargs.pobase != None or cmdargs.docbase != None
-                 or cmdargs.testsbase != None or cmdargs.auxdir != None
-                 or cmdargs.inctests != None or cmdargs.obsolete != None
-                 or cmdargs.inc_cxx_tests != None
-                 or cmdargs.inc_longrunning_tests != None
-                 or cmdargs.inc_privileged_tests != None
-                 or cmdargs.inc_unportable_tests != None
-                 or cmdargs.alltests != None
-                 or cmdargs.excl_cxx_tests != None
-                 or cmdargs.excl_longrunning_tests != None
-                 or cmdargs.excl_privileged_tests != None
-                 or cmdargs.excl_unportable_tests != None
-                 or cmdargs.avoids != None or cmdargs.lgpl != None
-                 or cmdargs.makefile_name != None
-                 or cmdargs.macro_prefix != None or cmdargs.podomain != None
-                 or cmdargs.witness_c_macro != None or cmdargs.vc_files != None))):
-        message = '%s: *** ' % constants.APP['name']
-        message += 'invalid options for --%s mode\n' % mode
-        message += 'Try \'gnulib-tool --help\' for more information.\n'
-        message += '%s: *** Stop.\n' % constants.APP['name']
-        sys.stderr.write(message)
-        sys.exit(1)
-    if cmdargs.pobase != None and cmdargs.podomain == None:
-        message = '%s: *** ' % constants.APP['name']
-        message += 'together with --po-base, you need to specify --po-domain\n'
-        message += 'Try \'gnulib-tool --help\' for more information.\n'
-        message += '%s: *** Stop.\n' % constants.APP['name']
-        sys.stderr.write(message)
-        sys.exit(1)
-    if cmdargs.pobase == None and cmdargs.podomain != None:
-        message = '%s: warning: --po-domain has no effect without a --po-base option\n' % constants.APP['name']
-        sys.stderr.write(message)
-    if mode != None and 'test' in mode and gnu_make:
-        message = '%s: --gnu-make not supported when including tests\n' % constants.APP['name']
-        sys.stderr.write(message)
-        sys.exit(1)
-
-    # Determine specific settings.
-    destdir = cmdargs.destdir
-    if destdir != None:
-        destdir = cmdargs.destdir[0]
-    localpath = cmdargs.localpath
-    if localpath != None:
-        localpath = [ dir
-                      for list1 in localpath
-                      for dir in list1 ]
-    libname = cmdargs.libname
-    if libname != None:
-        libname = cmdargs.libname[0]
-    auxdir = cmdargs.auxdir
-    if auxdir != None:
-        auxdir = cmdargs.auxdir[0]
-    sourcebase = cmdargs.sourcebase
-    if sourcebase != None:
-        sourcebase = cmdargs.sourcebase[0]
-    m4base = cmdargs.m4base
-    if m4base != None:
-        m4base = cmdargs.m4base[0]
-    pobase = cmdargs.pobase
-    if pobase != None:
-        pobase = cmdargs.pobase[0]
-    testsbase = cmdargs.testsbase
-    if testsbase != None:
-        testsbase = cmdargs.testsbase[0]
-    dryrun = cmdargs.dryrun
-    verbose = -cmdargs.quiet + cmdargs.verbose
-    inctests = cmdargs.inctests
-    # Canonicalize the inctests variable.
-    if inctests == None:
-        if mode in ['import', 'add-import', 'remove-import', 'update']:
-            inctests = False
-        elif mode in ['create-testdir', 'create-megatestdir', 'test', 'megatest']:
-            inctests = True
-    incl_test_categories = []
-    if inctests:
-        incl_test_categories += [constants.TESTS['tests']]
-    if cmdargs.obsolete:
-        incl_test_categories += [constants.TESTS['obsolete']]
-    if cmdargs.inc_cxx_tests:
-        incl_test_categories += [constants.TESTS['cxx-tests']]
-    if cmdargs.inc_longrunning_tests:
-        incl_test_categories += [constants.TESTS['longrunning-tests']]
-    if cmdargs.inc_privileged_tests:
-        incl_test_categories += [constants.TESTS['privileged-tests']]
-    if cmdargs.inc_unportable_tests:
-        incl_test_categories += [constants.TESTS['unportable-tests']]
-    if cmdargs.alltests:
-        incl_test_categories += [constants.TESTS['all-tests']]
-    excl_test_categories = []
-    if cmdargs.excl_cxx_tests:
-        excl_test_categories += [constants.TESTS['cxx-tests']]
-    if cmdargs.excl_longrunning_tests:
-        excl_test_categories += [constants.TESTS['longrunning-tests']]
-    if cmdargs.excl_privileged_tests:
-        excl_test_categories += [constants.TESTS['privileged-tests']]
-    if cmdargs.excl_unportable_tests:
-        excl_test_categories += [constants.TESTS['unportable-tests']]
-    lgpl = cmdargs.lgpl
-    if lgpl != None:
-        lgpl = lgpl[-1]
-        if lgpl == None:
-            lgpl = True
-    cond_dependencies = cmdargs.cond_dependencies
-    libtool = cmdargs.libtool
-    gnu_make = cmdargs.gnu_make == True
-    makefile_name = cmdargs.makefile_name
-    if makefile_name != None:
-        makefile_name = makefile_name[0]
-    macro_prefix = cmdargs.macro_prefix
-    if macro_prefix != None:
-        macro_prefix = macro_prefix[0]
-    podomain = cmdargs.podomain
-    if podomain != None:
-        podomain = podomain[0]
-    witness_c_macro = cmdargs.witness_c_macro
-    if witness_c_macro != None:
-        witness_c_macro = witness_c_macro[0]
-    vc_files = cmdargs.vc_files
-    avoids = cmdargs.avoids
-    if avoids != None:
-        avoids = [ module
-                   for list1 in avoids
-                   for module in list1 ]
-    symlink = cmdargs.symlink == True
-    lsymlink = cmdargs.lsymlink == True
-    single_configure = cmdargs.single_configure
-    docbase = None
-
-    # Create pygnulib configuration.
-    config = classes.GLConfig(
-        destdir=destdir,
-        localpath=localpath,
-        m4base=m4base,
-        auxdir=auxdir,
-        modules=modules,
-        avoids=avoids,
-        sourcebase=sourcebase,
-        pobase=pobase,
-        docbase=docbase,
-        testsbase=testsbase,
-        incl_test_categories=incl_test_categories,
-        excl_test_categories=excl_test_categories,
-        libname=libname,
-        lgpl=lgpl,
-        gnu_make=gnu_make,
-        makefile_name=makefile_name,
-        libtool=libtool,
-        conddeps=cond_dependencies,
-        macro_prefix=macro_prefix,
-        podomain=podomain,
-        witness_c_macro=witness_c_macro,
-        vc_files=vc_files,
-        symbolic=symlink,
-        lsymbolic=lsymlink,
-        single_configure=single_configure,
-        verbose=verbose,
-        dryrun=dryrun,
-    )
-
-    # Work in the given mode.
-    if mode == 'list':
-        modulesystem = classes.GLModuleSystem(config)
-        listing = modulesystem.list()
-        result = '\n'.join(listing)
-        os.rmdir(config['tempdir'])
-        print(result)
-
-    elif mode == 'find':
-        modulesystem = classes.GLModuleSystem(config)
-        for filename in files:
-            if (isfile(joinpath(DIRS['root'], filename))
-                    or (localpath != None
-                        and any([ isfile(joinpath(localdir, filename))
-                                  for localdir in localpath ]))):
-                # Convert the file name to a POSIX basic regex.
-                # Needs to handle . [ \ * ^ $.
-                filename_regex = filename.replace('\\', '\\\\').replace('[', '\\[').replace('^', '\\^')
-                filename_regex = re.compile('([.*$])').sub('[\\1]', filename_regex)
-                filename_line_regex = '^' + filename_regex + '$'
-                # Read module candidates from gnulib root directory.
-                command = "find modules -type f -print | xargs -n 100 grep -l %s /dev/null | sed -e 's,^modules/,,'" % shlex.quote(filename_line_regex)
-                os.chdir(constants.DIRS['root'])
-                with sp.Popen(command, shell=True, stdout=sp.PIPE) as proc:
-                    result = proc.stdout.read().decode("UTF-8")
-                os.chdir(DIRS['cwd'])
-                # Read module candidates from local directories.
-                if localpath != None and len(localpath) > 0:
-                    command = "find modules -type f -print | xargs -n 100 grep -l %s /dev/null | sed -e 's,^modules/,,' -e 's,\\.diff$,,'" % shlex.quote(filename_line_regex)
-                    for localdir in localpath:
-                        os.chdir(localdir)
-                        with sp.Popen(command, shell=True, stdout=sp.PIPE) as proc:
-                            result += proc.stdout.read().decode("UTF-8")
-                        os.chdir(DIRS['cwd'])
-                listing = [ line
-                            for line in result.split('\n')
-                            if line.strip() ]
-                # Remove modules/ prefix from each file name.
-                pattern = re.compile('^modules/')
-                listing = [ pattern.sub('', line)
-                            for line in listing ]
-                # Filter out undesired file names.
-                listing = [ line
-                            for line in listing
-                            if modulesystem.file_is_module(line) ]
-                candidates = sorted(set(listing))
-                for name in candidates:
-                    module = modulesystem.find(name)
-                    if module:  # Ignore module candidates that don't actually exist.
-                        if module.getFiles():
-                            print(name)
-            else:
-                message = '%s: warning: file %s does not exist\n' % (constants.APP['name'], filename)
-                sys.stderr.write(message)
-
-    elif mode in ['import', 'add-import', 'remove-import', 'update']:
-        mode = MODES[mode]
-        if not destdir:
-            destdir = '.'
-        config.setDestDir(destdir)
-
-        if mode == MODES['import']:
-            # Set variables to default values.
-            if not sourcebase:
-                sourcebase = 'lib'
-            if not m4base:
-                m4base = 'm4'
-            if not docbase:
-                docbase = 'doc'
-            if not testsbase:
-                testsbase = 'tests'
-            if not macro_prefix:
-                macro_prefix = 'gl'
-            config.setSourceBase(sourcebase)
-            config.setM4Base(m4base)
-            config.setDocBase(docbase)
-            config.setTestsBase(testsbase)
-            config.setMacroPrefix(macro_prefix)
-
-            # Perform GLImport actions.
-            importer = classes.GLImport(config, mode)
-            filetable, transformers = importer.prepare()
-            importer.execute(filetable, transformers)
-
-        else:  # if mode != MODE['--import']
-            if m4base:
-                if not isfile(joinpath(destdir, m4base, 'gnulib-cache.m4')):
-                    if not sourcebase:
-                        sourcebase = 'lib'
-                    if not docbase:
-                        docbase = 'doc'
-                    if not testsbase:
-                        testsbase = 'tests'
-                    if not macro_prefix:
-                        macro_prefix = 'gl'
-                    config.setSourceBase(sourcebase)
-                    config.setM4Base(m4base)
-                    config.setDocBase(docbase)
-                    config.setTestsBase(testsbase)
-                    config.setMacroPrefix(macro_prefix)
-                # Perform GLImport actions.
-                importer = classes.GLImport(config, mode)
-                filetable, transformers = importer.prepare()
-                importer.execute(filetable, transformers)
-            else:  # if not m4base
-                m4dirs = list()
-                dirisnext = bool()
-                filepath = joinpath(destdir, 'Makefile.am')
-                if isfile(filepath):
-                    with codecs.open(filepath, 'rb', 'UTF-8') as file:
-                        data = file.read()
-                        data = data.split('ACLOCAL_AMFLAGS')[1]
-                        data = data[data.find('=') + 1:data.find('\n')]
-                    aclocal_amflags = data.split()
-                    for aclocal_amflag in aclocal_amflags:
-                        if dirisnext:
-                            if not isabs(aclocal_amflag):
-                                m4dirs += [aclocal_amflag]
-                        else:  # if not dirisnext
-                            if aclocal_amflag == '-I':
-                                dirisnext = True
-                            else:  # if aclocal_amflag != '-I'
-                                dirisnext = False
-                else:  # if not isfile(filepath)
-                    filepath = joinpath(destdir, 'aclocal.m4')
-                    if isfile(filepath):
-                        pattern = re.compile(r'm4_include\(\[(.*?)\]\)')
-                        with codecs.open(filepath, 'rb', 'UTF-8') as file:
-                            m4dirs = pattern.findall(file.read())
-                        m4dirs = [ os.path.dirname(m4dir)
-                                   for m4dir in m4dirs ]
-                        m4dirs = [ m4dir
-                                   for m4dir in m4dirs
-                                   if isfile(joinpath(destdir, m4dir, 'gnulib-cache.m4')) ]
-                        m4dirs = sorted(set(m4dirs))
-                if len(m4dirs) == 0:
-                    # First use of gnulib in a package.
-                    # Any number of additional modules can be given.
-                    if not sourcebase:
-                        sourcebase = 'lib'
-                    m4base = 'm4'
-                    if not docbase:
-                        docbase = 'doc'
-                    if not testsbase:
-                        testsbase = 'tests'
-                    if not macro_prefix:
-                        macro_prefix = 'gl'
-                    config.setSourceBase(sourcebase)
-                    config.setM4Base(m4base)
-                    config.setDocBase(docbase)
-                    config.setTestsBase(testsbase)
-                    config.setMacroPrefix(macro_prefix)
-                    # Perform GLImport actions.
-                    importer = classes.GLImport(config, mode)
-                    filetable, transformers = importer.prepare()
-                    importer.execute(filetable, transformers)
-                elif len(m4dirs) == 1:
-                    m4base = m4dirs[-1]
-                    config.setM4Base(m4base)
-                    # Perform GLImport actions.
-                    importer = classes.GLImport(config, mode)
-                    filetable, transformers = importer.prepare()
-                    importer.execute(filetable, transformers)
-                else:  # if len(m4dirs) > 1
-                    for m4base in m4dirs:
-                        config.setM4Base(m4base)
-                        # Perform GLImport actions.
-                        importer = classes.GLImport(config, mode)
-                        filetable, transformers = importer.prepare()
-                        importer.execute(filetable, transformers)
-
-    elif mode == 'create-testdir':
-        if not destdir:
-            message = '%s: *** ' % constants.APP['name']
-            message += 'please specify --dir option\n'
-            message += '%s: *** Stop.\n' % constants.APP['name']
-            sys.stderr.write(message)
-            sys.exit(1)
-        if not auxdir:
-            auxdir = 'build-aux'
-        config.setAuxDir(auxdir)
-        testdir = classes.GLTestDir(config, destdir)
-        testdir.execute()
-
-    elif mode == 'create-megatestdir':
-        if not destdir:
-            message = '%s: *** ' % constants.APP['name']
-            message += 'please specify --dir option\n'
-            message += '%s: *** Stop.\n' % constants.APP['name']
-            sys.stderr.write(message)
-            sys.exit(1)
-        if not auxdir:
-            auxdir = 'build-aux'
-        config.setAuxDir(auxdir)
-        testdir = classes.GLMegaTestDir(config, destdir)
-        testdir.execute()
-
-    elif mode == 'test':
-        if not destdir:
-            destdir = 'testdir%04d' % random.randrange(0, 9999)
-        if not auxdir:
-            auxdir = 'build-aux'
-        config.setAuxDir(auxdir)
-        testdir = classes.GLTestDir(config, destdir)
-        testdir.execute()
-        os.chdir(destdir)
-        os.mkdir('build')
-        os.chdir('build')
-        try:  # Try to execute commands
-            sp.call(['../configure'])
-            sp.call([UTILS['make']])
-            sp.call([UTILS['make'], 'check'])
-            sp.call([UTILS['make'], 'distclean'])
-        except Exception as error:
-            sys.exit(1)
-        args = ['find', '.', '-type', 'f', '-print']
-        remaining = sp.check_output(args).decode(ENCS['shell'])
-        lines = [ line.strip()
-                  for line in remaining.split('\n')
-                  if line.strip() ]
-        remaining = ' '.join(lines)
-        if remaining:
-            message = 'Remaining files: %s\n' % remaining
-            message += 'gnulib-tool: *** Stop.\n'
-            sys.stderr.write(message)
-            sys.exit(1)
-        os.chdir('../..')
-        sp.call(['rm', '-rf', destdir], shell=False)
-
-    elif mode == 'megatest':
-        if not destdir:
-            destdir = 'testdir %04d' % random.randrange(0, 9999)
-        if not auxdir:
-            auxdir = 'build-aux'
-        config.setAuxDir(auxdir)
-        testdir = classes.GLMegaTestDir(config, destdir)
-        testdir.execute()
-        os.chdir(destdir)
-        os.mkdir('build')
-        os.chdir('build')
-        sp.call(['../configure'])
-        sp.call([UTILS['make']])
-        sp.call([UTILS['make'], 'check'])
-        sp.call([UTILS['make'], 'distclean'])
-        args = ['find', '.', '-type', 'f', '-print']
-        remaining = sp.check_output(args).decode(ENCS['shell'])
-        lines = [ line.strip()
-                  for line in remaining.split('\n')
-                  if line.strip() ]
-        remaining = ' '.join(lines)
-        if remaining:
-            message = 'Remaining files: %s\n' % remaining
-            message += 'gnulib-tool: *** Stop.\n'
-            sys.stderr.write(message)
-            sys.exit(1)
-        os.chdir('../..')
-        sp.call(['rm', '-rf', destdir], shell=False)
-
-    elif mode == 'extract-description':
-        modulesystem = classes.GLModuleSystem(config)
-        for name in modules:
-            module = modulesystem.find(name)
-            if module:
-                sys.stdout.write(module.getDescription())
-
-    elif mode == 'extract-comment':
-        modulesystem = classes.GLModuleSystem(config)
-        for name in modules:
-            module = modulesystem.find(name)
-            if module:
-                sys.stdout.write(module.getComment())
-
-    elif mode == 'extract-status':
-        modulesystem = classes.GLModuleSystem(config)
-        for name in modules:
-            module = modulesystem.find(name)
-            if module:
-                sys.stdout.write(module.getStatus())
-
-    elif mode == 'extract-notice':
-        modulesystem = classes.GLModuleSystem(config)
-        for name in modules:
-            module = modulesystem.find(name)
-            if module:
-                sys.stdout.write(module.getNotice())
-
-    elif mode == 'extract-applicability':
-        modulesystem = classes.GLModuleSystem(config)
-        for name in modules:
-            module = modulesystem.find(name)
-            if module:
-                print(module.getApplicability())
-
-    elif mode == 'extract-filelist':
-        modulesystem = classes.GLModuleSystem(config)
-        for name in modules:
-            module = modulesystem.find(name)
-            if module:
-                files = module.getFiles()
-                print('\n'.join(files))
-
-    elif mode == 'extract-dependencies':
-        if avoids:
-            message = '%s: *** ' % constants.APP['name']
-            message += 'cannot combine --avoid and --extract-dependencies\n'
-            message += '%s: *** Stop.\n' % constants.APP['name']
-            sys.stderr.write(message)
-            sys.exit(1)
-        modulesystem = classes.GLModuleSystem(config)
-        for name in modules:
-            module = modulesystem.find(name)
-            if module:
-                sys.stdout.write(module.getDependencies())
-
-    elif mode == 'extract-autoconf-snippet':
-        modulesystem = classes.GLModuleSystem(config)
-        for name in modules:
-            module = modulesystem.find(name)
-            if module:
-                sys.stdout.write(module.getAutoconfSnippet())
-
-    elif mode == 'extract-automake-snippet':
-        modulesystem = classes.GLModuleSystem(config)
-        for name in modules:
-            module = modulesystem.find(name)
-            if module:
-                sys.stdout.write(module.getAutomakeSnippet())
-
-    elif mode == 'extract-include-directive':
-        modulesystem = classes.GLModuleSystem(config)
-        for name in modules:
-            module = modulesystem.find(name)
-            if module:
-                sys.stdout.write(module.getInclude())
-
-    elif mode == 'extract-link-directive':
-        modulesystem = classes.GLModuleSystem(config)
-        for name in modules:
-            module = modulesystem.find(name)
-            if module:
-                sys.stdout.write(module.getLink())
-
-    elif mode == 'extract-license':
-        modulesystem = classes.GLModuleSystem(config)
-        for name in modules:
-            module = modulesystem.find(name)
-            if module:
-                print(module.getLicense())
-
-    elif mode == 'extract-maintainer':
-        modulesystem = classes.GLModuleSystem(config)
-        for name in modules:
-            module = modulesystem.find(name)
-            if module:
-                sys.stdout.write(module.getMaintainer())
-
-    elif mode == 'extract-tests-module':
-        modulesystem = classes.GLModuleSystem(config)
-        for name in modules:
-            module = modulesystem.find(name)
-            if module:
-                if module.getTestsModule():
-                    print(module.getTestsName())
-
-    elif mode == 'copy-file':
-        srcpath = files[0]
-        # The second argument is the destination; either a directory ot a file.
-        # It defaults to the current directory.
-        if len(files) == 2:
-            dest = files[1]
-        else:  # if len(files) < 2
-            dest = '.'
-        if not auxdir:
-            auxdir = 'build-aux'
-        if not sourcebase:
-            sourcebase = 'lib'
-        if not m4base:
-            m4base = 'm4'
-        if not docbase:
-            docbase = 'doc'
-        if not testsbase:
-            testsbase = 'tests'
-        config.setAuxDir(auxdir)
-        config.setSourceBase(sourcebase)
-        config.setM4Base(m4base)
-        config.setDocBase(docbase)
-        config.setTestsBase(testsbase)
-        filesystem = classes.GLFileSystem(config)
-        lookedup, flag = filesystem.lookup(srcpath)
-        if isdir(dest):
-            destdir = dest
-            if srcpath.startswith('build-aux/'):
-                destpath = constants.substart('build-aux/', '%s/' % auxdir, srcpath)
-            elif srcpath.startswith('doc/'):
-                destpath = constants.substart('doc/', '%s/' % docbase, srcpath)
-            elif srcpath.startswith('lib/'):
-                destpath = constants.substart('lib/', '%s/' % sourcebase, srcpath)
-            elif srcpath.startswith('m4/'):
-                destpath = constants.substart('m4/', '%s/' % m4base, srcpath)
-            elif srcpath.startswith('tests/'):
-                destpath = constants.substart('tests/', '%s/' % testsbase, srcpath)
-            elif srcpath.startswith('top/'):
-                destpath = constants.substart('top/', '', srcpath)
-            else:  # either case
-                destpath = srcpath
-        else:  # if not isdir(dest)
-            destdir = os.path.dirname(dest)
-            destpath = os.path.basename(dest)
-        # Create the directory for destfile.
-        dirname = os.path.dirname(joinpath(destdir, destpath))
-        if not config['dryrun']:
-            if dirname and not isdir(dirname):
-                try:  # Try to create directories
-                    os.makedirs(dirname)
-                except FileExistsError:
-                    pass
-        # Copy the file.
-        assistant = classes.GLFileAssistant(config)
-        tmpfile = assistant.tmpfilename(destpath)
-        copyfile(lookedup, tmpfile)
-        assistant.setOriginal(srcpath)
-        assistant.config.setDestDir(destdir)
-        assistant.setRewritten(destpath)
-        if isfile(joinpath(destdir, destpath)):
-            # The file already exists.
-            assistant.update(lookedup, flag, tmpfile, True)
-        else:  # if not isfile(joinpath(destdir, destpath))
-            # Install the file.
-            # Don't protest if the file should be there but isn't: it happens
-            # frequently that developers don't put autogenerated files under
-            # version control.
-            assistant.add(lookedup, flag, tmpfile)
-        if isfile(tmpfile):
-            os.remove(tmpfile)
-
-    else:
-        message = '%s: *** ' % constants.APP['name']
-        message += 'no mode specified\n'
-        message += '%s: *** Stop.\n' % constants.APP['name']
-        sys.stderr.write(message)
-        sys.exit(1)
-
-
-if __name__ == '__main__':
-    try:  # Try to execute
-        main()
-    except classes.GLError as error:
-        errmode = 0  # gnulib-style errors
-        errno = error.errno
-        errinfo = error.errinfo
-        if errmode == 0:
-            message = '%s: *** ' % constants.APP['name']
-            if errinfo == None:
-                errinfo = ''
-            if errno == 1:
-                message += 'file %s not found' % errinfo
-            elif errno == 2:
-                message += 'patch file %s didn\'t apply cleanly' % errinfo
-            elif errno == 3:
-                message += 'cannot find %s - make sure you run gnulib-tool from within your package\'s directory' % errinfo
-            elif errno == 4:
-                message += 'minimum supported autoconf version is 2.59. Try adding'
-                message += 'AC_PREREQ([%s])' % constants.DEFAULT_AUTOCONF_MINVERSION
-                message += ' to your configure.ac.'
-            elif errno == 5:
-                message += '%s is expected to contain gl_M4_BASE([%s])' % (repr(os.path.join(errinfo, 'gnulib-comp.m4')), repr(errinfo))
-            elif errno == 6:
-                message += 'missing --source-base option'
-            elif errno == 7:
-                message += 'missing --doc-base option. --doc-base has been introduced '
-                message += 'on 2006-07-11; if your last invocation of \'gnulib-tool '
-                message += '--import\' is before that date, you need to run'
-                message += '\'gnulib-tool --import\' once, with a --doc-base option.'
-            elif errno == 8:
-                message += 'missing --tests-base option'
-            elif errno == 9:
-                message += 'missing --lib option'
-            elif errno == 10:
-                message = 'gnulib-tool: option --conditional-dependencies is not supported with --with-tests'
-            elif errno == 11:
-                incompatibilities = ''
-                message += 'incompatible license on modules:%s' % constants.NL
-                for pair in errinfo:
-                    incompatibilities += pair[0]
-                    incompatibilities += ' %s' % pair[1]
-                    incompatibilities += constants.NL
-                tempname = mktemp()
-                with codecs.open(tempname, 'wb', 'UTF-8') as file:
-                    file.write(incompatibilities)
-                sed_table = 's,^\\([^ ]*\\) ,\\1' + ' ' * 51 + ',\n'
-                sed_table += 's,^\\(' + '.' * 49 + '[^ ]*\\) *,' + ' ' * 17 + '\\1 ,'
-                args = ['sed', '-e', sed_table, tempname]
-                incompatibilities = sp.check_output(args).decode(ENCS['default'])
-                message += incompatibilities
-                os.remove(tempname)
-            elif errno == 12:
-                message += 'refusing to do nothing'
-            elif errno == 13:
-                message += 'could not create directory %s' % errinfo
-            elif errno == 14:
-                message += 'could not delete file %s' % errinfo
-            elif errno == 15:
-                message += 'could not create file %s' % errinfo
-            elif errno == 16:
-                message += 'could not transform file %s' % errinfo
-            elif errno == 17:
-                message += 'could not update file %s' % errinfo
-            elif errno == 18:
-                message += 'module %s lacks a license' % errinfo
-            elif errno == 19:
-                message += 'could not create destination directory: %s' % errinfo
-            message += '\n%s: *** Stop.\n' % constants.APP['name']
-            sys.stderr.write(message)
-            sys.exit(1)
+# This program invokes the Python rewrite of gnulib-tool.
+# It is meant to behave identically to gnulib-tool, just faster.
+
+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 OSF/1 and Solaris loses all empty fields (at the
+      #     beginning, at the end, and in the middle),
+      #   - /bin/sh on IRIX and /bin/ksh on IRIX and OSF/1 lose empty fields
+      #     at the beginning and at the end,
+      #   - 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,/[^/]*$,,'`
+}
+
+func_gnulib_dir
+
+# Setting the PYTHONPATH environment variable is needed to avoid an error:
+#   from . import constants          =>   ImportError: attempted relative import with no known parent package
+#   from pygnulib import constants   =>   ModuleNotFoundError: No module named 'pygnulib'
+# Explanation: https://stackoverflow.com/questions/16981921/relative-imports-in-python-3
+exec env PYTHONPATH="$gnulib_dir" python3 "$gnulib_dir/pygnulib/main.py" "$@"
index a5554956c1d47a418bcb10552a348f02f8c11415..22430f0df3ee6e8430453002b174ac0a7fcbffa9 100644 (file)
@@ -72,13 +72,12 @@ if ENCS['shell'] == None:
     ENCS['shell'] = 'UTF-8'
 
 # Set APP dictionary
-APP['name'] = sys.argv[0]
-if not APP['name']:
-    APP['name'] = 'gnulib-tool.py'
-APP['path'] = os.path.realpath(sys.argv[0])
+APP['path'] = os.path.realpath(sys.argv[0])                 # file name of <gnulib>/pygnulib/main.py
+APP['root'] = os.path.dirname(os.path.dirname(APP['path'])) # file name of <gnulib>
+APP['name'] = os.path.join(APP['root'], 'gnulib-tool.py')
 
-# Set DIRS dictionary
-DIRS['root'] = os.path.dirname(APP['path'])
+# Set DIRS directory
+DIRS['root'] = APP['root']
 DIRS['cwd'] = os.getcwd()
 DIRS['build-aux'] = os.path.join(DIRS['root'], 'build-aux')
 DIRS['config'] = os.path.join(DIRS['root'], 'config')
diff --git a/pygnulib/main.py b/pygnulib/main.py
new file mode 100644 (file)
index 0000000..3d615dd
--- /dev/null
@@ -0,0 +1,1248 @@
+# Copyright (C) 2002-2024 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 is meant for authors or maintainers which want to import
+# modules from gnulib into their packages.
+
+# CODING STYLE for this file and its companions:
+# Like PEP 8 <https://peps.python.org/pep-0008/>, except
+# - Line length is not limited to 79 characters.
+# - Line breaking before or after binary operators? Better before, like in GNU.
+# - Place line breaks to help reading the code:
+#   Avoid line breaks inside expressions, if they can be avoided.
+#   Do use line breaks to separate the parts of [ ... for ... ] iterations.
+# You can use this command to check the style:
+#   $ pycodestyle --max-line-length=136 --ignore=E265,W503,E241,E711,E712,E201,E202,E221 pygnulib/*.py
+
+# You can use this command to check for mistakes:
+#   $ pylint --disable=C0103,C0114,C0121,C0209,C0301,C0302,R0902,R0912,R0913,R0914,R0915,R1705,R1702,R1720 pygnulib/*.py
+
+
+#===============================================================================
+# Define global imports
+#===============================================================================
+import os
+import re
+import sys
+import codecs
+import random
+import argparse
+import subprocess as sp
+import shlex
+from tempfile import mktemp
+from pygnulib import constants
+from pygnulib import classes
+
+
+#===============================================================================
+# Define global constants
+#===============================================================================
+APP = constants.APP
+DIRS = constants.DIRS
+ENCS = constants.ENCS
+UTILS = constants.UTILS
+MODES = constants.MODES
+TESTS = constants.TESTS
+joinpath = constants.joinpath
+copyfile = constants.copyfile
+isabs = os.path.isabs
+isdir = os.path.isdir
+isfile = os.path.isfile
+
+
+#===============================================================================
+# Define main part
+#===============================================================================
+def main():
+    info = classes.GLInfo()
+    parser = argparse.ArgumentParser(
+        prog=constants.APP['name'],
+        usage='gnulib-tool.py --help',
+        add_help=False)
+
+    # Here we list the options in the order they are listed in the --help output.
+
+    # list
+    parser.add_argument('--list',
+                        dest='mode_list',
+                        default=None,
+                        action='store_true')
+    # find
+    parser.add_argument('--find',
+                        dest='mode_find',
+                        default=None,
+                        action='store_true')
+    # import
+    parser.add_argument('--import',
+                        dest='mode_import',
+                        default=None,
+                        action='store_true')
+    # add-import
+    parser.add_argument('--add-import',
+                        dest='mode_add_import',
+                        default=None,
+                        action='store_true')
+    # remove-import
+    parser.add_argument('--remove-import',
+                        dest='mode_remove_import',
+                        default=None,
+                        action='store_true')
+    # update
+    parser.add_argument('--update',
+                        dest='mode_update',
+                        default=None,
+                        action='store_true')
+    # create-testdir
+    parser.add_argument('--create-testdir',
+                        dest='mode_create_testdir',
+                        default=None,
+                        action='store_true')
+    # create-megatestdir
+    parser.add_argument('--create-megatestdir',
+                        dest='mode_create_megatestdir',
+                        default=None,
+                        action='store_true')
+    # test
+    parser.add_argument('--test',
+                        dest='mode_test',
+                        default=None,
+                        action='store_true')
+    # megatest
+    parser.add_argument('--megatest',
+                        dest='mode_megatest',
+                        default=None,
+                        action='store_true')
+    # extract-*
+    parser.add_argument('--extract-description',
+                        dest='mode_xdescription',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--extract-comment',
+                        dest='mode_xcomment',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--extract-status',
+                        dest='mode_xstatus',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--extract-notice',
+                        dest='mode_xnotice',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--extract-applicability',
+                        dest='mode_xapplicability',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--extract-filelist',
+                        dest='mode_xfilelist',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--extract-dependencies',
+                        dest='mode_xdependencies',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--extract-autoconf-snippet',
+                        dest='mode_xautoconf',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--extract-automake-snippet',
+                        dest='mode_xautomake',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--extract-include-directive',
+                        dest='mode_xinclude',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--extract-link-directive',
+                        dest='mode_xlink',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--extract-license',
+                        dest='mode_xlicense',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--extract-maintainer',
+                        dest='mode_xmaintainer',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--extract-tests-module',
+                        dest='mode_xtests',
+                        default=None,
+                        action='store_true')
+    # copy-file
+    parser.add_argument('--copy-file',
+                        dest='mode_copy_file',
+                        default=None,
+                        action='store_true')
+    # help
+    parser.add_argument('--help', '--hel', '--he', '--h',
+                        dest='help',
+                        default=None,
+                        action='store_true')
+    # version
+    parser.add_argument('--version', '--versio', '--versi', '--vers',
+                        dest='version',
+                        default=None,
+                        action='store_true')
+    # no-changelog: a no-op for backward compatibility
+    parser.add_argument('--no-changelog',
+                        dest='changelog',
+                        default=None,
+                        action='store_false')
+    # destdir
+    parser.add_argument('--dir',
+                        dest='destdir',
+                        default=None,
+                        nargs=1)
+    # localpath
+    parser.add_argument('--local-dir',
+                        action='append',
+                        dest='localpath',
+                        default=None,
+                        nargs=1)
+    # cache-modules: a no-op for backward compatibility
+    parser.add_argument('--cache-modules',
+                        dest='cache_modules',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--no-cache-modules',
+                        dest='cache_modules',
+                        default=None,
+                        action='store_false')
+    # verbose
+    parser.add_argument('--verbose',
+                        default=0,
+                        action='count')
+    # quiet
+    parser.add_argument('--quiet',
+                        default=0,
+                        action='count')
+    # dryrun
+    parser.add_argument('--dry-run',
+                        dest='dryrun',
+                        default=None,
+                        action='store_true')
+    # inctests
+    parser.add_argument('--with-tests',
+                        dest='inctests',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--without-tests',
+                        dest='inctests',
+                        default=None,
+                        action='store_false')
+    # obsolete
+    parser.add_argument('--with-obsolete',
+                        dest='obsolete',
+                        default=None,
+                        action='store_true')
+    # c++-tests
+    parser.add_argument('--with-c++-tests',
+                        dest='inc_cxx_tests',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--without-c++-tests',
+                        dest='excl_cxx_tests',
+                        default=None,
+                        action='store_true')
+    # longrunning-tests
+    parser.add_argument('--with-longrunning-tests',
+                        dest='inc_longrunning_tests',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--without-longrunning-tests',
+                        dest='excl_longrunning_tests',
+                        default=None,
+                        action='store_true')
+    # privileged-tests
+    parser.add_argument('--with-privileged-tests',
+                        dest='inc_privileged_tests',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--without-privileged-tests',
+                        dest='excl_privileged_tests',
+                        default=None,
+                        action='store_true')
+    # unportable-tests
+    parser.add_argument('--with-unportable-tests',
+                        dest='inc_unportable_tests',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--without-unportable-tests',
+                        dest='excl_unportable_tests',
+                        default=None,
+                        action='store_true')
+    # all-tests
+    parser.add_argument('--with-all-tests',
+                        dest='alltests',
+                        default=None,
+                        action='store_true')
+    # avoids
+    parser.add_argument('--avoid',
+                        dest='avoids',
+                        default=None,
+                        action='append',
+                        nargs=1)
+    # conditional-dependencies
+    parser.add_argument('--conditional-dependencies',
+                        dest='cond_dependencies',
+                        default=None,
+                        action="store_true")
+    parser.add_argument('--no-conditional-dependencies',
+                        dest='cond_dependencies',
+                        default=None,
+                        action="store_false")
+    # libtool
+    parser.add_argument('--libtool',
+                        dest='libtool',
+                        default=None,
+                        action="store_true")
+    parser.add_argument('--no-libtool',
+                        dest='libtool',
+                        default=None,
+                        action="store_false")
+    # libname
+    parser.add_argument('--lib',
+                        dest='libname',
+                        default=None,
+                        nargs=1)
+    # sourcebase
+    parser.add_argument('--source-base',
+                        dest='sourcebase',
+                        default=None,
+                        nargs=1)
+    # m4base
+    parser.add_argument('--m4-base',
+                        dest='m4base',
+                        default=None,
+                        nargs=1)
+    # pobase
+    parser.add_argument('--po-base',
+                        dest='pobase',
+                        default=None,
+                        nargs=1)
+    # docbase
+    parser.add_argument('--doc-base',
+                        dest='docbase',
+                        default=None,
+                        nargs=1)
+    # testsbase
+    parser.add_argument('--tests-base',
+                        dest='testsbase',
+                        default=None,
+                        nargs=1)
+    # auxdir
+    parser.add_argument('--aux-dir',
+                        dest='auxdir',
+                        default=None,
+                        nargs=1)
+    # lgpl
+    parser.add_argument('--lgpl',
+                        dest='lgpl',
+                        default=None,
+                        action='append',
+                        choices=['2', '3orGPLv2', '3'],
+                        nargs='?')
+    # gnu-make
+    parser.add_argument('--gnu-make',
+                        dest='gnu_make',
+                        default=None,
+                        action='store_true')
+    # makefile-name
+    parser.add_argument('--makefile-name',
+                        dest='makefile_name',
+                        default=None,
+                        nargs=1)
+    # macro-prefix
+    parser.add_argument('--macro-prefix',
+                        dest='macro_prefix',
+                        default=None,
+                        nargs=1)
+    # po-domain
+    parser.add_argument('--po-domain',
+                        dest='podomain',
+                        default=None,
+                        nargs=1)
+    # witness-c-macro
+    parser.add_argument('--witness-c-macro',
+                        dest='witness_c_macro',
+                        default=None,
+                        nargs=1)
+    # vc-files
+    parser.add_argument('--vc-files',
+                        dest='vc_files',
+                        default=None,
+                        action='store_true')
+    parser.add_argument('--no-vc-files',
+                        dest='vc_files',
+                        default=None,
+                        action='store_false')
+    # single-configure
+    parser.add_argument('--single-configure',
+                        dest='single_configure',
+                        default=None,
+                        action='store_true')
+    # symlink
+    parser.add_argument('-s', '--symbolic', '--symlink',
+                        dest='symlink',
+                        default=None,
+                        action='store_true')
+    # local-symlink
+    parser.add_argument('--local-symlink',
+                        dest='lsymlink',
+                        default=None,
+                        action='store_true')
+    # All other arguments are collected.
+    parser.add_argument("non_option_arguments",
+                        nargs='*')
+
+    # Parse the given arguments. Don't signal an error if non-option arguments
+    # occur between or after options.
+    cmdargs, unhandled = parser.parse_known_args()
+
+    # Handle --help and --version, ignoring all other options.
+    if cmdargs.help != None:
+        print(info.usage())
+        sys.exit(0)
+    if cmdargs.version != None:
+        version = info.version()
+        if version != '':
+            version = ' ' + version
+        message = '''gnulib-tool (%s %s)%s\n%s\n%s\n\nWritten by %s.''' \
+            % (info.package(), info.date(), version, info.copyright(),
+               info.license(), info.authors())
+        print(message)
+        sys.exit(0)
+
+    # Report unhandled arguments.
+    for arg in unhandled:
+        if arg.startswith('-'):
+            message = '%s: Unrecognized option \'%s\'.\n' % (constants.APP['name'], arg)
+            message += 'Try \'gnulib-tool --help\' for more information.\n'
+            sys.stderr.write(message)
+            sys.exit(1)
+    # By now, all unhandled arguments were non-options.
+    cmdargs.non_option_arguments += unhandled
+
+    # Determine when user tries to combine modes.
+    args = [
+        cmdargs.mode_list,
+        cmdargs.mode_find,
+        cmdargs.mode_import,
+        cmdargs.mode_add_import,
+        cmdargs.mode_remove_import,
+        cmdargs.mode_update,
+        cmdargs.mode_create_testdir,
+        cmdargs.mode_create_megatestdir,
+        cmdargs.mode_test,
+        cmdargs.mode_megatest,
+        cmdargs.mode_xdescription,
+        cmdargs.mode_xcomment,
+        cmdargs.mode_xstatus,
+        cmdargs.mode_xnotice,
+        cmdargs.mode_xapplicability,
+        cmdargs.mode_xfilelist,
+        cmdargs.mode_xdependencies,
+        cmdargs.mode_xautoconf,
+        cmdargs.mode_xautomake,
+        cmdargs.mode_xinclude,
+        cmdargs.mode_xlink,
+        cmdargs.mode_xlicense,
+        cmdargs.mode_xmaintainer,
+        cmdargs.mode_xtests,
+        cmdargs.mode_copy_file,
+    ]
+    overflow = [ arg
+                 for arg in args
+                 if arg != None ]
+    if len(overflow) > 1:
+        message = '%s: Unable to combine different modes of work.\n' % constants.APP['name']
+        message += 'Try \'gnulib-tool --help\' for more information.\n'
+        sys.stderr.write(message)
+        sys.exit(1)
+
+    # Determine selected mode.
+    mode = None
+    modules = None
+    files = None
+    if cmdargs.mode_list != None:
+        mode = 'list'
+    if cmdargs.mode_find != None:
+        mode = 'find'
+        files = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_import != None:
+        mode = 'import'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_add_import != None:
+        mode = 'add-import'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_remove_import != None:
+        mode = 'remove-import'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_update != None:
+        mode = 'update'
+        if len(cmdargs.non_option_arguments) > 0:
+            message = '%s: too many arguments in \'update\' mode\n'
+            message += 'Try \'gnulib-tool --help\' for more information.\n'
+            message += 'If you really want to modify the gnulib configuration of your project,\n'
+            message += 'you need to use \'gnulib-tool --import\' - at your own risk!\n'
+            sys.stderr.write(message)
+            sys.exit(1)
+    if cmdargs.mode_create_testdir != None:
+        mode = 'create-testdir'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_create_megatestdir != None:
+        mode = 'create-megatestdir'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_test != None:
+        mode = 'test'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_megatest != None:
+        mode = 'megatest'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_xdescription != None:
+        mode = 'extract-description'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_xcomment != None:
+        mode = 'extract-comment'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_xstatus != None:
+        mode = 'extract-status'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_xnotice != None:
+        mode = 'extract-notice'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_xapplicability != None:
+        mode = 'extract-applicability'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_xfilelist != None:
+        mode = 'extract-filelist'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_xautoconf != None:
+        mode = 'extract-autoconf-snippet'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_xautomake != None:
+        mode = 'extract-automake-snippet'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_xdependencies != None:
+        mode = 'extract-dependencies'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_xinclude != None:
+        mode = 'extract-include-directive'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_xlink != None:
+        mode = 'extract-link-directive'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_xlicense != None:
+        mode = 'extract-license'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_xmaintainer != None:
+        mode = 'extract-maintainer'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_xtests != None:
+        mode = 'extract-tests-module'
+        modules = list(cmdargs.non_option_arguments)
+    if cmdargs.mode_copy_file != None:
+        mode = 'copy-file'
+        if len(cmdargs.non_option_arguments) < 1 or len(cmdargs.non_option_arguments) > 2:
+            message = '%s: *** ' % constants.APP['name']
+            message += 'invalid number of arguments for --%s\n' % mode
+            message += 'Try \'gnulib-tool --help\' for more information.\n'
+            message += '%s: *** Stop.\n' % constants.APP['name']
+            sys.stderr.write(message)
+            sys.exit(1)
+        files = list(cmdargs.non_option_arguments)
+
+    if ((mode in ['import', 'add-import', 'remove-import']
+         and (cmdargs.excl_cxx_tests or cmdargs.excl_longrunning_tests
+              or cmdargs.excl_privileged_tests or cmdargs.excl_unportable_tests
+              or cmdargs.single_configure))
+        or (mode == 'update'
+            and (cmdargs.localpath != None or cmdargs.libname != None
+                 or cmdargs.sourcebase != None or cmdargs.m4base != None
+                 or cmdargs.pobase != None or cmdargs.docbase != None
+                 or cmdargs.testsbase != None or cmdargs.auxdir != None
+                 or cmdargs.inctests != None or cmdargs.obsolete != None
+                 or cmdargs.inc_cxx_tests != None
+                 or cmdargs.inc_longrunning_tests != None
+                 or cmdargs.inc_privileged_tests != None
+                 or cmdargs.inc_unportable_tests != None
+                 or cmdargs.alltests != None
+                 or cmdargs.excl_cxx_tests != None
+                 or cmdargs.excl_longrunning_tests != None
+                 or cmdargs.excl_privileged_tests != None
+                 or cmdargs.excl_unportable_tests != None
+                 or cmdargs.avoids != None or cmdargs.lgpl != None
+                 or cmdargs.makefile_name != None
+                 or cmdargs.macro_prefix != None or cmdargs.podomain != None
+                 or cmdargs.witness_c_macro != None or cmdargs.vc_files != None))):
+        message = '%s: *** ' % constants.APP['name']
+        message += 'invalid options for --%s mode\n' % mode
+        message += 'Try \'gnulib-tool --help\' for more information.\n'
+        message += '%s: *** Stop.\n' % constants.APP['name']
+        sys.stderr.write(message)
+        sys.exit(1)
+    if cmdargs.pobase != None and cmdargs.podomain == None:
+        message = '%s: *** ' % constants.APP['name']
+        message += 'together with --po-base, you need to specify --po-domain\n'
+        message += 'Try \'gnulib-tool --help\' for more information.\n'
+        message += '%s: *** Stop.\n' % constants.APP['name']
+        sys.stderr.write(message)
+        sys.exit(1)
+    if cmdargs.pobase == None and cmdargs.podomain != None:
+        message = '%s: warning: --po-domain has no effect without a --po-base option\n' % constants.APP['name']
+        sys.stderr.write(message)
+    if mode != None and 'test' in mode and gnu_make:
+        message = '%s: --gnu-make not supported when including tests\n' % constants.APP['name']
+        sys.stderr.write(message)
+        sys.exit(1)
+
+    # Determine specific settings.
+    destdir = cmdargs.destdir
+    if destdir != None:
+        destdir = cmdargs.destdir[0]
+    localpath = cmdargs.localpath
+    if localpath != None:
+        localpath = [ dir
+                      for list1 in localpath
+                      for dir in list1 ]
+    libname = cmdargs.libname
+    if libname != None:
+        libname = cmdargs.libname[0]
+    auxdir = cmdargs.auxdir
+    if auxdir != None:
+        auxdir = cmdargs.auxdir[0]
+    sourcebase = cmdargs.sourcebase
+    if sourcebase != None:
+        sourcebase = cmdargs.sourcebase[0]
+    m4base = cmdargs.m4base
+    if m4base != None:
+        m4base = cmdargs.m4base[0]
+    pobase = cmdargs.pobase
+    if pobase != None:
+        pobase = cmdargs.pobase[0]
+    testsbase = cmdargs.testsbase
+    if testsbase != None:
+        testsbase = cmdargs.testsbase[0]
+    dryrun = cmdargs.dryrun
+    verbose = -cmdargs.quiet + cmdargs.verbose
+    inctests = cmdargs.inctests
+    # Canonicalize the inctests variable.
+    if inctests == None:
+        if mode in ['import', 'add-import', 'remove-import', 'update']:
+            inctests = False
+        elif mode in ['create-testdir', 'create-megatestdir', 'test', 'megatest']:
+            inctests = True
+    incl_test_categories = []
+    if inctests:
+        incl_test_categories += [constants.TESTS['tests']]
+    if cmdargs.obsolete:
+        incl_test_categories += [constants.TESTS['obsolete']]
+    if cmdargs.inc_cxx_tests:
+        incl_test_categories += [constants.TESTS['cxx-tests']]
+    if cmdargs.inc_longrunning_tests:
+        incl_test_categories += [constants.TESTS['longrunning-tests']]
+    if cmdargs.inc_privileged_tests:
+        incl_test_categories += [constants.TESTS['privileged-tests']]
+    if cmdargs.inc_unportable_tests:
+        incl_test_categories += [constants.TESTS['unportable-tests']]
+    if cmdargs.alltests:
+        incl_test_categories += [constants.TESTS['all-tests']]
+    excl_test_categories = []
+    if cmdargs.excl_cxx_tests:
+        excl_test_categories += [constants.TESTS['cxx-tests']]
+    if cmdargs.excl_longrunning_tests:
+        excl_test_categories += [constants.TESTS['longrunning-tests']]
+    if cmdargs.excl_privileged_tests:
+        excl_test_categories += [constants.TESTS['privileged-tests']]
+    if cmdargs.excl_unportable_tests:
+        excl_test_categories += [constants.TESTS['unportable-tests']]
+    lgpl = cmdargs.lgpl
+    if lgpl != None:
+        lgpl = lgpl[-1]
+        if lgpl == None:
+            lgpl = True
+    cond_dependencies = cmdargs.cond_dependencies
+    libtool = cmdargs.libtool
+    gnu_make = cmdargs.gnu_make == True
+    makefile_name = cmdargs.makefile_name
+    if makefile_name != None:
+        makefile_name = makefile_name[0]
+    macro_prefix = cmdargs.macro_prefix
+    if macro_prefix != None:
+        macro_prefix = macro_prefix[0]
+    podomain = cmdargs.podomain
+    if podomain != None:
+        podomain = podomain[0]
+    witness_c_macro = cmdargs.witness_c_macro
+    if witness_c_macro != None:
+        witness_c_macro = witness_c_macro[0]
+    vc_files = cmdargs.vc_files
+    avoids = cmdargs.avoids
+    if avoids != None:
+        avoids = [ module
+                   for list1 in avoids
+                   for module in list1 ]
+    symlink = cmdargs.symlink == True
+    lsymlink = cmdargs.lsymlink == True
+    single_configure = cmdargs.single_configure
+    docbase = None
+
+    # Create pygnulib configuration.
+    config = classes.GLConfig(
+        destdir=destdir,
+        localpath=localpath,
+        m4base=m4base,
+        auxdir=auxdir,
+        modules=modules,
+        avoids=avoids,
+        sourcebase=sourcebase,
+        pobase=pobase,
+        docbase=docbase,
+        testsbase=testsbase,
+        incl_test_categories=incl_test_categories,
+        excl_test_categories=excl_test_categories,
+        libname=libname,
+        lgpl=lgpl,
+        gnu_make=gnu_make,
+        makefile_name=makefile_name,
+        libtool=libtool,
+        conddeps=cond_dependencies,
+        macro_prefix=macro_prefix,
+        podomain=podomain,
+        witness_c_macro=witness_c_macro,
+        vc_files=vc_files,
+        symbolic=symlink,
+        lsymbolic=lsymlink,
+        single_configure=single_configure,
+        verbose=verbose,
+        dryrun=dryrun,
+    )
+
+    # Work in the given mode.
+    if mode == 'list':
+        modulesystem = classes.GLModuleSystem(config)
+        listing = modulesystem.list()
+        result = '\n'.join(listing)
+        os.rmdir(config['tempdir'])
+        print(result)
+
+    elif mode == 'find':
+        modulesystem = classes.GLModuleSystem(config)
+        for filename in files:
+            if (isfile(joinpath(DIRS['root'], filename))
+                    or (localpath != None
+                        and any([ isfile(joinpath(localdir, filename))
+                                  for localdir in localpath ]))):
+                # Convert the file name to a POSIX basic regex.
+                # Needs to handle . [ \ * ^ $.
+                filename_regex = filename.replace('\\', '\\\\').replace('[', '\\[').replace('^', '\\^')
+                filename_regex = re.compile('([.*$])').sub('[\\1]', filename_regex)
+                filename_line_regex = '^' + filename_regex + '$'
+                # Read module candidates from gnulib root directory.
+                command = "find modules -type f -print | xargs -n 100 grep -l %s /dev/null | sed -e 's,^modules/,,'" % shlex.quote(filename_line_regex)
+                os.chdir(constants.DIRS['root'])
+                with sp.Popen(command, shell=True, stdout=sp.PIPE) as proc:
+                    result = proc.stdout.read().decode("UTF-8")
+                os.chdir(DIRS['cwd'])
+                # Read module candidates from local directories.
+                if localpath != None and len(localpath) > 0:
+                    command = "find modules -type f -print | xargs -n 100 grep -l %s /dev/null | sed -e 's,^modules/,,' -e 's,\\.diff$,,'" % shlex.quote(filename_line_regex)
+                    for localdir in localpath:
+                        os.chdir(localdir)
+                        with sp.Popen(command, shell=True, stdout=sp.PIPE) as proc:
+                            result += proc.stdout.read().decode("UTF-8")
+                        os.chdir(DIRS['cwd'])
+                listing = [ line
+                            for line in result.split('\n')
+                            if line.strip() ]
+                # Remove modules/ prefix from each file name.
+                pattern = re.compile('^modules/')
+                listing = [ pattern.sub('', line)
+                            for line in listing ]
+                # Filter out undesired file names.
+                listing = [ line
+                            for line in listing
+                            if modulesystem.file_is_module(line) ]
+                candidates = sorted(set(listing))
+                for name in candidates:
+                    module = modulesystem.find(name)
+                    if module:  # Ignore module candidates that don't actually exist.
+                        if module.getFiles():
+                            print(name)
+            else:
+                message = '%s: warning: file %s does not exist\n' % (constants.APP['name'], filename)
+                sys.stderr.write(message)
+
+    elif mode in ['import', 'add-import', 'remove-import', 'update']:
+        mode = MODES[mode]
+        if not destdir:
+            destdir = '.'
+        config.setDestDir(destdir)
+
+        if mode == MODES['import']:
+            # Set variables to default values.
+            if not sourcebase:
+                sourcebase = 'lib'
+            if not m4base:
+                m4base = 'm4'
+            if not docbase:
+                docbase = 'doc'
+            if not testsbase:
+                testsbase = 'tests'
+            if not macro_prefix:
+                macro_prefix = 'gl'
+            config.setSourceBase(sourcebase)
+            config.setM4Base(m4base)
+            config.setDocBase(docbase)
+            config.setTestsBase(testsbase)
+            config.setMacroPrefix(macro_prefix)
+
+            # Perform GLImport actions.
+            importer = classes.GLImport(config, mode)
+            filetable, transformers = importer.prepare()
+            importer.execute(filetable, transformers)
+
+        else:  # if mode != MODE['--import']
+            if m4base:
+                if not isfile(joinpath(destdir, m4base, 'gnulib-cache.m4')):
+                    if not sourcebase:
+                        sourcebase = 'lib'
+                    if not docbase:
+                        docbase = 'doc'
+                    if not testsbase:
+                        testsbase = 'tests'
+                    if not macro_prefix:
+                        macro_prefix = 'gl'
+                    config.setSourceBase(sourcebase)
+                    config.setM4Base(m4base)
+                    config.setDocBase(docbase)
+                    config.setTestsBase(testsbase)
+                    config.setMacroPrefix(macro_prefix)
+                # Perform GLImport actions.
+                importer = classes.GLImport(config, mode)
+                filetable, transformers = importer.prepare()
+                importer.execute(filetable, transformers)
+            else:  # if not m4base
+                m4dirs = list()
+                dirisnext = bool()
+                filepath = joinpath(destdir, 'Makefile.am')
+                if isfile(filepath):
+                    with codecs.open(filepath, 'rb', 'UTF-8') as file:
+                        data = file.read()
+                        data = data.split('ACLOCAL_AMFLAGS')[1]
+                        data = data[data.find('=') + 1:data.find('\n')]
+                    aclocal_amflags = data.split()
+                    for aclocal_amflag in aclocal_amflags:
+                        if dirisnext:
+                            if not isabs(aclocal_amflag):
+                                m4dirs += [aclocal_amflag]
+                        else:  # if not dirisnext
+                            if aclocal_amflag == '-I':
+                                dirisnext = True
+                            else:  # if aclocal_amflag != '-I'
+                                dirisnext = False
+                else:  # if not isfile(filepath)
+                    filepath = joinpath(destdir, 'aclocal.m4')
+                    if isfile(filepath):
+                        pattern = re.compile(r'm4_include\(\[(.*?)\]\)')
+                        with codecs.open(filepath, 'rb', 'UTF-8') as file:
+                            m4dirs = pattern.findall(file.read())
+                        m4dirs = [ os.path.dirname(m4dir)
+                                   for m4dir in m4dirs ]
+                        m4dirs = [ m4dir
+                                   for m4dir in m4dirs
+                                   if isfile(joinpath(destdir, m4dir, 'gnulib-cache.m4')) ]
+                        m4dirs = sorted(set(m4dirs))
+                if len(m4dirs) == 0:
+                    # First use of gnulib in a package.
+                    # Any number of additional modules can be given.
+                    if not sourcebase:
+                        sourcebase = 'lib'
+                    m4base = 'm4'
+                    if not docbase:
+                        docbase = 'doc'
+                    if not testsbase:
+                        testsbase = 'tests'
+                    if not macro_prefix:
+                        macro_prefix = 'gl'
+                    config.setSourceBase(sourcebase)
+                    config.setM4Base(m4base)
+                    config.setDocBase(docbase)
+                    config.setTestsBase(testsbase)
+                    config.setMacroPrefix(macro_prefix)
+                    # Perform GLImport actions.
+                    importer = classes.GLImport(config, mode)
+                    filetable, transformers = importer.prepare()
+                    importer.execute(filetable, transformers)
+                elif len(m4dirs) == 1:
+                    m4base = m4dirs[-1]
+                    config.setM4Base(m4base)
+                    # Perform GLImport actions.
+                    importer = classes.GLImport(config, mode)
+                    filetable, transformers = importer.prepare()
+                    importer.execute(filetable, transformers)
+                else:  # if len(m4dirs) > 1
+                    for m4base in m4dirs:
+                        config.setM4Base(m4base)
+                        # Perform GLImport actions.
+                        importer = classes.GLImport(config, mode)
+                        filetable, transformers = importer.prepare()
+                        importer.execute(filetable, transformers)
+
+    elif mode == 'create-testdir':
+        if not destdir:
+            message = '%s: *** ' % constants.APP['name']
+            message += 'please specify --dir option\n'
+            message += '%s: *** Stop.\n' % constants.APP['name']
+            sys.stderr.write(message)
+            sys.exit(1)
+        if not auxdir:
+            auxdir = 'build-aux'
+        config.setAuxDir(auxdir)
+        testdir = classes.GLTestDir(config, destdir)
+        testdir.execute()
+
+    elif mode == 'create-megatestdir':
+        if not destdir:
+            message = '%s: *** ' % constants.APP['name']
+            message += 'please specify --dir option\n'
+            message += '%s: *** Stop.\n' % constants.APP['name']
+            sys.stderr.write(message)
+            sys.exit(1)
+        if not auxdir:
+            auxdir = 'build-aux'
+        config.setAuxDir(auxdir)
+        testdir = classes.GLMegaTestDir(config, destdir)
+        testdir.execute()
+
+    elif mode == 'test':
+        if not destdir:
+            destdir = 'testdir%04d' % random.randrange(0, 9999)
+        if not auxdir:
+            auxdir = 'build-aux'
+        config.setAuxDir(auxdir)
+        testdir = classes.GLTestDir(config, destdir)
+        testdir.execute()
+        os.chdir(destdir)
+        os.mkdir('build')
+        os.chdir('build')
+        try:  # Try to execute commands
+            sp.call(['../configure'])
+            sp.call([UTILS['make']])
+            sp.call([UTILS['make'], 'check'])
+            sp.call([UTILS['make'], 'distclean'])
+        except Exception as error:
+            sys.exit(1)
+        args = ['find', '.', '-type', 'f', '-print']
+        remaining = sp.check_output(args).decode(ENCS['shell'])
+        lines = [ line.strip()
+                  for line in remaining.split('\n')
+                  if line.strip() ]
+        remaining = ' '.join(lines)
+        if remaining:
+            message = 'Remaining files: %s\n' % remaining
+            message += 'gnulib-tool: *** Stop.\n'
+            sys.stderr.write(message)
+            sys.exit(1)
+        os.chdir('../..')
+        sp.call(['rm', '-rf', destdir], shell=False)
+
+    elif mode == 'megatest':
+        if not destdir:
+            destdir = 'testdir %04d' % random.randrange(0, 9999)
+        if not auxdir:
+            auxdir = 'build-aux'
+        config.setAuxDir(auxdir)
+        testdir = classes.GLMegaTestDir(config, destdir)
+        testdir.execute()
+        os.chdir(destdir)
+        os.mkdir('build')
+        os.chdir('build')
+        sp.call(['../configure'])
+        sp.call([UTILS['make']])
+        sp.call([UTILS['make'], 'check'])
+        sp.call([UTILS['make'], 'distclean'])
+        args = ['find', '.', '-type', 'f', '-print']
+        remaining = sp.check_output(args).decode(ENCS['shell'])
+        lines = [ line.strip()
+                  for line in remaining.split('\n')
+                  if line.strip() ]
+        remaining = ' '.join(lines)
+        if remaining:
+            message = 'Remaining files: %s\n' % remaining
+            message += 'gnulib-tool: *** Stop.\n'
+            sys.stderr.write(message)
+            sys.exit(1)
+        os.chdir('../..')
+        sp.call(['rm', '-rf', destdir], shell=False)
+
+    elif mode == 'extract-description':
+        modulesystem = classes.GLModuleSystem(config)
+        for name in modules:
+            module = modulesystem.find(name)
+            if module:
+                sys.stdout.write(module.getDescription())
+
+    elif mode == 'extract-comment':
+        modulesystem = classes.GLModuleSystem(config)
+        for name in modules:
+            module = modulesystem.find(name)
+            if module:
+                sys.stdout.write(module.getComment())
+
+    elif mode == 'extract-status':
+        modulesystem = classes.GLModuleSystem(config)
+        for name in modules:
+            module = modulesystem.find(name)
+            if module:
+                sys.stdout.write(module.getStatus())
+
+    elif mode == 'extract-notice':
+        modulesystem = classes.GLModuleSystem(config)
+        for name in modules:
+            module = modulesystem.find(name)
+            if module:
+                sys.stdout.write(module.getNotice())
+
+    elif mode == 'extract-applicability':
+        modulesystem = classes.GLModuleSystem(config)
+        for name in modules:
+            module = modulesystem.find(name)
+            if module:
+                print(module.getApplicability())
+
+    elif mode == 'extract-filelist':
+        modulesystem = classes.GLModuleSystem(config)
+        for name in modules:
+            module = modulesystem.find(name)
+            if module:
+                files = module.getFiles()
+                print('\n'.join(files))
+
+    elif mode == 'extract-dependencies':
+        if avoids:
+            message = '%s: *** ' % constants.APP['name']
+            message += 'cannot combine --avoid and --extract-dependencies\n'
+            message += '%s: *** Stop.\n' % constants.APP['name']
+            sys.stderr.write(message)
+            sys.exit(1)
+        modulesystem = classes.GLModuleSystem(config)
+        for name in modules:
+            module = modulesystem.find(name)
+            if module:
+                sys.stdout.write(module.getDependencies())
+
+    elif mode == 'extract-autoconf-snippet':
+        modulesystem = classes.GLModuleSystem(config)
+        for name in modules:
+            module = modulesystem.find(name)
+            if module:
+                sys.stdout.write(module.getAutoconfSnippet())
+
+    elif mode == 'extract-automake-snippet':
+        modulesystem = classes.GLModuleSystem(config)
+        for name in modules:
+            module = modulesystem.find(name)
+            if module:
+                sys.stdout.write(module.getAutomakeSnippet())
+
+    elif mode == 'extract-include-directive':
+        modulesystem = classes.GLModuleSystem(config)
+        for name in modules:
+            module = modulesystem.find(name)
+            if module:
+                sys.stdout.write(module.getInclude())
+
+    elif mode == 'extract-link-directive':
+        modulesystem = classes.GLModuleSystem(config)
+        for name in modules:
+            module = modulesystem.find(name)
+            if module:
+                sys.stdout.write(module.getLink())
+
+    elif mode == 'extract-license':
+        modulesystem = classes.GLModuleSystem(config)
+        for name in modules:
+            module = modulesystem.find(name)
+            if module:
+                print(module.getLicense())
+
+    elif mode == 'extract-maintainer':
+        modulesystem = classes.GLModuleSystem(config)
+        for name in modules:
+            module = modulesystem.find(name)
+            if module:
+                sys.stdout.write(module.getMaintainer())
+
+    elif mode == 'extract-tests-module':
+        modulesystem = classes.GLModuleSystem(config)
+        for name in modules:
+            module = modulesystem.find(name)
+            if module:
+                if module.getTestsModule():
+                    print(module.getTestsName())
+
+    elif mode == 'copy-file':
+        srcpath = files[0]
+        # The second argument is the destination; either a directory ot a file.
+        # It defaults to the current directory.
+        if len(files) == 2:
+            dest = files[1]
+        else:  # if len(files) < 2
+            dest = '.'
+        if not auxdir:
+            auxdir = 'build-aux'
+        if not sourcebase:
+            sourcebase = 'lib'
+        if not m4base:
+            m4base = 'm4'
+        if not docbase:
+            docbase = 'doc'
+        if not testsbase:
+            testsbase = 'tests'
+        config.setAuxDir(auxdir)
+        config.setSourceBase(sourcebase)
+        config.setM4Base(m4base)
+        config.setDocBase(docbase)
+        config.setTestsBase(testsbase)
+        filesystem = classes.GLFileSystem(config)
+        lookedup, flag = filesystem.lookup(srcpath)
+        if isdir(dest):
+            destdir = dest
+            if srcpath.startswith('build-aux/'):
+                destpath = constants.substart('build-aux/', '%s/' % auxdir, srcpath)
+            elif srcpath.startswith('doc/'):
+                destpath = constants.substart('doc/', '%s/' % docbase, srcpath)
+            elif srcpath.startswith('lib/'):
+                destpath = constants.substart('lib/', '%s/' % sourcebase, srcpath)
+            elif srcpath.startswith('m4/'):
+                destpath = constants.substart('m4/', '%s/' % m4base, srcpath)
+            elif srcpath.startswith('tests/'):
+                destpath = constants.substart('tests/', '%s/' % testsbase, srcpath)
+            elif srcpath.startswith('top/'):
+                destpath = constants.substart('top/', '', srcpath)
+            else:  # either case
+                destpath = srcpath
+        else:  # if not isdir(dest)
+            destdir = os.path.dirname(dest)
+            destpath = os.path.basename(dest)
+        # Create the directory for destfile.
+        dirname = os.path.dirname(joinpath(destdir, destpath))
+        if not config['dryrun']:
+            if dirname and not isdir(dirname):
+                try:  # Try to create directories
+                    os.makedirs(dirname)
+                except FileExistsError:
+                    pass
+        # Copy the file.
+        assistant = classes.GLFileAssistant(config)
+        tmpfile = assistant.tmpfilename(destpath)
+        copyfile(lookedup, tmpfile)
+        assistant.setOriginal(srcpath)
+        assistant.config.setDestDir(destdir)
+        assistant.setRewritten(destpath)
+        if isfile(joinpath(destdir, destpath)):
+            # The file already exists.
+            assistant.update(lookedup, flag, tmpfile, True)
+        else:  # if not isfile(joinpath(destdir, destpath))
+            # Install the file.
+            # Don't protest if the file should be there but isn't: it happens
+            # frequently that developers don't put autogenerated files under
+            # version control.
+            assistant.add(lookedup, flag, tmpfile)
+        if isfile(tmpfile):
+            os.remove(tmpfile)
+
+    else:
+        message = '%s: *** ' % constants.APP['name']
+        message += 'no mode specified\n'
+        message += '%s: *** Stop.\n' % constants.APP['name']
+        sys.stderr.write(message)
+        sys.exit(1)
+
+
+if __name__ == '__main__':
+    try:  # Try to execute
+        main()
+    except classes.GLError as error:
+        errmode = 0  # gnulib-style errors
+        errno = error.errno
+        errinfo = error.errinfo
+        if errmode == 0:
+            message = '%s: *** ' % constants.APP['name']
+            if errinfo == None:
+                errinfo = ''
+            if errno == 1:
+                message += 'file %s not found' % errinfo
+            elif errno == 2:
+                message += 'patch file %s didn\'t apply cleanly' % errinfo
+            elif errno == 3:
+                message += 'cannot find %s - make sure you run gnulib-tool from within your package\'s directory' % errinfo
+            elif errno == 4:
+                message += 'minimum supported autoconf version is 2.59. Try adding'
+                message += 'AC_PREREQ([%s])' % constants.DEFAULT_AUTOCONF_MINVERSION
+                message += ' to your configure.ac.'
+            elif errno == 5:
+                message += '%s is expected to contain gl_M4_BASE([%s])' % (repr(os.path.join(errinfo, 'gnulib-comp.m4')), repr(errinfo))
+            elif errno == 6:
+                message += 'missing --source-base option'
+            elif errno == 7:
+                message += 'missing --doc-base option. --doc-base has been introduced '
+                message += 'on 2006-07-11; if your last invocation of \'gnulib-tool '
+                message += '--import\' is before that date, you need to run'
+                message += '\'gnulib-tool --import\' once, with a --doc-base option.'
+            elif errno == 8:
+                message += 'missing --tests-base option'
+            elif errno == 9:
+                message += 'missing --lib option'
+            elif errno == 10:
+                message = 'gnulib-tool: option --conditional-dependencies is not supported with --with-tests'
+            elif errno == 11:
+                incompatibilities = ''
+                message += 'incompatible license on modules:%s' % constants.NL
+                for pair in errinfo:
+                    incompatibilities += pair[0]
+                    incompatibilities += ' %s' % pair[1]
+                    incompatibilities += constants.NL
+                tempname = mktemp()
+                with codecs.open(tempname, 'wb', 'UTF-8') as file:
+                    file.write(incompatibilities)
+                sed_table = 's,^\\([^ ]*\\) ,\\1' + ' ' * 51 + ',\n'
+                sed_table += 's,^\\(' + '.' * 49 + '[^ ]*\\) *,' + ' ' * 17 + '\\1 ,'
+                args = ['sed', '-e', sed_table, tempname]
+                incompatibilities = sp.check_output(args).decode(ENCS['default'])
+                message += incompatibilities
+                os.remove(tempname)
+            elif errno == 12:
+                message += 'refusing to do nothing'
+            elif errno == 13:
+                message += 'could not create directory %s' % errinfo
+            elif errno == 14:
+                message += 'could not delete file %s' % errinfo
+            elif errno == 15:
+                message += 'could not create file %s' % errinfo
+            elif errno == 16:
+                message += 'could not transform file %s' % errinfo
+            elif errno == 17:
+                message += 'could not update file %s' % errinfo
+            elif errno == 18:
+                message += 'module %s lacks a license' % errinfo
+            elif errno == 19:
+                message += 'could not create destination directory: %s' % errinfo
+            message += '\n%s: *** Stop.\n' % constants.APP['name']
+            sys.stderr.write(message)
+            sys.exit(1)