Add interfaces for the build event protocol

Bazel in the will provide a machine-readable stream of important build
events. These interfaces set up the framework and expectations about
the produced events and the entities distributing those events.

--
Change-Id: If2c3b2e11c31b0136b57eadeef2d2f8f8fe5e2e7
Reviewed-on: https://bazel-review.googlesource.com/#/c/6272
MOS_MIGRATED_REVID=134522369
diff --git a/scripts/bootstrap/compile.sh b/scripts/bootstrap/compile.sh
index a5141e8..f4939c1 100755
--- a/scripts/bootstrap/compile.sh
+++ b/scripts/bootstrap/compile.sh
@@ -16,7 +16,7 @@
 
 # Script for building bazel from scratch without bazel
 
-PROTO_FILES=$(ls src/main/protobuf/*.proto)
+PROTO_FILES=$(ls src/main/protobuf/*.proto src/main/java/com/google/devtools/build/lib/buildeventstream/proto/*.proto)
 LIBRARY_JARS=$(find third_party -name '*.jar' | grep -Fv /javac.jar | grep -Fv /javac7.jar | grep -Fv JavaBuilder | grep -ve third_party/grpc/grpc.*jar | tr "\n" " ")
 GRPC_JAVA_VERSION=0.15.0
 GRPC_LIBRARY_JARS=$(find third_party/grpc -name '*.jar' | grep -e .*${GRPC_JAVA_VERSION}.*jar | tr "\n" " ")
@@ -180,7 +180,9 @@
 if [ -z "${BAZEL_SKIP_JAVA_COMPILATION}" ]; then
   log "Compiling Java stubs for protocol buffers..."
   for f in $PROTO_FILES ; do
-    run "${PROTOC}" -Isrc/main/protobuf/ --java_out=${OUTPUT_DIR}/src \
+    run "${PROTOC}" -Isrc/main/protobuf/ \
+        -Isrc/main/java/com/google/devtools/build/lib/buildeventstream/proto/ \
+        --java_out=${OUTPUT_DIR}/src \
         --plugin=protoc-gen-grpc="${GRPC_JAVA_PLUGIN-}" \
         --grpc_out=${OUTPUT_DIR}/src "$f"
   done
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 244ec20..eb7c8d7 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -294,6 +294,18 @@
     ],
 )
 
+# External build-event reporting infrastructure
+java_library(
+    name = "buildeventstream",
+    srcs = glob(["buildeventstream/*.java"]),
+    deps = [
+        "//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
+        "//src/main/java/com/google/devtools/build/lib/cmdline",
+        "//third_party:jsr305",
+        "//third_party/protobuf",
+    ],
+)
+
 ########################################################################
 #
 # The "foundation" library (concurrent, events, util, vfs, inmemoryfs, options)
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEvent.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEvent.java
new file mode 100644
index 0000000..901586f
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEvent.java
@@ -0,0 +1,31 @@
+// Copyright 2016 The Bazel Authors. 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.
+
+package com.google.devtools.build.lib.buildeventstream;
+
+/**
+ * Interface for objects that can be posted on the public event stream.
+ *
+ * <p>Objects posted on the build-event stream will implement this interface. This allows
+ * pass-through of events, as well as proper chaining of events.
+ */
+public interface BuildEvent extends ChainableEvent {
+  /**
+   * Provide a binary representation of the event.
+   *
+   * <p>Provide a presentation of the event according to the specified binary format, as appropriate
+   * protocol buffer.
+   */
+  BuildEventStreamProtos.BuildEvent asStreamProto();
+}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventId.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventId.java
new file mode 100644
index 0000000..644760b
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventId.java
@@ -0,0 +1,76 @@
+// Copyright 2016 The Bazel Authors. 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.
+
+package com.google.devtools.build.lib.buildeventstream;
+
+import com.google.protobuf.TextFormat;
+import java.io.Serializable;
+import java.util.Objects;
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * Class of identifiers for publically posted events.
+ *
+ * <p>Since event identifiers need to be created before the actual event, the event IDs are highly
+ * structured so that equal identifiers can easily be generated. The main way of pregenerating event
+ * identifiers that do not accidentally coincide is by providing a target or a target pattern;
+ * therefore, those (if provided) are made specially visible.
+ */
+@Immutable
+public final class BuildEventId implements Serializable {
+  private final BuildEventStreamProtos.BuildEventId protoid;
+
+  private BuildEventId(BuildEventStreamProtos.BuildEventId protoid) {
+    this.protoid = protoid;
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(protoid);
+  }
+
+  @Override
+  public boolean equals(Object other) {
+    if (other == null || !other.getClass().equals(getClass())) {
+      return false;
+    }
+    BuildEventId that = (BuildEventId) other;
+    return Objects.equals(this.protoid, that.protoid);
+  }
+
+  @Override
+  public String toString() {
+    return "BuildEventId {" + TextFormat.printToString(protoid) + "}";
+  }
+
+  public BuildEventStreamProtos.BuildEventId asStreamProto() {
+    return protoid;
+  }
+
+  public static BuildEventId unknownBuildEventId(String details) {
+    BuildEventStreamProtos.BuildEventId.UnknownBuildEventId id =
+        BuildEventStreamProtos.BuildEventId.UnknownBuildEventId.newBuilder()
+            .setDetails(details)
+            .build();
+    return new BuildEventId(
+        BuildEventStreamProtos.BuildEventId.newBuilder().setUnknown(id).build());
+  }
+
+  public static BuildEventId progressId(int count) {
+    BuildEventStreamProtos.BuildEventId.ProgressId id =
+        BuildEventStreamProtos.BuildEventId.ProgressId.newBuilder().setOpaqueCount(count).build();
+    return new BuildEventId(
+        BuildEventStreamProtos.BuildEventId.newBuilder().setProgress(id).build());
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventTransport.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventTransport.java
new file mode 100644
index 0000000..f539e3a
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventTransport.java
@@ -0,0 +1,34 @@
+// Copyright 2016 The Bazel Authors. 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.
+
+package com.google.devtools.build.lib.buildeventstream;
+
+import java.io.IOException;
+
+/** Interface for transports of the build-event stream. */
+public interface BuildEventTransport {
+
+  /**
+   * Ensure that the event will eventually be reported to the receiver this object is a transport
+   * for; the transport is responsible that events arrive at the endpoint in the order they are sent
+   * by invocations of this method.
+   */
+  void sendBuildEvent(BuildEvent event) throws IOException;
+
+  /**
+   * Close all open resources, if any. This method will be called on the transport after all events
+   * have been sent. If a transport is stateless, it is correct to do nothing.
+   */
+  void close() throws IOException;
+}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/ChainableEvent.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/ChainableEvent.java
new file mode 100644
index 0000000..3fdf22c
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/ChainableEvent.java
@@ -0,0 +1,50 @@
+// Copyright 2016 The Bazel Authors. 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.
+
+package com.google.devtools.build.lib.buildeventstream;
+
+import java.util.Collection;
+
+/**
+ * Interface for objects organised in a DAG-like fashion.
+ *
+ * <p>When objects that are naturally organised in a directed acyclic graph are sent sequentially
+ * over some channel, the graph-structure needs to represented in some way. We chose the
+ * representation that each node knows its immediate sucessor nodes (rather than its predecessors)
+ * to suit the * properties of the event stream: new parents of a node might be discovered late,
+ * e.g., if a test suite is only expanded after one of its tests is already finished as it was also
+ * needed for another target.
+ */
+public interface ChainableEvent {
+
+  /**
+   * Provide the identifier of the event.
+   *
+   * <p>Event identifiers have to be unique within the set of events belonging to the same build
+   * invocation.
+   */
+  BuildEventId getEventId();
+
+  /**
+   * Provide the children of the event.
+   *
+   * <p>It is a requirement of a well-formed event stream that for every event that does not
+   * indicate the beginning of a new build, at least one parent be present before the event itself.
+   * However, more parents might appear later in the stream (e.g., if a test suite expanded later
+   * discovers that a test that is already completed belongs to it).
+   *
+   * <p>A build-event stream is finished if and only if all announced children have occurred.
+   */
+  Collection<BuildEventId> getChildrenEvents();
+}