From 1154962d4d4379775cb0a001ab5714d4725bde20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 29 Jun 2020 18:49:39 +0300 Subject: [PATCH] #4528 Support embedded files with manifest created by Microsoft.Extensions.FileProviders.Embedded --- .../Volo.Abp.VirtualFileSystem.csproj | 1 + .../AbpVirtualFileSystemOptions.cs | 2 +- .../Embedded/EmbeddedFileSet.cs | 27 +++++-- .../VirtualFileSystem/VirtualFileProvider.cs | 52 +++----------- .../VirtualFileSystem/VirtualFileSetInfo.cs | 35 ++++++++++ .../VirtualFileSystem/VirtualFileSetList.cs | 9 +-- .../VirtualFileSetListExtensions.cs | 70 ++++++++++++++----- .../Volo.Abp.VirtualFileSystem.Tests.csproj | 2 + .../MyResources/js/my{test}.2.9.min.js | 1 + .../VirtualFileProvider_Tests.cs | 25 ++++++- ...anyName.MyProjectName.Domain.Shared.csproj | 8 ++- .../MyFolder/{Person.Name}.txt | 1 + 12 files changed, 152 insertions(+), 81 deletions(-) create mode 100644 framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileSetInfo.cs create mode 100644 framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/MyResources/js/my{test}.2.9.min.js create mode 100644 templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/MyFolder/{Person.Name}.txt diff --git a/framework/src/Volo.Abp.VirtualFileSystem/Volo.Abp.VirtualFileSystem.csproj b/framework/src/Volo.Abp.VirtualFileSystem/Volo.Abp.VirtualFileSystem.csproj index f3a0fefb2a..b4aa55b1c0 100644 --- a/framework/src/Volo.Abp.VirtualFileSystem/Volo.Abp.VirtualFileSystem.csproj +++ b/framework/src/Volo.Abp.VirtualFileSystem/Volo.Abp.VirtualFileSystem.csproj @@ -17,6 +17,7 @@ + diff --git a/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/AbpVirtualFileSystemOptions.cs b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/AbpVirtualFileSystemOptions.cs index c4a4d203d2..aff1aee4e9 100644 --- a/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/AbpVirtualFileSystemOptions.cs +++ b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/AbpVirtualFileSystemOptions.cs @@ -3,7 +3,7 @@ public class AbpVirtualFileSystemOptions { public VirtualFileSetList FileSets { get; } - + public AbpVirtualFileSystemOptions() { FileSets = new VirtualFileSetList(); diff --git a/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/Embedded/EmbeddedFileSet.cs b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/Embedded/EmbeddedFileSet.cs index d2a0556527..9c09a901dc 100644 --- a/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/Embedded/EmbeddedFileSet.cs +++ b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/Embedded/EmbeddedFileSet.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.FileProviders; namespace Volo.Abp.VirtualFileSystem.Embedded { - public class EmbeddedFileSet : IVirtualFileSet + public class EmbeddedFileSet : DictionaryBasedFileProvider { [NotNull] public Assembly Assembly { get; } @@ -16,19 +16,22 @@ namespace Volo.Abp.VirtualFileSystem.Embedded [CanBeNull] public string BaseNamespace { get; } - [CanBeNull] - public string BaseFolderInProject { get; } + protected override IDictionary Files => _files.Value; + private readonly Lazy> _files; public EmbeddedFileSet( [NotNull] Assembly assembly, - [CanBeNull] string baseNamespace = null, - [CanBeNull] string baseFolderInProject = null) + [CanBeNull] string baseNamespace = null) { Check.NotNull(assembly, nameof(assembly)); Assembly = assembly; BaseNamespace = baseNamespace; - BaseFolderInProject = baseFolderInProject; + + _files = new Lazy>( + CreateFiles, + true + ); } public void AddFiles(Dictionary files) @@ -127,5 +130,17 @@ namespace Volo.Abp.VirtualFileSystem.Embedded return filePath.Substring(filePath.LastIndexOf("/", StringComparison.Ordinal) + 1); } + + protected override string NormalizePath(string subpath) + { + return VirtualFilePathHelper.NormalizePath(subpath); + } + + private Dictionary CreateFiles() + { + var files = new Dictionary(StringComparer.OrdinalIgnoreCase); + AddFiles(files); + return files; + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileProvider.cs b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileProvider.cs index 5f90ef7925..eb4cd4e415 100644 --- a/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileProvider.cs +++ b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileProvider.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Options; @@ -28,6 +27,11 @@ namespace Volo.Abp.VirtualFileSystem public virtual IDirectoryContents GetDirectoryContents(string subpath) { + if (subpath == "") + { + subpath = "/"; + } + return _hybridFileProvider.GetDirectoryContents(subpath); } @@ -42,52 +46,12 @@ namespace Volo.Abp.VirtualFileSystem fileProviders.Add(dynamicFileProvider); - if (_options.FileSets.PhysicalPaths.Any()) + foreach (var fileSet in _options.FileSets.AsEnumerable().Reverse()) { - fileProviders.AddRange( - _options.FileSets.PhysicalPaths - .Select(rootPath => new PhysicalFileProvider(rootPath)) - .Reverse() - ); + fileProviders.Add(fileSet.FileProvider); } - fileProviders.Add(new InternalVirtualFileProvider(_options)); - return new CompositeFileProvider(fileProviders); } - - protected class InternalVirtualFileProvider : DictionaryBasedFileProvider - { - protected override IDictionary Files => _files.Value; - - private readonly AbpVirtualFileSystemOptions _options; - private readonly Lazy> _files; - - public InternalVirtualFileProvider(AbpVirtualFileSystemOptions options) - { - _options = options; - _files = new Lazy>( - CreateFiles, - true - ); - } - - private Dictionary CreateFiles() - { - var files = new Dictionary(StringComparer.OrdinalIgnoreCase); - - foreach (var set in _options.FileSets) - { - set.AddFiles(files); - } - - return files; - } - - protected override string NormalizePath(string subpath) - { - return VirtualFilePathHelper.NormalizePath(subpath); - } - } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileSetInfo.cs b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileSetInfo.cs new file mode 100644 index 0000000000..b425932c51 --- /dev/null +++ b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileSetInfo.cs @@ -0,0 +1,35 @@ +using System.IO; +using System.Reflection; +using Microsoft.Extensions.FileProviders; + +namespace Volo.Abp.VirtualFileSystem +{ + public class VirtualFileSetInfo + { + public IFileProvider FileProvider + { + get => _fileProvider; + set => _fileProvider = Check.NotNull(value, nameof(value)); + } + private IFileProvider _fileProvider; + + public VirtualFileSetInfo(IFileProvider fileProvider) + { + FileProvider = fileProvider; + } + } + + public class EmbeddedVirtualFileSetInfo : VirtualFileSetInfo + { + public Assembly Assembly { get; } + + public string BaseFolder { get; } + + public EmbeddedVirtualFileSetInfo(IFileProvider fileProvider, Assembly assembly, string baseFolder = null) + : base(fileProvider) + { + Assembly = assembly; + BaseFolder = baseFolder; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileSetList.cs b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileSetList.cs index 2ddd0ff3a4..371f8350d8 100644 --- a/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileSetList.cs +++ b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileSetList.cs @@ -2,13 +2,8 @@ namespace Volo.Abp.VirtualFileSystem { - public class VirtualFileSetList : List + public class VirtualFileSetList : List { - public List PhysicalPaths { get; } - - public VirtualFileSetList() - { - PhysicalPaths = new List(); - } + } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileSetListExtensions.cs b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileSetListExtensions.cs index 399f76f408..ebf745916d 100644 --- a/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileSetListExtensions.cs +++ b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileSetListExtensions.cs @@ -1,44 +1,76 @@ using System; using System.IO; -using System.Linq; +using System.Reflection; using JetBrains.Annotations; +using Microsoft.Extensions.FileProviders; using Volo.Abp.VirtualFileSystem.Embedded; namespace Volo.Abp.VirtualFileSystem { public static class VirtualFileSetListExtensions { - public static void AddEmbedded([NotNull] this VirtualFileSetList list, [CanBeNull] string baseNamespace = null, string baseFolderInProject = null) + public static void AddEmbedded( + [NotNull] this VirtualFileSetList list, + [CanBeNull] string baseNamespace = null, + [CanBeNull] string baseFolder = null) { Check.NotNull(list, nameof(list)); - list.Add( - new EmbeddedFileSet( - typeof(T).Assembly, - baseNamespace, - baseFolderInProject - ) + var assembly = typeof(T).Assembly; + var fileProvider = CreateFileProvider( + assembly, + baseNamespace, + baseFolder ); + + list.Add(new EmbeddedVirtualFileSetInfo(fileProvider, assembly, baseFolder)); } - public static void ReplaceEmbeddedByPhysical([NotNull] this VirtualFileSetList list, [NotNull] string pyhsicalPath) + private static IFileProvider CreateFileProvider( + [NotNull] Assembly assembly, + [CanBeNull] string baseNamespace = null, + [CanBeNull] string baseFolder = null) { - Check.NotNull(list, nameof(list)); - Check.NotNull(pyhsicalPath, nameof(pyhsicalPath)); + Check.NotNull(assembly, nameof(assembly)); - var assembly = typeof(T).Assembly; - var embeddedFileSets = list.OfType().Where(fs => fs.Assembly == assembly).ToList(); + var info = assembly.GetManifestResourceInfo("Microsoft.Extensions.FileProviders.Embedded.Manifest.xml"); - foreach (var embeddedFileSet in embeddedFileSets) + if (info == null) { - list.Remove(embeddedFileSet); + return new EmbeddedFileSet(assembly, baseNamespace); + } + + if (baseFolder == null) + { + return new ManifestEmbeddedFileProvider(assembly); + } + + return new ManifestEmbeddedFileProvider(assembly, baseFolder); + } + + public static void ReplaceEmbeddedByPhysical( + [NotNull] this VirtualFileSetList fileSets, + [NotNull] string pyhsicalPath) + { + Check.NotNull(fileSets, nameof(fileSets)); + Check.NotNullOrWhiteSpace(pyhsicalPath, nameof(pyhsicalPath)); + + var assembly = typeof(T).Assembly; - if (!embeddedFileSet.BaseFolderInProject.IsNullOrEmpty()) + for (var i = 0; i < fileSets.Count; i++) + { + if (fileSets[i] is EmbeddedVirtualFileSetInfo embeddedVirtualFileSet && + embeddedVirtualFileSet.Assembly == assembly) { - pyhsicalPath = Path.Combine(pyhsicalPath, embeddedFileSet.BaseFolderInProject); - } + var thisPath = pyhsicalPath; - list.PhysicalPaths.Add(pyhsicalPath); + if (!embeddedVirtualFileSet.BaseFolder.IsNullOrEmpty()) + { + thisPath = Path.Combine(thisPath, embeddedVirtualFileSet.BaseFolder); + } + + fileSets[i] = new VirtualFileSetInfo(new PhysicalFileProvider(thisPath)); + } } } } diff --git a/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo.Abp.VirtualFileSystem.Tests.csproj b/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo.Abp.VirtualFileSystem.Tests.csproj index 9f8f904aa4..bcb9dcbf74 100644 --- a/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo.Abp.VirtualFileSystem.Tests.csproj +++ b/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo.Abp.VirtualFileSystem.Tests.csproj @@ -4,6 +4,7 @@ netcoreapp3.1 + true @@ -15,6 +16,7 @@ + diff --git a/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/MyResources/js/my{test}.2.9.min.js b/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/MyResources/js/my{test}.2.9.min.js new file mode 100644 index 0000000000..1c74f24545 --- /dev/null +++ b/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/MyResources/js/my{test}.2.9.min.js @@ -0,0 +1 @@ +//my{test}.2.9.min.js-content \ No newline at end of file diff --git a/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/VirtualFileProvider_Tests.cs b/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/VirtualFileProvider_Tests.cs index 2243d9a11a..aae01ff912 100644 --- a/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/VirtualFileProvider_Tests.cs +++ b/framework/test/Volo.Abp.VirtualFileSystem.Tests/Volo/Abp/VirtualFileSystem/VirtualFileProvider_Tests.cs @@ -1,5 +1,4 @@ -using System; -using System.IO; +using System.IO; using System.Linq; using System.Text; using Microsoft.Extensions.DependencyInjection; @@ -34,6 +33,22 @@ namespace Volo.Abp.VirtualFileSystem Encoding.UTF8.GetString(stream.GetAllBytes()).ShouldBe("//jquery-3-1-1-min.js-contents"); } } + + [Fact] + public void Should_Define_And_Get_Embedded_Resources_With_Special_Chars() + { + //Act + var resource = _virtualFileProvider.GetFileInfo("/js/my{test}.2.9.min.js"); + + //Assert + resource.ShouldNotBeNull(); + resource.Exists.ShouldBeTrue(); + + using (var stream = resource.CreateReadStream()) + { + Encoding.UTF8.GetString(stream.GetAllBytes()).ShouldBe("//my{test}.2.9.min.js-content"); + } + } [Fact] public void Should_Define_And_Get_Embedded_Directory_Contents() @@ -45,7 +60,9 @@ namespace Volo.Abp.VirtualFileSystem contents.Exists.ShouldNotBeNull(); var contentList = contents.ToList(); + contentList.ShouldContain(x => x.Name == "jquery-3-1-1-min.js"); + contentList.ShouldContain(x => x.Name == "my{test}.2.9.min.js"); } [Theory] @@ -70,7 +87,9 @@ namespace Volo.Abp.VirtualFileSystem { Configure(options => { - options.FileSets.AddEmbedded("Volo.Abp.VirtualFileSystem.MyResources"); + options.FileSets.AddEmbedded( + baseFolder: "/Volo/Abp/VirtualFileSystem/MyResources" + ); }); } } diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/MyCompanyName.MyProjectName.Domain.Shared.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/MyCompanyName.MyProjectName.Domain.Shared.csproj index f0b3cc8b33..72ba0ec00f 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/MyCompanyName.MyProjectName.Domain.Shared.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/MyCompanyName.MyProjectName.Domain.Shared.csproj @@ -5,8 +5,9 @@ netstandard2.0 MyCompanyName.MyProjectName + true - + @@ -23,4 +24,9 @@ + + + + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/MyFolder/{Person.Name}.txt b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/MyFolder/{Person.Name}.txt new file mode 100644 index 0000000000..d61a270d39 --- /dev/null +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/MyFolder/{Person.Name}.txt @@ -0,0 +1 @@ +testing just... \ No newline at end of file