1#!/usr/bin/python 2# encoding: UTF-8 3 4#=============================================================================== 5# Define global imports 6#=============================================================================== 7import os 8import re 9import sys 10import locale 11import codecs 12import shutil 13import filecmp 14import subprocess as sp 15from . import constants 16from .GLError import GLError 17from .GLConfig import GLConfig 18from .GLModuleSystem import GLModule 19from .GLModuleSystem import GLModuleTable 20from .GLModuleSystem import GLModuleSystem 21from .GLFileSystem import GLFileSystem 22from .GLFileSystem import GLFileAssistant 23from .GLMakefileTable import GLMakefileTable 24from .GLEmiter import GLEmiter 25 26 27#=============================================================================== 28# Define module information 29#=============================================================================== 30__author__ = constants.__author__ 31__license__ = constants.__license__ 32__copyright__ = constants.__copyright__ 33 34 35#=============================================================================== 36# Define global constants 37#=============================================================================== 38PYTHON3 = constants.PYTHON3 39NoneType = type(None) 40APP = constants.APP 41DIRS = constants.DIRS 42ENCS = constants.ENCS 43UTILS = constants.UTILS 44MODES = constants.MODES 45TESTS = constants.TESTS 46compiler = constants.compiler 47joinpath = constants.joinpath 48cleaner = constants.cleaner 49relpath = constants.relativize 50string = constants.string 51isabs = os.path.isabs 52isdir = os.path.isdir 53isfile = os.path.isfile 54normpath = os.path.normpath 55 56 57#=============================================================================== 58# Define GLImport class 59#=============================================================================== 60class GLImport(object): 61 '''GLImport class is used to provide methods for --import, --add-import, 62 --remove-import and --update actions. This is a high-level class, so 63 developers may have to use lower-level classes to create their own 64 scripts. However, if user needs just to use power of gnulib-tool, this class 65 is a very good choice.''' 66 67 def __init__(self, config, mode): 68 '''Create GLImport instance. 69 The first variable, mode, must be one of the values of the MODES dict 70 object, which is accessible from constants module. The second one, config, 71 must be a GLConfig object.''' 72 if type(config) is not GLConfig: 73 raise(TypeError('config must have GLConfig type, not %s' % 74 repr(config))) 75 if type(mode) is int and \ 76 MODES['import'] <= mode <= MODES['update']: 77 self.mode = mode 78 else: # if mode is not int or is not 0-3 79 raise(TypeError('mode must be 0 <= mode <= 3, not %s' % 80 repr(mode))) 81 82 # Initialize some values. 83 self.cache = GLConfig() 84 self.config = config.copy() 85 os.rmdir(self.cache['tempdir']) 86 87 # Get cached auxdir and libtool from configure.ac/in. 88 self.cache.setAuxDir('.') 89 path = joinpath(self.config['destdir'], 'configure.ac') 90 if not isfile(path): 91 path = joinpath(self.config['destdir'], 'configure.in') 92 if not isfile(path): 93 raise(GLError(3, path)) 94 self.config.setAutoconfFile(path) 95 with codecs.open(path, 'rb', 'UTF-8') as file: 96 data = file.read() 97 pattern = compiler(r'^AC_CONFIG_AUX_DIR\((.*?)\)$', re.S | re.M) 98 match = pattern.findall(data) 99 if match: 100 result = cleaner(match)[0] 101 self.cache.setAuxDir(joinpath(result, self.config['destdir'])) 102 pattern = compiler(r'A[CM]_PROG_LIBTOOL', re.S | re.M) 103 guessed_libtool = bool(pattern.findall(data)) 104 if self.config['auxdir'] == None: 105 self.config.setAuxDir(self.cache['auxdir']) 106 107 # Guess autoconf version. 108 pattern = compiler('.*AC_PREREQ\((.*?)\)', re.S | re.M) 109 versions = cleaner(pattern.findall(data)) 110 if versions: 111 version = sorted(set([float(version) for version in versions]))[-1] 112 self.config.setAutoconfVersion(version) 113 if version < 2.59: 114 raise(GLError(4, version)) 115 116 # Get other cached variables. 117 path = joinpath(self.config['m4base'], 'gnulib-cache.m4') 118 if isfile(joinpath(self.config['m4base'], 'gnulib-cache.m4')): 119 with codecs.open(path, 'rb', 'UTF-8') as file: 120 data = file.read() 121 122 # Create regex object and keys. 123 pattern = compiler('^(gl_.*?)\\((.*?)\\)$', re.S | re.M) 124 keys = \ 125 [ 126 'gl_LOCAL_DIR', 'gl_MODULES', 'gl_AVOID', 'gl_SOURCE_BASE', 127 'gl_M4_BASE', 'gl_PO_BASE', 'gl_DOC_BASE', 'gl_TESTS_BASE', 128 'gl_MAKEFILE_NAME', 'gl_MACRO_PREFIX', 'gl_PO_DOMAIN', 129 'gl_WITNESS_C_MACRO', 'gl_VC_FILES', 'gl_LIB', 130 ] 131 132 # Find bool values. 133 if 'gl_LGPL(' in data: 134 keys.append('gl_LGPL') 135 self.cache.setLGPL(True) 136 if 'gl_LIBTOOL' in data: 137 self.cache.enableLibtool() 138 data = data.replace('gl_LIBTOOL', '') 139 if 'gl_CONDITIONAL_DEPENDENCIES' in data: 140 self.cache.enableCondDeps() 141 data = data.replace('gl_CONDITIONAL_DEPENDENCIES', '') 142 if 'gl_VC_FILES' in data: 143 self.cache.enableVCFiles() 144 data = data.replace('gl_VC_FILES', '') 145 if 'gl_WITH_TESTS' in data: 146 self.cache.enableTestFlag(TESTS['tests']) 147 data = data.replace('gl_WITH_TESTS', '') 148 if 'gl_WITH_OBSOLETE' in data: 149 self.cache.enableTestFlag(TESTS['obsolete']) 150 data = data.replace('gl_WITH_OBSOLETE', '') 151 if 'gl_WITH_CXX_TESTS' in data: 152 self.cache.enableTestFlag(TESTS['c++-test']) 153 data = data.replace('gl_WITH_CXX_TESTS', '') 154 if 'gl_WITH_LONGRUNNING_TESTS' in data: 155 self.cache.enableTestFlag(TESTS['longrunning-test']) 156 data = data.replace('gl_WITH_LONGRUNNING_TESTS', '') 157 if 'gl_WITH_PRIVILEGED_TESTS' in data: 158 self.cache.enableTestFlag(TESTS['privileged-test']) 159 data = data.replace('gl_WITH_PRIVILEGED_TESTS', '') 160 if 'gl_WITH_UNPORTABLE_TESTS' in data: 161 self.cache.enableTestFlag(TESTS['unportable-test']) 162 data = data.replace('gl_WITH_UNPORTABLE_TESTS', '') 163 if 'gl_WITH_ALL_TESTS' in data: 164 self.cache.enableTestFlag(TESTS['all-test']) 165 data = data.replace('gl_WITH_ALL_TESTS', '') 166 # Find string values 167 result = dict(pattern.findall(data)) 168 values = cleaner([result.get(key, '') for key in keys]) 169 tempdict = dict(zip(keys, values)) 170 if 'gl_LGPL' in tempdict: 171 lgpl = cleaner(tempdict['gl_LGPL']) 172 if lgpl.isdecimal(): 173 self.cache.setLGPL(int(self.cache['lgpl'])) 174 else: # if 'gl_LGPL' not in tempdict 175 self.cache.setLGPL(False) 176 if tempdict['gl_LIB']: 177 self.cache.setLibName(cleaner(tempdict['gl_LIB'])) 178 if tempdict['gl_LOCAL_DIR']: 179 self.cache.setLocalDir(cleaner(tempdict['gl_LOCAL_DIR'])) 180 if tempdict['gl_MODULES']: 181 self.cache.setModules(cleaner(tempdict['gl_MODULES'].split())) 182 if tempdict['gl_AVOID']: 183 self.cache.setAvoids(cleaner(tempdict['gl_AVOID'].split())) 184 if tempdict['gl_SOURCE_BASE']: 185 self.cache.setSourceBase(cleaner(tempdict['gl_SOURCE_BASE'])) 186 if tempdict['gl_M4_BASE']: 187 self.cache.setM4Base(cleaner(tempdict['gl_M4_BASE'])) 188 if tempdict['gl_PO_BASE']: 189 self.cache.setPoBase(cleaner(tempdict['gl_PO_BASE'])) 190 if tempdict['gl_DOC_BASE']: 191 self.cache.setDocBase(cleaner(tempdict['gl_DOC_BASE'])) 192 if tempdict['gl_TESTS_BASE']: 193 self.cache.setTestsBase(cleaner(tempdict['gl_TESTS_BASE'])) 194 if tempdict['gl_MAKEFILE_NAME']: 195 self.cache.setMakefile(cleaner(tempdict['gl_MAKEFILE_NAME'])) 196 if tempdict['gl_MACRO_PREFIX']: 197 self.cache.setMacroPrefix(cleaner(tempdict['gl_MACRO_PREFIX'])) 198 if tempdict['gl_PO_DOMAIN']: 199 self.cache.setPoDomain(cleaner(tempdict['gl_PO_DOMAIN'])) 200 if tempdict['gl_WITNESS_C_MACRO']: 201 self.cache.setWitnessCMacro( 202 cleaner(tempdict['gl_WITNESS_C_MACRO'])) 203 204 # Get cached filelist from gnulib-comp.m4. 205 destdir, m4base = self.config.getDestDir(), self.config.getM4Base() 206 path = joinpath(destdir, m4base, 'gnulib-comp.m4') 207 if isfile(path): 208 with codecs.open(path, 'rb', 'UTF-8') as file: 209 data = file.read() 210 regex = 'AC_DEFUN\\(\\[%s_FILE_LIST\\], \\[(.*?)\\]\\)' % \ 211 self.cache['macro_prefix'] 212 pattern = compiler(regex, re.S | re.M) 213 self.cache.setFiles(pattern.findall(data)[-1].strip().split()) 214 215 # The self.config['localdir'] defaults to the cached one. Recall that the 216 # cached one is relative to $destdir, whereas the one we use is relative 217 # to . or absolute. 218 if not self.config['localdir']: 219 if self.cache['localdir']: 220 if isabs(self.config['destdir']): 221 localdir = joinpath( 222 self.config['destdir'], self.cache['localdir']) 223 else: # if not isabs(self.config['destdir']) 224 if isabs(self.cache['localdir']): 225 localdir = joinpath( 226 self.config['destdir'], self.cache['localdir']) 227 else: # if not isabs(self.cache['localdir']) 228 # NOTE: I NEED TO IMPLEMENT RELATIVE_CONCAT 229 localdir = os.path.relpath(joinpath(self.config['destdir'], 230 self.cache['localdir'])) 231 self.config.setLocalDir(localdir) 232 233 if self.mode != MODES['import']: 234 if self.cache['m4base'] and \ 235 (self.config['m4base'] != self.cache['m4base']): 236 raise(GLError(5, m4base)) 237 238 # Perform actions with modules. In --add-import, append each given module 239 # to the list of cached modules; in --remove-import, remove each given 240 # module from the list of cached modules; in --update, simply set 241 # self.config['modules'] to its cached version. 242 new, old = self.config.getModules(), self.cache.getModules() 243 if self.mode == MODES['add-import']: 244 modules = sorted(set(new + old)) 245 elif self.mode == MODES['remove-import']: 246 modules = [module for module in old if module in new] 247 elif self.mode == MODES['update']: 248 modules = self.cache.getModules() 249 250 # If user tries to apply conddeps and testflag['tests'] together. 251 if self.config['tests'] and self.config['conddeps']: 252 raise(GLError(10, None)) 253 254 # Update configuration dictionary. 255 self.config.update(self.cache) 256 for key in config.keys(): 257 value = config[key] 258 if not config.isdefault(key, value): 259 self.config.update_key(config, key) 260 self.config.setModules(modules) 261 262 # Check if conddeps is enabled together with inctests. 263 inctests = self.config.checkTestFlag(TESTS['tests']) 264 if self.config['conddeps'] and inctests: 265 raise(GLError(10, None)) 266 267 # Define GLImport attributes. 268 self.emiter = GLEmiter(self.config) 269 self.filesystem = GLFileSystem(self.config) 270 self.modulesystem = GLModuleSystem(self.config) 271 self.moduletable = GLModuleTable(self.config, list()) 272 self.makefiletable = GLMakefileTable(self.config) 273 274 def __repr__(self): 275 '''x.__repr__ <==> repr(x)''' 276 result = '<pygnulib.GLImport %s>' % hex(id(self)) 277 return(result) 278 279 def rewrite_old_files(self, files): 280 '''GLImport.rewrite_old_files(files) -> list 281 282 Replace auxdir, docbase, sourcebase, m4base and testsbase from default 283 to their version from cached config.''' 284 if type(files) is not list: 285 raise(TypeError( 286 'files argument must has list type, not %s' % type(files).__name__)) 287 files = \ 288 [ # Begin to convert bytes to string 289 file.decode(ENCS['default']) \ 290 if type(file) is bytes else file \ 291 for file in files 292 ] # Finish to convert bytes to string 293 for file in files: 294 if type(file) is not string: 295 raise(TypeError('each file must be a string instance')) 296 files = sorted(set(files)) 297 files = ['%s%s' % (file, os.path.sep) for file in files] 298 auxdir = self.cache['auxdir'] 299 docbase = self.cache['docbase'] 300 sourcebase = self.cache['sourcebase'] 301 m4base = self.cache['m4base'] 302 testsbase = self.cache['testsbase'] 303 result = list() 304 for file in files: 305 if file.startswith('build-aux/'): 306 path = constants.substart('build-aux/', '%s/' % auxdir, file) 307 elif file.startswith('doc/'): 308 path = constants.substart('doc/', '%s/' % docbase, file) 309 elif file.startswith('lib/'): 310 path = constants.substart('lib/', '%s/' % sourcebase, file) 311 elif file.startswith('m4/'): 312 path = constants.substart('m4/', '%s/' % m4base, file) 313 elif file.startswith('tests/'): 314 path = constants.substart('tests/', '%s/' % testsbase, file) 315 elif file.startswith('tests=lib/'): 316 path = constants.substart( 317 'tests=lib/', '%s/' % testsbase, file) 318 elif file.startswith('top/'): 319 path = constants.substart('top/', '', file) 320 else: # file is not a special file 321 path = file 322 result += [os.path.normpath(path)] 323 result = sorted(set(result)) 324 return(list(result)) 325 326 def rewrite_new_files(self, files): 327 '''GLImport.rewrite_new_files(files) 328 329 Replace auxdir, docbase, sourcebase, m4base and testsbase from default 330 to their version from config.''' 331 if type(files) is not list: 332 raise(TypeError( 333 'files argument must has list type, not %s' % type(files).__name__)) 334 files = \ 335 [ # Begin to convert bytes to string 336 file.decode(ENCS['default']) \ 337 if type(file) is bytes else file \ 338 for file in files 339 ] # Finish to convert bytes to string 340 for file in files: 341 if type(file) is not string: 342 raise(TypeError('each file must be a string instance')) 343 files = sorted(set(files)) 344 auxdir = self.config['auxdir'] 345 docbase = self.config['docbase'] 346 sourcebase = self.config['sourcebase'] 347 m4base = self.config['m4base'] 348 testsbase = self.config['testsbase'] 349 result = list() 350 for file in files: 351 if file.startswith('build-aux/'): 352 path = constants.substart('build-aux/', '%s/' % auxdir, file) 353 elif file.startswith('doc/'): 354 path = constants.substart('doc/', '%s/' % docbase, file) 355 elif file.startswith('lib/'): 356 path = constants.substart('lib/', '%s/' % sourcebase, file) 357 elif file.startswith('m4/'): 358 path = constants.substart('m4/', '%s/' % m4base, file) 359 elif file.startswith('tests/'): 360 path = constants.substart('tests/', '%s/' % testsbase, file) 361 elif file.startswith('tests=lib/'): 362 path = constants.substart( 363 'tests=lib/', '%s/' % testsbase, file) 364 elif file.startswith('top/'): 365 path = constants.substart('top/', '', file) 366 else: # file is not a special file 367 path = file 368 result += [os.path.normpath(path)] 369 result = sorted(set(result)) 370 return(list(result)) 371 372 def actioncmd(self): 373 '''Return command-line invocation comment.''' 374 modules = self.config.getModules() 375 avoids = self.config.getAvoids() 376 destdir = self.config.getDestDir() 377 localdir = self.config.getLocalDir() 378 auxdir = self.config.getAuxDir() 379 sourcebase = self.config.getSourceBase() 380 m4base = self.config.getM4Base() 381 docbase = self.config.getDocBase() 382 pobase = self.config.getPoBase() 383 testsbase = self.config.getTestsBase() 384 testflags = self.config.getTestFlags() 385 conddeps = self.config.checkCondDeps() 386 libname = self.config.getLibName() 387 lgpl = self.config.getLGPL() 388 makefile = self.config.getMakefile() 389 libtool = self.config.checkLibtool() 390 macro_prefix = self.config.getMacroPrefix() 391 witness_c_macro = self.config.getWitnessCMacro() 392 podomain = self.config.getPoDomain() 393 vc_files = self.config.checkVCFiles() 394 verbose = self.config.getVerbosity() 395 396 # Create command-line invocation comment. 397 actioncmd = 'gnulib-tool --import' 398 actioncmd += ' --dir=%s' % destdir 399 if localdir: 400 actioncmd += ' --local-dir=%s' % localdir 401 actioncmd += ' --lib=%s' % libname 402 actioncmd += ' --source-base=%s' % sourcebase 403 actioncmd += ' --m4-base=%s' % m4base 404 if pobase: 405 actioncmd += ' --po-base=%s' % pobase 406 actioncmd += ' --doc-base=%s' % docbase 407 actioncmd += ' --tests-base=%s' % testsbase 408 actioncmd += ' --aux-dir=%s' % auxdir 409 if self.config.checkTestFlag(TESTS['tests']): 410 actioncmd += ' --with-tests' 411 if self.config.checkTestFlag(TESTS['obsolete']): 412 actioncmd += ' --with-obsolete' 413 if self.config.checkTestFlag(TESTS['c++-test']): 414 actioncmd += ' --with-c++-tests' 415 if self.config.checkTestFlag(TESTS['longrunning-test']): 416 actioncmd += ' --with-longrunning-tests' 417 if self.config.checkTestFlag(TESTS['privileged-test']): 418 actioncmd += ' --with-privileged-test' 419 if self.config.checkTestFlag(TESTS['unportable-test']): 420 actioncmd += ' --with-unportable-tests' 421 if self.config.checkTestFlag(TESTS['all-test']): 422 actioncmd += ' --with-all-tests' 423 for module in avoids: 424 actioncmd += ' --avoid=%s' % module 425 if lgpl: 426 if lgpl == True: 427 actioncmd += ' --lgpl' 428 else: # if lgpl != True 429 actioncmd += ' --lgpl=%s' % lgpl 430 if makefile: 431 actioncmd += ' --makefile-name=%s' % makefile 432 if conddeps: 433 actioncmd += ' --conditional-dependencies' 434 else: # if not conddeps 435 actioncmd += ' --no-conditional-dependencies' 436 if libtool: 437 actioncmd += ' --libtool' 438 else: # if not libtool 439 actioncmd += ' --no-libtool' 440 actioncmd += ' --macro-prefix=%s' % macro_prefix 441 if podomain: 442 actioncmd = ' --podomain=%s' % podomain 443 if witness_c_macro: 444 actioncmd += ' --witness_c_macro=%s' % witness_c_macro 445 if vc_files == True: 446 actioncmd += ' --vc-files' 447 elif vc_files == False: 448 actioncmd += ' --no-vc-files' 449 actioncmd += ' ' # Add a space 450 actioncmd += ' '.join(modules) 451 return(actioncmd) 452 453 def gnulib_cache(self): 454 '''GLImport.gnulib_cache() -> string 455 456 Emit the contents of generated $m4base/gnulib-cache.m4 file. 457 GLConfig: destdir, localdir, tests, sourcebase, m4base, pobase, docbase, 458 testsbase, conddeps, libtool, macro_prefix, podomain, vc_files.''' 459 emit = string() 460 moduletable = self.moduletable 461 actioncmd = self.actioncmd() 462 destdir = self.config['destdir'] 463 localdir = self.config['localdir'] 464 testflags = list(self.config['testflags']) 465 sourcebase = self.config['sourcebase'] 466 m4base = self.config['m4base'] 467 pobase = self.config['pobase'] 468 docbase = self.config['docbase'] 469 testsbase = self.config['testsbase'] 470 lgpl = self.config['lgpl'] 471 libname = self.config['libname'] 472 makefile = self.config['makefile'] 473 conddeps = self.config['conddeps'] 474 libtool = self.config['libtool'] 475 macro_prefix = self.config['macro_prefix'] 476 podomain = self.config['podomain'] 477 witness_c_macro = self.config['witness_c_macro'] 478 vc_files = self.config['vc_files'] 479 modules = [str(module) for module in moduletable['base']] 480 avoids = [str(avoid) for avoid in moduletable['avoids']] 481 emit += self.emiter.copyright_notice() 482 emit += '''# 483# This file represents the specification of how gnulib-tool is used. 484# It acts as a cache: It is written and read by gnulib-tool. 485# In projects that use version control, this file is meant to be put under 486# version control, like the configure.ac and various Makefile.am files. 487 488 489# Specification in the form of a command-line invocation: 490# %s 491 492# Specification in the form of a few \ 493gnulib-tool.m4 macro invocations:\n''' % actioncmd 494 if not localdir or localdir.startswith('/'): 495 relative_localdir = localdir 496 else: # if localdir or not localdir.startswith('/') 497 relative_localdir = constants.relativize(destdir, localdir) 498 emit += 'gl_LOCAL_DIR([%s])\n' % relative_localdir 499 emit += 'gl_MODULES([\n' 500 emit += ' %s\n' % '\n '.join(modules) 501 emit += '])\n' 502 if self.config.checkTestFlag(TESTS['obsolete']): 503 emit += 'gl_WITH_OBSOLETE\n' 504 if self.config.checkTestFlag(TESTS['cxx-tests']): 505 emit += 'gl_WITH_CXX_TESTS\n' 506 if self.config.checkTestFlag(TESTS['privileged-tests']): 507 emit += 'gl_WITH_PRIVILEGED_TESTS\n' 508 if self.config.checkTestFlag(TESTS['unportable-tests']): 509 emit += 'gl_WITH_UNPORTABLE_TESTS\n' 510 if self.config.checkTestFlag(TESTS['all-tests']): 511 emit += 'gl_WITH_ALL_TESTS\n' 512 emit += 'gl_AVOID([%s])\n' % ' '.join(avoids) 513 emit += 'gl_SOURCE_BASE([%s])\n' % sourcebase 514 emit += 'gl_M4_BASE([%s])\n' % m4base 515 emit += 'gl_PO_BASE([%s])\n' % pobase 516 emit += 'gl_DOC_BASE([%s])\n' % docbase 517 emit += 'gl_TESTS_BASE([%s])\n' % testsbase 518 if self.config.checkTestFlag(TESTS['tests']): 519 emit += 'gl_WITH_TESTS\n' 520 emit += 'gl_LIB([%s])\n' % libname 521 if lgpl != False: 522 if lgpl == True: 523 emit += 'gl_LGPL\n' 524 else: # if lgpl != True 525 emit += 'gl_LGPL([%d])\n' % lgpl 526 emit += 'gl_MAKEFILE_NAME([%s])\n' % makefile 527 if conddeps: 528 emit += 'gl_CONDITIONAL_DEPENDENCIES\n' 529 if libtool: 530 emit += 'gl_LIBTOOL\n' 531 emit += 'gl_MACRO_PREFIX([%s])\n' % macro_prefix 532 emit += 'gl_PO_DOMAIN([%s])\n' % podomain 533 emit += 'gl_WITNESS_C_MACRO([%s])\n' % witness_c_macro 534 if vc_files: 535 emit += 'gl_VC_FILES([%s])\n' % vc_files 536 if type(emit) is bytes: 537 emit = emit.decode(ENCS['default']) 538 return(constants.nlconvert(emit)) 539 540 def gnulib_comp(self, files): 541 '''GLImport.gnulib_comp(files) -> string 542 543 Emit the contents of generated $m4base/gnulib-comp.m4 file. 544 GLConfig: destdir, localdir, tests, sourcebase, m4base, pobase, docbase, 545 testsbase, conddeps, libtool, macro_prefix, podomain, vc_files.''' 546 emit = string() 547 assistant = self.assistant 548 moduletable = self.moduletable 549 destdir = self.config['destdir'] 550 localdir = self.config['localdir'] 551 auxdir = self.config['auxdir'] 552 testflags = list(self.config['testflags']) 553 sourcebase = self.config['sourcebase'] 554 m4base = self.config['m4base'] 555 pobase = self.config['pobase'] 556 docbase = self.config['docbase'] 557 testsbase = self.config['testsbase'] 558 lgpl = self.config['lgpl'] 559 libname = self.config['libname'] 560 makefile = self.config['makefile'] 561 conddeps = self.config['conddeps'] 562 libtool = self.config['libtool'] 563 macro_prefix = self.config['macro_prefix'] 564 podomain = self.config['podomain'] 565 witness_c_macro = self.config['witness_c_macro'] 566 configure_ac = self.config['configure_ac'] 567 vc_files = self.config['vc_files'] 568 libtests = self.config['libtests'] 569 modules = [str(module) for module in moduletable['base']] 570 avoids = [str(avoid) for avoid in moduletable['avoids']] 571 emit += '# DO NOT EDIT! GENERATED AUTOMATICALLY!\n' 572 emit += self.emiter.copyright_notice() 573 emit += '''# 574# This file represents the compiled summary of the specification in 575# gnulib-cache.m4. It lists the computed macro invocations that need 576# to be invoked from configure.ac. 577# In projects that use version control, this file can be treated like 578# other built files. 579 580 581# This macro should be invoked from %s, in the section 582# "Checks for programs", right after AC_PROG_CC, and certainly before 583# any checks for libraries, header files, types and library functions. 584AC_DEFUN([%s_EARLY], 585[ 586 m4_pattern_forbid([^gl_[A-Z]])dnl the gnulib macro namespace 587 m4_pattern_allow([^gl_ES$])dnl a valid locale name 588 m4_pattern_allow([^gl_LIBOBJS$])dnl a variable 589 m4_pattern_allow([^gl_LTLIBOBJS$])dnl a variable 590 AC_REQUIRE([gl_PROG_AR_RANLIB])\n''' % (configure_ac, macro_prefix) 591 uses_subdirs = False 592 for module in moduletable['main']: 593 # Test whether there are some source files in subdirectories. 594 for file in module.getFiles(): 595 if file.startswith('lib/') and file.endswith('.c') and \ 596 file.count('/') > 1: 597 uses_subdirs = True 598 break 599 if uses_subdirs: 600 emit += ' AC_REQUIRE([AM_PROG_CC_C_O])\n' 601 for module in moduletable['final']: 602 emit += ' # Code from module %s:\n' % str(module) 603 snippet = module.getAutoconfSnippet_Early() 604 lines = [line for line in snippet.split( 605 constants.NL) if line != ''] 606 if lines: 607 emit += ' %s\n' % '\n '.join(lines) 608 emit += '])\n' 609 emit += ''' 610# This macro should be invoked from %s, in the section 611# "Check for header files, types and library functions". 612AC_DEFUN([%s_INIT], 613[\n''' % (configure_ac, macro_prefix) 614 if libtool: 615 emit += ' AM_CONDITIONAL([GL_COND_LIBTOOL], [true])\n' 616 emit += ' gl_cond_libtool=true\n' 617 else: # if not libtool 618 emit += ' AM_CONDITIONAL([GL_COND_LIBTOOL], [false])\n' 619 emit += ' gl_cond_libtool=false\n' 620 emit += ' gl_libdeps=\n' 621 emit += ' gl_ltlibdeps=\n' 622 replace_auxdir = False 623 if auxdir != 'build-aux': 624 replace_auxdir = True 625 emit += ' gl_m4_base=\'%s\'\n' % m4base 626 emit += self.emiter.initmacro_start(macro_prefix) 627 emit += ' gl_source_base=\'%s\'\n' % sourcebase 628 if witness_c_macro: 629 emit += ' m4_pushdef([gl_MODULE_INDICATOR_CONDITION], [%s])\n' % \ 630 witness_c_macro 631 # Emit main autoconf snippets. 632 emit += self.emiter.autoconfSnippets(moduletable['main'], 633 moduletable, assistant, 0, True, False, True, replace_auxdir) 634 if witness_c_macro: 635 emit += ' m4_popdef([gl_MODULE_INDICATOR_CONDITION])\n' 636 emit += ' # End of code from modules\n' 637 emit += self.emiter.initmacro_end(macro_prefix) 638 emit += ' gltests_libdeps=\n' 639 emit += ' gltests_ltlibdeps=\n' 640 emit += self.emiter.initmacro_start('%stests' % macro_prefix) 641 emit += ' gl_source_base=\'%s\'\n' % testsbase 642 # Define a tests witness macro that depends on the package. 643 # PACKAGE is defined by AM_INIT_AUTOMAKE, PACKAGE_TARNAME is defined by 644 # AC_INIT. 645 # See <https://lists.gnu.org/r/automake/2009-05/msg00145.html>. 646 emit += 'changequote(,)dnl\n' 647 emit += ' %stests_WITNESS=' % macro_prefix 648 emit += 'IN_`echo "${PACKAGE-$PACKAGE_TARNAME}" | LC_ALL=C tr \ 649abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ | LC_ALL=C sed -e \ 650\'s/[^A-Z0-9_]/_/g\'`_GNULIB_TESTS\n' 651 emit += 'changequote([, ])dnl\n' 652 emit += ' AC_SUBST([%stests_WITNESS])\n' % macro_prefix 653 emit += ' gl_module_indicator_condition=$%stests_WITNESS\n' % macro_prefix 654 emit += ' m4_pushdef([gl_MODULE_INDICATOR_CONDITION], ' 655 emit += '[$gl_module_indicator_condition])\n' 656 # Emit tests autoconf snippets. 657 emit += self.emiter.autoconfSnippets(moduletable['tests'], 658 moduletable, assistant, 0, True, True, True, replace_auxdir) 659 emit += ' m4_popdef([gl_MODULE_INDICATOR_CONDITION])\n' 660 emit += self.emiter.initmacro_end('%stests' % macro_prefix) 661 # _LIBDEPS and _LTLIBDEPS variables are not needed if this library is 662 # created using libtool, because libtool already handles the dependencies. 663 if not libtool: 664 libname_upper = libname.upper().replace('-', '_') 665 emit += ' %s_LIBDEPS="$gl_libdeps"\n' % libname_upper 666 emit += ' AC_SUBST([%s_LIBDEPS])\n' % libname_upper 667 emit += ' %s_LTLIBDEPS="$gl_ltlibdeps"\n' % libname_upper 668 emit += ' AC_SUBST([%s_LTLIBDEPS])\n' % libname_upper 669 if libtests: 670 emit += ' LIBTESTS_LIBDEPS="$gltests_libdeps"\n' 671 emit += ' AC_SUBST([LIBTESTS_LIBDEPS])\n' 672 emit += '])\n' 673 emit += self.emiter.initmacro_done(macro_prefix, sourcebase) 674 emit += self.emiter.initmacro_done('%stests' % macro_prefix, testsbase) 675 emit += ''' 676# This macro records the list of files which have been installed by 677# gnulib-tool and may be removed by future gnulib-tool invocations. 678AC_DEFUN([%s_FILE_LIST], [\n''' % macro_prefix 679 emit += ' %s\n' % '\n '.join(files) 680 emit += '])\n' 681 if type(emit) is bytes: 682 emit = emit.decode(ENCS['default']) 683 return(emit) 684 685 def _done_dir_(self, directory, dirs_added, dirs_removed): 686 '''GLImport._done_dir_(directory, dirs_added, dirs_removed) 687 688 This method is used to determine ignore argument for _update_ignorelist_ 689 method and then call it.''' 690 destdir = self.config['destdir'] 691 if isdir(joinpath(destdir, 'CVS')) or \ 692 isdir(joinpath(destdir, directory, 'CVS')) or \ 693 isfile(joinpath(destdir, directory, '.cvsignore')): 694 self._update_ignorelist_(directory, '.cvsignore', 695 dirs_added, dirs_removed) 696 if isdir(joinpath(destdir, '.git')) or \ 697 isfile(joinpath(destdir, directory, '.gitignore')): 698 self._update_ignorelist_(directory, '.gitignore', 699 dirs_added, dirs_removed) 700 701 def _update_ignorelist_(self, directory, ignore, dirs_added, dirs_removed): 702 '''GLImport._update_ignorelist_(directory, ignore, dirs_added, dirs_removed) 703 704 Update .gitignore or .cvsignore files.''' 705 result = string() 706 destdir = self.config['destdir'] 707 if ignore == '.gitignore': 708 anchor = '/' 709 else: 710 anchor = '' 711 srcpath = joinpath(destdir, directory, ignore) 712 backupname = '%s~' % srcpath 713 if isfile(srcpath): 714 if dirs_added or dirs_removed: 715 with codecs.open(srcpath, 'rb', 'UTF-8') as file: 716 srcdata = file.read() 717 dirs_ignore = sorted(set(srcdata.split('\n'))) 718 dirs_ignore = [line for line in dirs_ignore if line.strip()] 719 srcdata = '\n'.join(sorted(set(dirs_ignore))).strip() 720 dirs_ignore += [d for d in dirs_added if d not in dirs_ignore] 721 dirs_ignore = [d for d in dirs_ignore if d in dirs_removed] 722 dirs_ignore = ['%s%s' % (anchor, d) for d in dirs_ignore] 723 dirs_ignore = sorted(set(dirs_ignore)) 724 destdata = '\n'.join(sorted(set(dirs_ignore))).strip() 725 if srcdata != destdata: 726 if not self.config['dryrun']: 727 print('Updating %s (backup in %s)' % 728 (srcpath, backupname)) 729 shutil.copy2(srcpath, backupname) 730 result = string() 731 with codecs.open(srcpath, 'ab', 'UTF-8') as file: 732 file.write(destdata) 733 else: # if self.config['dryrun'] 734 print('Updating %s (backup in %s)' % 735 (srcpath, backupname)) 736 else: # if not isfile(srcpath) 737 if dirs_added: 738 if not self.config['dryrun']: 739 print('Creating %s' % srcpath) 740 dirs_added = sorted(set(dirs_added)) 741 dirs_added = ['%s%s' % (anchor, d) for d in dirs_added] 742 if ignore == '.cvsignore': 743 dirs_added = ['.deps', '.dirstamp'] + dirs_added 744 with codecs.open(srcpath, 'wb', 'UTF-8') as file: 745 file.write('\n'.join(dirs_added)) 746 file.write('\n') 747 else: # if self.config['dryrun'] 748 print('Create %s' % srcpath) 749 750 def prepare(self): 751 '''Make all preparations before the execution of the code. 752 Returns filetable and sed transformers, which change the license.''' 753 destdir = self.config['destdir'] 754 localdir = self.config['localdir'] 755 auxdir = self.config['auxdir'] 756 modules = list(self.config['modules']) 757 avoids = list(self.config['avoids']) 758 testflags = list(self.config['testflags']) 759 sourcebase = self.config['sourcebase'] 760 m4base = self.config['m4base'] 761 pobase = self.config['pobase'] 762 docbase = self.config['docbase'] 763 testsbase = self.config['testsbase'] 764 lgpl = self.config['lgpl'] 765 copyrights = self.config['copyrights'] 766 libname = self.config['libname'] 767 makefile = self.config['makefile'] 768 conddeps = self.config['conddeps'] 769 libtool = self.config['libtool'] 770 macro_prefix = self.config['macro_prefix'] 771 podomain = self.config['podomain'] 772 witness_c_macro = self.config['witness_c_macro'] 773 vc_files = self.config['vc_files'] 774 configure_ac = self.config['configure_ac'] 775 ac_version = self.config['ac_version'] 776 verbose = self.config['verbosity'] 777 base_modules = sorted( 778 set([self.modulesystem.find(m) for m in modules])) 779 avoids = sorted(set([self.modulesystem.find(a) for a in avoids])) 780 781 # Perform transitive closure. 782 self.moduletable.setAvoids(avoids) 783 final_modules = self.moduletable.transitive_closure(base_modules) 784 785 # Show final module list. 786 if verbose >= 0: 787 bold_on = '' 788 bold_off = '' 789 term = os.getenv('TERM') 790 if term == 'xterm': 791 bold_on = '\x1b[1m' 792 bold_off = '\x1b[0m' 793 print('Module list with included dependencies (indented):') 794 for module in final_modules: 795 if str(module) in self.config.getModules(): 796 print(' %s%s%s' % (bold_on, module, bold_off)) 797 else: # if str(module) not in self.config.getModules() 798 print(' %s' % module) 799 800 # Separate modules into main_modules and tests_modules. 801 modules = self.moduletable.transitive_closure_separately( 802 base_modules, final_modules) 803 main_modules, tests_modules = modules 804 805 # Transmit base_modules, final_modules, main_modules and tests_modules. 806 self.moduletable.setBaseModules(base_modules) 807 self.moduletable.setFinalModules(final_modules) 808 self.moduletable.setMainModules(main_modules) 809 self.moduletable.setTestsModules(tests_modules) 810 811 # Print main_modules and tests_modules. 812 if verbose >= 1: 813 print('Main module list:') 814 for module in main_modules: 815 print(' %s' % str(module)) 816 print('Tests-related module list:') 817 for module in tests_modules: 818 print(' %s' % str(module)) 819 820 # Determine whether a $testsbase/libtests.a is needed. 821 libtests = False 822 for module in tests_modules: 823 files = module.getFiles() 824 for file in files: 825 if file.startswith('lib/'): 826 libtests = True 827 break 828 if libtests: 829 self.config.enableLibtests() 830 831 # Add dummy package if it is needed. 832 main_modules = self.moduletable.add_dummy(main_modules) 833 if libtests: # if we need to use libtests.a 834 tests_modules = self.moduletable.add_dummy(tests_modules) 835 836 # Check license incompatibilities. 837 listing = list() 838 compatibilities = dict() 839 incompatibilities = string() 840 compatibilities['all'] = ['GPLv2+ build tool', 'GPLed build tool', 841 'public domain', 'unlimited', 842 'unmodifiable license text'] 843 compatibilities[3] = ['LGPL', 'LGPLv2+', 'LGPLv3+'] 844 compatibilities[2] = ['LGPLv2+'] 845 if lgpl: 846 for module in main_modules: 847 license = module.getLicense() 848 if license not in compatibilities['all']: 849 if lgpl == 3 or lgpl == True: 850 if license not in compatibilities[3]: 851 listing.append(tuple([str(module), license])) 852 elif lgpl == 2: 853 if license not in compatibilities[2]: 854 listing.append(tuple([str(module), license])) 855 if listing: 856 raise(GLError(11, listing)) 857 858 # Print notices from modules. 859 for module in main_modules: 860 notice = module.getNotice() 861 notice = notice.strip() 862 if notice: 863 print('Notice from module %s:' % str(module)) 864 pattern = compiler('^(.*?)$', re.S | re.M) 865 notice = pattern.sub(' \\1', notice) 866 print(notice) 867 868 # Determine script to apply to imported library files. 869 lgpl2gpl = ''' 870 s/GNU Lesser General/GNU General/g 871 s/Lesser General Public License/General Public License/g 872 s/GNU Library General/GNU General/g 873 s/Library General Public License/General Public License/g 874 s/version 2\\(.1\\)\\{0,1\\}\\([ ,]\\)/version 3\\2/g''' 875 sed_transform_lib_file = string() 876 if 'config-h' in [str(module) for module in main_modules]: 877 sed_transform_lib_file += ''' 878 s/^#ifdef[\t ]*HAVE_CONFIG_H[\t ]*$/#if 1/ 879 ''' 880 sed_transform_main_lib_file = sed_transform_lib_file 881 if copyrights: 882 if lgpl: # if lgpl is enabled 883 if lgpl == 3: 884 sed_transform_main_lib_file += ''' 885 s/GNU General/GNU Lesser General/g 886 s/General Public License/Lesser General Public License/g 887 s/Lesser Lesser General Public License/Lesser General Public''' \ 888 + ' License/g' 889 elif lgpl == 2: 890 sed_transform_main_lib_file += ''' 891 s/GNU General/GNU Lesser General/g 892 s/General Public License/Lesser General Public License/g 893 s/Lesser Lesser General Public License/Lesser General Public''' \ 894 + '''License/g 895 s/version [23]\\([ ,]\\)/version 2.1\\1/g''' 896 else: # if lgpl is disabled 897 sed_transform_main_lib_file += lgpl2gpl 898 899 # Determine script to apply to auxiliary files that go into $auxdir/. 900 sed_transform_build_aux_file = string() 901 if copyrights: 902 sed_transform_build_aux_file += lgpl2gpl 903 904 # Determine script to apply to library files that go into $testsbase/. 905 sed_transform_testsrelated_lib_file = sed_transform_lib_file 906 if copyrights: 907 sed_transform_testsrelated_lib_file += lgpl2gpl 908 909 # Determine the final file lists. 910 main_filelist, tests_filelist = \ 911 self.moduletable.filelist_separately(main_modules, tests_modules) 912 filelist = sorted( 913 set(main_filelist + tests_filelist), key=string.lower) 914 if not filelist: 915 raise(GLError(12, None)) 916 917 # Print list of files. 918 if verbose >= 0: 919 print('File list:') 920 for file in filelist: 921 if file.startswith('tests=lib/'): 922 rest = file[10:] 923 print(' lib/%s -> tests/%s' % (rest, rest)) 924 else: 925 print(' %s' % file) 926 927 # Prepare basic filelist and basic old_files/new_files variables. 928 filelist = sorted(set(filelist)) 929 new_files = filelist + ['m4/gnulib-tool.m4'] 930 old_files = list(self.cache['files']) 931 path = joinpath(destdir, m4base, 'gnulib-tool.m4') 932 if isfile(path): 933 old_files += [joinpath('m4', 'gnulib-tool.m4')] 934 935 # Construct tables and transformers. 936 transformers = dict() 937 transformers['lib'] = string(sed_transform_lib_file) 938 transformers['aux'] = string(sed_transform_build_aux_file) 939 transformers['main'] = string(sed_transform_main_lib_file) 940 transformers['tests'] = string(sed_transform_testsrelated_lib_file) 941 old_table = list() 942 new_table = list() 943 for src in old_files: 944 dest = self.rewrite_old_files([src])[-1] 945 old_table += [tuple([dest, src])] 946 for src in new_files: 947 dest = self.rewrite_new_files([src])[-1] 948 new_table += [tuple([dest, src])] 949 old_table = sorted(set(old_table)) 950 new_table = sorted(set(new_table)) 951 952 # Prepare the filetable. 953 filetable = dict() 954 filetable['all'] = sorted(set(filelist)) 955 filetable['old'] = \ 956 sorted(set(old_table), key=lambda t: tuple(t[0].lower())) 957 filetable['new'] = \ 958 sorted(set(new_table), key=lambda t: tuple(t[0].lower())) 959 filetable['added'] = list() 960 filetable['removed'] = list() 961 962 # Return the result. 963 result = tuple([filetable, transformers]) 964 return(result) 965 966 def execute(self, filetable, transformers): 967 '''Perform operations on the lists of files, which are given in a special 968 format except filelist argument. Such lists of files can be created using 969 GLImport.prepare() function.''' 970 if type(filetable) is not dict: 971 raise(TypeError('filetable must be a dict, not %s' % 972 type(filetable).__name__)) 973 for key in ['all', 'old', 'new', 'added', 'removed']: 974 if key not in filetable: 975 raise(KeyError('filetable must contain key %s' % repr(key))) 976 destdir = self.config['destdir'] 977 localdir = self.config['localdir'] 978 auxdir = self.config['auxdir'] 979 modules = list(self.config['modules']) 980 avoids = list(self.config['avoids']) 981 testflags = list(self.config['testflags']) 982 sourcebase = self.config['sourcebase'] 983 m4base = self.config['m4base'] 984 pobase = self.config['pobase'] 985 docbase = self.config['docbase'] 986 testsbase = self.config['testsbase'] 987 lgpl = self.config['lgpl'] 988 copyrights = self.config['copyrights'] 989 libname = self.config['libname'] 990 makefile = self.config['makefile'] 991 conddeps = self.config['conddeps'] 992 libtool = self.config['libtool'] 993 macro_prefix = self.config['macro_prefix'] 994 podomain = self.config['podomain'] 995 witness_c_macro = self.config['witness_c_macro'] 996 vc_files = self.config['vc_files'] 997 configure_ac = self.config['configure_ac'] 998 ac_version = self.config['ac_version'] 999 verbose = self.config['verbosity'] 1000 actioncmd = self.actioncmd() 1001 1002 # Create all necessary directories. 1003 dirs = list() 1004 if pobase: 1005 dirs += [pobase] 1006 if [file for file in filetable['all'] if file.startswith('doc/')]: 1007 dirs += [docbase] 1008 dirs += [sourcebase, m4base, auxdir] 1009 dirs += [os.path.dirname(pair[0]) for pair in filetable['new']] 1010 dirs = sorted(set([joinpath(destdir, d) for d in dirs])) 1011 for directory in dirs: 1012 if not isdir(directory): 1013 print('Creating directory %s' % directory) 1014 if not self.config['dryrun']: 1015 try: # Try to create directory 1016 os.makedirs(directory) 1017 except Exception as error: 1018 raise(GLError(13, directory)) 1019 else: # if self.config['dryrun'] 1020 print('Create directory %s' % directory) 1021 1022 # Create GLFileAssistant instance to process files. 1023 self.assistant = GLFileAssistant(self.config, transformers) 1024 1025 # Files which are in filetable['old'] and not in filetable['new']. 1026 # They will be removed and added to filetable['removed'] list. 1027 pairs = [f for f in filetable['old'] if f not in filetable['old']] 1028 pairs = sorted(set(pairs), key=lambda t: tuple(t[0].lower())) 1029 files = sorted(set(pair[0] for pair in pairs)) 1030 for file in files: 1031 path = joinpath(destdir, file) 1032 if isfile(path) or os.path.islink(path): 1033 if not self.config['dryrun']: 1034 backup = string('%s~' % path) 1035 print('Removing file %s (backup in )' % (path, backup)) 1036 try: # Try to move file 1037 if os.path.exists(backup): 1038 os.remove(backup) 1039 shutil.move(path, '%s~' % path) 1040 except Exception as error: 1041 raise(GLError(14, file)) 1042 else: # if self.config['dryrun'] 1043 print('Remove file %s (backup in %s~)' % (path, path)) 1044 filetable['removed'] += [file] 1045 1046 # Files which are in filetable['new'] and not in filetable['old']. 1047 # They will be added/updated and added to filetable['added'] list. 1048 already_present = False 1049 pairs = [f for f in filetable['new'] if f not in filetable['old']] 1050 pairs = sorted(set(pairs)) 1051 for pair in pairs: 1052 original = pair[1] 1053 rewritten = pair[0] 1054 self.assistant.setOriginal(original) 1055 self.assistant.setRewritten(rewritten) 1056 self.assistant.add_or_update(already_present) 1057 1058 # Files which are in filetable['new'] and in filetable['old']. 1059 # They will be added/updated and added to filetable['added'] list. 1060 already_present = True 1061 pairs = [f for f in filetable['new'] if f in filetable['old']] 1062 pairs = sorted(set(pairs)) 1063 for pair in pairs: 1064 original = pair[1] 1065 rewritten = pair[0] 1066 self.assistant.setOriginal(original) 1067 self.assistant.setRewritten(rewritten) 1068 self.assistant.add_or_update(already_present) 1069 1070 # Add files which were added to the list of filetable['added']. 1071 filetable['added'] += self.assistant.getFiles() 1072 filetable['added'] = sorted(set(filetable['added'])) 1073 1074 # Determine include_guard_prefix. 1075 include_guard_prefix = self.config['include_guard_prefix'] 1076 1077 # Determine makefile name. 1078 if not makefile: 1079 makefile_am = string('Makefile.am') 1080 else: # if makefile 1081 makefile_am = makefile 1082 1083 # Create normal Makefile.ams. 1084 for_test = False 1085 1086 # Setup list of Makefile.am edits that are to be performed afterwards. 1087 # Some of these edits apply to files that we will generate; others are 1088 # under the responsibility of the developer. 1089 makefile_am_edits = dict() 1090 if makefile_am == 'Makefile.am': 1091 sourcebase_dir = os.path.dirname(sourcebase) 1092 sourcebase_base = os.path.basename(sourcebase) 1093 self.makefiletable.editor( 1094 sourcebase_dir, 'SUBDIRS', sourcebase_base) 1095 if pobase: 1096 pobase_dir = os.path.dirname(pobase) 1097 pobase_base = os.path.basename(pobase) 1098 self.makefiletable.editor(pobase_dir, 'SUBDIRS', pobase_base) 1099 if self.config.checkTestFlag(TESTS['tests']): 1100 if makefile_am == 'Makefile.am': 1101 testsbase_dir = os.path.dirname(testsbase) 1102 testsbase_base = os.path.basename(testsbase) 1103 self.makefiletable.editor( 1104 testsbase_dir, 'SUBDIRS', testsbase_base) 1105 self.makefiletable.editor('', 'ACLOCAL_AMFLAGS', '-I %s' % m4base) 1106 self.makefiletable.parent() 1107 1108 # Create library makefile. 1109 basename = joinpath(sourcebase, makefile_am) 1110 tmpfile = self.assistant.tmpfilename(basename) 1111 emit, uses_subdirs = self.emiter.lib_Makefile_am(basename, 1112 self.moduletable['main'], self.moduletable, self.makefiletable, 1113 actioncmd, for_test) 1114 with codecs.open(tmpfile, 'wb', 'UTF-8') as file: 1115 file.write(emit) 1116 filename, backup, flag = self.assistant.super_update(basename, tmpfile) 1117 if flag == 1: 1118 if not self.config['dryrun']: 1119 print('Updating %s (backup in %s)' % (filename, backup)) 1120 else: # if self.config['dryrun'] 1121 print('Update %s (backup in %s)' % (filename, backup)) 1122 elif flag == 2: 1123 if not self.config['dryrun']: 1124 print('Creating %s' % filename) 1125 else: # if self.config['dryrun']: 1126 print('Create %s' % filename) 1127 filetable['added'] += [filename] 1128 if isfile(tmpfile): 1129 os.remove(tmpfile) 1130 1131 # Create po/ directory. 1132 filesystem = GLFileSystem(self.config) 1133 if pobase: 1134 # Create po makefile and auxiliary files. 1135 for file in ['Makefile.in.in', 'remove-potcdate.sin']: 1136 tmpfile = self.assistant.tmpfilename(joinpath(pobase, file)) 1137 path = joinpath('build-aux', 'po', file) 1138 lookedup, flag = filesystem.lookup(path) 1139 shutil.move(lookedup, tmpfile) 1140 basename = joinpath(pobase, file) 1141 filename, backup, flag = self.assistant.super_update( 1142 basename, tmpfile) 1143 if flag == 1: 1144 if not self.config['dryrun']: 1145 print('Updating %s (backup in %s)' % 1146 (filename, backup)) 1147 else: # if self.config['dryrun'] 1148 print('Update %s (backup in %s)' % (filename, backup)) 1149 elif flag == 2: 1150 if not self.config['dryrun']: 1151 print('Creating %s' % filename) 1152 else: # if self.config['dryrun']: 1153 print('Create %s' % filename) 1154 filetable['added'] += [filename] 1155 if isfile(tmpfile): 1156 os.remove(tmpfile) 1157 1158 # Create po makefile parameterization, part 1. 1159 basename = joinpath(pobase, 'Makevars') 1160 tmpfile = self.assistant.tmpfilename(basename) 1161 emit = self.emiter.po_Makevars() 1162 with codecs.open(tmpfile, 'wb', 'UTF-8') as file: 1163 file.write(emit) 1164 filename, backup, flag = self.assistant.super_update( 1165 basename, tmpfile) 1166 if flag == 1: 1167 if not self.config['dryrun']: 1168 print('Updating %s (backup in %s)' % (filename, backup)) 1169 else: # if self.config['dryrun'] 1170 print('Update %s (backup in %s)' % (filename, backup)) 1171 elif flag == 2: 1172 if not self.config['dryrun']: 1173 print('Creating %s' % filename) 1174 else: # if self.config['dryrun']: 1175 print('Create %s' % filename) 1176 filetable['added'] += [filename] 1177 if isfile(tmpfile): 1178 os.remove(tmpfile) 1179 1180 # Create po makefile parameterization, part 2. 1181 basename = joinpath(pobase, 'POTFILES.in') 1182 tmpfile = self.assistant.tmpfilename(basename) 1183 with codecs.open(tmpfile, 'wb', 'UTF-8') as file: 1184 file.write(self.emiter.po_POTFILES_in(filetable['all'])) 1185 basename = joinpath(pobase, 'POTFILES.in') 1186 filename, backup, flag = self.assistant.super_update( 1187 basename, tmpfile) 1188 if flag == 1: 1189 if not self.config['dryrun']: 1190 print('Updating %s (backup in %s)' % (filename, backup)) 1191 else: # if self.config['dryrun'] 1192 print('Update %s (backup in %s)' % (filename, backup)) 1193 elif flag == 2: 1194 if not self.config['dryrun']: 1195 print('Creating %s' % filename) 1196 else: # if self.config['dryrun']: 1197 print('Create %s' % filename) 1198 filetable['added'] += [filename] 1199 if isfile(tmpfile): 1200 os.remove(tmpfile) 1201 1202 # Fetch PO files. 1203 TP_URL = 'https://translationproject.org/latest/' 1204 if not self.config['dryrun']: 1205 print('Fetching gnulib PO files from %s' % TP_URL) 1206 os.chdir(joinpath(destdir, pobase)) 1207 args = ['wget', '--no-verbose', '--mirror', '--level=1', '-nd', '-A.po', '-P', '.', 1208 '%sgnulib/' % TP_URL] 1209 sp.call(args, shell=True) 1210 else: # if self.config['dryrun'] 1211 print('Fetch gnulib PO files from %s' % TP_URL) 1212 1213 # Create po/LINGUAS. 1214 basename = joinpath(pobase, 'LINGUAS') 1215 if not self.config['dryrun']: 1216 tmpfile = self.assistant.tmpfilename(basename) 1217 data = string('# Set of available languages.\n') 1218 files = [constants.subend('.po', '', file) 1219 for file in os.listdir(joinpath(destdir, pobase))] 1220 files = [file.decode(ENCS['default']) if type(file) is bytes 1221 else file for file in files] 1222 data += '\n'.join(files) 1223 with codecs.open(tmpfile, 'wb', 'UTF-8') as file: 1224 file.write(data) 1225 filename, backup, flag = self.assistant.super_update( 1226 basename, tmpfile) 1227 if flag == 1: 1228 print('Updating %s (backup in %s)' % (filename, backup)) 1229 elif flag == 2: 1230 print('Creating %s' % filename) 1231 filetable['added'] += [filename] 1232 if isfile(tmpfile): 1233 os.remove(tmpfile) 1234 else: # if not self.config['dryrun'] 1235 backupname = '%s~' % basename 1236 if isfile(destdir, basename): 1237 print('Update %s (backup in %s)' % (basename, backupname)) 1238 else: # if not isfile(destdir, basename) 1239 print('Create %s' % basename) 1240 1241 # Create m4/gnulib-cache.m4. 1242 basename = joinpath(m4base, 'gnulib-cache.m4') 1243 tmpfile = self.assistant.tmpfilename(basename) 1244 emit = self.gnulib_cache() 1245 with codecs.open(tmpfile, 'wb', 'UTF-8') as file: 1246 file.write(emit) 1247 filename, backup, flag = self.assistant.super_update(basename, tmpfile) 1248 if flag == 1: 1249 if not self.config['dryrun']: 1250 print('Updating %s (backup in %s)' % (filename, backup)) 1251 else: # if self.config['dryrun'] 1252 print('Update %s (backup in %s)' % (filename, backup)) 1253 elif flag == 2: 1254 if not self.config['dryrun']: 1255 print('Creating %s' % filename) 1256 else: # if self.config['dryrun']: 1257 print('Create %s' % filename) 1258 if emit[-2:] == '\r\n': 1259 emit = emit[:-2] 1260 elif emit[-1:] == '\n': 1261 emit = emit[:-1] 1262 print(emit) 1263 if isfile(tmpfile): 1264 os.remove(tmpfile) 1265 1266 # Create m4/gnulib-comp.m4. 1267 basename = joinpath(m4base, 'gnulib-comp.m4') 1268 tmpfile = self.assistant.tmpfilename(basename) 1269 emit = self.gnulib_comp(filetable['all']) 1270 with codecs.open(tmpfile, 'wb', 'UTF-8') as file: 1271 file.write(emit) 1272 filename, backup, flag = self.assistant.super_update(basename, tmpfile) 1273 if flag == 1: 1274 if not self.config['dryrun']: 1275 print('Updating %s (backup in %s)' % (filename, backup)) 1276 else: # if self.config['dryrun'] 1277 print('Update %s (backup in %s)' % (filename, backup)) 1278 elif flag == 2: 1279 if not self.config['dryrun']: 1280 print('Creating %s' % filename) 1281 else: # if self.config['dryrun']: 1282 print('Create %s' % filename) 1283 if emit[-2:] == '\r\n': 1284 emit = emit[:-2] 1285 elif emit[-1:] == '\n': 1286 emit = emit[:-1] 1287 print(emit) 1288 if isfile(tmpfile): 1289 os.remove(tmpfile) 1290 1291 # Create tests Makefile. 1292 inctests = self.config.checkTestFlag(TESTS['tests']) 1293 if inctests: 1294 basename = joinpath(testsbase, makefile_am) 1295 tmpfile = self.assistant.tmpfilename(basename) 1296 emit, uses_subdirs = self.emiter.lib_Makefile_am(basename, 1297 self.moduletable['tests'], self.moduletable, self.makefiletable, 1298 actioncmd, for_test) 1299 with codecs.open(tmpfile, 'wb', 'UTF-8') as file: 1300 file.write(emit) 1301 filename, backup, flag = self.assistant.super_update( 1302 basename, tmpfile) 1303 if flag == 1: 1304 if not self.config['dryrun']: 1305 print('Updating %s (backup in %s)' % (filename, backup)) 1306 else: # if self.config['dryrun'] 1307 print('Update %s (backup in %s)' % (filename, backup)) 1308 elif flag == 2: 1309 if not self.config['dryrun']: 1310 print('Creating %s' % filename) 1311 else: # if self.config['dryrun']: 1312 print('Create %s' % filename) 1313 filetable['added'] += [filename] 1314 if isfile(tmpfile): 1315 os.remove(tmpfile) 1316 1317 # Update the .cvsignore and .gitignore files. 1318 ignorelist = list() 1319 filetable['added'] = sorted(set(filetable['added'])) 1320 filetable['removed'] = sorted(set(filetable['added'])) 1321 for file in filetable['added']: 1322 directory, basename = os.path.split(file) 1323 ignorelist += [tuple([directory, '|A|', basename])] 1324 for file in filetable['removed']: 1325 directory, basename = os.path.split(file) 1326 ignorelist += [tuple([directory, '|R|', basename])] 1327 last_dir = string() 1328 last_dirs_added = list() 1329 last_dirs_removed = list() 1330 for row in ignorelist: 1331 next_dir = row[0] 1332 operand = row[1] 1333 filename = row[2] 1334 if next_dir != last_dir: 1335 self._done_dir_(last_dir, last_dirs_added, last_dirs_removed) 1336 last_dir = next_dir 1337 last_dirs_added = list() 1338 last_dirs_removed = list() 1339 if operand == '|A|': 1340 last_dirs_added += [filename] 1341 elif operand == '|R|': 1342 last_dirs_removed += [filename] 1343 self._done_dir_(last_dir, last_dirs_added, last_dirs_removed) 1344 exit() 1345 1346 # Finish the work. 1347 print('Finished.\n') 1348 print('You may need to add #include directives \ 1349for the following .h files.') 1350 modules = sorted(set([module for module in self.moduletable['base'] 1351 if module in self.moduletable['main']])) 1352 # First the #include <...> directives without #ifs, sorted for convenience, 1353 # then the #include "..." directives without #ifs, sorted for convenience, 1354 # then the #include directives that are surrounded by #ifs. Not sorted. 1355 includes_angles = list() 1356 includes_quotes = list() 1357 includes_if = list() 1358 for module in modules: 1359 include = module.getInclude() 1360 for include in include.split('\n'): 1361 if '%s#if' % constants.NL in '%s%s' % (constants.NL, include): 1362 includes_if += [include] 1363 # if '%s#if' % constants.NL in '%s%s' % (constants.NL, include) 1364 else: 1365 if 'include "' in include: 1366 includes_quotes += [include] 1367 else: # if 'include "' not in include 1368 includes_angles += [include] 1369 includes_angles = sorted(set(includes_angles)) 1370 includes_quotes = sorted(set(includes_quotes)) 1371 includes = includes_angles + includes_quotes + includes_if 1372 includes = [include for include in includes if include.split()] 1373 for include in includes: 1374 print(' %s' % include) 1375 1376 # Get link directives. 1377 links = [module.getLink() for module in self.moduletable['main']] 1378 ulinks = list() 1379 for link in links: 1380 for lib in link: 1381 ulinks += [lib] 1382 ulinks = sorted(set(ulinks)) 1383 if ulinks: 1384 print(''' 1385You may need to use the following Makefile variables when linking. 1386Use them in <program>_LDADD when linking a program, or 1387in <library>_a_LDFLAGS or <library>_la_LDFLAGS when linking a library.''') 1388 for link in ulinks: 1389 print(' %s' % link) 1390 1391 # Print reminders. 1392 print('') 1393 print('Don\'t forget to') 1394 if makefile_am == 'Makefile.am': 1395 print(' - add "%s/Makefile" to AC_CONFIG_FILES in %s,' % 1396 (sourcebase, configure_ac)) 1397 else: # if makefile_am != 'Makefile.am' 1398 print(' - "include %s" from within "%s/Makefile.am",' % 1399 (makefile, sourcebase)) 1400 if pobase: 1401 print(' - add "%s/Makefile.in to AC_CONFIG_FILES in %s,' % 1402 (pobase, configure_ac)) 1403 if inctests: 1404 if makefile_am == 'Makefile.am': 1405 print(' - add "%s/Makefile" to AC_CONFIG_FILES in %s,' % 1406 (testsbase, configure_ac)) 1407 else: # if makefile_am != 'Makefile.am' 1408 print(' - "include %s" from within "%s/Makefile.am",' % 1409 (makefile, testsbase)) 1410 # Print makefile edits. 1411 current_edit = int() 1412 makefile_am_edits = self.makefiletable.count() 1413 while current_edit != makefile_am_edits: 1414 dictionary = self.makefiletable[current_edit] 1415 if dictionary['var']: 1416 print(' - mention "%s" in %s in %s,' % 1417 (dictionary['val'], dictionary['var'], 1418 joinpath(dictionary['dir'], 'Makefile.am'))) 1419 current_edit += 1 1420 1421 # Detect position_early_after. 1422 with codecs.open(configure_ac, 'rb', 'UTF-8') as file: 1423 data = file.read() 1424 match_result1 = \ 1425 bool(compiler('^ *AC_PROG_CC_STDC', re.S | re.M).findall(data)) 1426 match_result2 = \ 1427 bool(compiler('^ *AC_PROG_CC_C99', re.S | re.M).findall(data)) 1428 if match_result1: 1429 position_early_after = 'AC_PROG_CC_STDC' 1430 elif match_result2: 1431 position_early_after = 'AC_PROG_CC_C99' 1432 else: # if not any([match_result1, match_result2]) 1433 position_early_after = 'AC_PROG_CC' 1434 print(' - invoke %s_EARLY in %s, right after %s,' % 1435 (macro_prefix, configure_ac, position_early_after)) 1436 print(' - invoke %s_INIT in %s.' % 1437 (macro_prefix, configure_ac)) 1438 sp.call(['rm', '-rf', self.config['tempdir']], shell=False) 1439