Skip to content

Commit

Permalink
Add new skyfunction to create build configuration keys.
Browse files Browse the repository at this point in the history
This essentially exposes BuildConfigurationKeyProducer as a SkyFunction.

Work towards platform-based flags: #19409.

PiperOrigin-RevId: 599838440
Change-Id: Id6c0b00f43fe813f77dbed8c7a6fee0f989649a6
  • Loading branch information
katre authored and copybara-github committed Jan 19, 2024
1 parent f9f2240 commit 4ddc4a1
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ public final class SkyFunctions {
static final SkyFunctionName TEST_COMPLETION = SkyFunctionName.createHermetic("TEST_COMPLETION");
public static final SkyFunctionName BUILD_CONFIGURATION =
SkyFunctionName.createHermetic("BUILD_CONFIGURATION");
public static final SkyFunctionName BUILD_CONFIGURATION_KEY =
SkyFunctionName.createHermetic("BUILD_CONFIGURATION_KEY");
public static final SkyFunctionName BASELINE_OPTIONS =
SkyFunctionName.createHermetic("BASELINE_OPTIONS");
public static final SkyFunctionName STARLARK_BUILD_SETTINGS_DETAILS =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@
import com.google.devtools.build.lib.skyframe.config.BaselineOptionsFunction;
import com.google.devtools.build.lib.skyframe.config.BuildConfigurationFunction;
import com.google.devtools.build.lib.skyframe.config.BuildConfigurationKey;
import com.google.devtools.build.lib.skyframe.config.BuildConfigurationKeyFunction;
import com.google.devtools.build.lib.skyframe.config.PlatformMappingFunction;
import com.google.devtools.build.lib.skyframe.config.PlatformMappingValue;
import com.google.devtools.build.lib.skyframe.rewinding.ActionRewindStrategy;
Expand Down Expand Up @@ -664,6 +665,7 @@ private ImmutableMap<SkyFunctionName, SkyFunction> skyFunctions() {
map.put(
SkyFunctions.BUILD_CONFIGURATION,
new BuildConfigurationFunction(directories, ruleClassProvider));
map.put(SkyFunctions.BUILD_CONFIGURATION_KEY, new BuildConfigurationKeyFunction());
map.put(SkyFunctions.BASELINE_OPTIONS, new BaselineOptionsFunction());
map.put(
SkyFunctions.STARLARK_BUILD_SETTINGS_DETAILS, new StarlarkBuildSettingsDetailsFunction());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ java_library(
srcs = [
"BaselineOptionsFunction.java",
"BuildConfigurationFunction.java",
"BuildConfigurationKeyFunction.java",
"PlatformMappingFunction.java",
],
deps = [
Expand Down Expand Up @@ -80,6 +81,7 @@ java_library(
name = "config",
srcs = [
"BuildConfigurationKey.java",
"BuildConfigurationKeyValue.java",
"PlatformMappingValue.java",
],
deps = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Copyright 2024 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.skyframe.config;

import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.producers.BuildConfigurationKeyProducer;
import com.google.devtools.build.lib.analysis.producers.BuildConfigurationKeyProducer.ResultSink;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyFunctionException;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import com.google.devtools.build.skyframe.state.Driver;
import com.google.devtools.build.skyframe.state.StateMachine;
import com.google.devtools.common.options.OptionsParsingException;
import javax.annotation.Nullable;

/** Function that returns a fully updated {@link BuildConfigurationKey}. */
public class BuildConfigurationKeyFunction implements SkyFunction {
/**
* {@link BuildConfigurationKeyProducer} works on a {@code Map<String, BuildOptions>}, but this
* skyfunction only operates on a single {@link BuildOptions}, so this static key is used to
* create that map and read the resulting {@link BuildConfigurationKey}.
*/
private static final String BUILD_OPTIONS_MAP_SINGLETON_KEY = "key";

@Nullable
@Override
public SkyValue compute(SkyKey skyKey, Environment env)
throws BuildConfigurationKeyFunctionException, InterruptedException {
// Delegate all work to BuildConfigurationKeyProducer.
BuildConfigurationKeyValue.Key key = (BuildConfigurationKeyValue.Key) skyKey.argument();
BuildOptions buildOptions = key.buildOptions();
Sink sink = new Sink();
Driver driver =
new Driver(
new BuildConfigurationKeyProducer(
sink,
/* runAfter= */ StateMachine.DONE,
ImmutableMap.of(BUILD_OPTIONS_MAP_SINGLETON_KEY, buildOptions)));

boolean complete = driver.drive(env);

try {
// Check for exceptions before returning whether to restart.
sink.checkErrors();
if (!complete) {
return null;
}

BuildConfigurationKey buildConfigurationKey = sink.getKey();
return BuildConfigurationKeyValue.create(buildConfigurationKey);
} catch (OptionsParsingException e) {
throw new BuildConfigurationKeyFunctionException(e);
} catch (PlatformMappingException e) {
throw new BuildConfigurationKeyFunctionException(e);
}
}

/** Sink implementation to handle results from {@link BuildConfigurationKeyProducer}. */
private static final class Sink implements ResultSink {
@Nullable private ImmutableMap<String, BuildConfigurationKey> transitionedOptions;
@Nullable private OptionsParsingException transitionError;
@Nullable private PlatformMappingException platformMappingException;

@Override
public void acceptTransitionError(OptionsParsingException e) {
this.transitionError = e;
}

@Override
public void acceptPlatformMappingError(PlatformMappingException e) {
this.platformMappingException = e;
}

@Override
public void acceptTransitionedConfigurations(
ImmutableMap<String, BuildConfigurationKey> transitionedOptions) {
this.transitionedOptions = transitionedOptions;
}

void checkErrors() throws OptionsParsingException, PlatformMappingException {
if (this.transitionError != null) {
throw this.transitionError;
}
if (this.platformMappingException != null) {
throw this.platformMappingException;
}
}

BuildConfigurationKey getKey() {
if (this.transitionedOptions != null) {
return this.transitionedOptions.get(BUILD_OPTIONS_MAP_SINGLETON_KEY);
}
throw new IllegalStateException("No exceptions or result value found");
}
}

/** Exception type for errors while creating the {@link BuildConfigurationKeyValue}. */
public static final class BuildConfigurationKeyFunctionException extends SkyFunctionException {

public BuildConfigurationKeyFunctionException(OptionsParsingException optionsParsingException) {
super(optionsParsingException, Transience.PERSISTENT);
}

public BuildConfigurationKeyFunctionException(
PlatformMappingException platformMappingException) {
super(platformMappingException, Transience.PERSISTENT);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright 2024 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.skyframe.config;

import com.google.common.base.MoreObjects;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.concurrent.ThreadSafety;
import com.google.devtools.build.lib.skyframe.SkyFunctions;
import com.google.devtools.build.lib.skyframe.serialization.VisibleForSerialization;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.skyframe.SkyFunctionName;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import java.util.Objects;

/** Stores a {@link BuildConfigurationKey} with all platform mappings applied. */
@AutoCodec
public final class BuildConfigurationKeyValue implements SkyValue {

/** Key for {@link BuildConfigurationKeyValue} based on the build options. */
@ThreadSafety.Immutable
@AutoCodec
public static final class Key implements SkyKey {
private static final SkyKeyInterner<Key> interner = SkyKey.newInterner();

@AutoCodec.Instantiator
@VisibleForSerialization
public static Key create(BuildOptions buildOptions) {
return interner.intern(new Key(buildOptions));
}

private final BuildOptions buildOptions;

private Key(BuildOptions buildOptions) {
this.buildOptions = buildOptions;
}

public BuildOptions buildOptions() {
return buildOptions;
}

@Override
public SkyFunctionName functionName() {
return SkyFunctions.BUILD_CONFIGURATION_KEY;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Key key = (Key) o;
return Objects.equals(buildOptions, key.buildOptions);
}

@Override
public int hashCode() {
return Objects.hashCode(buildOptions);
}

@Override
public String toString() {
return "BuildConfigurationKeyValue.Key{buildOptions=" + buildOptions.checksum() + "}";
}

@Override
public SkyKeyInterner<Key> getSkyKeyInterner() {
return interner;
}
}

public static BuildConfigurationKeyValue create(BuildConfigurationKey buildConfigurationKey) {
return new BuildConfigurationKeyValue(buildConfigurationKey);
}

private final BuildConfigurationKey buildConfigurationKey;

BuildConfigurationKeyValue(BuildConfigurationKey buildConfigurationKey) {
this.buildConfigurationKey = buildConfigurationKey;
}

public BuildConfigurationKey buildConfigurationKey() {
return buildConfigurationKey;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof BuildConfigurationKeyValue)) {
return false;
}
BuildConfigurationKeyValue that = (BuildConfigurationKeyValue) obj;
return this.buildConfigurationKey.equals(that.buildConfigurationKey);
}

@Override
public int hashCode() {
return Objects.hashCode(buildConfigurationKey);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("buildConfigurationKey", buildConfigurationKey)
.toString();
}
}

0 comments on commit 4ddc4a1

Please sign in to comment.