diff --git a/CHANGELOG.md b/CHANGELOG.md index 3844c402f..651e93c3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [vNext] +## [0.19.0] / 2019-05-03 +- Changed MSBuild targets to be invoked with `Exec` task +- Changed `ProcessTasks` to avoid Mono when using WSL +- Added output for non-default working directories +- Added `GitVersion.VersionSourceSha` +- Added `ReportTypes.TeamCitySummary` +- Fixed parameter resolution to handle hyphens +- Fixed MSBuild resolution for Visual Studio 2019 +- Fixed issues when build has no default target defined + ## [0.18.0] / 2019-03-24 - Changed `ParameterService` to strip dashes when resolving value - Changed formatting of skip reason @@ -146,7 +156,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Fixed bootstrapping scripts to exit without closing PowerShell - Fixed expansion for Unix environment variables - Fixed separator for target parameters -- Fixed `ToolPathResolver` to resolve decidedly +- Fixed `ToolPathResolver` to resolve decidedly - Fixed `GitVersionTasks` to resolve based on `GitVersion.CommandLine.DotNetCore` package - Fixed `InjectionAttributeBase` to pass build instance - Fixed `ReflectionService` to be public to allow usage in addons @@ -154,7 +164,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [0.12.0] / 2018-11-15 - Changed `NukeBuild` properties to be static -- Changed `NukeBuild.RootDirectory` to allow resolution from parameter +- Changed `NukeBuild.RootDirectory` to allow resolution from parameter - Added package resolution for Paket - Added shell-completion for global tool - Added parameter resolution for `Enumeration` subclasses @@ -237,7 +247,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [0.6.1] / 2018-08-09 - Fixed global tool to have 'same as global tool' as fallback version -- Fixed PowerShell invocation to use `-ExecutionPolicy ByPass` and `-NoProfile` +- Fixed PowerShell invocation to use `-ExecutionPolicy ByPass` and `-NoProfile` ## [0.6.0] / 2018-08-05 - Removed setup scripts in favor of `:setup` command in global tool @@ -339,7 +349,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Added CLT tasks for Git - Fixed background color in console output -[vNext]: https://github.com/nuke-build/common/compare/0.18.0...HEAD +[vNext]: https://github.com/nuke-build/common/compare/0.19.0...HEAD +[0.19.0]: https://github.com/nuke-build/common/compare/0.18.0...0.19.0 [0.18.0]: https://github.com/nuke-build/common/compare/0.17.7...0.18.0 [0.17.7]: https://github.com/nuke-build/common/compare/0.17.6...0.17.7 [0.17.6]: https://github.com/nuke-build/common/compare/0.17.5...0.17.6 diff --git a/build/Build.GitFlow.cs b/build/Build.GitFlow.cs index 7d8901892..52362714d 100644 --- a/build/Build.GitFlow.cs +++ b/build/Build.GitFlow.cs @@ -8,7 +8,6 @@ using Nuke.Common.Git; using Nuke.Common.Tooling; using Nuke.Common.Tools.GitVersion; -using Nuke.Common.Utilities; using static Nuke.Common.ChangeLog.ChangelogTasks; using static Nuke.Common.Tools.Git.GitTasks; using static Nuke.Common.Tools.GitVersion.GitVersionTasks; diff --git a/build/Build.cs b/build/Build.cs index 8ffe44df2..a3512ebdf 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -1,4 +1,4 @@ -// Copyright 2019 Maintainers of NUKE. +// Copyright 2019 Maintainers of NUKE. // Distributed under the MIT License. // https://github.com/nuke-build/nuke/blob/master/LICENSE @@ -73,9 +73,8 @@ partial class Build : NukeBuild .SetProjectFile(Solution)); }); - [Unlisted] [ProjectFrom(nameof(Solution))] Project CommonProject; [Unlisted] [ProjectFrom(nameof(Solution))] Project GlobalToolProject; - [Unlisted] [ProjectFrom(nameof(Solution))] Project CodeGenerationProject; + [Unlisted] [ProjectFrom(nameof(Solution))] Project MSBuildTaskRunnerProject; Target Compile => _ => _ .DependsOn(Restore) @@ -96,7 +95,7 @@ partial class Build : NukeBuild .SetFileVersion(GitVersion.GetNormalizedFileVersion()) .SetInformationalVersion(GitVersion.InformationalVersion) .CombineWith( - from project in new[] { GlobalToolProject, CommonProject, CodeGenerationProject } + from project in new[] { GlobalToolProject, MSBuildTaskRunnerProject } from framework in project.GetTargetFrameworks() select new { project, framework }, (cs, v) => cs .SetProject(v.project) @@ -180,22 +179,26 @@ from framework in project.GetTargetFrameworks() .SetTargetPath(v)), degreeOfParallelism: 5, completeOnFailure: true); + }); - if (GitRepository.Branch.EqualsOrdinalIgnoreCase(MasterBranch)) - { - SendSlackMessage(m => m - .SetText(new StringBuilder() - .AppendLine($" :mega::shipit: *NUKE {GitVersion.SemVer} IS OUT!!!*") - .AppendLine() - .AppendLine(ChangelogSectionNotes.Select(x => x.Replace("- ", "• ")).JoinNewLine()).ToString()), - SlackWebhook); - - SendGitterMessage(new StringBuilder() - .AppendLine($"@/all :mega::shipit: **NUKE {GitVersion.SemVer} IS OUT!!!**") + Target Announce => _ => _ + .TriggeredBy(Publish) + .AssuredAfterFailure() + .OnlyWhenStatic(() => GitRepository.IsOnMasterBranch()) + .Executes(() => + { + SendSlackMessage(m => m + .SetText(new StringBuilder() + .AppendLine($" :mega::shipit: *NUKE {GitVersion.SemVer} IS OUT!!!*") .AppendLine() - .AppendLine(ChangelogSectionNotes.Select(x => x.Replace("- ", "* ")).JoinNewLine()).ToString(), - "593f3dadd73408ce4f66db89", - GitterAuthToken); - } + .AppendLine(ChangelogSectionNotes.Select(x => x.Replace("- ", "• ")).JoinNewLine()).ToString()), + SlackWebhook); + + SendGitterMessage(new StringBuilder() + .AppendLine($"@/all :mega::shipit: **NUKE {GitVersion.SemVer} IS OUT!!!**") + .AppendLine() + .AppendLine(ChangelogSectionNotes.Select(x => x.Replace("- ", "* ")).JoinNewLine()).ToString(), + "593f3dadd73408ce4f66db89", + GitterAuthToken); }); } diff --git a/build/specifications/GitVersion.json b/build/specifications/GitVersion.json index 7b66730c9..595cb1adc 100644 --- a/build/specifications/GitVersion.json +++ b/build/specifications/GitVersion.json @@ -260,6 +260,10 @@ "name": "NuGetPreReleaseTag", "type": "string" }, + { + "name": "VersionSourceSha", + "type": "string" + }, { "name": "CommitsSinceVersionSource", "type": "string" diff --git a/build/specifications/ReportGenerator.json b/build/specifications/ReportGenerator.json index 567674e01..39a7adb32 100644 --- a/build/specifications/ReportGenerator.json +++ b/build/specifications/ReportGenerator.json @@ -102,7 +102,8 @@ "TextSummary", "Xml", "XmlSummary", - "SonarQube" + "SonarQube", + "TeamCitySummary" ] }, { diff --git a/nuke-common.sln b/nuke-common.sln index 5175495ef..1c57cab05 100644 --- a/nuke-common.sln +++ b/nuke-common.sln @@ -33,6 +33,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nuke.GlobalTool", "source\N EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nuke.GlobalTool.Tests", "source\Nuke.GlobalTool.Tests\Nuke.GlobalTool.Tests.csproj", "{BD416DD4-06F4-4246-B92C-B261B026B6E9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nuke.MSBuildTaskRunner", "source\Nuke.MSBuildTaskRunner\Nuke.MSBuildTaskRunner.csproj", "{8166FF13-87CF-45BC-B307-7A16329B6981}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -65,6 +67,10 @@ Global {BD416DD4-06F4-4246-B92C-B261B026B6E9}.Debug|Any CPU.Build.0 = Debug|Any CPU {BD416DD4-06F4-4246-B92C-B261B026B6E9}.Release|Any CPU.ActiveCfg = Release|Any CPU {BD416DD4-06F4-4246-B92C-B261B026B6E9}.Release|Any CPU.Build.0 = Release|Any CPU + {8166FF13-87CF-45BC-B307-7A16329B6981}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8166FF13-87CF-45BC-B307-7A16329B6981}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8166FF13-87CF-45BC-B307-7A16329B6981}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8166FF13-87CF-45BC-B307-7A16329B6981}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/shell-completion.yml b/shell-completion.yml index 4fa3db8d9..cc8532498 100644 --- a/shell-completion.yml +++ b/shell-completion.yml @@ -14,10 +14,12 @@ Host: - TeamCity - TeamServices - Travis +NoLogo: Plan: Root: Skip: - Analysis +- Announce - Changelog - Clean - Compile @@ -36,6 +38,7 @@ Source: SymbolSource: Target: - Analysis +- Announce - Changelog - Clean - Compile diff --git a/source/Nuke.CodeGeneration/CodeGenerator.cs b/source/Nuke.CodeGeneration/CodeGenerator.cs index c88fcc226..0339ed36a 100644 --- a/source/Nuke.CodeGeneration/CodeGenerator.cs +++ b/source/Nuke.CodeGeneration/CodeGenerator.cs @@ -51,10 +51,7 @@ public static void GenerateCode( tool.Namespace = namespaceProvider?.Invoke(tool); ApplyRuntimeInformation(tool, specificationFile, sourceFileProvider, namespaceProvider); - var outputFile = outputFileProvider?.Invoke(tool) ?? - Path.Combine(Path.GetDirectoryName(tool.SpecificationFile).NotNull(), tool.DefaultOutputFileName); - - GenerateCode(tool, outputFile); + GenerateCode(tool, outputFileProvider?.Invoke(tool) ?? tool.DefaultOutputFile); } } diff --git a/source/Nuke.CodeGeneration/CodeGeneratorTask.cs b/source/Nuke.CodeGeneration/CodeGeneratorTask.cs deleted file mode 100644 index 88e298715..000000000 --- a/source/Nuke.CodeGeneration/CodeGeneratorTask.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2019 Maintainers of NUKE. -// Distributed under the MIT License. -// https://github.com/nuke-build/nuke/blob/master/LICENSE - -using System; -using System.Linq; -using JetBrains.Annotations; -using Microsoft.Build.Framework; -using Nuke.Common.Git; -using Nuke.Common; -using static Nuke.Common.IO.PathConstruction; - -namespace Nuke.CodeGeneration -{ - [PublicAPI] - public class CodeGeneratorTask : ITask - { - private const string c_exampleUrl = "https://raw.githubusercontent.com/nuke-build/nuke/master/source/Nuke.CodeGeneration/RandomTool.json"; - - public IBuildEngine BuildEngine { get; set; } - public ITaskHost HostObject { get; set; } - - [Microsoft.Build.Framework.Required] - public ITaskItem[] SpecificationFiles { get; set; } - - [Microsoft.Build.Framework.Required] - public string BaseDirectory { get; set; } - - public bool UseNestedNamespaces { get; set; } - - [CanBeNull] - public string BaseNamespace { get; set; } - - public bool UpdateReferences { get; set; } - - public bool Execute() - { - var specificationFiles = SpecificationFiles.Select(x => x.GetMetadata("Fullpath")).ToList(); - var repository = ControlFlow.SuppressErrors(() => GitRepository.FromLocalDirectory(BaseDirectory)); - - CodeGenerator.GenerateCode( - specificationFiles, - outputFileProvider: x => - (AbsolutePath) BaseDirectory - / (UseNestedNamespaces ? x.Name : ".") - / x.DefaultOutputFileName, - namespaceProvider: x => - !UseNestedNamespaces - ? BaseNamespace - : string.IsNullOrEmpty(BaseNamespace) - ? x.Name - : $"{BaseNamespace}.{x.Name}", - sourceFileProvider: x => - repository.IsGitHubRepository() ? repository?.GetGitHubDownloadUrl(x.SpecificationFile) : null); - - if (UpdateReferences) - ReferenceUpdater.UpdateReferences(specificationFiles); - - return true; - } - } -} diff --git a/source/Nuke.CodeGeneration/Generators/ModelExtensions.cs b/source/Nuke.CodeGeneration/Generators/ModelExtensions.cs index 629852028..0ceacbddf 100644 --- a/source/Nuke.CodeGeneration/Generators/ModelExtensions.cs +++ b/source/Nuke.CodeGeneration/Generators/ModelExtensions.cs @@ -5,7 +5,6 @@ using System; using System.Linq; using System.Text.RegularExpressions; -using JetBrains.Annotations; using Nuke.CodeGeneration.Model; using Nuke.Common; using Nuke.Common.Utilities; diff --git a/source/Nuke.CodeGeneration/Generators/StringExtensions.cs b/source/Nuke.CodeGeneration/Generators/StringExtensions.cs index dbe928289..4d28d922f 100644 --- a/source/Nuke.CodeGeneration/Generators/StringExtensions.cs +++ b/source/Nuke.CodeGeneration/Generators/StringExtensions.cs @@ -7,9 +7,7 @@ using System.Globalization; using System.Linq; using Humanizer; -using JetBrains.Annotations; using Nuke.Common; -using Nuke.Common.Utilities; namespace Nuke.CodeGeneration.Generators { diff --git a/source/Nuke.CodeGeneration/Model/Property.cs b/source/Nuke.CodeGeneration/Model/Property.cs index e752f15f2..55d103ab4 100644 --- a/source/Nuke.CodeGeneration/Model/Property.cs +++ b/source/Nuke.CodeGeneration/Model/Property.cs @@ -9,7 +9,6 @@ using System.Linq; using JetBrains.Annotations; using Newtonsoft.Json; -using Newtonsoft.Json.Converters; namespace Nuke.CodeGeneration.Model { diff --git a/source/Nuke.CodeGeneration/Nuke.CodeGeneration.csproj b/source/Nuke.CodeGeneration/Nuke.CodeGeneration.csproj index b8c5f1e3a..3db6833b7 100644 --- a/source/Nuke.CodeGeneration/Nuke.CodeGeneration.csproj +++ b/source/Nuke.CodeGeneration/Nuke.CodeGeneration.csproj @@ -1,9 +1,9 @@  - + netstandard2.0;net461 - + @@ -11,20 +11,13 @@ - + - - - - - - - - + diff --git a/source/Nuke.Common.Tests/ExternalFilesTaskTest.cs b/source/Nuke.Common.Tests/ExternalFilesTaskTest.cs deleted file mode 100644 index 40714b09d..000000000 --- a/source/Nuke.Common.Tests/ExternalFilesTaskTest.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2019 Maintainers of NUKE. -// Distributed under the MIT License. -// https://github.com/nuke-build/nuke/blob/master/LICENSE - -using System; -using System.Threading.Tasks; -using Nuke.Common.BuildTasks; - -namespace Nuke.Common.Tests -{ - public class ExternalFilesTaskTest - { - public async Task Test() - { - await ExternalFilesTask.DownloadExternalFile( - "/Users/matt/code/nuke/repositories/nuke-build/compression/build/Build2.cs.ext", - timeout: 1000, - (file, message) => throw new Exception(message), - (file, message) => throw new Exception(message)); - } - } -} diff --git a/source/Nuke.Common.Tests/ParameterServiceTest.cs b/source/Nuke.Common.Tests/ParameterServiceTest.cs index 1561ab8a3..de987a32e 100644 --- a/source/Nuke.Common.Tests/ParameterServiceTest.cs +++ b/source/Nuke.Common.Tests/ParameterServiceTest.cs @@ -52,6 +52,7 @@ public void TestConversion(string argument, Type destinationType, object expecte [Theory] [InlineData("MSBuildConfiguration", typeof(string), "msbcfg")] [InlineData("dockerConfiguration", typeof(string), "dkrcfg")] + [InlineData("publish-dir", typeof(string), "dir")] public void TestSplitted(string argument, Type destinationType, object expectedValue) { GetService( @@ -60,7 +61,9 @@ public void TestSplitted(string argument, Type destinationType, object expectedV "-msbuild-configuration", "msbcfg", "-docker-configuration", - "dkrcfg" + "dkrcfg", + "--publish-dir", + "dir" }).GetCommandLineArgument(argument, destinationType).Should().Be(expectedValue); } diff --git a/source/Nuke.Common.Tests/ProjectModelTest.cs b/source/Nuke.Common.Tests/ProjectModelTest.cs index 3027e4a67..a5d8f5168 100644 --- a/source/Nuke.Common.Tests/ProjectModelTest.cs +++ b/source/Nuke.Common.Tests/ProjectModelTest.cs @@ -24,7 +24,7 @@ public void SolutionTest() var solution = ProjectModelTasks.ParseSolution(SolutionFile); solution.SolutionFolders.Select(x => x.Name).Should().BeEquivalentTo("misc"); - solution.AllProjects.Where(x => x.Is(ProjectType.CSharpProject)).Should().HaveCount(7); + solution.AllProjects.Where(x => x.Is(ProjectType.CSharpProject)).Should().HaveCount(8); var buildProject = solution.AllProjects.SingleOrDefault(x => x.Name == "_build"); buildProject.Should().NotBeNull(); diff --git a/source/Nuke.Common/BuildTasks/ExternalFilesTask.cs b/source/Nuke.Common/BuildTasks/ExternalFilesTask.cs deleted file mode 100644 index df4382e26..000000000 --- a/source/Nuke.Common/BuildTasks/ExternalFilesTask.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2019 Maintainers of NUKE. -// Distributed under the MIT License. -// https://github.com/nuke-build/nuke/blob/master/LICENSE - -using System; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using JetBrains.Annotations; -using Microsoft.Build.Framework; -using Nuke.Common.IO; -using Nuke.Common.Utilities; - -namespace Nuke.Common.BuildTasks -{ - [PublicAPI] - public class ExternalFilesTask : ITask - { - public IBuildEngine BuildEngine { get; set; } - public ITaskHost HostObject { get; set; } - - [Microsoft.Build.Framework.Required] - public ITaskItem[] ExternalFiles { get; set; } - - public int Timeout { get; set; } - - public bool Execute() - { - return ExternalFiles - .Select(x => DownloadExternalFile(x.GetMetadata("Fullpath"), Timeout, ReportWarning, ReportError)) - .ToList() - .All(x => x.Result); - } - - public static async Task DownloadExternalFile( - string externalFile, - int timeout, - Action warningSink, - Action errorSink) - { - try - { - var lines = File.ReadAllLines(externalFile).Where(x => !string.IsNullOrWhiteSpace(x)).ToList(); - var uriConversion = Uri.TryCreate(lines.FirstOrDefault(), UriKind.Absolute, out var uri); - ControlFlow.Assert(uriConversion, $"Could not parse URI for external file from first line of '{externalFile}'."); - - var outputFile = externalFile.Substring(startIndex: 0, length: externalFile.Length - 4); - var previousHash = File.Exists(outputFile) ? FileSystemTasks.GetFileHash(outputFile) : null; - - var template = (await HttpTasks.HttpDownloadStringAsync(uri.OriginalString)).SplitLineBreaks(); - var replacements = lines.Skip(1) - .Where(x => x.Contains('=')) - .Select(x => x.Split('=')) - .Where(x => x.Length == 2) - .ToDictionary( - x => $"_{x.First().Trim('_').ToUpperInvariant()}_", - x => x.ElementAt(1)); - var definitions = lines.Skip(1) - .Where(x => !x.Contains('=') && !string.IsNullOrWhiteSpace(x)) - .Select(x => x.ToUpperInvariant()) - .ToList(); - - File.WriteAllLines(outputFile, TemplateUtility.FillTemplate(template, definitions, replacements)); - var newHash = FileSystemTasks.GetFileHash(outputFile); - - if (newHash != previousHash) - warningSink(externalFile, "External file has been updated."); - - return true; - } - catch (Exception exception) - { - errorSink(externalFile, exception.Message); - return false; - } - } - - private void ReportWarning(string externalFile, string message) - { - BuildEngine.LogWarningEvent( - new BuildWarningEventArgs( - subcategory: "Build", - code: null, - file: externalFile, - lineNumber: 0, - columnNumber: 0, - endLineNumber: 0, - endColumnNumber: 0, - message: message, - helpKeyword: null, - senderName: typeof(ExternalFilesTask).FullName)); - } - - private void ReportError(string externalFile, string message) - { - BuildEngine.LogErrorEvent(new BuildErrorEventArgs( - subcategory: "Build", - code: null, - file: externalFile, - lineNumber: 0, - columnNumber: 0, - endLineNumber: 0, - endColumnNumber: 0, - message: message, - helpKeyword: null, - senderName: typeof(ExternalFilesTask).FullName)); - } - } -} diff --git a/source/Nuke.Common/BuildTasks/Nuke.Common.targets b/source/Nuke.Common/BuildTasks/Nuke.Common.targets deleted file mode 100644 index 9f13da6b8..000000000 --- a/source/Nuke.Common/BuildTasks/Nuke.Common.targets +++ /dev/null @@ -1,35 +0,0 @@ - - - - False - 5000 - - - - - - - - - - - - - - - - <_PackageFiles Include="@(_PackageToolFiles)" /> - - - - diff --git a/source/Nuke.Common/BuildTasks/PackPackageToolsTask.cs b/source/Nuke.Common/BuildTasks/PackPackageToolsTask.cs deleted file mode 100644 index 52ac65299..000000000 --- a/source/Nuke.Common/BuildTasks/PackPackageToolsTask.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2019 Maintainers of NUKE. -// Distributed under the MIT License. -// https://github.com/nuke-build/nuke/blob/master/LICENSE - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.Serialization.Json; -using System.Text; -using System.Xml; -using System.Xml.Linq; -using System.Xml.XPath; -using JetBrains.Annotations; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using Nuke.Common.IO; - -namespace Nuke.Common.BuildTasks -{ - [PublicAPI] - public class PackPackageToolsTask : ITask - { - public IBuildEngine BuildEngine { get; set; } - public ITaskHost HostObject { get; set; } - - [Microsoft.Build.Framework.Required] - public string ProjectAssetsFile { get; set; } - - [Microsoft.Build.Framework.Required] - public string NuGetPackageRoot { get; set; } - - [Microsoft.Build.Framework.Required] - public string TargetFramework { get; set; } - - [Output] - public ITaskItem[] TargetOutputs { get; set; } - - public bool Execute() - { - var assetFileContent = File.ReadAllText(ProjectAssetsFile); - var reader = JsonReaderWriterFactory.CreateJsonReader( - Encoding.UTF8.GetBytes(assetFileContent), - new XmlDictionaryReaderQuotas()); - - var root = XElement.Load(reader); - var packages = root.XPathSelectElements("//libraries/*/path") - .Select(x => x.Value.Split(new[] { "/" }, StringSplitOptions.None)) - .Select(x => new { Id = x[0], Version = x[1] }).ToList(); - - TargetOutputs = packages.SelectMany(x => GetFiles(x.Id, x.Version)).ToArray(); - - return true; - } - - private IEnumerable GetFiles(string packageId, string packageVersion) - { - var packageToolsPath = Path.Combine(NuGetPackageRoot, packageId, packageVersion, "tools"); - if (!Directory.Exists(packageToolsPath)) - yield break; - - foreach (var file in Directory.GetFiles(packageToolsPath, "*", SearchOption.AllDirectories)) - { - var taskItem = new TaskItem(file); - taskItem.SetMetadata("BuildAction", "None"); - taskItem.SetMetadata("PackagePath", - Path.Combine("tools", - TargetFramework, - "any", - packageId, - PathConstruction.GetRelativePath(packageToolsPath, file))); - yield return taskItem; - } - } - } -} diff --git a/source/Nuke.Common/EnvironmentInfo.Platform.cs b/source/Nuke.Common/EnvironmentInfo.Platform.cs index 753e62c5b..39541b72d 100644 --- a/source/Nuke.Common/EnvironmentInfo.Platform.cs +++ b/source/Nuke.Common/EnvironmentInfo.Platform.cs @@ -3,9 +3,11 @@ // https://github.com/nuke-build/nuke/blob/master/LICENSE using System; +using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.Versioning; +using Nuke.Common.Utilities; namespace Nuke.Common { @@ -54,6 +56,25 @@ public static bool Is64Bit /// public static bool IsOsx => Platform == PlatformFamily.OSX; + /// + /// Returns whether the operating system is running under Windows Subsystem for Linux. + /// + public static bool IsWsl { get; } = GetIsWsl(); + + private static bool GetIsWsl() { + + if (!IsLinux) + return false; + + try { + var version = File.ReadAllText("/proc/version"); + return version.ContainsOrdinalIgnoreCase("Microsoft"); + } + catch (IOException) { + return false; + } + } + /// /// Returns the framework the build is running on. /// diff --git a/source/Nuke.Common/Execution/BuildExtensionAttributeBase.cs b/source/Nuke.Common/Execution/BuildExtensionAttributeBase.cs index 9d2fbc121..ae12d9db0 100644 --- a/source/Nuke.Common/Execution/BuildExtensionAttributeBase.cs +++ b/source/Nuke.Common/Execution/BuildExtensionAttributeBase.cs @@ -10,7 +10,7 @@ namespace Nuke.Common.Execution { public interface IBuildExtension { - void Execute(NukeBuild build, IReadOnlyCollection executableTargets); + void Execute(NukeBuild build, IReadOnlyCollection executableTargets, IReadOnlyCollection executionPlan); } public interface IPreLogoBuildExtension : IBuildExtension diff --git a/source/Nuke.Common/Execution/BuildManager.cs b/source/Nuke.Common/Execution/BuildManager.cs index 10bc94f6c..1852183fd 100644 --- a/source/Nuke.Common/Execution/BuildManager.cs +++ b/source/Nuke.Common/Execution/BuildManager.cs @@ -45,14 +45,27 @@ public static int Execute(Expression> defaultTargetExpression Logger.LogLevel = NukeBuild.LogLevel; ToolPathResolver.NuGetPackagesConfigFile = build.NuGetPackagesConfigFile; - Logger.Normal($"NUKE Execution Engine {typeof(BuildManager).Assembly.GetInformationalText()}"); - Logger.Normal(FigletTransform.GetText("NUKE")); + if (!NukeBuild.NoLogo) + { + Logger.Normal(); + Logger.Normal("███╗ ██╗██╗ ██╗██╗ ██╗███████╗"); + Logger.Normal("████╗ ██║██║ ██║██║ ██╔╝██╔════╝"); + Logger.Normal("██╔██╗ ██║██║ ██║█████╔╝ █████╗ "); + Logger.Normal("██║╚██╗██║██║ ██║██╔═██╗ ██╔══╝ "); + Logger.Normal("██║ ╚████║╚██████╔╝██║ ██╗███████╗"); + Logger.Normal("╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝"); + Logger.Normal(); + } + + Logger.Info($"NUKE Execution Engine {typeof(BuildManager).Assembly.GetInformationalText()}"); + Logger.Normal(); - build.ExecuteExtensions(); build.ExecutionPlan = ExecutionPlanner.GetExecutionPlan( build.ExecutableTargets, ParameterService.Instance.GetParameter(() => build.InvokedTargets) ?? ParameterService.Instance.GetPositionalCommandLineArguments(separator: Constants.TargetsSeparator.Single())); + + build.ExecuteExtensions(); CancellationHandler += Finish; InjectionUtility.InjectValues(build, x => !x.IsFast); @@ -127,9 +140,9 @@ string CreateLine(string target, string executionStatus, string duration, string string ToMinutesAndSeconds(TimeSpan duration) => $"{(int) duration.TotalMinutes}:{duration:ss}"; - Logger.Normal(new string(c: '=', count: allColumns)); + Logger.Normal(new string(c: '═', count: allColumns)); Logger.Info(CreateLine("Target", "Status", "Duration")); - Logger.Normal(new string(c: '-', count: allColumns)); + Logger.Normal(new string(c: '─', count: allColumns)); foreach (var target in build.ExecutionPlan) { var line = CreateLine(target.Name, target.Status.ToString(), ToMinutesAndSeconds(target.Duration), target.SkipReason); @@ -149,9 +162,9 @@ string ToMinutesAndSeconds(TimeSpan duration) } } - Logger.Normal(new string(c: '-', count: allColumns)); + Logger.Normal(new string(c: '─', count: allColumns)); Logger.Info(CreateLine("Total", "", ToMinutesAndSeconds(totalDuration))); - Logger.Normal(new string(c: '=', count: allColumns)); + Logger.Normal(new string(c: '═', count: allColumns)); Logger.Normal(); var buildSucceeded = IsSuccessful(build); diff --git a/source/Nuke.Common/Execution/CheckBuildProjectConfigurationsAttribute.cs b/source/Nuke.Common/Execution/CheckBuildProjectConfigurationsAttribute.cs index af3c42c19..8b1798a2a 100644 --- a/source/Nuke.Common/Execution/CheckBuildProjectConfigurationsAttribute.cs +++ b/source/Nuke.Common/Execution/CheckBuildProjectConfigurationsAttribute.cs @@ -19,7 +19,10 @@ public class CheckBuildProjectConfigurationsAttribute : Attribute, IPostLogoBuil { public int TimeoutInMilliseconds { get; set; } = 500; - public void Execute(NukeBuild build, IReadOnlyCollection executableTargets) + public void Execute( + NukeBuild build, + IReadOnlyCollection executableTargets, + IReadOnlyCollection executionPlan) { ControlFlow.AssertWarn(Task.Run(CheckConfiguration).Wait(TimeoutInMilliseconds), $"Could not complete checking build configurations within {TimeoutInMilliseconds} milliseconds."); diff --git a/source/Nuke.Common/Execution/CheckPathEnvironmentVariableAttribute.cs b/source/Nuke.Common/Execution/CheckPathEnvironmentVariableAttribute.cs index 7bdeb4c76..11aed0476 100644 --- a/source/Nuke.Common/Execution/CheckPathEnvironmentVariableAttribute.cs +++ b/source/Nuke.Common/Execution/CheckPathEnvironmentVariableAttribute.cs @@ -14,7 +14,10 @@ namespace Nuke.Common.Execution [AttributeUsage(AttributeTargets.Class)] public class CheckPathEnvironmentVariableAttribute : Attribute, IPostLogoBuildExtension { - public void Execute(NukeBuild build, IReadOnlyCollection executableTargets) + public void Execute( + NukeBuild build, + IReadOnlyCollection executableTargets, + IReadOnlyCollection executionPlan) { ProcessTasks.CheckPathEnvironmentVariable(); } diff --git a/source/Nuke.Common/Execution/ExecutionPlanHtmlService.cs b/source/Nuke.Common/Execution/ExecutionPlanHtmlService.cs index 048cfbcb0..c6330a2ed 100644 --- a/source/Nuke.Common/Execution/ExecutionPlanHtmlService.cs +++ b/source/Nuke.Common/Execution/ExecutionPlanHtmlService.cs @@ -7,7 +7,6 @@ using System.Diagnostics; using System.IO; using System.Linq; -using System.Reflection; using System.Text; using Nuke.Common.Utilities; using Nuke.Common.Utilities.Collections; @@ -66,7 +65,10 @@ private static string GetEvents(IReadOnlyCollection executable var builder = new StringBuilder(); // When not hovering anything, highlight the default plan - var defaultPlan = ExecutionPlanner.GetExecutionPlan(executableTargets, new[] { executableTargets.Single(x => x.IsDefault).Name }); + var defaultTarget = executableTargets.SingleOrDefault(x => x.IsDefault); + var defaultPlan = defaultTarget != null + ? ExecutionPlanner.GetExecutionPlan(executableTargets, new[] { defaultTarget?.Name }) + : new ExecutableTarget[0]; defaultPlan.ForEach(x => builder.AppendLine($@" $(""#{x.Name}"").addClass('highlight');")); foreach (var executableTarget in executableTargets) diff --git a/source/Nuke.Common/Execution/ExecutionPlanner.cs b/source/Nuke.Common/Execution/ExecutionPlanner.cs index 722d6b17a..f43c3aaa6 100644 --- a/source/Nuke.Common/Execution/ExecutionPlanner.cs +++ b/source/Nuke.Common/Execution/ExecutionPlanner.cs @@ -51,10 +51,11 @@ private static IReadOnlyCollection GetExecutionPlanInternal( var cycles = scc.DetectCycle(graphAsList).Cycles().ToList(); if (cycles.Count > 0) { - ControlFlow.Fail( + Logger.Error( new[] { "Circular dependencies between targets:" } .Concat(cycles.Select(x => $" - {x.Select(y => y.Value.Name).JoinComma()}")) .JoinNewLine()); + Environment.Exit(exitCode: -1); } while (graphAsList.Any()) @@ -62,10 +63,11 @@ private static IReadOnlyCollection GetExecutionPlanInternal( var independents = graphAsList.Where(x => !graphAsList.Any(y => y.Dependencies.Contains(x))).ToList(); if (EnvironmentInfo.ArgumentSwitch("strict") && independents.Count > 1) { - ControlFlow.Fail( - new[] { "Incomplete target definition order." } + Logger.Error( + new[]{"Incomplete target definition order."} .Concat(independents.Select(x => $" - {x.Value.Name}")) .JoinNewLine()); + Environment.Exit(exitCode: -1); } var independent = independents.First(); @@ -100,7 +102,13 @@ private static ExecutableTarget GetExecutableTarget( { var executableTarget = executableTargets.SingleOrDefault(x => x.Name.EqualsOrdinalIgnoreCase(targetName)); if (executableTarget == null) - ControlFlow.Fail($"Target with name '{targetName}' is not available."); + { + Logger.Error( + new[] { $"Target with name '{targetName}' does not exist. Available targets are:" } + .Concat(executableTargets.Select(x => $" - {x.Name}").OrderBy(x => x)) + .JoinNewLine()); + Environment.Exit(exitCode: -1); + } return executableTarget; } @@ -108,10 +116,7 @@ private static ExecutableTarget GetExecutableTarget( private static ExecutableTarget[] GetDefaultTarget(IReadOnlyCollection executableTargets) { var target = executableTargets.SingleOrDefault(x => x.IsDefault); - if (target == null) - Fail("No target has been marked to be the default.", executableTargets); - - return new[] { target }; + return target != null ? new[] { target } : new ExecutableTarget[0]; } private static void Fail(string message, IReadOnlyCollection executableTargets) diff --git a/source/Nuke.Common/Execution/HandleHelpRequestAttribute.cs b/source/Nuke.Common/Execution/HandleHelpRequestAttribute.cs new file mode 100644 index 000000000..a99d8e8d1 --- /dev/null +++ b/source/Nuke.Common/Execution/HandleHelpRequestAttribute.cs @@ -0,0 +1,28 @@ +// Copyright 2019 Maintainers of NUKE. +// Distributed under the MIT License. +// https://github.com/nuke-build/nuke/blob/master/LICENSE + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Nuke.Common.Execution +{ + [AttributeUsage(AttributeTargets.Class)] + internal class HandleHelpRequestAttribute : Attribute, IPostLogoBuildExtension + { + public void Execute( + NukeBuild build, + IReadOnlyCollection executableTargets, + IReadOnlyCollection executionPlan) + { + if (!NukeBuild.Help && executionPlan.Count > 0) + return; + + Logger.Normal(HelpTextService.GetTargetsText(build.ExecutableTargets)); + Logger.Normal(HelpTextService.GetParametersText(build)); + + Environment.Exit(exitCode: 0); + } + } +} diff --git a/source/Nuke.Common/Execution/HandleHelpRequestsAttribute.cs b/source/Nuke.Common/Execution/HandleHelpRequestsAttribute.cs deleted file mode 100644 index 1f19d825d..000000000 --- a/source/Nuke.Common/Execution/HandleHelpRequestsAttribute.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2019 Maintainers of NUKE. -// Distributed under the MIT License. -// https://github.com/nuke-build/nuke/blob/master/LICENSE - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Nuke.Common.Execution -{ - [AttributeUsage(AttributeTargets.Class)] - internal class HandleHelpRequestsAttribute : Attribute, IPostLogoBuildExtension - { - public void Execute(NukeBuild build, IReadOnlyCollection executableTargets) - { - if (NukeBuild.Help) - { - Logger.Normal(HelpTextService.GetTargetsText(build.ExecutableTargets)); - Logger.Normal(HelpTextService.GetParametersText(build)); - } - - if (NukeBuild.Plan) - ExecutionPlanHtmlService.ShowPlan(build.ExecutableTargets); - - if (NukeBuild.Help || NukeBuild.Plan) - Environment.Exit(exitCode: 0); - } - } -} diff --git a/source/Nuke.Common/Execution/HandlePlanRequestAttribute.cs b/source/Nuke.Common/Execution/HandlePlanRequestAttribute.cs new file mode 100644 index 000000000..24863d4e9 --- /dev/null +++ b/source/Nuke.Common/Execution/HandlePlanRequestAttribute.cs @@ -0,0 +1,26 @@ +// Copyright 2019 Maintainers of NUKE. +// Distributed under the MIT License. +// https://github.com/nuke-build/nuke/blob/master/LICENSE + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Nuke.Common.Execution +{ + [AttributeUsage(AttributeTargets.Class)] + internal class HandlePlanRequestAttribute : Attribute, IPostLogoBuildExtension + { + public void Execute( + NukeBuild build, + IReadOnlyCollection executableTargets, + IReadOnlyCollection executionPlan) + { + if (!NukeBuild.Plan) + return; + + ExecutionPlanHtmlService.ShowPlan(build.ExecutableTargets); + Environment.Exit(exitCode: 0); + } + } +} diff --git a/source/Nuke.Common/Execution/HandleShellCompletionAttribute.cs b/source/Nuke.Common/Execution/HandleShellCompletionAttribute.cs index e33d0f89c..1a9c68b53 100644 --- a/source/Nuke.Common/Execution/HandleShellCompletionAttribute.cs +++ b/source/Nuke.Common/Execution/HandleShellCompletionAttribute.cs @@ -6,14 +6,16 @@ using System.Collections.Generic; using System.Linq; using Nuke.Common.IO; -using Nuke.Common.Tooling; namespace Nuke.Common.Execution { [AttributeUsage(AttributeTargets.Class)] internal class HandleShellCompletionAttribute : Attribute, IPreLogoBuildExtension { - public void Execute(NukeBuild build, IReadOnlyCollection executableTargets) + public void Execute( + NukeBuild build, + IReadOnlyCollection executableTargets, + IReadOnlyCollection executionPlan) { var completionItems = new SortedDictionary(); diff --git a/source/Nuke.Common/Execution/HandleVisualStudioDebuggingAttribute.cs b/source/Nuke.Common/Execution/HandleVisualStudioDebuggingAttribute.cs index 3d1eb9671..780224515 100644 --- a/source/Nuke.Common/Execution/HandleVisualStudioDebuggingAttribute.cs +++ b/source/Nuke.Common/Execution/HandleVisualStudioDebuggingAttribute.cs @@ -18,7 +18,10 @@ public class HandleVisualStudioDebuggingAttribute : Attribute, IPreLogoBuildExte { public int TimeoutInMilliseconds { get; } = 10_000; - public void Execute(NukeBuild build, IReadOnlyCollection executableTargets) + public void Execute( + NukeBuild build, + IReadOnlyCollection executableTargets, + IReadOnlyCollection executionPlan) { if (!ParameterService.Instance.GetParameter(Constants.VisualStudioDebugParameterName)) return; diff --git a/source/Nuke.Common/Execution/HelpTextService.cs b/source/Nuke.Common/Execution/HelpTextService.cs index 7173fc8fc..463699eef 100644 --- a/source/Nuke.Common/Execution/HelpTextService.cs +++ b/source/Nuke.Common/Execution/HelpTextService.cs @@ -37,7 +37,7 @@ public static string GetTargetsText(IReadOnlyCollection execut public static string GetParametersText(NukeBuild build) { - var defaultTarget = build.ExecutableTargets.Single(x => x.IsDefault); + var defaultTarget = build.ExecutableTargets.SingleOrDefault(x => x.IsDefault); var builder = new StringBuilder(); var parameters = InjectionUtility.GetParameterMembers(build.GetType()) @@ -50,7 +50,7 @@ void PrintParameter(MemberInfo parameter) var description = SplitLines( // TODO: remove ParameterService.Instance.GetParameterDescription(parameter) - ?.Replace("{default_target}", defaultTarget.Name).Append(".") + ?.Replace("{default_target}", defaultTarget?.Name).Append(".") ?? ""); var parameterName = ParameterService.Instance.GetParameterName(parameter).SplitCamelHumpsWithSeparator("-"); builder.AppendLine($" --{parameterName.PadRight(padRightParameter)} {description.First()}"); diff --git a/source/Nuke.Common/Execution/ParameterService.cs b/source/Nuke.Common/Execution/ParameterService.cs index 7c70aba40..63ed3742c 100644 --- a/source/Nuke.Common/Execution/ParameterService.cs +++ b/source/Nuke.Common/Execution/ParameterService.cs @@ -8,7 +8,6 @@ using System.Linq.Expressions; using System.Reflection; using JetBrains.Annotations; -using Nuke.Common.Tooling; using Nuke.Common.Utilities; using Nuke.Common.Utilities.Collections; using static Nuke.Common.Execution.ReflectionService; @@ -161,7 +160,7 @@ public object GetPositionalCommandLineArguments(Type destinationType, char? sepa return GetDefaultValue(destinationType); return ConvertCommandLineArguments( - $"$all-positional", + "$all-positional", positionalArguments, destinationType, _commandLineArguments, @@ -205,7 +204,7 @@ private bool HasCommandLineArgument(string argumentName, bool checkNames) private int GetCommandLineArgumentIndex(string argumentName, bool checkNames) { var index = Array.FindLastIndex(_commandLineArguments, - x => x.StartsWith("-") && x.Replace("-", string.Empty).EqualsOrdinalIgnoreCase(argumentName)); + x => x.StartsWith("-") && x.Replace("-", string.Empty).EqualsOrdinalIgnoreCase(argumentName.Replace("-", string.Empty))); if (index == -1 && checkNames) { diff --git a/source/Nuke.Common/Execution/UnsetVisualStudioEnvironmentVariablesAttribute.cs b/source/Nuke.Common/Execution/UnsetVisualStudioEnvironmentVariablesAttribute.cs index a4d5dc149..e7d576f13 100644 --- a/source/Nuke.Common/Execution/UnsetVisualStudioEnvironmentVariablesAttribute.cs +++ b/source/Nuke.Common/Execution/UnsetVisualStudioEnvironmentVariablesAttribute.cs @@ -14,7 +14,10 @@ namespace Nuke.Common.Execution [AttributeUsage(AttributeTargets.Class)] public class UnsetVisualStudioEnvironmentVariablesAttribute : Attribute, IPreLogoBuildExtension { - public void Execute(NukeBuild build, IReadOnlyCollection executableTargets) + public void Execute( + NukeBuild build, + IReadOnlyCollection executableTargets, + IReadOnlyCollection executionPlan) { new[] { diff --git a/source/Nuke.Common/IO/FileSystemTasks.cs b/source/Nuke.Common/IO/FileSystemTasks.cs index 1c4685e94..dd43f08c7 100644 --- a/source/Nuke.Common/IO/FileSystemTasks.cs +++ b/source/Nuke.Common/IO/FileSystemTasks.cs @@ -3,12 +3,10 @@ // https://github.com/nuke-build/nuke/blob/master/LICENSE using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; -using System.Threading; using JetBrains.Annotations; using Nuke.Common.Utilities.Collections; diff --git a/source/Nuke.Common/Nuke.Common.csproj b/source/Nuke.Common/Nuke.Common.csproj index 02f98495a..d3c1e125d 100644 --- a/source/Nuke.Common/Nuke.Common.csproj +++ b/source/Nuke.Common/Nuke.Common.csproj @@ -30,10 +30,10 @@ - - - - + + + + diff --git a/source/Nuke.Common/Nuke.Common.targets b/source/Nuke.Common/Nuke.Common.targets new file mode 100644 index 000000000..3b1fe14f6 --- /dev/null +++ b/source/Nuke.Common/Nuke.Common.targets @@ -0,0 +1,6 @@ + + + + + + diff --git a/source/Nuke.Common/NukeBuild.Statics.cs b/source/Nuke.Common/NukeBuild.Statics.cs index 7d187719b..aa6ed412b 100644 --- a/source/Nuke.Common/NukeBuild.Statics.cs +++ b/source/Nuke.Common/NukeBuild.Statics.cs @@ -31,6 +31,7 @@ static NukeBuild() Continue = ParameterService.Instance.GetParameter(() => Continue); Plan = ParameterService.Instance.GetParameter(() => Plan); Help = ParameterService.Instance.GetParameter(() => Help); + NoLogo = ParameterService.Instance.GetParameter(() => NoLogo); } /// @@ -51,7 +52,7 @@ static NukeBuild() public static PathConstruction.AbsolutePath BuildAssemblyDirectory { get; } /// - /// Gets the full path to the build project directory, or null + /// Gets the full path to the build project directory, or null /// [CanBeNull] public static PathConstruction.AbsolutePath BuildProjectDirectory { get; } @@ -80,6 +81,12 @@ static NukeBuild() [Parameter("Shows the help text for this build assembly.")] public static bool Help { get; } + /// + /// Gets a value whether to display the NUKE logo. + /// + [Parameter("Disables displaying the NUKE logo.")] + public static bool NoLogo { get; } + public static bool IsLocalBuild => Host == HostType.Console; public static bool IsServerBuild => Host != HostType.Console; diff --git a/source/Nuke.Common/NukeBuild.cs b/source/Nuke.Common/NukeBuild.cs index 79f9f283c..bde8f4a04 100644 --- a/source/Nuke.Common/NukeBuild.cs +++ b/source/Nuke.Common/NukeBuild.cs @@ -28,13 +28,13 @@ namespace Nuke.Common /// class DefaultBuild : NukeBuild /// { /// public static int Main () => Execute<DefaultBuild>(x => x.Compile); - /// + /// /// Target Clean => _ => _ /// .Executes(() => /// { /// EnsureCleanDirectory(OutputDirectory); /// }); - /// + /// /// Target Compile => _ => _ /// .DependsOn(Clean) /// .Executes(() => @@ -45,7 +45,8 @@ namespace Nuke.Common /// /// [PublicAPI] - [HandleHelpRequests] + [HandleHelpRequest] + [HandlePlanRequest] [HandleShellCompletion] [HandleVisualStudioDebugging] public abstract partial class NukeBuild @@ -87,7 +88,7 @@ protected static int Execute(Expression> defaultTargetExpress internal void ExecuteExtensions() where T : IBuildExtension { - GetType().GetCustomAttributes().OfType().ForEach(x => x.Execute(this, ExecutableTargets)); + GetType().GetCustomAttributes().OfType().ForEach(x => x.Execute(this, ExecutableTargets, ExecutionPlan)); } protected internal virtual IOutputSink OutputSink diff --git a/source/Nuke.Common/OutputSinks/FigletTransform.cs b/source/Nuke.Common/OutputSinks/FigletTransform.cs index e7249f8e6..8c3c1b3ea 100644 --- a/source/Nuke.Common/OutputSinks/FigletTransform.cs +++ b/source/Nuke.Common/OutputSinks/FigletTransform.cs @@ -3,12 +3,9 @@ // https://github.com/nuke-build/nuke/blob/master/LICENSE using System; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; -using System.Reflection; -using AutoMapper.XpressionMapper; using Colorful; using Nuke.Common.Utilities; diff --git a/source/Nuke.Common/ProjectModel/ProjectFromAttribute.cs b/source/Nuke.Common/ProjectModel/ProjectFromAttribute.cs index ed2568e5f..2cd5ad285 100644 --- a/source/Nuke.Common/ProjectModel/ProjectFromAttribute.cs +++ b/source/Nuke.Common/ProjectModel/ProjectFromAttribute.cs @@ -4,11 +4,9 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Reflection; using Nuke.Common.Execution; -using Nuke.Common.IO; using Nuke.Common.Utilities; namespace Nuke.Common.ProjectModel @@ -52,6 +50,8 @@ Project GetProject(string name) if (parameterValue != null) return GetProject(parameterValue); + ControlFlow.Assert(member.GetCustomAttribute() == null, + $"No project for member '{member.Name}' found in solution '{solution.FileName}'."); return null; } diff --git a/source/Nuke.Common/ProjectModel/ProjectModelTasks.cs b/source/Nuke.Common/ProjectModel/ProjectModelTasks.cs index b141e3e8e..2d944fc1b 100644 --- a/source/Nuke.Common/ProjectModel/ProjectModelTasks.cs +++ b/source/Nuke.Common/ProjectModel/ProjectModelTasks.cs @@ -25,7 +25,7 @@ public static Solution ParseSolution(string solutionFile) { var dotnet = ToolPathResolver.TryGetEnvironmentExecutable("DOTNET_EXE") ?? ToolPathResolver.GetPathExecutable("dotnet"); - var output = ProcessTasks.StartProcess(dotnet, "--info", EnvironmentInfo.WorkingDirectory, logOutput: false).AssertZeroExitCode().Output; + var output = ProcessTasks.StartProcess(dotnet, "--info", logOutput: false).AssertZeroExitCode().Output; var basePath = (PathConstruction.AbsolutePath) output .Select(x => x.Text.Trim()) .Single(x => x.StartsWith("Base Path:")) diff --git a/source/Nuke.Common/Tooling/Configure.cs b/source/Nuke.Common/Tooling/Configure.cs index d29160292..f300e3d77 100644 --- a/source/Nuke.Common/Tooling/Configure.cs +++ b/source/Nuke.Common/Tooling/Configure.cs @@ -6,7 +6,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; -using System.Threading; using JetBrains.Annotations; using Nuke.Common.Utilities.Collections; diff --git a/source/Nuke.Common/Tooling/LocalExecutableAttribute.cs b/source/Nuke.Common/Tooling/LocalExecutableAttribute.cs index 0ceb042d3..1a634fdc3 100644 --- a/source/Nuke.Common/Tooling/LocalExecutableAttribute.cs +++ b/source/Nuke.Common/Tooling/LocalExecutableAttribute.cs @@ -3,7 +3,6 @@ // https://github.com/nuke-build/nuke/blob/master/LICENSE using System; -using System.IO; using System.Linq; using System.Reflection; using Nuke.Common.Execution; diff --git a/source/Nuke.Common/Tooling/PathExecutableAttribute.cs b/source/Nuke.Common/Tooling/PathExecutableAttribute.cs index 3ff00cc95..9ac22750f 100644 --- a/source/Nuke.Common/Tooling/PathExecutableAttribute.cs +++ b/source/Nuke.Common/Tooling/PathExecutableAttribute.cs @@ -5,7 +5,6 @@ using System; using System.Linq; using System.Reflection; -using Microsoft.Build.Execution; using Nuke.Common.Execution; namespace Nuke.Common.Tooling diff --git a/source/Nuke.Common/Tooling/ProcessTasks.cs b/source/Nuke.Common/Tooling/ProcessTasks.cs index 624c6323f..07e0314f1 100644 --- a/source/Nuke.Common/Tooling/ProcessTasks.cs +++ b/source/Nuke.Common/Tooling/ProcessTasks.cs @@ -19,6 +19,7 @@ public static class ProcessTasks { public static bool DefaultLogOutput = true; public static bool DefaultLogInvocation = true; + public static bool LogWorkingDirectory = true; private static readonly char[] s_pathSeparators = { EnvironmentInfo.IsWin ? ';' : ':' }; @@ -62,7 +63,11 @@ public static IProcess StartProcess( outputFilter = outputFilter ?? (x => x); ControlFlow.Assert(File.Exists(toolPath), $"ToolPath '{toolPath}' does not exist."); if (logInvocation ?? DefaultLogInvocation) + { Logger.Info($"> {Path.GetFullPath(toolPath).DoubleQuoteIfNeeded()} {outputFilter(arguments)}"); + if (LogWorkingDirectory && workingDirectory != null) + Logger.Info($"@ {workingDirectory}"); + } return StartProcessInternal(toolPath, arguments, @@ -84,7 +89,9 @@ private static string GetToolPathOverride(string toolPath) } #if NETCORE - if (EnvironmentInfo.IsUnix && toolPath.EndsWithOrdinalIgnoreCase(".exe")) + if (EnvironmentInfo.IsUnix && + toolPath.EndsWithOrdinalIgnoreCase(".exe") && + !EnvironmentInfo.IsWsl) return ToolPathResolver.GetPathExecutable("mono"); #endif diff --git a/source/Nuke.Common/Tooling/ToolSettings.Combinatorial.cs b/source/Nuke.Common/Tooling/ToolSettings.Combinatorial.cs index 21c55da10..0d368c5d9 100644 --- a/source/Nuke.Common/Tooling/ToolSettings.Combinatorial.cs +++ b/source/Nuke.Common/Tooling/ToolSettings.Combinatorial.cs @@ -4,9 +4,7 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; -using JetBrains.Annotations; namespace Nuke.Common.Tooling { diff --git a/source/Nuke.Common/Tooling/ToolSettings.Standard.cs b/source/Nuke.Common/Tooling/ToolSettings.Standard.cs index bd6a6d01a..5048286ae 100644 --- a/source/Nuke.Common/Tooling/ToolSettings.Standard.cs +++ b/source/Nuke.Common/Tooling/ToolSettings.Standard.cs @@ -3,7 +3,6 @@ // https://github.com/nuke-build/nuke/blob/master/LICENSE using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using JetBrains.Annotations; diff --git a/source/Nuke.Common/Tooling/ToolSettings.When.cs b/source/Nuke.Common/Tooling/ToolSettings.When.cs index fc5c79453..db084f810 100644 --- a/source/Nuke.Common/Tooling/ToolSettings.When.cs +++ b/source/Nuke.Common/Tooling/ToolSettings.When.cs @@ -3,10 +3,7 @@ // https://github.com/nuke-build/nuke/blob/master/LICENSE using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; -using JetBrains.Annotations; namespace Nuke.Common.Tooling { diff --git a/source/Nuke.Common/Tooling/VerbosityMappingAttribute.cs b/source/Nuke.Common/Tooling/VerbosityMappingAttribute.cs index 5cf9a7457..274adc10a 100644 --- a/source/Nuke.Common/Tooling/VerbosityMappingAttribute.cs +++ b/source/Nuke.Common/Tooling/VerbosityMappingAttribute.cs @@ -25,7 +25,10 @@ public VerbosityMappingAttribute(Type targetType) public string Normal { get; set; } public string Verbose { get; set; } - public void Execute(NukeBuild build, IReadOnlyCollection executableTargets) + public void Execute( + NukeBuild build, + IReadOnlyCollection executableTargets, + IReadOnlyCollection executionPlan) { object GetMappedValue(string name) => _targetType diff --git a/source/Nuke.Common/Tools/Git/GitTasks.cs b/source/Nuke.Common/Tools/Git/GitTasks.cs index 0cfdf0244..d378ba77c 100644 --- a/source/Nuke.Common/Tools/Git/GitTasks.cs +++ b/source/Nuke.Common/Tools/Git/GitTasks.cs @@ -11,7 +11,7 @@ public static partial class GitTasks { public static bool GitIsDetached() { - return GitIsDetached(EnvironmentInfo.WorkingDirectory); + return GitIsDetached(workingDirectory: null); } public static bool GitIsDetached(string workingDirectory) @@ -21,7 +21,7 @@ public static bool GitIsDetached(string workingDirectory) public static bool GitHasCleanWorkingCopy() { - return GitHasCleanWorkingCopy(EnvironmentInfo.WorkingDirectory); + return GitHasCleanWorkingCopy(workingDirectory: null); } public static bool GitHasCleanWorkingCopy(string workingDirectory) @@ -31,7 +31,7 @@ public static bool GitHasCleanWorkingCopy(string workingDirectory) public static string GitCurrentBranch() { - return GitCurrentBranch(EnvironmentInfo.WorkingDirectory); + return GitCurrentBranch(workingDirectory: null); } private static string GitCurrentBranch(string workingDirectory) diff --git a/source/Nuke.Common/Tools/GitVersion/GitVersion.Generated.cs b/source/Nuke.Common/Tools/GitVersion/GitVersion.Generated.cs index b6afd43dc..53e94ef68 100644 --- a/source/Nuke.Common/Tools/GitVersion/GitVersion.Generated.cs +++ b/source/Nuke.Common/Tools/GitVersion/GitVersion.Generated.cs @@ -299,6 +299,7 @@ public partial class GitVersion : ISettingsEntity public virtual string NuGetVersion { get; internal set; } public virtual string NuGetPreReleaseTagV2 { get; internal set; } public virtual string NuGetPreReleaseTag { get; internal set; } + public virtual string VersionSourceSha { get; internal set; } public virtual string CommitsSinceVersionSource { get; internal set; } public virtual string CommitsSinceVersionSourcePadded { get; internal set; } public virtual string CommitDate { get; internal set; } diff --git a/source/Nuke.Common/Tools/GitVersion/GitVersionAttribute.cs b/source/Nuke.Common/Tools/GitVersion/GitVersionAttribute.cs index caaa2803c..3f9a61370 100644 --- a/source/Nuke.Common/Tools/GitVersion/GitVersionAttribute.cs +++ b/source/Nuke.Common/Tools/GitVersion/GitVersionAttribute.cs @@ -31,7 +31,6 @@ public override object GetValue(MemberInfo member, object instance) return ControlFlow.SuppressErrors(() => GitVersionTasks.GitVersion(s => s - .SetWorkingDirectory(NukeBuild.RootDirectory) .DisableLogOutput()) .Result, includeStackTrace: true); diff --git a/source/Nuke.Common/Tools/GitVersion/GitVersionTasks.cs b/source/Nuke.Common/Tools/GitVersion/GitVersionTasks.cs index e2dc37ef4..6cc5e2820 100644 --- a/source/Nuke.Common/Tools/GitVersion/GitVersionTasks.cs +++ b/source/Nuke.Common/Tools/GitVersion/GitVersionTasks.cs @@ -3,15 +3,12 @@ // https://github.com/nuke-build/nuke/blob/master/LICENSE using System; -using System.IO; using System.Linq; using System.Reflection; using JetBrains.Annotations; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Nuke.Common.Tooling; -using Nuke.Common.Utilities; -using Nuke.Common.Utilities.Collections; namespace Nuke.Common.Tools.GitVersion { diff --git a/source/Nuke.Common/Tools/MSBuild/MSBuildToolPathResolver.cs b/source/Nuke.Common/Tools/MSBuild/MSBuildToolPathResolver.cs index 6418a800d..872e46e10 100644 --- a/source/Nuke.Common/Tools/MSBuild/MSBuildToolPathResolver.cs +++ b/source/Nuke.Common/Tools/MSBuild/MSBuildToolPathResolver.cs @@ -7,10 +7,7 @@ using System.Diagnostics; using System.IO; using System.Linq; - -#if LOCATOR -using Nuke.MSBuildLocator; -#endif +using Nuke.Common.Utilities; namespace Nuke.Common.Tools.MSBuild { @@ -42,9 +39,10 @@ private static IEnumerable ResolveInternal(MSBuildVersion? msBuildVersio var instances = new List(); instances.AddRange( - from vs2017Edition in new[] { "Enterprise", "Professional", "Community", "BuildTools" } - from platform1 in s_platforms - select GetVs2017Instance(platform1, vs2017Edition)); + from version in new[]{MSBuildVersion.VS2019, MSBuildVersion.VS2017} + from platform in s_platforms + from edition in new[] { "Enterprise", "Professional", "Community", "BuildTools" } + select GetFromVs2017Instance(version, platform, edition)); instances.AddRange( from version in new[] { MSBuildVersion.VS2015, MSBuildVersion.VS2013 } @@ -63,14 +61,15 @@ from platform in s_platforms return filteredInstances.Select(x => x.ToolPath); } - private static Instance GetVs2017Instance(MSBuildPlatform platform, string vs2017Edition) + private static Instance GetFromVs2017Instance(MSBuildVersion version, MSBuildPlatform platform, string edition) { + var versionDirectoryName = version.ToString().TrimStart("VS"); var basePath = Path.Combine( EnvironmentInfo.SpecialFolder(SpecialFolders.ProgramFilesX86).NotNull("path1 != null"), - $@"Microsoft Visual Studio\2017\{vs2017Edition}\MSBuild\{GetVersionFolder(MSBuildVersion.VS2017)}\Bin"); + $@"Microsoft Visual Studio\{versionDirectoryName}\{edition}\MSBuild\{GetVersionFolder(version)}\Bin"); return new Instance( - MSBuildVersion.VS2017, + version, platform, platform == MSBuildPlatform.x64 ? Path.Combine(basePath, "amd64") @@ -95,6 +94,8 @@ private static string GetVersionFolder(MSBuildVersion version) { switch (version) { + case MSBuildVersion.VS2019: + return "Current"; case MSBuildVersion.VS2017: return "15.0"; case MSBuildVersion.VS2015: diff --git a/source/Nuke.Common/Tools/MSBuild/MSBuildVersion.cs b/source/Nuke.Common/Tools/MSBuild/MSBuildVersion.cs index a569f5ca0..746ef0e0a 100644 --- a/source/Nuke.Common/Tools/MSBuild/MSBuildVersion.cs +++ b/source/Nuke.Common/Tools/MSBuild/MSBuildVersion.cs @@ -15,6 +15,7 @@ namespace Nuke.Common.Tools.MSBuild [PublicAPI] public enum MSBuildVersion { + VS2019, VS2017, VS2015, VS2013 diff --git a/source/Nuke.Common/Tools/ReportGenerator/ReportGenerator.Generated.cs b/source/Nuke.Common/Tools/ReportGenerator/ReportGenerator.Generated.cs index be0a96ac0..73efe747c 100644 --- a/source/Nuke.Common/Tools/ReportGenerator/ReportGenerator.Generated.cs +++ b/source/Nuke.Common/Tools/ReportGenerator/ReportGenerator.Generated.cs @@ -793,6 +793,7 @@ public partial class ReportTypes : Enumeration public static ReportTypes Xml = new ReportTypes { Value = "Xml" }; public static ReportTypes XmlSummary = new ReportTypes { Value = "XmlSummary" }; public static ReportTypes SonarQube = new ReportTypes { Value = "SonarQube" }; + public static ReportTypes TeamCitySummary = new ReportTypes { Value = "TeamCitySummary" }; } #endregion #region ReportGeneratorVerbosity diff --git a/source/Nuke.Common/Utilities/String.PrependAppend.cs b/source/Nuke.Common/Utilities/String.PrependAppend.cs index c990bdb77..4a617982e 100644 --- a/source/Nuke.Common/Utilities/String.PrependAppend.cs +++ b/source/Nuke.Common/Utilities/String.PrependAppend.cs @@ -3,7 +3,6 @@ // https://github.com/nuke-build/nuke/blob/master/LICENSE using System; -using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; diff --git a/source/Nuke.GlobalTool.Tests/ProgramTest.cs b/source/Nuke.GlobalTool.Tests/ProgramTest.cs index 5cf425e82..7ac8e4e74 100644 --- a/source/Nuke.GlobalTool.Tests/ProgramTest.cs +++ b/source/Nuke.GlobalTool.Tests/ProgramTest.cs @@ -3,10 +3,8 @@ // https://github.com/nuke-build/nuke/blob/master/LICENSE using System; -using System.Collections.Generic; using System.Linq; using FluentAssertions; -using Nuke.Common; using Xunit; namespace Nuke.GlobalTool.Tests diff --git a/source/Nuke.GlobalTool/Program.cs b/source/Nuke.GlobalTool/Program.cs index 561287e1b..f8e8223f4 100644 --- a/source/Nuke.GlobalTool/Program.cs +++ b/source/Nuke.GlobalTool/Program.cs @@ -7,7 +7,6 @@ using System.IO; using System.Linq; using System.Reflection; -using System.Reflection.Metadata; using JetBrains.Annotations; using Nuke.Common; using Nuke.Common.Tooling; diff --git a/source/Nuke.GlobalTool/templates/_build.sdk.csproj b/source/Nuke.GlobalTool/templates/_build.sdk.csproj index b4efb450e..e453a58a6 100644 --- a/source/Nuke.GlobalTool/templates/_build.sdk.csproj +++ b/source/Nuke.GlobalTool/templates/_build.sdk.csproj @@ -11,12 +11,11 @@ - // GENERATION // GITVERSION - + diff --git a/source/Nuke.MSBuildLocator/Program.cs b/source/Nuke.MSBuildLocator/Program.cs index 645399dca..ee352bc1d 100644 --- a/source/Nuke.MSBuildLocator/Program.cs +++ b/source/Nuke.MSBuildLocator/Program.cs @@ -14,33 +14,33 @@ namespace Nuke.MSBuildLocator { public static class Program { - private const string c_msBuildComponent = "Microsoft.Component.MSBuild"; - private const string c_netCoreComponent = "Microsoft.Net.Core.Component.SDK"; - private const string c_vsWhereExecutableName = "vswhere.exe"; + private const string c_msbuildComponent = "Microsoft.Component.MSBuild"; + private const string c_netcoreComponent = "Microsoft.Net.Core.Component.SDK"; + private const string c_vswhereExecutableName = "vswhere.exe"; [STAThread] public static void Main(string[] args) { - var vsWherePath = args.FirstOrDefault(); - if (vsWherePath != null && !vsWherePath.EndsWith(c_vsWhereExecutableName)) - vsWherePath = Path.Combine(vsWherePath, c_vsWhereExecutableName); + var vswherePath = args.FirstOrDefault(); + if (vswherePath != null && !vswherePath.EndsWith(c_vswhereExecutableName)) + vswherePath = Path.Combine(vswherePath, c_vswhereExecutableName); - Trace.Assert(vsWherePath != null, $"Path to {c_vsWhereExecutableName} must be passed"); - Trace.Assert(File.Exists(vsWherePath), $"File '{vsWherePath}' does not exists"); + Trace.Assert(vswherePath != null, $"Path to {c_vswhereExecutableName} must be passed"); + Trace.Assert(File.Exists(vswherePath), $"File '{vswherePath}' does not exists"); - var msBuildLocator = new MSBuildLocator(vsWherePath); - var msBuildPath = msBuildLocator.Resolve(); - Trace.Assert(msBuildPath != null, "msBuildPath != null"); - Console.WriteLine(msBuildPath); + var msbuildLocator = new MSBuildLocator(vswherePath); + var msbuildPath = msbuildLocator.Resolve(); + Trace.Assert(msbuildPath != null, "msbuildPath != null"); + Console.WriteLine(msbuildPath); } private class MSBuildLocator { - private readonly string _vsWherePath; + private readonly string _vswherePath; - public MSBuildLocator(string vsWherePath) + public MSBuildLocator(string vswherePath) { - _vsWherePath = vsWherePath; + _vswherePath = vswherePath; } [CanBeNull] @@ -53,8 +53,8 @@ public string Resolve() "/usr/local/bin/msbuild", "/Library/Frameworks/Mono.framework/Versions/Current/Commands/msbuild" }.FirstOrDefault(File.Exists) - : TryGetMSBuildPath(products: "*", requires: new[] { c_msBuildComponent, c_netCoreComponent }, legacy: false) ?? - TryGetMSBuildPath(products: "*", requires: new[] { c_msBuildComponent }, legacy: false) ?? + : TryGetMSBuildPath(products: "*", requires: new[] { c_msbuildComponent, c_netcoreComponent }, legacy: false) ?? + TryGetMSBuildPath(products: "*", requires: new[] { c_msbuildComponent }, legacy: false) ?? TryGetMSBuildPath(products: null, requires: null, legacy: true); } @@ -74,10 +74,15 @@ private string TryGetMSBuildPath( if (installation == null) return null; + var msbuildMajorVersion = installation.Version.Split('.')[0]; + var msbuildVersionDirectoryName = int.TryParse(msbuildMajorVersion, out var major) && major < 16 + ? $"{installation.Version.Split('.')[0]}.0" + : "Current"; + var msbuildPath = Path.Combine( installation.Path, "MSBuild", - $"{installation.Version.Split('.')[0]}.0", + msbuildVersionDirectoryName, "Bin", Environment.Is64BitOperatingSystem ? "amd64" : ".", "MSBuild.exe"); @@ -122,7 +127,7 @@ bool TryGetSingleValue(string identifier, out string value) private string GetProcessOutput(string arguments) { - var info = new ProcessStartInfo(_vsWherePath, arguments) + var info = new ProcessStartInfo(_vswherePath, arguments) { RedirectStandardOutput = true, RedirectStandardError = true, diff --git a/source/Nuke.MSBuildTaskRunner/Nuke.MSBuildTaskRunner.csproj b/source/Nuke.MSBuildTaskRunner/Nuke.MSBuildTaskRunner.csproj new file mode 100644 index 000000000..86206b7e0 --- /dev/null +++ b/source/Nuke.MSBuildTaskRunner/Nuke.MSBuildTaskRunner.csproj @@ -0,0 +1,18 @@ + + + + false + Exe + netcoreapp2.0 + $(NoWarn);CS0649 + + + + + + + + + + + diff --git a/source/Nuke.MSBuildTaskRunner/Nuke.MSBuildTaskRunner.targets b/source/Nuke.MSBuildTaskRunner/Nuke.MSBuildTaskRunner.targets new file mode 100644 index 000000000..7c9b3b884 --- /dev/null +++ b/source/Nuke.MSBuildTaskRunner/Nuke.MSBuildTaskRunner.targets @@ -0,0 +1,58 @@ + + + + + dotnet exec "$(MSBuildThisFileDirectory)$(MSBuildThisFileName).dll" -- + + + + + + + + + + + + + + + + + + + + + + + + + <_PackageFilesRaw Remove="%(_PackageFilesRaw.Identity)" Condition="$([System.String]::Copy('%(Identity)').StartsWith('error'))" /> + <_PackageFilesRaw Remove="%(_PackageFilesRaw.Identity)" Condition="$([System.String]::Copy('%(Identity)').StartsWith('warning'))" /> + + <_PackageFilesRaw + Part1="$([System.String]::Copy('%(Identity)').Split('@')[0].Trim())" + Part2="$([System.String]::Copy('%(Identity)').Split('@')[1].Trim())" /> + + <_PackageFiles + Include="%(_PackageFilesRaw.Part1)" + BuildAction="None" + PackagePath="%(_PackageFilesRaw.Part2)"/> + + + + + diff --git a/source/Nuke.MSBuildTaskRunner/Program.cs b/source/Nuke.MSBuildTaskRunner/Program.cs new file mode 100644 index 000000000..e5dc3a62d --- /dev/null +++ b/source/Nuke.MSBuildTaskRunner/Program.cs @@ -0,0 +1,167 @@ +// Copyright 2019 Maintainers of NUKE. +// Distributed under the MIT License. +// https://github.com/nuke-build/nuke/blob/master/LICENSE + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.Serialization.Json; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; +using Nuke.CodeGeneration; +using Nuke.Common; +using Nuke.Common.Execution; +using Nuke.Common.IO; +using Nuke.Common.Utilities; +using Nuke.Common.Utilities.Collections; +using static Nuke.Common.IO.PathConstruction; + +namespace Nuke.MSBuildTaskRunner +{ + public class Program + { + [Parameter] static bool Debug; + + [Parameter] static TaskAction Action; + [Parameter(Separator = ";")] static AbsolutePath[] Files; + [Parameter] static string ProjectAssetsFile; + [Parameter] static string NuGetPackageRoot; + [Parameter] static string TargetFramework; + + public static int Main() + { + InjectionUtility.InjectValues(); + + if (Debug) + { + Warning("Waiting for debugger to attach..."); + SpinWait.SpinUntil(() => Debugger.IsAttached); + } + + try + { + switch (Action) + { + case TaskAction.CodeGeneration: + CodeGenerator.GenerateCode(Files.Select(x => x.ToString()).ToList()); + break; + case TaskAction.ExternalFilesDownload: + var results = Files.Select(x => x.ToString()).Select(DownloadExternalFiles).ToList(); + ControlFlow.Assert(results.All(x => x.Result), "results.All(x => x.Result)"); + break; + case TaskAction.GlobalToolPackaging: + GetAdditionalPackageFiles().ForEach(x => Console.WriteLine(x)); + break; + default: + throw new ArgumentOutOfRangeException(nameof(Action)); + } + + return 0; + } + catch (Exception ex) + { + Error(ex.Message); + return -1; + } + } + + private static void Error(string text) + { + Console.Error.WriteLine($"error: {text}"); + } + + private static void Warning(string text) + { + Console.WriteLine($"warning: {text}"); + } + + private static async Task DownloadExternalFiles(string sharedFile) + { + try + { + var lines = File.ReadAllLines(sharedFile).Where(x => !string.IsNullOrWhiteSpace(x)).ToList(); + var uriConversion = Uri.TryCreate(lines.FirstOrDefault(), UriKind.Absolute, out var uri); + ControlFlow.Assert(uriConversion, $"Could not parse URI from first line of '{sharedFile}'."); + + var outputFile = sharedFile.Substring(startIndex: 0, length: sharedFile.Length - 4); + var previousHash = File.Exists(outputFile) ? FileSystemTasks.GetFileHash(outputFile) : null; + + var template = (await HttpTasks.HttpDownloadStringAsync(uri.OriginalString)).SplitLineBreaks(); + var replacements = lines.Skip(1) + .Where(x => x.Contains('=')) + .Select(x => x.Split('=')) + .Where(x => x.Length == 2) + .ToDictionary( + x => $"_{x.First().Trim('_').ToUpperInvariant()}_", + x => x.ElementAt(1)); + var definitions = lines.Skip(1) + .Where(x => !x.Contains('=') && !string.IsNullOrWhiteSpace(x)) + .Select(x => x.ToUpperInvariant()) + .ToList(); + + File.WriteAllLines(outputFile, TemplateUtility.FillTemplate(template, definitions, replacements)); + var newHash = FileSystemTasks.GetFileHash(outputFile); + + if (newHash != previousHash) + Warning($"External file '{outputFile}' has been updated."); + + return true; + } + catch (Exception exception) + { + Error(exception.Message); + return false; + } + } + + private static IEnumerable GetAdditionalPackageFiles() + { + var assetFileContent = File.ReadAllText(ProjectAssetsFile); + var reader = JsonReaderWriterFactory.CreateJsonReader( + Encoding.UTF8.GetBytes(assetFileContent), + new XmlDictionaryReaderQuotas()); + + var root = XElement.Load(reader); + var packages = root.XPathSelectElements("//libraries/*/path") + .Select(x => x.Value.Split(new[] { "/" }, StringSplitOptions.None)) + .Select(x => new + { + Id = x[0], + Version = x[1] + }) + .Select(x => new + { + x.Id, + Directory = Path.Combine(NuGetPackageRoot, x.Id, x.Version, "tools") + }).ToList(); + + var files = packages + .Where(x => Directory.Exists(x.Directory)) + .SelectMany( + x => Directory.GetFiles(x.Directory, "*", SearchOption.AllDirectories), + (x, f) => new + { + x.Id, + AbsolutePath = f, + PackageRelativePath = GetRelativePath(x.Directory, f) + }).ToList(); + + foreach (var file in files) + { + var packagePath = Path.Combine("tools", + TargetFramework, + "any", + file.Id, + file.PackageRelativePath); + + yield return $"{file.AbsolutePath}@{packagePath}"; + } + } + } +} diff --git a/source/Nuke.MSBuildTaskRunner/TaskAction.cs b/source/Nuke.MSBuildTaskRunner/TaskAction.cs new file mode 100644 index 000000000..6212d40f7 --- /dev/null +++ b/source/Nuke.MSBuildTaskRunner/TaskAction.cs @@ -0,0 +1,16 @@ +// Copyright 2019 Maintainers of NUKE. +// Distributed under the MIT License. +// https://github.com/nuke-build/nuke/blob/master/LICENSE + +using System; +using System.Linq; + +namespace Nuke.MSBuildTaskRunner +{ + public enum TaskAction + { + CodeGeneration, + ExternalFilesDownload, + GlobalToolPackaging + } +}