#!/usr/bin/env python # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import subprocess import os import argparse import logging ROOT_DIR = os.path.abspath(os.path.join(__file__, os.pardir, os.pardir, os.pardir)) # Where to cache GN results (they're expensive to compute). GN_CACHE_PATH = os.path.abspath(os.path.join(ROOT_DIR, 'in_gn.txt')) def stripped_lines_from_command(cmd, cwd=None): lines = subprocess.check_output(cmd, cwd=cwd).splitlines() return map(str.strip, lines) def gn_desc(*args): # GN doesn't understand absolute paths yet, so use a relative BUILD_DIR # and pass ROOT_DIR as the CWD. # Hard-coding Debug for now: BUILD_DIR = '//out/Debug' # // means repository root-relative. cmd = ['gn', 'desc', BUILD_DIR] + list(args) return stripped_lines_from_command(cmd, cwd=ROOT_DIR) def targets_under(target): targets = gn_desc(target, 'deps', '--all') return filter(lambda s: s.startswith(target), targets) def used_files(target): logging.info(target) sources = map(lambda s: s[2:], gn_desc(target, 'sources')) inputs = map(lambda s: s[2:], gn_desc(target, 'inputs')) public = map(lambda s: s[2:], gn_desc(target, 'public')) script = map(lambda s: s[2:], gn_desc(target, 'script')) return sources + inputs + public + script def find_on_disk(path): # FIXME: Use os.walk and do fancier ignoring. find_cmd = ['find', path, '-type', 'f'] return stripped_lines_from_command(find_cmd, cwd=ROOT_DIR) def main(): logging.basicConfig(level=logging.INFO) if os.path.exists(GN_CACHE_PATH): logging.info('Using cached GN list: %s' % GN_CACHE_PATH) in_gn = set(map(str.strip, open(GN_CACHE_PATH).readlines())) else: logging.info('No gn cache found, rebuilding: %s' % GN_CACHE_PATH) in_gn = set(sum(map(used_files, targets_under('//sky')), [])) open(GN_CACHE_PATH, 'w+').write('\n'.join(in_gn)) on_disk = set(find_on_disk('sky/engine')) # Ignore web/tests and bindings/tests on_disk = set(filter(lambda p: '/tests/' not in p, on_disk)) missing_from_gn = sorted(on_disk - in_gn) IGNORED_EXTENSIONS = [ '.py', # Probably some to remove, probably some to teach gn about. # Python files not being known to gn can cause flaky builds too! '.pyc', '.gypi', '.gn', '.gni', ] for ext in IGNORED_EXTENSIONS: missing_from_gn = filter(lambda p: not p.endswith(ext), missing_from_gn) # All upper-case files like README, DEPS, etc. are fine. missing_from_gn = filter(lambda p: not os.path.basename(p).isupper(), missing_from_gn) print '\n'.join(missing_from_gn) if __name__ == '__main__': main()