Adjusting FileSystemStorageProvider path semantics

All path information coming in and out is within a tenant-specific location
The location is now an implementation detail of the component

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-04-30 10:02:16 -07:00
parent 312d6d812c
commit f60608368c
4 changed files with 212 additions and 53 deletions

View File

@@ -3,43 +3,170 @@ using System.IO;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using System; using System;
using Orchard.Environment.Configuration;
using Orchard.Storage; using Orchard.Storage;
namespace Orchard.Tests.Storage { namespace Orchard.Tests.Storage {
[TestFixture] [TestFixture]
public class FileSystemStorageProviderTests { public class FileSystemStorageProviderTests {
#region Setup/Teardown
[TestFixtureSetUp] [SetUp]
public void InitFixture() { public void Init() {
_folderPath = Directory.CreateDirectory(Path.GetTempPath() + "filesystemstorageprovidertests").FullName; _folderPath = Path.Combine(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Media"), "Default");
_filePath = _folderPath + "\\testfile.txt"; _filePath = _folderPath + "\\testfile.txt";
FileStream fileStream = File.Create(_filePath);
fileStream.Close(); Directory.CreateDirectory(_folderPath);
_fileSystemStorageProvider = new FileSystemStorageProvider(); File.WriteAllText(_filePath, "testfile contents");
var subfolder1 = Path.Combine(_folderPath, "Subfolder1");
Directory.CreateDirectory(subfolder1);
File.WriteAllText(Path.Combine(subfolder1, "one.txt"), "one contents");
File.WriteAllText(Path.Combine(subfolder1, "two.txt"), "two contents");
var subsubfolder1 = Path.Combine(subfolder1, "SubSubfolder1");
Directory.CreateDirectory(subsubfolder1);
_storageProvider = new FileSystemStorageProvider(new ShellSettings { Name = "Default" });
} }
[TestFixtureTearDown] [TearDown]
public void TermFixture() { public void Term() {
Directory.Delete(_folderPath, true); Directory.Delete(_folderPath, true);
} }
#endregion
private string _filePath; private string _filePath;
private string _folderPath; private string _folderPath;
private FileSystemStorageProvider _fileSystemStorageProvider; private IStorageProvider _storageProvider;
[Test] [Test]
[ExpectedException(typeof(ArgumentException))] [ExpectedException(typeof(ArgumentException))]
public void GetFileThatDoesNotExistShouldThrow() { public void GetFileThatDoesNotExistShouldThrow() {
_fileSystemStorageProvider.GetFile("notexisting"); _storageProvider.GetFile("notexisting");
} }
[Test] [Test]
public void ListFilesShouldReturnFilesFromFilesystem() { public void ListFilesShouldReturnFilesFromFilesystem() {
IEnumerable<IStorageFile> files = _fileSystemStorageProvider.ListFiles(_folderPath); IEnumerable<IStorageFile> files = _storageProvider.ListFiles(_folderPath);
Assert.That(files.Count(), Is.EqualTo(1)); Assert.That(files.Count(), Is.EqualTo(1));
} }
[Test]
public void ExistingFileIsReturnedWithShortPath() {
var file = _storageProvider.GetFile("testfile.txt");
Assert.That(file, Is.Not.Null);
Assert.That(file.GetPath(), Is.EqualTo("testfile.txt"));
Assert.That(file.GetName(), Is.EqualTo("testfile.txt"));
}
[Test]
public void ListFilesReturnsItemsWithShortPathAndEnvironmentSlashes() {
var files = _storageProvider.ListFiles("Subfolder1");
Assert.That(files, Is.Not.Null);
Assert.That(files.Count(), Is.EqualTo(2));
var one = files.Single(x => x.GetName() == "one.txt");
var two = files.Single(x => x.GetName() == "two.txt");
Assert.That(one.GetPath(), Is.EqualTo("Subfolder1" + Path.DirectorySeparatorChar + "one.txt"));
Assert.That(two.GetPath(), Is.EqualTo("Subfolder1" + Path.DirectorySeparatorChar + "two.txt"));
}
[Test]
public void AnySlashInGetFileBecomesEnvironmentAppropriate() {
var file1 = _storageProvider.GetFile(@"Subfolder1/one.txt");
var file2 = _storageProvider.GetFile(@"Subfolder1\one.txt");
Assert.That(file1.GetPath(), Is.EqualTo("Subfolder1" + Path.DirectorySeparatorChar + "one.txt"));
Assert.That(file2.GetPath(), Is.EqualTo("Subfolder1" + Path.DirectorySeparatorChar + "one.txt"));
}
[Test]
public void ListFoldersReturnsItemsWithShortPathAndEnvironmentSlashes() {
var folders = _storageProvider.ListFolders(@"Subfolder1");
Assert.That(folders, Is.Not.Null);
Assert.That(folders.Count(), Is.EqualTo(1));
Assert.That(folders.Single().GetName(), Is.EqualTo("SubSubfolder1"));
Assert.That(folders.Single().GetPath(), Is.EqualTo(Path.Combine("Subfolder1", "SubSubfolder1")));
}
[Test]
public void ParentFolderPathIsStillShort() {
var subsubfolder = _storageProvider.ListFolders(@"Subfolder1").Single();
var subfolder = subsubfolder.GetParent();
Assert.That(subsubfolder.GetName(), Is.EqualTo("SubSubfolder1"));
Assert.That(subsubfolder.GetPath(), Is.EqualTo(Path.Combine("Subfolder1", "SubSubfolder1")));
Assert.That(subfolder.GetName(), Is.EqualTo("Subfolder1"));
Assert.That(subfolder.GetPath(), Is.EqualTo("Subfolder1"));
}
[Test]
public void CreateFolderAndDeleteFolderTakesAnySlash() {
Assert.That(_storageProvider.ListFolders(@"Subfolder1").Count(), Is.EqualTo(1));
_storageProvider.CreateFolder(@"SubFolder1/SubSubFolder2");
_storageProvider.CreateFolder(@"SubFolder1\SubSubFolder3");
Assert.That(_storageProvider.ListFolders(@"Subfolder1").Count(), Is.EqualTo(3));
_storageProvider.DeleteFolder(@"SubFolder1/SubSubFolder2");
_storageProvider.DeleteFolder(@"SubFolder1\SubSubFolder3");
Assert.That(_storageProvider.ListFolders(@"Subfolder1").Count(), Is.EqualTo(1));
}
private IStorageFolder GetFolder(string path) {
return _storageProvider.ListFolders(Path.GetDirectoryName(path))
.SingleOrDefault(x => string.Equals(x.GetName(), Path.GetFileName(path), StringComparison.OrdinalIgnoreCase));
}
private IStorageFile GetFile(string path) {
try {
return _storageProvider.GetFile(path);
}
catch (ArgumentException) {
return null;
} }
} }
[Test]
public void RenameFolderTakesShortPathWithAnyKindOfSlash() {
Assert.That(GetFolder(@"SubFolder1/SubSubFolder1"), Is.Not.Null);
_storageProvider.RenameFolder(@"SubFolder1\SubSubFolder1", @"SubFolder1/SubSubFolder2");
_storageProvider.RenameFolder(@"SubFolder1\SubSubFolder2", @"SubFolder1\SubSubFolder3");
_storageProvider.RenameFolder(@"SubFolder1/SubSubFolder3", @"SubFolder1\SubSubFolder4");
_storageProvider.RenameFolder(@"SubFolder1/SubSubFolder4", @"SubFolder1/SubSubFolder5");
Assert.That(GetFolder(Path.Combine("SubFolder1", "SubSubFolder1")), Is.Null);
Assert.That(GetFolder(Path.Combine("SubFolder1", "SubSubFolder2")), Is.Null);
Assert.That(GetFolder(Path.Combine("SubFolder1", "SubSubFolder3")), Is.Null);
Assert.That(GetFolder(Path.Combine("SubFolder1", "SubSubFolder4")), Is.Null);
Assert.That(GetFolder(Path.Combine("SubFolder1", "SubSubFolder5")), Is.Not.Null);
}
[Test]
public void CreateFileAndDeleteFileTakesAnySlash() {
Assert.That(_storageProvider.ListFiles(@"Subfolder1").Count(), Is.EqualTo(2));
var alpha = _storageProvider.CreateFile(@"SubFolder1/alpha.txt");
var beta = _storageProvider.CreateFile(@"SubFolder1\beta.txt");
Assert.That(_storageProvider.ListFiles(@"Subfolder1").Count(), Is.EqualTo(4));
Assert.That(alpha.GetPath(), Is.EqualTo(Path.Combine("SubFolder1", "alpha.txt")));
Assert.That(beta.GetPath(), Is.EqualTo(Path.Combine("SubFolder1", "beta.txt")));
_storageProvider.DeleteFile(@"SubFolder1\alpha.txt");
_storageProvider.DeleteFile(@"SubFolder1/beta.txt");
Assert.That(_storageProvider.ListFiles(@"Subfolder1").Count(), Is.EqualTo(2));
}
[Test]
public void RenameFileTakesShortPathWithAnyKindOfSlash() {
Assert.That(GetFile(@"Subfolder1/one.txt"), Is.Not.Null);
_storageProvider.RenameFile(@"SubFolder1\one.txt", @"SubFolder1/testfile2.txt");
_storageProvider.RenameFile(@"SubFolder1\testfile2.txt", @"SubFolder1\testfile3.txt");
_storageProvider.RenameFile(@"SubFolder1/testfile3.txt", @"SubFolder1\testfile4.txt");
_storageProvider.RenameFile(@"SubFolder1/testfile4.txt", @"SubFolder1/testfile5.txt");
Assert.That(GetFile(Path.Combine("SubFolder1", "one.txt")), Is.Null);
Assert.That(GetFile(Path.Combine("SubFolder1", "testfile2.txt")), Is.Null);
Assert.That(GetFile(Path.Combine("SubFolder1", "testfile3.txt")), Is.Null);
Assert.That(GetFile(Path.Combine("SubFolder1", "testfile4.txt")), Is.Null);
Assert.That(GetFile(Path.Combine("SubFolder1", "testfile5.txt")), Is.Not.Null);
}
}
}

View File

@@ -102,6 +102,10 @@
<Project>{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}</Project> <Project>{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}</Project>
<Name>Orchard.Framework</Name> <Name>Orchard.Framework</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\Tools\Orchard\Orchard.csproj">
<Project>{33B1BC8D-E292-4972-A363-22056B207156}</Project>
<Name>Orchard</Name>
</ProjectReference>
<ProjectReference Include="Core\Orchard.Core.csproj"> <ProjectReference Include="Core\Orchard.Core.csproj">
<Project>{9916839C-39FC-4CEB-A5AF-89CA7E87119F}</Project> <Project>{9916839C-39FC-4CEB-A5AF-89CA7E87119F}</Project>
<Name>Orchard.Core</Name> <Name>Orchard.Core</Name>

View File

@@ -2,44 +2,68 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Web.Hosting;
using Orchard.Environment.Configuration;
namespace Orchard.Storage { namespace Orchard.Storage {
public class FileSystemStorageProvider : IStorageProvider { public class FileSystemStorageProvider : IStorageProvider {
private readonly ShellSettings _settings;
private string _storagePath;
public FileSystemStorageProvider(ShellSettings settings) {
_settings = settings;
var mediaPath = HostingEnvironment.IsHosted
? HostingEnvironment.MapPath("~/Media/")
: Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Media");
_storagePath = Path.Combine(mediaPath, settings.Name);
}
string Map(string path) {
return Path.Combine(_storagePath, path);
}
static string Fix(string path) {
return Path.DirectorySeparatorChar != '/'
? path.Replace('/', Path.DirectorySeparatorChar)
: path;
}
#region Implementation of IStorageProvider #region Implementation of IStorageProvider
public IStorageFile GetFile(string path) { public IStorageFile GetFile(string path) {
if (!File.Exists(path)) { if (!File.Exists(Map(path))) {
throw new ArgumentException("File " + path + " does not exist"); throw new ArgumentException("File " + path + " does not exist");
} }
return new FileSystemStorageFile(new FileInfo(path)); return new FileSystemStorageFile(Fix(path), new FileInfo(Map(path)));
} }
public IEnumerable<IStorageFile> ListFiles(string path) { public IEnumerable<IStorageFile> ListFiles(string path) {
if (!Directory.Exists(path)) { if (!Directory.Exists(Map(path))) {
throw new ArgumentException("Directory " + path + " does not exist"); throw new ArgumentException("Directory " + path + " does not exist");
} }
return new DirectoryInfo(path) return new DirectoryInfo(Map(path))
.GetFiles() .GetFiles()
.Where(fi => !IsHidden(fi)) .Where(fi => !IsHidden(fi))
.Select<FileInfo, IStorageFile>(fi => new FileSystemStorageFile(fi)) .Select<FileInfo, IStorageFile>(fi => new FileSystemStorageFile(Path.Combine(Fix(path), fi.Name), fi))
.ToList(); .ToList();
} }
public IEnumerable<IStorageFolder> ListFolders(string path) { public IEnumerable<IStorageFolder> ListFolders(string path) {
if (!Directory.Exists(path)) { if (!Directory.Exists(Map(path))) {
try { try {
Directory.CreateDirectory(path); Directory.CreateDirectory(Map(path));
} }
catch (Exception ex) { catch (Exception ex) {
throw new ArgumentException(string.Format("The folder could not be created at path: {0}. {1}", path, ex)); throw new ArgumentException(string.Format("The folder could not be created at path: {0}. {1}", path, ex));
} }
} }
return new DirectoryInfo(path) return new DirectoryInfo(Map(path))
.GetDirectories() .GetDirectories()
.Where(di => !IsHidden(di)) .Where(di => !IsHidden(di))
.Select<DirectoryInfo, IStorageFolder>(di => new FileSystemStorageFolder(di)) .Select<DirectoryInfo, IStorageFolder>(di => new FileSystemStorageFolder(Path.Combine(Fix(path), di.Name), di))
.ToList(); .ToList();
} }
@@ -48,81 +72,80 @@ namespace Orchard.Storage {
} }
public void CreateFolder(string path) { public void CreateFolder(string path) {
if (Directory.Exists(path)) { if (Directory.Exists(Map(path))) {
throw new ArgumentException("Directory " + path + " already exists"); throw new ArgumentException("Directory " + path + " already exists");
} }
Directory.CreateDirectory(path); Directory.CreateDirectory(Map(path));
} }
public void DeleteFolder(string path) { public void DeleteFolder(string path) {
if (!Directory.Exists(path)) { if (!Directory.Exists(Map(path))) {
throw new ArgumentException("Directory " + path + " does not exist"); throw new ArgumentException("Directory " + path + " does not exist");
} }
Directory.Delete(path, true); Directory.Delete(Map(path), true);
} }
public void RenameFolder(string path, string newPath) { public void RenameFolder(string path, string newPath) {
if (!Directory.Exists(path)) { if (!Directory.Exists(Map(path))) {
throw new ArgumentException("Directory " + path + "does not exist"); throw new ArgumentException("Directory " + path + "does not exist");
} }
if (Directory.Exists(newPath)) { if (Directory.Exists(Map(newPath))) {
throw new ArgumentException("Directory " + newPath + " already exists"); throw new ArgumentException("Directory " + newPath + " already exists");
} }
Directory.Move(path, newPath); Directory.Move(Map(path), Map(newPath));
} }
public IStorageFile CreateFile(string path) { public IStorageFile CreateFile(string path) {
if (File.Exists(path)) { if (File.Exists(Map(path))) {
throw new ArgumentException("File " + path + " already exists"); throw new ArgumentException("File " + path + " already exists");
} }
var fileInfo = new FileInfo(path); var fileInfo = new FileInfo(Map(path));
fileInfo.Create(); using (var stream = fileInfo.Create()) {
return new FileSystemStorageFile(fileInfo);
}
return new FileSystemStorageFile(Fix(path), fileInfo);
} }
public void DeleteFile(string path) { public void DeleteFile(string path) {
if (!File.Exists(path)) { if (!File.Exists(Map(path))) {
throw new ArgumentException("File " + path + " does not exist"); throw new ArgumentException("File " + path + " does not exist");
} }
File.Delete(path); File.Delete(Map(path));
} }
public void RenameFile(string path, string newPath) { public void RenameFile(string path, string newPath) {
if (!File.Exists(path)) { if (!File.Exists(Map(path))) {
throw new ArgumentException("File " + path + " does not exist"); throw new ArgumentException("File " + path + " does not exist");
} }
if (File.Exists(newPath)) { if (File.Exists(Map(newPath))) {
throw new ArgumentException("File " + newPath + " already exists"); throw new ArgumentException("File " + newPath + " already exists");
} }
File.Move(path, newPath); File.Move(Map(path), Map(newPath));
}
public string Combine(string path1, string path2)
{
return Path.Combine(path1, path2);
} }
#endregion #endregion
private class FileSystemStorageFile : IStorageFile { private class FileSystemStorageFile : IStorageFile {
private readonly string _path;
private readonly FileInfo _fileInfo; private readonly FileInfo _fileInfo;
public FileSystemStorageFile(FileInfo fileInfo) { public FileSystemStorageFile(string path, FileInfo fileInfo) {
_path = path;
_fileInfo = fileInfo; _fileInfo = fileInfo;
} }
#region Implementation of IStorageFile #region Implementation of IStorageFile
public string GetPath() { public string GetPath() {
return _fileInfo.FullName; return _path;
} }
public string GetName() { public string GetName() {
@@ -141,13 +164,11 @@ namespace Orchard.Storage {
return _fileInfo.Extension; return _fileInfo.Extension;
} }
public Stream OpenRead() public Stream OpenRead() {
{
return new FileStream(_fileInfo.FullName, FileMode.Open, FileAccess.Read); return new FileStream(_fileInfo.FullName, FileMode.Open, FileAccess.Read);
} }
public Stream OpenWrite() public Stream OpenWrite() {
{
return new FileStream(_fileInfo.FullName, FileMode.Open, FileAccess.ReadWrite); return new FileStream(_fileInfo.FullName, FileMode.Open, FileAccess.ReadWrite);
} }
@@ -155,14 +176,20 @@ namespace Orchard.Storage {
} }
private class FileSystemStorageFolder : IStorageFolder { private class FileSystemStorageFolder : IStorageFolder {
private readonly string _path;
private readonly DirectoryInfo _directoryInfo; private readonly DirectoryInfo _directoryInfo;
public FileSystemStorageFolder(DirectoryInfo directoryInfo) { public FileSystemStorageFolder(string path, DirectoryInfo directoryInfo) {
_path = path;
_directoryInfo = directoryInfo; _directoryInfo = directoryInfo;
} }
#region Implementation of IStorageFolder #region Implementation of IStorageFolder
public string GetPath() {
return _path;
}
public string GetName() { public string GetName() {
return _directoryInfo.Name; return _directoryInfo.Name;
} }
@@ -177,7 +204,7 @@ namespace Orchard.Storage {
public IStorageFolder GetParent() { public IStorageFolder GetParent() {
if (_directoryInfo.Parent != null) { if (_directoryInfo.Parent != null) {
return new FileSystemStorageFolder(_directoryInfo.Parent); return new FileSystemStorageFolder(Path.GetDirectoryName(_path), _directoryInfo.Parent);
} }
throw new ArgumentException("Directory " + _directoryInfo.Name + " does not have a parent directory"); throw new ArgumentException("Directory " + _directoryInfo.Name + " does not have a parent directory");
} }

View File

@@ -2,6 +2,7 @@
namespace Orchard.Storage { namespace Orchard.Storage {
public interface IStorageFolder { public interface IStorageFolder {
string GetPath();
string GetName(); string GetName();
long GetSize(); long GetSize();
DateTime GetLastUpdated(); DateTime GetLastUpdated();