Fix up diagnostics
- Show all diagnostics and the relevant location in project.json even for transitive dependencies - Removed LibraryRange from LibraryDescription and added a list instead - Show stack traces in debug mode - Fixed LibraryType.GetHashCode()
This commit is contained in:
parent
89d3d710de
commit
086207ebcc
12 changed files with 131 additions and 109 deletions
|
@ -66,7 +66,11 @@ namespace Microsoft.DotNet.Tools.Compiler
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
Console.Error.WriteLine(ex);
|
||||
#else
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,11 @@ namespace Microsoft.DotNet.Tools.Publish
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
Console.Error.WriteLine(ex);
|
||||
#else
|
||||
Console.Error.WriteLine(ex.Message);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,12 +22,12 @@ namespace Microsoft.Extensions.ProjectModel.Graph
|
|||
public static bool TryParse(string value, out LibraryType type)
|
||||
{
|
||||
// We only support values we know about
|
||||
if(string.Equals(Package.Value, value, StringComparison.OrdinalIgnoreCase))
|
||||
if (string.Equals(Package.Value, value, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
type = Package;
|
||||
return true;
|
||||
}
|
||||
else if(string.Equals(Project.Value, value, StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(Project.Value, value, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
type = Project;
|
||||
return true;
|
||||
|
@ -80,6 +80,10 @@ namespace Microsoft.Extensions.ProjectModel.Graph
|
|||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Value))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return StringComparer.OrdinalIgnoreCase.GetHashCode(Value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using Microsoft.Extensions.ProjectModel.Graph;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
|
@ -14,7 +16,6 @@ namespace Microsoft.Extensions.ProjectModel
|
|||
public class LibraryDescription
|
||||
{
|
||||
public LibraryDescription(
|
||||
LibraryRange requestedRange,
|
||||
LibraryIdentity identity,
|
||||
string path,
|
||||
IEnumerable<LibraryRange> dependencies,
|
||||
|
@ -23,7 +24,6 @@ namespace Microsoft.Extensions.ProjectModel
|
|||
bool compatible)
|
||||
{
|
||||
Path = path;
|
||||
RequestedRange = requestedRange;
|
||||
Identity = identity;
|
||||
Dependencies = dependencies ?? Enumerable.Empty<LibraryRange>();
|
||||
Framework = framework;
|
||||
|
@ -31,9 +31,9 @@ namespace Microsoft.Extensions.ProjectModel
|
|||
Compatible = compatible;
|
||||
}
|
||||
|
||||
public LibraryRange RequestedRange { get; }
|
||||
public LibraryIdentity Identity { get; }
|
||||
public List<LibraryDescription> Parents { get; set; } = new List<LibraryDescription>();
|
||||
public HashSet<LibraryRange> RequestedRanges { get; } = new HashSet<LibraryRange>(new LibraryRangeEqualityComparer());
|
||||
public List<LibraryDescription> Parents { get; } = new List<LibraryDescription>();
|
||||
public string Path { get; }
|
||||
public IEnumerable<LibraryRange> Dependencies { get; }
|
||||
public bool Compatible { get; }
|
||||
|
@ -45,5 +45,29 @@ namespace Microsoft.Extensions.ProjectModel
|
|||
{
|
||||
return $"{Identity} = {Path}";
|
||||
}
|
||||
|
||||
// For diagnostics, we don't want to duplicate requested dependencies so we
|
||||
// dedupe dependencies defined in project.json
|
||||
private class LibraryRangeEqualityComparer : IEqualityComparer<LibraryRange>
|
||||
{
|
||||
public bool Equals(LibraryRange x, LibraryRange y)
|
||||
{
|
||||
return x.Equals(y) &&
|
||||
x.SourceColumn == y.SourceColumn &&
|
||||
x.SourceLine == y.SourceLine &&
|
||||
string.Equals(x.SourceFilePath, y.SourceFilePath, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public int GetHashCode(LibraryRange obj)
|
||||
{
|
||||
var combiner = HashCodeCombiner.Start();
|
||||
combiner.Add(obj);
|
||||
combiner.Add(obj.SourceFilePath);
|
||||
combiner.Add(obj.SourceLine);
|
||||
combiner.Add(obj.SourceColumn);
|
||||
|
||||
return combiner.CombinedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,19 +6,17 @@ namespace Microsoft.Extensions.ProjectModel
|
|||
public class PackageDescription : LibraryDescription
|
||||
{
|
||||
public PackageDescription(
|
||||
LibraryRange requestedRange,
|
||||
string path,
|
||||
LockFilePackageLibrary package,
|
||||
LockFileTargetLibrary lockFileLibrary,
|
||||
IEnumerable<LibraryRange> dependencies,
|
||||
bool compatible)
|
||||
: base(
|
||||
requestedRange,
|
||||
new LibraryIdentity(package.Name, package.Version, LibraryType.Package),
|
||||
path,
|
||||
dependencies: dependencies,
|
||||
framework: null,
|
||||
resolved: true,
|
||||
resolved: compatible,
|
||||
compatible: compatible)
|
||||
{
|
||||
Library = package;
|
||||
|
|
|
@ -110,7 +110,7 @@ namespace Microsoft.Extensions.ProjectModel
|
|||
}
|
||||
|
||||
// Create a library manager
|
||||
var libraryManager = new LibraryManager(Project.ProjectFilePath, libraries.Values.ToList(), diagnostics);
|
||||
var libraryManager = new LibraryManager(libraries.Values.ToList(), diagnostics);
|
||||
|
||||
return new ProjectContext(
|
||||
GlobalSettings,
|
||||
|
@ -153,6 +153,7 @@ namespace Microsoft.Extensions.ProjectModel
|
|||
}
|
||||
}
|
||||
|
||||
dep.RequestedRanges.Add(dependency);
|
||||
dep.Parents.Add(library);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ namespace Microsoft.Extensions.ProjectModel
|
|||
// Create an unresolved project description
|
||||
public ProjectDescription(string name, string path)
|
||||
: base(
|
||||
new LibraryRange(name, LibraryType.Unspecified),
|
||||
new LibraryIdentity(name, LibraryType.Project),
|
||||
path,
|
||||
Enumerable.Empty<LibraryRange>(),
|
||||
|
@ -28,7 +27,6 @@ namespace Microsoft.Extensions.ProjectModel
|
|||
TargetFrameworkInformation targetFrameworkInfo,
|
||||
bool resolved) :
|
||||
base(
|
||||
libraryRange,
|
||||
new LibraryIdentity(project.Name, project.Version, LibraryType.Project),
|
||||
project.ProjectFilePath,
|
||||
dependencies,
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using NuGet.Frameworks;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.ProjectModel.Graph;
|
||||
using NuGet.Versioning;
|
||||
|
||||
namespace Microsoft.Extensions.ProjectModel.Resolution
|
||||
|
@ -12,13 +14,10 @@ namespace Microsoft.Extensions.ProjectModel.Resolution
|
|||
{
|
||||
private readonly IList<LibraryDescription> _libraries;
|
||||
private readonly IList<DiagnosticMessage> _diagnostics;
|
||||
private readonly string _projectPath;
|
||||
|
||||
public LibraryManager(string projectPath,
|
||||
IList<LibraryDescription> libraries,
|
||||
public LibraryManager(IList<LibraryDescription> libraries,
|
||||
IList<DiagnosticMessage> diagnostics)
|
||||
{
|
||||
_projectPath = projectPath;
|
||||
_libraries = libraries;
|
||||
_diagnostics = diagnostics;
|
||||
}
|
||||
|
@ -39,72 +38,110 @@ namespace Microsoft.Extensions.ProjectModel.Resolution
|
|||
|
||||
foreach (var library in GetLibraries())
|
||||
{
|
||||
string projectPath = library.RequestedRange.SourceFilePath ?? _projectPath;
|
||||
|
||||
if (!library.Resolved)
|
||||
{
|
||||
string message;
|
||||
string errorCode;
|
||||
if (library.Compatible)
|
||||
{
|
||||
errorCode = ErrorCodes.NU1001;
|
||||
message = $"The dependency {library.RequestedRange.Name} {library.RequestedRange.VersionRange} could not be resolved.";
|
||||
foreach (var range in library.RequestedRanges)
|
||||
{
|
||||
errorCode = ErrorCodes.NU1001;
|
||||
message = $"The dependency {range.Name} {range.VersionRange} could not be resolved.";
|
||||
|
||||
AddDiagnostics(messages, library, message, errorCode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errorCode = ErrorCodes.NU1002;
|
||||
var projectName = Directory.GetParent(_projectPath).Name;
|
||||
message = $"The dependency {library.Identity} in project {projectName} does not support framework {library.Framework}.";
|
||||
}
|
||||
message = $"The dependency {library.Identity} does not support framework {library.Framework}.";
|
||||
|
||||
messages.Add(
|
||||
new DiagnosticMessage(
|
||||
errorCode,
|
||||
message,
|
||||
projectPath,
|
||||
DiagnosticMessageSeverity.Error,
|
||||
library.RequestedRange.SourceLine,
|
||||
library.RequestedRange.SourceColumn,
|
||||
library));
|
||||
AddDiagnostics(messages, library, message, errorCode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Skip libraries that aren't specified in a project.json
|
||||
if (string.IsNullOrEmpty(library.RequestedRange.SourceFilePath))
|
||||
foreach (var range in library.RequestedRanges)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Skip libraries that aren't specified in a project.json
|
||||
if (string.IsNullOrEmpty(range.SourceFilePath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (library.RequestedRange.VersionRange == null)
|
||||
{
|
||||
// TODO: Show errors/warnings for things without versions
|
||||
continue;
|
||||
}
|
||||
if (range.VersionRange == null)
|
||||
{
|
||||
// TODO: Show errors/warnings for things without versions
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we ended up with a declared version that isn't what was asked for directly
|
||||
// then report a warning
|
||||
// Case 1: Non floating version and the minimum doesn't match what was specified
|
||||
// Case 2: Floating version that fell outside of the range
|
||||
if ((!library.RequestedRange.VersionRange.IsFloating &&
|
||||
library.RequestedRange.VersionRange.MinVersion != library.Identity.Version) ||
|
||||
(library.RequestedRange.VersionRange.IsFloating &&
|
||||
!library.RequestedRange.VersionRange.EqualsFloating(library.Identity.Version)))
|
||||
{
|
||||
var message = string.Format("Dependency specified was {0} but ended up with {1}.", library.RequestedRange, library.Identity);
|
||||
messages.Add(
|
||||
new DiagnosticMessage(
|
||||
ErrorCodes.NU1007,
|
||||
message,
|
||||
projectPath,
|
||||
DiagnosticMessageSeverity.Warning,
|
||||
library.RequestedRange.SourceLine,
|
||||
library.RequestedRange.SourceColumn,
|
||||
library));
|
||||
// If we ended up with a declared version that isn't what was asked for directly
|
||||
// then report a warning
|
||||
// Case 1: Non floating version and the minimum doesn't match what was specified
|
||||
// Case 2: Floating version that fell outside of the range
|
||||
if ((!range.VersionRange.IsFloating &&
|
||||
range.VersionRange.MinVersion != library.Identity.Version) ||
|
||||
(range.VersionRange.IsFloating &&
|
||||
!range.VersionRange.Float.Satisfies(library.Identity.Version)))
|
||||
{
|
||||
var message = $"Dependency specified was {range} but ended up with {library.Identity}.";
|
||||
|
||||
foreach (var source in GetRangesWithSourceLocations(library))
|
||||
{
|
||||
messages.Add(
|
||||
new DiagnosticMessage(
|
||||
ErrorCodes.NU1007,
|
||||
message,
|
||||
source.SourceFilePath,
|
||||
DiagnosticMessageSeverity.Warning,
|
||||
source.SourceLine,
|
||||
source.SourceColumn,
|
||||
library));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
private void AddDiagnostics(List<DiagnosticMessage> messages, LibraryDescription library, string message, string errorCode)
|
||||
{
|
||||
// A (in project.json) -> B (unresolved) (not in project.json)
|
||||
foreach (var source in GetRangesWithSourceLocations(library).Distinct())
|
||||
{
|
||||
messages.Add(
|
||||
new DiagnosticMessage(
|
||||
errorCode,
|
||||
message,
|
||||
source.SourceFilePath,
|
||||
DiagnosticMessageSeverity.Error,
|
||||
source.SourceLine,
|
||||
source.SourceColumn,
|
||||
library));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<LibraryRange> GetRangesWithSourceLocations(LibraryDescription library)
|
||||
{
|
||||
foreach (var range in library.RequestedRanges)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(range.SourceFilePath))
|
||||
{
|
||||
yield return range;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var parent in library.Parents)
|
||||
{
|
||||
foreach (var relevantPath in GetRangesWithSourceLocations(parent))
|
||||
{
|
||||
yield return relevantPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,7 +36,6 @@ namespace Microsoft.Extensions.ProjectModel.Resolution
|
|||
var path = _packagePathResolver.GetInstallPath(package.Name, package.Version);
|
||||
|
||||
var packageDescription = new PackageDescription(
|
||||
new LibraryRange(package.Name, new VersionRange(package.Version), LibraryType.Package, LibraryDependencyType.Default),
|
||||
path,
|
||||
package,
|
||||
targetLibrary,
|
||||
|
|
|
@ -41,7 +41,6 @@ namespace Microsoft.Extensions.ProjectModel.Resolution
|
|||
if (version == null || version.Version == assemblyVersion)
|
||||
{
|
||||
return new LibraryDescription(
|
||||
libraryRange,
|
||||
new LibraryIdentity(libraryRange.Name, new NuGetVersion(assemblyVersion), LibraryType.ReferenceAssembly),
|
||||
path,
|
||||
Enumerable.Empty<LibraryRange>(),
|
||||
|
|
|
@ -12,7 +12,6 @@ namespace Microsoft.Extensions.ProjectModel.Resolution
|
|||
public static LibraryDescription GetDescription(LibraryRange libraryRange, NuGetFramework targetFramework)
|
||||
{
|
||||
return new LibraryDescription(
|
||||
libraryRange,
|
||||
new LibraryIdentity(libraryRange.Name, libraryRange.VersionRange?.MinVersion, libraryRange.Target),
|
||||
path: null,
|
||||
dependencies: Enumerable.Empty<LibraryRange>(),
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace NuGet.Versioning
|
||||
{
|
||||
public static class VersioningExtensions
|
||||
{
|
||||
public static bool EqualsFloating(this VersionRange self, NuGetVersion version)
|
||||
{
|
||||
if(!self.IsFloating)
|
||||
{
|
||||
return Equals(self.MinVersion, version);
|
||||
}
|
||||
|
||||
switch (self.Float.FloatBehavior)
|
||||
{
|
||||
case NuGetVersionFloatBehavior.Prerelease:
|
||||
return self.MinVersion.Version == version.Version &&
|
||||
version.Release.StartsWith(self.MinVersion.Release, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
case NuGetVersionFloatBehavior.Revision:
|
||||
return self.MinVersion.Major == version.Major &&
|
||||
self.MinVersion.Minor == version.Minor &&
|
||||
self.MinVersion.Patch == version.Patch &&
|
||||
self.MinVersion.Revision == version.Revision;
|
||||
|
||||
case NuGetVersionFloatBehavior.Patch:
|
||||
return self.MinVersion.Major == version.Major &&
|
||||
self.MinVersion.Minor == version.Minor &&
|
||||
self.MinVersion.Patch == version.Patch;
|
||||
|
||||
case NuGetVersionFloatBehavior.Minor:
|
||||
return self.MinVersion.Major == version.Major &&
|
||||
self.MinVersion.Minor == version.Minor;
|
||||
|
||||
case NuGetVersionFloatBehavior.Major:
|
||||
return self.MinVersion.Major == version.Major;
|
||||
|
||||
case NuGetVersionFloatBehavior.None:
|
||||
return self.MinVersion == version;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue