Added: Platform Detection Improvements

pull/2/head
Qstick 6 years ago
parent ea5ad24944
commit aef89160e2

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

@ -79,7 +79,7 @@ namespace NzbDrone.Api.Frontend.Mappers
private string GetIndexText()
{
if (RuntimeInfoBase.IsProduction && _generatedContent != null)
if (RuntimeInfo.IsProduction && _generatedContent != null)
{
return _generatedContent;
}
@ -111,7 +111,7 @@ namespace NzbDrone.Api.Frontend.Mappers
text = text.Replace("APP_BRANCH", _configFileProvider.Branch.ToLower());
text = text.Replace("APP_ANALYTICS", _analyticsService.IsEnabled.ToString().ToLowerInvariant());
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;

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

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

@ -1,4 +1,4 @@
using System.Linq;
using System.Linq;
using Nancy.Bootstrapper;
using Nancy.Diagnostics;
using NLog;
@ -24,9 +24,9 @@ namespace NzbDrone.Api
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);
}

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

@ -4,7 +4,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="FluentMigrator" publicKeyToken="aacfc7de5acabf05" culture="neutral"/>

@ -4,7 +4,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="FluentMigrator" publicKeyToken="aacfc7de5acabf05" culture="neutral" />

@ -29,7 +29,7 @@ namespace NzbDrone.Common.Test
[Test]
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]

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@ -9,6 +9,7 @@ using Moq;
using NLog;
using NUnit.Framework;
using NzbDrone.Common.Cache;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Http;
using NzbDrone.Common.Http.Dispatchers;
using NzbDrone.Common.Http.Proxy;
@ -30,6 +31,13 @@ namespace NzbDrone.Common.Test.Http
[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<ICreateManagedWebProxy>(Mocker.Resolve<ManagedWebProxyFactory>());
Mocker.SetConstant<IRateLimitService>(Mocker.Resolve<RateLimitService>());
@ -48,7 +56,7 @@ namespace NzbDrone.Common.Test.Http
[Test]
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);
@ -58,7 +66,7 @@ namespace NzbDrone.Common.Test.Http
[Test]
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);
@ -68,7 +76,7 @@ namespace NzbDrone.Common.Test.Http
[Test]
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);
@ -80,7 +88,7 @@ namespace NzbDrone.Common.Test.Http
{
var message = "{ my: 1 }";
var request = new HttpRequest(string.Format("http://{0}/post", _httpBinHost));
var request = new HttpRequest($"http://{_httpBinHost}/post");
request.SetContent(message);
var response = Subject.Post<HttpBinResource>(request);
@ -91,7 +99,7 @@ namespace NzbDrone.Common.Test.Http
[TestCase("gzip")]
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);
@ -107,7 +115,7 @@ namespace NzbDrone.Common.Test.Http
[TestCase(HttpStatusCode.BadGateway)]
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));
@ -119,7 +127,7 @@ namespace NzbDrone.Common.Test.Http
[Test]
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);
@ -129,7 +137,7 @@ namespace NzbDrone.Common.Test.Http
[Test]
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;
var response = Subject.Get(request);
@ -182,7 +190,7 @@ namespace NzbDrone.Common.Test.Http
[Test]
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);
@ -196,7 +204,7 @@ namespace NzbDrone.Common.Test.Http
[TestCase("Accept", "text/xml, text/rss+xml, application/rss+xml")]
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);
var response = Subject.Get<HttpBinResource>(request);
@ -219,7 +227,7 @@ namespace NzbDrone.Common.Test.Http
[Test]
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";
var response = Subject.Get<HttpBinResource>(request);
@ -236,7 +244,7 @@ namespace NzbDrone.Common.Test.Http
var oldRequest = new HttpRequest("http://eu.httpbin.org/get");
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);
@ -329,7 +337,7 @@ namespace NzbDrone.Common.Test.Http
[Test]
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.StoreRequestCookie = false;
requestSet.StoreResponseCookie.Should().BeFalse();
@ -348,7 +356,7 @@ namespace NzbDrone.Common.Test.Http
[Test]
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.StoreRequestCookie = false;
requestSet.StoreResponseCookie = true;
@ -527,7 +535,7 @@ namespace NzbDrone.Common.Test.Http
[Test]
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));
@ -547,7 +555,7 @@ namespace NzbDrone.Common.Test.Http
.Setup(v => v.PostResponse(It.IsAny<HttpResponse>()))
.Returns<HttpResponse>(r => r);
var request = new HttpRequest(string.Format("http://{0}/get", _httpBinHost));
var request = new HttpRequest($"http://{_httpBinHost}/get");
Subject.Get(request);
@ -569,7 +577,7 @@ namespace NzbDrone.Common.Test.Http
{
// 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";
var requestSet = new HttpRequestBuilder(string.Format("http://{0}/response-headers", _httpBinHost))
var requestSet = new HttpRequestBuilder($"http://{_httpBinHost}/response-headers")
.AddQueryParam("Set-Cookie", malformedCookie)
.Build();
@ -578,7 +586,7 @@ namespace NzbDrone.Common.Test.Http
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);
@ -602,7 +610,8 @@ namespace NzbDrone.Common.Test.Http
{
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);
requestSet.AllowAutoRedirect = false;
@ -610,7 +619,7 @@ namespace NzbDrone.Common.Test.Http
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);

@ -0,0 +1,30 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Http;
using NzbDrone.Test.Common;
namespace NzbDrone.Common.Test.Http
{
[TestFixture]
public class UserAgentBuilderFixture : TestBase<UserAgentBuilder>
{
[Test]
public void should_get_user_agent_if_os_version_is_null()
{
Mocker.GetMock<IOsInfo>().SetupGet(c => c.Version).Returns((string)null);
Mocker.GetMock<IOsInfo>().SetupGet(c => c.Name).Returns("TestOS");
Subject.GetUserAgent(false).Should().NotBeNullOrWhiteSpace();
}
[Test]
public void should_get_use_os_family_if_name_is_null()
{
Mocker.GetMock<IOsInfo>().SetupGet(c => c.Version).Returns((string)null);
Mocker.GetMock<IOsInfo>().SetupGet(c => c.Name).Returns((string)null);
Subject.GetUserAgent(false).Should().NotBeNullOrWhiteSpace();
}
}
}

@ -92,6 +92,7 @@
<Compile Include="Http\HttpRequestBuilderFixture.cs" />
<Compile Include="Http\HttpRequestFixture.cs" />
<Compile Include="Http\HttpUriFixture.cs" />
<Compile Include="Http\UserAgentBuilderFixture.cs" />
<Compile Include="InstrumentationTests\CleanseLogMessageFixture.cs" />
<Compile Include="LevenshteinDistanceFixture.cs" />
<Compile Include="OsPathFixture.cs" />

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
@ -13,12 +13,15 @@ namespace NzbDrone.Common.Composition
{
private readonly List<Type> _loadedTypes;
public IContainer Container { get; private set; }
protected IContainer Container { get; }
protected ContainerBuilderBase(IStartupContext args, params string[] assemblies)
protected ContainerBuilderBase(IStartupContext args, List<string> assemblies)
{
_loadedTypes = new List<Type>();
assemblies.Add(OsInfo.IsWindows ? "NzbDrone.Windows" : "NzbDrone.Mono");
assemblies.Add("NzbDrone.Common");
foreach (var assembly in assemblies)
{
_loadedTypes.AddRange(Assembly.Load(assembly).GetTypes());

@ -17,6 +17,19 @@ namespace NzbDrone.Common.Disk
{
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 void InheritFolderPermissions(string filename);
public abstract void SetPermissions(string path, string mask, string user, string group);
@ -87,7 +100,7 @@ namespace NzbDrone.Common.Disk
public bool FileExists(string path)
{
Ensure.That(path, () => path).IsValidPath();
return FileExists(path, OsInfo.PathStringComparison);
return FileExists(path, PathStringComparison);
}
public bool FileExists(string path, StringComparison stringComparison)

@ -101,12 +101,12 @@ namespace NzbDrone.Common.EnsureThat
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));
}
}
}

@ -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,50 @@
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 static string PlatformName
{
get
{
if (IsDotNet)
{
return ".NET";
}
return "Mono";
}
}
public abstract Version Version { get; }
}
}

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

@ -1,93 +1,101 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NLog;
namespace NzbDrone.Common.EnvironmentInfo
{
public static class OsInfo
public class OsInfo : IOsInfo
{
public static Os Os { get; }
static OsInfo()
{
var platform = (int)Environment.OSVersion.Platform;
public static bool IsNotWindows => !IsWindows;
public static bool IsLinux => Os == Os.Linux;
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;
IsNotWindows = (platform == 4) || (platform == 6) || (platform == 128);
IsOsx = IsRunningOnMac();
IsLinux = IsNotWindows && !IsOsx;
IsWindows = !IsNotWindows;
FirstDayOfWeek = CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek;
static OsInfo()
{
var platform = Environment.OSVersion.Platform;
if (IsWindows)
{
Os = Os.Windows;
PathStringComparison = StringComparison.OrdinalIgnoreCase;
}
else
switch (platform)
{
Os = IsOsx ? Os.Osx : Os.Linux;
PathStringComparison = StringComparison.Ordinal;
case PlatformID.Win32NT:
{
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 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()
public OsInfo(IEnumerable<IOsVersionAdapter> versionAdapters, Logger logger)
{
var buf = IntPtr.Zero;
OsVersionModel osInfo = null;
try
foreach (var osVersionAdapter in versionAdapters.Where(c => c.Enabled))
{
buf = Marshal.AllocHGlobal(8192);
// This is a hacktastic way of getting sysname from uname ()
if (uname(buf) == 0)
try
{
var os = Marshal.PtrToStringAnsi(buf);
osInfo = osVersionAdapter.Read();
}
catch (Exception e)
{
logger.Error(e, "Couldn't get OS Version info");
}
if (os == "Darwin")
{
return true;
}
if (osInfo != null)
{
break;
}
}
catch
if (osInfo != null)
{
Name = osInfo.Name;
Version = osInfo.Version;
FullName = osInfo.FullName;
}
finally
else
{
if (buf != IntPtr.Zero)
{
Marshal.FreeHGlobal(buf);
}
Name = Os.ToString();
FullName = Name;
}
return false;
}
}
public interface IOsInfo
{
string Version { get; }
string Name { get; }
string FullName { get; }
}
public enum Os
{
Windows,
Linux,
Osx
}
}
}

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

@ -1,4 +1,4 @@
using System;
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
@ -9,11 +9,11 @@ using NzbDrone.Common.Processes;
namespace NzbDrone.Common.EnvironmentInfo
{
public abstract class RuntimeInfoBase : IRuntimeInfo
public class RuntimeInfo : IRuntimeInfo
{
private readonly Logger _logger;
public RuntimeInfoBase(IServiceProvider serviceProvider, Logger logger)
public RuntimeInfo(IServiceProvider serviceProvider, Logger logger)
{
_logger = logger;
@ -28,10 +28,11 @@ namespace NzbDrone.Common.EnvironmentInfo
if (entry != null)
{
ExecutingApplication = entry.Location;
IsWindowsTray = entry.ManifestModule.Name == $"{ProcessProvider.NZB_DRONE_PROCESS_NAME}.exe";
}
}
static RuntimeInfoBase()
static RuntimeInfo()
{
IsProduction = InternalIsProduction();
}
@ -59,31 +60,18 @@ namespace NzbDrone.Common.EnvironmentInfo
public bool IsWindowsService { get; private set; }
public bool IsConsole
{
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 IsExiting { 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; private set; }
public static bool IsProduction { get; }
private static bool InternalIsProduction()
{
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
{
@ -99,21 +87,23 @@ namespace NzbDrone.Common.EnvironmentInfo
}
try
{
var currentAssmeblyLocation = typeof(RuntimeInfoBase).Assembly.Location;
if(currentAssmeblyLocation.ToLower().Contains("_output"))return false;
}
catch
{
try
{
var currentAssmeblyLocation = typeof(RuntimeInfo).Assembly.Location;
if (currentAssmeblyLocation.ToLower().Contains("_output")) return false;
}
catch
{
}
}
string lowerCurrentDir = Directory.GetCurrentDirectory().ToLower();
var lowerCurrentDir = Directory.GetCurrentDirectory().ToLower();
if (lowerCurrentDir.Contains("teamcity")) return false;
if (lowerCurrentDir.Contains("_output")) return false;
return true;
}
public bool IsWindowsTray { get; private set; }
}
}

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

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

@ -21,6 +21,7 @@ namespace NzbDrone.Common.Http.Dispatchers
private static readonly Regex ExpiryDate = new Regex(@"(expires=)([^;]+)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private readonly IHttpProxySettingsProvider _proxySettingsProvider;
private readonly IUserAgentBuilder _userAgentBuilder;
private readonly Logger _logger;
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;
_userAgentBuilder = userAgentBuilder;
_logger = logger;
}

@ -10,21 +10,23 @@ namespace NzbDrone.Common.Http.Dispatchers
{
private readonly ManagedHttpDispatcher _managedDispatcher;
private readonly CurlHttpDispatcher _curlDispatcher;
private readonly IPlatformInfo _platformInfo;
private readonly Logger _logger;
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;
_curlDispatcher = curlDispatcher;
_platformInfo = platformInfo;
_curlTLSFallbackCache = cacheManager.GetCache<bool>(GetType(), "curlTLSFallback");
_logger = logger;
}
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))
{

@ -13,22 +13,35 @@ namespace NzbDrone.Common.Http.Dispatchers
{
private readonly IHttpProxySettingsProvider _proxySettingsProvider;
private readonly ICreateManagedWebProxy _createManagedWebProxy;
private readonly IUserAgentBuilder _userAgentBuilder;
public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, ICreateManagedWebProxy createManagedWebProxy)
public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, ICreateManagedWebProxy createManagedWebProxy, IUserAgentBuilder userAgentBuilder)
{
_proxySettingsProvider = proxySettingsProvider;
_createManagedWebProxy = createManagedWebProxy;
_userAgentBuilder = userAgentBuilder;
}
public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
{
HttpWebResponse httpWebResponse = null;
HttpWebRequest webRequest = null;
try
var webRequest = (HttpWebRequest)WebRequest.Create((Uri)request.Url);
// Deflate is not a standard and could break depending on implementation.
// we should just stick with the more compatible Gzip
//http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net
webRequest.AutomaticDecompression = DecompressionMethods.GZip;
webRequest.Method = request.Method.ToString();
webRequest.UserAgent = _userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent);
webRequest.KeepAlive = request.ConnectionKeepAlive;
webRequest.AllowAutoRedirect = false;
webRequest.CookieContainer = cookies;
if (request.RequestTimeout != TimeSpan.Zero)
{
webRequest = (HttpWebRequest) WebRequest.Create((Uri) request.Url);
if (OsInfo.IsMonoRuntime)
if (PlatformInfo.IsMonoRuntime)
{
// On Mono GZipStream/DeflateStream leaks memory if an exception is thrown, use an intermediate buffer in that case.
webRequest.AutomaticDecompression = DecompressionMethods.None;
@ -98,7 +111,7 @@ namespace NzbDrone.Common.Http.Dispatchers
{
data = responseStream.ToBytes();
if (OsInfo.IsMonoRuntime && httpWebResponse.ContentEncoding == "gzip")
if (PlatformInfo.IsMonoRuntime && httpWebResponse.ContentEncoding == "gzip")
{
using (var compressedStream = new MemoryStream(data))
using (var gzip = new GZipStream(compressedStream, CompressionMode.Decompress))

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@ -31,12 +31,14 @@ namespace NzbDrone.Common.Http
private readonly ICached<CookieContainer> _cookieContainerCache;
private readonly List<IHttpRequestInterceptor> _requestInterceptors;
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();
_rateLimitService = rateLimitService;
_httpDispatcher = httpDispatcher;
_userAgentBuilder = userAgentBuilder;
_logger = logger;
ServicePointManager.DefaultConnectionLimit = 12;
@ -71,7 +73,7 @@ namespace NzbDrone.Common.Http
while (response.HasHttpRedirect);
}
if (response.HasHttpRedirect && !RuntimeInfoBase.IsProduction)
if (response.HasHttpRedirect && !RuntimeInfo.IsProduction)
{
_logger.Error("Server requested a redirect to [{0}] while in developer mode. Update the request URL to avoid this redirect.", response.Headers["Location"]);
}

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

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

@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
@ -35,7 +35,7 @@ namespace NzbDrone.Common.Instrumentation
return;
}
if (OsInfo.IsMonoRuntime)
if (PlatformInfo.IsMono)
{
if (exception is TypeInitializationException && exception.InnerException is DllNotFoundException ||
exception is DllNotFoundException)
@ -51,4 +51,4 @@ namespace NzbDrone.Common.Instrumentation
Logger.Fatal(exception, "EPIC FAIL: " + exception.Message);
}
}
}
}

@ -1,4 +1,4 @@
using System;
using System;
using System.Diagnostics;
using System.IO;
using LogentriesNLog;
@ -48,7 +48,7 @@ namespace NzbDrone.Common.Instrumentation
}
else
{
if (inConsole && (OsInfo.IsNotWindows || RuntimeInfoBase.IsUserInteractive))
if (inConsole && (OsInfo.IsNotWindows || RuntimeInfo.IsUserInteractive))
{
RegisterConsole();
}
@ -152,16 +152,6 @@ namespace NzbDrone.Common.Instrumentation
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)
{
return LogManager.GetLogger(obj.Name.Replace("NzbDrone.", ""));

@ -94,6 +94,10 @@
<Compile Include="Disk\RelativeFileSystemModel.cs" />
<Compile Include="Disk\FileSystemModel.cs" />
<Compile Include="Disk\FileSystemResult.cs" />
<Compile Include="EnvironmentInfo\IOperatingSystemVersionInfo.cs" />
<Compile Include="EnvironmentInfo\IOsVersionAdapter.cs" />
<Compile Include="EnvironmentInfo\IPlatformInfo.cs" />
<Compile Include="EnvironmentInfo\OsVersionModel.cs" />
<Compile Include="Extensions\DictionaryExtensions.cs" />
<Compile Include="Disk\GdiPlusInterop.cs" />
<Compile Include="Disk\OsPath.cs" />
@ -125,13 +129,12 @@
<Compile Include="EnvironmentInfo\BuildInfo.cs" />
<Compile Include="EnvironmentInfo\OsInfo.cs" />
<Compile Include="EnvironmentInfo\IRuntimeInfo.cs" />
<Compile Include="EnvironmentInfo\RuntimeInfoBase.cs" />
<Compile Include="EnvironmentInfo\RuntimeInfo.cs" />
<Compile Include="EnvironmentInfo\StartupContext.cs" />
<Compile Include="Exceptions\NotParentException.cs" />
<Compile Include="Exceptions\NzbDroneException.cs" />
<Compile Include="Exceptron\Configuration\ExceptronConfiguration.cs" />
<Compile Include="Exceptron\ExceptionData.cs" />
<Compile Include="Exceptron\ExceptionExtentions.cs" />
<Compile Include="Exceptron\ExceptionSeverity.cs" />
<Compile Include="Exceptron\ExceptronApiException.cs" />
<Compile Include="Exceptron\ExceptronClient.cs" />
@ -194,7 +197,6 @@
<Compile Include="Extensions\IEnumerableExtensions.cs" />
<Compile Include="Http\UserAgentBuilder.cs" />
<Compile Include="Instrumentation\CleanseLogMessage.cs" />
<Compile Include="Instrumentation\ExceptronTarget.cs" />
<Compile Include="Instrumentation\Extensions\LoggerProgressExtensions.cs" />
<Compile Include="Instrumentation\GlobalExceptionHandlers.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)
{
if (OsInfo.IsMonoRuntime && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
if (PlatformInfo.IsMono && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
{
args = GetMonoArgs(path, args);
path = "mono";
@ -192,7 +192,7 @@ namespace NzbDrone.Common.Processes
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);
path = "mono";

@ -4,7 +4,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>

@ -1,9 +1,9 @@
using System.Collections.Specialized;
using System.Security.AccessControl;
using Moq;
using System;
using NUnit.Framework;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Cloud;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Http;
using NzbDrone.Common.Http.Dispatchers;
using NzbDrone.Common.TPL;
@ -24,12 +24,16 @@ namespace NzbDrone.Core.Test.Framework
{
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<ICreateManagedWebProxy>(new ManagedWebProxyFactory(Mocker.Resolve<CacheManager>()));
Mocker.SetConstant<ManagedHttpDispatcher>(new ManagedHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<ICreateManagedWebProxy>()));
Mocker.SetConstant<CurlHttpDispatcher>(new CurlHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<NLog.Logger>()));
Mocker.SetConstant<ManagedHttpDispatcher>(new ManagedHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<ICreateManagedWebProxy>(), Mocker.Resolve<UserAgentBuilder>()));
Mocker.SetConstant<CurlHttpDispatcher>(new CurlHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<UserAgentBuilder>(), Mocker.Resolve<NLog.Logger>()));
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<IRadarrCloudRequestBuilder>(new RadarrCloudRequestBuilder());
}

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

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

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

@ -5,7 +5,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="FluentMigrator" publicKeyToken="aacfc7de5acabf05" culture="neutral"/>

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

@ -1,7 +1,6 @@
using System;
using System;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
@ -9,50 +8,43 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
public class MonoVersionCheck : HealthCheckBase
{
private readonly IRuntimeInfo _runtimeInfo;
private readonly IPlatformInfo _platformInfo;
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;
}
public override HealthCheck Check()
{
if (OsInfo.IsWindows)
if (!PlatformInfo.IsMono)
{
return new HealthCheck(GetType());
}
var versionString = _runtimeInfo.RuntimeVersion;
var versionMatch = VersionRegex.Match(versionString);
var monoVersion = _platformInfo.Version;
if (versionMatch.Success)
if (monoVersion == new Version("3.4.0") && HasMonoBug18599())
{
var version = new Version(versionMatch.Groups["version"].Value);
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());
}
_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");
}
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;
@ -70,7 +62,8 @@ namespace NzbDrone.Core.HealthCheck.Checks
return false;
}
var fieldInfo = numberFormatterType.GetField("userFormatProvider", BindingFlags.Static | BindingFlags.NonPublic);
var fieldInfo = numberFormatterType.GetField("userFormatProvider",
BindingFlags.Static | BindingFlags.NonPublic);
if (fieldInfo == null)
{

@ -1,18 +1,14 @@
using NzbDrone.Common.Messaging;
using NzbDrone.Common.Messaging;
namespace NzbDrone.Core.Lifecycle
{
public class ApplicationShutdownRequested : IEvent
{
public bool Restarting { get; set; }
public bool Restarting { get; }
public ApplicationShutdownRequested()
{
}
public ApplicationShutdownRequested(bool restarting)
public ApplicationShutdownRequested(bool restarting = false)
{
Restarting = restarting;
}
}
}
}

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

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

@ -1,4 +1,3 @@
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration;
@ -14,16 +13,11 @@ namespace NzbDrone.Core.Update
private readonly IUpdatePackageProvider _updatePackageProvider;
private readonly IConfigFileProvider _configFileProvider;
private readonly Logger _logger;
public CheckUpdateService(IUpdatePackageProvider updatePackageProvider,
IConfigFileProvider configFileProvider,
Logger logger)
IConfigFileProvider configFileProvider)
{
_updatePackageProvider = updatePackageProvider;
_configFileProvider = configFileProvider;
_logger = logger;
}
public UpdatePackage AvailableUpdate()
@ -31,4 +25,4 @@ namespace NzbDrone.Core.Update
return _updatePackageProvider.GetLatestUpdate(_configFileProvider.Branch, BuildInfo.Version);
}
}
}
}

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using NzbDrone.Common.Cloud;
using NzbDrone.Common.EnvironmentInfo;
@ -15,11 +15,13 @@ namespace NzbDrone.Core.Update
public class UpdatePackageProvider : IUpdatePackageProvider
{
private readonly IHttpClient _httpClient;
private readonly IPlatformInfo _platformInfo;
private readonly IHttpRequestBuilderFactory _requestBuilder;
public UpdatePackageProvider(IHttpClient httpClient, IRadarrCloudRequestBuilder requestBuilder)
public UpdatePackageProvider(IHttpClient httpClient, IRadarrCloudRequestBuilder requestBuilder, IPlatformInfo platformInfo)
{
_httpClient = httpClient;
_platformInfo = platformInfo;
_requestBuilder = requestBuilder.Services;
}
@ -29,6 +31,7 @@ namespace NzbDrone.Core.Update
.Resource("/update/{branch}")
.AddQueryParam("version", currentVersion)
.AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant())
.AddQueryParam("runtimeVer", _platformInfo.Version)
.SetSegment("branch", branch)
.Build();
@ -45,6 +48,7 @@ namespace NzbDrone.Core.Update
.Resource("/update/{branch}/changes")
.AddQueryParam("version", currentVersion)
.AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant())
.AddQueryParam("runtimeVer", _platformInfo.Version)
.SetSegment("branch", branch)
.Build();
@ -53,4 +57,4 @@ namespace NzbDrone.Core.Update
return updates.Resource;
}
}
}
}

@ -20,6 +20,7 @@ namespace Radarr.Host.AccessControl
private readonly INetshProvider _netshProvider;
private readonly IConfigFileProvider _configFileProvider;
private readonly IRuntimeInfo _runtimeInfo;
private readonly IOsInfo _osInfo;
private readonly Logger _logger;
public List<string> Urls
@ -30,7 +31,7 @@ namespace Radarr.Host.AccessControl
}
}
private List<UrlAcl> InternalUrls { get; set; }
private List<UrlAcl> InternalUrls { get; }
private List<UrlAcl> RegisteredUrls { get; set; }
private static readonly Regex UrlAclRegex = new Regex(@"(?<scheme>https?)\:\/\/(?<address>.+?)\:(?<port>\d+)/(?<urlbase>.+)?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
@ -38,19 +39,26 @@ namespace Radarr.Host.AccessControl
public UrlAclAdapter(INetshProvider netshProvider,
IConfigFileProvider configFileProvider,
IRuntimeInfo runtimeInfo,
IOsInfo osInfo,
Logger logger)
{
_netshProvider = netshProvider;
_configFileProvider = configFileProvider;
_runtimeInfo = runtimeInfo;
_osInfo = osInfo;
_logger = logger;
InternalUrls = new List<UrlAcl>();
RegisteredUrls = GetRegisteredUrls();
RegisteredUrls = new List<UrlAcl>();
}
public void ConfigureUrls()
{
if (RegisteredUrls.Empty())
{
GetRegisteredUrls();
}
var localHostHttpUrls = BuildUrlAcls("http", "localhost", _configFileProvider.Port);
var interfaceHttpUrls = BuildUrlAcls("http", _configFileProvider.BindAddress, _configFileProvider.Port);
@ -105,7 +113,8 @@ namespace Radarr.Host.AccessControl
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)
{
@ -124,19 +133,24 @@ namespace Radarr.Host.AccessControl
c.UrlBase == urlAcl.UrlBase);
}
private List<UrlAcl> GetRegisteredUrls()
private void GetRegisteredUrls()
{
if (OsInfo.IsNotWindows)
{
return new List<UrlAcl>();
return;
}
if (RegisteredUrls.Any())
{
return;
}
var arguments = string.Format("http show urlacl");
var output = _netshProvider.Run(arguments);
if (output == null || !output.Standard.Any()) return new List<UrlAcl>();
if (output == null || !output.Standard.Any()) return;
return output.Standard.Select(line =>
RegisteredUrls = output.Standard.Select(line =>
{
var match = UrlAclRegex.Match(line.Content);

@ -58,7 +58,7 @@ namespace Radarr.Host
//_cancelHandler = new CancelHandler();
}
_runtimeInfo.IsRunning = true;
_runtimeInfo.IsExiting = false;
DbFactory.RegisterDatabase(_container);
_hostController.StartServer();
@ -87,7 +87,7 @@ namespace Radarr.Host
_logger.Info("Attempting to stop application.");
_hostController.StopServer();
_logger.Info("Application has finished stop routine.");
_runtimeInfo.IsRunning = false;
_runtimeInfo.IsExiting = true;
}
public void Handle(ApplicationShutdownRequested message)

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Nancy.Bootstrapper;
using NzbDrone.Api;
using NzbDrone.Common.Composition;
@ -15,26 +15,15 @@ namespace Radarr.Host
var assemblies = new List<string>
{
"Radarr.Host",
"NzbDrone.Common",
"NzbDrone.Core",
"NzbDrone.Api",
"NzbDrone.SignalR"
};
if (OsInfo.IsWindows)
{
assemblies.Add("NzbDrone.Windows");
}
else
{
assemblies.Add("NzbDrone.Mono");
}
return new MainAppContainerBuilder(args, assemblies.ToArray()).Container;
return new MainAppContainerBuilder(args, assemblies).Container;
}
private MainAppContainerBuilder(StartupContext args, string[] assemblies)
private MainAppContainerBuilder(StartupContext args, List<string> assemblies)
: base(args, assemblies)
{
AutoRegisterImplementations<NzbDronePersistentConnection>();
@ -43,4 +32,4 @@ namespace Radarr.Host
Container.Register<IHttpDispatcher, FallbackHttpDispatcher>();
}
}
}
}

@ -1,5 +1,6 @@
using NLog;
using NLog;
using NzbDrone.Common;
using NzbDrone.Common.EnvironmentInfo;
namespace Radarr.Host
{
@ -8,14 +9,16 @@ namespace Radarr.Host
private readonly INzbDroneServiceFactory _nzbDroneServiceFactory;
private readonly IServiceProvider _serviceProvider;
private readonly IConsoleService _consoleService;
private readonly IRuntimeInfo _runtimeInfo;
private readonly Logger _logger;
public Router(INzbDroneServiceFactory nzbDroneServiceFactory, IServiceProvider serviceProvider,
IConsoleService consoleService, Logger logger)
IConsoleService consoleService, IRuntimeInfo runtimeInfo, Logger logger)
{
_nzbDroneServiceFactory = nzbDroneServiceFactory;
_serviceProvider = serviceProvider;
_consoleService = consoleService;
_runtimeInfo = runtimeInfo;
_logger = logger;
}
@ -34,7 +37,7 @@ namespace Radarr.Host
case ApplicationModes.Interactive:
{
_logger.Debug("Console selected");
_logger.Debug(_runtimeInfo.IsWindowsTray ? "Tray selected" : "Console selected");
_nzbDroneServiceFactory.Start();
break;
}

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

@ -14,7 +14,7 @@
<probing privatePath="libs" />
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="NLog" publicKeyToken="5120e14c03d0593c" culture="neutral" />

@ -4,7 +4,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="FluentMigrator" publicKeyToken="aacfc7de5acabf05" culture="neutral" />

@ -0,0 +1,23 @@
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().BeOneOf(4, 5);
if (Subject.Version.Major == 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"

@ -82,10 +82,26 @@
<ItemGroup>
<Compile Include="DiskProviderTests\DiskProviderFixture.cs" />
<Compile Include="DiskProviderTests\FreeSpaceFixture.cs" />
<Compile Include="EnvironmentInfo\MonoPlatformInfoFixture.cs" />
<Compile Include="EnvironmentInfo\ReleaseFileVersionAdapterFixture.cs" />
<Compile Include="EnvironmentInfo\VersionAdapters\MacOsVersionAdapterFixture.cs" />
<Compile Include="EnvironmentInfo\VersionAdapters\ReleaseFileVersionAdapterFixture.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="Files\linux\lsb-release">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Files\linux\os-release">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Files\macOS\SystemVersion.plist">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Files\synology\VERSION">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>

@ -8,7 +8,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="FluentMigrator" publicKeyToken="aacfc7de5acabf05" culture="neutral" />

@ -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");
}
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].Trim('"');
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;
}
}

@ -79,9 +79,13 @@
<Compile Include="Disk\DiskProvider.cs" />
<Compile Include="Disk\FindDriveType.cs" />
<Compile Include="Disk\LinuxPermissionsException.cs" />
<Compile Include="EnvironmentInfo\MonoRuntimeProvider.cs" />
<Compile Include="EnvironmentInfo\MonoPlatformInfo.cs" />
<Compile Include="Disk\ProcMount.cs" />
<Compile Include="Disk\ProcMountProvider.cs" />
<Compile Include="EnvironmentInfo\VersionAdapters\IssueFileVersionAdapter.cs" />
<Compile Include="EnvironmentInfo\VersionAdapters\MacOsVersionAdapter.cs" />
<Compile Include="EnvironmentInfo\VersionAdapters\ReleaseFileVersionAdapter.cs" />
<Compile Include="EnvironmentInfo\VersionAdapters\SynologyVersionAdapter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Disk\SymbolicLinkResolver.cs" />
</ItemGroup>
@ -92,6 +96,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

@ -4,7 +4,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="FluentMigrator" publicKeyToken="aacfc7de5acabf05" culture="neutral"/>

@ -1,5 +1,3 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
@ -151,7 +149,7 @@ namespace NzbDrone.Test.Common.AutoMoq
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
@ -190,4 +188,4 @@ namespace NzbDrone.Test.Common.AutoMoq
#endregion
}
}
}

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

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using NzbDrone.Common.Composition;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Http.Dispatchers;
@ -7,7 +7,7 @@ namespace NzbDrone.Update
{
public class UpdateContainerBuilder : ContainerBuilderBase
{
private UpdateContainerBuilder(IStartupContext startupContext, string[] assemblies)
private UpdateContainerBuilder(IStartupContext startupContext, List<string> assemblies)
: base(startupContext, assemblies)
{
Container.Register<IHttpDispatcher, FallbackHttpDispatcher>();
@ -17,22 +17,10 @@ namespace NzbDrone.Update
{
var assemblies = new List<string>
{
"Radarr.Update",
"NzbDrone.Common"
"Radarr.Update"
};
if (OsInfo.IsWindows)
{
assemblies.Add("NzbDrone.Windows");
}
else
{
assemblies.Add("NzbDrone.Mono");
}
return new UpdateContainerBuilder(startupContext, assemblies.ToArray()).Container;
return new UpdateContainerBuilder(startupContext, assemblies).Container;
}
}
}

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

@ -11,7 +11,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0"/>
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>

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

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

@ -8,7 +8,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="FluentMigrator" publicKeyToken="aacfc7de5acabf05" culture="neutral" />

@ -0,0 +1,70 @@
using System;
using Microsoft.Win32;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Windows.EnvironmentInfo
{
public class DotNetPlatformInfo : PlatformInfo
{
private readonly Logger _logger;
public DotNetPlatformInfo(Logger logger)
{
_logger = logger;
var version = GetFrameworkVersion();
Environment.SetEnvironmentVariable("RUNTIME_VERSION", version.ToString());
Version = version;
}
public override Version Version { get; }
private Version GetFrameworkVersion()
{
try
{
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);
}
}
}
catch (Exception e)
{
_logger.Error(e, "Couldnt get .NET framework version");
}
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,49 @@
using System;
using Microsoft.Win32;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Windows.EnvironmentInfo
{
public class WindowsVersionInfo : IOsVersionAdapter
{
private readonly Logger _logger;
public bool Enabled => OsInfo.IsWindows;
public WindowsVersionInfo(Logger logger)
{
_logger = logger;
}
public OsVersionModel Read()
{
var windowsServer = IsServer();
var osName = windowsServer ? "Windows Server" : "Windows";
return new OsVersionModel(osName, Environment.OSVersion.Version.ToString(), Environment.OSVersion.VersionString);
}
private bool IsServer()
{
try
{
const string subkey = @"Software\Microsoft\Windows NT\CurrentVersion";
var openSubKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey);
if (openSubKey != null)
{
var productName = openSubKey.GetValue("ProductName").ToString();
if (productName.ToLower().Contains("server"))
{
return true;
}
}
}
catch (Exception e)
{
_logger.Error(e, "Couldn't detect if running Windows Server");
}
return false;
}
}
}

@ -73,7 +73,8 @@
</ItemGroup>
<ItemGroup>
<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" />
</ItemGroup>
<ItemGroup>
@ -83,6 +84,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

@ -0,0 +1,4 @@
[ViewState]
Mode=
Vid=
FolderType=Documents
Loading…
Cancel
Save