mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
118 lines
4.2 KiB
C#
118 lines
4.2 KiB
C#
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 DotNetCliWrapper dotNet;
|
|
private readonly string sourceGeneratorFolder;
|
|
private readonly string cscPath;
|
|
|
|
public Razor(DotnetVersion sdk, DotNetCliWrapper 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
|
|
}
|
|
}
|
|
}
|
|
} |