e5fe2f06e9
Add ConfigurationValidationRunner with IConfigurationValidator interface for validating required settings at startup. Includes SecureStore and LDAP validators. Expand ConfigManager with pipeline editing UI, dialogs, and step editors. Update documentation with config validation guidance.
116 lines
4.7 KiB
C#
116 lines
4.7 KiB
C#
using Microsoft.Extensions.Logging;
|
|
|
|
namespace JdeScoping.ConfigManager.Services;
|
|
|
|
/// <summary>
|
|
/// Service for auto-discovering configuration file locations.
|
|
/// Searches in prioritized order:
|
|
/// 1. JDESCOPING_CONFIG_PATH environment variable
|
|
/// 2. Same directory as executable
|
|
/// 3. ../JdeScoping.Host/ relative to executable
|
|
/// 4. User config directory (~/.jdescoping on Unix, %LOCALAPPDATA%\JdeScoping on Windows)
|
|
/// </summary>
|
|
public class AutoDiscoveryService : IAutoDiscoveryService
|
|
{
|
|
private readonly IFileSystem _fileSystem;
|
|
private readonly ILogger<AutoDiscoveryService>? _logger;
|
|
private const string EnvVarName = "JDESCOPING_CONFIG_PATH";
|
|
private const string AppSettingsFileName = "appsettings.json";
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="AutoDiscoveryService"/> class.
|
|
/// </summary>
|
|
/// <param name="fileSystem">The file system abstraction to use for directory and file checks.</param>
|
|
/// <param name="logger">Optional logger for recording discovery process information.</param>
|
|
public AutoDiscoveryService(IFileSystem fileSystem, ILogger<AutoDiscoveryService>? logger = null)
|
|
{
|
|
_fileSystem = fileSystem;
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds the configuration folder using a prioritized search strategy.
|
|
/// </summary>
|
|
/// <param name="ct">Cancellation token for the async operation.</param>
|
|
/// <returns>The path to a valid configuration folder, or null if none is found.</returns>
|
|
public Task<string?> FindConfigFolderAsync(CancellationToken ct = default)
|
|
{
|
|
// 1. Check environment variable
|
|
var envPath = Environment.GetEnvironmentVariable(EnvVarName);
|
|
if (!string.IsNullOrEmpty(envPath) && IsValidConfigFolder(envPath))
|
|
{
|
|
_logger?.LogInformation("Found config folder from environment variable: {Path}", envPath);
|
|
return Task.FromResult<string?>(envPath);
|
|
}
|
|
|
|
// 2. Check same directory as executable
|
|
var exeDir = AppContext.BaseDirectory;
|
|
if (IsValidConfigFolder(exeDir))
|
|
{
|
|
_logger?.LogInformation("Found config folder in executable directory: {Path}", exeDir);
|
|
return Task.FromResult<string?>(exeDir);
|
|
}
|
|
|
|
// 3. Check ../JdeScoping.Host/ relative to executable
|
|
var hostDir = _fileSystem.Combine(exeDir, "..", "JdeScoping.Host");
|
|
if (IsValidConfigFolder(hostDir))
|
|
{
|
|
_logger?.LogInformation("Found config folder in host directory: {Path}", hostDir);
|
|
return Task.FromResult<string?>(hostDir);
|
|
}
|
|
|
|
// 4. Check project structure paths (for development)
|
|
// When running from bin/Debug/net10.0, go up to find src/JdeScoping.Host
|
|
var projectHostPaths = new[]
|
|
{
|
|
// From bin/Debug/net10.0 -> src/JdeScoping.Host
|
|
_fileSystem.Combine(exeDir, "..", "..", "..", "..", "..", "JdeScoping.Host"),
|
|
// Absolute fallback for development
|
|
"/Users/dohertj2/Desktop/JdeScopingTool/NEW/src/JdeScoping.Host"
|
|
};
|
|
|
|
foreach (var projectPath in projectHostPaths)
|
|
{
|
|
if (IsValidConfigFolder(projectPath))
|
|
{
|
|
_logger?.LogInformation("Found config folder in project directory: {Path}", projectPath);
|
|
return Task.FromResult<string?>(Path.GetFullPath(projectPath));
|
|
}
|
|
}
|
|
|
|
// 5. Check user config directory
|
|
var userConfigDir = GetUserConfigDirectory();
|
|
if (userConfigDir != null && IsValidConfigFolder(userConfigDir))
|
|
{
|
|
_logger?.LogInformation("Found config folder in user directory: {Path}", userConfigDir);
|
|
return Task.FromResult<string?>(userConfigDir);
|
|
}
|
|
|
|
_logger?.LogWarning("Could not find config folder in any standard location");
|
|
return Task.FromResult<string?>(null);
|
|
}
|
|
|
|
private bool IsValidConfigFolder(string path)
|
|
{
|
|
if (!_fileSystem.DirectoryExists(path))
|
|
return false;
|
|
|
|
var appSettingsPath = _fileSystem.Combine(path, AppSettingsFileName);
|
|
return _fileSystem.FileExists(appSettingsPath);
|
|
}
|
|
|
|
private string? GetUserConfigDirectory()
|
|
{
|
|
if (OperatingSystem.IsWindows())
|
|
{
|
|
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
|
return _fileSystem.Combine(localAppData, "JdeScoping");
|
|
}
|
|
else
|
|
{
|
|
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
|
return _fileSystem.Combine(home, ".jdescoping");
|
|
}
|
|
}
|
|
}
|