From 57d7cb70f1fdd4c0054ce55cfb16e31a309fff0e Mon Sep 17 00:00:00 2001 From: James Connor Date: Thu, 17 Feb 2022 11:22:26 +0000 Subject: [PATCH] Add dotnet sln and list commands --- src/Cake.Common/Tools/DotNet/DotNetAliases.cs | 141 ++++++++++++++++ .../Tools/DotNet/List/DotNetList.cs | 86 ++++++++++ .../Tools/DotNet/List/DotNetListSettings.cs | 13 ++ src/Cake.Common/Tools/DotNet/Sln/DotNetSln.cs | 154 ++++++++++++++++++ .../Tools/DotNet/Sln/DotNetSlnSettings.cs | 13 ++ 5 files changed, 407 insertions(+) create mode 100644 src/Cake.Common/Tools/DotNet/List/DotNetList.cs create mode 100644 src/Cake.Common/Tools/DotNet/List/DotNetListSettings.cs create mode 100644 src/Cake.Common/Tools/DotNet/Sln/DotNetSln.cs create mode 100644 src/Cake.Common/Tools/DotNet/Sln/DotNetSlnSettings.cs diff --git a/src/Cake.Common/Tools/DotNet/DotNetAliases.cs b/src/Cake.Common/Tools/DotNet/DotNetAliases.cs index 595e626d37..65db764e92 100644 --- a/src/Cake.Common/Tools/DotNet/DotNetAliases.cs +++ b/src/Cake.Common/Tools/DotNet/DotNetAliases.cs @@ -10,6 +10,7 @@ using Cake.Common.Tools.DotNet.Clean; using Cake.Common.Tools.DotNet.Execute; using Cake.Common.Tools.DotNet.Format; +using Cake.Common.Tools.DotNet.List; using Cake.Common.Tools.DotNet.MSBuild; using Cake.Common.Tools.DotNet.NuGet.Delete; using Cake.Common.Tools.DotNet.NuGet.Push; @@ -26,6 +27,7 @@ using Cake.Common.Tools.DotNet.Restore; using Cake.Common.Tools.DotNet.Run; using Cake.Common.Tools.DotNet.SDKCheck; +using Cake.Common.Tools.DotNet.Sln; using Cake.Common.Tools.DotNet.Test; using Cake.Common.Tools.DotNet.Tool; using Cake.Common.Tools.DotNet.VSTest; @@ -1306,6 +1308,145 @@ public static void DotNetMSBuild(this ICakeContext context, string projectOrDire builder.Build(projectOrDirectory, settings); } + /// + /// Adds a project to a solution + /// + /// The context. + /// Solution file to add to. Uses working directory if null. + /// Project file to add. + /// Solution folder name to add the reference to. Created if it doesn't exist. Adds project to solution root if null. + /// The settings. + /// + /// + /// DotNetSlnAdd("MySolution.sln", "MyProject.csproj", null, settings); + /// + /// DotNetSlnAdd("MySolution.sln", "MyProject.csproj", "MySolutionFolder", settings); + /// + /// + /// + /// If a solution file is not specified, dotnet searches the current working directory for a solution file and uses that file. + /// + [CakeMethodAlias] + [CakeAliasCategory("Sln")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Sln")] + public static void DotNetSlnAdd(this ICakeContext context, string solution, string project, + string solutionFolder, DotNetSlnSettings settings) + { + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (settings is null) + { + settings = new DotNetSlnSettings(); + } + + var executor = new DotNetSln(context.FileSystem, context.Environment, context.ProcessRunner, context.Tools); + executor.Add(solution, project, solutionFolder, settings); + } + + /// + /// Removes a project to a solution + /// + /// The context. + /// Solution file to remove from. Searches working directory if null. + /// Project file to remove. + /// The settings. + /// + /// + /// DotNetSlnRemove("MySolution.sln", "MyProject.csproj", settings); + /// + /// + /// + /// If a solution file is not specified, dotnet searches the current working directory for a solution file and uses that file. + /// + [CakeMethodAlias] + [CakeAliasCategory("Sln")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Sln")] + public static void DotNetSlnRemove(this ICakeContext context, string solution, string project, + DotNetSlnSettings settings) + { + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (settings is null) + { + settings = new DotNetSlnSettings(); + } + + var executor = new DotNetSln(context.FileSystem, context.Environment, context.ProcessRunner, context.Tools); + executor.Remove(solution, project, settings); + } + + /// + /// Lists project references in a solution + /// + /// The context. + /// Solution file to add to. Uses working directory if null. + /// The settings. + /// An array of absolute paths to any references found. These can be .csproj, .fsproj, .dwproj files etc. + /// + /// + /// DotNetSlnList("MySolution.sln", settings); + /// + /// + /// + /// If a solution file is not specified, dotnet searches the current working directory for a solution file and uses that file. + /// + [CakeMethodAlias] + [CakeAliasCategory("Sln")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.Sln")] + public static string[] DotNetSlnList(this ICakeContext context, string solution, DotNetSlnSettings settings) + { + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (settings is null) + { + settings = new DotNetSlnSettings(); + } + + var executor = new DotNetSln(context.FileSystem, context.Environment, context.ProcessRunner, context.Tools); + return executor.List(solution, settings); + } + + + /// + /// Given a project file, lists project references. + /// + /// The context. + /// The project to inspect for project references. + /// The settings. + /// An array of absolute paths to any project references found. These can be .csproj, .fsproj, .dwproj files etc. + /// + /// + /// DotNetListProjectReferences("MyProject.csproj", settings); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("List")] + [CakeNamespaceImport("Cake.Common.Tools.DotNet.List")] + public static string[] DotNetListProjectReferences(ICakeContext context, string project, DotNetListSettings settings) + { + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (settings is null) + { + settings = new DotNetListSettings(); + } + + var executor = new DotNetList(context.FileSystem, context.Environment, context.ProcessRunner, + context.Tools); + return executor.ListProjectReferences(project, settings); + } /// /// Test one or more projects specified by a path or glob pattern using the VS Test host runner. /// diff --git a/src/Cake.Common/Tools/DotNet/List/DotNetList.cs b/src/Cake.Common/Tools/DotNet/List/DotNetList.cs new file mode 100644 index 0000000000..e6d5d4d56e --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/List/DotNetList.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using System.Linq; +using Cake.Common.Tools.DotNet.Format; +using Cake.Core; +using Cake.Core.IO; +using Cake.Core.Tooling; + +namespace Cake.Common.Tools.DotNet.List +{ + /// + /// 'dotnet list' commands + /// + public sealed class DotNetList : DotNetTool + { + /// + /// Initializes a new instance of the class. + /// + /// The file system. + /// The environment. + /// The process runner. + /// The tool locator. + public DotNetList( + IFileSystem fileSystem, + ICakeEnvironment environment, + IProcessRunner processRunner, + IToolLocator tools) : base(fileSystem, environment, processRunner, tools) + { + } + + /// + /// Given a project, outputs all project references + /// + /// The target project path. + /// The settings. + public string[] ListProjectReferences(string project, DotNetListSettings settings) + { + if (project == null) + { + throw new ArgumentNullException(nameof(project)); + } + + if (settings == null) + { + throw new ArgumentNullException(nameof(settings)); + } + + var references = Array.Empty(); + Run(settings, GetListProjectReferencesArguments(project, settings), + new ProcessSettings { RedirectStandardOutput = true }, + process => + { + var projDir = new FileInfo(project).DirectoryName; + + references = + process.GetStandardOutput().Skip(2) + .Select(p => + System.IO.Path.GetFullPath(System.IO.Path.Join(projDir, p)).Replace('/', '\\')) + .ToArray(); + }); + + return references; + } + + private ProcessArgumentBuilder GetListProjectReferencesArguments(string project, DotNetListSettings settings) + { + var builder = CreateArgumentBuilder(settings); + + builder.Append("list"); + + // Specific path? + if (project != null) + { + builder.AppendQuoted(project); + } + + builder.Append("reference"); + + return builder; + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Tools/DotNet/List/DotNetListSettings.cs b/src/Cake.Common/Tools/DotNet/List/DotNetListSettings.cs new file mode 100644 index 0000000000..8803a94a1d --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/List/DotNetListSettings.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Cake.Common.Tools.DotNet.List +{ + /// + /// DotNetListSettings class + /// + public class DotNetListSettings : DotNetSettings + { + } +} diff --git a/src/Cake.Common/Tools/DotNet/Sln/DotNetSln.cs b/src/Cake.Common/Tools/DotNet/Sln/DotNetSln.cs new file mode 100644 index 0000000000..9fb2049cd5 --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/Sln/DotNetSln.cs @@ -0,0 +1,154 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable +using System; +using System.IO; +using System.Linq; +using Cake.Core; +using Cake.Core.IO; +using Cake.Core.Tooling; + +namespace Cake.Common.Tools.DotNet.Sln +{ + /// + /// 'dotnet sln' commands + /// + public sealed class DotNetSln : DotNetTool + { + private readonly ICakeEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The file system. + /// The environment. + /// The process runner. + /// The tool locator. + public DotNetSln( + IFileSystem fileSystem, + ICakeEnvironment environment, + IProcessRunner processRunner, + IToolLocator tools) : base(fileSystem, environment, processRunner, tools) + { + _environment = environment; + } + + public void Add(string? solution, string project, string? solutionFolder, DotNetSlnSettings settings) + { + if (project == null) + { + throw new ArgumentNullException(nameof(project)); + } + + Run(settings, GetAddArguments(solution, project, solutionFolder, settings)); + } + + private ProcessArgumentBuilder GetAddArguments(string? solution, string project, string? solutionFolder, + DotNetSlnSettings settings) + { + var builder = CreateArgumentBuilder(settings); + + builder.Append("sln"); + + // Specific path? + if (solution != null) + { + builder.AppendQuoted(solution); + } + + builder.Append("add"); + + if (solutionFolder != null) + { + builder.Append("-s"); + builder.AppendQuoted(solutionFolder); + } + else + { + builder.Append("--in-root"); + } + + builder.AppendQuoted(project); + + return builder; + } + + public void Remove(string? solution, string project, DotNetSlnSettings settings) + { + if (project == null) + { + throw new ArgumentNullException(nameof(project)); + } + + Run(settings, GetRemoveArguments(solution, project, settings)); + } + + private ProcessArgumentBuilder GetRemoveArguments(string? solution, string project, DotNetSlnSettings settings) + { + var builder = CreateArgumentBuilder(settings); + + builder.Append("sln"); + + // Specific path? + if (solution != null) + { + builder.AppendQuoted(solution); + } + + builder.Append("remove"); + + builder.AppendQuoted(project); + + return builder; + } + + /// + /// Cleans the project's output using the specified path and settings. + /// + /// The target project path. + /// The settings. + public string[] List(string? solution, DotNetSlnSettings settings) + { + if (settings == null) + { + throw new ArgumentNullException(nameof(settings)); + } + + string[] projects = Array.Empty(); + Run(settings, GetListArguments(solution, settings), new ProcessSettings { RedirectStandardOutput = true }, + process => + { + var slnDir = solution is null + ? _environment.WorkingDirectory + : new FileInfo(solution).DirectoryName; + + projects = + process.GetStandardOutput().Skip(2).Select(p => + System.IO.Path.GetFullPath(System.IO.Path.Join(slnDir.ToString(), p)) + .Replace('/', '\\')) + .ToArray(); + }); + + return projects; + } + + private ProcessArgumentBuilder GetListArguments(string? solution, DotNetSlnSettings settings) + { + var builder = CreateArgumentBuilder(settings); + + builder.Append("sln"); + + // Specific path? + if (solution != null) + { + builder.AppendQuoted(solution); + } + + builder.Append("list"); + + return builder; + } + } +} \ No newline at end of file diff --git a/src/Cake.Common/Tools/DotNet/Sln/DotNetSlnSettings.cs b/src/Cake.Common/Tools/DotNet/Sln/DotNetSlnSettings.cs new file mode 100644 index 0000000000..e91f1974e6 --- /dev/null +++ b/src/Cake.Common/Tools/DotNet/Sln/DotNetSlnSettings.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Cake.Common.Tools.DotNet.Sln +{ + /// + /// DotNetSlnSettings class + /// + public class DotNetSlnSettings : DotNetSettings + { + } +}