using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; using NuGet.Versioning; using Semmle.Util; using Semmle.Util.Logging; namespace Semmle.Extraction.CSharp.DependencyFetching { internal partial class Sdk { private readonly IDotNet dotNet; private readonly ILogger logger; private readonly Lazy cscPath; public string? CscPath => cscPath.Value; private readonly Lazy newestSdkVersion; public DotNetVersion? Version => newestSdkVersion.Value; public Sdk(IDotNet dotNet, ILogger logger) { this.dotNet = dotNet; this.logger = logger; newestSdkVersion = new Lazy(GetNewestSdkVersion); cscPath = new Lazy(GetCscPath); } [GeneratedRegex(@"^(\d+\.\d+\.\d+(-[a-z]+\.\d+\.\d+\.\d+)?)\s\[(.+)\]$")] private static partial Regex SdkRegex(); private static HashSet ParseSdks(IList listed) { var sdks = new HashSet(); var regex = SdkRegex(); listed.ForEach(r => { var match = regex.Match(r); if (match.Success && NuGetVersion.TryParse(match.Groups[1].Value, out var version)) { sdks.Add(new DotNetVersion(match.Groups[3].Value, version)); } }); return sdks; } private DotNetVersion? GetNewestSdkVersion() { var listed = dotNet.GetListedSdks(); var sdks = ParseSdks(listed); return sdks.Max(); } private string? GetCscPath() { var version = Version; if (version is null) { logger.LogWarning("No dotnet SDK found."); return null; } var path = Path.Combine(version.FullPath, "Roslyn", "bincore", "csc.dll"); logger.LogDebug($"Source generator CSC: '{path}'"); if (!File.Exists(path)) { logger.LogWarning($"csc.dll not found at '{path}'."); return null; } return path; } } }