// 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.actions; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.util.Fingerprint; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; /** * Environment variables for build or test actions. * *

The action environment consists of two parts. *

    *
  1. All the environment variables with a fixed value, stored in a map. *
  2. All the environment variables inherited from the client environment, stored in a set. *
* *

Inherited environment variables must be declared in the Action interface * (see {@link Action#getClientEnvironmentVariables}), so that the dependency on the client * environment is known to the execution framework for correct incremental builds. */ public final class ActionEnvironment { /** * An empty environment, mainly for testing. Production code should never use this, but instead * get the proper environment from the current configuration. */ // TODO(ulfjack): Migrate all production code to use the proper action environment, and then make // this @VisibleForTesting or rename it to clarify. public static final ActionEnvironment EMPTY = new ActionEnvironment(ImmutableMap.of(), ImmutableSet.of()); /** * Splits the given map into a map of variables with a fixed value, and a set of variables that * should be inherited, the latter of which are identified by having a {@code null} value in the * given map. Returns these two parts as a new {@link ActionEnvironment} instance. */ public static ActionEnvironment split(Map env) { // Care needs to be taken that the two sets don't overlap - the order in which the two parts are // combined later is undefined. Map fixedEnv = new TreeMap<>(); Set inheritedEnv = new TreeSet<>(); for (Map.Entry entry : env.entrySet()) { if (entry.getValue() != null) { fixedEnv.put(entry.getKey(), entry.getValue()); } else { String key = entry.getKey(); inheritedEnv.add(key); } } return create(fixedEnv, inheritedEnv); } private final ImmutableMap fixedEnv; private final ImmutableSet inheritedEnv; private ActionEnvironment(Map fixedEnv, Set inheritedEnv) { this.fixedEnv = ImmutableMap.copyOf(fixedEnv); this.inheritedEnv = ImmutableSet.copyOf(inheritedEnv); } /** * Creates a new action environment. The order in which the environments are combined is * undefined, so callers need to take care that the key set of the {@code fixedEnv} map and the * set of {@code inheritedEnv} elements are disjoint. */ public static ActionEnvironment create(Map fixedEnv, Set inheritedEnv) { if (fixedEnv.isEmpty() && inheritedEnv.isEmpty()) { return EMPTY; } return new ActionEnvironment(fixedEnv, inheritedEnv); } public static ActionEnvironment create(Map fixedEnv) { return new ActionEnvironment(fixedEnv, ImmutableSet.of()); } public ImmutableMap getFixedEnv() { return fixedEnv; } public ImmutableSet getInheritedEnv() { return inheritedEnv; } /** * Resolves the action environment and adds the resulting entries to the given {@code result} map, * by looking up any inherited env variables in the given {@code clientEnv}. * *

We pass in a map to mutate to avoid creating and merging intermediate maps. */ public void resolve(Map result, Map clientEnv) { Preconditions.checkNotNull(clientEnv); result.putAll(fixedEnv); for (String var : inheritedEnv) { String value = clientEnv.get(var); if (value != null) { result.put(var, value); } } } public void addTo(Fingerprint f) { f.addStringMap(fixedEnv); } }