-
Notifications
You must be signed in to change notification settings - Fork 695
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
Support for ContentFiles in generated props. #1061
Conversation
30710ba
to
18bb75f
Compare
Fixes NuGet/Home#4098 Fixes NuGet/Home#3928 Fixes NuGet/Home#3683 Fixes NuGet/Home#4098 Fixes NuGet/Home#3399 Adding tests to verify files are written out on failure
18bb75f
to
0b91475
Compare
|
||
// Get assets for each framework | ||
foreach (var projectFramework in project.TargetFrameworks.Select(f => f.FrameworkName)) | ||
public static string ReplacePathsWithMacros(string path) |
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.
Method's name and logic are quite specific to the MSBuild restore scenario. I'd keep it private.
/// </summary> | ||
public static void AddNuGetProperties(XDocument doc, IEnumerable<string> packageFolders, string repositoryRoot, RestoreOutputType outputType, bool success) | ||
{ | ||
var projectStyle = "Unknown"; |
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.
var projectStyle = "Unknown"; [](start = 12, length = 29)
Needs to be an enum. And public conversion methods.
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.
I like the enum idea. This will be changed in a different PR to cover NuGet/Home#4047 and several similar issues where these values will now be used across the SDK, NuGet, and packages. This property had a different goal originally.
bool success) | ||
{ | ||
var firstImport = files.Where(file => file.Content != null) | ||
.OrderByDescending(file => file.Path.EndsWith(PropsExtension) ? 1 : 0) |
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.
OrderByDescending [](start = 17, length = 17)
Why not just Where
?
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.
For project.json there could be only a targets file, or no files that will be written out at all. For PackageReference this will always be props however.
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.
Ah.. That's clever. However I'd add a comment line here.
{ | ||
var libraryIdentity = globalGroupEntry.Key; | ||
var buildGroupSet = globalGroupEntry.Value; | ||
// Use a simple string compare to check if the files match |
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.
Use a simple string compare to check if the files match [](start = 23, length = 55)
This should be a hash comparison. I'd suggest filing an issue for that.
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.
Good call. This didn't change in this PR, it just moved. But now that contentFiles could potentially make these files larger proper hashing would be nice. NuGet/Home#4120
// convert graph items to package dependency info list | ||
var dependencies = ConvertToPackageDependencyInfo(graph.Flattened); | ||
// Add additional conditionals for multi targeting | ||
var multiTargetingFromMetadata = (request.Project.RestoreMetadata?.CrossTargeting == true); |
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.
CrossTargeting [](start = 79, length = 14)
Any plans to rename this property of ProjectRestoreMetadata
as well?
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.
This is only internal so it seemed unneeded for now. There are many fields that still have the old project.json names such as SuppressParent that should be renamed to the new PackageReference equivalent. All of those changes for PackageSpec could be better done in a single change.
|
||
// sort graph nodes by dependencies order | ||
var sortedItems = TopologicalSortUtility.SortPackagesByDependencyOrder(dependencies); | ||
var isCrossTargeting = multiTargetingFromMetadata |
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.
isCrossTargeting [](start = 16, length = 16)
isMultiTargeting
?
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.
I can update it, internally it is all the same.
string propsPath, | ||
RestoreOutputType restoreType, | ||
ILogger log, | ||
CancellationToken token) |
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.
token [](start = 30, length = 5)
not needed here
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.
removed
RestoreRequest request, | ||
bool restoreSuccess, | ||
ILogger log, | ||
CancellationToken token) |
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.
token [](start = 30, length = 5)
Not needed. The method is not async
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.
CancellationToken can be used without async. here is wasn't used, it was just kept from the previous result commit method. I'll remove it.
@alpaix updated |
|
||
var targetsGroup = new MSBuildRestoreImportGroup(); | ||
public static XElement GetProperty(string propertyName, string content) |
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.
GetProperty [](start = 31, length = 11)
GenerateProperty
would be more consistent
GetProperty("RestoreSuccess", success.ToString()), | ||
GetProperty("RestoreTool", "NuGet"), | ||
GetProperty("NuGetPackageRoot", ReplacePathsWithMacros(repositoryRoot)), | ||
GetProperty("NuGetPackageFolders", string.Join(";", packageFolders)), |
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.
packageFolders [](start = 80, length = 14)
Noted this is an absolute path. Although it points to the same location as NuGetPackageRoot
: C:\Users\alpanov\.nuget\packages\
.
Should it be also substituted with a macro?
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.
I considered this also. It would help make this more portable, but at the same time it would then be out of sync with the packageFolders list in project.assets.json. The goal here was to make that list available in MSBuild so that users could search those folders to find where NuGet downloaded the packages and work with them through MSBuild if needed.
For now I am going to leave it as an identical copy of what is in the assets file. I think we need some real user scenarios around this to decide further.
public static XElement GenerateContentFilesItem(string path, LockFileContentFile item, string packageId, string packageVersion) | ||
{ | ||
var entry = new XElement(Namespace + item.BuildAction.Value, | ||
new XAttribute("Include", path), |
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.
path [](start = 58, length = 4)
Beginning of import project path is substituted with the repository root. While the item include path is an absolute path. Looks inconsistent to me.
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.
Good catch, it looks like the ordering is off when applying macros for content files, I'll update it.
@alpaix updated |
.Select(path => GetImportPath(path, repositoryRoot)) | ||
.Select(GenerateImport)); | ||
|
||
targets.AddRange(GetGroupsWithConditions(buildCrossTargetsGroup, isMultiTargeting, CrossTargetingCondition)); |
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.
targets.AddRange [](start = 20, length = 16)
Same targets/props may be added multiple times, IE one time per each tfm.
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.
Yes, that's by design and the existing behavior. If there is a need to optimize this I think it should be done separate from this. In theory this could combine everything together and combine the conditions, but all of these need to be in dependency order which makes this and combining language flags on content items non-trivial.
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.
Forcing the TFM conditions also avoid scenarios where the user adds a new TFM to $(TargetFrameworks) but hasn't done a restore yet.
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.
If we leave it this way msbuild will keep complaining:
1>C:\Users\alpanov\documents\visual studio 2017\Projects\ConsoleApp6\ConsoleApp6\obj\ConsoleApp6.csproj.nuget.g.props(15,5): warning MSB4011: "C:\Users\alpanov.nuget\packages\alex.contentfiles\1.0.4\buildMultiTargeting\Alex.ContentFiles.props" cannot be imported again. It was already imported at "C:\Users\alpanov\documents\visual studio 2017\Projects\ConsoleApp6\ConsoleApp6\obj\ConsoleApp6.csproj.nuget.g.props (12,5)". This is most likely a build authoring error. This subsequent import will be ignored. [C:\Users\alpanov\documents\visual studio 2017\Projects\ConsoleApp6\ConsoleApp6\ConsoleApp6.csproj]
1>C:\Users\alpanov\documents\visual studio 2017\Projects\ConsoleApp6\ConsoleApp6\obj\ConsoleApp6.csproj.nuget.g.targets(7,5): warning MSB4011: "C:\Users\alpanov.nuget\packages\alex.contentfiles\1.0.4\buildMultiTargeting\Alex.ContentFiles.targets" cannot be imported again. It was already imported at "C:\Users\alpanov\documents\visual studio 2017\Projects\ConsoleApp6\ConsoleApp6\obj\ConsoleApp6.csproj.nuget.g.targets (4,5)". This is most likely a build authoring error. This subsequent import will be ignored. [C:\Users\alpanov\documents\visual studio 2017\Projects\ConsoleApp6\ConsoleApp6\ConsoleApp6.csproj]
.Where(e => pkg.Value.Exists()) | ||
.OrderBy(e => e.Path, StringComparer.Ordinal) | ||
.Select(e => | ||
new Tuple<LockFileTargetLibrary, LockFileContentFile, string>( |
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.
Tuple [](start = 40, length = 5)
nit: Tuple.Create(...)
new Tuple<LockFileTargetLibrary, LockFileContentFile, string>( | ||
item1: pkg.Key, | ||
item2: e, | ||
item3: pkg.Value.GetAbsolutePath(GetImportPath(e.Path, repositoryRoot))))) |
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.
GetImportPath [](start = 73, length = 13)
Should it be in reverse order:
GetImportPath(GetAbsolutePath(...))
?
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.
Fixed in the latest commit. I have no clue how this was compiling even, GetAbsolutePath does not take a string...
PackageIdentity libraryIdentity, | ||
ContentItemGroup buildItems, | ||
TargetsAndProps targetsAndProps) | ||
private static IEnumerable<MSBuildRestoreItemGroup> GetGroupsWithConditions( |
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.
GetGroupsWithConditions [](start = 60, length = 23)
=> GenerateGroupsWithConditions
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.
Looks ✨! Your call on eliminating duplicate imports.
Fixes NuGet/Home#4098
Fixes NuGet/Home#3928
Fixes NuGet/Home#3683
Fixes NuGet/Home#3399
Fixes NuGet/Home#4116
//cc @alpaix @mishra14 @rohit21agrawal @nkolev92 @jainaashish