using System; using System.IO; namespace Semmle.Extraction.CSharp.DependencyFetching { internal record DotNetVersion : IComparable { private readonly string dir; private readonly Version version; private readonly Version? preReleaseVersion; private readonly string? preReleaseVersionType; private bool IsPreRelease => preReleaseVersionType is not null && preReleaseVersion is not null; private string FullVersion { get { var preRelease = IsPreRelease ? $"-{preReleaseVersionType}.{preReleaseVersion}" : ""; return this.version + preRelease; } } public string FullPath => Path.Combine(dir, FullVersion); /** * The full path to the reference assemblies for this runtime. * This is the same as FullPath, except that we assume that the * reference assemblies are in a directory called "packs" and * the reference assemblies themselves are in a directory called * "[Framework].Ref/ref". * Example: * FullPath: /usr/share/dotnet/shared/Microsoft.NETCore.App/7.0.2 * FullPathReferenceAssemblies: /usr/share/dotnet/packs/Microsoft.NETCore.App.Ref/7.0.2/ref */ public string? FullPathReferenceAssemblies { get { var directories = dir.Split(Path.DirectorySeparatorChar); if (directories.Length >= 2) { directories[^2] = "packs"; directories[^1] = $"{directories[^1]}.Ref"; return Path.Combine(string.Join(Path.DirectorySeparatorChar, directories), FullVersion, "ref"); } return null; } } public DotNetVersion(string dir, string version, string preReleaseVersionType, string preReleaseVersion) { this.dir = dir; this.version = Version.Parse(version); if (!string.IsNullOrEmpty(preReleaseVersion) && !string.IsNullOrEmpty(preReleaseVersionType)) { this.preReleaseVersionType = preReleaseVersionType; this.preReleaseVersion = Version.Parse(preReleaseVersion); } } public int CompareTo(DotNetVersion? other) { var c = version.CompareTo(other?.version); if (c == 0 && IsPreRelease) { if (!other!.IsPreRelease) { return -1; } // Both are pre-release like runtime versions. // The pre-release version types are sorted alphabetically (e.g. alpha, beta, preview, rc) // and the pre-release version types are more important that the pre-release version numbers. return preReleaseVersionType != other!.preReleaseVersionType ? preReleaseVersionType!.CompareTo(other!.preReleaseVersionType) : preReleaseVersion!.CompareTo(other!.preReleaseVersion); } return c; } public override string ToString() => FullPath; } }