144 lines
4.0 KiB
C#
144 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 inf = new FileInfo(f);
|
|
_currentFiles.Add(workPath, new WorkspaceFile(inf.LastWriteTimeUtc, workPath, inf.Length));
|
|
}
|
|
|
|
LastScanTimeUtc = DateTime.UtcNow;
|
|
|
|
// Find those are changed
|
|
var changes = _currentFiles.Values.Where(v =>
|
|
_baseline.TryGetValue(v.WorkPath, out var fi) &&
|
|
(fi.ModifyTime != v.ModifyTime || fi.Size != v.Size));
|
|
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));
|
|
}
|
|
} |