#!/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()
