# Things aren't as nice in here as we'd like, but that's because
# we need to preserve how things build in the autoconf and windows
# builds for watchman.

compiler_flags = [
    "-Wunused-variable",
    "-DWATCHMAN_FACEBOOK_INTERNAL",
]

# Generates 'config.h' by probing for system capabilities
def prober():
    import os

    # We're going to extract the configured compiler from the buck config
    # and pass that down to the probe script.
    config_flags = {
      'cc': 'cc_real',
      'cppflags': 'cppflags',
      'ldflags': 'ldflags',
    }

    probe_cmd = [
        'python',
        '$SRCDIR/probe.py',
        '--configure=$SRCDIR/configure.ac',
        '--cwd=%s' % os.getcwd()]

    for name, key in config_flags.iteritems():
        val = read_config('cxx', key)
        probe_cmd.append("--%s='%s'" % (name, val))

    probe_cmd.append('> $OUT')

    buck_genrule(
        name='generate_config_h',
        srcs=[
            'probe.py',
            'configure.ac',
        ],
        cmd=' '.join(probe_cmd),
        out='config.h',
    )

def config_h():
    # we use this same convention in the eden build to discover whether
    # we are building in the internal fb repo or in the opensourced project(s).
    if read_config('codebase', 'mode') == 'public':
        prober()
    else:
        # Just copy the pre-configured linux attributes so that we have
        # know precisely what the characteristics will be for this build.
        buck_genrule(
            name='generate_config_h',
            srcs=['facebook/linux_config.h'],
            cmd='cp $SRCDIR/facebook/linux_config.h $OUT',
            out='config.h',
        )

config_h()

# Wraps the generated config.h file in a library rule that we can
# depend upon.
buck_cxx_library(
    name = "config_h",
    header_namespace = "",
    exported_headers = [
        ":generate_config_h",
    ],
    visibility = ["PUBLIC"],
)

# Exports all watchman headers without the 'watchman/' prefix that
# they would otherwise have in our build tree.
buck_cxx_library(
    name = "headers",
    header_namespace = "",
    exported_headers = glob(["**/*.h"]),
    exported_deps = [
        ":config_h",
        "//common/base:build_info",
        "//watchman/thirdparty/jansson:config_h",
    ],
    visibility = ["PUBLIC"],
)

cpp_library(
    name = "eden_watcher",
    srcs = [
        "watcher/eden.cpp",
    ],
    compiler_flags = compiler_flags,
    # We use constructors to declare commands rather than maintaining
    # static tables of things.  Ensure that they don't get stripped
    # out of the final binary!
    link_whole = True,
    supported_platforms_regex = "glibc",
    deps = [
        ":err",
        ":headers",
        "@/eden/fs/service:thrift-streaming-cpp2",
    ],
)

# Linux specific watcher module
cpp_library(
    name = "sysdep_watcher",
    srcs = ["watcher/inotify.cpp"],
    compiler_flags = compiler_flags,
    # We use constructors to declare commands rather than maintaining
    # static tables of things.  Ensure that they don't get stripped
    # out of the final binary!
    link_whole = True,
    supported_platforms_regex = "glibc",
    deps = [
        ":eden_watcher",
        ":err",
        ":headers",
    ],
)

# mac specific watcher module
cpp_library(
    name = "sysdep_watcher",
    srcs = [
        "watcher/fsevents.cpp",
        "watcher/kqueue.cpp",
    ],
    compiler_flags = compiler_flags,
    # We use constructors to declare commands rather than maintaining
    # static tables of things.  Ensure that they don't get stripped
    # out of the final binary!
    link_whole = True,
    supported_platforms_regex = "macos",
    deps = [":headers"],
)

# windows specific watcher module
cpp_library(
    name = "sysdep_watcher",
    srcs = ["watcher/win32.cpp"],
    compiler_flags = compiler_flags,
    # We use constructors to declare commands rather than maintaining
    # static tables of things.  Ensure that they don't get stripped
    # out of the final binary!
    link_whole = True,
    supported_platforms_regex = "windows",
    deps = [":headers"],
)

cpp_library(
    name = "log",
    srcs = [
        "PubSub.cpp",
        "log.cpp",
    ],
    compiler_flags = compiler_flags,
    deps = [
        ":headers",
        "@/watchman/thirdparty/jansson:jansson",
    ],
)

cpp_library(
    name = "hash",
    srcs = ["hash.cpp"],
    compiler_flags = compiler_flags,
    deps = [":headers"],
)

cpp_library(
    name = "string",
    srcs = ["string.cpp"],
    compiler_flags = compiler_flags,
    deps = [
        ":hash",
        ":headers",
        "@/watchman/thirdparty/jansson:utf",
    ],
)

cpp_library(
    name = "err",
    srcs = [
        "root/poison.cpp",
        "root/warnerr.cpp",
    ],
    compiler_flags = compiler_flags,
    deps = [":headers"],
)

cpp_library(
    name = "pcre",
    srcs = ["query/pcre.cpp"],
    compiler_flags = ["-DHAVE_PCRE_H"] + compiler_flags,
    link_whole = True,
    deps = [":headers"],
    external_deps = ["pcre"],
)

cpp_library(
    name = "testsupport",
    srcs = [
        "ChildProcess.cpp",
        "FileDescriptor.cpp",
        "FileInformation.cpp",
        "Pipe.cpp",
        "ThreadPool.cpp",
        "bser.cpp",
        "cfg.cpp",
        "expflags.cpp",
        "ignore.cpp",
        "opendir.cpp",
        "pending.cpp",
        "time.cpp",
    ],
    compiler_flags = compiler_flags,
    deps = [
        ":headers",
        ":log",
        ":string",
        "@/watchman/thirdparty/jansson:jansson",
        "@/watchman/thirdparty/libart/src:art",
    ],
)

# The bulk of the watchman implementation lives in this library
cpp_library(
    name = "watchmanlib",
    srcs = glob(
        [
            "*.cpp",
            "query/*.cpp",
            "watcher/auto.cpp",
            "root/*.cpp",
            "cmds/*.cpp",
            "scm/*.cpp",
        ],
        excludes = [
            "main.cpp",
            "stream_win.cpp",
            "log.cpp",
            "query/pcre.cpp",
            "root/warnerr.cpp",
            "root/poison.cpp",
        ],
    ),
    compiler_flags = compiler_flags,
    # We use constructors to declare commands rather than maintaining
    # static tables of things.  Ensure that they don't get stripped
    # out of the final binary!
    link_whole = True,
    deps = [
        ":err",
        ":headers",
        ":log",
        ":pcre",
        ":string",
        ":sysdep_watcher",
        "@/watchman/thirdparty/jansson:jansson",
        "@/watchman/thirdparty/libart/src:art",
        "@/watchman/thirdparty/wildmatch:wildmatch",
    ],
)

# and the watchman binary itself
cpp_binary(
    name = "watchman",
    srcs = ["main.cpp"],
    compiler_flags = compiler_flags,
    deps = [
        ":headers",
        ":watchmanlib",
    ],
)

# This is the custom test runner used by the open source build.
python_library(
    name = "runtests",
    srcs = ["runtests.py"],
    py_version = "<3",
    deps = [
        ":watchman",
        "@/watchman/tests/integration:testlib",
    ],
)

python_library(
    name = "runtests-py3",
    srcs = ["runtests.py"],
    py_version = ">=3.5",
    deps = [
        ":watchman",
        "@/watchman/tests/integration:testlib-py3",
    ],
)
