| // 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.remote; |
| |
| import com.google.common.hash.HashCode; |
| import com.google.common.hash.Hashing; |
| import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe; |
| import com.google.devtools.build.lib.remote.RemoteProtocol.Action; |
| import com.google.devtools.build.lib.remote.RemoteProtocol.ContentDigest; |
| import com.google.devtools.build.lib.vfs.Path; |
| import com.google.protobuf.ByteString; |
| import com.google.protobuf.Message; |
| import java.io.IOException; |
| |
| /** Helper methods relating to computing ContentDigest messages for remote execution. */ |
| @ThreadSafe |
| public final class ContentDigests { |
| private ContentDigests() {} |
| |
| public static ContentDigest computeDigest(byte[] blob) { |
| return buildDigest(Hashing.sha1().hashBytes(blob).asBytes(), blob.length); |
| } |
| |
| // TODO(olaola): cache these in ActionInputFileCache! |
| public static ContentDigest computeDigest(Path file) throws IOException { |
| return buildDigest(file.getSHA1Digest(), file.getFileSize()); |
| } |
| |
| /** |
| * Computes a digest of the given proto message. Currently, we simply rely on message output as |
| * bytes, but this implementation relies on the stability of the proto encoding, in particular |
| * between different platforms and languages. TODO(olaola): upgrade to a better implementation! |
| */ |
| public static ContentDigest computeDigest(Message message) { |
| return computeDigest(message.toByteArray()); |
| } |
| |
| /** |
| * A special type of ContentDigest that is used only as a remote action cache key. This is a |
| * separate type in order to prevent accidentally using other ContentDigests as action keys. |
| */ |
| public static final class ActionKey { |
| private final ContentDigest digest; |
| |
| public ContentDigest getDigest() { |
| return digest; |
| } |
| |
| private ActionKey(ContentDigest digest) { |
| this.digest = digest; |
| } |
| } |
| |
| public static ActionKey computeActionKey(Action action) { |
| return new ActionKey(computeDigest(action)); |
| } |
| |
| /** |
| * Assumes that the given ContentDigest is a valid digest of an Action, and creates an ActionKey |
| * wrapper. This should not be called on the client side! |
| */ |
| public static ActionKey unsafeActionKeyFromDigest(ContentDigest digest) { |
| return new ActionKey(digest); |
| } |
| |
| public static ContentDigest buildDigest(byte[] digest, long size) { |
| ContentDigest.Builder b = ContentDigest.newBuilder(); |
| b.setDigest(ByteString.copyFrom(digest)).setSizeBytes(size); |
| return b.build(); |
| } |
| |
| public static String toHexString(ContentDigest digest) { |
| return digest.getSizeBytes() > 0 |
| ? HashCode.fromBytes(digest.getDigest().toByteArray()).toString() |
| : ""; |
| } |
| |
| public static String toString(ContentDigest digest) { |
| return "<digest: " + toHexString(digest) + ", size: " + digest.getSizeBytes() + " bytes>"; |
| } |
| } |