/// <summary> /// Finds objects of the same name, but different hashes /// </summary> private static void FindModifieds(ChangelogBuilder changelog, string prefix, VDKeyedCollection byName, VDKeyedCollection otherByName) { var toRemove = new LinkedList <string>(); foreach (var otherVD in otherByName) { //if (byName.ContainsKey(pair.Key)) if (byName.Contains(otherVD.Filename)) { VersionData thisVD = byName[otherVD.Filename]; if (otherVD.Filetype == thisVD.Filetype) { string fpath = PrefixFilename(prefix, otherVD.Filename); changelog.Modify(fpath, otherVD.Hash); if (otherVD.Filetype == FileType.Directory) { var subchangelog = BuildChangelog(thisVD, otherVD, fpath); changelog.Aggregate(subchangelog); } toRemove.AddLast(otherVD.Filename); } } } foreach (string s in toRemove) { byName.Remove(s); otherByName.Remove(s); } }
/// <summary> /// Finds objects of the same hash but different names /// </summary> private static void FindRenames(ChangelogBuilder changelog, string prefix, VDKeyedCollection byName, VDKeyedCollection otherByName, Dictionary <string, LinkedList <string> > byHash, Dictionary <string, LinkedList <string> > otherByHash) { foreach (var pair in byHash) { if (otherByHash.ContainsKey(pair.Key)) { var thisll = pair.Value; var otherll = otherByHash[pair.Key]; while (thisll.Count > 0 && otherll.Count > 0) { string thisfile = thisll.First.Value; string otherfile = otherll.First.Value; byName.Remove(thisfile); otherByName.Remove(otherfile); string thisfpath = PrefixFilename(prefix, thisfile); string otherfpath = PrefixFilename(prefix, otherfile); changelog.Rename(thisfpath, otherfpath); thisll.RemoveFirst(); otherll.RemoveFirst(); } } } }
/// <summary> /// Adds all descendant files of a Directory to a changelog /// </summary> private static void AggregateAdd(ChangelogBuilder changelog, string prefix, VersionData update) { foreach (var child in update.Children) { string fpath = PrefixFilename(prefix, child.Filename); changelog.Add(fpath, child.Hash); if (child.Filetype == FileType.Directory) { var subchangelog = BuildChangelog(child, null, fpath); changelog.Aggregate(subchangelog); } } }
/// <summary> /// Removes all descendant files of a Directory to a changelog /// </summary> private static void AggregateRemove(ChangelogBuilder changelog, string prefix, VersionData original) { foreach (var child in original.Children) { string fpath = PrefixFilename(prefix, child.Filename); changelog.Remove(fpath); if (child.Filetype == FileType.Directory) { var subchangelog = BuildChangelog(child, null, fpath); changelog.Aggregate(subchangelog); } } }
/// <summary> /// Aggregates with another ChangelogBuilder /// </summary> /// <param name="other"></param> public void Aggregate(ChangelogBuilder other) { foreach (var a in other.added) { added.Add(a.Key, a.Value); } foreach (var m in other.modified) { modified.Add(m.Key, m.Value); } foreach (var r in other.removed) { removed.Add(r); } foreach (var r in other.renamed) { renamed.Add(r.Key, r.Value); } }
/// <summary> /// Recursively builds a Changelog by comparing each directory to its analogue and finding differences /// </summary> /// <param name="original"></param> /// <param name="update"></param> /// <param name="prefix"></param> /// <returns></returns> public static ChangelogBuilder BuildChangelog(VersionData original, VersionData update, string prefix = "") { ChangelogBuilder changelog = new ChangelogBuilder(); var byHash = new Dictionary <string, LinkedList <string> >(); var otherByHash = new Dictionary <string, LinkedList <string> >(); var byName = new VDKeyedCollection(); var otherByName = new VDKeyedCollection(); if (original == null) { if (update == null) { throw new ArgumentNullException("original and update"); } } else if (original.filetype == FileType.File) { throw new InvalidOperationException("Cannot call GetChangelog on a FileType.File type"); } if (update != null && update.filetype == FileType.File) { throw new ArgumentException("child must be of type FileType.File"); } if (update == null) { AggregateRemove(changelog, prefix, original); return(changelog); } if (original == null) { AggregateAdd(changelog, prefix, update); return(changelog); } AddAlteredFiles(original.children, update.children, byName, byHash); AddAlteredFiles(update.children, original.children, otherByName, otherByHash); FindRenames(changelog, prefix, byName, otherByName, byHash, otherByHash); FindModifieds(changelog, prefix, byName, otherByName); FindAddRemoveds(changelog, prefix, byName, otherByName); return(changelog); }
/// <summary> /// Finds objects that exist in one collection but not the other /// </summary> private static void FindAddRemoveds(ChangelogBuilder changelog, string prefix, VDKeyedCollection byName, VDKeyedCollection otherByName) { foreach (var pair in byName) { string fpath = PrefixFilename(prefix, pair.Filename); changelog.Remove(fpath); if (pair.Filetype == FileType.Directory) { var subchangelog = BuildChangelog(pair, null, fpath); changelog.Aggregate(subchangelog); } } foreach (var pair in otherByName) { string fpath = PrefixFilename(prefix, pair.Filename); changelog.Add(fpath, pair.Hash); if (pair.Filetype == FileType.Directory) { var subchangelog = BuildChangelog(null, pair, fpath); changelog.Aggregate(subchangelog); } } }