mirror of https://github.com/abpframework/abp.git
committed by
GitHub
17 changed files with 588 additions and 102 deletions
@ -0,0 +1,82 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using ICSharpCode.SharpZipLib.Core; |
|||
using ICSharpCode.SharpZipLib.Zip; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Volo.Abp.Cli.Args; |
|||
using Volo.Abp.Cli.ProjectBuilding; |
|||
using Volo.Abp.Cli.ProjectBuilding.Building; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Cli.Commands.Services |
|||
{ |
|||
public class SourceCodeDownloadService : ITransientDependency |
|||
{ |
|||
public ModuleProjectBuilder ModuleProjectBuilder { get; } |
|||
public ILogger<SourceCodeDownloadService> Logger { get; set; } |
|||
|
|||
public SourceCodeDownloadService(ModuleProjectBuilder moduleProjectBuilder) |
|||
{ |
|||
ModuleProjectBuilder = moduleProjectBuilder; |
|||
Logger = NullLogger<SourceCodeDownloadService>.Instance; |
|||
} |
|||
|
|||
public async Task DownloadAsync(string moduleName, string outputFolder, string version, string gitHubLocalRepositoryPath, AbpCommandLineOptions options) |
|||
{ |
|||
Logger.LogInformation("Downloading source code of " + moduleName); |
|||
Logger.LogInformation("Version: " + version); |
|||
Logger.LogInformation("Output folder: " + outputFolder); |
|||
|
|||
var result = await ModuleProjectBuilder.BuildAsync( |
|||
new ProjectBuildArgs( |
|||
SolutionName.Parse(moduleName), |
|||
moduleName, |
|||
version, |
|||
DatabaseProvider.NotSpecified, |
|||
UiFramework.NotSpecified, |
|||
gitHubLocalRepositoryPath, |
|||
options |
|||
) |
|||
); |
|||
|
|||
using (var templateFileStream = new MemoryStream(result.ZipContent)) |
|||
{ |
|||
using (var zipInputStream = new ZipInputStream(templateFileStream)) |
|||
{ |
|||
var zipEntry = zipInputStream.GetNextEntry(); |
|||
while (zipEntry != null) |
|||
{ |
|||
var fullZipToPath = Path.Combine(outputFolder, zipEntry.Name); |
|||
var directoryName = Path.GetDirectoryName(fullZipToPath); |
|||
|
|||
if (!string.IsNullOrEmpty(directoryName)) |
|||
{ |
|||
Directory.CreateDirectory(directoryName); |
|||
} |
|||
|
|||
var fileName = Path.GetFileName(fullZipToPath); |
|||
if (fileName.Length == 0) |
|||
{ |
|||
zipEntry = zipInputStream.GetNextEntry(); |
|||
continue; |
|||
} |
|||
|
|||
var buffer = new byte[4096]; // 4K is optimum
|
|||
using (var streamWriter = File.Create(fullZipToPath)) |
|||
{ |
|||
StreamUtils.Copy(zipInputStream, streamWriter, buffer); |
|||
} |
|||
|
|||
zipEntry = zipInputStream.GetNextEntry(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
Logger.LogInformation($"'{moduleName}' has been successfully downloaded to '{outputFolder}'"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Text.RegularExpressions; |
|||
using System.Xml; |
|||
using Volo.Abp.Cli.ProjectBuilding.Files; |
|||
using Volo.Abp.Cli.Utils; |
|||
|
|||
namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps |
|||
{ |
|||
public class ReplaceConfigureAwaitPropsStep : ProjectBuildPipelineStep |
|||
{ |
|||
public override void Execute(ProjectBuildContext context) |
|||
{ |
|||
new ConfigureAwaitPropsReplacer(context.Files).Run(); |
|||
} |
|||
|
|||
private class ConfigureAwaitPropsReplacer |
|||
{ |
|||
private readonly List<FileEntry> _entries; |
|||
|
|||
public ConfigureAwaitPropsReplacer( |
|||
List<FileEntry> entries) |
|||
{ |
|||
_entries = entries; |
|||
} |
|||
|
|||
public void Run() |
|||
{ |
|||
foreach (var fileEntry in _entries) |
|||
{ |
|||
if (fileEntry.Name.EndsWith(".csproj")) |
|||
{ |
|||
fileEntry.SetContent(ProcessFileContent(fileEntry.Content)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private string ProcessFileContent(string content) |
|||
{ |
|||
Check.NotNull(content, nameof(content)); |
|||
|
|||
var doc = new XmlDocument() { PreserveWhitespace = true }; |
|||
|
|||
doc.Load(StreamHelper.GenerateStreamFromString(content)); |
|||
|
|||
return ProcessReferenceNodes(doc, content); |
|||
} |
|||
|
|||
private string ProcessReferenceNodes(XmlDocument doc, string content) |
|||
{ |
|||
Check.NotNull(content, nameof(content)); |
|||
|
|||
var importNodes = doc.SelectNodes("/Project/Import[@Project]"); |
|||
|
|||
if (importNodes == null) |
|||
{ |
|||
return doc.OuterXml; |
|||
} |
|||
|
|||
foreach (XmlNode node in importNodes) |
|||
{ |
|||
if (!(node.Attributes?["Project"]?.Value?.EndsWith("\\configureawait.props") ?? false)) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
node.ParentNode?.RemoveChild(node); |
|||
} |
|||
|
|||
return doc.OuterXml; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.Cli.ProjectModification |
|||
{ |
|||
public class ModuleWithMastersInfo : ModuleInfo |
|||
{ |
|||
public List<ModuleWithMastersInfo> MasterModuleInfos { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,127 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using System.Xml; |
|||
using Volo.Abp.Cli.Utils; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Cli.ProjectModification |
|||
{ |
|||
public class NugetPackageToLocalReferenceConverter : ITransientDependency |
|||
{ |
|||
public async Task Convert(ModuleWithMastersInfo module, string solutionFile) |
|||
{ |
|||
var nugetPackageList = GetNugetPackages(module); |
|||
|
|||
var projectFilesUnderModules = GetProjectFilesUnder(Path.Combine(Path.GetDirectoryName(solutionFile), "modules")); |
|||
var projectFilesUnderSrc = GetProjectFilesUnder(Path.Combine(Path.GetDirectoryName(solutionFile), "src")); |
|||
var projectFilesUnderTest = GetProjectFilesUnder(Path.Combine(Path.GetDirectoryName(solutionFile), "test")); |
|||
|
|||
foreach (var projectFile in projectFilesUnderModules) |
|||
{ |
|||
ConvertToLocalReference(projectFile, nugetPackageList, "..\\..\\..\\"); |
|||
} |
|||
foreach (var projectFile in projectFilesUnderSrc) |
|||
{ |
|||
ConvertToLocalReference(projectFile, nugetPackageList, "..\\..\\modules\\"); |
|||
} |
|||
foreach (var projectFile in projectFilesUnderTest) |
|||
{ |
|||
ConvertToLocalReference(projectFile, nugetPackageList, "..\\..\\modules\\", "test"); |
|||
} |
|||
} |
|||
|
|||
private void ConvertToLocalReference(string projectFile, List<NugetPackageInfoWithModuleName> nugetPackageList, string localPathPrefix, string sourceFile = "src") |
|||
{ |
|||
var content = File.ReadAllText(projectFile); |
|||
var doc = new XmlDocument() { PreserveWhitespace = true }; |
|||
|
|||
doc.Load(StreamHelper.GenerateStreamFromString(content)); |
|||
|
|||
var convertedProject = ProcessReferenceNodes(doc, nugetPackageList, localPathPrefix, sourceFile); |
|||
|
|||
File.WriteAllText(projectFile, convertedProject); |
|||
} |
|||
|
|||
|
|||
private string ProcessReferenceNodes(XmlDocument doc, List<NugetPackageInfoWithModuleName> nugetPackageList, string localPathPrefix, string sourceFile = "src") |
|||
{ |
|||
var nodes = doc.SelectNodes("/Project/ItemGroup/PackageReference[@Include]"); |
|||
|
|||
if (nodes == null) |
|||
{ |
|||
return doc.OuterXml; |
|||
} |
|||
|
|||
foreach (XmlNode oldNode in nodes) |
|||
{ |
|||
var oldNodeIncludeValue = oldNode?.Attributes?["Include"]?.Value; |
|||
|
|||
var nugetPackage = nugetPackageList.FirstOrDefault(n => n.NugetPackage.Name == oldNodeIncludeValue); |
|||
|
|||
if (nugetPackage == null) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
var referenceProjectPath = |
|||
$"{localPathPrefix}{nugetPackage.ModuleName}\\{sourceFile}\\{nugetPackage.NugetPackage.Name}\\{nugetPackage.NugetPackage.Name}.csproj"; |
|||
|
|||
XmlNode newNode = GetNewReferenceNode(doc, referenceProjectPath); |
|||
|
|||
oldNode?.ParentNode?.ReplaceChild(newNode, oldNode); |
|||
} |
|||
|
|||
return doc.OuterXml; |
|||
} |
|||
|
|||
protected XmlElement GetNewReferenceNode(XmlDocument doc, string newValue) |
|||
{ |
|||
var newNode = doc.CreateElement("ProjectReference"); |
|||
|
|||
var includeAttr = doc.CreateAttribute("Include"); |
|||
includeAttr.Value = newValue; |
|||
newNode.Attributes.Append(includeAttr); |
|||
|
|||
return newNode; |
|||
} |
|||
|
|||
public List<NugetPackageInfoWithModuleName> GetNugetPackages(ModuleWithMastersInfo module) |
|||
{ |
|||
var list = new List<NugetPackageInfoWithModuleName>(); |
|||
|
|||
list.AddRange(module.NugetPackages.Select(n => new NugetPackageInfoWithModuleName |
|||
{ |
|||
ModuleName = module.Name, |
|||
NugetPackage = n |
|||
})); |
|||
|
|||
if (module.MasterModuleInfos != null) |
|||
{ |
|||
foreach (var masterModule in module.MasterModuleInfos) |
|||
{ |
|||
list.AddRange(GetNugetPackages(masterModule)); |
|||
} |
|||
} |
|||
|
|||
return list; |
|||
} |
|||
|
|||
private static string[] GetProjectFilesUnder(string path) |
|||
{ |
|||
return Directory.GetFiles(path, |
|||
"*.csproj", |
|||
SearchOption.AllDirectories); |
|||
} |
|||
|
|||
public class NugetPackageInfoWithModuleName |
|||
{ |
|||
public NugetPackageInfo NugetPackage { get; set; } |
|||
|
|||
public string ModuleName { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
using System.IO; |
|||
using System.Xml; |
|||
using Volo.Abp.Cli.Utils; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Cli.ProjectModification |
|||
{ |
|||
public class SolutionAbpVersionFinder : ITransientDependency |
|||
{ |
|||
public string Find(string solutionFile) |
|||
{ |
|||
var projectFilesUnderSrc = Directory.GetFiles(Path.GetDirectoryName(solutionFile), |
|||
"*.csproj", |
|||
SearchOption.AllDirectories); |
|||
|
|||
foreach (var projectFile in projectFilesUnderSrc) |
|||
{ |
|||
var content = File.ReadAllText(projectFile); |
|||
var doc = new XmlDocument() { PreserveWhitespace = true }; |
|||
|
|||
doc.Load(StreamHelper.GenerateStreamFromString(content)); |
|||
|
|||
var nodes = doc.SelectNodes("/Project/ItemGroup/PackageReference[starts-with(@Include, 'Volo.Abp')]"); |
|||
|
|||
var value = nodes?[0]?.Attributes?["Version"]?.Value; |
|||
|
|||
if (value != null) |
|||
{ |
|||
return value; |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,117 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Cli.ProjectModification |
|||
{ |
|||
public class SolutionFileModifier : ITransientDependency |
|||
{ |
|||
public async Task AddModuleToSolutionFileAsync(ModuleWithMastersInfo module, string solutionFile) |
|||
{ |
|||
await AddModule(module, solutionFile); |
|||
} |
|||
|
|||
private async Task AddModule(ModuleWithMastersInfo module, string solutionFile) |
|||
{ |
|||
var srcModuleFolderId = await AddNewFolderAndGetIdOrGetExistingId(solutionFile, module.Name, await AddNewFolderAndGetIdOrGetExistingId(solutionFile, "modules")); |
|||
var testModuleFolderId = await AddNewFolderAndGetIdOrGetExistingId(solutionFile, module.Name + ".Tests", await AddNewFolderAndGetIdOrGetExistingId(solutionFile, "test")); |
|||
|
|||
var file = File.ReadAllText(solutionFile); |
|||
var lines = file.Split(Environment.NewLine).ToList(); |
|||
|
|||
|
|||
var projectsUnderModule = Directory.GetFiles( |
|||
Path.Combine(Path.GetDirectoryName(solutionFile), "modules", module.Name), |
|||
"*.csproj", |
|||
SearchOption.AllDirectories); |
|||
|
|||
var projectsUnderTest = Directory.GetFiles( |
|||
Path.Combine(Path.GetDirectoryName(solutionFile), "modules", module.Name, "test"), |
|||
"*.csproj", |
|||
SearchOption.AllDirectories); |
|||
|
|||
foreach (var projectPath in projectsUnderModule) |
|||
{ |
|||
var parentFolderId = projectsUnderTest.Contains(projectPath) ? testModuleFolderId : srcModuleFolderId; |
|||
var projectId = Path.GetFileName(projectPath).Replace(".csproj",""); |
|||
var projectParentFolderInModule = projectsUnderTest.Contains(projectPath) ? "test" : "src"; |
|||
|
|||
if (lines.Any(l => l.Contains($"\"{projectId}\""))) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
var projectGuid = Guid.NewGuid().ToString(); |
|||
|
|||
var newProjectLine = "Project(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"" + projectId + "\"," + |
|||
" \"modules\\" + module.Name + "\\"+ projectParentFolderInModule + "\\" + projectId + "\\" + projectId + ".csproj\", \"{" + projectGuid + "}\"" |
|||
+ Environment.NewLine + "EndProject"; |
|||
|
|||
lines.InsertAfter(l => l.Trim().Equals("EndProject"), newProjectLine); |
|||
|
|||
var newPostSolutionLine = |
|||
" {" + projectGuid + "}.Debug|Any CPU.ActiveCfg = Debug|Any CPU" + Environment.NewLine + |
|||
" {" + projectGuid + "}.Debug|Any CPU.Build.0 = Debug|Any CPU" + Environment.NewLine + |
|||
" {" + projectGuid + "}.Release|Any CPU.ActiveCfg = Release|Any CPU" + Environment.NewLine + |
|||
" {" + projectGuid + "}.Release|Any CPU.Build.0 = Release|Any CPU"; |
|||
|
|||
lines.InsertAfter(l=>l.Contains("GlobalSection") && l.Contains("ProjectConfigurationPlatforms"), newPostSolutionLine); |
|||
|
|||
var newPreSolutionLine = |
|||
" {"+ projectGuid + "} = {"+ parentFolderId + "}"; |
|||
|
|||
lines.InsertAfter(l=>l.Contains("GlobalSection") && l.Contains("NestedProjects"), newPreSolutionLine); |
|||
} |
|||
|
|||
File.WriteAllText(solutionFile, string.Join(Environment.NewLine, lines)); |
|||
|
|||
if (module.MasterModuleInfos != null) |
|||
{ |
|||
foreach (var masterModule in module.MasterModuleInfos) |
|||
{ |
|||
await AddModule(masterModule, solutionFile); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private async Task<string> AddNewFolderAndGetIdOrGetExistingId(string solutionFile, string folderName, string parentFolderId = null) |
|||
{ |
|||
var file = File.ReadAllText(solutionFile); |
|||
var lines = file.Split(Environment.NewLine).ToList(); |
|||
string folderId; |
|||
|
|||
var folderLineIndex = lines.FindIndex(l => |
|||
l.Contains("2150E333-8FDC-42A3-9474-1A3956D46DE8") && l.Contains("\""+ folderName + "\"")); |
|||
|
|||
if (folderLineIndex < 0) |
|||
{ |
|||
folderId = Guid.NewGuid().ToString(); |
|||
var newFolderLine = "Project(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \""+ folderName + "\", \""+ folderName + "\", \"{" + folderId + "}\"" |
|||
+ Environment.NewLine + "EndProject"; |
|||
|
|||
lines.InsertAfter(l => l.Trim().Equals("EndProject"), newFolderLine); |
|||
|
|||
if (parentFolderId != null) |
|||
{ |
|||
var newPreSolutionLine = |
|||
" {" + folderId + "} = {" + parentFolderId + "}"; |
|||
|
|||
lines.InsertAfter(l => l.Contains("GlobalSection") && l.Contains("NestedProjects"), newPreSolutionLine); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
folderId = lines[folderLineIndex].Replace("\"", " ").Replace("{", " ").Replace("}", " ").TrimEnd() |
|||
.Split(" ").Last(); |
|||
} |
|||
|
|||
File.WriteAllText(solutionFile, string.Join(Environment.NewLine, lines)); |
|||
|
|||
return folderId; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Text; |
|||
|
|||
namespace Volo.Abp.Cli.Utils |
|||
{ |
|||
public static class StreamHelper |
|||
{ |
|||
public static Stream GenerateStreamFromString(string s) |
|||
{ |
|||
var stream = new MemoryStream(); |
|||
var writer = new StreamWriter(stream); |
|||
writer.Write(s); |
|||
writer.Flush(); |
|||
stream.Position = 0; |
|||
return stream; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue