mirror of
https://github.com/github/codeql.git
synced 2026-04-25 00:35:20 +02:00
Merge pull request #13957 from tamasvajk/razor-standalone-2
C#: Generate source files from cshtml files in standalone
This commit is contained in:
@@ -23,13 +23,14 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
private readonly IDictionary<string, string> unresolvedReferences = new ConcurrentDictionary<string, string>();
|
||||
private int failedProjects;
|
||||
private int succeededProjects;
|
||||
private readonly string[] allSources;
|
||||
private readonly List<string> allSources;
|
||||
private int conflictedReferences = 0;
|
||||
private readonly IDependencyOptions options;
|
||||
private readonly DirectoryInfo sourceDir;
|
||||
private readonly DotNet dotnet;
|
||||
private readonly FileContent fileContent;
|
||||
private readonly TemporaryDirectory packageDirectory;
|
||||
private TemporaryDirectory? razorWorkingDirectory;
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -60,7 +61,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
packageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName));
|
||||
|
||||
this.fileContent = new FileContent(packageDirectory, progressMonitor, () => GetFiles("*.*"));
|
||||
this.allSources = GetFiles("*.cs").ToArray();
|
||||
this.allSources = GetFiles("*.cs").ToList();
|
||||
var allProjects = GetFiles("*.csproj");
|
||||
var solutions = options.SolutionFile is not null
|
||||
? new[] { options.SolutionFile }
|
||||
@@ -131,6 +132,13 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
progressMonitor.UnresolvedReference(r.Key, r.Value);
|
||||
}
|
||||
|
||||
var webViewExtractionOption = Environment.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_STANDALONE_EXTRACT_WEB_VIEWS");
|
||||
if (bool.TryParse(webViewExtractionOption, out var shouldExtractWebViews) &&
|
||||
shouldExtractWebViews)
|
||||
{
|
||||
GenerateSourceFilesFromWebViews();
|
||||
}
|
||||
|
||||
progressMonitor.Summary(
|
||||
AllSourceFiles.Count(),
|
||||
ProjectSourceFiles.Count(),
|
||||
@@ -143,6 +151,38 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
DateTime.Now - startTime);
|
||||
}
|
||||
|
||||
private void GenerateSourceFilesFromWebViews()
|
||||
{
|
||||
progressMonitor.LogInfo($"Generating source files from cshtml and razor files.");
|
||||
|
||||
var views = GetFiles("*.cshtml")
|
||||
.Concat(GetFiles("*.razor"))
|
||||
.ToArray();
|
||||
|
||||
if (views.Length > 0)
|
||||
{
|
||||
progressMonitor.LogInfo($"Found {views.Length} cshtml and razor files.");
|
||||
|
||||
// TODO: use SDK specified in global.json
|
||||
var sdk = new Sdk(dotnet).GetNewestSdk();
|
||||
if (sdk != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var razor = new Razor(sdk, dotnet, progressMonitor);
|
||||
razorWorkingDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName, "razor"));
|
||||
var generatedFiles = razor.GenerateFiles(views, usedReferences.Keys, razorWorkingDirectory.ToString());
|
||||
this.allSources.AddRange(generatedFiles);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// It's okay, we tried our best to generate source files from cshtml files.
|
||||
progressMonitor.LogInfo($"Failed to generate source files from cshtml files: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DependencyManager(string srcDir) : this(srcDir, DependencyOptions.Default, new ConsoleLogger(Verbosity.Info)) { }
|
||||
|
||||
private IEnumerable<string> GetFiles(string pattern, bool recurseSubdirectories = true)
|
||||
@@ -156,9 +196,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
/// Computes a unique temp directory for the packages associated
|
||||
/// with this source tree. Use a SHA1 of the directory name.
|
||||
/// </summary>
|
||||
/// <param name="srcDir"></param>
|
||||
/// <returns>The full path of the temp directory.</returns>
|
||||
private static string ComputeTempDirectory(string srcDir)
|
||||
private static string ComputeTempDirectory(string srcDir, string subfolderName = "packages")
|
||||
{
|
||||
var bytes = Encoding.Unicode.GetBytes(srcDir);
|
||||
var sha = SHA1.HashData(bytes);
|
||||
@@ -166,7 +205,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
foreach (var b in sha.Take(8))
|
||||
sb.AppendFormat("{0:x2}", b);
|
||||
|
||||
return Path.Combine(Path.GetTempPath(), "GitHub", "packages", sb.ToString());
|
||||
return Path.Combine(Path.GetTempPath(), "GitHub", subfolderName, sb.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -392,6 +431,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose() => packageDirectory?.Dispose();
|
||||
public void Dispose()
|
||||
{
|
||||
packageDirectory?.Dispose();
|
||||
razorWorkingDirectory?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,6 @@ using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
internal interface IDotNet
|
||||
{
|
||||
bool RestoreToDirectory(string project, string directory, string? pathToNugetConfig = null);
|
||||
bool New(string folder);
|
||||
bool AddPackage(string folder, string package);
|
||||
IList<string> GetListedRuntimes();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Utilities to run the "dotnet" command.
|
||||
/// </summary>
|
||||
@@ -30,29 +22,31 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
private void Info()
|
||||
{
|
||||
// TODO: make sure the below `dotnet` version is matching the one specified in global.json
|
||||
progressMonitor.RunningProcess($"{dotnet} --info");
|
||||
using var proc = Process.Start(dotnet, "--info");
|
||||
proc.WaitForExit();
|
||||
var ret = proc.ExitCode;
|
||||
|
||||
if (ret != 0)
|
||||
var res = RunCommand("--info");
|
||||
if (!res)
|
||||
{
|
||||
progressMonitor.CommandFailed(dotnet, "--info", ret);
|
||||
throw new Exception($"{dotnet} --info failed with exit code {ret}.");
|
||||
throw new Exception($"{dotnet} --info failed.");
|
||||
}
|
||||
}
|
||||
|
||||
private static ProcessStartInfo MakeDotnetStartInfo(string args, bool redirectStandardOutput) =>
|
||||
new ProcessStartInfo(dotnet, args)
|
||||
{
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = redirectStandardOutput
|
||||
};
|
||||
|
||||
private bool RunCommand(string args)
|
||||
{
|
||||
progressMonitor.RunningProcess($"{dotnet} {args}");
|
||||
using var proc = Process.Start(dotnet, args);
|
||||
proc.WaitForExit();
|
||||
if (proc.ExitCode != 0)
|
||||
using var proc = Process.Start(MakeDotnetStartInfo(args, redirectStandardOutput: false));
|
||||
proc?.WaitForExit();
|
||||
var exitCode = proc?.ExitCode ?? -1;
|
||||
if (exitCode != 0)
|
||||
{
|
||||
progressMonitor.CommandFailed(dotnet, args, proc.ExitCode);
|
||||
progressMonitor.CommandFailed(dotnet, args, exitCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -76,23 +70,28 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
return RunCommand(args);
|
||||
}
|
||||
|
||||
public IList<string> GetListedRuntimes()
|
||||
public IList<string> GetListedRuntimes() => GetListed("--list-runtimes", "runtime");
|
||||
|
||||
public IList<string> GetListedSdks() => GetListed("--list-sdks", "SDK");
|
||||
|
||||
private IList<string> GetListed(string args, string artifact)
|
||||
{
|
||||
const string args = "--list-runtimes";
|
||||
progressMonitor.RunningProcess($"{dotnet} {args}");
|
||||
var pi = new ProcessStartInfo(dotnet, args)
|
||||
{
|
||||
RedirectStandardOutput = true,
|
||||
UseShellExecute = false
|
||||
};
|
||||
var exitCode = pi.ReadOutput(out var runtimes);
|
||||
var pi = MakeDotnetStartInfo(args, redirectStandardOutput: true);
|
||||
var exitCode = pi.ReadOutput(out var artifacts);
|
||||
if (exitCode != 0)
|
||||
{
|
||||
progressMonitor.CommandFailed(dotnet, args, exitCode);
|
||||
return new List<string>();
|
||||
}
|
||||
progressMonitor.LogInfo($"Found runtimes: {string.Join("\n", runtimes)}");
|
||||
return runtimes;
|
||||
progressMonitor.LogInfo($"Found {artifact}s: {string.Join("\n", artifacts)}");
|
||||
return artifacts;
|
||||
}
|
||||
|
||||
public bool Exec(string execArgs)
|
||||
{
|
||||
var args = $"exec {execArgs}";
|
||||
return RunCommand(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
internal record DotnetVersion : IComparable<DotnetVersion>
|
||||
{
|
||||
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;
|
||||
public string FullPath
|
||||
{
|
||||
get
|
||||
{
|
||||
var preRelease = IsPreRelease ? $"-{preReleaseVersionType}.{preReleaseVersion}" : "";
|
||||
var version = this.version + preRelease;
|
||||
return Path.Combine(dir, version);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
internal interface IDotNet
|
||||
{
|
||||
bool RestoreToDirectory(string project, string directory, string? pathToNugetConfig = null);
|
||||
bool New(string folder);
|
||||
bool AddPackage(string folder, string package);
|
||||
IList<string> GetListedRuntimes();
|
||||
IList<string> GetListedSdks();
|
||||
bool Exec(string execArgs);
|
||||
}
|
||||
}
|
||||
@@ -108,5 +108,14 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
internal void NoTopLevelNugetConfig() =>
|
||||
LogInfo("Could not find a top-level nuget.config file.");
|
||||
|
||||
internal void RazorSourceGeneratorMissing(string fullPath) =>
|
||||
LogInfo($"Razor source generator folder {fullPath} does not exist.");
|
||||
|
||||
internal void CscMissing(string cscPath) =>
|
||||
LogInfo($"Csc.exe not found at {cscPath}.");
|
||||
|
||||
internal void RazorCscArgs(string args) =>
|
||||
LogInfo($"Running CSC to generate Razor source files. Args: {args}.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
internal class Razor
|
||||
{
|
||||
private readonly DotnetVersion sdk;
|
||||
private readonly ProgressMonitor progressMonitor;
|
||||
private readonly DotNet dotNet;
|
||||
private readonly string sourceGeneratorFolder;
|
||||
private readonly string cscPath;
|
||||
|
||||
public Razor(DotnetVersion sdk, DotNet dotNet, ProgressMonitor progressMonitor)
|
||||
{
|
||||
this.sdk = sdk;
|
||||
this.progressMonitor = progressMonitor;
|
||||
this.dotNet = dotNet;
|
||||
|
||||
sourceGeneratorFolder = Path.Combine(this.sdk.FullPath, "Sdks", "Microsoft.NET.Sdk.Razor", "source-generators");
|
||||
if (!Directory.Exists(sourceGeneratorFolder))
|
||||
{
|
||||
this.progressMonitor.RazorSourceGeneratorMissing(sourceGeneratorFolder);
|
||||
throw new Exception($"Razor source generator folder {sourceGeneratorFolder} does not exist.");
|
||||
}
|
||||
|
||||
cscPath = Path.Combine(this.sdk.FullPath, "Roslyn", "bincore", "csc.dll");
|
||||
if (!File.Exists(cscPath))
|
||||
{
|
||||
this.progressMonitor.CscMissing(cscPath);
|
||||
throw new Exception($"csc.dll {cscPath} does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateAnalyzerConfig(IEnumerable<string> cshtmls, string analyzerConfigPath)
|
||||
{
|
||||
using var sw = new StreamWriter(analyzerConfigPath);
|
||||
sw.WriteLine("is_global = true");
|
||||
|
||||
foreach (var f in cshtmls.Select(f => f.Replace('\\', '/')))
|
||||
{
|
||||
sw.WriteLine($"\n[{f}]");
|
||||
var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(f)); // TODO: this should be the relative path of the file.
|
||||
sw.WriteLine($"build_metadata.AdditionalFiles.TargetPath = {base64}");
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> GenerateFiles(IEnumerable<string> cshtmls, IEnumerable<string> references, string workingDirectory)
|
||||
{
|
||||
var name = Guid.NewGuid().ToString("N").ToUpper();
|
||||
var tempPath = Path.GetTempPath();
|
||||
var analyzerConfig = Path.Combine(tempPath, $"{name}.txt");
|
||||
var dllPath = Path.Combine(tempPath, $"{name}.dll");
|
||||
var cscArgsPath = Path.Combine(tempPath, $"{name}.rsp");
|
||||
var outputFolder = Path.Combine(workingDirectory, name);
|
||||
Directory.CreateDirectory(outputFolder);
|
||||
|
||||
try
|
||||
{
|
||||
GenerateAnalyzerConfig(cshtmls, analyzerConfig);
|
||||
|
||||
progressMonitor.LogInfo($"Analyzer config content: {File.ReadAllText(analyzerConfig)}");
|
||||
|
||||
var args = new StringBuilder();
|
||||
args.Append($"/target:exe /generatedfilesout:\"{outputFolder}\" /out:\"{dllPath}\" /analyzerconfig:\"{analyzerConfig}\" ");
|
||||
|
||||
foreach (var f in Directory.GetFiles(sourceGeneratorFolder, "*.dll"))
|
||||
{
|
||||
args.Append($"/analyzer:\"{f}\" ");
|
||||
}
|
||||
|
||||
foreach (var f in cshtmls)
|
||||
{
|
||||
args.Append($"/additionalfile:\"{f}\" ");
|
||||
}
|
||||
|
||||
foreach (var f in references)
|
||||
{
|
||||
args.Append($"/reference:\"{f}\" ");
|
||||
}
|
||||
|
||||
var argsString = args.ToString();
|
||||
|
||||
progressMonitor.RazorCscArgs(argsString);
|
||||
|
||||
using (var sw = new StreamWriter(cscArgsPath))
|
||||
{
|
||||
sw.Write(argsString);
|
||||
}
|
||||
|
||||
dotNet.Exec($"\"{cscPath}\" /noconfig @\"{cscArgsPath}\"");
|
||||
|
||||
return Directory.GetFiles(outputFolder, "*.*", new EnumerationOptions { RecurseSubdirectories = true });
|
||||
}
|
||||
finally
|
||||
{
|
||||
DeleteFile(analyzerConfig);
|
||||
DeleteFile(dllPath);
|
||||
DeleteFile(cscArgsPath);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeleteFile(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
private const string aspNetCoreApp = "Microsoft.AspNetCore.App";
|
||||
|
||||
private readonly IDotNet dotNet;
|
||||
private readonly Lazy<Dictionary<string, RuntimeVersion>> newestRuntimes;
|
||||
private Dictionary<string, RuntimeVersion> NewestRuntimes => newestRuntimes.Value;
|
||||
private readonly Lazy<Dictionary<string, DotnetVersion>> newestRuntimes;
|
||||
private Dictionary<string, DotnetVersion> NewestRuntimes => newestRuntimes.Value;
|
||||
private static string ExecutingRuntime => RuntimeEnvironment.GetRuntimeDirectory();
|
||||
|
||||
public Runtime(IDotNet dotNet)
|
||||
@@ -27,58 +27,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
this.newestRuntimes = new(GetNewestRuntimes);
|
||||
}
|
||||
|
||||
internal record RuntimeVersion : IComparable<RuntimeVersion>
|
||||
{
|
||||
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;
|
||||
public string FullPath
|
||||
{
|
||||
get
|
||||
{
|
||||
var preRelease = IsPreRelease ? $"-{preReleaseVersionType}.{preReleaseVersion}" : "";
|
||||
var version = this.version + preRelease;
|
||||
return Path.Combine(dir, version);
|
||||
}
|
||||
}
|
||||
|
||||
public RuntimeVersion(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(RuntimeVersion? 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;
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"^(\S+)\s(\d+\.\d+\.\d+)(-([a-z]+)\.(\d+\.\d+\.\d+))?\s\[(.+)\]$")]
|
||||
private static partial Regex RuntimeRegex();
|
||||
|
||||
@@ -88,16 +36,17 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
/// It is assume that the format of a listed runtime is something like:
|
||||
/// Microsoft.NETCore.App 7.0.2 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
|
||||
/// </summary>
|
||||
private static Dictionary<string, RuntimeVersion> ParseRuntimes(IList<string> listed)
|
||||
private static Dictionary<string, DotnetVersion> ParseRuntimes(IList<string> listed)
|
||||
{
|
||||
// Parse listed runtimes.
|
||||
var runtimes = new Dictionary<string, RuntimeVersion>();
|
||||
var runtimes = new Dictionary<string, DotnetVersion>();
|
||||
var regex = RuntimeRegex();
|
||||
listed.ForEach(r =>
|
||||
{
|
||||
var match = RuntimeRegex().Match(r);
|
||||
var match = regex.Match(r);
|
||||
if (match.Success)
|
||||
{
|
||||
runtimes.AddOrUpdateToLatest(match.Groups[1].Value, new RuntimeVersion(match.Groups[6].Value, match.Groups[2].Value, match.Groups[4].Value, match.Groups[5].Value));
|
||||
runtimes.AddOrUpdateToLatest(match.Groups[1].Value, new DotnetVersion(match.Groups[6].Value, match.Groups[2].Value, match.Groups[4].Value, match.Groups[5].Value));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -107,7 +56,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
/// <summary>
|
||||
/// Returns a dictionary mapping runtimes to their newest version.
|
||||
/// </summary>
|
||||
internal Dictionary<string, RuntimeVersion> GetNewestRuntimes()
|
||||
internal Dictionary<string, DotnetVersion> GetNewestRuntimes()
|
||||
{
|
||||
var listed = dotNet.GetListedRuntimes();
|
||||
return ParseRuntimes(listed);
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using Semmle.Util;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
internal partial class Sdk
|
||||
{
|
||||
private readonly IDotNet dotNet;
|
||||
|
||||
public Sdk(IDotNet dotNet) => this.dotNet = dotNet;
|
||||
|
||||
[GeneratedRegex(@"^(\d+\.\d+\.\d+)(-([a-z]+)\.(\d+\.\d+\.\d+))?\s\[(.+)\]$")]
|
||||
private static partial Regex SdkRegex();
|
||||
|
||||
private static HashSet<DotnetVersion> ParseSdks(IList<string> listed)
|
||||
{
|
||||
var sdks = new HashSet<DotnetVersion>();
|
||||
var regex = SdkRegex();
|
||||
listed.ForEach(r =>
|
||||
{
|
||||
var match = regex.Match(r);
|
||||
if (match.Success)
|
||||
{
|
||||
sdks.Add(new DotnetVersion(match.Groups[5].Value, match.Groups[1].Value, match.Groups[3].Value, match.Groups[4].Value));
|
||||
}
|
||||
});
|
||||
|
||||
return sdks;
|
||||
}
|
||||
|
||||
public DotnetVersion? GetNewestSdk()
|
||||
{
|
||||
var listed = dotNet.GetListedSdks();
|
||||
var sdks = ParseSdks(listed);
|
||||
return sdks.Max();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,13 @@ namespace Semmle.Extraction.Tests
|
||||
internal class DotNetStub : IDotNet
|
||||
{
|
||||
private readonly IList<string> runtimes;
|
||||
private readonly IList<string> sdks;
|
||||
|
||||
public DotNetStub(IList<string> runtimes) => this.runtimes = runtimes;
|
||||
|
||||
public DotNetStub(IList<string> runtimes, IList<string> sdks)
|
||||
{
|
||||
this.runtimes = runtimes;
|
||||
this.sdks = sdks;
|
||||
}
|
||||
public bool AddPackage(string folder, string package) => true;
|
||||
|
||||
public bool New(string folder) => true;
|
||||
@@ -17,6 +21,10 @@ namespace Semmle.Extraction.Tests
|
||||
public bool RestoreToDirectory(string project, string directory, string? pathToNugetConfig = null) => true;
|
||||
|
||||
public IList<string> GetListedRuntimes() => runtimes;
|
||||
|
||||
public IList<string> GetListedSdks() => sdks;
|
||||
|
||||
public bool Exec(string execArgs) => true;
|
||||
}
|
||||
|
||||
public class RuntimeTests
|
||||
@@ -37,7 +45,7 @@ namespace Semmle.Extraction.Tests
|
||||
"Microsoft.NETCore.App 7.0.0 [/path/dotnet/shared/Microsoft.NETCore.App]",
|
||||
"Microsoft.NETCore.App 7.0.2 [/path/dotnet/shared/Microsoft.NETCore.App]"
|
||||
};
|
||||
var dotnet = new DotNetStub(listedRuntimes);
|
||||
var dotnet = new DotNetStub(listedRuntimes, null!);
|
||||
var runtime = new Runtime(dotnet);
|
||||
|
||||
// Execute
|
||||
@@ -63,7 +71,7 @@ namespace Semmle.Extraction.Tests
|
||||
"Microsoft.NETCore.App 8.0.0-preview.5.43280.8 [/path/dotnet/shared/Microsoft.NETCore.App]",
|
||||
"Microsoft.NETCore.App 8.0.0-preview.5.23280.8 [/path/dotnet/shared/Microsoft.NETCore.App]"
|
||||
};
|
||||
var dotnet = new DotNetStub(listedRuntimes);
|
||||
var dotnet = new DotNetStub(listedRuntimes, null!);
|
||||
var runtime = new Runtime(dotnet);
|
||||
|
||||
// Execute
|
||||
@@ -86,7 +94,7 @@ namespace Semmle.Extraction.Tests
|
||||
"Microsoft.NETCore.App 8.0.0-rc.4.43280.8 [/path/dotnet/shared/Microsoft.NETCore.App]",
|
||||
"Microsoft.NETCore.App 8.0.0-preview.5.23280.8 [/path/dotnet/shared/Microsoft.NETCore.App]"
|
||||
};
|
||||
var dotnet = new DotNetStub(listedRuntimes);
|
||||
var dotnet = new DotNetStub(listedRuntimes, null!);
|
||||
var runtime = new Runtime(dotnet);
|
||||
|
||||
// Execute
|
||||
@@ -115,7 +123,7 @@ namespace Semmle.Extraction.Tests
|
||||
@"Microsoft.WindowsDesktop.App 6.0.20 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]",
|
||||
@"Microsoft.WindowsDesktop.App 7.0.4 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]"
|
||||
};
|
||||
var dotnet = new DotNetStub(listedRuntimes);
|
||||
var dotnet = new DotNetStub(listedRuntimes, null!);
|
||||
var runtime = new Runtime(dotnet);
|
||||
|
||||
// Execute
|
||||
@@ -131,4 +139,56 @@ namespace Semmle.Extraction.Tests
|
||||
Assert.Equal(@"C:/Program Files/dotnet/shared/Microsoft.NETCore.App/7.0.2", FixExpectedPathOnWindows(netCoreApp.FullPath));
|
||||
}
|
||||
}
|
||||
|
||||
public class SdkTests
|
||||
{
|
||||
private static string FixExpectedPathOnWindows(string path) => path.Replace('\\', '/');
|
||||
|
||||
[Fact]
|
||||
public void TestSdk1()
|
||||
{
|
||||
// Setup
|
||||
var listedSdks = new List<string>
|
||||
{
|
||||
"6.0.413 [/usr/local/share/dotnet/sdk1]",
|
||||
"7.0.102 [/usr/local/share/dotnet/sdk2]",
|
||||
"7.0.302 [/usr/local/share/dotnet/sdk3]",
|
||||
"7.0.400 [/usr/local/share/dotnet/sdk4]",
|
||||
"5.0.402 [/usr/local/share/dotnet/sdk5]",
|
||||
"6.0.102 [/usr/local/share/dotnet/sdk6]",
|
||||
"6.0.301 [/usr/local/share/dotnet/sdk7]",
|
||||
};
|
||||
var dotnet = new DotNetStub(null!, listedSdks);
|
||||
var sdk = new Sdk(dotnet);
|
||||
|
||||
// Execute
|
||||
var version = sdk.GetNewestSdk();
|
||||
|
||||
// Verify
|
||||
Assert.NotNull(version);
|
||||
Assert.Equal("/usr/local/share/dotnet/sdk4/7.0.400", FixExpectedPathOnWindows(version.FullPath));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestSdk2()
|
||||
{
|
||||
// Setup
|
||||
var listedSdks = new List<string>
|
||||
{
|
||||
"6.0.413 [/usr/local/share/dotnet/sdk1]",
|
||||
"7.0.102 [/usr/local/share/dotnet/sdk2]",
|
||||
"8.0.100-preview.7.23376.3 [/usr/local/share/dotnet/sdk3]",
|
||||
"7.0.400 [/usr/local/share/dotnet/sdk4]",
|
||||
};
|
||||
var dotnet = new DotNetStub(null!, listedSdks);
|
||||
var sdk = new Sdk(dotnet);
|
||||
|
||||
// Execute
|
||||
var version = sdk.GetNewestSdk();
|
||||
|
||||
// Verify
|
||||
Assert.NotNull(version);
|
||||
Assert.Equal("/usr/local/share/dotnet/sdk3/8.0.100-preview.7.23376.3", FixExpectedPathOnWindows(version.FullPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
| Program.cs:0:0:0:0 | Program.cs |
|
||||
| Views/Home/Index.cshtml:0:0:0:0 | Views/Home/Index.cshtml |
|
||||
| obj/Debug/net7.0/.NETCoreApp,Version=v7.0.AssemblyAttributes.cs:0:0:0:0 | obj/Debug/net7.0/.NETCoreApp,Version=v7.0.AssemblyAttributes.cs |
|
||||
| obj/Debug/net7.0/cshtml.AssemblyInfo.cs:0:0:0:0 | obj/Debug/net7.0/cshtml.AssemblyInfo.cs |
|
||||
| obj/Debug/net7.0/cshtml.GlobalUsings.g.cs:0:0:0:0 | obj/Debug/net7.0/cshtml.GlobalUsings.g.cs |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import csharp
|
||||
|
||||
from File f
|
||||
where f.fromSource()
|
||||
where f.fromSource() or f.getExtension() = "cshtml"
|
||||
select f
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
| Program.cs |
|
||||
| Views/Home/Index.cshtml |
|
||||
| _semmle_code_target_codeql_csharp_integration_tests_ql_csharp_ql_integration_tests_all_platforms_cshtml_standalone_Views_Home_Index_cshtml.g.cs |
|
||||
@@ -0,0 +1,17 @@
|
||||
import csharp
|
||||
|
||||
private string getPath(File f) {
|
||||
result = f.getRelativePath()
|
||||
or
|
||||
not exists(f.getRelativePath()) and
|
||||
exists(int index |
|
||||
index =
|
||||
f.getBaseName()
|
||||
.indexOf("_semmle_code_target_codeql_csharp_integration_tests_ql_csharp_ql_integration_tests_all_platforms_cshtml_standalone_") and
|
||||
result = f.getBaseName().substring(index, f.getBaseName().length())
|
||||
)
|
||||
}
|
||||
|
||||
from File f
|
||||
where f.fromSource() or f.getExtension() = "cshtml"
|
||||
select getPath(f)
|
||||
@@ -0,0 +1 @@
|
||||
var dummy = "dummy";
|
||||
@@ -0,0 +1,8 @@
|
||||
@{
|
||||
ViewData["Title"] = "Home Page";
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h1 class="display-4">Welcome</h1>
|
||||
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="DeleteBinObjFolders" BeforeTargets="Clean">
|
||||
<RemoveDir Directories=".\bin" />
|
||||
<RemoveDir Directories=".\obj" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,6 @@
|
||||
import os
|
||||
from create_database_utils import *
|
||||
|
||||
|
||||
os.environ['CODEQL_EXTRACTOR_CSHARP_STANDALONE_EXTRACT_WEB_VIEWS'] = 'true'
|
||||
run_codeql_database_create(lang="csharp", extra_args=["--extractor-option=buildless=true", "--extractor-option=cil=false"])
|
||||
@@ -150,6 +150,8 @@ function RegisterExtractorPack(id)
|
||||
end
|
||||
|
||||
local windowsMatchers = {
|
||||
CreatePatternMatcher({ '^semmle%.extraction%.csharp%.standalone%.exe$' },
|
||||
MatchCompilerName, nil, { trace = false }),
|
||||
DotnetMatcherBuild,
|
||||
MsBuildMatcher,
|
||||
CreatePatternMatcher({ '^csc.*%.exe$' }, MatchCompilerName, extractor, {
|
||||
@@ -191,6 +193,9 @@ function RegisterExtractorPack(id)
|
||||
end
|
||||
}
|
||||
local posixMatchers = {
|
||||
-- The compiler name is case sensitive on Linux and lower cased on MacOS
|
||||
CreatePatternMatcher({ '^semmle%.extraction%.csharp%.standalone$', '^Semmle%.Extraction%.CSharp%.Standalone$' },
|
||||
MatchCompilerName, nil, { trace = false }),
|
||||
DotnetMatcherBuild,
|
||||
CreatePatternMatcher({ '^mcs%.exe$', '^csc%.exe$' }, MatchCompilerName,
|
||||
extractor, {
|
||||
|
||||
Reference in New Issue
Block a user