diff --git a/src/ResourcesGenerator/ResourceCreator.cs b/src/ResourcesGenerator/ResourceCreator.cs index 1141e016..878b3dee 100644 --- a/src/ResourcesGenerator/ResourceCreator.cs +++ b/src/ResourcesGenerator/ResourceCreator.cs @@ -1,4 +1,5 @@ using System.Collections; + using System.Collections.Generic; using System.Globalization; using System.IO; @@ -51,6 +52,8 @@ public class ResourceCreator "TaskFoundFromFactory", "TaskFound", "PropertyReassignment", + "PropertyAssignment", + "UninitializedPropertyRead", "ProjectImported", "ProjectImportSkippedMissingFile", "ProjectImportSkippedInvalidFile", @@ -66,16 +69,7 @@ public class ResourceCreator "SearchPathsForMSBuildExtensionsPath", "OverridingTarget", "TryingExtensionsPath", - "ProjectImported", "DuplicateImport", - "ProjectImportSkippedEmptyFile", - "ProjectImportSkippedFalseCondition", - "ProjectImportSkippedNoMatches", - "ProjectImportSkippedMissingFile", - "ProjectImportSkippedInvalidFile", - "PropertyReassignment", - "EvaluationStarted", - "EvaluationFinished", "CouldNotResolveSdk", "ProjectImportSkippedExpressionEvaluatedToEmpty", "SkipTargetBecauseOutputsUpToDate", diff --git a/src/StructuredLogger/BinaryLogger/BinaryLogger.cs b/src/StructuredLogger/BinaryLogger/BinaryLogger.cs index aecfac2b..09e7be2a 100644 --- a/src/StructuredLogger/BinaryLogger/BinaryLogger.cs +++ b/src/StructuredLogger/BinaryLogger/BinaryLogger.cs @@ -78,6 +78,8 @@ public sealed class BinaryLogger : ILogger // BuildCheckTracingEvent, BuildCheckAcquisitionEvent, BuildSubmissionStartedEvent // version 24: // - new record kind: BuildCanceledEvent + // version 25: + // - add extra information to PropertyInitialValueSetEventArgs and PropertyReassignmentEventArgs and change parsing logic of Message property in them. // This should be never changed. // The minimum version of the binary log reader that can read log of above version. @@ -85,7 +87,7 @@ public sealed class BinaryLogger : ILogger // The current version of the binary log representation. // Changes with each update of the binary log format. - internal const int FileFormatVersion = 24; + internal const int FileFormatVersion = 25; // The minimum version of the binary log reader that can read log of above version. // This should be changed only when the binary log format is changed in a way that would prevent it from being // read by older readers. (changing of the individual BuildEventArgs or adding new is fine - as reader can diff --git a/src/StructuredLogger/BinaryLogger/BuildEventArgsReader.cs b/src/StructuredLogger/BinaryLogger/BuildEventArgsReader.cs index 3e633070..710efd46 100644 --- a/src/StructuredLogger/BinaryLogger/BuildEventArgsReader.cs +++ b/src/StructuredLogger/BinaryLogger/BuildEventArgsReader.cs @@ -1360,7 +1360,25 @@ private BuildEventArgs ReadPropertyReassignmentEventArgs() string message = fields.Message; if (_fileFormatVersion >= 13) { - message = GetPropertyReassignmentMessage(propertyName, newValue, previousValue, location); + if (_fileFormatVersion >= 25) + { + var extendedEvent = new ExtendedPropertyReassignmentEventArgs( + propertyName, + previousValue, + newValue, + fields.File, + fields.LineNumber, + fields.ColumnNumber, + GetPropertyReassignmentMessage(propertyName, newValue, previousValue, $"{fields.File} ({fields.LineNumber},{fields.ColumnNumber})")); + + SetCommonFields(extendedEvent, fields); + + return extendedEvent; + } + else + { + message = GetPropertyReassignmentMessage(propertyName, newValue, previousValue, location); + } } var e = new PropertyReassignmentEventArgs( @@ -1373,7 +1391,6 @@ private BuildEventArgs ReadPropertyReassignmentEventArgs() fields.SenderName, fields.Importance); SetCommonFields(e, fields); - return e; } @@ -1381,10 +1398,16 @@ private BuildEventArgs ReadUninitializedPropertyReadEventArgs() { var fields = ReadBuildEventArgsFields(readImportance: true); string propertyName = ReadDeduplicatedString(); + string? message = fields.Message ?? string.Empty; + + if (_fileFormatVersion >= 25) + { + message = FormatResourceStringIgnoreCodeAndKeyword(Strings.UninitializedPropertyRead, propertyName); + } var e = new UninitializedPropertyReadEventArgs( propertyName, - fields.Message, + message, fields.HelpKeyword, fields.SenderName, fields.Importance); @@ -1401,11 +1424,24 @@ private BuildEventArgs ReadPropertyInitialValueSetEventArgs() string propertyValue = ReadDeduplicatedString(); string propertySource = ReadDeduplicatedString(); - var e = new PropertyInitialValueSetEventArgs( + string message = fields.Message; + if (_fileFormatVersion >= 25) + { + string formattedSource = string.IsNullOrEmpty(fields.File) + ? propertySource + : $"{fields.File} ({fields.LineNumber},{fields.ColumnNumber})"; + + message = FormatResourceStringIgnoreCodeAndKeyword(Strings.PropertyAssignment, propertyName, propertyValue, formattedSource); + } + + var e = new ExtendedPropertyInitialValueSetEventArgs( propertyName, propertyValue, propertySource, - fields.Message, + fields.File, + fields.LineNumber, + fields.ColumnNumber, + message, fields.HelpKeyword, fields.SenderName, fields.Importance); diff --git a/src/StructuredLogger/BinaryLogger/ExtendedPropertyInitialValueSetEventArgs.cs b/src/StructuredLogger/BinaryLogger/ExtendedPropertyInitialValueSetEventArgs.cs new file mode 100644 index 00000000..fe649e2c --- /dev/null +++ b/src/StructuredLogger/BinaryLogger/ExtendedPropertyInitialValueSetEventArgs.cs @@ -0,0 +1,53 @@ +using Microsoft.Build.Framework; + +namespace StructuredLogger.BinaryLogger +{ + internal class ExtendedPropertyInitialValueSetEventArgs : BuildMessageEventArgs + { + /// + /// Creates an instance of the class. + /// + /// The name of the property. + /// The value of the property. + /// The source of the property. + /// The file associated with the event. + /// The line number (0 if not applicable). + /// The column number (0 if not applicable). + /// The message of the property. + /// The help keyword. + /// The sender name of the event. + /// The importance of the message. + public ExtendedPropertyInitialValueSetEventArgs( + string propertyName, + string propertyValue, + string propertySource, + string file, + int line, + int column, + string message, + string helpKeyword = null, + string senderName = null, + MessageImportance importance = MessageImportance.Low) + : base(subcategory: null, code: null, file: file, lineNumber: line, columnNumber: column, 0, 0, message, helpKeyword, senderName, importance) + { + PropertyName = propertyName; + PropertyValue = propertyValue; + PropertySource = propertySource; + } + + /// + /// The name of the property. + /// + public string PropertyName { get; set; } + + /// + /// The value of the property. + /// + public string PropertyValue { get; set; } + + /// + /// The source of the property. + /// + public string PropertySource { get; set; } + } +} diff --git a/src/StructuredLogger/BinaryLogger/ExtendedPropertyReassignmentEventArgs.cs b/src/StructuredLogger/BinaryLogger/ExtendedPropertyReassignmentEventArgs.cs new file mode 100644 index 00000000..51e434fb --- /dev/null +++ b/src/StructuredLogger/BinaryLogger/ExtendedPropertyReassignmentEventArgs.cs @@ -0,0 +1,53 @@ +using Microsoft.Build.Framework; + +namespace StructuredLogger.BinaryLogger +{ + internal class ExtendedPropertyReassignmentEventArgs : BuildMessageEventArgs + { + /// + /// Creates an instance of the class. + /// + /// The name of the property whose value was reassigned. + /// The previous value of the reassigned property. + /// The new value of the reassigned property. + /// The file associated with the event. + /// The line number (0 if not applicable). + /// The column number (0 if not applicable). + /// The message of the property. + /// The help keyword. + /// The sender name of the event. + /// The importance of the message. + public ExtendedPropertyReassignmentEventArgs( + string propertyName, + string previousValue, + string newValue, + string file, + int line, + int column, + string message, + string helpKeyword = null, + string senderName = null, + MessageImportance importance = MessageImportance.Low) + : base(subcategory: null, code: null, file: file, lineNumber: line, columnNumber: column, 0, 0, message, helpKeyword, senderName, importance) + { + PropertyName = propertyName; + PreviousValue = previousValue; + NewValue = newValue; + } + + /// + /// The name of the property whose value was reassigned. + /// + public string PropertyName { get; set; } + + /// + /// The previous value of the reassigned property. + /// + public string PreviousValue { get; set; } + + /// + /// The new value of the reassigned property. + /// + public string NewValue { get; set; } + } +} diff --git a/src/StructuredLogger/Strings/Strings.cs b/src/StructuredLogger/Strings/Strings.cs index 9faed348..00f54ffd 100644 --- a/src/StructuredLogger/Strings/Strings.cs +++ b/src/StructuredLogger/Strings/Strings.cs @@ -144,6 +144,10 @@ private static void InitializeRegex() string propertyReassignment = GetPropertyReassignmentText(); PropertyReassignmentRegex = new Regex(propertyReassignment, RegexOptions.Compiled | RegexOptions.Singleline); + PropertyAssignment = GetString("PropertyAssignment"); + + UninitializedPropertyRead = GetString("UninitializedPropertyRead"); + // MSBuild 17.6 shipped with this hardcoded to English (the first part of the regex), but it was switched to a different // localized message in https://github.com/dotnet/msbuild/pull/8665. Support both here. string deferredResponseFile = ("^(?:Included response file: {0}|" + GetString("PickedUpSwitchesFromAutoResponse") + ")$") @@ -443,7 +447,9 @@ public static Regex CreateRegex(string text, int replacePlaceholders = 0, RegexO public static string ProjectImportSkippedFalseCondition { get; set; } public static string CouldNotResolveSdk { get; set; } public static string ProjectImportSkippedExpressionEvaluatedToEmpty { get; set; } + public static string PropertyAssignment { get; set; } public static string PropertyReassignment { get; set; } + public static string UninitializedPropertyRead { get; set; } public static string ProjectImportSkippedNoMatches { get; set; } public static string ProjectImportSkippedMissingFile { get; set; } public static string ProjectImportSkippedInvalidFile { get; set; } diff --git a/src/StructuredLogger/Strings/Strings.json b/src/StructuredLogger/Strings/Strings.json index 508e8191..97c889b8 100644 --- a/src/StructuredLogger/Strings/Strings.json +++ b/src/StructuredLogger/Strings/Strings.json @@ -35,6 +35,8 @@ "TargetAlreadyCompleteSuccess": "Target \"{0}\" skipped. Previously built successfully.", "TryingExtensionsPath": "Trying to import {0} using extensions path {1}", "PropertyReassignment": "Property reassignment: $({0})=\"{1}\" (previous value: \"{2}\") at {3}", + "PropertyAssignment": "Property initial value: $({0})=\"{1}\". Source: {2}", + "UninitializedPropertyRead": "Read uninitialized property \"{0}\"", "ProjectImportSkippedExpressionEvaluatedToEmpty": "Project \"{0}\" was not imported by \"{1}\" at ({2},{3}), due to the expression evaluating to an empty string.", "General.GlobalProperties": "Global Properties:", "General.UndefineProperties": "Removing Properties:", @@ -89,6 +91,8 @@ "TargetAlreadyCompleteSuccess": "Das Ziel \"{0}\" wurde übersprungen. Die vorherige Erstellung war erfolgreich.", "TryingExtensionsPath": "Versucht {0} mithilfe des Erweiterungspfad {1} zu importieren.", "PropertyReassignment": "Neuzuweisung der Eigenschaft: $({0})=\"{1}\" (vorheriger Wert: \"{2}\") unter {3}", + "PropertyAssignment": "Anfangswert der Eigenschaft: $({0})=\"{1}\". Quelle: {2}", + "UninitializedPropertyRead": "Nicht initialisierte Eigenschaft \"{0}\" gelesen", "ProjectImportSkippedExpressionEvaluatedToEmpty": "Das Projekt \"{0}\" wurde nicht von \"{1}\" bei ({2},{3}) importiert, weil der Ausdruck in eine leere Zeichenfolge ausgewertet wurde.", "General.GlobalProperties": "Globale Eigenschaften:", "General.UndefineProperties": "Eigenschaften werden entfernt:", @@ -143,6 +147,8 @@ "TargetAlreadyCompleteSuccess": "La destinazione \"{0}\" è stata ignorata. La compilazione era stata completata in precedenza.", "TryingExtensionsPath": "Si sta provando a importare {0} usando il percorso delle estensioni {1}", "PropertyReassignment": "Riassegnazione della proprietà: $({0})=\"{1}\" (valore precedente: \"{2}\") in {3}", + "PropertyAssignment": "Valore iniziale della proprietà: $({0})=\"{1}\". Origine: {2}", + "UninitializedPropertyRead": "Lettura della proprietà non inizializzata \"{0}\"", "ProjectImportSkippedExpressionEvaluatedToEmpty": "Il progetto \"{0}\" non è stato importato da \"{1}\" alla posizione ({2},{3}) perché l'espressione restituisce una stringa vuota.", "General.GlobalProperties": "Proprietà globali:", "General.UndefineProperties": "Rimozione proprietà:", @@ -197,6 +203,8 @@ "TargetAlreadyCompleteSuccess": "Se omitió el destino \"{0}\". Compilado previamente de forma correcta.", "TryingExtensionsPath": "Intentando importar {0} con la ruta de acceso de extensiones {1}", "PropertyReassignment": "Reasignación de propiedad: $({0})=\"{1}\" (valor anterior: \"{2}\") en {3}", + "PropertyAssignment": "Valor inicial de la propiedad: $({0})=\"{1}\". Origen: {2}", + "UninitializedPropertyRead": "Se leyó la propiedad no inicializada \"{0}\"", "ProjectImportSkippedExpressionEvaluatedToEmpty": "\"{1}\" no importó el proyecto \"{0}\" en ({2},{3}) porque la expresión se evalúa en una cadena vacía.", "General.GlobalProperties": "Propiedades globales:", "General.UndefineProperties": "Quitando propiedades:", @@ -251,6 +259,8 @@ "TargetAlreadyCompleteSuccess": "Cible \"{0}\" ignorée. Elle a été générée.", "TryingExtensionsPath": "Tentative d'importation de {0} en utilisant le chemin d'extensions {1}", "PropertyReassignment": "Réassignation de propriété : $({0})=\"{1}\" (valeur précédente : \"{2}\") à {3}", + "PropertyAssignment": "Valeur initiale de la propriété: $({0})=\"{1}\". Source: {2}", + "UninitializedPropertyRead": "Lecture de la propriété non initialisée \"{0}\"", "ProjectImportSkippedExpressionEvaluatedToEmpty": "Le projet \"{0}\" n'a pas été importé par \"{1}\" sur ({2},{3}), car l'expression a la valeur d'une chaîne vide.", "General.GlobalProperties": "Propriétés globales :", "General.UndefineProperties": "Suppression des propriétés :", @@ -305,6 +315,8 @@ "TargetAlreadyCompleteSuccess": "Cíl {0} byl vynechán. Předchozí sestavení bylo úspěšné.", "TryingExtensionsPath": "Zkouší se import {0} pomocí cesty rozšíření {1}.", "PropertyReassignment": "Opětovné přiřazení vlastnosti: $({0})={1} (předchozí hodnota: {2}) v {3}", + "PropertyAssignment": "Počáteční hodnota vlastnosti: $({0})=\"{1}\". Zdroj: {2}", + "UninitializedPropertyRead": "Čtení neinicializované vlastnosti \"{0}\"", "ProjectImportSkippedExpressionEvaluatedToEmpty": "{1} neimportoval projekt {0} v ({2},{3}), protože se výraz vyhodnocuje na prázdný řetězec.", "General.GlobalProperties": "Globální vlastnosti:", "General.UndefineProperties": "Odstraňování vlastností:", @@ -359,6 +371,8 @@ "TargetAlreadyCompleteSuccess": "ターゲット \"{0}\" を省略しました。以前に正しくビルドされていました。", "TryingExtensionsPath": "拡張パス {1} を使用して {0} をインポートしようとしています", "PropertyReassignment": "プロパティの再代入: $({0})=\"{1}\" (以前の値: \"{2}\") {3}", + "PropertyAssignment": "プロパティの初期値: $({0})=\"{1}\". ソース: {2}", + "UninitializedPropertyRead": "初期化されていないプロパティ \"{0}\" を読み取りました", "ProjectImportSkippedExpressionEvaluatedToEmpty": "式の評価結果が空の文字列になったため、プロジェクト \"{0}\" は \"{1}\" によって ({2},{3}) でインポートされませんでした。", "General.GlobalProperties": "グローバル プロパティ:", "General.UndefineProperties": "プロパティの削除:", @@ -413,6 +427,8 @@ "TargetAlreadyCompleteSuccess": "\"{0}\" 대상을 건너뜁니다. 이전에 빌드되었습니다.", "TryingExtensionsPath": "확장 경로 {1}을(를) 사용하여 {0}을(를) 가져옵니다.", "PropertyReassignment": "속성 재할당: $({0})={3}의 \"{1}\"(이전 값: \"{2}\")", + "PropertyAssignment": "속성 초기값: $({0})=\"{1}\" 소스: {2}", + "UninitializedPropertyRead": "초기화되지 않은 속성 \"{0}\" 읽음", "ProjectImportSkippedExpressionEvaluatedToEmpty": "빈 문자열로 평가되는 식 때문에 ({2},{3})의 \"{1}\"이(가) 프로젝트 \"{0}\"을(를) 가져오지 않았습니다.", "General.GlobalProperties": "전역 속성:", "General.UndefineProperties": "속성 제거:", @@ -467,6 +483,8 @@ "TargetAlreadyCompleteSuccess": "Целевой объект \"{0}\" пропущен. Предыдущая сборка успешна.", "TryingExtensionsPath": "Попытка импортировать \"{0}\" с помощью пути расширений {1}", "PropertyReassignment": "Повторное назначение свойства: $({0})=\"{1}\" (предыдущее значение: \"{2}\") для {3}", + "PropertyAssignment": "Начальное значение свойства: $({0})=\"{1}\". Источник: {2}", + "UninitializedPropertyRead": "Чтение неинициализированного свойства \"{0}\"", "ProjectImportSkippedExpressionEvaluatedToEmpty": "Проект \"{0}\" не был импортирован \"{1}\" в ({2},{3}), так как результатом вычисления выражения была пустая строка.", "General.GlobalProperties": "Глобальные свойства:", "General.UndefineProperties": "Удаление свойств:", @@ -521,6 +539,8 @@ "TargetAlreadyCompleteSuccess": "Pominięto element docelowy „{0}”. Wcześniejsza kompilacja powiodła się.", "TryingExtensionsPath": "Próba zaimportowania elementu {0} przy użyciu ścieżki rozszerzeń {1}", "PropertyReassignment": "Ponowne przypisanie właściwości: $({0})=„{1}” (poprzednia wartość: „{2}”) w {3}", + "PropertyAssignment": "Wartość początkowa właściwości: $({0})=\"{1}\". Źródło: {2}", + "UninitializedPropertyRead": "Odczytano niezainicjowaną właściwość \"{0}\"", "ProjectImportSkippedExpressionEvaluatedToEmpty": "Projekt „{0}” nie został zaimportowany przez projekt „{1}” o ({2},{3}) z powodu wyrażenia ocenianego jako pusty ciąg.", "General.GlobalProperties": "Właściwości globalne:", "General.UndefineProperties": "Usuwanie właściwości:", @@ -575,6 +595,8 @@ "TargetAlreadyCompleteSuccess": "Destino \"{0}\" ignorado. Compilado anteriormente com êxito.", "TryingExtensionsPath": "Tentando importar {0} usando o caminho das extensões {1}", "PropertyReassignment": "Reatribuição de propriedade: $({0})=\"{1}\" (valor anterior: \"{2}\") em {3}", + "PropertyAssignment": "Valor inicial da propriedade: $({0})=\"{1}\". Origem: {2}", + "UninitializedPropertyRead":"Leitura de propriedade não inicializada \"{0}\"", "ProjectImportSkippedExpressionEvaluatedToEmpty": "O projeto \"{0}\" não foi importado por \"{1}\" em ({2},{3}), porque a expressão foi avaliada como uma cadeia de caracteres vazia.", "General.GlobalProperties": "Propriedades globais:", "General.UndefineProperties": "Removendo Propriedades:", @@ -629,6 +651,8 @@ "TargetAlreadyCompleteSuccess": "\"{0}\" hedefi atlandı. Önceden başarılı bir şekilde derlenmişti.", "TryingExtensionsPath": "{1} uzantı yolları kullanılarak {0} içeri aktarılmaya çalışılıyor", "PropertyReassignment": "Özellik yeniden ataması: $({0})=\"{1}\" (önceki değer: \"{2}\") konum: {3}", + "PropertyAssignment": "Özellik başlangıç değeri: $({0})=\"{1}\". Kaynak: {2}", + "UninitializedPropertyRead": "Başlatılmamış özellik \"{0}\" okundu", "ProjectImportSkippedExpressionEvaluatedToEmpty": "\"{0}\" adlı proje, ifadenin boş dize olarak değerlendirilmesi nedeniyle ({2},{3}) konumundaki \"{1}\" tarafından içeri aktarılmadı.", "General.GlobalProperties": "Genel Özellikler:", "General.UndefineProperties": "Özellikler kaldırılıyor:", @@ -683,6 +707,8 @@ "TargetAlreadyCompleteSuccess": "已跳过目标“{0}”。以前的生成已成功。", "TryingExtensionsPath": "尝试使用扩展路径 {1} 导入 {0}", "PropertyReassignment": "在 {3} 处重新分配属性: $({0})=“{1}”(先前值:“{2}”)", + "PropertyAssignment": "属性初始值: $({0})=\"{1}\"来源: {2}", + "UninitializedPropertyRead": "读取未初始化的属性 \"{0}\"", "ProjectImportSkippedExpressionEvaluatedToEmpty": "由于表达式评估为空字符串,因此项目“{0}”不由 ({2}、{3}) 处的“{1}”导入。", "General.GlobalProperties": "全局属性:", "General.UndefineProperties": "移除属性:",