Skip to content

Commit 25cec66

Browse files
authored
Switch oss.cs CLI arg parsing to ConsoleAppFramework (#38)
Allows specifying --project, --repo and --package arguments ## Changes ```csharp // Before: ~10 lines of plumbing + SetHandler(..., projectOption, repoOption, packageOption) // After: await ConsoleApp.RunAsync(args, async ( /// <summary>Project name</summary> string? project = null, /// <summary>Repo name (defaults to project name)</summary> string? repo = null, /// <summary>Package ID (defaults to Devlooped.{project})</summary> string? package = null) => { // handler body unchanged }); ```
1 parent c76f0cc commit 25cec66

1 file changed

Lines changed: 123 additions & 112 deletions

File tree

‎oss.cs‎

Lines changed: 123 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Subsequently: dnx runfile oss --yes
33
#:package Spectre.Console@*
44
#:package CliWrap@*
5+
#:package ConsoleAppFramework@*
56

67
using System;
78
using System.IO;
@@ -10,118 +11,128 @@
1011
using System.Threading.Tasks;
1112
using System.Xml.Linq;
1213
using CliWrap;
14+
using ConsoleAppFramework;
1315
using Spectre.Console;
1416

15-
string dotnet = Path.GetFullPath(
16-
Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), "..", "..", "..",
17-
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dotnet.exe" : "dotnet"));
18-
19-
AnsiConsole.Write(new FigletText("devlooped oss").Color(Color.Green));
20-
AnsiConsole.WriteLine();
21-
22-
var projectName = AnsiConsole.Prompt(
23-
new TextPrompt<string>("[green]Project name[/]:")
24-
.PromptStyle("yellow")
25-
.ValidationErrorMessage("[red]Project name cannot be empty[/]")
26-
.Validate(v => !string.IsNullOrWhiteSpace(v)));
27-
28-
var repoName = AnsiConsole.Prompt(
29-
new TextPrompt<string>("[green]Repo name[/]:")
30-
.PromptStyle("yellow")
31-
.DefaultValue(projectName));
32-
33-
var packageId = AnsiConsole.Prompt(
34-
new TextPrompt<string>("[green]Package ID[/]:")
35-
.PromptStyle("yellow")
36-
.DefaultValue($"Devlooped.{projectName}"));
37-
38-
AnsiConsole.WriteLine();
39-
AnsiConsole.Write(new Rule("[yellow]Setting up OSS project[/]").RuleStyle("grey").LeftJustified());
40-
AnsiConsole.WriteLine();
41-
42-
await RunDotNet("file init https://github.com/devlooped/oss/blob/main/.netconfig", "Initializing dotnet file sync from devlooped/oss");
43-
await RunDotNet($"new classlib -n {projectName} -o src/{projectName} -f net10.0", $"Creating class library src/{projectName}");
44-
File.Delete($"src/{projectName}/Class1.cs");
45-
await RunDotNet($"package add NuGetizer --project src/{projectName}/{projectName}.csproj", "Adding NuGetizer");
46-
await RunDotNet($"new xunit -n Tests -o src/Tests -f net10.0", "Creating xUnit test project src/Tests");
47-
File.Delete($"src/Tests/UnitTest1.cs");
48-
await RunDotNet($"add src/Tests/Tests.csproj reference src/{projectName}/{projectName}.csproj", $"Adding reference from Tests to {projectName}");
49-
50-
var doc = XDocument.Load($"src/{projectName}/{projectName}.csproj", LoadOptions.None);
51-
doc.Root?.Element("PropertyGroup")?.Element("ImplicitUsings")?.Remove();
52-
doc.Root?.Element("PropertyGroup")?.Element("Nullable")?.Remove();
53-
doc.Root?.Element("PropertyGroup")?.Add(new XElement("PackageId", packageId));
54-
doc.Save($"src/{projectName}/{projectName}.csproj");
55-
56-
doc = XDocument.Load($"src/Tests/Tests.csproj", LoadOptions.None);
57-
doc.Root?.Element("PropertyGroup")?.Element("ImplicitUsings")?.Remove();
58-
doc.Root?.Element("PropertyGroup")?.Element("Nullable")?.Remove();
59-
doc.Root?.Element("PropertyGroup")?.Element("IsPackable")?.Remove();
60-
doc.Save($"src/Tests/Tests.csproj");
61-
62-
File.WriteAllText($"src/Directory.props",
63-
$"""
64-
<Project>
65-
<PropertyGroup>
66-
<Product>{projectName}</Product>
67-
<ImplicitUsings>true</ImplicitUsings>
68-
</PropertyGroup>
69-
</Project>
70-
""");
71-
72-
await RunDotNet($"new solution -n {projectName}", $"Creating solution {projectName}.slnx");
73-
await RunDotNet($"sln {projectName}.slnx add --in-root src/{projectName}/{projectName}.csproj src/Tests/Tests.csproj", $"Adding projects to {projectName}.slnx");
74-
75-
await AnsiConsole.Status()
76-
.Spinner(Spinner.Known.Dots)
77-
.SpinnerStyle(Style.Parse("green"))
78-
.StartAsync("Downloading readme.md template...", async ctx =>
79-
{
80-
using var http = new HttpClient();
81-
var readmeContent = await http.GetStringAsync(
82-
"https://raw.githubusercontent.com/devlooped/oss/main/readme.tmp.md");
83-
84-
readmeContent = readmeContent
85-
.Replace("{{PROJECT_NAME}}", projectName)
86-
.Replace("{{PACKAGE_ID}}", packageId)
87-
.Replace("{{REPO_NAME}}", repoName);
88-
89-
await File.WriteAllTextAsync("readme.md", readmeContent);
90-
ctx.Status("Downloaded and processed readme.md");
91-
});
92-
93-
AnsiConsole.MarkupLine("[green]✓[/] Created [yellow]readme.md[/]");
94-
95-
await File.WriteAllTextAsync(
96-
Path.Combine("src", projectName, "readme.md"),
97-
$"""
98-
[![EULA](https://img.shields.io/badge/EULA-OSMF-blue?labelColor=black&color=C9FF30)](osmfeula.txt)
99-
[![OSS](https://img.shields.io/github/license/devlooped/oss.svg?color=blue)](license.txt)
100-
[![GitHub](https://img.shields.io/badge/-source-181717.svg?logo=GitHub)](https://github.com/devlooped/{repoName})
101-
102-
<!-- include ../../readme.md#content -->
103-
104-
<!-- include https://github.com/devlooped/.github/raw/main/osmf.md -->
105-
106-
<!-- include https://github.com/devlooped/sponsors/raw/main/footer.md -->
107-
108-
<!-- exclude -->
109-
""");
110-
111-
AnsiConsole.WriteLine();
112-
AnsiConsole.Write(new Rule("[green]Done![/]").RuleStyle("grey").LeftJustified());
113-
AnsiConsole.WriteLine();
114-
AnsiConsole.MarkupLine($"[bold]Project:[/] [yellow]{projectName}[/]");
115-
AnsiConsole.MarkupLine($"[bold]Repo:[/] [yellow]{repoName}[/]");
116-
AnsiConsole.MarkupLine($"[bold]Package ID:[/] [yellow]{packageId}[/]");
117-
118-
async Task RunDotNet(string command, string description)
17+
await ConsoleApp.RunAsync(args, async (
18+
/// <summary>Project name</summary>
19+
string? project = null,
20+
/// <summary>Repo name (defaults to project name)</summary>
21+
string? repo = null,
22+
/// <summary>Package ID (defaults to Devlooped.{project})</summary>
23+
string? package = null) =>
11924
{
120-
AnsiConsole.MarkupLine($"[grey]{Markup.Escape(description)}...[/]");
121-
await Cli.Wrap(dotnet)
122-
.WithArguments(command)
123-
.WithStandardOutputPipe(PipeTarget.ToStream(Console.OpenStandardOutput()))
124-
.WithStandardErrorPipe(PipeTarget.ToStream(Console.OpenStandardError()))
125-
.ExecuteAsync();
126-
AnsiConsole.MarkupLine($"[green]✓[/] {Markup.Escape(description)}");
127-
}
25+
string dotnet = Path.GetFullPath(
26+
Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), "..", "..", "..",
27+
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "dotnet.exe" : "dotnet"));
28+
29+
AnsiConsole.Write(new FigletText("devlooped oss").Color(Color.Green));
30+
AnsiConsole.WriteLine();
31+
32+
var projectName = project ?? AnsiConsole.Prompt(
33+
new TextPrompt<string>("[green]Project name[/]:")
34+
.PromptStyle("yellow")
35+
.ValidationErrorMessage("[red]Project name cannot be empty[/]")
36+
.Validate(v => !string.IsNullOrWhiteSpace(v)));
37+
38+
var repoName = repo ?? AnsiConsole.Prompt(
39+
new TextPrompt<string>("[green]Repo name[/]:")
40+
.PromptStyle("yellow")
41+
.DefaultValue(projectName));
42+
43+
var packageId = package ?? AnsiConsole.Prompt(
44+
new TextPrompt<string>("[green]Package ID[/]:")
45+
.PromptStyle("yellow")
46+
.DefaultValue($"Devlooped.{projectName}"));
47+
48+
AnsiConsole.WriteLine();
49+
AnsiConsole.Write(new Rule("[yellow]Setting up OSS project[/]").RuleStyle("grey").LeftJustified());
50+
AnsiConsole.WriteLine();
51+
52+
await RunDotNet("file init https://github.com/devlooped/oss/blob/main/.netconfig", "Initializing dotnet file sync from devlooped/oss");
53+
await RunDotNet($"new classlib -n {projectName} -o src/{projectName} -f net10.0", $"Creating class library src/{projectName}");
54+
File.Delete($"src/{projectName}/Class1.cs");
55+
await RunDotNet($"package add NuGetizer --project src/{projectName}/{projectName}.csproj", "Adding NuGetizer");
56+
await RunDotNet($"new xunit -n Tests -o src/Tests -f net10.0", "Creating xUnit test project src/Tests");
57+
File.Delete($"src/Tests/UnitTest1.cs");
58+
await RunDotNet($"add src/Tests/Tests.csproj reference src/{projectName}/{projectName}.csproj", $"Adding reference from Tests to {projectName}");
59+
60+
var doc = XDocument.Load($"src/{projectName}/{projectName}.csproj", LoadOptions.None);
61+
doc.Root?.Element("PropertyGroup")?.Element("ImplicitUsings")?.Remove();
62+
doc.Root?.Element("PropertyGroup")?.Element("Nullable")?.Remove();
63+
doc.Root?.Element("PropertyGroup")?.Add(new XElement("PackageId", packageId));
64+
doc.Save($"src/{projectName}/{projectName}.csproj");
65+
66+
doc = XDocument.Load($"src/Tests/Tests.csproj", LoadOptions.None);
67+
doc.Root?.Element("PropertyGroup")?.Element("ImplicitUsings")?.Remove();
68+
doc.Root?.Element("PropertyGroup")?.Element("Nullable")?.Remove();
69+
doc.Root?.Element("PropertyGroup")?.Element("IsPackable")?.Remove();
70+
doc.Save($"src/Tests/Tests.csproj");
71+
72+
File.WriteAllText($"src/Directory.props",
73+
$"""
74+
<Project>
75+
<PropertyGroup>
76+
<Product>{projectName}</Product>
77+
<ImplicitUsings>true</ImplicitUsings>
78+
</PropertyGroup>
79+
</Project>
80+
""");
81+
82+
await RunDotNet($"new solution -n {projectName}", $"Creating solution {projectName}.slnx");
83+
await RunDotNet($"sln {projectName}.slnx add --in-root src/{projectName}/{projectName}.csproj src/Tests/Tests.csproj", $"Adding projects to {projectName}.slnx");
84+
85+
await AnsiConsole.Status()
86+
.Spinner(Spinner.Known.Dots)
87+
.SpinnerStyle(Style.Parse("green"))
88+
.StartAsync("Downloading readme.md template...", async ctx =>
89+
{
90+
using var http = new HttpClient();
91+
var readmeContent = await http.GetStringAsync(
92+
"https://raw.githubusercontent.com/devlooped/oss/main/readme.tmp.md");
93+
94+
readmeContent = readmeContent
95+
.Replace("{{PROJECT_NAME}}", projectName)
96+
.Replace("{{PACKAGE_ID}}", packageId)
97+
.Replace("{{REPO_NAME}}", repoName);
98+
99+
await File.WriteAllTextAsync("readme.md", readmeContent);
100+
ctx.Status("Downloaded and processed readme.md");
101+
});
102+
103+
AnsiConsole.MarkupLine("[green]✓[/] Created [yellow]readme.md[/]");
104+
105+
await File.WriteAllTextAsync(
106+
Path.Combine("src", projectName, "readme.md"),
107+
$"""
108+
[![EULA](https://img.shields.io/badge/EULA-OSMF-blue?labelColor=black&color=C9FF30)](osmfeula.txt)
109+
[![OSS](https://img.shields.io/github/license/devlooped/oss.svg?color=blue)](license.txt)
110+
[![GitHub](https://img.shields.io/badge/-source-181717.svg?logo=GitHub)](https://github.com/devlooped/{repoName})
111+
112+
<!-- include ../../readme.md#content -->
113+
114+
<!-- include https://github.com/devlooped/.github/raw/main/osmf.md -->
115+
116+
<!-- include https://github.com/devlooped/sponsors/raw/main/footer.md -->
117+
118+
<!-- exclude -->
119+
""");
120+
121+
AnsiConsole.WriteLine();
122+
AnsiConsole.Write(new Rule("[green]Done![/]").RuleStyle("grey").LeftJustified());
123+
AnsiConsole.WriteLine();
124+
AnsiConsole.MarkupLine($"[bold]Project:[/] [yellow]{projectName}[/]");
125+
AnsiConsole.MarkupLine($"[bold]Repo:[/] [yellow]{repoName}[/]");
126+
AnsiConsole.MarkupLine($"[bold]Package ID:[/] [yellow]{packageId}[/]");
127+
128+
async Task RunDotNet(string command, string description)
129+
{
130+
AnsiConsole.MarkupLine($"[grey]{Markup.Escape(description)}...[/]");
131+
await Cli.Wrap(dotnet)
132+
.WithArguments(command)
133+
.WithStandardOutputPipe(PipeTarget.ToStream(Console.OpenStandardOutput()))
134+
.WithStandardErrorPipe(PipeTarget.ToStream(Console.OpenStandardError()))
135+
.ExecuteAsync();
136+
AnsiConsole.MarkupLine($"[green]✓[/] {Markup.Escape(description)}");
137+
}
138+
});

0 commit comments

Comments
 (0)