Browse Source

Linking module source-code improvements

pull/2926/head
Yunus Emre Kalkan 7 years ago
parent
commit
d7a7802ce2
  1. 11
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs
  2. 81
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs
  3. 82
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs
  4. 9
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ModuleWithMastersInfo.cs
  5. 117
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionFileModifier.cs
  6. 60
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs

11
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs

@ -37,11 +37,15 @@ namespace Volo.Abp.Cli.Commands
var skipDbMigrations = Convert.ToBoolean(
commandLineArgs.Options.GetOrNull(Options.DbMigrations.Skip) ?? "false");
var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long);
await SolutionModuleAdder.AddAsync(
GetSolutionFile(commandLineArgs),
commandLineArgs.Target,
commandLineArgs.Options.GetOrNull(Options.StartupProject.Short, Options.StartupProject.Long),
skipDbMigrations
version,
skipDbMigrations,
commandLineArgs.Options.ContainsKey("with-source-code")
);
}
@ -126,6 +130,11 @@ namespace Volo.Abp.Cli.Commands
public const string Short = "s";
public const string Long = "solution";
}
public static class Version
{
public const string Short = "v";
public const string Long = "version";
}
public static class DbMigrations
{

81
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs

@ -7,6 +7,7 @@ using ICSharpCode.SharpZipLib.Zip;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Commands.Services;
using Volo.Abp.Cli.ProjectBuilding;
using Volo.Abp.Cli.ProjectBuilding.Building;
using Volo.Abp.DependencyInjection;
@ -15,12 +16,14 @@ namespace Volo.Abp.Cli.Commands
{
public class GetSourceCommand : IConsoleCommand, ITransientDependency
{
private readonly SourceCodeDownloadService _sourceCodeDownloadService;
public ModuleProjectBuilder ModuleProjectBuilder { get; }
public ILogger<NewCommand> Logger { get; set; }
public GetSourceCommand(ModuleProjectBuilder moduleProjectBuilder)
public GetSourceCommand(ModuleProjectBuilder moduleProjectBuilder, SourceCodeDownloadService sourceCodeDownloadService)
{
_sourceCodeDownloadService = sourceCodeDownloadService;
ModuleProjectBuilder = moduleProjectBuilder;
Logger = NullLogger<NewCommand>.Instance;
}
@ -36,29 +39,13 @@ namespace Volo.Abp.Cli.Commands
);
}
Logger.LogInformation("Downloading source code of " + commandLineArgs.Target);
var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long);
if (version != null)
{
Logger.LogInformation("Version: " + version);
}
var outputFolder = commandLineArgs.Options.GetOrNull(Options.OutputFolder.Short, Options.OutputFolder.Long);
if (outputFolder != null)
{
if (!Directory.Exists(outputFolder))
{
Directory.CreateDirectory(outputFolder);
}
outputFolder = Path.GetFullPath(outputFolder);
}
else
{
outputFolder = Directory.GetCurrentDirectory();
}
var outputFolder = GetOutPutFolder(commandLineArgs);
Logger.LogInformation("Output folder: " + outputFolder);
var gitHubLocalRepositoryPath = commandLineArgs.Options.GetOrNull(Options.GitHubLocalRepositoryPath.Long);
@ -69,52 +56,28 @@ namespace Volo.Abp.Cli.Commands
commandLineArgs.Options.Add(CliConsts.Command, commandLineArgs.Command);
var result = await ModuleProjectBuilder.BuildAsync(
new ProjectBuildArgs(
SolutionName.Parse(commandLineArgs.Target),
commandLineArgs.Target,
version,
DatabaseProvider.NotSpecified,
UiFramework.NotSpecified,
gitHubLocalRepositoryPath,
commandLineArgs.Options
)
);
using (var templateFileStream = new MemoryStream(result.ZipContent))
await _sourceCodeDownloadService.DownloadAsync(
commandLineArgs.Target, outputFolder, version, gitHubLocalRepositoryPath, commandLineArgs.Options);
}
private static string GetOutPutFolder(CommandLineArgs commandLineArgs)
{
var outputFolder = commandLineArgs.Options.GetOrNull(Options.OutputFolder.Short, Options.OutputFolder.Long);
if (outputFolder != null)
{
using (var zipInputStream = new ZipInputStream(templateFileStream))
if (!Directory.Exists(outputFolder))
{
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();
}
Directory.CreateDirectory(outputFolder);
}
outputFolder = Path.GetFullPath(outputFolder);
}
else
{
outputFolder = Directory.GetCurrentDirectory();
}
Logger.LogInformation($"'{commandLineArgs.Target}' has been successfully downloaded to '{outputFolder}'");
return outputFolder;
}
public string GetUsageInfo()

82
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs

@ -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}'");
}
}
}

9
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ModuleWithMastersInfo.cs

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Volo.Abp.Cli.ProjectModification
{
public class ModuleWithMastersInfo : ModuleInfo
{
public List<ModuleWithMastersInfo> MasterModuleInfos { get; set; }
}
}

117
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionFileModifier.cs

@ -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;
}
}
}

60
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs

@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Volo.Abp.Cli.Commands.Services;
using Volo.Abp.Cli.Http;
using Volo.Abp.Cli.ProjectBuilding;
using Volo.Abp.DependencyInjection;
@ -26,6 +27,8 @@ namespace Volo.Abp.Cli.ProjectModification
protected ProjectNpmPackageAdder ProjectNpmPackageAdder { get; }
protected NpmGlobalPackagesChecker NpmGlobalPackagesChecker { get; }
protected IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; }
public SourceCodeDownloadService SourceCodeDownloadService { get; }
public SolutionFileModifier SolutionFileModifier { get; }
public SolutionModuleAdder(
IJsonSerializer jsonSerializer,
@ -35,7 +38,9 @@ namespace Volo.Abp.Cli.ProjectModification
DerivedClassFinder derivedClassFinder,
ProjectNpmPackageAdder projectNpmPackageAdder,
NpmGlobalPackagesChecker npmGlobalPackagesChecker,
IRemoteServiceExceptionHandler remoteServiceExceptionHandler)
IRemoteServiceExceptionHandler remoteServiceExceptionHandler,
SourceCodeDownloadService sourceCodeDownloadService,
SolutionFileModifier solutionFileModifier)
{
JsonSerializer = jsonSerializer;
ProjectNugetPackageAdder = projectNugetPackageAdder;
@ -45,6 +50,8 @@ namespace Volo.Abp.Cli.ProjectModification
ProjectNpmPackageAdder = projectNpmPackageAdder;
NpmGlobalPackagesChecker = npmGlobalPackagesChecker;
RemoteServiceExceptionHandler = remoteServiceExceptionHandler;
SourceCodeDownloadService = sourceCodeDownloadService;
SolutionFileModifier = solutionFileModifier;
Logger = NullLogger<SolutionModuleAdder>.Instance;
}
@ -52,7 +59,9 @@ namespace Volo.Abp.Cli.ProjectModification
[NotNull] string solutionFile,
[NotNull] string moduleName,
string startupProject,
bool skipDbMigrations = false)
string version,
bool skipDbMigrations = false,
bool withSourceCode = false)
{
Check.NotNull(solutionFile, nameof(solutionFile));
Check.NotNull(moduleName, nameof(moduleName));
@ -63,6 +72,41 @@ namespace Volo.Abp.Cli.ProjectModification
var projectFiles = ProjectFinder.GetProjectFiles(solutionFile);
await AddNugetAndNpmReferences(module, projectFiles);
if (withSourceCode)
{
var modulesFolderInSolution = Path.Combine(Path.GetDirectoryName(solutionFile), "modules");
await DownloadSourceCodesToSolutionFolder(module, modulesFolderInSolution, version);
await SolutionFileModifier.AddModuleToSolutionFileAsync(module, solutionFile);
}
ModifyDbContext(projectFiles, module, startupProject, skipDbMigrations);
}
private async Task DownloadSourceCodesToSolutionFolder(ModuleWithMastersInfo module, string modulesFolderInSolution, string version = null)
{
await SourceCodeDownloadService.DownloadAsync(
module.Name,
Path.Combine(modulesFolderInSolution, module.Name),
version,
null,
null
);
if (module.MasterModuleInfos == null)
{
return;
}
foreach (var masterModule in module.MasterModuleInfos)
{
await DownloadSourceCodesToSolutionFolder(masterModule, modulesFolderInSolution, version);
}
}
private async Task AddNugetAndNpmReferences(ModuleWithMastersInfo module, string[] projectFiles)
{
foreach (var nugetPackage in module.NugetPackages)
{
var targetProjectFile = ProjectFinder.FindNuGetTargetProjectFile(projectFiles, nugetPackage.Target);
@ -84,7 +128,8 @@ namespace Volo.Abp.Cli.ProjectModification
foreach (var targetProject in targetProjects)
{
foreach (var npmPackage in module.NpmPackages.Where(p => p.ApplicationType.HasFlag(NpmApplicationType.Mvc)))
foreach (var npmPackage in module.NpmPackages.Where(p =>
p.ApplicationType.HasFlag(NpmApplicationType.Mvc)))
{
await ProjectNpmPackageAdder.AddAsync(Path.GetDirectoryName(targetProject), npmPackage);
}
@ -95,8 +140,6 @@ namespace Volo.Abp.Cli.ProjectModification
Logger.LogDebug("Target project is not available for NPM packages.");
}
}
ModifyDbContext(projectFiles, module, startupProject, skipDbMigrations);
}
protected void ModifyDbContext(string[] projectFiles, ModuleInfo module, string startupProject, bool skipDbMigrations = false)
@ -129,18 +172,17 @@ namespace Volo.Abp.Cli.ProjectModification
DbContextFileBuilderConfigureAdder.Add(dbContextFile, module.EfCoreConfigureMethodName);
if (!skipDbMigrations)
{
EfCoreMigrationAdder.AddMigration(dbMigrationsProject, module.Name, startupProject);
}
}
protected virtual async Task<ModuleInfo> FindModuleInfoAsync(string moduleName)
protected virtual async Task<ModuleWithMastersInfo> FindModuleInfoAsync(string moduleName)
{
using (var client = new CliHttpClient())
{
var url = $"{CliUrls.WwwAbpIo}api/app/module/byName/?name=" + moduleName;
var url = $"{CliUrls.WwwAbpIo}api/app/module/byNameWithDetails/?name=" + moduleName;
var response = await client.GetAsync(url);
@ -155,7 +197,7 @@ namespace Volo.Abp.Cli.ProjectModification
}
var responseContent = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<ModuleInfo>(responseContent);
return JsonSerializer.Deserialize<ModuleWithMastersInfo>(responseContent);
}
}
}

Loading…
Cancel
Save