Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
!**/.gitignore
!.git/HEAD
!.git/config
!.git/packed-refs
!.git/refs/heads/**
24 changes: 24 additions & 0 deletions MintPlayer.Dotnet.Tools.sln
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.AdminHelper", "A
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdminTest", "AdminHelper\AdminTest\AdminTest.csproj", "{CC34556F-529A-4186-AD6C-5F986808D8A5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CommandLineApp", "CommandLineApp", "{752F83A4-B5A2-431F-B7A9-871FD0BD1617}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.CommandLineApp", "SourceGenerators\CommandLineApp\MintPlayer.CommandLineApp\MintPlayer.CommandLineApp.csproj", "{83309DAC-700C-4A03-B7CD-EC1C4F77CC85}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MintPlayer.CommandLineApp.Attributes", "SourceGenerators\CommandLineApp\MintPlayer.CommandLineApp.Attributes\MintPlayer.CommandLineApp.Attributes.csproj", "{53451C47-4933-47BE-8B44-ED911D9163AB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommandLineAppDebugging", "SourceGenerators\TestProjects\CommandLineAppDebugging\CommandLineAppDebugging.csproj", "{4CA948F7-9118-4442-885F-CE8CFFE5E0A2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -390,6 +398,18 @@ Global
{9BCC691D-02F6-4F52-BB14-BB99825959B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9BCC691D-02F6-4F52-BB14-BB99825959B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9BCC691D-02F6-4F52-BB14-BB99825959B9}.Release|Any CPU.Build.0 = Release|Any CPU
{83309DAC-700C-4A03-B7CD-EC1C4F77CC85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{83309DAC-700C-4A03-B7CD-EC1C4F77CC85}.Debug|Any CPU.Build.0 = Debug|Any CPU
{83309DAC-700C-4A03-B7CD-EC1C4F77CC85}.Release|Any CPU.ActiveCfg = Release|Any CPU
{83309DAC-700C-4A03-B7CD-EC1C4F77CC85}.Release|Any CPU.Build.0 = Release|Any CPU
{53451C47-4933-47BE-8B44-ED911D9163AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{53451C47-4933-47BE-8B44-ED911D9163AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{53451C47-4933-47BE-8B44-ED911D9163AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{53451C47-4933-47BE-8B44-ED911D9163AB}.Release|Any CPU.Build.0 = Release|Any CPU
{4CA948F7-9118-4442-885F-CE8CFFE5E0A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4CA948F7-9118-4442-885F-CE8CFFE5E0A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4CA948F7-9118-4442-885F-CE8CFFE5E0A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4CA948F7-9118-4442-885F-CE8CFFE5E0A2}.Release|Any CPU.Build.0 = Release|Any CPU
{447355EB-ED1F-4701-955F-598D00E1E207}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{447355EB-ED1F-4701-955F-598D00E1E207}.Debug|Any CPU.Build.0 = Debug|Any CPU
{447355EB-ED1F-4701-955F-598D00E1E207}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -466,6 +486,10 @@ Global
{9BCC691D-02F6-4F52-BB14-BB99825959B9} = {BE967E23-E7A7-4A55-912D-38FD21068E1D}
{447355EB-ED1F-4701-955F-598D00E1E207} = {41AC5E0E-BCB6-4F0F-A991-C5D19C66828C}
{CC34556F-529A-4186-AD6C-5F986808D8A5} = {41AC5E0E-BCB6-4F0F-A991-C5D19C66828C}
{752F83A4-B5A2-431F-B7A9-871FD0BD1617} = {C65054D9-CAD1-4124-B474-D03C178D9D78}
{83309DAC-700C-4A03-B7CD-EC1C4F77CC85} = {752F83A4-B5A2-431F-B7A9-871FD0BD1617}
{53451C47-4933-47BE-8B44-ED911D9163AB} = {752F83A4-B5A2-431F-B7A9-871FD0BD1617}
{4CA948F7-9118-4442-885F-CE8CFFE5E0A2} = {1614A8B2-CA9A-4F94-B68A-BCC8ED244648}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D5378D43-9246-4355-8C4B-880DB15B07DA}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace MintPlayer.CommandLineApp.Attributes;

[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class ConsoleAppAttribute : Attribute
{
public ConsoleAppAttribute(string description)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>13</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.CommandLine" Version="2.0.0-rc.1.25451.107" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
; Shipped analyzer releases
; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
; Unshipped analyzer release
; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md

### New Rules

Rule ID | Category | Severity | Notes
--------|----------|----------|-------
COMLAPP001 | ConsoleAppGenerator | Error | DiagnosticRules
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using Microsoft.CodeAnalysis;
using MintPlayer.CommandLineApp.Models;
using MintPlayer.SourceGenerators.Tools;
using MintPlayer.SourceGenerators.Tools.Extensions;
using System.CodeDom.Compiler;

namespace MintPlayer.CommandLineApp.Generators;

public class LaunchSettingsSummaryProducer : Producer, IDiagnosticReporter
{
private readonly IEnumerable<ConsoleApp> consoleApps;
private readonly IEnumerable<Location> filesWithTopLevelStatements;
public LaunchSettingsSummaryProducer(IEnumerable<ConsoleApp> consoleApps, IEnumerable<Location> filesWithTopLevelStatements, string rootNamespace) : base(rootNamespace, "LaunchSettingsSummary.g.cs")
{
this.consoleApps = consoleApps;
this.filesWithTopLevelStatements = filesWithTopLevelStatements;
}

public IEnumerable<Diagnostic> GetDiagnostics()
{
if (consoleApps.Count() > 1)
return consoleApps.Select(ca => DiagnosticRules.OnlyOneConsoleAppAllowed.Create(ca.ClassSymbolLocation));
else
return Enumerable.Empty<Diagnostic>();

//return filesWithTopLevelStatements.Select(f => DiagnosticRules.CannotHaveTopLevelStatements.Create(f));
}

protected override void ProduceSource(IndentedTextWriter writer, CancellationToken cancellationToken)
{
foreach (var consoleApp in consoleApps)
{
if (!string.IsNullOrEmpty(consoleApp.Namespace))
{
writer.WriteLine($"namespace {consoleApp.Namespace}");
writer.WriteLine("{");
writer.Indent++;
}

writer.WriteLine($"public static class {consoleApp.ClassName}App");
writer.WriteLine("{");
writer.Indent++;

writer.WriteLine("public static async global::System.Threading.Tasks.Task Run(string[] args)");
writer.WriteLine("{");
writer.Indent++;

ProduceMainMethod(writer, consoleApp);

writer.Indent--;
writer.WriteLine("}");

writer.Indent--;
writer.WriteLine("}");


if (!string.IsNullOrEmpty(consoleApp.Namespace))
{
writer.Indent--;
writer.WriteLine("}");
}
}
}

private void ProduceMainMethod(IndentedTextWriter writer, ConsoleApp consoleApp)
{
var description = consoleApp.Description ?? string.Empty;
writer.WriteLine($""""
var rootCommand = new System.CommandLine.RootCommand("{description.Replace("\"", "\\\"")}");
"""");
writer.WriteLine($""""
var parsed = rootCommand.Parse(args);
"""");
writer.WriteLine($""""
await parsed.InvokeAsync();
"""");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Microsoft.CodeAnalysis;

namespace MintPlayer.CommandLineApp.Generators;

public static partial class DiagnosticRules
{
public static readonly DiagnosticDescriptor CannotHaveTopLevelStatements = new(
id: "COMLAPP001",
title: "A console app that uses the [ConsoleApp] attribute cannot have top-level statements",
messageFormat: "A console app that uses the [ConsoleApp] attribute cannot have top-level statements",
category: "ConsoleAppGenerator",
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);

public static readonly DiagnosticDescriptor OnlyOneConsoleAppAllowed = new(
id: "COMLAPP002",
title: "Only one console app with the [ConsoleApp] attribute is allowed",
messageFormat: "Only one console app with the [ConsoleApp] attribute is allowed",
category: "ConsoleAppGenerator",
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using MintPlayer.SourceGenerators.Tools;
using MintPlayer.SourceGenerators.Tools.ValueComparers;

namespace MintPlayer.CommandLineApp.Generators
{
[Generator(LanguageNames.CSharp)]
public sealed class LaunchSettingsSummaryGenerator : IncrementalGenerator
{
const string consoleAppAttribute = "MintPlayer.CommandLineApp.Attributes.ConsoleAppAttribute";

public override void Initialize(IncrementalGeneratorInitializationContext context, IncrementalValueProvider<Settings> settingsProvider)
{
var filesWithTopLevelStatements = context.CompilationProvider
.SelectMany(static (compilation, ct) => compilation.SyntaxTrees
.Where(st => st.GetRoot(ct).DescendantNodesAndSelf().OfType<GlobalStatementSyntax>().Any())
.Select(f => f.GetLocation(TextSpan.FromBounds(0, f.Length - 1))))
.WithComparer(ValueComparer<Location>.Instance)
.Collect();

var consoleAppsProvider = context.SyntaxProvider.ForAttributeWithMetadataName(
consoleAppAttribute,
static (node, ct) => node is ClassDeclarationSyntax { AttributeLists.Count: > 0 },
static (context, ct) =>
{
if (context.TargetNode is ClassDeclarationSyntax classDeclaration &&
context.SemanticModel.GetDeclaredSymbol(classDeclaration, ct) is INamedTypeSymbol classSymbol)
{
return new Models.ConsoleApp
{
Description = context.Attributes.FirstOrDefault(a => a.AttributeClass?.ToDisplayString() == consoleAppAttribute)
?.ConstructorArguments.FirstOrDefault().Value?.ToString() ?? string.Empty,
ClassName = classSymbol.Name,
Namespace = classSymbol.ContainingNamespace.IsGlobalNamespace ? string.Empty : classSymbol.ContainingNamespace?.ToDisplayString(),
ClassSymbolLocation = classSymbol.Locations.FirstOrDefault(),
};
}

return default;
})
.WithNullableComparer()
.Collect();

var consoleAppsSourceProvider = consoleAppsProvider
.Join(filesWithTopLevelStatements)
.Join(settingsProvider)
.Select(static Producer (prov, ct) => new LaunchSettingsSummaryProducer(prov.Item1, prov.Item2, prov.Item3.RootNamespace!));

var consoleAppsDiagnosticProvider = consoleAppsProvider
.Join(filesWithTopLevelStatements)
.Join(settingsProvider)
.Select(static IDiagnosticReporter (prov, ct) => new LaunchSettingsSummaryProducer(prov.Item1, prov.Item2, prov.Item3.RootNamespace!));

context.ProduceCode(consoleAppsSourceProvider);
context.ReportDiagnostics(consoleAppsDiagnosticProvider);
}

public override void RegisterComparers()
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<GetTargetPathDependsOn>$(GetTargetPathDependsOn);GetDependencyTargetPaths</GetTargetPathDependsOn>
</PropertyGroup>

<Target Name="GetDependencyTargetPaths">
<ItemGroup>
<TargetPathWithTargetPlatformMoniker Include="$(MSBuildThisFileDirectory)\..\MintPlayer.CommandLineApp.Attributes\bin\$(Configuration)\netstandard2.0\MintPlayer.CommandLineApp.Attributes.dll" IncludeRuntimeDependency="true" />
</ItemGroup>
</Target>

<ItemGroup>
<!-- Dependency DLLs -->
<None Condition="'$(Configuration)' == 'Release' " Include="..\MintPlayer.CommandLineApp.Attributes\bin\$(Configuration)\netstandard2.0\*.dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="true" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\MintPlayer.CommandLineApp.Attributes\MintPlayer.CommandLineApp.Attributes.csproj" />
</ItemGroup>

<Import Project="..\..\eng\sourcegenerator.targets" />
<Import Project="..\..\eng\valuecomparergenerator.targets" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using MintPlayer.ValueComparerGenerator.Attributes;

namespace MintPlayer.CommandLineApp.Models;

[AutoValueComparer]
public partial class ConsoleApp
{
public Microsoft.CodeAnalysis.Location? ClassSymbolLocation { get; set; }
public string? Namespace { get; set; }
public string? ClassName { get; set; }
public string? Description { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"profiles": {
"Debug CommandLineApp Generators on CommandLineAppDebugging": {
"commandName": "DebugRoslynComponent",
"targetProject": "..\\..\\TestProjects\\CommandLineAppDebugging\\CommandLineAppDebugging.csproj"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Microsoft.CodeAnalysis;
using MintPlayer.SourceGenerators.Tools.ValueComparers;

namespace MintPlayer.SourceGenerators.Tools;

public static class ComparerExtensions
{
/// <summary>
/// Only use this method on simple types, like bool
/// </summary>
public static IncrementalValueProvider<T> WithDefaultComparer<T>(this IncrementalValueProvider<T> provider) where T : struct
{
return provider.WithComparer(DefaultValueComparer<T>.Instance);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<PublishAot>true</PublishAot>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\CommandLineApp\MintPlayer.CommandLineApp.Attributes\MintPlayer.CommandLineApp.Attributes.csproj" />
<ProjectReference Include="..\..\CommandLineApp\MintPlayer.CommandLineApp\MintPlayer.CommandLineApp.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// See https://aka.ms/new-console-template for more information
using MintPlayer.CommandLineApp.Attributes;

await ListAspnetcoreAppsApp.Run(args);

[ConsoleApp("Lists all ASP.NET Core apps under the current folder")]
public class ListAspnetcoreApps
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"profiles": {
"CommandLineAppDebugging": {
"commandName": "Project"
},
"Container (Dockerfile)": {
"commandName": "Docker"
}
}
}
Loading