blob: daefc112aee1f268a10f7178f60fa374495ee773 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.packages;
16
17import com.google.common.annotations.VisibleForTesting;
tomlua155b532017-11-08 20:12:47 +010018import com.google.common.base.Preconditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010019import com.google.common.collect.ImmutableList;
20import com.google.common.collect.ImmutableMap;
21import com.google.common.collect.ImmutableSet;
22import com.google.common.collect.ImmutableSortedSet;
23import com.google.common.collect.Iterables;
24import com.google.common.collect.Lists;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000025import com.google.devtools.build.lib.cmdline.Label;
Lukacs Berkia6434362015-09-15 13:56:14 +000026import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
Kristina Chodorow73fa2032015-08-28 17:57:46 +000027import com.google.devtools.build.lib.cmdline.PackageIdentifier;
dannarkc3495852018-06-04 13:53:22 -070028import com.google.devtools.build.lib.cmdline.RepositoryName;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010029import com.google.devtools.build.lib.collect.CollectionUtils;
30import com.google.devtools.build.lib.collect.ImmutableSortedKeyMap;
31import com.google.devtools.build.lib.events.Event;
32import com.google.devtools.build.lib.events.EventHandler;
Klaus Aehlig5c04d2a2017-06-13 18:14:15 +020033import com.google.devtools.build.lib.events.ExtendedEventHandler.Postable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010034import com.google.devtools.build.lib.events.Location;
35import com.google.devtools.build.lib.packages.AttributeMap.AcceptsLabelAttribute;
36import com.google.devtools.build.lib.packages.License.DistributionType;
michajlo095a3412018-02-13 16:45:05 -080037import com.google.devtools.build.lib.skyframe.serialization.DeserializationContext;
shahanfae34b92018-02-13 10:08:47 -080038import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec;
michajlo095a3412018-02-13 16:45:05 -080039import com.google.devtools.build.lib.skyframe.serialization.SerializationContext;
shahanc7667ae82018-01-11 10:10:37 -080040import com.google.devtools.build.lib.skyframe.serialization.SerializationException;
brandjonfba45f52017-10-26 18:03:24 +020041import com.google.devtools.build.lib.syntax.SkylarkSemantics;
Laurent Le Brund8b80c32016-06-03 14:38:19 +000042import com.google.devtools.build.lib.util.SpellChecker;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010043import com.google.devtools.build.lib.vfs.Path;
44import com.google.devtools.build.lib.vfs.PathFragment;
tomluee6a6862018-01-17 14:36:26 -080045import com.google.devtools.build.lib.vfs.Root;
shahanc7667ae82018-01-11 10:10:37 -080046import com.google.protobuf.CodedInputStream;
47import com.google.protobuf.CodedOutputStream;
janakr28adce52017-07-13 19:55:32 +020048import java.io.IOException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010049import java.io.PrintStream;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010050import java.util.ArrayList;
51import java.util.Collection;
52import java.util.Collections;
53import java.util.HashMap;
54import java.util.List;
55import java.util.Map;
lberki0d8d4cf2017-09-05 16:01:44 +020056import java.util.Objects;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010057import java.util.Set;
lberki3ef288c2018-03-23 03:06:27 -070058import java.util.TreeMap;
Han-Wen Nienhuys67e6f982016-01-15 15:54:12 +000059import javax.annotation.Nullable;
60
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010061/**
shahanc7667ae82018-01-11 10:10:37 -080062 * A package, which is a container of {@link Rule}s, each of which contains a dictionary of named
63 * attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010064 *
shahanc7667ae82018-01-11 10:10:37 -080065 * <p>Package instances are intended to be immutable and for all practical purposes can be treated
66 * as such. Note, however, that some member variables exposed via the public interface are not
67 * strictly immutable, so until their types are guaranteed immutable we're not applying the
68 * {@code @Immutable} annotation here.
janakrcbf8c0a2018-02-16 12:16:36 -080069 *
70 * <p>When changing this class, make sure to make corresponding changes to serialization!
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010071 */
shahanc7667ae82018-01-11 10:10:37 -080072@SuppressWarnings("JavaLangClash")
Michajlo Matijkiw17f11eb2015-10-14 04:19:28 +000073public class Package {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010074 /**
75 * Common superclass for all name-conflict exceptions.
76 */
77 public static class NameConflictException extends Exception {
78 protected NameConflictException(String message) {
79 super(message);
80 }
81 }
82
83 /**
84 * The repository identifier for this package.
85 */
86 private final PackageIdentifier packageIdentifier;
87
88 /**
89 * The name of the package, e.g. "foo/bar".
90 */
91 protected final String name;
92
93 /**
94 * Like name, but in the form of a PathFragment.
95 */
96 private final PathFragment nameFragment;
97
98 /**
99 * The filename of this package's BUILD file.
100 */
101 protected Path filename;
102
103 /**
104 * The directory in which this package's BUILD file resides. All InputFile
105 * members of the packages are located relative to this directory.
106 */
107 private Path packageDirectory;
108
109 /**
Kristina Chodorow91876f02015-02-27 17:14:12 +0000110 * The name of the workspace this package is in. Used as a prefix for the runfiles directory.
111 * This can be set in the WORKSPACE file. This must be a valid target name.
112 */
Ulf Adamsd13207c2015-09-04 14:53:43 +0000113 protected String workspaceName;
Kristina Chodorow91876f02015-02-27 17:14:12 +0000114
115 /**
tomluee6a6862018-01-17 14:36:26 -0800116 * The root of the source tree in which this package was found. It is an invariant that {@code
117 * sourceRoot.getRelative(packageId.getSourceRoot()).equals(packageDirectory)}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100118 */
tomluee6a6862018-01-17 14:36:26 -0800119 private Root sourceRoot;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100120
121 /**
122 * The "Make" environment of this package, containing package-local
123 * definitions of "Make" variables.
124 */
lberki3ef288c2018-03-23 03:06:27 -0700125 private ImmutableMap<String, String> makeEnv;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100126
carmi31c6a612017-05-17 22:56:19 +0200127 /** The collection of all targets defined in this package, indexed by name. */
128 protected ImmutableSortedKeyMap<String, Target> targets;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100129
130 /**
Laurent Le Brun41079bd2015-06-19 09:37:25 +0000131 * Default visibility for rules that do not specify it.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100132 */
133 private RuleVisibility defaultVisibility;
134 private boolean defaultVisibilitySet;
135
136 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100137 * Default package-level 'testonly' value for rules that do not specify it.
138 */
139 private boolean defaultTestOnly = false;
140
141 /**
142 * Default package-level 'deprecation' value for rules that do not specify it.
143 */
144 private String defaultDeprecation;
145
146 /**
147 * Default header strictness checking for rules that do not specify it.
148 */
149 private String defaultHdrsCheck;
150
Carmi Grushko81dca612016-07-27 02:12:15 +0000151 /** Default copts for cc_* rules. The rules' individual copts will append to this value. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100152 private ImmutableList<String> defaultCopts;
153
154 /**
155 * The InputFile target corresponding to this package's BUILD file.
156 */
157 private InputFile buildFile;
158
159 /**
160 * True iff this package's BUILD files contained lexical or grammatical
161 * errors, or experienced errors during evaluation, or semantic errors during
162 * the construction of any rule.
163 *
164 * <p>Note: A package containing errors does not necessarily prevent a build;
165 * if all the rules needed for a given build were constructed prior to the
166 * first error, the build may proceed.
167 */
168 private boolean containsErrors;
169
170 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100171 * The list of transitive closure of the Skylark file dependencies.
172 */
173 private ImmutableList<Label> skylarkFileDependencies;
174
175 /**
176 * The package's default "licenses" and "distribs" attributes, as specified
177 * in calls to licenses() and distribs() in the BUILD file.
178 */
179 // These sets contain the values specified by the most recent licenses() or
180 // distribs() declarations encountered during package parsing:
181 private License defaultLicense;
182 private Set<License.DistributionType> defaultDistributionSet;
183
dannarkc3495852018-06-04 13:53:22 -0700184 /**
185 * The map from each repository to that repository's remappings map.
186 * This is only used in the //external package, it is an empty map for all other packages.
187 * For example, an entry of {"@foo" : {"@x", "@y"}} indicates that, within repository foo,
188 * "@x" should be remapped to "@y".
189 */
190 private ImmutableMap<RepositoryName, ImmutableMap<RepositoryName, RepositoryName>>
191 externalPackageRepositoryMappings;
192
193 /**
194 * The map of repository reassignments for BUILD packages. This will be empty for packages
195 * within the main workspace.
196 */
197 private ImmutableMap<RepositoryName, RepositoryName> repositoryMapping;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100198
199 /**
200 * The names of the package() attributes that declare default values for rule
201 * {@link RuleClass#COMPATIBLE_ENVIRONMENT_ATTR} and {@link RuleClass#RESTRICTED_ENVIRONMENT_ATTR}
202 * values when not explicitly specified.
203 */
204 public static final String DEFAULT_COMPATIBLE_WITH_ATTRIBUTE = "default_compatible_with";
205 public static final String DEFAULT_RESTRICTED_TO_ATTRIBUTE = "default_restricted_to";
206
207 private Set<Label> defaultCompatibleWith = ImmutableSet.of();
208 private Set<Label> defaultRestrictedTo = ImmutableSet.of();
209
210 private ImmutableSet<String> features;
211
212 private ImmutableList<Event> events;
Klaus Aehlig5c04d2a2017-06-13 18:14:15 +0200213 private ImmutableList<Postable> posts;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100214
John Cater0084e162018-03-12 18:50:56 -0700215 private ImmutableList<String> registeredExecutionPlatforms;
216 private ImmutableList<String> registeredToolchains;
John Cater64a6c152017-07-11 16:50:27 +0200217
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100218 /**
219 * Package initialization, part 1 of 3: instantiates a new package with the
220 * given name.
221 *
222 * <p>As part of initialization, {@link Builder} constructs {@link InputFile}
223 * and {@link PackageGroup} instances that require a valid Package instance where
224 * {@link Package#getNameFragment()} is accessible. That's why these settings are
225 * applied here at the start.
226 *
227 * @precondition {@code name} must be a suffix of
228 * {@code filename.getParentDirectory())}.
229 */
kchodorow63570922017-07-11 22:22:22 +0200230 protected Package(PackageIdentifier packageId, String runfilesPrefix) {
231 this.packageIdentifier = packageId;
232 this.workspaceName = runfilesPrefix;
shreyaxa1f90ce2018-02-15 12:05:13 -0800233 this.nameFragment = packageId.getPackageFragment();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100234 this.name = nameFragment.getPathString();
235 }
236
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100237 /** Returns this packages' identifier. */
238 public PackageIdentifier getPackageIdentifier() {
239 return packageIdentifier;
240 }
241
242 /**
dannarkc3495852018-06-04 13:53:22 -0700243 * Returns the repository mapping for the requested external repository.
244 *
245 * @throws UnsupportedOperationException if called from a package other than
246 * the //external package
247 */
248 public ImmutableMap<RepositoryName, RepositoryName> getRepositoryMapping(
249 RepositoryName repository) {
250 if (!isWorkspace()) {
251 throw new UnsupportedOperationException("Can only access the external package repository"
252 + "mappings from the //external package");
253 }
254 return externalPackageRepositoryMappings.getOrDefault(repository, ImmutableMap.of());
255 }
256
257 /**
dannarkc7c5ab12018-06-21 14:40:46 -0700258 * Returns the repository mapping for the requested external repository.
dannarkc3495852018-06-04 13:53:22 -0700259 *
260 * @throws LabelSyntaxException if repository is not a valid {@link RepositoryName}
dannarkc7c5ab12018-06-21 14:40:46 -0700261 * @throws UnsupportedOperationException if called from any package other than the //external
262 * package
dannarkc3495852018-06-04 13:53:22 -0700263 */
dannarkc7c5ab12018-06-21 14:40:46 -0700264 public ImmutableMap<RepositoryName, RepositoryName> getRepositoryMapping(String repository)
265 throws LabelSyntaxException, UnsupportedOperationException {
dannarkc3495852018-06-04 13:53:22 -0700266 RepositoryName repositoryName = RepositoryName.create(repository);
267 return getRepositoryMapping(repositoryName);
268 }
269
dannarkc7c5ab12018-06-21 14:40:46 -0700270 /** Get the repository mapping for this package. */
271 public ImmutableMap<RepositoryName, RepositoryName> getRepositoryMapping() {
272 return repositoryMapping;
273 }
274
dannarkc3495852018-06-04 13:53:22 -0700275 /**
276 * Gets the global name for a repository within an external repository.
277 *
278 * <p>{@code localName} is a repository name reference found in a BUILD file within a repository
279 * external to the main workspace. This method returns the main workspace's global remapped name
280 * for {@code localName}.
281 */
282 public RepositoryName getGlobalName(RepositoryName localName) {
283 RepositoryName globalname = repositoryMapping.get(localName);
284 return globalname != null ? globalname : localName;
285 }
286
287 /** Returns whether we are in the WORKSPACE file or not. */
288 public boolean isWorkspace() {
289 return getPackageIdentifier().equals(Label.EXTERNAL_PACKAGE_IDENTIFIER);
290 }
291
292 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100293 * Package initialization: part 2 of 3: sets this package's default header
294 * strictness checking.
295 *
296 * <p>This is needed to support C++-related rule classes
297 * which accesses {@link #getDefaultHdrsCheck} from the still-under-construction
298 * package.
299 */
300 protected void setDefaultHdrsCheck(String defaultHdrsCheck) {
301 this.defaultHdrsCheck = defaultHdrsCheck;
302 }
303
304 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100305 * Set the default 'testonly' value for this package.
306 */
307 protected void setDefaultTestOnly(boolean testOnly) {
308 defaultTestOnly = testOnly;
309 }
310
311 /**
312 * Set the default 'deprecation' value for this package.
313 */
314 protected void setDefaultDeprecation(String deprecation) {
315 defaultDeprecation = deprecation;
316 }
317
318 /**
319 * Sets the default value to use for a rule's {@link RuleClass#COMPATIBLE_ENVIRONMENT_ATTR}
320 * attribute when not explicitly specified by the rule.
321 */
322 protected void setDefaultCompatibleWith(Set<Label> environments) {
323 defaultCompatibleWith = environments;
324 }
325
326 /**
327 * Sets the default value to use for a rule's {@link RuleClass#RESTRICTED_ENVIRONMENT_ATTR}
328 * attribute when not explicitly specified by the rule.
329 */
330 protected void setDefaultRestrictedTo(Set<Label> environments) {
331 defaultRestrictedTo = environments;
332 }
333
Klaus Aehlig6e7c2082018-01-12 10:36:06 -0800334 /**
335 * Returns the source root (a directory) beneath which this package's BUILD file was found.
336 *
tomluee6a6862018-01-17 14:36:26 -0800337 * <p>Assumes invariant: {@code
338 * getSourceRoot().getRelative(packageId.getSourceRoot()).equals(getPackageDirectory())}
Klaus Aehlig6e7c2082018-01-12 10:36:06 -0800339 */
tomluee6a6862018-01-17 14:36:26 -0800340 public Root getSourceRoot() {
Klaus Aehlig6e7c2082018-01-12 10:36:06 -0800341 return sourceRoot;
342 }
343
Ulf Adamsa28b5402017-02-24 09:28:44 +0000344 // This must always be consistent with Root.computeSourceRoot; otherwise computing source roots
345 // from exec paths does not work, which can break the action cache for input-discovering actions.
tomluee6a6862018-01-17 14:36:26 -0800346 private static Root getSourceRoot(Path buildFile, PathFragment packageFragment) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100347 Path current = buildFile.getParentDirectory();
Kristina Chodorowb6fbab72016-01-28 14:38:31 +0000348 for (int i = 0, len = packageFragment.segmentCount();
349 i < len && !packageFragment.equals(PathFragment.EMPTY_FRAGMENT); i++) {
Klaus Aehlig30ef6292018-06-08 07:23:34 -0700350 if (current != null) {
351 current = current.getParentDirectory();
352 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100353 }
tomluee6a6862018-01-17 14:36:26 -0800354 return Root.fromPath(current);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100355 }
356
357 /**
358 * Package initialization: part 3 of 3: applies all other settings and completes
359 * initialization of the package.
360 *
361 * <p>Only after this method is called can this package be considered "complete"
362 * and be shared publicly.
363 */
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +0000364 protected void finishInit(Builder builder) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100365 // If any error occurred during evaluation of this package, consider all
366 // rules in the package to be "in error" also (even if they were evaluated
367 // prior to the error). This behaviour is arguably stricter than need be,
368 // but stopping a build only for some errors but not others creates user
369 // confusion.
370 if (builder.containsErrors) {
371 for (Rule rule : builder.getTargets(Rule.class)) {
372 rule.setContainsErrors();
373 }
374 }
Laurent Le Brun41079bd2015-06-19 09:37:25 +0000375 this.filename = builder.getFilename();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100376 this.packageDirectory = filename.getParentDirectory();
377
Dmitry Lomove36a66c2017-02-17 14:48:48 +0000378 this.sourceRoot = getSourceRoot(filename, packageIdentifier.getSourceRoot());
Klaus Aehlig30ef6292018-06-08 07:23:34 -0700379 if ((sourceRoot.asPath() == null
380 || !sourceRoot.getRelative(packageIdentifier.getSourceRoot()).equals(packageDirectory))
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100381 && !filename.getBaseName().equals("WORKSPACE")) {
382 throw new IllegalArgumentException(
Kristina Chodorowdc30c072015-04-22 13:48:47 +0000383 "Invalid BUILD file name for package '" + packageIdentifier + "': " + filename);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100384 }
kchodorow63570922017-07-11 22:22:22 +0200385
lberki3ef288c2018-03-23 03:06:27 -0700386 this.makeEnv = ImmutableMap.copyOf(builder.makeEnv);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100387 this.targets = ImmutableSortedKeyMap.copyOf(builder.targets);
388 this.defaultVisibility = builder.defaultVisibility;
389 this.defaultVisibilitySet = builder.defaultVisibilitySet;
390 if (builder.defaultCopts == null) {
391 this.defaultCopts = ImmutableList.of();
392 } else {
393 this.defaultCopts = ImmutableList.copyOf(builder.defaultCopts);
394 }
395 this.buildFile = builder.buildFile;
396 this.containsErrors = builder.containsErrors;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100397 this.skylarkFileDependencies = builder.skylarkFileDependencies;
398 this.defaultLicense = builder.defaultLicense;
399 this.defaultDistributionSet = builder.defaultDistributionSet;
400 this.features = ImmutableSortedSet.copyOf(builder.features);
401 this.events = ImmutableList.copyOf(builder.events);
Klaus Aehlig5c04d2a2017-06-13 18:14:15 +0200402 this.posts = ImmutableList.copyOf(builder.posts);
John Cater0084e162018-03-12 18:50:56 -0700403 this.registeredExecutionPlatforms = ImmutableList.copyOf(builder.registeredExecutionPlatforms);
404 this.registeredToolchains = ImmutableList.copyOf(builder.registeredToolchains);
dannarka19a56d2018-06-26 11:55:40 -0700405 this.repositoryMapping = Preconditions.checkNotNull(builder.repositoryMapping);
dannarkc3495852018-06-04 13:53:22 -0700406 ImmutableMap.Builder<RepositoryName, ImmutableMap<RepositoryName, RepositoryName>>
407 repositoryMappingsBuilder = ImmutableMap.builder();
408 if (!builder.externalPackageRepositoryMappings.isEmpty() && !builder.isWorkspace()) {
409 // 'repo_mapping' should only be used in the //external package, i.e. should only appear
410 // in WORKSPACE files. Currently, if someone tries to use 'repo_mapping' in a BUILD rule, they
411 // will get a "no such attribute" error. This check is to protect against a 'repo_mapping'
412 // attribute being added to a rule in the future.
413 throw new IllegalArgumentException(
414 "'repo_mapping' may only be used in the //external package");
415 }
416 builder.externalPackageRepositoryMappings.forEach((k, v) ->
417 repositoryMappingsBuilder.put(k, ImmutableMap.copyOf(v)));
418 this.externalPackageRepositoryMappings = repositoryMappingsBuilder.build();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100419 }
420
421 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100422 * Returns the list of transitive closure of the Skylark file dependencies of this package.
423 */
424 public ImmutableList<Label> getSkylarkFileDependencies() {
425 return skylarkFileDependencies;
426 }
427
428 /**
429 * Returns the filename of the BUILD file which defines this package. The
430 * parent directory of the BUILD file is the package directory.
431 */
432 public Path getFilename() {
433 return filename;
434 }
435
436 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100437 * Returns the directory containing the package's BUILD file.
438 */
439 public Path getPackageDirectory() {
440 return packageDirectory;
441 }
442
443 /**
444 * Returns the name of this package. If this build is using external repositories then this name
445 * may not be unique!
446 */
447 public String getName() {
448 return name;
449 }
450
451 /**
452 * Like {@link #getName}, but has type {@code PathFragment}.
453 */
454 public PathFragment getNameFragment() {
455 return nameFragment;
456 }
457
458 /**
Laurent Le Brune8ce8472015-03-12 14:20:01 +0000459 * Returns all make variables for a given platform.
460 */
lberki3ef288c2018-03-23 03:06:27 -0700461 public ImmutableMap<String, String> getMakeEnvironment() {
462 return makeEnv;
Laurent Le Brune8ce8472015-03-12 14:20:01 +0000463 }
464
465 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100466 * Returns the label of this package's BUILD file.
467 *
Laurent Le Brun41079bd2015-06-19 09:37:25 +0000468 * <p> Typically <code>getBuildFileLabel().getName().equals("BUILD")</code> --
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100469 * though not necessarily: data in a subdirectory of a test package may use a
470 * different filename to avoid inadvertently creating a new package.
471 */
Mark Schaller4fa83ac2015-07-10 16:59:37 +0000472 public Label getBuildFileLabel() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100473 return buildFile.getLabel();
474 }
475
476 /**
477 * Returns the InputFile target for this package's BUILD file.
478 */
479 public InputFile getBuildFile() {
480 return buildFile;
481 }
482
483 /**
484 * Returns true if errors were encountered during evaluation of this package.
485 * (The package may be incomplete and its contents should not be relied upon
486 * for critical operations. However, any Rules belonging to the package are
487 * guaranteed to be intact, unless their <code>containsErrors()</code> flag
488 * is set.)
489 */
490 public boolean containsErrors() {
491 return containsErrors;
492 }
493
Klaus Aehlig5c04d2a2017-06-13 18:14:15 +0200494 public List<Postable> getPosts() {
495 return posts;
496 }
497
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100498 public List<Event> getEvents() {
499 return events;
500 }
501
nharmata59c16f62017-08-07 19:49:09 +0200502 /** Returns an (immutable, ordered) view of all the targets belonging to this package. */
carmi31c6a612017-05-17 22:56:19 +0200503 public ImmutableSortedKeyMap<String, Target> getTargets() {
504 return targets;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100505 }
506
507 /**
carmi31c6a612017-05-17 22:56:19 +0200508 * Common getTargets implementation, accessible by {@link Package.Builder}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100509 */
510 private static Collection<Target> getTargets(Map<String, Target> targetMap) {
511 return Collections.unmodifiableCollection(targetMap.values());
512 }
513
514 /**
nharmata59c16f62017-08-07 19:49:09 +0200515 * Returns a (read-only, ordered) iterable of all the targets belonging
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100516 * to this package which are instances of the specified class.
517 */
518 public <T extends Target> Iterable<T> getTargets(Class<T> targetClass) {
519 return getTargets(targets, targetClass);
520 }
521
522 /**
523 * Common getTargets implementation, accessible by both {@link Package} and
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +0000524 * {@link Package.Builder}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100525 */
526 private static <T extends Target> Iterable<T> getTargets(Map<String, Target> targetMap,
527 Class<T> targetClass) {
528 return Iterables.filter(targetMap.values(), targetClass);
529 }
530
531 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100532 * Returns the rule that corresponds to a particular BUILD target name. Useful
533 * for walking through the dependency graph of a target.
534 * Fails if the target is not a Rule.
535 */
Ulf Adamsb313a972015-05-04 12:05:57 +0000536 @VisibleForTesting // Should be package-private
537 public Rule getRule(String targetName) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100538 return (Rule) targets.get(targetName);
539 }
540
John Caterb4f461e2016-10-25 16:16:35 +0000541 /** Returns all rules in the package that match the given rule class. */
542 public Iterable<Rule> getRulesMatchingRuleClass(final String ruleClass) {
543 Iterable<Rule> targets = getTargets(Rule.class);
laurentlb3d2a68c2017-06-30 00:32:04 +0200544 return Iterables.filter(targets, rule -> rule.getRuleClass().equals(ruleClass));
John Caterb4f461e2016-10-25 16:16:35 +0000545 }
546
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100547 /**
Kristina Chodorow91876f02015-02-27 17:14:12 +0000548 * Returns this package's workspace name.
Kristina Chodorow91876f02015-02-27 17:14:12 +0000549 */
Kristina Chodorow734e7f72016-01-29 15:04:31 +0000550 public String getWorkspaceName() {
Kristina Chodorow91876f02015-02-27 17:14:12 +0000551 return workspaceName;
552 }
553
554 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100555 * Returns the features specified in the <code>package()</code> declaration.
556 */
557 public ImmutableSet<String> getFeatures() {
558 return features;
559 }
560
561 /**
562 * Returns the target (a member of this package) whose name is "targetName".
563 * First rules are searched, then output files, then input files. The target
564 * name must be valid, as defined by {@code LabelValidator#validateTargetName}.
565 *
566 * @throws NoSuchTargetException if the specified target was not found.
567 */
568 public Target getTarget(String targetName) throws NoSuchTargetException {
569 Target target = targets.get(targetName);
570 if (target != null) {
571 return target;
572 }
573
574 // No such target.
575
576 // If there's a file on the disk that's not mentioned in the BUILD file,
577 // produce a more informative error. NOTE! this code path is only executed
578 // on failure, which is (relatively) very rare. In the common case no
579 // stat(2) is executed.
580 Path filename = getPackageDirectory().getRelative(targetName);
581 String suffix;
twerthc4ba94c2018-05-30 11:48:57 -0700582 if (!PathFragment.isNormalized(targetName) || "*".equals(targetName)) {
583 // Don't check for file existence if the target name is not normalized
584 // because the error message would be confusing and wrong. If the
585 // targetName is "foo/bar/.", and there is a directory "foo/bar", it
586 // doesn't mean that "//pkg:foo/bar/." is a valid label.
587 // Also don't check if the target name is a single * character since
588 // it's invalid on Windows.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100589 suffix = "";
590 } else if (filename.isDirectory()) {
591 suffix = "; however, a source directory of this name exists. (Perhaps add "
592 + "'exports_files([\"" + targetName + "\"])' to " + name + "/BUILD, or define a "
593 + "filegroup?)";
594 } else if (filename.exists()) {
595 suffix = "; however, a source file of this name exists. (Perhaps add "
596 + "'exports_files([\"" + targetName + "\"])' to " + name + "/BUILD?)";
597 } else {
Laurent Le Brun57badf42017-01-02 15:12:24 +0000598 suffix = SpellChecker.didYouMean(targetName, targets.keySet());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100599 }
600
Nathan Harmata42fb5602016-05-25 20:32:08 +0000601 throw makeNoSuchTargetException(targetName, suffix);
602 }
603
604 protected NoSuchTargetException makeNoSuchTargetException(String targetName, String suffix) {
605 Label label;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100606 try {
Nathan Harmata42fb5602016-05-25 20:32:08 +0000607 label = createLabel(targetName);
Lukacs Berkia6434362015-09-15 13:56:14 +0000608 } catch (LabelSyntaxException e) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100609 throw new IllegalArgumentException(targetName);
610 }
Nathan Harmata42fb5602016-05-25 20:32:08 +0000611 String msg = String.format(
612 "target '%s' not declared in package '%s'%s defined by %s",
613 targetName,
614 name,
615 suffix,
616 filename);
617 return new NoSuchTargetException(label, msg);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100618 }
619
620 /**
621 * Creates a label for a target inside this package.
622 *
Lukacs Berkia6434362015-09-15 13:56:14 +0000623 * @throws LabelSyntaxException if the {@code targetName} is invalid
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100624 */
Lukacs Berkia6434362015-09-15 13:56:14 +0000625 public Label createLabel(String targetName) throws LabelSyntaxException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100626 return Label.create(packageIdentifier, targetName);
627 }
628
629 /**
630 * Returns the default visibility for this package.
631 */
632 public RuleVisibility getDefaultVisibility() {
Laurent Le Brun41079bd2015-06-19 09:37:25 +0000633 return defaultVisibility;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100634 }
635
636 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100637 * Returns the default testonly value.
638 */
639 public Boolean getDefaultTestOnly() {
640 return defaultTestOnly;
641 }
642
643 /**
Greg Estrenc48214d2015-03-17 22:43:19 +0000644 * Returns the default deprecation value.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100645 */
646 public String getDefaultDeprecation() {
647 return defaultDeprecation;
648 }
649
Carmi Grushko81dca612016-07-27 02:12:15 +0000650 /** Gets the default header checking mode. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100651 public String getDefaultHdrsCheck() {
Googler198a54f2016-01-18 11:02:10 +0000652 return defaultHdrsCheck != null ? defaultHdrsCheck : "strict";
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100653 }
654
655 /**
656 * Returns the default copts value, to which rules should append their
657 * specific copts.
658 */
659 public ImmutableList<String> getDefaultCopts() {
660 return defaultCopts;
661 }
662
663 /**
664 * Returns whether the default header checking mode has been set or it is the
665 * default value.
666 */
667 public boolean isDefaultHdrsCheckSet() {
668 return defaultHdrsCheck != null;
669 }
670
671 public boolean isDefaultVisibilitySet() {
672 return defaultVisibilitySet;
673 }
674
675 /**
676 * Gets the parsed license object for the default license
677 * declared by this package.
678 */
679 public License getDefaultLicense() {
680 return defaultLicense;
681 }
682
683 /**
684 * Returns the parsed set of distributions declared as the default for this
685 * package.
686 */
687 public Set<License.DistributionType> getDefaultDistribs() {
688 return defaultDistributionSet;
689 }
690
691 /**
692 * Returns the default value to use for a rule's {@link RuleClass#COMPATIBLE_ENVIRONMENT_ATTR}
693 * attribute when not explicitly specified by the rule.
694 */
695 public Set<Label> getDefaultCompatibleWith() {
696 return defaultCompatibleWith;
697 }
698
699 /**
700 * Returns the default value to use for a rule's {@link RuleClass#RESTRICTED_ENVIRONMENT_ATTR}
701 * attribute when not explicitly specified by the rule.
702 */
703 public Set<Label> getDefaultRestrictedTo() {
704 return defaultRestrictedTo;
705 }
706
John Cater0084e162018-03-12 18:50:56 -0700707 public ImmutableList<String> getRegisteredExecutionPlatforms() {
708 return registeredExecutionPlatforms;
John Cater0b29e642018-01-22 05:21:06 -0800709 }
710
John Cater0084e162018-03-12 18:50:56 -0700711 public ImmutableList<String> getRegisteredToolchains() {
712 return registeredToolchains;
John Cater64a6c152017-07-11 16:50:27 +0200713 }
714
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100715 @Override
716 public String toString() {
Han-Wen Nienhuys58070da2015-04-20 11:37:58 +0000717 return "Package(" + name + ")="
718 + (targets != null ? getTargets(Rule.class) : "initializing...");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100719 }
720
721 /**
722 * Dumps the package for debugging. Do not depend on the exact format/contents of this debugging
723 * output.
724 */
725 public void dump(PrintStream out) {
726 out.println(" Package " + getName() + " (" + getFilename() + ")");
727
728 // Rules:
729 out.println(" Rules");
730 for (Rule rule : getTargets(Rule.class)) {
731 out.println(" " + rule.getTargetKind() + " " + rule.getLabel());
732 for (Attribute attr : rule.getAttributes()) {
733 for (Object possibleValue : AggregatingAttributeMapper.of(rule)
734 .visitAttribute(attr.getName(), attr.getType())) {
735 out.println(" " + attr.getName() + " = " + possibleValue);
736 }
737 }
738 }
739
740 // Files:
741 out.println(" Files");
742 for (FileTarget file : getTargets(FileTarget.class)) {
743 out.print(" " + file.getTargetKind() + " " + file.getLabel());
744 if (file instanceof OutputFile) {
745 out.println(" (generated by " + ((OutputFile) file).getGeneratingRule().getLabel() + ")");
746 } else {
747 out.println();
748 }
749 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100750 }
751
Nathan Harmata42fb5602016-05-25 20:32:08 +0000752 public static Builder newExternalPackageBuilder(Builder.Helper helper, Path workspacePath,
753 String runfilesPrefix) {
754 Builder b = new Builder(helper.createFreshPackage(
755 Label.EXTERNAL_PACKAGE_IDENTIFIER, runfilesPrefix));
Han-Wen Nienhuysf172d392015-09-18 17:37:51 +0000756 b.setFilename(workspacePath);
Han-Wen Nienhuysf172d392015-09-18 17:37:51 +0000757 return b;
758 }
759
Nathan Harmatacaa000a2016-06-07 17:46:19 +0000760 /**
761 * A builder for {@link Package} objects. Only intended to be used by {@link PackageFactory} and
762 * {@link com.google.devtools.build.lib.skyframe.PackageFunction}.
763 */
Han-Wen Nienhuysf172d392015-09-18 17:37:51 +0000764 public static class Builder {
John Cater64a6c152017-07-11 16:50:27 +0200765
nharmata23319fc2018-02-28 13:03:12 -0800766 public interface Helper {
Nathan Harmata42fb5602016-05-25 20:32:08 +0000767 /**
768 * Returns a fresh {@link Package} instance that a {@link Builder} will internally mutate
Nathan Harmatacaa000a2016-06-07 17:46:19 +0000769 * during package loading. Called by {@link PackageFactory}.
Nathan Harmata42fb5602016-05-25 20:32:08 +0000770 */
771 Package createFreshPackage(PackageIdentifier packageId, String runfilesPrefix);
Nathan Harmatacaa000a2016-06-07 17:46:19 +0000772
773 /**
774 * Called after {@link com.google.devtools.build.lib.skyframe.PackageFunction} is completely
nharmata23319fc2018-02-28 13:03:12 -0800775 * done loading the given {@link Package}.
776 *
777 * @param pkg the loaded {@link Package}
778 * @param skylarkSemantics are the semantics used to load the package
nharmataa2fc4e32018-03-07 16:25:10 -0800779 * @param loadTimeMs the wall time, in ms, that it took to load the package. More precisely,
780 * this is the wall time of the call to {@link PackageFactory#createPackageFromAst}.
781 * Notably, this does not include the time to read and parse the package's BUILD file, nor
782 * the time to read, parse, or evaluate any of the transitively loaded .bzl files.
Nathan Harmatacaa000a2016-06-07 17:46:19 +0000783 */
nharmata23319fc2018-02-28 13:03:12 -0800784 void onLoadingComplete(Package pkg, SkylarkSemantics skylarkSemantics, long loadTimeMs);
Nathan Harmata42fb5602016-05-25 20:32:08 +0000785 }
786
787 /** {@link Helper} that simply calls the {@link Package} constructor. */
788 public static class DefaultHelper implements Helper {
789 public static final DefaultHelper INSTANCE = new DefaultHelper();
790
791 private DefaultHelper() {
792 }
793
794 @Override
795 public Package createFreshPackage(PackageIdentifier packageId, String runfilesPrefix) {
796 return new Package(packageId, runfilesPrefix);
797 }
Nathan Harmatacaa000a2016-06-07 17:46:19 +0000798
799 @Override
nharmata23319fc2018-02-28 13:03:12 -0800800 public void onLoadingComplete(
801 Package pkg, SkylarkSemantics skylarkSemantics, long loadTimeMs) {
Nathan Harmatacaa000a2016-06-07 17:46:19 +0000802 }
Ulf Adams4226be22015-09-03 17:00:54 +0000803 }
804
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100805 /**
806 * The output instance for this builder. Needs to be instantiated and
807 * available with name info throughout initialization. All other settings
Michajlo Matijkiw17f11eb2015-10-14 04:19:28 +0000808 * are applied during {@link #build}. See {@link Package#Package}
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100809 * and {@link Package#finishInit} for details.
810 */
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +0000811 protected Package pkg;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100812
dannarkc3495852018-06-04 13:53:22 -0700813 // The map from each repository to that repository's remappings map.
814 // This is only used in the //external package, it is an empty map for all other packages.
815 private final HashMap<RepositoryName, HashMap<RepositoryName, RepositoryName>>
816 externalPackageRepositoryMappings = new HashMap<>();
817 // The map of repository reassignments for BUILD packages loaded within external repositories.
dannarkc82074a2018-08-01 16:01:23 -0700818 // It contains an entry from "@<main workspace name>" to "@" for packages within
819 // the main workspace.
dannarkc3495852018-06-04 13:53:22 -0700820 private ImmutableMap<RepositoryName, RepositoryName> repositoryMapping = ImmutableMap.of();
Laurent Le Brun41079bd2015-06-19 09:37:25 +0000821 private Path filename = null;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100822 private Label buildFileLabel = null;
823 private InputFile buildFile = null;
lberki3ef288c2018-03-23 03:06:27 -0700824 // TreeMap so that the iteration order of variables is predictable. This is useful so that the
825 // serialized representation is deterministic.
826 private TreeMap<String, String> makeEnv = new TreeMap<>();
Laurent Le Brun41079bd2015-06-19 09:37:25 +0000827 private RuleVisibility defaultVisibility = ConstantRuleVisibility.PRIVATE;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100828 private boolean defaultVisibilitySet;
829 private List<String> defaultCopts = null;
830 private List<String> features = new ArrayList<>();
831 private List<Event> events = Lists.newArrayList();
Klaus Aehlig5c04d2a2017-06-13 18:14:15 +0200832 private List<Postable> posts = Lists.newArrayList();
janakr28adce52017-07-13 19:55:32 +0200833 @Nullable String ioExceptionMessage = null;
834 @Nullable private IOException ioException = null;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100835 private boolean containsErrors = false;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100836
837 private License defaultLicense = License.NO_LICENSE;
838 private Set<License.DistributionType> defaultDistributionSet = License.DEFAULT_DISTRIB;
839
840 protected Map<String, Target> targets = new HashMap<>();
841 protected Map<Label, EnvironmentGroup> environmentGroups = new HashMap<>();
842
Kristina Chodorow91876f02015-02-27 17:14:12 +0000843 protected ImmutableList<Label> skylarkFileDependencies = ImmutableList.of();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100844
John Cater0084e162018-03-12 18:50:56 -0700845 protected List<String> registeredExecutionPlatforms = new ArrayList<>();
846 protected List<String> registeredToolchains = new ArrayList<>();
John Cater64a6c152017-07-11 16:50:27 +0200847
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100848 /**
849 * True iff the "package" function has already been called in this package.
850 */
851 private boolean packageFunctionUsed;
852
853 /**
854 * The collection of the prefixes of every output file. Maps every prefix
855 * to an output file whose prefix it is.
856 *
857 * <p>This is needed to make the output file prefix conflict check be
858 * reasonably fast. However, since it can potentially take a lot of memory and
859 * is useless after the package has been loaded, it isn't passed to the
860 * package itself.
861 */
862 private Map<String, OutputFile> outputFilePrefixes = new HashMap<>();
863
864 private boolean alreadyBuilt = false;
865
866 private EventHandler builderEventHandler = new EventHandler() {
867 @Override
868 public void handle(Event event) {
869 addEvent(event);
870 }
871 };
872
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +0000873 protected Builder(Package pkg) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100874 this.pkg = pkg;
875 if (pkg.getName().startsWith("javatests/")) {
876 setDefaultTestonly(true);
877 }
878 }
879
Nathan Harmata42fb5602016-05-25 20:32:08 +0000880 public Builder(Helper helper, PackageIdentifier id, String runfilesPrefix) {
881 this(helper.createFreshPackage(id, runfilesPrefix));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100882 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100883
884 protected PackageIdentifier getPackageIdentifier() {
885 return pkg.getPackageIdentifier();
886 }
887
Damien Martin-Guillerez8ca065c22015-11-27 16:22:59 +0000888 /** Determine if we are in the WORKSPACE file or not */
889 public boolean isWorkspace() {
Lukacs Berkie19ee272015-12-10 11:34:29 +0000890 return pkg.getPackageIdentifier().equals(Label.EXTERNAL_PACKAGE_IDENTIFIER);
Damien Martin-Guillerez8ca065c22015-11-27 16:22:59 +0000891 }
892
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100893 /**
dannarkc3495852018-06-04 13:53:22 -0700894 * Updates the externalPackageRepositoryMappings entry for {@code repoWithin}. Adds new
895 * entry from {@code localName} to {@code mappedName} in {@code repoWithin}'s map.
896 *
897 * @param repoWithin the RepositoryName within which the mapping should apply
898 * @param localName the RepositoryName that actually appears in the WORKSPACE and BUILD files
899 * in the {@code repoWithin} repository
900 * @param mappedName the RepositoryName by which localName should be referenced
901 */
902 public Builder addRepositoryMappingEntry(
903 RepositoryName repoWithin, RepositoryName localName, RepositoryName mappedName) {
904 HashMap<RepositoryName, RepositoryName> mapping =
905 externalPackageRepositoryMappings
906 .computeIfAbsent(repoWithin, (RepositoryName k) -> new HashMap<>());
907 mapping.put(localName, mappedName);
908 return this;
909 }
910
911 /** Adds all the mappings from a given {@link Package}. */
912 public Builder addRepositoryMappings(Package aPackage) {
913 ImmutableMap<RepositoryName, ImmutableMap<RepositoryName, RepositoryName>>
914 repositoryMappings = aPackage.externalPackageRepositoryMappings;
915 for (Map.Entry<RepositoryName, ImmutableMap<RepositoryName, RepositoryName>> repositoryName :
916 repositoryMappings.entrySet()) {
917 for (Map.Entry<RepositoryName, RepositoryName> repositoryNameRepositoryNameEntry :
918 repositoryName.getValue().entrySet()) {
919 addRepositoryMappingEntry(
920 repositoryName.getKey(),
921 repositoryNameRepositoryNameEntry.getKey(),
922 repositoryNameRepositoryNameEntry.getValue());
923 }
924 }
925 return this;
926 }
927
928 /**
929 * Sets the repository mapping for a regular, BUILD file package (i.e. not the //external
930 * package)
931 */
932 Builder setRepositoryMapping(ImmutableMap<RepositoryName, RepositoryName> repositoryMapping) {
dannarka19a56d2018-06-26 11:55:40 -0700933 this.repositoryMapping = Preconditions.checkNotNull(repositoryMapping);
dannarkc3495852018-06-04 13:53:22 -0700934 return this;
935 }
936
dannarkf24479d2018-06-21 11:55:44 -0700937 /** Get the repository mapping for this package */
938 ImmutableMap<RepositoryName, RepositoryName> getRepositoryMapping() {
939 return this.repositoryMapping;
940 }
941
dannarkc3495852018-06-04 13:53:22 -0700942 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100943 * Sets the name of this package's BUILD file.
944 */
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +0000945 Builder setFilename(Path filename) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100946 this.filename = filename;
947 try {
948 buildFileLabel = createLabel(filename.getBaseName());
949 addInputFile(buildFileLabel, Location.fromFile(filename));
Lukacs Berkia6434362015-09-15 13:56:14 +0000950 } catch (LabelSyntaxException e) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100951 // This can't actually happen.
952 throw new AssertionError("Package BUILD file has an illegal name: " + filename);
953 }
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +0000954 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100955 }
956
957 public Label getBuildFileLabel() {
958 return buildFileLabel;
959 }
960
961 Path getFilename() {
962 return filename;
963 }
964
Klaus Aehlig5c04d2a2017-06-13 18:14:15 +0200965 public List<Postable> getPosts() {
966 return posts;
967 }
968
Janak Ramakrishnan0a4c6e42015-09-17 00:37:58 +0000969 public List<Event> getEvents() {
970 return events;
971 }
972
lberki3ef288c2018-03-23 03:06:27 -0700973 Builder setMakeVariable(String name, String value) {
974 this.makeEnv.put(name, value);
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +0000975 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100976 }
977
978 /**
979 * Sets the default visibility for this package. Called at most once per
980 * package from PackageFactory.
981 */
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +0000982 Builder setDefaultVisibility(RuleVisibility visibility) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100983 this.defaultVisibility = visibility;
984 this.defaultVisibilitySet = true;
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +0000985 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100986 }
987
988 /**
989 * Sets whether the default visibility is set in the BUILD file.
990 */
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +0000991 Builder setDefaultVisibilitySet(boolean defaultVisibilitySet) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100992 this.defaultVisibilitySet = defaultVisibilitySet;
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +0000993 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100994 }
995
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100996 /** Sets the default value of 'testonly'. Rule-level 'testonly' will override this. */
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +0000997 Builder setDefaultTestonly(boolean defaultTestonly) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100998 pkg.setDefaultTestOnly(defaultTestonly);
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +0000999 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001000 }
1001
1002 /**
1003 * Sets the default value of 'deprecation'. Rule-level 'deprecation' will append to this.
1004 */
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001005 Builder setDefaultDeprecation(String defaultDeprecation) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001006 pkg.setDefaultDeprecation(defaultDeprecation);
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001007 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001008 }
1009
1010 /**
Kristina Chodorow91876f02015-02-27 17:14:12 +00001011 * Uses the workspace name from {@code //external} to set this package's workspace name.
1012 */
Han-Wen Nienhuys2cffe032015-09-21 15:28:40 +00001013 @VisibleForTesting
1014 public Builder setWorkspaceName(String workspaceName) {
Kristina Chodorow91876f02015-02-27 17:14:12 +00001015 pkg.workspaceName = workspaceName;
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001016 return this;
Kristina Chodorow91876f02015-02-27 17:14:12 +00001017 }
1018
1019 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001020 * Returns whether the "package" function has been called yet
1021 */
1022 public boolean isPackageFunctionUsed() {
1023 return packageFunctionUsed;
1024 }
1025
1026 public void setPackageFunctionUsed() {
1027 packageFunctionUsed = true;
1028 }
1029
1030 /**
1031 * Sets the default header checking mode.
1032 */
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001033 public Builder setDefaultHdrsCheck(String hdrsCheck) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001034 // Note that this setting is propagated directly to the package because
1035 // other code needs the ability to read this info directly from the
1036 // under-construction package. See {@link Package#setDefaultHdrsCheck}.
1037 pkg.setDefaultHdrsCheck(hdrsCheck);
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001038 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001039 }
1040
Carmi Grushko81dca612016-07-27 02:12:15 +00001041 /** Sets the default value of copts. Rule-level copts will append to this. */
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001042 public Builder setDefaultCopts(List<String> defaultCopts) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001043 this.defaultCopts = defaultCopts;
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001044 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001045 }
1046
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001047 public Builder addFeatures(Iterable<String> features) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001048 Iterables.addAll(this.features, features);
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001049 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001050 }
1051
janakr28adce52017-07-13 19:55:32 +02001052 Builder setIOExceptionAndMessage(IOException e, String message) {
1053 this.ioException = e;
1054 this.ioExceptionMessage = message;
1055 return setContainsErrors();
1056 }
1057
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001058 /**
1059 * Declares that errors were encountering while loading this package.
1060 */
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001061 public Builder setContainsErrors() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001062 containsErrors = true;
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001063 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001064 }
1065
1066 public boolean containsErrors() {
1067 return containsErrors;
1068 }
1069
Klaus Aehlig5c04d2a2017-06-13 18:14:15 +02001070 public Builder addPosts(Iterable<Postable> posts) {
1071 for (Postable post : posts) {
1072 addPost(post);
1073 }
1074 return this;
1075 }
1076
1077 public Builder addPost(Postable post) {
1078 this.posts.add(post);
1079 return this;
1080 }
1081
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001082 public Builder addEvents(Iterable<Event> events) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001083 for (Event event : events) {
1084 addEvent(event);
1085 }
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001086 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001087 }
1088
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001089 public Builder addEvent(Event event) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001090 this.events.add(event);
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001091 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001092 }
1093
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001094 Builder setSkylarkFileDependencies(ImmutableList<Label> skylarkFileDependencies) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001095 this.skylarkFileDependencies = skylarkFileDependencies;
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001096 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001097 }
1098
1099 /**
1100 * Sets the default license for this package.
1101 */
1102 void setDefaultLicense(License license) {
1103 this.defaultLicense = license;
1104 }
1105
1106 License getDefaultLicense() {
1107 return defaultLicense;
1108 }
1109
1110 /**
1111 * Initializes the default set of distributions for targets in this package.
1112 *
Laurent Le Brun41079bd2015-06-19 09:37:25 +00001113 * <p> TODO(bazel-team): (2011) consider moving the license & distribs info into Metadata--maybe
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001114 * even in the Build language.
1115 */
1116 void setDefaultDistribs(Set<DistributionType> dists) {
1117 this.defaultDistributionSet = dists;
1118 }
1119
1120 Set<DistributionType> getDefaultDistribs() {
1121 return defaultDistributionSet;
1122 }
1123
1124 /**
1125 * Sets the default value to use for a rule's {@link RuleClass#COMPATIBLE_ENVIRONMENT_ATTR}
1126 * attribute when not explicitly specified by the rule. Records a package error if
1127 * any labels are duplicated.
1128 */
1129 void setDefaultCompatibleWith(List<Label> environments, String attrName, Location location) {
1130 if (!checkForDuplicateLabels(environments, "package " + pkg.getName(), attrName, location,
1131 builderEventHandler)) {
1132 setContainsErrors();
1133 }
1134 pkg.setDefaultCompatibleWith(ImmutableSet.copyOf(environments));
1135 }
1136
1137 /**
1138 * Sets the default value to use for a rule's {@link RuleClass#RESTRICTED_ENVIRONMENT_ATTR}
1139 * attribute when not explicitly specified by the rule. Records a package error if
1140 * any labels are duplicated.
1141 */
1142 void setDefaultRestrictedTo(List<Label> environments, String attrName, Location location) {
1143 if (!checkForDuplicateLabels(environments, "package " + pkg.getName(), attrName, location,
1144 builderEventHandler)) {
1145 setContainsErrors();
1146 }
1147
1148 pkg.setDefaultRestrictedTo(ImmutableSet.copyOf(environments));
1149 }
1150
1151 /**
Mark Schalleree624452016-01-13 18:41:24 +00001152 * Creates a new {@link Rule} {@code r} where {@code r.getPackage()} is the {@link Package}
1153 * associated with this {@link Builder}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001154 *
Mark Schalleree624452016-01-13 18:41:24 +00001155 * <p>The created {@link Rule} will have no attribute values, no output files, and therefore
1156 * will be in an invalid state.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001157 */
Mark Schalleree624452016-01-13 18:41:24 +00001158 Rule createRule(
1159 Label label,
1160 RuleClass ruleClass,
1161 Location location,
Michajlo Matijkiw1a759072015-10-22 13:52:00 +00001162 AttributeContainer attributeContainer) {
Michajlo Matijkiw6d471412016-08-09 20:35:45 +00001163 return new Rule(
1164 pkg,
1165 label,
1166 ruleClass,
1167 location,
1168 attributeContainer);
1169 }
1170
1171 /**
Michajlo Matijkiw0433a682016-08-15 15:02:36 +00001172 * Same as {@link #createRule(Label, RuleClass, Location, AttributeContainer)}, except
Michajlo Matijkiw6d471412016-08-09 20:35:45 +00001173 * allows specifying an {@link ImplicitOutputsFunction} override. Only use if you know what
1174 * you're doing.
1175 */
1176 Rule createRule(
1177 Label label,
1178 RuleClass ruleClass,
1179 Location location,
1180 AttributeContainer attributeContainer,
1181 ImplicitOutputsFunction implicitOutputsFunction) {
1182 return new Rule(
1183 pkg,
1184 label,
1185 ruleClass,
1186 location,
1187 attributeContainer,
1188 implicitOutputsFunction);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001189 }
1190
Han-Wen Nienhuys67e6f982016-01-15 15:54:12 +00001191 @Nullable
1192 public Target getTarget(String name) {
1193 return targets.get(name);
1194 }
1195
Klaus Aehlig6e7c2082018-01-12 10:36:06 -08001196 public Collection<Target> getTargets() {
1197 return Package.getTargets(targets);
1198 }
1199
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001200 /**
1201 * Returns an (immutable, unordered) view of all the targets belonging to
1202 * this package which are instances of the specified class.
1203 */
1204 <T extends Target> Iterable<T> getTargets(Class<T> targetClass) {
1205 return Package.getTargets(targets, targetClass);
1206 }
1207
1208 /**
1209 * An input file name conflicts with an existing package member.
1210 */
1211 static class GeneratedLabelConflict extends NameConflictException {
1212 private GeneratedLabelConflict(String message) {
1213 super(message);
1214 }
1215 }
1216
1217 /**
1218 * Creates an input file target in this package with the specified name.
1219 *
1220 * @param targetName name of the input file. This must be a valid target
1221 * name as defined by {@link
1222 * com.google.devtools.build.lib.cmdline.LabelValidator#validateTargetName}.
1223 * @return the newly-created InputFile, or the old one if it already existed.
1224 * @throws GeneratedLabelConflict if the name was already taken by a Rule or
1225 * an OutputFile target.
1226 * @throws IllegalArgumentException if the name is not a valid label
1227 */
1228 InputFile createInputFile(String targetName, Location location)
1229 throws GeneratedLabelConflict {
1230 Target existing = targets.get(targetName);
1231 if (existing == null) {
1232 try {
1233 return addInputFile(createLabel(targetName), location);
Lukacs Berkia6434362015-09-15 13:56:14 +00001234 } catch (LabelSyntaxException e) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001235 throw new IllegalArgumentException("FileTarget in package " + pkg.getName()
1236 + " has illegal name: " + targetName);
1237 }
1238 } else if (existing instanceof InputFile) {
1239 return (InputFile) existing; // idempotent
1240 } else {
1241 throw new GeneratedLabelConflict("generated label '//" + pkg.getName() + ":"
1242 + targetName + "' conflicts with existing "
1243 + existing.getTargetKind());
1244 }
1245 }
1246
1247 /**
1248 * Sets the visibility and license for an input file. The input file must already exist as
1249 * a member of this package.
1250 * @throws IllegalArgumentException if the input file doesn't exist in this
1251 * package's target map.
1252 */
1253 void setVisibilityAndLicense(InputFile inputFile, RuleVisibility visibility, License license) {
1254 String filename = inputFile.getName();
1255 Target cacheInstance = targets.get(filename);
Ulf Adams07dba942015-03-05 14:47:37 +00001256 if (!(cacheInstance instanceof InputFile)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001257 throw new IllegalArgumentException("Can't set visibility for nonexistent FileTarget "
1258 + filename + " in package " + pkg.getName() + ".");
1259 }
1260 if (!((InputFile) cacheInstance).isVisibilitySpecified()
1261 || cacheInstance.getVisibility() != visibility
lberki0d8d4cf2017-09-05 16:01:44 +02001262 || !Objects.equals(cacheInstance.getLicense(), license)) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001263 targets.put(filename, new InputFile(
1264 pkg, cacheInstance.getLabel(), cacheInstance.getLocation(), visibility, license));
1265 }
1266 }
1267
1268 /**
1269 * Creates a label for a target inside this package.
1270 *
Lukacs Berkia6434362015-09-15 13:56:14 +00001271 * @throws LabelSyntaxException if the {@code targetName} is invalid
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001272 */
Lukacs Berkia6434362015-09-15 13:56:14 +00001273 Label createLabel(String targetName) throws LabelSyntaxException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001274 return Label.create(pkg.getPackageIdentifier(), targetName);
1275 }
1276
1277 /**
1278 * Adds a package group to the package.
1279 */
1280 void addPackageGroup(String name, Collection<String> packages, Collection<Label> includes,
1281 EventHandler eventHandler, Location location)
Lukacs Berkia6434362015-09-15 13:56:14 +00001282 throws NameConflictException, LabelSyntaxException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001283 PackageGroup group =
1284 new PackageGroup(createLabel(name), pkg, packages, includes, eventHandler, location);
1285 Target existing = targets.get(group.getName());
1286 if (existing != null) {
1287 throw nameConflict(group, existing);
1288 }
1289
1290 targets.put(group.getName(), group);
1291
1292 if (group.containsErrors()) {
1293 setContainsErrors();
1294 }
1295 }
1296
1297 /**
1298 * Checks if any labels in the given list appear multiple times and reports an appropriate
1299 * error message if so. Returns true if no duplicates were found, false otherwise.
1300 *
Laurent Le Brun41079bd2015-06-19 09:37:25 +00001301 * <p> TODO(bazel-team): apply this to all build functions (maybe automatically?), possibly
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001302 * integrate with RuleClass.checkForDuplicateLabels.
1303 */
1304 private static boolean checkForDuplicateLabels(Collection<Label> labels, String owner,
1305 String attrName, Location location, EventHandler eventHandler) {
1306 Set<Label> dupes = CollectionUtils.duplicatedElementsOf(labels);
1307 for (Label dupe : dupes) {
1308 eventHandler.handle(Event.error(location, String.format(
1309 "label '%s' is duplicated in the '%s' list of '%s'", dupe, attrName, owner)));
1310 }
1311 return dupes.isEmpty();
1312 }
1313
1314 /**
1315 * Adds an environment group to the package.
1316 */
1317 void addEnvironmentGroup(String name, List<Label> environments, List<Label> defaults,
1318 EventHandler eventHandler, Location location)
Lukacs Berkia6434362015-09-15 13:56:14 +00001319 throws NameConflictException, LabelSyntaxException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001320
1321 if (!checkForDuplicateLabels(environments, name, "environments", location, eventHandler)
1322 || !checkForDuplicateLabels(defaults, name, "defaults", location, eventHandler)) {
1323 setContainsErrors();
1324 return;
1325 }
1326
1327 EnvironmentGroup group = new EnvironmentGroup(createLabel(name), pkg, environments,
1328 defaults, location);
1329 Target existing = targets.get(group.getName());
1330 if (existing != null) {
1331 throw nameConflict(group, existing);
1332 }
1333
1334 targets.put(group.getName(), group);
1335 Collection<Event> membershipErrors = group.validateMembership();
1336 if (!membershipErrors.isEmpty()) {
1337 for (Event error : membershipErrors) {
1338 eventHandler.handle(error);
1339 }
1340 setContainsErrors();
1341 return;
1342 }
1343
1344 // For each declared environment, make sure it doesn't also belong to some other group.
1345 for (Label environment : group.getEnvironments()) {
1346 EnvironmentGroup otherGroup = environmentGroups.get(environment);
1347 if (otherGroup != null) {
1348 eventHandler.handle(Event.error(location, "environment " + environment + " belongs to"
1349 + " both " + group.getLabel() + " and " + otherGroup.getLabel()));
1350 setContainsErrors();
1351 } else {
1352 environmentGroups.put(environment, group);
1353 }
1354 }
1355 }
1356
Nathan Harmatacf738442016-06-28 14:52:21 +00001357 /**
1358 * Same as {@link #addRule}, except with no name conflict checks.
1359 *
1360 * <p>Don't call this function unless you know what you're doing.
1361 */
1362 void addRuleUnchecked(Rule rule) {
Lukacs Berki4867ef72016-05-17 11:15:19 +00001363 Preconditions.checkArgument(rule.getPackage() == pkg);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001364 // Now, modify the package:
1365 for (OutputFile outputFile : rule.getOutputFiles()) {
1366 targets.put(outputFile.getName(), outputFile);
nharmatab4060b62017-04-04 17:11:39 +00001367 PathFragment outputFileFragment = PathFragment.create(outputFile.getName());
tomlue7552c52018-01-19 10:25:19 -08001368 int segmentCount = outputFileFragment.segmentCount();
1369 for (int i = 1; i < segmentCount; i++) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001370 String prefix = outputFileFragment.subFragment(0, i).toString();
laurentlb3d2a68c2017-06-30 00:32:04 +02001371 outputFilePrefixes.putIfAbsent(prefix, outputFile);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001372 }
1373 }
1374 targets.put(rule.getName(), rule);
1375 if (rule.containsErrors()) {
1376 this.setContainsErrors();
1377 }
1378 }
1379
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +00001380 void addRule(Rule rule) throws NameConflictException, InterruptedException {
Nathan Harmatacf738442016-06-28 14:52:21 +00001381 checkForConflicts(rule);
1382 addRuleUnchecked(rule);
1383 }
1384
John Cater0084e162018-03-12 18:50:56 -07001385 public void addRegisteredExecutionPlatforms(List<String> platforms) {
1386 this.registeredExecutionPlatforms.addAll(platforms);
John Cater0b29e642018-01-22 05:21:06 -08001387 }
1388
John Cater0084e162018-03-12 18:50:56 -07001389 void addRegisteredToolchains(List<String> toolchains) {
1390 this.registeredToolchains.addAll(toolchains);
John Cater64a6c152017-07-11 16:50:27 +02001391 }
1392
janakr28adce52017-07-13 19:55:32 +02001393 private Builder beforeBuild(boolean discoverAssumedInputFiles)
1394 throws InterruptedException, NoSuchPackageException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001395 Preconditions.checkNotNull(pkg);
1396 Preconditions.checkNotNull(filename);
1397 Preconditions.checkNotNull(buildFileLabel);
1398 Preconditions.checkNotNull(makeEnv);
janakr28adce52017-07-13 19:55:32 +02001399 if (ioException != null) {
1400 throw new NoSuchPackageException(getPackageIdentifier(), ioExceptionMessage, ioException);
1401 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001402
1403 // We create the original BUILD InputFile when the package filename is set; however, the
1404 // visibility may be overridden with an exports_files directive, so we need to obtain the
1405 // current instance here.
1406 buildFile = (InputFile) Preconditions.checkNotNull(targets.get(buildFileLabel.getName()));
1407
nharmata59c16f62017-08-07 19:49:09 +02001408 // The Iterable returned by getTargets is sorted, so when we build up the list of tests by
1409 // processing it in order below, that list will be sorted too.
1410 Iterable<Rule> sortedRules = Lists.newArrayList(getTargets(Rule.class));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001411
Michajlo Matijkiwaa096482016-10-19 14:50:32 +00001412 if (discoverAssumedInputFiles) {
1413 // All labels mentioned in a rule that refer to an unknown target in the
1414 // current package are assumed to be InputFiles, so let's create them:
nharmata59c16f62017-08-07 19:49:09 +02001415 for (final Rule rule : sortedRules) {
Michajlo Matijkiwaa096482016-10-19 14:50:32 +00001416 AggregatingAttributeMapper.of(rule).visitLabels(new AcceptsLabelAttribute() {
1417 @Override
1418 public void acceptLabelAttribute(Label label, Attribute attribute) {
1419 createInputFileMaybe(label, rule.getAttributeLocation(attribute.getName()));
1420 }
1421 });
1422 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001423 }
1424
1425 // "test_suite" rules have the idiosyncratic semantics of implicitly
1426 // depending on all tests in the package, iff tests=[] and suites=[].
1427 // Note, we implement this here when the Package is fully constructed,
1428 // since clearly this information isn't available at Rule construction
1429 // time, as forward references are permitted.
nharmata59c16f62017-08-07 19:49:09 +02001430 List<Label> sortedTests = new ArrayList<>();
1431 for (Rule rule : sortedRules) {
Greg Estrenc48214d2015-03-17 22:43:19 +00001432 if (TargetUtils.isTestRule(rule) && !TargetUtils.hasManualTag(rule)) {
nharmata59c16f62017-08-07 19:49:09 +02001433 sortedTests.add(rule.getLabel());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001434 }
1435 }
nharmata59c16f62017-08-07 19:49:09 +02001436 for (Rule rule : sortedRules) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001437 AttributeMap attributes = NonconfigurableAttributeMapper.of(rule);
1438 if (rule.getRuleClass().equals("test_suite")
Greg Estrenc83a7012016-12-21 00:05:46 +00001439 && attributes.get("tests", BuildType.LABEL_LIST).isEmpty()) {
nharmata59c16f62017-08-07 19:49:09 +02001440 rule.setAttributeValueByName("$implicit_tests", sortedTests);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001441 }
1442 }
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001443 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001444 }
1445
Michajlo Matijkiw91407182015-05-29 14:27:09 +00001446 /** Intended for use by {@link com.google.devtools.build.lib.skyframe.PackageFunction} only. */
janakr28adce52017-07-13 19:55:32 +02001447 public Builder buildPartial() throws InterruptedException, NoSuchPackageException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001448 if (alreadyBuilt) {
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001449 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001450 }
Michajlo Matijkiwaa096482016-10-19 14:50:32 +00001451 return beforeBuild(/*discoverAssumedInputFiles=*/ true);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001452 }
1453
Nathan Harmata6b253fa2016-05-24 15:27:18 +00001454 /**
1455 * Removes a target from the {@link Package} under construction. Intended to be used only by
1456 * {@link com.google.devtools.build.lib.skyframe.PackageFunction} to remove targets whose
1457 * labels cross subpackage boundaries.
1458 */
1459 public void removeTarget(Target target) {
1460 if (target.getPackage() == pkg) {
1461 this.targets.remove(target.getName());
1462 }
1463 }
1464
Michajlo Matijkiw91407182015-05-29 14:27:09 +00001465 /** Intended for use by {@link com.google.devtools.build.lib.skyframe.PackageFunction} only. */
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00001466 public Package finishBuild() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001467 if (alreadyBuilt) {
1468 return pkg;
1469 }
Han-Wen Nienhuysf172d392015-09-18 17:37:51 +00001470
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001471 // Freeze targets and distributions.
1472 targets = ImmutableMap.copyOf(targets);
1473 defaultDistributionSet =
1474 Collections.unmodifiableSet(defaultDistributionSet);
1475
Greg Estrend0f10dc2015-03-17 22:19:37 +00001476 // Now all targets have been loaded, so we validate the group's member environments.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001477 for (EnvironmentGroup envGroup : ImmutableSet.copyOf(environmentGroups.values())) {
Greg Estrend0f10dc2015-03-17 22:19:37 +00001478 Collection<Event> errors = envGroup.processMemberEnvironments(targets);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001479 if (!errors.isEmpty()) {
1480 addEvents(errors);
1481 setContainsErrors();
1482 }
1483 }
1484
1485 // Build the package.
1486 pkg.finishInit(this);
1487 alreadyBuilt = true;
1488 return pkg;
1489 }
1490
janakr28adce52017-07-13 19:55:32 +02001491 public Package build() throws InterruptedException, NoSuchPackageException {
Michajlo Matijkiwaa096482016-10-19 14:50:32 +00001492 return build(/*discoverAssumedInputFiles=*/ true);
1493 }
1494
1495 /**
janakr28adce52017-07-13 19:55:32 +02001496 * Build the package, optionally adding any labels in the package not already associated with a
1497 * target as an input file.
Michajlo Matijkiwaa096482016-10-19 14:50:32 +00001498 */
janakr28adce52017-07-13 19:55:32 +02001499 public Package build(boolean discoverAssumedInputFiles)
1500 throws InterruptedException, NoSuchPackageException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001501 if (alreadyBuilt) {
1502 return pkg;
1503 }
Michajlo Matijkiwaa096482016-10-19 14:50:32 +00001504 beforeBuild(discoverAssumedInputFiles);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001505 return finishBuild();
1506 }
1507
1508 /**
1509 * If "label" refers to a non-existent target in the current package, create
1510 * an InputFile target.
1511 */
1512 void createInputFileMaybe(Label label, Location location) {
Damien Martin-Guillerez49978052016-01-21 19:55:07 +00001513 if (label != null && label.getPackageIdentifier().equals(pkg.getPackageIdentifier())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001514 if (!targets.containsKey(label.getName())) {
1515 addInputFile(label, location);
1516 }
1517 }
1518 }
1519
1520 private InputFile addInputFile(Label label, Location location) {
1521 InputFile inputFile = new InputFile(pkg, label, location);
1522 Target prev = targets.put(label.getName(), inputFile);
1523 Preconditions.checkState(prev == null);
1524 return inputFile;
1525 }
1526
1527 /**
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +00001528 * Precondition check for addRule. We must maintain these invariants of the package:
1529 *
1530 * <ul>
1531 * <li>Each name refers to at most one target.
1532 * <li>No rule with errors is inserted into the package.
1533 * <li>The generating rule of every output file in the package must itself be in the package.
1534 * </ul>
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001535 */
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +00001536 private void checkForConflicts(Rule rule) throws NameConflictException, InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001537 String name = rule.getName();
1538 Target existing = targets.get(name);
1539 if (existing != null) {
1540 throw nameConflict(rule, existing);
1541 }
1542 Map<String, OutputFile> outputFiles = new HashMap<>();
1543
1544 for (OutputFile outputFile : rule.getOutputFiles()) {
1545 String outputFileName = outputFile.getName();
1546 if (outputFiles.put(outputFileName, outputFile) != null) { // dups within a single rule:
1547 throw duplicateOutputFile(outputFile, outputFile);
1548 }
1549 existing = targets.get(outputFileName);
1550 if (existing != null) {
1551 throw duplicateOutputFile(outputFile, existing);
1552 }
1553
1554 // Check if this output file is the prefix of an already existing one
1555 if (outputFilePrefixes.containsKey(outputFileName)) {
1556 throw conflictingOutputFile(outputFile, outputFilePrefixes.get(outputFileName));
1557 }
1558
1559 // Check if a prefix of this output file matches an already existing one
nharmatab4060b62017-04-04 17:11:39 +00001560 PathFragment outputFileFragment = PathFragment.create(outputFileName);
tomlue7552c52018-01-19 10:25:19 -08001561 int segmentCount = outputFileFragment.segmentCount();
1562 for (int i = 1; i < segmentCount; i++) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001563 String prefix = outputFileFragment.subFragment(0, i).toString();
1564 if (outputFiles.containsKey(prefix)) {
1565 throw conflictingOutputFile(outputFile, outputFiles.get(prefix));
1566 }
1567 if (targets.containsKey(prefix)
1568 && targets.get(prefix) instanceof OutputFile) {
1569 throw conflictingOutputFile(outputFile, (OutputFile) targets.get(prefix));
1570 }
1571
laurentlb3d2a68c2017-06-30 00:32:04 +02001572 outputFilePrefixes.putIfAbsent(prefix, outputFile);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001573 }
1574 }
1575
1576 checkForInputOutputConflicts(rule, outputFiles.keySet());
1577 }
1578
1579 /**
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +00001580 * A utility method that checks for conflicts between input file names and output file names for
1581 * a rule from a build file.
1582 *
1583 * @param rule the rule whose inputs and outputs are to be checked for conflicts.
1584 * @param outputFiles a set containing the names of output files to be generated by the rule.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001585 * @throws NameConflictException if a conflict is found.
1586 */
1587 private void checkForInputOutputConflicts(Rule rule, Set<String> outputFiles)
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +00001588 throws NameConflictException, InterruptedException {
Klaus Aehlig6e7c2082018-01-12 10:36:06 -08001589 PackageIdentifier packageIdentifier = rule.getLabel().getPackageIdentifier();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001590 for (Label inputLabel : rule.getLabels()) {
Klaus Aehlig6e7c2082018-01-12 10:36:06 -08001591 if (packageIdentifier.equals(inputLabel.getPackageIdentifier())
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001592 && outputFiles.contains(inputLabel.getName())) {
1593 throw inputOutputNameConflict(rule, inputLabel.getName());
1594 }
1595 }
1596 }
1597
1598 /** An output file conflicts with another output file or the BUILD file. */
1599 private NameConflictException duplicateOutputFile(OutputFile duplicate, Target existing) {
1600 return new NameConflictException(duplicate.getTargetKind() + " '" + duplicate.getName()
1601 + "' in rule '" + duplicate.getGeneratingRule().getName() + "' "
1602 + conflictsWith(existing));
1603 }
1604
1605 /** The package contains two targets with the same name. */
1606 private NameConflictException nameConflict(Target duplicate, Target existing) {
1607 return new NameConflictException(duplicate.getTargetKind() + " '" + duplicate.getName()
1608 + "' in package '" + duplicate.getLabel().getPackageName() + "' "
1609 + conflictsWith(existing));
1610 }
1611
1612 /** A a rule has a input/output name conflict. */
1613 private NameConflictException inputOutputNameConflict(Rule rule, String conflictingName) {
1614 return new NameConflictException("rule '" + rule.getName() + "' has file '"
1615 + conflictingName + "' as both an input and an output");
1616 }
1617
1618 private static NameConflictException conflictingOutputFile(
1619 OutputFile added, OutputFile existing) {
1620 if (added.getGeneratingRule() == existing.getGeneratingRule()) {
1621 return new NameConflictException(String.format(
1622 "rule '%s' has conflicting output files '%s' and '%s'", added.getGeneratingRule()
1623 .getName(), added.getName(), existing.getName()));
1624 } else {
1625 return new NameConflictException(String.format(
1626 "output file '%s' of rule '%s' conflicts with output file '%s' of rule '%s'", added
1627 .getName(), added.getGeneratingRule().getName(), existing.getName(), existing
1628 .getGeneratingRule().getName()));
1629 }
1630 }
1631
1632 /**
1633 * Utility function for generating exception messages.
1634 */
1635 private static String conflictsWith(Target target) {
1636 String message = "conflicts with existing ";
1637 if (target instanceof OutputFile) {
Laurent Le Brun1159cc22017-01-04 12:27:39 +00001638 message +=
1639 "generated file from rule '"
1640 + ((OutputFile) target).getGeneratingRule().getName()
1641 + "'";
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001642 } else {
Laurent Le Brun1159cc22017-01-04 12:27:39 +00001643 message += target.getTargetKind();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001644 }
Laurent Le Brun1159cc22017-01-04 12:27:39 +00001645 return message + ", defined at " + target.getLocation();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001646 }
1647 }
shahanc7667ae82018-01-11 10:10:37 -08001648
1649 /** Package codec implementation. */
shahan20f35b42018-02-28 15:57:33 -08001650 @VisibleForTesting
1651 static final class PackageCodec implements ObjectCodec<Package> {
shahanc7667ae82018-01-11 10:10:37 -08001652 @Override
1653 public Class<Package> getEncodedClass() {
1654 return Package.class;
1655 }
1656
1657 @Override
1658 public void serialize(
michajlo095a3412018-02-13 16:45:05 -08001659 SerializationContext context,
michajloe45c0552018-02-11 09:23:55 -08001660 Package input,
1661 CodedOutputStream codedOut)
cpeyser47c04a12018-01-30 09:17:49 -08001662 throws IOException, SerializationException {
janakr459b2442018-06-05 10:26:02 -07001663 context.checkClassExplicitlyAllowed(Package.class);
shahanfae34b92018-02-13 10:08:47 -08001664 PackageCodecDependencies codecDeps = context.getDependency(PackageCodecDependencies.class);
michajlo095a3412018-02-13 16:45:05 -08001665 codecDeps.getPackageSerializer().serialize(context, input, codedOut);
shahanc7667ae82018-01-11 10:10:37 -08001666 }
1667
1668 @Override
michajloe45c0552018-02-11 09:23:55 -08001669 public Package deserialize(
michajlo095a3412018-02-13 16:45:05 -08001670 DeserializationContext context,
michajloe45c0552018-02-11 09:23:55 -08001671 CodedInputStream codedIn)
shahanc7667ae82018-01-11 10:10:37 -08001672 throws SerializationException, IOException {
shahanfae34b92018-02-13 10:08:47 -08001673 PackageCodecDependencies codecDeps = context.getDependency(PackageCodecDependencies.class);
shahanc7667ae82018-01-11 10:10:37 -08001674 try {
michajlo095a3412018-02-13 16:45:05 -08001675 return codecDeps.getPackageDeserializer().deserialize(context, codedIn);
shahanc7667ae82018-01-11 10:10:37 -08001676 } catch (InterruptedException e) {
1677 throw new IllegalStateException(
1678 "Unexpected InterruptedException during Package deserialization", e);
1679 }
1680 }
1681 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001682}