|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import os |
|
|
import re |
|
|
import subprocess as sp |
|
|
from .constants import ( |
|
|
DIRS, |
|
|
UTILS, |
|
|
MODES, |
|
|
TESTS, |
|
|
cleaner, |
|
|
joinpath, |
|
|
lines_to_multiline, |
|
|
movefile, |
|
|
copyfile, |
|
|
copyfile2, |
|
|
substart, |
|
|
subend, |
|
|
bold_escapes, |
|
|
relconcat, |
|
|
relativize, |
|
|
rmtree, |
|
|
) |
|
|
from .functions import rewrite_file_name |
|
|
from .GLError import GLError |
|
|
from .GLConfig import GLConfig |
|
|
from .GLModuleSystem import GLModuleTable |
|
|
from .GLModuleSystem import GLModuleSystem |
|
|
from .GLFileSystem import GLFileSystem |
|
|
from .GLFileSystem import GLFileAssistant |
|
|
from .GLMakefileTable import GLMakefileTable |
|
|
from .GLEmiter import GLEmiter |
|
|
from .GLFileTable import GLFileTable |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GLImport: |
|
|
'''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.''' |
|
|
|
|
|
mode: int |
|
|
m4dirs: list[str] |
|
|
config: GLConfig |
|
|
cache: GLConfig |
|
|
emitter: GLEmiter |
|
|
modulesystem: GLModuleSystem |
|
|
moduletable: GLModuleTable |
|
|
makefiletable: GLMakefileTable |
|
|
|
|
|
def __init__(self, config: GLConfig, mode: int, m4dirs: list[str]) -> None: |
|
|
'''Create GLImport instance. |
|
|
config - must be a GLConfig object. |
|
|
mode - must be one of the values of the constants.MODES values. |
|
|
m4dirs - list of all directories that contain relevant .m4 files.''' |
|
|
if type(config) is not GLConfig: |
|
|
raise TypeError('config must have GLConfig type, not %s' |
|
|
% repr(config)) |
|
|
if not (type(mode) is int and MODES['import'] <= mode <= MODES['update']): |
|
|
raise TypeError('mode must be 0 <= mode <= 3, not %s' |
|
|
% repr(mode)) |
|
|
if type(m4dirs) is not list: |
|
|
raise TypeError('m4dirs must be a list of strings, not %s' |
|
|
% repr(m4dirs)) |
|
|
|
|
|
self.mode = mode |
|
|
self.m4dirs = m4dirs |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.config = config.copy() |
|
|
|
|
|
|
|
|
|
|
|
self.cache = GLConfig() |
|
|
|
|
|
|
|
|
with open(self.config.getAutoconfFile(), mode='r', newline='\n', encoding='utf-8') as file: |
|
|
data = file.read() |
|
|
|
|
|
|
|
|
self.cache.setAuxDir('.') |
|
|
pattern = re.compile(r'^AC_CONFIG_AUX_DIR\([\[ ]*([^]"$`\\)]+).*?$', re.MULTILINE) |
|
|
match = pattern.search(data) |
|
|
if match: |
|
|
self.cache.setAuxDir(match.group(1)) |
|
|
if self.config['auxdir'] == '': |
|
|
self.config.setAuxDir(self.cache['auxdir']) |
|
|
|
|
|
|
|
|
|
|
|
pattern = re.compile(r'A[CM]_PROG_LIBTOOL', re.M) |
|
|
guessed_libtool = bool(pattern.findall(data)) |
|
|
|
|
|
|
|
|
pattern = re.compile(r'.*AC_PREREQ\((.*)\)', re.M) |
|
|
versions = cleaner(pattern.findall(data)) |
|
|
if versions: |
|
|
version = max({ float(version) |
|
|
for version in versions }) |
|
|
self.config.setAutoconfVersion(version) |
|
|
if version < 2.64: |
|
|
raise GLError(4, version) |
|
|
|
|
|
|
|
|
path = joinpath(self.config['m4base'], 'gnulib-cache.m4') |
|
|
if os.path.isfile(path): |
|
|
with open(path, mode='r', newline='\n', encoding='utf-8') as file: |
|
|
data = file.read() |
|
|
|
|
|
|
|
|
|
|
|
pattern = re.compile(r'^gl_LGPL$', re.M) |
|
|
if pattern.search(data): |
|
|
self.cache.setLGPL(True) |
|
|
|
|
|
if 'gl_LIBTOOL' in data: |
|
|
self.cache.setLibtool(True) |
|
|
data = data.replace('gl_LIBTOOL', '') |
|
|
if 'gl_CONDITIONAL_DEPENDENCIES' in data: |
|
|
self.cache.setCondDeps(True) |
|
|
data = data.replace('gl_CONDITIONAL_DEPENDENCIES', '') |
|
|
if 'gl_WITH_TESTS' in data: |
|
|
self.cache.enableInclTestCategory(TESTS['tests']) |
|
|
data = data.replace('gl_WITH_TESTS', '') |
|
|
if 'gl_WITH_OBSOLETE' in data: |
|
|
self.cache.setIncObsolete(True) |
|
|
data = data.replace('gl_WITH_OBSOLETE', '') |
|
|
if 'gl_WITH_CXX_TESTS' in data: |
|
|
self.cache.enableInclTestCategory(TESTS['c++-test']) |
|
|
data = data.replace('gl_WITH_CXX_TESTS', '') |
|
|
if 'gl_WITH_LONGRUNNING_TESTS' in data: |
|
|
self.cache.enableInclTestCategory(TESTS['longrunning-test']) |
|
|
data = data.replace('gl_WITH_LONGRUNNING_TESTS', '') |
|
|
if 'gl_WITH_PRIVILEGED_TESTS' in data: |
|
|
self.cache.enableInclTestCategory(TESTS['privileged-test']) |
|
|
data = data.replace('gl_WITH_PRIVILEGED_TESTS', '') |
|
|
if 'gl_WITH_UNPORTABLE_TESTS' in data: |
|
|
self.cache.enableInclTestCategory(TESTS['unportable-test']) |
|
|
data = data.replace('gl_WITH_UNPORTABLE_TESTS', '') |
|
|
if 'gl_WITH_ALL_TESTS' in data: |
|
|
self.cache.enableInclTestCategory(TESTS['all-test']) |
|
|
data = data.replace('gl_WITH_ALL_TESTS', '') |
|
|
if 'gl_AUTOMAKE_SUBDIR' in data: |
|
|
self.cache.setAutomakeSubdir(True) |
|
|
data = data.replace('gl_AUTOMAKE_SUBDIR', '') |
|
|
|
|
|
pattern = re.compile(r'^(gl_[A-Z0-9_]*)\((.*?)\)$', 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_LIB', 'gl_LGPL', 'gl_GPL', |
|
|
'gl_MAKEFILE_NAME', 'gl_TESTS_MAKEFILE_NAME', |
|
|
'gl_MACRO_PREFIX', 'gl_PO_DOMAIN', 'gl_WITNESS_C_MACRO', |
|
|
'gl_VC_FILES', |
|
|
] |
|
|
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 != '': |
|
|
self.cache.setLGPL(lgpl) |
|
|
else: |
|
|
self.cache.setLGPL(None) |
|
|
if tempdict['gl_LIB']: |
|
|
self.cache.setLibName(cleaner(tempdict['gl_LIB'])) |
|
|
if tempdict['gl_GPL']: |
|
|
self.cache.setLibName(cleaner(tempdict['gl_GPL'])) |
|
|
if 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']: |
|
|
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.setMakefileName(cleaner(tempdict['gl_MAKEFILE_NAME'])) |
|
|
if tempdict['gl_TESTS_MAKEFILE_NAME']: |
|
|
self.cache.setTestsMakefileName(cleaner(tempdict['gl_TESTS_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'])) |
|
|
if tempdict['gl_VC_FILES'] != '': |
|
|
self.cache.setVCFiles(cleaner(tempdict['gl_VC_FILES'])) |
|
|
|
|
|
|
|
|
destdir, m4base = self.config.getDestDir(), self.config.getM4Base() |
|
|
path = joinpath(destdir, m4base, 'gnulib-comp.m4') |
|
|
if os.path.isfile(path): |
|
|
with open(path, mode='r', newline='\n', encoding='utf-8') as file: |
|
|
data = file.read() |
|
|
regex = r'AC_DEFUN\(\[%s_FILE_LIST\], \[(.*?)\]\)' % self.cache['macro_prefix'] |
|
|
pattern = re.compile(regex, re.S | re.M) |
|
|
matches = pattern.findall(data) |
|
|
if matches: |
|
|
files = matches[-1].strip().split() |
|
|
else: |
|
|
files = [] |
|
|
self.cache.setFiles(files) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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']: |
|
|
self.config.setModules(sorted(self.config.getModules())) |
|
|
else: |
|
|
if self.cache['m4base'] and (self.config['m4base'] != self.cache['m4base']): |
|
|
raise GLError(5, m4base) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 not module in new ] |
|
|
elif self.mode == MODES['update']: |
|
|
modules = self.cache.getModules() |
|
|
|
|
|
|
|
|
self.config.update(self.cache) |
|
|
|
|
|
self.config.setModules(modules) |
|
|
|
|
|
|
|
|
|
|
|
for key in config.keys(): |
|
|
if key not in ['modules', 'avoids', |
|
|
'incl_test_categories', 'excl_test_categories']: |
|
|
value = config[key] |
|
|
if not config.isdefault(key, value): |
|
|
self.config.update_key(config, key) |
|
|
|
|
|
|
|
|
if self.config['automake_subdir'] or self.config['automake_subdir_tests']: |
|
|
found_subdir_objects = False |
|
|
if self.config['destdir']: |
|
|
with open(self.config['configure_ac'], mode='r', newline='\n', encoding='utf-8') as file: |
|
|
data = file.read() |
|
|
pattern = re.compile(r'^.*AM_INIT_AUTOMAKE\([\[ ]*([^])]*).*$', re.MULTILINE) |
|
|
configure_ac_automake_options = pattern.findall(data) |
|
|
if configure_ac_automake_options: |
|
|
automake_options = { x |
|
|
for y in configure_ac_automake_options |
|
|
for x in y.split() } |
|
|
found_subdir_objects = 'subdir-objects' in automake_options |
|
|
if not found_subdir_objects: |
|
|
if self.config['destdir']: |
|
|
base = self.config['destdir'] |
|
|
else: |
|
|
base = '.' |
|
|
if os.path.isfile(joinpath(base, 'Makefile.am')): |
|
|
with open(joinpath(base, 'Makefile.am'), mode='r', newline='\n', encoding='utf-8') as file: |
|
|
data = file.read() |
|
|
pattern = re.compile(r'^AUTOMAKE_OPTIONS[\t ]*=(.*)$', re.MULTILINE) |
|
|
automake_options = pattern.findall(data) |
|
|
if automake_options: |
|
|
automake_options = { x |
|
|
for y in automake_options |
|
|
for x in y.split() } |
|
|
found_subdir_objects = 'subdir-objects' in automake_options |
|
|
if not found_subdir_objects: |
|
|
raise GLError(21, None) |
|
|
|
|
|
|
|
|
self.emitter = GLEmiter(self.config) |
|
|
self.modulesystem = GLModuleSystem(self.config) |
|
|
self.moduletable = GLModuleTable(self.config, |
|
|
self.config.checkInclTestCategory(TESTS['all-tests']), |
|
|
self.config.checkInclTestCategory(TESTS['all-tests'])) |
|
|
self.makefiletable = GLMakefileTable(self.config) |
|
|
|
|
|
def __repr__(self) -> str: |
|
|
'''x.__repr__ <==> repr(x)''' |
|
|
result = '<pygnulib.GLImport %s>' % hex(id(self)) |
|
|
return result |
|
|
|
|
|
def actioncmd(self) -> str: |
|
|
'''Return command-line invocation comment.''' |
|
|
modules = self.config.getModules() |
|
|
avoids = self.config.getAvoids() |
|
|
localpath = self.config.getLocalPath() |
|
|
auxdir = self.config.getAuxDir() |
|
|
sourcebase = self.config.getSourceBase() |
|
|
m4base = self.config.getM4Base() |
|
|
docbase = self.config.getDocBase() |
|
|
pobase = self.config.getPoBase() |
|
|
testsbase = self.config.getTestsBase() |
|
|
conddeps = self.config.checkCondDeps() |
|
|
libname = self.config.getLibName() |
|
|
lgpl = self.config.getLGPL() |
|
|
gpl = self.config.getGPL() |
|
|
gnu_make = self.config.getGnuMake() |
|
|
makefile_name = self.config.getMakefileName() |
|
|
tests_makefile_name = self.config.getTestsMakefileName() |
|
|
automake_subdir = self.config.getAutomakeSubdir() |
|
|
automake_subdir_tests = self.config.getAutomakeSubdirTests() |
|
|
libtool = self.config.checkLibtool() |
|
|
macro_prefix = self.config.getMacroPrefix() |
|
|
witness_c_macro = self.config.getWitnessCMacro() |
|
|
podomain = self.config.getPoDomain() |
|
|
vc_files = self.config.checkVCFiles() |
|
|
|
|
|
|
|
|
actioncmd = '# gnulib-tool --import' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if len(localpath) > 0: |
|
|
actioncmd += ''.join([f' \\\n# --local-dir={x}' for x in localpath]) |
|
|
actioncmd += ' \\\n# --lib=%s' % libname |
|
|
actioncmd += ' \\\n# --source-base=%s' % sourcebase |
|
|
actioncmd += ' \\\n# --m4-base=%s' % m4base |
|
|
if pobase: |
|
|
actioncmd += ' \\\n# --po-base=%s' % pobase |
|
|
actioncmd += ' \\\n# --doc-base=%s' % docbase |
|
|
actioncmd += ' \\\n# --tests-base=%s' % testsbase |
|
|
actioncmd += ' \\\n# --aux-dir=%s' % auxdir |
|
|
if self.config.checkInclTestCategory(TESTS['tests']): |
|
|
actioncmd += ' \\\n# --with-tests' |
|
|
if self.config.checkIncObsolete(): |
|
|
actioncmd += ' \\\n# --with-obsolete' |
|
|
if self.config.checkInclTestCategory(TESTS['c++-test']): |
|
|
actioncmd += ' \\\n# --with-c++-tests' |
|
|
if self.config.checkInclTestCategory(TESTS['longrunning-test']): |
|
|
actioncmd += ' \\\n# --with-longrunning-tests' |
|
|
if self.config.checkInclTestCategory(TESTS['privileged-test']): |
|
|
actioncmd += ' \\\n# --with-privileged-tests' |
|
|
if self.config.checkInclTestCategory(TESTS['unportable-test']): |
|
|
actioncmd += ' \\\n# --with-unportable-tests' |
|
|
if self.config.checkInclTestCategory(TESTS['all-test']): |
|
|
actioncmd += ' \\\n# --with-all-tests' |
|
|
if lgpl: |
|
|
if lgpl == True: |
|
|
actioncmd += ' \\\n# --lgpl' |
|
|
else: |
|
|
actioncmd += ' \\\n# --lgpl=%s' % lgpl |
|
|
if gpl: |
|
|
actioncmd += ' \\\n# --gpl=%s' % gpl |
|
|
if gnu_make: |
|
|
actioncmd += ' \\\n# --gnu-make' |
|
|
if makefile_name: |
|
|
actioncmd += ' \\\n# --makefile-name=%s' % makefile_name |
|
|
if tests_makefile_name: |
|
|
actioncmd += ' \\\n# --tests-makefile-name=%s' % tests_makefile_name |
|
|
if automake_subdir: |
|
|
actioncmd += ' \\\n# --automake-subdir' |
|
|
if automake_subdir_tests: |
|
|
actioncmd += ' \\\n# --automake-subdir-tests' |
|
|
if conddeps == True: |
|
|
actioncmd += ' \\\n# --conditional-dependencies' |
|
|
else: |
|
|
actioncmd += ' \\\n# --no-conditional-dependencies' |
|
|
if libtool == True: |
|
|
actioncmd += ' \\\n# --libtool' |
|
|
else: |
|
|
actioncmd += ' \\\n# --no-libtool' |
|
|
actioncmd += ' \\\n# --macro-prefix=%s' % macro_prefix |
|
|
if podomain: |
|
|
actioncmd += ' \\\n# --po-domain=%s' % podomain |
|
|
if witness_c_macro: |
|
|
actioncmd += ' \\\n# --witness-c-macro=%s' % witness_c_macro |
|
|
if vc_files == True: |
|
|
actioncmd += ' \\\n# --vc-files' |
|
|
elif vc_files == False: |
|
|
actioncmd += ' \\\n# --no-vc-files' |
|
|
if len(avoids) > 0: |
|
|
actioncmd += ''.join([f' \\\n# --avoid={x}' for x in avoids]) |
|
|
if len(modules) > 0: |
|
|
actioncmd += ''.join([f' \\\n# {x}' for x in modules]) |
|
|
return actioncmd |
|
|
|
|
|
def relative_to_destdir(self, dir: str) -> 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 os.path.isabs(dir): |
|
|
return dir |
|
|
else: |
|
|
if os.path.isabs(destdir): |
|
|
|
|
|
return dir |
|
|
else: |
|
|
return relativize(destdir, dir) |
|
|
|
|
|
def relative_to_currdir(self, dir: str) -> 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 os.path.isabs(dir): |
|
|
return dir |
|
|
else: |
|
|
if os.path.isabs(destdir): |
|
|
|
|
|
return joinpath(destdir, dir) |
|
|
else: |
|
|
return relconcat(destdir, dir) |
|
|
|
|
|
def gnulib_cache(self) -> str: |
|
|
'''Emit the contents of generated $m4base/gnulib-cache.m4 file. |
|
|
GLConfig: destdir, localpath, tests, sourcebase, m4base, pobase, docbase, |
|
|
testsbase, conddeps, libtool, macro_prefix, podomain, vc_files.''' |
|
|
emit = '' |
|
|
actioncmd = self.actioncmd() |
|
|
localpath = self.config['localpath'] |
|
|
sourcebase = self.config['sourcebase'] |
|
|
m4base = self.config['m4base'] |
|
|
pobase = self.config['pobase'] |
|
|
docbase = self.config['docbase'] |
|
|
testsbase = self.config['testsbase'] |
|
|
lgpl = self.config['lgpl'] |
|
|
gpl = self.config['gpl'] |
|
|
libname = self.config['libname'] |
|
|
makefile_name = self.config['makefile_name'] |
|
|
tests_makefile_name = self.config['tests_makefile_name'] |
|
|
automake_subdir = self.config['automake_subdir'] |
|
|
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 = self.config['modules'] |
|
|
avoids = self.config['avoids'] |
|
|
emit += self.emitter.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 |
|
|
|
|
|
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' |
|
|
if self.config.checkIncObsolete(): |
|
|
emit += 'gl_WITH_OBSOLETE\n' |
|
|
if self.config.checkInclTestCategory(TESTS['cxx-tests']): |
|
|
emit += 'gl_WITH_CXX_TESTS\n' |
|
|
if self.config.checkInclTestCategory(TESTS['longrunning-tests']): |
|
|
emit += 'gl_WITH_LONGRUNNING_TESTS\n' |
|
|
if self.config.checkInclTestCategory(TESTS['privileged-tests']): |
|
|
emit += 'gl_WITH_PRIVILEGED_TESTS\n' |
|
|
if self.config.checkInclTestCategory(TESTS['unportable-tests']): |
|
|
emit += 'gl_WITH_UNPORTABLE_TESTS\n' |
|
|
if self.config.checkInclTestCategory(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.checkInclTestCategory(TESTS['tests']): |
|
|
emit += 'gl_WITH_TESTS\n' |
|
|
emit += 'gl_LIB([%s])\n' % libname |
|
|
if lgpl != None: |
|
|
if lgpl == True: |
|
|
emit += 'gl_LGPL\n' |
|
|
else: |
|
|
emit += 'gl_LGPL([%s])\n' % lgpl |
|
|
if gpl != None: |
|
|
emit += 'gl_GPL([%s])\n' % gpl |
|
|
emit += 'gl_MAKEFILE_NAME([%s])\n' % makefile_name |
|
|
if tests_makefile_name: |
|
|
emit += 'gl_TESTS_MAKEFILE_NAME([%s])\n' % tests_makefile_name |
|
|
if automake_subdir: |
|
|
emit += 'gl_AUTOMAKE_SUBDIR\n' |
|
|
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_MACRO([%s])\n' % witness_c_macro |
|
|
if vc_files != None: |
|
|
|
|
|
emit += 'gl_VC_FILES([%s])\n' % str(vc_files).lower() |
|
|
return emit |
|
|
|
|
|
def gnulib_comp(self, filetable: GLFileTable, gentests: bool) -> str: |
|
|
'''Emit the contents of generated $m4base/gnulib-comp.m4 file. |
|
|
GLConfig: destdir, localpath, tests, sourcebase, m4base, pobase, docbase, |
|
|
testsbase, conddeps, libtool, macro_prefix, podomain, vc_files. |
|
|
|
|
|
filetable is a GLFileTable containing file information for this |
|
|
import. |
|
|
gentests is True if a tests Makefile.am is being generated, False |
|
|
otherwise.''' |
|
|
if type(filetable) is not GLFileTable: |
|
|
raise TypeError(f'filetable should be a GLFileTable, not {type(filetable).__name__}') |
|
|
if type(gentests) is not bool: |
|
|
raise TypeError(f'gentests should be a bool, not {type(gentests).__name__}') |
|
|
emit = '' |
|
|
moduletable = self.moduletable |
|
|
auxdir = self.config['auxdir'] |
|
|
sourcebase = self.config['sourcebase'] |
|
|
m4base = self.config['m4base'] |
|
|
testsbase = self.config['testsbase'] |
|
|
libname = self.config['libname'] |
|
|
libtool = self.config['libtool'] |
|
|
macro_prefix = self.config['macro_prefix'] |
|
|
witness_c_macro = self.config['witness_c_macro'] |
|
|
configure_ac = self.config['configure_ac'] |
|
|
libtests = self.config['libtests'] |
|
|
emit += '# DO NOT EDIT! GENERATED AUTOMATICALLY!\n' |
|
|
emit += self.emitter.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\n''' % (configure_ac, macro_prefix) |
|
|
emit += self.emitter.preEarlyMacros(True, ' ', moduletable.getFinalModules()) |
|
|
for module in moduletable.getFinalModules(): |
|
|
emit += ' # Code from module %s:\n' % module.name |
|
|
snippet = module.getAutoconfEarlySnippet() |
|
|
lines = [ line |
|
|
for line in snippet.split('\n') |
|
|
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) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
newfile_set = { pair[1] |
|
|
for pair in filetable.new_files } |
|
|
if 'lib/alloca.c' in newfile_set: |
|
|
emit += ' AC_CONFIG_LIBOBJ_DIR([%s])\n' % sourcebase |
|
|
elif 'tests=lib/alloca.c' in newfile_set: |
|
|
|
|
|
emit += ' AC_CONFIG_LIBOBJ_DIR([%s])\n' % testsbase |
|
|
|
|
|
if libtool: |
|
|
emit += ' AM_CONDITIONAL([GL_COND_LIBTOOL], [true])\n' |
|
|
emit += ' gl_cond_libtool=true\n' |
|
|
else: |
|
|
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.emitter.initmacro_start(macro_prefix, False) |
|
|
emit += self.emitter.shellvars_init(False, sourcebase) |
|
|
if witness_c_macro: |
|
|
emit += ' m4_pushdef([gl_MODULE_INDICATOR_CONDITION], [%s])\n' % witness_c_macro |
|
|
|
|
|
emit += self.emitter.autoconfSnippets(moduletable.getMainModules(), moduletable.getMainModules(), |
|
|
moduletable, lambda module: True, 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.emitter.initmacro_end(macro_prefix, False) |
|
|
emit += ' gltests_libdeps=\n' |
|
|
emit += ' gltests_ltlibdeps=\n' |
|
|
emit += self.emitter.initmacro_start('%stests' % macro_prefix, gentests) |
|
|
emit += self.emitter.shellvars_init(True, testsbase) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 += self.emitter.autoconfSnippets(moduletable.getTestsModules(), |
|
|
moduletable.getMainModules() + moduletable.getTestsModules(), |
|
|
moduletable, lambda module: True, True, True, True, replace_auxdir) |
|
|
emit += ' m4_popdef([gl_MODULE_INDICATOR_CONDITION])\n' |
|
|
emit += self.emitter.initmacro_end('%stests' % macro_prefix, gentests) |
|
|
emit += ' AC_REQUIRE([gl_CC_GNULIB_WARNINGS])\n' |
|
|
|
|
|
|
|
|
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.emitter.initmacro_done(macro_prefix, sourcebase) |
|
|
emit += self.emitter.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(filetable.all_files) |
|
|
emit += '])\n' |
|
|
return emit |
|
|
|
|
|
def _done_dir_(self, directory: str, files_added: list[str], files_removed: list[str]) -> None: |
|
|
'''This method is used to determine ignore argument for _update_ignorelist_ |
|
|
method and then call it.''' |
|
|
destdir = self.config['destdir'] |
|
|
if (os.path.isdir(joinpath(destdir, 'CVS')) |
|
|
or os.path.isdir(joinpath(destdir, directory, 'CVS')) |
|
|
or os.path.isfile(joinpath(destdir, directory, '.cvsignore'))): |
|
|
self._update_ignorelist_(directory, '.cvsignore', |
|
|
files_added, files_removed) |
|
|
if (os.path.isdir(joinpath(destdir, '.git')) |
|
|
or os.path.isfile(joinpath(destdir, '.gitignore')) |
|
|
or os.path.isfile(joinpath(destdir, directory, '.gitignore'))): |
|
|
self._update_ignorelist_(directory, '.gitignore', |
|
|
files_added, files_removed) |
|
|
|
|
|
def _update_ignorelist_(self, directory: str, ignore: str, files_added: list[str], |
|
|
files_removed: list[str]) -> None: |
|
|
'''Update .gitignore or .cvsignore files.''' |
|
|
destdir = self.config['destdir'] |
|
|
if ignore == '.gitignore': |
|
|
|
|
|
|
|
|
anchor = '/' |
|
|
else: |
|
|
anchor = '' |
|
|
srcpath = joinpath(directory, ignore) |
|
|
backupname = '%s~' % srcpath |
|
|
if os.path.isfile(joinpath(destdir, srcpath)): |
|
|
if files_added or files_removed: |
|
|
with open(joinpath(destdir, srcpath), mode='r', newline='\n', encoding='utf-8') as file: |
|
|
original_lines = file.readlines() |
|
|
|
|
|
original_lines = [ line.rstrip('\n') |
|
|
for line in original_lines ] |
|
|
already_listed_filenames = { substart(anchor, '', filename) |
|
|
for filename in original_lines |
|
|
if filename.strip() } |
|
|
filenames_to_add = set(files_added).difference(already_listed_filenames) |
|
|
filenames_to_remove = set(files_removed) |
|
|
if filenames_to_add or filenames_to_remove: |
|
|
if not self.config['dryrun']: |
|
|
print('Updating %s (backup in %s)' % (srcpath, backupname)) |
|
|
copyfile2(joinpath(destdir, srcpath), joinpath(destdir, backupname)) |
|
|
new_lines = original_lines + [ f'{anchor}{filename}' |
|
|
for filename in sorted(filenames_to_add) ] |
|
|
if anchor != '': |
|
|
lines_to_remove = filenames_to_remove.union({ f'{anchor}{filename}' |
|
|
for filename in filenames_to_remove }) |
|
|
else: |
|
|
lines_to_remove = filenames_to_remove |
|
|
new_lines = [ line |
|
|
for line in new_lines |
|
|
if line not in lines_to_remove ] |
|
|
with open(joinpath(destdir, srcpath), mode='w', newline='\n', encoding='utf-8') as file: |
|
|
file.write(lines_to_multiline(new_lines)) |
|
|
else: |
|
|
print('Update %s (backup in %s)' % (srcpath, backupname)) |
|
|
else: |
|
|
if files_added: |
|
|
if not self.config['dryrun']: |
|
|
print('Creating %s' % srcpath) |
|
|
files_added = sorted(set(files_added)) |
|
|
files_added = [ '%s%s' % (anchor, f) |
|
|
for f in files_added ] |
|
|
if ignore == '.cvsignore': |
|
|
|
|
|
files_added = ['.deps', '.dirstamp'] + files_added |
|
|
with open(joinpath(destdir, srcpath), mode='w', newline='\n', encoding='utf-8') as file: |
|
|
file.write(lines_to_multiline(files_added)) |
|
|
else: |
|
|
print('Create %s' % srcpath) |
|
|
|
|
|
def prepare(self) -> tuple[GLFileTable, dict[str, tuple[re.Pattern, str] | None]]: |
|
|
'''Perform preperations before GLImport.execute(). |
|
|
Returns a filetable and the transformers passed to GLFileAssistant().''' |
|
|
destdir = self.config['destdir'] |
|
|
modules = list(self.config['modules']) |
|
|
m4base = self.config['m4base'] |
|
|
lgpl = self.config['lgpl'] |
|
|
gpl = self.config['gpl'] |
|
|
verbose = self.config['verbosity'] |
|
|
base_modules = set() |
|
|
for name in modules: |
|
|
module = self.modulesystem.find(name) |
|
|
if module is not None: |
|
|
base_modules.add(module) |
|
|
base_modules = sorted(base_modules) |
|
|
|
|
|
|
|
|
final_modules = self.moduletable.transitive_closure(base_modules) |
|
|
|
|
|
|
|
|
if verbose >= 0: |
|
|
(bold_on, bold_off) = bold_escapes() |
|
|
print('Module list with included dependencies (indented):') |
|
|
for module in final_modules: |
|
|
if module.name in self.config.getModules(): |
|
|
print(' %s%s%s' % (bold_on, module.name, bold_off)) |
|
|
else: |
|
|
print(' %s' % module.name) |
|
|
|
|
|
|
|
|
modules = \ |
|
|
self.moduletable.transitive_closure_separately(base_modules, final_modules) |
|
|
main_modules, tests_modules = modules |
|
|
|
|
|
|
|
|
if verbose >= 1: |
|
|
print('Main module list:') |
|
|
for module in main_modules: |
|
|
print(' %s' % module.name) |
|
|
print('Tests-related module list:') |
|
|
for module in tests_modules: |
|
|
print(' %s' % module.name) |
|
|
|
|
|
|
|
|
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.setLibtests(True) |
|
|
|
|
|
|
|
|
main_modules = self.moduletable.add_dummy(main_modules) |
|
|
if libtests: |
|
|
|
|
|
tests_modules = self.moduletable.add_dummy(tests_modules) |
|
|
|
|
|
|
|
|
self.moduletable.setBaseModules(base_modules) |
|
|
self.moduletable.setFinalModules(final_modules) |
|
|
self.moduletable.setMainModules(main_modules) |
|
|
self.moduletable.setTestsModules(tests_modules) |
|
|
|
|
|
|
|
|
listing = [] |
|
|
compatibilities = dict() |
|
|
compatibilities['all'] = ['GPLv2+ build tool', 'GPLed build tool', |
|
|
'public domain', 'unlimited', |
|
|
'unmodifiable license text'] |
|
|
compatibilities['GPLv3'] = ['LGPLv2+', 'LGPLv3+ or GPLv2+', 'LGPLv3+', 'LGPL', 'GPLv2+', 'GPLv3+', 'GPL'] |
|
|
compatibilities['GPLv2'] = ['LGPLv2+', 'LGPLv3+ or GPLv2+', 'GPLv2+'] |
|
|
compatibilities['LGPLv3'] = ['LGPLv2+', 'LGPLv3+ or GPLv2+', 'LGPLv3+', 'LGPL'] |
|
|
compatibilities['LGPLv3orGPLv2'] = ['LGPLv2+', 'LGPLv3+ or GPLv2+'] |
|
|
compatibilities['LGPLv2'] = ['LGPLv2+'] |
|
|
if lgpl or gpl: |
|
|
for module in main_modules: |
|
|
license = module.getLicense() |
|
|
if license not in compatibilities['all']: |
|
|
if lgpl == True: |
|
|
if license not in compatibilities['LGPLv3']: |
|
|
listing.append(tuple([module.name, license])) |
|
|
elif lgpl: |
|
|
if license not in compatibilities['LGPLv'+lgpl]: |
|
|
listing.append(tuple([module.name, license])) |
|
|
elif gpl: |
|
|
if license not in compatibilities['GPLv'+gpl]: |
|
|
listing.append(tuple([module.name, license])) |
|
|
if listing: |
|
|
raise GLError(11, listing) |
|
|
|
|
|
|
|
|
if verbose >= -1: |
|
|
for module in main_modules: |
|
|
notice = module.getNotice().strip('\n') |
|
|
if notice: |
|
|
print('Notice from module %s:' % module.name) |
|
|
pattern = re.compile(r'^(.*?)$', re.S | re.M) |
|
|
notice = pattern.sub(r' \1', notice) |
|
|
print(notice) |
|
|
|
|
|
|
|
|
sed_transform_lib_file = None |
|
|
if 'config-h' in [ module.name |
|
|
for module in main_modules ]: |
|
|
sed_transform_lib_file = (re.compile(r'^#ifdef[\t ]*HAVE_CONFIG_H[\t ]*$', re.MULTILINE), r'#if 1') |
|
|
|
|
|
sed_transform_main_lib_file = sed_transform_lib_file |
|
|
|
|
|
|
|
|
sed_transform_build_aux_file = None |
|
|
|
|
|
|
|
|
sed_transform_testsrelated_lib_file = sed_transform_lib_file |
|
|
|
|
|
|
|
|
main_filelist, tests_filelist = \ |
|
|
self.moduletable.filelist_separately(main_modules, tests_modules) |
|
|
filelist = sorted(set(main_filelist + tests_filelist)) |
|
|
if not filelist: |
|
|
raise GLError(12, None) |
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
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 os.path.isfile(path): |
|
|
old_files.append(joinpath('m4', 'gnulib-tool.m4')) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
transformers = dict() |
|
|
transformers['lib'] = sed_transform_lib_file |
|
|
transformers['aux'] = sed_transform_build_aux_file |
|
|
transformers['main'] = sed_transform_main_lib_file |
|
|
transformers['tests'] = sed_transform_testsrelated_lib_file |
|
|
|
|
|
|
|
|
|
|
|
old_table = { (rewrite_file_name(file_name, self.cache, True), file_name) |
|
|
for file_name in old_files } |
|
|
|
|
|
|
|
|
|
|
|
new_table = { (rewrite_file_name(file_name, self.config, True), file_name) |
|
|
for file_name in new_files } |
|
|
|
|
|
|
|
|
filetable = GLFileTable(sorted(set(filelist))) |
|
|
filetable.old_files = sorted(old_table, key=lambda pair: pair[0]) |
|
|
filetable.new_files = sorted(new_table, key=lambda pair: pair[0]) |
|
|
|
|
|
|
|
|
result = tuple([filetable, transformers]) |
|
|
return result |
|
|
|
|
|
def execute(self, filetable: GLFileTable, transformers: dict[str, tuple[re.Pattern, str] | None]) -> None: |
|
|
'''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 GLFileTable: |
|
|
raise TypeError('filetable must be a GLFileTable, not %s' |
|
|
% type(filetable).__name__) |
|
|
destdir = self.config['destdir'] |
|
|
auxdir = self.config['auxdir'] |
|
|
sourcebase = self.config['sourcebase'] |
|
|
m4base = self.config['m4base'] |
|
|
pobase = self.config['pobase'] |
|
|
docbase = self.config['docbase'] |
|
|
testsbase = self.config['testsbase'] |
|
|
libname = self.config['libname'] |
|
|
makefile_name = self.config['makefile_name'] |
|
|
tests_makefile_name = self.config['tests_makefile_name'] |
|
|
automake_subdir = self.config['automake_subdir'] |
|
|
macro_prefix = self.config['macro_prefix'] |
|
|
vc_files = self.config['vc_files'] |
|
|
configure_ac = self.config['configure_ac'] |
|
|
actioncmd = self.actioncmd() |
|
|
|
|
|
|
|
|
testsfiles = [ file |
|
|
for file in filetable.all_files |
|
|
if file.startswith('tests/') or file.startswith('tests=lib/') ] |
|
|
gentests = len(testsfiles) > 0 |
|
|
|
|
|
|
|
|
dirs = [sourcebase, m4base] |
|
|
if pobase: |
|
|
dirs.append(pobase) |
|
|
if [ file |
|
|
for file in filetable.all_files |
|
|
if file.startswith('doc/') ]: |
|
|
dirs.append(docbase) |
|
|
if gentests: |
|
|
dirs.append(testsbase) |
|
|
dirs.append(auxdir) |
|
|
dirs += sorted([ os.path.dirname(pair[0]) |
|
|
for pair in filetable.new_files ]) |
|
|
dirs = [ os.path.join(destdir, d) |
|
|
for d in dirs ] |
|
|
for directory in dirs: |
|
|
if not os.path.isdir(directory): |
|
|
print('Creating directory %s' % directory) |
|
|
if not self.config['dryrun']: |
|
|
try: |
|
|
os.makedirs(directory) |
|
|
except Exception as exc: |
|
|
raise GLError(13, directory) from exc |
|
|
else: |
|
|
print('Create directory %s' % directory) |
|
|
|
|
|
|
|
|
assistant = GLFileAssistant(self.config, transformers) |
|
|
|
|
|
|
|
|
old_rewritten_files = { pair[0] |
|
|
for pair in filetable.old_files } |
|
|
|
|
|
new_rewritten_files = { pair[0] |
|
|
for pair in filetable.new_files } |
|
|
|
|
|
|
|
|
|
|
|
pairs = [ pair |
|
|
for pair in filetable.old_files |
|
|
if pair[0] not in new_rewritten_files ] |
|
|
pairs = sorted(set(pairs), key=lambda pair: pair[0]) |
|
|
files = sorted(set(pair[0] for pair in pairs)) |
|
|
for file in files: |
|
|
path = joinpath(destdir, file) |
|
|
if os.path.isfile(path) or os.path.islink(path): |
|
|
if not self.config['dryrun']: |
|
|
backup = '%s~' % path |
|
|
print('Removing file %s (backup in %s)' % (path, backup)) |
|
|
try: |
|
|
if os.path.exists(backup): |
|
|
os.remove(backup) |
|
|
movefile(path, '%s~' % path) |
|
|
except Exception as exc: |
|
|
raise GLError(14, file) from exc |
|
|
else: |
|
|
print('Remove file %s (backup in %s~)' % (path, path)) |
|
|
filetable.removed_files.append(file) |
|
|
|
|
|
|
|
|
|
|
|
already_present = False |
|
|
pairs = [ pair |
|
|
for pair in filetable.new_files |
|
|
if pair[0] not in old_rewritten_files ] |
|
|
pairs = sorted(set(pairs)) |
|
|
for pair in pairs: |
|
|
original = pair[1] |
|
|
rewritten = pair[0] |
|
|
assistant.setOriginal(original) |
|
|
assistant.setRewritten(rewritten) |
|
|
assistant.add_or_update(already_present) |
|
|
|
|
|
|
|
|
|
|
|
already_present = True |
|
|
pairs = [ pair |
|
|
for pair in filetable.new_files |
|
|
if pair[0] in old_rewritten_files ] |
|
|
pairs = sorted(set(pairs)) |
|
|
for pair in pairs: |
|
|
original = pair[1] |
|
|
rewritten = pair[0] |
|
|
assistant.setOriginal(original) |
|
|
assistant.setRewritten(rewritten) |
|
|
assistant.add_or_update(already_present) |
|
|
|
|
|
|
|
|
filetable.added_files += assistant.getFiles() |
|
|
filetable.added_files = sorted(set(filetable.added_files)) |
|
|
|
|
|
|
|
|
if makefile_name: |
|
|
source_makefile_am = makefile_name |
|
|
else: |
|
|
source_makefile_am = 'Makefile.am' |
|
|
|
|
|
if tests_makefile_name: |
|
|
tests_makefile_am = tests_makefile_name |
|
|
else: |
|
|
tests_makefile_am = source_makefile_am |
|
|
|
|
|
|
|
|
for_test = False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if source_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.checkInclTestCategory(TESTS['tests']): |
|
|
if tests_makefile_am == 'Makefile.am': |
|
|
testsbase_dir = os.path.dirname(testsbase) |
|
|
testsbase_base = os.path.basename(testsbase) |
|
|
self.makefiletable.editor(testsbase_dir, 'SUBDIRS', testsbase_base, True) |
|
|
self.makefiletable.editor('', 'ACLOCAL_AMFLAGS', m4base) |
|
|
self.makefiletable.parent(gentests, source_makefile_am, tests_makefile_am) |
|
|
|
|
|
|
|
|
filesystem = GLFileSystem(self.config) |
|
|
if pobase: |
|
|
|
|
|
for file in ['Makefile.in.in', 'remove-potcdate.sin', 'remove-potcdate.sed']: |
|
|
tmpfile = assistant.tmpfilename(joinpath(pobase, file)) |
|
|
path = joinpath('build-aux', 'po', file) |
|
|
if os.path.exists(joinpath(DIRS['root'], path)): |
|
|
lookedup, flag = filesystem.lookup(path) |
|
|
copyfile(lookedup, tmpfile) |
|
|
basename = joinpath(pobase, file) |
|
|
filename, backup, flag = assistant.super_update(basename, tmpfile) |
|
|
if flag == 1: |
|
|
if not self.config['dryrun']: |
|
|
print('Updating %s (backup in %s)' % (filename, backup)) |
|
|
else: |
|
|
print('Update %s (backup in %s)' % (filename, backup)) |
|
|
elif flag == 2: |
|
|
if not self.config['dryrun']: |
|
|
print('Creating %s' % filename) |
|
|
else: |
|
|
print('Create %s' % filename) |
|
|
filetable.added_files.append(filename) |
|
|
if os.path.isfile(tmpfile): |
|
|
os.remove(tmpfile) |
|
|
|
|
|
|
|
|
basename = joinpath(pobase, 'Makevars') |
|
|
tmpfile = assistant.tmpfilename(basename) |
|
|
emit = self.emitter.po_Makevars() |
|
|
with open(tmpfile, mode='w', newline='\n', encoding='utf-8') as file: |
|
|
file.write(emit) |
|
|
filename, backup, flag = assistant.super_update(basename, tmpfile) |
|
|
if flag == 1: |
|
|
if not self.config['dryrun']: |
|
|
print('Updating %s (backup in %s)' % (filename, backup)) |
|
|
else: |
|
|
print('Update %s (backup in %s)' % (filename, backup)) |
|
|
elif flag == 2: |
|
|
if not self.config['dryrun']: |
|
|
print('Creating %s' % filename) |
|
|
else: |
|
|
print('Create %s' % filename) |
|
|
filetable.added_files.append(filename) |
|
|
if os.path.isfile(tmpfile): |
|
|
os.remove(tmpfile) |
|
|
|
|
|
|
|
|
basename = joinpath(pobase, 'POTFILES.in') |
|
|
tmpfile = assistant.tmpfilename(basename) |
|
|
with open(tmpfile, mode='w', newline='\n', encoding='utf-8') as file: |
|
|
file.write(self.emitter.po_POTFILES_in(filetable.all_files)) |
|
|
basename = joinpath(pobase, 'POTFILES.in') |
|
|
filename, backup, flag = assistant.super_update(basename, tmpfile) |
|
|
if flag == 1: |
|
|
if not self.config['dryrun']: |
|
|
print('Updating %s (backup in %s)' % (filename, backup)) |
|
|
else: |
|
|
print('Update %s (backup in %s)' % (filename, backup)) |
|
|
elif flag == 2: |
|
|
if not self.config['dryrun']: |
|
|
print('Creating %s' % filename) |
|
|
else: |
|
|
print('Create %s' % filename) |
|
|
filetable.added_files.append(filename) |
|
|
if os.path.isfile(tmpfile): |
|
|
os.remove(tmpfile) |
|
|
|
|
|
|
|
|
TP_URL = 'https://translationproject.org/latest/' |
|
|
if not self.config['dryrun']: |
|
|
print('Fetching gnulib PO files from %s' % TP_URL) |
|
|
args = ['wget', '--no-verbose', '--mirror', '--level=1', '-nd', '-A.po', '-P', '.', |
|
|
'%sgnulib/' % TP_URL] |
|
|
sp.call(args, cwd=joinpath(destdir, pobase)) |
|
|
else: |
|
|
print('Fetch gnulib PO files from %s' % TP_URL) |
|
|
|
|
|
|
|
|
basename = joinpath(pobase, 'LINGUAS') |
|
|
if not self.config['dryrun']: |
|
|
tmpfile = assistant.tmpfilename(basename) |
|
|
data = '# Set of available languages.\n' |
|
|
files = sorted([ subend('.po', '', file) |
|
|
for file in os.listdir(joinpath(destdir, pobase)) |
|
|
if file.endswith('.po') ]) |
|
|
data += lines_to_multiline(files) |
|
|
with open(tmpfile, mode='w', newline='\n', encoding='utf-8') as file: |
|
|
file.write(data) |
|
|
filename, backup, flag = 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_files.append(filename) |
|
|
if os.path.isfile(tmpfile): |
|
|
os.remove(tmpfile) |
|
|
else: |
|
|
backupname = '%s~' % basename |
|
|
if os.path.isfile(joinpath(destdir, basename)): |
|
|
print('Update %s (backup in %s)' % (basename, backupname)) |
|
|
else: |
|
|
print('Create %s' % basename) |
|
|
|
|
|
|
|
|
basename = joinpath(m4base, 'gnulib-cache.m4') |
|
|
tmpfile = assistant.tmpfilename(basename) |
|
|
emit = self.gnulib_cache() |
|
|
with open(tmpfile, mode='w', newline='\n', encoding='utf-8') as file: |
|
|
file.write(emit) |
|
|
filename, backup, flag = assistant.super_update(basename, tmpfile) |
|
|
if flag == 1: |
|
|
if not self.config['dryrun']: |
|
|
print('Updating %s (backup in %s)' % (filename, backup)) |
|
|
else: |
|
|
print('Update %s (backup in %s)' % (filename, backup)) |
|
|
elif flag == 2: |
|
|
if not self.config['dryrun']: |
|
|
print('Creating %s' % filename) |
|
|
else: |
|
|
print('Create %s' % filename) |
|
|
if emit[-2:] == '\r\n': |
|
|
emit = emit[:-2] |
|
|
elif emit[-1:] == '\n': |
|
|
emit = emit[:-1] |
|
|
print(emit) |
|
|
if os.path.isfile(tmpfile): |
|
|
os.remove(tmpfile) |
|
|
|
|
|
|
|
|
basename = joinpath(m4base, 'gnulib-comp.m4') |
|
|
tmpfile = assistant.tmpfilename(basename) |
|
|
emit = self.gnulib_comp(filetable, gentests) |
|
|
with open(tmpfile, mode='w', newline='\n', encoding='utf-8') as file: |
|
|
file.write(emit) |
|
|
filename, backup, flag = assistant.super_update(basename, tmpfile) |
|
|
if flag == 1: |
|
|
if not self.config['dryrun']: |
|
|
print('Updating %s (backup in %s)' % (filename, backup)) |
|
|
else: |
|
|
print('Update %s (backup in %s)' % (filename, backup)) |
|
|
elif flag == 2: |
|
|
if not self.config['dryrun']: |
|
|
print('Creating %s' % filename) |
|
|
else: |
|
|
print('Create %s' % filename) |
|
|
if emit[-2:] == '\r\n': |
|
|
emit = emit[:-2] |
|
|
elif emit[-1:] == '\n': |
|
|
emit = emit[:-1] |
|
|
print(emit) |
|
|
if os.path.isfile(tmpfile): |
|
|
os.remove(tmpfile) |
|
|
|
|
|
if self.config['gnu_make']: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
aclocal_args = [] |
|
|
for dir in self.m4dirs: |
|
|
aclocal_args.append('-I') |
|
|
aclocal_args.append(dir) |
|
|
sp.run([UTILS['aclocal']] + aclocal_args, cwd=destdir) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
basename = joinpath(sourcebase, source_makefile_am) |
|
|
tmpfile = assistant.tmpfilename(basename) |
|
|
emit = self.emitter.lib_Makefile_am(basename, self.moduletable.getMainModules(), |
|
|
self.moduletable, self.makefiletable, |
|
|
actioncmd, for_test) |
|
|
if automake_subdir: |
|
|
emit = sp.run([joinpath(DIRS['root'], 'build-aux/prefix-gnulib-mk'), '--from-gnulib-tool', |
|
|
f'--lib-name={libname}', f'--prefix={sourcebase}/'], |
|
|
input=emit, text=True, capture_output=True).stdout |
|
|
with open(tmpfile, mode='w', newline='\n', encoding='utf-8') as file: |
|
|
file.write(emit) |
|
|
filename, backup, flag = assistant.super_update(basename, tmpfile) |
|
|
if flag == 1: |
|
|
if not self.config['dryrun']: |
|
|
print('Updating %s (backup in %s)' % (filename, backup)) |
|
|
else: |
|
|
print('Update %s (backup in %s)' % (filename, backup)) |
|
|
elif flag == 2: |
|
|
if not self.config['dryrun']: |
|
|
print('Creating %s' % filename) |
|
|
else: |
|
|
print('Create %s' % filename) |
|
|
filetable.added_files.append(filename) |
|
|
if os.path.isfile(tmpfile): |
|
|
os.remove(tmpfile) |
|
|
|
|
|
|
|
|
if gentests: |
|
|
basename = joinpath(testsbase, tests_makefile_am) |
|
|
tmpfile = assistant.tmpfilename(basename) |
|
|
emit = self.emitter.tests_Makefile_am(basename, self.moduletable.getTestsModules(), |
|
|
self.moduletable, self.makefiletable, |
|
|
'%stests_WITNESS' % macro_prefix, for_test) |
|
|
with open(tmpfile, mode='w', newline='\n', encoding='utf-8') as file: |
|
|
file.write(emit) |
|
|
filename, backup, flag = assistant.super_update(basename, tmpfile) |
|
|
if flag == 1: |
|
|
if not self.config['dryrun']: |
|
|
print('Updating %s (backup in %s)' % (filename, backup)) |
|
|
else: |
|
|
print('Update %s (backup in %s)' % (filename, backup)) |
|
|
elif flag == 2: |
|
|
if not self.config['dryrun']: |
|
|
print('Creating %s' % filename) |
|
|
else: |
|
|
print('Create %s' % filename) |
|
|
filetable.added_files.append(filename) |
|
|
if os.path.isfile(tmpfile): |
|
|
os.remove(tmpfile) |
|
|
|
|
|
if vc_files != False: |
|
|
|
|
|
ignorelist = [] |
|
|
|
|
|
filetable.added_files.append(joinpath(m4base, 'gnulib-comp.m4')) |
|
|
filetable.added_files = sorted(set(filetable.added_files)) |
|
|
filetable.removed_files = sorted(set(filetable.removed_files)) |
|
|
for file in filetable.added_files: |
|
|
directory, basename = os.path.split(file) |
|
|
ignorelist.append(tuple([directory, '|A|', basename])) |
|
|
for file in filetable.removed_files: |
|
|
directory, basename = os.path.split(file) |
|
|
ignorelist.append(tuple([directory, '|R|', basename])) |
|
|
|
|
|
ignorelist = sorted(ignorelist, key=lambda row: row[0]) |
|
|
last_dir = '' |
|
|
last_dir_files_added = [] |
|
|
last_dir_files_removed = [] |
|
|
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_dir_files_added, last_dir_files_removed) |
|
|
last_dir = next_dir |
|
|
last_dir_files_added = [] |
|
|
last_dir_files_removed = [] |
|
|
if operand == '|A|': |
|
|
last_dir_files_added.append(filename) |
|
|
elif operand == '|R|': |
|
|
last_dir_files_removed.append(filename) |
|
|
self._done_dir_(last_dir, last_dir_files_added, last_dir_files_removed) |
|
|
|
|
|
|
|
|
print('Finished.\n') |
|
|
print('You may need to add #include directives for the following .h files.') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
modules = sorted(set(self.moduletable.getBaseModules()).intersection(self.moduletable.getMainModules())) |
|
|
|
|
|
|
|
|
|
|
|
include_angles = [] |
|
|
include_quotes = [] |
|
|
include_if = [] |
|
|
for module in modules: |
|
|
include = module.getInclude() |
|
|
if '\n#if' in '\n'+include: |
|
|
include_if += [ f' {line}' |
|
|
for line in include.split('\n') |
|
|
if line.strip() ] |
|
|
else: |
|
|
include_angles += [ f' {line}' |
|
|
for line in include.split('\n') |
|
|
if 'include "' not in line and line.strip() ] |
|
|
include_quotes += [ f' {line}' |
|
|
for line in include.split('\n') |
|
|
if 'include "' in line and line.strip() ] |
|
|
|
|
|
includes = lines_to_multiline(sorted(set(include_angles))) |
|
|
includes += lines_to_multiline(sorted(set(include_quotes))) |
|
|
includes += lines_to_multiline(include_if) |
|
|
print(includes, end='') |
|
|
|
|
|
|
|
|
links = [ module.getLink() |
|
|
for module in self.moduletable.getMainModules() ] |
|
|
lines = [ line |
|
|
for link in links |
|
|
for line in link.split('\n') |
|
|
if line != '' ] |
|
|
lines = sorted(set(lines)) |
|
|
if lines: |
|
|
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 line in lines: |
|
|
print(' %s' % line) |
|
|
|
|
|
|
|
|
print('') |
|
|
print('Don\'t forget to') |
|
|
if source_makefile_am == 'Makefile.am': |
|
|
print(' - add "%s/Makefile" to AC_CONFIG_FILES in %s,' % (sourcebase, configure_ac)) |
|
|
else: |
|
|
print(' - "include %s" from within "%s/Makefile.am",' % (source_makefile_am, sourcebase)) |
|
|
if pobase: |
|
|
print(' - add "%s/Makefile.in" to AC_CONFIG_FILES in %s,' % (pobase, configure_ac)) |
|
|
if gentests: |
|
|
if tests_makefile_am == 'Makefile.am': |
|
|
print(' - add "%s/Makefile" to AC_CONFIG_FILES in %s,' % (testsbase, configure_ac)) |
|
|
else: |
|
|
print(' - "include %s" from within "%s/Makefile.am",' % (tests_makefile_am, testsbase)) |
|
|
|
|
|
for current_edit in range(0, self.makefiletable.count()): |
|
|
dictionary = self.makefiletable[current_edit] |
|
|
if 'var' in dictionary: |
|
|
if dictionary['var'] == 'ACLOCAL_AMFLAGS': |
|
|
print(' - mention "-I %s" in %s in %s' |
|
|
% (dictionary['val'], dictionary['var'], joinpath(dictionary['dir'], 'Makefile.am'))) |
|
|
print(' or add an AC_CONFIG_MACRO_DIRS([%s]) invocation in %s,' |
|
|
% (dictionary['val'], configure_ac)) |
|
|
else: |
|
|
print(' - mention "%s" in %s in %s,' |
|
|
% (dictionary['val'], dictionary['var'], joinpath(dictionary['dir'], 'Makefile.am'))) |
|
|
|
|
|
|
|
|
with open(configure_ac, mode='r', newline='\n', encoding='utf-8') as file: |
|
|
data = file.read() |
|
|
match_result1 = re.compile(r'^ *AC_PROG_CC_STDC', re.MULTILINE).search(data) |
|
|
match_result2 = re.compile(r'^ *AC_PROG_CC_C99', re.MULTILINE).search(data) |
|
|
if match_result1: |
|
|
print(' - replace AC_PROG_CC_STDC with AC_PROG_CC in %s,' % (configure_ac)) |
|
|
position_early_after = 'AC_PROG_CC_STDC' |
|
|
elif match_result2: |
|
|
print(' - replace AC_PROG_CC_C99 with AC_PROG_CC in %s,' % (configure_ac)) |
|
|
position_early_after = 'AC_PROG_CC_C99' |
|
|
else: |
|
|
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)) |
|
|
|