#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import print_function

"""
Simple script to test cyclical dependencies in modules.

Requirements:
    - SnakeFood (pip install snakefood)
    - NetworkX (yum/apt-get install python-networkx)
"""

__author__ = 'Ruda Moura <rmoura@redhat.com>'

import os
import sys
import subprocess
import tempfile

# it doesn't make sense to go any further on Python 3 because snakefood
# won't be available anyway.  it's not fair to say this check failed, so
# let's exit successfully.  the check should be performend when running
# on Python 2.
if sys.version_info[0] == 3:
    sys.exit(0)


try:
    import networkx as nx
except ImportError:
    print("NetworkX is not installed and is required!", file=sys.stderr)
    print("Please, install 'python-networkx' with yum or apt.", file=sys.stderr)
    sys.exit(2)

# simple magic for using scripts within a source tree
basedir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if os.path.isdir(os.path.join(basedir, 'avocado')):
    os.environ['PATH'] += ":" + os.path.join(basedir, 'scripts')
    os.environ['PATH'] += ":" + os.path.join(basedir, 'libexec')
    sys.path.append(basedir)

from avocado.utils import process


def has_snakefood():
    with open(os.devnull, 'w') as null:
        try:
            cmd = ['sfood', '-h']
            subprocess.call(cmd, stdout=null)
        except Exception as e:
            print("Could not find sfood utility: %s: %s" % (cmd, e), file=sys.stderr)
            print("Did you forget to 'pip install snakefood'?", file=sys.stderr)
            return False
    return True


def generate_dot_file(path):
    cmdline = 'sfood --internal %s | sfood-graph --remove-extensions'
    output = process.system_output(cmdline % path, shell=True)
    tmp = tempfile.mktemp()
    with open(tmp, 'w') as sfood_file:
        sfood_file.write(output)
    return tmp


def cyclical_deps(path_dot):
    graph = nx.DiGraph(nx.nx_agraph.read_dot(path_dot))

    cycles = list(nx.simple_cycles(graph))
    if cycles:
        print('Found cyclical dependencies in module(s):')
        for cycle in cycles:
            print('*', ' <=> '.join(cycle))
        return True
    else:
        print('No cyclical dependencies found')
        print('OK')
        return False


if __name__ == '__main__':
    if sys.argv[1:] and has_snakefood():
        dot = generate_dot_file(sys.argv[1])
        has_cycles = cyclical_deps(dot)
        os.remove(dot)
        if has_cycles:
            sys.exit(1)
    else:
        sys.exit(2)
    sys.exit(0)
