-
Notifications
You must be signed in to change notification settings - Fork 353
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
Add inferred runtime identifiers #7141
Closed
Closed
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
6103106
Refactor GenerateRuntimeGraph into multiple files
ericstj 78dec6f
Add the ability to infer additional RuntimeGroups from RIDs
ericstj 7916e11
Ensure we preserve version string verbatim
ericstj c537d55
Add some more tests for RID related types
ericstj f8a7773
Refactor RID addition and tests
ericstj File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
327 changes: 49 additions & 278 deletions
327
src/Microsoft.DotNet.Build.Tasks.Packaging/src/GenerateRuntimeGraph.cs
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.Diagnostics; | ||
using System.Text; | ||
|
||
namespace Microsoft.DotNet.Build.Tasks.Packaging | ||
{ | ||
internal class RID | ||
{ | ||
internal const char VersionDelimiter = '.'; | ||
internal const char ArchitectureDelimiter = '-'; | ||
internal const char QualifierDelimiter = '-'; | ||
|
||
public string BaseRID { get; set; } | ||
public bool OmitVersionDelimiter { get; set; } | ||
public RuntimeVersion Version { get; set; } | ||
public string Architecture { get; set; } | ||
public string Qualifier { get; set; } | ||
|
||
public override string ToString() | ||
{ | ||
StringBuilder builder = new StringBuilder(BaseRID); | ||
|
||
if (HasVersion) | ||
{ | ||
if (!OmitVersionDelimiter) | ||
{ | ||
builder.Append(VersionDelimiter); | ||
} | ||
builder.Append(Version); | ||
} | ||
|
||
if (HasArchitecture) | ||
{ | ||
builder.Append(ArchitectureDelimiter); | ||
builder.Append(Architecture); | ||
} | ||
|
||
if (HasQualifier) | ||
{ | ||
builder.Append(QualifierDelimiter); | ||
builder.Append(Qualifier); | ||
} | ||
|
||
return builder.ToString(); | ||
} | ||
|
||
|
||
enum RIDPart : int | ||
{ | ||
Base = 0, | ||
Version, | ||
Architcture, | ||
Qualifier, | ||
Max = Qualifier | ||
} | ||
|
||
public static RID Parse(string runtimeIdentifier) | ||
{ | ||
string[] parts = new string[(int)RIDPart.Max + 1]; | ||
bool omitVersionDelimiter = true; | ||
RIDPart parseState = RIDPart.Base; | ||
|
||
int partStart = 0, partLength = 0; | ||
|
||
// qualifier is indistinguishable from arch so we cannot distinguish it for parsing purposes | ||
Debug.Assert(ArchitectureDelimiter == QualifierDelimiter); | ||
|
||
for (int i = 0; i < runtimeIdentifier.Length; i++) | ||
{ | ||
char current = runtimeIdentifier[i]; | ||
partLength = i - partStart; | ||
|
||
switch (parseState) | ||
{ | ||
case RIDPart.Base: | ||
// treat any number as the start of the version | ||
if (current == VersionDelimiter || (current >= '0' && current <= '9')) | ||
{ | ||
SetPart(); | ||
partStart = i; | ||
if (current == VersionDelimiter) | ||
{ | ||
omitVersionDelimiter = false; | ||
partStart = i + 1; | ||
} | ||
parseState = RIDPart.Version; | ||
} | ||
// version might be omitted | ||
else if (current == ArchitectureDelimiter) | ||
{ | ||
// ensure there's no version later in the string | ||
if (-1 != runtimeIdentifier.IndexOf(VersionDelimiter, i)) | ||
{ | ||
break; | ||
} | ||
SetPart(); | ||
partStart = i + 1; // skip delimiter | ||
parseState = RIDPart.Architcture; | ||
} | ||
break; | ||
case RIDPart.Version: | ||
if (current == ArchitectureDelimiter) | ||
{ | ||
SetPart(); | ||
partStart = i + 1; // skip delimiter | ||
parseState = RIDPart.Architcture; | ||
} | ||
break; | ||
case RIDPart.Architcture: | ||
if (current == QualifierDelimiter) | ||
{ | ||
SetPart(); | ||
partStart = i + 1; // skip delimiter | ||
parseState = RIDPart.Qualifier; | ||
} | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
partLength = runtimeIdentifier.Length - partStart; | ||
if (partLength > 0) | ||
{ | ||
SetPart(); | ||
} | ||
|
||
string GetPart(RIDPart part) | ||
{ | ||
return parts[(int)part]; | ||
} | ||
|
||
void SetPart() | ||
{ | ||
if (partLength == 0) | ||
{ | ||
throw new ArgumentException($"unexpected delimiter at position {partStart} in {runtimeIdentifier}"); | ||
} | ||
|
||
parts[(int)parseState] = runtimeIdentifier.Substring(partStart, partLength); | ||
} | ||
|
||
string version = GetPart(RIDPart.Version); | ||
|
||
if (version == null) | ||
{ | ||
omitVersionDelimiter = false; | ||
} | ||
|
||
return new RID() | ||
{ | ||
BaseRID = GetPart(RIDPart.Base), | ||
OmitVersionDelimiter = omitVersionDelimiter, | ||
Version = version == null ? null : new RuntimeVersion(version), | ||
Architecture = GetPart(RIDPart.Architcture), | ||
Qualifier = GetPart(RIDPart.Qualifier) | ||
}; | ||
} | ||
|
||
|
||
public bool HasVersion => Version != null; | ||
|
||
public bool HasArchitecture => Architecture != null; | ||
|
||
public bool HasQualifier => Qualifier != null; | ||
|
||
public override bool Equals(object obj) | ||
{ | ||
return Equals(obj as RID); | ||
} | ||
|
||
public bool Equals(RID obj) | ||
{ | ||
return object.ReferenceEquals(obj, this) || | ||
(!(obj is null) && | ||
BaseRID == obj.BaseRID && | ||
OmitVersionDelimiter == obj.OmitVersionDelimiter && | ||
Version == obj.Version && | ||
Architecture == obj.Architecture && | ||
Qualifier == obj.Qualifier); | ||
|
||
} | ||
|
||
public override int GetHashCode() | ||
{ | ||
#if NETFRAMEWORK | ||
return BaseRID.GetHashCode(); | ||
#else | ||
HashCode hashCode = new HashCode(); | ||
hashCode.Add(BaseRID); | ||
hashCode.Add(VersionDelimiter); | ||
hashCode.Add(Version); | ||
hashCode.Add(ArchitectureDelimiter); | ||
hashCode.Add(Architecture); | ||
hashCode.Add(QualifierDelimiter); | ||
hashCode.Add(Qualifier); | ||
return hashCode.ToHashCode(); | ||
#endif | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Did you consider using a regular expression for parsing instead?
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 had a regex and it was much more difficult to read once it was complicated enough to handle all cases and capture all fields that we needed. This simple state machine is easier to read and debug (and happens to be more efficient though that's not a real concern for this one shot task).