New: Better platform detection specifically for Non-Windows Systems

pull/6/head
Keivan Beigi 8 years ago
parent 598b5322b7
commit ad7d571b24

@ -14,7 +14,7 @@ namespace NzbDrone.Api.Frontend
{ {
public bool IsCacheable(NancyContext context) public bool IsCacheable(NancyContext context)
{ {
if (!RuntimeInfoBase.IsProduction) if (!RuntimeInfo.IsProduction)
{ {
return false; return false;
} }

@ -74,7 +74,7 @@ namespace NzbDrone.Api.Frontend.Mappers
private string GetIndexText() private string GetIndexText()
{ {
if (RuntimeInfoBase.IsProduction && _generatedContent != null) if (RuntimeInfo.IsProduction && _generatedContent != null)
{ {
return _generatedContent; return _generatedContent;
} }
@ -106,7 +106,7 @@ namespace NzbDrone.Api.Frontend.Mappers
text = text.Replace("APP_BRANCH", _configFileProvider.Branch.ToLower()); text = text.Replace("APP_BRANCH", _configFileProvider.Branch.ToLower());
text = text.Replace("APP_ANALYTICS", _analyticsService.IsEnabled.ToString().ToLowerInvariant()); text = text.Replace("APP_ANALYTICS", _analyticsService.IsEnabled.ToString().ToLowerInvariant());
text = text.Replace("URL_BASE", URL_BASE); text = text.Replace("URL_BASE", URL_BASE);
text = text.Replace("PRODUCTION", RuntimeInfoBase.IsProduction.ToString().ToLowerInvariant()); text = text.Replace("PRODUCTION", RuntimeInfo.IsProduction.ToString().ToLowerInvariant());
_generatedContent = text; _generatedContent = text;

@ -67,7 +67,7 @@ namespace NzbDrone.Api.Frontend.Mappers
private string GetLoginText() private string GetLoginText()
{ {
if (RuntimeInfoBase.IsProduction && _generatedContent != null) if (RuntimeInfo.IsProduction && _generatedContent != null)
{ {
return _generatedContent; return _generatedContent;
} }

@ -21,7 +21,7 @@ namespace NzbDrone.Api.Frontend.Mappers
_diskProvider = diskProvider; _diskProvider = diskProvider;
_logger = logger; _logger = logger;
if (!RuntimeInfoBase.IsProduction) if (!RuntimeInfo.IsProduction)
{ {
_caseSensitive = StringComparison.OrdinalIgnoreCase; _caseSensitive = StringComparison.OrdinalIgnoreCase;
} }

@ -24,9 +24,9 @@ namespace NzbDrone.Api
protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
{ {
Logger.Info("Starting NzbDrone API"); Logger.Info("Starting Web Server");
if (RuntimeInfoBase.IsProduction) if (RuntimeInfo.IsProduction)
{ {
DiagnosticsHook.Disable(pipelines); DiagnosticsHook.Disable(pipelines);
} }

@ -180,7 +180,7 @@ namespace NzbDrone.Api.Series
foreach (var season in resource.Seasons) foreach (var season in resource.Seasons)
{ {
season.Statistics = SeasonStatisticsResourceMapper.ToResource(dictSeasonStats.GetValueOrDefault(season.SeasonNumber)); season.Statistics = dictSeasonStats.GetValueOrDefault(season.SeasonNumber).ToResource();
} }
} }
} }

@ -13,6 +13,8 @@ namespace NzbDrone.Api.System
{ {
private readonly IAppFolderInfo _appFolderInfo; private readonly IAppFolderInfo _appFolderInfo;
private readonly IRuntimeInfo _runtimeInfo; private readonly IRuntimeInfo _runtimeInfo;
private readonly IPlatformInfo _platformInfo;
private readonly IOsInfo _osInfo;
private readonly IRouteCacheProvider _routeCacheProvider; private readonly IRouteCacheProvider _routeCacheProvider;
private readonly IConfigFileProvider _configFileProvider; private readonly IConfigFileProvider _configFileProvider;
private readonly IMainDatabase _database; private readonly IMainDatabase _database;
@ -20,14 +22,17 @@ namespace NzbDrone.Api.System
public SystemModule(IAppFolderInfo appFolderInfo, public SystemModule(IAppFolderInfo appFolderInfo,
IRuntimeInfo runtimeInfo, IRuntimeInfo runtimeInfo,
IPlatformInfo platformInfo,
IOsInfo osInfo,
IRouteCacheProvider routeCacheProvider, IRouteCacheProvider routeCacheProvider,
IConfigFileProvider configFileProvider, IConfigFileProvider configFileProvider,
IMainDatabase database, IMainDatabase database,
ILifecycleService lifecycleService) ILifecycleService lifecycleService) : base("system")
: base("system")
{ {
_appFolderInfo = appFolderInfo; _appFolderInfo = appFolderInfo;
_runtimeInfo = runtimeInfo; _runtimeInfo = runtimeInfo;
_platformInfo = platformInfo;
_osInfo = osInfo;
_routeCacheProvider = routeCacheProvider; _routeCacheProvider = routeCacheProvider;
_configFileProvider = configFileProvider; _configFileProvider = configFileProvider;
_database = database; _database = database;
@ -41,27 +46,29 @@ namespace NzbDrone.Api.System
private Response GetStatus() private Response GetStatus()
{ {
return new return new
{ {
Version = BuildInfo.Version.ToString(), Version = BuildInfo.Version.ToString(),
BuildTime = BuildInfo.BuildDateTime, BuildTime = BuildInfo.BuildDateTime,
IsDebug = BuildInfo.IsDebug, IsDebug = BuildInfo.IsDebug,
IsProduction = RuntimeInfoBase.IsProduction, IsProduction = RuntimeInfo.IsProduction,
IsAdmin = _runtimeInfo.IsAdmin, IsAdmin = _runtimeInfo.IsAdmin,
IsUserInteractive = RuntimeInfoBase.IsUserInteractive, IsUserInteractive = RuntimeInfo.IsUserInteractive,
StartupPath = _appFolderInfo.StartUpFolder, StartupPath = _appFolderInfo.StartUpFolder,
AppData = _appFolderInfo.GetAppDataPath(), AppData = _appFolderInfo.GetAppDataPath(),
OsVersion = OsInfo.Version.ToString(), OsName = _osInfo.Name,
IsMonoRuntime = OsInfo.IsMonoRuntime, OsVersion = _osInfo.Version,
IsMono = OsInfo.IsNotWindows, IsMonoRuntime = PlatformInfo.IsMono,
IsLinux = OsInfo.IsLinux, IsMono = PlatformInfo.IsMono,
IsOsx = OsInfo.IsOsx, IsLinux = OsInfo.IsLinux,
IsWindows = OsInfo.IsWindows, IsOsx = OsInfo.IsOsx,
Branch = _configFileProvider.Branch, IsWindows = OsInfo.IsWindows,
Authentication = _configFileProvider.AuthenticationMethod, Branch = _configFileProvider.Branch,
SqliteVersion = _database.Version, Authentication = _configFileProvider.AuthenticationMethod,
UrlBase = _configFileProvider.UrlBase, SqliteVersion = _database.Version,
RuntimeVersion = _runtimeInfo.RuntimeVersion UrlBase = _configFileProvider.UrlBase,
}.AsResponse(); RuntimeVersion = _platformInfo.Version,
RuntimeName = PlatformInfo.Platform
}.AsResponse();
} }
private Response GetRoutes() private Response GetRoutes()

@ -29,7 +29,7 @@ namespace NzbDrone.Common.Test
[Test] [Test]
public void IsProduction_should_return_false_when_run_within_nunit() public void IsProduction_should_return_false_when_run_within_nunit()
{ {
RuntimeInfoBase.IsProduction.Should().BeFalse("Process name is " + Process.GetCurrentProcess().ProcessName + " Folder is " + Directory.GetCurrentDirectory()); RuntimeInfo.IsProduction.Should().BeFalse("Process name is " + Process.GetCurrentProcess().ProcessName + " Folder is " + Directory.GetCurrentDirectory());
} }
[Test] [Test]

@ -9,6 +9,7 @@ using Moq;
using NLog; using NLog;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.Cache; using NzbDrone.Common.Cache;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Http.Dispatchers; using NzbDrone.Common.Http.Dispatchers;
using NzbDrone.Common.Http.Proxy; using NzbDrone.Common.Http.Proxy;
@ -30,6 +31,12 @@ namespace NzbDrone.Common.Test.Http
[SetUp] [SetUp]
public void SetUp() public void SetUp()
{ {
Mocker.GetMock<IPlatformInfo>().Setup(c => c.Version).Returns(new Version("1.0.0"));
Mocker.GetMock<IOsInfo>().Setup(c => c.Name).Returns("TestOS");
Mocker.GetMock<IOsInfo>().Setup(c => c.Version).Returns("9.0.0");
Mocker.SetConstant<IUserAgentBuilder>(Mocker.Resolve<UserAgentBuilder>());
Mocker.SetConstant<ICacheManager>(Mocker.Resolve<CacheManager>()); Mocker.SetConstant<ICacheManager>(Mocker.Resolve<CacheManager>());
Mocker.SetConstant<ICreateManagedWebProxy>(Mocker.Resolve<ManagedWebProxyFactory>()); Mocker.SetConstant<ICreateManagedWebProxy>(Mocker.Resolve<ManagedWebProxyFactory>());
Mocker.SetConstant<IRateLimitService>(Mocker.Resolve<RateLimitService>()); Mocker.SetConstant<IRateLimitService>(Mocker.Resolve<RateLimitService>());
@ -48,7 +55,7 @@ namespace NzbDrone.Common.Test.Http
[Test] [Test]
public void should_execute_simple_get() public void should_execute_simple_get()
{ {
var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/get");
var response = Subject.Execute(request); var response = Subject.Execute(request);
@ -58,7 +65,7 @@ namespace NzbDrone.Common.Test.Http
[Test] [Test]
public void should_execute_https_get() public void should_execute_https_get()
{ {
var request = new HttpRequest(string.Format("https://{0}/get", _httpBinHost)); var request = new HttpRequest($"https://{_httpBinHost}/get");
var response = Subject.Execute(request); var response = Subject.Execute(request);
@ -68,7 +75,7 @@ namespace NzbDrone.Common.Test.Http
[Test] [Test]
public void should_execute_typed_get() public void should_execute_typed_get()
{ {
var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/get");
var response = Subject.Get<HttpBinResource>(request); var response = Subject.Get<HttpBinResource>(request);
@ -80,7 +87,7 @@ namespace NzbDrone.Common.Test.Http
{ {
var message = "{ my: 1 }"; var message = "{ my: 1 }";
var request = new HttpRequest(string.Format("http://{0}/post", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/post");
request.SetContent(message); request.SetContent(message);
var response = Subject.Post<HttpBinResource>(request); var response = Subject.Post<HttpBinResource>(request);
@ -91,7 +98,7 @@ namespace NzbDrone.Common.Test.Http
[TestCase("gzip")] [TestCase("gzip")]
public void should_execute_get_using_gzip(string compression) public void should_execute_get_using_gzip(string compression)
{ {
var request = new HttpRequest(string.Format("http://{0}/{1}", _httpBinHost, compression)); var request = new HttpRequest($"http://{_httpBinHost}/{compression}");
var response = Subject.Get<HttpBinResource>(request); var response = Subject.Get<HttpBinResource>(request);
@ -107,7 +114,7 @@ namespace NzbDrone.Common.Test.Http
[TestCase(HttpStatusCode.BadGateway)] [TestCase(HttpStatusCode.BadGateway)]
public void should_throw_on_unsuccessful_status_codes(int statusCode) public void should_throw_on_unsuccessful_status_codes(int statusCode)
{ {
var request = new HttpRequest(string.Format("http://{0}/status/{1}", _httpBinHost, statusCode)); var request = new HttpRequest($"http://{_httpBinHost}/status/{statusCode}");
var exception = Assert.Throws<HttpException>(() => Subject.Get<HttpBinResource>(request)); var exception = Assert.Throws<HttpException>(() => Subject.Get<HttpBinResource>(request));
@ -119,7 +126,7 @@ namespace NzbDrone.Common.Test.Http
[Test] [Test]
public void should_not_follow_redirects_when_not_in_production() public void should_not_follow_redirects_when_not_in_production()
{ {
var request = new HttpRequest(string.Format("http://{0}/redirect/1", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/redirect/1");
Subject.Get(request); Subject.Get(request);
@ -129,7 +136,7 @@ namespace NzbDrone.Common.Test.Http
[Test] [Test]
public void should_follow_redirects() public void should_follow_redirects()
{ {
var request = new HttpRequest(string.Format("http://{0}/redirect/1", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/redirect/1");
request.AllowAutoRedirect = true; request.AllowAutoRedirect = true;
Subject.Get(request); Subject.Get(request);
@ -140,7 +147,7 @@ namespace NzbDrone.Common.Test.Http
[Test] [Test]
public void should_send_user_agent() public void should_send_user_agent()
{ {
var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/get");
var response = Subject.Get<HttpBinResource>(request); var response = Subject.Get<HttpBinResource>(request);
@ -154,7 +161,7 @@ namespace NzbDrone.Common.Test.Http
[TestCase("Accept", "text/xml, text/rss+xml, application/rss+xml")] [TestCase("Accept", "text/xml, text/rss+xml, application/rss+xml")]
public void should_send_headers(string header, string value) public void should_send_headers(string header, string value)
{ {
var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/get");
request.Headers.Add(header, value); request.Headers.Add(header, value);
var response = Subject.Get<HttpBinResource>(request); var response = Subject.Get<HttpBinResource>(request);
@ -177,7 +184,7 @@ namespace NzbDrone.Common.Test.Http
[Test] [Test]
public void should_send_cookie() public void should_send_cookie()
{ {
var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/get");
request.Cookies["my"] = "cookie"; request.Cookies["my"] = "cookie";
var response = Subject.Get<HttpBinResource>(request); var response = Subject.Get<HttpBinResource>(request);
@ -194,7 +201,7 @@ namespace NzbDrone.Common.Test.Http
var oldRequest = new HttpRequest("http://eu.httpbin.org/get"); var oldRequest = new HttpRequest("http://eu.httpbin.org/get");
oldRequest.Cookies["my"] = "cookie"; oldRequest.Cookies["my"] = "cookie";
var oldClient = new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve<ICacheManager>(), Mocker.Resolve<IRateLimitService>(), Mocker.Resolve<IHttpDispatcher>(), Mocker.Resolve<Logger>()); var oldClient = new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve<ICacheManager>(), Mocker.Resolve<IRateLimitService>(), Mocker.Resolve<IHttpDispatcher>(), Mocker.GetMock<IUserAgentBuilder>().Object, Mocker.Resolve<Logger>());
oldClient.Should().NotBeSameAs(Subject); oldClient.Should().NotBeSameAs(Subject);
@ -234,12 +241,12 @@ namespace NzbDrone.Common.Test.Http
[Test] [Test]
public void should_not_store_response_cookie() public void should_not_store_response_cookie()
{ {
var requestSet = new HttpRequest(string.Format("http://{0}/cookies/set?my=cookie", _httpBinHost)); var requestSet = new HttpRequest($"http://{_httpBinHost}/cookies/set?my=cookie");
requestSet.AllowAutoRedirect = false; requestSet.AllowAutoRedirect = false;
var responseSet = Subject.Get(requestSet); var responseSet = Subject.Get(requestSet);
var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/get");
var response = Subject.Get<HttpBinResource>(request); var response = Subject.Get<HttpBinResource>(request);
@ -251,13 +258,13 @@ namespace NzbDrone.Common.Test.Http
[Test] [Test]
public void should_store_response_cookie() public void should_store_response_cookie()
{ {
var requestSet = new HttpRequest(string.Format("http://{0}/cookies/set?my=cookie", _httpBinHost)); var requestSet = new HttpRequest($"http://{_httpBinHost}/cookies/set?my=cookie");
requestSet.AllowAutoRedirect = false; requestSet.AllowAutoRedirect = false;
requestSet.StoreResponseCookie = true; requestSet.StoreResponseCookie = true;
var responseSet = Subject.Get(requestSet); var responseSet = Subject.Get(requestSet);
var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/get");
var response = Subject.Get<HttpBinResource>(request); var response = Subject.Get<HttpBinResource>(request);
@ -273,14 +280,14 @@ namespace NzbDrone.Common.Test.Http
[Test] [Test]
public void should_overwrite_response_cookie() public void should_overwrite_response_cookie()
{ {
var requestSet = new HttpRequest(string.Format("http://{0}/cookies/set?my=cookie", _httpBinHost)); var requestSet = new HttpRequest($"http://{_httpBinHost}/cookies/set?my=cookie");
requestSet.AllowAutoRedirect = false; requestSet.AllowAutoRedirect = false;
requestSet.StoreResponseCookie = true; requestSet.StoreResponseCookie = true;
requestSet.Cookies["my"] = "oldcookie"; requestSet.Cookies["my"] = "oldcookie";
var responseSet = Subject.Get(requestSet); var responseSet = Subject.Get(requestSet);
var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/get");
var response = Subject.Get<HttpBinResource>(request); var response = Subject.Get<HttpBinResource>(request);
@ -296,7 +303,7 @@ namespace NzbDrone.Common.Test.Http
[Test] [Test]
public void should_throw_on_http429_too_many_requests() public void should_throw_on_http429_too_many_requests()
{ {
var request = new HttpRequest(string.Format("http://{0}/status/429", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/status/429");
Assert.Throws<TooManyRequestsException>(() => Subject.Get(request)); Assert.Throws<TooManyRequestsException>(() => Subject.Get(request));
@ -316,7 +323,7 @@ namespace NzbDrone.Common.Test.Http
.Setup(v => v.PostResponse(It.IsAny<HttpResponse>())) .Setup(v => v.PostResponse(It.IsAny<HttpResponse>()))
.Returns<HttpResponse>(r => r); .Returns<HttpResponse>(r => r);
var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/get");
Subject.Get(request); Subject.Get(request);
@ -338,7 +345,7 @@ namespace NzbDrone.Common.Test.Http
{ {
// the date is bad in the below - should be 13-Jul-2026 // the date is bad in the below - should be 13-Jul-2026
string malformedCookie = @"__cfduid=d29e686a9d65800021c66faca0a29b4261436890790; expires=Mon, 13-Jul-26 16:19:50 GMT; path=/; HttpOnly"; string malformedCookie = @"__cfduid=d29e686a9d65800021c66faca0a29b4261436890790; expires=Mon, 13-Jul-26 16:19:50 GMT; path=/; HttpOnly";
var requestSet = new HttpRequestBuilder(string.Format("http://{0}/response-headers", _httpBinHost)) var requestSet = new HttpRequestBuilder($"http://{_httpBinHost}/response-headers")
.AddQueryParam("Set-Cookie", malformedCookie) .AddQueryParam("Set-Cookie", malformedCookie)
.Build(); .Build();
@ -347,7 +354,7 @@ namespace NzbDrone.Common.Test.Http
var responseSet = Subject.Get(requestSet); var responseSet = Subject.Get(requestSet);
var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/get");
var response = Subject.Get<HttpBinResource>(request); var response = Subject.Get<HttpBinResource>(request);
@ -371,7 +378,7 @@ namespace NzbDrone.Common.Test.Http
{ {
try try
{ {
string url = string.Format("http://{0}/response-headers?Set-Cookie={1}", _httpBinHost, Uri.EscapeUriString(malformedCookie)); string url = $"http://{_httpBinHost}/response-headers?Set-Cookie={Uri.EscapeUriString(malformedCookie)}";
var requestSet = new HttpRequest(url); var requestSet = new HttpRequest(url);
requestSet.AllowAutoRedirect = false; requestSet.AllowAutoRedirect = false;
@ -379,7 +386,7 @@ namespace NzbDrone.Common.Test.Http
var responseSet = Subject.Get(requestSet); var responseSet = Subject.Get(requestSet);
var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost)); var request = new HttpRequest($"http://{_httpBinHost}/get");
var response = Subject.Get<HttpBinResource>(request); var response = Subject.Get<HttpBinResource>(request);

@ -20,8 +20,8 @@ namespace NzbDrone.Common.Cloud
.CreateFactory(); .CreateFactory();
} }
public IHttpRequestBuilderFactory Services { get; private set; } public IHttpRequestBuilderFactory Services { get; }
public IHttpRequestBuilderFactory SkyHookTvdb { get; private set; } public IHttpRequestBuilderFactory SkyHookTvdb { get; }
} }
} }

@ -16,6 +16,19 @@ namespace NzbDrone.Common.Disk
{ {
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(DiskProviderBase)); private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(DiskProviderBase));
public static StringComparison PathStringComparison
{
get
{
if (OsInfo.IsWindows)
{
return StringComparison.OrdinalIgnoreCase;
}
return StringComparison.Ordinal;
}
}
public abstract long? GetAvailableSpace(string path); public abstract long? GetAvailableSpace(string path);
public abstract void InheritFolderPermissions(string filename); public abstract void InheritFolderPermissions(string filename);
public abstract void SetPermissions(string path, string mask, string user, string group); public abstract void SetPermissions(string path, string mask, string user, string group);
@ -86,7 +99,7 @@ namespace NzbDrone.Common.Disk
public bool FileExists(string path) public bool FileExists(string path)
{ {
Ensure.That(path, () => path).IsValidPath(); Ensure.That(path, () => path).IsValidPath();
return FileExists(path, OsInfo.PathStringComparison); return FileExists(path, PathStringComparison);
} }
public bool FileExists(string path, StringComparison stringComparison) public bool FileExists(string path, StringComparison stringComparison)

@ -101,12 +101,12 @@ namespace NzbDrone.Common.EnsureThat
if (param.Value.IsPathValid()) return param; if (param.Value.IsPathValid()) return param;
if (OsInfo.IsNotWindows) if (OsInfo.IsWindows)
{ {
throw ExceptionFactory.CreateForParamValidation(param.Name, string.Format("value [{0}] is not a valid *nix path. paths must start with /", param.Value)); throw ExceptionFactory.CreateForParamValidation(param.Name, string.Format("value [{0}] is not a valid Windows path. paths must be a full path eg. C:\\Windows", param.Value));
} }
throw ExceptionFactory.CreateForParamValidation(param.Name, string.Format("value [{0}] is not a valid Windows path. paths must be a full path eg. C:\\Windows", param.Value)); throw ExceptionFactory.CreateForParamValidation(param.Name, string.Format("value [{0}] is not a valid *nix path. paths must start with /", param.Value));
} }
} }
} }

@ -41,10 +41,10 @@ namespace NzbDrone.Common.EnvironmentInfo
TempFolder = Path.GetTempPath(); TempFolder = Path.GetTempPath();
} }
public string AppDataFolder { get; private set; } public string AppDataFolder { get; }
public string StartUpFolder { get; private set; } public string StartUpFolder { get; }
public string TempFolder { get; private set; } public string TempFolder { get; }
} }
} }

@ -0,0 +1,9 @@
namespace NzbDrone.Common.EnvironmentInfo
{
public interface IOperatingSystemVersionInfo
{
string Version { get; }
string Name { get; }
string FullName { get; }
}
}

@ -0,0 +1,9 @@
namespace NzbDrone.Common.EnvironmentInfo
{
public interface IOsVersionAdapter
{
bool Enabled { get; }
OsVersionModel Read();
}
}

@ -0,0 +1,37 @@
using System;
namespace NzbDrone.Common.EnvironmentInfo
{
public enum PlatformType
{
DotNet = 0,
Mono = 1
}
public interface IPlatformInfo
{
Version Version { get; }
}
public abstract class PlatformInfo : IPlatformInfo
{
static PlatformInfo()
{
if (Type.GetType("Mono.Runtime") != null)
{
Platform = PlatformType.Mono;
}
else
{
Platform = PlatformType.DotNet;
}
}
public static PlatformType Platform { get; }
public static bool IsMono => Platform == PlatformType.Mono;
public static bool IsDotNet => Platform == PlatformType.DotNet;
public abstract Version Version { get; }
}
}

@ -1,14 +1,14 @@
namespace NzbDrone.Common.EnvironmentInfo using System;
namespace NzbDrone.Common.EnvironmentInfo
{ {
public interface IRuntimeInfo public interface IRuntimeInfo
{ {
bool IsUserInteractive { get; } bool IsUserInteractive { get; }
bool IsAdmin { get; } bool IsAdmin { get; }
bool IsWindowsService { get; } bool IsWindowsService { get; }
bool IsConsole { get; } bool IsExiting { get; set; }
bool IsRunning { get; set; }
bool RestartPending { get; set; } bool RestartPending { get; set; }
string ExecutingApplication { get; } string ExecutingApplication { get; }
string RuntimeVersion { get; }
} }
} }

@ -1,89 +1,97 @@
using System; using System;
using System.Diagnostics; using System.Collections.Generic;
using System.Globalization; using System.IO;
using System.Runtime.InteropServices; using System.Linq;
using NLog;
namespace NzbDrone.Common.EnvironmentInfo namespace NzbDrone.Common.EnvironmentInfo
{ {
public static class OsInfo public class OsInfo : IOsInfo
{ {
public static Os Os { get; }
static OsInfo() public static bool IsNotWindows => !IsWindows;
{ public static bool IsLinux => Os == Os.Linux;
var platform = (int)Environment.OSVersion.Platform; public static bool IsOsx => Os == Os.Osx;
public static bool IsWindows => Os == Os.Windows;
Version = Environment.OSVersion.Version; public string Version { get; }
public string Name { get; }
public string FullName { get; }
IsMonoRuntime = Type.GetType("Mono.Runtime") != null; static OsInfo()
IsNotWindows = (platform == 4) || (platform == 6) || (platform == 128); {
IsOsx = IsRunningOnMac(); var platform = Environment.OSVersion.Platform;
IsLinux = IsNotWindows && !IsOsx;
IsWindows = !IsNotWindows;
FirstDayOfWeek = CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek;
if (IsWindows) switch (platform)
{
Os = Os.Windows;
PathStringComparison = StringComparison.OrdinalIgnoreCase;
}
else
{ {
Os = IsOsx ? Os.Osx : Os.Linux; case PlatformID.Win32NT:
{
PathStringComparison = StringComparison.Ordinal; Os = Os.Windows;
break;
}
case PlatformID.MacOSX:
case PlatformID.Unix:
{
// Sometimes Mac OS reports itself as Unix
if (Directory.Exists("/System/Library/CoreServices/") &&
(File.Exists("/System/Library/CoreServices/SystemVersion.plist") ||
File.Exists("/System/Library/CoreServices/ServerVersion.plist"))
)
{
Os = Os.Osx;
}
else
{
Os = Os.Linux;
}
break;
}
} }
} }
public static Version Version { get; private set; } public OsInfo(IEnumerable<IOsVersionAdapter> versionAdapters, Logger logger)
public static bool IsMonoRuntime { get; private set; }
public static bool IsNotWindows { get; private set; }
public static bool IsLinux { get; private set; }
public static bool IsOsx { get; private set; }
public static bool IsWindows { get; private set; }
public static Os Os { get; private set; }
public static DayOfWeek FirstDayOfWeek { get; private set; }
public static StringComparison PathStringComparison { get; private set; }
//Borrowed from: https://github.com/jpobst/Pinta/blob/master/Pinta.Core/Managers/SystemManager.cs
//From Managed.Windows.Forms/XplatUI
[DllImport("libc")]
static extern int uname(IntPtr buf);
[DebuggerStepThrough]
static bool IsRunningOnMac()
{ {
var buf = IntPtr.Zero; OsVersionModel osInfo = null;
try foreach (var osVersionAdapter in versionAdapters.Where(c => c.Enabled))
{ {
buf = Marshal.AllocHGlobal(8192); try
// This is a hacktastic way of getting sysname from uname ()
if (uname(buf) == 0)
{ {
var os = Marshal.PtrToStringAnsi(buf); osInfo = osVersionAdapter.Read();
}
catch (Exception e)
{
logger.Error(e, "Couldn't get OS Version info");
}
if (os == "Darwin") if (osInfo != null)
{ {
return true; break;
}
} }
} }
catch
if (osInfo != null)
{ {
Name = osInfo.Name;
Version = osInfo.Version;
FullName = osInfo.FullName;
} }
finally else
{ {
if (buf != IntPtr.Zero) Name = Os.ToString();
{ FullName = Name;
Marshal.FreeHGlobal(buf);
}
} }
return false;
} }
} }
public interface IOsInfo
{
string Version { get; }
string Name { get; }
string FullName { get; }
}
public enum Os public enum Os
{ {
Windows, Windows,

@ -0,0 +1,29 @@
namespace NzbDrone.Common.EnvironmentInfo
{
public class OsVersionModel
{
public OsVersionModel(string name, string version, string fullName = null)
{
Name = Trim(name);
Version = Trim(version);
if (string.IsNullOrWhiteSpace(fullName))
{
fullName = $"{Name} {Version}";
}
FullName = Trim(fullName);
}
private static string Trim(string source)
{
return source.Trim().Trim('"', '\'');
}
public string Name { get; }
public string FullName { get; }
public string Version { get; }
}
}

@ -5,15 +5,14 @@ using System.Reflection;
using System.Security.Principal; using System.Security.Principal;
using System.ServiceProcess; using System.ServiceProcess;
using NLog; using NLog;
using NzbDrone.Common.Processes;
namespace NzbDrone.Common.EnvironmentInfo namespace NzbDrone.Common.EnvironmentInfo
{ {
public abstract class RuntimeInfoBase : IRuntimeInfo public class RuntimeInfo : IRuntimeInfo
{ {
private readonly Logger _logger; private readonly Logger _logger;
public RuntimeInfoBase(IServiceProvider serviceProvider, Logger logger) public RuntimeInfo(IServiceProvider serviceProvider, Logger logger)
{ {
_logger = logger; _logger = logger;
@ -31,7 +30,7 @@ namespace NzbDrone.Common.EnvironmentInfo
} }
} }
static RuntimeInfoBase() static RuntimeInfo()
{ {
IsProduction = InternalIsProduction(); IsProduction = InternalIsProduction();
} }
@ -59,31 +58,18 @@ namespace NzbDrone.Common.EnvironmentInfo
public bool IsWindowsService { get; private set; } public bool IsWindowsService { get; private set; }
public bool IsConsole public bool IsExiting { get; set; }
{
get
{
if (OsInfo.IsWindows)
{
return IsUserInteractive && Process.GetCurrentProcess().ProcessName.Equals(ProcessProvider.NZB_DRONE_CONSOLE_PROCESS_NAME, StringComparison.InvariantCultureIgnoreCase);
}
return true;
}
}
public bool IsRunning { get; set; }
public bool RestartPending { get; set; } public bool RestartPending { get; set; }
public string ExecutingApplication { get; private set; } public string ExecutingApplication { get; }
public abstract string RuntimeVersion { get; } public static bool IsProduction { get; }
public static bool IsProduction { get; private set; }
private static bool InternalIsProduction() private static bool InternalIsProduction()
{ {
if (BuildInfo.IsDebug || Debugger.IsAttached) return false; if (BuildInfo.IsDebug || Debugger.IsAttached) return false;
if (BuildInfo.Version.Revision > 10000) return false; //Official builds will never have such a high revision
//Official builds will never have such a high revision
if (BuildInfo.Version.Revision > 10000) return false;
try try
{ {
@ -99,17 +85,17 @@ namespace NzbDrone.Common.EnvironmentInfo
} }
try try
{ {
var currentAssmeblyLocation = typeof(RuntimeInfoBase).Assembly.Location; var currentAssemblyLocation = typeof(RuntimeInfo).Assembly.Location;
if(currentAssmeblyLocation.ToLower().Contains("_output"))return false; if (currentAssemblyLocation.ToLower().Contains("_output")) return false;
} }
catch catch
{ {
} }
string lowerCurrentDir = Directory.GetCurrentDirectory().ToLower(); var lowerCurrentDir = Directory.GetCurrentDirectory().ToLower();
if (lowerCurrentDir.Contains("teamcity")) return false; if (lowerCurrentDir.Contains("teamcity")) return false;
if (lowerCurrentDir.Contains("_output")) return false; if (lowerCurrentDir.Contains("_output")) return false;

@ -1,31 +0,0 @@
using System;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Common.Exceptron
{
public static class ExceptionExtentions
{
private const string IGNORE_FLAG = "exceptron_ignore";
public static Exception ExceptronIgnoreOnMono(this Exception exception)
{
if (OsInfo.IsNotWindows)
{
exception.ExceptronIgnore();
}
return exception;
}
public static Exception ExceptronIgnore(this Exception exception)
{
exception.Data.Add(IGNORE_FLAG, true);
return exception;
}
public static bool ExceptronShouldIgnore(this Exception exception)
{
return exception.Data.Contains(IGNORE_FLAG);
}
}
}

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnsureThat; using NzbDrone.Common.EnsureThat;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
@ -47,7 +48,7 @@ namespace NzbDrone.Common.Extensions
{ {
if (!comparison.HasValue) if (!comparison.HasValue)
{ {
comparison = OsInfo.PathStringComparison; comparison = DiskProviderBase.PathStringComparison;
} }
if (firstPath.Equals(secondPath, comparison.Value)) return true; if (firstPath.Equals(secondPath, comparison.Value)) return true;
@ -93,7 +94,7 @@ namespace NzbDrone.Common.Extensions
while (child.Parent != null) while (child.Parent != null)
{ {
if (child.Parent.FullName.Equals(parent.FullName, OsInfo.PathStringComparison)) if (child.Parent.FullName.Equals(parent.FullName, DiskProviderBase.PathStringComparison))
{ {
return true; return true;
} }

@ -21,6 +21,7 @@ namespace NzbDrone.Common.Http.Dispatchers
private static readonly Regex ExpiryDate = new Regex(@"(expires=)([^;]+)", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex ExpiryDate = new Regex(@"(expires=)([^;]+)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private readonly IHttpProxySettingsProvider _proxySettingsProvider; private readonly IHttpProxySettingsProvider _proxySettingsProvider;
private readonly IUserAgentBuilder _userAgentBuilder;
private readonly Logger _logger; private readonly Logger _logger;
private const string _caBundleFileName = "curl-ca-bundle.crt"; private const string _caBundleFileName = "curl-ca-bundle.crt";
@ -38,9 +39,10 @@ namespace NzbDrone.Common.Http.Dispatchers
} }
} }
public CurlHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, Logger logger) public CurlHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, IUserAgentBuilder userAgentBuilder, Logger logger)
{ {
_proxySettingsProvider = proxySettingsProvider; _proxySettingsProvider = proxySettingsProvider;
_userAgentBuilder = userAgentBuilder;
_logger = logger; _logger = logger;
} }
@ -102,9 +104,9 @@ namespace NzbDrone.Common.Http.Dispatchers
break; break;
default: default:
throw new NotSupportedException(string.Format("HttpCurl method {0} not supported", request.Method)); throw new NotSupportedException($"HttpCurl method {request.Method} not supported");
} }
curlEasy.UserAgent = request.UseSimplifiedUserAgent ? UserAgentBuilder.UserAgentSimplified : UserAgentBuilder.UserAgent; ; curlEasy.UserAgent = _userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent);
curlEasy.FollowLocation = request.AllowAutoRedirect; curlEasy.FollowLocation = request.AllowAutoRedirect;
if (request.RequestTimeout != TimeSpan.Zero) if (request.RequestTimeout != TimeSpan.Zero)

@ -10,21 +10,23 @@ namespace NzbDrone.Common.Http.Dispatchers
{ {
private readonly ManagedHttpDispatcher _managedDispatcher; private readonly ManagedHttpDispatcher _managedDispatcher;
private readonly CurlHttpDispatcher _curlDispatcher; private readonly CurlHttpDispatcher _curlDispatcher;
private readonly IPlatformInfo _platformInfo;
private readonly Logger _logger; private readonly Logger _logger;
private readonly ICached<bool> _curlTLSFallbackCache; private readonly ICached<bool> _curlTLSFallbackCache;
public FallbackHttpDispatcher(ManagedHttpDispatcher managedDispatcher, CurlHttpDispatcher curlDispatcher, ICacheManager cacheManager, Logger logger) public FallbackHttpDispatcher(ManagedHttpDispatcher managedDispatcher, CurlHttpDispatcher curlDispatcher, ICacheManager cacheManager, IPlatformInfo platformInfo, Logger logger)
{ {
_managedDispatcher = managedDispatcher; _managedDispatcher = managedDispatcher;
_curlDispatcher = curlDispatcher; _curlDispatcher = curlDispatcher;
_platformInfo = platformInfo;
_curlTLSFallbackCache = cacheManager.GetCache<bool>(GetType(), "curlTLSFallback"); _curlTLSFallbackCache = cacheManager.GetCache<bool>(GetType(), "curlTLSFallback");
_logger = logger; _logger = logger;
} }
public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies) public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
{ {
if (OsInfo.IsMonoRuntime && request.Url.Scheme == "https") if (PlatformInfo.IsMono && request.Url.Scheme == "https")
{ {
if (!_curlTLSFallbackCache.Find(request.Url.Host)) if (!_curlTLSFallbackCache.Find(request.Url.Host))
{ {

@ -11,11 +11,13 @@ namespace NzbDrone.Common.Http.Dispatchers
{ {
private readonly IHttpProxySettingsProvider _proxySettingsProvider; private readonly IHttpProxySettingsProvider _proxySettingsProvider;
private readonly ICreateManagedWebProxy _createManagedWebProxy; private readonly ICreateManagedWebProxy _createManagedWebProxy;
private readonly IUserAgentBuilder _userAgentBuilder;
public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, ICreateManagedWebProxy createManagedWebProxy) public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, ICreateManagedWebProxy createManagedWebProxy, IUserAgentBuilder userAgentBuilder)
{ {
_proxySettingsProvider = proxySettingsProvider; _proxySettingsProvider = proxySettingsProvider;
_createManagedWebProxy = createManagedWebProxy; _createManagedWebProxy = createManagedWebProxy;
_userAgentBuilder = userAgentBuilder;
} }
public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies) public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
@ -28,7 +30,7 @@ namespace NzbDrone.Common.Http.Dispatchers
webRequest.AutomaticDecompression = DecompressionMethods.GZip; webRequest.AutomaticDecompression = DecompressionMethods.GZip;
webRequest.Method = request.Method.ToString(); webRequest.Method = request.Method.ToString();
webRequest.UserAgent = request.UseSimplifiedUserAgent ? UserAgentBuilder.UserAgentSimplified : UserAgentBuilder.UserAgent; webRequest.UserAgent = _userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent);
webRequest.KeepAlive = request.ConnectionKeepAlive; webRequest.KeepAlive = request.ConnectionKeepAlive;
webRequest.AllowAutoRedirect = request.AllowAutoRedirect; webRequest.AllowAutoRedirect = request.AllowAutoRedirect;
webRequest.CookieContainer = cookies; webRequest.CookieContainer = cookies;

@ -30,12 +30,19 @@ namespace NzbDrone.Common.Http
private readonly ICached<CookieContainer> _cookieContainerCache; private readonly ICached<CookieContainer> _cookieContainerCache;
private readonly List<IHttpRequestInterceptor> _requestInterceptors; private readonly List<IHttpRequestInterceptor> _requestInterceptors;
private readonly IHttpDispatcher _httpDispatcher; private readonly IHttpDispatcher _httpDispatcher;
private readonly IUserAgentBuilder _userAgentBuilder;
public HttpClient(IEnumerable<IHttpRequestInterceptor> requestInterceptors, ICacheManager cacheManager, IRateLimitService rateLimitService, IHttpDispatcher httpDispatcher, Logger logger)
public HttpClient(IEnumerable<IHttpRequestInterceptor> requestInterceptors,
ICacheManager cacheManager,
IRateLimitService rateLimitService,
IHttpDispatcher httpDispatcher,
IUserAgentBuilder userAgentBuilder,
Logger logger)
{ {
_requestInterceptors = requestInterceptors.ToList(); _requestInterceptors = requestInterceptors.ToList();
_rateLimitService = rateLimitService; _rateLimitService = rateLimitService;
_httpDispatcher = httpDispatcher; _httpDispatcher = httpDispatcher;
_userAgentBuilder = userAgentBuilder;
_logger = logger; _logger = logger;
ServicePointManager.DefaultConnectionLimit = 12; ServicePointManager.DefaultConnectionLimit = 12;
@ -78,7 +85,7 @@ namespace NzbDrone.Common.Http
_logger.Trace("Response content ({0} bytes): {1}", response.ResponseData.Length, response.Content); _logger.Trace("Response content ({0} bytes): {1}", response.ResponseData.Length, response.Content);
} }
if (!RuntimeInfoBase.IsProduction && if (!RuntimeInfo.IsProduction &&
(response.StatusCode == HttpStatusCode.Moved || (response.StatusCode == HttpStatusCode.Moved ||
response.StatusCode == HttpStatusCode.MovedPermanently || response.StatusCode == HttpStatusCode.MovedPermanently ||
response.StatusCode == HttpStatusCode.Found)) response.StatusCode == HttpStatusCode.Found))
@ -163,7 +170,7 @@ namespace NzbDrone.Common.Http
var stopWatch = Stopwatch.StartNew(); var stopWatch = Stopwatch.StartNew();
var webClient = new GZipWebClient(); var webClient = new GZipWebClient();
webClient.Headers.Add(HttpRequestHeader.UserAgent, UserAgentBuilder.UserAgent); webClient.Headers.Add(HttpRequestHeader.UserAgent, _userAgentBuilder.GetUserAgent());
webClient.DownloadFile(url, fileName); webClient.DownloadFile(url, fileName);
stopWatch.Stop(); stopWatch.Stop();
_logger.Debug("Downloading Completed. took {0:0}s", stopWatch.Elapsed.Seconds); _logger.Debug("Downloading Completed. took {0:0}s", stopWatch.Elapsed.Seconds);

@ -15,7 +15,7 @@ namespace NzbDrone.Common.Http
AllowAutoRedirect = true; AllowAutoRedirect = true;
Cookies = new Dictionary<string, string>(); Cookies = new Dictionary<string, string>();
if (!RuntimeInfoBase.IsProduction) if (!RuntimeInfo.IsProduction)
{ {
AllowAutoRedirect = false; AllowAutoRedirect = false;
} }

@ -2,19 +2,33 @@ using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Common.Http namespace NzbDrone.Common.Http
{ {
public static class UserAgentBuilder public interface IUserAgentBuilder
{ {
public static string UserAgent { get; private set; } string GetUserAgent(bool simplified = false);
public static string UserAgentSimplified { get; private set; } }
public class UserAgentBuilder : IUserAgentBuilder
{
private readonly string _userAgentSimplified;
private readonly string _userAgent;
public string GetUserAgent(bool simplified)
{
if (simplified)
{
return _userAgentSimplified;
}
return _userAgent;
}
static UserAgentBuilder() public UserAgentBuilder(IOsInfo osInfo)
{ {
UserAgent = string.Format("Sonarr/{0} ({1} {2})", var osName = osInfo.Name.ToLower();
BuildInfo.Version, var osVersion = osInfo.Version.ToLower();
OsInfo.Os, OsInfo.Version.ToString(2));
UserAgentSimplified = string.Format("Sonarr/{0}", _userAgent = $"Sonarr/{BuildInfo.Version} ({osName} {osVersion})";
BuildInfo.Version.ToString(2)); _userAgentSimplified = $"Sonarr/{BuildInfo.Version.ToString(2)}";
} }
} }
} }

@ -1,89 +0,0 @@
using System;
using NLog;
using NLog.Common;
using NLog.Layouts;
using NLog.Targets;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Exceptron;
using NzbDrone.Common.Exceptron.Configuration;
namespace NzbDrone.Common.Instrumentation
{
/// <summary>
/// <see cref="NLog"/> target for exceptron. Allows you to automatically report all
/// exceptions logged to Nlog/>
/// </summary>
[Target("Exceptron")]
public class ExceptronTarget : Target
{
/// <summary>
/// <see cref="ExceptronClient"/> instance that Nlog Target uses to report the exceptions.
/// </summary>
public IExceptronClient ExceptronClient { get; internal set; }
protected override void InitializeTarget()
{
var config = new ExceptronConfiguration
{
ApiKey = "d64e0a72845d495abc625af3a27cf5f5",
IncludeMachineName = true,
};
if (RuntimeInfoBase.IsProduction)
{
config.ApiKey = "82c0f66dd2d64d1480cc88b551c9bdd8";
}
ExceptronClient = new ExceptronClient(config, BuildInfo.Version);
}
/// <summary>
/// String that identifies the active user
/// </summary>
public Layout UserId { get; set; }
protected override void Write(LogEventInfo logEvent)
{
if (logEvent == null || logEvent.Exception == null || logEvent.Exception.ExceptronShouldIgnore()) return;
try
{
var exceptionData = new ExceptionData
{
Exception = logEvent.Exception,
Component = logEvent.LoggerName,
Message = logEvent.FormattedMessage,
};
if (UserId != null)
{
exceptionData.UserId = UserId.Render(logEvent);
}
if (logEvent.Level <= LogLevel.Info)
{
exceptionData.Severity = ExceptionSeverity.None;
}
else if (logEvent.Level <= LogLevel.Warn)
{
exceptionData.Severity = ExceptionSeverity.Warning;
}
else if (logEvent.Level <= LogLevel.Error)
{
exceptionData.Severity = ExceptionSeverity.Error;
}
else if (logEvent.Level <= LogLevel.Fatal)
{
exceptionData.Severity = ExceptionSeverity.Fatal;
}
ExceptronClient.SubmitException(exceptionData);
}
catch (Exception e)
{
InternalLogger.Warn("Unable to report exception. {0}", e);
}
}
}
}

@ -35,7 +35,7 @@ namespace NzbDrone.Common.Instrumentation
return; return;
} }
if (OsInfo.IsMonoRuntime) if (PlatformInfo.IsMono)
{ {
if (exception is TypeInitializationException && exception.InnerException is DllNotFoundException || if (exception is TypeInitializationException && exception.InnerException is DllNotFoundException ||
exception is DllNotFoundException) exception is DllNotFoundException)

@ -48,7 +48,7 @@ namespace NzbDrone.Common.Instrumentation
} }
else else
{ {
if (inConsole && (OsInfo.IsNotWindows || RuntimeInfoBase.IsUserInteractive)) if (inConsole && (OsInfo.IsNotWindows || RuntimeInfo.IsUserInteractive))
{ {
RegisterConsole(); RegisterConsole();
} }
@ -152,16 +152,6 @@ namespace NzbDrone.Common.Instrumentation
LogManager.Configuration.LoggingRules.Add(loggingRule); LogManager.Configuration.LoggingRules.Add(loggingRule);
} }
private static void RegisterExceptron()
{
var exceptronTarget = new ExceptronTarget();
var rule = new LoggingRule("*", LogLevel.Warn, exceptronTarget);
LogManager.Configuration.AddTarget("ExceptronTarget", exceptronTarget);
LogManager.Configuration.LoggingRules.Add(rule);
}
public static Logger GetLogger(Type obj) public static Logger GetLogger(Type obj)
{ {
return LogManager.GetLogger(obj.Name.Replace("NzbDrone.", "")); return LogManager.GetLogger(obj.Name.Replace("NzbDrone.", ""));

@ -88,6 +88,9 @@
<Compile Include="Disk\RelativeFileSystemModel.cs" /> <Compile Include="Disk\RelativeFileSystemModel.cs" />
<Compile Include="Disk\FileSystemModel.cs" /> <Compile Include="Disk\FileSystemModel.cs" />
<Compile Include="Disk\FileSystemResult.cs" /> <Compile Include="Disk\FileSystemResult.cs" />
<Compile Include="EnvironmentInfo\IOsVersionAdapter.cs" />
<Compile Include="EnvironmentInfo\IPlatformInfo.cs" />
<Compile Include="EnvironmentInfo\OsVersionModel.cs" />
<Compile Include="Extensions\DictionaryExtensions.cs" /> <Compile Include="Extensions\DictionaryExtensions.cs" />
<Compile Include="Disk\OsPath.cs" /> <Compile Include="Disk\OsPath.cs" />
<Compile Include="Disk\DiskProviderBase.cs" /> <Compile Include="Disk\DiskProviderBase.cs" />
@ -118,13 +121,12 @@
<Compile Include="EnvironmentInfo\BuildInfo.cs" /> <Compile Include="EnvironmentInfo\BuildInfo.cs" />
<Compile Include="EnvironmentInfo\OsInfo.cs" /> <Compile Include="EnvironmentInfo\OsInfo.cs" />
<Compile Include="EnvironmentInfo\IRuntimeInfo.cs" /> <Compile Include="EnvironmentInfo\IRuntimeInfo.cs" />
<Compile Include="EnvironmentInfo\RuntimeInfoBase.cs" /> <Compile Include="EnvironmentInfo\RuntimeInfo.cs" />
<Compile Include="EnvironmentInfo\StartupContext.cs" /> <Compile Include="EnvironmentInfo\StartupContext.cs" />
<Compile Include="Exceptions\NotParentException.cs" /> <Compile Include="Exceptions\NotParentException.cs" />
<Compile Include="Exceptions\NzbDroneException.cs" /> <Compile Include="Exceptions\NzbDroneException.cs" />
<Compile Include="Exceptron\Configuration\ExceptronConfiguration.cs" /> <Compile Include="Exceptron\Configuration\ExceptronConfiguration.cs" />
<Compile Include="Exceptron\ExceptionData.cs" /> <Compile Include="Exceptron\ExceptionData.cs" />
<Compile Include="Exceptron\ExceptionExtentions.cs" />
<Compile Include="Exceptron\ExceptionSeverity.cs" /> <Compile Include="Exceptron\ExceptionSeverity.cs" />
<Compile Include="Exceptron\ExceptronApiException.cs" /> <Compile Include="Exceptron\ExceptronApiException.cs" />
<Compile Include="Exceptron\ExceptronClient.cs" /> <Compile Include="Exceptron\ExceptronClient.cs" />
@ -187,7 +189,6 @@
<Compile Include="Extensions\IEnumerableExtensions.cs" /> <Compile Include="Extensions\IEnumerableExtensions.cs" />
<Compile Include="Http\UserAgentBuilder.cs" /> <Compile Include="Http\UserAgentBuilder.cs" />
<Compile Include="Instrumentation\CleanseLogMessage.cs" /> <Compile Include="Instrumentation\CleanseLogMessage.cs" />
<Compile Include="Instrumentation\ExceptronTarget.cs" />
<Compile Include="Instrumentation\Extensions\LoggerProgressExtensions.cs" /> <Compile Include="Instrumentation\Extensions\LoggerProgressExtensions.cs" />
<Compile Include="Instrumentation\GlobalExceptionHandlers.cs" /> <Compile Include="Instrumentation\GlobalExceptionHandlers.cs" />
<Compile Include="Instrumentation\LogEventExtensions.cs" /> <Compile Include="Instrumentation\LogEventExtensions.cs" />

@ -108,7 +108,7 @@ namespace NzbDrone.Common.Processes
public Process Start(string path, string args = null, StringDictionary environmentVariables = null, Action<string> onOutputDataReceived = null, Action<string> onErrorDataReceived = null) public Process Start(string path, string args = null, StringDictionary environmentVariables = null, Action<string> onOutputDataReceived = null, Action<string> onErrorDataReceived = null)
{ {
if (OsInfo.IsMonoRuntime && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase)) if (PlatformInfo.IsMono && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
{ {
args = GetMonoArgs(path, args); args = GetMonoArgs(path, args);
path = "mono"; path = "mono";
@ -174,7 +174,7 @@ namespace NzbDrone.Common.Processes
public Process SpawnNewProcess(string path, string args = null, StringDictionary environmentVariables = null) public Process SpawnNewProcess(string path, string args = null, StringDictionary environmentVariables = null)
{ {
if (OsInfo.IsMonoRuntime && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase)) if (PlatformInfo.IsMono && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
{ {
args = GetMonoArgs(path, args); args = GetMonoArgs(path, args);
path = "mono"; path = "mono";

@ -1,6 +1,8 @@
using NUnit.Framework; using System;
using NUnit.Framework;
using NzbDrone.Common.Cache; using NzbDrone.Common.Cache;
using NzbDrone.Common.Cloud; using NzbDrone.Common.Cloud;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Http.Dispatchers; using NzbDrone.Common.Http.Dispatchers;
using NzbDrone.Common.TPL; using NzbDrone.Common.TPL;
@ -15,12 +17,16 @@ namespace NzbDrone.Core.Test.Framework
{ {
protected void UseRealHttp() protected void UseRealHttp()
{ {
Mocker.GetMock<IPlatformInfo>().SetupGet(c => c.Version).Returns(new Version("3.0.0"));
Mocker.GetMock<IOsInfo>().SetupGet(c=>c.Version).Returns("1.0.0");
Mocker.GetMock<IOsInfo>().SetupGet(c=>c.Name).Returns("TestOS");
Mocker.SetConstant<IHttpProxySettingsProvider>(new HttpProxySettingsProvider(Mocker.Resolve<ConfigService>())); Mocker.SetConstant<IHttpProxySettingsProvider>(new HttpProxySettingsProvider(Mocker.Resolve<ConfigService>()));
Mocker.SetConstant<ICreateManagedWebProxy>(new ManagedWebProxyFactory(Mocker.Resolve<CacheManager>())); Mocker.SetConstant<ICreateManagedWebProxy>(new ManagedWebProxyFactory(Mocker.Resolve<CacheManager>()));
Mocker.SetConstant<ManagedHttpDispatcher>(new ManagedHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<ICreateManagedWebProxy>())); Mocker.SetConstant<ManagedHttpDispatcher>(new ManagedHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<ICreateManagedWebProxy>(), Mocker.Resolve<UserAgentBuilder>()));
Mocker.SetConstant<CurlHttpDispatcher>(new CurlHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<NLog.Logger>())); Mocker.SetConstant<CurlHttpDispatcher>(new CurlHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<UserAgentBuilder>(), Mocker.Resolve<NLog.Logger>()));
Mocker.SetConstant<IHttpProvider>(new HttpProvider(TestLogger)); Mocker.SetConstant<IHttpProvider>(new HttpProvider(TestLogger));
Mocker.SetConstant<IHttpClient>(new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve<CacheManager>(), Mocker.Resolve<RateLimitService>(), Mocker.Resolve<FallbackHttpDispatcher>(), TestLogger)); Mocker.SetConstant<IHttpClient>(new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve<CacheManager>(), Mocker.Resolve<RateLimitService>(), Mocker.Resolve<FallbackHttpDispatcher>(), Mocker.Resolve<UserAgentBuilder>(), TestLogger));
Mocker.SetConstant<ISonarrCloudRequestBuilder>(new SonarrCloudRequestBuilder()); Mocker.SetConstant<ISonarrCloudRequestBuilder>(new SonarrCloudRequestBuilder());
} }
} }

@ -1,4 +1,5 @@
using NUnit.Framework; using System;
using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.HealthCheck.Checks; using NzbDrone.Core.HealthCheck.Checks;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
@ -8,17 +9,13 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
[TestFixture] [TestFixture]
public class MonoVersionCheckFixture : CoreTest<MonoVersionCheck> public class MonoVersionCheckFixture : CoreTest<MonoVersionCheck>
{ {
[SetUp] private void GivenOutput(string version)
public void Setup()
{ {
MonoOnly(); MonoOnly();
}
private void GivenOutput(string version) Mocker.GetMock<IPlatformInfo>()
{ .SetupGet(s => s.Version)
Mocker.GetMock<IRuntimeInfo>() .Returns(new Version(version));
.SetupGet(s => s.RuntimeVersion)
.Returns(string.Format("{0} (tarball Wed Sep 25 16:35:44 CDT 2013)", version));
} }
[TestCase("3.10")] [TestCase("3.10")]

@ -2,6 +2,7 @@ using System;
using System.Linq; using System.Linq;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Update; using NzbDrone.Core.Update;
@ -10,6 +11,12 @@ namespace NzbDrone.Core.Test.UpdateTests
{ {
public class UpdatePackageProviderFixture : CoreTest<UpdatePackageProvider> public class UpdatePackageProviderFixture : CoreTest<UpdatePackageProvider>
{ {
[SetUp]
public void Setup()
{
Mocker.GetMock<IPlatformInfo>().SetupGet(c => c.Version).Returns(new Version("9.9.9"));
}
[Test] [Test]
public void no_update_when_version_higher() public void no_update_when_version_higher()
{ {

@ -17,6 +17,6 @@ namespace NzbDrone.Core.Analytics
_configFileProvider = configFileProvider; _configFileProvider = configFileProvider;
} }
public bool IsEnabled => _configFileProvider.AnalyticsEnabled && RuntimeInfoBase.IsProduction; public bool IsEnabled => _configFileProvider.AnalyticsEnabled && RuntimeInfo.IsProduction;
} }
} }

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Common.EnsureThat; using NzbDrone.Common.EnsureThat;
@ -246,7 +247,7 @@ namespace NzbDrone.Core.Configuration
public int FirstDayOfWeek public int FirstDayOfWeek
{ {
get { return GetValueInt("FirstDayOfWeek", (int)OsInfo.FirstDayOfWeek); } get { return GetValueInt("FirstDayOfWeek", (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek); }
set { SetValue("FirstDayOfWeek", value); } set { SetValue("FirstDayOfWeek", value); }
} }

@ -1,7 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text.RegularExpressions;
using NLog; using NLog;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
@ -9,50 +8,43 @@ namespace NzbDrone.Core.HealthCheck.Checks
{ {
public class MonoVersionCheck : HealthCheckBase public class MonoVersionCheck : HealthCheckBase
{ {
private readonly IRuntimeInfo _runtimeInfo; private readonly IPlatformInfo _platformInfo;
private readonly Logger _logger; private readonly Logger _logger;
private static readonly Regex VersionRegex = new Regex(@"(?<=\W|^)(?<version>\d+\.\d+(\.\d+)?(\.\d+)?)(?=\W)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public MonoVersionCheck(IRuntimeInfo runtimeInfo, Logger logger) public MonoVersionCheck(IPlatformInfo platformInfo, Logger logger)
{ {
_runtimeInfo = runtimeInfo; _platformInfo = platformInfo;
_logger = logger; _logger = logger;
} }
public override HealthCheck Check() public override HealthCheck Check()
{ {
if (OsInfo.IsWindows) if (!PlatformInfo.IsMono)
{ {
return new HealthCheck(GetType()); return new HealthCheck(GetType());
} }
var versionString = _runtimeInfo.RuntimeVersion; var monoVersion = _platformInfo.Version;
var versionMatch = VersionRegex.Match(versionString);
if (versionMatch.Success) if (monoVersion == new Version("3.4.0") && HasMonoBug18599())
{ {
var version = new Version(versionMatch.Groups["version"].Value); _logger.Debug("Mono version 3.4.0, checking for Mono bug #18599 returned positive.");
return new HealthCheck(GetType(), HealthCheckResult.Error, "You are running an old and unsupported version of Mono with a known bug. You should upgrade to a higher version");
if (version == new Version(3, 4, 0) && HasMonoBug18599())
{
_logger.Debug("mono version 3.4.0, checking for mono bug #18599 returned positive.");
return new HealthCheck(GetType(), HealthCheckResult.Error, "your mono version 3.4.0 has a critical bug, you should upgrade to a higher version");
}
if (version == new Version(4, 4, 0) || version == new Version(4, 4, 1))
{
_logger.Debug("mono version {0}", version);
return new HealthCheck(GetType(), HealthCheckResult.Error, $"your mono version {version} has a bug that causes issues connecting to indexers/download clients");
}
if (version >= new Version(3, 10))
{
_logger.Debug("mono version is 3.10 or better: {0}", version.ToString());
return new HealthCheck(GetType());
}
} }
return new HealthCheck(GetType(), HealthCheckResult.Warning, "mono version is less than 3.10, upgrade for improved stability"); if (monoVersion == new Version("4.4.0") || monoVersion == new Version("4.4.1"))
{
_logger.Debug("Mono version {0}", monoVersion);
return new HealthCheck(GetType(), HealthCheckResult.Error, $"Your Mono version {monoVersion} has a bug that causes issues connecting to indexers/download clients. You should upgrade to a higher version");
}
if (monoVersion >= new Version("3.10"))
{
_logger.Debug("Mono version is 3.10 or better: {0}", monoVersion);
return new HealthCheck(GetType());
}
return new HealthCheck(GetType(), HealthCheckResult.Warning, "You are running an old and unsupported version of Mono. Please upgrade Mono for improved stability.");
} }
public override bool CheckOnConfigChange => false; public override bool CheckOnConfigChange => false;
@ -70,7 +62,8 @@ namespace NzbDrone.Core.HealthCheck.Checks
return false; return false;
} }
var fieldInfo = numberFormatterType.GetField("userFormatProvider", BindingFlags.Static | BindingFlags.NonPublic); var fieldInfo = numberFormatterType.GetField("userFormatProvider",
BindingFlags.Static | BindingFlags.NonPublic);
if (fieldInfo == null) if (fieldInfo == null)
{ {
@ -87,4 +80,4 @@ namespace NzbDrone.Core.HealthCheck.Checks
return false; return false;
} }
} }
} }

@ -4,13 +4,9 @@ namespace NzbDrone.Core.Lifecycle
{ {
public class ApplicationShutdownRequested : IEvent public class ApplicationShutdownRequested : IEvent
{ {
public bool Restarting { get; set; } public bool Restarting { get; }
public ApplicationShutdownRequested() public ApplicationShutdownRequested(bool restarting = false)
{
}
public ApplicationShutdownRequested(bool restarting)
{ {
Restarting = restarting; Restarting = restarting;
} }

@ -164,7 +164,6 @@ namespace NzbDrone.Core.MediaFiles
catch (Exception ex) catch (Exception ex)
{ {
ex.ExceptronIgnoreOnMono();
_logger.Warn(ex, "Unable to set date of file [" + filePath + "]"); _logger.Warn(ex, "Unable to set date of file [" + filePath + "]");
} }
} }

@ -7,12 +7,11 @@ namespace NzbDrone.Core.Rest
{ {
public static RestClient BuildClient(string baseUrl) public static RestClient BuildClient(string baseUrl)
{ {
var restClient = new RestClient(baseUrl); var restClient = new RestClient(baseUrl)
{
UserAgent = $"Sonarr/{BuildInfo.Version} ({OsInfo.Os})"
};
restClient.UserAgent = string.Format("Sonarr/{0} (RestSharp/{1}; {2}/{3})",
BuildInfo.Version,
restClient.GetType().Assembly.GetName().Version,
OsInfo.Os, OsInfo.Version.ToString(2));
return restClient; return restClient;
} }

@ -1,5 +1,4 @@
using NLog; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
namespace NzbDrone.Core.Update namespace NzbDrone.Core.Update
@ -14,16 +13,12 @@ namespace NzbDrone.Core.Update
private readonly IUpdatePackageProvider _updatePackageProvider; private readonly IUpdatePackageProvider _updatePackageProvider;
private readonly IConfigFileProvider _configFileProvider; private readonly IConfigFileProvider _configFileProvider;
private readonly Logger _logger;
public CheckUpdateService(IUpdatePackageProvider updatePackageProvider, public CheckUpdateService(IUpdatePackageProvider updatePackageProvider,
IConfigFileProvider configFileProvider, IConfigFileProvider configFileProvider)
Logger logger)
{ {
_updatePackageProvider = updatePackageProvider; _updatePackageProvider = updatePackageProvider;
_configFileProvider = configFileProvider; _configFileProvider = configFileProvider;
_logger = logger;
} }
public UpdatePackage AvailableUpdate() public UpdatePackage AvailableUpdate()

@ -15,11 +15,13 @@ namespace NzbDrone.Core.Update
public class UpdatePackageProvider : IUpdatePackageProvider public class UpdatePackageProvider : IUpdatePackageProvider
{ {
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly IPlatformInfo _platformInfo;
private readonly IHttpRequestBuilderFactory _requestBuilder; private readonly IHttpRequestBuilderFactory _requestBuilder;
public UpdatePackageProvider(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder) public UpdatePackageProvider(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, IPlatformInfo platformInfo)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_platformInfo = platformInfo;
_requestBuilder = requestBuilder.Services; _requestBuilder = requestBuilder.Services;
} }
@ -29,6 +31,7 @@ namespace NzbDrone.Core.Update
.Resource("/update/{branch}") .Resource("/update/{branch}")
.AddQueryParam("version", currentVersion) .AddQueryParam("version", currentVersion)
.AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant()) .AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant())
.AddQueryParam("runtimeVer", _platformInfo.Version)
.SetSegment("branch", branch) .SetSegment("branch", branch)
.Build(); .Build();
@ -45,6 +48,7 @@ namespace NzbDrone.Core.Update
.Resource("/update/{branch}/changes") .Resource("/update/{branch}/changes")
.AddQueryParam("version", currentVersion) .AddQueryParam("version", currentVersion)
.AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant()) .AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant())
.AddQueryParam("runtimeVer", _platformInfo.Version)
.SetSegment("branch", branch) .SetSegment("branch", branch)
.Build(); .Build();

@ -20,6 +20,7 @@ namespace NzbDrone.Host.AccessControl
private readonly INetshProvider _netshProvider; private readonly INetshProvider _netshProvider;
private readonly IConfigFileProvider _configFileProvider; private readonly IConfigFileProvider _configFileProvider;
private readonly IRuntimeInfo _runtimeInfo; private readonly IRuntimeInfo _runtimeInfo;
private readonly IOsInfo _osInfo;
private readonly Logger _logger; private readonly Logger _logger;
public List<string> Urls public List<string> Urls
@ -30,19 +31,21 @@ namespace NzbDrone.Host.AccessControl
} }
} }
private List<UrlAcl> InternalUrls { get; set; } private List<UrlAcl> InternalUrls { get; }
private List<UrlAcl> RegisteredUrls { get; set; } private List<UrlAcl> RegisteredUrls { get; }
private static readonly Regex UrlAclRegex = new Regex(@"(?<scheme>https?)\:\/\/(?<address>.+?)\:(?<port>\d+)/(?<urlbase>.+)?", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex UrlAclRegex = new Regex(@"(?<scheme>https?)\:\/\/(?<address>.+?)\:(?<port>\d+)/(?<urlbase>.+)?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public UrlAclAdapter(INetshProvider netshProvider, public UrlAclAdapter(INetshProvider netshProvider,
IConfigFileProvider configFileProvider, IConfigFileProvider configFileProvider,
IRuntimeInfo runtimeInfo, IRuntimeInfo runtimeInfo,
IOsInfo osInfo,
Logger logger) Logger logger)
{ {
_netshProvider = netshProvider; _netshProvider = netshProvider;
_configFileProvider = configFileProvider; _configFileProvider = configFileProvider;
_runtimeInfo = runtimeInfo; _runtimeInfo = runtimeInfo;
_osInfo = osInfo;
_logger = logger; _logger = logger;
InternalUrls = new List<UrlAcl>(); InternalUrls = new List<UrlAcl>();
@ -105,7 +108,8 @@ namespace NzbDrone.Host.AccessControl
private void RefreshRegistration() private void RefreshRegistration()
{ {
if (OsInfo.Version.Major < 6) return; var osVersion = new Version(_osInfo.Version);
if (osVersion.Major < 6) return;
foreach (var urlAcl in InternalUrls) foreach (var urlAcl in InternalUrls)
{ {

@ -51,7 +51,7 @@ namespace NzbDrone.Host
Console.CancelKeyPress += (sender, eventArgs) => LogManager.Configuration = null; Console.CancelKeyPress += (sender, eventArgs) => LogManager.Configuration = null;
} }
_runtimeInfo.IsRunning = true; _runtimeInfo.IsExiting = false;
_hostController.StartServer(); _hostController.StartServer();
if (!_startupContext.Flags.Contains(StartupContext.NO_BROWSER) if (!_startupContext.Flags.Contains(StartupContext.NO_BROWSER)
@ -76,7 +76,7 @@ namespace NzbDrone.Host
_logger.Info("Attempting to stop application."); _logger.Info("Attempting to stop application.");
_hostController.StopServer(); _hostController.StopServer();
_logger.Info("Application has finished stop routine."); _logger.Info("Application has finished stop routine.");
_runtimeInfo.IsRunning = false; _runtimeInfo.IsExiting = true;
} }
public void Handle(ApplicationShutdownRequested message) public void Handle(ApplicationShutdownRequested message)

@ -1,6 +1,5 @@
using System.Threading; using System.Threading;
using NLog; using NLog;
using NLog.Common;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Processes; using NzbDrone.Common.Processes;
@ -28,7 +27,7 @@ namespace NzbDrone.Host
public void Spin() public void Spin()
{ {
while (_runtimeInfo.IsRunning) while (!_runtimeInfo.IsExiting)
{ {
Thread.Sleep(1000); Thread.Sleep(1000);
} }

@ -25,7 +25,7 @@ namespace NzbDrone.Integration.Test
protected override void InitializeTestTarget() protected override void InitializeTestTarget()
{ {
// Add Wombles // Add Wombles
var wombles = Indexers.Post(new Api.Indexers.IndexerResource Indexers.Post(new Api.Indexers.IndexerResource
{ {
EnableRss = true, EnableRss = true,
ConfigContract = "NullConfig", ConfigContract = "NullConfig",

@ -0,0 +1,20 @@
using System;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Mono.EnvironmentInfo;
using NzbDrone.Test.Common;
namespace NzbDrone.Mono.Test.EnvironmentInfo
{
[TestFixture]
[Platform("Mono")]
public class MonoPlatformInfoFixture : TestBase<MonoPlatformInfo>
{
[Test]
public void should_get_framework_version()
{
Subject.Version.Major.Should().Be(4);
Subject.Version.Minor.Should().BeOneOf(0, 5, 6);
}
}
}

@ -0,0 +1,29 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Mono.Disk;
using NzbDrone.Mono.EnvironmentInfo.VersionAdapters;
using NzbDrone.Test.Common;
namespace NzbDrone.Mono.Test.EnvironmentInfo
{
[TestFixture]
[Platform("Mono")]
public class ReleaseFileVersionAdapterFixture : TestBase<ReleaseFileVersionAdapter>
{
[SetUp]
public void Setup()
{
Mocker.SetConstant<IDiskProvider>(Mocker.Resolve<DiskProvider>());
}
[Test]
public void should_get_version_info()
{
var info = Subject.Read();
info.FullName.Should().NotBeNullOrWhiteSpace();
info.Name.Should().NotBeNullOrWhiteSpace();
info.Version.Should().NotBeNullOrWhiteSpace();
}
}
}

@ -0,0 +1,77 @@
using System;
using System.IO;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Mono.EnvironmentInfo.VersionAdapters;
using NzbDrone.Test.Common;
namespace NzbDrone.Mono.Test.EnvironmentInfo.VersionAdapters
{
[TestFixture]
public class MacOsVersionAdapterFixture : TestBase<MacOsVersionAdapter>
{
[TestCase("10.8.0")]
[TestCase("10.8")]
[TestCase("10.8.1")]
[TestCase("10.11.20")]
public void should_get_version_info(string versionString)
{
var fileContent = File.ReadAllText(GetTestPath("Files/macOS/SystemVersion.plist")).Replace("10.0.0", versionString);
const string plistPath = "/System/Library/CoreServices/SystemVersion.plist";
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.FolderExists("/System/Library/CoreServices/")).Returns(true);
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFiles("/System/Library/CoreServices/", SearchOption.TopDirectoryOnly))
.Returns(new[] { plistPath });
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.ReadAllText(plistPath))
.Returns(fileContent);
var versionName = Subject.Read();
versionName.Version.Should().Be(versionString);
versionName.Name.Should().Be("macOS");
versionName.FullName.Should().Be("macOS " + versionString);
}
[TestCase]
public void should_detect_server()
{
var fileContent = File.ReadAllText(GetTestPath("Files/macOS/SystemVersion.plist"));
const string plistPath = "/System/Library/CoreServices/ServerVersion.plist";
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.FolderExists("/System/Library/CoreServices/")).Returns(true);
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFiles("/System/Library/CoreServices/", SearchOption.TopDirectoryOnly))
.Returns(new[] { plistPath });
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.ReadAllText(plistPath))
.Returns(fileContent);
var versionName = Subject.Read();
versionName.Name.Should().Be("macOS Server");
}
[TestCase]
public void should_return_null_if_folder_doesnt_exist()
{
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.FolderExists("/System/Library/CoreServices/")).Returns(false);
Subject.Read().Should().BeNull();
Mocker.GetMock<IDiskProvider>()
.Verify(c => c.GetFiles(It.IsAny<string>(), SearchOption.TopDirectoryOnly), Times.Never());
}
}
}

@ -0,0 +1,82 @@
using System.IO;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Mono.Disk;
using NzbDrone.Mono.EnvironmentInfo.VersionAdapters;
using NzbDrone.Test.Common;
using NzbDrone.Test.Common.Categories;
namespace NzbDrone.Mono.Test.EnvironmentInfo.VersionAdapters
{
[TestFixture]
public class ReleaseFileVersionAdapterFixture : TestBase<ReleaseFileVersionAdapter>
{
[Test]
[IntegrationTest]
[Platform("Mono")]
public void should_get_version_info_from_actual_linux()
{
Mocker.SetConstant<IDiskProvider>(Mocker.Resolve<DiskProvider>());
var info = Subject.Read();
info.FullName.Should().NotBeNullOrWhiteSpace();
info.Name.Should().NotBeNullOrWhiteSpace();
info.Version.Should().NotBeNullOrWhiteSpace();
}
[Test]
public void should_return_null_if_etc_doestn_exist()
{
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists("/etc/")).Returns(false);
Subject.Read().Should().BeNull();
Mocker.GetMock<IDiskProvider>()
.Verify(c => c.GetFiles(It.IsAny<string>(), SearchOption.TopDirectoryOnly), Times.Never());
Subject.Read().Should().BeNull();
}
[Test]
public void should_return_null_if_release_file_doestn_exist()
{
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists("/etc/")).Returns(true);
Subject.Read().Should().BeNull();
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFiles(It.IsAny<string>(), SearchOption.TopDirectoryOnly)).Returns(new string[0]);
Subject.Read().Should().BeNull();
}
[Test]
public void should_detect_version()
{
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists("/etc/")).Returns(true);
Subject.Read().Should().BeNull();
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.GetFiles(It.IsAny<string>(), SearchOption.TopDirectoryOnly)).Returns(new[]
{
"/etc/lsb-release",
"/etc/os-release"
});
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.ReadAllText("/etc/lsb-release"))
.Returns(File.ReadAllText(GetTestPath("Files/linux/lsb-release")));
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.ReadAllText("/etc/os-release"))
.Returns(File.ReadAllText(GetTestPath("Files/linux/os-release")));
var version = Subject.Read();
version.Should().NotBeNull();
version.Name.Should().Be("ubuntu");
version.Version.Should().Be("14.04");
version.FullName.Should().Be("Ubuntu 14.04.5 LTS");
}
}
}

@ -0,0 +1,4 @@
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.5 LTS"

@ -0,0 +1,9 @@
NAME="Ubuntu"
VERSION="14.04.5 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04.5 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ProductBuildVersion</key>
<string>16C68</string>
<key>ProductCopyright</key>
<string>1983-2016 Apple Inc.</string>
<key>ProductName</key>
<string>Mac OS X</string>
<key>ProductUserVisibleVersion</key>
<string>10.0.0</string>
<key>ProductVersion</key>
<string>10.0.0</string>
</dict>
</plist>

@ -0,0 +1,8 @@
majorversion="6"
minorversion="0"
productversion="6.0.2"
buildphase="hotfix"
buildnumber="8451"
smallfixnumber="7"
builddate="2016/12/20"
buildtime="05:11:44"

@ -81,10 +81,17 @@
<ItemGroup> <ItemGroup>
<Compile Include="DiskProviderTests\DiskProviderFixture.cs" /> <Compile Include="DiskProviderTests\DiskProviderFixture.cs" />
<Compile Include="DiskProviderTests\FreeSpaceFixture.cs" /> <Compile Include="DiskProviderTests\FreeSpaceFixture.cs" />
<Compile Include="EnvironmentInfo\MonoPlatformInfoFixture.cs" />
<Compile Include="EnvironmentInfo\ReleaseFileVersionAdapterFixture.cs" />
<Compile Include="EnvironmentInfo\VersionAdapters\ReleaseFileVersionAdapterFixture.cs" />
<Compile Include="EnvironmentInfo\VersionAdapters\MacOsVersionAdapterFixture.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" /> <None Include="app.config" />
<None Include="Files\macOS\SystemVersion.plist">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -116,6 +123,19 @@
<ItemGroup> <ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="Files\linux\lsb-release">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="Files\linux\os-release">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="Files\synology\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

@ -0,0 +1,46 @@
using System;
using System.Reflection;
using System.Text.RegularExpressions;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Mono.EnvironmentInfo
{
public class MonoPlatformInfo : PlatformInfo
{
private static readonly Regex VersionRegex = new Regex(@"(?<=\W|^)(?<version>\d+\.\d+(\.\d+)?(\.\d+)?)(?=\W)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public override Version Version { get; }
public MonoPlatformInfo(Logger logger)
{
var runTimeVersion = new Version();
try
{
var type = Type.GetType("Mono.Runtime");
if (type != null)
{
var displayNameMethod = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
if (displayNameMethod != null)
{
var displayName = displayNameMethod.Invoke(null, null).ToString();
var versionMatch = VersionRegex.Match(displayName);
if (versionMatch.Success)
{
runTimeVersion = new Version(versionMatch.Groups["version"].Value);
}
}
}
}
catch (Exception ex)
{
logger.Error(ex, "Unable to get mono version: " + ex.Message);
}
Version = runTimeVersion;
}
}
}

@ -1,45 +0,0 @@
using System;
using System.Reflection;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Mono.EnvironmentInfo
{
public class MonoRuntimeProvider : RuntimeInfoBase
{
private readonly Logger _logger;
public MonoRuntimeProvider(Common.IServiceProvider serviceProvider, Logger logger)
:base(serviceProvider, logger)
{
_logger = logger;
}
public override string RuntimeVersion
{
get
{
try
{
var type = Type.GetType("Mono.Runtime");
if (type != null)
{
var displayName = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
if (displayName != null)
{
return displayName.Invoke(null, null).ToString();
}
}
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to get mono version: " + ex.Message);
}
return string.Empty;
}
}
}
}

@ -0,0 +1,52 @@
using System.IO;
using System.Linq;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Mono.EnvironmentInfo.VersionAdapters
{
public class IssueFileVersionAdapter : IOsVersionAdapter
{
private readonly IDiskProvider _diskProvider;
public IssueFileVersionAdapter(IDiskProvider diskProvider)
{
_diskProvider = diskProvider;
}
public OsVersionModel Read()
{
if (!_diskProvider.FolderExists("/etc/"))
{
return null;
}
var issueFile = _diskProvider.GetFiles("/etc/", SearchOption.TopDirectoryOnly).SingleOrDefault(c => c.EndsWith("/issue"));
if (issueFile == null)
{
return null;
}
var fileContent = _diskProvider.ReadAllText(issueFile);
// Ubuntu 14.04.5 LTS \n \l
// Ubuntu 16.04.1 LTS \n \l
// Fedora/Centos
// Kernel \r on an \m (\l)
// Arch Linux \r (\l)
// Debian GNU/Linux 8 \n \l
if (fileContent.Contains("Arch Linux"))
{
return new OsVersionModel("Arch", "1.0", "Arch Linux");
}
return null;
}
public bool Enabled => OsInfo.IsLinux;
}
}

@ -0,0 +1,69 @@
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Mono.EnvironmentInfo.VersionAdapters
{
public class MacOsVersionAdapter : IOsVersionAdapter
{
private static readonly Regex DarwinVersionRegex = new Regex("<string>(?<version>10\\.\\d{1,2}\\.?\\d{0,2}?)<\\/string>",
RegexOptions.Compiled |
RegexOptions.IgnoreCase
);
private const string PLIST_DIR = "/System/Library/CoreServices/";
private readonly IDiskProvider _diskProvider;
private readonly Logger _logger;
public MacOsVersionAdapter(IDiskProvider diskProvider, Logger logger)
{
_diskProvider = diskProvider;
_logger = logger;
}
public OsVersionModel Read()
{
var version = "10.0";
if (!_diskProvider.FolderExists(PLIST_DIR))
{
_logger.Debug("Directory {0} doesn't exist", PLIST_DIR);
return null;
}
var allFiles = _diskProvider.GetFiles(PLIST_DIR, SearchOption.TopDirectoryOnly);
var versionFile = allFiles.SingleOrDefault(c =>
c.EndsWith("SystemVersion.plist") ||
c.EndsWith("ServerVersion.plist")
);
if (string.IsNullOrWhiteSpace(versionFile))
{
_logger.Debug("Couldn't find version plist file in {0}", PLIST_DIR);
return null;
}
var text = _diskProvider.ReadAllText(versionFile);
var match = DarwinVersionRegex.Match(text);
if (match.Success)
{
version = match.Groups["version"].Value;
}
var name = versionFile.Contains("Server") ? "macOS Server" : "macOS";
return new OsVersionModel(name, version);
}
public bool Enabled => OsInfo.IsOsx;
}
}

@ -0,0 +1,79 @@
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Mono.EnvironmentInfo.VersionAdapters
{
public class ReleaseFileVersionAdapter : IOsVersionAdapter
{
private readonly IDiskProvider _diskProvider;
public ReleaseFileVersionAdapter(IDiskProvider diskProvider)
{
_diskProvider = diskProvider;
}
public OsVersionModel Read()
{
if (!_diskProvider.FolderExists("/etc/"))
{
return null;
}
var releaseFiles = _diskProvider.GetFiles("/etc/", SearchOption.TopDirectoryOnly).Where(c => c.EndsWith("release")).ToList();
var name = "Linux";
var fullName = "";
var version = "";
bool success = false;
foreach (var releaseFile in releaseFiles)
{
var fileContent = _diskProvider.ReadAllText(releaseFile);
var lines = Regex.Split(fileContent, "\r\n|\r|\n"); ;
foreach (var line in lines)
{
var parts = line.Split('=');
if (parts.Length >= 2)
{
var key = parts[0];
var value = parts[1];
if (!string.IsNullOrWhiteSpace(value))
{
switch (key)
{
case "ID":
success = true;
name = value;
break;
case "PRETTY_NAME":
success = true;
fullName = value;
break;
case "VERSION_ID":
success = true;
version = value;
break;
}
}
}
}
}
if (!success)
{
return null;
}
return new OsVersionModel(name, version, fullName);
}
public bool Enabled => OsInfo.IsLinux;
}
}

@ -0,0 +1,78 @@
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Mono.EnvironmentInfo.VersionAdapters
{
public class SynologyVersionAdapter : IOsVersionAdapter
{
private readonly IDiskProvider _diskProvider;
private const string NAME = "DSM";
private const string FULL_NAME = "Synology DSM";
public SynologyVersionAdapter(IDiskProvider diskProvider)
{
_diskProvider = diskProvider;
}
public OsVersionModel Read()
{
if (!_diskProvider.FolderExists("/etc.defaults/"))
{
return null;
}
var versionFile = _diskProvider.GetFiles("/etc.defaults/", SearchOption.TopDirectoryOnly).SingleOrDefault(c => c.EndsWith("VERSION"));
if (versionFile == null)
{
return null;
}
var version = "";
var major = "";
var minor = "0";
var fileContent = _diskProvider.ReadAllText(versionFile);
var lines = Regex.Split(fileContent, "\r\n|\r|\n"); ;
foreach (var line in lines)
{
var parts = line.Split('=');
if (parts.Length >= 2)
{
var key = parts[0];
var value = parts[1];
if (!string.IsNullOrWhiteSpace(value))
{
switch (key)
{
case "productversion":
version = value;
break;
case "majorversion":
major = value;
break;
case "minorversion":
minor = value;
break;
}
}
}
}
if (string.IsNullOrWhiteSpace(version) && !string.IsNullOrWhiteSpace(major))
{
version = $"{major}.{minor}";
}
return new OsVersionModel(NAME, version, $"{FULL_NAME} {version}");
}
public bool Enabled => OsInfo.IsLinux;
}
}

@ -71,9 +71,13 @@
<Compile Include="Disk\DiskProvider.cs" /> <Compile Include="Disk\DiskProvider.cs" />
<Compile Include="Disk\FindDriveType.cs" /> <Compile Include="Disk\FindDriveType.cs" />
<Compile Include="Disk\LinuxPermissionsException.cs" /> <Compile Include="Disk\LinuxPermissionsException.cs" />
<Compile Include="EnvironmentInfo\MonoRuntimeProvider.cs" /> <Compile Include="EnvironmentInfo\VersionAdapters\IssueFileVersionAdapter.cs" />
<Compile Include="EnvironmentInfo\VersionAdapters\MacOsVersionAdapter.cs" />
<Compile Include="EnvironmentInfo\MonoPlatformInfo.cs" />
<Compile Include="Disk\ProcMount.cs" /> <Compile Include="Disk\ProcMount.cs" />
<Compile Include="Disk\ProcMountProvider.cs" /> <Compile Include="Disk\ProcMountProvider.cs" />
<Compile Include="EnvironmentInfo\VersionAdapters\SynologyVersionAdapter.cs" />
<Compile Include="EnvironmentInfo\VersionAdapters\ReleaseFileVersionAdapter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Disk\SymbolicLinkResolver.cs" /> <Compile Include="Disk\SymbolicLinkResolver.cs" />
</ItemGroup> </ItemGroup>

@ -1,5 +1,3 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -151,7 +149,7 @@ namespace NzbDrone.Test.Common.AutoMoq
private Mock<T> TheRegisteredMockForThisType<T>(Type type) where T : class private Mock<T> TheRegisteredMockForThisType<T>(Type type) where T : class
{ {
return (Mock<T>)_registeredMocks.Where(x => x.Key == type).First().Value; return (Mock<T>)_registeredMocks.First(x => x.Key == type).Value;
} }
private void CreateANewMockAndRegisterIt<T>(Type type, MockBehavior behavior) where T : class private void CreateANewMockAndRegisterIt<T>(Type type, MockBehavior behavior) where T : class

@ -133,7 +133,7 @@ namespace NzbDrone.Test.Common
protected void MonoOnly() protected void MonoOnly()
{ {
if (OsInfo.IsWindows) if (!PlatformInfo.IsMono)
{ {
throw new IgnoreException("mono specific test"); throw new IgnoreException("mono specific test");
} }

@ -24,7 +24,7 @@ namespace NzbDrone.Update.UpdateEngine
{ {
if (OsInfo.IsNotWindows) if (OsInfo.IsNotWindows)
{ {
//Tehcnically its the console, but its been renamed for mono (Linux/OS X) // Technically it is the console, but it has been renamed for mono (Linux/OS X)
return AppType.Normal; return AppType.Normal;
} }

@ -0,0 +1,19 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Test.Common;
using NzbDrone.Windows.EnvironmentInfo;
namespace NzbDrone.Windows.Test.EnvironmentInfo
{
[TestFixture]
[Platform("Win")]
public class DotNetPlatformInfoFixture : TestBase<DotNetPlatformInfo>
{
[Test]
public void should_get_framework_version()
{
Subject.Version.Major.Should().Be(4);
Subject.Version.Minor.Should().BeOneOf(0, 5, 6);
}
}
}

@ -0,0 +1,23 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Test.Common;
using NzbDrone.Windows.EnvironmentInfo;
namespace NzbDrone.Windows.Test.EnvironmentInfo
{
[TestFixture]
[Platform("Win")]
public class WindowsVersionInfoFixture : TestBase<WindowsVersionInfo>
{
[Test]
public void should_get_windows_version()
{
var info = Subject.Read();
info.Version.Should().NotBeNullOrWhiteSpace();
info.Name.Should().Contain("Windows");
info.FullName.Should().Contain("Windows");
info.FullName.Should().Contain("NT");
info.FullName.Should().Contain(info.Version);
}
}
}

@ -73,6 +73,8 @@
<ItemGroup> <ItemGroup>
<Compile Include="DiskProviderTests\DiskProviderFixture.cs" /> <Compile Include="DiskProviderTests\DiskProviderFixture.cs" />
<Compile Include="DiskProviderTests\FreeSpaceFixture.cs" /> <Compile Include="DiskProviderTests\FreeSpaceFixture.cs" />
<Compile Include="EnvironmentInfo\WindowsVersionInfoFixture.cs" />
<Compile Include="EnvironmentInfo\DotNetPlatformInfoFixture.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -0,0 +1,57 @@
using System;
using Microsoft.Win32;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Windows.EnvironmentInfo
{
public class DotNetPlatformInfo : PlatformInfo
{
public DotNetPlatformInfo()
{
Version = GetFrameworkVersion();
}
public override Version Version { get; }
private static Version GetFrameworkVersion()
{
const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\";
using (var ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey))
{
if (ndpKey == null)
{
return new Version(4, 0);
}
var releaseKey = (int)ndpKey.GetValue("Release");
if (releaseKey >= 394802)
{
return new Version(4,6,2);
}
if (releaseKey >= 394254)
{
return new Version(4,6,1);
}
if (releaseKey >= 393295)
{
return new Version(4,6);
}
if (releaseKey >= 379893)
{
return new Version(4,5,2);
}
if (releaseKey >= 378675)
{
return new Version(4,5,1);
}
if (releaseKey >= 378389)
{
return new Version(4,5);
}
return new Version(4, 0);
}
}
}
}

@ -1,16 +0,0 @@
using System;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Windows.EnvironmentInfo
{
public class DotNetRuntimeProvider : RuntimeInfoBase
{
public DotNetRuntimeProvider(Common.IServiceProvider serviceProvider, Logger logger)
: base(serviceProvider, logger)
{
}
public override string RuntimeVersion => Environment.Version.ToString();
}
}

@ -0,0 +1,14 @@
using System;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Windows.EnvironmentInfo
{
public class WindowsVersionInfo : IOsVersionAdapter
{
public bool Enabled => OsInfo.IsWindows;
public OsVersionModel Read()
{
return new OsVersionModel("Windows", Environment.OSVersion.Version.ToString(), Environment.OSVersion.VersionString);
}
}
}

@ -64,7 +64,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Disk\DiskProvider.cs" /> <Compile Include="Disk\DiskProvider.cs" />
<Compile Include="EnvironmentInfo\DotNetRuntimeProvider.cs" /> <Compile Include="EnvironmentInfo\DotNetPlatformInfo.cs" />
<Compile Include="EnvironmentInfo\WindowsVersionInfo.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14 # Visual Studio 14
VisualStudioVersion = 14.0.24720.0 VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{57A04B72-8088-4F75-A582-1158CF8291F7}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{57A04B72-8088-4F75-A582-1158CF8291F7}"
EndProject EndProject

@ -57,8 +57,10 @@
<s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File5C7F3FB135E52A44B9447C48B2EEEE92/@KeyIndexDefined">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File5C7F3FB135E52A44B9447C48B2EEEE92/@KeyIndexDefined">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File5C7F3FB135E52A44B9447C48B2EEEE92/IsOn/@EntryValue">False</s:Boolean>
<s:Double x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File5C7F3FB135E52A44B9447C48B2EEEE92/RelativePriority/@EntryValue">1</s:Double> <s:Double x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File5C7F3FB135E52A44B9447C48B2EEEE92/RelativePriority/@EntryValue">1</s:Double>
<s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=FileEAB6F2886783AB41B46249432F57475A/@KeyIndexDefined">True</s:Boolean> <s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=FileEAB6F2886783AB41B46249432F57475A/@KeyIndexDefined">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=FileEAB6F2886783AB41B46249432F57475A/IsOn/@EntryValue">False</s:Boolean>
<s:Double x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=FileEAB6F2886783AB41B46249432F57475A/RelativePriority/@EntryValue">3</s:Double> <s:Double x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=FileEAB6F2886783AB41B46249432F57475A/RelativePriority/@EntryValue">3</s:Double>

Loading…
Cancel
Save