2121import com .google .devtools .build .lib .actions .ActionExecutionContext ;
2222import com .google .devtools .build .lib .actions .ActionExecutionException ;
2323import com .google .devtools .build .lib .actions .Artifact ;
24- import com .google .devtools .build .lib .actions .EnvironmentalExecException ;
2524import com .google .devtools .build .lib .actions .ExecException ;
2625import com .google .devtools .build .lib .actions .FilesetOutputSymlink ;
2726import com .google .devtools .build .lib .actions .RunningActionEvent ;
3029import com .google .devtools .build .lib .analysis .config .BuildConfigurationValue .RunfileSymlinksMode ;
3130import com .google .devtools .build .lib .profiler .AutoProfiler ;
3231import com .google .devtools .build .lib .profiler .GoogleAutoProfilerUtils ;
33- import com .google .devtools .build .lib .server .FailureDetails .Execution ;
34- import com .google .devtools .build .lib .server .FailureDetails .Execution .Code ;
35- import com .google .devtools .build .lib .server .FailureDetails .FailureDetail ;
3632import com .google .devtools .build .lib .vfs .OutputService ;
37- import com .google .devtools .build .lib .vfs .Path ;
3833import com .google .devtools .build .lib .vfs .PathFragment ;
39- import java .io .IOException ;
4034import java .time .Duration ;
4135import java .util .Map ;
4236
@@ -66,11 +60,13 @@ public void createSymlinks(
6660 actionExecutionContext .getEventHandler ().post (new RunningActionEvent (action , "local" ));
6761 try (AutoProfiler p =
6862 GoogleAutoProfilerUtils .logged ("running " + action .prettyPrint (), MIN_LOGGING )) {
63+ SymlinkTreeHelper helper = createSymlinkTreeHelper (action , actionExecutionContext );
6964 // TODO(tjgq): Respect RunfileSymlinksMode.SKIP even in the presence of an OutputService.
7065 try {
66+ // Note that the output manifest must always be created last, as its presence ascertains
67+ // that the runfiles tree has been updated (only the output manifest is an action output,
68+ // so Skyframe cannot invalidate the symlink tree).
7169 if (outputService .canCreateSymlinkTree ()) {
72- Path inputManifest = actionExecutionContext .getInputPath (action .getInputManifest ());
73-
7470 Map <PathFragment , PathFragment > symlinks ;
7571 if (action .isFilesetTree ()) {
7672 symlinks = getFilesetMap (action , actionExecutionContext );
@@ -79,31 +75,22 @@ public void createSymlinks(
7975 // created textually.
8076 symlinks = Maps .transformValues (getRunfilesMap (action ), TO_PATH );
8177 }
82-
8378 outputService .createSymlinkTree (
8479 symlinks , action .getOutputManifest ().getExecPath ().getParentDirectory ());
85-
86- createOutput (action , actionExecutionContext , inputManifest );
80+ helper .linkManifest ();
8781 } else if (action .getRunfileSymlinksMode () == RunfileSymlinksMode .SKIP ) {
88- // Delete symlinks possibly left over by a previous invocation with a different mode.
89- // This is required because only the output manifest is considered an action output, so
90- // Skyframe does not clear the directory for us.
91- createSymlinkTreeHelper (action , actionExecutionContext ).clearRunfilesDirectory ();
82+ // Clear the runfiles directory, then create just the output manifest and the workspace
83+ // subdirectory. This is required because only the output manifest is considered an action
84+ // output, so if the previous invocation created a symlink tree, Skyframe will not clear
85+ // it for us.
86+ helper .createMinimalRunfilesDirectory ();
9287 } else {
93- try {
94- SymlinkTreeHelper helper = createSymlinkTreeHelper (action , actionExecutionContext );
95- if (action .isFilesetTree ()) {
96- helper .createFilesetSymlinks (getFilesetMap (action , actionExecutionContext ));
97- } else {
98- helper .createRunfilesSymlinks (getRunfilesMap (action ));
99- }
100- } catch (IOException e ) {
101- throw ActionExecutionException .fromExecException (
102- new EnvironmentalExecException (e , Code .SYMLINK_TREE_CREATION_IO_EXCEPTION ), action );
88+ if (action .isFilesetTree ()) {
89+ helper .createFilesetSymlinks (getFilesetMap (action , actionExecutionContext ));
90+ } else {
91+ helper .createRunfilesSymlinks (getRunfilesMap (action ));
10392 }
104-
105- Path inputManifest = actionExecutionContext .getInputPath (action .getInputManifest ());
106- createOutput (action , actionExecutionContext , inputManifest );
93+ helper .linkManifest ();
10794 }
10895 } catch (ExecException e ) {
10996 throw ActionExecutionException .fromExecException (e , action );
@@ -127,20 +114,6 @@ private static Map<PathFragment, Artifact> getRunfilesMap(SymlinkTreeAction acti
127114 return action .getRunfiles ().getRunfilesInputs (action .getRepoMappingManifest ());
128115 }
129116
130- private static void createOutput (
131- SymlinkTreeAction action , ActionExecutionContext actionExecutionContext , Path inputManifest )
132- throws EnvironmentalExecException {
133- Path outputManifest = actionExecutionContext .getInputPath (action .getOutputManifest ());
134- // Link output manifest on success. We avoid a file copy as these manifests may be
135- // large. Note that this step has to come last because the OutputService may delete any
136- // pre-existing symlink tree before creating a new one.
137- try {
138- outputManifest .createSymbolicLink (inputManifest );
139- } catch (IOException e ) {
140- throw createLinkFailureException (outputManifest , e );
141- }
142- }
143-
144117 private SymlinkTreeHelper createSymlinkTreeHelper (
145118 SymlinkTreeAction action , ActionExecutionContext actionExecutionContext ) {
146119 return new SymlinkTreeHelper (
@@ -149,15 +122,4 @@ private SymlinkTreeHelper createSymlinkTreeHelper(
149122 actionExecutionContext .getInputPath (action .getOutputManifest ()).getParentDirectory (),
150123 workspaceName );
151124 }
152-
153- private static EnvironmentalExecException createLinkFailureException (
154- Path outputManifest , IOException e ) {
155- return new EnvironmentalExecException (
156- e ,
157- FailureDetail .newBuilder ()
158- .setMessage ("Failed to link output manifest '" + outputManifest .getPathString () + "'" )
159- .setExecution (
160- Execution .newBuilder ().setCode (Code .SYMLINK_TREE_MANIFEST_LINK_IO_EXCEPTION ))
161- .build ());
162- }
163125}
0 commit comments