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