Implement Bazel build

TEST PLAN:
  $ bazel test gitiles-servlet/...

Run debug version:
  $ sh {path/to/src}/tools/run_bazel_dev.sh

TODO:

 * publishing maven artifacts.
 * check out Bazel's generate_workspace.
 * intellij/eclipse project generation

Change-Id: I288011ce622536ce72c59a1961f962db9fe9e761
diff --git a/.gitignore b/.gitignore
index 60ee4e8..d68222d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,9 @@
 /.buckd
 /.idea
 *.iml
+*~
+/bazel-bin
+/bazel-genfiles
+/bazel-gitiles
+/bazel-out
+/bazel-testlogs
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 0000000..1e34b35
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,245 @@
+maven_jar(
+    name = "commons_lang",
+    artifact = "org.apache.commons:commons-lang3:3.1",
+    sha1 = "905075e6c80f206bbe6cf1e809d2caa69f420c76",
+)
+
+maven_jar(
+    name = "gson",
+    artifact = "com.google.code.gson:gson:2.7",
+    sha1 = "751f548c85fa49f330cecbb1875893f971b33c4e",
+)
+
+maven_jar(
+    name = "guava",
+    artifact = "com.google.guava:guava:19.0",
+    sha1 = "6ce200f6b23222af3d8abb6b6459e6c44f4bb0e9",
+)
+
+maven_jar(
+    name = "joda_time",
+    artifact = "joda-time:joda-time:2.9.4",
+    sha1 = "1c295b462f16702ebe720bbb08f62e1ba80da41b",
+)
+
+maven_jar(
+    name = "jsr305",
+    artifact = "com.google.code.findbugs:jsr305:3.0.0",
+    sha1 = "5871fb60dc68d67da54a663c3fd636a10a532948",
+)
+
+maven_jar(
+    name = "prettify",
+    artifact = "prettify:java-prettify:1.2.1",
+    repository = "http://gerrit-maven.storage.googleapis.com/",
+    sha1 = "29ad8d072f9d0b83d1a2e9aa6ccb0905e6d543c6",
+)
+
+COMMONMARK_VERSION = "0.6.0"
+
+# When upgrading commonmark it should also be updated in plugins/gitiles
+maven_jar(
+    name = "commonmark",
+    artifact = "com.atlassian.commonmark:commonmark:" + COMMONMARK_VERSION,
+    sha1 = "5df3f6fa3073966620685924aa22d08ece7213f2",
+)
+
+maven_jar(
+    name = "cm_autolink",
+    artifact = "com.atlassian.commonmark:commonmark-ext-autolink:" + COMMONMARK_VERSION,
+    sha1 = "4d7e828a4651e2f590b4a059925991be58e62da6",
+)
+
+maven_jar(
+    name = "autolink",
+    artifact = "org.nibor.autolink:autolink:0.5.0",
+    sha1 = "dab74ea929a5fb4c99189af18c9528faf8d5340b",
+)
+
+maven_jar(
+    name = "gfm_strikethrough",
+    artifact = "com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:" + COMMONMARK_VERSION,
+    sha1 = "75a95aaec77810496de41239bcc773adfb13285f",
+)
+
+maven_jar(
+    name = "gfm_tables",
+    artifact = "com.atlassian.commonmark:commonmark-ext-gfm-tables:" + COMMONMARK_VERSION,
+    sha1 = "ae1c701517e8116bc205b561b9b215a53df8abc7",
+)
+
+maven_jar(
+    name = "servlet_api_2_5",
+    artifact = "org.eclipse.jetty.orbit:javax.servlet:2.5.0.v201103041518",
+    sha1 = "9c16011c06bc6fe5e9dba080fcb40ddb4b75dc85",
+)
+
+maven_jar(
+    name = "servlet_api_3_0",
+    artifact = "org.eclipse.jetty.orbit:javax.servlet:3.0.0.v201112011016",
+    sha1 = "0aaaa85845fb5c59da00193f06b8e5278d8bf3f8",
+)
+
+maven_jar(
+    name = "truth",
+    artifact = "com.google.truth:truth:0.28",
+    sha1 = "0a388c7877c845ff4b8e19689dda5ac9d34622c4",
+)
+
+maven_jar(
+    name = "soy",
+    artifact = "com.google.template:soy:2016-08-09",
+    sha1 = "43d33651e95480d515fe26c10a662faafe3ad1e4",
+)
+
+maven_jar(
+    name = "icu4j",
+    artifact = "com.ibm.icu:icu4j:57.1",
+    sha1 = "198ea005f41219f038f4291f0b0e9f3259730e92",
+)
+
+JGIT_VERS = "4.5.0.201609210915-r"
+
+maven_jar(
+    name = "jgit",
+    artifact = "org.eclipse.jgit:org.eclipse.jgit:" + JGIT_VERS,
+    sha1 = "3e3d0b73dcf4ad649f37758ea8502d92f3d299de",
+)
+
+maven_jar(
+    name = "jgit_servlet",
+    artifact = "org.eclipse.jgit:org.eclipse.jgit.http.server:" + JGIT_VERS,
+    sha1 = "6e36638888918d9941dddec7e2abe1f162cc74d9",
+)
+
+maven_jar(
+    name = "jgit_junit",
+    artifact = "org.eclipse.jgit:org.eclipse.jgit.junit:" + JGIT_VERS,
+    sha1 = "e8fb1d81f588c3174a9730bdecdbde9faa04140a",
+)
+
+maven_jar(
+    name = "jgit_archive_library",
+    artifact = "org.eclipse.jgit:org.eclipse.jgit.archive:" + JGIT_VERS,
+    sha1 = "2db2e7666672a31fa41b7e1dadcba51df6d30954",
+)
+
+maven_jar(
+    name = "ewah",
+    artifact = "com.googlecode.javaewah:JavaEWAH:0.7.9",
+    sha1 = "eceaf316a8faf0e794296ebe158ae110c7d72a5a",
+)
+
+maven_jar(
+    name = "commons_compress",
+    artifact = "org.apache.commons:commons-compress:1.7",
+    sha1 = "ab365c96ee9bc88adcc6fa40d185c8e15a31410d",
+)
+
+maven_jar(
+    name = "tukaani_xz",
+    artifact = "org.tukaani:xz:1.4",
+    sha1 = "18a9a2ce6abf32ea1b5fd31dae5210ad93f4e5e3",
+)
+
+maven_jar(
+    name = "junit",
+    artifact = "junit:junit:4.11",
+    sha1 = "4e031bb61df09069aeb2bffb4019e7a5034a4ee0",
+)
+
+maven_jar(
+    name = "hamcrest_core",
+    artifact = "org.hamcrest:hamcrest-core:1.3",
+    sha1 = "42a25dc3219429f0e5d060061f71acb49bf010a0",
+)
+
+SL_VERS = "1.7.7"
+
+maven_jar(
+    name = "slf4j_api",
+    artifact = "org.slf4j:slf4j-api:" + SL_VERS,
+    sha1 = "2b8019b6249bb05d81d3a3094e468753e2b21311",
+)
+
+maven_jar(
+    name = "slf4j_simple",
+    artifact = "org.slf4j:slf4j-simple:" + SL_VERS,
+    sha1 = "8095d0b9f7e0a9cd79a663c740e0f8fb31d0e2c8",
+)
+
+GUICE_VERSION = "4.1.0"
+
+maven_jar(
+    name = "multibindings",
+    artifact = "com.google.inject.extensions:guice-multibindings:" + GUICE_VERSION,
+    sha1 = "3b27257997ac51b0f8d19676f1ea170427e86d51",
+)
+
+maven_jar(
+    name = "guice_library",
+    artifact = "com.google.inject:guice:" + GUICE_VERSION,
+    sha1 = "eeb69005da379a10071aa4948c48d89250febb07",
+)
+
+maven_jar(
+    name = "guice_assistedinject",
+    artifact = "com.google.inject.extensions:guice-assistedinject:" + GUICE_VERSION,
+    sha1 = "af799dd7e23e6fe8c988da12314582072b07edcb",
+)
+
+maven_jar(
+    name = "aopalliance",
+    artifact = "aopalliance:aopalliance:1.0",
+    sha1 = "0235ba8b489512805ac13a8f9ea77a1ca5ebe3e8",
+)
+
+maven_jar(
+    name = "javax_inject",
+    artifact = "javax.inject:javax.inject:1",
+    sha1 = "6975da39a7040257bd51d21a231b76c915872d38",
+)
+
+JETTY_VERSION = "9.2.14.v20151106"
+
+maven_jar(
+    name = "servlet",
+    artifact = "org.eclipse.jetty:jetty-servlet:" + JETTY_VERSION,
+    sha1 = "3a2cd4d8351a38c5d60e0eee010fee11d87483ef",
+)
+
+maven_jar(
+    name = "security",
+    artifact = "org.eclipse.jetty:jetty-security:" + JETTY_VERSION,
+    sha1 = "2d36974323fcb31e54745c1527b996990835db67",
+)
+
+maven_jar(
+    name = "server",
+    artifact = "org.eclipse.jetty:jetty-server:" + JETTY_VERSION,
+    sha1 = "70b22c1353e884accf6300093362b25993dac0f5",
+)
+
+maven_jar(
+    name = "continuation",
+    artifact = "org.eclipse.jetty:jetty-continuation:" + JETTY_VERSION,
+    sha1 = "8909d62fd7e28351e2da30de6fb4105539b949c0",
+)
+
+maven_jar(
+    name = "http",
+    artifact = "org.eclipse.jetty:jetty-http:" + JETTY_VERSION,
+    sha1 = "699ad1f2fa6fb0717e1b308a8c9e1b8c69d81ef6",
+)
+
+maven_jar(
+    name = "io",
+    artifact = "org.eclipse.jetty:jetty-io:" + JETTY_VERSION,
+    sha1 = "dfa4137371a3f08769820138ca1a2184dacda267",
+)
+
+maven_jar(
+    name = "util",
+    artifact = "org.eclipse.jetty:jetty-util:" + JETTY_VERSION,
+    sha1 = "0057e00b912ae0c35859ac81594a996007706a0b",
+)
diff --git a/blame-cache/BUILD b/blame-cache/BUILD
new file mode 100644
index 0000000..9b1a966
--- /dev/null
+++ b/blame-cache/BUILD
@@ -0,0 +1,13 @@
+SRCS = glob(["src/main/java/**/*.java"])
+
+DEPS = [
+    "//lib:guava",
+    "//lib/jgit:jgit",
+]
+
+java_library(
+    name = "lib",
+    srcs = SRCS,
+    visibility = ["//visibility:public"],
+    deps = DEPS,
+)
diff --git a/gitiles-dev/BUILD b/gitiles-dev/BUILD
new file mode 100644
index 0000000..3a062c7
--- /dev/null
+++ b/gitiles-dev/BUILD
@@ -0,0 +1,22 @@
+java_library(
+    name = "lib",
+    srcs = glob(["src/main/java/**/*.java"]),
+    deps = [
+        "//gitiles-servlet:servlet",
+        "//lib:guava",
+        "//lib:servlet-api_3_0",
+        "//lib/jetty:server",
+        "//lib/jetty:servlet",
+        "//lib/jgit",
+        "//lib/jgit:jgit-servlet",
+        "//lib/slf4j:slf4j-api",
+        "//lib/slf4j:slf4j-simple",
+        "//lib/soy",
+    ],
+)
+
+java_binary(
+    name = "dev",
+    main_class = "com.google.gitiles.dev.Main",
+    runtime_deps = [":lib"],
+)
diff --git a/gitiles-servlet/BUILD b/gitiles-servlet/BUILD
new file mode 100644
index 0000000..ff33933
--- /dev/null
+++ b/gitiles-servlet/BUILD
@@ -0,0 +1,84 @@
+java_library(
+    name = "servlet-api",
+    neverlink = 1,
+    exports = ["//lib:servlet-api_2_5"],
+)
+
+java_library(
+    name = "servlet",
+    srcs = glob(["src/main/java/**/*.java"]),
+    resources = glob(["src/main/resources/**/*"]),
+    visibility = ["//visibility:public"],
+    deps = [
+        ":servlet-api",
+        "//blame-cache:lib",
+        "//lib:autolink",
+        "//lib:cm-autolink",
+        "//lib:commonmark",
+        "//lib:commons-lang",
+        "//lib:gfm-strikethrough",
+        "//lib:gfm-tables",
+        "//lib:gson",
+        "//lib:guava",
+        "//lib:joda-time",
+        "//lib:jsr305",
+        "//lib:prettify",
+        "//lib/guice",
+        "//lib/jgit",
+        "//lib/jgit:jgit-archive",
+        "//lib/jgit:jgit-servlet",
+        "//lib/slf4j:slf4j-api",
+        "//lib/soy",
+    ],
+)
+
+java_library(
+    name = "testutil",
+    srcs = glob(
+        ["src/test/java/**/*.java"],
+        exclude = ["src/test/java/**/*Test.java"],
+    ) + glob(["**/ServletTest.java"]),
+    deps = [
+        ":servlet",
+        "//lib:gson",
+        "//lib:guava",
+        "//lib:servlet-api_2_5",
+        "//lib:truth",
+        "//lib/jgit",
+        "//lib/jgit:jgit-servlet",
+        "//lib/jgit:junit",
+        "//lib/junit",
+    ],
+)
+
+load("//gitiles-servlet:junit.bzl", "junit_tests")
+
+junit_tests(
+    name = "ServletTests",
+    srcs = glob(
+        [
+            "src/test/java/**/*Test.java",
+        ],
+        exclude = ["**/ServletTest.java"],
+    ),
+    runtime_deps = ["//lib/junit:hamcrest-core"],
+    deps = [
+        ":servlet",
+        ":testutil",
+        "//lib:autolink",
+        "//lib:cm-autolink",
+        "//lib:commonmark",
+        "//lib:gfm-strikethrough",
+        "//lib:gfm-tables",
+        "//lib:gson",
+        "//lib:guava",
+        "//lib:joda-time",
+        "//lib:servlet-api_2_5",
+        "//lib:truth",
+        "//lib/jgit",
+        "//lib/jgit:jgit-servlet",
+        "//lib/jgit:junit",
+        "//lib/junit",
+        "//lib/soy",
+    ],
+)
diff --git a/gitiles-servlet/junit.bzl b/gitiles-servlet/junit.bzl
new file mode 100644
index 0000000..ee79637
--- /dev/null
+++ b/gitiles-servlet/junit.bzl
@@ -0,0 +1,60 @@
+# skylark rule to generate a Junit4 TestSuite
+# Assumes srcs are all .java Test files
+# Assumes junit4 is already added to deps by the user.
+
+# See https://github.com/bazelbuild/bazel/issues/1017 for background.
+
+_OUTPUT = """import org.junit.runners.Suite;
+import org.junit.runner.RunWith;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({%s})
+public class %s {}
+"""
+
+_PREFIXES = ("org", "com", "edu")
+
+def _SafeIndex(l, val):
+    for i, v in enumerate(l):
+        if val == v:
+            return i
+    return -1
+
+def _AsClassName(fname):
+    fname = [x.path for x in fname.files][0]
+    toks = fname[:-5].split("/")
+    findex = -1
+    for s in _PREFIXES:
+        findex = _SafeIndex(toks, s)
+        if findex != -1:
+            break
+    if findex == -1:
+        fail("%s does not contain any of %s",
+                         fname, _PREFIXES)
+    return ".".join(toks[findex:]) + ".class"
+
+def _impl(ctx):
+    classes = ",".join(
+        [_AsClassName(x) for x in ctx.attr.srcs])
+    ctx.file_action(output=ctx.outputs.out, content=_OUTPUT % (
+            classes, ctx.attr.outname))
+
+_GenSuite = rule(
+    attrs = {
+        "srcs": attr.label_list(allow_files = True),
+        "outname": attr.string(),
+    },
+    outputs = {"out": "%{name}.java"},
+    implementation = _impl,
+)
+
+def junit_tests(name, srcs, **kwargs):
+    s_name = name + "TestSuite"
+    j_name = s_name + ".java",
+    _GenSuite(name=s_name,
+              srcs=srcs,
+              outname=s_name)
+    native.java_test(name=name,
+                     test_class=s_name,
+                     srcs = srcs + [":"+s_name],
+                     **kwargs)
diff --git a/lib/BUILD b/lib/BUILD
new file mode 100644
index 0000000..595854e
--- /dev/null
+++ b/lib/BUILD
@@ -0,0 +1,24 @@
+package(
+    default_visibility = ["//visibility:public"],
+)
+
+[java_library(
+    name = n,
+    exports = ["@%s//jar" % n.replace("-", "_")],
+) for n in [
+    "autolink",
+    "commonmark",
+    "commons-lang",
+    "cm-autolink",
+    "gfm-strikethrough",
+    "gfm-tables",
+    "jsr305",
+    "jgit-archive-library",
+    "joda-time",
+    "servlet-api_2_5",
+    "servlet-api_3_0",
+    "truth",
+    "gson",
+    "guava",
+    "prettify",
+]]
diff --git a/lib/guice/BUILD b/lib/guice/BUILD
new file mode 100644
index 0000000..6646fce
--- /dev/null
+++ b/lib/guice/BUILD
@@ -0,0 +1,25 @@
+package(
+    default_visibility = ["//visibility:public"],
+)
+
+java_library(
+    name = "guice",
+    exports = [
+        ":aopalliance",
+        ":guice-assistedinject",
+        ":guice_library",
+        ":javax-inject",
+        ":multibindings",
+    ],
+)
+
+[java_library(
+    name = n,
+    runtime_deps = ["@%s//jar" % n.replace("-", "_")],
+) for n in [
+    "guice_library",
+    "guice-assistedinject",
+    "multibindings",
+    "javax-inject",
+    "aopalliance",
+]]
diff --git a/lib/jetty/BUILD b/lib/jetty/BUILD
new file mode 100644
index 0000000..2c97028
--- /dev/null
+++ b/lib/jetty/BUILD
@@ -0,0 +1,55 @@
+package(
+    default_visibility = ["//visibility:public"],
+)
+
+java_library(
+    name = "servlet",
+    exports = [
+        ":security",
+        "//lib:servlet-api_3_0",  # Different from the rest of gitiles-server.
+        "@servlet//jar",
+    ],
+)
+
+java_library(
+    name = "security",
+    exports = [
+        ":server",
+        "@security//jar",
+    ],
+)
+
+java_library(
+    name = "server",
+    exports = [
+        ":continuation",
+        ":http",
+        "@server//jar",
+    ],
+)
+
+java_library(
+    name = "continuation",
+    exports = ["@continuation//jar"],
+)
+
+java_library(
+    name = "http",
+    exports = [
+        ":io",
+        "@http//jar",
+    ],
+)
+
+java_library(
+    name = "io",
+    exports = [
+        ":util",
+        "@io//jar",
+    ],
+)
+
+java_library(
+    name = "util",
+    exports = ["@util//jar"],
+)
diff --git a/lib/jgit/BUILD b/lib/jgit/BUILD
new file mode 100644
index 0000000..9fd1d4f
--- /dev/null
+++ b/lib/jgit/BUILD
@@ -0,0 +1,42 @@
+package(
+    default_visibility = ["//visibility:public"],
+)
+
+java_library(
+    name = "jgit-servlet",
+    exports = ["@jgit_servlet//jar"],
+)
+
+java_library(
+    name = "jgit",
+    exports = ["@jgit//jar"],
+)
+
+java_library(
+    name = "jgit-archive",
+    exports = [
+        ":commons-compress",
+        ":jgit-archive_library",
+        ":tukaani-xz",
+    ],
+)
+
+java_library(
+    name = "tukaani-xz",
+    exports = ["@tukaani_xz//jar"],
+)
+
+java_library(
+    name = "commons-compress",
+    exports = ["@commons_compress//jar"],
+)
+
+java_library(
+    name = "jgit-archive_library",
+    exports = ["@jgit_archive_library//jar"],
+)
+
+java_library(
+    name = "junit",
+    exports = ["@jgit_junit//jar"],
+)
diff --git a/lib/junit/BUILD b/lib/junit/BUILD
new file mode 100644
index 0000000..c2a6fcc
--- /dev/null
+++ b/lib/junit/BUILD
@@ -0,0 +1,13 @@
+package(
+    default_visibility = ["//visibility:public"],
+)
+
+java_library(
+    name = "junit",
+    exports = ["@junit//jar"],
+)
+
+java_library(
+    name = "hamcrest-core",
+    exports = ["@hamcrest_core//jar"],
+)
diff --git a/lib/slf4j/BUILD b/lib/slf4j/BUILD
new file mode 100644
index 0000000..4a27aac
--- /dev/null
+++ b/lib/slf4j/BUILD
@@ -0,0 +1,16 @@
+package(
+    default_visibility = ["//visibility:public"],
+)
+
+java_library(
+    name = "slf4j-api",
+    exports = ["@slf4j_api//jar"],
+)
+
+java_library(
+    name = "slf4j-simple",
+    runtime_deps = [
+        ":slf4j-api",
+        "@slf4j_simple//jar",
+    ],
+)
diff --git a/lib/soy/BUILD b/lib/soy/BUILD
new file mode 100644
index 0000000..4f19143
--- /dev/null
+++ b/lib/soy/BUILD
@@ -0,0 +1,9 @@
+package(
+    default_visibility = ["//visibility:public"],
+)
+
+java_library(
+    name = "soy",
+    exports = ["@soy//jar"],
+    runtime_deps = ["@icu4j//jar"],
+)
diff --git a/tools/run_bazel_dev.sh b/tools/run_bazel_dev.sh
new file mode 100755
index 0000000..57f365e
--- /dev/null
+++ b/tools/run_bazel_dev.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# Copyright 2016 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+ROOT="$(cd $(dirname "$0")/..; pwd)"
+PROPERTIES=
+if [ "x$1" != "x" ]; then
+  PROPERTIES="--jvm_flag=-Dcom.google.gitiles.configPath=$1"
+fi
+
+PROPERTIES="$PROPERTIES --jvm_flag=-Dcom.google.gitiles.sourcePath=$ROOT"
+
+(
+  cd "$ROOT"
+  bazel build gitiles-dev:dev
+)
+
+sh $ROOT/bazel-bin/gitiles-dev/dev $PROPERTIES