libc-config: Fix __GNUC_PREREQ macro.
[gnulib.git] / pygnulib / GLImport.py
blob4352a7ec550b969a842c19987807ea9488610b67
1 #!/usr/bin/python
2 # encoding: UTF-8
4 #===============================================================================
5 # Define global imports
6 #===============================================================================
7 import os
8 import re
9 import sys
10 import locale
11 import codecs
12 import shutil
13 import filecmp
14 import subprocess as sp
15 from . import constants
16 from .GLError import GLError
17 from .GLConfig import GLConfig
18 from .GLModuleSystem import GLModule
19 from .GLModuleSystem import GLModuleTable
20 from .GLModuleSystem import GLModuleSystem
21 from .GLFileSystem import GLFileSystem
22 from .GLFileSystem import GLFileAssistant
23 from .GLMakefileTable import GLMakefileTable
24 from .GLEmiter import GLEmiter
27 #===============================================================================
28 # Define module information
29 #===============================================================================
30 __author__ = constants.__author__
31 __license__ = constants.__license__
32 __copyright__ = constants.__copyright__
35 #===============================================================================
36 # Define global constants
37 #===============================================================================
38 PYTHON3 = constants.PYTHON3
39 NoneType = type(None)
40 APP = constants.APP
41 DIRS = constants.DIRS
42 ENCS = constants.ENCS
43 UTILS = constants.UTILS
44 MODES = constants.MODES
45 TESTS = constants.TESTS
46 compiler = constants.compiler
47 joinpath = constants.joinpath
48 cleaner = constants.cleaner
49 relpath = constants.relativize
50 string = constants.string
51 isabs = os.path.isabs
52 isdir = os.path.isdir
53 isfile = os.path.isfile
54 normpath = os.path.normpath
57 #===============================================================================
58 # Define GLImport class
59 #===============================================================================
60 class 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.'''
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)))
82 # Initialize some values.
83 self.cache = GLConfig()
84 self.config = config.copy()
85 os.rmdir(self.cache['tempdir'])
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'])
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))
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()
122 # Create regex object and keys.
123 pattern = compiler('^(gl_.*?)\\((.*?)\\)$', re.S | re.M)
124 keys = \
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',
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']))
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())
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)
233 if self.mode != MODES['import']:
234 if self.cache['m4base'] and \
235 (self.config['m4base'] != self.cache['m4base']):
236 raise(GLError(5, m4base))
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()
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))
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)
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))
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)
274 def __repr__(self):
275 '''x.__repr__ <==> repr(x)'''
276 result = '<pygnulib.GLImport %s>' % hex(id(self))
277 return(result)
279 def rewrite_old_files(self, files):
280 '''GLImport.rewrite_old_files(files) -> list
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))
326 def rewrite_new_files(self, files):
327 '''GLImport.rewrite_new_files(files)
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))
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()
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)
453 def gnulib_cache(self):
454 '''GLImport.gnulib_cache() -> string
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.
489 # Specification in the form of a command-line invocation:
490 # %s
492 # Specification in the form of a few \
493 gnulib-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))
540 def gnulib_comp(self, files):
541 '''GLImport.gnulib_comp(files) -> string
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.
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.
584 AC_DEFUN([%s_EARLY],
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".
612 AC_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 <http://lists.gnu.org/archive/html/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 \
649 abcdefghijklmnopqrstuvwxyz 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.
678 AC_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)
685 def _done_dir_(self, directory, dirs_added, dirs_removed):
686 '''GLImport._done_dir_(directory, dirs_added, dirs_removed)
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)
701 def _update_ignorelist_(self, directory, ignore, dirs_added, dirs_removed):
702 '''GLImport._update_ignorelist_(directory, ignore, dirs_added, dirs_removed)
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.move(srcpath, backupname)
730 result = string()
731 with codecs.open(srcpath, 'wb', '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)
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]))
781 # Perform transitive closure.
782 self.moduletable.setAvoids(avoids)
783 final_modules = self.moduletable.transitive_closure(base_modules)
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)
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
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)
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))
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()
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)
836 # Check license incompatibilities.
837 listing = list()
838 compatibilities = dict()
839 incompatibilities = string()
840 compatibilities['all'] = ['GPLed build tool', 'public domain', 'unlimited',
841 'unmodifiable license text']
842 compatibilities[3] = ['LGPL', 'LGPLv2+', 'LGPLv3+']
843 compatibilities[2] = ['LGPLv2+']
844 if lgpl:
845 for module in main_modules:
846 license = module.getLicense()
847 if license not in compatibilities['all']:
848 if lgpl == 3 or lgpl == True:
849 if license not in compatibilities[3]:
850 listing.append(tuple([str(module), license]))
851 elif lgpl == 2:
852 if license not in compatibilities[2]:
853 listing.append(tuple([str(module), license]))
854 if listing:
855 raise(GLError(11, listing))
857 # Print notices from modules.
858 for module in main_modules:
859 notice = module.getNotice()
860 notice = notice.strip()
861 if notice:
862 print('Notice from module %s:' % str(module))
863 pattern = compiler('^(.*?)$', re.S | re.M)
864 notice = pattern.sub(' \\1', notice)
865 print(notice)
867 # Determine script to apply to imported library files.
868 lgpl2gpl = '''
869 s/GNU Lesser General/GNU General/g
870 s/Lesser General Public License/General Public License/g
871 s/GNU Library General/GNU General/g
872 s/Library General Public License/General Public License/g
873 s/version 2\\(.1\\)\\{0,1\\}\\([ ,]\\)/version 3\\2/g'''
874 sed_transform_lib_file = string()
875 if 'config-h' in [str(module) for module in main_modules]:
876 sed_transform_lib_file += '''
877 s/^#ifdef[\t ]*HAVE_CONFIG_H[\t ]*$/#if 1/
879 sed_transform_main_lib_file = sed_transform_lib_file
880 if copyrights:
881 if lgpl: # if lgpl is enabled
882 if lgpl == 3:
883 sed_transform_main_lib_file += '''
884 s/GNU General/GNU Lesser General/g
885 s/General Public License/Lesser General Public License/g
886 s/Lesser Lesser General Public License/Lesser General Public''' \
887 + ' License/g'
888 elif lgpl == 2:
889 sed_transform_main_lib_file += '''
890 s/GNU General/GNU Lesser General/g
891 s/General Public License/Lesser General Public License/g
892 s/Lesser Lesser General Public License/Lesser General Public''' \
893 + '''License/g
894 s/version [23]\\([ ,]\\)/version 2.1\\1/g'''
895 else: # if lgpl is disabled
896 sed_transform_main_lib_file += lgpl2gpl
898 # Determine script to apply to auxiliary files that go into $auxdir/.
899 sed_transform_build_aux_file = string()
900 if copyrights:
901 sed_transform_build_aux_file += lgpl2gpl
903 # Determine script to apply to library files that go into $testsbase/.
904 sed_transform_testsrelated_lib_file = sed_transform_lib_file
905 if copyrights:
906 sed_transform_testsrelated_lib_file += lgpl2gpl
908 # Determine the final file lists.
909 main_filelist, tests_filelist = \
910 self.moduletable.filelist_separately(main_modules, tests_modules)
911 filelist = sorted(
912 set(main_filelist + tests_filelist), key=string.lower)
913 if not filelist:
914 raise(GLError(12, None))
916 # Print list of files.
917 if verbose >= 0:
918 print('File list:')
919 for file in filelist:
920 if file.startswith('tests=lib/'):
921 rest = file[10:]
922 print(' lib/%s -> tests/%s' % (rest, rest))
923 else:
924 print(' %s' % file)
926 # Prepare basic filelist and basic old_files/new_files variables.
927 filelist = sorted(set(filelist))
928 new_files = filelist + ['m4/gnulib-tool.m4']
929 old_files = list(self.cache['files'])
930 path = joinpath(destdir, m4base, 'gnulib-tool.m4')
931 if isfile(path):
932 old_files += [joinpath('m4', 'gnulib-tool.m4')]
934 # Construct tables and transformers.
935 transformers = dict()
936 transformers['lib'] = string(sed_transform_lib_file)
937 transformers['aux'] = string(sed_transform_build_aux_file)
938 transformers['main'] = string(sed_transform_main_lib_file)
939 transformers['tests'] = string(sed_transform_testsrelated_lib_file)
940 old_table = list()
941 new_table = list()
942 for src in old_files:
943 dest = self.rewrite_old_files([src])[-1]
944 old_table += [tuple([dest, src])]
945 for src in new_files:
946 dest = self.rewrite_new_files([src])[-1]
947 new_table += [tuple([dest, src])]
948 old_table = sorted(set(old_table))
949 new_table = sorted(set(new_table))
951 # Prepare the filetable.
952 filetable = dict()
953 filetable['all'] = sorted(set(filelist))
954 filetable['old'] = \
955 sorted(set(old_table), key=lambda t: tuple(t[0].lower()))
956 filetable['new'] = \
957 sorted(set(new_table), key=lambda t: tuple(t[0].lower()))
958 filetable['added'] = list()
959 filetable['removed'] = list()
961 # Return the result.
962 result = tuple([filetable, transformers])
963 return(result)
965 def execute(self, filetable, transformers):
966 '''Perform operations on the lists of files, which are given in a special
967 format except filelist argument. Such lists of files can be created using
968 GLImport.prepare() function.'''
969 if type(filetable) is not dict:
970 raise(TypeError('filetable must be a dict, not %s' %
971 type(filetable).__name__))
972 for key in ['all', 'old', 'new', 'added', 'removed']:
973 if key not in filetable:
974 raise(KeyError('filetable must contain key %s' % repr(key)))
975 destdir = self.config['destdir']
976 localdir = self.config['localdir']
977 auxdir = self.config['auxdir']
978 modules = list(self.config['modules'])
979 avoids = list(self.config['avoids'])
980 testflags = list(self.config['testflags'])
981 sourcebase = self.config['sourcebase']
982 m4base = self.config['m4base']
983 pobase = self.config['pobase']
984 docbase = self.config['docbase']
985 testsbase = self.config['testsbase']
986 lgpl = self.config['lgpl']
987 copyrights = self.config['copyrights']
988 libname = self.config['libname']
989 makefile = self.config['makefile']
990 conddeps = self.config['conddeps']
991 libtool = self.config['libtool']
992 macro_prefix = self.config['macro_prefix']
993 podomain = self.config['podomain']
994 witness_c_macro = self.config['witness_c_macro']
995 vc_files = self.config['vc_files']
996 configure_ac = self.config['configure_ac']
997 ac_version = self.config['ac_version']
998 verbose = self.config['verbosity']
999 actioncmd = self.actioncmd()
1001 # Create all necessary directories.
1002 dirs = list()
1003 if pobase:
1004 dirs += [pobase]
1005 if [file for file in filetable['all'] if file.startswith('doc/')]:
1006 dirs += [docbase]
1007 dirs += [sourcebase, m4base, auxdir]
1008 dirs += [os.path.dirname(pair[0]) for pair in filetable['new']]
1009 dirs = sorted(set([joinpath(destdir, d) for d in dirs]))
1010 for directory in dirs:
1011 if not isdir(directory):
1012 print('Creating directory %s' % directory)
1013 if not self.config['dryrun']:
1014 try: # Try to create directory
1015 os.makedirs(directory)
1016 except Exception as error:
1017 raise(GLError(13, directory))
1018 else: # if self.config['dryrun']
1019 print('Create directory %s' % directory)
1021 # Create GLFileAssistant instance to process files.
1022 self.assistant = GLFileAssistant(self.config, transformers)
1024 # Files which are in filetable['old'] and not in filetable['new'].
1025 # They will be removed and added to filetable['removed'] list.
1026 pairs = [f for f in filetable['old'] if f not in filetable['old']]
1027 pairs = sorted(set(pairs), key=lambda t: tuple(t[0].lower()))
1028 files = sorted(set(pair[0] for pair in pairs))
1029 for file in files:
1030 path = joinpath(destdir, file)
1031 if isfile(path) or os.path.islink(path):
1032 if not self.config['dryrun']:
1033 backup = string('%s~' % path)
1034 print('Removing file %s (backup in )' % (path, backup))
1035 try: # Try to move file
1036 if os.path.exists(backup):
1037 os.remove(backup)
1038 shutil.move(path, '%s~' % path)
1039 except Exception as error:
1040 raise(GLError(14, file))
1041 else: # if self.config['dryrun']
1042 print('Remove file %s (backup in %s~)' % (path, path))
1043 filetable['removed'] += [file]
1045 # Files which are in filetable['new'] and not in filetable['old'].
1046 # They will be added/updated and added to filetable['added'] list.
1047 already_present = False
1048 pairs = [f for f in filetable['new'] if f not in filetable['old']]
1049 pairs = sorted(set(pairs))
1050 for pair in pairs:
1051 original = pair[1]
1052 rewritten = pair[0]
1053 self.assistant.setOriginal(original)
1054 self.assistant.setRewritten(rewritten)
1055 self.assistant.add_or_update(already_present)
1057 # Files which are in filetable['new'] and in filetable['old'].
1058 # They will be added/updated and added to filetable['added'] list.
1059 already_present = True
1060 pairs = [f for f in filetable['new'] if f in filetable['old']]
1061 pairs = sorted(set(pairs))
1062 for pair in pairs:
1063 original = pair[1]
1064 rewritten = pair[0]
1065 self.assistant.setOriginal(original)
1066 self.assistant.setRewritten(rewritten)
1067 self.assistant.add_or_update(already_present)
1069 # Add files which were added to the list of filetable['added'].
1070 filetable['added'] += self.assistant.getFiles()
1071 filetable['added'] = sorted(set(filetable['added']))
1073 # Determine include_guard_prefix.
1074 include_guard_prefix = self.config['include_guard_prefix']
1076 # Determine makefile name.
1077 if not makefile:
1078 makefile_am = string('Makefile.am')
1079 else: # if makefile
1080 makefile_am = makefile
1082 # Create normal Makefile.ams.
1083 for_test = False
1085 # Setup list of Makefile.am edits that are to be performed afterwards.
1086 # Some of these edits apply to files that we will generate; others are
1087 # under the responsibility of the developer.
1088 makefile_am_edits = dict()
1089 if makefile_am == 'Makefile.am':
1090 sourcebase_dir = os.path.dirname(sourcebase)
1091 sourcebase_base = os.path.basename(sourcebase)
1092 self.makefiletable.editor(
1093 sourcebase_dir, 'SUBDIRS', sourcebase_base)
1094 if pobase:
1095 pobase_dir = os.path.dirname(pobase)
1096 pobase_base = os.path.basename(pobase)
1097 self.makefiletable.editor(pobase_dir, 'SUBDIRS', pobase_base)
1098 if self.config.checkTestFlag(TESTS['tests']):
1099 if makefile_am == 'Makefile.am':
1100 testsbase_dir = os.path.dirname(testsbase)
1101 testsbase_base = os.path.basename(testsbase)
1102 self.makefiletable.editor(
1103 testsbase_dir, 'SUBDIRS', testsbase_base)
1104 self.makefiletable.editor('', 'ACLOCAL_AMFLAGS', '-I %s' % m4base)
1105 self.makefiletable.parent()
1107 # Create library makefile.
1108 basename = joinpath(sourcebase, makefile_am)
1109 tmpfile = self.assistant.tmpfilename(basename)
1110 emit, uses_subdirs = self.emiter.lib_Makefile_am(basename,
1111 self.moduletable['main'], self.moduletable, self.makefiletable,
1112 actioncmd, for_test)
1113 with codecs.open(tmpfile, 'wb', 'UTF-8') as file:
1114 file.write(emit)
1115 filename, backup, flag = self.assistant.super_update(basename, tmpfile)
1116 if flag == 1:
1117 if not self.config['dryrun']:
1118 print('Updating %s (backup in %s)' % (filename, backup))
1119 else: # if self.config['dryrun']
1120 print('Update %s (backup in %s)' % (filename, backup))
1121 elif flag == 2:
1122 if not self.config['dryrun']:
1123 print('Creating %s' % filename)
1124 else: # if self.config['dryrun']:
1125 print('Create %s' % filename)
1126 filetable['added'] += [filename]
1127 if isfile(tmpfile):
1128 os.remove(tmpfile)
1130 # Create po/ directory.
1131 filesystem = GLFileSystem(self.config)
1132 if pobase:
1133 # Create po makefile and auxiliary files.
1134 for file in ['Makefile.in.in', 'remove-potcdate.sin']:
1135 tmpfile = self.assistant.tmpfilename(joinpath(pobase, file))
1136 path = joinpath('build-aux', 'po', file)
1137 lookedup, flag = filesystem.lookup(path)
1138 shutil.move(lookedup, tmpfile)
1139 basename = joinpath(pobase, file)
1140 filename, backup, flag = self.assistant.super_update(
1141 basename, tmpfile)
1142 if flag == 1:
1143 if not self.config['dryrun']:
1144 print('Updating %s (backup in %s)' %
1145 (filename, backup))
1146 else: # if self.config['dryrun']
1147 print('Update %s (backup in %s)' % (filename, backup))
1148 elif flag == 2:
1149 if not self.config['dryrun']:
1150 print('Creating %s' % filename)
1151 else: # if self.config['dryrun']:
1152 print('Create %s' % filename)
1153 filetable['added'] += [filename]
1154 if isfile(tmpfile):
1155 os.remove(tmpfile)
1157 # Create po makefile parameterization, part 1.
1158 basename = joinpath(pobase, 'Makevars')
1159 tmpfile = self.assistant.tmpfilename(basename)
1160 emit = self.emiter.po_Makevars()
1161 with codecs.open(tmpfile, 'wb', 'UTF-8') as file:
1162 file.write(emit)
1163 filename, backup, flag = self.assistant.super_update(
1164 basename, tmpfile)
1165 if flag == 1:
1166 if not self.config['dryrun']:
1167 print('Updating %s (backup in %s)' % (filename, backup))
1168 else: # if self.config['dryrun']
1169 print('Update %s (backup in %s)' % (filename, backup))
1170 elif flag == 2:
1171 if not self.config['dryrun']:
1172 print('Creating %s' % filename)
1173 else: # if self.config['dryrun']:
1174 print('Create %s' % filename)
1175 filetable['added'] += [filename]
1176 if isfile(tmpfile):
1177 os.remove(tmpfile)
1179 # Create po makefile parameterization, part 2.
1180 basename = joinpath(pobase, 'POTFILES.in')
1181 tmpfile = self.assistant.tmpfilename(basename)
1182 with codecs.open(tmpfile, 'wb', 'UTF-8') as file:
1183 file.write(self.emiter.po_POTFILES_in(filetable['all']))
1184 basename = joinpath(pobase, 'POTFILES.in')
1185 filename, backup, flag = self.assistant.super_update(
1186 basename, tmpfile)
1187 if flag == 1:
1188 if not self.config['dryrun']:
1189 print('Updating %s (backup in %s)' % (filename, backup))
1190 else: # if self.config['dryrun']
1191 print('Update %s (backup in %s)' % (filename, backup))
1192 elif flag == 2:
1193 if not self.config['dryrun']:
1194 print('Creating %s' % filename)
1195 else: # if self.config['dryrun']:
1196 print('Create %s' % filename)
1197 filetable['added'] += [filename]
1198 if isfile(tmpfile):
1199 os.remove(tmpfile)
1201 # Fetch PO files.
1202 TP_URL = 'http://translationproject.org/latest/'
1203 TP_RSYNC_URI = 'translationproject.org::tp/latest/'
1204 if not self.config['dryrun']:
1205 print('Fetching gnulib PO files from %s' % TP_URL)
1206 os.chdir(joinpath(destdir, pobase))
1207 cmd = 'type rsync 2>/dev/null | grep / > /dev/null'
1208 result = sp.call(cmd, shell=True)
1209 if result == 0: # use rsync
1210 args = ['rsync', '--delete', '--exclude', '*.s1', '-Lrtz', '%sgnulib/' % TP_RSYNC_URI, '.']
1211 result = sp.call(args, shell=True)
1212 if result != 0: # use wget
1213 args = ['wget', '--no-verbose', '--mirror', '-nd', '-np', '-A.po', '-P', '.',
1214 '%sgnulib/' % TP_URL]
1215 sp.call(args, shell=True)
1216 else: # if self.config['dryrun']
1217 print('Fetch gnulib PO files from %s' % TP_URL)
1219 # Create po/LINGUAS.
1220 basename = joinpath(pobase, 'LINGUAS')
1221 if not self.config['dryrun']:
1222 tmpfile = self.assistant.tmpfilename(basename)
1223 data = string('# Set of available languages.\n')
1224 files = [constants.subend('.po', '', file)
1225 for file in os.listdir(joinpath(destdir, pobase))]
1226 files = [file.decode(ENCS['default']) if type(file) is bytes
1227 else file for file in files]
1228 data += '\n'.join(files)
1229 with codecs.open(tmpfile, 'wb', 'UTF-8') as file:
1230 file.write(data)
1231 filename, backup, flag = self.assistant.super_update(
1232 basename, tmpfile)
1233 if flag == 1:
1234 print('Updating %s (backup in %s)' % (filename, backup))
1235 elif flag == 2:
1236 print('Creating %s' % filename)
1237 filetable['added'] += [filename]
1238 if isfile(tmpfile):
1239 os.remove(tmpfile)
1240 else: # if not self.config['dryrun']
1241 backupname = '%s~' % basename
1242 if isfile(destdir, basename):
1243 print('Update %s (backup in %s)' % (basename, backupname))
1244 else: # if not isfile(destdir, basename)
1245 print('Create %s' % basename)
1247 # Create m4/gnulib-cache.m4.
1248 basename = joinpath(m4base, 'gnulib-cache.m4')
1249 tmpfile = self.assistant.tmpfilename(basename)
1250 emit = self.gnulib_cache()
1251 with codecs.open(tmpfile, 'wb', 'UTF-8') as file:
1252 file.write(emit)
1253 filename, backup, flag = self.assistant.super_update(basename, tmpfile)
1254 if flag == 1:
1255 if not self.config['dryrun']:
1256 print('Updating %s (backup in %s)' % (filename, backup))
1257 else: # if self.config['dryrun']
1258 print('Update %s (backup in %s)' % (filename, backup))
1259 elif flag == 2:
1260 if not self.config['dryrun']:
1261 print('Creating %s' % filename)
1262 else: # if self.config['dryrun']:
1263 print('Create %s' % filename)
1264 if emit[-2:] == '\r\n':
1265 emit = emit[:-2]
1266 elif emit[-1:] == '\n':
1267 emit = emit[:-1]
1268 print(emit)
1269 if isfile(tmpfile):
1270 os.remove(tmpfile)
1272 # Create m4/gnulib-comp.m4.
1273 basename = joinpath(m4base, 'gnulib-comp.m4')
1274 tmpfile = self.assistant.tmpfilename(basename)
1275 emit = self.gnulib_comp(filetable['all'])
1276 with codecs.open(tmpfile, 'wb', 'UTF-8') as file:
1277 file.write(emit)
1278 filename, backup, flag = self.assistant.super_update(basename, tmpfile)
1279 if flag == 1:
1280 if not self.config['dryrun']:
1281 print('Updating %s (backup in %s)' % (filename, backup))
1282 else: # if self.config['dryrun']
1283 print('Update %s (backup in %s)' % (filename, backup))
1284 elif flag == 2:
1285 if not self.config['dryrun']:
1286 print('Creating %s' % filename)
1287 else: # if self.config['dryrun']:
1288 print('Create %s' % filename)
1289 if emit[-2:] == '\r\n':
1290 emit = emit[:-2]
1291 elif emit[-1:] == '\n':
1292 emit = emit[:-1]
1293 print(emit)
1294 if isfile(tmpfile):
1295 os.remove(tmpfile)
1297 # Create tests Makefile.
1298 inctests = self.config.checkTestFlag(TESTS['tests'])
1299 if inctests:
1300 basename = joinpath(testsbase, makefile_am)
1301 tmpfile = self.assistant.tmpfilename(basename)
1302 emit, uses_subdirs = self.emiter.lib_Makefile_am(basename,
1303 self.moduletable['tests'], self.moduletable, self.makefiletable,
1304 actioncmd, for_test)
1305 with codecs.open(tmpfile, 'wb', 'UTF-8') as file:
1306 file.write(emit)
1307 filename, backup, flag = self.assistant.super_update(
1308 basename, tmpfile)
1309 if flag == 1:
1310 if not self.config['dryrun']:
1311 print('Updating %s (backup in %s)' % (filename, backup))
1312 else: # if self.config['dryrun']
1313 print('Update %s (backup in %s)' % (filename, backup))
1314 elif flag == 2:
1315 if not self.config['dryrun']:
1316 print('Creating %s' % filename)
1317 else: # if self.config['dryrun']:
1318 print('Create %s' % filename)
1319 filetable['added'] += [filename]
1320 if isfile(tmpfile):
1321 os.remove(tmpfile)
1323 # Update the .cvsignore and .gitignore files.
1324 ignorelist = list()
1325 filetable['added'] = sorted(set(filetable['added']))
1326 filetable['removed'] = sorted(set(filetable['added']))
1327 for file in filetable['added']:
1328 directory, basename = os.path.split(file)
1329 ignorelist += [tuple([directory, '|A|', basename])]
1330 for file in filetable['removed']:
1331 directory, basename = os.path.split(file)
1332 ignorelist += [tuple([directory, '|R|', basename])]
1333 last_dir = string()
1334 last_dirs_added = list()
1335 last_dirs_removed = list()
1336 for row in ignorelist:
1337 next_dir = row[0]
1338 operand = row[1]
1339 filename = row[2]
1340 if next_dir != last_dir:
1341 self._done_dir_(last_dir, last_dirs_added, last_dirs_removed)
1342 last_dir = next_dir
1343 last_dirs_added = list()
1344 last_dirs_removed = list()
1345 if operand == '|A|':
1346 last_dirs_added += [filename]
1347 elif operand == '|R|':
1348 last_dirs_removed += [filename]
1349 self._done_dir_(last_dir, last_dirs_added, last_dirs_removed)
1350 exit()
1352 # Finish the work.
1353 print('Finished.\n')
1354 print('You may need to add #include directives \
1355 for the following .h files.')
1356 modules = sorted(set([module for module in self.moduletable['base']
1357 if module in self.moduletable['main']]))
1358 # First the #include <...> directives without #ifs, sorted for convenience,
1359 # then the #include "..." directives without #ifs, sorted for convenience,
1360 # then the #include directives that are surrounded by #ifs. Not sorted.
1361 includes_angles = list()
1362 includes_quotes = list()
1363 includes_if = list()
1364 for module in modules:
1365 include = module.getInclude()
1366 for include in include.split('\n'):
1367 if '%s#if' % constants.NL in '%s%s' % (constants.NL, include):
1368 includes_if += [include]
1369 # if '%s#if' % constants.NL in '%s%s' % (constants.NL, include)
1370 else:
1371 if 'include "' in include:
1372 includes_quotes += [include]
1373 else: # if 'include "' not in include
1374 includes_angles += [include]
1375 includes_angles = sorted(set(includes_angles))
1376 includes_quotes = sorted(set(includes_quotes))
1377 includes = includes_angles + includes_quotes + includes_if
1378 includes = [include for include in includes if include.split()]
1379 for include in includes:
1380 print(' %s' % include)
1382 # Get link directives.
1383 links = [module.getLink() for module in self.moduletable['main']]
1384 links = sorted(set([link for link in links if link.strip()]))
1385 if links:
1386 print('''
1387 You may need to use the following Makefile variables when linking.
1388 Use them in <program>_LDADD when linking a program, or
1389 in <library>_a_LDFLAGS or <library>_la_LDFLAGS when linking a library.''')
1390 for link in links:
1391 print(' %s' % link)
1393 # Print reminders.
1394 print('')
1395 print('Don\'t forget to')
1396 if makefile_am == 'Makefile.am':
1397 print(' - add "%s/Makefile" to AC_CONFIG_FILES in %s,' %
1398 (sourcebase, configure_ac))
1399 else: # if makefile_am != 'Makefile.am'
1400 print(' - "include %s" from within "%s/Makefile.am",' %
1401 (makefile, sourcebase))
1402 if pobase:
1403 print(' - add "%s/Makefile.in to AC_CONFIG_FILES in %s,' %
1404 (pobase, configure_ac))
1405 if inctests:
1406 if makefile_am == 'Makefile.am':
1407 print(' - add "%s/Makefile" to AC_CONFIG_FILES in %s,' %
1408 (testsbase, configure_ac))
1409 else: # if makefile_am != 'Makefile.am'
1410 print(' - "include %s" from within "%s/Makefile.am",' %
1411 (makefile, testsbase))
1412 # Print makefile edits.
1413 current_edit = int()
1414 makefile_am_edits = self.makefiletable.count()
1415 while current_edit != makefile_am_edits:
1416 dictionary = self.makefiletable[current_edit]
1417 if dictionary['var']:
1418 print(' - mention "%s" in %s in %s,' %
1419 (dictionary['val'], dictionary['var'],
1420 joinpath(dictionary['dir'], 'Makefile.am')))
1421 current_edit += 1
1423 # Detect position_early_after.
1424 with codecs.open(configure_ac, 'rb', 'UTF-8') as file:
1425 data = file.read()
1426 match_result1 = \
1427 bool(compiler('^ *AC_PROG_CC_STDC', re.S | re.M).findall(data))
1428 match_result2 = \
1429 bool(compiler('^ *AC_PROG_CC_C99', re.S | re.M).findall(data))
1430 if match_result1:
1431 position_early_after = 'AC_PROG_CC_STDC'
1432 elif match_result2:
1433 position_early_after = 'AC_PROG_CC_C99'
1434 else: # if not any([match_result1, match_result2])
1435 position_early_after = 'AC_PROG_CC'
1436 print(' - invoke %s_EARLY in %s, right after %s,' %
1437 (macro_prefix, configure_ac, position_early_after))
1438 print(' - invoke %s_INIT in %s.' %
1439 (macro_prefix, configure_ac))
1440 sp.call(['rm', '-rf', self.config['tempdir']], shell=False)