| // Copyright 2014 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.events; |
| |
| import static java.nio.charset.StandardCharsets.UTF_8; |
| |
| import com.google.common.base.Preconditions; |
| import java.io.Serializable; |
| import java.util.Arrays; |
| import java.util.Objects; |
| import javax.annotation.Nullable; |
| import javax.annotation.concurrent.Immutable; |
| |
| /** |
| * An event is a situation encountered by the build system that's worth |
| * reporting: A 3-tuple of ({@link EventKind}, {@link Location}, message). |
| */ |
| @Immutable |
| public final class Event implements Serializable { |
| private final EventKind kind; |
| private final Location location; |
| private final String message; |
| @Nullable private final String stdout; |
| @Nullable private final String stderr; |
| |
| /** |
| * An alternative representation for message. |
| * |
| * <p>Exactly one of message or messageBytes will be non-null. If messageBytes is non-null, then |
| * it contains the UTF-8-encoded bytes of the message. We do this to avoid converting back and |
| * forth between Strings and bytes. |
| */ |
| private final byte[] messageBytes; |
| |
| @Nullable |
| private final String tag; |
| |
| private final int hashCode; |
| |
| private Event( |
| EventKind kind, |
| @Nullable Location location, |
| String message, |
| @Nullable String tag, |
| @Nullable String stdout, |
| @Nullable String stderr) { |
| this.kind = Preconditions.checkNotNull(kind); |
| this.location = location; |
| this.message = Preconditions.checkNotNull(message); |
| this.messageBytes = null; |
| this.tag = tag; |
| this.stdout = stdout; |
| this.stderr = stderr; |
| this.hashCode = |
| Objects.hash(kind, location, message, tag, Arrays.hashCode(messageBytes), stdout, stderr); |
| } |
| |
| private Event( |
| EventKind kind, |
| @Nullable Location location, |
| byte[] messageBytes, |
| @Nullable String tag, |
| @Nullable String stdout, |
| @Nullable String stderr) { |
| this.kind = Preconditions.checkNotNull(kind); |
| this.location = location; |
| this.message = null; |
| this.messageBytes = Preconditions.checkNotNull(messageBytes); |
| this.tag = tag; |
| this.stdout = stdout; |
| this.stderr = stderr; |
| this.hashCode = |
| Objects.hash(kind, location, message, tag, Arrays.hashCode(messageBytes), stdout, stderr); |
| } |
| |
| public Event withTag(String tag) { |
| if (Objects.equals(tag, this.tag)) { |
| return this; |
| } |
| if (this.message != null) { |
| return new Event(this.kind, this.location, this.message, tag, this.stdout, this.stderr); |
| } else { |
| return new Event(this.kind, this.location, this.messageBytes, tag, this.stdout, this.stderr); |
| } |
| } |
| |
| public Event withStdoutStderr(String stdout, String stderr) { |
| if (this.message != null) { |
| return new Event(this.kind, this.location, this.message, this.tag, stdout, stderr); |
| } else { |
| return new Event(this.kind, this.location, this.messageBytes, this.tag, stdout, stderr); |
| } |
| } |
| |
| public String getMessage() { |
| return message != null ? message : new String(messageBytes, UTF_8); |
| } |
| |
| public byte[] getMessageBytes() { |
| return messageBytes != null ? messageBytes : message.getBytes(UTF_8); |
| } |
| |
| public EventKind getKind() { |
| return kind; |
| } |
| |
| /** |
| * the tag is typically the action that generated the event. |
| */ |
| @Nullable |
| public String getTag() { |
| return tag; |
| } |
| |
| /** |
| * Get the stdout bytes associated with this event; typically, the event will report where the |
| * output originated from. |
| */ |
| @Nullable |
| public String getStdOut() { |
| return stdout; |
| } |
| |
| /** |
| * Get the stdout bytes associated with this event; typically, the event will report where the |
| * output originated from. |
| */ |
| @Nullable |
| public String getStdErr() { |
| return stderr; |
| } |
| |
| /** |
| * Returns the location of this event, if any. Returns null iff the event |
| * wasn't associated with any particular location, for example, a progress |
| * message. |
| */ |
| @Nullable public Location getLocation() { |
| return location; |
| } |
| |
| /** |
| * Returns <i>some</i> moderately sane representation of the event. Should never be used in |
| * user-visible places, only for debugging and testing. |
| */ |
| @Override |
| public String toString() { |
| return kind + " " + (location != null ? location.print() : "<no location>") + ": " |
| + getMessage(); |
| } |
| |
| @Override |
| public int hashCode() { |
| return hashCode; |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) { |
| return true; |
| } |
| if (other == null || !other.getClass().equals(getClass())) { |
| return false; |
| } |
| Event that = (Event) other; |
| return Objects.equals(this.kind, that.kind) |
| && Objects.equals(this.location, that.location) |
| && Objects.equals(this.tag, that.tag) |
| && Objects.equals(this.message, that.message) |
| && Objects.equals(this.stdout, that.stdout) |
| && Objects.equals(this.stderr, that.stderr) |
| && Arrays.equals(this.messageBytes, that.messageBytes); |
| } |
| |
| /** |
| * Replay a sequence of events on an {@link EventHandler}. |
| */ |
| public static void replayEventsOn(EventHandler eventHandler, Iterable<Event> events) { |
| for (Event event : events) { |
| eventHandler.handle(event); |
| } |
| } |
| |
| public static Event of(EventKind kind, @Nullable Location location, String message) { |
| return new Event(kind, location, message, null, null, null); |
| } |
| |
| /** |
| * Construct an event by passing in the {@code byte[]} array instead of a String. |
| * |
| * The bytes must be decodable as UTF-8 text. |
| */ |
| public static Event of(EventKind kind, @Nullable Location location, byte[] messageBytes) { |
| return new Event(kind, location, messageBytes, null, null, null); |
| } |
| |
| /** Reports an error. */ |
| public static Event error(@Nullable Location location, String message) { |
| return new Event(EventKind.ERROR, location, message, null, null, null); |
| } |
| |
| /** Reports an error. */ |
| public static Event error(String message) { |
| return error(null, message); |
| } |
| |
| /** Reports a warning. */ |
| public static Event warn(@Nullable Location location, String message) { |
| return new Event(EventKind.WARNING, location, message, null, null, null); |
| } |
| |
| /** Reports a warning. */ |
| public static Event warn(String message) { |
| return warn(null, message); |
| } |
| |
| /** |
| * Reports atemporal statements about the build, i.e. they're true for the duration of execution. |
| */ |
| public static Event info(@Nullable Location location, String message) { |
| return new Event(EventKind.INFO, location, message, null, null, null); |
| } |
| |
| /** |
| * Reports atemporal statements about the build, i.e. they're true for the duration of execution. |
| */ |
| public static Event info(String message) { |
| return info(null, message); |
| } |
| |
| /** Reports a temporal statement about the build. */ |
| public static Event progress(@Nullable Location location, String message) { |
| return new Event(EventKind.PROGRESS, location, message, null, null, null); |
| } |
| |
| /** Reports a temporal statement about the build. */ |
| public static Event progress(String message) { |
| return progress(null, message); |
| } |
| |
| /** Reports a debug message. */ |
| public static Event debug(@Nullable Location location, String message) { |
| return new Event(EventKind.DEBUG, location, message, null, null, null); |
| } |
| |
| /** |
| * Reports a debug message. |
| */ |
| public static Event debug(String message) { |
| return debug(null, message); |
| } |
| } |