diff --git a/src/NuGet.Core/NuGet.ProjectModel/LockFile/LockFileFormat.cs b/src/NuGet.Core/NuGet.ProjectModel/LockFile/LockFileFormat.cs index d9a98a5bc..01d4f9e0c 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/LockFile/LockFileFormat.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/LockFile/LockFileFormat.cs @@ -183,9 +183,12 @@ namespace NuGet.ProjectModel Targets = ReadObject(cursor[TargetsProperty] as JObject, ReadTarget), ProjectFileDependencyGroups = ReadObject(cursor[ProjectFileDependencyGroupsProperty] as JObject, ReadProjectFileDependencyGroup), PackageFolders = ReadObject(cursor[PackageFoldersProperty] as JObject, ReadFileItem), - PackageSpec = ReadPackageSpec(cursor[PackageSpecProperty] as JObject), - LogMessages = ReadArray(cursor[LogsProperty] as JArray, ReadLogMessage) + PackageSpec = ReadPackageSpec(cursor[PackageSpecProperty] as JObject) }; + + lockFile.LogMessages = ReadLogMessageArray(cursor[LogsProperty] as JArray, + lockFile?.PackageSpec?.RestoreMetadata?.ProjectPath); + return lockFile; } @@ -218,7 +221,8 @@ namespace NuGet.ProjectModel { if(lockFile.LogMessages.Count > 0) { - json[LogsProperty] = WriteLogMessages(lockFile.LogMessages); + var projectPath = lockFile.PackageSpec?.RestoreMetadata?.ProjectPath; + json[LogsProperty] = WriteLogMessages(lockFile.LogMessages, projectPath); } } @@ -309,7 +313,7 @@ namespace NuGet.ProjectModel /// /// IAssetsLogMessage representing the log message. /// JObject containg the json representation of the log message. - private static JObject WriteLogMessage(IAssetsLogMessage logMessage) + private static JObject WriteLogMessage(IAssetsLogMessage logMessage, string projectPath) { var logJObject = new JObject() { @@ -322,8 +326,11 @@ namespace NuGet.ProjectModel logJObject[LogMessageProperties.WARNING_LEVEL] = logMessage.WarningLevel.ToString(); } - if (logMessage.FilePath != null) + if (logMessage.FilePath != null && + (projectPath == null || !PathUtility.GetStringComparerBasedOnOS().Equals(logMessage.FilePath, projectPath))) { + // Do not write the file path if it is the same as the project path. + // This prevents duplicate information in the lock file. logJObject[LogMessageProperties.FILE_PATH] = logMessage.FilePath; } @@ -372,7 +379,7 @@ namespace NuGet.ProjectModel /// /// JObject containg the json representation of the log message. /// IAssetsLogMessage representing the log message. - private static IAssetsLogMessage ReadLogMessage(JObject json) + private static IAssetsLogMessage ReadLogMessage(JObject json, string projectPath) { AssetsLogMessage assetsLogMessage = null; @@ -412,6 +419,10 @@ namespace NuGet.ProjectModel { assetsLogMessage.FilePath = filePathJson.Value(); } + else + { + assetsLogMessage.FilePath = projectPath; + } if (startLineNumberJson != null) { @@ -443,17 +454,12 @@ namespace NuGet.ProjectModel return assetsLogMessage; } - private static IAssetsLogMessage ReadLogMessage(JToken json) - { - return ReadLogMessage(json as JObject); - } - - private static JArray WriteLogMessages(IEnumerable logMessages) + private static JArray WriteLogMessages(IEnumerable logMessages, string projectPath) { var logMessageArray = new JArray(); foreach(var logMessage in logMessages) { - logMessageArray.Add(WriteLogMessage(logMessage)); + logMessageArray.Add(WriteLogMessage(logMessage, projectPath)); } return logMessageArray; } @@ -696,6 +702,25 @@ namespace NuGet.ProjectModel return items; } + private static IList ReadLogMessageArray(JArray json, string projectPath) + { + if (json == null) + { + return new List(); + } + + var items = new List(); + foreach (var child in json) + { + var logMessage = ReadLogMessage(child as JObject, projectPath); + if (logMessage != null) + { + items.Add(logMessage); + } + } + return items; + } + private static IList ReadPathArray(JArray json, Func readItem) { return ReadArray(json, readItem).Select(f => GetPathWithForwardSlashes(f)).ToList(); diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileFormatTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileFormatTests.cs index 692085705..0967a8932 100644 --- a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileFormatTests.cs +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileFormatTests.cs @@ -800,6 +800,134 @@ namespace NuGet.ProjectModel.Test Assert.Equal(expected, output); } + [Fact] + public void LockFileFormat_WritesErrorMessageWithFilePathSameAsProjectPath() + { + + // Arrange + var lockFileContent = @"{ + ""version"": 3, + ""targets"": { + "".NETPlatform,Version=v5.0"": { + ""System.Runtime/4.0.20-beta-22927"": { + ""type"": ""package"", + ""dependencies"": { + ""Frob"": ""4.0.20"" + }, + ""compile"": { + ""ref/dotnet/System.Runtime.dll"": {} + } + } + } + }, + ""libraries"": { + ""System.Runtime/4.0.20-beta-22927"": { + ""sha512"": ""sup3rs3cur3"", + ""type"": ""package"", + ""files"": [ + ""System.Runtime.nuspec"" + ] + } + }, + ""projectFileDependencyGroups"": { + """": [ + ""System.Runtime [4.0.10-beta-*, )"" + ], + "".NETPlatform,Version=v5.0"": [] + }, + ""project"": { + ""restore"": { + ""projectPath"": ""kung\\fu\\fighting.csproj"" + } + }, + ""logs"": [ + { + ""code"": ""NU1000"", + ""level"": ""Error"", + ""startLineNumber"": 11, + ""startColumnNumber"": 2, + ""endLineNumber"": 11, + ""endColumnNumber"": 10, + ""message"": ""test log message"", + ""libraryId"": ""nuget.versioning"", + ""targetGraphs"": [ + ""net46"", + ""netcoreapp1.0"", + ""netstandard1.6"" + ] + } + ] +}"; + var lockFile = new LockFile() + { + Version = 3 + }; + + var target = new LockFileTarget() + { + TargetFramework = FrameworkConstants.CommonFrameworks.DotNet + }; + + var targetLib = new LockFileTargetLibrary() + { + Name = "System.Runtime", + Version = NuGetVersion.Parse("4.0.20-beta-22927"), + Type = LibraryType.Package + }; + + targetLib.Dependencies.Add(new Packaging.Core.PackageDependency("Frob", + new VersionRange(NuGetVersion.Parse("4.0.20")))); + targetLib.CompileTimeAssemblies.Add(new LockFileItem("ref/dotnet/System.Runtime.dll")); + target.Libraries.Add(targetLib); + lockFile.Targets.Add(target); + + var lib = new LockFileLibrary() + { + Name = "System.Runtime", + Version = NuGetVersion.Parse("4.0.20-beta-22927"), + Type = LibraryType.Package, + Sha512 = "sup3rs3cur3" + }; + lib.Files.Add("System.Runtime.nuspec"); + lockFile.Libraries.Add(lib); + + lockFile.ProjectFileDependencyGroups.Add( + new ProjectFileDependencyGroup("", new string[] { "System.Runtime [4.0.10-beta-*, )" })); + lockFile.ProjectFileDependencyGroups.Add( + new ProjectFileDependencyGroup(FrameworkConstants.CommonFrameworks.DotNet.DotNetFrameworkName, new string[0])); + + lockFile.PackageSpec = new PackageSpec(new List()) + { + RestoreMetadata = new ProjectRestoreMetadata() + { + ProjectPath = "kung\\fu\\fighting.csproj" + } + }; + + lockFile.LogMessages = new List + { + new AssetsLogMessage(LogLevel.Error, NuGetLogCode.NU1000, "test log message") + { + FilePath = @"kung\fu\fighting.csproj", + ProjectPath = @"kung\fu\fighting.csproj", + TargetGraphs = new List{ "net46", "netcoreapp1.0", "netstandard1.6" }, + StartLineNumber = 11, + StartColumnNumber = 2, + EndLineNumber = 11, + EndColumnNumber = 10, + LibraryId = "nuget.versioning" + } + }; + + // Act + var lockFileFormat = new LockFileFormat(); + var output = JObject.Parse(lockFileFormat.Render(lockFile)).ToString(); + var expected = JObject.Parse(lockFileContent).ToString(); + + // Assert + Assert.Equal(expected, output); + } + [Fact] public void LockFileFormat_ReadsMinimalErrorMessage() { @@ -957,6 +1085,7 @@ namespace NuGet.ProjectModel.Test [Fact] public void LockFileFormat_ReadsWarningMessage() { + // Arrange var lockFileContent = @"{ ""version"": 3, @@ -1128,5 +1257,161 @@ namespace NuGet.ProjectModel.Test Assert.Equal(1, lockFileObj.LogMessages.Where(m => m.Code == NuGetLogCode.NU1001).Count()); } + [Fact] + public void LockFileFormat_ReadsLogMessageWithSameFilePathAndProjectPath() + { + // Arrange + var lockFileContent = @"{ + ""version"": 3, + ""targets"": { + "".NETPlatform,Version=v5.0"": { + ""System.Runtime/4.0.20-beta-22927"": { + ""type"": ""package"", + ""dependencies"": { + ""Frob"": ""4.0.20"" + }, + ""compile"": { + ""ref/dotnet/System.Runtime.dll"": {} + } + } + } + }, + ""libraries"": { + ""System.Runtime/4.0.20-beta-22927"": { + ""sha512"": ""sup3rs3cur3"", + ""type"": ""package"", + ""files"": [ + ""System.Runtime.nuspec"" + ] + } + }, + ""projectFileDependencyGroups"": { + """": [ + ""System.Runtime [4.0.10-beta-*, )"" + ], + "".NETPlatform,Version=v5.0"": [] + }, + ""project"": { + ""restore"": { + ""projectPath"": ""kung\\fu\\fighting.csproj"" + } + }, + ""logs"": [ + { + ""code"": ""NU1000"", + ""level"": ""Error"", + ""message"": ""test log message"", + ""filePath"": ""kung\\fu\\fighting.csproj"" + } + ] +}"; + LockFile lockFileObj = null; + IAssetsLogMessage logMessage = null; + using (var lockFile = new TempFile()) + { + + File.WriteAllText(lockFile, lockFileContent); + + // Act + var reader = new LockFileFormat(); + lockFileObj = reader.Read(lockFile); + logMessage = lockFileObj?.LogMessages?.First(); + } + + + // Assert + Assert.NotNull(lockFileObj); + Assert.NotNull(logMessage); + Assert.Equal(1, lockFileObj.LogMessages.Count()); + Assert.Equal(LogLevel.Error, logMessage.Level); + Assert.Equal(NuGetLogCode.NU1000, logMessage.Code); + Assert.NotNull(logMessage.FilePath); + Assert.Equal("kung\\fu\\fighting.csproj", logMessage.FilePath); + Assert.Equal(-1, logMessage.StartLineNumber); + Assert.Equal(-1, logMessage.EndLineNumber); + Assert.Equal(-1, logMessage.StartColumnNumber); + Assert.Equal(-1, logMessage.EndColumnNumber); + Assert.NotNull(logMessage.TargetGraphs); + Assert.Equal(0, logMessage.TargetGraphs.Count); + Assert.Equal("test log message", logMessage.Message); + } + + [Fact] + public void LockFileFormat_ReadsLogMessageWithNoFilePath() + { + // Arrange + var lockFileContent = @"{ + ""version"": 3, + ""targets"": { + "".NETPlatform,Version=v5.0"": { + ""System.Runtime/4.0.20-beta-22927"": { + ""type"": ""package"", + ""dependencies"": { + ""Frob"": ""4.0.20"" + }, + ""compile"": { + ""ref/dotnet/System.Runtime.dll"": {} + } + } + } + }, + ""libraries"": { + ""System.Runtime/4.0.20-beta-22927"": { + ""sha512"": ""sup3rs3cur3"", + ""type"": ""package"", + ""files"": [ + ""System.Runtime.nuspec"" + ] + } + }, + ""projectFileDependencyGroups"": { + """": [ + ""System.Runtime [4.0.10-beta-*, )"" + ], + "".NETPlatform,Version=v5.0"": [] + }, + ""project"": { + ""restore"": { + ""projectPath"": ""kung\\fu\\fighting.csproj"" + } + }, + ""logs"": [ + { + ""code"": ""NU1000"", + ""level"": ""Error"", + ""message"": ""test log message"" + } + ] +}"; + LockFile lockFileObj = null; + IAssetsLogMessage logMessage = null; + using (var lockFile = new TempFile()) + { + + File.WriteAllText(lockFile, lockFileContent); + + // Act + var reader = new LockFileFormat(); + lockFileObj = reader.Read(lockFile); + logMessage = lockFileObj?.LogMessages?.First(); + } + + + // Assert + Assert.NotNull(lockFileObj); + Assert.NotNull(logMessage); + Assert.Equal(1, lockFileObj.LogMessages.Count()); + Assert.Equal(LogLevel.Error, logMessage.Level); + Assert.Equal(NuGetLogCode.NU1000, logMessage.Code); + Assert.NotNull(logMessage.FilePath); + Assert.Equal("kung\\fu\\fighting.csproj", logMessage.FilePath); + Assert.Equal(-1, logMessage.StartLineNumber); + Assert.Equal(-1, logMessage.EndLineNumber); + Assert.Equal(-1, logMessage.StartColumnNumber); + Assert.Equal(-1, logMessage.EndColumnNumber); + Assert.NotNull(logMessage.TargetGraphs); + Assert.Equal(0, logMessage.TargetGraphs.Count); + Assert.Equal("test log message", logMessage.Message); + } } }