// 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.skyframe; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException; import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.syntax.Environment.Extension; import com.google.devtools.build.lib.util.Preconditions; import com.google.devtools.build.lib.vfs.RootedPath; import com.google.devtools.build.skyframe.LegacySkyKey; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; import java.util.Map; import java.util.Objects; /** * A SkyValue that contains the result of the parsing of one part of the WORKSPACE file. The parsing * of the WORKSPACE file is split before each series of load statement because we need to resolve * repositories before being able to load from those repositories. */ public class WorkspaceFileValue implements SkyValue { /** * Argument for the SkyKey to request a WorkspaceFileValue. */ @Immutable public static class WorkspaceFileKey { private final RootedPath path; private final int idx; /** * Creates a Key for the WorkspaceFileFunction. The path to the workspace file is specified * by {@code path}. This key will ask WorkspaceFileFunction to get the {@code idx+1}-th part of * the workspace file (so idx = 0 represents the first part, idx = 1, the second part, etc...). */ public WorkspaceFileKey(RootedPath path, int idx) { this.path = path; this.idx = idx; } public RootedPath getPath() { return path; } public int getIndex() { return idx; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof WorkspaceFileKey)) { return false; } WorkspaceFileKey other = (WorkspaceFileKey) obj; return Objects.equals(path, other.path) && idx == other.idx; } @Override public int hashCode() { return Objects.hash(path.hashCode(), idx); } @Override public String toString() { return path + ", " + idx; } } private final Package pkg; private final int idx; private final RootedPath path; private final boolean hasNext; // TODO(dmarting): The bindings bind to "Object" which we should ultimately replace by a super // type in the Environment class (that would ease the serialization of this object). private final ImmutableMap<String, Object> bindings; private final ImmutableMap<String, Extension> importMap; /** * Create a WorkspaceFileValue containing the various values necessary to compute the split * WORKSPACE file. * @param pkg Package built by agreggating all parts of the split WORKSPACE file up to this one. * @param importMap List of imports (i.e., load statements) present in all parts of the split * WORKSPACE file up to this one. * @param bindings List of top-level variable bindings from the all parts of the split * WORKSPACE file up to this one. The key is the name of the bindings and the value is the actual * object. * @param path The rooted path to workspace file to parse. * @param idx The index of this part of the split WORKSPACE file (0 for the first one, 1 for the * second one and so on). * @param hasNext Is there a next part in the WORKSPACE file or this part the last one? */ public WorkspaceFileValue( Package pkg, Map<String, Extension> importMap, Map<String, Object> bindings, RootedPath path, int idx, boolean hasNext) { this.pkg = Preconditions.checkNotNull(pkg); this.idx = idx; this.path = path; this.hasNext = hasNext; this.bindings = ImmutableMap.copyOf(bindings); this.importMap = ImmutableMap.copyOf(importMap); } /** * Returns the package. This package may contain errors, in which case the caller should throw * a {@link BuildFileContainsErrorsException}. */ public Package getPackage() { return pkg; } @Override public String toString() { return "<WorkspaceFileValue path=" + path + " idx=" + idx + ">"; } static SkyKey key(RootedPath path, int idx) { return LegacySkyKey.create(SkyFunctions.WORKSPACE_FILE, new WorkspaceFileKey(path, idx)); } public static SkyKey key(RootedPath path) { return key(path, 0); } /** * Get the key for the next WorkspaceFileValue or null if this value is the last part of the * workspace file. */ public SkyKey next() { if (hasNext) { return key(path, idx + 1); } else { return null; } } /** * The workspace file parsing is cut in several parts and this function returns the index of the * part of the workspace file that this value holds. For the first part, this index will be 0, for * the second part, it will be 1 and so on. */ public int getIndex() { return idx; } /** * The workspace file parsing is cut in several parts and this function returns true if there is * a part following the part holds by this value (or false if this is the last part of the * WORKSPACE file. * * <p>This method is public for serialization of the WorkspaceFileValue, #next() should be used * to iterate instead of this method. */ public boolean hasNext() { return hasNext; } public RootedPath getPath() { return path; } public ImmutableMap<String, Object> getBindings() { return bindings; } public ImmutableMap<String, Extension> getImportMap() { return importMap; } }