#!/usr/bin/python
# Copyright (c) 2012 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.

"""Diagnose some common system configuration problems on Linux, and
suggest fixes."""

import os
import subprocess
import sys

all_checks = []

def Check(name):
    """Decorator that defines a diagnostic check."""
    def wrap(func):
        all_checks.append((name, func))
        return func
    return wrap


@Check("/usr/bin/ld is not gold")
def CheckSystemLd():
    proc = subprocess.Popen(['/usr/bin/ld', '-v'], stdout=subprocess.PIPE)
    stdout = proc.communicate()[0]
    if 'GNU gold' in stdout:
        return ("When /usr/bin/ld is gold, system updates can silently\n"
                "corrupt your graphics drivers.\n"
                "Try 'sudo apt-get remove binutils-gold'.\n")
    return None


@Check("random lds are not in the $PATH")
def CheckPathLd():
    proc = subprocess.Popen(['which', '-a', 'ld'], stdout=subprocess.PIPE)
    stdout = proc.communicate()[0]
    instances = stdout.split()
    if len(instances) > 1:
        return ("You have multiple 'ld' binaries in your $PATH:\n"
                + '\n'.join(' - ' + i for i in instances) + "\n"
                "You should delete all of them but your system one.\n"
                "gold is hooked into your build via gyp.\n")
    return None


@Check("/usr/bin/ld doesn't point to gold")
def CheckLocalGold():
    # Check /usr/bin/ld* symlinks.
    for path in ('ld.bfd', 'ld'):
        path = '/usr/bin/' + path
        try:
            target = os.readlink(path)
        except OSError, e:
            if e.errno == 2:
                continue  # No such file
            if e.errno == 22:
                continue  # Not a symlink
            raise
        if '/usr/local/gold' in target:
            return ("%s is a symlink into /usr/local/gold.\n"
                    "It's difficult to make a recommendation, because you\n"
                    "probably set this up yourself.  But you should make\n"
                    "/usr/bin/ld be the standard linker, which you likely\n"
                    "renamed /usr/bin/ld.bfd or something like that.\n" % path)

    return None


@Check("random ninja binaries are not in the $PATH")
def CheckPathNinja():
    proc = subprocess.Popen(['which', 'ninja'], stdout=subprocess.PIPE)
    stdout = proc.communicate()[0]
    if not 'depot_tools' in stdout:
        return ("The ninja binary in your path isn't from depot_tools:\n"
                + "    " + stdout +
                "Remove custom ninjas from your path so that the one\n"
                "in depot_tools is used.\n")
    return None


@Check("build dependencies are satisfied")
def CheckBuildDeps():
    script_path = os.path.join(
        os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'build',
        'install-build-deps.sh')
    proc = subprocess.Popen([script_path, '--quick-check'],
                            stdout=subprocess.PIPE)
    stdout = proc.communicate()[0]
    if 'WARNING' in stdout:
        return ("Your build dependencies are out-of-date.\n"
                "Run '" + script_path + "' to update.")
    return None


def RunChecks():
    for name, check in all_checks:
        sys.stdout.write("* Checking %s: " % name)
        sys.stdout.flush()
        error = check()
        if not error:
            print "ok"
        else:
            print "FAIL"
            print error


if __name__ == '__main__':
    RunChecks()
