diff --git a/README.md b/README.md index 8f0771559f..3a59c76e57 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,7 @@ Options: --exclude A list of relative file or folder paths to exclude from formatting. --check Formats files without saving changes to disk. Terminates with a non-zero exit code if any files were formatted. --report Accepts a file path, which if provided, will produce a json report in the given directory. + --binarylog Log all project or solution load information to a binary log file. --verbosity, -v Set the verbosity level. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic] --version Show version information ``` diff --git a/docs/README.md b/docs/README.md index 362eb74989..08fb125093 100644 --- a/docs/README.md +++ b/docs/README.md @@ -117,6 +117,7 @@ dotnet format -f --include ./src/ ./tests/ --exclude ./src/submodule-a/ --check - `--verbosity` - Set the verbosity level. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic] - `--report` - Writes a json file to the given directory. Defaults to 'format-report.json' if no filename given. +- `--binarylog` - Writes a [binary log file](https://msbuildlog.com/) to help in diagnosing solution or project load errors. Defaults to 'format.binlog' if no filename given. ### Validate formatting diff --git a/src/CodeFormatter.cs b/src/CodeFormatter.cs index 6fcef04741..244c61e9bc 100644 --- a/src/CodeFormatter.cs +++ b/src/CodeFormatter.cs @@ -32,7 +32,7 @@ internal static class CodeFormatter FormatOptions formatOptions, ILogger logger, CancellationToken cancellationToken, - bool createBinaryLog = false) + string? binaryLogPath = null) { var logWorkspaceWarnings = formatOptions.LogLevel == LogLevel.Trace; @@ -44,7 +44,7 @@ internal static class CodeFormatter using var workspace = formatOptions.WorkspaceType == WorkspaceType.Folder ? OpenFolderWorkspace(formatOptions.WorkspaceFilePath, formatOptions.FileMatcher) - : await OpenMSBuildWorkspaceAsync(formatOptions.WorkspaceFilePath, formatOptions.WorkspaceType, createBinaryLog, logWorkspaceWarnings, logger, cancellationToken).ConfigureAwait(false); + : await OpenMSBuildWorkspaceAsync(formatOptions.WorkspaceFilePath, formatOptions.WorkspaceType, binaryLogPath, logWorkspaceWarnings, logger, cancellationToken).ConfigureAwait(false); if (workspace is null) { @@ -123,12 +123,12 @@ private static Workspace OpenFolderWorkspace(string workspacePath, SourceFileMat private static Task OpenMSBuildWorkspaceAsync( string solutionOrProjectPath, WorkspaceType workspaceType, - bool createBinaryLog, + string? binaryLogPath, bool logWorkspaceWarnings, ILogger logger, CancellationToken cancellationToken) { - return MSBuildWorkspaceLoader.LoadAsync(solutionOrProjectPath, workspaceType, createBinaryLog, logWorkspaceWarnings, logger, cancellationToken); + return MSBuildWorkspaceLoader.LoadAsync(solutionOrProjectPath, workspaceType, binaryLogPath, logWorkspaceWarnings, logger, cancellationToken); } private static async Task RunCodeFormattersAsync( diff --git a/src/FormatCommand.cs b/src/FormatCommand.cs index 0de958fa97..1e845d481e 100644 --- a/src/FormatCommand.cs +++ b/src/FormatCommand.cs @@ -10,7 +10,7 @@ namespace Microsoft.CodeAnalysis.Tools { internal static class FormatCommand { - // This delegate should be kept in Sync with the FormatCommand options and arguement names + // This delegate should be kept in Sync with the FormatCommand options and argument names // so that values bind correctly. internal delegate Task Handler( string? workspace, @@ -25,6 +25,7 @@ internal static class FormatCommand string[] exclude, string? report, bool includeGenerated, + string? binarylog, IConsole console); internal static string[] VerbosityLevels => new[] { "q", "quiet", "m", "minimal", "n", "normal", "d", "detailed", "diag", "diagnostic" }; @@ -75,11 +76,16 @@ internal static RootCommand CreateCommandLineOptions() { IsHidden = true }, + new Option(new[] { "--binarylog" }, Resources.Log_all_project_or_solution_load_information_to_a_binary_log_file) + { + Argument = new Argument(() => null) { Name = "binary-log-path", Arity = ArgumentArity.ZeroOrOne }.LegalFilePathsOnly() + }, }; rootCommand.Description = "dotnet-format"; rootCommand.AddValidator(EnsureFolderNotSpecifiedWhenFixingStyle); rootCommand.AddValidator(EnsureFolderNotSpecifiedWhenFixingAnalyzers); + rootCommand.AddValidator(EnsureFolderNotSpecifiedWhenLoggingBinlog); return rootCommand; } @@ -102,6 +108,15 @@ internal static RootCommand CreateCommandLineOptions() : null; } + internal static string? EnsureFolderNotSpecifiedWhenLoggingBinlog(CommandResult symbolResult) + { + var folder = symbolResult.ValueForOption("--folder"); + var binarylog = symbolResult.OptionResult("--binarylog"); + return folder && binarylog is not null && !binarylog.IsImplicit + ? Resources.Cannot_specify_the_folder_option_when_writing_a_binary_log + : null; + } + internal static bool WasOptionUsed(this ParseResult result, params string[] aliases) { return result.Tokens diff --git a/src/Program.cs b/src/Program.cs index 99a349306e..6cec2cde0d 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -12,6 +12,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; + using Microsoft.CodeAnalysis.Tools.Logging; using Microsoft.CodeAnalysis.Tools.MSBuild; using Microsoft.CodeAnalysis.Tools.Utilities; @@ -55,6 +56,7 @@ private static async Task Main(string[] args) string[] exclude, string? report, bool includeGenerated, + string? binarylog, IConsole console = null!) { if (s_parseResult == null) @@ -182,9 +184,28 @@ private static async Task Main(string[] args) formatOptions, logger, cancellationTokenSource.Token, - createBinaryLog: logLevel == LogLevel.Trace).ConfigureAwait(false); + binaryLogPath: GetBinaryLogPath(s_parseResult, binarylog)).ConfigureAwait(false); return GetExitCode(formatResult, check); + + static string? GetBinaryLogPath(ParseResult parseResult, string? binarylog) + { + if (parseResult.WasOptionUsed("--binarylog")) + { + if (binarylog is null) + { + return Path.Combine(Directory.GetCurrentDirectory(), "format.binlog"); + } + else if (Path.GetExtension(binarylog)?.Equals(".binlog") == false) + { + return Path.ChangeExtension(binarylog, ".binlog"); + } + + return binarylog; + } + + return null; + } } catch (FileNotFoundException fex) { diff --git a/src/Resources.resx b/src/Resources.resx index 3df29ecc26..4fb17389f6 100644 --- a/src/Resources.resx +++ b/src/Resources.resx @@ -1,4 +1,4 @@ - +