build/subconfigure.py

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

michael@0 1 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 4
michael@0 5 # This script is used to capture the content of config.status-generated
michael@0 6 # files and subsequently restore their timestamp if they haven't changed.
michael@0 7
michael@0 8 import os
michael@0 9 import re
michael@0 10 import subprocess
michael@0 11 import sys
michael@0 12 import pickle
michael@0 13
michael@0 14 class File(object):
michael@0 15 def __init__(self, path):
michael@0 16 self._path = path
michael@0 17 self._content = open(path, 'rb').read()
michael@0 18 stat = os.stat(path)
michael@0 19 self._times = (stat.st_atime, stat.st_mtime)
michael@0 20
michael@0 21 @property
michael@0 22 def path(self):
michael@0 23 return self._path
michael@0 24
michael@0 25 @property
michael@0 26 def mtime(self):
michael@0 27 return self._times[1]
michael@0 28
michael@0 29 def update_time(self):
michael@0 30 '''If the file hasn't changed since the instance was created,
michael@0 31 restore its old modification time.'''
michael@0 32 if not os.path.exists(self._path):
michael@0 33 return
michael@0 34 if open(self._path, 'rb').read() == self._content:
michael@0 35 os.utime(self._path, self._times)
michael@0 36
michael@0 37
michael@0 38 # As defined in the various sub-configures in the tree
michael@0 39 PRECIOUS_VARS = set([
michael@0 40 'build_alias',
michael@0 41 'host_alias',
michael@0 42 'target_alias',
michael@0 43 'CC',
michael@0 44 'CFLAGS',
michael@0 45 'LDFLAGS',
michael@0 46 'LIBS',
michael@0 47 'CPPFLAGS',
michael@0 48 'CPP',
michael@0 49 'CCC',
michael@0 50 'CXXFLAGS',
michael@0 51 'CXX',
michael@0 52 'CCASFLAGS',
michael@0 53 'CCAS',
michael@0 54 ])
michael@0 55
michael@0 56
michael@0 57 # Autoconf, in some of the sub-configures used in the tree, likes to error
michael@0 58 # out when "precious" variables change in value. The solution it gives to
michael@0 59 # straighten things is to either run make distclean or remove config.cache.
michael@0 60 # There's no reason not to do the latter automatically instead of failing,
michael@0 61 # doing the cleanup (which, on buildbots means a full clobber), and
michael@0 62 # restarting from scratch.
michael@0 63 def maybe_clear_cache():
michael@0 64 comment = re.compile(r'^\s+#')
michael@0 65 cache = {}
michael@0 66 with open('config.cache') as f:
michael@0 67 for line in f.readlines():
michael@0 68 if not comment.match(line) and '=' in line:
michael@0 69 key, value = line.split('=', 1)
michael@0 70 cache[key] = value
michael@0 71 for precious in PRECIOUS_VARS:
michael@0 72 entry = 'ac_cv_env_%s_value' % precious
michael@0 73 if entry in cache and (not precious in os.environ or os.environ[precious] != cache[entry]):
michael@0 74 os.remove('config.cache')
michael@0 75 return
michael@0 76
michael@0 77
michael@0 78 def dump(dump_file, shell):
michael@0 79 if os.path.exists('config.cache'):
michael@0 80 maybe_clear_cache()
michael@0 81 if not os.path.exists('config.status'):
michael@0 82 if os.path.exists(dump_file):
michael@0 83 os.remove(dump_file)
michael@0 84 return
michael@0 85
michael@0 86 config_files = [File('config.status')]
michael@0 87
michael@0 88 # Scan the config.status output for information about configuration files
michael@0 89 # it generates.
michael@0 90 config_status_output = subprocess.check_output(
michael@0 91 [shell, '-c', './config.status --help'],
michael@0 92 stderr=subprocess.STDOUT).splitlines()
michael@0 93 state = None
michael@0 94 for line in config_status_output:
michael@0 95 if line.startswith('Configuration') and line.endswith(':'):
michael@0 96 state = 'config'
michael@0 97 elif not line.startswith(' '):
michael@0 98 state = None
michael@0 99 elif state == 'config':
michael@0 100 for f in (couple.split(':')[0] for couple in line.split()):
michael@0 101 if os.path.isfile(f):
michael@0 102 config_files.append(File(f))
michael@0 103
michael@0 104 with open(dump_file, 'wb') as f:
michael@0 105 pickle.dump(config_files, f)
michael@0 106
michael@0 107
michael@0 108 def adjust(dump_file, configure):
michael@0 109 if not os.path.exists(dump_file):
michael@0 110 return
michael@0 111
michael@0 112 config_files = []
michael@0 113
michael@0 114 try:
michael@0 115 with open(dump_file, 'rb') as f:
michael@0 116 config_files = pickle.load(f)
michael@0 117 except Exception:
michael@0 118 pass
michael@0 119
michael@0 120 for f in config_files:
michael@0 121 # Still touch config.status if configure is newer than its original
michael@0 122 # mtime.
michael@0 123 if configure and os.path.basename(f.path) == 'config.status' and \
michael@0 124 os.path.getmtime(configure) > f.mtime:
michael@0 125 continue
michael@0 126 f.update_time()
michael@0 127
michael@0 128 os.remove(dump_file)
michael@0 129
michael@0 130
michael@0 131 CONFIG_DUMP = 'config_files.pkl'
michael@0 132
michael@0 133 if __name__ == '__main__':
michael@0 134 if sys.argv[1] == 'dump':
michael@0 135 dump(CONFIG_DUMP, sys.argv[2])
michael@0 136 elif sys.argv[1] == 'adjust':
michael@0 137 adjust(CONFIG_DUMP, sys.argv[2] if len(sys.argv) > 2 else None)

mercurial