/// <summary> /// Path set hash inputs are stored separately from the strong fingerprint inputs. /// This merges the path set hash inputs tree into the strong fingerprint inputs tree /// while maintaining the 1:1 relationship between the path set and observed inputs. /// /// Node notation: /// [id] "{name}":"{value}" /// Tree notation: /// {parentNode} /// {childNode} /// /// Start with the following subtrees: /// /// From strong fingerprint /// /// [1] "PathSet":"VSO0:7E2E49845EC0AE7413519E3EE605272078AF0B1C2911C021681D1D9197CC134A00" /// [2] "ObservedInputs":"" /// [3] "E":"VSO0:E0C5007DC8CF2D331236F156F136C50CACE2A5D549CD132D9B44ABD1F13D50CC00", /// /// From path set hash /// /// [4] "PathSet":"" /// [5] "Path":"B:/out/objects/n/x/qbkexxlc8je93wycw7yrlw0a305n7k/xunit-out/CacheMissAnaAD836B23/3/obj/readonly/src_0" /// [6] "Flags":"IsDirectoryPath, DirectoryEnumeration, DirectoryEnumerationWithAllPattern" /// [7] "EnumeratePatternRegex":"^.*$" /// /// And end with: /// /// [1] "PathSet":"VSO0:7E2E49845EC0AE7413519E3EE605272078AF0B1C2911C021681D1D9197CC134A00" /// [5'] "B:/out/objects/n/x/qbkexxlc8je93wycw7yrlw0a305n7k/xunit-out/CacheMissAnaAD836B23/3/obj/readonly/src_0":"" /// [6'] "Flags":"IsDirectoryPath, DirectoryEnumeration, DirectoryEnumerationWithAllPattern" /// [7'] "EnumeratePatternRegex":"^.*$" /// [3'] "ObservedInput":"E:VSO0:E0C5007DC8CF2D331236F156F136C50CACE2A5D549CD132D9B44ABD1F13D50CC00" /// [8] "Members":"[src_1, src_2]" /// </summary> /// <returns> /// The root node of the merged tree (which will be the strong fingerprint tree's root). /// </returns> private JsonNode MergeStrongFingerprintAndPathSetTrees(JsonNode strongFingerprintTree, JsonNode pathSetTree) { // [1] "PathSet":"VSO0:7E2E49845EC0AE7413519E3EE605272078AF0B1C2911C021681D1D9197CC134A00") var parentPathNode = JsonTree.FindNodeByName(strongFingerprintTree, ObservedPathEntryConstants.PathSet); // [2] "ObservedInputs":"" var observedInputsNode = JsonTree.FindNodeByName(strongFingerprintTree, ObservedInputConstants.ObservedInputs); JsonTree.EmancipateBranch(observedInputsNode); // In preparation for merging with observed inputs nodes, // remove the path set node's branch from the path set tree // [4] "PathSet":"" var pathSetNode = JsonTree.FindNodeByName(pathSetTree, ObservedPathEntryConstants.PathSet); JsonTree.EmancipateBranch(pathSetNode); JsonNode currPathNode = null; JsonNode currFlagNode = null; JsonNode currRegexNode = null; var observedInputIt = observedInputsNode.Children.First; for (var it = pathSetNode.Children.First; it != null; it = pathSetNode.Children.First) { var child = it.Value; switch (child.Name) { case ObservedPathEntryConstants.Path: currPathNode = child; // Switch from literal string "path" to actual file system path // [5'] "B:/out/objects/n/x/qbkexxlc8je93wycw7yrlw0a305n7k/xunit-out/CacheMissAnaAD836B23/3/obj/readonly/src_0":"" currPathNode.Name = currPathNode.Values[0]; // The name captures the node's value, so clear the values to avoid extraneous value comparison when diffing currPathNode.Values.Clear(); JsonTree.ReparentBranch(currPathNode, parentPathNode); // [6'] "Flags":"IsDirectoryPath, DirectoryEnumeration, DirectoryEnumerationWithAllPattern" JsonTree.ReparentBranch(currFlagNode, currPathNode); // [7'] "EnumeratePatternRegex":"^.*$" JsonTree.ReparentBranch(currRegexNode, currPathNode); // [3'] "ObservedInput":"E:VSO0:E0C5007DC8CF2D331236F156F136C50CACE2A5D549CD132D9B44ABD1F13D50CC00" // [8] "Members":"[src_1, src_2]" ReparentObservedInput(observedInputIt.Value, currPathNode); observedInputIt = observedInputsNode.Children.First; break; case ObservedPathEntryConstants.Flags: // [6] "Flags":"IsDirectoryPath, DirectoryEnumeration, DirectoryEnumerationWithAllPattern" currFlagNode = child; JsonTree.EmancipateBranch(currFlagNode); break; case ObservedPathEntryConstants.EnumeratePatternRegex: // [7] "EnumeratePatternRegex":"^.*$" currRegexNode = child; JsonTree.EmancipateBranch(currRegexNode); break; default: break; } } // Re-parent any other branches of the path set tree to the strong fingerprint tree // so they are still in a full strong fingerprint tree comparison. // We re-parent under parentPathNode because branches of pathSetTree are elements of PathSet var node = pathSetTree.Children.First; while (node != null) { JsonTree.ReparentBranch(node.Value, parentPathNode); node = pathSetTree.Children.First; } return(strongFingerprintTree); }