Files
jdescopingtool/NEW/src/Utils/JdeScoping.ConfigManager/Services/AutoDiscoveryService.cs
T
Joseph Doherty e5fe2f06e9 feat: add startup config validation and document ConfigManager pipeline editor
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.
2026-01-21 17:47:15 -05:00

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