|  | // 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)); | 
|  | } | 
|  |  | 
|  | 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>"; | 
|  | } | 
|  | } |