CLI refactor, test & improvements.

pull/1126/head
Halil ibrahim Kalkan 7 years ago
parent da0a03dc43
commit f369fc34fd

@ -224,15 +224,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.FluentValidation",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.FluentValidation.Tests", "test\Volo.Abp.FluentValidation.Tests\Volo.Abp.FluentValidation.Tests.csproj", "{E9E1714F-7ED2-4BD1-BA4A-BA06E398288A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Cli.Tests", "test\Volo.Abp.Cli.Tests\Volo.Abp.Cli.Tests.csproj", "{92B70EFF-C1B1-4D1D-8BCE-D116908FC6FF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EntityFrameworkCore.Sqlite", "src\Volo.Abp.EntityFrameworkCore.Sqlite\Volo.Abp.EntityFrameworkCore.Sqlite.csproj", "{58CF8957-5045-4F81-884D-72DF48F721CC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Cli.Core", "src\Volo.Abp.Cli.Core\Volo.Abp.Cli.Core.csproj", "{3DA9923E-048E-4FE7-9748-3A0194F5D196}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Specifications", "src\Volo.Abp.Specifications\Volo.Abp.Specifications.csproj", "{2C621EED-563C-4F81-A75E-50879E173544}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Specifications.Tests", "test\Volo.Abp.Specifications.Tests\Volo.Abp.Specifications.Tests.csproj", "{D078553A-C70C-4F56-B3E2-9C5BA6384C72}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Specifications.Tests", "test\Volo.Abp.Specifications.Tests\Volo.Abp.Specifications.Tests.csproj", "{D078553A-C70C-4F56-B3E2-9C5BA6384C72}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Cli.Core.Tests", "test\Volo.Abp.Cli.Core.Tests\Volo.Abp.Cli.Core.Tests.csproj", "{F006B0B4-F25D-4511-9FB3-F17AA44BDCEA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -676,10 +676,6 @@ Global
{E9E1714F-7ED2-4BD1-BA4A-BA06E398288A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E9E1714F-7ED2-4BD1-BA4A-BA06E398288A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E9E1714F-7ED2-4BD1-BA4A-BA06E398288A}.Release|Any CPU.Build.0 = Release|Any CPU
{92B70EFF-C1B1-4D1D-8BCE-D116908FC6FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{92B70EFF-C1B1-4D1D-8BCE-D116908FC6FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{92B70EFF-C1B1-4D1D-8BCE-D116908FC6FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{92B70EFF-C1B1-4D1D-8BCE-D116908FC6FF}.Release|Any CPU.Build.0 = Release|Any CPU
{58CF8957-5045-4F81-884D-72DF48F721CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{58CF8957-5045-4F81-884D-72DF48F721CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{58CF8957-5045-4F81-884D-72DF48F721CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -696,6 +692,10 @@ Global
{D078553A-C70C-4F56-B3E2-9C5BA6384C72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D078553A-C70C-4F56-B3E2-9C5BA6384C72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D078553A-C70C-4F56-B3E2-9C5BA6384C72}.Release|Any CPU.Build.0 = Release|Any CPU
{F006B0B4-F25D-4511-9FB3-F17AA44BDCEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F006B0B4-F25D-4511-9FB3-F17AA44BDCEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F006B0B4-F25D-4511-9FB3-F17AA44BDCEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F006B0B4-F25D-4511-9FB3-F17AA44BDCEA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -810,11 +810,11 @@ Global
{69168816-4394-4DDA-BB6B-C21983D37F0B} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{43D5FE61-ECBF-4B16-AD95-0043E18EB93A} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{E9E1714F-7ED2-4BD1-BA4A-BA06E398288A} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{92B70EFF-C1B1-4D1D-8BCE-D116908FC6FF} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{58CF8957-5045-4F81-884D-72DF48F721CC} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{3DA9923E-048E-4FE7-9748-3A0194F5D196} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{2C621EED-563C-4F81-A75E-50879E173544} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{D078553A-C70C-4F56-B3E2-9C5BA6384C72} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{F006B0B4-F25D-4511-9FB3-F17AA44BDCEA} = {447C8A77-E5F0-4538-8687-7383196D04EA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

@ -13,7 +13,10 @@ namespace Volo.Abp.Cli.ProjectModification
{
var moduleFilePaths = new List<string>();
var csFiles = GetAllCsFilesUnderDirectory(Path.GetDirectoryName(csprojFilePath), new List<string>());
var csFiles = new DirectoryInfo(Path.GetDirectoryName(csprojFilePath))
.GetFiles("*Module.cs", SearchOption.AllDirectories) //TODO: Module assumption is not so good!
.Select(f => f.FullName)
.ToList();
foreach (var csFile in csFiles)
{
@ -35,25 +38,5 @@ namespace Volo.Abp.Cli.ProjectModification
return classDeclaration.BaseList?.Types
.Any(t => t.ToString().Contains("AbpModule")) ?? false;
}
protected virtual List<string> GetAllCsFilesUnderDirectory(string path, List<string> allCsFileList)
{
var directory = new DirectoryInfo(path);
var files = directory.GetFiles("*.cs").Select(f => f.DirectoryName + "\\" + f.Name).ToList();
foreach (var s in files)
{
allCsFileList.Add(s);
}
var directories = directory.GetDirectories().Select(d => path + "\\" + d.Name).ToList();
foreach (var subDirectory in directories)
{
allCsFileList = GetAllCsFilesUnderDirectory(subDirectory, allCsFileList);
}
return allCsFileList;
}
}
}

@ -78,7 +78,7 @@ namespace Volo.Abp.Cli.ProjectModification
protected virtual string GetDependsOnAttribute(string moduleName)
{
return "[DependsOn(" + moduleName + ")]" + Environment.NewLine + " ";
return "[DependsOn(typeof(" + moduleName + "))]" + Environment.NewLine + " ";
}
protected virtual string GetUsingStatement(string nameSpace)

@ -0,0 +1,10 @@
using System;
namespace Volo.Abp.Cli.ProjectModification
{
[Flags]
public enum NpmApplicationType
{
Mvc = 1
}
}

@ -4,6 +4,6 @@
{
public string Name { get; set; }
public int ApplicationType { get; set; } //TODO: Enum?
public NpmApplicationType ApplicationType { get; set; }
}
}

@ -7,7 +7,5 @@
public string ModuleClass { get; set; }
public NuGetPackageTarget Target { get; set; }
public NpmPackageInfo DependedNpmPackage { get; set; }
}
}

@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Volo.Abp.Cli.ProjectModification
{
public static class ProjectFinder
{
public static string FindNuGetTargetProjectFile(string[] projectFiles, NuGetPackageTarget target)
{
if (!projectFiles.Any())
{
return null;
}
var assemblyNames = GetAssemblyNames(projectFiles);
switch (target)
{
case NuGetPackageTarget.Web:
return FindProjectEndsWith(projectFiles, assemblyNames, ".Web");
case NuGetPackageTarget.EntityFrameworkCore:
return FindProjectEndsWith(projectFiles, assemblyNames, ".EntityFrameworkCore");
case NuGetPackageTarget.MongoDB:
return FindProjectEndsWith(projectFiles, assemblyNames, ".MongoDB");
case NuGetPackageTarget.Application:
return FindProjectEndsWith(projectFiles, assemblyNames, ".Application") ??
FindProjectEndsWith(projectFiles, assemblyNames, ".Web");
case NuGetPackageTarget.ApplicationContracts:
return FindProjectEndsWith(projectFiles, assemblyNames, ".Application.Contracts");
case NuGetPackageTarget.Domain:
return FindProjectEndsWith(projectFiles, assemblyNames, ".Domain") ??
FindProjectEndsWith(projectFiles, assemblyNames, ".Application") ??
FindProjectEndsWith(projectFiles, assemblyNames, ".Web");
case NuGetPackageTarget.DomainShared:
return FindProjectEndsWith(projectFiles, assemblyNames, ".Domain.Shared");
case NuGetPackageTarget.HttpApi:
return FindProjectEndsWith(projectFiles, assemblyNames, ".HttpApi");
case NuGetPackageTarget.HttpApiClient:
return FindProjectEndsWith(projectFiles, assemblyNames, ".HttpApi.Client");
default:
throw new ApplicationException($"{nameof(NuGetPackageTarget)}.{target} has not implemented!");
}
}
public static string[] FindNpmTargetProjectFile(string[] projectFiles)
{
if (!projectFiles.Any())
{
return Array.Empty<string>();
}
var assemblyNames = GetAssemblyNames(projectFiles);
var projects = new List<string>();
var project = FindProjectEndsWith(projectFiles, assemblyNames, ".Web.Host");
if (project != null)
{
projects.Add(project);
}
project = FindProjectEndsWith(projectFiles, assemblyNames, ".Host", ".HttpApi.Host");
if (project != null)
{
projects.Add(project);
}
if (projects.Any())
{
return projects.ToArray();
}
project = FindProjectEndsWith(projectFiles, assemblyNames, ".Web");
if (project != null)
{
projects.Add(project);
}
return projects.ToArray();
}
public static string[] GetProjectFiles(string solutionFile)
{
var baseProjectFolder = GetBaseProjectFolder(solutionFile);
return Directory.GetFiles(baseProjectFolder, "*.csproj", SearchOption.AllDirectories);
}
public static string[] GetAssemblyNames(string[] projectFiles)
{
return projectFiles.Select(GetAssemblyName).ToArray();
}
public static string GetAssemblyName(string projectFile)
{
return projectFile
.Substring(projectFile.LastIndexOf(Path.DirectorySeparatorChar) + 1)
.RemovePostFix(StringComparison.OrdinalIgnoreCase, ".csproj");
}
private static string FindProjectEndsWith(
string[] projectFiles,
string[] assemblyNames,
string postfix,
string excludePostfix = null)
{
for (var i = 0; i < assemblyNames.Length; i++)
{
var assemblyName = assemblyNames[i];
if(assemblyName.EndsWith(postfix, StringComparison.OrdinalIgnoreCase) &&
(excludePostfix == null || !assemblyName.EndsWith(excludePostfix)))
{
return projectFiles[i];
}
}
return null;
}
private static string GetBaseProjectFolder(string solutionFile)
{
var baseFolder = Path.GetDirectoryName(solutionFile);
var srcFolder = Path.Combine(baseFolder, "src");
if (Directory.Exists(srcFolder))
{
baseFolder = srcFolder;
}
return baseFolder;
}
}
}

@ -65,16 +65,10 @@ namespace Volo.Abp.Cli.ProjectModification
ModuleClassDependcyAdder.Add(moduleFiles.First(), package.ModuleClass);
if (package.DependedNpmPackage != null)
{
await NpmPackageAdder.AddAsync(Path.GetDirectoryName(projectFile), package.DependedNpmPackage);
}
Logger.LogInformation("Successfully installed.");
}
}
protected virtual async Task<NugetPackageInfo> FindNugetPackageInfoAsync(string moduleName)
{
using (var client = new HttpClient())

@ -1,12 +1,13 @@
using System;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
@ -18,107 +19,64 @@ namespace Volo.Abp.Cli.ProjectModification
protected IJsonSerializer JsonSerializer { get; }
protected ProjectNugetPackageAdder ProjectNugetPackageAdder { get; }
protected ProjectNpmPackageAdder ProjectNpmPackageAdder { get; }
public SolutionModuleAdder(
IJsonSerializer jsonSerializer,
ProjectNugetPackageAdder projectNugetPackageAdder)
IJsonSerializer jsonSerializer,
ProjectNugetPackageAdder projectNugetPackageAdder,
ProjectNpmPackageAdder projectNpmPackageAdder)
{
JsonSerializer = jsonSerializer;
ProjectNugetPackageAdder = projectNugetPackageAdder;
ProjectNpmPackageAdder = projectNpmPackageAdder;
Logger = NullLogger<SolutionModuleAdder>.Instance;
}
public virtual async Task AddAsync(
[NotNull] string solutionFile,
[NotNull] string solutionFile,
[NotNull] string moduleName)
{
Check.NotNull(solutionFile, nameof(solutionFile));
Check.NotNull(moduleName, nameof(moduleName));
var module = await FindModuleInfoAsync(moduleName);
var projectFiles = GetProjectFiles(solutionFile);
Logger.LogInformation($"Installing module '{module.Name}' to the solution '{Path.GetFileNameWithoutExtension(solutionFile)}'");
var projectFiles = ProjectFinder.GetProjectFiles(solutionFile);
foreach (var nugetPackage in module.NugetPackages)
{
var targetProjectFile = FindTargetProjectFile(projectFiles, nugetPackage.Target);
var targetProjectFile = ProjectFinder.FindNuGetTargetProjectFile(projectFiles, nugetPackage.Target);
if (targetProjectFile == null)
{
Logger.LogDebug($"Target project is not available for NuGet package '{nugetPackage.Name}'");
continue;
}
await ProjectNugetPackageAdder.AddAsync(targetProjectFile, nugetPackage);
}
}
private string FindTargetProjectFile(string[] projectFiles, NuGetPackageTarget target)
{
if (!projectFiles.Any())
{
return null;
}
var assemblyNames = projectFiles
.Select(
filePath => filePath
.Replace("\\", "/")
.Substring(filePath.LastIndexOf("/", StringComparison.OrdinalIgnoreCase) + 1)
.RemovePostFix(StringComparison.OrdinalIgnoreCase, ".csproj")
).ToArray();
switch (target)
if (!module.NpmPackages.IsNullOrEmpty())
{
case NuGetPackageTarget.Web:
return FindProjectEndsWith(assemblyNames, ".Web");
case NuGetPackageTarget.EntityFrameworkCore:
return FindProjectEndsWith(assemblyNames, ".EntityFrameworkCore") ??
FindProjectEndsWith(assemblyNames, ".Web");
case NuGetPackageTarget.MongoDB:
return FindProjectEndsWith(assemblyNames, ".MongoDB") ??
FindProjectEndsWith(assemblyNames, ".Web");
case NuGetPackageTarget.Application:
return FindProjectEndsWith(assemblyNames, ".Application") ??
FindProjectEndsWith(assemblyNames, ".Web");
case NuGetPackageTarget.ApplicationContracts:
return FindProjectEndsWith(assemblyNames, ".Application.Contracts");
case NuGetPackageTarget.Domain:
return FindProjectEndsWith(assemblyNames, ".Domain") ??
FindProjectEndsWith(assemblyNames, ".Application") ??
FindProjectEndsWith(assemblyNames, ".Web");
case NuGetPackageTarget.DomainShared:
return FindProjectEndsWith(assemblyNames, ".Domain.Shared");
case NuGetPackageTarget.HttpApi:
return FindProjectEndsWith(assemblyNames, ".HttpApi") ??
FindProjectEndsWith(assemblyNames, ".Web");
case NuGetPackageTarget.HttpApiClient:
return FindProjectEndsWith(assemblyNames, ".HttpApi.Client");
default:
throw new ApplicationException($"{nameof(NuGetPackageTarget)} has not implemented: {target}");
}
}
private static string FindProjectEndsWith(string[] projectAssemblyNames, string postfix)
{
return projectAssemblyNames.FirstOrDefault(p => p.EndsWith(postfix, StringComparison.OrdinalIgnoreCase));
}
protected virtual string[] GetProjectFiles(string solutionFile)
{
var baseProjectFolder = GetBaseProjectFolder(solutionFile);
return Directory.GetFiles(baseProjectFolder, "*.csproj", SearchOption.AllDirectories);
}
protected virtual string GetBaseProjectFolder(string solutionFile)
{
var baseFolder = Path.GetDirectoryName(solutionFile);
var srcFolder = Path.Combine(baseFolder, "src");
if (Directory.Exists(srcFolder))
{
baseFolder = srcFolder;
var targetProjects = ProjectFinder.FindNpmTargetProjectFile(projectFiles);
if (targetProjects.Any())
{
foreach (var targetProject in targetProjects)
{
foreach (var npmPackage in module.NpmPackages.Where(p => p.ApplicationType.HasFlag(NpmApplicationType.Mvc)))
{
await ProjectNpmPackageAdder.AddAsync(Path.GetDirectoryName(targetProject), npmPackage);
}
}
}
else
{
Logger.LogDebug("Target project is not available for NPM packages.");
}
}
return baseFolder;
}
protected virtual async Task<ModuleInfo> FindModuleInfoAsync(string moduleName)
{
using (var client = new HttpClient())

@ -14,7 +14,11 @@ namespace Volo.Abp.Cli
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("Volo.Abp", LogEventLevel.Warning)
#if DEBUG
.MinimumLevel.Override("Volo.Abp.Cli", LogEventLevel.Debug)
#else
.MinimumLevel.Override("Volo.Abp.Cli", LogEventLevel.Information)
#endif
.Enrich.FromLogContext()
.WriteTo.File(Path.Combine(CliPaths.Log, "abp-cli-logs.txt"))
.WriteTo.Console()

@ -8,7 +8,7 @@
<ItemGroup>
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Cli\Volo.Abp.Cli.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Cli.Core\Volo.Abp.Cli.Core.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
</ItemGroup>

@ -4,7 +4,7 @@ namespace Volo.Abp.Cli
{
[DependsOn(
typeof(AbpTestBaseModule),
typeof(AbpCliModule)
typeof(AbpCliCoreModule)
)]
public class AbpCliTestModule : AbpModule
{

@ -0,0 +1,46 @@
using System.IO;
using Shouldly;
using Volo.Abp.Cli.ProjectModification;
using Xunit;
namespace Volo.Abp.Cli
{
public class ProjectFinder_Tests
{
[Fact]
public void FindNpmTargetProjectFile_Tests()
{
var npmTargets = ProjectFinder.FindNpmTargetProjectFile(
new []
{
GetNormalizedPath(@"c:\temp\project\folder\src\Acme.PhoneBook.Host.csproj"),
GetNormalizedPath(@"c:\temp\project\folder\src\Acme.PhoneBook.Web.Host.csproj"),
GetNormalizedPath(@"c:\temp\project\folder\src\Acme.PhoneBook.HttpApi.Host.csproj"),
GetNormalizedPath(@"c:\temp\project\folder\src\Acme.PhoneBook.Application.Contracts.csproj"),
GetNormalizedPath(@"c:\temp\project\folder\src\Acme.PhoneBook.Application.csproj"),
GetNormalizedPath(@"c:\temp\project\folder\src\Acme.PhoneBook.EntityFrameworkCore.csproj")
}
);
npmTargets.ShouldContain(GetNormalizedPath(@"c:\temp\project\folder\src\Acme.PhoneBook.Host.csproj"));
npmTargets.ShouldContain(GetNormalizedPath(@"c:\temp\project\folder\src\Acme.PhoneBook.Web.Host.csproj"));
}
[Fact]
public void GetAssemblyName_Tests()
{
var assemblyName = ProjectFinder.GetAssemblyName(
GetNormalizedPath(
@"c:\temp\project\folder\src\Acme.PhoneBook.Host.csproj"
)
);
assemblyName.ShouldBe("Acme.PhoneBook.Host");
}
private static string GetNormalizedPath(string path)
{
return path.Replace('\\', Path.DirectorySeparatorChar);
}
}
}
Loading…
Cancel
Save