-
Notifications
You must be signed in to change notification settings - Fork 698
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
Use ReadOnlyMemory when calculating the related file extensions #5943
Changes from all commits
d88a6a3
7311108
c4cafc2
0cd6d8a
579cac7
39b3833
de1360f
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 |
---|---|---|
|
@@ -2,17 +2,19 @@ | |
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
|
||
namespace NuGet.ContentModel | ||
{ | ||
public class ContentItemCollection | ||
{ | ||
private static readonly ReadOnlyMemory<char> Dll = ".dll".AsMemory(); | ||
private static readonly ReadOnlyMemory<char> Exe = ".exe".AsMemory(); | ||
private static readonly ReadOnlyMemory<char> Winmd = ".winmd".AsMemory(); | ||
|
||
private List<Asset> _assets; | ||
private ConcurrentDictionary<string, string> _assemblyRelatedExtensions; | ||
private Dictionary<ReadOnlyMemory<char>, string> _assemblyRelatedExtensions; | ||
|
||
/// <summary> | ||
/// True if lib/contract exists | ||
|
@@ -22,7 +24,7 @@ public class ContentItemCollection | |
public void Load(IEnumerable<string> paths) | ||
{ | ||
// Cache for assembly and it's related file extensions. | ||
_assemblyRelatedExtensions = new ConcurrentDictionary<string, string>(); | ||
_assemblyRelatedExtensions = new(); | ||
|
||
// Read already loaded assets | ||
_assets = new List<Asset>(); | ||
|
@@ -50,6 +52,7 @@ public void Load(IEnumerable<string> paths) | |
} | ||
} | ||
|
||
[Obsolete("Unused and will be removed in a future version.")] | ||
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. this seems to be used in the dotnet/sdk: dotnet/sdk#42458 (comment) 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. 2 options for you.
I'll revert the obsolete attribute for now. 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. 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. Thanks. I think moving to PopulateItemGroups is the right approach going forward. |
||
public IEnumerable<ContentItem> FindItems(PatternSet definition) | ||
{ | ||
return FindItemsImplementation(definition, _assets); | ||
|
@@ -271,7 +274,7 @@ private List<ContentItem> FindItemsImplementation(PatternSet definition, IEnumer | |
internal string GetRelatedFileExtensionProperty(string assemblyPath, IEnumerable<Asset> assets) | ||
{ | ||
//E.g. if path is "lib/net472/A.B.C.dll", the prefix will be "lib/net472/A.B.C." | ||
string assemblyPrefix = assemblyPath.Substring(0, assemblyPath.LastIndexOf('.') + 1); | ||
ReadOnlyMemory<char> assemblyPrefix = assemblyPath.AsMemory(0, assemblyPath.LastIndexOf('.') + 1); | ||
|
||
if (_assemblyRelatedExtensions.TryGetValue(assemblyPrefix, out string relatedProperty)) | ||
{ | ||
|
@@ -283,16 +286,17 @@ internal string GetRelatedFileExtensionProperty(string assemblyPath, IEnumerable | |
{ | ||
if (asset.Path is not null) | ||
{ | ||
string extension = Path.GetExtension(asset.Path); | ||
if (extension != string.Empty && | ||
var extension = GetExtension(asset); | ||
|
||
if (extension.Length > 0 && | ||
//Assembly properties are files with extensions ".dll", ".winmd", ".exe", see ManagedCodeConventions. | ||
!extension.Equals(".dll", StringComparison.OrdinalIgnoreCase) && | ||
!extension.Equals(".exe", StringComparison.OrdinalIgnoreCase) && | ||
!extension.Equals(".winmd", StringComparison.OrdinalIgnoreCase) && | ||
!ReadOnlyMemoryEquals(extension, Dll) && | ||
!ReadOnlyMemoryEquals(extension, Exe) && | ||
!ReadOnlyMemoryEquals(extension, Winmd) && | ||
!asset.Path.Equals(assemblyPath, StringComparison.OrdinalIgnoreCase) && | ||
//The prefix should match exactly (case sensitive), as file names are case sensitive on certain OSes. | ||
//E.g. for lib/net472/A.B.C.dll and lib/net472/a.b.c.xml, if we generate related property '.xml', the related file path is not predictable on case sensitive OSes. | ||
asset.Path.StartsWith(assemblyPrefix, StringComparison.Ordinal)) | ||
asset.Path.AsMemory().Span.StartsWith(assemblyPrefix.Span, StringComparison.Ordinal)) | ||
{ | ||
if (relatedFileExtensionList is null) | ||
{ | ||
|
@@ -306,16 +310,31 @@ internal string GetRelatedFileExtensionProperty(string assemblyPath, IEnumerable | |
// If no related files found. | ||
if (relatedFileExtensionList is null || relatedFileExtensionList.Count == 0) | ||
{ | ||
_assemblyRelatedExtensions.TryAdd(assemblyPrefix, null); | ||
_assemblyRelatedExtensions[assemblyPrefix] = null; | ||
return null; | ||
} | ||
else | ||
{ | ||
relatedFileExtensionList.Sort(); | ||
string relatedFileExtensionsProperty = string.Join(";", relatedFileExtensionList); | ||
_assemblyRelatedExtensions.TryAdd(assemblyPrefix, relatedFileExtensionsProperty); | ||
_assemblyRelatedExtensions[assemblyPrefix] = relatedFileExtensionsProperty; | ||
return relatedFileExtensionsProperty; | ||
} | ||
|
||
static bool ReadOnlyMemoryEquals(ReadOnlyMemory<char> x, ReadOnlyMemory<char> y) | ||
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 it worth making this an extension method that the whole repo can use? 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. Sorry, I had merged before this. |
||
{ | ||
return x.Span.Equals(y.Span, StringComparison.OrdinalIgnoreCase); | ||
} | ||
|
||
static ReadOnlyMemory<char> GetExtension(Asset asset) | ||
{ | ||
int lastIndexOfDot = asset.Path.LastIndexOf('.'); | ||
if (lastIndexOfDot != -1) | ||
{ | ||
return asset.Path.AsMemory(lastIndexOfDot); | ||
} | ||
return default; | ||
} | ||
} | ||
|
||
/// <summary> | ||
|
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.
@nkolev92 the SDK PR is now failing with this error in multiple tests, I wonder if it is related to this change:
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.
Weird, this codepath isn't run concurrently.