// 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.analysis.actions; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.io.ByteStreams; import com.google.devtools.build.lib.actions.ActionExecutionContext; import com.google.devtools.build.lib.actions.ActionKeyContext; import com.google.devtools.build.lib.actions.ActionOwner; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.util.Fingerprint; import com.google.devtools.build.lib.util.OS; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; import javax.annotation.Nullable; /** Action that writes a native {@code .exe} launcher for {java,sh,py}_binary rules on Windows. */ public final class LauncherFileWriteAction extends AbstractFileWriteAction { // Generated with /usr/bin/uuidgen. // This GUID doesn't have to be anything specific, we only use it to salt action cache keys so it // just has to be unique among other actions. private static final String GUID = "1f57afe7-f6f8-487c-9a8a-0a0286172fef"; private final LaunchInfo launchInfo; private final Artifact launcher; /** Creates a new {@link LauncherFileWriteAction}, registering it with the {@code ruleContext}. */ public static void createAndRegister( RuleContext ruleContext, Artifact output, LaunchInfo launchInfo) { ruleContext.registerAction( new LauncherFileWriteAction( ruleContext.getActionOwner(), output, ruleContext.getPrerequisiteArtifact("$launcher", Mode.HOST), launchInfo)); } /** Creates a new {@code LauncherFileWriteAction}. */ private LauncherFileWriteAction( ActionOwner owner, Artifact output, Artifact launcher, LaunchInfo launchInfo) { super( owner, ImmutableList.of(Preconditions.checkNotNull(launcher)), output, /*makeExecutable=*/ true); this.launcher = launcher; // already null-checked in the superclass c'tor this.launchInfo = Preconditions.checkNotNull(launchInfo); } @Override public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx) { // TODO(laszlocsomor): make this code check for the execution platform, not the host platform, // once Bazel supports distinguishing between the two. // OS.getCurrent() returns the host platform, not the execution platform, which is fine in a // single-machine execution environment, but problematic with remote execution. Preconditions.checkState(OS.getCurrent() == OS.WINDOWS); return out -> { try (InputStream in = ctx.getInputPath(this.launcher).getInputStream()) { ByteStreams.copy(in, out); } long dataLength = this.launchInfo.write(out); ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES); buffer.order(ByteOrder.LITTLE_ENDIAN); // All Windows versions are little endian. buffer.putLong(dataLength); out.write(buffer.array()); out.flush(); }; } @Override protected void computeKey(ActionKeyContext actionKeyContext, Fingerprint fp) { fp.addString(GUID); fp.addPath(this.launcher.getExecPath()); fp.addString(this.launchInfo.fingerPrint); } /** * Metadata that describes the payload of the native launcher binary. * *
This object constructs the binary metadata lazily, to save memory.
*/
public static final class LaunchInfo {
/** Precomputed fingerprint of this object. */
public final String fingerPrint;
private final ImmutableList Examples:
*
* Examples:
*
*
*
*/
public Builder addKeyValuePair(String key, @Nullable String value) {
Preconditions.checkNotNull(key);
if (!key.isEmpty()) {
entries.add(new KeyValuePair(key, value));
}
return this;
}
/**
* Adds a key and list of lazily-joined values.
*
*
*
*/
public Builder addJoinedValues(
String key, String delimiter, @Nullable Iterable