public Results.ReconcileResult Reconcile(Results.ScanResult a, Results.ScanResult b) { var pathsA = new HashSet <string>(a.Keys); var pathsB = new HashSet <string>(b.Keys); var suspectedConflicts = new HashSet <string>(pathsA); suspectedConflicts.IntersectWith(pathsB); var unchangedFiles = new HashSet <string>(); foreach (var entry in suspectedConflicts) { if (a[entry].Equals(b[entry])) { unchangedFiles.Add(entry); } } var conflicts = new HashSet <string>(suspectedConflicts); conflicts.RemoveWhere(entry => unchangedFiles.Contains(entry)); return(new Results.ReconcileResult( this.GeneratePatch(b, a, pathsB, pathsA, unchangedFiles, conflicts), this.GeneratePatch(a, b, pathsA, pathsB, unchangedFiles, conflicts) )); }
private Results.PatchResult GeneratePatch( Results.ScanResult src, Results.ScanResult target, HashSet <string> srcPaths, HashSet <string> targetPaths, HashSet <string> unchanged, HashSet <string> conflicts) { var retVal = new Results.PatchResult(); var additions = new HashSet <string>(srcPaths); int addCount = additions.RemoveWhere(entry => targetPaths.Contains(entry)); retVal[Results.ReconcileOperation.ADD] = new List <FileResult>(addCount); foreach (var entry in additions) { retVal[Results.ReconcileOperation.ADD].Add(src[entry]); } retVal[Results.ReconcileOperation.UNCHANGED] = new List <FileResult>(unchanged.Count); foreach (var entry in unchanged) { retVal[Results.ReconcileOperation.UNCHANGED].Add(src[entry]); } retVal[Results.ReconcileOperation.CONFLICT] = new List <FileResult>(conflicts.Count); foreach (var entry in conflicts) { retVal[Results.ReconcileOperation.CONFLICT].Add(target[entry]); } return(retVal); }
public Task <Results.ScanResult> ScanDirectory(string root) { var cutIndex = root.Length + 1; var files = Directory.EnumerateFiles(root, "*", SearchOption.AllDirectories); // Return a task that runs this in a parallel foreach // Because Parallel.ForEach doesn't return a task and is not awaitable, // then we have to wrap it in this way. // The resulting code is faster than having a List<Task> that is then sent to Task.WaitAll // since Parallel.ForEach scales better. return(Task.Run( () => { var scanResult = new Results.ScanResult(); Parallel.ForEach(files, (filepath) => { var canonicalPath = filepath.Substring(cutIndex); scanResult[canonicalPath] = this.HashFile(filepath, canonicalPath); }); return scanResult; } )); }