1
0

142 lines
4.0 KiB
C#

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 enum ChangeInfoType
{
Folder = 0,
Add,
Remove,
Modify
}
public struct ChangeInfo : IEquatable<ChangeInfo>
{
public ChangeInfoType Type { get; }
public WorkspaceFile File { get; }
public ChangeInfo(ChangeInfoType type, WorkspaceFile file)
{
Type = type;
File = file;
}
public bool Equals(ChangeInfo other)
{
return Type == other.Type && File.Equals(other.File);
}
public override bool Equals(object? obj)
{
return obj is ChangeInfo other && Equals(other);
}
public override int GetHashCode()
{
return HashCode.Combine((int)Type, File);
}
public static bool operator ==(ChangeInfo left, ChangeInfo right)
{
return left.Equals(right);
}
public static bool operator !=(ChangeInfo left, ChangeInfo right)
{
return !left.Equals(right);
}
}
public class LocalFileTreeAccessor
{
private static readonly string[] IgnoredDirectories =
{
AppDefaultValues.RepoLocalStorageManagerFolder
};
private readonly RepositoryModel _repo;
private readonly string _rootDirectory;
private IReadOnlyDictionary<string, WorkspaceFile> _baseline;
private Dictionary<string, ChangeInfo> _changes = new();
private Dictionary<string, WorkspaceFile> _currentFiles = new();
private object _optLock = new();
public DateTime LastScanTimeUtc { get; private set; }
public string WorkingDirectory => _rootDirectory;
public IReadOnlyDictionary<string, WorkspaceFile> BaselineFiles => _baseline;
public IReadOnlyDictionary<string, ChangeInfo> Changes => _changes;
public IReadOnlyDictionary<string, WorkspaceFile> CurrentFiles => _currentFiles;
public LocalFileTreeAccessor(RepositoryModel repo, IEnumerable<WorkspaceFile> baselines)
{
_repo = repo;
_baseline = baselines.ToImmutableDictionary(b => b.WorkPath);
_rootDirectory = PathUtility.GetWorkspacePath(Api.Current.Username.Value!, repo.OwnerName, repo.Name);
}
public void SetBaseline(IEnumerable<WorkspaceFile> 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 ChangeInfo(ChangeInfoType.Modify, f));
foreach (var f in news) _changes.Add(f.WorkPath, new ChangeInfo(ChangeInfoType.Add, f));
foreach (var f in removed) _changes.Add(f.WorkPath, new ChangeInfo(ChangeInfoType.Remove, f));
}
}