@Override protected void internalExecute(ActionExecutionContext actionExecutionContext) throws ExecException, InterruptedException { EventHandler reporter = actionExecutionContext.getExecutor().getEventHandler(); checkInputsForDirectories(reporter, actionExecutionContext.getMetadataHandler()); super.internalExecute(actionExecutionContext); checkOutputsForDirectories(reporter); }
@Override public void execute(ActionExecutionContext actionExecutionContext) throws ActionExecutionException, InterruptedException { actionExecutionContext .getExecutor() .getContext(SymlinkTreeActionContext.class) .createSymlinks(this, actionExecutionContext, shExecutable); }
/** * Ensure the runfiles tree exists and is consistent with the TestAction's manifest * ($0.runfiles_manifest), bringing it into consistency if not. The contents of the output file * $0.runfiles/MANIFEST, if it exists, are used a proxy for the set of existing symlinks, to avoid * the need for recursion. */ private static void updateLocalRunfilesDirectory( TestRunnerAction testAction, Path runfilesDir, ActionExecutionContext actionExecutionContext, BinTools binTools, ImmutableMap<String, String> shellEnvironment, boolean enableRunfiles) throws ExecException, InterruptedException { Executor executor = actionExecutionContext.getExecutor(); TestTargetExecutionSettings execSettings = testAction.getExecutionSettings(); try { // Avoid rebuilding the runfiles directory if the manifest in it matches the input manifest, // implying the symlinks exist and are already up to date. if (Arrays.equals( runfilesDir.getRelative("MANIFEST").getMD5Digest(), execSettings.getInputManifest().getPath().getMD5Digest())) { return; } } catch (IOException e1) { // Ignore it - we will just try to create runfiles directory. } executor .getEventHandler() .handle( Event.progress( "Building runfiles directory for '" + execSettings.getExecutable().prettyPrint() + "'.")); new SymlinkTreeHelper(execSettings.getInputManifest().getPath(), runfilesDir, false) .createSymlinks( testAction, actionExecutionContext, binTools, shellEnvironment, enableRunfiles); executor.getEventHandler().handle(Event.progress(testAction.getProgressMessage())); }
@Override @ThreadCompatible public void execute(ActionExecutionContext actionExecutionContext) throws ActionExecutionException, InterruptedException { Executor executor = actionExecutionContext.getExecutor(); // First, do a normal compilation, to generate the ".d" file. The generated object file is built // to a temporary location (tempOutputFile) and ignored afterwards. LOG.info("Generating " + getDotdFile()); CppCompileActionContext context = executor.getContext(actionContext); CppCompileActionContext.Reply reply = null; try { // We delegate stdout/stderr to nowhere, i.e. same as redirecting to /dev/null. reply = context.execWithReply(this, actionExecutionContext.withFileOutErr(new FileOutErr())); } catch (ExecException e) { // We ignore failures here (other than capturing the Distributor reply). // The compilation may well fail (that's the whole point of negative compilation tests). // We execute it here just for the side effect of generating the ".d" file. reply = context.getReplyFromException(e, this); if (reply == null) { // This can only happen if the ExecException does not come from remote execution. throw e.toActionExecutionException( "Fake C++ Compilation of rule '" + getOwner().getLabel() + "'", executor.getVerboseFailures(), this); } } IncludeScanningContext scanningContext = executor.getContext(IncludeScanningContext.class); NestedSet<Artifact> discoveredInputs = discoverInputsFromDotdFiles( executor.getExecRoot(), scanningContext.getArtifactResolver(), reply); reply = null; // Clear in-memory .d files early. // Even cc_fake_binary rules need to properly declare their dependencies... // In fact, they need to declare their dependencies even more than cc_binary rules do. // CcCommonConfiguredTarget passes in an empty set of declaredIncludeDirs, // so this check below will only allow inclusion of header files that are explicitly // listed in the "srcs" of the cc_fake_binary or in the "srcs" of a cc_library that it // depends on. try { validateInclusions( discoveredInputs, actionExecutionContext.getArtifactExpander(), executor.getEventHandler()); } catch (ActionExecutionException e) { // TODO(bazel-team): (2009) make this into an error, once most of the current warnings // are fixed. executor .getEventHandler() .handle( Event.warn( getOwner().getLocation(), e.getMessage() + ";\n this warning may eventually become an error")); } updateActionInputs(discoveredInputs); // Generate a fake ".o" file containing the command line needed to generate // the real object file. LOG.info("Generating " + outputFile); // A cc_fake_binary rule generates fake .o files and a fake target file, // which merely contain instructions on building the real target. We need to // be careful to use a new set of output file names in the instructions, as // to not overwrite the fake output files when someone tries to follow the // instructions. As the real compilation is executed by the test from its // runfiles directory (where writing is forbidden), we patch the command // line to write to $TEST_TMPDIR instead. final String outputPrefix = "$TEST_TMPDIR/"; String argv = Joiner.on(' ') .join( Iterables.transform( getArgv(outputFile.getExecPath()), new Function<String, String>() { @Override public String apply(String input) { String result = ShellEscaper.escapeString(input); // Once -c and -o options are added into action_config, the argument of // getArgv(outputFile.getExecPath()) won't be used anymore. There will // always be // -c <tempOutputFile>, but here it has to be outputFile, so we replace it. if (input.equals(tempOutputFile.getPathString())) { result = outputPrefix + ShellEscaper.escapeString(outputFile.getExecPathString()); } if (input.equals(outputFile.getExecPathString()) || input.equals(getDotdFile().getSafeExecPath().getPathString())) { result = outputPrefix + ShellEscaper.escapeString(input); } return result; } })); // Write the command needed to build the real .o file to the fake .o file. // Generate a command to ensure that the output directory exists; otherwise // the compilation would fail. try { // Ensure that the .d file and .o file are siblings, so that the "mkdir" below works for // both. Preconditions.checkState( outputFile .getExecPath() .getParentDirectory() .equals(getDotdFile().getSafeExecPath().getParentDirectory())); FileSystemUtils.writeContent( outputFile.getPath(), ISO_8859_1, outputFile.getPath().getBaseName() + ": " + "mkdir -p " + outputPrefix + "$(dirname " + outputFile.getExecPath() + ")" + " && " + argv + "\n"); } catch (IOException e) { throw new ActionExecutionException( "failed to create fake compile command for rule '" + getOwner().getLabel() + ": " + e.getMessage(), this, false); } }