Added DotNet global tool for code formatting. #29403
Conversation
317c43d
to
9f1894a
|
||
MSBuildEnvironment.ApplyEnvironmentVariables(); | ||
|
||
return await CodeFormatter.FormatWorkspaceAsync(logger, workspacePath, isSolution, cancellationTokenSource.Token); |
wli3
Aug 20, 2018
Is this directly calling a fullframework library? Did you try to install the tool and invoke locally? As long as that works it is fine.
JoeRobich
Aug 21, 2018
Author
Member
I ended up changing the Workspaces.MSBuild project to multi-target. Only required a couple changes to code that was already conditionally compiling. I've tested on Win10 and Ubuntu 18.04.
.UseParseErrorReporting() | ||
.UseExceptionHandler() | ||
.AddOption(new[] { "-w", "--workspace" }, "The project or solution to format", a => a.WithDefaultValue(() => null).ExactlyOne()) | ||
.AddOption(new[] { "-q", "--quiet" }, "Suppresses all output except warnings and errors", a => a.ParseArgumentsAs<bool>((sr) => ArgumentParseResult.Success(true), new ArgumentArityValidator(0, 0))) |
jonsequitur
Aug 20, 2018
•
This can be simpler. Just this should do what you want:
a.ParseArgumentsAs<bool>()
The arity is inferred from the type if you don't specify it.
Also, I think the following will always evaluate as true because you're not parsing the sr
value that you're receiving in the lambda:
a => a.ParseArgumentsAs<bool>((sr) => ArgumentParseResult.Success(true)
JoeRobich
Aug 21, 2018
Author
Member
I wanted an arity of 0 for those options since I was treating them as simple flags. This gives the behavior that my tool could be invoked like dotnet format -v .\SomePath\
and verbose would be set and the .\SomePath\
would get interpreted as the workspace. Just using a.ParseArgumentsAs<bool>()
would try to interpret .\SomePath\
as a bool
and error.
Thankfully it doesn't always return true. It has the desired behavior of only being true when the option is present.
jonsequitur
Aug 21, 2018
The default behavior for bool
is that the argument can be supplied or not (e.g. an arity of 0 - 1), and either way will work:
format -q
format -q true
format -q false
I'm wondering if you found a bug. I'll try to repro.
9f1894a
to
9f69e72
{ | ||
internal class CodeFormatter | ||
{ | ||
public static async Task<int> FormatWorkspaceAsync(ILogger logger, string workspacePath, bool isSolution, CancellationToken token) |
{ "AlwaysCompileMarkupFilesInSeparateDomain", bool.FalseString }, | ||
|
||
// Use the latest language version to force the full set of available analyzers to run on the project. | ||
{ "LangVersion", "latest" }, |
jmarolf
Aug 21, 2018
Member
I would think we would want to respect the language version of each project. I wouldn't want 7.3 features added if they break my project.
} | ||
|
||
var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); | ||
if (GeneratedCodeUtilities.IsGeneratedCode(syntaxTree, isCommentTrivia, cancellationToken)) |
jmarolf
Aug 21, 2018
Member
Should we control this with an option? Some people may want to format generated code.
sharwell
Aug 28, 2018
•
Member
We probably should not. Code generators have the option of applying the formatting themselves during the code generation process, but we should assume that once the tool completes the form is finalized.
@@ -0,0 +1,66 @@ | |||
using System; |
else | ||
{ | ||
break; | ||
} |
CyrusNajmabadi
Aug 21, 2018
Contributor
all this code looks like an exact duplicate of code that is above.
} | ||
catch (Exception ex) | ||
{ | ||
throw new Exception($"Unable to write standard error output when running command {commandInfo.Name}: {ex.Message}"); |
var buffer = new char[512]; | ||
while (true) | ||
{ | ||
var readCount = process.StandardOutput.Read(buffer, 0, 512); |
{ | ||
Name = "where", | ||
Arguments = commandName | ||
}, timeoutInMilliseconds: 1000); |
{ | ||
using (var outputStream = new MemoryStream()) | ||
{ | ||
using (var outputStreamWriter = new StreamWriter(outputStream)) |
private static IEnumerable<string> FindSolutionFiles(string basePath) => Directory.EnumerateFileSystemEntries(basePath, "*.sln", SearchOption.TopDirectoryOnly); | ||
|
||
private static IEnumerable<string> FindProjectFiles(string basePath) => Directory.EnumerateFileSystemEntries(basePath, "*.*proj", SearchOption.TopDirectoryOnly) | ||
.Where(f => !".xproj".Equals(Path.GetExtension(f), StringComparison.OrdinalIgnoreCase)); |
} | ||
catch (Exception ex) | ||
{ | ||
if (ex is TaskCanceledException || ex is OperationCanceledException) |
CyrusNajmabadi
Aug 21, 2018
Contributor
TaskCanceledException is already an OperationCanceledException. So it's redundant to have both checks.
} | ||
|
||
logger.LogError(ex.ToString()); | ||
logger.LogError((string)"An unexpected error occurred"); |
@@ -0,0 +1,48 @@ | |||
dotnet-format | |||
============= | |||
`dotnet-format` is a code formatter for `dotnet` that reads style preferences from your `.editorconfig` file and applies them to a project or solution. |
CyrusNajmabadi
Aug 21, 2018
Contributor
i missed it, but what code actually ensures there is a .editorconfig file?
JoeRobich
Aug 22, 2018
Author
Member
That is a good point.
In the absence of an .editorconfig file it will use the default formatting options. This behavior might be useful to some users who do not wish to choose formatting options for their project but simply enforce some level of consistency (like Prettier). Something to consider.
<value>Formatting code files in workspace '{0}'.</value> | ||
</data> | ||
<data name="Warn_UnsupportedProject" xml:space="preserve"> | ||
<value>Could not format '{0}'. Format currently supports only C# and VisualBasic projects.</value> |
JoeRobich
Aug 22, 2018
Author
Member
Thanks. Having a bit of a "Berenstain Bears" moment here. I guess I always assumed in the same way QuickBasic was one word, that Visual Basic was too and just never noticed otherwise.
Dumb question: why does this need to live in the Roslyn repo? It seems like it would be fine living elsewhere. |
@@ -268,6 +271,8 @@ | |||
https://myget.org/F/vs-editor/api/v3/index.json; | |||
https://vside.myget.org/F/vssdk/api/v3/index.json; | |||
https://vside.myget.org/F/vs-impl/api/v3/index.json; | |||
https://dotnet.myget.org/F/system-commandline/api/v3/index.json; | |||
|
// AppDomains will likely not work due to https://github.com/Microsoft/MSBuildLocator/issues/16. | ||
{ "AlwaysCompileMarkupFilesInSeparateDomain", bool.FalseString }, | ||
|
||
// Use the latest language version to force the full set of available analyzers to run on the project. |
CyrusNajmabadi
Aug 21, 2018
Contributor
why do we need analyzers running if this is just updating code formatting?
09900cf
to
0bcddd8
Tool can be run on a project, solution, or folder containing a project or solution. Tool pulls formatting configuration from an .editorconfig if present, otherwise formats with roslyn defaults.
0bcddd8
to
6113fa0
|
||
// LICENSING NOTE: The license for this file is from the originating | ||
// source and not the general https://github.com/dotnet/roslyn license. | ||
// See https://github.com/Microsoft/MSBuildLocator/blob/6631a6dbf9be72b2426e260c99dc0f345e79b8e5/src/MSBuildLocator/MSBuildLocator.cs |
sharwell
Sep 19, 2018
Member
PackageReference
for now, and sent a pull request to that project to add x-plat support instead of coding it all here in a forked copy?
JoeRobich
Sep 20, 2018
Author
Member
Looks like they have an open PR to support the .net core use case. I can add a comment that links to the PR and recommends moving to use their package once it gets in.
DustinCampbell
Oct 8, 2018
Member
IIRC, that PR hit some significant roadblocks. Have you reached out to the right folks on the .NET Core SDK and MSBuild teams to determine whether the solution here is the right one? I think the MSBuild Locator PR has pretty much stalled out. At a minimum, I'd start with @nguerrera.
nguerrera
Oct 9, 2018
Member
There were really two things with the locator PR:
-
It doesn't work on Mac (nor all flavors of Linux). This is a technical issue about how it is assuming it can P/Invoke to already loaded hostfxr.dll. This does not apply to the alternate approach of parsing dotnet -info.
-
It ties the locator to implementation details of the CLI. This applies to both approaches. See microsoft/MSBuildLocator#33 (comment)
As on the locator PR, I can let (2) go here if you agree to update this code if/when the layout changes. We do not consider the current placement of msbuild dlls in the CLI as a contract for tools outside the CLI.
@wli3, Not a lot has changed, but if you can just confirm that things still look OK I would be grateful. |
Is there an ETA for release? /cc @JoeRobich @jaredpar |
@MarcoRossignoli, If the request is to fail a build based on formatting issues, then there is a second PR for a Formatting Analyzer that you will be able to install through NuGet. You could configure the severity of that analyzer to fail your build and give you error locations. |
@JoeRobich thank's!I'll take a look! |
The pull request needs to be rewritten to avoid including dotnet-format.2.11.0-dev.nupkg in the source control history. |
|
||
namespace Microsoft.CodeAnalysis.Tools.CodeFormatter | ||
{ | ||
internal class CodeFormatter |
private readonly IConsole _console; | ||
private readonly LogLevel _logLevel; | ||
|
||
private readonly IReadOnlyDictionary<LogLevel, ConsoleColor> _logLevelColorMap = new Dictionary<LogLevel, ConsoleColor> |
private readonly IConsole _console; | ||
private readonly LogLevel _logLevel; | ||
|
||
private readonly IReadOnlyDictionary<LogLevel, ConsoleColor> _logLevelColorMap = new Dictionary<LogLevel, ConsoleColor> |
{ | ||
internal class EditorConfigOptionsApplier | ||
{ | ||
private IReadOnlyList<(IOption, OptionStorageLocation, MethodInfo)> _formattingOptionsWithStorage; |
{ | ||
internal class EditorConfigOptionsApplier | ||
{ | ||
private IReadOnlyList<(IOption, OptionStorageLocation, MethodInfo)> _formattingOptionsWithStorage; |
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>netcoreapp2.1</TargetFramework> |
sharwell
Oct 9, 2018
•
Member
global tools only support netcoreapp2.1 and above
jaredpar
Oct 9, 2018
Member
Note: we are on netcoreapp2.1 now in master and netcoreapp2.0 is actually no longer even supported.
...Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj
Show resolved
Hide resolved
For global tools packaging concern, the current state is good. And global tools only support netcoreapp2.1 and up (due to the dependency on the framework dependent apphost added in runtime 2.1) |
d9ae946
to
8571fde
@sharwell I removed the nupkg from the commit history and addressed the open feedback. Could you give it another look? |
Logged ubuntu_16_debug_prtest failure as #30374 |
retest ubuntu_16_debug_prtest please |
I think this needs to handle localized |
|
||
// LICENSING NOTE: The license for this file is from the originating | ||
// source and not the general https://github.com/dotnet/roslyn license. | ||
// See https://github.com/Microsoft/MSBuildLocator/blob/6631a6dbf9be72b2426e260c99dc0f345e79b8e5/src/MSBuildLocator/MSBuildLocator.cs |
DustinCampbell
Oct 8, 2018
Member
IIRC, that PR hit some significant roadblocks. Have you reached out to the right folks on the .NET Core SDK and MSBuild teams to determine whether the solution here is the right one? I think the MSBuild Locator PR has pretty much stalled out. At a minimum, I'd start with @nguerrera.
...Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj
Show resolved
Hide resolved
Looks good! My meta feedback is that we need to get this code into the MSBuildLocator because this PR makes MSBuildWorkspace available to .NET Core applications but those applications still lack the connective tissue to make it work. |
I did not review the entire PR, only the place where I was mentioned. I approve this with the understanding that we will look for a more permanent home in MSBuildLocator and also that this approval does not mean that the MSBuild.dll location in the SDK cannot be changed in future versions. The tool here (or better, MSBuildLocator) will need to react to such changes. |
0f340a5
into
dotnet:dev16.0.x
Tool can be run on a project, solution, or folder containing a
project or solution. Tool pulls formatting configuration from an
.editorconfig if present, otherwise formats with roslyn defaults.