-
Notifications
You must be signed in to change notification settings - Fork 419
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Clean up unresolved dependencies check #862
Changes from all commits
61277a8
551ca2a
8851516
162c14a
1b140cb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.IO; | ||
using System.Linq; | ||
using Microsoft.Extensions.Logging; | ||
using NuGet.ProjectModel; | ||
using OmniSharp.MSBuild.ProjectFile; | ||
|
||
namespace OmniSharp.MSBuild.Resolution | ||
{ | ||
internal class PackageDependencyResolver | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there much value in writing tests for this class? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there's definitely value in having tests, but I don't want to gate this PR on them. I want to write tests for the MSBuildProjectSystem in general because there's really not much today. Now that we have the test infrastructure in place, I'd like to write some broader MSBuildProjectSystem tests. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added #863 to track adding tests. |
||
{ | ||
private readonly ILogger _logger; | ||
|
||
public PackageDependencyResolver(ILoggerFactory loggerFactory) | ||
{ | ||
_logger = loggerFactory.CreateLogger<PackageDependencyResolver>(); | ||
} | ||
|
||
public ImmutableArray<PackageReference> FindUnresolvedPackageReferences(ProjectFileInfo projectFile) | ||
{ | ||
if (projectFile.PackageReferences.Length == 0) | ||
{ | ||
return ImmutableArray<PackageReference>.Empty; | ||
} | ||
|
||
// If the lock file does not exist, all of the package references are unresolved. | ||
if (!File.Exists(projectFile.ProjectAssetsFile)) | ||
{ | ||
return projectFile.PackageReferences; | ||
} | ||
|
||
var lockFileFormat = new LockFileFormat(); | ||
var lockFile = lockFileFormat.Read(projectFile.ProjectAssetsFile); | ||
|
||
return FindUnresolvedPackageReferencesInLockFile(projectFile, lockFile); | ||
} | ||
|
||
private ImmutableArray<PackageReference> FindUnresolvedPackageReferencesInLockFile(ProjectFileInfo projectFile, LockFile lockFile) | ||
{ | ||
var libraryMap = CreateLibraryMap(lockFile); | ||
|
||
var unresolved = ImmutableArray.CreateBuilder<PackageReference>(); | ||
|
||
// Iterate through each package reference and see if we can find a library with the same name | ||
// that satisfies the reference's version range in the lock file. | ||
|
||
foreach (var reference in projectFile.PackageReferences) | ||
{ | ||
if (!libraryMap.TryGetValue(reference.Dependency.Id, out var libraries)) | ||
{ | ||
_logger.LogWarning($"{projectFile.Name}: Did not find '{reference.Dependency.Id}' in lock file."); | ||
unresolved.Add(reference); | ||
} | ||
else | ||
{ | ||
var found = false; | ||
foreach (var library in libraries) | ||
{ | ||
if (reference.Dependency.VersionRange.Satisfies(library.Version)) | ||
{ | ||
found = true; | ||
break; | ||
} | ||
} | ||
|
||
if (!found) | ||
{ | ||
var referenceText = reference.IsImplicitlyDefined | ||
? "implicit package reference" | ||
: "package reference"; | ||
|
||
var versions = string.Join(", ", libraries.Select(l => '"' + l.Version.ToString() + '"')); | ||
|
||
_logger.LogWarning($"{projectFile.Name}: Found {referenceText} '{reference.Dependency.Id}', but none of the versions in the lock file ({versions}) satisfy {reference.Dependency.VersionRange}"); | ||
unresolved.Add(reference); | ||
} | ||
} | ||
} | ||
|
||
return unresolved.ToImmutable(); | ||
} | ||
|
||
private static Dictionary<string, List<LockFileLibrary>> CreateLibraryMap(LockFile lockFile) | ||
{ | ||
// Create map of all libraries in the lock file by their name. | ||
// Note that the map's key is case-insensitive. | ||
|
||
var libraryMap = new Dictionary<string, List<LockFileLibrary>>( | ||
capacity: lockFile.Libraries.Count, | ||
comparer: StringComparer.OrdinalIgnoreCase); | ||
|
||
foreach (var library in lockFile.Libraries) | ||
{ | ||
if (!libraryMap.TryGetValue(library.Name, out var libraries)) | ||
{ | ||
libraries = new List<LockFileLibrary>(); | ||
libraryMap.Add(library.Name, libraries); | ||
} | ||
|
||
libraries.Add(library); | ||
} | ||
|
||
return libraryMap; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when lock file doesn't exist at all I believe the error code would be
NU1009
.Should that be taken into account as well? a restore would then generate the lock file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, maybe it doesn't matter anymore - it's legacy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I wasn't trying to clean up
DotNetProjectSystem
too much. I've been thinking of that as a bit frozen so I don't unintentionally break anything.