load("//tools/skylark:cc.bzl", "cc_library")
load("//tools/workspace:generate_file.bzl", "generate_file")

def cc_library_vendored(
        name,
        hdrs = None,
        hdrs_vendored = None,
        srcs = None,
        srcs_vendored = None,
        vendor_tool_args = None,
        **kwargs):
    """
    Compiles a third-party C++ library using altered include paths and
    namespaces so that it will not interfere with co-habitating builds
    of the same library by others.

    The lists of hdrs and hdrs_vendored paths must be equal in length and
    correspond as elementwise pairs. The hdrs gives the list of library
    header file paths as found in the third-party source layout; the
    hdrs_vendored gives the list of header file paths to use for Drake's
    vendored build. Typically we will prefix "drake_vendor/" to the path.

    The lists of srcs and srcs_vendored paths must be equal in length and
    correspond as elementwise pairs. The srcs gives the list of library
    source file paths as found in the third-party source layout; the
    srcs_vendored gives the list of source file paths to use for Drake's
    vendored build.
    """
    hdrs = hdrs or []
    hdrs_vendored = hdrs_vendored or []
    srcs = srcs or []
    srcs_vendored = srcs_vendored or []
    if len(hdrs) != len(hdrs_vendored):
        fail("The hdrs= and hdrs_vendored= list lengths must match")
    if len(srcs) != len(srcs_vendored):
        fail("The srcs= and srcs_vendored= list lengths must match")
    native.genrule(
        name = "_{}_vendoring".format(name),
        srcs = hdrs + srcs,
        outs = hdrs_vendored + srcs_vendored,
        cmd = " ".join([
            "$(execpath @drake//tools/workspace:vendor_cxx)",
        ] + (vendor_tool_args or []) + [
            "$(execpath {}):$(execpath {})".format(old, new)
            for old, new in (zip(hdrs, hdrs_vendored) +
                             zip(srcs, srcs_vendored))
        ]),
        tools = ["@drake//tools/workspace:vendor_cxx"],
        tags = ["manual"],
        visibility = ["//visibility:private"],
    )
    cc_library(
        name = name,
        hdrs = hdrs_vendored,
        srcs = srcs_vendored,
        **kwargs
    )

def generate_vendor_patch(name, srcs, srcs_vendored, extra_prologue = None):
    """
    Creates a patch file named `name` that encompasses the differences beteween
    `srcs` and `srcs_vendored`.
    """
    if len(srcs) != len(srcs_vendored):
        fail("The srcs= and srcs_vendored= list lengths must match")
    for upstream_src, vendor_src in zip(srcs, srcs_vendored):
        native.genrule(
            name = "_generate_{}.patch".format(vendor_src),
            srcs = [upstream_src, vendor_src],
            outs = [vendor_src + ".patch"],
            cmd = " ".join([
                "(diff -U0",
                "--label={upstream_src} $(execpath {upstream_src})",
                "--label={vendor_src} $(execpath {vendor_src})",
                "> $@ || [[ $$? == 1 ]])",
            ]).format(
                upstream_src = upstream_src,
                vendor_src = vendor_src,
            ),
        )
    prologue = """
This patch was automatically generated by Drake's vendor_cxx.py tool. It shows
the edits made by Drake's build system to adjust the namespace of the software.
""" + (extra_prologue or "")
    generate_file(
        name = "_prologue_{}".format(name),
        content = prologue.strip() + "\n\n",
    )
    native.genrule(
        name = "_generate_{}".format(name),
        srcs = [
            ":_prologue_{}".format(name),
        ] + [
            vendor_src + ".patch"
            for vendor_src in srcs_vendored
        ],
        outs = [name],
        cmd = "cat $(SRCS) > $@",
    )
