>From b228f782b10a44736af152f0bdb7c94c7429ceab Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 31 Jul 2022 18:39:19 +0200 Subject: [PATCH 03/16] gnulib-tool.py: Follow gnulib-tool changes, part 19. Follow gnulib-tool changes 2015-12-09 Pavel Raiskup gnulib-tool: allow multiple --local-dir usage 2019-02-14 Bruno Haible gnulib-tool: Improve handling of multiple --local-dir options. * gnulib-tool (func_reconstruct_cached_dir): When the argument is absolute, return it unmodified. (func_compute_relative_local_gnulib_path): Renamed from func_count_relative_local_gnulib_path. Add comment. * gnulib-tool.py: Accept multiple --local-dir options and collect the values into localpath. * pygnulib/GLConfig.py: Take a localpath argument instead of a localdir argument. (getLocalDir, setLocalDir, resetLocalDir): Remove methods. (getLocalPath, setLocalPath, resetLocalPath): New methods. * pygnulib/GLFileSystem.py (CopyAction): New class. (GLFileSystem.lookup): Consider all dirs in localpath. (GLFileSystem.shouldLink): New method. (GLFileAssistant): Use shouldLink. * pygnulib/GLModuleSystem.py (GLModuleSystem.exists): Iterate over all dirs in localpath. (GLModuleSystem.list): Likewise. * pygnulib/GLEmiter.py: Update. * pygnulib/GLImport.py (GLImport.__init__): Put the argument of gl_LOCAL_DIR into localpath, not localdir. (GLImport.actioncmd): Consider all dirs in localpath. (GLImport.relative_to_destdir, GLImport.relative_to_currdir): New methods. (GLImport.gnulib_cache): Combine all dirs in localpath. Use self.relative_to_destdir. * pygnulib/GLTestDir.py (GLTestDir.execute): Use shouldLink. --- ChangeLog | 33 +++++++++++ gnulib-tool | 17 +++--- gnulib-tool.py | 17 +++--- gnulib-tool.py.TODO | 90 ++++++++++------------------ pygnulib/GLConfig.py | 61 ++++++++++--------- pygnulib/GLEmiter.py | 6 +- pygnulib/GLFileSystem.py | 117 ++++++++++++++++++++++++------------- pygnulib/GLImport.py | 87 ++++++++++++++++----------- pygnulib/GLModuleSystem.py | 45 +++++++------- pygnulib/GLTestDir.py | 6 +- 10 files changed, 269 insertions(+), 210 deletions(-) diff --git a/ChangeLog b/ChangeLog index 00ffeffa52..98438a58a4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,38 @@ 2022-07-31 Bruno Haible + gnulib-tool.py: Follow gnulib-tool changes, part 19. + Follow gnulib-tool changes + 2015-12-09 Pavel Raiskup + gnulib-tool: allow multiple --local-dir usage + 2019-02-14 Bruno Haible + gnulib-tool: Improve handling of multiple --local-dir options. + * gnulib-tool (func_reconstruct_cached_dir): When the argument is + absolute, return it unmodified. + (func_compute_relative_local_gnulib_path): Renamed from + func_count_relative_local_gnulib_path. Add comment. + * gnulib-tool.py: Accept multiple --local-dir options and collect the + values into localpath. + * pygnulib/GLConfig.py: Take a localpath argument instead of a localdir + argument. + (getLocalDir, setLocalDir, resetLocalDir): Remove methods. + (getLocalPath, setLocalPath, resetLocalPath): New methods. + * pygnulib/GLFileSystem.py (CopyAction): New class. + (GLFileSystem.lookup): Consider all dirs in localpath. + (GLFileSystem.shouldLink): New method. + (GLFileAssistant): Use shouldLink. + * pygnulib/GLModuleSystem.py (GLModuleSystem.exists): Iterate over all + dirs in localpath. + (GLModuleSystem.list): Likewise. + * pygnulib/GLEmiter.py: Update. + * pygnulib/GLImport.py (GLImport.__init__): Put the argument of + gl_LOCAL_DIR into localpath, not localdir. + (GLImport.actioncmd): Consider all dirs in localpath. + (GLImport.relative_to_destdir, GLImport.relative_to_currdir): New + methods. + (GLImport.gnulib_cache): Combine all dirs in localpath. Use + self.relative_to_destdir. + * pygnulib/GLTestDir.py (GLTestDir.execute): Use shouldLink. + gnulib-tool.py: Improve the primitives for relative file names. * pygnulib/constants.py (relativize): Don't attempt to handle absolute file names. Fix bug with relativize('../foo/bar', '../foo/bla/zut'). diff --git a/gnulib-tool b/gnulib-tool index bee85856f4..f1665f4002 100755 --- a/gnulib-tool +++ b/gnulib-tool @@ -4846,12 +4846,13 @@ func_reconstruct_cached_dir () { cached_dir=$1 if test -n "$cached_dir"; then - case "$destdir" in + case "$cached_dir" in /*) - func_path_append local_gnulib_path "$destdir/$cached_dir" ;; + func_path_append local_gnulib_path "$cached_dir" ;; *) - case "$cached_dir" in + case "$destdir" in /*) + # XXX This doesn't look right. func_path_append local_gnulib_path "$destdir/$cached_dir" ;; *) func_relconcat "$destdir" "$cached_dir" @@ -5835,14 +5836,14 @@ s,//*$,/,' fi fi - # func_count_relative_local_gnulib_path + # func_compute_relative_local_gnulib_path # gl_LOCAL_DIR requires local_gnulib_path to be set relatively to destdir # Input: # - local_gnulib_path from --local-dir # - destdir from --dir # Output: # - relative_local_dir path to be stored into gl_LOCAL_DIR - func_count_relative_local_gnulib_path () + func_compute_relative_local_gnulib_path () { relative_local_gnulib_path= save_IFS="$IFS" @@ -5856,7 +5857,9 @@ s,//*$,/,' relative_local_dir="$local_dir" ;; * ) case "$destdir" in - /*) relative_local_dir="$local_dir" ;; + /*) + # XXX This doesn't look right. + relative_local_dir="$local_dir" ;; *) # destdir, local_dir are both relative. func_relativize "$destdir" "$local_dir" @@ -5883,7 +5886,7 @@ s,//*$,/,' printf '%s\n' "$actioncmd" echo echo "# Specification in the form of a few gnulib-tool.m4 macro invocations:" - func_count_relative_local_gnulib_path + func_compute_relative_local_gnulib_path echo "gl_LOCAL_DIR([$relative_local_gnulib_path])" echo "gl_MODULES([" echo "$specified_modules" | sed -e 's/^/ /g' diff --git a/gnulib-tool.py b/gnulib-tool.py index 523de7769e..0b2f866920 100755 --- a/gnulib-tool.py +++ b/gnulib-tool.py @@ -24,7 +24,7 @@ # - Line length is not limited to 79 characters. # - Line breaking before or after binary operators? Better before, like in GNU. # You can use this command to check the style: -# $ pycodestyle --max-line-length=128 --ignore=E265,W503,E241,E711,E712 gnulib-tool.py pygnulib/*.py +# $ pycodestyle --max-line-length=128 --ignore=E265,W503,E241,E711,E712,E201,E202 gnulib-tool.py pygnulib/*.py #=============================================================================== @@ -66,7 +66,7 @@ def main(): # Reset arguments mode = None destdir = None - localdir = None + localpath = None modcache = None verbose = None auxdir = None @@ -224,11 +224,12 @@ def main(): dest='destdir', default=None, nargs=1) - # localdir + # localpath parser.add_argument('-ld', '--local-dir', - dest='localdir', + action='append', + dest='localpath', default=None, - nargs=1) + nargs='?') # verbose parser.add_argument('-v', '--verbose', default=0, @@ -458,9 +459,7 @@ def main(): destdir = cmdargs.destdir if destdir != None: destdir = cmdargs.destdir[0] - localdir = cmdargs.localdir - if localdir != None: - localdir = cmdargs.localdir[0] + localpath = cmdargs.localpath libname = cmdargs.libname if libname != None: libname = cmdargs.libname[0] @@ -514,7 +513,7 @@ def main(): # Create pygnulib configuration. config = classes.GLConfig( destdir=destdir, - localdir=localdir, + localpath=localpath, m4base=m4base, auxdir=auxdir, modules=modules, diff --git a/gnulib-tool.py.TODO b/gnulib-tool.py.TODO index c0a2c975f3..26c59c5353 100644 --- a/gnulib-tool.py.TODO +++ b/gnulib-tool.py.TODO @@ -15,6 +15,37 @@ The following commits to gnulib-tool have not yet been reflected in -------------------------------------------------------------------------------- +Implement the options: + --find + --without-tests + --without-c++-tests + --without-longrunning-tests + --without-privileged-tests + --without-unportable-tests + --single-configure + --conditional-dependencies + --no-conditional-dependencies + --gnu-make + --tests-makefile-name + --automake-subdir + --no-libtool + --macro-prefix + --po-domain + --witness-c-macro + --vc-files + --no-vc-files + --no-changelog + -s | --symbolic + --local-symlink + -h | --hardlink + --local-hardlink + -S | --more-symlinks + -H | --more-hardlinks + --help (same output) + --version + +-------------------------------------------------------------------------------- + commit 76c7703cb2e9e0e803d1296618d8ab9e86e13d6c Author: Akim Demaille Date: Mon Jul 4 07:18:07 2022 +0200 @@ -1079,65 +1110,6 @@ Date: Wed May 1 13:39:22 2013 +0900 -------------------------------------------------------------------------------- -commit 49137e3bc6a2b3fd83c502a514e4a3b89fc1571c -Author: Bruno Haible -Date: Thu Feb 14 20:50:57 2019 +0100 - - gnulib-tool: Improve handling of multiple --local-dir options. - - * doc/gnulib.texi (Extending Gnulib): Explain how multiple --local-dir - options work. - * gnulib-tool (func_path_prepend): Remove function. - (func_path_foreach): Make IFS handling more robust. - (local_gnulib_path): Collect --local-dir values using func_path_append, - not func_path_prepend. - (func_determine_path_separator): Make IFS handling more robust. - (func_lookup_file_cb): New function. - (func_lookup_file): Rewritten to use func_lookup_file_cb instead of - func_lookup_local_file. Apply the patches in the reverse order of their - origin in $local_gnulib_path. - (func_count_relative_local_gnulib_path): Make IFS handling more robust. - * NEWS: Mention that the first --local-dir option is the one with - highest priority. - -commit 55c6f22b8043843aa7cf6843326eb4abed4de75c -Author: Pavel Raiskup -Date: Sat Nov 21 14:09:15 2015 +0100 - - gnulib-tool: allow multiple --local-dir usage - - * gnulib-tool: Use --local-dir to construct compound - $local_gnulib_path path instead of $local_gnulib_dir. Determine - PATH_SEPARATOR early. - (local_gnulib_dir): Rename into $local_gnulib_path everywhere. - (func_gnulib_dir): Cut out PATH_SEPARATOR detection code into - func_determine_path_separator because that needs to be detected - earlier now. - (func_determine_path_separator): New function. - (func_path_foreach, func_path_foreach_inner): New functions. - (func_path_prepend, func_path_append): Likewise. - (func_lookup_local_file, func_lookup_local_file_cb): Likewise. - (func_lookup_file, func_all_modules): Use new functions to work - with local_gnulib_path. - (func_modules_in_dir, func_exists_module): New callbacks for - func_path_foreach. - (func_exists_module, func_get_tests_module): Likewise. - (func_is_local_file, func_should_symlink): New helper methods. - (func_add_file, func_update_file): Use new func_should_symlink - instead, DRY. - (func_reconstruct_cached_local_gnulib_path): New helper. - (func_reconstruct_cached_dir): New callback. - (func_import): The cached_local_gnulib_dir renamed to - cached_local_gnulib_path similarly to local_gnulib_dir. - Use new func_reconstruct_cached_local_gnulib_path. - (func_count_relative_local_gnulib_path): New sub-method. - (func_create_testdir): Use func_should_symlink, DRY. - (func_create_megatestdir): Use new functions to work with - local_gnulib_path correctly. - (func_append_local_dir): New helper. - --------------------------------------------------------------------------------- - commit 9bdf6c8a0cdeb13c12e4b65dee9538c5468dbe1d Author: Bruno Haible Date: Sun Aug 19 14:06:50 2012 +0200 diff --git a/pygnulib/GLConfig.py b/pygnulib/GLConfig.py index d203820427..55b6cd2986 100644 --- a/pygnulib/GLConfig.py +++ b/pygnulib/GLConfig.py @@ -56,7 +56,7 @@ class GLConfig(object): By default all attributes are set to empty string, empty list or zero. The most common value, however, is a None value.''' - def __init__(self, destdir=None, localdir=None, auxdir=None, + def __init__(self, destdir=None, localpath=None, auxdir=None, sourcebase=None, m4base=None, pobase=None, docbase=None, testsbase=None, modules=None, avoids=None, files=None, testflags=None, libname=None, lgpl=None, makefile=None, libtool=None, conddeps=None, macro_prefix=None, @@ -77,10 +77,10 @@ class GLConfig(object): self.resetDestDir() if destdir != None: self.setDestDir(destdir) - # localdir - self.resetLocalDir() - if localdir != None: - self.setLocalDir(localdir) + # localpath + self.resetLocalPath() + if localpath != None: + self.setLocalPath(localpath) # auxdir self.resetAuxDir() if auxdir != None: @@ -402,26 +402,29 @@ class GLConfig(object): configure.ac can be found. Defaults to current directory.''' self.table['destdir'] = '' - # Define localdir methods. - def getLocalDir(self): - '''Return a local override directory where to look up files before looking - in gnulib's directory.''' - return self.table['localdir'] - - def setLocalDir(self, localdir): - '''Specify a local override directory where to look up files before looking - in gnulib's directory.''' - if type(localdir) is str: - if localdir: - self.table['localdir'] = remove_trailing_slashes(localdir) - else: # if localdir has not str type - raise TypeError('localdir must be a string, not %s' % - type(localdir).__name__) - - def resetLocalDir(self): - '''Reset a local override directory where to look up files before looking - in gnulib's directory.''' - self.table['localdir'] = '' + # Define localpath methods. + def getLocalPath(self): + '''Return a list of local override directories where to look up files + before looking in gnulib's directory. The first one has the highest + priority.''' + return self.table['localpath'] + + def setLocalPath(self, localpath): + '''Specify a list of local override directories where to look up files + before looking in gnulib's directory. The first one has the highest + priority.''' + if type(localpath) is list: + for dir in localpath: + if type(dir) is not str: + raise TypeError('localpath element must be a string, not %s' % type(dir).__name__) + else: + raise TypeError('localpath must be a list, not %s' % type(localpath).__name__) + self.table['localpath'] = [ remove_trailing_slashes(dir) for dir in localpath ] + + def resetLocalPath(self): + '''Reset a list of local override directories where to look up files + before looking in gnulib's directory.''' + self.table['localpath'] = [] # Define auxdir methods. def getAuxDir(self): @@ -998,22 +1001,22 @@ class GLConfig(object): # Define lsymbolic methods. def checkLSymbolic(self): '''Check if pygnulib will make symbolic links instead of copying files, only - for files from the local override directory.''' + for files from the local override directories.''' return self.table['lsymbolic'] def enableLSymbolic(self): '''Enable creation of symbolic links instead of copying files, only for - files from the local override directory.''' + files from the local override directories.''' self.table['lsymbolic'] = True def disableLSymbolic(self): '''Disable creation of symbolic links instead of copying files, only for - files from the local override directory.''' + files from the local override directories.''' self.table['lsymbolic'] = False def resetLSymbolic(self): '''Reset creation of symbolic links instead of copying files, only for - files from the local override directory.''' + files from the local override directories.''' self.table['lsymbolic'] = False # Define verbosity methods. diff --git a/pygnulib/GLEmiter.py b/pygnulib/GLEmiter.py index c41d4c5518..a5a13e63fb 100644 --- a/pygnulib/GLEmiter.py +++ b/pygnulib/GLEmiter.py @@ -605,7 +605,7 @@ AC_DEFUN([%V1%_LIBSOURCES], [ Emit the contents of the library Makefile. Returns str and a bool variable which shows if subdirectories are used. - GLConfig: localdir, sourcebase, libname, pobase, auxdir, makefile, libtool, + GLConfig: localpath, sourcebase, libname, pobase, auxdir, makefile, libtool, macro_prefix, podomain, conddeps, witness_c_macro. destfile is a filename relative to destdir of Makefile being generated. @@ -635,7 +635,6 @@ AC_DEFUN([%V1%_LIBSOURCES], [ raise TypeError('for_test must be a bool, not %s' % type(for_test).__name__) emit = '' - localdir = self.config['localdir'] sourcebase = self.config['sourcebase'] modcache = self.config['modcache'] libname = self.config['libname'] @@ -885,7 +884,7 @@ AC_DEFUN([%V1%_LIBSOURCES], [ Emit the contents of the tests Makefile. Returns str and a bool variable which shows if subdirectories are used. - GLConfig: localdir, modules, libname, auxdir, makefile, libtool, + GLConfig: localpath, modules, libname, auxdir, makefile, libtool, sourcebase, m4base, testsbase, macro_prefix, witness_c_macro, single_configure, libtests. @@ -914,7 +913,6 @@ AC_DEFUN([%V1%_LIBSOURCES], [ raise TypeError('for_test must be a bool, not %s' % type(for_test).__name__) emit = '' - localdir = self.config['localdir'] auxdir = self.config['auxdir'] sourcebase = self.config['sourcebase'] modcache = self.config['modcache'] diff --git a/pygnulib/GLFileSystem.py b/pygnulib/GLFileSystem.py index f17466187d..dfb1bb903f 100644 --- a/pygnulib/GLFileSystem.py +++ b/pygnulib/GLFileSystem.py @@ -23,6 +23,7 @@ import codecs import shutil import filecmp import subprocess as sp +from enum import Enum from . import constants from .GLError import GLError from .GLConfig import GLConfig @@ -45,18 +46,26 @@ isdir = os.path.isdir isfile = os.path.isfile +#=============================================================================== +# Define CopyAction class +#=============================================================================== +class CopyAction(Enum): + Copy = 0 + Symlink = 1 + + #=============================================================================== # Define GLFileSystem class #=============================================================================== class GLFileSystem(object): - '''GLFileSystem class is used to create virtual filesystem, which is based on - the gnulib directory and directory specified by localdir argument. Its main - method lookup(file) is used to find file in these directories or combine it - using Linux 'patch' utility.''' + '''GLFileSystem class is used to create virtual filesystem, which is based + on the gnulib directory and directories specified by localpath argument. + Its main method lookup(file) is used to find file in these directories or + combine it using Linux 'patch' utility.''' def __init__(self, config): - '''Create new GLFileSystem instance. The only argument is localdir, - which can be an empty string too.''' + '''Create new GLFileSystem instance. The only argument is localpath, + which can be an empty list.''' if type(config) is not GLConfig: raise TypeError('config must be a GLConfig, not %s' % type(config).__name__) @@ -70,43 +79,75 @@ class GLFileSystem(object): def lookup(self, name): '''GLFileSystem.lookup(name) -> tuple - Lookup a file in gnulib and localdir directories or combine it using Linux + Lookup a file in gnulib and localpath directories or combine it using 'patch' utility. If file was found, method returns string, else it raises GLError telling that file was not found. Function also returns flag which indicates whether file is a temporary file. - GLConfig: localdir.''' + GLConfig: localpath.''' if type(name) is not str: raise TypeError( 'name must be a string, not %s' % type(module).__name__) - # If name exists in localdir, then we use it - path_gnulib = joinpath(DIRS['root'], name) - path_local = joinpath(self.config['localdir'], name) - path_diff = joinpath(self.config['localdir'], '%s.diff' % name) - path_temp = joinpath(self.config['tempdir'], name) - try: # Try to create directories - os.makedirs(os.path.dirname(path_temp)) - except OSError as error: - pass # Skip errors if directory exists - if isfile(path_temp): - os.remove(path_temp) - if self.config['localdir'] and isfile(path_local): - result = (path_local, False) - else: # if path_local does not exist - if isfile(path_gnulib): - if self.config['localdir'] and isfile(path_diff): - shutil.copy(path_gnulib, path_temp) - command = 'patch -s "%s" < "%s" >&2' % (path_temp, path_diff) + localpath = self.config['localpath'] + # Each element in localpath is a directory whose contents overrides + # or amends the result of the lookup in the rest of localpath and + # the gnulib dir. So, the first element of localpath is the highest + # priority one. + lookedupFile = None + lookedupPatches = [] + for localdir in localpath: + file_in_localdir = joinpath(localdir, name) + if isfile(file_in_localdir): + lookedupFile = file_in_localdir + break + diff_in_localdir = joinpath(localdir, '%s.diff' % name) + if isfile(diff_in_localdir): + lookedupPatches.append(diff_in_localdir) + # Treat the gnulib dir like a lowest-priority --local-dir, except that + # here we don't look for .diff files. + if lookedupFile == None: + file_in_localdir = joinpath(DIRS['root'], name) + if isfile(file_in_localdir): + lookedupFile = file_in_localdir + if lookedupFile != None: + if len(lookedupPatches) > 0: + # Apply the patches, from lowest-priority to highest-priority. + tempFile = joinpath(self.config['tempdir'], name) + try: # Try to create directories + os.makedirs(os.path.dirname(tempFile)) + except OSError as error: + pass # Skip errors if directory exists + if isfile(tempFile): + os.remove(tempFile) + shutil.copy(lookedupFile, tempFile) + for diff_in_localdir in reversed(lookedupPatches): + command = 'patch -s "%s" < "%s" >&2' % (tempFile, diff_in_localdir) try: # Try to apply patch sp.check_call(command, shell=True) except sp.CalledProcessError as error: raise GLError(2, name) - result = (path_temp, True) - else: # if path_diff does not exist - result = (path_gnulib, False) - else: # if path_gnulib does not exist - raise GLError(1, name) + result = (tempFile, True) + else: + result = (lookedupFile, False) + else: + raise GLError(1, name) return result + def shouldLink(self, original, lookedup): + '''GLFileSystem.shouldLink(original, lookedup) + + Determines whether the original file should be copied or symlinked. + Returns a CopyAction.''' + symbolic = self.config['symbolic'] + lsymbolic = self.config['lsymbolic'] + localpath = self.config['localpath'] + if symbolic: + return CopyAction.Symlink + if lsymbolic: + for localdir in localpath: + if lookedup == joinpath(localdir, original): + return CopyAction.Symlink + return CopyAction.Copy + #=============================================================================== # Define GLFileAssistant class @@ -212,16 +253,13 @@ class GLFileAssistant(object): original = self.original rewritten = self.rewritten destdir = self.config['destdir'] - symbolic = self.config['symbolic'] - lsymbolic = self.config['lsymbolic'] if original == None: raise TypeError('original must be set before applying the method') - elif rewritten == None: + if rewritten == None: raise TypeError('rewritten must be set before applying the method') if not self.config['dryrun']: print('Copying file %s' % rewritten) - loriginal = joinpath(self.config['localdir'], original) - if (symbolic or (lsymbolic and lookedup == loriginal)) \ + if self.filesystem.shouldLink(original, lookedup) == CopyAction.Symlink \ and not tmpflag and filecmp.cmp(lookedup, tmpfile): constants.link_if_changed( lookedup, joinpath(destdir, rewritten)) @@ -242,11 +280,9 @@ class GLFileAssistant(object): original = self.original rewritten = self.rewritten destdir = self.config['destdir'] - symbolic = self.config['symbolic'] - lsymbolic = self.config['lsymbolic'] if original == None: raise TypeError('original must be set before applying the method') - elif rewritten == None: + if rewritten == None: raise TypeError('rewritten must be set before applying the method') if type(lookedup) is not str: raise TypeError('lookedup must be a string, not %s' % @@ -274,8 +310,7 @@ class GLFileAssistant(object): shutil.move(basepath, backuppath) except Exception as error: raise GLError(17, original) - loriginal = joinpath(self.config['localdir'], original) - if (symbolic or (lsymbolic and lookedup == loriginal)) \ + if self.filesystem.shouldLink(original, lookedup) == CopyAction.Symlink \ and not tmpflag and filecmp.cmp(lookedup, tmpfile): constants.link_if_changed(lookedup, basepath) else: # if any of these conditions is not met diff --git a/pygnulib/GLImport.py b/pygnulib/GLImport.py index b2691a976d..2b16ce0ea4 100644 --- a/pygnulib/GLImport.py +++ b/pygnulib/GLImport.py @@ -52,7 +52,6 @@ TESTS = constants.TESTS compiler = constants.compiler joinpath = constants.joinpath cleaner = constants.cleaner -relpath = constants.relativize isabs = os.path.isabs isdir = os.path.isdir isfile = os.path.isfile @@ -181,7 +180,7 @@ class GLImport(object): if tempdict['gl_LIB']: self.cache.setLibName(cleaner(tempdict['gl_LIB'])) if tempdict['gl_LOCAL_DIR']: - self.cache.setLocalDir(cleaner(tempdict['gl_LOCAL_DIR'])) + self.cache.setLocalPath(cleaner(tempdict['gl_LOCAL_DIR']).split(':')) if tempdict['gl_MODULES']: self.cache.setModules(cleaner(tempdict['gl_MODULES'].split())) if tempdict['gl_AVOID']: @@ -217,23 +216,14 @@ class GLImport(object): pattern = compiler(regex, re.S | re.M) self.cache.setFiles(pattern.findall(data)[-1].strip().split()) - # The self.config['localdir'] defaults to the cached one. Recall that the - # cached one is relative to $destdir, whereas the one we use is relative - # to . or absolute. - if not self.config['localdir']: - if self.cache['localdir']: - if isabs(self.config['destdir']): - localdir = joinpath( - self.config['destdir'], self.cache['localdir']) - else: # if not isabs(self.config['destdir']) - if isabs(self.cache['localdir']): - localdir = joinpath( - self.config['destdir'], self.cache['localdir']) - else: # if not isabs(self.cache['localdir']) - # NOTE: I NEED TO IMPLEMENT RELATIVE_CONCAT - localdir = os.path.relpath(joinpath(self.config['destdir'], - self.cache['localdir'])) - self.config.setLocalDir(localdir) + # The self.config['localpath'] defaults to the cached one. Recall that + # the cached one is relative to self.config['destdir'], whereas the one + # we use is relative to . or absolute. + if len(self.config['localpath']) == 0: + if len(self.cache['localpath']) > 0: + localpath = [ self.relative_to_currdir(localdir) + for localdir in self.cache['localpath'] ] + self.config.setLocalPath(localpath) if self.mode != MODES['import']: if self.cache['m4base'] and \ @@ -367,7 +357,7 @@ class GLImport(object): modules = self.config.getModules() avoids = self.config.getAvoids() destdir = self.config.getDestDir() - localdir = self.config.getLocalDir() + localpath = self.config.getLocalPath() auxdir = self.config.getAuxDir() sourcebase = self.config.getSourceBase() m4base = self.config.getM4Base() @@ -389,7 +379,7 @@ class GLImport(object): # Create command-line invocation comment. actioncmd = 'gnulib-tool --import' actioncmd += ' --dir=%s' % destdir - if localdir: + for localdir in localpath: actioncmd += ' --local-dir=%s' % localdir actioncmd += ' --lib=%s' % libname actioncmd += ' --source-base=%s' % sourcebase @@ -443,17 +433,49 @@ class GLImport(object): actioncmd += ' '.join(modules) return actioncmd + def relative_to_destdir(self, dir): + '''GLImport.relative_to_destdir(dir) -> str + + Convert a filename that represents dir, relative to the current directory, + to a filename relative to destdir. + GLConfig: destdir.''' + destdir = self.config['destdir'] + if dir.startswith('/'): + return dir + else: + if destdir.startswith('/'): + # XXX This doesn't look right. + return dir + else: + return constants.relativize(destdir, dir) + + def relative_to_currdir(self, dir): + '''GLImport.relative_to_currdir(dir) -> str + + The opposite of GLImport.relative_to_destdir: + Convert a filename that represents dir, relative to destdir, + to a filename relative to the current directory. + GLConfig: destdir.''' + destdir = self.config['destdir'] + if dir.startswith('/'): + return dir + else: + if destdir.startswith('/'): + # XXX This doesn't look right. + return joinpath(destdir, dir) + else: + return constants.relconcat(destdir, dir) + def gnulib_cache(self): '''GLImport.gnulib_cache() -> str Emit the contents of generated $m4base/gnulib-cache.m4 file. - GLConfig: destdir, localdir, tests, sourcebase, m4base, pobase, docbase, + GLConfig: destdir, localpath, tests, sourcebase, m4base, pobase, docbase, testsbase, conddeps, libtool, macro_prefix, podomain, vc_files.''' emit = '' moduletable = self.moduletable actioncmd = self.actioncmd() - destdir = self.config['destdir'] - localdir = self.config['localdir'] + localpath = self.config['localpath'] testflags = list(self.config['testflags']) sourcebase = self.config['sourcebase'] m4base = self.config['m4base'] @@ -482,13 +504,11 @@ class GLImport(object): # Specification in the form of a command-line invocation: # %s -# Specification in the form of a few \ -gnulib-tool.m4 macro invocations:\n''' % actioncmd - if not localdir or localdir.startswith('/'): - relative_localdir = localdir - else: # if localdir or not localdir.startswith('/') - relative_localdir = constants.relativize(destdir, localdir) - emit += 'gl_LOCAL_DIR([%s])\n' % relative_localdir +# Specification in the form of a few gnulib-tool.m4 macro invocations:\n''' % actioncmd + # Store the localpath relative to destdir. + relative_localpath = [ self.relative_to_destdir(localdir) + for localdir in localpath ] + emit += 'gl_LOCAL_DIR([%s])\n' % ':'.join(relative_localpath) emit += 'gl_MODULES([\n' emit += ' %s\n' % '\n '.join(modules) emit += '])\n' @@ -532,13 +552,12 @@ gnulib-tool.m4 macro invocations:\n''' % actioncmd '''GLImport.gnulib_comp(files) -> str Emit the contents of generated $m4base/gnulib-comp.m4 file. - GLConfig: destdir, localdir, tests, sourcebase, m4base, pobase, docbase, + GLConfig: destdir, localpath, tests, sourcebase, m4base, pobase, docbase, testsbase, conddeps, libtool, macro_prefix, podomain, vc_files.''' emit = '' assistant = self.assistant moduletable = self.moduletable destdir = self.config['destdir'] - localdir = self.config['localdir'] auxdir = self.config['auxdir'] testflags = list(self.config['testflags']) sourcebase = self.config['sourcebase'] @@ -740,7 +759,6 @@ AC_DEFUN([%s_FILE_LIST], [\n''' % macro_prefix '''Make all preparations before the execution of the code. Returns filetable and sed transformers, which change the license.''' destdir = self.config['destdir'] - localdir = self.config['localdir'] auxdir = self.config['auxdir'] modules = list(self.config['modules']) avoids = list(self.config['avoids']) @@ -963,7 +981,6 @@ AC_DEFUN([%s_FILE_LIST], [\n''' % macro_prefix if key not in filetable: raise KeyError('filetable must contain key %s' % repr(key)) destdir = self.config['destdir'] - localdir = self.config['localdir'] auxdir = self.config['auxdir'] modules = list(self.config['modules']) avoids = list(self.config['avoids']) diff --git a/pygnulib/GLModuleSystem.py b/pygnulib/GLModuleSystem.py index 48515ce36d..00b2c5f035 100644 --- a/pygnulib/GLModuleSystem.py +++ b/pygnulib/GLModuleSystem.py @@ -60,7 +60,7 @@ class GLModuleSystem(object): '''GLModuleSystem.__init__(config) -> GLModuleSystem Create new GLModuleSystem instance. Some functions use GLFileSystem class - to look up a file in localdir or gnulib directories, or combine it through + to look up a file in localpath or gnulib directories, or combine it through 'patch' utility.''' self.args = dict() if type(config) is not GLConfig: @@ -78,22 +78,22 @@ class GLModuleSystem(object): '''GLModuleSystem.exists(module) -> bool Check whether the given module exists. - GLConfig: localdir.''' + GLConfig: localpath.''' if type(module) is not str: raise TypeError( 'module must be a string, not %s' % type(module).__name__) - result = bool() + localpath = self.config['localpath'] + result = False badnames = ['ChangeLog', 'COPYING', 'README', 'TEMPLATE', 'TEMPLATE-EXTENDED', 'TEMPLATE-TESTS'] - if isfile(joinpath(DIRS['modules'], module)) or \ - all([ # Begin all(iterable) function - self.config['localdir'], - isdir(joinpath(self.config['localdir'], 'modules')), - isfile( - joinpath(self.config['localdir'], 'modules', module)) - ]): # Close all(iterable) function - if module not in badnames: - result = True + if module not in badnames: + result = isfile(joinpath(DIRS['modules'], module)) + if not result: + for localdir in localpath: + if isdir(joinpath(localdir, 'modules')) \ + and isfile(joinpath(localdir, 'modules', module)): + result = True + break return result def find(self, module): @@ -122,7 +122,7 @@ class GLModuleSystem(object): complete, so this version uses subprocess to run shell commands.''' result = '' listing = list() - localdir = self.config['localdir'] + localpath = self.config['localpath'] find_args = ['find', 'modules', '-type', 'f', '-print'] sed_args = \ [ @@ -146,16 +146,18 @@ class GLModuleSystem(object): os.chdir(constants.DIRS['root']) find = sp.Popen(find_args, stdout=sp.PIPE) result += find.stdout.read().decode("UTF-8") + os.chdir(DIRS['cwd']) - # Read modules from local directory. - if localdir and isdir(joinpath(localdir, 'modules')): - os.chdir(localdir) - find = sp.Popen(find_args, stdout=sp.PIPE) - result += find.stdout.read().decode("UTF-8") + # Read modules from local directories. + if len(localpath) > 0: + for localdir in localpath: + os.chdir(localdir) + find = sp.Popen(find_args, stdout=sp.PIPE) + result += find.stdout.read().decode("UTF-8") + os.chdir(DIRS['cwd']) sed_args += ['-e', r's,\.diff$,,'] # Save the list of the modules to file. - os.chdir(DIRS['cwd']) path = joinpath(self.config['tempdir'], 'list') with codecs.open(path, 'wb', 'UTF-8') as file: file.write(result) @@ -538,8 +540,7 @@ Include:|Link:|License:|Maintainer:)' '''GLModule.getDependencies() -> list Return list of dependencies. - GLConfig: localdir.''' - localdir = self.config['localdir'] + GLConfig: localpath.''' result = list() section = 'Depends-on:' if 'dependencies' not in self.cache: @@ -871,7 +872,7 @@ class GLModuleTable(object): included in the final modules list. If testflags iterable is enabled, then don't add module which status is in the testflags. If conddeps are enabled, then store condition for each dependency if it has a condition. - The only necessary argument is localdir, which is needed just to create + The only necessary argument is localpath, which is needed just to create modulesystem instance to look for dependencies.''' self.avoids = list() # Avoids self.dependers = dict() # Dependencies diff --git a/pygnulib/GLTestDir.py b/pygnulib/GLTestDir.py index 79f67a8fdc..7a7f5c52fb 100644 --- a/pygnulib/GLTestDir.py +++ b/pygnulib/GLTestDir.py @@ -30,6 +30,7 @@ from .GLConfig import GLConfig from .GLModuleSystem import GLModule from .GLModuleSystem import GLModuleTable from .GLModuleSystem import GLModuleSystem +from .GLFileSystem import CopyAction from .GLFileSystem import GLFileSystem from .GLFileSystem import GLFileAssistant from .GLMakefileTable import GLMakefileTable @@ -143,7 +144,6 @@ class GLTestDir(object): '''GLTestDir.execute() Create a scratch package with the given modules.''' - localdir = self.config['localdir'] auxdir = self.config['auxdir'] testflags = list(self.config['testflags']) sourcebase = self.config['sourcebase'] @@ -154,8 +154,6 @@ class GLTestDir(object): libname = self.config['libname'] libtool = self.config['libtool'] witness_c_macro = self.config['witness_c_macro'] - symbolic = self.config['symbolic'] - lsymbolic = self.config['lsymbolic'] single_configure = self.config['single_configure'] include_guard_prefix = self.config['include_guard_prefix'] macro_prefix = self.config['macro_prefix'] @@ -337,7 +335,7 @@ class GLTestDir(object): if flag: shutil.copy(lookedup, destpath) else: # if not flag - if symbolic or (lsymbolic and lookedup == joinpath(localdir, src)): + if self.filesystem.shouldLink(src, lookedup) == CopyAction.Symlink: constants.link_relative(lookedup, destpath) else: shutil.copy(lookedup, destpath) -- 2.34.1