# Path: alibuild_helpers/deps.py
# def doDeps(args, parser):
# 
#   # Check if we have an output file
#   if not args.outgraph:
#     parser.error("Specify a PDF output file with --outgraph")
# 
#   # In case we are using Docker
#   dockerImage = args.dockerImage if "dockerImage" in args else ""
#   if args.docker and not dockerImage:
#     dockerImage = "alisw/%s-builder" % args.architecture.split("_")[0]
# 
#   # Resolve all the package parsing boilerplate
#   specs = {}
#   defaultsReader = lambda: readDefaults(args.configDir, args.defaults, parser.error, args.architecture)
#   (err, overrides, taps) = parseDefaults(args.disable, defaultsReader, debug)
#   with DockerRunner(dockerImage, ["--network=host"]) as getstatusoutput_docker:
#     systemPackages, ownPackages, failed, validDefaults = \
#       getPackageList(packages                = [args.package],
#                      specs                   = specs,
#                      configDir               = args.configDir,
#                      preferSystem            = args.preferSystem,
#                      noSystem                = args.noSystem,
#                      architecture            = args.architecture,
#                      disable                 = args.disable,
#                      defaults                = args.defaults,
#                      performPreferCheck      = lambda pkg, cmd: getstatusoutput_docker(cmd),
#                      performRequirementCheck = lambda pkg, cmd: getstatusoutput_docker(cmd),
#                      performValidateDefaults = lambda spec: validateDefaults(spec, args.defaults),
#                      overrides               = overrides,
#                      taps                    = taps,
#                      log                     = debug)
# 
#   dieOnError(validDefaults and args.defaults not in validDefaults,
#              "Specified default `%s' is not compatible with the packages you want to build.\n" % args.defaults +
#              "Valid defaults:\n\n- " +
#              "\n- ".join(sorted(validDefaults)))
# 
#   for s in specs.values():
#     # Remove disabled packages
#     s["requires"] = [r for r in s["requires"] if not r in args.disable and r != "defaults-release"]
#     s["build_requires"] = [r for r in s["build_requires"] if not r in args.disable and r != "defaults-release"]
#     s["runtime_requires"] = [r for r in s["runtime_requires"] if not r in args.disable and r != "defaults-release"]
# 
#   # Determine which pacakages are only build/runtime dependencies
#   all_build   = set()
#   all_runtime = set()
#   for k,spec in specs.items():
#     all_build.update(spec["build_requires"])
#     all_runtime.update(spec["runtime_requires"])
#   all_both = all_build.intersection(all_runtime)
# 
#   dot = "digraph {\n"
#   for k,spec in specs.items():
#     if k == "defaults-release":
#       continue
# 
#     # Determine node color based on its dependency status
#     color = None
#     if k in all_both:
#       color = "tomato1"
#     elif k in all_runtime:
#       color = "greenyellow"
#     elif k in all_build:
#       color = "plum"
#     elif k == args.package:
#       color = "gold"
#     else:
#       assert color, "This should not happen (happened for %s)" % k
# 
#     # Node definition
#     dot += '"%s" [shape=box, style="rounded,filled", fontname="helvetica", fillcolor=%s]\n' % (k,color)
# 
#     # Connections (different whether it's a build dependency or a runtime one)
#     for dep in spec["build_requires"]:
#      dot += '"%s" -> "%s" [color=grey70]\n' % (k, dep)
#     for dep in spec["runtime_requires"]:
#      dot += '"%s" -> "%s" [color=dodgerblue3]\n' % (k, dep)
# 
#   dot += "}\n"
# 
#   if args.outdot:
#     fp = open(args.outdot, "wt")
#   else:
#     fp = NamedTemporaryFile(delete=False, mode="wt")
#   fp.write(dot)
#   fp.close()
# 
#   try:
#     if args.neat:
#       execute(format("tred %(dotFile)s > %(dotFile)s.0 && mv %(dotFile)s.0 %(dotFile)s",
#               dotFile=fp.name))
#     execute(["dot", fp.name, "-Tpdf", "-o", args.outgraph])
#   except Exception as e:
#     error("Error generating dependencies with dot: %s: %s", type(e).__name__, e)
#   else:
#     info("Dependencies graph generated: %s" % args.outgraph)
#   if fp.name != args.outdot:
#     remove(fp.name)
#   else:
#     info("Intermediate dot file for Graphviz saved: %s" % args.outdot)
#   return True


  from unittest.mock import patch, call, MagicMock  # In Python 3, mock is built-in
  from io import StringIO
  from mock import patch, call, MagicMock  # Python 2
  from StringIO import StringIO
  from collections import OrderedDict
  from ordereddict import OrderedDict
from alibuild_helpers.deps import doDeps
from argparse import Namespace
import unittest
                                       "/dist/gcc-toolchain.sh"    : StringIO(RECIPE_GCC_TOOLCHAIN),
                                       "/dist/defaults-release.sh" : StringIO(RECIPE_DEFAULTS_RELEASE) }[f]

    class NamedStringIO(StringIO):
      name = ""
    def depsOpen(fn, mode):
      dot.name = fn
      return dot
    dot = NamedStringIO()
    mockExecute.side_effect = lambda cmd: True
    mockDepsOpen.side_effect = depsOpen

    args = Namespace(workDir="/work",
                     configDir="/dist",
                     debug=False,
                     docker=False,
                     preferSystem=[],
                     noSystem=True,
                     architecture="slc7_x86-64",
                     disable=[],
                     neat=True,
                     outdot="/tmp/out.dot",
                     outgraph="/tmp/outgraph.pdf",
                     package="AliRoot",
                     defaults="release")

    doDeps(args, MagicMock())

    # Same check without explicit intermediate dotfile
    args.outdot = None

# Path: alibuild_helpers/deps.py
# def doDeps(args, parser):
# 
#   # Check if we have an output file
#   if not args.outgraph:
#     parser.error("Specify a PDF output file with --outgraph")
# 
#   # In case we are using Docker
#   dockerImage = args.dockerImage if "dockerImage" in args else ""
#   if args.docker and not dockerImage:
#     dockerImage = "alisw/%s-builder" % args.architecture.split("_")[0]
# 
#   # Resolve all the package parsing boilerplate
#   specs = {}
#   defaultsReader = lambda: readDefaults(args.configDir, args.defaults, parser.error, args.architecture)
#   (err, overrides, taps) = parseDefaults(args.disable, defaultsReader, debug)
#   with DockerRunner(dockerImage, ["--network=host"]) as getstatusoutput_docker:
#     systemPackages, ownPackages, failed, validDefaults = \
#       getPackageList(packages                = [args.package],
#                      specs                   = specs,
#                      configDir               = args.configDir,
#                      preferSystem            = args.preferSystem,
#                      noSystem                = args.noSystem,
#                      architecture            = args.architecture,
#                      disable                 = args.disable,
#                      defaults                = args.defaults,
#                      performPreferCheck      = lambda pkg, cmd: getstatusoutput_docker(cmd),
#                      performRequirementCheck = lambda pkg, cmd: getstatusoutput_docker(cmd),
#                      performValidateDefaults = lambda spec: validateDefaults(spec, args.defaults),
#                      overrides               = overrides,
#                      taps                    = taps,
#                      log                     = debug)
# 
#   dieOnError(validDefaults and args.defaults not in validDefaults,
#              "Specified default `%s' is not compatible with the packages you want to build.\n" % args.defaults +
#              "Valid defaults:\n\n- " +
#              "\n- ".join(sorted(validDefaults)))
# 
#   for s in specs.values():
#     # Remove disabled packages
#     s["requires"] = [r for r in s["requires"] if not r in args.disable and r != "defaults-release"]
#     s["build_requires"] = [r for r in s["build_requires"] if not r in args.disable and r != "defaults-release"]
#     s["runtime_requires"] = [r for r in s["runtime_requires"] if not r in args.disable and r != "defaults-release"]
# 
#   # Determine which pacakages are only build/runtime dependencies
#   all_build   = set()
#   all_runtime = set()
#   for k,spec in specs.items():
#     all_build.update(spec["build_requires"])
#     all_runtime.update(spec["runtime_requires"])
#   all_both = all_build.intersection(all_runtime)
# 
#   dot = "digraph {\n"
#   for k,spec in specs.items():
#     if k == "defaults-release":
#       continue
# 
#     # Determine node color based on its dependency status
#     color = None
#     if k in all_both:
#       color = "tomato1"
#     elif k in all_runtime:
#       color = "greenyellow"
#     elif k in all_build:
#       color = "plum"
#     elif k == args.package:
#       color = "gold"
#     else:
#       assert color, "This should not happen (happened for %s)" % k
# 
#     # Node definition
#     dot += '"%s" [shape=box, style="rounded,filled", fontname="helvetica", fillcolor=%s]\n' % (k,color)
# 
#     # Connections (different whether it's a build dependency or a runtime one)
#     for dep in spec["build_requires"]:
#      dot += '"%s" -> "%s" [color=grey70]\n' % (k, dep)
#     for dep in spec["runtime_requires"]:
#      dot += '"%s" -> "%s" [color=dodgerblue3]\n' % (k, dep)
# 
#   dot += "}\n"
# 
#   if args.outdot:
#     fp = open(args.outdot, "wt")
#   else:
#     fp = NamedTemporaryFile(delete=False, mode="wt")
#   fp.write(dot)
#   fp.close()
# 
#   try:
#     if args.neat:
#       execute(format("tred %(dotFile)s > %(dotFile)s.0 && mv %(dotFile)s.0 %(dotFile)s",
#               dotFile=fp.name))
#     execute(["dot", fp.name, "-Tpdf", "-o", args.outgraph])
#   except Exception as e:
#     error("Error generating dependencies with dot: %s: %s", type(e).__name__, e)
#   else:
#     info("Dependencies graph generated: %s" % args.outgraph)
#   if fp.name != args.outdot:
#     remove(fp.name)
#   else:
#     info("Intermediate dot file for Graphviz saved: %s" % args.outdot)
#   return True


# Path: tests/test_deps.py
  from unittest.mock import patch, call, MagicMock  # In Python 3, mock is built-in
  from io import StringIO
  from mock import patch, call, MagicMock  # Python 2
  from StringIO import StringIO
  from collections import OrderedDict
  from ordereddict import OrderedDict
from alibuild_helpers.deps import doDeps
from argparse import Namespace
import unittest

                                       "/dist/gcc-toolchain.sh"    : StringIO(RECIPE_GCC_TOOLCHAIN),
                                       "/dist/defaults-release.sh" : StringIO(RECIPE_DEFAULTS_RELEASE) }[f]

    class NamedStringIO(StringIO):
      name = ""
    def depsOpen(fn, mode):
      dot.name = fn
      return dot
    dot = NamedStringIO()
    mockExecute.side_effect = lambda cmd: True
    mockDepsOpen.side_effect = depsOpen

    args = Namespace(workDir="/work",
                     configDir="/dist",
                     debug=False,
                     docker=False,
                     preferSystem=[],
                     noSystem=True,
                     architecture="slc7_x86-64",
                     disable=[],
                     neat=True,
                     outdot="/tmp/out.dot",
                     outgraph="/tmp/outgraph.pdf",
                     package="AliRoot",
                     defaults="release")

    doDeps(args, MagicMock())

    # Same check without explicit intermediate dotfile
    args.outdot = None

    doDeps(args, MagicMock())