Rewrite rules for determining app paths and use XDG_CONFIG_HOME for configDir (#781)
Re-write rules for determining dataDir, configDir and logDir. Generally, arguments from command line take precedence, then JELLYFIN env vars, before using XDG names. Co-Authored-By: ploughpuff <33969763+ploughpuff@users.noreply.github.com>
This commit is contained in:
parent
eb4b705167
commit
a2dd2ddd55
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
|
|
||||||
|
@ -14,50 +15,44 @@ namespace Emby.Server.Implementations.AppBase
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected BaseApplicationPaths(
|
protected BaseApplicationPaths(
|
||||||
string programDataPath,
|
string programDataPath,
|
||||||
string appFolderPath,
|
string logDirectoryPath,
|
||||||
string logDirectoryPath = null,
|
string configurationDirectoryPath,
|
||||||
string configurationDirectoryPath = null,
|
string cacheDirectoryPath)
|
||||||
string cacheDirectoryPath = null)
|
|
||||||
{
|
{
|
||||||
ProgramDataPath = programDataPath;
|
ProgramDataPath = programDataPath;
|
||||||
ProgramSystemPath = appFolderPath;
|
|
||||||
LogDirectoryPath = logDirectoryPath;
|
LogDirectoryPath = logDirectoryPath;
|
||||||
ConfigurationDirectoryPath = configurationDirectoryPath;
|
ConfigurationDirectoryPath = configurationDirectoryPath;
|
||||||
CachePath = cacheDirectoryPath;
|
CachePath = cacheDirectoryPath;
|
||||||
|
|
||||||
|
DataPath = Path.Combine(ProgramDataPath, "data");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to the program data folder
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The program data path.</value>
|
||||||
public string ProgramDataPath { get; private set; }
|
public string ProgramDataPath { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the path to the system folder
|
/// Gets the path to the system folder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ProgramSystemPath { get; private set; }
|
public string ProgramSystemPath { get; } = AppContext.BaseDirectory;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The _data directory
|
|
||||||
/// </summary>
|
|
||||||
private string _dataDirectory;
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the folder path to the data directory
|
/// Gets the folder path to the data directory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The data directory.</value>
|
/// <value>The data directory.</value>
|
||||||
|
private string _dataPath;
|
||||||
public string DataPath
|
public string DataPath
|
||||||
{
|
{
|
||||||
get
|
get => _dataPath;
|
||||||
{
|
private set => _dataPath = Directory.CreateDirectory(value).FullName;
|
||||||
if (_dataDirectory == null)
|
|
||||||
{
|
|
||||||
_dataDirectory = Path.Combine(ProgramDataPath, "data");
|
|
||||||
|
|
||||||
Directory.CreateDirectory(_dataDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _dataDirectory;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private const string _virtualDataPath = "%AppDataPath%";
|
/// <summary>
|
||||||
public string VirtualDataPath => _virtualDataPath;
|
/// Gets the magic strings used for virtual path manipulation.
|
||||||
|
/// </summary>
|
||||||
|
public string VirtualDataPath { get; } = "%AppDataPath%";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the image cache path.
|
/// Gets the image cache path.
|
||||||
|
@ -83,55 +78,17 @@ namespace Emby.Server.Implementations.AppBase
|
||||||
/// <value>The plugin configurations path.</value>
|
/// <value>The plugin configurations path.</value>
|
||||||
public string TempUpdatePath => Path.Combine(ProgramDataPath, "updates");
|
public string TempUpdatePath => Path.Combine(ProgramDataPath, "updates");
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The _log directory
|
|
||||||
/// </summary>
|
|
||||||
private string _logDirectoryPath;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the path to the log directory
|
/// Gets the path to the log directory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The log directory path.</value>
|
/// <value>The log directory path.</value>
|
||||||
public string LogDirectoryPath
|
public string LogDirectoryPath { get; private set; }
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(_logDirectoryPath))
|
|
||||||
{
|
|
||||||
_logDirectoryPath = Path.Combine(ProgramDataPath, "logs");
|
|
||||||
|
|
||||||
Directory.CreateDirectory(_logDirectoryPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _logDirectoryPath;
|
|
||||||
}
|
|
||||||
set => _logDirectoryPath = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The _config directory
|
|
||||||
/// </summary>
|
|
||||||
private string _configurationDirectoryPath;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the path to the application configuration root directory
|
/// Gets the path to the application configuration root directory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The configuration directory path.</value>
|
/// <value>The configuration directory path.</value>
|
||||||
public string ConfigurationDirectoryPath
|
public string ConfigurationDirectoryPath { get; private set; }
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(_configurationDirectoryPath))
|
|
||||||
{
|
|
||||||
_configurationDirectoryPath = Path.Combine(ProgramDataPath, "config");
|
|
||||||
|
|
||||||
Directory.CreateDirectory(_configurationDirectoryPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _configurationDirectoryPath;
|
|
||||||
}
|
|
||||||
set => _configurationDirectoryPath = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the path to the system configuration file
|
/// Gets the path to the system configuration file
|
||||||
|
@ -139,29 +96,11 @@ namespace Emby.Server.Implementations.AppBase
|
||||||
/// <value>The system configuration file path.</value>
|
/// <value>The system configuration file path.</value>
|
||||||
public string SystemConfigurationFilePath => Path.Combine(ConfigurationDirectoryPath, "system.xml");
|
public string SystemConfigurationFilePath => Path.Combine(ConfigurationDirectoryPath, "system.xml");
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The _cache directory
|
|
||||||
/// </summary>
|
|
||||||
private string _cachePath;
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the folder path to the cache directory
|
/// Gets the folder path to the cache directory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The cache directory.</value>
|
/// <value>The cache directory.</value>
|
||||||
public string CachePath
|
public string CachePath { get; set; }
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(_cachePath))
|
|
||||||
{
|
|
||||||
_cachePath = Path.Combine(ProgramDataPath, "cache");
|
|
||||||
|
|
||||||
Directory.CreateDirectory(_cachePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _cachePath;
|
|
||||||
}
|
|
||||||
set => _cachePath = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the folder path to the temp directory within the cache folder
|
/// Gets the folder path to the temp directory within the cache folder
|
||||||
|
|
|
@ -15,21 +15,17 @@ namespace Emby.Server.Implementations
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ServerApplicationPaths(
|
public ServerApplicationPaths(
|
||||||
string programDataPath,
|
string programDataPath,
|
||||||
string appFolderPath,
|
string logDirectoryPath,
|
||||||
string applicationResourcesPath,
|
string configurationDirectoryPath,
|
||||||
string logDirectoryPath = null,
|
string cacheDirectoryPath)
|
||||||
string configurationDirectoryPath = null,
|
|
||||||
string cacheDirectoryPath = null)
|
|
||||||
: base(programDataPath,
|
: base(programDataPath,
|
||||||
appFolderPath,
|
|
||||||
logDirectoryPath,
|
logDirectoryPath,
|
||||||
configurationDirectoryPath,
|
configurationDirectoryPath,
|
||||||
cacheDirectoryPath)
|
cacheDirectoryPath)
|
||||||
{
|
{
|
||||||
ApplicationResourcesPath = applicationResourcesPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ApplicationResourcesPath { get; private set; }
|
public string ApplicationResourcesPath { get; } = AppContext.BaseDirectory;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the path to the base root media directory
|
/// Gets the path to the base root media directory
|
||||||
|
@ -148,7 +144,6 @@ namespace Emby.Server.Implementations
|
||||||
set => _internalMetadataPath = value;
|
set => _internalMetadataPath = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private const string _virtualInternalMetadataPath = "%MetadataPath%";
|
public string VirtualInternalMetadataPath { get; } = "%MetadataPath%";
|
||||||
public string VirtualInternalMetadataPath => _virtualInternalMetadataPath;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,112 +139,156 @@ namespace Jellyfin.Server
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create the data, config and log paths from the variety of inputs(command line args,
|
||||||
|
/// environment variables) or decide on what default to use. For Windows it's %AppPath%
|
||||||
|
/// for everything else the XDG approach is followed:
|
||||||
|
/// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <returns>ServerApplicationPaths</returns>
|
||||||
private static ServerApplicationPaths CreateApplicationPaths(StartupOptions options)
|
private static ServerApplicationPaths CreateApplicationPaths(StartupOptions options)
|
||||||
{
|
{
|
||||||
string programDataPath = Environment.GetEnvironmentVariable("JELLYFIN_DATA_PATH");
|
// dataDir
|
||||||
if (string.IsNullOrEmpty(programDataPath))
|
// IF --datadir
|
||||||
|
// ELSE IF $JELLYFIN_DATA_PATH
|
||||||
|
// ELSE IF windows, use <%APPDATA%>/jellyfin
|
||||||
|
// ELSE IF $XDG_DATA_HOME then use $XDG_DATA_HOME/jellyfin
|
||||||
|
// ELSE use $HOME/.local/share/jellyfin
|
||||||
|
var dataDir = options.DataDir;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(dataDir))
|
||||||
{
|
{
|
||||||
if (options.DataDir != null)
|
dataDir = Environment.GetEnvironmentVariable("JELLYFIN_DATA_PATH");
|
||||||
{
|
|
||||||
programDataPath = options.DataDir;
|
if (string.IsNullOrEmpty(dataDir))
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
{
|
{
|
||||||
programDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
dataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// $XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored.
|
// $XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored.
|
||||||
programDataPath = Environment.GetEnvironmentVariable("XDG_DATA_HOME");
|
dataDir = Environment.GetEnvironmentVariable("XDG_DATA_HOME");
|
||||||
// If $XDG_DATA_HOME is either not set or empty, $HOME/.local/share should be used.
|
|
||||||
if (string.IsNullOrEmpty(programDataPath))
|
// If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used.
|
||||||
|
if (string.IsNullOrEmpty(dataDir))
|
||||||
{
|
{
|
||||||
programDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share");
|
dataDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
programDataPath = Path.Combine(programDataPath, "jellyfin");
|
dataDir = Path.Combine(dataDir, "jellyfin");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(programDataPath))
|
// configDir
|
||||||
{
|
// IF --configdir
|
||||||
Console.WriteLine("Cannot continue without path to program data folder (try -programdata)");
|
// ELSE IF $JELLYFIN_CONFIG_DIR
|
||||||
Environment.Exit(1);
|
// ELSE IF --datadir, use <datadir>/config (assume portable run)
|
||||||
}
|
// ELSE IF <datadir>/config exists, use that
|
||||||
else
|
// ELSE IF windows, use <datadir>/config
|
||||||
{
|
// ELSE IF $XDG_CONFIG_HOME use $XDG_CONFIG_HOME/jellyfin
|
||||||
Directory.CreateDirectory(programDataPath);
|
// ELSE $HOME/.config/jellyfin
|
||||||
}
|
var configDir = options.ConfigDir;
|
||||||
|
|
||||||
string configDir = Environment.GetEnvironmentVariable("JELLYFIN_CONFIG_DIR");
|
|
||||||
if (string.IsNullOrEmpty(configDir))
|
if (string.IsNullOrEmpty(configDir))
|
||||||
{
|
{
|
||||||
if (options.ConfigDir != null)
|
configDir = Environment.GetEnvironmentVariable("JELLYFIN_CONFIG_DIR");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(configDir))
|
||||||
{
|
{
|
||||||
configDir = options.ConfigDir;
|
if (options.DataDir != null || Directory.Exists(Path.Combine(dataDir, "config")) || RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
}
|
{
|
||||||
else
|
// Hang config folder off already set dataDir
|
||||||
{
|
configDir = Path.Combine(dataDir, "config");
|
||||||
// Let BaseApplicationPaths set up the default value
|
}
|
||||||
configDir = null;
|
else
|
||||||
|
{
|
||||||
|
// $XDG_CONFIG_HOME defines the base directory relative to which user specific configuration files should be stored.
|
||||||
|
configDir = Environment.GetEnvironmentVariable("XDG_CONFIG_HOME");
|
||||||
|
|
||||||
|
// If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME /.config should be used.
|
||||||
|
if (string.IsNullOrEmpty(configDir))
|
||||||
|
{
|
||||||
|
configDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config");
|
||||||
|
}
|
||||||
|
|
||||||
|
configDir = Path.Combine(configDir, "jellyfin");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (configDir != null)
|
// cacheDir
|
||||||
{
|
// IF --cachedir
|
||||||
Directory.CreateDirectory(configDir);
|
// ELSE IF $JELLYFIN_CACHE_DIR
|
||||||
}
|
// ELSE IF windows, use <datadir>/cache
|
||||||
|
// ELSE IF XDG_CACHE_HOME, use $XDG_CACHE_HOME/jellyfin
|
||||||
|
// ELSE HOME/.cache/jellyfin
|
||||||
|
var cacheDir = options.CacheDir;
|
||||||
|
|
||||||
string cacheDir = Environment.GetEnvironmentVariable("JELLYFIN_CACHE_DIR");
|
|
||||||
if (string.IsNullOrEmpty(cacheDir))
|
if (string.IsNullOrEmpty(cacheDir))
|
||||||
{
|
{
|
||||||
if (options.CacheDir != null)
|
cacheDir = Environment.GetEnvironmentVariable("JELLYFIN_CACHE_DIR");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(cacheDir))
|
||||||
{
|
{
|
||||||
cacheDir = options.CacheDir;
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
}
|
|
||||||
else if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
||||||
{
|
|
||||||
// $XDG_CACHE_HOME defines the base directory relative to which user specific non-essential data files should be stored.
|
|
||||||
cacheDir = Environment.GetEnvironmentVariable("XDG_CACHE_HOME");
|
|
||||||
// If $XDG_CACHE_HOME is either not set or empty, $HOME/.cache should be used.
|
|
||||||
if (string.IsNullOrEmpty(cacheDir))
|
|
||||||
{
|
{
|
||||||
cacheDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".cache");
|
// Hang cache folder off already set dataDir
|
||||||
|
cacheDir = Path.Combine(dataDir, "cache");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// $XDG_CACHE_HOME defines the base directory relative to which user specific non-essential data files should be stored.
|
||||||
|
cacheDir = Environment.GetEnvironmentVariable("XDG_CACHE_HOME");
|
||||||
|
|
||||||
|
// If $XDG_CACHE_HOME is either not set or empty, a default equal to $HOME/.cache should be used.
|
||||||
|
if (string.IsNullOrEmpty(cacheDir))
|
||||||
|
{
|
||||||
|
cacheDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
cacheDir = Path.Combine(cacheDir, "jellyfin");
|
||||||
}
|
}
|
||||||
cacheDir = Path.Combine(cacheDir, "jellyfin");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cacheDir != null)
|
// logDir
|
||||||
{
|
// IF --logdir
|
||||||
Directory.CreateDirectory(cacheDir);
|
// ELSE IF $JELLYFIN_LOG_DIR
|
||||||
}
|
// ELSE IF --datadir, use <datadir>/log (assume portable run)
|
||||||
|
// ELSE <datadir>/log
|
||||||
|
var logDir = options.LogDir;
|
||||||
|
|
||||||
string logDir = Environment.GetEnvironmentVariable("JELLYFIN_LOG_DIR");
|
|
||||||
if (string.IsNullOrEmpty(logDir))
|
if (string.IsNullOrEmpty(logDir))
|
||||||
{
|
{
|
||||||
if (options.LogDir != null)
|
logDir = Environment.GetEnvironmentVariable("JELLYFIN_LOG_DIR");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(logDir))
|
||||||
{
|
{
|
||||||
logDir = options.LogDir;
|
// Hang log folder off already set dataDir
|
||||||
}
|
logDir = Path.Combine(dataDir, "log");
|
||||||
else
|
|
||||||
{
|
|
||||||
// Let BaseApplicationPaths set up the default value
|
|
||||||
logDir = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logDir != null)
|
// Ensure the main folders exist before we continue
|
||||||
|
try
|
||||||
{
|
{
|
||||||
|
Directory.CreateDirectory(dataDir);
|
||||||
Directory.CreateDirectory(logDir);
|
Directory.CreateDirectory(logDir);
|
||||||
|
Directory.CreateDirectory(configDir);
|
||||||
|
Directory.CreateDirectory(cacheDir);
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("Error whilst attempting to create folder");
|
||||||
|
Console.Error.WriteLine(ex.ToString());
|
||||||
|
Environment.Exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
string appPath = AppContext.BaseDirectory;
|
return new ServerApplicationPaths(dataDir, logDir, configDir, cacheDir);
|
||||||
|
|
||||||
return new ServerApplicationPaths(programDataPath, appPath, appPath, logDir, configDir, cacheDir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task CreateLogger(IApplicationPaths appPaths)
|
private static async Task CreateLogger(IApplicationPaths appPaths)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user