1
0
mirror of https://github.com/Radarr/Radarr.git synced 2024-09-17 15:02:34 +02:00

Added OsPath to handle OS agnostic path handling.

This commit is contained in:
Taloth Saldono 2014-10-13 00:00:03 +02:00
parent 67cd5703a1
commit 8a86b8acdc
28 changed files with 799 additions and 182 deletions

View File

@ -80,6 +80,7 @@
<Compile Include="Http\HttpRequestFixture.cs" />
<Compile Include="InstrumentationTests\CleanseLogMessageFixture.cs" />
<Compile Include="LevenshteinDistanceFixture.cs" />
<Compile Include="OsPathFixture.cs" />
<Compile Include="PathExtensionFixture.cs" />
<Compile Include="ProcessProviderTests.cs" />
<Compile Include="ReflectionExtensions.cs" />

View File

@ -0,0 +1,237 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Test.Common;
using FluentAssertions;
namespace NzbDrone.Common.Test
{
public class OsPathFixture : TestBase
{
[TestCase(@"C:\rooted\windows\path\", OsPathKind.Windows)]
[TestCase(@"C:\rooted\windows\path", OsPathKind.Windows)]
[TestCase(@"C:\", OsPathKind.Windows)]
[TestCase(@"C:", OsPathKind.Windows)]
[TestCase(@"\\rooted\unc\path\", OsPathKind.Windows)]
[TestCase(@"\\rooted\unc\path", OsPathKind.Windows)]
[TestCase(@"\relative\windows\path\", OsPathKind.Windows)]
[TestCase(@"\relative\windows\path", OsPathKind.Windows)]
[TestCase(@"relative\windows\path\", OsPathKind.Windows)]
[TestCase(@"relative\windows\path", OsPathKind.Windows)]
[TestCase(@"relative\", OsPathKind.Windows)]
[TestCase(@"relative", OsPathKind.Unknown)]
[TestCase("/rooted/linux/path/", OsPathKind.Unix)]
[TestCase("/rooted/linux/path", OsPathKind.Unix)]
[TestCase("/", OsPathKind.Unix)]
[TestCase("linux/path", OsPathKind.Unix)]
public void should_auto_detect_kind(String path, OsPathKind kind)
{
var result = new OsPath(path);
result.Kind.Should().Be(kind);
if (kind == OsPathKind.Windows)
{
result.IsWindowsPath.Should().BeTrue();
result.IsUnixPath.Should().BeFalse();
}
else if (kind == OsPathKind.Unix)
{
result.IsWindowsPath.Should().BeFalse();
result.IsUnixPath.Should().BeTrue();
}
else
{
result.IsWindowsPath.Should().BeFalse();
result.IsUnixPath.Should().BeFalse();
}
}
[Test]
public void should_add_directory_slash()
{
var osPath = new OsPath(@"C:\rooted\windows\path\");
osPath.Directory.Should().NotBeNull();
osPath.Directory.ToString().Should().Be(@"C:\rooted\windows\");
}
[TestCase(@"C:\rooted\windows\path", @"C:\rooted\windows\")]
[TestCase(@"C:\rooted", @"C:\")]
[TestCase(@"C:", null)]
[TestCase("/rooted/linux/path", "/rooted/linux/")]
[TestCase("/rooted", "/")]
[TestCase("/", null)]
public void should_return_parent_directory(String path, String expectedParent)
{
var osPath = new OsPath(path);
osPath.Directory.Should().NotBeNull();
osPath.Directory.Should().Be(new OsPath(expectedParent));
}
[Test]
public void should_return_empty_as_parent_of_root_unc()
{
var osPath = new OsPath(@"\\unc");
osPath.Directory.IsEmpty.Should().BeTrue();
}
[TestCase(@"C:\rooted\windows\path")]
[TestCase(@"C:")]
[TestCase(@"\\blaat")]
[TestCase("/rooted/linux/path")]
[TestCase("/")]
public void should_detect_rooted_ospaths(String path)
{
var osPath = new OsPath(path);
osPath.IsRooted.Should().BeTrue();
}
[TestCase(@"\rooted\windows\path")]
[TestCase(@"rooted\windows\path")]
[TestCase(@"path")]
[TestCase("linux/path")]
public void should_detect_unrooted_ospaths(String path)
{
var osPath = new OsPath(path);
osPath.IsRooted.Should().BeFalse();
}
[TestCase(@"C:\rooted\windows\path", "path")]
[TestCase(@"C:", "C:")]
[TestCase(@"\\blaat", "blaat")]
[TestCase("/rooted/linux/path", "path")]
[TestCase("/", null)]
[TestCase(@"\rooted\windows\path\", "path")]
[TestCase(@"rooted\windows\path", "path")]
[TestCase(@"path", "path")]
[TestCase("linux/path", "path")]
public void should_return_filename(String path, String expectedFilePath)
{
var osPath = new OsPath(path);
osPath.FileName.Should().Be(expectedFilePath);
}
[Test]
public void should_compare_windows_ospathkind_case_insensitive()
{
var left = new OsPath(@"C:\rooted\Windows\path");
var right = new OsPath(@"C:\rooted\windows\path");
left.Should().Be(right);
}
[Test]
public void should_compare_unix_ospathkind_case_sensitive()
{
var left = new OsPath(@"/rooted/Linux/path");
var right = new OsPath(@"/rooted/linux/path");
left.Should().NotBe(right);
}
[Test]
public void should_not_ignore_trailing_slash_during_compare()
{
var left = new OsPath(@"/rooted/linux/path/");
var right = new OsPath(@"/rooted/linux/path");
left.Should().NotBe(right);
}
[TestCase(@"C:\Test", @"sub", @"C:\Test\sub")]
[TestCase(@"C:\Test", @"sub\test", @"C:\Test\sub\test")]
[TestCase(@"C:\Test\", @"\sub", @"C:\Test\sub")]
[TestCase(@"C:\Test", @"sub\", @"C:\Test\sub\")]
[TestCase(@"C:\Test", @"C:\Test2\sub", @"C:\Test2\sub")]
[TestCase(@"/Test", @"sub", @"/Test/sub")]
[TestCase(@"/Test", @"sub/", @"/Test/sub/")]
[TestCase(@"/Test", @"sub/", @"/Test/sub/")]
[TestCase(@"/Test/", @"sub/test/", @"/Test/sub/test/")]
[TestCase(@"/Test/", @"/Test2/", @"/Test2/")]
[TestCase(@"C:\Test", "", @"C:\Test")]
public void should_combine_path(String left, String right, String expectedResult)
{
var osPathLeft = new OsPath(left);
var osPathRight = new OsPath(right);
var result = osPathLeft + osPathRight;
result.FullPath.Should().Be(expectedResult);
}
[Test]
public void should_fix_slashes_windows()
{
var osPath = new OsPath(@"C:/on/windows/transmission\uses/forward/slashes");
osPath.Kind.Should().Be(OsPathKind.Windows);
osPath.FullPath.Should().Be(@"C:\on\windows\transmission\uses\forward\slashes");
}
[Test]
public void should_fix_slashes_unix()
{
var osPath = new OsPath(@"/just/a/test\to\verify the/slashes\");
osPath.Kind.Should().Be(OsPathKind.Unix);
osPath.FullPath.Should().Be(@"/just/a/test/to/verify the/slashes/");
}
[Test]
public void should_combine_mixed_slashes()
{
var left = new OsPath(@"C:/on/windows/transmission");
var right = new OsPath(@"uses/forward/slashes", OsPathKind.Unknown);
var osPath = left + right;
osPath.Kind.Should().Be(OsPathKind.Windows);
osPath.FullPath.Should().Be(@"C:\on\windows\transmission\uses\forward\slashes");
}
[TestCase(@"C:\Test\Data\", @"C:\Test\Data\Sub\Folder", @"Sub\Folder")]
[TestCase(@"C:\Test\Data\", @"C:\Test\Data2\Sub\Folder", @"..\Data2\Sub\Folder")]
[TestCase(@"/parent/folder", @"/parent/folder/Sub/Folder", @"Sub/Folder")]
public void should_create_relative_path(String parent, String child, String expected)
{
var left = new OsPath(child);
var right = new OsPath(parent);
var osPath = left - right;
osPath.Kind.Should().Be(OsPathKind.Unknown);
osPath.FullPath.Should().Be(expected);
}
[Test]
public void should_parse_null_as_empty()
{
var result = new OsPath(null);
result.FullPath.Should().BeEmpty();
result.IsEmpty.Should().BeTrue();
}
[TestCase(@"C:\Test\", @"C:\Test", true)]
[TestCase(@"C:\Test\", @"C:\Test\Contains\", true)]
[TestCase(@"C:\Test\", @"C:\Other\", false)]
public void should_evaluate_contains(String parent, String child, Boolean expectedResult)
{
var left = new OsPath(parent);
var right = new OsPath(child);
var result = left.Contains(right);
result.Should().Be(expectedResult);
}
}
}

View File

@ -0,0 +1,406 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NzbDrone.Common.Exceptions;
namespace NzbDrone.Common.Disk
{
public struct OsPath : IEquatable<OsPath>
{
private readonly String _path;
private readonly OsPathKind _kind;
public OsPath(String path)
{
if (path == null)
{
_kind = OsPathKind.Unknown;
_path = String.Empty;
}
else
{
_kind = DetectPathKind(path);
_path = FixSlashes(path, _kind);
}
}
public OsPath(String path, OsPathKind kind)
{
if (path == null)
{
_kind = kind;
_path = String.Empty;
}
else
{
_kind = kind;
_path = FixSlashes(path, kind);
}
}
private static OsPathKind DetectPathKind(String path)
{
if (path.StartsWith("/"))
{
return OsPathKind.Unix;
}
if (path.Contains(':') || path.Contains('\\'))
{
return OsPathKind.Windows;
}
else if (path.Contains('/'))
{
return OsPathKind.Unix;
}
else
{
return OsPathKind.Unknown;
}
}
private static String FixSlashes(String path, OsPathKind kind)
{
if (kind == OsPathKind.Windows)
{
return path.Replace('/', '\\');
}
else if (kind == OsPathKind.Unix)
{
return path.Replace('\\', '/');
}
return path;
}
public OsPathKind Kind
{
get { return _kind; }
}
public Boolean IsWindowsPath
{
get { return _kind == OsPathKind.Windows; }
}
public Boolean IsUnixPath
{
get { return _kind == OsPathKind.Unix; }
}
public Boolean IsEmpty
{
get
{
return _path.IsNullOrWhiteSpace();
}
}
public Boolean IsRooted
{
get
{
if (IsWindowsPath)
{
return _path.StartsWith(@"\\") || _path.Contains(':');
}
else if (IsUnixPath)
{
return _path.StartsWith("/");
}
else
{
return false;
}
}
}
public OsPath Directory
{
get
{
var index = GetFileNameIndex();
if (index == -1)
{
return new OsPath(null);
}
else
{
return new OsPath(_path.Substring(0, index), _kind).AsDirectory();
}
}
}
public String FullPath
{
get
{
return _path;
}
}
public String FileName
{
get
{
var index = GetFileNameIndex();
if (index == -1)
{
var path = _path.Trim('\\', '/');
if (path.Length == 0)
{
return null;
}
return path;
}
else
{
return _path.Substring(index).Trim('\\', '/');
}
}
}
private Int32 GetFileNameIndex()
{
if (_path.Length < 2)
{
return -1;
}
var index = _path.LastIndexOfAny(new[] { '/', '\\' }, _path.Length - 2);
if (index == -1)
{
return -1;
}
if (_path.StartsWith(@"\\") && index < 2)
{
return -1;
}
if (_path.StartsWith("/") && index == 0)
{
index++;
}
return index;
}
private String[] GetFragments()
{
return _path.Split(new char[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
}
public override String ToString()
{
return _path;
}
public override Int32 GetHashCode()
{
return _path.ToLowerInvariant().GetHashCode();
}
public override Boolean Equals(Object obj)
{
if (obj is OsPath)
{
return Equals((OsPath)obj);
}
else if (obj is String)
{
return Equals(new OsPath(obj as String));
}
else
{
return false;
}
}
public OsPath AsDirectory()
{
if (IsEmpty)
{
return this;
}
if (Kind == OsPathKind.Windows)
{
return new OsPath(_path.TrimEnd('\\') + "\\", _kind);
}
else if (Kind == OsPathKind.Unix)
{
return new OsPath(_path.TrimEnd('/') + "/", _kind);
}
else
{
return this;
}
}
public Boolean Contains(OsPath other)
{
if (!IsRooted || !other.IsRooted)
{
return false;
}
var leftFragments = GetFragments();
var rightFragments = other.GetFragments();
if (rightFragments.Length < leftFragments.Length)
{
return false;
}
var stringComparison = (Kind == OsPathKind.Windows || other.Kind == OsPathKind.Windows) ? StringComparison.InvariantCultureIgnoreCase : StringComparison.InvariantCulture;
for (int i = 0; i < leftFragments.Length; i++)
{
if (!String.Equals(leftFragments[i], rightFragments[i], stringComparison))
{
return false;
}
}
return true;
}
public Boolean Equals(OsPath other)
{
if (ReferenceEquals(other, null)) return false;
if (_path == other._path)
{
return true;
}
var left = _path;
var right = other._path;
if (Kind == OsPathKind.Windows || other.Kind == OsPathKind.Windows)
{
return String.Equals(left, right, StringComparison.InvariantCultureIgnoreCase);
}
else
{
return String.Equals(left, right, StringComparison.InvariantCulture);
}
}
public static Boolean operator ==(OsPath left, OsPath right)
{
if (ReferenceEquals(left, null)) return ReferenceEquals(right, null);
return left.Equals(right);
}
public static Boolean operator !=(OsPath left, OsPath right)
{
if (ReferenceEquals(left, null)) return !ReferenceEquals(right, null);
return !left.Equals(right);
}
public static OsPath operator +(OsPath left, OsPath right)
{
if (left.Kind != right.Kind && right.Kind != OsPathKind.Unknown)
{
throw new Exception(String.Format("Cannot combine OsPaths of different platforms ('{0}' + '{1}')", left, right));
}
if (right.IsEmpty)
{
return left;
}
if (right.IsRooted)
{
return right;
}
if (left.Kind == OsPathKind.Windows || right.Kind == OsPathKind.Windows)
{
return new OsPath(String.Join("\\", left._path.TrimEnd('\\'), right._path.TrimStart('\\')), OsPathKind.Windows);
}
else if (left.Kind == OsPathKind.Unix || right.Kind == OsPathKind.Unix)
{
return new OsPath(String.Join("/", left._path.TrimEnd('/'), right._path), OsPathKind.Unix);
}
else
{
return new OsPath(String.Join("/", left._path, right._path), OsPathKind.Unknown);
}
}
public static OsPath operator +(OsPath left, String right)
{
return left + new OsPath(right);
}
public static OsPath operator -(OsPath left, OsPath right)
{
if (!left.IsRooted || !right.IsRooted)
{
throw new ArgumentException("Cannot determine relative path for unrooted paths.");
}
var leftFragments = left.GetFragments();
var rightFragments = right.GetFragments();
var stringComparison = (left.Kind == OsPathKind.Windows || right.Kind == OsPathKind.Windows) ? StringComparison.InvariantCultureIgnoreCase : StringComparison.InvariantCulture;
int i;
for (i = 0; i < leftFragments.Length && i < rightFragments.Length; i++)
{
if (!String.Equals(leftFragments[i], rightFragments[i], stringComparison))
{
break;
}
}
if (i == 0)
{
return right;
}
var newFragments = new List<String>();
for (int j = i; j < rightFragments.Length; j++)
{
newFragments.Add("..");
}
for (int j = i; j < leftFragments.Length; j++)
{
newFragments.Add(leftFragments[j]);
}
if (left.FullPath.EndsWith("\\") || left.FullPath.EndsWith("/"))
{
newFragments.Add(String.Empty);
}
if (left.Kind == OsPathKind.Windows || right.Kind == OsPathKind.Windows)
{
return new OsPath(String.Join("\\", newFragments), OsPathKind.Unknown);
}
else
{
return new OsPath(String.Join("/", newFragments), OsPathKind.Unknown);
}
}
}
public enum OsPathKind
{
Unknown,
Windows,
Unix
}
}

View File

@ -71,6 +71,7 @@
<Compile Include="ConvertBase32.cs" />
<Compile Include="Crypto\HashProvider.cs" />
<Compile Include="DictionaryExtensions.cs" />
<Compile Include="Disk\OsPath.cs" />
<Compile Include="Disk\DiskProviderBase.cs" />
<Compile Include="Disk\IDiskProvider.cs" />
<Compile Include="Disk\TransferMode.cs" />

View File

@ -31,7 +31,7 @@ public void Setup()
_completed = Builder<DownloadClientItem>.CreateListOfSize(1)
.All()
.With(h => h.Status = DownloadItemStatus.Completed)
.With(h => h.OutputPath = @"C:\DropFolder\MyDownload".AsOsAgnostic())
.With(h => h.OutputPath = new OsPath(@"C:\DropFolder\MyDownload".AsOsAgnostic()))
.With(h => h.Title = "Drone.S01E01.HDTV")
.Build()
.ToList();
@ -325,7 +325,7 @@ public void should_process_as_already_imported_if_drone_factory_import_history_e
_completed.AddRange(Builder<DownloadClientItem>.CreateListOfSize(2)
.All()
.With(h => h.Status = DownloadItemStatus.Completed)
.With(h => h.OutputPath = @"C:\DropFolder\MyDownload".AsOsAgnostic())
.With(h => h.OutputPath = new OsPath(@"C:\DropFolder\MyDownload".AsOsAgnostic()))
.With(h => h.Title = "Drone.S01E01.HDTV")
.Build());

View File

@ -39,8 +39,8 @@ public void SetupBase()
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new Byte[0]));
Mocker.GetMock<IRemotePathMappingService>()
.Setup(v => v.RemapRemoteToLocal(It.IsAny<String>(), It.IsAny<String>()))
.Returns<String, String>((h,r) => r);
.Setup(v => v.RemapRemoteToLocal(It.IsAny<String>(), It.IsAny<OsPath>()))
.Returns<String, OsPath>((h, r) => r);
}
protected virtual RemoteEpisode CreateRemoteEpisode()

View File

@ -14,6 +14,7 @@
using NzbDrone.Test.Common;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Common.Disk;
namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
{
@ -300,8 +301,8 @@ public void should_return_status_with_outputdir()
public void should_return_status_with_mounted_outputdir()
{
Mocker.GetMock<IRemotePathMappingService>()
.Setup(v => v.RemapRemoteToLocal("127.0.0.1", "/remote/mount/tv"))
.Returns(@"O:\mymount".AsOsAgnostic());
.Setup(v => v.RemapRemoteToLocal("127.0.0.1", It.IsAny<OsPath>()))
.Returns(new OsPath(@"O:\mymount".AsOsAgnostic()));
var result = Subject.GetStatus();
@ -314,8 +315,8 @@ public void should_return_status_with_mounted_outputdir()
public void should_remap_storage_if_mounted()
{
Mocker.GetMock<IRemotePathMappingService>()
.Setup(v => v.RemapRemoteToLocal("127.0.0.1", "/remote/mount/tv/Droned.S01E01.Pilot.1080p.WEB-DL-DRONE"))
.Returns(@"O:\mymount\Droned.S01E01.Pilot.1080p.WEB-DL-DRONE".AsOsAgnostic());
.Setup(v => v.RemapRemoteToLocal("127.0.0.1", It.IsAny<OsPath>()))
.Returns(new OsPath(@"O:\mymount\Droned.S01E01.Pilot.1080p.WEB-DL-DRONE".AsOsAgnostic()));
GivenQueue(null);
GivenHistory(_completed);

View File

@ -11,6 +11,7 @@
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Common.Disk;
namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
{
@ -303,15 +304,15 @@ public void should_return_path_to_jobfolder(String title, String storage)
var result = Subject.GetItems().Single();
result.OutputPath.Should().Be((@"C:\sorted\" + title).AsOsAgnostic());
result.OutputPath.Should().Be(new OsPath((@"C:\sorted\" + title).AsOsAgnostic()).AsDirectory());
}
[Test]
public void should_remap_storage_if_mounted()
{
Mocker.GetMock<IRemotePathMappingService>()
.Setup(v => v.RemapRemoteToLocal("127.0.0.1", "/remote/mount/vv/Droned.S01E01.Pilot.1080p.WEB-DL-DRONE"))
.Returns(@"O:\mymount\Droned.S01E01.Pilot.1080p.WEB-DL-DRONE".AsOsAgnostic());
.Setup(v => v.RemapRemoteToLocal("127.0.0.1", It.IsAny<OsPath>()))
.Returns(new OsPath(@"O:\mymount\Droned.S01E01.Pilot.1080p.WEB-DL-DRONE".AsOsAgnostic()));
GivenQueue(null);
GivenHistory(_completed);
@ -370,8 +371,8 @@ public void should_return_status_with_outputdir(String rootFolder, String comple
public void should_return_status_with_mounted_outputdir()
{
Mocker.GetMock<IRemotePathMappingService>()
.Setup(v => v.RemapRemoteToLocal("127.0.0.1", "/remote/mount/vv"))
.Returns(@"O:\mymount".AsOsAgnostic());
.Setup(v => v.RemapRemoteToLocal("127.0.0.1", It.IsAny<OsPath>()))
.Returns(new OsPath(@"O:\mymount".AsOsAgnostic()));
GivenQueue(null);

View File

@ -39,7 +39,7 @@ private void GivenCompletedDownloadHandling(bool? enabled = null)
.With(v => v.State == TrackedDownloadState.Downloading)
.With(v => v.DownloadItem = new DownloadClientItem())
.With(v => v.DownloadItem.Status = DownloadItemStatus.Completed)
.With(v => v.DownloadItem.OutputPath = @"C:\Test\DropFolder\myfile.mkv".AsOsAgnostic())
.With(v => v.DownloadItem.OutputPath = new OsPath(@"C:\Test\DropFolder\myfile.mkv".AsOsAgnostic()))
.Build();
Mocker.GetMock<IDownloadTrackingService>()
@ -78,7 +78,7 @@ public void should_return_warning_when_downloadclient_drops_in_dronefactory_fold
GivenCompletedDownloadHandling(true);
GivenDroneFactoryFolder(true);
_completed.First().DownloadItem.OutputPath = (DRONE_FACTORY_FOLDER + @"\myfile.mkv").AsOsAgnostic();
_completed.First().DownloadItem.OutputPath = new OsPath((DRONE_FACTORY_FOLDER + @"\myfile.mkv").AsOsAgnostic());
Subject.Check().ShouldBeWarning();
}

View File

@ -97,13 +97,13 @@ public void should_remap_remote_to_local(String host, String remotePath, String
GivenMapping();
var result = Subject.RemapRemoteToLocal(host, remotePath);
var result = Subject.RemapRemoteToLocal(host, new OsPath(remotePath));
result.Should().Be(expectedLocalPath);
}
[TestCase("my-server.localdomain", "/mnt/storage/downloads/tv", @"D:\mountedstorage\downloads\tv")]
[TestCase("my-server.localdomain", "/mnt/storage", @"D:\mountedstorage")]
[TestCase("my-server.localdomain", "/mnt/storage/", @"D:\mountedstorage")]
[TestCase("my-2server.localdomain", "/mnt/storage/downloads/tv", "/mnt/storage/downloads/tv")]
[TestCase("my-server.localdomain", "/mnt/storageabc/downloads/tv", "/mnt/storageabc/downloads/tv")]
public void should_remap_local_to_remote(String host, String expectedRemotePath, String localPath)
@ -112,7 +112,7 @@ public void should_remap_local_to_remote(String host, String expectedRemotePath,
GivenMapping();
var result = Subject.RemapLocalToRemote(host, localPath);
var result = Subject.RemapLocalToRemote(host, new OsPath(localPath));
result.Should().Be(expectedRemotePath);
}

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Marr.Data.Converters;
using Marr.Data.Mapping;
using Newtonsoft.Json;
using NzbDrone.Common.Disk;
namespace NzbDrone.Core.Datastore.Converters
{
public class OsPathConverter : IConverter
{
public Object FromDB(ConverterContext context)
{
if (context.DbValue == DBNull.Value)
{
return DBNull.Value;
}
var value = (String)context.DbValue;
return new OsPath(value);
}
public Object FromDB(ColumnMap map, Object dbValue)
{
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
}
public Object ToDB(Object clrValue)
{
var value = (OsPath)clrValue;
return value.FullPath;
}
public Type DbType
{
get { return typeof(String); }
}
}
}

View File

@ -28,6 +28,7 @@
using NzbDrone.Core.Tags;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Tv;
using NzbDrone.Common.Disk;
namespace NzbDrone.Core.Datastore
{
@ -114,6 +115,7 @@ private static void RegisterMappers()
MapRepository.Instance.RegisterTypeConverter(typeof(ParsedEpisodeInfo), new EmbeddedDocumentConverter());
MapRepository.Instance.RegisterTypeConverter(typeof(ReleaseInfo), new EmbeddedDocumentConverter());
MapRepository.Instance.RegisterTypeConverter(typeof(HashSet<Int32>), new EmbeddedDocumentConverter());
MapRepository.Instance.RegisterTypeConverter(typeof(OsPath), new OsPathConverter());
}
private static void RegisterProviderSettingConverter()

View File

@ -115,8 +115,8 @@ public override IEnumerable<DownloadClientItem> GetItems()
item.DownloadClient = Definition.Name;
item.DownloadTime = TimeSpan.FromSeconds(torrent.SecondsDownloading);
var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, torrent.DownloadPath);
item.OutputPath = Path.Combine(outputPath, torrent.Name);
var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.DownloadPath));
item.OutputPath = outputPath + torrent.Name;
item.RemainingSize = torrent.Size - torrent.BytesDownloaded;
item.RemainingTime = TimeSpan.FromSeconds(torrent.Eta);
item.TotalSize = torrent.Size;
@ -172,11 +172,11 @@ public override DownloadClientStatus GetStatus()
{
var config = _proxy.GetConfig(Settings);
var destDir = config.GetValueOrDefault("download_location") as string;
var destDir = new OsPath(config.GetValueOrDefault("download_location") as string);
if (config.GetValueOrDefault("move_completed", false).ToString() == "True")
{
destDir = config.GetValueOrDefault("move_completed_path") as string;
destDir = new OsPath(config.GetValueOrDefault("move_completed_path") as string);
}
var status = new DownloadClientStatus
@ -184,9 +184,9 @@ public override DownloadClientStatus GetStatus()
IsLocalhost = Settings.Host == "127.0.0.1" || Settings.Host == "localhost"
};
if (destDir != null)
if (!destDir.IsEmpty)
{
status.OutputRootFolders = new List<string> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, destDir) };
status.OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, destDir) };
}
return status;

View File

@ -131,7 +131,7 @@ private IEnumerable<DownloadClientItem> GetHistory()
historyItem.DownloadClientId = droneParameter == null ? item.Id.ToString() : droneParameter.Value.ToString();
historyItem.Title = item.Name;
historyItem.TotalSize = MakeInt64(item.FileSizeHi, item.FileSizeLo);
historyItem.OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, item.DestDir);
historyItem.OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(item.DestDir));
historyItem.Category = item.Category;
historyItem.Message = String.Format("PAR Status: {0} - Unpack Status: {1} - Move Status: {2} - Script Status: {3} - Delete Status: {4} - Mark Status: {5}", item.ParStatus, item.UnpackStatus, item.MoveStatus, item.ScriptStatus, item.DeleteStatus, item.MarkStatus);
historyItem.Status = DownloadItemStatus.Completed;
@ -215,7 +215,7 @@ public override DownloadClientStatus GetStatus()
if (category != null)
{
status.OutputRootFolders = new List<String> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, category.DestDir) };
status.OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(category.DestDir)) };
}
return status;
@ -321,10 +321,10 @@ private void MigrateLocalCategoryPath()
if (category != null)
{
var localPath = Settings.TvCategoryLocalPath;
var localPath = new OsPath(Settings.TvCategoryLocalPath);
Settings.TvCategoryLocalPath = null;
_remotePathMappingService.MigrateLocalCategoryPath(Definition.Id, Settings, Settings.Host, category.DestDir, localPath);
_remotePathMappingService.MigrateLocalCategoryPath(Definition.Id, Settings, Settings.Host, new OsPath(category.DestDir), localPath);
_logger.Info("Discovered Local Category Path for {0}, the setting was automatically moved to the Remote Path Mapping table.", Definition.Name);
}

View File

@ -89,7 +89,7 @@ public override IEnumerable<DownloadClientItem> GetItems()
TotalSize = _diskProvider.GetFileSize(file),
OutputPath = file
OutputPath = new OsPath(file)
};
if (_diskProvider.IsFileLocked(file))

View File

@ -156,20 +156,20 @@ private IEnumerable<DownloadClientItem> GetHistory()
historyItem.Status = DownloadItemStatus.Downloading;
}
var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, sabHistoryItem.Storage);
var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(sabHistoryItem.Storage));
if (!outputPath.IsNullOrWhiteSpace())
if (!outputPath.IsEmpty)
{
historyItem.OutputPath = outputPath;
var parent = outputPath.GetParentPath();
while (parent != null)
var parent = outputPath.Directory;
while (!parent.IsEmpty)
{
if (Path.GetFileName(parent) == sabHistoryItem.Title)
if (parent.FileName == sabHistoryItem.Title)
{
historyItem.OutputPath = parent;
}
parent = parent.GetParentPath();
parent = parent.Directory;
}
}
@ -259,52 +259,21 @@ public override String RetryDownload(String id)
protected IEnumerable<SabnzbdCategory> GetCategories(SabnzbdConfig config)
{
var completeDir = config.Misc.complete_dir.TrimEnd('\\', '/');
var completeDir = new OsPath(config.Misc.complete_dir);
if (!completeDir.StartsWith("/") && !completeDir.StartsWith("\\") && !completeDir.Contains(':'))
if (!completeDir.IsRooted)
{
var queue = _proxy.GetQueue(0, 1, Settings);
var defaultRootFolder = new OsPath(queue.DefaultRootFolder);
if (queue.DefaultRootFolder.StartsWith("/"))
{
completeDir = queue.DefaultRootFolder + "/" + completeDir;
}
else
{
completeDir = queue.DefaultRootFolder + "\\" + completeDir;
}
completeDir = defaultRootFolder + completeDir;
}
foreach (var category in config.Categories)
{
var relativeDir = category.Dir.TrimEnd('*');
var relativeDir = new OsPath(category.Dir.TrimEnd('*'));
if (relativeDir.IsNullOrWhiteSpace())
{
category.FullPath = completeDir;
}
else if (completeDir.StartsWith("/"))
{ // Process remote Linux paths irrespective of our own OS.
if (relativeDir.StartsWith("/"))
{
category.FullPath = relativeDir;
}
else
{
category.FullPath = completeDir + "/" + relativeDir;
}
}
else
{ // Process remote Windows paths irrespective of our own OS.
if (relativeDir.StartsWith("\\") || relativeDir.Contains(':'))
{
category.FullPath = relativeDir;
}
else
{
category.FullPath = completeDir + "\\" + relativeDir;
}
}
category.FullPath = completeDir + relativeDir;
yield return category;
}
@ -329,7 +298,7 @@ public override DownloadClientStatus GetStatus()
if (category != null)
{
status.OutputRootFolders = new List<String> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, category.FullPath) };
status.OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, category.FullPath) };
}
return status;
@ -454,7 +423,7 @@ private void MigrateLocalCategoryPath()
if (category != null)
{
var localPath = Settings.TvCategoryLocalPath;
var localPath = new OsPath(Settings.TvCategoryLocalPath);
Settings.TvCategoryLocalPath = null;
_remotePathMappingService.MigrateLocalCategoryPath(Definition.Id, Settings, Settings.Host, category.FullPath, localPath);

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NzbDrone.Common.Disk;
namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
@ -30,6 +31,6 @@ public class SabnzbdCategory
public String Script { get; set; }
public String Dir { get; set; }
public String FullPath { get; set; }
public OsPath FullPath { get; set; }
}
}

View File

@ -78,7 +78,7 @@ public override IEnumerable<DownloadClientItem> GetItems()
TotalSize = files.Select(_diskProvider.GetFileSize).Sum(),
OutputPath = folder
OutputPath = new OsPath(folder)
};
if (files.Any(_diskProvider.IsFileLocked))
@ -108,7 +108,7 @@ public override IEnumerable<DownloadClientItem> GetItems()
TotalSize = _diskProvider.GetFileSize(videoFile),
OutputPath = videoFile
OutputPath = new OsPath(videoFile)
};
if (_diskProvider.IsFileLocked(videoFile))
@ -140,7 +140,7 @@ public override DownloadClientStatus GetStatus()
return new DownloadClientStatus
{
IsLocalhost = true,
OutputRootFolders = new List<string> { Settings.WatchFolder }
OutputRootFolders = new List<OsPath> { new OsPath(Settings.WatchFolder) }
};
}

View File

@ -94,19 +94,11 @@ public override IEnumerable<DownloadClientItem> GetItems()
foreach (var torrent in torrents)
{
var outputPath = torrent.DownloadDir;
// Transmission always returns path with forward slashes, even on windows.
if (outputPath.IsNotNullOrWhiteSpace() && (outputPath.StartsWith(@"\\") || outputPath.Contains(':')))
{
outputPath = outputPath.Replace('/', '\\');
}
outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, outputPath);
var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.DownloadDir));
if (Settings.TvCategory.IsNotNullOrWhiteSpace())
{
var directories = outputPath.Split('\\', '/');
var directories = outputPath.FullPath.Split('\\', '/');
if (!directories.Contains(String.Format(".{0}", Settings.TvCategory))) continue;
}
@ -119,7 +111,7 @@ public override IEnumerable<DownloadClientItem> GetItems()
item.DownloadTime = TimeSpan.FromSeconds(torrent.SecondsDownloading);
item.Message = torrent.ErrorString;
item.OutputPath = Path.Combine(outputPath, torrent.Name);
item.OutputPath = outputPath + torrent.Name;
item.RemainingSize = torrent.LeftUntilDone;
item.RemainingTime = TimeSpan.FromSeconds(torrent.Eta);
item.TotalSize = torrent.TotalSize;
@ -173,16 +165,10 @@ public override DownloadClientStatus GetStatus()
destDir = String.Format("{0}/.{1}", destDir, Settings.TvCategory);
}
// Transmission always returns path with forward slashes, even on windows.
if (destDir.StartsWith(@"\\") || destDir.Contains(':'))
{
destDir = destDir.Replace('/', '\\');
}
return new DownloadClientStatus
{
IsLocalhost = Settings.Host == "127.0.0.1" || Settings.Host == "localhost",
OutputRootFolders = new List<string> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, destDir) }
OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(destDir)) }
};
}

View File

@ -75,7 +75,7 @@ public override IEnumerable<DownloadClientItem> GetItems()
TotalSize = files.Select(_diskProvider.GetFileSize).Sum(),
OutputPath = folder
OutputPath = new OsPath(folder)
};
if (files.Any(_diskProvider.IsFileLocked))
@ -105,7 +105,7 @@ public override IEnumerable<DownloadClientItem> GetItems()
TotalSize = _diskProvider.GetFileSize(videoFile),
OutputPath = videoFile
OutputPath = new OsPath(videoFile)
};
if (_diskProvider.IsFileLocked(videoFile))
@ -137,7 +137,7 @@ public override DownloadClientStatus GetStatus()
return new DownloadClientStatus
{
IsLocalhost = true,
OutputRootFolders = new List<string> { Settings.WatchFolder }
OutputRootFolders = new List<OsPath> { new OsPath(Settings.WatchFolder) }
};
}

View File

@ -102,19 +102,15 @@ public override IEnumerable<DownloadClientItem> GetItems()
item.RemainingTime = TimeSpan.FromSeconds(torrent.Eta);
}
var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, torrent.RootDownloadPath);
var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.RootDownloadPath));
if (outputPath == null || Path.GetFileName(outputPath) == torrent.Name)
if (outputPath == null || outputPath.FileName == torrent.Name)
{
item.OutputPath = outputPath;
}
else if (OsInfo.IsWindows && outputPath.EndsWith(":"))
{
item.OutputPath = Path.Combine(outputPath + Path.DirectorySeparatorChar, torrent.Name);
}
else
{
item.OutputPath = Path.Combine(outputPath, torrent.Name);
item.OutputPath = outputPath + torrent.Name;
}
if (torrent.Status.HasFlag(UTorrentTorrentStatus.Error))
@ -162,20 +158,20 @@ public override DownloadClientStatus GetStatus()
{
var config = _proxy.GetConfig(Settings);
String destDir = null;
OsPath destDir = new OsPath(null);
if (config.GetValueOrDefault("dir_active_download_flag") == "true")
{
destDir = config.GetValueOrDefault("dir_active_download");
destDir = new OsPath(config.GetValueOrDefault("dir_active_download"));
}
if (config.GetValueOrDefault("dir_completed_download_flag") == "true")
{
destDir = config.GetValueOrDefault("dir_completed_download");
destDir = new OsPath(config.GetValueOrDefault("dir_completed_download"));
if (config.GetValueOrDefault("dir_add_label") == "true")
{
destDir = Path.Combine(destDir, Settings.TvCategory);
destDir = destDir + Settings.TvCategory;
}
}
@ -184,9 +180,9 @@ public override DownloadClientStatus GetStatus()
IsLocalhost = Settings.Host == "127.0.0.1" || Settings.Host == "localhost"
};
if (destDir != null)
if (!destDir.IsEmpty)
{
status.OutputRootFolders = new List<String> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, destDir) };
status.OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, destDir) };
}
return status;

View File

@ -79,16 +79,16 @@ public void CheckForCompletedItem(IDownloadClient downloadClient, TrackedDownloa
else
{
var downloadedEpisodesFolder = _configService.DownloadedEpisodesFolder;
var downloadedEpisodesFolder = new OsPath(_configService.DownloadedEpisodesFolder);
var downloadItemOutputPath = trackedDownload.DownloadItem.OutputPath;
if (downloadItemOutputPath.IsNullOrWhiteSpace())
if (downloadItemOutputPath.IsEmpty)
{
UpdateStatusMessage(trackedDownload, LogLevel.Warn, "Download doesn't contain intermediate path, ignoring download.");
return;
}
if (!downloadedEpisodesFolder.IsNullOrWhiteSpace() && (downloadedEpisodesFolder.PathEquals(downloadItemOutputPath) || downloadedEpisodesFolder.IsParentPath(downloadItemOutputPath)))
if (!downloadedEpisodesFolder.IsEmpty && downloadedEpisodesFolder.Contains(downloadItemOutputPath))
{
UpdateStatusMessage(trackedDownload, LogLevel.Warn, "Intermediate Download path inside drone factory, ignoring download.");
return;
@ -113,7 +113,7 @@ public void CheckForCompletedItem(IDownloadClient downloadClient, TrackedDownloa
public List<ImportResult> Import(TrackedDownload trackedDownload, String overrideOutputPath = null)
{
var importResults = new List<ImportResult>();
var outputPath = overrideOutputPath ?? trackedDownload.DownloadItem.OutputPath;
var outputPath = overrideOutputPath ?? trackedDownload.DownloadItem.OutputPath.FullPath;
if (_diskProvider.FolderExists(outputPath))
{
@ -216,16 +216,16 @@ private void RemoveCompleted(TrackedDownload trackedDownload, IDownloadClient do
_logger.Debug("[{0}] Removing completed download from history.", trackedDownload.DownloadItem.Title);
downloadClient.RemoveItem(trackedDownload.DownloadItem.DownloadClientId);
if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath))
if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath.FullPath))
{
_logger.Debug("Removing completed download directory: {0}",
trackedDownload.DownloadItem.OutputPath);
_diskProvider.DeleteFolder(trackedDownload.DownloadItem.OutputPath, true);
_diskProvider.DeleteFolder(trackedDownload.DownloadItem.OutputPath.FullPath, true);
}
else if (_diskProvider.FileExists(trackedDownload.DownloadItem.OutputPath))
else if (_diskProvider.FileExists(trackedDownload.DownloadItem.OutputPath.FullPath))
{
_logger.Debug("Removing completed download file: {0}", trackedDownload.DownloadItem.OutputPath);
_diskProvider.DeleteFile(trackedDownload.DownloadItem.OutputPath);
_diskProvider.DeleteFile(trackedDownload.DownloadItem.OutputPath.FullPath);
}
trackedDownload.State = TrackedDownloadState.Removed;

View File

@ -1,4 +1,6 @@
using System;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download
{
@ -14,7 +16,7 @@ public class DownloadClientItem
public TimeSpan? DownloadTime { get; set; }
public TimeSpan? RemainingTime { get; set; }
public String OutputPath { get; set; }
public OsPath OutputPath { get; set; }
public String Message { get; set; }
public DownloadItemStatus Status { get; set; }

View File

@ -2,12 +2,13 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NzbDrone.Common.Disk;
namespace NzbDrone.Core.Download
{
public class DownloadClientStatus
{
public Boolean IsLocalhost { get; set; }
public List<String> OutputRootFolders { get; set; }
public List<OsPath> OutputRootFolders { get; set; }
}
}

View File

@ -25,12 +25,12 @@ public ImportMechanismCheck(IConfigService configService, IProvideDownloadClient
public override HealthCheck Check()
{
var droneFactoryFolder = _configService.DownloadedEpisodesFolder;
var droneFactoryFolder = new OsPath(_configService.DownloadedEpisodesFolder);
var downloadClients = _provideDownloadClient.GetDownloadClients().Select(v => new { downloadClient = v, status = v.GetStatus() }).ToList();
var downloadClientIsLocalHost = downloadClients.All(v => v.status.IsLocalhost);
var downloadClientOutputInDroneFactory = !droneFactoryFolder.IsNullOrWhiteSpace()
&& downloadClients.Any(v => v.status.OutputRootFolders != null && v.status.OutputRootFolders.Contains(droneFactoryFolder, PathEqualityComparer.Instance));
var downloadClientOutputInDroneFactory = !droneFactoryFolder.IsEmpty
&& downloadClients.Any(v => v.status.OutputRootFolders != null && v.status.OutputRootFolders.Any(droneFactoryFolder.Contains));
if (!_configService.IsDefined("EnableCompletedDownloadHandling"))
{
@ -66,14 +66,14 @@ public override HealthCheck Check()
}
}
if (!_configService.EnableCompletedDownloadHandling && droneFactoryFolder.IsNullOrWhiteSpace())
if (!_configService.EnableCompletedDownloadHandling && droneFactoryFolder.IsEmpty)
{
return new HealthCheck(GetType(), HealthCheckResult.Warning, "Enable Completed Download Handling or configure Drone factory");
}
if (_configService.EnableCompletedDownloadHandling && !droneFactoryFolder.IsNullOrWhiteSpace())
if (_configService.EnableCompletedDownloadHandling && !droneFactoryFolder.IsEmpty)
{
if (_downloadTrackingService.GetCompletedDownloads().Any(v => droneFactoryFolder.PathEquals(v.DownloadItem.OutputPath) || droneFactoryFolder.IsParentPath(v.DownloadItem.OutputPath)))
if (_downloadTrackingService.GetCompletedDownloads().Any(v => droneFactoryFolder.Contains(v.DownloadItem.OutputPath)))
{
return new HealthCheck(GetType(), HealthCheckResult.Warning, "Completed Download Handling conflict with Drone Factory (Conflicting History Item)", "Migrating-to-Completed-Download-Handling#conflicting-download-client-category");
}

View File

@ -148,6 +148,7 @@
<Compile Include="Datastore\Converters\EmbeddedDocumentConverter.cs" />
<Compile Include="Datastore\Converters\EnumIntConverter.cs" />
<Compile Include="Datastore\Converters\Int32Converter.cs" />
<Compile Include="Datastore\Converters\OsPathConverter.cs" />
<Compile Include="Datastore\Converters\ProviderSettingConverter.cs" />
<Compile Include="Datastore\Converters\QualityIntConverter.cs" />
<Compile Include="Datastore\Converters\UtcConverter.cs" />

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Datastore;

View File

@ -22,11 +22,11 @@ public interface IRemotePathMappingService
RemotePathMapping Get(int id);
RemotePathMapping Update(RemotePathMapping mapping);
String RemapRemoteToLocal(String host, String remotePath);
String RemapLocalToRemote(String host, String localPath);
OsPath RemapRemoteToLocal(String host, OsPath remotePath);
OsPath RemapLocalToRemote(String host, OsPath localPath);
// TODO: Remove around January 2015. Used to migrate legacy Local Category Path settings.
void MigrateLocalCategoryPath(Int32 downloadClientId, IProviderConfig newSettings, String host, String remotePath, String localPath);
void MigrateLocalCategoryPath(Int32 downloadClientId, IProviderConfig newSettings, String host, OsPath remotePath, OsPath localPath);
}
public class RemotePathMappingService : IRemotePathMappingService
@ -60,8 +60,8 @@ public List<RemotePathMapping> All()
public RemotePathMapping Add(RemotePathMapping mapping)
{
mapping.LocalPath = CleanPath(mapping.LocalPath);
mapping.RemotePath = CleanPath(mapping.RemotePath);
mapping.LocalPath = new OsPath(mapping.LocalPath).AsDirectory().FullPath;
mapping.RemotePath = new OsPath(mapping.RemotePath).AsDirectory().FullPath;
var all = All();
@ -106,17 +106,20 @@ private void ValidateMapping(List<RemotePathMapping> existing, RemotePathMapping
throw new ArgumentException("Invalid Host");
}
if (mapping.RemotePath.IsNullOrWhiteSpace())
var remotePath = new OsPath(mapping.RemotePath);
var localPath = new OsPath(mapping.LocalPath);
if (remotePath.IsEmpty)
{
throw new ArgumentException("Invalid RemotePath");
}
if (mapping.LocalPath.IsNullOrWhiteSpace() || !Path.IsPathRooted(mapping.LocalPath))
if (localPath.IsEmpty || !localPath.IsRooted)
{
throw new ArgumentException("Invalid LocalPath");
}
if (!_diskProvider.FolderExists(mapping.LocalPath))
if (!_diskProvider.FolderExists(localPath.FullPath))
{
throw new DirectoryNotFoundException("Can't add mount point directory that doesn't exist.");
}
@ -127,27 +130,18 @@ private void ValidateMapping(List<RemotePathMapping> existing, RemotePathMapping
}
}
public String RemapRemoteToLocal(String host, String remotePath)
public OsPath RemapRemoteToLocal(String host, OsPath remotePath)
{
if (remotePath.IsNullOrWhiteSpace())
if (remotePath.IsEmpty)
{
return remotePath;
}
var cleanRemotePath = CleanPath(remotePath);
foreach (var mapping in All())
{
if (host == mapping.Host && cleanRemotePath.StartsWith(mapping.RemotePath))
if (host == mapping.Host && new OsPath(mapping.RemotePath).Contains(remotePath))
{
var localPath = mapping.LocalPath + cleanRemotePath.Substring(mapping.RemotePath.Length);
localPath = localPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
if (!remotePath.EndsWith("/") && !remotePath.EndsWith("\\"))
{
localPath = localPath.TrimEnd('/', '\\');
}
var localPath = new OsPath(mapping.LocalPath) + (remotePath - new OsPath(mapping.RemotePath));
return localPath;
}
@ -156,29 +150,18 @@ public String RemapRemoteToLocal(String host, String remotePath)
return remotePath;
}
public String RemapLocalToRemote(String host, String localPath)
public OsPath RemapLocalToRemote(String host, OsPath localPath)
{
if (localPath.IsNullOrWhiteSpace())
if (localPath.IsEmpty)
{
return localPath;
}
var cleanLocalPath = CleanPath(localPath);
foreach (var mapping in All())
{
if (host != mapping.Host) continue;
if (cleanLocalPath.StartsWith(mapping.LocalPath))
if (host == mapping.Host && new OsPath(mapping.LocalPath).Contains(localPath))
{
var remotePath = mapping.RemotePath + cleanLocalPath.Substring(mapping.LocalPath.Length);
remotePath = remotePath.Replace(Path.DirectorySeparatorChar, mapping.RemotePath.Contains('\\') ? '\\' : '/');
if (!localPath.EndsWith("/") && !localPath.EndsWith("\\"))
{
remotePath = remotePath.TrimEnd('/', '\\');
}
var remotePath = new OsPath(mapping.RemotePath) + (localPath - new OsPath(mapping.LocalPath));
return remotePath;
}
@ -188,35 +171,20 @@ public String RemapLocalToRemote(String host, String localPath)
}
// TODO: Remove around January 2015. Used to migrate legacy Local Category Path settings.
public void MigrateLocalCategoryPath(Int32 downloadClientId, IProviderConfig newSettings, String host, String remotePath, String localPath)
public void MigrateLocalCategoryPath(Int32 downloadClientId, IProviderConfig newSettings, String host, OsPath remotePath, OsPath localPath)
{
_logger.Debug("Migrating local category path for Host {0}/{1} to {2}", host, remotePath, localPath);
var existingMappings = All().Where(v => v.Host == host).ToList();
remotePath = CleanPath(remotePath);
localPath = CleanPath(localPath);
if (!existingMappings.Any(v => v.LocalPath == localPath && v.RemotePath == remotePath))
if (!existingMappings.Any(v => new OsPath(v.LocalPath) == localPath && new OsPath(v.RemotePath) == remotePath))
{
Add(new RemotePathMapping { Host = host, RemotePath = remotePath, LocalPath = localPath });
Add(new RemotePathMapping { Host = host, RemotePath = remotePath.FullPath, LocalPath = localPath.FullPath });
}
var downloadClient = _downloadClientRepository.Get(downloadClientId);
downloadClient.Settings = newSettings;
_downloadClientRepository.Update(downloadClient);
}
private static String CleanPath(String path)
{
if (path.StartsWith(@"\\") || path.Contains(':'))
{
return path.TrimEnd('\\', '/').Replace('/', '\\') + "\\";
}
else
{
return path.TrimEnd('\\', '/').Replace('\\', '/') + "/";
}
}
}
}