Refactor filesystems (again)

This commit is contained in:
Stephan
2018-11-19 14:40:59 +01:00
parent 3960791bf2
commit 87a64b7406
19 changed files with 203 additions and 254 deletions

View File

@@ -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);
}
}
}

View File

@@ -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>();

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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; }
}
}

View File

@@ -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();
}
}
}
}
}

View File

@@ -34,10 +34,5 @@
/// Gets the MVC views filesystem.
/// </summary>
IFileSystem MvcViewsFileSystem { get; }
/// <summary>
/// Gets the media filesystem.
/// </summary>
IMediaFileSystem MediaFileSystem { get; }
}
}

View File

@@ -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);
}
}
}

View File

@@ -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>

View File

@@ -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);
}
}
}

View File

@@ -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",

View File

@@ -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" />

View File

@@ -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)
{ }
}
*/
}
}

View File

@@ -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]

View File

@@ -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>());
}

View File

@@ -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))

View File

@@ -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;
}

View File

@@ -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>();

View File

@@ -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));