Skip to content

Commit

Permalink
WIP: Converting dotnet list parsing to lockfile parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
digitalcoyote committed Apr 16, 2024
1 parent 0366dee commit 0f11f71
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 2 deletions.
2 changes: 2 additions & 0 deletions Src/NuGetDefense.Core/NuGetDefense.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageVersion>2.0.8</PackageVersion>
<AssemblyVersion>2.0.8</AssemblyVersion>
<PackageVersion>2.0.8.1-issue180</PackageVersion>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<Nullable>enable</Nullable>
</PropertyGroup>
Expand All @@ -31,6 +32,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageReference Include="NuGet.ProjectModel" Version="6.9.1" />
<PackageReference Include="NuGet.Versioning" Version="6.9.1" />
</ItemGroup>
<ItemGroup>
Expand Down
43 changes: 41 additions & 2 deletions Src/NuGetDefense.Core/NuGetFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using NuGet.Common;
using NuGet.Frameworks;
using NuGet.ProjectModel;
using NuGet.Versioning;

namespace NuGetDefense.Core
Expand Down Expand Up @@ -145,6 +149,7 @@ private string ExtractPackageReferenceVersion(XElement x)
/// <param name="targetFramework"></param>
/// <param name="projectectReferencePackages"></param>
/// <returns></returns>
[Obsolete("Per Issue #180 `dotnet list` parsing is not reliable use parseLockFile instead")]
public static Dictionary<string, NuGetPackage> dotnetListPackages(string projectFile,
string targetFramework,
out Dictionary<string, NuGetPackage[]> projectectReferencePackages)
Expand Down Expand Up @@ -184,15 +189,46 @@ public static Dictionary<string, NuGetPackage> dotnetListPackages(string project
return pkgs;
}

[Obsolete("Per Issue #180 `dotnet list` parsing is not reliable use parseLockFile instead")]
public static Dictionary<string, NuGetPackage> ParseListPackages(string dotnetListOutput)
{
var lines = dotnetListOutput.Split(new[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
if (lines.Length < 3) throw new Exception("Invalid dotnet list output. Run `dotnet restore` then build again.");
if (lines.Length < 3)
{
Console.WriteLine($"DEBUG: dotnet list output | {dotnetListOutput}");
throw new Exception($"Invalid dotnet list output. Run `dotnet restore` then build again. DOTNET LIST OUTPUT: {dotnetListOutput}");
}
var pkgs = ParseDotnetListProjectSection(lines);

return pkgs;
}


/// <summary>
/// Parses the project.assets.json file which is created when running `dotnet restore`
/// </summary>
/// <param name="projectAssetsJsonPath">This is a path to the project.assets.json file. It's usually located in the obj folder of the project</param>
/// <param name="targetFrameworkMoniker">This is the tfm used to determine the dependencies for a specific target framework. If not provided it will check all present</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static Dictionary<string, NuGetPackage> parseLockFile(string projectAssetsJsonPath, string? targetFrameworkMoniker)
{
var lockFileFormat = new LockFileFormat();
var lockFile = lockFileFormat.Read(projectAssetsJsonPath);
IEnumerable<LockFileTargetLibrary>? libraries;
if (!string.IsNullOrWhiteSpace(targetFrameworkMoniker))
{
libraries = lockFile.Targets.FirstOrDefault(t => t.RuntimeIdentifier == targetFrameworkMoniker)?.Libraries;
}
else libraries = lockFile.Targets.SelectMany(t => t.Libraries);

if (libraries == null) return new Dictionary<string, NuGetPackage>();

return libraries.Where(l =>l.Version != null && !string.IsNullOrWhiteSpace(l.Name)).ToDictionary(l => l.Name!, l => new NuGetPackage{Id = l.Name!, Version = l.Version!.ToString()} );

}

[Obsolete("Per Issue #180 `dotnet list` parsing is not reliable use parseLockFile instead")]
private static Dictionary<string, NuGetPackage> ParseDotnetListProjectSection(string[] lines)
{
var pkgs = lines
Expand All @@ -212,7 +248,7 @@ private static Dictionary<string, NuGetPackage> ParseDotnetListProjectSection(st
.ToDictionary(p => p.Id);

var transitivelines = lines
// Skip the informational Text at hte beginning
// Skip the informational Text at the beginning
.SkipWhile(l => l.IndexOf('>') == -1)
// Skip the Direct Dependencies
.SkipWhile(l => l.IndexOf('>') != -1)
Expand Down Expand Up @@ -247,6 +283,7 @@ private static Dictionary<string, NuGetPackage> ParseDotnetListProjectSection(st
}


[Obsolete("Per Issue #180 `dotnet list` parsing is not reliable use parseSlnLockFile instead")]
public static Dictionary<string, Dictionary<string, NuGetPackage>> ParseListSlnPackages(string dotnetListOutput)
{
var projects = new Dictionary<string, Dictionary<string, NuGetPackage>>();
Expand All @@ -268,6 +305,7 @@ public static Dictionary<string, Dictionary<string, NuGetPackage>> ParseListSlnP
return projects;
}

[Obsolete("Per Issue #180 `dotnet list` parsing is not reliable use parseLockFile instead")]
public static IEnumerable<string[]> DotNetListOutputByProject(
string[] source)
{
Expand All @@ -283,6 +321,7 @@ public static IEnumerable<string[]> DotNetListOutputByProject(
}
}

[Obsolete("Per Issue #180 `dotnet list` parsing is not reliable use parseLockFile instead")]
private static bool ParseProjectLines(in IEnumerable<string> projectReferenceLines)
{
throw new NotImplementedException();
Expand Down

0 comments on commit 0f11f71

Please sign in to comment.