Example #1
0
 private static void PopulateNameValuePairData(JsonNode nameValuePairNode, Dictionary <string, NameValuePairData> nameValuePairData)
 {
     JsonTree.VisitTree(
         nameValuePairNode,
         node =>
     {
         nameValuePairData[node.Name] = new NameValuePairData(
             node.Name,
             node.Values.Count > 0 ? node.Values[0] : CacheMissAnalysisUtilities.RepeatedStrings.MissingValue);
     },
         recurse: false);
 }
Example #2
0
        /// <summary>
        /// Diffs weak fingerprints.
        /// </summary>
        /// <param name="weakFingerprint">Weak fingerprint.</param>
        /// <param name="weakFingerprintTree">Weak fingerprint tree.</param>
        /// <param name="otherWeakFingerprint">Other weak fingerprint.</param>
        /// <param name="otherWeakFingerprintTree">Other weak fingerprint tree.</param>
        /// <returns></returns>
        public static JObject DiffWeakFingerprints(
            string weakFingerprint,
            JsonNode weakFingerprintTree,
            string otherWeakFingerprint,
            JsonNode otherWeakFingerprintTree)
        {
            JObject result = new JObject();

            if (weakFingerprint == otherWeakFingerprint)
            {
                return(result);
            }

            // {
            //   WeakFingerprint: { Old: old_weak_fingerprint, New: new_weak_fingerprint }
            // }
            AddPropertyIfNotNull(result, RenderSingleValueDiff("WeakFingerprint", weakFingerprint, otherWeakFingerprint));

            using (var weakFingerprintDataPool = JsonNodeMapPool.GetInstance())
                using (var otherWeakFingerprintDataPool = JsonNodeMapPool.GetInstance())
                {
                    var weakFingerprintData      = weakFingerprintDataPool.Instance;
                    var otherWeakFingerprintData = otherWeakFingerprintDataPool.Instance;

                    JsonTree.VisitTree(weakFingerprintTree, wfNode => weakFingerprintData[wfNode.Name]           = wfNode, recurse: false);
                    JsonTree.VisitTree(otherWeakFingerprintTree, wfNode => otherWeakFingerprintData[wfNode.Name] = wfNode, recurse: false);

                    var fields = new HashSet <string>(weakFingerprintData.Keys.Concat(otherWeakFingerprintData.Keys));

                    foreach (var field in fields)
                    {
                        bool getFieldNode      = weakFingerprintData.TryGetValue(field, out JsonNode fieldNode);
                        bool getOtherFieldNode = otherWeakFingerprintData.TryGetValue(field, out JsonNode otherFieldNode);

                        if (getFieldNode != getOtherFieldNode)
                        {
                            string fieldValue = getFieldNode
                            ? (fieldNode.Values != null && fieldNode.Values.Count == 1
                                ? fieldNode.Values[0]
                                : CacheMissAnalysisUtilities.RepeatedStrings.ExistentValue)
                            : CacheMissAnalysisUtilities.RepeatedStrings.UnspecifiedValue;
                            string otherFieldValue = getOtherFieldNode
                            ? (otherFieldNode.Values != null && otherFieldNode.Values.Count == 1
                                ? otherFieldNode.Values[0]
                                : CacheMissAnalysisUtilities.RepeatedStrings.ExistentValue)
                            : CacheMissAnalysisUtilities.RepeatedStrings.UnspecifiedValue;

                            AddPropertyIfNotNull(result, RenderSingleValueDiff(field, fieldValue, otherFieldValue));
                        }
                        else if (getFieldNode && getOtherFieldNode)
                        {
                            Contract.Assert(fieldNode != null);
                            Contract.Assert(otherFieldNode != null);

                            AddPropertyIfNotNull(result, DiffWeakFingerprintField(fieldNode, otherFieldNode));
                        }
                    }
                }

            Contract.Assert(result.Count > 0);

            return(result);
        }
Example #3
0
        private static JProperty DiffWeakFingerprintField(JsonNode fieldNode, JsonNode otherFieldNode)
        {
            Contract.Requires(fieldNode != null);
            Contract.Requires(otherFieldNode != null);
            Contract.Requires(fieldNode.Name == otherFieldNode.Name);

            switch (fieldNode.Name)
            {
            case nameof(Process.Dependencies):
            {
                using (var inputFileDataPool = InputFileDataMapPool.GetInstance())
                    using (var otherInputFileDataPool = InputFileDataMapPool.GetInstance())
                    {
                        var inputFileData      = inputFileDataPool.Instance;
                        var otherInputFileData = otherInputFileDataPool.Instance;
                        populateInputFileData(fieldNode, inputFileData);
                        populateInputFileData(otherFieldNode, otherInputFileData);
                        return(ExtractUnorderedMapDiff(
                                   inputFileData,
                                   otherInputFileData,
                                   (dOld, dNew) => dOld.Equals(dNew),
                                   out var added,
                                   out var removed,
                                   out var changed)
                            ? new JProperty(fieldNode.Name, RenderUnorderedMapDiff(
                                                inputFileData,
                                                otherInputFileData,
                                                added,
                                                removed,
                                                changed,
                                                RenderPath,
                                                (dataA, dataB) => dataA.HashOrContent))
                            : null);
                    }
            }

            case nameof(Process.FileOutputs):
            {
                using (var outputFileDataPool = OutputFileDataMapPool.GetInstance())
                    using (var otherOutputFileDataPool = OutputFileDataMapPool.GetInstance())
                    {
                        var outputFileData      = outputFileDataPool.Instance;
                        var otherOutputFileData = otherOutputFileDataPool.Instance;
                        populateOutputFileData(fieldNode, outputFileData);
                        populateOutputFileData(otherFieldNode, otherOutputFileData);
                        return(ExtractUnorderedMapDiff(
                                   outputFileData,
                                   otherOutputFileData,
                                   (dOld, dNew) => dOld.Equals(dNew),
                                   out var added,
                                   out var removed,
                                   out var changed)
                            ? new JProperty(fieldNode.Name, RenderUnorderedMapDiff(
                                                outputFileData,
                                                otherOutputFileData,
                                                added,
                                                removed,
                                                changed,
                                                RenderPath,
                                                (dataA, dataB) => dataA.Attributes))
                            : null);
                    }
            }

            case nameof(PipFingerprintField.ExecutionAndFingerprintOptions):
            case nameof(Process.EnvironmentVariables):
            {
                var result = DiffNameValuePairs(fieldNode, otherFieldNode);
                return(result != null ? new JProperty(fieldNode.Name, result) : null);
            }

            case nameof(Process.DirectoryDependencies):
            case nameof(Process.DirectoryOutputs):
            case nameof(Process.UntrackedPaths):
            case nameof(Process.UntrackedScopes):
            case nameof(Process.PreserveOutputAllowlist):
            case nameof(Process.SuccessExitCodes):
            case PipFingerprintField.Process.SourceChangeAffectedInputList:
            case nameof(Process.ChildProcessesToBreakawayFromSandbox):
            {
                var data      = fieldNode.Values;
                var otherData = otherFieldNode.Values;
                return(ExtractUnorderedListDiff(data, otherData, out var added, out var removed)
                        ? new JProperty(fieldNode.Name, RenderUnorderedListDiff(added, removed, RenderPath))
                        : null);
            }

            default:
                return(RenderSingleValueDiff(fieldNode.Name, getSingleValueNode(fieldNode), getSingleValueNode(otherFieldNode)));
            }

            string getSingleValueNode(JsonNode node) =>
            node.Values.Count > 0
                    ? node.Values[0]
                    : CacheMissAnalysisUtilities.RepeatedStrings.MissingValue;

            void populateInputFileData(JsonNode dependencyNode, Dictionary <string, InputFileData> inputFileData)
            {
                JsonTree.VisitTree(
                    dependencyNode,
                    node =>
                {
                    string value = CacheMissAnalysisUtilities.RepeatedStrings.MissingValue;
                    if (node.Values.Count > 0)
                    {
                        value = node.Values[0];
                    }
                    else if (node.Children.First != null &&
                             node.Children.First.Value.Name == PipFingerprintField.FileDependency.PathNormalizedWriteFileContent &&
                             node.Children.First.Value.Values.Count > 0)
                    {
                        value = node.Children.First.Value.Values[0];
                    }

                    inputFileData[node.Name] = new InputFileData(node.Name, value);
                },
                    recurse: false);
            }

            void populateOutputFileData(JsonNode outputNode, Dictionary <string, OutputFileData> outputFileData)
            {
                JsonTree.VisitTree(
                    outputNode,
                    node =>
                {
                    string value = CacheMissAnalysisUtilities.RepeatedStrings.MissingValue;
                    if (node.Children.First != null &&
                        node.Children.First.Value.Name == PipFingerprintField.FileOutput.Attributes &&
                        node.Children.First.Value.Values.Count > 0)
                    {
                        value = node.Children.First.Value.Values[0];
                    }

                    outputFileData[node.Name] = new OutputFileData(node.Name, value);
                },
                    recurse: false);
            }
        }