From f0ca1475d2ce18599b00dd400aaeccda88a87670 Mon Sep 17 00:00:00 2001
From: cKey <35512826+colinin@users.noreply.github.com>
Date: Wed, 1 Dec 2021 21:59:21 +0800
Subject: [PATCH] =?UTF-8?q?feat(cli):=20=E5=8F=91=E5=B8=83cli?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
aspnet-core/.gitignore | 4 +-
aspnet-core/LINGYUN.MicroService.Common.sln | 10 +
aspnet-core/modules/cli/Directory.Build.props | 17 +
.../LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj | 31 ++
.../LINGYUN/Abp/Cli/AbpCliModule.cs | 22 ++
.../LINGYUN/Abp/Cli/Commands/CreateCommand.cs | 276 +++++++++++++++
.../LINGYUN/Abp/Cli/Commands/CreateOptions.cs | 25 ++
.../Abp/Cli/Commands/ICreateProjectService.cs | 9 +
.../Commands/LocalFileCreateProjectService.cs | 322 ++++++++++++++++++
.../Abp/Cli/Commands/ProjectCreateArgs.cs | 52 +++
.../LINGYUN/Abp/Cli/Program.cs | 55 +++
.../Properties/launchSettings.json | 8 +
12 files changed, 830 insertions(+), 1 deletion(-)
create mode 100644 aspnet-core/modules/cli/Directory.Build.props
create mode 100644 aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj
create mode 100644 aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/AbpCliModule.cs
create mode 100644 aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/CreateCommand.cs
create mode 100644 aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/CreateOptions.cs
create mode 100644 aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/ICreateProjectService.cs
create mode 100644 aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/LocalFileCreateProjectService.cs
create mode 100644 aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/ProjectCreateArgs.cs
create mode 100644 aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Program.cs
create mode 100644 aspnet-core/modules/cli/LINGYUN.Abp.Cli/Properties/launchSettings.json
diff --git a/aspnet-core/.gitignore b/aspnet-core/.gitignore
index 8e1f553e1..a6454ea49 100644
--- a/aspnet-core/.gitignore
+++ b/aspnet-core/.gitignore
@@ -1,4 +1,6 @@
.vs
LocalNuget
*.DotSettings.user
-**/*.csproj.user
\ No newline at end of file
+**/*.csproj.user
+templates
+nupkg
\ No newline at end of file
diff --git a/aspnet-core/LINGYUN.MicroService.Common.sln b/aspnet-core/LINGYUN.MicroService.Common.sln
index 533f69ae7..cfecaca0b 100644
--- a/aspnet-core/LINGYUN.MicroService.Common.sln
+++ b/aspnet-core/LINGYUN.MicroService.Common.sln
@@ -218,6 +218,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenApi.Sdk", "modules\open
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OpenApi.Tests", "tests\LINGYUN.Abp.OpenApi.Tests\LINGYUN.Abp.OpenApi.Tests.csproj", "{6C75799E-4B46-434D-BE1B-4AD71DF49686}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cli", "cli", "{FE372F22-80A2-4859-9330-949C27CA94ED}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Cli", "modules\cli\LINGYUN.Abp.Cli\LINGYUN.Abp.Cli.csproj", "{33007EF7-BC1D-4B32-ACDA-6B9117200FAD}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -568,6 +572,10 @@ Global
{6C75799E-4B46-434D-BE1B-4AD71DF49686}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C75799E-4B46-434D-BE1B-4AD71DF49686}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C75799E-4B46-434D-BE1B-4AD71DF49686}.Release|Any CPU.Build.0 = Release|Any CPU
+ {33007EF7-BC1D-4B32-ACDA-6B9117200FAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {33007EF7-BC1D-4B32-ACDA-6B9117200FAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {33007EF7-BC1D-4B32-ACDA-6B9117200FAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {33007EF7-BC1D-4B32-ACDA-6B9117200FAD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -677,6 +685,8 @@ Global
{3CE350AF-5574-46EC-8120-8542350AED20} = {8C688427-DD35-4F0B-86DA-6F536D3852D5}
{108192F3-3780-423F-9871-A1BBE323413E} = {8C688427-DD35-4F0B-86DA-6F536D3852D5}
{6C75799E-4B46-434D-BE1B-4AD71DF49686} = {B86C21A4-73B7-471E-B73A-B4B905EC9435}
+ {FE372F22-80A2-4859-9330-949C27CA94ED} = {02EA4E78-5891-43BC-944F-3E52FEE032E4}
+ {33007EF7-BC1D-4B32-ACDA-6B9117200FAD} = {FE372F22-80A2-4859-9330-949C27CA94ED}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {06C707C6-02C0-411A-AD3B-2D0E13787CB8}
diff --git a/aspnet-core/modules/cli/Directory.Build.props b/aspnet-core/modules/cli/Directory.Build.props
new file mode 100644
index 000000000..e2ff4ffa7
--- /dev/null
+++ b/aspnet-core/modules/cli/Directory.Build.props
@@ -0,0 +1,17 @@
+
+
+ 4.4.0
+ 4.4.0
+ 4.1.0
+ 2.2.0
+ 2.0.0
+ 2.0.1
+ 3.1.0
+ 3.0.1
+ 3.1.0
+ 4.0.0
+ 8.4.1
+ 5.0.0
+ 5.0.*
+
+
\ No newline at end of file
diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj
new file mode 100644
index 000000000..f77bc43c9
--- /dev/null
+++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj
@@ -0,0 +1,31 @@
+
+
+
+ Exe
+ net5.0
+ 4.4.0
+ true
+ labp
+ ./nupkg
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/AbpCliModule.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/AbpCliModule.cs
new file mode 100644
index 000000000..4c2bf7e80
--- /dev/null
+++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/AbpCliModule.cs
@@ -0,0 +1,22 @@
+using LINGYUN.Abp.Cli.Commands;
+using Volo.Abp.Autofac;
+using Volo.Abp.Cli;
+using Volo.Abp.Modularity;
+
+namespace LINGYUN.Abp.Cli
+{
+ [DependsOn(
+ typeof(AbpCliCoreModule),
+ typeof(AbpAutofacModule)
+ )]
+ public class AbpCliModule : AbpModule
+ {
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.Commands["create"] = typeof(CreateCommand);
+ });
+ }
+ }
+}
diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/CreateCommand.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/CreateCommand.cs
new file mode 100644
index 000000000..6a5f3eed2
--- /dev/null
+++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/CreateCommand.cs
@@ -0,0 +1,276 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Cli;
+using Volo.Abp.Cli.Args;
+using Volo.Abp.Cli.Commands;
+using Volo.Abp.Cli.Commands.Services;
+using Volo.Abp.Cli.ProjectBuilding;
+using Volo.Abp.Cli.ProjectBuilding.Building;
+using Volo.Abp.Cli.Utils;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.IO;
+
+namespace LINGYUN.Abp.Cli.Commands
+{
+ public class CreateCommand : IConsoleCommand, ITransientDependency
+ {
+ public class FindFile
+ {
+ public string Path { get; }
+ public string Name { get; }
+ public int Depth { get; }
+ public bool IsFolder { get; }
+ public FindFile() { }
+ public FindFile(
+ string path,
+ string name,
+ int depth,
+ bool isFolder)
+ {
+ Path = path;
+ Name = name;
+ Depth = depth;
+ IsFolder = isFolder;
+ }
+ }
+
+ public ILogger Logger { get; set; }
+
+ public ConnectionStringProvider ConnectionStringProvider { get; }
+
+ public ICreateProjectService CreateProjectService { get; }
+
+ public CreateCommand(
+ ICreateProjectService createProjectService,
+ ConnectionStringProvider connectionStringProvider)
+ {
+ CreateProjectService = createProjectService;
+ ConnectionStringProvider = connectionStringProvider;
+
+ Logger = NullLogger.Instance;
+ }
+
+ public async Task ExecuteAsync(CommandLineArgs commandLineArgs)
+ {
+ var projectName = NamespaceHelper.NormalizeNamespace(commandLineArgs.Target);
+ if (string.IsNullOrWhiteSpace(projectName))
+ {
+ throw new CliUsageException("Project name is missing!" + Environment.NewLine + Environment.NewLine + GetUsageInfo());
+ }
+
+ var packageName = commandLineArgs.Options.GetOrNull(CreateOptions.Package.Short, CreateOptions.Package.Long);
+ packageName ??= "app";
+
+ Logger.LogInformation("Package Name: " + packageName);
+
+ var version = commandLineArgs.Options.GetOrNull(NewCommand.Options.Version.Short, NewCommand.Options.Version.Long);
+
+ if (version != null)
+ {
+ Logger.LogInformation("Version: " + version);
+ }
+
+ var templateName = commandLineArgs.Options.GetOrNull(NewCommand.Options.Template.Short, NewCommand.Options.Template.Long);
+ templateName ??= "lam";
+
+ Logger.LogInformation("Template: " + templateName);
+
+ var gitHubAbpLocalRepositoryPath = commandLineArgs.Options.GetOrNull(NewCommand.Options.GitHubAbpLocalRepositoryPath.Long);
+ if (gitHubAbpLocalRepositoryPath != null)
+ {
+ Logger.LogInformation("GitHub Abp Local Repository Path: " + gitHubAbpLocalRepositoryPath);
+ }
+
+ var gitHubVoloLocalRepositoryPath = commandLineArgs.Options.GetOrNull(NewCommand.Options.GitHubVoloLocalRepositoryPath.Long);
+ if (gitHubVoloLocalRepositoryPath != null)
+ {
+ Logger.LogInformation("GitHub Volo Local Repository Path: " + gitHubVoloLocalRepositoryPath);
+ }
+
+ var databaseProvider = GetDatabaseProvider(commandLineArgs);
+ if (databaseProvider != DatabaseProvider.NotSpecified)
+ {
+ Logger.LogInformation("Database provider: " + databaseProvider);
+ }
+
+ var connectionString = GetConnectionString(commandLineArgs);
+ if (connectionString != null)
+ {
+ Logger.LogInformation("Connection string: " + connectionString);
+ }
+
+ var databaseManagementSystem = GetDatabaseManagementSystem(commandLineArgs);
+ if (databaseManagementSystem != DatabaseManagementSystem.NotSpecified)
+ {
+ Logger.LogInformation("DBMS: " + databaseManagementSystem);
+ }
+
+ var randomPort = string.IsNullOrWhiteSpace(
+ commandLineArgs.Options.GetOrNull(CreateOptions.NoRandomPort.Short, CreateOptions.NoRandomPort.Long));
+ var applicationPort = randomPort ? RandomHelper.GetRandom(5001, 65535).ToString() : "5000";
+
+ Logger.LogInformation("Application Launch Port: " + applicationPort);
+
+ var daprPort = randomPort ? RandomHelper.GetRandom(3501, 65535).ToString() : "3500";
+
+ Logger.LogInformation("Dapr Listening Http Port: " + daprPort);
+
+ var createSolutionFolder = GetCreateSolutionFolderPreference(commandLineArgs);
+ var outputFolder = commandLineArgs.Options.GetOrNull(NewCommand.Options.OutputFolder.Short, NewCommand.Options.OutputFolder.Long);
+
+ var outputFolderRoot =
+ outputFolder != null ? Path.GetFullPath(outputFolder) : Directory.GetCurrentDirectory();
+
+ outputFolder = createSolutionFolder ?
+ Path.Combine(outputFolderRoot, SolutionName.Parse(projectName).FullName) :
+ outputFolderRoot;
+
+ var solutionName = SolutionName.Parse(projectName);
+
+ DirectoryHelper.CreateIfNotExists(outputFolder);
+
+ Logger.LogInformation("Output folder: " + outputFolder);
+
+ if (connectionString == null &&
+ databaseManagementSystem != DatabaseManagementSystem.NotSpecified &&
+ databaseManagementSystem != DatabaseManagementSystem.SQLServer)
+ {
+ connectionString = ConnectionStringProvider.GetByDbms(databaseManagementSystem, outputFolder);
+ }
+
+ commandLineArgs.Options.Add(CliConsts.Command, commandLineArgs.Command);
+
+ var projectArgs = new ProjectCreateArgs(
+ packageName,
+ solutionName,
+ templateName,
+ version,
+ outputFolder,
+ databaseProvider,
+ databaseManagementSystem,
+ UiFramework.None,
+ null,
+ false,
+ gitHubAbpLocalRepositoryPath,
+ gitHubVoloLocalRepositoryPath,
+ "",
+ commandLineArgs.Options,
+ connectionString,
+ applicationPort,
+ daprPort
+ );
+
+ await CreateProjectService.CreateAsync(projectArgs);
+ }
+
+ public string GetShortDescription()
+ {
+ return "Generate a new solution based on the customed ABP startup templates.";
+ }
+
+ public string GetUsageInfo()
+ {
+ var sb = new StringBuilder();
+
+ sb.AppendLine("");
+ sb.AppendLine("Usage:");
+ sb.AppendLine("");
+ sb.AppendLine(" labp create [options]");
+ sb.AppendLine("");
+ sb.AppendLine("Options:");
+ sb.AppendLine("");
+ sb.AppendLine("-pk|--package (default: app)");
+ sb.AppendLine("-t|--template (default: lam)");
+ sb.AppendLine("-d|--database-provider (if supported by the template)");
+ sb.AppendLine("-o|--output-folder (default: current folder)");
+ sb.AppendLine("-v|--version (default: latest version)");
+ //sb.AppendLine("-ts|--template-source (your local or network abp template source)");
+ sb.AppendLine("-csf|--create-solution-folder (default: true)");
+ sb.AppendLine("-cs|--connection-string (your database connection string)");
+ sb.AppendLine("--dbms (your database management system)");
+ sb.AppendLine("--no-random-port (Use template's default ports)");
+ sb.AppendLine("");
+ sb.AppendLine("Examples:");
+ sb.AppendLine("");
+ sb.AppendLine(" labp create Acme.BookStore");
+ sb.AppendLine(" labp create Acme.BookStore -p Com");
+ sb.AppendLine(" labp create Acme.BookStore -d mongodb");
+ sb.AppendLine(" labp create Acme.BookStore -d mongodb -o d:\\my-project");
+ sb.AppendLine(" labp create Acme.BookStore -ts \"D:\\localTemplate\\abp\"");
+ sb.AppendLine(" labp create Acme.BookStore -csf false");
+ sb.AppendLine(" labp create Acme.BookStore --local-framework-ref --abp-path \"D:\\github\\abp\"");
+ sb.AppendLine(" labp create Acme.BookStore --dbms mysql");
+ sb.AppendLine(" labp create Acme.BookStore --connection-string \"Server=myServerName\\myInstanceName;Database=myDatabase;User Id=myUsername;Password=myPassword\"");
+ sb.AppendLine("");
+ // TODO: 文档
+ // sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI");
+
+ return sb.ToString();
+ }
+
+ protected bool GetCreateSolutionFolderPreference(CommandLineArgs commandLineArgs)
+ {
+ return commandLineArgs.Options.ContainsKey(NewCommand.Options.CreateSolutionFolder.Long)
+ || commandLineArgs.Options.ContainsKey(NewCommand.Options.CreateSolutionFolder.Short);
+ }
+
+ protected virtual DatabaseProvider GetDatabaseProvider(CommandLineArgs commandLineArgs)
+ {
+ var optionValue = commandLineArgs.Options.GetOrNull(
+ NewCommand.Options.DatabaseProvider.Short,
+ NewCommand.Options.DatabaseProvider.Long);
+ switch (optionValue)
+ {
+ case "ef":
+ return DatabaseProvider.EntityFrameworkCore;
+ case "mongodb":
+ return DatabaseProvider.MongoDb;
+ default:
+ return DatabaseProvider.NotSpecified;
+ }
+ }
+
+ protected virtual DatabaseManagementSystem GetDatabaseManagementSystem(CommandLineArgs commandLineArgs)
+ {
+ var optionValue = commandLineArgs.Options.GetOrNull(
+ NewCommand.Options.DatabaseManagementSystem.Short,
+ NewCommand.Options.DatabaseManagementSystem.Long);
+
+ if (optionValue == null)
+ {
+ return DatabaseManagementSystem.NotSpecified;
+ }
+
+ switch (optionValue.ToLowerInvariant())
+ {
+ case "sqlserver":
+ return DatabaseManagementSystem.SQLServer;
+ case "mysql":
+ return DatabaseManagementSystem.MySQL;
+ case "postgresql":
+ return DatabaseManagementSystem.PostgreSQL;
+ case "oracle-devart":
+ return DatabaseManagementSystem.OracleDevart;
+ case "sqlite":
+ return DatabaseManagementSystem.SQLite;
+ case "oracle":
+ return DatabaseManagementSystem.Oracle;
+ default:
+ return DatabaseManagementSystem.NotSpecified;
+ }
+ }
+
+ protected static string GetConnectionString(CommandLineArgs commandLineArgs)
+ {
+ var connectionString = commandLineArgs.Options.GetOrNull(
+ NewCommand.Options.ConnectionString.Short,
+ NewCommand.Options.ConnectionString.Long);
+ return string.IsNullOrWhiteSpace(connectionString) ? null : connectionString;
+ }
+ }
+}
diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/CreateOptions.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/CreateOptions.cs
new file mode 100644
index 000000000..93a3a1279
--- /dev/null
+++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/CreateOptions.cs
@@ -0,0 +1,25 @@
+namespace LINGYUN.Abp.Cli.Commands
+{
+ public static class CreateOptions
+ {
+ public static string[] ExclusionFolder = new string[3] { ".github", ".vs", ".svn" };
+
+ public static class Package
+ {
+ public const string Short = "pk";
+ public const string Long = "package";
+ }
+
+ public static class Company
+ {
+ public const string Short = "cp";
+ public const string Long = "company";
+ }
+
+ public static class NoRandomPort
+ {
+ public const string Short = "nrp";
+ public const string Long = "no-random-port";
+ }
+ }
+}
diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/ICreateProjectService.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/ICreateProjectService.cs
new file mode 100644
index 000000000..abeb291d1
--- /dev/null
+++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/ICreateProjectService.cs
@@ -0,0 +1,9 @@
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.Cli.Commands
+{
+ public interface ICreateProjectService
+ {
+ Task CreateAsync(ProjectCreateArgs createArgs);
+ }
+}
diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/LocalFileCreateProjectService.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/LocalFileCreateProjectService.cs
new file mode 100644
index 000000000..6629b2d54
--- /dev/null
+++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/LocalFileCreateProjectService.cs
@@ -0,0 +1,322 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Volo.Abp.Cli.ProjectBuilding.Building;
+using Volo.Abp.Cli.Utils;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.IO;
+
+namespace LINGYUN.Abp.Cli.Commands
+{
+ public class LocalFileCreateProjectService : ICreateProjectService, ISingletonDependency
+ {
+ public class FindFile
+ {
+ public string Path { get; }
+ public string Name { get; }
+ public int Depth { get; }
+ public bool IsFolder { get; }
+ public FindFile() { }
+ public FindFile(
+ string path,
+ string name,
+ int depth,
+ bool isFolder)
+ {
+ Path = path;
+ Name = name;
+ Depth = depth;
+ IsFolder = isFolder;
+ }
+ }
+
+ public ILogger Logger { get; set; }
+
+ public LocalFileCreateProjectService()
+ {
+ Logger = NullLogger.Instance;
+ }
+
+ public virtual async Task CreateAsync(ProjectCreateArgs createArgs)
+ {
+ Logger.LogInformation("Execute dotnet command...");
+
+ var commandBuilder = new StringBuilder("dotnet new");
+ commandBuilder.AppendFormat(" {0}", createArgs.TemplateName);
+ commandBuilder.AppendFormat(" -n {0}", createArgs.SolutionName.ProjectName);
+ commandBuilder.AppendFormat(" -o {0}", createArgs.OutputFolder);
+
+ var cmdError = CmdHelper.RunCmdAndGetOutput(commandBuilder.ToString(), out bool isSuccessful);
+ if (!isSuccessful)
+ {
+ Logger.LogError("Execute command error: " + cmdError);
+ return;
+ }
+
+ Logger.LogInformation("Execute command: " + cmdError);
+
+ var projectFiles = new List();
+
+ Logger.LogInformation("Search Solution files.");
+ SearchSolutionPath(projectFiles, createArgs.OutputFolder, 0);
+
+ Logger.LogInformation("Rewrite Package and company name.");
+
+ await TryReplacePackageAndCompanyNameWithProjectFile(
+ projectFiles,
+ createArgs.PackageName,
+ createArgs.SolutionName.CompanyName,
+ createArgs.DatabaseManagementSystem);
+
+ Logger.LogInformation("Rewrite appsettings.json.");
+ await TryReplaceAppSettingsWithProjectFile(
+ projectFiles,
+ createArgs.PackageName,
+ createArgs.SolutionName.CompanyName,
+ createArgs.SolutionName.ProjectName,
+ createArgs.ConnectionString,
+ createArgs.DatabaseManagementSystem);
+
+ Logger.LogInformation("Rewrite application url.");
+ await TryReplaceApplicationUrlWithProjectFile(
+ projectFiles,
+ createArgs.ApplicationPort,
+ createArgs.DaprPort);
+
+ Logger.LogInformation("Rewrite package version.");
+ await TryReplaceVersionWithProjectFile(
+ projectFiles,
+ createArgs.Version);
+
+ Logger.LogInformation("Rewrite project folder.");
+ await TryReplacePackageAndCompanyNameWithProjectFolder(
+ projectFiles,
+ createArgs.PackageName,
+ createArgs.SolutionName.CompanyName,
+ createArgs.DatabaseManagementSystem);
+
+ Logger.LogInformation($"'{createArgs.SolutionName.ProjectName}' has been successfully created to '{createArgs.OutputFolder}'");
+ }
+
+ protected virtual void SearchSolutionPath(List projectFiles, string solutionPath, int depth)
+ {
+ var searchFiles = Directory.GetFileSystemEntries(solutionPath, "*.*", SearchOption.TopDirectoryOnly);
+ searchFiles = searchFiles.Where(f => !CreateOptions.ExclusionFolder.Any(ef => f.EndsWith(ef))).ToArray();
+ foreach (var searchFile in searchFiles)
+ {
+ projectFiles.Add(new FindFile(solutionPath, searchFile, depth, Directory.Exists(searchFile)));
+ if (Directory.Exists(searchFile))
+ {
+ SearchSolutionPath(projectFiles, searchFile, depth++);
+ }
+ }
+ }
+
+ protected virtual async Task TryReplaceVersionWithProjectFile(
+ List projectFiles,
+ string version)
+ {
+ if (version.IsNullOrWhiteSpace())
+ {
+ return;
+ }
+ var assemblyVersion = GetType().Assembly.GetName().Version;
+ var currentVersion = $"{assemblyVersion.Major}.{assemblyVersion.Minor}.{assemblyVersion.Build}";
+
+ var buildPropsFile = projectFiles.FirstOrDefault(f => f.Name.EndsWith("Directory.Build.props"));
+ if (buildPropsFile != null)
+ {
+ await ReplaceFileTextAsync(
+ buildPropsFile,
+ $"{currentVersion}",
+ $"{version}");
+
+ await ReplaceFileTextAsync(
+ buildPropsFile,
+ $"{currentVersion}",
+ $"{version}");
+ }
+
+ var commonPropsFile = projectFiles.FirstOrDefault(f => f.Name.EndsWith("common.props"));
+ if (commonPropsFile != null)
+ {
+ await ReplaceFileTextAsync(
+ commonPropsFile,
+ $"{currentVersion}",
+ $"{version}");
+ }
+ }
+
+ protected virtual async Task TryReplaceApplicationUrlWithProjectFile(
+ List projectFiles,
+ string port = "5000",
+ string daprPort = "3500")
+ {
+ var launchFile = projectFiles.FirstOrDefault(f => f.Name.EndsWith("launchSettings.json"));
+ if (launchFile != null)
+ {
+ string applicationUrl = $"http://localhost:{port}";
+ await ReplaceFileTextAsync(launchFile, "http://localhost:5000", applicationUrl);
+ }
+
+ var daprScriptFile = projectFiles.FirstOrDefault(f => f.Name.EndsWith("dapr.sh"));
+ if (daprScriptFile != null)
+ {
+ await ReplaceFileTextAsync(daprScriptFile, "--app-port 5000 -H 3500", $"--app-port {port} -H {daprPort}");
+ }
+ }
+
+ protected virtual async Task TryReplaceAppSettingsWithProjectFile(
+ List projectFiles,
+ string packageName,
+ string companyName,
+ string projectName,
+ string connectionString = null,
+ DatabaseManagementSystem database = DatabaseManagementSystem.NotSpecified)
+ {
+ var canReplaceFiles = projectFiles.Where(f => !f.IsFolder && f.Name.Contains("appsettings"));
+ foreach (var projectFile in canReplaceFiles)
+ {
+ await ReplaceFileTextAsync(projectFile, "PackageName", packageName);
+ await ReplaceFileTextAsync(projectFile, "CompanyName", companyName);
+
+ var defaultConnectionString = $"Server=127.0.0.1;Database={projectName};User Id=root;Password=123456";
+ connectionString ??= defaultConnectionString;
+ await ReplaceFileTextAsync(projectFile, defaultConnectionString, connectionString);
+
+ switch (database)
+ {
+ case DatabaseManagementSystem.SQLServer:
+ await ReplaceFileTextAsync(projectFile, "MySQL", "SqlServer");
+ break;
+ case DatabaseManagementSystem.SQLite:
+ await ReplaceFileTextAsync(projectFile, "MySQL", "Sqlite");
+ break;
+ case DatabaseManagementSystem.Oracle:
+ await ReplaceFileTextAsync(projectFile, "MySQL", "Oracle");
+ break;
+ case DatabaseManagementSystem.OracleDevart:
+ await ReplaceFileTextAsync(projectFile, "MySQL", "Oracle.Devart");
+ break;
+ case DatabaseManagementSystem.PostgreSQL:
+ await ReplaceFileTextAsync(projectFile, "MySQL", "PostgreSql");
+ break;
+ }
+ }
+ }
+
+ protected virtual async Task TryReplacePackageAndCompanyNameWithProjectFile(
+ List projectFiles,
+ string packageName,
+ string companyName,
+ DatabaseManagementSystem database = DatabaseManagementSystem.NotSpecified)
+ {
+ var canReplaceFiles = projectFiles.Where(f => !f.IsFolder && !f.Name.Contains("appsettings"));
+ foreach (var projectFile in canReplaceFiles)
+ {
+ await ReplaceFileTextAsync(projectFile, "PackageName", packageName);
+ await ReplaceFileTextAsync(projectFile, "CompanyName", companyName);
+
+ if (database != DatabaseManagementSystem.NotSpecified &&
+ database != DatabaseManagementSystem.MySQL &&
+ projectFile.Name.EndsWith("MigrationsDbContextFactory.cs"))
+ {
+ await ReplaceFileTextAsync(
+ projectFile,
+ // 非 MySql 替换一下这一句
+ "connectionString, ServerVersion.AutoDetect(connectionString)",
+ "connectionString");
+ }
+ // DB 驱动
+ switch (database)
+ {
+ case DatabaseManagementSystem.SQLServer:
+ await ReplaceFileTextAsync(projectFile, "MySQL", "SqlServer");
+ break;
+ case DatabaseManagementSystem.SQLite:
+ await ReplaceFileTextAsync(projectFile, "MySQL", "Sqlite");
+ break;
+ case DatabaseManagementSystem.Oracle:
+ await ReplaceFileTextAsync(projectFile, "MySQL", "Oracle");
+ break;
+ case DatabaseManagementSystem.OracleDevart:
+ await ReplaceFileTextAsync(projectFile, "MySQL", "Oracle.Devart");
+ break;
+ case DatabaseManagementSystem.PostgreSQL:
+ await ReplaceFileTextAsync(projectFile, "MySQL", "PostgreSql");
+ break;
+ }
+ }
+ }
+
+ protected virtual Task TryReplacePackageAndCompanyNameWithProjectFolder(
+ List projectFiles,
+ string packageName,
+ string companyName,
+ DatabaseManagementSystem database = DatabaseManagementSystem.NotSpecified)
+ {
+ var canReplaceFiles = projectFiles
+ .OrderByDescending(f => f.Depth)
+ .OrderByDescending(f => !f.IsFolder);
+ foreach (var projectFile in canReplaceFiles)
+ {
+ var replaceFileName = projectFile.Name.Replace("PackageName", packageName).Replace("CompanyName", companyName);
+ switch (database)
+ {
+ case DatabaseManagementSystem.SQLServer:
+ replaceFileName = replaceFileName.Replace("MySQL", "SqlServer", StringComparison.InvariantCultureIgnoreCase);
+ break;
+ case DatabaseManagementSystem.SQLite:
+ replaceFileName = replaceFileName.Replace("MySQL", "Sqlite", StringComparison.InvariantCultureIgnoreCase);
+ break;
+ case DatabaseManagementSystem.Oracle:
+ replaceFileName = replaceFileName.Replace("MySQL", "Oracle", StringComparison.InvariantCultureIgnoreCase);
+ break;
+ case DatabaseManagementSystem.OracleDevart:
+ replaceFileName = replaceFileName.Replace("MySQL", "Oracle.Devart", StringComparison.InvariantCultureIgnoreCase);
+ break;
+ case DatabaseManagementSystem.PostgreSQL:
+ replaceFileName = replaceFileName.Replace("MySQL", "PostgreSQL", StringComparison.InvariantCultureIgnoreCase);
+ break;
+ }
+
+ if (File.Exists(projectFile.Name))
+ {
+ DirectoryHelper.CreateIfNotExists(Path.GetDirectoryName(replaceFileName));
+ File.Move(projectFile.Name, replaceFileName);
+ }
+ }
+
+ var canReplacePaths = projectFiles
+ .Where(projectFile => projectFile.Name.Contains("PackageName") || projectFile.Name.Contains("CompanyName"))
+ .OrderByDescending(f => f.Depth)
+ .OrderByDescending(f => f.IsFolder);
+ foreach (var projectFile in canReplacePaths)
+ {
+ DirectoryHelper.DeleteIfExists(projectFile.Name, true);
+ }
+
+ return Task.CompletedTask;
+ }
+
+ protected static async Task ReplaceFileTextAsync(FindFile projectFile, string sourceText, string replaceText)
+ {
+ string fileText;
+ using (var stream = new StreamReader(projectFile.Name, Encoding.UTF8))
+ {
+ fileText = await stream.ReadToEndAsync();
+ }
+ fileText = fileText.Replace(sourceText, replaceText, StringComparison.InvariantCultureIgnoreCase);
+
+ using (StreamWriter writer = new StreamWriter(projectFile.Name, false, Encoding.UTF8))
+ {
+ await writer.WriteAsync(fileText);
+ }
+ }
+ }
+}
diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/ProjectCreateArgs.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/ProjectCreateArgs.cs
new file mode 100644
index 000000000..f4bded532
--- /dev/null
+++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Commands/ProjectCreateArgs.cs
@@ -0,0 +1,52 @@
+using System.Collections.Generic;
+using Volo.Abp.Cli.ProjectBuilding;
+using Volo.Abp.Cli.ProjectBuilding.Building;
+
+namespace LINGYUN.Abp.Cli.Commands
+{
+ public class ProjectCreateArgs : ProjectBuildArgs
+ {
+ public string PackageName { get; }
+ public string OutputFolder { get; }
+ public string ApplicationPort { get; }
+ public string DaprPort { get; }
+ public ProjectCreateArgs(
+ string packageName,
+ SolutionName solutionName,
+ string templateName = null,
+ string version = null,
+ string outputFolder = null,
+ DatabaseProvider databaseProvider = DatabaseProvider.NotSpecified,
+ DatabaseManagementSystem databaseManagementSystem = DatabaseManagementSystem.NotSpecified,
+ UiFramework uiFramework = UiFramework.NotSpecified,
+ MobileApp? mobileApp = null,
+ bool publicWebSite = false,
+ string abpGitHubLocalRepositoryPath = null,
+ string voloGitHubLocalRepositoryPath = null,
+ string templateSource = null,
+ Dictionary extraProperties = null,
+ string connectionString = null,
+ string applicationPort = "5000",
+ string daprPort = "3500")
+ : base(
+ solutionName,
+ templateName,
+ version,
+ databaseProvider,
+ databaseManagementSystem,
+ uiFramework,
+ mobileApp,
+ publicWebSite,
+ abpGitHubLocalRepositoryPath,
+ voloGitHubLocalRepositoryPath,
+ templateSource,
+ extraProperties,
+ connectionString)
+ {
+ PackageName = packageName;
+ OutputFolder = outputFolder;
+ ApplicationPort = applicationPort;
+ DaprPort = daprPort;
+ }
+ }
+}
diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Program.cs b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Program.cs
new file mode 100644
index 000000000..ef13d4e4d
--- /dev/null
+++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/Program.cs
@@ -0,0 +1,55 @@
+using Microsoft.Extensions.DependencyInjection;
+using Serilog;
+using Serilog.Events;
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Cli;
+
+namespace LINGYUN.Abp.Cli
+{
+ public class Program
+ {
+ private static async Task Main(string[] args)
+ {
+ Console.OutputEncoding = System.Text.Encoding.UTF8;
+
+ Log.Logger = new LoggerConfiguration()
+ .MinimumLevel.Information()
+ .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
+ .MinimumLevel.Override("Volo.Abp", LogEventLevel.Warning)
+ .MinimumLevel.Override("LINGYUN.Abp", LogEventLevel.Warning)
+ .MinimumLevel.Override("System.Net.Http.HttpClient", LogEventLevel.Warning)
+#if DEBUG
+ .MinimumLevel.Override("Volo.Abp.Cli", LogEventLevel.Debug)
+ .MinimumLevel.Override("LINGYUN.Abp.Cli", LogEventLevel.Debug)
+#else
+ .MinimumLevel.Override("Volo.Abp.Cli", LogEventLevel.Information)
+ .MinimumLevel.Override("LINGYUN.Abp.Cli", LogEventLevel.Information)
+#endif
+ .Enrich.FromLogContext()
+ .WriteTo.File(Path.Combine(CliPaths.Log, "lingyun-abp-cli-logs.txt"))
+ .WriteTo.Console()
+ .CreateLogger();
+
+ using (var application = AbpApplicationFactory.Create(
+ options =>
+ {
+ options.UseAutofac();
+ options.Services.AddLogging(c => c.AddSerilog());
+ }))
+ {
+ application.Initialize();
+
+ await application.ServiceProvider
+ .GetRequiredService()
+ .RunAsync(args);
+
+ application.Shutdown();
+
+ Log.CloseAndFlush();
+ }
+ }
+ }
+}
diff --git a/aspnet-core/modules/cli/LINGYUN.Abp.Cli/Properties/launchSettings.json b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/Properties/launchSettings.json
new file mode 100644
index 000000000..9cc02bacb
--- /dev/null
+++ b/aspnet-core/modules/cli/LINGYUN.Abp.Cli/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "LINGYUN.Abp.Cli": {
+ "commandName": "Project",
+ "commandLineArgs": "create MyCompany.MyProject -pk MyPackage -t lam -dbms sqlserver -cs \"Server=127.0.0.1;Database=master;User Id=sa;Password=662871\" -o \"D:\\Projects\\MicroService\\CRM\\Vue\\vue-abp\\aspnet-core\\modules\\cli\\LINGYUN.Abp.Cli\\bin\\Debug\\net5.0\\TTT\""
+ }
+ }
+}
\ No newline at end of file