DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (27a812186ff4)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

# This script is used to capture the content of config.status-generated
# files and subsequently restore their timestamp if they haven't changed.

import os
import re
import subprocess
import sys
import pickle

class File(object):
    def __init__(self, path):
        self._path = path
        self._content = open(path, 'rb').read()
        stat = os.stat(path)
        self._times = (stat.st_atime, stat.st_mtime)

    @property
    def path(self):
        return self._path

    @property
    def mtime(self):
        return self._times[1]

    def update_time(self):
        '''If the file hasn't changed since the instance was created,
           restore its old modification time.'''
        if not os.path.exists(self._path):
            return
        if open(self._path, 'rb').read() == self._content:
            os.utime(self._path, self._times)


# As defined in the various sub-configures in the tree
PRECIOUS_VARS = set([
    'build_alias',
    'host_alias',
    'target_alias',
    'CC',
    'CFLAGS',
    'LDFLAGS',
    'LIBS',
    'CPPFLAGS',
    'CPP',
    'CCC',
    'CXXFLAGS',
    'CXX',
    'CCASFLAGS',
    'CCAS',
])


# Autoconf, in some of the sub-configures used in the tree, likes to error
# out when "precious" variables change in value. The solution it gives to
# straighten things is to either run make distclean or remove config.cache.
# There's no reason not to do the latter automatically instead of failing,
# doing the cleanup (which, on buildbots means a full clobber), and
# restarting from scratch.
def maybe_clear_cache():
    comment = re.compile(r'^\s+#')
    cache = {}
    with open('config.cache') as f:
        for line in f.readlines():
            if not comment.match(line) and '=' in line:
                key, value = line.split('=', 1)
                cache[key] = value
    for precious in PRECIOUS_VARS:
        entry = 'ac_cv_env_%s_value' % precious
        if entry in cache and (not precious in os.environ or os.environ[precious] != cache[entry]):
            os.remove('config.cache')
            return


def dump(dump_file, shell):
    if os.path.exists('config.cache'):
        maybe_clear_cache()
    if not os.path.exists('config.status'):
        if os.path.exists(dump_file):
            os.remove(dump_file)
        return

    config_files = [File('config.status')]

    # Scan the config.status output for information about configuration files
    # it generates.
    config_status_output = subprocess.check_output(
        [shell, '-c', './config.status --help'],
        stderr=subprocess.STDOUT).splitlines()
    state = None
    for line in config_status_output:
        if line.startswith('Configuration') and line.endswith(':'):
            state = 'config'
        elif not line.startswith(' '):
            state = None
        elif state == 'config':
            for f in (couple.split(':')[0] for couple in line.split()):
                if os.path.isfile(f):
                    config_files.append(File(f))

    with open(dump_file, 'wb') as f:
        pickle.dump(config_files, f)


def adjust(dump_file, configure):
    if not os.path.exists(dump_file):
        return

    config_files = []

    try:
        with open(dump_file, 'rb') as f:
            config_files = pickle.load(f)
    except Exception:
        pass

    for f in config_files:
        # Still touch config.status if configure is newer than its original
        # mtime.
        if configure and os.path.basename(f.path) == 'config.status' and \
                os.path.getmtime(configure) > f.mtime:
            continue
        f.update_time()

    os.remove(dump_file)


CONFIG_DUMP = 'config_files.pkl'

if __name__ == '__main__':
    if sys.argv[1] == 'dump':
        dump(CONFIG_DUMP, sys.argv[2])
    elif sys.argv[1] == 'adjust':
        adjust(CONFIG_DUMP, sys.argv[2] if len(sys.argv) > 2 else None)