namespace Flyshot.Core.Config; /// /// 标识需要生成哪一种平台风格的兼容路径。 /// public enum CompatibilityPathStyle { /// /// 使用 Linux/Unix 风格路径。 /// Posix, /// /// 使用 Windows 风格路径。 /// Windows } /// /// 提供旧配置与新服务端之间的路径兼容策略。 /// public static class PathCompatibility { /// /// 按当前服务配置目录约定解析配置文件路径。 /// /// 调用方传入的原始配置路径。 /// 当前兼容搜索的仓库根目录。 /// 命中的绝对配置路径。 public static string ResolveConfigPath(string configPath, string repoRoot) { if (string.IsNullOrWhiteSpace(configPath)) { throw new ArgumentException("配置路径不能为空。", nameof(configPath)); } if (string.IsNullOrWhiteSpace(repoRoot)) { throw new ArgumentException("仓库根目录不能为空。", nameof(repoRoot)); } var rawPath = configPath.Trim(); if (Path.IsPathRooted(rawPath)) { return File.Exists(rawPath) ? Path.GetFullPath(rawPath) : throw new FileNotFoundException($"未找到配置文件: {rawPath}", rawPath); } var normalizedRepoRoot = Path.GetFullPath(repoRoot); var checkedPaths = new List(); // 相对路径只允许落在当前服务根目录的 Config 下,避免隐式回退到父工作区旧文件。 foreach (var candidate in BuildConfigCandidates(normalizedRepoRoot, rawPath)) { var fullCandidate = Path.GetFullPath(candidate); if (checkedPaths.Contains(fullCandidate, StringComparer.OrdinalIgnoreCase)) { continue; } checkedPaths.Add(fullCandidate); if (File.Exists(fullCandidate)) { return fullCandidate; } } throw new FileNotFoundException( $"未找到配置文件 '{configPath}'。已检查: {string.Join(", ", checkedPaths)}", configPath); } /// /// 构造当前平台约定的用户数据根目录。 /// /// 用户主目录。 /// 目标平台风格。 /// 兼容旧系统的用户数据目录。 public static string BuildUserDataRoot(string homeDirectory, CompatibilityPathStyle pathStyle) { if (string.IsNullOrWhiteSpace(homeDirectory)) { throw new ArgumentException("用户目录不能为空。", nameof(homeDirectory)); } return pathStyle switch { CompatibilityPathStyle.Posix => JoinPosix(homeDirectory, ".Rvbust", "Data"), CompatibilityPathStyle.Windows => JoinWindows(homeDirectory, ".Rvbust", "Data"), _ => throw new ArgumentOutOfRangeException(nameof(pathStyle), pathStyle, "不支持的路径风格。") }; } /// /// 枚举当前服务配置目录下允许的配置候选路径。 /// private static IEnumerable BuildConfigCandidates(string repoRoot, string rawPath) { yield return Path.Combine(repoRoot, "Config", rawPath); } /// /// 使用 Posix 风格拼接路径,便于在 Linux 下验证固定输出。 /// private static string JoinPosix(string root, params string[] segments) { var trimmedRoot = root.TrimEnd('/'); return string.Join("/", new[] { trimmedRoot }.Concat(segments)); } /// /// 使用 Windows 风格拼接路径,避免在 Linux 上测试时被当前平台分隔符污染。 /// private static string JoinWindows(string root, params string[] segments) { var normalizedRoot = root.TrimEnd('\\', '/').Replace('/', '\\'); return string.Join("\\", new[] { normalizedRoot }.Concat(segments)); } }