Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
matkoch committed Jul 28, 2024
1 parent 33fc9ae commit d58700d
Show file tree
Hide file tree
Showing 18 changed files with 382 additions and 160 deletions.
2 changes: 1 addition & 1 deletion .teamcity/settings.kts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ project {
text (
"env.SignPathSettings",
label = "SignPathSettings",
value = "",
value = "SignPathSettings { OrganizationId = 0fdaf334-6910-41f4-83d2-e58e4cccb087, ProjectSlug = nuke, PolicySlug = release-signing }",
allowEmpty = true,
display = ParameterDisplay.NORMAL)
text (
Expand Down
2 changes: 1 addition & 1 deletion build/Build.CodeGeneration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ partial class Build
Target GenerateTools => _ => _
.Executes(() =>
{
SpecificationsDirectory.GlobFiles("*/*.json").Where(x => x.Name.Contains("DotNet")).ForEach(x =>
SpecificationsDirectory.GlobFiles("*/*.json").Where(x => x.Name != "foo").ForEach(x =>
GenerateCode(
x,
namespaceProvider: x => $"Nuke.Common.Tools.{x.Name}",
Expand Down
3 changes: 3 additions & 0 deletions build/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Nuke.Common.Tools.DotNet;
using Nuke.Common.Tools.GitVersion;
using Nuke.Components;
using Nuke.Tooling;
using static Nuke.Common.ControlFlow;
using static Nuke.Common.Tools.DotNet.DotNetTasks;
using static Nuke.Common.Tools.ReSharper.ReSharperTasks;
Expand Down Expand Up @@ -56,6 +57,8 @@ partial class Build
{
DotNet(
$"");
DotNetRestore(new DotNetRestoreSettings());
});

[CI] readonly TeamCity TeamCity;
Expand Down
4 changes: 4 additions & 0 deletions nuke-common.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,9 @@ https://github.com/nuke-build/nuke/blob/master/LICENSE</s:String>
<s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=FileA68CFA51EFE4364DA61BFD270E021A11/@KeyIndexDefined">True</s:Boolean>
<s:Double x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=FileA68CFA51EFE4364DA61BFD270E021A11/RelativePriority/@EntryValue">1</s:Double>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002ECodeCleanup_002EFileHeader_002EFileHeaderSettingsMigrate/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>
10 changes: 2 additions & 8 deletions source/Nuke.Common.Tests/SettingsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Nuke.Common.Tooling;
using Nuke.Common.Tools.DotNet;
using Nuke.Common.Utilities;
using Nuke.Tooling;
using Xunit;

namespace Nuke.Common.Tests;
Expand All @@ -34,18 +35,11 @@ public void TestCommon()
var settings = new DotNetRunSettings()
.SetProcessToolPath("/path/to/dotnet")
.SetProcessEnvironmentVariable("key", "value")
.SetProcessExecutionTimeout(TimeSpan.FromMilliseconds(1_000))
.SetProcessArgumentConfigurator(_ => _
.Add("/switch"))
.SetProcessLogger((type, str) => logEntry = (type, str))
.EnableProcessLogInvocation();
settings.ProcessLogger.Invoke(OutputType.Err, "text");
.SetProcessExecutionTimeout(TimeSpan.FromMilliseconds(1_000));

settings.ProcessToolPath.Should().Be("/path/to/dotnet");
settings.ProcessEnvironmentVariables.Should().ContainSingle(x => x.Key == "key" && x.Value == "value");
settings.ProcessExecutionTimeout.Should().Be(1_000);
settings.ProcessArgumentConfigurator.Invoke(new Arguments()).RenderForOutput().Should().Be("/switch");
logEntry.Should().Be((OutputType.Err, "text"));
}

[Fact]
Expand Down
2 changes: 1 addition & 1 deletion source/Nuke.Components/IReportIssues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,4 @@ sealed void ReportIssueCount(
.When(warningCount > 0, _ => _
.AddPair("Warnings", warningCount.ToString())));
}
}
}
18 changes: 17 additions & 1 deletion source/Nuke.Tooling.Generator/Generators/DataClassGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,34 @@ public static void Run(DataClass dataClass, ToolWriter toolWriter)
var writer = new DataClassWriter(dataClass, toolWriter);
var baseType = dataClass.BaseClass ?? (dataClass.Name.EndsWith("Settings") ? "ToolOptions" : "Options");


writer
.WriteLine($"#region {dataClass.Name}")
.WriteSummary(dataClass)
.WriteLine("[PublicAPI]")
.WriteObsoleteAttributeWhenObsolete(dataClass)
.WriteLine("[ExcludeFromCodeCoverage]")
.WriteLine("[Serializable]")
.WriteLine($"[Command(Type = typeof({dataClass.Tool.GetClassName()}))]")
.WriteLine(GetCommandAttribute())
.WriteLine($"public partial class {dataClass.Name} : {baseType}")
.WriteBlock(w => w
.ForEach(dataClass.Properties, WritePropertyDeclaration))
.WriteLine("#endregion");

string GetCommandAttribute()
{
if (dataClass is not SettingsClass settingsClass)
return null;

var commandArguments = new (string Name, string Value)[]
{
(nameof(CommandAttribute.Type), $"typeof({dataClass.Tool.GetClassName()})"),
(nameof(CommandAttribute.Command), $"nameof({dataClass.Tool.GetClassName()}.{settingsClass.Task.GetTaskMethodName()})"),
(nameof(CommandAttribute.Arguments), $"{settingsClass.Task.DefiniteArgument.DoubleQuote()}"),
}.Where(x => x.Item2 != null)
.Select(x => $"{x.Name} = {x.Value}").JoinCommaSpace();
return $"[Command({commandArguments})]";
}
}

private static void CheckMissingValue(Property property)
Expand Down
149 changes: 37 additions & 112 deletions source/Nuke.Tooling.Generator/Generators/TaskGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
// https://github.com/nuke-build/nuke/blob/master/LICENSE

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Nuke.CodeGeneration.Model;
using Nuke.CodeGeneration.Writers;
Expand All @@ -25,27 +23,22 @@ public static void Run(Tool tool, ToolWriter toolWriter)
.WriteSummary(tool)
.WriteLine("[PublicAPI]")
.WriteLine("[ExcludeFromCodeCoverage]")
.WriteLineIfTrue(tool.NuGetPackageId != null, $"[NuGetPackageRequirement({tool.Name}PackageId)]")
.WriteLineIfTrue(tool.NuGetPackageId != null, $"[NuGetTool(PackageId = {tool.Name}PackageId, Executable = {tool.PackageExecutable.DoubleQuote()})]")
.WriteLineIfTrue(tool.NpmPackageId != null, $"[NpmPackageRequirement({tool.Name}PackageId)]")
.WriteLineIfTrue(tool.AptGetPackageId != null, $"[AptGetPackageRequirement({tool.Name}PackageId)]")
.WriteLineIfTrue(tool.PathExecutable != null, $"[PathToolRequirement({tool.Name}PathExecutable)]")
.WriteLineIfTrue(tool.PathExecutable != null, $"[PathTool(Executable = {tool.PathExecutable.DoubleQuote()})]")
.WriteLine($"public partial class {tool.GetClassName()}")
.WriteLineIfTrue(tool.NuGetPackageId != null, " : IRequireNuGetPackage")
.WriteLineIfTrue(tool.NpmPackageId != null, " : IRequireNpmPackage")
.WriteLineIfTrue(tool.AptGetPackageId != null, " : IRequireAptGetPackage")
.WriteLineIfTrue(tool.PathExecutable != null, " : IRequirePathTool")
.WriteLineIfTrue(tool.NuGetPackageId != null, "[NuGetPackageRequirement(PackageId)]")
.WriteLineIfTrue(tool.NuGetPackageId != null, "[NuGetTool(Id = PackageId)]")
.WriteLineIfTrue(tool.NpmPackageId != null, "[NpmPackageRequirement(PackageId)]")
.WriteLineIfTrue(tool.AptGetPackageId != null, "[AptGetPackageRequirement(PackageId)]")
.WriteLineIfTrue(tool.PathExecutable != null, "[PathToolRequirement(PathExecutable)]")
.WriteLineIfTrue(tool.PathExecutable != null, "[PathTool(Executable = PathExecutable)]")
.WriteLine($"public partial class {tool.GetClassName()} : ToolTasks")
.WriteBlock(w =>
{
w
.WriteLineIfTrue(tool.NuGetPackageId != null, $"public const string {tool.Name}PackageId = {tool.NuGetPackageId.DoubleQuote()};")
.WriteLineIfTrue(tool.NpmPackageId != null, $"public const string {tool.Name}PackageId = {tool.NpmPackageId.DoubleQuote()};")
.WriteLineIfTrue(tool.AptGetPackageId != null, $"public const string {tool.Name}PackageId = {tool.AptGetPackageId.DoubleQuote()};")
.WriteLineIfTrue(tool.PathExecutable != null, $"public const string {tool.Name}PathExecutable = {tool.PathExecutable.DoubleQuote()};")
.WriteToolPath()
.WriteToolLogger()
.WriteToolExitHandler()
.WriteLine($"public static string {tool.Name}Path => new {tool.GetClassName()}().GetToolPath();")
.WriteLineIfTrue(tool.NuGetPackageId != null, $"public const string PackageId = {tool.NuGetPackageId.DoubleQuote()};")
.WriteLineIfTrue(tool.PackageExecutable != null, $"public const string PackageExecutable = {tool.PackageExecutable.DoubleQuote()};")
.WriteLineIfTrue(tool.NpmPackageId != null, $"public const string PackageId = {tool.NpmPackageId.DoubleQuote()};")
.WriteLineIfTrue(tool.AptGetPackageId != null, $"public const string PackageId = {tool.AptGetPackageId.DoubleQuote()};")
.WriteLineIfTrue(tool.PathExecutable != null, $"public const string PathExecutable = {tool.PathExecutable.DoubleQuote()};")
.WriteGenericTask();
tool.Tasks.ForEach(x => new TaskWriter(x, toolWriter)
Expand All @@ -71,62 +64,57 @@ private static void WriteGenericTask(this ToolWriter writer)
};
var arguments = new[]
{
$"{tool.Name}Path",
"arguments",
"workingDirectory",
"environmentVariables",
"timeout",
"logOutput",
"logInvocation",
$"logger ?? {tool.Name}Logger",
"logger",
"exitHandler"
};
var signature = $"IReadOnlyCollection<Output> {tool.Name}({parameters.JoinCommaSpace()})";
var invocation = $"Run<{tool.GetClassName()}>({arguments.JoinCommaSpace()})";
writer
.WriteSummary(tool)
.WriteObsoleteAttributeWhenObsolete(tool)
.WriteLine($"public static IReadOnlyCollection<Output> {tool.Name}({parameters.JoinCommaSpace()})")
.WriteBlock(w => w
.WriteLine($"using var process = ProcessTasks.StartProcess({arguments.JoinCommaSpace()});")
.WriteLine($"(exitHandler ?? (p => {tool.Name}ExitHandler.Invoke(null, p))).Invoke(process.AssertWaitForExit());")
.WriteLine("return process.Output;"));
.WriteLine($"public static {signature} => {invocation};");
}

private static TaskWriter WriteToolSettingsTask(this TaskWriter writer)
{
var task = writer.Task;
var returnType = task.HasReturnValue()
? $"({task.ReturnType} Result, IReadOnlyCollection<Output> Output)"
: "IReadOnlyCollection<Output>";
var returnType = !task.HasReturnValue()
? "IReadOnlyCollection<Output>"
: $"({task.ReturnType} Result, IReadOnlyCollection<Output> Output)";
var signature = $"{returnType} {task.GetTaskMethodName()}({task.SettingsClass.Name} options = null)";
var invocation = !task.HasReturnValue()
? $"Run<{task.Tool.GetClassName()}>(options)"
: $"Run<{task.Tool.GetClassName()}, {task.ReturnType}>(options)";

return writer
.WriteSummary(task)
.WriteRemarks(task)
.WriteObsoleteAttributeWhenObsolete(task)
.WriteLine($"public static {returnType} {task.GetTaskMethodName()}({task.SettingsClass.Name} toolSettings = null)")
.WriteBlock(w => w
.WriteLine($"toolSettings = toolSettings ?? new {task.SettingsClass.Name}();")
.WriteLineIfTrue(task.PreProcess, "PreProcess(ref toolSettings);")
.WriteLine($"using var process = {GetProcessStart(task)};")
.WriteLine(GetProcessAssertion(task))
.WriteLineIfTrue(task.PostProcess, "PostProcess(toolSettings);")
.WriteLine(task.HasReturnValue()
? "return (GetResult(process, toolSettings), process.Output);"
: "return process.Output;"));
.WriteLine($"public static {signature} => {invocation};");
}

private static TaskWriter WriteConfiguratorTask(this TaskWriter writer)
{
var task = writer.Task;
var returnType = task.HasReturnValue()
? $"({task.ReturnType} Result, IReadOnlyCollection<Output> Output)"
: "IReadOnlyCollection<Output>";
var returnType = !task.HasReturnValue()
? "IReadOnlyCollection<Output>"
: $"({task.ReturnType} Result, IReadOnlyCollection<Output> Output)";
var signature = $"{returnType} {task.GetTaskMethodName()}(Configure<{task.SettingsClass.Name}> configurator)";
var invocation = !task.HasReturnValue()
? $"Run<{task.Tool.GetClassName()}>(configurator.Invoke(new {task.SettingsClass.Name}()))"
: $"Run<{task.Tool.GetClassName()}, {task.ReturnType}>(configurator.Invoke(new {task.SettingsClass.Name}()))";

return writer
.WriteSummary(task)
.WriteRemarks(task)
.WriteObsoleteAttributeWhenObsolete(task)
.WriteLine($"public static {returnType} {task.GetTaskMethodName()}(Configure<{task.SettingsClass.Name}> configurator)")
.WriteBlock(w => w
.WriteLine($"return {task.GetTaskMethodName()}(configurator(new {task.SettingsClass.Name}()));"));
.WriteLine($"public static {signature} => {invocation};");
}

private static TaskWriter WriteCombinatorialConfiguratorTask(this TaskWriter writer)
Expand All @@ -143,76 +131,13 @@ private static TaskWriter WriteCombinatorialConfiguratorTask(this TaskWriter wri
"int degreeOfParallelism = 1",
"bool completeOnFailure = false"
}.JoinCommaSpace();
var signature = $"{returnType} {task.GetTaskMethodName()}({parameters})";
var invocation = $"configurator.Invoke2({task.GetTaskMethodName()}, degreeOfParallelism, completeOnFailure)";

return writer
.WriteSummary(task)
.WriteRemarks(task)
.WriteObsoleteAttributeWhenObsolete(task)
.WriteLine($"public static {returnType} {task.GetTaskMethodName()}({parameters})")
.WriteBlock(w => w
.WriteLine(
$"return configurator.Invoke({task.GetTaskMethodName()}, {task.Tool.Name}Logger, degreeOfParallelism, completeOnFailure);"));
}

private static string GetProcessStart(Task task)
{
return !task.CustomStart
? "ProcessTasks.StartProcess(toolSettings)"
: "StartProcess(toolSettings)";
}

private static string GetProcessAssertion(Task task)
{
return !task.CustomAssertion
? "toolSettings.ProcessExitHandler.Invoke(toolSettings, process.AssertWaitForExit());"
: "AssertProcess(process.AssertWaitForExit(), toolSettings);";
}

private static ToolWriter WriteToolPath(this ToolWriter writer)
{
var tool = writer.Tool;
var resolvers = new List<string>();

if (tool.NuGetPackageId != null && tool.PackageExecutable != null)
{
resolvers.Add("NuGetToolPathResolver.GetPackageExecutable(" +
$"{tool.NuGetPackageId.DoubleQuote()}, " +
$"{tool.PackageExecutable.DoubleQuote()})");
}

if (tool.NpmPackageId != null && tool.PackageExecutable != null)
{
resolvers.Add($"NpmToolPathResolver.GetNpmExecutable({tool.PackageExecutable.DoubleQuote()})");
}

if (tool.PathExecutable != null)
resolvers.Add($"ToolPathResolver.GetPathExecutable({tool.PathExecutable.DoubleQuote()})");

if (resolvers.Count == 0)
resolvers.Add("GetToolPath()");

Trace.Assert(resolvers.Count == 1, "resolvers.Count == 1");

return writer
.WriteSummary($"Path to the {tool.Name} executable.")
.WriteLine($"public static string {tool.Name}Path =>")
.WriteLine($" ToolPathResolver.TryGetEnvironmentExecutable(\"{tool.Name.ToUpperInvariant()}_EXE\") ??")
.WriteLine($" {resolvers.Single()};");
}

private static ToolWriter WriteToolLogger(this ToolWriter writer)
{
var tool = writer.Tool;
var logger = tool.CustomLogger ? "CustomLogger" : "ProcessTasks.DefaultLogger";
return writer
.WriteLine($"public static Action<OutputType, string> {tool.Name}Logger {{ get; set; }} = {logger};");
}

private static ToolWriter WriteToolExitHandler(this ToolWriter writer)
{
var tool = writer.Tool;
var exitHandler = tool.CustomExitHandler ? "CustomExitHandler" : "ProcessTasks.DefaultExitHandler";
return writer
.WriteLine($"public static Action<ToolSettings, IProcess> {tool.Name}ExitHandler {{ get; set; }} = {exitHandler};");
.WriteLine($"public static {signature} => {invocation};");
}
}
3 changes: 2 additions & 1 deletion source/Nuke.Tooling.Generator/Writers/WriterExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Nuke.Common.Utilities;

namespace Nuke.CodeGeneration.Writers;

Expand Down Expand Up @@ -48,7 +49,7 @@ public static TWrapper ForEach<TWrapper, TItem>(
public static T WriteLine<T>(this T writerWrapper, [CanBeNull] string text)
where T : IWriterWrapper
{
if (text != null)
if (!text.IsNullOrWhiteSpace())
writerWrapper.Writer.WriteLine(text);
return writerWrapper;
}
Expand Down
13 changes: 12 additions & 1 deletion source/Nuke.Tooling.Tests/ToolOptionsArgumentsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,15 @@ private class BoolToolOptions : ToolOptions
public void TestString()
{
Assert<StringToolOptions>(new { String = "value" }, ["--string", "value",]);

var options = SetInternalOptions<StringToolOptions>(new { Secret = "secret-value" });
options.GetSecrets().Should().Equal("secret-value");
}

private class StringToolOptions : ToolOptions
{
[Argument(Format = "--string {value}")] public string String => Get<string>(() => String);
[Argument(Format = "--secret {value}", Secret = true)] public string Secret => Get<string>(() => Secret);
}

[Fact]
Expand Down Expand Up @@ -179,9 +183,16 @@ public void TestLookup()

private void Assert<T>(object obj, string[] arguments)
where T : ToolOptions, new()
{
var options = SetInternalOptions<T>(obj);
options.GetArguments().Should().Equal(arguments);
}

private static T SetInternalOptions<T>(object obj)
where T : ToolOptions, new()
{
var options = new T();
options.InternalOptions = obj.ToJObject(Options.JsonSerializer);
options.GetArguments().Should().Equal(arguments);
return options;
}
}
Loading

0 comments on commit d58700d

Please sign in to comment.