/* * Copyright 2016-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package com.facebook.buck.rage; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.model.Pair; import com.facebook.buck.util.Console; import com.facebook.buck.util.environment.BuildEnvironmentDescription; import com.facebook.buck.util.unit.SizeUnit; import com.facebook.buck.util.versioncontrol.VersionControlStatsGenerator; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Optional; import java.util.OptionalInt; /** * Responsible for gathering logs and other interesting information from buck, driven by user * interaction. */ public class InteractiveReport extends AbstractReport { private static final int ARGS_MAX_CHARS = 60; private final BuildLogHelper buildLogHelper; private final Console console; private final UserInput input; public InteractiveReport( DefectReporter defectReporter, ProjectFilesystem filesystem, Console console, InputStream stdin, BuildEnvironmentDescription buildEnvironmentDescription, VersionControlStatsGenerator versionControlStatsGenerator, RageConfig rageConfig, ExtraInfoCollector extraInfoCollector, Optional<WatchmanDiagReportCollector> watchmanDiagReportCollector) { super( filesystem, defectReporter, buildEnvironmentDescription, versionControlStatsGenerator, console, rageConfig, extraInfoCollector, watchmanDiagReportCollector); this.buildLogHelper = new BuildLogHelper(filesystem); this.console = console; this.input = new UserInput(console.getStdOut(), new BufferedReader(new InputStreamReader(stdin))); } @Override public ImmutableSet<BuildLogEntry> promptForBuildSelection() throws IOException { ImmutableList<BuildLogEntry> buildLogs = buildLogHelper.getBuildLogs(); if (buildLogs.isEmpty()) { return ImmutableSet.of(); } return input.selectRange( "Which buck invocations would you like to report?", buildLogs, entry -> { Pair<Double, SizeUnit> humanReadableSize = SizeUnit.getHumanReadableSize(entry.getSize(), SizeUnit.BYTES); String cmdArgs = entry.getCommandArgs().orElse("unknown command"); cmdArgs = cmdArgs.substring(0, Math.min(cmdArgs.length(), ARGS_MAX_CHARS)); return String.format( "\t%s\tbuck [%s] %s (%.2f %s)", entry.getLastModifiedTime(), cmdArgs, prettyPrintExitCode(entry.getExitCode()), humanReadableSize.getFirst(), humanReadableSize.getSecond().getAbbreviation()); }); } @Override protected Optional<FileChangesIgnoredReport> getFileChangesIgnoredReport() throws IOException, InterruptedException { return runWatchmanDiagReportCollector(input); } @Override protected Optional<SourceControlInfo> getSourceControlInfo() throws IOException, InterruptedException { if (!input.confirm( "Would you like to attach source control information (this includes " + "information about commits and changed files)?")) { return Optional.empty(); } return super.getSourceControlInfo(); } private String prettyPrintExitCode(OptionalInt exitCode) { String result = "Exit code: " + (exitCode.isPresent() ? Integer.toString(exitCode.getAsInt()) : "Unknown"); if (exitCode.isPresent() && console.getAnsi().isAnsiTerminal()) { if (exitCode.getAsInt() == 0) { return console.getAnsi().asGreenText(result); } else { return console.getAnsi().asRedText(result); } } return result; } @Override protected Optional<UserReport> getUserReport() throws IOException { UserReport.Builder userReport = UserReport.builder(); userReport.setUserIssueDescription( input.ask("Please describe the problem you wish to report:")); return Optional.of(userReport.build()); } }