Refactor filesystems (again)
This commit is contained in:
@@ -76,15 +76,13 @@ namespace Umbraco.Core.Composing.Composers
|
||||
// register IFileSystems, which gives access too all filesystems
|
||||
container.RegisterSingleton<IFileSystems>(factory => factory.GetInstance<FileSystems>());
|
||||
|
||||
// register IMediaFileSystem
|
||||
var virtualRoot = GetMediaFileSystemVirtualRoot();
|
||||
container.RegisterSingleton<IFileSystem>("media", factory => new PhysicalFileSystem(virtualRoot));
|
||||
container.RegisterSingleton<IMediaFileSystem>(factory => factory.GetInstance<FileSystems>().GetFileSystem<MediaFileSystem>());
|
||||
// register IMediaFileSystem with its actual, underlying filesystem factory
|
||||
container.RegisterSingleton<IMediaFileSystem>(factory => factory.GetInstance<FileSystems>().GetFileSystem<MediaFileSystem>(MediaInnerFileSystemFactory));
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
private static string GetMediaFileSystemVirtualRoot()
|
||||
private static IFileSystem MediaInnerFileSystemFactory()
|
||||
{
|
||||
// for the time being, we still use the FileSystemProvider config file
|
||||
// but, detect if ppl are trying to use it to change the "provider"
|
||||
@@ -93,13 +91,13 @@ namespace Umbraco.Core.Composing.Composers
|
||||
|
||||
var config = (FileSystemProvidersSection)ConfigurationManager.GetSection("umbracoConfiguration/FileSystemProviders");
|
||||
var p = config?.Providers["media"];
|
||||
if (p == null) return virtualRoot;
|
||||
if (p == null) return new PhysicalFileSystem(virtualRoot);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(p.Type) && p.Type != "Umbraco.Core.IO.PhysicalFileSystem, Umbraco.Core")
|
||||
throw new InvalidOperationException("Setting a provider type in FileSystemProviders.config is not supported anymore, see FileSystemsComposer for help.");
|
||||
|
||||
virtualRoot = p?.Parameters["virtualRoot"]?.Value ?? "~/media";
|
||||
return virtualRoot;
|
||||
return new PhysicalFileSystem(virtualRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,9 @@ namespace Umbraco.Core.Composing
|
||||
public static IFileSystems FileSystems
|
||||
=> Container.GetInstance<IFileSystems>();
|
||||
|
||||
public static IMediaFileSystem MediaFileSystem
|
||||
=> Container.GetInstance<IMediaFileSystem>();
|
||||
|
||||
public static UrlSegmentProviderCollection UrlSegmentProviders
|
||||
=> Container.GetInstance<UrlSegmentProviderCollection>();
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
// this ain't pretty
|
||||
private static IMediaFileSystem _mediaFileSystem;
|
||||
private static IMediaFileSystem MediaFileSystem => _mediaFileSystem ?? (_mediaFileSystem = Current.FileSystems.MediaFileSystem);
|
||||
private static IMediaFileSystem MediaFileSystem => _mediaFileSystem ?? (_mediaFileSystem = Current.MediaFileSystem);
|
||||
|
||||
#region IContent
|
||||
|
||||
|
||||
@@ -35,6 +35,6 @@ namespace Umbraco.Core.Events
|
||||
private IMediaFileSystem _mediaFileSystem;
|
||||
|
||||
// fixme inject
|
||||
private IMediaFileSystem MediaFileSystem => _mediaFileSystem ?? (_mediaFileSystem = Current.FileSystems.MediaFileSystem);
|
||||
private IMediaFileSystem MediaFileSystem => _mediaFileSystem ?? (_mediaFileSystem = Current.MediaFileSystem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Decorates a filesystem.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
public class FileSystemAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FileSystemAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="alias"></param>
|
||||
public FileSystemAttribute(string alias)
|
||||
{
|
||||
Alias = alias;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the alias of the filesystem.
|
||||
/// </summary>
|
||||
public string Alias { get; }
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
public class FileSystems : IFileSystems
|
||||
{
|
||||
private readonly ConcurrentSet<ShadowWrapper> _wrappers = new ConcurrentSet<ShadowWrapper>();
|
||||
private readonly IContainer _container;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
@@ -23,13 +22,16 @@ namespace Umbraco.Core.IO
|
||||
private ShadowWrapper _scriptsFileSystem;
|
||||
private ShadowWrapper _masterPagesFileSystem;
|
||||
private ShadowWrapper _mvcViewsFileSystem;
|
||||
|
||||
|
||||
// well-known file systems lazy initialization
|
||||
private object _wkfsLock = new object();
|
||||
private bool _wkfsInitialized;
|
||||
private object _wkfsObject;
|
||||
private object _wkfsObject; // unused
|
||||
|
||||
private MediaFileSystem _mediaFileSystem;
|
||||
// shadow support
|
||||
private readonly List<ShadowWrapper> _shadowWrappers = new List<ShadowWrapper>();
|
||||
private readonly object _shadowLocker = new object();
|
||||
private static Guid _shadowCurrentId = Guid.Empty; // static - unique!!
|
||||
|
||||
#region Constructor
|
||||
|
||||
@@ -43,11 +45,19 @@ namespace Umbraco.Core.IO
|
||||
// for tests only, totally unsafe
|
||||
internal void Reset()
|
||||
{
|
||||
_wrappers.Clear();
|
||||
_shadowWrappers.Clear();
|
||||
_filesystems.Clear();
|
||||
Volatile.Write(ref _wkfsInitialized, false);
|
||||
_shadowCurrentId = Guid.Empty;
|
||||
}
|
||||
|
||||
// for tests only, totally unsafe
|
||||
internal static void ResetShadowId()
|
||||
{
|
||||
_shadowCurrentId = Guid.Empty;
|
||||
}
|
||||
|
||||
// set by the scope provider when taking control of filesystems
|
||||
internal Func<bool> IsScoped { get; set; } = () => false;
|
||||
|
||||
#endregion
|
||||
@@ -114,16 +124,6 @@ namespace Umbraco.Core.IO
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IMediaFileSystem MediaFileSystem
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Volatile.Read(ref _wkfsInitialized) == false) EnsureWellKnownFileSystems();
|
||||
return _mediaFileSystem;
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureWellKnownFileSystems()
|
||||
{
|
||||
LazyInitializer.EnsureInitialized(ref _wkfsObject, ref _wkfsInitialized, ref _wkfsLock, CreateWellKnownFileSystems);
|
||||
@@ -140,15 +140,20 @@ namespace Umbraco.Core.IO
|
||||
var masterPagesFileSystem = new PhysicalFileSystem(SystemDirectories.Masterpages);
|
||||
var mvcViewsFileSystem = new PhysicalFileSystem(SystemDirectories.MvcViews);
|
||||
|
||||
_macroPartialFileSystem = new ShadowWrapper(macroPartialFileSystem, "Views/MacroPartials", () => IsScoped());
|
||||
_partialViewsFileSystem = new ShadowWrapper(partialViewsFileSystem, "Views/Partials", () => IsScoped());
|
||||
_stylesheetsFileSystem = new ShadowWrapper(stylesheetsFileSystem, "css", () => IsScoped());
|
||||
_scriptsFileSystem = new ShadowWrapper(scriptsFileSystem, "scripts", () => IsScoped());
|
||||
_masterPagesFileSystem = new ShadowWrapper(masterPagesFileSystem, "masterpages", () => IsScoped());
|
||||
_mvcViewsFileSystem = new ShadowWrapper(mvcViewsFileSystem, "Views", () => IsScoped());
|
||||
_macroPartialFileSystem = new ShadowWrapper(macroPartialFileSystem, "Views/MacroPartials", IsScoped);
|
||||
_partialViewsFileSystem = new ShadowWrapper(partialViewsFileSystem, "Views/Partials", IsScoped);
|
||||
_stylesheetsFileSystem = new ShadowWrapper(stylesheetsFileSystem, "css", IsScoped);
|
||||
_scriptsFileSystem = new ShadowWrapper(scriptsFileSystem, "scripts", IsScoped);
|
||||
_masterPagesFileSystem = new ShadowWrapper(masterPagesFileSystem, "masterpages", IsScoped);
|
||||
_mvcViewsFileSystem = new ShadowWrapper(mvcViewsFileSystem, "Views", IsScoped);
|
||||
|
||||
// filesystems obtained from GetFileSystemProvider are already wrapped and do not need to be wrapped again
|
||||
_mediaFileSystem = GetFileSystem<MediaFileSystem>();
|
||||
// fixme locking?
|
||||
_shadowWrappers.Add(_macroPartialFileSystem);
|
||||
_shadowWrappers.Add(_partialViewsFileSystem);
|
||||
_shadowWrappers.Add(_stylesheetsFileSystem);
|
||||
_shadowWrappers.Add(_scriptsFileSystem);
|
||||
_shadowWrappers.Add(_masterPagesFileSystem);
|
||||
_shadowWrappers.Add(_mvcViewsFileSystem);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -166,37 +171,22 @@ namespace Umbraco.Core.IO
|
||||
/// <para>Note that any filesystem created by this method *after* shadowing begins, will *not* be
|
||||
/// shadowing (and an exception will be thrown by the ShadowWrapper).</para>
|
||||
/// </remarks>
|
||||
public TFileSystem GetFileSystem<TFileSystem>()
|
||||
public TFileSystem GetFileSystem<TFileSystem>(Func<IFileSystem> innerFileSystemFactory)
|
||||
where TFileSystem : FileSystemWrapper
|
||||
{
|
||||
var alias = GetFileSystemAlias<TFileSystem>();
|
||||
if (Volatile.Read(ref _wkfsInitialized) == false) EnsureWellKnownFileSystems();
|
||||
|
||||
// note: GetOrAdd can run multiple times - and here, since we have side effects
|
||||
// (adding to _wrappers) we want to be sure the factory runs only once, hence the
|
||||
// additional Lazy.
|
||||
return (TFileSystem) _filesystems.GetOrAdd(alias, _ => new Lazy<IFileSystem>(() =>
|
||||
var name = typeof(TFileSystem).FullName;
|
||||
if (name == null) throw new Exception("panic!");
|
||||
|
||||
return (TFileSystem) _filesystems.GetOrAdd(name, _ => new Lazy<IFileSystem>(() =>
|
||||
{
|
||||
var supportingFileSystem = _container.GetInstance<IFileSystem>(alias);
|
||||
var shadowWrapper = new ShadowWrapper(supportingFileSystem, "typed/" + alias, () => IsScoped());
|
||||
|
||||
_wrappers.Add(shadowWrapper); // _wrappers is a concurrent set - this is safe
|
||||
|
||||
return _container.CreateInstance<TFileSystem>(new { innerFileSystem = shadowWrapper});
|
||||
var innerFileSystem = innerFileSystemFactory();
|
||||
var shadowWrapper = CreateShadowWrapper(innerFileSystem, "typed/" + name);
|
||||
return _container.CreateInstance<TFileSystem>(new { innerFileSystem = shadowWrapper });
|
||||
})).Value;
|
||||
}
|
||||
|
||||
private string GetFileSystemAlias<TFileSystem>()
|
||||
{
|
||||
var fileSystemType = typeof(TFileSystem);
|
||||
|
||||
// find the attribute and get the alias
|
||||
var attr = (FileSystemAttribute) fileSystemType.GetCustomAttributes(typeof(FileSystemAttribute), false).SingleOrDefault();
|
||||
if (attr == null)
|
||||
throw new InvalidOperationException("Type " + fileSystemType.FullName + "is missing the required FileSystemProviderAttribute.");
|
||||
|
||||
return attr.Alias;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Shadow
|
||||
@@ -223,50 +213,70 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
if (Volatile.Read(ref _wkfsInitialized) == false) EnsureWellKnownFileSystems();
|
||||
|
||||
var typed = _wrappers.ToArray();
|
||||
var wrappers = new ShadowWrapper[typed.Length + 6];
|
||||
var i = 0;
|
||||
while (i < typed.Length) wrappers[i] = typed[i++];
|
||||
wrappers[i++] = _macroPartialFileSystem;
|
||||
wrappers[i++] = _partialViewsFileSystem;
|
||||
wrappers[i++] = _stylesheetsFileSystem;
|
||||
wrappers[i++] = _scriptsFileSystem;
|
||||
wrappers[i++] = _masterPagesFileSystem;
|
||||
wrappers[i] = _mvcViewsFileSystem;
|
||||
return new ShadowFileSystems(this, id); // will invoke BeginShadow and EndShadow
|
||||
}
|
||||
|
||||
return new ShadowFileSystems(id, wrappers, _logger);
|
||||
internal void BeginShadow(Guid id)
|
||||
{
|
||||
lock (_shadowLocker)
|
||||
{
|
||||
// if we throw here, it means that something very wrong happened.
|
||||
if (_shadowCurrentId != Guid.Empty)
|
||||
throw new InvalidOperationException("Already shadowing.");
|
||||
_shadowCurrentId = id;
|
||||
|
||||
_logger.Debug<ShadowFileSystems>("Shadow '{ShadowId}'", id);
|
||||
|
||||
foreach (var wrapper in _shadowWrappers)
|
||||
wrapper.Shadow(id);
|
||||
}
|
||||
}
|
||||
|
||||
internal void EndShadow(Guid id, bool completed)
|
||||
{
|
||||
lock (_shadowLocker)
|
||||
{
|
||||
// if we throw here, it means that something very wrong happened.
|
||||
if (_shadowCurrentId == Guid.Empty)
|
||||
throw new InvalidOperationException("Not shadowing.");
|
||||
if (id != _shadowCurrentId)
|
||||
throw new InvalidOperationException("Not the current shadow.");
|
||||
|
||||
_logger.Debug<ShadowFileSystems>("UnShadow '{ShadowId}' {Status}", id, completed ? "complete" : "abort");
|
||||
|
||||
var exceptions = new List<Exception>();
|
||||
foreach (var wrapper in _shadowWrappers)
|
||||
{
|
||||
try
|
||||
{
|
||||
// this may throw an AggregateException if some of the changes could not be applied
|
||||
wrapper.UnShadow(completed);
|
||||
}
|
||||
catch (AggregateException ae)
|
||||
{
|
||||
exceptions.Add(ae);
|
||||
}
|
||||
}
|
||||
|
||||
_shadowCurrentId = Guid.Empty;
|
||||
|
||||
if (exceptions.Count > 0)
|
||||
throw new AggregateException(completed ? "Failed to apply all changes (see exceptions)." : "Failed to abort (see exceptions).", exceptions);
|
||||
}
|
||||
}
|
||||
|
||||
private ShadowWrapper CreateShadowWrapper(IFileSystem filesystem, string shadowPath)
|
||||
{
|
||||
lock (_shadowLocker)
|
||||
{
|
||||
var wrapper = new ShadowWrapper(filesystem, shadowPath, IsScoped);
|
||||
if (_shadowCurrentId != Guid.Empty)
|
||||
wrapper.Shadow(_shadowCurrentId);
|
||||
_shadowWrappers.Add(wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private class ConcurrentSet<T>
|
||||
where T : class
|
||||
{
|
||||
private readonly HashSet<T> _set = new HashSet<T>();
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
lock (_set)
|
||||
{
|
||||
_set.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
lock (_set)
|
||||
{
|
||||
_set.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public T[] ToArray()
|
||||
{
|
||||
lock (_set)
|
||||
{
|
||||
return _set.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,5 @@
|
||||
/// Gets the MVC views filesystem.
|
||||
/// </summary>
|
||||
IFileSystem MvcViewsFileSystem { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media filesystem.
|
||||
/// </summary>
|
||||
IMediaFileSystem MediaFileSystem { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,4 +63,4 @@ namespace Umbraco.Core.IO
|
||||
/// <returns>The filesystem-relative path to the copy of the media file.</returns>
|
||||
string CopyFile(IContentBase content, PropertyType propertyType, string sourcepath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ namespace Umbraco.Core.IO
|
||||
/// <summary>
|
||||
/// A custom file system provider for media
|
||||
/// </summary>
|
||||
[FileSystem("media")]
|
||||
public class MediaFileSystem : FileSystemWrapper, IMediaFileSystem
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -1,41 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
// shadow filesystems is definitively ... too convoluted
|
||||
|
||||
internal class ShadowFileSystems : ICompletable
|
||||
{
|
||||
private static readonly object Locker = new object();
|
||||
private static Guid _currentId = Guid.Empty;
|
||||
|
||||
private readonly Guid _id;
|
||||
private readonly ShadowWrapper[] _wrappers;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private readonly FileSystems _fileSystems;
|
||||
private bool _completed;
|
||||
|
||||
// invoked by the filesystems when shadowing
|
||||
// can only be 1 shadow at a time (static)
|
||||
public ShadowFileSystems(Guid id, ShadowWrapper[] wrappers, ILogger logger)
|
||||
public ShadowFileSystems(FileSystems fileSystems, Guid id)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
// if we throw here, it means that something very wrong happened.
|
||||
if (_currentId != Guid.Empty)
|
||||
throw new InvalidOperationException("Already shadowing.");
|
||||
_currentId = id;
|
||||
}
|
||||
_fileSystems = fileSystems;
|
||||
Id = id;
|
||||
|
||||
_logger = logger;
|
||||
_logger.Debug<ShadowFileSystems>("Shadow '{ShadowId}'", id);
|
||||
_id = id;
|
||||
|
||||
_wrappers = wrappers;
|
||||
foreach (var wrapper in _wrappers)
|
||||
wrapper.Shadow(id);
|
||||
_fileSystems.BeginShadow(id);
|
||||
}
|
||||
|
||||
// for tests
|
||||
public Guid Id { get; }
|
||||
|
||||
// invoked by the scope when exiting, if completed
|
||||
public void Complete()
|
||||
{
|
||||
@@ -45,41 +30,7 @@ namespace Umbraco.Core.IO
|
||||
// invoked by the scope when exiting
|
||||
public void Dispose()
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
// if we throw here, it means that something very wrong happened.
|
||||
if (_currentId == Guid.Empty)
|
||||
throw new InvalidOperationException("Not shadowing.");
|
||||
if (_id != _currentId)
|
||||
throw new InvalidOperationException("Not the current shadow.");
|
||||
|
||||
_logger.Debug<ShadowFileSystems>("UnShadow '{ShadowId}' {Status}", _id, _completed ? "complete" : "abort");
|
||||
|
||||
var exceptions = new List<Exception>();
|
||||
foreach (var wrapper in _wrappers)
|
||||
{
|
||||
try
|
||||
{
|
||||
// this may throw an AggregateException if some of the changes could not be applied
|
||||
wrapper.UnShadow(_completed);
|
||||
}
|
||||
catch (AggregateException ae)
|
||||
{
|
||||
exceptions.Add(ae);
|
||||
}
|
||||
}
|
||||
|
||||
_currentId = Guid.Empty;
|
||||
|
||||
if (exceptions.Count > 0)
|
||||
throw new AggregateException(_completed ? "Failed to apply all changes (see exceptions)." : "Failed to abort (see exceptions).", exceptions);
|
||||
}
|
||||
}
|
||||
|
||||
// for tests
|
||||
internal static void ResetId()
|
||||
{
|
||||
_currentId = Guid.Empty;
|
||||
_fileSystems.EndShadow(Id, _completed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
//use the custom avatar
|
||||
var avatarUrl = Current.FileSystems.MediaFileSystem.GetUrl(user.Avatar);
|
||||
var avatarUrl = Current.MediaFileSystem.GetUrl(user.Avatar);
|
||||
return new[]
|
||||
{
|
||||
avatarUrl + "?width=30&height=30&mode=crop",
|
||||
|
||||
@@ -576,7 +576,6 @@
|
||||
<Compile Include="IntExtensions.cs" />
|
||||
<Compile Include="IO\FileSecurityException.cs" />
|
||||
<Compile Include="IO\FileSystemExtensions.cs" />
|
||||
<Compile Include="IO\FileSystemAttribute.cs" />
|
||||
<Compile Include="IO\FileSystems.cs" />
|
||||
<Compile Include="IO\FileSystemWrapper.cs" />
|
||||
<Compile Include="IO\IFileSystem.cs" />
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Umbraco.Tests.IO
|
||||
[Test]
|
||||
public void Can_Get_MediaFileSystem()
|
||||
{
|
||||
var fileSystem = FileSystems.GetFileSystem<MediaFileSystem>();
|
||||
var fileSystem = _container.GetInstance<IMediaFileSystem>();
|
||||
Assert.NotNull(fileSystem);
|
||||
}
|
||||
|
||||
@@ -67,14 +67,6 @@ namespace Umbraco.Tests.IO
|
||||
Assert.NotNull(fileSystem);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MediaFileSystem_Is_Singleton()
|
||||
{
|
||||
var fileSystem1 = FileSystems.GetFileSystem<MediaFileSystem>();
|
||||
var fileSystem2 = FileSystems.GetFileSystem<MediaFileSystem>();
|
||||
Assert.AreSame(fileSystem1, fileSystem2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IMediaFileSystem_Is_Singleton()
|
||||
{
|
||||
@@ -86,7 +78,7 @@ namespace Umbraco.Tests.IO
|
||||
[Test]
|
||||
public void Can_Delete_MediaFiles()
|
||||
{
|
||||
var fs = FileSystems.GetFileSystem<MediaFileSystem>();
|
||||
var fs = _container.GetInstance<IMediaFileSystem>();
|
||||
var ms = new MemoryStream(Encoding.UTF8.GetBytes("test"));
|
||||
var virtPath = fs.GetMediaPath("file.txt", Guid.NewGuid(), Guid.NewGuid());
|
||||
fs.AddFile(virtPath, ms);
|
||||
@@ -108,6 +100,9 @@ namespace Umbraco.Tests.IO
|
||||
Assert.IsTrue(Directory.Exists(physPath));
|
||||
}
|
||||
|
||||
|
||||
// fixme - don't make sense anymore
|
||||
/*
|
||||
[Test]
|
||||
public void Cannot_Get_InvalidFileSystem()
|
||||
{
|
||||
@@ -134,12 +129,13 @@ namespace Umbraco.Tests.IO
|
||||
{ }
|
||||
}
|
||||
|
||||
[FileSystem("noconfig")]
|
||||
[InnerFileSystem("noconfig")]
|
||||
internal class NonConfiguredFileSystem : FileSystemWrapper
|
||||
{
|
||||
public NonConfiguredFileSystem(IFileSystem innerFileSystem)
|
||||
: base(innerFileSystem)
|
||||
{ }
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Scoping;
|
||||
@@ -25,7 +27,7 @@ namespace Umbraco.Tests.IO
|
||||
{
|
||||
SafeCallContext.Clear();
|
||||
ClearFiles();
|
||||
ShadowFileSystems.ResetId();
|
||||
FileSystems.ResetShadowId();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
@@ -33,7 +35,7 @@ namespace Umbraco.Tests.IO
|
||||
{
|
||||
SafeCallContext.Clear();
|
||||
ClearFiles();
|
||||
ShadowFileSystems.ResetId();
|
||||
FileSystems.ResetShadowId();
|
||||
}
|
||||
|
||||
private static void ClearFiles()
|
||||
@@ -373,6 +375,13 @@ namespace Umbraco.Tests.IO
|
||||
Assert.IsFalse(File.Exists(path + "/ShadowTests/sub/sub/f2.txt"));
|
||||
}
|
||||
|
||||
class FS : FileSystemWrapper
|
||||
{
|
||||
public FS(IFileSystem innerFileSystem)
|
||||
: base(innerFileSystem)
|
||||
{ }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShadowScopeComplete()
|
||||
{
|
||||
@@ -385,13 +394,16 @@ namespace Umbraco.Tests.IO
|
||||
|
||||
var scopedFileSystems = false;
|
||||
|
||||
var fs = new PhysicalFileSystem(path, "ignore");
|
||||
var sw = new ShadowWrapper(fs, "shadow", () => scopedFileSystems);
|
||||
var swa = new[] { sw };
|
||||
var phy = new PhysicalFileSystem(path, "ignore");
|
||||
|
||||
var container = Mock.Of<IContainer>();
|
||||
var fileSystems = new FileSystems(container, logger) { IsScoped = () => scopedFileSystems };
|
||||
var fs = fileSystems.GetFileSystem<FS>(() => phy);
|
||||
var sw = (ShadowWrapper) fs.InnerFileSystem;
|
||||
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f1.txt", ms);
|
||||
Assert.IsTrue(fs.FileExists("sub/f1.txt"));
|
||||
Assert.IsTrue(phy.FileExists("sub/f1.txt"));
|
||||
|
||||
Guid id;
|
||||
|
||||
@@ -400,47 +412,55 @@ namespace Umbraco.Tests.IO
|
||||
Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f2.txt", ms);
|
||||
Assert.IsTrue(fs.FileExists("sub/f2.txt"));
|
||||
Assert.IsTrue(phy.FileExists("sub/f2.txt"));
|
||||
sw.UnShadow(true);
|
||||
Assert.IsTrue(fs.FileExists("sub/f2.txt"));
|
||||
Assert.IsTrue(phy.FileExists("sub/f2.txt"));
|
||||
Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
|
||||
|
||||
// shadow with scope but no complete does not complete
|
||||
scopedFileSystems = true; // pretend we have a scope
|
||||
var scope = new ShadowFileSystems(id = Guid.NewGuid(), swa, logger);
|
||||
var scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
|
||||
Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f3.txt", ms);
|
||||
Assert.IsFalse(fs.FileExists("sub/f3.txt"));
|
||||
Assert.AreEqual(1, Directory.GetDirectories(appdata + "/TEMP/ShadowFs").Length);
|
||||
Assert.IsFalse(phy.FileExists("sub/f3.txt"));
|
||||
var dirs = Directory.GetDirectories(appdata + "/TEMP/ShadowFs");
|
||||
Assert.AreEqual(1, dirs.Length);
|
||||
Assert.AreEqual((appdata + "/TEMP/ShadowFs/" + id).Replace('\\', '/'), dirs[0].Replace('\\', '/'));
|
||||
dirs = Directory.GetDirectories(dirs[0]);
|
||||
var typedDir = dirs.FirstOrDefault(x => x.Replace('\\', '/').EndsWith("/typed"));
|
||||
Assert.IsNotNull(typedDir);
|
||||
dirs = Directory.GetDirectories(typedDir);
|
||||
var scopedDir = dirs.FirstOrDefault(x => x.Replace('\\', '/').EndsWith("/Umbraco.Tests.IO.ShadowFileSystemTests+FS")); // this is where files go
|
||||
Assert.IsNotNull(scopedDir);
|
||||
scope.Dispose();
|
||||
scopedFileSystems = false;
|
||||
Assert.IsFalse(fs.FileExists("sub/f3.txt"));
|
||||
Assert.IsFalse(phy.FileExists("sub/f3.txt"));
|
||||
TestHelper.TryAssert(() => Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id)));
|
||||
|
||||
// shadow with scope and complete does complete
|
||||
scopedFileSystems = true; // pretend we have a scope
|
||||
scope = new ShadowFileSystems(id = Guid.NewGuid(), swa, logger);
|
||||
scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
|
||||
Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f4.txt", ms);
|
||||
Assert.IsFalse(fs.FileExists("sub/f4.txt"));
|
||||
Assert.IsFalse(phy.FileExists("sub/f4.txt"));
|
||||
Assert.AreEqual(1, Directory.GetDirectories(appdata + "/TEMP/ShadowFs").Length);
|
||||
scope.Complete();
|
||||
scope.Dispose();
|
||||
scopedFileSystems = false;
|
||||
TestHelper.TryAssert(() => Assert.AreEqual(0, Directory.GetDirectories(appdata + "/TEMP/ShadowFs").Length));
|
||||
Assert.IsTrue(fs.FileExists("sub/f4.txt"));
|
||||
Assert.IsTrue(phy.FileExists("sub/f4.txt"));
|
||||
Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
|
||||
|
||||
// test scope for "another thread"
|
||||
|
||||
scopedFileSystems = true; // pretend we have a scope
|
||||
scope = new ShadowFileSystems(id = Guid.NewGuid(), swa, logger);
|
||||
scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
|
||||
Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f5.txt", ms);
|
||||
Assert.IsFalse(fs.FileExists("sub/f5.txt"));
|
||||
Assert.IsFalse(phy.FileExists("sub/f5.txt"));
|
||||
|
||||
// pretend we're another thread w/out scope
|
||||
scopedFileSystems = false;
|
||||
@@ -448,11 +468,11 @@ namespace Umbraco.Tests.IO
|
||||
sw.AddFile("sub/f6.txt", ms);
|
||||
scopedFileSystems = true; // pretend we have a scope
|
||||
|
||||
Assert.IsTrue(fs.FileExists("sub/f6.txt")); // other thread has written out to fs
|
||||
Assert.IsTrue(phy.FileExists("sub/f6.txt")); // other thread has written out to fs
|
||||
scope.Complete();
|
||||
scope.Dispose();
|
||||
scopedFileSystems = false;
|
||||
Assert.IsTrue(fs.FileExists("sub/f5.txt"));
|
||||
Assert.IsTrue(phy.FileExists("sub/f5.txt"));
|
||||
Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
|
||||
}
|
||||
|
||||
@@ -467,22 +487,25 @@ namespace Umbraco.Tests.IO
|
||||
|
||||
var scopedFileSystems = false;
|
||||
|
||||
var fs = new PhysicalFileSystem(path, "ignore");
|
||||
var sw = new ShadowWrapper(fs, "shadow", () => scopedFileSystems);
|
||||
var swa = new[] { sw };
|
||||
var phy = new PhysicalFileSystem(path, "ignore");
|
||||
|
||||
var container = Mock.Of<IContainer>();
|
||||
var fileSystems = new FileSystems(container, logger) { IsScoped = () => scopedFileSystems };
|
||||
var fs = fileSystems.GetFileSystem<FS>(() => phy);
|
||||
var sw = (ShadowWrapper) fs.InnerFileSystem;
|
||||
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f1.txt", ms);
|
||||
Assert.IsTrue(fs.FileExists("sub/f1.txt"));
|
||||
Assert.IsTrue(phy.FileExists("sub/f1.txt"));
|
||||
|
||||
Guid id;
|
||||
|
||||
scopedFileSystems = true; // pretend we have a scope
|
||||
var scope = new ShadowFileSystems(id = Guid.NewGuid(), swa, logger);
|
||||
var scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
|
||||
Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f2.txt", ms);
|
||||
Assert.IsFalse(fs.FileExists("sub/f2.txt"));
|
||||
Assert.IsFalse(phy.FileExists("sub/f2.txt"));
|
||||
|
||||
// pretend we're another thread w/out scope
|
||||
scopedFileSystems = false;
|
||||
@@ -490,15 +513,15 @@ namespace Umbraco.Tests.IO
|
||||
sw.AddFile("sub/f2.txt", ms);
|
||||
scopedFileSystems = true; // pretend we have a scope
|
||||
|
||||
Assert.IsTrue(fs.FileExists("sub/f2.txt")); // other thread has written out to fs
|
||||
Assert.IsTrue(phy.FileExists("sub/f2.txt")); // other thread has written out to fs
|
||||
scope.Complete();
|
||||
scope.Dispose();
|
||||
scopedFileSystems = false;
|
||||
Assert.IsTrue(fs.FileExists("sub/f2.txt"));
|
||||
Assert.IsTrue(phy.FileExists("sub/f2.txt"));
|
||||
TestHelper.TryAssert(() => Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id)));
|
||||
|
||||
string text;
|
||||
using (var s = fs.OpenFile("sub/f2.txt"))
|
||||
using (var s = phy.OpenFile("sub/f2.txt"))
|
||||
using (var r = new StreamReader(s))
|
||||
text = r.ReadToEnd();
|
||||
|
||||
@@ -517,22 +540,25 @@ namespace Umbraco.Tests.IO
|
||||
|
||||
var scopedFileSystems = false;
|
||||
|
||||
var fs = new PhysicalFileSystem(path, "ignore");
|
||||
var sw = new ShadowWrapper(fs, "shadow", () => scopedFileSystems);
|
||||
var swa = new[] { sw };
|
||||
var phy = new PhysicalFileSystem(path, "ignore");
|
||||
|
||||
var container = Mock.Of<IContainer>();
|
||||
var fileSystems = new FileSystems(container, logger) { IsScoped = () => scopedFileSystems };
|
||||
var fs = fileSystems.GetFileSystem<FS>(() => phy);
|
||||
var sw = (ShadowWrapper)fs.InnerFileSystem;
|
||||
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f1.txt", ms);
|
||||
Assert.IsTrue(fs.FileExists("sub/f1.txt"));
|
||||
Assert.IsTrue(phy.FileExists("sub/f1.txt"));
|
||||
|
||||
Guid id;
|
||||
|
||||
scopedFileSystems = true; // pretend we have a scope
|
||||
var scope = new ShadowFileSystems(id = Guid.NewGuid(), swa, logger);
|
||||
var scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
|
||||
Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f2.txt", ms);
|
||||
Assert.IsFalse(fs.FileExists("sub/f2.txt"));
|
||||
Assert.IsFalse(phy.FileExists("sub/f2.txt"));
|
||||
|
||||
// pretend we're another thread w/out scope
|
||||
scopedFileSystems = false;
|
||||
@@ -540,11 +566,11 @@ namespace Umbraco.Tests.IO
|
||||
sw.AddFile("sub/f2.txt/f2.txt", ms);
|
||||
scopedFileSystems = true; // pretend we have a scope
|
||||
|
||||
Assert.IsTrue(fs.FileExists("sub/f2.txt/f2.txt")); // other thread has written out to fs
|
||||
Assert.IsTrue(phy.FileExists("sub/f2.txt/f2.txt")); // other thread has written out to fs
|
||||
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f3.txt", ms);
|
||||
Assert.IsFalse(fs.FileExists("sub/f3.txt"));
|
||||
Assert.IsFalse(phy.FileExists("sub/f3.txt"));
|
||||
|
||||
scope.Complete();
|
||||
|
||||
@@ -570,7 +596,7 @@ namespace Umbraco.Tests.IO
|
||||
}
|
||||
|
||||
// still, the rest of the changes has been applied ok
|
||||
Assert.IsTrue(fs.FileExists("sub/f3.txt"));
|
||||
Assert.IsTrue(phy.FileExists("sub/f3.txt"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -10,6 +10,7 @@ using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Composing.Composers;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -40,9 +41,8 @@ namespace Umbraco.Tests.Models
|
||||
base.Compose();
|
||||
|
||||
Container.Register(_ => Mock.Of<ILogger>());
|
||||
Container.Register<FileSystems>();
|
||||
Container.Register<IFileSystems>(factory => factory.GetInstance<FileSystems>());
|
||||
Container.Register(factory => factory.GetInstance<IFileSystems>().MediaFileSystem);
|
||||
Container.ComposeFileSystems();
|
||||
|
||||
Container.Register(_ => Mock.Of<IDataTypeService>());
|
||||
Container.Register(_ => Mock.Of<IContentSection>());
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Umbraco.Tests.Scoping
|
||||
{
|
||||
base.TearDown();
|
||||
SafeCallContext.Clear();
|
||||
ShadowFileSystems.ResetId();
|
||||
FileSystems.ResetShadowId();
|
||||
ClearFiles();
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Umbraco.Tests.Scoping
|
||||
public void CreateMediaTest(bool complete)
|
||||
{
|
||||
var physMediaFileSystem = new PhysicalFileSystem(IOHelper.MapPath("media"), "ignore");
|
||||
var mediaFileSystem = Current.FileSystems.MediaFileSystem;
|
||||
var mediaFileSystem = Current.MediaFileSystem;
|
||||
|
||||
Assert.IsFalse(physMediaFileSystem.FileExists("f1.txt"));
|
||||
|
||||
@@ -72,12 +72,12 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
if (complete)
|
||||
{
|
||||
Assert.IsTrue(Current.FileSystems.MediaFileSystem.FileExists("f1.txt"));
|
||||
Assert.IsTrue(Current.MediaFileSystem.FileExists("f1.txt"));
|
||||
Assert.IsTrue(physMediaFileSystem.FileExists("f1.txt"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsFalse(Current.FileSystems.MediaFileSystem.FileExists("f1.txt"));
|
||||
Assert.IsFalse(Current.MediaFileSystem.FileExists("f1.txt"));
|
||||
Assert.IsFalse(physMediaFileSystem.FileExists("f1.txt"));
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@ namespace Umbraco.Tests.Scoping
|
||||
public void MultiThread()
|
||||
{
|
||||
var physMediaFileSystem = new PhysicalFileSystem(IOHelper.MapPath("media"), "ignore");
|
||||
var mediaFileSystem = Current.FileSystems.MediaFileSystem;
|
||||
var mediaFileSystem = Current.MediaFileSystem;
|
||||
|
||||
var scopeProvider = ScopeProvider;
|
||||
using (var scope = scopeProvider.CreateScope(scopeFileSystems: true))
|
||||
|
||||
@@ -150,9 +150,6 @@ namespace Umbraco.Tests.TestHelpers
|
||||
MockFs(fileSystems, x => x.ScriptsFileSystem);
|
||||
MockFs(fileSystems, x => x.StylesheetsFileSystem);
|
||||
|
||||
var mediaFs = new MediaFileSystem(Mock.Of<IFileSystem>());
|
||||
Mock.Get(fileSystems).Setup(x => x.MediaFileSystem).Returns(mediaFs);
|
||||
|
||||
return fileSystems;
|
||||
}
|
||||
|
||||
|
||||
@@ -297,7 +297,7 @@ namespace Umbraco.Tests.Testing
|
||||
|
||||
// register filesystems
|
||||
Container.RegisterSingleton(factory => TestObjects.GetFileSystemsMock());
|
||||
Container.RegisterSingleton(factory => factory.GetInstance<IFileSystems>().MediaFileSystem);
|
||||
Container.RegisterSingleton<IMediaFileSystem>(factory => new MediaFileSystem(Mock.Of<IFileSystem>()));
|
||||
|
||||
// no factory (noop)
|
||||
Container.RegisterSingleton<IPublishedModelFactory, NoopPublishedModelFactory>();
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
using (var fs = System.IO.File.OpenRead(file.LocalFileName))
|
||||
{
|
||||
Current.FileSystems.MediaFileSystem.AddFile(user.Avatar, fs, true);
|
||||
Current.MediaFileSystem.AddFile(user.Avatar, fs, true);
|
||||
}
|
||||
|
||||
userService.Save(user);
|
||||
@@ -146,8 +146,8 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
if (filePath.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
if (Current.FileSystems.MediaFileSystem.FileExists(filePath))
|
||||
Current.FileSystems.MediaFileSystem.DeleteFile(filePath);
|
||||
if (Current.MediaFileSystem.FileExists(filePath))
|
||||
Current.MediaFileSystem.DeleteFile(filePath);
|
||||
}
|
||||
|
||||
return Request.CreateResponse(HttpStatusCode.OK, found.GetUserAvatarUrls(ApplicationCache.StaticCache));
|
||||
|
||||
Reference in New Issue
Block a user