From c6ebca1857e9d4113a52480259526ba1ed1c14d1 Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Mon, 2 Nov 2020 15:50:24 +0300 Subject: [PATCH] Create a new module inside the solution --- docs/en/CLI.md | 18 +- .../Volo/Abp/Cli/Commands/AddModuleCommand.cs | 29 ++- .../NugetPackageToLocalReferenceConverter.cs | 16 +- .../ProjectNugetPackageAdder.cs | 77 ++++++- .../SolutionFileModifier.cs | 14 +- .../SolutionModuleAdder.cs | 188 +++++++++++++++--- 6 files changed, 285 insertions(+), 57 deletions(-) diff --git a/docs/en/CLI.md b/docs/en/CLI.md index 8713bc9019..ccd6a00661 100644 --- a/docs/en/CLI.md +++ b/docs/en/CLI.md @@ -159,6 +159,8 @@ abp add-package Volo.Abp.MongoDB Adds a [multi-package application module](Modules/Index) to a solution by finding all packages of the module, finding related projects in the solution and adding each package to the corresponding project in the solution. +It can also create a fresh new module for your solution and add it to your solution. See `--new-template` option. + > A business module generally consists of several packages (because of layering, different database provider options or other reasons). Using `add-module` command dramatically simplifies adding a module to a solution. However, each module may require some additional configurations which is generally indicated in the documentation of the related module. Usage @@ -167,21 +169,29 @@ Usage abp add-module [options] ```` -Example: +Examples: ```bash abp add-module Volo.Blogging ``` -* This example add the Volo.Blogging module to the solution. +* This example adds the `Volo.Blogging` module to the solution. + +```bash +abp add-module ProductManagement --new-template --add-to-solution-file +``` + +* This example creates a fresh new module specialized for your solution (named `ProductManagement`) and adds it to your solution & solution file. + #### Options * `--solution` or `-s`: Specifies the solution (.sln) file path. If not specified, CLI tries to find a .sln file in the current directory. * `--skip-db-migrations`: For EF Core database provider, it automatically adds a new code first migration (`Add-Migration`) and updates the database (`Update-Database`) if necessary. Specify this option to skip this operation. * `-sp` or `--startup-project`: Relative path to the project folder of the startup project. Default value is the current folder. -* `--with-source-code`: Downloads the source code of the module to your solution folder and uses local project references instead of NuGet/NPM packages. -* `--add-to-solution-file`: Adds the downloaded module to your solution file, so you will also see the projects of the module when you open the solution on a IDE. (only available when `--with-source-code` is used.) +* `--new-template`: Creates a fresh new module (speсialized for your solution) and adds it to your solution. +* `--with-source-code`: Downloads the source code of the module to your solution folder and uses local project references instead of NuGet/NPM packages. This options is always `True` if `--new-template` is used. +* `--add-to-solution-file`: Adds the downloaded/created module to your solution file, so you will also see the projects of the module when you open the solution on a IDE. (only available when `--with-source-code` is `True`.) ### get-source diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs index 42a8d76b98..5b4180d989 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddModuleCommand.cs @@ -36,10 +36,12 @@ namespace Volo.Abp.Cli.Commands ); } - var withSourceCode = commandLineArgs.Options.ContainsKey(Options.SourceCode.Long); + var newTemplate = commandLineArgs.Options.ContainsKey(Options.NewTemplate.Long); + var newProTemplate = commandLineArgs.Options.ContainsKey(Options.NewProTemplate.Long); + var withSourceCode = newTemplate || newProTemplate || commandLineArgs.Options.ContainsKey(Options.SourceCode.Long); var addSourceCodeToSolutionFile = withSourceCode && commandLineArgs.Options.ContainsKey("add-to-solution-file"); - var skipDbMigrations = Convert.ToBoolean( + var skipDbMigrations = newTemplate || newProTemplate || Convert.ToBoolean( commandLineArgs.Options.GetOrNull(Options.DbMigrations.Skip) ?? "false"); var solutionFile = GetSolutionFile(commandLineArgs); @@ -57,7 +59,9 @@ namespace Volo.Abp.Cli.Commands version, skipDbMigrations, withSourceCode, - addSourceCodeToSolutionFile + addSourceCodeToSolutionFile, + newTemplate, + newProTemplate ); } @@ -73,10 +77,11 @@ namespace Volo.Abp.Cli.Commands sb.AppendLine(" abp add-module [options]"); sb.AppendLine(""); sb.AppendLine("Options:"); - sb.AppendLine(" --with-source-code Downloads the source code of the module to your solution folder."); - sb.AppendLine(" --add-to-solution-file Adds the downloaded module to your solution file. (only available when --with-source-code used)"); + sb.AppendLine(" --new-template Creates a fresh new module (speсialized for your solution) and adds it your solution."); + sb.AppendLine(" --with-source-code Downloads the source code of the module to your solution folder. (Always True if `--new-template` is used.)"); + sb.AppendLine(" --add-to-solution-file Adds the downloaded/created module to your solution file. (only available when --with-source-code used)"); sb.AppendLine(" -s|--solution Specify the solution file explicitly."); - sb.AppendLine(" --skip-db-migrations Specify if a new migration will be added or not."); + sb.AppendLine(" --skip-db-migrations Specify if a new migration will be added or not. (Always True if `--new-template` is used.)"); sb.AppendLine(" -sp|--startup-project Relative path to the project folder of the startup project. Default value is the current folder."); sb.AppendLine(" -v|--version Specify the version of the module. Default is your project's ABP version."); sb.AppendLine(""); @@ -86,6 +91,8 @@ namespace Volo.Abp.Cli.Commands sb.AppendLine(" abp add-module Volo.Blogging -s Acme.BookStore Adds the module to the given solution."); sb.AppendLine(" abp add-module Volo.Blogging -s Acme.BookStore --skip-db-migrations false Adds the module to the given solution but doesn't create a database migration."); sb.AppendLine(@" abp add-module Volo.Blogging -s Acme.BookStore -sp ..\Acme.BookStore.Web\Acme.BookStore.Web.csproj Adds the module to the given solution and specify migration startup project."); + sb.AppendLine(@" abp add-module ProductManagement --new-template -sp ..\Acme.BookStore.Web\Acme.BookStore.Web.csproj Crates a new module named `ProductManagement` and adds it to your solution."); + sb.AppendLine(@" abp add-module ProductManagement --new-template --add-to-solution-file -sp ..\Acme.BookStore.Web\Acme.BookStore.Web.csproj Crates a new module named `ProductManagement`, adds it to your solution & solution file."); sb.AppendLine(""); sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI"); @@ -166,6 +173,16 @@ namespace Volo.Abp.Cli.Commands { public const string Long = "with-source-code"; } + + public class NewTemplate + { + public const string Long = "new-template"; + } + + public class NewProTemplate + { + public const string Long = "new-pro-template"; + } } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NugetPackageToLocalReferenceConverter.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NugetPackageToLocalReferenceConverter.cs index d342e993d7..8e45378f72 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NugetPackageToLocalReferenceConverter.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NugetPackageToLocalReferenceConverter.cs @@ -12,19 +12,19 @@ namespace Volo.Abp.Cli.ProjectModification { public class NugetPackageToLocalReferenceConverter : ITransientDependency { - public async Task Convert(ModuleWithMastersInfo module, string solutionFile) + public async Task Convert(ModuleWithMastersInfo module, string solutionFile, string modulePrefix = "Volo.") { var nugetPackageList = GetNugetPackages(module); var modulesFolder = Path.Combine(Path.GetDirectoryName(solutionFile), "modules"); var srcFolder = Path.Combine(Path.GetDirectoryName(solutionFile), "src"); var testFolder = Path.Combine(Path.GetDirectoryName(solutionFile), "test"); - ConvertToLocalReference(modulesFolder, nugetPackageList, "..\\..\\..\\"); - ConvertToLocalReference(srcFolder, nugetPackageList, "..\\..\\modules\\"); - ConvertToLocalReference(testFolder, nugetPackageList, "..\\..\\modules\\", "test"); + ConvertToLocalReference(modulesFolder, nugetPackageList, "..\\..\\..\\", "src", modulePrefix); + ConvertToLocalReference(srcFolder, nugetPackageList, "..\\..\\modules\\", "src", modulePrefix); + ConvertToLocalReference(testFolder, nugetPackageList, "..\\..\\modules\\", "test", modulePrefix); } - private void ConvertToLocalReference(string folder, List nugetPackageList, string localPathPrefix, string sourceFile = "src") + private void ConvertToLocalReference(string folder, List nugetPackageList, string localPathPrefix, string sourceFile, string modulePrefix) { var projectFiles = GetProjectFilesUnder(folder); @@ -35,15 +35,15 @@ namespace Volo.Abp.Cli.ProjectModification doc.Load(StreamHelper.GenerateStreamFromString(content)); - var convertedProject = ProcessReferenceNodes(folder, doc, nugetPackageList, localPathPrefix, sourceFile); + var convertedProject = ProcessReferenceNodes(folder, doc, nugetPackageList, localPathPrefix, sourceFile, modulePrefix); File.WriteAllText(projectFile, convertedProject); } } - private string ProcessReferenceNodes(string folder, XmlDocument doc, List nugetPackageList, string localPathPrefix, string sourceFile = "src") + private string ProcessReferenceNodes(string folder, XmlDocument doc, List nugetPackageList, string localPathPrefix, string sourceFile, string modulePrefix) { - var nodes = doc.SelectNodes("/Project/ItemGroup/PackageReference[starts-with(@Include, 'Volo.')]"); + var nodes = doc.SelectNodes($"/Project/ItemGroup/PackageReference[starts-with(@Include, '{modulePrefix}')]"); if (nodes == null) { diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs index 5f1e18efbd..de25b11da7 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/ProjectNugetPackageAdder.cs @@ -50,7 +50,8 @@ namespace Volo.Abp.Cli.ProjectModification ); } - public Task AddAsync(string projectFile, NugetPackageInfo package, string version = null) + public Task AddAsync(string projectFile, NugetPackageInfo package, string version = null, + bool useDotnetCliToInstall = true) { var projectFileContent = File.ReadAllText(projectFile); @@ -66,21 +67,30 @@ namespace Volo.Abp.Cli.ProjectModification using (DirectoryHelper.ChangeCurrentDirectory(Path.GetDirectoryName(projectFile))) { - Logger.LogInformation($"Installing '{package.Name}' package to the project '{Path.GetFileNameWithoutExtension(projectFile)}'..."); + Logger.LogInformation( + $"Installing '{package.Name}' package to the project '{Path.GetFileNameWithoutExtension(projectFile)}'..."); - var versionOption = version == null ? "" : $" -v {version}"; - - CmdHelper.Run("dotnet", $"add package {package.Name}{versionOption}"); + if (useDotnetCliToInstall) + { + AddUsingDotnetCli(package, version); + } + else + { + AddToCsprojManuallyAsync(projectFile, package, version); + } var moduleFiles = ModuleClassFinder.Find(projectFile, "AbpModule"); if (moduleFiles.Count == 0) { - throw new CliUsageException($"Could not find a class derived from AbpModule in the project {projectFile}"); + throw new CliUsageException( + $"Could not find a class derived from AbpModule in the project {projectFile}"); } if (moduleFiles.Count > 1) { - throw new CliUsageException($"There are multiple classes derived from AbpModule in the project {projectFile}: " + moduleFiles.JoinAsString(", ")); + throw new CliUsageException( + $"There are multiple classes derived from AbpModule in the project {projectFile}: " + + moduleFiles.JoinAsString(", ")); } ModuleClassDependcyAdder.Add(moduleFiles.First(), package.ModuleClass); @@ -91,9 +101,60 @@ namespace Volo.Abp.Cli.ProjectModification return Task.CompletedTask; } + private Task AddUsingDotnetCli(NugetPackageInfo package, string version = null) + { + var versionOption = version == null ? "" : $" -v {version}"; + + CmdHelper.Run("dotnet", $"add package {package.Name}{versionOption}"); + + return Task.CompletedTask; + } + + private Task AddToCsprojManuallyAsync(string projectFile, NugetPackageInfo package, string version = null) + { + var projectFileContent = File.ReadAllText(projectFile); + var doc = new XmlDocument() {PreserveWhitespace = true}; + doc.Load(StreamHelper.GenerateStreamFromString(projectFileContent)); + + var itemGroupNodes = doc.SelectNodes("/Project/ItemGroup"); + XmlNode itemGroupNode = null; + + if (itemGroupNodes == null || itemGroupNodes.Count < 1) + { + var projectNodes = doc.SelectNodes("/Project"); + var projectNode = projectNodes[0]; + + itemGroupNode = doc.CreateElement("ItemGroup"); + projectNode.AppendChild(itemGroupNode); + } + else + { + itemGroupNode = itemGroupNodes[0]; + } + + var packageReferenceNode = doc.CreateElement("PackageReference"); + + var includeAttr = doc.CreateAttribute("Include"); + includeAttr.Value = package.Name; + packageReferenceNode.Attributes.Append(includeAttr); + + if (version != null) + { + var versionAttr = doc.CreateAttribute("Version"); + versionAttr.Value = version; + packageReferenceNode.Attributes.Append(versionAttr); + } + + itemGroupNode.AppendChild(packageReferenceNode); + + File.WriteAllText(projectFile, doc.OuterXml); + + return Task.CompletedTask; + } + private string GetAbpVersionOrNull(string projectFileContent) { - var doc = new XmlDocument() { PreserveWhitespace = true }; + var doc = new XmlDocument() {PreserveWhitespace = true}; doc.Load(StreamHelper.GenerateStreamFromString(projectFileContent)); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionFileModifier.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionFileModifier.cs index a24b31e5f1..9eda6efa10 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionFileModifier.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionFileModifier.cs @@ -18,6 +18,11 @@ namespace Volo.Abp.Cli.ProjectModification File.WriteAllText(solutionFile, RemoveProject(lines.ToList(), projectName).JoinAsString(Environment.NewLine)); } + public async Task AddModuleToSolutionFileAsync(ModuleWithMastersInfo module, string solutionFile) + { + await AddModuleAsync(module, solutionFile); + } + private List RemoveProject(List solutionFileLines, string projectName) { var projectKey = FindProjectKey(solutionFileLines, projectName); @@ -65,12 +70,7 @@ namespace Volo.Abp.Cli.ProjectModification return null; } - public async Task AddModuleToSolutionFileAsync(ModuleWithMastersInfo module, string solutionFile) - { - await AddModule(module, solutionFile); - } - - private async Task AddModule(ModuleWithMastersInfo module, string solutionFile) + private async Task AddModuleAsync(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")); @@ -128,7 +128,7 @@ namespace Volo.Abp.Cli.ProjectModification { foreach (var masterModule in module.MasterModuleInfos) { - await AddModule(masterModule, solutionFile); + await AddModuleAsync(masterModule, solutionFile); } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs index cc563f97cf..3bcdc34bc9 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs @@ -1,15 +1,17 @@ using JetBrains.Annotations; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Threading.Tasks; +using Volo.Abp.Cli.Args; +using Volo.Abp.Cli.Commands; using Volo.Abp.Cli.Commands.Services; using Volo.Abp.Cli.Http; using Volo.Abp.Cli.ProjectBuilding; +using Volo.Abp.Cli.ProjectBuilding.Templates.MvcModule; using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; using Volo.Abp.Json; @@ -32,6 +34,7 @@ namespace Volo.Abp.Cli.ProjectModification public SolutionFileModifier SolutionFileModifier { get; } public NugetPackageToLocalReferenceConverter NugetPackageToLocalReferenceConverter { get; } public AngularModuleSourceCodeAdder AngularModuleSourceCodeAdder { get; } + public NewCommand NewCommand { get; } public SolutionModuleAdder( IJsonSerializer jsonSerializer, @@ -45,7 +48,8 @@ namespace Volo.Abp.Cli.ProjectModification SourceCodeDownloadService sourceCodeDownloadService, SolutionFileModifier solutionFileModifier, NugetPackageToLocalReferenceConverter nugetPackageToLocalReferenceConverter, - AngularModuleSourceCodeAdder angularModuleSourceCodeAdder) + AngularModuleSourceCodeAdder angularModuleSourceCodeAdder, + NewCommand newCommand) { JsonSerializer = jsonSerializer; ProjectNugetPackageAdder = projectNugetPackageAdder; @@ -59,6 +63,7 @@ namespace Volo.Abp.Cli.ProjectModification SolutionFileModifier = solutionFileModifier; NugetPackageToLocalReferenceConverter = nugetPackageToLocalReferenceConverter; AngularModuleSourceCodeAdder = angularModuleSourceCodeAdder; + NewCommand = newCommand; Logger = NullLogger.Instance; } @@ -69,24 +74,27 @@ namespace Volo.Abp.Cli.ProjectModification string version, bool skipDbMigrations = false, bool withSourceCode = false, - bool addSourceCodeToSolutionFile = false) + bool addSourceCodeToSolutionFile = false, + bool newTemplate = false, + bool newProTemplate = false) { Check.NotNull(solutionFile, nameof(solutionFile)); Check.NotNull(moduleName, nameof(moduleName)); - var module = await FindModuleInfoAsync(moduleName); + var module = await GetModuleInfoAsync(moduleName, newTemplate, newProTemplate); Logger.LogInformation( $"Installing module '{module.Name}' to the solution '{Path.GetFileNameWithoutExtension(solutionFile)}'"); var projectFiles = ProjectFinder.GetProjectFiles(solutionFile); - await AddNugetAndNpmReferences(module, projectFiles); + await AddNugetAndNpmReferences(module, projectFiles, !(newTemplate || newProTemplate)); - if (withSourceCode) + if (withSourceCode || newTemplate || newProTemplate) { var modulesFolderInSolution = Path.Combine(Path.GetDirectoryName(solutionFile), "modules"); - await DownloadSourceCodesToSolutionFolder(module, modulesFolderInSolution, version); + await DownloadSourceCodesToSolutionFolder(module, modulesFolderInSolution, version, newTemplate, + newProTemplate); await RemoveUnnecessaryProjectsAsync(Path.GetDirectoryName(solutionFile), module, projectFiles); if (addSourceCodeToSolutionFile) @@ -94,7 +102,15 @@ namespace Volo.Abp.Cli.ProjectModification await SolutionFileModifier.AddModuleToSolutionFileAsync(module, solutionFile); } - await NugetPackageToLocalReferenceConverter.Convert(module, solutionFile); + if (newTemplate || newProTemplate) + { + await NugetPackageToLocalReferenceConverter.Convert(module, solutionFile, $"{module.Name}."); + } + else + { + await NugetPackageToLocalReferenceConverter.Convert(module, solutionFile); + } + await AddAngularSourceCode(modulesFolderInSolution, solutionFile); } else @@ -105,15 +121,17 @@ namespace Volo.Abp.Cli.ProjectModification ModifyDbContext(projectFiles, module, startupProject, skipDbMigrations); } - private async Task RemoveUnnecessaryProjectsAsync(string solutionDirectory, ModuleWithMastersInfo module, string[] projectFiles) + private async Task RemoveUnnecessaryProjectsAsync(string solutionDirectory, ModuleWithMastersInfo module, + string[] projectFiles) { var moduleDirectory = Path.Combine(solutionDirectory, "modules", module.Name); - var moduleSolutionFile = Directory.GetFiles(moduleDirectory, "*.sln", SearchOption.TopDirectoryOnly).First(); + var moduleSolutionFile = + Directory.GetFiles(moduleDirectory, "*.sln", SearchOption.TopDirectoryOnly).First(); var isProjectTiered = await IsProjectTiered(projectFiles); if (!projectFiles.Any(p => p.EndsWith(".Blazor.csproj"))) { - await RemoveProjectByTarget(module, moduleSolutionFile, NuGetPackageTarget.Blazor,isProjectTiered); + await RemoveProjectByTarget(module, moduleSolutionFile, NuGetPackageTarget.Blazor, isProjectTiered); } if (!projectFiles.Any(p => p.EndsWith(".Web.csproj"))) @@ -124,15 +142,18 @@ namespace Volo.Abp.Cli.ProjectModification if (!projectFiles.Any(p => p.EndsWith(".MongoDB.csproj"))) { await RemoveProjectByTarget(module, moduleSolutionFile, NuGetPackageTarget.MongoDB, isProjectTiered); + await RemoveProjectByPostFix(module, moduleSolutionFile, "test", ".MongoDB.Tests"); } if (!projectFiles.Any(p => p.EndsWith(".EntityFrameworkCore.csproj"))) { await RemoveProjectByTarget(module, moduleSolutionFile, NuGetPackageTarget.EntityFrameworkCore, isProjectTiered); + await RemoveProjectByPostFix(module, moduleSolutionFile, "test", ".EntityFrameworkCore.Tests"); } } - private async Task RemoveProjectByTarget(ModuleWithMastersInfo module, string moduleSolutionFile, NuGetPackageTarget target, bool isTieredProject) + private async Task RemoveProjectByTarget(ModuleWithMastersInfo module, string moduleSolutionFile, + NuGetPackageTarget target, bool isTieredProject) { var packages = module.NugetPackages.Where(n => (isTieredProject && n.TieredTarget != NuGetPackageTarget.Undefined @@ -152,6 +173,19 @@ namespace Volo.Abp.Cli.ProjectModification } } + private async Task RemoveProjectByPostFix(ModuleWithMastersInfo module, string moduleSolutionFile, string targetFolder, + string postFix) + { + var srcPath = Path.Combine(Path.GetDirectoryName(moduleSolutionFile), targetFolder); + var projectFolderPath = Directory.GetDirectories(srcPath).FirstOrDefault(d=> d.EndsWith(postFix)); + await SolutionFileModifier.RemoveProjectFromSolutionFileAsync(moduleSolutionFile, Path.GetDirectoryName(projectFolderPath)); + + if (Directory.Exists(projectFolderPath)) + { + Directory.Delete(projectFolderPath, true); + } + } + private async Task AddAngularPackages(string solutionFilePath, ModuleWithMastersInfo module) { var angularPath = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(solutionFilePath)), "angular"); @@ -201,18 +235,26 @@ namespace Volo.Abp.Cli.ProjectModification } private async Task DownloadSourceCodesToSolutionFolder(ModuleWithMastersInfo module, - string modulesFolderInSolution, string version = null) + string modulesFolderInSolution, string version = null, bool newTemplate = false, + bool newProTemplate = false) { var targetModuleFolder = Path.Combine(modulesFolderInSolution, module.Name); - await SourceCodeDownloadService.DownloadAsync( - module.Name, - targetModuleFolder, - version, - null, - null, - null - ); + if (newTemplate || newProTemplate) + { + await CreateNewModuleAsync(module, modulesFolderInSolution, version, newProTemplate); + } + else + { + await SourceCodeDownloadService.DownloadAsync( + module.Name, + targetModuleFolder, + version, + null, + null, + null + ); + } await DeleteAppAndDemoFolderAsync(targetModuleFolder); @@ -227,6 +269,18 @@ namespace Volo.Abp.Cli.ProjectModification } } + private async Task CreateNewModuleAsync(ModuleWithMastersInfo module, string modulesFolderInSolution, + string version, bool newProTemplate = false) + { + var args = new CommandLineArgs("new", module.Name); + + args.Options.Add("t", newProTemplate ? ModuleProTemplate.TemplateName : ModuleTemplate.TemplateName); + args.Options.Add("v", version); + args.Options.Add("o", Path.Combine(modulesFolderInSolution, module.Name)); + + await NewCommand.ExecuteAsync(args); + } + private async Task DeleteAppAndDemoFolderAsync(string targetModuleFolder) { var appFolder = Path.Combine(targetModuleFolder, "app"); @@ -248,7 +302,8 @@ namespace Volo.Abp.Cli.ProjectModification } } - private async Task AddNugetAndNpmReferences(ModuleWithMastersInfo module, string[] projectFiles) + private async Task AddNugetAndNpmReferences(ModuleWithMastersInfo module, string[] projectFiles, + bool useDotnetCliToInstall) { foreach (var nugetPackage in module.NugetPackages) { @@ -264,7 +319,7 @@ namespace Volo.Abp.Cli.ProjectModification continue; } - await ProjectNugetPackageAdder.AddAsync(targetProjectFile, nugetPackage); + await ProjectNugetPackageAdder.AddAsync(targetProjectFile, nugetPackage, null, useDotnetCliToInstall); } var mvcNpmPackages = module.NpmPackages?.Where(p => p.ApplicationType.HasFlag(NpmApplicationType.Mvc)) @@ -357,8 +412,14 @@ namespace Volo.Abp.Cli.ProjectModification } } - protected virtual async Task FindModuleInfoAsync(string moduleName) + protected virtual async Task GetModuleInfoAsync(string moduleName, bool newTemplate, + bool newProTemplate = false) { + if (newTemplate || newProTemplate) + { + return await GetEmptyModuleProjectInfoAsync(moduleName, newProTemplate); + } + using (var client = new CliHttpClient()) { var url = $"{CliUrls.WwwAbpIo}api/app/module/byNameWithDetails/?name=" + moduleName; @@ -380,6 +441,85 @@ namespace Volo.Abp.Cli.ProjectModification } } + private async Task GetEmptyModuleProjectInfoAsync(string moduleName, + bool newProTemplate = false) + { + var module = new ModuleWithMastersInfo(); + + module.Name = moduleName; + module.DisplayName = moduleName; + module.EfCoreConfigureMethodName = $"{module.Name}.EntityFrameworkCore:Configure{module.Name}"; + module.MasterModuleInfos = new List(); + + module.NugetPackages = new List + { + new NugetPackageInfo + { + Name = $"{module.Name}.Application", + ModuleClass = $"{module.Name}.{module.Name}ApplicationModule", + Target = NuGetPackageTarget.Application + }, + new NugetPackageInfo + { + Name = $"{module.Name}.Application.Contracts", + ModuleClass = $"{module.Name}.{module.Name}ApplicationContractsModule", + Target = NuGetPackageTarget.ApplicationContracts + }, + new NugetPackageInfo + { + Name = $"{module.Name}.Blazor", + ModuleClass = $"{module.Name}.Blazor.{module.Name}BlazorModule", + Target = NuGetPackageTarget.Blazor + }, + new NugetPackageInfo + { + Name = $"{module.Name}.Domain", + ModuleClass = $"{module.Name}.{module.Name}DomainModule", + Target = NuGetPackageTarget.Domain + }, + new NugetPackageInfo + { + Name = $"{module.Name}.Domain.Shared", + ModuleClass = $"{module.Name}.{module.Name}DomainSharedModule", + Target = NuGetPackageTarget.DomainShared + }, + new NugetPackageInfo + { + Name = $"{module.Name}.EntityFrameworkCore", + ModuleClass = $"{module.Name}.EntityFrameworkCore.{module.Name}EntityFrameworkCoreModule", + Target = NuGetPackageTarget.EntityFrameworkCore + }, + new NugetPackageInfo + { + Name = $"{module.Name}.HttpApi", + ModuleClass = $"{module.Name}.{module.Name}HttpApiModule", + Target = NuGetPackageTarget.HttpApi + }, + new NugetPackageInfo + { + Name = $"{module.Name}.HttpApi.Client", + ModuleClass = $"{module.Name}.{module.Name}HttpApiClientModule", + Target = NuGetPackageTarget.HttpApiClient + }, + new NugetPackageInfo + { + Name = $"{module.Name}.MongoDB", + ModuleClass = $"{module.Name}.MongoDB.{module.Name}MongoDbModule", + Target = NuGetPackageTarget.MongoDB + }, + new NugetPackageInfo + { + Name = $"{module.Name}.Web", + ModuleClass = $"{module.Name}.Web.{module.Name}WebModule", + Target = NuGetPackageTarget.Web + }, + }; + + module.NpmPackages = new List(); + + return module; + } + protected virtual async Task IsProjectTiered(string[] projectFiles) { return projectFiles.Select(ProjectFileNameHelper.GetAssemblyNameFromProjectPath)