From 481d679132e9cefddd618964445c982829a73f9f Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Mon, 17 Apr 2023 11:30:01 +0300 Subject: [PATCH] Created LocalReferenceConverter --- .../Abp/Cli/Commands/SwitchToLocalCommand.cs | 23 +++- .../LocalReferenceConverter.cs | 109 ++++++++++++++++++ 2 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/LocalReferenceConverter.cs diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToLocalCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToLocalCommand.cs index 7f49fa763d..32a6e4b063 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToLocalCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/SwitchToLocalCommand.cs @@ -6,16 +6,23 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Volo.Abp.Cli.Args; +using Volo.Abp.Cli.ProjectModification; using Volo.Abp.DependencyInjection; namespace Volo.Abp.Cli.Commands; public class SwitchToLocal : IConsoleCommand, ITransientDependency { + private readonly LocalReferenceConverter _localReferenceConverter; public const string Name = "switch-to-local"; public ILogger Logger { get; set; } + public SwitchToLocal(LocalReferenceConverter localReferenceConverter) + { + _localReferenceConverter = localReferenceConverter; + } + public async Task ExecuteAsync(CommandLineArgs commandLineArgs) { var workingDirectory = GetWorkingDirectory(commandLineArgs) ?? Directory.GetCurrentDirectory(); @@ -29,8 +36,8 @@ public class SwitchToLocal : IConsoleCommand, ITransientDependency ); } - var paths = GetPaths(commandLineArgs); - + await _localReferenceConverter.ConvertAsync(workingDirectory, GetPaths(commandLineArgs)); + } private List GetPaths(CommandLineArgs commandLineArgs) @@ -74,7 +81,8 @@ public class SwitchToLocal : IConsoleCommand, ITransientDependency public string GetShortDescription() { - return "Bundles all third party styles and scripts required by modules and updates index.html file."; + return "Changes all NuGet package references to local project references for all the .csproj files in the specified folder" + + " (and all its subfolders with any deep)"; } public string GetUsageInfo() @@ -88,9 +96,14 @@ public class SwitchToLocal : IConsoleCommand, ITransientDependency sb.AppendLine(""); sb.AppendLine("Options:"); sb.AppendLine(""); - sb.AppendLine("-s|--solution (default: current directory)"); - sb.AppendLine("-p | --paths (Required)"); + sb.AppendLine("-s |--solution (default: current directory)"); + sb.AppendLine("-p | --paths (Required)"); + sb.AppendLine(""); + sb.AppendLine("Examples:"); sb.AppendLine(""); + sb.AppendLine(" abp switch-to-local --paths D:\\Github\\abp"); + sb.AppendLine(" abp switch-to-local --paths D:\\Github\\abp --solution D:\\test\\MyProject"); + sb.AppendLine(" abp switch-to-local --paths \"D:\\Github\\abp|D:\\Github\\volo\""); sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI"); return sb.ToString(); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/LocalReferenceConverter.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/LocalReferenceConverter.cs new file mode 100644 index 0000000000..b76ac9ef5f --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/LocalReferenceConverter.cs @@ -0,0 +1,109 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; +using JetBrains.Annotations; +using Microsoft.Extensions.Logging; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Cli.ProjectModification; + +public class LocalReferenceConverter : ITransientDependency +{ + + public ILogger Logger { get; set; } + + public async Task ConvertAsync( + [NotNull] string directory, + [NotNull] List localPaths) + { + Check.NotNull(directory, nameof(directory)); + Check.NotNull(localPaths, nameof(localPaths)); + + var localProjects = GetLocalProjects(localPaths); + var targetProjects = Directory.GetFiles(directory, "*.csproj", SearchOption.AllDirectories); + + Logger.LogInformation($"Converting projects to local reference."); + + foreach (var targetProject in targetProjects) + { + Logger.LogInformation($"Converting to local reference: {targetProject}"); + + await ConvertProjectToLocalReferences(targetProject, localProjects); + } + + Logger.LogInformation($"Converted {targetProjects.Length} projects to local references."); + } + + private async Task ConvertProjectToLocalReferences(string targetProject, LocalProjectList localProjects) + { + var xmlDocument = new XmlDocument() { PreserveWhitespace = true }; + xmlDocument.Load(GenerateStreamFromString(File.ReadAllText(targetProject))); + + var matchedNodes = xmlDocument.SelectNodes($"/Project/ItemGroup/PackageReference[@Include]"); + + if (matchedNodes == null || matchedNodes.Count == 0) + { + return; + } + + foreach (XmlNode matchedNode in matchedNodes) + { + var packageName = matchedNode!.Attributes!["Include"].Value; + + var localProject = localProjects.GetByName(packageName); + + if (localProject == null) + { + continue; + } + + var parentNode = matchedNode.ParentNode; + parentNode!.RemoveChild(matchedNode); + + var newNode = xmlDocument.CreateElement("ProjectReference"); + var includeAttr = xmlDocument.CreateAttribute("Include"); + includeAttr.Value = localProject; + newNode.Attributes.Append(includeAttr); + parentNode.AppendChild(newNode); + } + + File.WriteAllText(targetProject, XDocument.Parse(xmlDocument.OuterXml).ToString()); + } + + private LocalProjectList GetLocalProjects(List localPaths) + { + var list = new LocalProjectList(); + + foreach (var localPath in localPaths) + { + if (!Directory.Exists(localPath)) + { + continue; + } + + list.AddRange(Directory.GetFiles(localPath, "*.csproj", SearchOption.AllDirectories)); + } + + return list; + } + + private MemoryStream GenerateStreamFromString(string s) + { + var stream = new MemoryStream(); + var writer = new StreamWriter(stream); + writer.Write(s); + writer.Flush(); + stream.Position = 0; + return stream; + } + + private class LocalProjectList : List + { + public string GetByName(string projectName) + { + return Find(x => x.EndsWith($"{projectName}.csproj") || x.EndsWith(projectName)); + } + } +}