blob: 5f231e4fd087cd66571b46064a9fc35072932a4c [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.
14package com.google.devtools.build.lib.exec;
15
Ulf Adams015aad92016-07-13 16:49:40 +000016import com.google.common.annotations.VisibleForTesting;
Damien Martin-Guillereze5b7c592016-01-18 11:03:59 +000017import com.google.common.base.Preconditions;
ruperts7967f332017-11-21 16:37:13 -080018import com.google.common.collect.ImmutableList;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010019import com.google.common.collect.ImmutableMap;
cparsons83581482018-04-16 11:49:24 -070020import com.google.common.collect.Lists;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010021import com.google.devtools.build.lib.actions.ActionExecutionContext;
ulfjack4d7f8f72017-11-29 03:37:04 -080022import com.google.devtools.build.lib.actions.ActionExecutionMetadata;
23import com.google.devtools.build.lib.actions.ActionInput;
24import com.google.devtools.build.lib.actions.Artifact;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010025import com.google.devtools.build.lib.actions.ExecException;
ulfjack4d7f8f72017-11-29 03:37:04 -080026import com.google.devtools.build.lib.actions.ExecutionRequirements;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010027import com.google.devtools.build.lib.actions.ResourceSet;
ulfjack4d7f8f72017-11-29 03:37:04 -080028import com.google.devtools.build.lib.actions.SimpleSpawn;
29import com.google.devtools.build.lib.actions.Spawn;
ruperts4050a892017-10-07 00:46:20 +020030import com.google.devtools.build.lib.actions.SpawnResult;
Lukacs Berki31b059f2016-08-04 11:55:20 +000031import com.google.devtools.build.lib.actions.UserExecException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010032import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
33import com.google.devtools.build.lib.shell.CommandException;
34import com.google.devtools.build.lib.util.CommandBuilder;
35import com.google.devtools.build.lib.util.OsUtils;
Lukacs Berki31b059f2016-08-04 11:55:20 +000036import com.google.devtools.build.lib.vfs.FileSystemUtils;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010037import com.google.devtools.build.lib.vfs.Path;
38import com.google.devtools.build.lib.vfs.PathFragment;
Lukacs Berki31b059f2016-08-04 11:55:20 +000039import java.io.IOException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010040import java.util.List;
41
42/**
ulfjack4d7f8f72017-11-29 03:37:04 -080043 * Helper class responsible for the symlink tree creation. Used to generate runfiles and fileset
44 * symlink farms.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010045 */
46public final class SymlinkTreeHelper {
Ulf Adams015aad92016-07-13 16:49:40 +000047 @VisibleForTesting
48 public static final String BUILD_RUNFILES = "build-runfiles" + OsUtils.executableExtension();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010049
50 /**
ulfjack4d7f8f72017-11-29 03:37:04 -080051 * These actions run faster overall when serialized, because most of their cost is in the ext2
52 * block allocator, and there's less seeking required if their directory creations get
53 * non-interleaved allocations. So we give them a huge resource cost.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010054 */
Mark Schaller5d81dd52015-02-20 23:14:47 +000055 public static final ResourceSet RESOURCE_SET = ResourceSet.createWithRamCpuIo(1000, 0.5, 0.75);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010056
Lukacs Berki31b059f2016-08-04 11:55:20 +000057 private final Path inputManifest;
58 private final Path symlinkTreeRoot;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010059 private final boolean filesetTree;
60
61 /**
ulfjack4d7f8f72017-11-29 03:37:04 -080062 * Creates SymlinkTreeHelper instance. Can be used independently of SymlinkTreeAction.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010063 *
64 * @param inputManifest exec path to the input runfiles manifest
Lukacs Berki31b059f2016-08-04 11:55:20 +000065 * @param symlinkTreeRoot the root of the symlink tree to be created
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010066 * @param filesetTree true if this is fileset symlink tree,
67 * false if this is a runfiles symlink tree.
68 */
ulfjack4d7f8f72017-11-29 03:37:04 -080069 public SymlinkTreeHelper(Path inputManifest, Path symlinkTreeRoot, boolean filesetTree) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010070 this.inputManifest = inputManifest;
71 this.symlinkTreeRoot = symlinkTreeRoot;
72 this.filesetTree = filesetTree;
73 }
74
Lukacs Berki31b059f2016-08-04 11:55:20 +000075 public Path getOutputManifest() {
76 return symlinkTreeRoot;
77 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010078
79 /**
ulfjack4d7f8f72017-11-29 03:37:04 -080080 * Creates a symlink tree using a CommandBuilder. This means that the symlink tree will always be
81 * present on the developer's workstation. Useful when running commands locally.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010082 *
ulfjack4d7f8f72017-11-29 03:37:04 -080083 * Warning: this method REALLY executes the command on the box Bazel is running on, without any
84 * kind of synchronization, locking, or anything else.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010085 *
86 * @param config the configuration that is used for creating the symlink tree.
87 * @throws CommandException
88 */
ulfjack4d7f8f72017-11-29 03:37:04 -080089 public void createSymlinksUsingCommand(
90 Path execRoot, BuildConfiguration config, BinTools binTools)
91 throws CommandException {
ulfjackd3dd6a12018-03-06 00:49:37 -080092 List<String> argv = getSpawnArgumentList(execRoot, binTools.getExecPath(BUILD_RUNFILES));
cparsons83581482018-04-16 11:49:24 -070093 CommandBuilder builder = new CommandBuilder();
94 builder.addArgs(argv);
95 builder.setWorkingDir(execRoot);
96 builder.build().execute();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010097 }
98
99 /**
ruperts4050a892017-10-07 00:46:20 +0200100 * Creates symlink tree using appropriate method. At this time tree always created using
101 * build-runfiles helper application.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100102 *
ulfjack4d7f8f72017-11-29 03:37:04 -0800103 * @param owner action instance that requested symlink tree creation
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100104 * @param actionExecutionContext Services that are in the scope of the action.
Dmitry Lomova148b4c2016-06-21 12:04:34 +0000105 * @param enableRunfiles
ruperts7967f332017-11-21 16:37:13 -0800106 * @return a list of SpawnResults created during symlink creation, if any
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100107 */
ruperts7967f332017-11-21 16:37:13 -0800108 public List<SpawnResult> createSymlinks(
ulfjack4d7f8f72017-11-29 03:37:04 -0800109 ActionExecutionMetadata owner,
Dmitry Lomovdfe2f102016-02-12 14:41:05 +0000110 ActionExecutionContext actionExecutionContext,
111 BinTools binTools,
Dmitry Lomova148b4c2016-06-21 12:04:34 +0000112 ImmutableMap<String, String> shellEnvironment,
ulfjack4d7f8f72017-11-29 03:37:04 -0800113 Artifact inputManifestArtifact,
Dmitry Lomova148b4c2016-06-21 12:04:34 +0000114 boolean enableRunfiles)
ulfjack4d7f8f72017-11-29 03:37:04 -0800115 throws ExecException, InterruptedException {
shahan18726b72018-03-15 14:18:46 -0700116 Preconditions.checkState(
117 actionExecutionContext.getInputPath(inputManifestArtifact).equals(inputManifest));
Lukacs Berki31b059f2016-08-04 11:55:20 +0000118 if (enableRunfiles) {
Googler3b9e1522018-03-26 11:03:30 -0700119 Spawn spawn =
120 createSpawn(
121 owner,
122 actionExecutionContext.getExecRoot(),
123 binTools,
124 shellEnvironment,
125 inputManifestArtifact);
ruperts4050a892017-10-07 00:46:20 +0200126 return actionExecutionContext
Googler2c3990c2018-03-26 16:33:56 -0700127 .getSpawnActionContext(spawn)
Googler3b9e1522018-03-26 11:03:30 -0700128 .exec(spawn, actionExecutionContext);
Lukacs Berki31b059f2016-08-04 11:55:20 +0000129 } else {
130 // Pretend we created the runfiles tree by copying the manifest
131 try {
ulfjackd3dd6a12018-03-06 00:49:37 -0800132 symlinkTreeRoot.createDirectoryAndParents();
Lukacs Berki31b059f2016-08-04 11:55:20 +0000133 FileSystemUtils.copyFile(inputManifest, symlinkTreeRoot.getChild("MANIFEST"));
134 } catch (IOException e) {
135 throw new UserExecException(e.getMessage(), e);
136 }
ruperts7967f332017-11-21 16:37:13 -0800137 return ImmutableList.of();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100138 }
139 }
140
ulfjack4d7f8f72017-11-29 03:37:04 -0800141 @VisibleForTesting
142 Spawn createSpawn(
143 ActionExecutionMetadata owner,
144 Path execRoot,
145 BinTools binTools,
146 ImmutableMap<String, String> environment,
147 ActionInput inputManifestArtifact) {
ulfjackd3dd6a12018-03-06 00:49:37 -0800148 ActionInput buildRunfiles = binTools.getActionInput(BUILD_RUNFILES);
ulfjack4d7f8f72017-11-29 03:37:04 -0800149 return new SimpleSpawn(
150 owner,
cparsons83581482018-04-16 11:49:24 -0700151 getSpawnArgumentList(execRoot, buildRunfiles.getExecPath()),
ulfjack4d7f8f72017-11-29 03:37:04 -0800152 environment,
153 ImmutableMap.of(
154 ExecutionRequirements.LOCAL, "",
155 ExecutionRequirements.NO_CACHE, "",
156 ExecutionRequirements.NO_SANDBOX, ""),
ulfjackd3dd6a12018-03-06 00:49:37 -0800157 ImmutableList.of(inputManifestArtifact, buildRunfiles),
ulfjack4d7f8f72017-11-29 03:37:04 -0800158 /*outputs=*/ ImmutableList.of(),
159 RESOURCE_SET);
160 }
161
cparsons83581482018-04-16 11:49:24 -0700162 /**
163 * Returns the complete argument list build-runfiles has to be called with.
164 */
165 private ImmutableList<String> getSpawnArgumentList(Path execRoot, PathFragment buildRunfiles) {
166 List<String> args = Lists.newArrayList();
ulfjackd3dd6a12018-03-06 00:49:37 -0800167 args.add(buildRunfiles.getPathString());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100168
169 if (filesetTree) {
170 args.add("--allow_relative");
171 args.add("--use_metadata");
172 }
173
Dmitry Lomove36a66c2017-02-17 14:48:48 +0000174 args.add(inputManifest.relativeTo(execRoot).getPathString());
175 args.add(symlinkTreeRoot.relativeTo(execRoot).getPathString());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100176
cparsons83581482018-04-16 11:49:24 -0700177 return ImmutableList.copyOf(args);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100178 }
179}