Conversation
1e1109e to
5284a9e
Compare
333cded to
5e4a630
Compare
| } | ||
| } | ||
|
|
||
| private bool IsProjectBuildIntegrated(PackageSpec packageSpec) |
There was a problem hiding this comment.
This wasn't used at all.
9fb6b9d to
c0a3152
Compare
| <_RestoreProjectName>$(MSBuildProjectName)</_RestoreProjectName> | ||
| <_RestoreProjectName Condition=" '$(RestoreProjectStyle)' == 'PackageReference' AND '$(AssemblyName)' != '' ">$(AssemblyName)</_RestoreProjectName> | ||
| <_RestoreProjectName Condition=" '$(RestoreProjectStyle)' == 'PackageReference' AND '$(PackageId)' != '' ">$(PackageId)</_RestoreProjectName> | ||
| <_RestoreProjectName Condition=" ('$(RestoreProjectStyle)' == 'PackageReference' OR '$(RestoreProjectStyle)' == 'DotnetToolReference') AND '$(AssemblyName)' != '' ">$(AssemblyName)</_RestoreProjectName> |
There was a problem hiding this comment.
This is used a lot, I suggest storing the value of ('$(RestoreProjectStyle)' == 'PackageReference' OR '$(RestoreProjectStyle)' == 'DotnetToolReference') as a property and re-using it for these conditions. It can be done local to this target.
| contentItems.Load(compatibilityData.Files); | ||
|
|
||
|
|
||
| if (compatibilityData.TargetLibrary.PackageType.Any(e => e.Equals(PackageType.DotnetTool))) |
There was a problem hiding this comment.
.Contains(PackageType.DotnetTool) might be a better fit than Any
| new PackageIdentity(node.Key.Name, node.Key.Version)); | ||
|
|
||
| issues.Add(issue); | ||
| await _log.LogAsync(GetErrorMessage(NuGetLogCode.NU1204, issue, graph));// |
| } | ||
|
|
||
| if (containsDotnetToolPackageType && | ||
| !(HasCompatibleAssets(compatibilityData.TargetLibrary) || !compatibilityData.Files.Any(p => p.StartsWith("tools/", StringComparison.OrdinalIgnoreCase)))) |
There was a problem hiding this comment.
Why allow non-tools compatible assets? Shouldn't this only look at the tools folder for a package of that type?
There was a problem hiding this comment.
I'm not sure I understand this method, should there be one path for tool projects and another for everything else?
|
|
||
| if (ProjectStyle.DotnetToolReference == compatibilityData.PackageSpec.RestoreMetadata?.ProjectStyle) | ||
| { | ||
| if (compatibilityData.PackageSpec.GetAllPackageDependencies().Any(e => e.Name.Equals(compatibilityData.TargetLibrary.Name))) |
| targetLibrary.Build.Count > 0 || // Build | ||
| targetLibrary.BuildMultiTargeting.Count > 0; // Cross targeting build | ||
| targetLibrary.BuildMultiTargeting.Count > 0 || // Cross targeting build | ||
| targetLibrary.ToolsAssemblies.Count > 0; // Tools assemblies - This makes a package not backwards compatible potentially, but do tools assets matter |
There was a problem hiding this comment.
This should be separate check, a regular project should not see tool packages as compatible. I am guessing that this wouldn't be populated if it wasn't a tools project, but it would be more clear if there were a different method to check tool assets.
| </PropertyGroup> | ||
| <!-- Determine the restore output path --> | ||
| <PropertyGroup Condition=" '$(RestoreProjectStyle)' == 'PackageReference' OR '$(RestoreProjectStyle)' == 'ProjectJson' "> | ||
| <PropertyGroup Condition=" '$(PackageReferenceCompatibleProjectStyle)' == 'true' OR '$(RestoreProjectStyle)' == 'ProjectJson' "> |
| /// DotnetToolReference project | ||
| /// </summary> | ||
| DotnetCliTool = 3, | ||
| DotnetToolReference = 3, |
There was a problem hiding this comment.
It shouldn't matter since I don't think anyone is using this enum where there would be a mix of NuGet.*.dll versions, but I'd typically expect this to be added at the end and not change the numbers of existing values.
| }, | ||
| pathPatterns: new PatternDefinition[] | ||
| { | ||
| new PatternDefinition("tools/{tfm}/{rid}/{any}", table: DotnetAnyTable), |
There was a problem hiding this comment.
Use DefaultTfmAny instead of DotnetAnyTable for both. At this point dotnet is deprecated so it would cause problems to use that for netstandard.
You also want the real Any like build/ uses.
You'll need to update the tests around this also.
| [PlatformTheory(Platform.Windows)] | ||
| [InlineData("net461")] | ||
| [InlineData("netcoreapp1.0")] | ||
| public void DotnetToolTests_NoPackageReferenceToolRestore_ThrowsError(string tfm) |
| using NuGet.Packaging.PackageExtraction; | ||
| using NuGet.Protocol; | ||
| using Xunit; | ||
| using NuGet.Packaging.Core; |
| RestorePackagesPath="$(RestorePackagesPath)" | ||
| RestoreFallbackFolders="$(RestoreFallbackFolders)" | ||
| RestoreConfigFile="$(RestoreConfigFile)" | ||
| RestoreRootConfigDirectory="$(RestoreRootConfigDirectory)" |
There was a problem hiding this comment.
do we wanna support this RestoreRootConfigDirectory via commandLine restore as well?
There was a problem hiding this comment.
What do you mean by commandline?
People can set the MSBuild property if they want to, because we can't really hide it.
It's not called in the normal nuget.exe/dotnet.exe workflows.
| { | ||
| await logger.LogAsync(LogLevel.Verbose, string.Format(CultureInfo.CurrentCulture, Strings.Log_CheckingCompatibility, graph.Name)); | ||
| if (!(ProjectStyle.DotnetToolReference == project.RestoreMetadata?.ProjectStyle && string.IsNullOrEmpty(graph.RuntimeIdentifier))) | ||
| { // Don't do compat checks for the ridless graph of DotnetTooReference restore. Everything relevant will be caught in the graph with the rid |
|
I'll do the change for nested folders separately. Don't want to overextend this PR. |
|
Just out of curiosity, how this handles local tool installation? |
|
From a NuGet perspective, there is no design/implementation work on global vs local (not even sure what/how they're doing that, it's still a WIP). There's 2 difference between global and local tools...how the tools can be invoked and where they are installed. The global tools, are as the name suggests, global, can be invoked from anywhere, so the tool location, which is at a global location, is added to the global path. The local tools are just meant to be invokable in a certain context, and they'll be installed to the global packages folder of the user. So the only thing that changes for us, is the global packages folder, which is a core scenario of ours anyways. |
5c3e98e to
ade7829
Compare
| --> | ||
| <Target Name="_GetRestoreSettingsAllFrameworks" | ||
| Condition=" '$(TargetFrameworks)' != '' AND '$(RestoreProjectStyle)' == 'PackageReference' " | ||
| Condition=" '$(TargetFrameworks)' != '' AND ( '$(RestoreProjectStyle)' == 'PackageReference' OR '$(RestoreProjectStyle)' == 'DotnetToolReference' ) " |
There was a problem hiding this comment.
why not use PackageReferenceCompatibleProjectStyle here?
| --> | ||
| <Target Name="_GetRestoreSettingsCurrentProject" | ||
| Condition=" '$(TargetFrameworks)' == '' AND '$(RestoreProjectStyle)' == 'PackageReference' " | ||
| Condition=" '$(TargetFrameworks)' == '' AND ( '$(RestoreProjectStyle)' == 'PackageReference' OR '$(RestoreProjectStyle)' == 'DotnetToolReference' ) " |
There was a problem hiding this comment.
PackageReferenceCompatibleProjectStyle
There was a problem hiding this comment.
The scope of that property is local.
There was a problem hiding this comment.
as long as the target in which it is defined is executed before this one, that property can be used. it's much easier to maintain if there is only one place to add a future PackageReference compatible project style
There was a problem hiding this comment.
Refactored it.
I was more comfortable to just add it to the _GetRestoreProjectStyle returns list.
|
|
||
| if (packageSpec.RestoreMetadata?.ProjectStyle == ProjectStyle.DotnetToolReference) | ||
| { | ||
| if (packageSpec.GetAllPackageDependencies().Count() != 1) |
There was a problem hiding this comment.
can this return a null list for zero package dependencies?
There was a problem hiding this comment.
No, it'll return an empty set.
| graph.Conventions.Patterns.CompileRefAssemblies, | ||
| graph.Conventions.Patterns.RuntimeAssemblies, | ||
| graph.Conventions.Patterns.ContentFiles | ||
| graph.Conventions.Patterns.ContentFiles, |
There was a problem hiding this comment.
why the , in the end?
There was a problem hiding this comment.
Stuff was added, then removed in a later commit, but the , got left over.
| group.Properties.TryGetValue(ManagedCodeConventions.PropertyNames.RuntimeIdentifier, out var ridObj); | ||
| group.Properties.TryGetValue(ManagedCodeConventions.PropertyNames.TargetFrameworkMoniker, out var tfmObj); | ||
|
|
||
| var tfm = tfmObj as NuGetFramework; |
There was a problem hiding this comment.
you are assumbing TryGetValue returned the right value for both of these, is that a safe assumption?
There was a problem hiding this comment.
What do you mean by the right value?
Nulls are ok, won't cause any problems, but that'll be caught way earlier.
This is mostly for tests.
We already do the same thing on L269
| } | ||
|
|
||
| if (containsDotnetToolPackageType && | ||
| !(HasCompatibleToolsAssets(compatibilityData.TargetLibrary) || !compatibilityData.Files.Any(p => p.StartsWith("tools/", StringComparison.OrdinalIgnoreCase)))) |
There was a problem hiding this comment.
since you do a check for files fairly often, can we abstract out functions that would tell us if there are any lib files or tool files like this:
compatibilityData.HasLibFiles
compatibilityData.HasToolsFiles etc etc.
There was a problem hiding this comment.
HasCompatibleToolsAssetts is a static used once in the compat checker, and once in the lock file builder.
It can't be bound to the CompatibilityData model.
| !compatibilityData.Files.Any(p => | ||
| p.StartsWith("ref/", StringComparison.OrdinalIgnoreCase) | ||
| || p.StartsWith("lib/", StringComparison.OrdinalIgnoreCase)); // No assemblies at all (for any TxM) | ||
| || p.StartsWith("lib/", StringComparison.OrdinalIgnoreCase)); // No assemblies at all (for any TxM) |
There was a problem hiding this comment.
There was a problem hiding this comment.
I'd rather not refactor code that doesn't need changing.
Same as above, can't tie to the model.
| { | ||
| if (compatibilityData.PackageSpec.GetAllPackageDependencies().Any(e => e.Name.Equals(compatibilityData.TargetLibrary.Name, StringComparison.OrdinalIgnoreCase))) | ||
| { | ||
| if (!containsDotnetToolPackageType) |
There was a problem hiding this comment.
change this to :
if(!containsDotnetToolPackageType && compatibilityData.PackageSpec.GetAllPackageDependencies().Any(e => e.Name.Equals(compatibilityData.TargetLibrary.Name, StringComparison.OrdinalIgnoreCase)))
this way it will not have to evaluate the more expensive check if containsDotnetToolPackageType is false.
There was a problem hiding this comment.
Good catch. Not sure how I missed that simplification.
…s check for tools vs dependency packages
…otnet tool reference
6a581f6 to
90dbfd5
Compare
emgarten
left a comment
There was a problem hiding this comment.
Minor comments. This looks very complete and with lots of tests great! 👏
| <comment>{0} is the certificate store name</comment> | ||
| </data> | ||
| <data name="Error_ProjectWithIncorrectDependenciesCount" xml:space="preserve"> | ||
| <value>Project {0} must have exactly {1} package reference(s).</value> |
There was a problem hiding this comment.
nit: this could just say a single package reference, I'm not sure that writing in the number is needed.
| <value>Invalid project-package combination for {0} {1}. DotnetToolReference project style can only contain references of the DotnetTool type</value> | ||
| </data> | ||
| <data name="Error_ToolsPackageWithExtraPackageTypes" xml:space="preserve"> | ||
| <value>Invalid tools package {0} {1}. Tools packages cannot contain more than 1 PackageType.</value> |
There was a problem hiding this comment.
nit: as a general rule numbers smaller than 10 should be written out as the word, not as the numeral. So: more than one PackageType here
|
|
||
| var res = StringComparer.OrdinalIgnoreCase.Compare(Name, other.Name); | ||
|
|
||
| if(res != 0) |
| return res; | ||
| } | ||
|
|
||
| return Version.CompareTo(other.Version); |
There was a problem hiding this comment.
Looks like Version could be null here and throw. Maybe the parser prevents this, but this class seems to allow it.
There was a problem hiding this comment.
There's a null version check, so version can not be null.
| } | ||
| try | ||
| { | ||
| File.Delete(targetFilePath); |
|
|
||
| // Assert | ||
| Assert.Equal(1, groups.Count); | ||
| Assert.Equal(NuGetFramework.AnyFramework, (NuGetFramework)groups.First().Properties["tfm"]); |
Bug
Fixes: NuGet/Home#6199, NuGet/Home#6198, NuGet/Home#6197, NuGet/Home#6200
Regression: No
If Regression then when did it last work:
If Regression then how are we preventing it in future:
Fix
Details:
Here's the spec for the global tools implementation.
https://github.com/NuGet/Home/wiki/Global-Tools---NuGet-Implementation
The brief is, we introduce a new package type for dotnet tools, with compatible asset as "tools/tfm/rid/any.extension.
That package is only compatible with a special project type that the CLI will create, DotnetToolReference.
1 package per project, that package has to be a dotnettool.
DotnetTooReference works almost exactly the same way as Package Reference with the above restrictions in place.
Notable: Tool Restore does not generate Msbuild props and targets, for failures
No no-op artifacts for tool restore.
The core logic is in:
CompatibilityChecker
CompatibilityIssue
RestoreCommand
LockFileUtils
LockFileFormat
LockFileTargetLibrary
ManagedCodeConventions
Most relevant tests:
DotnetToolTests
ContentModelToolsTests
Testing/Validation
Tests Added: Yes
Reason for not adding tests:
Validation done: Manual, by Will from CLI team, automation
PS. This will go in dev when it's shifted to 15.7
//cc @wli3 @rrelyea