Compare commits

..

2 Commits

Author SHA1 Message Date
bakerboy448
ab4d80faa6 align mock with upstream 2025-10-30 12:06:17 -05:00
bakerboy448
a2afcff6df Fallback to host sqlite3 on FreeBSD and Linux
also align with upstream
2025-10-30 11:13:40 -05:00
12 changed files with 47 additions and 112 deletions

View File

@@ -1,18 +1,14 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, { Component } from 'react'; import React, { Component } from 'react';
import Label from 'Components/Label';
import Button from 'Components/Link/Button'; import Button from 'Components/Link/Button';
import Link from 'Components/Link/Link'; import Link from 'Components/Link/Link';
import Menu from 'Components/Menu/Menu'; import Menu from 'Components/Menu/Menu';
import MenuContent from 'Components/Menu/MenuContent'; import MenuContent from 'Components/Menu/MenuContent';
import { kinds, sizes } from 'Helpers/Props'; import { sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
import AddApplicationPresetMenuItem from './AddApplicationPresetMenuItem'; import AddApplicationPresetMenuItem from './AddApplicationPresetMenuItem';
import styles from './AddApplicationItem.css'; import styles from './AddApplicationItem.css';
const DEPRECATED_APPLICATIONS = ['Readarr'];
const OBSOLETE_APPLICATIONS = [];
class AddApplicationItem extends Component { class AddApplicationItem extends Component {
// //
@@ -40,8 +36,6 @@ class AddApplicationItem extends Component {
} = this.props; } = this.props;
const hasPresets = !!presets && !!presets.length; const hasPresets = !!presets && !!presets.length;
const isDeprecated = DEPRECATED_APPLICATIONS.includes(implementation);
const isObsolete = OBSOLETE_APPLICATIONS.includes(implementation);
return ( return (
<div <div
@@ -55,24 +49,6 @@ class AddApplicationItem extends Component {
<div className={styles.overlay}> <div className={styles.overlay}>
<div className={styles.name}> <div className={styles.name}>
{implementationName} {implementationName}
{
isDeprecated &&
<Label
kind={kinds.WARNING}
title={translate('DeprecatedApplicationMessage', { applicationName: implementationName })}
>
{translate('Deprecated')}
</Label>
}
{
isObsolete &&
<Label
kind={kinds.DANGER}
title={translate('ObsoleteApplicationMessage', { applicationName: implementationName })}
>
{translate('Obsolete')}
</Label>
}
</div> </div>
<div className={styles.actions}> <div className={styles.actions}>

View File

@@ -10,9 +10,6 @@ import translate from 'Utilities/String/translate';
import EditApplicationModalConnector from './EditApplicationModalConnector'; import EditApplicationModalConnector from './EditApplicationModalConnector';
import styles from './Application.css'; import styles from './Application.css';
const DEPRECATED_APPLICATIONS = ['Readarr'];
const OBSOLETE_APPLICATIONS = [];
class Application extends Component { class Application extends Component {
// //
@@ -64,13 +61,10 @@ class Application extends Component {
syncLevel, syncLevel,
fields, fields,
tags, tags,
tagList, tagList
implementation
} = this.props; } = this.props;
const applicationUrl = fields.find((field) => field.name === 'baseUrl')?.value; const applicationUrl = fields.find((field) => field.name === 'baseUrl')?.value;
const isDeprecated = DEPRECATED_APPLICATIONS.includes(implementation);
const isObsolete = OBSOLETE_APPLICATIONS.includes(implementation);
return ( return (
<Card <Card
@@ -94,26 +88,6 @@ class Application extends Component {
} }
</div> </div>
{
isDeprecated &&
<Label
kind={kinds.WARNING}
title={translate('DeprecatedApplicationMessage', { applicationName: implementation })}
>
{translate('Deprecated')}
</Label>
}
{
isObsolete &&
<Label
kind={kinds.DANGER}
title={translate('ObsoleteApplicationMessage', { applicationName: implementation })}
>
{translate('Obsolete')}
</Label>
}
{ {
syncLevel === 'addOnly' && syncLevel === 'addOnly' &&
<Label kind={kinds.WARNING}> <Label kind={kinds.WARNING}>
@@ -167,7 +141,6 @@ class Application extends Component {
Application.propTypes = { Application.propTypes = {
id: PropTypes.number.isRequired, id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
implementation: PropTypes.string.isRequired,
enable: PropTypes.bool.isRequired, enable: PropTypes.bool.isRequired,
syncLevel: PropTypes.string.isRequired, syncLevel: PropTypes.string.isRequired,
fields: PropTypes.arrayOf(PropTypes.object).isRequired, fields: PropTypes.arrayOf(PropTypes.object).isRequired,

View File

@@ -39,9 +39,6 @@ const syncLevelOptions = [
} }
]; ];
const DEPRECATED_APPLICATIONS = ['Readarr'];
const OBSOLETE_APPLICATIONS = [];
function EditApplicationModalContent(props) { function EditApplicationModalContent(props) {
const { const {
advancedSettings, advancedSettings,
@@ -63,7 +60,6 @@ function EditApplicationModalContent(props) {
const { const {
id, id,
implementation,
implementationName, implementationName,
name, name,
syncLevel, syncLevel,
@@ -72,9 +68,6 @@ function EditApplicationModalContent(props) {
message message
} = item; } = item;
const isDeprecated = DEPRECATED_APPLICATIONS.includes(implementation);
const isObsolete = OBSOLETE_APPLICATIONS.includes(implementation);
return ( return (
<ModalContent onModalClose={onModalClose}> <ModalContent onModalClose={onModalClose}>
<ModalHeader> <ModalHeader>
@@ -97,28 +90,6 @@ function EditApplicationModalContent(props) {
{ {
!isFetching && !error && !isFetching && !error &&
<Form {...otherProps}> <Form {...otherProps}>
{
isDeprecated &&
<Alert
className={styles.message}
kind={kinds.WARNING}
>
<div>{translate('DeprecatedApplicationTitle', { applicationName: implementationName })}</div>
<div>{translate('DeprecatedApplicationMessage', { applicationName: implementationName })}</div>
</Alert>
}
{
isObsolete &&
<Alert
className={styles.message}
kind={kinds.DANGER}
>
<div>{translate('ObsoleteApplicationTitle', { applicationName: implementationName })}</div>
<div>{translate('ObsoleteApplicationMessage', { applicationName: implementationName })}</div>
</Alert>
}
{ {
!!message && !!message &&
<Alert <Alert

View File

@@ -14,7 +14,6 @@ namespace NzbDrone.Common.Composition
static AssemblyLoader() static AssemblyLoader()
{ {
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ContainerResolveEventHandler); AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ContainerResolveEventHandler);
RegisterSQLiteResolver();
} }
public static IList<Assembly> Load(IList<string> assemblyNames) public static IList<Assembly> Load(IList<string> assemblyNames)
@@ -23,6 +22,10 @@ namespace NzbDrone.Common.Composition
toLoad.Add("Prowlarr.Common"); toLoad.Add("Prowlarr.Common");
toLoad.Add(OsInfo.IsWindows ? "Prowlarr.Windows" : "Prowlarr.Mono"); toLoad.Add(OsInfo.IsWindows ? "Prowlarr.Windows" : "Prowlarr.Mono");
var toRegisterResolver = new List<string> { "System.Data.SQLite" };
toRegisterResolver.AddRange(assemblyNames.Intersect(new[] { "Prowlarr.Core" }));
RegisterNativeResolver(toRegisterResolver);
var startupPath = AppDomain.CurrentDomain.BaseDirectory; var startupPath = AppDomain.CurrentDomain.BaseDirectory;
return toLoad return toLoad
@@ -43,27 +46,46 @@ namespace NzbDrone.Common.Composition
return AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath); return AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
} }
public static void RegisterSQLiteResolver() public static void RegisterNativeResolver(IEnumerable<string> assemblyNames)
{ {
// This ensures we look for sqlite3 using libsqlite3.so.0 on Linux and not libsqlite3.so which foreach (var name in assemblyNames)
// is less likely to exist. {
var sqliteAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath( // This ensures we look for sqlite3 using libsqlite3.so.0 on Linux and not libsqlite3.so which
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "System.Data.SQLite.dll")); // is less likely to exist.
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{name}.dll"));
try try
{ {
NativeLibrary.SetDllImportResolver(sqliteAssembly, LoadSqliteNativeLib); NativeLibrary.SetDllImportResolver(assembly, LoadNativeLib);
} }
catch (InvalidOperationException) catch (InvalidOperationException)
{ {
// This can only be set once per assembly // This can only be set once per assembly
// Catch required for NzbDrone.Host tests // Catch required for NzbDrone.Host tests
}
} }
} }
private static IntPtr LoadSqliteNativeLib(string libraryName, Assembly assembly, DllImportSearchPath? dllImportSearchPath) private static IntPtr LoadNativeLib(string libraryName, Assembly assembly, DllImportSearchPath? dllImportSearchPath)
{ {
var mappedName = OsInfo.IsLinux && libraryName == "sqlite3" ? "libsqlite3.so.0" : libraryName; ArgumentException.ThrowIfNullOrWhiteSpace(libraryName);
var mappedName = libraryName;
if (libraryName is "sqlite3" or "e_sqlite3")
{
if (OsInfo.IsLinux)
{
if (NativeLibrary.TryLoad(libraryName, assembly, dllImportSearchPath, out var libHandle))
{
return libHandle;
}
mappedName = "libsqlite3.so.0";
}
}
return NativeLibrary.Load(mappedName, assembly, dllImportSearchPath); return NativeLibrary.Load(mappedName, assembly, dllImportSearchPath);
} }
} }

View File

@@ -159,7 +159,7 @@ namespace NzbDrone.Core.Applications.Lidarr
case HttpStatusCode.BadRequest: case HttpStatusCode.BadRequest:
if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase)) if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase))
{ {
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: https://wiki.servarr.com/prowlarr/faq#prowlarr-will-not-sync-x-indexer-to-app"); _logger.Warn(ex, "No Results in configured categories. See FAQ Entry: Prowlarr will not sync X Indexer to App");
break; break;
} }

View File

@@ -172,7 +172,7 @@ namespace NzbDrone.Core.Applications.Radarr
case HttpStatusCode.BadRequest: case HttpStatusCode.BadRequest:
if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase)) if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase))
{ {
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: https://wiki.servarr.com/prowlarr/faq#prowlarr-will-not-sync-x-indexer-to-app"); _logger.Warn(ex, "No Results in configured categories. See FAQ Entry: Prowlarr will not sync X Indexer to App");
break; break;
} }

View File

@@ -14,7 +14,6 @@ using NzbDrone.Core.Indexers;
namespace NzbDrone.Core.Applications.Readarr namespace NzbDrone.Core.Applications.Readarr
{ {
[Obsolete("Readarr is deprecated and will be removed in a future version")]
public class Readarr : ApplicationBase<ReadarrSettings> public class Readarr : ApplicationBase<ReadarrSettings>
{ {
public override string Name => "Readarr"; public override string Name => "Readarr";

View File

@@ -146,7 +146,7 @@ namespace NzbDrone.Core.Applications.Readarr
case HttpStatusCode.BadRequest: case HttpStatusCode.BadRequest:
if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase)) if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase))
{ {
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: https://wiki.servarr.com/prowlarr/faq#prowlarr-will-not-sync-x-indexer-to-app"); _logger.Warn(ex, "No Results in configured categories. See FAQ Entry: Prowlarr will not sync X Indexer to App");
break; break;
} }

View File

@@ -159,7 +159,7 @@ namespace NzbDrone.Core.Applications.Sonarr
case HttpStatusCode.BadRequest: case HttpStatusCode.BadRequest:
if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase)) if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase))
{ {
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: https://wiki.servarr.com/prowlarr/faq#prowlarr-will-not-sync-x-indexer-to-app"); _logger.Warn(ex, "No Results in configured categories. See FAQ Entry: Prowlarr will not sync X Indexer to App");
break; break;
} }

View File

@@ -144,7 +144,7 @@ namespace NzbDrone.Core.Applications.Whisparr
case HttpStatusCode.BadRequest: case HttpStatusCode.BadRequest:
if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase)) if (ex.Response.Content.Contains("Query successful, but no results in the configured categories were returned from your indexer.", StringComparison.InvariantCultureIgnoreCase))
{ {
_logger.Warn(ex, "No Results in configured categories. See FAQ Entry: https://wiki.servarr.com/prowlarr/faq#prowlarr-will-not-sync-x-indexer-to-app"); _logger.Warn(ex, "No Results in configured categories. See FAQ Entry: Prowlarr will not sync X Indexer to App");
break; break;
} }

View File

@@ -538,12 +538,6 @@
"NotificationsTelegramSettingsIncludeAppName": "Include {appName} in Title", "NotificationsTelegramSettingsIncludeAppName": "Include {appName} in Title",
"NotificationsTelegramSettingsIncludeAppNameHelpText": "Optionally prefix message title with {appName} to differentiate notifications from different applications", "NotificationsTelegramSettingsIncludeAppNameHelpText": "Optionally prefix message title with {appName} to differentiate notifications from different applications",
"OAuthPopupMessage": "Pop-ups are being blocked by your browser", "OAuthPopupMessage": "Pop-ups are being blocked by your browser",
"Obsolete": "Obsolete",
"ObsoleteApplicationMessage": "{applicationName} is obsolete and has been removed",
"ObsoleteApplicationTitle": "{applicationName} is Obsolete",
"Deprecated": "Deprecated",
"DeprecatedApplicationMessage": "{applicationName} is deprecated and will be removed in a future version",
"DeprecatedApplicationTitle": "{applicationName} is Deprecated",
"Ok": "Ok", "Ok": "Ok",
"OnApplicationUpdate": "On Application Update", "OnApplicationUpdate": "On Application Update",
"OnApplicationUpdateHelpText": "On Application Update", "OnApplicationUpdateHelpText": "On Application Update",

View File

@@ -51,7 +51,7 @@ namespace NzbDrone.Test.Common.AutoMoq
if (behavior != MockBehavior.Default && mock.Behavior == MockBehavior.Default) if (behavior != MockBehavior.Default && mock.Behavior == MockBehavior.Default)
{ {
throw new InvalidOperationException("Unable to change be behaviour of a an existing mock."); throw new InvalidOperationException("Unable to change be behaviour of an existing mock.");
} }
return mock; return mock;
@@ -139,7 +139,7 @@ namespace NzbDrone.Test.Common.AutoMoq
LoadPlatformLibrary(); LoadPlatformLibrary();
AssemblyLoader.RegisterSQLiteResolver(); AssemblyLoader.RegisterNativeResolver(new[] { "System.Data.SQLite", "Prowlarr.Core" });
} }
private Mock<T> TheRegisteredMockForThisType<T>(Type type) private Mock<T> TheRegisteredMockForThisType<T>(Type type)