diff --git a/src/Fallout.Cli/Program.Setup.cs b/src/Fallout.Cli/BuildScaffolder.cs
similarity index 79%
rename from src/Fallout.Cli/Program.Setup.cs
rename to src/Fallout.Cli/BuildScaffolder.cs
index 036d1c68..2337e1d0 100644
--- a/src/Fallout.Cli/Program.Setup.cs
+++ b/src/Fallout.Cli/BuildScaffolder.cs
@@ -1,16 +1,9 @@
-using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
using System.Reflection;
-using System.Text;
using Fallout.Common;
-using Fallout.Common.Execution;
using Fallout.Common.IO;
-using Fallout.Common.Tooling;
using Fallout.Common.Utilities;
-using Fallout.Common.Utilities.Collections;
-using Spectre.Console;
using static Fallout.Common.Constants;
using static Fallout.Common.EnvironmentInfo;
using static Fallout.Common.Tooling.ProcessTasks;
@@ -18,70 +11,27 @@
namespace Fallout.Cli;
-partial class Program
+/// Writes the build scripts, configuration file and solution wiring when scaffolding a build.
+public interface IBuildScaffolder
{
- // ReSharper disable InconsistentNaming
+ void WriteBuildScripts(AbsolutePath scriptDirectory, AbsolutePath rootDirectory, AbsolutePath buildDirectory, string buildProjectName);
+ void WriteConfigurationFile(AbsolutePath rootDirectory, AbsolutePath solutionFile);
+ void UpdateSolutionFileContent(List content, string buildProjectFileRelative, string buildProjectGuid, string buildProjectName);
+ string[] GetTemplate(string templateName);
+}
+///
+public sealed class BuildScaffolder : IBuildScaffolder
+{
private const string PROJECT_KIND = "9A19103F-16F7-4668-BE54-9A1E7A4F7556";
- // Transitional shim: cake (still a legacy handler) invokes setup directly. Removed once cake is
- // converted; the dispatcher itself resolves SetupCommand from the registry, not this.
- internal static int Setup(string[] args, AbsolutePath rootDirectory, AbsolutePath buildScript)
- => new Commands.SetupCommand(s_prompts).Execute(args, rootDirectory, buildScript);
-
- // Residual after the :setup command moved to SetupCommand: these scaffolding helpers are shared
- // with update (and UpdateSolutionFileContent is exercised directly by tests). They move into a
- // scaffolding service in the #392 collapse PR.
- internal static void UpdateSolutionFileContent(
- List content,
- string buildProjectFileRelative,
- string buildProjectGuid,
- string buildProjectName)
- {
- if (content.Any(x => x.Contains(buildProjectFileRelative)))
- return;
-
- var globalIndex = content.IndexOf("Global");
- Assert.True(globalIndex != -1, "Could not find a 'Global' section in solution file");
-
- var projectConfigurationIndex = content.FindIndex(x => x.Contains("GlobalSection(ProjectConfigurationPlatforms)"));
- if (projectConfigurationIndex == -1)
- {
- var solutionConfigurationIndex = content.FindIndex(x => x.Contains("GlobalSection(SolutionConfigurationPlatforms)"));
- if (solutionConfigurationIndex == -1)
- {
- content.Insert(globalIndex + 1, "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution");
- content.Insert(globalIndex + 2, "\t\tDebug|Any CPU = Debug|Any CPU");
- content.Insert(globalIndex + 3, "\t\tRelease|Any CPU = Release|Any CPU");
- content.Insert(globalIndex + 4, "\tEndGlobalSection");
-
- solutionConfigurationIndex = globalIndex + 1;
- }
-
- var endGlobalSectionIndex = content.FindIndex(solutionConfigurationIndex, x => x.Contains("EndGlobalSection"));
-
- content.Insert(endGlobalSectionIndex + 1, "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution");
- content.Insert(endGlobalSectionIndex + 2, "\tEndGlobalSection");
-
- projectConfigurationIndex = endGlobalSectionIndex + 1;
- }
-
- content.Insert(projectConfigurationIndex + 1, $"\t\t{{{buildProjectGuid}}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU");
- content.Insert(projectConfigurationIndex + 2, $"\t\t{{{buildProjectGuid}}}.Release|Any CPU.ActiveCfg = Release|Any CPU");
-
- content.Insert(globalIndex,
- $"Project(\"{{{PROJECT_KIND}}}\") = \"{buildProjectName}\", \"{buildProjectFileRelative}\", \"{{{buildProjectGuid}}}\"");
- content.Insert(globalIndex + 1,
- "EndProject");
- }
-
- internal static string[] GetTemplate(string templateName)
+ public string[] GetTemplate(string templateName)
{
- return ResourceUtility.GetResourceAllLines($"templates.{templateName}");
+ // Anchored to the Fallout.Cli root namespace where the templates/* resources are embedded.
+ return ResourceUtility.GetResourceAllLines($"templates.{templateName}");
}
-
- internal static void WriteBuildScripts(
+ public void WriteBuildScripts(
AbsolutePath scriptDirectory,
AbsolutePath rootDirectory,
AbsolutePath buildDirectory,
@@ -121,7 +71,7 @@ internal static void WriteBuildScripts(
tokens: GetDictionary(
new
{
- FalloutCliVersion = typeof(Program).GetTypeInfo().Assembly.GetVersionText(),
+ FalloutCliVersion = typeof(BuildScaffolder).GetTypeInfo().Assembly.GetVersionText(),
})));
}
@@ -140,7 +90,7 @@ void MakeExecutable(AbsolutePath scriptFile)
}
}
- internal static void WriteConfigurationFile(AbsolutePath rootDirectory, AbsolutePath solutionFile)
+ public void WriteConfigurationFile(AbsolutePath rootDirectory, AbsolutePath solutionFile)
{
var parametersFile = GetDefaultParametersFile(rootDirectory);
var dictionary = new Dictionary { ["$schema"] = BuildSchemaFileName };
@@ -148,4 +98,47 @@ internal static void WriteConfigurationFile(AbsolutePath rootDirectory, Absolute
dictionary["Solution"] = rootDirectory.GetUnixRelativePathTo(solutionFile).ToString();
parametersFile.WriteJson(dictionary, JsonExtensions.DefaultSerializerOptions);
}
+
+ public void UpdateSolutionFileContent(
+ List content,
+ string buildProjectFileRelative,
+ string buildProjectGuid,
+ string buildProjectName)
+ {
+ if (content.Any(x => x.Contains(buildProjectFileRelative)))
+ return;
+
+ var globalIndex = content.IndexOf("Global");
+ Assert.True(globalIndex != -1, "Could not find a 'Global' section in solution file");
+
+ var projectConfigurationIndex = content.FindIndex(x => x.Contains("GlobalSection(ProjectConfigurationPlatforms)"));
+ if (projectConfigurationIndex == -1)
+ {
+ var solutionConfigurationIndex = content.FindIndex(x => x.Contains("GlobalSection(SolutionConfigurationPlatforms)"));
+ if (solutionConfigurationIndex == -1)
+ {
+ content.Insert(globalIndex + 1, "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution");
+ content.Insert(globalIndex + 2, "\t\tDebug|Any CPU = Debug|Any CPU");
+ content.Insert(globalIndex + 3, "\t\tRelease|Any CPU = Release|Any CPU");
+ content.Insert(globalIndex + 4, "\tEndGlobalSection");
+
+ solutionConfigurationIndex = globalIndex + 1;
+ }
+
+ var endGlobalSectionIndex = content.FindIndex(solutionConfigurationIndex, x => x.Contains("EndGlobalSection"));
+
+ content.Insert(endGlobalSectionIndex + 1, "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution");
+ content.Insert(endGlobalSectionIndex + 2, "\tEndGlobalSection");
+
+ projectConfigurationIndex = endGlobalSectionIndex + 1;
+ }
+
+ content.Insert(projectConfigurationIndex + 1, $"\t\t{{{buildProjectGuid}}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU");
+ content.Insert(projectConfigurationIndex + 2, $"\t\t{{{buildProjectGuid}}}.Release|Any CPU.ActiveCfg = Release|Any CPU");
+
+ content.Insert(globalIndex,
+ $"Project(\"{{{PROJECT_KIND}}}\") = \"{buildProjectName}\", \"{buildProjectFileRelative}\", \"{{{buildProjectGuid}}}\"");
+ content.Insert(globalIndex + 1,
+ "EndProject");
+ }
}
diff --git a/src/Fallout.Cli/Program.Cake.cs b/src/Fallout.Cli/CakeConverter.cs
similarity index 68%
rename from src/Fallout.Cli/Program.Cake.cs
rename to src/Fallout.Cli/CakeConverter.cs
index 5d9b7d76..85ea20fa 100644
--- a/src/Fallout.Cli/Program.Cake.cs
+++ b/src/Fallout.Cli/CakeConverter.cs
@@ -1,12 +1,10 @@
-ο»Ώusing System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Fallout.Common;
-using Fallout.Common.Execution;
using Fallout.Common.IO;
-using Fallout.Solutions;
using Fallout.Common.Tooling;
using Fallout.Common.Utilities;
using Fallout.Cli.Rewriting.Cake;
@@ -15,19 +13,17 @@
namespace Fallout.Cli;
-partial class Program
+/// Best-effort syntax rewriting of Cake (*.cake) scripts into Fallout C#.
+internal static class CakeConverter
{
- public const string CAKE_FILE_PATTERN = "*.cake";
+ public const string FilePattern = "*.cake";
- // Residual after the :cake-convert/:cake-clean commands moved to CakeConvertCommand/
- // CakeCleanCommand: these .cake syntax-rewriting helpers stay on Program until the #392 collapse
- // PR (GetCakeConvertedContent/GetCakePackages are exercised directly by tests).
- internal static IEnumerable GetCakeFiles()
+ public static IEnumerable GetCakeFiles()
{
- return (TryGetRootDirectoryFrom(WorkingDirectory) ?? WorkingDirectory).GlobFiles($"**/{CAKE_FILE_PATTERN}");
+ return (TryGetRootDirectoryFrom(WorkingDirectory) ?? WorkingDirectory).GlobFiles($"**/{FilePattern}");
}
- internal static string GetCakeConvertedContent(string content)
+ public static string GetConvertedContent(string content)
{
var options = new CSharpParseOptions(LanguageVersion.Latest, DocumentationMode.None, SourceCodeKind.Script);
var syntaxTree = CSharpSyntaxTree.ParseText(content, options);
@@ -49,7 +45,7 @@ internal static string GetCakeConvertedContent(string content)
.ToFullString();
}
- internal static IEnumerable<(string Type, string Id, string Version)> GetCakePackages(string content)
+ public static IEnumerable<(string Type, string Id, string Version)> GetPackages(string content)
{
IEnumerable<(string Type, string Id, string Version)> GetPackages(
string packageType,
@@ -66,8 +62,8 @@ internal static string GetCakeConvertedContent(string content)
}
}
- return GetPackages(PACKAGE_TYPE_DOWNLOAD, @"#tool ""nuget:\?package=(?'packageId'[\w\d\.]+)(&version=(?'version'[\w\d\.]+))?S*""")
- .Concat(GetPackages(PACKAGE_TYPE_REFERENCE, @"#addin ""nuget:\?package=(?'packageId'[\w\d\.]+)(&version=(?'version'[\w\d\.]+))?S*"""))
+ return GetPackages(PackageManager.DownloadType, @"#tool ""nuget:\?package=(?'packageId'[\w\d\.]+)(&version=(?'version'[\w\d\.]+))?S*""")
+ .Concat(GetPackages(PackageManager.ReferenceType, @"#addin ""nuget:\?package=(?'packageId'[\w\d\.]+)(&version=(?'version'[\w\d\.]+))?S*"""))
.Where(x => !x.Id.ContainsOrdinalIgnoreCase("Cake"));
}
}
diff --git a/src/Fallout.Cli/CliConventions.cs b/src/Fallout.Cli/CliConventions.cs
new file mode 100644
index 00000000..756bf64d
--- /dev/null
+++ b/src/Fallout.Cli/CliConventions.cs
@@ -0,0 +1,18 @@
+using Fallout.Common;
+using Fallout.Common.Utilities;
+
+namespace Fallout.Cli;
+
+/// Small CLI-wide conventions shared by the entry point and commands.
+internal static class CliConventions
+{
+ /// The build-script file name for the current platform.
+ public static string CurrentBuildScriptName => EnvironmentInfo.IsWin ? "build.ps1" : "build.sh";
+}
+
+/// Prints the global-tool banner.
+internal static class ToolBanner
+{
+ public static void Print()
+ => Host.Information($"NUKE Global Tool π {typeof(ToolBanner).Assembly.GetInformationalText()}");
+}
diff --git a/src/Fallout.Cli/Commands/AddPackageCommand.cs b/src/Fallout.Cli/Commands/AddPackageCommand.cs
index 2e4879ad..9383b293 100644
--- a/src/Fallout.Cli/Commands/AddPackageCommand.cs
+++ b/src/Fallout.Cli/Commands/AddPackageCommand.cs
@@ -13,11 +13,20 @@ namespace Fallout.Cli.Commands;
///
public sealed class AddPackageCommand : IFalloutCommand
{
+ private readonly IConfigurationReader _configuration;
+ private readonly IPackageManager _packages;
+
+ public AddPackageCommand(IConfigurationReader configuration, IPackageManager packages)
+ {
+ _configuration = configuration;
+ _packages = packages;
+ }
+
public string Name => "add-package";
public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath buildScript)
{
- Program.PrintInfo();
+ ToolBanner.Print();
Logging.Configure();
Telemetry.AddPackage();
ProjectModelTasks.Initialize();
@@ -30,19 +39,17 @@ public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath build
NuGetPackageResolver.GetGlobalInstalledPackage(packageId, version: null, packagesConfigFile: null)?.Version.ToString())
.NotNull("packageVersion != null");
- // GetConfiguration / AddOrReplacePackage / BUILD_PROJECT_FILE / PACKAGE_TYPE_* are shared
- // helpers still on Program; they move into services in the final #392 collapse PR.
- var configuration = Program.GetConfiguration(buildScript, evaluate: true);
- var buildProjectFile = configuration[Program.BUILD_PROJECT_FILE];
+ var configuration = _configuration.Read(buildScript, evaluate: true);
+ var buildProjectFile = configuration[ConfigurationReader.BuildProjectFileKey];
Host.Information($"Installing {packageId}/{packageVersion} to {buildProjectFile} ...");
- Program.AddOrReplacePackage(packageId, packageVersion, Program.PACKAGE_TYPE_DOWNLOAD, buildProjectFile);
+ _packages.AddOrReplacePackage(packageId, packageVersion, PackageManager.DownloadType, buildProjectFile);
DotNetTasks.DotNet($"restore {buildProjectFile}");
var installedPackage = NuGetPackageResolver.GetGlobalInstalledPackage(packageId, packageVersion, packagesConfigFile: null)
.NotNull("installedPackage != null");
var hasToolsDirectory = installedPackage.Directory.GlobDirectories("tools").Any();
if (!hasToolsDirectory)
- Program.AddOrReplacePackage(packageId, packageVersion, Program.PACKAGE_TYPE_REFERENCE, buildProjectFile);
+ _packages.AddOrReplacePackage(packageId, packageVersion, PackageManager.ReferenceType, buildProjectFile);
Host.Information($"Done installing {packageId}/{packageVersion} to {buildProjectFile}");
return 0;
diff --git a/src/Fallout.Cli/Commands/CakeCleanCommand.cs b/src/Fallout.Cli/Commands/CakeCleanCommand.cs
index 07205c4a..341848e0 100644
--- a/src/Fallout.Cli/Commands/CakeCleanCommand.cs
+++ b/src/Fallout.Cli/Commands/CakeCleanCommand.cs
@@ -18,7 +18,7 @@ public sealed class CakeCleanCommand : IFalloutCommand
public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath buildScript)
{
- var cakeFiles = Program.GetCakeFiles().ToList();
+ var cakeFiles = CakeConverter.GetCakeFiles().ToList();
Host.Information("Found .cake files:");
cakeFiles.ForEach(x => Host.Debug($" - {x}"));
diff --git a/src/Fallout.Cli/Commands/CakeConvertCommand.cs b/src/Fallout.Cli/Commands/CakeConvertCommand.cs
index 801c1b59..c91c1775 100644
--- a/src/Fallout.Cli/Commands/CakeConvertCommand.cs
+++ b/src/Fallout.Cli/Commands/CakeConvertCommand.cs
@@ -16,17 +16,27 @@ namespace Fallout.Cli.Commands;
public sealed class CakeConvertCommand : IFalloutCommand
{
private readonly IConsolePrompts _prompts;
+ private readonly IConfigurationReader _configuration;
+ private readonly IPackageManager _packages;
+ private readonly SetupCommand _setup;
- public CakeConvertCommand(IConsolePrompts prompts) => _prompts = prompts;
+ public CakeConvertCommand(
+ IConsolePrompts prompts,
+ IConfigurationReader configuration,
+ IPackageManager packages,
+ SetupCommand setup)
+ {
+ _prompts = prompts;
+ _configuration = configuration;
+ _packages = packages;
+ _setup = setup;
+ }
public string Name => "cake-convert";
- // The .cake syntax-rewriting helpers (GetCakeFiles/GetCakeConvertedContent/GetCakePackages) and
- // the shared GetConfiguration/AddOrReplacePackage helpers remain on Program until the #392
- // collapse PR; GetCakeConvertedContent/GetCakePackages are also exercised directly by tests.
public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath buildScript)
{
- Program.PrintInfo();
+ ToolBanner.Print();
Logging.Configure();
Telemetry.ConvertCake();
ProjectModelTasks.Initialize();
@@ -53,27 +63,27 @@ public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath build
if (buildScript == null &&
_prompts.PromptForConfirmation("Should a NUKE project be created for better results?"))
{
- Program.Setup(args, rootDirectory: null, buildScript: null);
+ _setup.Execute(args, rootDirectory: null, buildScript: null);
}
- var buildScriptFile = WorkingDirectory / Program.CurrentBuildScriptName;
+ var buildScriptFile = WorkingDirectory / CliConventions.CurrentBuildScriptName;
var buildProjectFile = buildScriptFile.Exists()
- ? Program.GetConfiguration(buildScriptFile, evaluate: true)
- .GetValueOrDefault(Program.BUILD_PROJECT_FILE, defaultValue: null)
+ ? _configuration.Read(buildScriptFile, evaluate: true)
+ .GetValueOrDefault(ConfigurationReader.BuildProjectFileKey, defaultValue: null)
: null;
- foreach (var cakeFile in Program.GetCakeFiles())
+ foreach (var cakeFile in CakeConverter.GetCakeFiles())
{
var outputFile = cakeFile.Parent / cakeFile.NameWithoutExtension.Capitalize() + ".cs";
- var content = Program.GetCakeConvertedContent(cakeFile.ReadAllText());
+ var content = CakeConverter.GetConvertedContent(cakeFile.ReadAllText());
outputFile.WriteAllText(content);
}
if (buildProjectFile != null)
{
- var packages = Program.GetCakeFiles().SelectMany(x => Program.GetCakePackages(x.ReadAllText()));
+ var packages = CakeConverter.GetCakeFiles().SelectMany(x => CakeConverter.GetPackages(x.ReadAllText()));
foreach (var package in packages)
- Program.AddOrReplacePackage(package.Id, package.Version, package.Type, buildProjectFile);
+ _packages.AddOrReplacePackage(package.Id, package.Version, package.Type, buildProjectFile);
}
return 0;
diff --git a/src/Fallout.Cli/Commands/DelegateCommand.cs b/src/Fallout.Cli/Commands/DelegateCommand.cs
deleted file mode 100644
index 5a60e855..00000000
--- a/src/Fallout.Cli/Commands/DelegateCommand.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System;
-using Fallout.Common.IO;
-
-namespace Fallout.Cli.Commands;
-
-///
-/// Transitional adapter that exposes a not-yet-extracted Program.X handler as an
-/// , so the dispatcher can route every command uniformly through the
-/// registry while the per-command conversion (issue #392) lands one PR at a time. Each conversion
-/// replaces one registration of this adapter with a real command type; the adapter is deleted once
-/// the last legacy handler is gone.
-///
-internal sealed class DelegateCommand : IFalloutCommand
-{
- private readonly Func _handler;
-
- public DelegateCommand(string name, Func handler)
- {
- Name = name;
- _handler = handler;
- }
-
- public string Name { get; }
-
- public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath buildScript)
- => _handler(args, rootDirectory, buildScript);
-}
diff --git a/src/Fallout.Cli/Commands/GetConfigurationCommand.cs b/src/Fallout.Cli/Commands/GetConfigurationCommand.cs
index 4af696eb..990aa1d6 100644
--- a/src/Fallout.Cli/Commands/GetConfigurationCommand.cs
+++ b/src/Fallout.Cli/Commands/GetConfigurationCommand.cs
@@ -11,13 +11,15 @@ namespace Fallout.Cli.Commands;
///
public sealed class GetConfigurationCommand : IFalloutCommand
{
+ private readonly IConfigurationReader _configuration;
+
+ public GetConfigurationCommand(IConfigurationReader configuration) => _configuration = configuration;
+
public string Name => "get-configuration";
public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath buildScript)
{
- // Program.GetConfiguration(buildScript, evaluate) is shared with add-package/update/cake;
- // it moves into a configuration service in the final #392 collapse PR.
- var configuration = Program.GetConfiguration(buildScript.NotNull(), evaluate: false);
+ var configuration = _configuration.Read(buildScript.NotNull(), evaluate: false);
Host.Information($"Configuration from {buildScript}:");
configuration.ForEach(x => Console.WriteLine($"{x.Key} = {x.Value}"));
diff --git a/src/Fallout.Cli/Commands/SetupCommand.cs b/src/Fallout.Cli/Commands/SetupCommand.cs
index fda9bb7e..121d5dfa 100644
--- a/src/Fallout.Cli/Commands/SetupCommand.cs
+++ b/src/Fallout.Cli/Commands/SetupCommand.cs
@@ -25,16 +25,19 @@ public sealed class SetupCommand : IFalloutCommand
private const string TARGET_FRAMEWORK = "net8.0";
private readonly IConsolePrompts _prompts;
+ private readonly IBuildScaffolder _scaffolder;
- public SetupCommand(IConsolePrompts prompts) => _prompts = prompts;
+ public SetupCommand(IConsolePrompts prompts, IBuildScaffolder scaffolder)
+ {
+ _prompts = prompts;
+ _scaffolder = scaffolder;
+ }
public string Name => "setup";
- // The scaffolding helpers (WriteBuildScripts/WriteConfigurationFile/UpdateSolutionFileContent/
- // GetTemplate) remain on Program as internal residual until the #392 collapse PR extracts them.
public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath buildScript)
{
- Program.PrintInfo();
+ ToolBanner.Print();
Logging.Configure();
Telemetry.SetupBuild();
@@ -100,25 +103,25 @@ public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath build
(rootDirectory / FalloutDirectoryName).CreateDirectory();
- Program.WriteBuildScripts(
+ _scaffolder.WriteBuildScripts(
scriptDirectory: WorkingDirectory,
rootDirectory,
buildDirectory,
buildProjectName);
- Program.WriteConfigurationFile(rootDirectory, solutionFile);
+ _scaffolder.WriteConfigurationFile(rootDirectory, solutionFile);
if (solutionFile != null)
{
var solutionFileContent = solutionFile.ReadAllLines().ToList();
var buildProjectFileRelative = solutionFile.Parent.GetWinRelativePathTo(buildProjectFile);
- Program.UpdateSolutionFileContent(solutionFileContent, buildProjectFileRelative, buildProjectGuid, buildProjectName);
+ _scaffolder.UpdateSolutionFileContent(solutionFileContent, buildProjectFileRelative, buildProjectGuid, buildProjectName);
solutionFile.WriteAllLines(solutionFileContent, Encoding.UTF8);
}
buildProjectFile.WriteAllLines(
FillTemplate(
- Program.GetTemplate("_build.csproj"),
+ _scaffolder.GetTemplate("_build.csproj"),
GetDictionary(
new
{
@@ -129,10 +132,10 @@ public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath build
NukeVersion = nukeVersion,
})));
- (buildDirectory / "Directory.Build.props").WriteAllLines(Program.GetTemplate("Directory.Build.props"));
- (buildDirectory / "Directory.Build.targets").WriteAllLines(Program.GetTemplate("Directory.Build.targets"));
- (buildDirectory / "Build.cs").WriteAllLines(FillTemplate(Program.GetTemplate("Build.cs")));
- (buildDirectory / "Configuration.cs").WriteAllLines(Program.GetTemplate("Configuration.cs"));
+ (buildDirectory / "Directory.Build.props").WriteAllLines(_scaffolder.GetTemplate("Directory.Build.props"));
+ (buildDirectory / "Directory.Build.targets").WriteAllLines(_scaffolder.GetTemplate("Directory.Build.targets"));
+ (buildDirectory / "Build.cs").WriteAllLines(FillTemplate(_scaffolder.GetTemplate("Build.cs")));
+ (buildDirectory / "Configuration.cs").WriteAllLines(_scaffolder.GetTemplate("Configuration.cs"));
#endregion
diff --git a/src/Fallout.Cli/Commands/UpdateCommand.cs b/src/Fallout.Cli/Commands/UpdateCommand.cs
index 6bf7ce2d..d8f0590a 100644
--- a/src/Fallout.Cli/Commands/UpdateCommand.cs
+++ b/src/Fallout.Cli/Commands/UpdateCommand.cs
@@ -18,16 +18,21 @@ namespace Fallout.Cli.Commands;
public sealed class UpdateCommand : IFalloutCommand
{
private readonly IConsolePrompts _prompts;
+ private readonly IConfigurationReader _configuration;
+ private readonly IBuildScaffolder _scaffolder;
- public UpdateCommand(IConsolePrompts prompts) => _prompts = prompts;
+ public UpdateCommand(IConsolePrompts prompts, IConfigurationReader configuration, IBuildScaffolder scaffolder)
+ {
+ _prompts = prompts;
+ _configuration = configuration;
+ _scaffolder = scaffolder;
+ }
public string Name => "update";
- // GetConfiguration / WriteBuildScripts / WriteConfigurationFile / BUILD_PROJECT_FILE remain on
- // Program as internal residual until the #392 collapse PR extracts them into services.
public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath buildScript)
{
- Program.PrintInfo();
+ ToolBanner.Print();
Logging.Configure();
Assert.NotNull(rootDirectory);
@@ -46,27 +51,27 @@ public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath build
return 0;
}
- private static void UpdateBuildScripts(AbsolutePath rootDirectory, AbsolutePath buildScript)
+ private void UpdateBuildScripts(AbsolutePath rootDirectory, AbsolutePath buildScript)
{
- var configuration = Program.GetConfiguration(buildScript, evaluate: true);
- var buildProjectFile = (AbsolutePath) configuration[Program.BUILD_PROJECT_FILE];
+ var configuration = _configuration.Read(buildScript, evaluate: true);
+ var buildProjectFile = (AbsolutePath) configuration[ConfigurationReader.BuildProjectFileKey];
- Program.WriteBuildScripts(
+ _scaffolder.WriteBuildScripts(
scriptDirectory: buildScript.Parent,
rootDirectory,
buildDirectory: buildProjectFile.NotNull().Parent,
buildProjectName: Path.GetFileNameWithoutExtension(buildProjectFile));
}
- private static void UpdateBuildProject(AbsolutePath buildScript)
+ private void UpdateBuildProject(AbsolutePath buildScript)
{
- var configuration = Program.GetConfiguration(buildScript, evaluate: true);
- var projectFile = configuration[Program.BUILD_PROJECT_FILE];
+ var configuration = _configuration.Read(buildScript, evaluate: true);
+ var projectFile = configuration[ConfigurationReader.BuildProjectFileKey];
ProjectModelTasks.Initialize();
ProjectUpdater.Update(projectFile);
}
- private static void UpdateConfigurationFile(AbsolutePath rootDirectory)
+ private void UpdateConfigurationFile(AbsolutePath rootDirectory)
{
var configurationFile = rootDirectory / FalloutDirectoryName;
if (!configurationFile.Exists())
@@ -75,7 +80,7 @@ private static void UpdateConfigurationFile(AbsolutePath rootDirectory)
var solutionFile = rootDirectory / configurationFile.ReadAllLines().FirstOrDefault(x => !x.IsNullOrEmpty());
configurationFile.DeleteFile();
- Program.WriteConfigurationFile(rootDirectory, solutionFile);
+ _scaffolder.WriteConfigurationFile(rootDirectory, solutionFile);
Host.Warning($"The previous {FalloutFileName} file was transformed to a {FalloutDirectoryName} directory.");
Host.Warning($"The .tmp directory can be cleared, as it is moved to {FalloutDirectoryName}/temp as well.");
if (solutionFile != null)
diff --git a/src/Fallout.Cli/Program.GetConfiguration.cs b/src/Fallout.Cli/ConfigurationReader.cs
similarity index 52%
rename from src/Fallout.Cli/Program.GetConfiguration.cs
rename to src/Fallout.Cli/ConfigurationReader.cs
index 6cda748b..ebbbc26a 100644
--- a/src/Fallout.Cli/Program.GetConfiguration.cs
+++ b/src/Fallout.Cli/ConfigurationReader.cs
@@ -1,27 +1,24 @@
-ο»Ώusing System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using Fallout.Common;
using Fallout.Common.IO;
using Fallout.Common.Utilities;
-using Fallout.Common.Utilities.Collections;
namespace Fallout.Cli;
-partial class Program
+/// Parses the # CONFIGURATION β¦ # EXECUTION block out of a build script.
+public interface IConfigurationReader
{
- // internal (not private): shared with AddPackage/Update/Cake; will move into a configuration
- // service in the final #392 collapse PR.
- internal const string BUILD_PROJECT_FILE = nameof(BUILD_PROJECT_FILE);
- private const string TEMP_DIRECTORY = nameof(TEMP_DIRECTORY);
- private const string DOTNET_GLOBAL_FILE = nameof(DOTNET_GLOBAL_FILE);
- private const string DOTNET_INSTALL_URL = nameof(DOTNET_INSTALL_URL);
- private const string DOTNET_CHANNEL = nameof(DOTNET_CHANNEL);
+ Dictionary Read(AbsolutePath buildScript, bool evaluate);
+}
+
+///
+public sealed class ConfigurationReader : IConfigurationReader
+{
+ /// Configuration key holding the build project file path.
+ public const string BuildProjectFileKey = "BUILD_PROJECT_FILE";
- // Residual after the :get-configuration command moved to GetConfigurationCommand: this helper is
- // shared with add-package/update/cake and moves into a configuration service in the #392 collapse PR.
- internal static Dictionary GetConfiguration(AbsolutePath buildScript, bool evaluate)
+ public Dictionary Read(AbsolutePath buildScript, bool evaluate)
{
string ReplaceScriptDirectory(string value)
=> evaluate
diff --git a/src/Fallout.Cli/PackageManager.cs b/src/Fallout.Cli/PackageManager.cs
new file mode 100644
index 00000000..ce131490
--- /dev/null
+++ b/src/Fallout.Cli/PackageManager.cs
@@ -0,0 +1,35 @@
+using System.Linq;
+using Fallout.Common;
+using Fallout.Common.Utilities;
+using Fallout.Solutions;
+
+namespace Fallout.Cli;
+
+/// Adds or replaces a package entry in the build project file.
+public interface IPackageManager
+{
+ void AddOrReplacePackage(string packageId, string packageVersion, string packageType, string buildProjectFile);
+}
+
+///
+public sealed class PackageManager : IPackageManager
+{
+ public const string DownloadType = "PackageDownload";
+ public const string ReferenceType = "PackageReference";
+
+ public void AddOrReplacePackage(string packageId, string packageVersion, string packageType, string buildProjectFile)
+ {
+ var buildProject = ProjectModelTasks.ParseProject(buildProjectFile).NotNull();
+
+ var previousPackage = buildProject.Items.SingleOrDefault(x => x.EvaluatedInclude == packageId);
+ if (previousPackage != null)
+ buildProject.RemoveItem(previousPackage);
+
+ var packageDownloadItem = buildProject.AddItem(packageType, packageId).Single();
+ packageDownloadItem.Xml.AddMetadata(
+ "Version",
+ packageType == ReferenceType ? packageVersion : $"[{packageVersion}]",
+ expressAsAttribute: true);
+ buildProject.Save();
+ }
+}
diff --git a/src/Fallout.Cli/Program.AddPackage.cs b/src/Fallout.Cli/Program.AddPackage.cs
deleted file mode 100644
index 87852ae4..00000000
--- a/src/Fallout.Cli/Program.AddPackage.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-ο»Ώusing System;
-using System.Linq;
-using Fallout.Common;
-using Fallout.Common.Execution;
-using Fallout.Common.IO;
-using Fallout.Solutions;
-using Fallout.Common.Tooling;
-using Fallout.Common.Tools.DotNet;
-
-namespace Fallout.Cli;
-
-partial class Program
-{
- public const string PACKAGE_TYPE_DOWNLOAD = "PackageDownload";
- public const string PACKAGE_TYPE_REFERENCE = "PackageReference";
-
- // Residual after the :add-package command moved to AddPackageCommand: this helper is shared with
- // cake and moves into a package service in the #392 collapse PR.
- internal static void AddOrReplacePackage(string packageId, string packageVersion, string packageType, string buildProjectFile)
- {
- var buildProject = ProjectModelTasks.ParseProject(buildProjectFile).NotNull();
-
- var previousPackage = buildProject.Items.SingleOrDefault(x => x.EvaluatedInclude == packageId);
- if (previousPackage != null)
- buildProject.RemoveItem(previousPackage);
-
- var packageDownloadItem = buildProject.AddItem(packageType, packageId).Single();
- packageDownloadItem.Xml.AddMetadata(
- "Version",
- packageType == PACKAGE_TYPE_REFERENCE ? packageVersion : $"[{packageVersion}]",
- expressAsAttribute: true);
- buildProject.Save();
- }
-}
diff --git a/src/Fallout.Cli/Program.cs b/src/Fallout.Cli/Program.cs
index b5f165af..8c686e1a 100644
--- a/src/Fallout.Cli/Program.cs
+++ b/src/Fallout.Cli/Program.cs
@@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using Fallout.Cli.Commands;
+using Fallout.Cli.Commands.Navigation;
using Fallout.Cli.Prompts;
using Fallout.Common;
using Fallout.Common.IO;
@@ -11,10 +12,8 @@
namespace Fallout.Cli;
-public partial class Program
+public class Program
{
- internal static string CurrentBuildScriptName => EnvironmentInfo.IsWin ? "build.ps1" : "build.sh";
-
private static int Main(string[] args)
{
Console.OutputEncoding = Encoding.UTF8;
@@ -24,7 +23,7 @@ private static int Main(string[] args)
var rootDirectory = TryGetRootDirectory();
var buildScript = rootDirectory != null
- ? rootDirectory.GetFiles(CurrentBuildScriptName, depth: 2)
+ ? rootDirectory.GetFiles(CliConventions.CurrentBuildScriptName, depth: 2)
.FirstOrDefault(x => Constants.TryGetRootDirectoryFrom(x.Parent) == rootDirectory)
: null;
@@ -43,7 +42,11 @@ private static ServiceProvider BuildServiceProvider()
var services = new ServiceCollection();
services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
services.AddSingleton();
+
RegisterCommands(services);
return services.BuildServiceProvider();
@@ -51,45 +54,31 @@ private static ServiceProvider BuildServiceProvider()
private static void RegisterCommands(IServiceCollection services)
{
- // Real command types β issue #392 converts one legacy handler per PR.
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
- services.AddSingleton();
-
- // Legacy handlers still living on Program, adapted until they are extracted into command
- // types. Each conversion deletes one line here plus its Program.X.cs partial.
services.AddSingleton();
services.AddSingleton();
-
- // Legacy handlers still living on Program, adapted until they are extracted into command
- // types. Each conversion deletes one line here plus its Program.X.cs partial.
services.AddSingleton();
services.AddSingleton();
-
- // Legacy handlers still living on Program, adapted until they are extracted into command
- // types. Each conversion deletes one line here plus its Program.X.cs partial.
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
-
- // Legacy handlers still living on Program, adapted until they are extracted into command
- // types. Each conversion deletes one line here plus its Program.X.cs partial.
- }
-
- internal static void PrintInfo()
- {
- Host.Information($"NUKE Global Tool π {typeof(Program).Assembly.GetInformationalText()}");
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+
+ // SetupCommand is also resolved directly by CakeConvertCommand, so register the concrete type
+ // and expose the same instance as an IFalloutCommand.
+ services.AddSingleton();
+ services.AddSingleton(sp => sp.GetRequiredService());
}
private static AbsolutePath TryGetRootDirectory()
{
// TODO: copied in FalloutBuild.GetRootDirectory
- AbsolutePath parameterValue = EnvironmentInfo.GetNamedArgument(Constants.RootDirectoryParameterName);
+ var parameterValue = EnvironmentInfo.GetNamedArgument(Constants.RootDirectoryParameterName);
if (parameterValue != null)
return parameterValue;
@@ -98,19 +87,4 @@ private static AbsolutePath TryGetRootDirectory()
return Constants.TryGetRootDirectoryFrom(Directory.GetCurrentDirectory());
}
-
- // ββ Transitional Spectre prompt delegators ββββββββββββββββββββββββββββββββββββββββββββββββββ
- // The implementations now live in SpectreConsolePrompts; these forwards keep the not-yet-extracted
- // Program.X.cs command handlers compiling. As each handler becomes a command type taking
- // IConsolePrompts via the constructor, its use of these disappears; the last conversion deletes them.
- private static readonly IConsolePrompts s_prompts = new SpectreConsolePrompts();
-
- private static void ShowInput(string emoji, string title, string value) => s_prompts.ShowInput(emoji, title, value);
- private static void ShowCompletion(string title) => s_prompts.ShowCompletion(title);
- private static void ClearPreviousLine() => s_prompts.ClearPreviousLine();
- private static bool PromptForConfirmation(string question) => s_prompts.PromptForConfirmation(question);
- private static string PromptForInput(string question, string defaultValue = null) => s_prompts.PromptForInput(question, defaultValue);
- private static string PromptForSecret(string title, int? minLength = null) => s_prompts.PromptForSecret(title, minLength);
- private static T PromptForChoice(string question, params (T Value, string Description)[] choices) => s_prompts.PromptForChoice(question, choices);
- private static void ConfirmExecution(string title, Action action) => s_prompts.ConfirmExecution(title, action);
}
diff --git a/tests/Fallout.Cli.Tests/CakeConversionTests.cs b/tests/Fallout.Cli.Tests/CakeConversionTests.cs
index 8357034f..fae2af97 100644
--- a/tests/Fallout.Cli.Tests/CakeConversionTests.cs
+++ b/tests/Fallout.Cli.Tests/CakeConversionTests.cs
@@ -18,7 +18,7 @@ public class CakeConversionTests
[MemberData(nameof(CakeFileNames))]
public Task Test(AbsolutePath file)
{
- var converted = Program.GetCakeConvertedContent(file.ReadAllText());
+ var converted = CakeConverter.GetConvertedContent(file.ReadAllText());
return Verifier.Verify(converted, extension: "cs")
.UseDirectory(CakeScriptsDirectory)
.UseFileName(file.NameWithoutExtension);
@@ -29,9 +29,9 @@ public void TestPackages()
{
var content = (CakeScriptsDirectory / "references.cake").ReadAllText();
- var packages = Program.GetCakePackages(content).ToList();
- packages.Should().Contain((Program.PACKAGE_TYPE_DOWNLOAD, "GitVersion.CommandLine", "4.0.0"));
- packages.Should().Contain((Program.PACKAGE_TYPE_REFERENCE, "SharpZipLib", "1.2.0"));
+ var packages = CakeConverter.GetPackages(content).ToList();
+ packages.Should().Contain((PackageManager.DownloadType, "GitVersion.CommandLine", "4.0.0"));
+ packages.Should().Contain((PackageManager.ReferenceType, "SharpZipLib", "1.2.0"));
packages.Should().Contain(x => x.Id == "TeamCity.Dotnet.Integration" &&
NuGetVersion.Parse(x.Version) > NuGetVersion.Parse("1.0.10"));
packages.Should().NotContain(x => x.Id.Contains("Cake"));
@@ -40,5 +40,5 @@ public void TestPackages()
private static AbsolutePath CakeScriptsDirectory => RootDirectory / "tests" / "Fallout.Cli.Tests" / "cake-scripts";
public static IEnumerable