using System; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Linq; using Flawless.Abstraction; using Flawless.Client.Models; using Flawless.Core.Modal; namespace Flawless.Client.Service; public class LocalFileTreeAccessor { public enum ChangeType { Folder = 0, Add, Remove, Modify } public struct ChangeRecord { public ChangeType Type { get; } public WorkspaceFile File { get; } public ChangeRecord(ChangeType type, WorkspaceFile file) { Type = type; File = file; } } private static readonly string[] IgnoredDirectories = { AppDefaultValues.RepoLocalStorageManagerFolder }; private readonly RepositoryModel _repo; private readonly string _rootDirectory; private IReadOnlyDictionary _baseline; private Dictionary _changes = new(); private Dictionary _currentFiles = new(); private object _optLock = new(); public DateTime LastScanTimeUtc { get; private set; } public string WorkingDirectory => _rootDirectory; public IReadOnlyDictionary BaselineFiles => _baseline; public IReadOnlyDictionary Changes => _changes; public IReadOnlyDictionary CurrentFiles => _currentFiles; public LocalFileTreeAccessor(RepositoryModel repo, IEnumerable baselines) { _repo = repo; _baseline = baselines.ToImmutableDictionary(b => b.WorkPath); _rootDirectory = PathUtility.GetWorkspacePath(repo.OwnerName, repo.Name); } public void SetBaseline(IEnumerable baselines) { lock (_optLock) { _baseline = baselines.ToImmutableDictionary(b => b.WorkPath); _changes.Clear(); RefreshInternal(); } } public void Refresh() { lock (_optLock) { _changes.Clear(); RefreshInternal(); } } private void RefreshInternal() { _currentFiles.Clear(); foreach (var f in Directory.GetFiles(_rootDirectory, "*", SearchOption.AllDirectories)) { var workPath = WorkPath.FromPlatformPath(f, _rootDirectory); if (!WorkPath.IsPathValid(workPath) || IgnoredDirectories.Any(d => workPath.StartsWith(d))) continue; var modifyTime = File.GetLastWriteTimeUtc(f); _currentFiles.Add(workPath, new WorkspaceFile { WorkPath = workPath, ModifyTime = modifyTime }); } LastScanTimeUtc = DateTime.UtcNow; // Find those are changed var changes = _currentFiles.Values.Where(v => _baseline.TryGetValue(v.WorkPath, out var fi) && fi.ModifyTime != v.ModifyTime); var news = _currentFiles.Values.Where(v => !_baseline.ContainsKey(v.WorkPath)); var removed = _baseline.Values.Where(v => !_currentFiles.ContainsKey(v.WorkPath)); foreach (var f in changes) _changes.Add(f.WorkPath, new ChangeRecord(ChangeType.Modify, f)); foreach (var f in news) _changes.Add(f.WorkPath, new ChangeRecord(ChangeType.Add, f)); foreach (var f in removed) _changes.Add(f.WorkPath, new ChangeRecord(ChangeType.Remove, f)); } }