diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/remote/util/DigestUtil.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/remote/util/DigestUtil.java | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/remote/util/DigestUtil.java b/src/main/java/com/google/devtools/build/lib/remote/util/DigestUtil.java new file mode 100644 index 0000000000..afd31ccdeb --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/remote/util/DigestUtil.java @@ -0,0 +1,121 @@ +// Copyright 2017 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.util; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.google.common.base.Preconditions; +import com.google.common.hash.HashCode; +import com.google.devtools.build.lib.actions.ActionInput; +import com.google.devtools.build.lib.actions.MetadataProvider; +import com.google.devtools.build.lib.actions.cache.DigestUtils; +import com.google.devtools.build.lib.actions.cache.Metadata; +import com.google.devtools.build.lib.actions.cache.VirtualActionInput; +import com.google.devtools.build.lib.vfs.FileSystem.HashFunction; +import com.google.devtools.build.lib.vfs.Path; +import com.google.devtools.remoteexecution.v1test.Action; +import com.google.devtools.remoteexecution.v1test.Digest; +import com.google.protobuf.Message; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** Utility methods to work with {@link Digest}. */ +public class DigestUtil { + + /** + * A special type of Digest that is used only as a remote action cache key. This is a separate + * type in order to prevent accidentally using other Digests as action keys. + */ + public static final class ActionKey { + private final Digest digest; + + public Digest getDigest() { + return digest; + } + + private ActionKey(Digest digest) { + this.digest = digest; + } + } + + private final HashFunction hashFn; + + public DigestUtil(HashFunction hashFn) { + this.hashFn = hashFn; + } + + public Digest compute(byte[] blob) { + return buildDigest(hashFn.getHash().hashBytes(blob).toString(), blob.length); + } + + public Digest compute(Path file) throws IOException { + long fileSize = file.getFileSize(); + byte[] digest = DigestUtils.getDigestOrFail(file, fileSize); + return buildDigest(digest, fileSize); + } + + public Digest compute(VirtualActionInput input) throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + input.writeTo(buffer); + return compute(buffer.toByteArray()); + } + + /** + * 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 Digest compute(Message message) { + return compute(message.toByteArray()); + } + + public Digest computeAsUtf8(String str) { + return compute(str.getBytes(UTF_8)); + } + + public DigestUtil.ActionKey computeActionKey(Action action) { + return new DigestUtil.ActionKey(compute(action)); + } + + /** + * Assumes that the given Digest is a valid digest of an Action, and creates an ActionKey wrapper. + * This should not be called on the client side! + */ + public DigestUtil.ActionKey asActionKey(Digest digest) { + return new DigestUtil.ActionKey(digest); + } + + public static Digest buildDigest(byte[] hash, long size) { + return buildDigest(HashCode.fromBytes(hash).toString(), size); + } + + public static Digest buildDigest(String hexHash, long size) { + return Digest.newBuilder().setHash(hexHash).setSizeBytes(size).build(); + } + + public String toString(Digest digest) { + return digest.getHash() + "/" + digest.getSizeBytes(); + } + + public static Digest getFromInputCache(ActionInput input, MetadataProvider cache) + throws IOException { + Metadata metadata = cache.getMetadata(input); + Preconditions.checkNotNull(metadata, "Input cache %s returned no value for %s", cache, input); + Preconditions.checkNotNull( + metadata.getDigest(), + "Null digest for %s, possible directory. Data dependencies on directories are not allowed.", + input); + return buildDigest(metadata.getDigest(), metadata.getSize()); + } +} |