diff --git a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json index fff1876a67..0edbb7a5dc 100644 --- a/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json +++ b/abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json @@ -196,6 +196,7 @@ "MultipleDBOptionsExplanation": "The framework can work with any data source, while the following providers are officially developed and supported;", "SelectLanguage": "Select language", "LatestArticleOnCommunity": "Latest Article on ABP Community", - "Register": "Register" + "Register": "Register", + "IsDownloadable": "Is downloadable" } } diff --git a/docs/en/Blog-Posts/2021-03-31 v4_3 Preview/POST.md b/docs/en/Blog-Posts/2021-03-31 v4_3 Preview/POST.md new file mode 100644 index 0000000000..632844ee27 --- /dev/null +++ b/docs/en/Blog-Posts/2021-03-31 v4_3 Preview/POST.md @@ -0,0 +1,93 @@ +# ABP Framework 4.3 RC Has Been Published + +We are super excited to announce the ABP Framework 4.3 RC (Release Candidate). Here, a list of highlights for this release; + +* **CMS Kit** module initial release. +* **Blazor UI server-side** support. +* **Module extensibility** system for the Blazor UI. +* Angular UI **resource owner password** flow comes back. +* **Volo.Abp.EntityFrameworkCore.Oracle** package is now compatible with .NET 5. +* CLI support to easily add the **Basic Theme** into the solution. +* New **IInitLogger** service to write logs before dependency injection phase completed. +* Infrastructure for **multi-lingual entities**. + +Beside the new features above, we've done many performance improvements, enhancements and bug fixes on the current features. See the [4.3 milestone](https://github.com/abpframework/abp/milestone/49) on GitHub for all changes made on this version. + +This version was a big development journey for us; [150+ issues](https://github.com/abpframework/abp/issues?q=is%3Aopen+is%3Aissue+milestone%3A4.3-preview) resolved, [260+ PRs](https://github.com/abpframework/abp/pulls?q=is%3Aopen+is%3Apr+milestone%3A4.3-preview) merged and 1,600+ commits done only in the [main framework repository](https://github.com/abpframework/abp). **Thanks to the ABP Framework team and all the contributors.** + +## The Migration Guide + +We normally don't make breaking changes in minor versions. However, this version has some small breaking changes, mostly related to Blazor UI WebAssembly & Server separation. **Please check the [migration guide](https://docs.abp.io/en/abp/4.3/Migration-Guides/Abp-4_3) before starting with the version 4.3**. + +## Get Started With The 4.3 RC + +If you want to try the version 4.3 today, follow the steps below; + +1) **Upgrade** the ABP CLI to the version `4.3.0-rc.1` using a command line terminal: + +````bash +dotnet tool update Volo.Abp.Cli -g --version 4.3.0-rc.1 +```` + +**or install** if you haven't installed before: + +````bash +dotnet tool install Volo.Abp.Cli -g --version 4.3.0-rc.1 +```` + +2) Create a **new application** with the `--preview` option: + +````bash +abp new BookStore --preview +```` + +See the [ABP CLI documentation](https://docs.abp.io/en/abp/4.3/CLI) for all the available options. + +> You can also use the *Direct Download* tab on the [Get Started](https://abp.io/get-started) page by selecting the **Preview checkbox**. + +## What's New With The ABP Framework 4.3 + +### CMS Kit + +TODO + +### Blazor Server Side + +TODO + +### Blazor UI Module Extensibility + +TODO + +### Angular UI Resource Owner Password Flow + +TODO + +### Volo.Abp.EntityFrameworkCore.Oracle Package + +TODO + +### Add Basic Theme Into Your Solution + +TODO + +### IInitLogger + +TODO + +### Multi-Lingual Entities + +TODO + +### Other News + +* [#7423](https://github.com/abpframework/abp/issues/7423) MongoDB repository base aggregation API. +* [#8163](https://github.com/abpframework/abp/issues/8163) Ignoring files on minification for MVC UI. +* [#7799](https://github.com/abpframework/abp/pull/7799) Added `RequiredPermissionName` to `ApplicationMenuItem` for MVC & Blazor UI to easily show/hide menu items based on user permissions. Also added `RequiredPermissionName` to `ToolbarItem` for the MVC UI for the same purpose. +* [#7523](https://github.com/abpframework/abp/pull/7523) Add more bundle methods to the distributed cache. + +See the [4.3 milestone](https://github.com/abpframework/abp/milestone/49) on GitHub for all changes made on this version. + +## Feedback + +Please check out the ABP Framework 4.3 RC and [provide feedback](https://github.com/abpframework/abp/issues/new) to help us to release a more stable version. **The planned release date for the [4.3.0 final](https://github.com/abpframework/abp/milestone/50) version is April 15, 2021**. \ No newline at end of file diff --git a/docs/en/Migration-Guides/Abp-4_3.md b/docs/en/Migration-Guides/Abp-4_3.md new file mode 100644 index 0000000000..c4541a6581 --- /dev/null +++ b/docs/en/Migration-Guides/Abp-4_3.md @@ -0,0 +1,3 @@ +# ABP Framework 4.x to 4.3 Migration Guide + +TODO \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs index 36530a7979..96740fa418 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/AddPackageCommand.cs @@ -35,11 +35,16 @@ namespace Volo.Abp.Cli.Commands } var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long); + var withSourceCode =commandLineArgs.Options.ContainsKey(Options.SourceCode.Long); + var addSourceCodeToSolutionFile = withSourceCode && commandLineArgs.Options.ContainsKey("add-to-solution-file"); await ProjectNugetPackageAdder.AddAsync( GetProjectFile(commandLineArgs), commandLineArgs.Target, - version + version, + true, + withSourceCode, + addSourceCodeToSolutionFile ); } @@ -128,6 +133,11 @@ namespace Volo.Abp.Cli.Commands public const string Short = "v"; public const string Long = "version"; } + + public static class SourceCode + { + public const string Long = "with-source-code"; + } } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs index 5bf5041c22..281183bfb5 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/GetSourceCommand.cs @@ -59,7 +59,7 @@ namespace Volo.Abp.Cli.Commands commandLineArgs.Options.Add(CliConsts.Command, commandLineArgs.Command); - await _sourceCodeDownloadService.DownloadAsync( + await _sourceCodeDownloadService.DownloadModuleAsync( commandLineArgs.Target, outputFolder, version, gitHubAbpLocalRepositoryPath, gitHubVoloLocalRepositoryPath, commandLineArgs.Options); } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs index 6306619e56..ad1c5cb7fe 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/Services/SourceCodeDownloadService.cs @@ -17,15 +17,17 @@ namespace Volo.Abp.Cli.Commands.Services public class SourceCodeDownloadService : ITransientDependency { public ModuleProjectBuilder ModuleProjectBuilder { get; } + public PackageProjectBuilder PackageProjectBuilder { get; } public ILogger Logger { get; set; } - public SourceCodeDownloadService(ModuleProjectBuilder moduleProjectBuilder) + public SourceCodeDownloadService(ModuleProjectBuilder moduleProjectBuilder, PackageProjectBuilder packageProjectBuilder) { ModuleProjectBuilder = moduleProjectBuilder; + PackageProjectBuilder = packageProjectBuilder; Logger = NullLogger.Instance; } - public async Task DownloadAsync(string moduleName, string outputFolder, string version, string gitHubAbpLocalRepositoryPath, string gitHubVoloLocalRepositoryPath, AbpCommandLineOptions options) + public async Task DownloadModuleAsync(string moduleName, string outputFolder, string version, string gitHubAbpLocalRepositoryPath, string gitHubVoloLocalRepositoryPath, AbpCommandLineOptions options) { Logger.LogInformation("Downloading source code of " + moduleName); Logger.LogInformation("Version: " + version); @@ -90,6 +92,62 @@ namespace Volo.Abp.Cli.Commands.Services Logger.LogInformation($"'{moduleName}' has been successfully downloaded to '{outputFolder}'"); } + public async Task DownloadPackageAsync(string packageName, string outputFolder, string version) + { + Logger.LogInformation("Downloading source code of " + packageName); + Logger.LogInformation("Version: " + version); + Logger.LogInformation("Output folder: " + outputFolder); + + var result = await PackageProjectBuilder.BuildAsync( + new ProjectBuildArgs( + SolutionName.Parse(packageName), + packageName, + version + ) + ); + + using (var templateFileStream = new MemoryStream(result.ZipContent)) + { + using (var zipInputStream = new ZipInputStream(templateFileStream)) + { + var zipEntry = zipInputStream.GetNextEntry(); + while (zipEntry != null) + { + if (IsAngularTestFile(zipEntry.Name)) + { + zipEntry = zipInputStream.GetNextEntry(); + continue; + } + + 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($"'{packageName}' has been successfully downloaded to '{outputFolder}'"); + } + private bool IsAngularTestFile(string zipEntryName) { if (string.IsNullOrEmpty(zipEntryName)) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs index bebe44542d..29ea93bd3d 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/AbpIoSourceCodeStore.cs @@ -159,6 +159,11 @@ namespace Volo.Abp.Cli.ProjectBuilding private async Task GetTemplateNugetVersionAsync(string name, string type, string version) { + if (type != SourceCodeTypes.Template) + { + return null; + } + try { var url = $"{CliUrls.WwwAbpIo}api/download/{type}/get-nuget-version/"; diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/PackageProjectBuildPipelineBuilder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/PackageProjectBuildPipelineBuilder.cs new file mode 100644 index 0000000000..79245dfaec --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/PackageProjectBuildPipelineBuilder.cs @@ -0,0 +1,21 @@ +using Volo.Abp.Cli.ProjectBuilding.Building.Steps; +using Volo.Abp.Cli.ProjectBuilding.Templates; + +namespace Volo.Abp.Cli.ProjectBuilding.Building +{ + public static class PackageProjectBuildPipelineBuilder + { + public static ProjectBuildPipeline Build(ProjectBuildContext context) + { + var pipeline = new ProjectBuildPipeline(context); + + pipeline.Steps.Add(new FileEntryListReadStep()); + pipeline.Steps.Add(new ProjectReferenceReplaceStep()); + pipeline.Steps.Add(new ReplaceCommonPropsStep()); + pipeline.Steps.Add(new ReplaceConfigureAwaitPropsStep()); + pipeline.Steps.Add(new CreateProjectResultZipStep()); + + return pipeline; + } + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/ProjectBuildContext.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/ProjectBuildContext.cs index 8b5522165f..b6c2baec88 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/ProjectBuildContext.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/ProjectBuildContext.cs @@ -1,5 +1,7 @@ -using JetBrains.Annotations; +using System.Collections.Generic; +using JetBrains.Annotations; using Volo.Abp.Cli.ProjectBuilding.Files; +using Volo.Abp.Cli.ProjectModification; namespace Volo.Abp.Cli.ProjectBuilding.Building { @@ -15,22 +17,29 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building public ModuleInfo Module { get; } + public NugetPackageInfo Package { get; } + public FileEntryList Files { get; set; } public ProjectResult Result { get; set; } + public List Symbols { get; } //TODO: Fill the symbols, like "UI-Angular", "CMS-KIT"! + public ProjectBuildContext( TemplateInfo template, ModuleInfo module, + NugetPackageInfo package, [NotNull] TemplateFile templateFile, [NotNull] ProjectBuildArgs buildArgs) { Template = template; Module = module; + Package = package; TemplateFile = Check.NotNull(templateFile, nameof(templateFile)); BuildArgs = Check.NotNull(buildArgs, nameof(buildArgs)); + Symbols = new List(); Result = new ProjectResult(); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveCmsKitStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveCmsKitStep.cs deleted file mode 100644 index a0778d5a4d..0000000000 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveCmsKitStep.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Linq; -using Volo.Abp.Cli.ProjectBuilding.Files; - -namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps -{ - public class RemoveCmsKitStep : ProjectBuildPipelineStep - { - public override void Execute(ProjectBuildContext context) - { - var commonFiles = context.Files.Where(f => - f.Name.EndsWith(".csproj") || - f.Name.EndsWith(".cs") || - f.Name.EndsWith(".json") || - f.Name.EndsWith(".cshtml")); - - foreach (var file in commonFiles) - { - file.RemoveTemplateCodeIfNot("CMS-KIT"); - } - } - } -} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveEfCoreRelatedCodeStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveEfCoreRelatedCodeStep.cs deleted file mode 100644 index df8f18128e..0000000000 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveEfCoreRelatedCodeStep.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Linq; -using Volo.Abp.Cli.ProjectBuilding.Files; - -namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps -{ - public class RemoveEfCoreRelatedCodeStep : ProjectBuildPipelineStep - { - public override void Execute(ProjectBuildContext context) - { - foreach (var file in context.Files) - { - if (file.Name.EndsWith(".cs") || file.Name.EndsWith(".csproj") || file.Name.EndsWith(".json")) - { - file.RemoveTemplateCodeIfNot("EFCORE"); - } - } - } - } -} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveGlobalFeaturesPackageStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveGlobalFeaturesPackageStep.cs deleted file mode 100644 index 15a84576c6..0000000000 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemoveGlobalFeaturesPackageStep.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Linq; -using Volo.Abp.Cli.ProjectBuilding.Files; - -namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps -{ - public class RemoveGlobalFeaturesPackageStep : ProjectBuildPipelineStep - { - public override void Execute(ProjectBuildContext context) - { - var commonFiles = context.Files.Where(f => - f.Name.EndsWith(".csproj") || - f.Name.EndsWith(".cs") || - f.Name.EndsWith(".cshtml")); - - foreach (var file in commonFiles) - { - file.RemoveTemplateCodeIf("CMS-KIT"); - } - } - } -} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemovePublicRedisStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemovePublicRedisStep.cs deleted file mode 100644 index eced4fd3e5..0000000000 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/RemovePublicRedisStep.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Linq; -using Volo.Abp.Cli.ProjectBuilding.Files; - -namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps -{ - public class RemovePublicRedisStep : ProjectBuildPipelineStep - { - public override void Execute(ProjectBuildContext context) - { - foreach (var file in context.Files) - { - if (file.Name.EndsWith(".cs") || file.Name.EndsWith(".csproj") || file.Name.EndsWith(".json")) - { - file.RemoveTemplateCodeIfNot("PUBLIC-REDIS"); - } - } - } - } -} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/TemplateCodeDeleteStep.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/TemplateCodeDeleteStep.cs index 8f17b90702..9b1183ba9a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/TemplateCodeDeleteStep.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/TemplateCodeDeleteStep.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps { if (file.Name.EndsWith(".cs") || file.Name.EndsWith(".csproj") || file.Name.EndsWith(".cshtml") || file.Name.EndsWith(".json")) { - file.RemoveTemplateCode(); + file.RemoveTemplateCode(context.Symbols); file.RemoveTemplateCodeMarkers(); } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Files/FileEntryExtensions.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Files/FileEntryExtensions.cs index 34200d41ac..bfc3d93ad1 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Files/FileEntryExtensions.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Files/FileEntryExtensions.cs @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using System.Linq; namespace Volo.Abp.Cli.ProjectBuilding.Files { @@ -11,19 +13,9 @@ namespace Volo.Abp.Cli.ProjectBuilding.Files return file; } - public static void RemoveTemplateCode(this FileEntry file) + public static void RemoveTemplateCode(this FileEntry file, List symbols) { - RemoveMarkedTemplateCode(file, ""); - } - - public static void RemoveTemplateCodeIf(this FileEntry file, string condition) - { - RemoveByCondition(file, "IF", condition); - } - - public static void RemoveTemplateCodeIfNot(this FileEntry file, string condition) - { - RemoveByCondition(file, "IF-NOT", condition); + RemoveMarkedTemplateCode(file, symbols); } public static void RemoveTemplateCodeMarkers(this FileEntry file) @@ -57,12 +49,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Files file.SetLines(newLines); } - private static void RemoveByCondition(this FileEntry file, string conditionName, string condition) - { - RemoveMarkedTemplateCode(file, $""); - } - - private static void RemoveMarkedTemplateCode(this FileEntry file, string beginMark) + private static void RemoveMarkedTemplateCode(this FileEntry file, List symbols) { if (!file.Content.Contains("")) { @@ -76,8 +63,40 @@ namespace Volo.Abp.Cli.ProjectBuilding.Files for (int i = 0; i < lines.Length; i++) { - if (lines[i].Contains(beginMark)) + if (lines[i].Contains(" !parsedMarker.IsNegativeCondition + ? symbols.Contains(s, StringComparer.InvariantCultureIgnoreCase) + : !symbols.Contains(s, StringComparer.InvariantCultureIgnoreCase)); + } + else if (parsedMarker.Operator == Operator.Or) + { + sectionShouldBeRemoved = !parsedMarker.Symbols.All(s => !parsedMarker.IsNegativeCondition + ? symbols.Contains(s, StringComparer.InvariantCultureIgnoreCase) + : !symbols.Contains(s, StringComparer.InvariantCultureIgnoreCase) == false); + } + + if (!sectionShouldBeRemoved) + { + continue; + } + while (i < lines.Length && !lines[i].Contains("")) { ++i; @@ -94,5 +113,65 @@ namespace Volo.Abp.Cli.ProjectBuilding.Files file.SetLines(newLines); } + + private static TemplateRemoveMarkerParseResult ParseTemplateRemoveMarker(string marker) + { + var result = new TemplateRemoveMarkerParseResult(); + + var condition = marker.Trim() + .RemovePreFix("//").Trim() + .RemovePreFix("@*").Trim() + .RemovePreFix("").Trim() + .RemovePostFix(">").Trim(); + + if (string.IsNullOrWhiteSpace(condition)) + { + return result; + } + + var conditionSplitted = condition.Split("="); + + result.IsNegativeCondition = conditionSplitted[0] == "IF-NOT"; + + var conditionContent = string.Join("=", conditionSplitted.Skip(1)) + .RemovePostFix("\"").RemovePreFix("\"") + .RemovePostFix("'").RemovePreFix("'"); + + if (conditionContent.Contains("&&")) + { + result.Operator = Operator.And; + result.Symbols = conditionContent.Split("&&").ToList(); + } + else if(conditionContent.Contains("||")) + { + result.Operator = Operator.Or; + result.Symbols = conditionContent.Split("||").ToList(); + } + else + { + result.Symbols.Add(conditionContent); + } + + return result; + } + + private class TemplateRemoveMarkerParseResult + { + public List Symbols { get; set; } = new List(); + + public Operator Operator { get; set; } = Operator.None; + + public bool IsNegativeCondition { get; set; } + } + + private enum Operator + { + None, + And, + Or + } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/INugetPackageInfoProvider.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/INugetPackageInfoProvider.cs new file mode 100644 index 0000000000..ddac517f3e --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/INugetPackageInfoProvider.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using Volo.Abp.Cli.ProjectModification; + +namespace Volo.Abp.Cli.ProjectBuilding +{ + public interface INugetPackageInfoProvider + { + Task GetAsync(string name); + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleProjectBuilder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleProjectBuilder.cs index 17b9585f16..029b687015 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleProjectBuilder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ModuleProjectBuilder.cs @@ -67,6 +67,7 @@ namespace Volo.Abp.Cli.ProjectBuilding var context = new ProjectBuildContext( null, moduleInfo, + null, templateFile, args ); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/NugetPackageInfoProvider.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/NugetPackageInfoProvider.cs new file mode 100644 index 0000000000..06c39e66f7 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/NugetPackageInfoProvider.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Json; +using Volo.Abp.Cli.Http; +using Volo.Abp.Cli.ProjectModification; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; + +namespace Volo.Abp.Cli.ProjectBuilding +{ + public class NugetPackageInfoProvider : INugetPackageInfoProvider, ITransientDependency + { + public IJsonSerializer JsonSerializer { get; } + public ICancellationTokenProvider CancellationTokenProvider { get; } + public IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; } + + private readonly CliHttpClientFactory _cliHttpClientFactory; + + public NugetPackageInfoProvider( + IJsonSerializer jsonSerializer, + ICancellationTokenProvider cancellationTokenProvider, + IRemoteServiceExceptionHandler remoteServiceExceptionHandler, + CliHttpClientFactory cliHttpClientFactory) + { + JsonSerializer = jsonSerializer; + CancellationTokenProvider = cancellationTokenProvider; + RemoteServiceExceptionHandler = remoteServiceExceptionHandler; + _cliHttpClientFactory = cliHttpClientFactory; + } + + public async Task GetAsync(string name) + { + var packageList = await GetPackageListInternalAsync(); + + var package = packageList.FirstOrDefault(m => m.Name == name); + + if (package == null) + { + throw new Exception("Package is not found or downloadable!"); + } + + return package; + } + + private async Task> GetPackageListInternalAsync() + { + var client = _cliHttpClientFactory.CreateClient(); + + using (var responseMessage = await client.GetAsync( + $"{CliUrls.WwwAbpIo}api/download/packages/", + CancellationTokenProvider.Token + )) + { + await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage); + var result = await responseMessage.Content.ReadAsStringAsync(); + return JsonSerializer.Deserialize>(result); + } + } + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/PackageProjectBuilder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/PackageProjectBuilder.cs new file mode 100644 index 0000000000..04518332a4 --- /dev/null +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/PackageProjectBuilder.cs @@ -0,0 +1,109 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using System; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Cli.Commands; +using Volo.Abp.Cli.Licensing; +using Volo.Abp.Cli.ProjectBuilding.Analyticses; +using Volo.Abp.Cli.ProjectBuilding.Building; +using Volo.Abp.Cli.ProjectModification; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Json; + +namespace Volo.Abp.Cli.ProjectBuilding +{ + public class PackageProjectBuilder : IProjectBuilder, ITransientDependency + { + public ILogger Logger { get; set; } + protected ISourceCodeStore SourceCodeStore { get; } + protected INugetPackageInfoProvider NugetPackageInfoProvider { get; } + protected ICliAnalyticsCollect CliAnalyticsCollect { get; } + protected AbpCliOptions Options { get; } + protected IJsonSerializer JsonSerializer { get; } + protected IApiKeyService ApiKeyService { get; } + + public PackageProjectBuilder(ISourceCodeStore sourceCodeStore, + INugetPackageInfoProvider nugetPackageInfoProvider, + ICliAnalyticsCollect cliAnalyticsCollect, + IOptions options, + IJsonSerializer jsonSerializer, + IApiKeyService apiKeyService) + { + SourceCodeStore = sourceCodeStore; + NugetPackageInfoProvider = nugetPackageInfoProvider; + CliAnalyticsCollect = cliAnalyticsCollect; + Options = options.Value; + JsonSerializer = jsonSerializer; + ApiKeyService = apiKeyService; + + Logger = NullLogger.Instance; + } + + public async Task BuildAsync(ProjectBuildArgs args) + { + var packageInfo = await GetPackageInfoAsync(args); + + var templateFile = await SourceCodeStore.GetAsync( + args.TemplateName, + SourceCodeTypes.Package, + args.Version, + null, + args.ExtraProperties.ContainsKey(GetSourceCommand.Options.Preview.Long) + ); + + var apiKeyResult = await ApiKeyService.GetApiKeyOrNullAsync(); + if (apiKeyResult?.ApiKey != null) + { + args.ExtraProperties["api-key"] = apiKeyResult.ApiKey; + } + + if (apiKeyResult?.LicenseCode != null) + { + args.ExtraProperties["license-code"] = apiKeyResult.LicenseCode; + } + + var context = new ProjectBuildContext( + null, + null, + packageInfo, + templateFile, + args + ); + + PackageProjectBuildPipelineBuilder.Build(context).Execute(); + + // Exclude unwanted or known options. + var options = args.ExtraProperties + .Where(x => !x.Key.Equals(CliConsts.Command, StringComparison.InvariantCultureIgnoreCase)) + .Where(x => !x.Key.Equals(NewCommand.Options.OutputFolder.Long, StringComparison.InvariantCultureIgnoreCase) && + !x.Key.Equals(NewCommand.Options.OutputFolder.Short, StringComparison.InvariantCultureIgnoreCase)) + .Where(x => !x.Key.Equals(NewCommand.Options.Version.Long, StringComparison.InvariantCultureIgnoreCase) && + !x.Key.Equals(NewCommand.Options.Version.Short, StringComparison.InvariantCultureIgnoreCase)) + .Where(x => !x.Key.Equals(NewCommand.Options.TemplateSource.Short, StringComparison.InvariantCultureIgnoreCase) && + !x.Key.Equals(NewCommand.Options.TemplateSource.Long, StringComparison.InvariantCultureIgnoreCase)) + .Select(x => x.Key).ToList(); + + await CliAnalyticsCollect.CollectAsync(new CliAnalyticsCollectInputDto + { + Tool = Options.ToolName, + Command = args.ExtraProperties.ContainsKey(CliConsts.Command) ? args.ExtraProperties[CliConsts.Command] : "", + DatabaseProvider = null, + IsTiered = null, + UiFramework = null, + Options = JsonSerializer.Serialize(options), + ProjectName = null, + TemplateName = args.TemplateName, + TemplateVersion = templateFile.Version + }); + + return new ProjectBuildResult(context.Result.ZipContent, args.TemplateName); + } + + private async Task GetPackageInfoAsync(ProjectBuildArgs args) + { + return await NugetPackageInfoProvider.GetAsync(args.TemplateName); + } + } +} diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/SourceCodeTypes.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/SourceCodeTypes.cs index 5f7ad58ef7..813ffe6b54 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/SourceCodeTypes.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/SourceCodeTypes.cs @@ -5,5 +5,7 @@ public const string Template = "template"; public const string Module = "module"; + + public const string Package = "package"; } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs index cbbb094d11..5823c3c488 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs @@ -105,6 +105,7 @@ namespace Volo.Abp.Cli.ProjectBuilding var context = new ProjectBuildContext( templateInfo, null, + null, templateFile, args ); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs index b0526a27d2..5e0436d91a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Templates/App/AppTemplateBase.cs @@ -28,6 +28,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App SwitchDatabaseProvider(context, steps); DeleteUnrelatedProjects(context, steps); RemoveMigrations(context, steps); + ConfigureTieredArchitecture(context, steps); ConfigurePublicWebSite(context, steps); RemoveUnnecessaryPorts(context, steps); RandomizeSslPorts(context, steps); @@ -64,7 +65,10 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.EntityFrameworkCore")); steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations")); steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.EntityFrameworkCore.Tests", projectFolderPath: "/aspnet-core/test/MyCompanyName.MyProjectName.EntityFrameworkCore.Tests")); - steps.Add(new RemoveEfCoreRelatedCodeStep()); + } + else + { + context.Symbols.Add("EFCORE"); } if (context.BuildArgs.DatabaseProvider != DatabaseProvider.MongoDb) @@ -144,14 +148,15 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App { if (!context.BuildArgs.PublicWebSite) { - if (!context.BuildArgs.ExtraProperties.ContainsKey(NewCommand.Options.Tiered.Long) && - !context.BuildArgs.ExtraProperties.ContainsKey("separate-identity-server")) + if (context.BuildArgs.ExtraProperties.ContainsKey(NewCommand.Options.Tiered.Long) || + context.BuildArgs.ExtraProperties.ContainsKey("separate-identity-server")) { - steps.Add(new RemovePublicRedisStep()); + context.Symbols.Add("PUBLIC-REDIS"); } - - steps.Add(new RemoveCmsKitStep()); - return; + } + else + { + context.Symbols.Add("public-website"); } if (context.BuildArgs.ExtraProperties.ContainsKey(NewCommand.Options.Tiered.Long) || context.BuildArgs.ExtraProperties.ContainsKey("separate-identity-server")) @@ -164,14 +169,9 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App steps.Add(new ChangePublicAuthPortStep()); } - // We disabled cms-kit for v4.2 release. - if (true || context.BuildArgs.ExtraProperties.ContainsKey("without-cms-kit")) - { - steps.Add(new RemoveCmsKitStep()); - } - else + if (!context.BuildArgs.ExtraProperties.ContainsKey("without-cms-kit")) { - steps.Add(new RemoveGlobalFeaturesPackageStep()); + context.Symbols.Add("CMS-KIT"); } } @@ -197,6 +197,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App private static void ConfigureWithBlazorUi(ProjectBuildContext context, List steps) { + context.Symbols.Add("ui:blazor"); + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web")); steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web.Host")); steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web.Tests", projectFolderPath: "/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests")); @@ -218,6 +220,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App private static void ConfigureWithBlazorServerUi(ProjectBuildContext context, List steps) { + context.Symbols.Add("ui:blazor-server"); + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor")); steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web")); steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web.Host")); @@ -242,6 +246,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App private static void ConfigureWithMvcUi(ProjectBuildContext context, List steps) { + context.Symbols.Add("ui:mvc"); + if (context.BuildArgs.ExtraProperties.ContainsKey("tiered")) { steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web")); @@ -262,6 +268,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App private static void ConfigureWithAngularUi(ProjectBuildContext context, List steps) { + context.Symbols.Add("ui:angular"); + steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web")); steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web.Host")); steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web.Tests", projectFolderPath: "/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests")); @@ -312,6 +320,15 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App ); } + private void ConfigureTieredArchitecture(ProjectBuildContext context, List steps) + { + if (context.BuildArgs.ExtraProperties.ContainsKey(NewCommand.Options.Tiered.Long) || + context.BuildArgs.ExtraProperties.ContainsKey("separate-identity-server")) + { + context.Symbols.Add("tiered"); + } + } + private static void RandomizeStringEncryption(ProjectBuildContext context, List steps) { steps.Add(new RandomizeStringEncryptionStep()); 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 f2b8160d53..8665a80bc3 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 @@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; 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.Utils; @@ -22,6 +23,8 @@ namespace Volo.Abp.Cli.ProjectModification { public ILogger Logger { get; set; } public BundleCommand BundleCommand { get; } + public SourceCodeDownloadService SourceCodeDownloadService { get; } + public SolutionFileModifier SolutionFileModifier { get; } protected IJsonSerializer JsonSerializer { get; } protected ProjectNpmPackageAdder NpmPackageAdder { get; } @@ -38,7 +41,9 @@ namespace Volo.Abp.Cli.ProjectModification ModuleClassDependcyAdder moduleClassDependcyAdder, IRemoteServiceExceptionHandler remoteServiceExceptionHandler, BundleCommand bundleCommand, - CliHttpClientFactory cliHttpClientFactory) + CliHttpClientFactory cliHttpClientFactory, + SourceCodeDownloadService sourceCodeDownloadService, + SolutionFileModifier solutionFileModifier) { JsonSerializer = jsonSerializer; NpmPackageAdder = npmPackageAdder; @@ -46,32 +51,162 @@ namespace Volo.Abp.Cli.ProjectModification ModuleClassDependcyAdder = moduleClassDependcyAdder; RemoteServiceExceptionHandler = remoteServiceExceptionHandler; BundleCommand = bundleCommand; + SourceCodeDownloadService = sourceCodeDownloadService; + SolutionFileModifier = solutionFileModifier; _cliHttpClientFactory = cliHttpClientFactory; Logger = NullLogger.Instance; } - public async Task AddAsync(string projectFile, string packageName, string version = null) + public async Task AddAsync( + string projectFile, + string packageName, + string version = null, + bool useDotnetCliToInstall = true, + bool withSourceCode = false, + bool addSourceCodeToSolutionFile = false) { await AddAsync( projectFile, await FindNugetPackageInfoAsync(packageName), - version + version, + useDotnetCliToInstall, + withSourceCode, + addSourceCodeToSolutionFile ); } - public async Task AddAsync(string projectFile, NugetPackageInfo package, string version = null, - bool useDotnetCliToInstall = true) + public async Task AddAsync( + string projectFile, + NugetPackageInfo package, + string version = null, + bool useDotnetCliToInstall = true, + bool withSourceCode = false, + bool addSourceCodeToSolutionFile = false) { - var projectFileContent = File.ReadAllText(projectFile); + if (version == null) + { + version = GetAbpVersionOrNull(projectFile); + } - if (projectFileContent.Contains($"\"{package.Name}\"")) + await AddAsPackageReference(projectFile, package, version, useDotnetCliToInstall); + + if (withSourceCode) + { + await AddSourceCode(projectFile, package, version); + await ConvertPackageReferenceToProjectReference(projectFile, package); + + if (addSourceCodeToSolutionFile) + { + await SolutionFileModifier.AddPackageToSolutionFileAsync(package, FindSolutionFile(projectFile)); + } + } + } + + private async Task ConvertPackageReferenceToProjectReference(string projectFile, NugetPackageInfo package) + { + var content = File.ReadAllText(projectFile); + var doc = new XmlDocument() {PreserveWhitespace = true}; + + doc.Load(StreamHelper.GenerateStreamFromString(content)); + + var nodes = doc.SelectNodes( + $"/Project/ItemGroup/PackageReference[starts-with(@Include, '{package.Name}')]"); + + if (nodes == null) { return; } - if (version == null) + var downloadedProjectPath = FindRelativeFolderToDownloadPackage(projectFile, package); + var oldNodeIncludeValue = nodes[0]?.Attributes?["Include"]?.Value; + + if (package.Name == oldNodeIncludeValue) + { + var referenceProjectPath = $"{downloadedProjectPath}\\{package.Name}.csproj"; + + var newNode = doc.CreateElement("ProjectReference"); + var includeAttr = doc.CreateAttribute("Include"); + includeAttr.Value = referenceProjectPath; + newNode.Attributes.Append(includeAttr); + + nodes[0]?.ParentNode?.ReplaceChild(newNode, nodes[0]); + } + + File.WriteAllText(projectFile, doc.OuterXml); + } + + private async Task AddSourceCode(string projectFile, NugetPackageInfo package, string version = null) + { + var targetFolder = FindFolderToDownloadPackage(projectFile, package); + + if (Directory.Exists(targetFolder)) + { + Directory.Delete(targetFolder, true); + } + + await DownloadSourceCode(targetFolder, package, version); + } + + private string FindFolderToDownloadPackage(string projectFile, NugetPackageInfo package) + { + return Path.Combine(FindSolutionFolder(projectFile), "packages", package.Name); + } + + private string FindRelativeFolderToDownloadPackage(string projectFile, NugetPackageInfo package) + { + var folder = Path.Combine(FindSolutionFolder(projectFile), "packages", package.Name); + + return new Uri(projectFile).MakeRelativeUri(new Uri(folder)).ToString().Replace("/", "\\"); + } + + private async Task DownloadSourceCode(string targetFolder, NugetPackageInfo package, string version = null) + { + await SourceCodeDownloadService.DownloadPackageAsync( + package.Name, + targetFolder, + version + ); + } + + private string FindSolutionFile(string projectFile) + { + var folder = FindSolutionFolder(projectFile); + + return Directory.GetFiles(folder, "*.sln", SearchOption.TopDirectoryOnly).FirstOrDefault(); + } + + private string FindSolutionFolder(string projectFile) + { + var targetFolder = Path.GetDirectoryName(projectFile); + + do + { + if (Directory.GetParent(targetFolder) != null) + { + targetFolder = Directory.GetParent(targetFolder).FullName; + } + else + { + return Path.GetDirectoryName(projectFile); + } + + if (Directory.GetFiles(targetFolder, "*.sln", SearchOption.TopDirectoryOnly).Any()) + { + break; + } + } while (targetFolder != null); + + return targetFolder; + } + + private async Task AddAsPackageReference(string projectFile, NugetPackageInfo package, string version, + bool useDotnetCliToInstall) + { + var projectFileContent = File.ReadAllText(projectFile); + + if (projectFileContent.Contains($"\"{package.Name}\"")) { - version = GetAbpVersionOrNull(projectFileContent); + return; } using (DirectoryHelper.ChangeCurrentDirectory(Path.GetDirectoryName(projectFile))) @@ -105,7 +240,9 @@ namespace Volo.Abp.Cli.ProjectModification ModuleClassDependcyAdder.Add(moduleFiles.First(), package.ModuleClass); } - if (useDotnetCliToInstall && (package.Target == NuGetPackageTarget.Blazor || package.Target == NuGetPackageTarget.BlazorServer || package.Target == NuGetPackageTarget.BlazorWebAssembly)) + if (useDotnetCliToInstall && (package.Target == NuGetPackageTarget.Blazor || + package.Target == NuGetPackageTarget.BlazorServer || + package.Target == NuGetPackageTarget.BlazorWebAssembly)) { await RunBundleForBlazorAsync(projectFile); } @@ -125,7 +262,7 @@ namespace Volo.Abp.Cli.ProjectModification private Task AddToCsprojManuallyAsync(string projectFile, NugetPackageInfo package, string version = null) { var projectFileContent = File.ReadAllText(projectFile); - var doc = new XmlDocument() { PreserveWhitespace = true }; + var doc = new XmlDocument() {PreserveWhitespace = true}; doc.Load(StreamHelper.GenerateStreamFromString(projectFileContent)); var itemGroupNodes = doc.SelectNodes("/Project/ItemGroup"); @@ -164,9 +301,11 @@ namespace Volo.Abp.Cli.ProjectModification return Task.CompletedTask; } - private string GetAbpVersionOrNull(string projectFileContent) + private string GetAbpVersionOrNull(string projectFile) { - var doc = new XmlDocument() { PreserveWhitespace = true }; + var projectFileContent = File.ReadAllText(projectFile); + + 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 9eda6efa10..ac40e8fb3b 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 @@ -15,7 +15,8 @@ namespace Volo.Abp.Cli.ProjectModification var solutionFileContent = File.ReadAllText(solutionFile); solutionFileContent.NormalizeLineEndings(); var lines = solutionFileContent.Split(new[] {Environment.NewLine, "\n"}, StringSplitOptions.None); - File.WriteAllText(solutionFile, RemoveProject(lines.ToList(), projectName).JoinAsString(Environment.NewLine)); + File.WriteAllText(solutionFile, + RemoveProject(lines.ToList(), projectName).JoinAsString(Environment.NewLine)); } public async Task AddModuleToSolutionFileAsync(ModuleWithMastersInfo module, string solutionFile) @@ -23,6 +24,49 @@ namespace Volo.Abp.Cli.ProjectModification await AddModuleAsync(module, solutionFile); } + public async Task AddPackageToSolutionFileAsync(NugetPackageInfo package, string solutionFile) + { + await AddPackageAsync(package, solutionFile); + } + + private async Task AddPackageAsync(NugetPackageInfo package, string solutionFile) + { + var srcFolderId = await AddNewFolderAndGetIdOrGetExistingIdAsync(solutionFile, "src"); + + var file = File.ReadAllText(solutionFile); + var lines = file.Split(Environment.NewLine).ToList(); + + if (lines.Any(l => l.Contains($"\"{package.Name}\""))) + { + return; + } + + var projectGuid = Guid.NewGuid().ToString(); + + var newProjectLine = "Project(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"" + package.Name + "\"," + + " \"packages\\" + package.Name + "\\" + + "\\" + package.Name + ".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 + "} = {" + srcFolderId + "}"; + + lines.InsertAfter(l => l.Contains("GlobalSection") && l.Contains("NestedProjects"), newPreSolutionLine); + + File.WriteAllText(solutionFile, string.Join(Environment.NewLine, lines)); + } + private List RemoveProject(List solutionFileLines, string projectName) { var projectKey = FindProjectKey(solutionFileLines, projectName); @@ -63,7 +107,8 @@ namespace Volo.Abp.Cli.ProjectModification { var curlyBracketStartIndex = solutionFileLine.LastIndexOf("{", StringComparison.OrdinalIgnoreCase); var curlyBracketEndIndex = solutionFileLine.LastIndexOf("}", StringComparison.OrdinalIgnoreCase); - return solutionFileLine.Substring(curlyBracketStartIndex + 1, curlyBracketEndIndex - curlyBracketStartIndex - 1); + return solutionFileLine.Substring(curlyBracketStartIndex + 1, + curlyBracketEndIndex - curlyBracketStartIndex - 1); } } @@ -72,13 +117,14 @@ namespace Volo.Abp.Cli.ProjectModification 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")); + var srcModuleFolderId = await AddNewFolderAndGetIdOrGetExistingIdAsync(solutionFile, module.Name, + await AddNewFolderAndGetIdOrGetExistingIdAsync(solutionFile, "modules")); + var testModuleFolderId = await AddNewFolderAndGetIdOrGetExistingIdAsync(solutionFile, module.Name + ".Tests", + await AddNewFolderAndGetIdOrGetExistingIdAsync(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", @@ -92,7 +138,7 @@ namespace Volo.Abp.Cli.ProjectModification foreach (var projectPath in projectsUnderModule) { var parentFolderId = projectsUnderTest.Contains(projectPath) ? testModuleFolderId : srcModuleFolderId; - var projectId = Path.GetFileName(projectPath).Replace(".csproj",""); + var projectId = Path.GetFileName(projectPath).Replace(".csproj", ""); var projectParentFolderInModule = projectsUnderTest.Contains(projectPath) ? "test" : "src"; if (lines.Any(l => l.Contains($"\"{projectId}\""))) @@ -103,8 +149,9 @@ namespace Volo.Abp.Cli.ProjectModification 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"; + " \"modules\\" + module.Name + "\\" + projectParentFolderInModule + "\\" + + projectId + "\\" + projectId + ".csproj\", \"{" + projectGuid + "}\"" + + Environment.NewLine + "EndProject"; lines.InsertAfter(l => l.Trim().Equals("EndProject"), newProjectLine); @@ -114,12 +161,13 @@ namespace Volo.Abp.Cli.ProjectModification " {" + 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); + lines.InsertAfter(l => l.Contains("GlobalSection") && l.Contains("ProjectConfigurationPlatforms"), + newPostSolutionLine); var newPreSolutionLine = - " {"+ projectGuid + "} = {"+ parentFolderId + "}"; + " {" + projectGuid + "} = {" + parentFolderId + "}"; - lines.InsertAfter(l=>l.Contains("GlobalSection") && l.Contains("NestedProjects"), newPreSolutionLine); + lines.InsertAfter(l => l.Contains("GlobalSection") && l.Contains("NestedProjects"), newPreSolutionLine); } File.WriteAllText(solutionFile, string.Join(Environment.NewLine, lines)); @@ -133,19 +181,21 @@ namespace Volo.Abp.Cli.ProjectModification } } - private async Task AddNewFolderAndGetIdOrGetExistingId(string solutionFile, string folderName, string parentFolderId = null) + private async Task AddNewFolderAndGetIdOrGetExistingIdAsync(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 + "\"")); + 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 + "}\"" + var newFolderLine = "Project(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"" + folderName + "\", \"" + + folderName + "\", \"{" + folderId + "}\"" + Environment.NewLine + "EndProject"; lines.InsertAfter(l => l.Trim().Equals("EndProject"), newFolderLine); @@ -155,7 +205,8 @@ namespace Volo.Abp.Cli.ProjectModification var newPreSolutionLine = " {" + folderId + "} = {" + parentFolderId + "}"; - lines.InsertAfter(l => l.Contains("GlobalSection") && l.Contains("NestedProjects"), newPreSolutionLine); + lines.InsertAfter(l => l.Contains("GlobalSection") && l.Contains("NestedProjects"), + newPreSolutionLine); } } else 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 44d8c26a9f..caf47e0a87 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 @@ -365,7 +365,7 @@ namespace Volo.Abp.Cli.ProjectModification } else { - await SourceCodeDownloadService.DownloadAsync( + await SourceCodeDownloadService.DownloadModuleAsync( module.Name, targetModuleFolder, version, diff --git a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ConsumerPool.cs b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ConsumerPool.cs index b2995d1079..73f3ad72a7 100644 --- a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ConsumerPool.cs +++ b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ConsumerPool.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; using Confluent.Kafka; @@ -15,7 +14,7 @@ namespace Volo.Abp.Kafka { protected AbpKafkaOptions Options { get; } - protected ConcurrentDictionary> Consumers { get; } + protected ConcurrentDictionary>> Consumers { get; } protected TimeSpan TotalDisposeWaitDuration { get; set; } = TimeSpan.FromSeconds(10); @@ -27,7 +26,7 @@ namespace Volo.Abp.Kafka { Options = options.Value; - Consumers = new ConcurrentDictionary>(); + Consumers = new ConcurrentDictionary>>(); Logger = new NullLogger(); } @@ -36,7 +35,7 @@ namespace Volo.Abp.Kafka connectionName ??= KafkaConnections.DefaultConnectionName; return Consumers.GetOrAdd( - connectionName, connection => + connectionName, connection => new Lazy>(() => { var config = new ConsumerConfig(Options.Connections.GetOrDefault(connection)) { @@ -45,10 +44,9 @@ namespace Volo.Abp.Kafka }; Options.ConfigureConsumer?.Invoke(config); - return new ConsumerBuilder(config).Build(); - } - ); + }) + ).Value; } public void Dispose() @@ -78,8 +76,8 @@ namespace Volo.Abp.Kafka try { - consumer.Close(); - consumer.Dispose(); + consumer.Value.Close(); + consumer.Value.Dispose(); } catch { diff --git a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ProducerPool.cs b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ProducerPool.cs index c4b4b9ead0..3381e373da 100644 --- a/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ProducerPool.cs +++ b/framework/src/Volo.Abp.Kafka/Volo/Abp/Kafka/ProducerPool.cs @@ -14,7 +14,7 @@ namespace Volo.Abp.Kafka { protected AbpKafkaOptions Options { get; } - protected ConcurrentDictionary> Producers { get; } + protected ConcurrentDictionary>> Producers { get; } protected TimeSpan TotalDisposeWaitDuration { get; set; } = TimeSpan.FromSeconds(10); @@ -26,7 +26,7 @@ namespace Volo.Abp.Kafka { Options = options.Value; - Producers = new ConcurrentDictionary>(); + Producers = new ConcurrentDictionary>>(); Logger = new NullLogger(); } @@ -35,14 +35,14 @@ namespace Volo.Abp.Kafka connectionName ??= KafkaConnections.DefaultConnectionName; return Producers.GetOrAdd( - connectionName, connection => + connectionName, connection => new Lazy>(() => { var config = Options.Connections.GetOrDefault(connection); Options.ConfigureProducer?.Invoke(new ProducerConfig(config)); return new ProducerBuilder(config).Build(); - }); + })).Value; } public void Dispose() @@ -72,7 +72,7 @@ namespace Volo.Abp.Kafka try { - producer.Dispose(); + producer.Value.Dispose(); } catch { diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ConnectionPool.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ConnectionPool.cs index 7ca8346d11..c227d978a1 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ConnectionPool.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/ConnectionPool.cs @@ -1,4 +1,5 @@ -using System.Collections.Concurrent; +using System; +using System.Collections.Concurrent; using System.Collections.Generic; using Microsoft.Extensions.Options; using RabbitMQ.Client; @@ -10,14 +11,14 @@ namespace Volo.Abp.RabbitMQ { protected AbpRabbitMqOptions Options { get; } - protected ConcurrentDictionary Connections { get; } + protected ConcurrentDictionary> Connections { get; } private bool _isDisposed; public ConnectionPool(IOptions options) { Options = options.Value; - Connections = new ConcurrentDictionary(); + Connections = new ConcurrentDictionary>(); } public virtual IConnection Get(string connectionName = null) @@ -25,15 +26,15 @@ namespace Volo.Abp.RabbitMQ connectionName ??= RabbitMqConnections.DefaultConnectionName; return Connections.GetOrAdd( - connectionName, - () => + connectionName, () => new Lazy(() => { var connection = Options.Connections.GetOrDefault(connectionName); var hostnames = connection.HostName.TrimEnd(';').Split(';'); // Handle Rabbit MQ Cluster. return hostnames.Length == 1 ? connection.CreateConnection() : connection.CreateConnection(hostnames); - } - ); + + }) + ).Value; } public void Dispose() @@ -49,7 +50,7 @@ namespace Volo.Abp.RabbitMQ { try { - connection.Dispose(); + connection.Value.Dispose(); } catch { diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/create.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/create.js index a21737ad30..5dc97f4492 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/create.js +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/create.js @@ -232,7 +232,7 @@ useCommandShortcut: true, initialValue: initialValue, previewStyle: 'tab', - height: "25em", + height: "95vh", minHeight: "25em", initialEditType: initialValue ? 'wysiwyg' : 'markdown', language: $editorContainer.data("language"), diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js index b4cbc2a5ff..d5cb5e9ac2 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/BlogPosts/update.js @@ -178,7 +178,7 @@ useCommandShortcut: true, initialValue: initialValue, previewStyle: 'tab', - height: "25em", + height: "95vh", minHeight: "25em", initialEditType: initialValue ? 'wysiwyg' : 'markdown', language: $editorContainer.data("language"), diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/create.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/create.js index 17ace2cbfc..f01ba0c4a9 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/create.js +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/create.js @@ -86,7 +86,7 @@ useCommandShortcut: true, initialValue: initialValue, previewStyle: 'tab', - height: "25em", + height: "95vh", minHeight: "25em", initialEditType: initialValue ? 'wysiwyg' : 'markdown', language: $editorContainer.data("language"), diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/update.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/update.js index 189d88f0c7..3d2dbd8834 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/update.js +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Pages/update.js @@ -61,7 +61,7 @@ useCommandShortcut: true, initialValue: initialValue, previewStyle: 'tab', - height: "25em", + height: "95vh", minHeight: "25em", initialEditType: initialValue ? 'wysiwyg' : 'markdown', language: $editorContainer.data("language"),