This commit is contained in:
Mike Phares 2025-05-12 11:09:52 -07:00
parent 631d47ddf9
commit 33f550a51f
5 changed files with 40 additions and 109 deletions

View File

@ -11,35 +11,23 @@ public record Record(string RelativePath,
long Ticks) long Ticks)
{ {
internal static ReadOnlyCollection<Record> GetCollection(SyncConfiguration syncConfiguration, string rightDirectory) internal static ReadOnlyCollection<Record> GetRecords(Matcher matcher, string directory)
{
ReadOnlyCollection<Record> results;
Matcher matcher = new();
string excludePatternsFile = Path.Combine(rightDirectory, syncConfiguration.ExcludePatternsFile);
string includePatternsFile = Path.Combine(rightDirectory, syncConfiguration.IncludePatternsFile);
matcher.AddIncludePatterns(!File.Exists(includePatternsFile) ? ["*"] : File.ReadAllLines(includePatternsFile));
matcher.AddExcludePatterns(!File.Exists(excludePatternsFile) ? ["System Volume Information"] : File.ReadAllLines(excludePatternsFile));
results = GetRecords(rightDirectory, matcher);
return results;
}
private static ReadOnlyCollection<Record> GetRecords(string rightDirectory, Matcher matcher)
{ {
List<Record> results = []; List<Record> results = [];
Record record; Record record;
FileInfo fileInfo; FileInfo fileInfo;
string relativePath; string relativePath;
ReadOnlyCollection<ReadOnlyCollection<string>> collection = GetFilesCollection(rightDirectory, "*", "*"); ReadOnlyCollection<ReadOnlyCollection<string>> collection = GetFilesCollection(directory, "*", "*");
foreach (ReadOnlyCollection<string> c in collection) foreach (ReadOnlyCollection<string> c in collection)
{ {
foreach (string f in c) foreach (string f in c)
{ {
if (!matcher.Match(rightDirectory, f).HasMatches) if (!matcher.Match(directory, f).HasMatches)
continue; continue;
fileInfo = new(f); fileInfo = new(f);
if (fileInfo.Length == 0) if (fileInfo.Length == 0)
continue; continue;
relativePath = Path.GetRelativePath(rightDirectory, fileInfo.FullName); relativePath = Path.GetRelativePath(directory, fileInfo.FullName);
record = new(RelativePath: relativePath, record = new(RelativePath: relativePath,
Size: fileInfo.Length, Size: fileInfo.Length,
Ticks: fileInfo.LastWriteTime.ToUniversalTime().Ticks); Ticks: fileInfo.LastWriteTime.ToUniversalTime().Ticks);

View File

@ -5,7 +5,8 @@ using System.Threading.Tasks;
namespace FileExposer.Models; namespace FileExposer.Models;
public record RelativePath(string Path, public record RelativePath(string LeftDirectory,
string? RightDirectory,
Record[] Records) Record[] Records)
{ {

View File

@ -36,29 +36,17 @@ public record Review(Segment[]? AreEqual,
private static ReadOnlyCollection<Segment> GetAreEqual(RelativePath relativePath, ReadOnlyCollection<Record> records) private static ReadOnlyCollection<Segment> GetAreEqual(RelativePath relativePath, ReadOnlyCollection<Record> records)
{ {
List<Segment> results = []; List<Segment> results = [];
Record? record;
Segment segment; Segment segment;
double totalSeconds; double totalSeconds;
string? checkDirectory = null;
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(relativePath); ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(relativePath);
foreach (Record r in records) foreach (Record r in records)
{ {
if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) if (!keyValuePairs.TryGetValue(r.RelativePath, out Record? record))
{
checkDirectory = r.RelativePath;
continue;
}
if (r.RelativePath == relativePath.Path)
continue;
if (!keyValuePairs.TryGetValue(r.RelativePath, out record))
continue; continue;
totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds; totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds;
if (record.Size != r.Size || totalSeconds is > 2 or < -2) if (record.Size != r.Size || totalSeconds is > 2 or < -2)
continue; continue;
segment = new(Left: r, segment = new(Left: r, Right: record);
LeftDirectory: checkDirectory,
Right: record,
RightDirectory: relativePath.Path);
results.Add(segment); results.Add(segment);
} }
return results.AsReadOnly(); return results.AsReadOnly();
@ -78,31 +66,19 @@ public record Review(Segment[]? AreEqual,
private static ReadOnlyCollection<Segment> GetNotEqualBut(RelativePath relativePath, ReadOnlyCollection<Record> records) private static ReadOnlyCollection<Segment> GetNotEqualBut(RelativePath relativePath, ReadOnlyCollection<Record> records)
{ {
List<Segment> results = []; List<Segment> results = [];
Record? record;
Segment segment; Segment segment;
double totalSeconds; double totalSeconds;
string? checkDirectory = null;
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(relativePath); ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(relativePath);
foreach (Record r in records) foreach (Record r in records)
{ {
if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) if (!keyValuePairs.TryGetValue(r.RelativePath, out Record? record))
{
checkDirectory = r.RelativePath;
continue;
}
if (r.RelativePath == relativePath.Path)
continue;
if (!keyValuePairs.TryGetValue(r.RelativePath, out record))
continue; continue;
if (record.Size == r.Size) if (record.Size == r.Size)
continue; continue;
totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds; totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds;
if (totalSeconds is >= 2 or <= -2) if (totalSeconds is >= 2 or <= -2)
continue; continue;
segment = new(Left: r, segment = new(Left: r, Right: record);
LeftDirectory: checkDirectory,
Right: record,
RightDirectory: relativePath.Path);
results.Add(segment); results.Add(segment);
} }
return results.AsReadOnly(); return results.AsReadOnly();
@ -111,25 +87,13 @@ public record Review(Segment[]? AreEqual,
private static ReadOnlyCollection<Segment> GetLeftSideOnly(RelativePath relativePath, ReadOnlyCollection<Record> records) private static ReadOnlyCollection<Segment> GetLeftSideOnly(RelativePath relativePath, ReadOnlyCollection<Record> records)
{ {
List<Segment> results = []; List<Segment> results = [];
Record? record;
Segment segment; Segment segment;
string? checkDirectory = null;
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(relativePath); ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(relativePath);
foreach (Record r in records) foreach (Record r in records)
{ {
if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) if (keyValuePairs.TryGetValue(r.RelativePath, out Record? record))
{
checkDirectory = r.RelativePath;
continue; continue;
} segment = new(Left: r, Right: record);
if (r.RelativePath == relativePath.Path)
continue;
if (keyValuePairs.TryGetValue(r.RelativePath, out record))
continue;
segment = new(Left: r,
LeftDirectory: checkDirectory,
Right: record,
RightDirectory: relativePath.Path);
results.Add(segment); results.Add(segment);
} }
return results.AsReadOnly(); return results.AsReadOnly();
@ -138,25 +102,13 @@ public record Review(Segment[]? AreEqual,
private static ReadOnlyCollection<Segment> GetRightSideOnly(RelativePath relativePath, ReadOnlyCollection<Record> records) private static ReadOnlyCollection<Segment> GetRightSideOnly(RelativePath relativePath, ReadOnlyCollection<Record> records)
{ {
List<Segment> results = []; List<Segment> results = [];
Record? record;
Segment segment; Segment segment;
string? checkDirectory = null;
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(records); ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(records);
foreach (Record r in relativePath.Records) foreach (Record r in relativePath.Records)
{ {
if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) if (keyValuePairs.TryGetValue(r.RelativePath, out Record? record))
{
checkDirectory = r.RelativePath;
continue; continue;
} segment = new(Left: record, Right: r);
if (r.RelativePath == relativePath.Path)
continue;
if (keyValuePairs.TryGetValue(r.RelativePath, out record))
continue;
segment = new(Left: record,
LeftDirectory: null,
Right: r,
RightDirectory: relativePath.Path);
results.Add(segment); results.Add(segment);
} }
return results.AsReadOnly(); return results.AsReadOnly();
@ -165,29 +117,17 @@ public record Review(Segment[]? AreEqual,
private static ReadOnlyCollection<Segment> GetLeftSideIsNewer(RelativePath relativePath, ReadOnlyCollection<Record> records) private static ReadOnlyCollection<Segment> GetLeftSideIsNewer(RelativePath relativePath, ReadOnlyCollection<Record> records)
{ {
List<Segment> results = []; List<Segment> results = [];
Record? record;
Segment segment; Segment segment;
double totalSeconds; double totalSeconds;
string? checkDirectory = null;
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(relativePath); ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(relativePath);
foreach (Record r in records) foreach (Record r in records)
{ {
if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) if (!keyValuePairs.TryGetValue(r.RelativePath, out Record? record))
{
checkDirectory = r.RelativePath;
continue;
}
if (r.RelativePath == relativePath.Path)
continue;
if (!keyValuePairs.TryGetValue(r.RelativePath, out record))
continue; continue;
totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds; totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds;
if (totalSeconds is > -2) if (totalSeconds is > -2)
continue; continue;
segment = new(Left: r, segment = new(Left: r, Right: record);
LeftDirectory: checkDirectory,
Right: record,
RightDirectory: relativePath.Path);
results.Add(segment); results.Add(segment);
} }
return results.AsReadOnly(); return results.AsReadOnly();
@ -196,29 +136,17 @@ public record Review(Segment[]? AreEqual,
private static ReadOnlyCollection<Segment> GetRightSideIsNewer(RelativePath relativePath, ReadOnlyCollection<Record> records) private static ReadOnlyCollection<Segment> GetRightSideIsNewer(RelativePath relativePath, ReadOnlyCollection<Record> records)
{ {
List<Segment> results = []; List<Segment> results = [];
Record? record;
Segment segment; Segment segment;
double totalSeconds; double totalSeconds;
string? checkDirectory = null;
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(records); ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(records);
foreach (Record r in relativePath.Records) foreach (Record r in relativePath.Records)
{ {
if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) if (!keyValuePairs.TryGetValue(r.RelativePath, out Record? record))
{
checkDirectory = r.RelativePath;
continue;
}
if (r.RelativePath == relativePath.Path)
continue;
if (!keyValuePairs.TryGetValue(r.RelativePath, out record))
continue; continue;
totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds; totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds;
if (totalSeconds is > -2) if (totalSeconds is > -2)
continue; continue;
segment = new(Left: record, segment = new(Left: record, Right: r);
LeftDirectory: null,
Right: r,
RightDirectory: relativePath.Path);
results.Add(segment); results.Add(segment);
} }
return results.AsReadOnly(); return results.AsReadOnly();

View File

@ -3,9 +3,7 @@ using System.Text.Json.Serialization;
namespace FileExposer.Models; namespace FileExposer.Models;
public record Segment(Record? Left, public record Segment(Record? Left,
string? LeftDirectory, Record? Right);
Record? Right,
string RightDirectory);
[JsonSourceGenerationOptions(WriteIndented = true)] [JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Segment))] [JsonSerializable(typeof(Segment))]

View File

@ -5,6 +5,7 @@ using System.Collections.ObjectModel;
using System.IO; using System.IO;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.FileSystemGlobbing;
public class SyncV1Repository(AppSettings appSettings) : ISyncV1Repository public class SyncV1Repository(AppSettings appSettings) : ISyncV1Repository
{ {
@ -28,20 +29,31 @@ public class SyncV1Repository(AppSettings appSettings) : ISyncV1Repository
if (size is not null && ticks is not null) if (size is not null && ticks is not null)
{ {
FileInfo fileInfo = Verify(path, size.Value, ticks.Value); FileInfo fileInfo = Verify(path, size.Value, ticks.Value);
result = new (JSON: null, Bytes: File.ReadAllBytes(fileInfo.FullName)); result = new(JSON: null, Bytes: File.ReadAllBytes(fileInfo.FullName));
} }
else else
{ {
if (File.Exists(path)) if (File.Exists(path))
throw new Exception("Must pass size and ticks when passing a file!"); throw new Exception("Must pass size and ticks when passing a file!");
string directory = Path.GetFullPath(path); string directory = Path.GetFullPath(path);
ReadOnlyCollection<Record> records = Record.GetCollection(_AppSettings.SyncConfiguration, directory); string excludePatternsFile = Path.Combine(directory, _AppSettings.SyncConfiguration.ExcludePatternsFile);
RelativePath relativePath = new(Path: path, Records: [.. records]); string includePatternsFile = Path.Combine(directory, _AppSettings.SyncConfiguration.IncludePatternsFile);
result = new (JSON: JsonSerializer.Serialize(relativePath, RelativePathSourceGenerationContext.Default.RelativePath), Bytes: null); Matcher matcher = GetMatcher(excludePatternsFile, includePatternsFile);
ReadOnlyCollection<Record> records = Record.GetRecords(matcher, directory);
RelativePath relativePath = new(LeftDirectory: path, Records: [.. records], RightDirectory: null);
result = new(JSON: JsonSerializer.Serialize(relativePath, RelativePathSourceGenerationContext.Default.RelativePath), Bytes: null);
} }
return result; return result;
} }
private static Matcher GetMatcher(string excludePatternsFile, string includePatternsFile)
{
Matcher result = new();
result.AddIncludePatterns(!File.Exists(includePatternsFile) ? ["*"] : File.ReadAllLines(includePatternsFile));
result.AddExcludePatterns(!File.Exists(excludePatternsFile) ? ["System Volume Information"] : File.ReadAllLines(excludePatternsFile));
return result;
}
private FileInfo Verify(string path, long size, long ticks) private FileInfo Verify(string path, long size, long ticks)
{ {
FileInfo fileInfo = new(path); FileInfo fileInfo = new(path);
@ -58,7 +70,11 @@ public class SyncV1Repository(AppSettings appSettings) : ISyncV1Repository
string result; string result;
RelativePath? relativePath = RelativePath.Get(stream) ?? RelativePath? relativePath = RelativePath.Get(stream) ??
throw new MissingFieldException(); throw new MissingFieldException();
ReadOnlyCollection<Record> records = Record.GetCollection(_AppSettings.SyncConfiguration, relativePath.Path); string directory = Path.GetFullPath(relativePath.LeftDirectory);
string excludePatternsFile = Path.Combine(directory, _AppSettings.SyncConfiguration.ExcludePatternsFile);
string includePatternsFile = Path.Combine(directory, _AppSettings.SyncConfiguration.IncludePatternsFile);
Matcher matcher = GetMatcher(excludePatternsFile, includePatternsFile);
ReadOnlyCollection<Record> records = Record.GetRecords(matcher, directory);
if (records.Count == 0) if (records.Count == 0)
throw new Exception("No source records"); throw new Exception("No source records");
Review review = Review.Get(relativePath, records); Review review = Review.Get(relativePath, records);