public Construction() { Build = new Build(); Build.Name = "Build"; this.stringTable = Build.StringTable; this.messageProcessor = new MessageProcessor(this, stringTable); Intern(Strings.Assembly); Intern(Strings.CommandLineArguments); Intern(Strings.DoubleWrites); Intern(Strings.Evaluation); Intern(Strings.Note); Intern(Strings.OutputItems); Intern(Strings.Parameters); Intern(Strings.Properties); Intern(Strings.UnusedLocations); Intern(Strings.Warnings); Intern(nameof(AddItem)); Intern(nameof(CopyTask)); Intern(nameof(CscTask)); Intern(nameof(ResolveAssemblyReferenceTask)); Intern(nameof(EntryTarget)); Intern(nameof(Folder)); Intern(nameof(Import)); Intern(nameof(Item)); Intern(nameof(Metadata)); Intern(nameof(NoImport)); Intern(nameof(Parameter)); Intern(nameof(ProjectEvaluation)); Intern(nameof(Property)); Intern(nameof(RemoveItem)); Intern(nameof(Target)); Intern(nameof(Task)); Intern(nameof(TimedNode)); }
public Construction() { Build = new Build(); Build.Name = "Build"; this.stringTable = Build.StringTable; this.messageProcessor = new MessageProcessor(this, stringTable); }
private BaseNode ReadNode(XElement element) { var name = element.Name.LocalName; if (name == "Metadata") { var metadata = new Metadata() { Name = GetString(element, AttributeNames.Name), Value = ReadTextContent(element) }; return(metadata); } else if (name == "Property") { var property = new Property() { Name = GetString(element, AttributeNames.Name), Value = ReadTextContent(element) }; return(property); } var node = Serialization.CreateNode(name); var folder = node as Folder; if (folder != null) { folder.Name = name; } var build = node as Build; if (build != null) { this.stringTable = build.StringTable; } ReadAttributes(node, element); if (element.HasElements) { var treeNode = (TreeNode)node; foreach (var childElement in element.Elements()) { var childNode = ReadNode(childElement); treeNode.AddChild(childNode); } } return(node); }
private object ReadNode(XElement element) { var name = element.Name.LocalName; if (name == "Metadata") { var metadata = new Metadata() { Name = GetString(element, AttributeNames.Name), Value = ReadTextContent(element) }; return(metadata); } else if (name == "Property") { var property = new Property() { Name = GetString(element, AttributeNames.Name), Value = ReadTextContent(element) }; return(property); } Type type = null; if (!Serialization.ObjectModelTypes.TryGetValue(name, out type)) { type = typeof(Folder); } var node = (TreeNode)Activator.CreateInstance(type); var build = node as Build; if (build != null) { this.stringTable = build.StringTable; } ReadAttributes(node, element); if (element.HasElements) { foreach (var childElement in element.Elements()) { var childNode = ReadNode(childElement); node.AddChild(childNode); } } return(node); }
public Construction() { Build = new Build(); Build.Name = "Build"; this.stringTable = Build.StringTable; this.messageProcessor = new MessageProcessor(this, stringTable); Intern(Strings.Evaluation); Intern(Strings.Properties); Intern(Strings.OutputItems); Intern(Strings.Parameters); }
private static void VisitMessage(Message message, StringCache stringTable) { var match = Strings.ImportingProjectRegex.Match(message.Text); if (match.Success && match.Groups.Count == 5) { var project = match.Groups["File"].Value; var importedProject = match.Groups["ImportedProject"].Value; var line = int.Parse(match.Groups["Line"].Value); var column = int.Parse(match.Groups["Column"].Value); project = stringTable.Intern(project); importedProject = stringTable.Intern(importedProject); AddImport( message, project, importedProject, line, column, imported: true); return; } string reason; match = Strings.ProjectWasNotImportedRegex(message.Text, out reason); if (match.Success && match.Groups.Count > 4) { var project = match.Groups["File"].Value; var importedProject = match.Groups["ImportedProject"].Value; var line = int.Parse(match.Groups["Line"].Value); var column = int.Parse(match.Groups["Column"].Value); // var reason = match.Groups["Reason"].Value; project = stringTable.Intern(project); importedProject = stringTable.Intern(importedProject); reason = stringTable.Intern("Not imported due to " + reason); AddImport( message, project, importedProject, line, column, imported: false, reason: reason); return; } }
static Item Add(TreeNode parent, string text, Span span, int spaces, StringCache stringTable) { if (spaces >= span.Length || parent == null) { return(null); } string line = text.Substring(span.Start + spaces, span.Length - spaces); var item = new Item { Text = stringTable.Intern(line) }; parent.AddChild(item); return(item); }
public static void ParseThereWasAConflict(TreeNode parent, string message, StringCache stringTable) { if (lineSpans == null) { lineSpans = new List <Span>(10240); } lineSpans.Clear(); message.CollectLineSpans(lineSpans, includeLineBreakInSpan: false); Item item4 = null; Item item8 = null; Item item10 = null; for (int i = 0; i < lineSpans.Count; i++) { var lineSpan = lineSpans[i]; var numberOfLeadingSpaces = TextUtilities.GetNumberOfLeadingSpaces(message, lineSpan); switch (numberOfLeadingSpaces) { case 0: case 4: item4 = Add(parent, message, lineSpan, numberOfLeadingSpaces, stringTable); item8 = null; item10 = null; break; case 8: item8 = Add(item4, message, lineSpan, numberOfLeadingSpaces, stringTable); item10 = null; break; case 10: item10 = Add(item8, message, lineSpan, numberOfLeadingSpaces, stringTable); break; case 12: Add(item10, message, lineSpan, numberOfLeadingSpaces, stringTable); break; default: Add(item10 ?? item8 ?? item4 ?? parent, message, lineSpan, numberOfLeadingSpaces, stringTable); break; } }
public static TextNode TryGetImportOrNoImport(string text, StringCache stringTable) { var match = Strings.ProjectImportedRegex.Match(text); if (match.Success && match.Groups.Count == 5) { var project = match.Groups["File"].Value; var importedProject = match.Groups["ImportedProject"].Value; var line = int.Parse(match.Groups["Line"].Value); var column = int.Parse(match.Groups["Column"].Value); project = stringTable.Intern(project); importedProject = stringTable.Intern(importedProject); var result = new Import(project, importedProject, line, column); return(result); } match = Strings.ProjectWasNotImportedRegex(text, out string reason); if (match.Success && match.Groups.Count > 4) { var project = match.Groups["File"].Value; var importedProject = match.Groups["ImportedProject"].Value; var line = int.Parse(match.Groups["Line"].Value); var column = int.Parse(match.Groups["Column"].Value); project = stringTable.Intern(project); importedProject = stringTable.Intern(importedProject); reason = stringTable.Intern("Not imported due to " + reason); var noImport = new NoImport(project, importedProject, line, column, reason); return(noImport); } return(null); }
/// <summary> /// Parses a log output string to a list of Items (e.g. ItemGroup with metadata or property string). /// </summary> /// <param name="message">The message output from the logger.</param> /// <param name="prefix">The prefix parsed out (e.g. 'Output Item(s): '.).</param> /// <param name="name">Out: The name of the list.</param> /// <returns>List of items within the list and all metadata.</returns> public static object ParsePropertyOrItemList(string message, string prefix, StringCache stringTable) { message = message.Replace("\r\n", "\n"); message = message.Replace('\r', '\n'); var lines = message.Split('\n'); if (lines.Length == 1) { var line = lines[0]; line = line.Substring(prefix.Length); var nameValue = ParseNameValue(line); var property = new Property { Name = stringTable.Intern(nameValue.Key), Value = stringTable.Intern(nameValue.Value) }; return(property); } var parameter = new Parameter(); if (lines[0].Length > prefix.Length) { // we have a weird case of multi-line value var nameValue = ParseNameValue(lines[0].Substring(prefix.Length)); parameter.Name = stringTable.Intern(nameValue.Key); parameter.AddChild(new Item { Text = stringTable.Intern(nameValue.Value.Replace("\r", "")) }); for (int i = 1; i < lines.Length; i++) { parameter.AddChild(new Item { Text = stringTable.Intern(lines[i].Replace("\r", "")) }); } return(parameter); } Item currentItem = null; foreach (var line in lines) { switch (GetNumberOfLeadingSpaces(line)) { case 4: if (line.EndsWith("=", StringComparison.Ordinal)) { parameter.Name = stringTable.Intern(line.Substring(4, line.Length - 5)); } break; case 8: currentItem = new Item { Text = stringTable.Intern(line.Substring(8)) }; parameter.AddChild(currentItem); break; case 16: if (currentItem != null) { var currentLine = line.Substring(16); if (!currentLine.Contains("=")) { // must be a continuation of the metadata value from the previous line if (currentItem.HasChildren) { var metadata = currentItem.Children[currentItem.Children.Count - 1] as Metadata; if (metadata != null) { metadata.Value = stringTable.Intern((metadata.Value ?? "") + currentLine); } } } else { var nameValue = ParseNameValue(currentLine); var metadata = new Metadata { Name = stringTable.Intern(nameValue.Key), Value = stringTable.Intern(nameValue.Value) }; currentItem.AddChild(metadata); } } break; } } return(parameter); }
public MessageProcessor(Construction construction, StringCache stringTable) { this.construction = construction; this.stringTable = stringTable; }
public static void HandleThereWasAConflict(Parameter parameter, string message, StringCache stringTable) { var numberOfLeadingSpaces = TextUtilities.GetNumberOfLeadingSpaces(message); TreeNode node = parameter; switch (numberOfLeadingSpaces) { case 0: parameter.AddChild(new Item() { Text = stringTable.Intern(message) }); break; case 4: node = parameter.LastChild as TreeNode ?? node; Add(node, message, 4); break; case 6: { if (parameter.LastChild is TreeNode item) { node = item; if (item.LastChild is TreeNode item2) { node = item2; } } Add(node, message, 6); } break; case 8: { if (parameter.LastChild is TreeNode item) { node = item; if (item.LastChild is TreeNode item2) { node = item2; if (item2.LastChild is TreeNode item3) { node = item3; } } } Add(node, message, 8); } break; default: Add(node, message, 0); break; } void Add(TreeNode parent, string text, int spaces) { text = text.Substring(spaces); parent.AddChild(new Item { Text = stringTable.Intern(text) }); } }
/// <summary> /// Parses a log output string to a list of Items (e.g. ItemGroup with metadata or property string). /// </summary> /// <param name="message">The message output from the logger.</param> /// <param name="prefix">The prefix parsed out (e.g. 'Output Item(s): '.).</param> /// <returns>List of items within the list and all metadata.</returns> public static object ParsePropertyOrItemList(string message, string prefix, StringCache stringTable) { if (!TextUtilities.ContainsLineBreak(message)) { var nameValue = TextUtilities.ParseNameValue(message, trimFromStart: prefix.Length); var property = new Property { Name = stringTable.Intern(nameValue.Key), Value = stringTable.Intern(nameValue.Value) }; return(property); } // Can't use a field initializer with ThreadStatic. if (lineSpans == null) { lineSpans = new List <Span>(10240); } lineSpans.Clear(); message.CollectLineSpans(lineSpans, includeLineBreakInSpan: false); var parameter = new Parameter(); if (lineSpans[0].Length > prefix.Length) { // we have a weird case of multi-line value var nameValue = TextUtilities.ParseNameValue(message, lineSpans[0].Skip(prefix.Length)); parameter.Name = stringTable.Intern(nameValue.Key); parameter.AddChild(new Item { Text = stringTable.Intern(nameValue.Value) }); for (int i = 1; i < lineSpans.Count; i++) { parameter.AddChild(new Item { Text = stringTable.Intern(message.Substring(lineSpans[i])) }); } return(parameter); } Item currentItem = null; Property currentProperty = null; foreach (var lineSpan in lineSpans) { if (TextUtilities.IsWhitespace(message, lineSpan)) { continue; } var numberOfLeadingSpaces = TextUtilities.GetNumberOfLeadingSpaces(message, lineSpan); switch (numberOfLeadingSpaces) { case 4: if (message[lineSpan.End - 1] == '=') { parameter.Name = stringTable.Intern(message.Substring(lineSpan.Start + 4, lineSpan.Length - 5)); } break; case 8: var skip8 = message.Substring(lineSpan.Skip(8)); var equals = skip8.IndexOf('='); if (equals != -1) { var kvp = TextUtilities.ParseNameValueWithEqualsPosition(skip8, equals); currentProperty = new Property { Name = stringTable.Intern(kvp.Key), Value = stringTable.Intern(kvp.Value) }; parameter.AddChild(currentProperty); currentItem = null; } else { currentItem = new Item { Text = stringTable.Intern(skip8) }; parameter.AddChild(currentItem); currentProperty = null; } break; case 16: if (currentItem == null && currentProperty != null) { // we incorrectly interpreted the previous line as Property, not Item (because it had '=') // and so we created a property out of name/value. // Fix this by turning it into an Item. if (parameter.LastChild == currentProperty) { currentItem = new Item { Text = currentProperty.Name + "=" + currentProperty.Value }; parameter.Children.RemoveAt(parameter.Children.Count - 1); currentProperty = null; parameter.AddChild(currentItem); } } if (currentItem != null) { var span16 = lineSpan.Skip(16); var equals16 = message.IndexOf(span16, '='); if (equals16 == -1) { // must be a continuation of the metadata value from the previous line if (currentItem.HasChildren) { var metadata = currentItem.Children[currentItem.Children.Count - 1] as Metadata; if (metadata != null) { var currentLine = message.Substring(span16); if (!string.IsNullOrEmpty(metadata.Value)) { metadata.Value = metadata.Value + currentLine; } else { metadata.Value = currentLine; } } } } else { var nameValue = TextUtilities.ParseNameValueWithEqualsPosition(message, span16, equals16); var metadata = new Metadata { Name = stringTable.Intern(nameValue.Key), Value = stringTable.Intern(nameValue.Value) }; currentItem.AddChild(metadata); } } break; default: var line = message.Substring(lineSpan); if (numberOfLeadingSpaces == 0 && line == prefix) { continue; } // must be a continuation of a multi-line value if (currentProperty != null) { currentProperty.Value += "\n" + line; } else if (currentItem != null && currentItem.HasChildren) { var metadata = currentItem.Children[currentItem.Children.Count - 1] as Metadata; if (metadata != null) { metadata.Value = (metadata.Value ?? "") + line; } } break; } } return(parameter); }
public Build Read(Stream stream) { Build build = new Build(); this.stringTable = build.StringTable; var stack = new Stack <object>(1024); stack.Push(build); XmlNodeType previous = XmlNodeType.None; try { var xmlReaderSettings = new XmlReaderSettings() { IgnoreWhitespace = true, }; using (reader = XmlReader.Create(stream, xmlReaderSettings)) { reader.MoveToContent(); ReadAttributes(); PopulateAttributes(build); // read the attributes on the root Build element that we created manually while (reader.Read()) { var nodeType = reader.NodeType; switch (reader.NodeType) { case XmlNodeType.Element: var node = ReadNode(); var parent = (TreeNode)stack.Peek(); parent.AddChild(node); if (!reader.IsEmptyElement) { stack.Push(node); } break; case XmlNodeType.EndElement: { // if the element content is an empty string if (previous == XmlNodeType.Element) { var valueNode = stack.Peek(); SetElementValue(valueNode, ""); } stack.Pop(); break; } case XmlNodeType.Text: { var valueNode = stack.Peek(); string value = reader.Value; SetElementValue(valueNode, stringTable.Intern(value)); break; } case XmlNodeType.Whitespace: { var valueNode = stack.Peek(); var nameValueNode = valueNode as NameValueNode; if (nameValueNode != null) { nameValueNode.Value = GetCurrentValue(); } else { var message = valueNode as Message; if (message != null) { message.Text = GetCurrentValue(); } } break; } case XmlNodeType.None: case XmlNodeType.Attribute: case XmlNodeType.CDATA: case XmlNodeType.EntityReference: case XmlNodeType.Entity: case XmlNodeType.ProcessingInstruction: case XmlNodeType.Comment: case XmlNodeType.Document: case XmlNodeType.DocumentType: case XmlNodeType.DocumentFragment: case XmlNodeType.Notation: case XmlNodeType.SignificantWhitespace: case XmlNodeType.EndEntity: case XmlNodeType.XmlDeclaration: default: break; } previous = nodeType; } } } catch (Exception ex) { build = new Build() { Succeeded = false }; build.AddChild(new Error() { Text = "Error when opening XML log file." }); build.AddChild(new Error() { Text = ex.ToString() }); } return(build); }
public static TextNode TryGetImportOrNoImport(ProjectImportedEventArgs args, StringCache stringTable) { var message = (string)buildEventArgsFieldMessage.GetValue(args); var arguments = lazyFormattedBuildEventArgsFieldArguments.GetValue(args) as object[]; if (arguments != null && arguments.Length > 0) { if (arguments.Length == 4) { if (message == Strings.ProjectImported) { var importedProject = stringTable.Intern((string)arguments[0]); var containingProject = stringTable.Intern((string)arguments[1]); var line = ParseInt(arguments[2]); var column = ParseInt(arguments[3]); var import = new Import( containingProject, importedProject, line, column); return(import); } else if ( message == Strings.ProjectImportSkippedExpressionEvaluatedToEmpty || message == Strings.ProjectImportSkippedNoMatches || message == Strings.ProjectImportSkippedMissingFile || message == Strings.ProjectImportSkippedInvalidFile) { var importedProject = stringTable.Intern((string)arguments[0]); var containingProject = stringTable.Intern((string)arguments[1]); var line = ParseInt(arguments[2]); var column = ParseInt(arguments[3]); string reason = ""; if (message == Strings.ProjectImportSkippedExpressionEvaluatedToEmpty) { reason = "empty expression"; } else if (message == Strings.ProjectImportSkippedNoMatches) { reason = "no matches"; } else if (message == Strings.ProjectImportSkippedMissingFile) { reason = "missing file"; } else if (message == Strings.ProjectImportSkippedInvalidFile) { reason = "invalid file"; } var noImport = new NoImport( containingProject, importedProject, line, column, stringTable.Intern(reason)); return(noImport); } } else if (arguments.Length == 6) { if (message == Strings.ProjectImportSkippedFalseCondition) { var project = (string)arguments[0]; var containingProject = (string)arguments[1]; var line = ParseInt(arguments[2]); var column = ParseInt(arguments[3]); var condition = (string)arguments[4]; var evaluatedCondition = (string)arguments[5]; string reason = $"false condition; ({condition} was evaluated as {evaluatedCondition})."; var noImport = new NoImport( stringTable.Intern(containingProject), stringTable.Intern(project), line, column, stringTable.Intern(reason)); return(noImport); } } else if (arguments.Length == 1) { if (message == Strings.CouldNotResolveSdk) { var sdk = (string)arguments[0]; var noImport = new NoImport( stringTable.Intern(args.ProjectFile), stringTable.Intern(args.ImportedProjectFile), args.LineNumber, args.ColumnNumber, stringTable.Intern(string.Format(message, sdk))); return(noImport); } } } var parsed = TryGetImportOrNoImport(args.Message, stringTable); return(parsed); }
/// <summary> /// Parses a log output string to a list of Items (e.g. ItemGroup with metadata or property string). /// </summary> /// <param name="message">The message output from the logger.</param> /// <param name="prefix">The prefix parsed out (e.g. 'Output Item(s): '.).</param> /// <param name="name">Out: The name of the list.</param> /// <returns>List of items within the list and all metadata.</returns> public static object ParsePropertyOrItemList(string message, string prefix, StringCache stringTable) { if (!Utilities.ContainsLineBreak(message)) { var nameValue = Utilities.ParseNameValue(message, trimFromStart: prefix.Length); var property = new Property { Name = stringTable.Intern(nameValue.Key), Value = stringTable.Intern(nameValue.Value) }; return(property); } message = message.Replace("\r\n", "\n"); message = message.Replace('\r', '\n'); var lines = message.Split('\n'); var parameter = new Parameter(); if (lines[0].Length > prefix.Length) { // we have a weird case of multi-line value var nameValue = Utilities.ParseNameValue(lines[0].Substring(prefix.Length)); parameter.Name = stringTable.Intern(nameValue.Key); parameter.AddChild(new Item { Text = stringTable.Intern(nameValue.Value.Replace("\r", "")) }); for (int i = 1; i < lines.Length; i++) { parameter.AddChild(new Item { Text = stringTable.Intern(lines[i].Replace("\r", "")) }); } return(parameter); } Item currentItem = null; Property currentProperty = null; foreach (var line in lines) { var numberOfLeadingSpaces = Utilities.GetNumberOfLeadingSpaces(line); switch (numberOfLeadingSpaces) { case 4: if (line.EndsWith("=", StringComparison.Ordinal)) { parameter.Name = stringTable.Intern(line.Substring(4, line.Length - 5)); } break; case 8: if (line.IndexOf('=') != -1) { var kvp = Utilities.ParseNameValue(line.Substring(8)); currentProperty = new Property { Name = stringTable.Intern(kvp.Key), Value = stringTable.Intern(kvp.Value) }; parameter.AddChild(currentProperty); currentItem = null; } else { currentItem = new Item { Text = stringTable.Intern(line.Substring(8)) }; parameter.AddChild(currentItem); currentProperty = null; } break; case 16: var currentLine = line.Substring(16); if (currentItem != null) { if (!currentLine.Contains("=")) { // must be a continuation of the metadata value from the previous line if (currentItem.HasChildren) { var metadata = currentItem.Children[currentItem.Children.Count - 1] as Metadata; if (metadata != null) { metadata.Value = stringTable.Intern((metadata.Value ?? "") + currentLine); } } } else { var nameValue = Utilities.ParseNameValue(currentLine); var metadata = new Metadata { Name = stringTable.Intern(nameValue.Key), Value = stringTable.Intern(nameValue.Value) }; currentItem.AddChild(metadata); } } break; default: if (numberOfLeadingSpaces == 0 && line == prefix) { continue; } // must be a continuation of a multi-line value if (currentProperty != null) { currentProperty.Value += "\n" + line; } else if (currentItem != null && currentItem.HasChildren) { var metadata = currentItem.Children[currentItem.Children.Count - 1] as Metadata; if (metadata != null) { metadata.Value = (metadata.Value ?? "") + line; } } break; } } return(parameter); }
public static void Analyze(Folder evaluation, StringCache stringTable) { evaluation.VisitAllChildren <Message>(m => VisitMessage(m, stringTable), takeChildrenSnapshot: true); }
public void AnalyzeResolveAssemblyReference(Task rar) { stringTable = rar.GetNearestParent <Build>()?.StringTable; currentUsedLocations.Clear(); var results = rar.FindChild <Folder>(c => c.Name == Strings.Results); var parameters = rar.FindChild <Folder>(c => c.Name == Strings.Parameters); TotalRARDuration += rar.Duration; IList <string> searchPaths = null; if (parameters != null) { var searchPathsNode = parameters.FindChild <NamedNode>(c => c.Name == Strings.SearchPaths); if (searchPathsNode != null) { searchPaths = searchPathsNode.Children.Select(c => c.ToString()).ToArray(); } } if (results != null) { results.SortChildren(); foreach (var reference in results.Children.OfType <Parameter>()) { const string ResolvedFilePathIs = "Resolved file path is \""; string resolvedFilePath = null; var resolvedFilePathNode = reference.FindChild <Item>(i => i.ToString().StartsWith(ResolvedFilePathIs, StringComparison.Ordinal)); if (resolvedFilePathNode != null) { var text = resolvedFilePathNode.ToString(); resolvedFilePath = text.Substring(ResolvedFilePathIs.Length, text.Length - ResolvedFilePathIs.Length - 2); } const string ReferenceFoundAt = "Reference found at search path location \""; var foundAtLocation = reference.FindChild <Item>(i => i.ToString().StartsWith(ReferenceFoundAt, StringComparison.Ordinal)); if (foundAtLocation != null) { var text = foundAtLocation.ToString(); var location = text.Substring(ReferenceFoundAt.Length, text.Length - ReferenceFoundAt.Length - 2); // filter out the case where the assembly is resolved from the AssemblyFiles parameter // In this case the location matches the resolved file path. if (resolvedFilePath == null || resolvedFilePath != location) { UsedLocations.Add(location); currentUsedLocations.Add(location); } } var thisReferenceName = ParseReferenceName(reference.Name); if (reference.Name.StartsWith("Dependency ", StringComparison.Ordinal) || reference.Name.StartsWith("Unified Dependency ", StringComparison.Ordinal)) { bool foundNotCopyLocalBecauseMetadata = false; var requiredBy = new List <Item>(); Item notCopyLocalMessage = null; foreach (var message in reference.Children.OfType <Item>()) { string text = message.Text; if (text.StartsWith("Required by \"")) { requiredBy.Add(message); } else if (text == @"This reference is not ""CopyLocal"" because at least one source item had ""Private"" set to ""false"" and no source items had ""Private"" set to ""true"".") { foundNotCopyLocalBecauseMetadata = true; notCopyLocalMessage = message; } } if (foundNotCopyLocalBecauseMetadata) { var assemblies = rar.FindChild <Folder>(Strings.Parameters)?.FindChild <Parameter>(Strings.Assemblies); if (assemblies != null) { var dictionary = assemblies.Children .OfType <Item>() .GroupBy(i => i.Text, StringComparer.OrdinalIgnoreCase) .ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase); foreach (var sourceItem in requiredBy) { int prefixLength = "Required by \"".Length; string text = sourceItem.Text; var referenceName = text.Substring(prefixLength, text.Length - prefixLength - 2); Item foundSourceItem; if (dictionary.TryGetValue(referenceName, out foundSourceItem)) { foreach (var metadata in foundSourceItem.Children.OfType <Metadata>()) { if (metadata.Name == "Private") { sourceItem.AddChild(new Metadata() { Name = metadata.Name, Value = metadata.Value }); if (notCopyLocalMessage != null) { var message = $"{foundSourceItem} has {metadata.Name} set to {metadata.Value}"; message = stringTable?.Intern(message); notCopyLocalMessage.AddChild(new Message { Text = message }); } } } } } } } } } } if (searchPaths != null) { foreach (var searchPath in searchPaths) { if (currentUsedLocations.Contains(searchPath)) { var usedLocations = rar.GetOrCreateNodeWithName <Folder>(Strings.UsedLocations); usedLocations.AddChild(new Item { Text = searchPath }); UnusedLocations.Remove(searchPath); } else { var unusedLocations = rar.GetOrCreateNodeWithName <Folder>(Strings.UnusedLocations); unusedLocations.AddChild(new Item { Text = searchPath }); if (!UsedLocations.Contains(searchPath)) { UnusedLocations.Add(searchPath); } else { UnusedLocations.Remove(searchPath); } } } } }