diff options
author | Dmitry Selyutin <ghostmansd@gmail.com> | 2017-08-20 11:17:58 +0300 |
---|---|---|
committer | Dmitry Selyutin <ghostmansd@gmail.com> | 2017-09-08 17:27:55 +0300 |
commit | 02a1f93ea265428559d5e60b3cd79b563371e00c (patch) | |
tree | d6cb20690ee563a185050021029285e825a09212 /pygnulib/GLImport.py | |
parent | 3ba4dbaefe671991083ff46a2714ff256adf75a1 (diff) | |
download | gnulib-02a1f93ea265428559d5e60b3cd79b563371e00c.tar.gz |
[pygnulib] initial merge (including some small bug fixes)
Diffstat (limited to 'pygnulib/GLImport.py')
-rw-r--r-- | pygnulib/GLImport.py | 1425 |
1 files changed, 1425 insertions, 0 deletions
diff --git a/pygnulib/GLImport.py b/pygnulib/GLImport.py new file mode 100644 index 0000000000..2859a22005 --- /dev/null +++ b/pygnulib/GLImport.py @@ -0,0 +1,1425 @@ +#!/usr/bin/python +# encoding: UTF-8 + +#=============================================================================== +# Define global imports +#=============================================================================== +import os +import re +import sys +import locale +import codecs +import shutil +import filecmp +import subprocess as sp +from . import constants +from .GLError import GLError +from .GLConfig import GLConfig +from .GLModuleSystem import GLModule +from .GLModuleSystem import GLModuleTable +from .GLModuleSystem import GLModuleSystem +from .GLFileSystem import GLFileSystem +from .GLFileSystem import GLFileAssistant +from .GLMakefileTable import GLMakefileTable +from .GLEmiter import GLEmiter + + +#=============================================================================== +# Define module information +#=============================================================================== +__author__ = constants.__author__ +__license__ = constants.__license__ +__copyright__ = constants.__copyright__ + + +#=============================================================================== +# Define global constants +#=============================================================================== +PYTHON3 = constants.PYTHON3 +NoneType = type(None) +APP = constants.APP +DIRS = constants.DIRS +ENCS = constants.ENCS +UTILS = constants.UTILS +FILES = constants.FILES +MODES = constants.MODES +TESTS = constants.TESTS +compiler = constants.compiler +joinpath = constants.joinpath +cleaner = constants.cleaner +relpath = constants.relativize +string = constants.string +isabs = os.path.isabs +isdir = os.path.isdir +isfile = os.path.isfile +normpath = os.path.normpath + + +#=============================================================================== +# Define GLImport class +#=============================================================================== +class GLImport(object): + '''GLImport class is used to provide methods for --import, --add-import, + --remove-import and --update actions. This is a high-level class, so + developers may have to use lower-level classes to create their own + scripts. However, if user needs just to use power of gnulib-tool, this class + is a very good choice.''' + + def __init__(self, config, mode): + '''Create GLImport instance. + The first variable, mode, must be one of the values of the MODES dict + object, which is accessible from constants module. The second one, config, + must be a GLConfig object.''' + if type(config) is not GLConfig: + raise(TypeError('config must have GLConfig type, not %s' % \ + repr(config))) + if type(mode) is int and \ + MODES['import'] <= mode <= MODES['update']: + self.mode = mode + else: # if mode is not int or is not 0-3 + raise(TypeError('mode must be 0 <= mode <= 3, not %s' % \ + repr(mode))) + + # Initialize some values. + self.cache = GLConfig() + self.config = config.copy() + os.rmdir(self.cache['tempdir']) + + # Get cached auxdir and libtool from configure.ac/in. + self.cache.setAuxDir('.') + path = joinpath(self.config['destdir'], 'configure.ac') + if not isfile(path): + path = joinpath(self.config['destdir'], 'configure.in') + if not isfile(path): + raise(GLError(3, path)) + self.config.setAutoconfFile(path) + with codecs.open(path, 'rb', 'UTF-8') as file: + data = file.read() + pattern = compiler(r'^AC_CONFIG_AUX_DIR\((.*?)\)$', re.S | re.M) + match = pattern.findall(data) + if match: + result = cleaner(match)[0] + self.cache.setAuxDir(joinpath(result, self.config['destdir'])) + pattern = compiler(r'A[CM]_PROG_LIBTOOL', re.S | re.M) + guessed_libtool = bool(pattern.findall(data)) + if self.config['auxdir'] == None: + self.config.setAuxDir(self.cache['auxdir']) + + # Guess autoconf version. + pattern = compiler('.*AC_PREREQ\((.*?)\)', re.S | re.M) + versions = cleaner(pattern.findall(data)) + if versions: + version = sorted(set([float(version) for version in versions]))[-1] + self.config.setAutoconfVersion(version) + if version < 2.59: + raise(GLError(4, version)) + + # Get other cached variables. + path = joinpath(self.config['m4base'], 'gnulib-cache.m4') + if isfile(joinpath(self.config['m4base'], 'gnulib-cache.m4')): + with codecs.open(path, 'rb', 'UTF-8') as file: + data = file.read() + + # Create regex object and keys. + pattern = compiler('^(gl_.*?)\\((.*?)\\)$', re.S | re.M) + keys = \ + [ + 'gl_LOCAL_DIR', 'gl_MODULES', 'gl_AVOID', 'gl_SOURCE_BASE', + 'gl_M4_BASE', 'gl_PO_BASE', 'gl_DOC_BASE', 'gl_TESTS_BASE', + 'gl_MAKEFILE_NAME', 'gl_MACRO_PREFIX', 'gl_PO_DOMAIN', + 'gl_WITNESS_C_MACRO', 'gl_VC_FILES', 'gl_LIB', + ] + + # Find bool values. + if 'gl_LGPL(' in data: + keys.append('gl_LGPL') + self.cache.setLGPL(True) + if 'gl_LIBTOOL' in data: + self.cache.enableLibtool() + data = data.replace('gl_LIBTOOL', '') + if 'gl_CONDITIONAL_DEPENDENCIES' in data: + self.cache.enableCondDeps() + data = data.replace('gl_CONDITIONAL_DEPENDENCIES', '') + if 'gl_VC_FILES' in data: + self.cache.enableVCFiles() + data = data.replace('gl_VC_FILES', '') + if 'gl_WITH_TESTS' in data: + self.cache.enableTestFlag(TESTS['tests']) + data = data.replace('gl_WITH_TESTS', '') + if 'gl_WITH_OBSOLETE' in data: + self.cache.enableTestFlag(TESTS['obsolete']) + data = data.replace('gl_WITH_OBSOLETE', '') + if 'gl_WITH_CXX_TESTS' in data: + self.cache.enableTestFlag(TESTS['c++-test']) + data = data.replace('gl_WITH_CXX_TESTS', '') + if 'gl_WITH_LONGRUNNING_TESTS' in data: + self.cache.enableTestFlag(TESTS['longrunning-test']) + data = data.replace('gl_WITH_LONGRUNNING_TESTS', '') + if 'gl_WITH_PRIVILEGED_TESTS' in data: + self.cache.enableTestFlag(TESTS['privileged-test']) + data = data.replace('gl_WITH_PRIVILEGED_TESTS', '') + if 'gl_WITH_UNPORTABLE_TESTS' in data: + self.cache.enableTestFlag(TESTS['unportable-test']) + data = data.replace('gl_WITH_UNPORTABLE_TESTS', '') + if 'gl_WITH_ALL_TESTS' in data: + self.cache.enableTestFlag(TESTS['all-test']) + data = data.replace('gl_WITH_ALL_TESTS', '') + # Find string values + result = dict(pattern.findall(data)) + values = cleaner([result.get(key, '') for key in keys]) + tempdict = dict(zip(keys, values)) + if 'gl_LGPL' in tempdict: + lgpl = cleaner(tempdict['gl_LGPL']) + if lgpl.isdecimal(): + self.cache.setLGPL(int(self.cache['lgpl'])) + else: # if 'gl_LGPL' not in tempdict + self.cache.setLGPL(False) + if tempdict['gl_LIB']: + self.cache.setLibName(cleaner(tempdict['gl_LIB'])) + if tempdict['gl_LOCAL_DIR']: + self.cache.setLocalDir(cleaner(tempdict['gl_LOCAL_DIR'])) + if tempdict['gl_MODULES']: + self.cache.setModules(cleaner(tempdict['gl_MODULES'].split())) + if tempdict['gl_AVOID']: + self.cache.setAvoids(cleaner(tempdict['gl_AVOID'].split())) + if tempdict['gl_SOURCE_BASE']: + self.cache.setSourceBase(cleaner(tempdict['gl_SOURCE_BASE'])) + if tempdict['gl_M4_BASE']: + self.cache.setM4Base(cleaner(tempdict['gl_M4_BASE'])) + if tempdict['gl_PO_BASE']: + self.cache.setPoBase(cleaner(tempdict['gl_PO_BASE'])) + if tempdict['gl_DOC_BASE']: + self.cache.setDocBase(cleaner(tempdict['gl_DOC_BASE'])) + if tempdict['gl_TESTS_BASE']: + self.cache.setTestsBase(cleaner(tempdict['gl_TESTS_BASE'])) + if tempdict['gl_MAKEFILE_NAME']: + self.cache.setMakefile(cleaner(tempdict['gl_MAKEFILE_NAME'])) + if tempdict['gl_MACRO_PREFIX']: + self.cache.setMacroPrefix(cleaner(tempdict['gl_MACRO_PREFIX'])) + if tempdict['gl_PO_DOMAIN']: + self.cache.setPoDomain(cleaner(tempdict['gl_PO_DOMAIN'])) + if tempdict['gl_WITNESS_C_MACRO']: + self.cache.setWitnessCMacro(cleaner(tempdict['gl_WITNESS_C_MACRO'])) + + # Get cached filelist from gnulib-comp.m4. + destdir, m4base = self.config.getDestDir(), self.config.getM4Base() + path = joinpath(destdir, m4base, 'gnulib-comp.m4') + if isfile(path): + with codecs.open(path, 'rb', 'UTF-8') as file: + data = file.read() + regex = 'AC_DEFUN\\(\\[%s_FILE_LIST\\], \\[(.*?)\\]\\)' % \ + self.cache['macro_prefix'] + 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) + + if self.mode != MODES['import']: + if self.cache['m4base'] and \ + (self.config['m4base'] != self.cache['m4base']): + raise(GLError(5, m4base)) + + # Perform actions with modules. In --add-import, append each given module + # to the list of cached modules; in --remove-import, remove each given + # module from the list of cached modules; in --update, simply set + # self.config['modules'] to its cached version. + new, old = self.config.getModules(), self.cache.getModules() + if self.mode == MODES['add-import']: + modules = sorted(set(new +old)) + elif self.mode == MODES['remove-import']: + modules = [module for module in old if module in new] + elif self.mode == MODES['update']: + modules = self.cache.getModules() + + # If user tries to apply conddeps and testflag['tests'] together. + if self.config['tests'] and self.config['conddeps']: + raise(GLError(10, None)) + + # Update configuration dictionary. + self.config.update(self.cache) + for key in config.keys(): + value = config[key] + if not config.isdefault(key, value): + self.config.update_key(config, key) + self.config.setModules(modules) + + # Check if conddeps is enabled together with inctests. + inctests = self.config.checkTestFlag(TESTS['tests']) + if self.config['conddeps'] and inctests: + raise(GLError(10, None)) + + # Define GLImport attributes. + self.emiter = GLEmiter(self.config) + self.filesystem = GLFileSystem(self.config) + self.modulesystem = GLModuleSystem(self.config) + self.moduletable = GLModuleTable(self.config, list()) + self.makefiletable = GLMakefileTable(self.config) + + def __repr__(self): + '''x.__repr__ <==> repr(x)''' + result = '<pygnulib.GLImport %s>' % hex(id(self)) + return(result) + + def rewrite_old_files(self, files): + '''GLImport.rewrite_old_files(files) -> list + + Replace auxdir, docbase, sourcebase, m4base and testsbase from default + to their version from cached config.''' + if type(files) is not list: + raise(TypeError( + 'files argument must has list type, not %s' % type(files).__name__)) + files = \ + [ # Begin to convert bytes to string + file.decode(ENCS['default']) \ + if type(file) is bytes else file \ + for file in files + ] # Finish to convert bytes to string + for file in files: + if type(file) is not string: + raise(TypeError('each file must be a string instance')) + files = sorted(set(files)) + files = ['%s%s' % (file, os.path.sep) for file in files] + auxdir = self.cache['auxdir'] + docbase = self.cache['docbase'] + sourcebase = self.cache['sourcebase'] + m4base = self.cache['m4base'] + testsbase = self.cache['testsbase'] + result = list() + for file in files: + if file.startswith('build-aux/'): + path = constants.substart('build-aux/', '%s/' % auxdir, file) + elif file.startswith('doc/'): + path = constants.substart('doc/', '%s/' % docbase, file) + elif file.startswith('lib/'): + path = constants.substart('lib/', '%s/' % sourcebase, file) + elif file.startswith('m4/'): + path = constants.substart('m4/', '%s/' % m4base, file) + elif file.startswith('tests/'): + path = constants.substart('tests/', '%s/' % testsbase, file) + elif file.startswith('tests=lib/'): + path = constants.substart('tests=lib/', '%s/' % testsbase, file) + elif file.startswith('top/'): + path = constants.substart('top/', '', file) + else: # file is not a special file + path = file + result += [os.path.normpath(path)] + result = sorted(set(result)) + return(list(result)) + + def rewrite_new_files(self, files): + '''GLImport.rewrite_new_files(files) + + Replace auxdir, docbase, sourcebase, m4base and testsbase from default + to their version from config.''' + if type(files) is not list: + raise(TypeError( + 'files argument must has list type, not %s' % type(files).__name__)) + files = \ + [ # Begin to convert bytes to string + file.decode(ENCS['default']) \ + if type(file) is bytes else file \ + for file in files + ] # Finish to convert bytes to string + for file in files: + if type(file) is not string: + raise(TypeError('each file must be a string instance')) + files = sorted(set(files)) + auxdir = self.config['auxdir'] + docbase = self.config['docbase'] + sourcebase = self.config['sourcebase'] + m4base = self.config['m4base'] + testsbase = self.config['testsbase'] + result = list() + for file in files: + if file.startswith('build-aux/'): + path = constants.substart('build-aux/', '%s/' % auxdir, file) + elif file.startswith('doc/'): + path = constants.substart('doc/', '%s/' % docbase, file) + elif file.startswith('lib/'): + path = constants.substart('lib/', '%s/' % sourcebase, file) + elif file.startswith('m4/'): + path = constants.substart('m4/', '%s/' % m4base, file) + elif file.startswith('tests/'): + path = constants.substart('tests/', '%s/' % testsbase, file) + elif file.startswith('tests=lib/'): + path = constants.substart('tests=lib/', '%s/' % testsbase, file) + elif file.startswith('top/'): + path = constants.substart('top/', '', file) + else: # file is not a special file + path = file + result += [os.path.normpath(path)] + result = sorted(set(result)) + return(list(result)) + + def actioncmd(self): + '''Return command-line invocation comment.''' + modules = self.config.getModules() + avoids = self.config.getAvoids() + destdir = self.config.getDestDir() + localdir = self.config.getLocalDir() + auxdir = self.config.getAuxDir() + sourcebase = self.config.getSourceBase() + m4base = self.config.getM4Base() + docbase = self.config.getDocBase() + pobase = self.config.getPoBase() + testsbase = self.config.getTestsBase() + testflags = self.config.getTestFlags() + conddeps = self.config.checkCondDeps() + libname = self.config.getLibName() + lgpl = self.config.getLGPL() + makefile = self.config.getMakefile() + libtool = self.config.checkLibtool() + macro_prefix = self.config.getMacroPrefix() + witness_c_macro = self.config.getWitnessCMacro() + podomain = self.config.getPoDomain() + vc_files = self.config.checkVCFiles() + verbose = self.config.getVerbosity() + + # Create command-line invocation comment. + actioncmd = 'gnulib-tool --import' + actioncmd += ' --dir=%s' % destdir + if localdir: + actioncmd += ' --local-dir=%s' % localdir + actioncmd += ' --lib=%s' % libname + actioncmd += ' --source-base=%s' % sourcebase + actioncmd += ' --m4-base=%s' % m4base + if pobase: + actioncmd += ' --po-base=%s' % pobase + actioncmd += ' --doc-base=%s' % docbase + actioncmd += ' --tests-base=%s' % testsbase + actioncmd += ' --aux-dir=%s' % auxdir + if self.config.checkTestFlag(TESTS['tests']): + actioncmd += ' --with-tests' + if self.config.checkTestFlag(TESTS['obsolete']): + actioncmd += ' --with-obsolete' + if self.config.checkTestFlag(TESTS['c++-test']): + actioncmd += ' --with-c++-tests' + if self.config.checkTestFlag(TESTS['longrunning-test']): + actioncmd += ' --with-longrunning-tests' + if self.config.checkTestFlag(TESTS['privileged-test']): + actioncmd += ' --with-privileged-test' + if self.config.checkTestFlag(TESTS['unportable-test']): + actioncmd += ' --with-unportable-tests' + if self.config.checkTestFlag(TESTS['all-test']): + actioncmd += ' --with-all-tests' + for module in avoids: + actioncmd += ' --avoid=%s' % module + if lgpl: + if lgpl == True: + actioncmd += ' --lgpl' + else: # if lgpl != True + actioncmd += ' --lgpl=%s' % lgpl + if makefile: + actioncmd += ' --makefile-name=%s' % makefile + if conddeps: + actioncmd += ' --conditional-dependencies' + else: # if not conddeps + actioncmd += ' --no-conditional-dependencies' + if libtool: + actioncmd += ' --libtool' + else: # if not libtool + actioncmd += ' --no-libtool' + actioncmd += ' --macro-prefix=%s' % macro_prefix + if podomain: + actioncmd = ' --podomain=%s' % podomain + if witness_c_macro: + actioncmd += ' --witness_c_macro=%s' % witness_c_macro + if vc_files == True: + actioncmd += ' --vc-files' + elif vc_files == False: + actioncmd += ' --no-vc-files' + actioncmd += ' ' # Add a space + actioncmd += ' '.join(modules) + return(actioncmd) + + def gnulib_cache(self): + '''GLImport.gnulib_cache() -> string + + Emit the contents of generated $m4base/gnulib-cache.m4 file. + GLConfig: destdir, localdir, tests, sourcebase, m4base, pobase, docbase, + testsbase, conddeps, libtool, macro_prefix, podomain, vc_files.''' + emit = string() + moduletable = self.moduletable + actioncmd = self.actioncmd() + destdir = self.config['destdir'] + localdir = self.config['localdir'] + testflags = list(self.config['testflags']) + sourcebase = self.config['sourcebase'] + m4base = self.config['m4base'] + pobase = self.config['pobase'] + docbase = self.config['docbase'] + testsbase = self.config['testsbase'] + lgpl = self.config['lgpl'] + libname = self.config['libname'] + makefile = self.config['makefile'] + conddeps = self.config['conddeps'] + libtool = self.config['libtool'] + macro_prefix = self.config['macro_prefix'] + podomain = self.config['podomain'] + witness_c_macro = self.config['witness_c_macro'] + vc_files = self.config['vc_files'] + modules = [str(module) for module in moduletable['base']] + avoids = [str(avoid) for avoid in moduletable['avoids']] + emit += self.emiter.copyright_notice() + emit += '''# +# This file represents the specification of how gnulib-tool is used. +# It acts as a cache: It is written and read by gnulib-tool. +# In projects that use version control, this file is meant to be put under +# version control, like the configure.ac and various Makefile.am files. + + +# 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 + emit += 'gl_MODULES([\n' + emit += ' %s\n' % '\n '.join(modules) + emit += '])\n' + if self.config.checkTestFlag(TESTS['obsolete']): + emit += 'gl_WITH_OBSOLETE\n' + if self.config.checkTestFlag(TESTS['cxx-tests']): + emit += 'gl_WITH_CXX_TESTS\n' + if self.config.checkTestFlag(TESTS['privileged-tests']): + emit += 'gl_WITH_PRIVILEGED_TESTS\n' + if self.config.checkTestFlag(TESTS['unportable-tests']): + emit += 'gl_WITH_UNPORTABLE_TESTS\n' + if self.config.checkTestFlag(TESTS['all-tests']): + emit += 'gl_WITH_ALL_TESTS\n' + emit += 'gl_AVOID([%s])\n' % ' '.join(avoids) + emit += 'gl_SOURCE_BASE([%s])\n' % sourcebase + emit += 'gl_M4_BASE([%s])\n' % m4base + emit += 'gl_PO_BASE([%s])\n' % pobase + emit += 'gl_DOC_BASE([%s])\n' % docbase + emit += 'gl_TESTS_BASE([%s])\n' % testsbase + if self.config.checkTestFlag(TESTS['tests']): + emit += 'gl_WITH_TESTS\n' + emit += 'gl_LIB([%s])\n' % libname + if lgpl != False: + if lgpl == True: + emit += 'gl_LGPL\n' + else: # if lgpl != True + emit += 'gl_LGPL([%d])\n' % lgpl + emit += 'gl_MAKEFILE_NAME([%s])\n' % makefile + if conddeps: + emit += 'gl_CONDITIONAL_DEPENDENCIES\n' + if libtool: + emit += 'gl_LIBTOOL\n' + emit += 'gl_MACRO_PREFIX([%s])\n' % macro_prefix + emit += 'gl_PO_DOMAIN([%s])\n' % podomain + emit += 'gl_WITNESS_C_DOMAIN([%s])\n' % witness_c_macro + if vc_files: + emit += 'gl_VC_FILES([%s])\n' % vc_files + if type(emit) is bytes: + emit = emit.decode(ENCS['default']) + return(constants.nlconvert(emit)) + + def gnulib_comp(self, files): + '''GLImport.gnulib_comp(files) -> string + + Emit the contents of generated $m4base/gnulib-comp.m4 file. + GLConfig: destdir, localdir, tests, sourcebase, m4base, pobase, docbase, + testsbase, conddeps, libtool, macro_prefix, podomain, vc_files.''' + emit = string() + 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'] + m4base = self.config['m4base'] + pobase = self.config['pobase'] + docbase = self.config['docbase'] + testsbase = self.config['testsbase'] + lgpl = self.config['lgpl'] + libname = self.config['libname'] + makefile = self.config['makefile'] + conddeps = self.config['conddeps'] + libtool = self.config['libtool'] + macro_prefix = self.config['macro_prefix'] + podomain = self.config['podomain'] + witness_c_macro = self.config['witness_c_macro'] + configure_ac = self.config['configure_ac'] + vc_files = self.config['vc_files'] + libtests = self.config['libtests'] + modules = [str(module) for module in moduletable['base']] + avoids = [str(avoid) for avoid in moduletable['avoids']] + emit += '# DO NOT EDIT! GENERATED AUTOMATICALLY!\n' + emit += self.emiter.copyright_notice() + emit += '''# +# This file represents the compiled summary of the specification in +# gnulib-cache.m4. It lists the computed macro invocations that need +# to be invoked from configure.ac. +# In projects that use version control, this file can be treated like +# other built files. + + +# This macro should be invoked from %s, in the section +# "Checks for programs", right after AC_PROG_CC, and certainly before +# any checks for libraries, header files, types and library functions. +AC_DEFUN([%s_EARLY], +[ + m4_pattern_forbid([^gl_[A-Z]])dnl the gnulib macro namespace + m4_pattern_allow([^gl_ES$])dnl a valid locale name + m4_pattern_allow([^gl_LIBOBJS$])dnl a variable + m4_pattern_allow([^gl_LTLIBOBJS$])dnl a variable + AC_REQUIRE([gl_PROG_AR_RANLIB])\n''' % (configure_ac, macro_prefix) + uses_subdirs = False + for module in moduletable['main']: + # Test whether there are some source files in subdirectories. + for file in module.getFiles(): + if file.startswith('lib/') and file.endswith('.c') and \ + file.count('/') > 1: + uses_subdirs = True + break + if uses_subdirs: + emit += ' AC_REQUIRE([AM_PROG_CC_C_O])\n' + for module in moduletable['final']: + emit += ' # Code from module %s:\n' % str(module) + snippet = module.getAutoconfSnippet_Early() + lines = [line for line in snippet.split(constants.NL) if line != ''] + if lines: + emit += ' %s\n' % '\n '.join(lines) + emit += '])\n' + emit += ''' +# This macro should be invoked from %s, in the section +# "Check for header files, types and library functions". +AC_DEFUN([%s_INIT], +[\n''' % (configure_ac, macro_prefix) + if libtool: + emit += ' AM_CONDITIONAL([GL_COND_LIBTOOL], [true])\n' + emit += ' gl_cond_libtool=true\n' + else: # if not libtool + emit += ' AM_CONDITIONAL([GL_COND_LIBTOOL], [false])\n' + emit += ' gl_cond_libtool=false\n' + emit += ' gl_libdeps=\n' + emit += ' gl_ltlibdeps=\n' + replace_auxdir = False + if auxdir != 'build-aux': + replace_auxdir = True + emit += ' gl_m4_base=\'%s\'\n' % m4base + emit += self.emiter.initmacro_start(macro_prefix) + emit += ' gl_source_base=\'%s\'\n' % sourcebase + if witness_c_macro: + emit += ' m4_pushdef([gl_MODULE_INDICATOR_CONDITION], [%s])\n' % \ + witness_c_macro + # Emit main autoconf snippets. + emit += self.emiter.autoconfSnippets(moduletable['main'], + moduletable, assistant, 0, True, False, True, replace_auxdir) + if witness_c_macro: + emit += ' m4_popdef([gl_MODULE_INDICATOR_CONDITION])\n' + emit += ' # End of code from modules\n' + emit += self.emiter.initmacro_end(macro_prefix) + emit += ' gltests_libdeps=\n' + emit += ' gltests_ltlibdeps=\n' + emit += self.emiter.initmacro_start('%stests' % macro_prefix) + emit += ' gl_source_base=\'%s\'\n' % testsbase + # Define a tests witness macro that depends on the package. + # PACKAGE is defined by AM_INIT_AUTOMAKE, PACKAGE_TARNAME is defined by + # AC_INIT. + # See <http://lists.gnu.org/archive/html/automake/2009-05/msg00145.html>. + emit += 'changequote(,)dnl\n' + emit += ' %stests_WITNESS=' % macro_prefix + emit += 'IN_`echo "${PACKAGE-$PACKAGE_TARNAME}" | LC_ALL=C tr \ +abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ | LC_ALL=C sed -e \ +\'s/[^A-Z0-9_]/_/g\'`_GNULIB_TESTS\n' + emit += 'changequote([, ])dnl\n' + emit += ' AC_SUBST([%stests_WITNESS])\n' % macro_prefix + emit += ' gl_module_indicator_condition=$%stests_WITNESS\n' % macro_prefix + emit += ' m4_pushdef([gl_MODULE_INDICATOR_CONDITION], ' + emit += '[$gl_module_indicator_condition])\n' + # Emit tests autoconf snippets. + emit += self.emiter.autoconfSnippets(moduletable['tests'], + moduletable, assistant, 0, True, True, True, replace_auxdir) + emit += ' m4_popdef([gl_MODULE_INDICATOR_CONDITION])\n' + emit += self.emiter.initmacro_end('%stests' % macro_prefix) + # _LIBDEPS and _LTLIBDEPS variables are not needed if this library is + # created using libtool, because libtool already handles the dependencies. + if not libtool: + libname_upper = libname.upper().replace('-', '_') + emit += ' %s_LIBDEPS="$gl_libdeps"\n' % libname_upper + emit += ' AC_SUBST([%s_LIBDEPS])\n' % libname_upper + emit += ' %s_LTLIBDEPS="$gl_ltlibdeps"\n' % libname_upper + emit += ' AC_SUBST([%s_LTLIBDEPS])\n' % libname_upper + if libtests: + emit += ' LIBTESTS_LIBDEPS="$gltests_libdeps"\n' + emit += ' AC_SUBST([LIBTESTS_LIBDEPS])\n' + emit += '])\n' + emit += self.emiter.initmacro_done(macro_prefix, sourcebase) + emit += self.emiter.initmacro_done('%stests' % macro_prefix, testsbase) + emit += ''' +# This macro records the list of files which have been installed by +# gnulib-tool and may be removed by future gnulib-tool invocations. +AC_DEFUN([%s_FILE_LIST], [\n''' % macro_prefix + emit += ' %s\n' % '\n '.join(files) + emit += '])\n' + if type(emit) is bytes: + emit = emit.decode(ENCS['default']) + return(emit) + + def _done_dir_(self, directory, dirs_added, dirs_removed): + '''GLImport._done_dir_(directory, dirs_added, dirs_removed) + + This method is used to determine ignore argument for _update_ignorelist_ + method and then call it.''' + destdir = self.config['destdir'] + if isdir(joinpath(destdir, 'CVS')) or \ + isdir(joinpath(destdir, directory, 'CVS')) or \ + isfile(joinpath(destdir, directory, '.cvsignore')): + self._update_ignorelist_(directory, '.cvsignore', + dirs_added, dirs_removed) + if isdir(joinpath(destdir, '.git')) or \ + isfile(joinpath(destdir, directory, '.gitignore')): + self._update_ignorelist_(directory, '.gitignore', + dirs_added, dirs_removed) + + + def _update_ignorelist_(self, directory, ignore, dirs_added, dirs_removed): + '''GLImport._update_ignorelist_(directory, ignore, dirs_added, dirs_removed) + + Update .gitignore or .cvsignore files.''' + result = string() + destdir = self.config['destdir'] + if ignore == '.gitignore': + anchor = '/' + else: + anchor = '' + srcpath = joinpath(destdir, directory, ignore) + backupname = '%s~' % srcpath + if isfile(srcpath): + if dirs_added or dirs_removed: + with codecs.open(srcpath, 'rb', 'UTF-8') as file: + srcdata = file.read() + dirs_ignore = sorted(set(srcdata.split('\n'))) + dirs_ignore = [line for line in dirs_ignore if line.strip()] + srcdata = '\n'.join(sorted(set(dirs_ignore))).strip() + dirs_ignore += [d for d in dirs_added if d not in dirs_ignore] + dirs_ignore = [d for d in dirs_ignore if d in dirs_removed] + dirs_ignore = ['%s%s' % (anchor, d) for d in dirs_ignore] + dirs_ignore = sorted(set(dirs_ignore)) + destdata = '\n'.join(sorted(set(dirs_ignore))).strip() + if srcdata != destdata: + if not self.config['dryrun']: + print('Updating %s (backup in %s)' % (srcpath, backupname)) + shutil.move(srcpath, backupname) + result = string() + with codecs.open(srcpath, 'wb', 'UTF-8') as file: + file.write(destdata) + else: # if self.config['dryrun'] + print('Updating %s (backup in %s)' % (srcpath, backupname)) + else: # if not isfile(srcpath) + if dirs_added: + if not self.config['dryrun']: + print('Creating %s' % srcpath) + dirs_added = sorted(set(dirs_added)) + dirs_added = ['%s%s' % (anchor, d) for d in dirs_added] + if ignore == '.cvsignore': + dirs_added = ['.deps', '.dirstamp'] +dirs_added + with codecs.open(srcpath, 'wb', 'UTF-8') as file: + file.write('\n'.join(dirs_added)) + file.write('\n') + else: # if self.config['dryrun'] + print('Create %s' % srcpath) + + def prepare(self): + '''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']) + testflags = list(self.config['testflags']) + sourcebase = self.config['sourcebase'] + m4base = self.config['m4base'] + pobase = self.config['pobase'] + docbase = self.config['docbase'] + testsbase = self.config['testsbase'] + lgpl = self.config['lgpl'] + copyrights = self.config['copyrights'] + libname = self.config['libname'] + makefile = self.config['makefile'] + conddeps = self.config['conddeps'] + libtool = self.config['libtool'] + macro_prefix = self.config['macro_prefix'] + podomain = self.config['podomain'] + witness_c_macro = self.config['witness_c_macro'] + vc_files = self.config['vc_files'] + configure_ac = self.config['configure_ac'] + ac_version = self.config['ac_version'] + verbose = self.config['verbosity'] + base_modules = sorted(set([self.modulesystem.find(m) for m in modules])) + avoids = sorted(set([self.modulesystem.find(a) for a in avoids])) + + # Perform transitive closure. + self.moduletable.setAvoids(avoids) + final_modules = self.moduletable.transitive_closure(base_modules) + + # Show final module list. + if verbose >= 0: + bold_on = '' + bold_off = '' + term = os.getenv('TERM') + if term == 'xterm': + bold_on = '\x1b[1m' + bold_off = '\x1b[0m' + print('Module list with included dependencies (indented):') + for module in final_modules: + if str(module) in self.config.getModules(): + print(' %s%s%s' % (bold_on, module, bold_off)) + else: # if str(module) not in self.config.getModules() + print(' %s' % module) + + # Separate modules into main_modules and tests_modules. + modules = self.moduletable.transitive_closure_separately( + base_modules, final_modules) + main_modules, tests_modules = modules + + # Transmit base_modules, final_modules, main_modules and tests_modules. + self.moduletable.setBaseModules(base_modules) + self.moduletable.setFinalModules(final_modules) + self.moduletable.setMainModules(main_modules) + self.moduletable.setTestsModules(tests_modules) + + # Print main_modules and tests_modules. + if verbose >= 1: + print('Main module list:') + for module in main_modules: + print(' %s' % str(module)) + print('Tests-related module list:') + for module in tests_modules: + print(' %s' % str(module)) + + # Determine whether a $testsbase/libtests.a is needed. + libtests = False + for module in tests_modules: + files = module.getFiles() + for file in files: + if file.startswith('lib/'): + libtests = True + break + if libtests: + self.config.enableLibtests() + + # Add dummy package if it is needed. + main_modules = self.moduletable.add_dummy(main_modules) + if libtests: # if we need to use libtests.a + tests_modules = self.moduletable.add_dummy(tests_modules) + + # Check license incompatibilities. + listing = list() + compatibilities = dict() + incompatibilities = string() + compatibilities['all'] = ['GPLed build tool', 'public domain', 'unlimited', + 'unmodifiable license text'] + compatibilities[3] = ['LGPL', 'LGPLv2+', 'LGPLv3+'] + compatibilities[2] = ['LGPLv2+'] + if lgpl: + for module in main_modules: + license = module.getLicense() + if license not in compatibilities['all']: + if lgpl == 3 or lgpl == True: + if license not in compatibilities[3]: + listing.append(tuple([str(module), license])) + elif lgpl == 2: + if license not in compatibilities[2]: + listing.append(tuple([str(module), license])) + if listing: + raise(GLError(11, listing)) + + # Print notices from modules. + for module in main_modules: + notice = module.getNotice() + notice = notice.strip() + if notice: + print('Notice from module %s:' % str(module)) + pattern = compiler('^(.*?)$', re.S | re.M) + notice = pattern.sub(' \\1', notice) + print(notice) + + # Determine script to apply to imported library files. + lgpl2gpl = ''' + s/GNU Lesser General/GNU General/g + s/Lesser General Public License/General Public License/g + s/GNU Library General/GNU General/g + s/Library General Public License/General Public License/g + s/version 2\\(.1\\)\\{0,1\\}\\([ ,]\\)/version 3\\2/g''' + sed_transform_lib_file = string() + if 'config-h' in [str(module) for module in main_modules]: + sed_transform_lib_file += ''' + s/^#ifdef[\t ]*HAVE_CONFIG_H[\t ]*$/#if 1/ + ''' + sed_transform_main_lib_file = sed_transform_lib_file + if copyrights: + if lgpl: # if lgpl is enabled + if lgpl == 3: + sed_transform_main_lib_file += ''' + s/GNU General/GNU Lesser General/g + s/General Public License/Lesser General Public License/g + s/Lesser Lesser General Public License/Lesser General Public''' \ + +' License/g' + elif lgpl == 2: + sed_transform_main_lib_file += ''' + s/GNU General/GNU Lesser General/g + s/General Public License/Lesser General Public License/g + s/Lesser Lesser General Public License/Lesser General Public''' \ + +'''License/g + s/version [23]\\([ ,]\\)/version 2.1\\1/g''' + else: # if lgpl is disabled + sed_transform_main_lib_file += lgpl2gpl + + # Determine script to apply to auxiliary files that go into $auxdir/. + sed_transform_build_aux_file = string() + if copyrights: + sed_transform_build_aux_file += lgpl2gpl + + # Determine script to apply to library files that go into $testsbase/. + sed_transform_testsrelated_lib_file = sed_transform_lib_file + if copyrights: + sed_transform_testsrelated_lib_file += lgpl2gpl + + # Determine the final file lists. + main_filelist, tests_filelist = \ + self.moduletable.filelist_separately(main_modules, tests_modules) + filelist = sorted(set(main_filelist +tests_filelist), key=string.lower) + if not filelist: + raise(GLError(12, None)) + + # Print list of files. + if verbose >= 0: + print('File list:') + for file in filelist: + if file.startswith('tests=lib/'): + rest = file[10:] + print(' lib/%s -> tests/%s' % (rest, rest)) + else: + print(' %s' % file) + + # Prepare basic filelist and basic old_files/new_files variables. + filelist = sorted(set(filelist)) + new_files = filelist +['m4/gnulib-tool.m4'] + old_files = list(self.cache['files']) + path = joinpath(destdir, m4base, 'gnulib-tool.m4') + if isfile(path): + old_files += [joinpath('m4', 'gnulib-tool.m4')] + + # Construct tables and transformers. + transformers = dict() + transformers['lib'] = string(sed_transform_lib_file) + transformers['aux'] = string(sed_transform_build_aux_file) + transformers['main'] = string(sed_transform_main_lib_file) + transformers['tests'] = string(sed_transform_testsrelated_lib_file) + old_table = list() + new_table = list() + for src in old_files: + dest = self.rewrite_old_files([src])[-1] + old_table += [tuple([dest, src])] + for src in new_files: + dest = self.rewrite_new_files([src])[-1] + new_table += [tuple([dest, src])] + old_table = sorted(set(old_table)) + new_table = sorted(set(new_table)) + + # Prepare the filetable. + filetable = dict() + filetable['all'] = sorted(set(filelist)) + filetable['old'] = \ + sorted(set(old_table), key=lambda t: tuple(t[0].lower())) + filetable['new'] = \ + sorted(set(new_table), key=lambda t: tuple(t[0].lower())) + filetable['added'] = list() + filetable['removed'] = list() + + # Return the result. + result = tuple([filetable, transformers]) + return(result) + + def execute(self, filetable, transformers): + '''Perform operations on the lists of files, which are given in a special + format except filelist argument. Such lists of files can be created using + GLImport.prepare() function.''' + if type(filetable) is not dict: + raise(TypeError('filetable must be a dict, not %s' % \ + type(filetable).__name__)) + for key in ['all', 'old', 'new', 'added', 'removed']: + 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']) + testflags = list(self.config['testflags']) + sourcebase = self.config['sourcebase'] + m4base = self.config['m4base'] + pobase = self.config['pobase'] + docbase = self.config['docbase'] + testsbase = self.config['testsbase'] + lgpl = self.config['lgpl'] + copyrights = self.config['copyrights'] + libname = self.config['libname'] + makefile = self.config['makefile'] + conddeps = self.config['conddeps'] + libtool = self.config['libtool'] + macro_prefix = self.config['macro_prefix'] + podomain = self.config['podomain'] + witness_c_macro = self.config['witness_c_macro'] + vc_files = self.config['vc_files'] + configure_ac = self.config['configure_ac'] + ac_version = self.config['ac_version'] + verbose = self.config['verbosity'] + actioncmd = self.actioncmd() + + # Create all necessary directories. + dirs = list() + if pobase: + dirs += [pobase] + if [file for file in filetable['all'] if file.startswith('doc/')]: + dirs += [docbase] + dirs += [sourcebase, m4base, auxdir] + dirs += [os.path.dirname(pair[0]) for pair in filetable['new']] + dirs = sorted(set([joinpath(destdir, d) for d in dirs])) + for directory in dirs: + if not isdir(directory): + print('Creating directory %s' % directory) + if not self.config['dryrun']: + try: # Try to create directory + os.makedirs(directory) + except Exception as error: + raise(GLError(13, directory)) + else: # if self.config['dryrun'] + print('Create directory %s' % directory) + + # Create GLFileAssistant instance to process files. + self.assistant = GLFileAssistant(self.config, transformers) + + # Files which are in filetable['old'] and not in filetable['new']. + # They will be removed and added to filetable['removed'] list. + pairs = [f for f in filetable['old'] if f not in filetable['old']] + pairs = sorted(set(pairs), key=lambda t: tuple(t[0].lower())) + files = sorted(set(pair[0] for pair in pairs)) + for file in files: + path = joinpath(destdir, file) + if isfile(path) or os.path.islink(path): + if not self.config['dryrun']: + backup = string('%s~' % path) + print('Removing file %s (backup in )' % (path, backup)) + try: # Try to move file + if os.path.exists(backup): + os.remove(backup) + shutil.move(path, '%s~' % path) + except Exception as error: + raise(GLError(14, file)) + else: # if self.config['dryrun'] + print('Remove file %s (backup in %s~)' % (path, path)) + filetable['removed'] += [file] + + # Files which are in filetable['new'] and not in filetable['old']. + # They will be added/updated and added to filetable['added'] list. + already_present = False + pairs = [f for f in filetable['new'] if f not in filetable['old']] + pairs = sorted(set(pairs)) + for pair in pairs: + original = pair[1] + rewritten = pair[0] + self.assistant.setOriginal(original) + self.assistant.setRewritten(rewritten) + self.assistant.add_or_update(already_present) + + # Files which are in filetable['new'] and in filetable['old']. + # They will be added/updated and added to filetable['added'] list. + already_present = True + pairs = [f for f in filetable['new'] if f in filetable['old']] + pairs = sorted(set(pairs)) + for pair in pairs: + original = pair[1] + rewritten = pair[0] + self.assistant.setOriginal(original) + self.assistant.setRewritten(rewritten) + self.assistant.add_or_update(already_present) + + # Add files which were added to the list of filetable['added']. + filetable['added'] += self.assistant.getFiles() + filetable['added'] = sorted(set(filetable['added'])) + + # Determine include_guard_prefix. + include_guard_prefix = self.config['include_guard_prefix'] + + # Determine makefile name. + if not makefile: + makefile_am = string('Makefile.am') + else: # if makefile + makefile_am = makefile + + # Create normal Makefile.ams. + for_test = False + + # Setup list of Makefile.am edits that are to be performed afterwards. + # Some of these edits apply to files that we will generate; others are + # under the responsibility of the developer. + makefile_am_edits = dict() + if makefile_am == 'Makefile.am': + sourcebase_dir = os.path.dirname(sourcebase) + sourcebase_base = os.path.basename(sourcebase) + self.makefiletable.editor(sourcebase_dir, 'SUBDIRS', sourcebase_base) + if pobase: + pobase_dir = os.path.dirname(pobase) + pobase_base = os.path.basename(pobase) + self.makefiletable.editor(pobase_dir, 'SUBDIRS', pobase_base) + if self.config.checkTestFlag(TESTS['tests']): + if makefile_am == 'Makefile.am': + testsbase_dir = os.path.dirname(testsbase) + testsbase_base = os.path.basename(testsbase) + self.makefiletable.editor(testsbase_dir, 'SUBDIRS', testsbase_base) + self.makefiletable.editor('', 'ACLOCAL_AMFLAGS', '-I %s' % m4base) + self.makefiletable.parent() + + # Create library makefile. + basename = joinpath(sourcebase, makefile_am) + tmpfile = self.assistant.tmpfilename(basename) + emit, uses_subdirs = self.emiter.lib_Makefile_am(basename, + self.moduletable['main'], self.moduletable, self.makefiletable, + actioncmd, for_test) + with codecs.open(tmpfile, 'wb', 'UTF-8') as file: + file.write(emit) + filename, backup, flag = self.assistant.super_update(basename, tmpfile) + if flag == 1: + if not self.config['dryrun']: + print('Updating %s (backup in %s)' % (filename, backup)) + else: # if self.config['dryrun'] + print('Update %s (backup in %s)' % (filename, backup)) + elif flag == 2: + if not self.config['dryrun']: + print('Creating %s' % filename) + else: # if self.config['dryrun']: + print('Create %s' % filename) + filetable['added'] += [filename] + if isfile(tmpfile): + os.remove(tmpfile) + + # Create po/ directory. + filesystem = GLFileSystem(self.config) + if pobase: + # Create po makefile and auxiliary files. + for file in ['Makefile.in.in', 'remove-potcdate.sin']: + tmpfile = self.assistant.tmpfilename(joinpath(pobase, file)) + path = joinpath('build-aux', 'po', file) + lookedup, flag = filesystem.lookup(path) + shutil.move(lookedup, tmpfile) + basename = joinpath(pobase, file) + filename, backup, flag = self.assistant.super_update(basename, tmpfile) + if flag == 1: + if not self.config['dryrun']: + print('Updating %s (backup in %s)' % (filename, backup)) + else: # if self.config['dryrun'] + print('Update %s (backup in %s)' % (filename, backup)) + elif flag == 2: + if not self.config['dryrun']: + print('Creating %s' % filename) + else: # if self.config['dryrun']: + print('Create %s' % filename) + filetable['added'] += [filename] + if isfile(tmpfile): + os.remove(tmpfile) + + # Create po makefile parameterization, part 1. + basename = joinpath(pobase, 'Makevars') + tmpfile = self.assistant.tmpfilename(basename) + emit = self.emiter.po_Makevars() + with codecs.open(tmpfile, 'wb', 'UTF-8') as file: + file.write(emit) + filename, backup, flag = self.assistant.super_update(basename, tmpfile) + if flag == 1: + if not self.config['dryrun']: + print('Updating %s (backup in %s)' % (filename, backup)) + else: # if self.config['dryrun'] + print('Update %s (backup in %s)' % (filename, backup)) + elif flag == 2: + if not self.config['dryrun']: + print('Creating %s' % filename) + else: # if self.config['dryrun']: + print('Create %s' % filename) + filetable['added'] += [filename] + if isfile(tmpfile): + os.remove(tmpfile) + + # Create po makefile parameterization, part 2. + basename = joinpath(pobase, 'POTFILES.in') + tmpfile = self.assistant.tmpfilename(basename) + with codecs.open(tmpfile, 'wb', 'UTF-8') as file: + file.write(self.emiter.po_POTFILES_in(filetable['all'])) + basename = joinpath(pobase, 'POTFILES.in') + filename, backup, flag = self.assistant.super_update(basename, tmpfile) + if flag == 1: + if not self.config['dryrun']: + print('Updating %s (backup in %s)' % (filename, backup)) + else: # if self.config['dryrun'] + print('Update %s (backup in %s)' % (filename, backup)) + elif flag == 2: + if not self.config['dryrun']: + print('Creating %s' % filename) + else: # if self.config['dryrun']: + print('Create %s' % filename) + filetable['added'] += [filename] + if isfile(tmpfile): + os.remove(tmpfile) + + # Fetch PO files. + TP_URL = 'http://translationproject.org/latest/' + TP_RSYNC_URI = 'translationproject.org::tp/latest/' + if not self.config['dryrun']: + print('Fetching gnulib PO files from %s' % TP_URL) + os.chdir(joinpath(destdir, pobase)) + cmd = 'if type rsync 2>/dev/null | grep / > /dev/null; ' + cmd += 'then echo 1; else echo 0; fi' + result = sp.check_output(cmd, shell=True) + result = bool(int(result)) + if result: # use rsync + args = ['rsync', '-Lrtz', '%sgulib/' % TP_RSYNC_URI, '.'] + else: # use wget + args = ['wget', '--quiet', '-r', '-l1', '-nd', '-np', 'A.po', + '%sgnulib' % TP_URL] + sp.call(args, shell=True) + else: # if self.config['dryrun'] + print('Fetch gnulib PO files from %s' % TP_URL) + + # Create po/LINGUAS. + basename = joinpath(pobase, 'LINGUAS') + if not self.config['dryrun']: + tmpfile = self.assistant.tmpfilename(basename) + data = string('# Set of available languages.\n') + files = [constants.subend('.po', '', file) \ + for file in os.listdir(joinpath(destdir, pobase))] + files = [file.decode(ENCS['default']) if type(file) is bytes \ + else file for file in files] + data += '\n'.join(files) + with codecs.open(tmpfile, 'wb', 'UTF-8') as file: + file.write(data) + filename, backup, flag = self.assistant.super_update(basename, tmpfile) + if flag == 1: + print('Updating %s (backup in %s)' % (filename, backup)) + elif flag == 2: + print('Creating %s' % filename) + filetable['added'] += [filename] + if isfile(tmpfile): + os.remove(tmpfile) + else: # if not self.config['dryrun'] + backupname = '%s~' % basename + if isfile(destdir, basename): + print('Update %s (backup in %s)' % (basename, backupname)) + else: # if not isfile(destdir, basename) + print('Create %s' % basename) + + # Create m4/gnulib-cache.m4. + basename = joinpath(m4base, 'gnulib-cache.m4') + tmpfile = self.assistant.tmpfilename(basename) + emit = self.gnulib_cache() + with codecs.open(tmpfile, 'wb', 'UTF-8') as file: + file.write(emit) + filename, backup, flag = self.assistant.super_update(basename, tmpfile) + if flag == 1: + if not self.config['dryrun']: + print('Updating %s (backup in %s)' % (filename, backup)) + else: # if self.config['dryrun'] + print('Update %s (backup in %s)' % (filename, backup)) + elif flag == 2: + if not self.config['dryrun']: + print('Creating %s' % filename) + else: # if self.config['dryrun']: + print('Create %s' % filename) + if emit[-2:] == '\r\n': + emit = emit[:-2] + elif emit[-1:] == '\n': + emit = emit[:-1] + print(emit) + if isfile(tmpfile): + os.remove(tmpfile) + + # Create m4/gnulib-comp.m4. + basename = joinpath(m4base, 'gnulib-comp.m4') + tmpfile = self.assistant.tmpfilename(basename) + emit = self.gnulib_comp(filetable['all']) + with codecs.open(tmpfile, 'wb', 'UTF-8') as file: + file.write(emit) + filename, backup, flag = self.assistant.super_update(basename, tmpfile) + if flag == 1: + if not self.config['dryrun']: + print('Updating %s (backup in %s)' % (filename, backup)) + else: # if self.config['dryrun'] + print('Update %s (backup in %s)' % (filename, backup)) + elif flag == 2: + if not self.config['dryrun']: + print('Creating %s' % filename) + else: # if self.config['dryrun']: + print('Create %s' % filename) + if emit[-2:] == '\r\n': + emit = emit[:-2] + elif emit[-1:] == '\n': + emit = emit[:-1] + print(emit) + if isfile(tmpfile): + os.remove(tmpfile) + + # Create tests Makefile. + inctests = self.config.checkTestFlag(TESTS['tests']) + if inctests: + basename = joinpath(testsbase, makefile_am) + tmpfile = self.assistant.tmpfilename(basename) + emit, uses_subdirs = self.emiter.lib_Makefile_am(basename, + self.moduletable['tests'], self.moduletable, self.makefiletable, + actioncmd, for_test) + with codecs.open(tmpfile, 'wb', 'UTF-8') as file: + file.write(emit) + filename, backup, flag = self.assistant.super_update(basename, tmpfile) + if flag == 1: + if not self.config['dryrun']: + print('Updating %s (backup in %s)' % (filename, backup)) + else: # if self.config['dryrun'] + print('Update %s (backup in %s)' % (filename, backup)) + elif flag == 2: + if not self.config['dryrun']: + print('Creating %s' % filename) + else: # if self.config['dryrun']: + print('Create %s' % filename) + filetable['added'] += [filename] + if isfile(tmpfile): + os.remove(tmpfile) + + # Update the .cvsignore and .gitignore files. + ignorelist = list() + filetable['added'] = sorted(set(filetable['added'])) + filetable['removed'] = sorted(set(filetable['added'])) + for file in filetable['added']: + directory, basename = os.path.split(file) + ignorelist += [tuple([directory, '|A|', basename])] + for file in filetable['removed']: + directory, basename = os.path.split(file) + ignorelist += [tuple([directory, '|R|', basename])] + last_dir = string() + last_dirs_added = list() + last_dirs_removed = list() + for row in ignorelist: + next_dir = row[0] + operand = row[1] + filename = row[2] + if next_dir != last_dir: + self._done_dir_(last_dir, last_dirs_added, last_dirs_removed) + last_dir = next_dir + last_dirs_added = list() + last_dirs_removed = list() + if operand == '|A|': + last_dirs_added += [filename] + elif operand == '|R|': + last_dirs_removed += [filename] + self._done_dir_(last_dir, last_dirs_added, last_dirs_removed) + exit() + + # Finish the work. + print('Finished.\n') + print('You may need to add #include directives \ +for the following .h files.') + modules = sorted(set([module for module in self.moduletable['base'] \ + if module in self.moduletable['main']])) + # First the #include <...> directives without #ifs, sorted for convenience, + # then the #include "..." directives without #ifs, sorted for convenience, + # then the #include directives that are surrounded by #ifs. Not sorted. + includes_angles = list() + includes_quotes = list() + includes_if = list() + for module in modules: + include = module.getInclude() + for include in include.split('\n'): + if '%s#if' % constants.NL in '%s%s' % (constants.NL, include): + includes_if += [include] + else: # if '%s#if' % constants.NL in '%s%s' % (constants.NL, include) + if 'include "' in include: + includes_quotes += [include] + else: # if 'include "' not in include + includes_angles += [include] + includes_angles = sorted(set(includes_angles)) + includes_quotes = sorted(set(includes_quotes)) + includes = includes_angles +includes_quotes +includes_if + includes = [include for include in includes if include.split()] + for include in includes: + print(' %s' % include) + + # Get link directives. + links = [module.getLink() for module in self.moduletable['main']] + links = sorted(set([link for link in links if link.strip()])) + if links: + print(''' +You may need to use the following Makefile variables when linking. +Use them in <program>_LDADD when linking a program, or +in <library>_a_LDFLAGS or <library>_la_LDFLAGS when linking a library.''') + for link in links: + print(' %s' % link) + + # Print reminders. + print('') + print('Don\'t forget to') + if makefile_am == 'Makefile.am': + print(' - add "%s/Makefile" to AC_CONFIG_FILES in %s,' % \ + (sourcebase, configure_ac)) + else: # if makefile_am != 'Makefile.am' + print(' - "include %s" from within "%s/Makefile.am",' % \ + (makefile, sourcebase)) + if pobase: + print(' - add "%s/Makefile.in to AC_CONFIG_FILES in %s,' % \ + (pobase, configure_ac)) + if inctests: + if makefile_am == 'Makefile.am': + print(' - add "%s/Makefile" to AC_CONFIG_FILES in %s,' % \ + (testsbase, configure_ac)) + else: # if makefile_am != 'Makefile.am' + print(' - "include %s" from within "%s/Makefile.am",' % \ + (makefile, testsbase)) + # Print makefile edits. + current_edit = int() + makefile_am_edits = self.makefiletable.count() + while current_edit != makefile_am_edits: + dictionary = self.makefiletable[current_edit] + if dictionary['var']: + print(' - mention "%s" in %s in %s,' % \ + (dictionary['val'], dictionary['var'], + joinpath(dictionary['dir'], 'Makefile.am'))) + current_edit += 1 + + # Detect position_early_after. + with codecs.open(configure_ac, 'rb', 'UTF-8') as file: + data = file.read() + match_result1 = \ + bool(compiler('^ *AC_PROG_CC_STDC', re.S | re.M).findall(data)) + match_result2 = \ + bool(compiler('^ *AC_PROG_CC_C99', re.S | re.M).findall(data)) + if match_result1: + position_early_after = 'AC_PROG_CC_STDC' + elif match_result2: + position_early_after = 'AC_PROG_CC_C99' + else: # if not any([match_result1, match_result2]) + position_early_after = 'AC_PROG_CC' + print(' - invoke %s_EARLY in %s, right after %s,' % \ + (macro_prefix, configure_ac, position_early_after)) + print(' - invoke %s_INIT in %s.' % \ + (macro_prefix, configure_ac)) + sp.call(['rm', '-rf', self.config['tempdir']], shell=False) + |