Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Apollo.Analysis.Worker/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@
{
Path = item.Path,
Content = item.Content
}).ToList()
}).ToList(),
NuGetReferences = request.Solution.NuGetReferences
};

var currentFile = cleanSolution.Items.FirstOrDefault(i => i.Path == request.Uri);
Expand Down
7 changes: 6 additions & 1 deletion Apollo.Analysis/MonacoService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ public async Task<byte[]> GetQuickInfoAsync(string quickInfoRequestString)
public async Task<byte[]> GetDiagnosticsAsync(string uri, Solution solution)
{
_projectService.UpdateSolution(solution);

if (solution.NuGetReferences?.Count > 0)
{
_projectService.SetNuGetReferences(solution.NuGetReferences);
}

if (_projectService.IsLoadingReferences)
{
Expand All @@ -270,7 +275,7 @@ public async Task<byte[]> GetDiagnosticsAsync(string uri, Solution solution)
"Temp" + Random.Shared.Next(),
syntaxTrees,
options: RoslynProject.CompilationDefaults.GetCompilationOptions(solution.Type),
references: _projectService.GetSystemReferencesOnly()
references: _projectService.GetAllReferences()
);

var allDiagnostics = await GetAllDiagnosticsAsync(compilation, syntaxTrees);
Expand Down
37 changes: 37 additions & 0 deletions Apollo.Analysis/RoslynProjectService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class RoslynProjectService
private ProjectId _projectId;
private string? _currentDocumentPath;
private MetadataReference? _userAssemblyReference;
private readonly List<MetadataReference> _nugetReferences = [];
private bool _isInitialized;
private bool _isLoadingReferences;

Expand Down Expand Up @@ -343,11 +344,47 @@ public IEnumerable<MetadataReference> GetSystemReferencesOnly()
public IEnumerable<MetadataReference> GetAllReferences()
{
var references = new List<MetadataReference>(_systemReferences);
references.AddRange(_nugetReferences);
if (_userAssemblyReference != null)
{
references.Add(_userAssemblyReference);
}
return references;
}

public void SetNuGetReferences(IEnumerable<NuGetReference> nugetRefs)
{
_nugetReferences.Clear();
foreach (var nugetRef in nugetRefs)
{
if (nugetRef.AssemblyData?.Length > 0)
{
try
{
var reference = MetadataReference.CreateFromImage(nugetRef.AssemblyData);
_nugetReferences.Add(reference);
_logger.LogTrace($"Added NuGet reference for analysis: {nugetRef.AssemblyName}");
}
catch (Exception ex)
{
_logger.LogWarning($"Failed to add NuGet reference {nugetRef.AssemblyName}: {ex.Message}");
}
}
}

UpdateNugetProjectReferences();
}

private void UpdateNugetProjectReferences()
{
var currentSolution = _workspace.CurrentSolution;
var project = currentSolution.GetProject(_projectId);
if (project == null) return;

var allReferences = GetAllReferences().ToList();
var newSolution = currentSolution.WithProjectMetadataReferences(_projectId, allReferences);
_workspace.TryApplyChanges(newSolution);
_logger.LogTrace($"Updated project with {allReferences.Count} total references");
}
}

4 changes: 4 additions & 0 deletions Apollo.Client/Layout/MainLayout.razor
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@using Apollo.Components
@using Apollo.Components.Code
@using Apollo.Components.Infrastructure.Keyboard
@using Apollo.Components.NuGet
@using Apollo.Components.Settings
@using Apollo.Components.Theme
@using Microsoft.FluentUI.AspNetCore.Components
Expand Down Expand Up @@ -33,6 +34,8 @@

[Inject] public KeyBindingsState KeyBindings { get; set; } = default!;

[Inject] public NuGetState NuGetState { get; set; } = default!;

bool _drawerOpen = true;

void DrawerToggle()
Expand Down Expand Up @@ -71,6 +74,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
await Settings.TryLoadSettingsFromStorageAsync();
await Settings.TrySetSystemThemeAsync();
await KeyBindings.LoadFromStorageAsync();
await NuGetState.InitializeAsync();
}
}

Expand Down
55 changes: 54 additions & 1 deletion Apollo.Compilation.Worker/Program.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System.Buffers.Text;
using System.Collections.Concurrent;
using System.Reflection;
using System.Runtime.Loader;
using System.Text.Json;
using Apollo.Compilation;
using Apollo.Compilation.Worker;
using Apollo.Contracts.Solutions;
using Apollo.Contracts.Workers;
using Apollo.Infrastructure;
using Apollo.Infrastructure.Workers;
Expand All @@ -21,9 +23,25 @@
var resolver = new MetadataReferenceResourceProvider(HostAddress.BaseUri);

byte[]? asmCache = [];
List<NuGetReference> nugetAssemblyCache = [];
Dictionary<string, Assembly> loadedNuGetAssemblies = new(StringComparer.OrdinalIgnoreCase);

ConcurrentBag<string> executionMessages = [];

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
var assemblyName = new AssemblyName(args.Name);
LogMessageWriter.Log($"Assembly resolve requested: {assemblyName.Name}", LogSeverity.Debug);

if (loadedNuGetAssemblies.TryGetValue(assemblyName.Name ?? "", out var assembly))
{
LogMessageWriter.Log($"Resolved from NuGet cache: {assemblyName.Name}", LogSeverity.Debug);
return assembly;
}

return null;
};

Console.SetOut(new WorkerConsoleWriter());
Console.SetError(new WorkerConsoleWriter());

Expand All @@ -46,6 +64,19 @@ await resolver.GetMetadataReferenceAsync("System.Console.wasm"),
await resolver.GetMetadataReferenceAsync("xunit.assert.wasm"),
await resolver.GetMetadataReferenceAsync("xunit.core.wasm")
};

nugetAssemblyCache = solution.NuGetReferences ?? [];

foreach (var nugetRef in nugetAssemblyCache)
{
if (nugetRef.AssemblyData?.Length > 0)
{
var nugetReference = MetadataReference.CreateFromImage(nugetRef.AssemblyData);
references.Add(nugetReference);
LogMessageWriter.Log($"Added NuGet reference: {nugetRef.AssemblyName}", LogSeverity.Debug);
}
}

var result = new CompilationService().Compile(solution, references);

asmCache = result.Assembly;
Expand All @@ -60,7 +91,29 @@ await resolver.GetMetadataReferenceAsync("xunit.core.wasm")
break;

case "execute":
// Load assembly and run.
// Load NuGet assemblies into runtime first and register for resolution
foreach (var nugetRef in nugetAssemblyCache)
{
if (nugetRef.AssemblyData?.Length > 0)
{
try
{
var loadedAsm = Assembly.Load(nugetRef.AssemblyData);
var asmName = loadedAsm.GetName().Name;
if (!string.IsNullOrEmpty(asmName))
{
loadedNuGetAssemblies[asmName] = loadedAsm;
}
LogMessageWriter.Log($"Loaded NuGet assembly for runtime: {nugetRef.AssemblyName} ({asmName})", LogSeverity.Debug);
}
catch (Exception ex)
{
LogMessageWriter.Log($"Failed to load NuGet assembly {nugetRef.AssemblyName}: {ex.Message}", LogSeverity.Warning);
}
}
}

// Load user assembly and run
byte[]? asm = Convert.FromBase64String(message.Payload);

var assembly = Assembly.Load(asm.Length > 0 ? asm : asmCache);
Expand Down
43 changes: 40 additions & 3 deletions Apollo.Compilation.Worker/WorkerConsoleWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,51 @@ namespace Apollo.Compilation.Worker;

class WorkerConsoleWriter : TextWriter
{
private readonly StringBuilder _buffer = new();

public override Encoding Encoding => Encoding.UTF8;

public override void Write(char value)
{
if (value == '\n')
{
Flush();
}
else if (value != '\r')
{
_buffer.Append(value);
}
}

public override void Write(string? value)
{
if (value == null) return;

foreach (var c in value)
{
Write(c);
}
}

public override void WriteLine(string? value)
{
base.WriteLine(value);
Write(value);
Flush();
}

var logModel = new CompilerLog(value, LogSeverity.Information);
// Post the log message to the main thread
public override void WriteLine()
{
Flush();
}

public override void Flush()
{
if (_buffer.Length == 0) return;

var message = _buffer.ToString();
_buffer.Clear();

var logModel = new CompilerLog(message, LogSeverity.Information);
Imports.PostMessage(JsonSerializer.Serialize(new WorkerMessage
{
Action = "log",
Expand Down
7 changes: 6 additions & 1 deletion Apollo.Compilation/CompilationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,12 @@ public ExecutionResult Execute(Assembly assembly, Action<string> logAction, Canc
catch (Exception ex)
{
stopwatch.Stop();
logAction?.Invoke($"Execution error: {ex.Message}");
var actualException = ex is System.Reflection.TargetInvocationException tie ? tie.InnerException ?? ex : ex;
logAction?.Invoke($"Execution error: {actualException.Message}");
if (actualException.StackTrace != null)
{
logAction?.Invoke(actualException.StackTrace);
}
return new ExecutionResult
{
Error = true,
Expand Down
41 changes: 40 additions & 1 deletion Apollo.Components/Analysis/CodeAnalysisState.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Text.Json;
using Apollo.Components.Console;
using Apollo.Components.Infrastructure.MessageBus;
using Apollo.Components.NuGet;
using Apollo.Components.Solutions;
using Apollo.Contracts.Analysis;
using Apollo.Contracts.Solutions;
using Apollo.Contracts.Workers;
using OmniSharp.Models.v1.Completion;
using Solution = Apollo.Contracts.Solutions.Solution;
Expand All @@ -16,6 +18,8 @@ public class CodeAnalysisState
private readonly IMessageBus _messageBus;
private readonly SolutionsState _solutionsState;
private readonly UserAssemblyStore _userAssemblyStore;
private readonly NuGetState _nuGetState;
private readonly INuGetStorageService _nuGetStorageService;
private bool _disabled;

public event Func<Task>? OnCodeAnalysisStateChanged;
Expand Down Expand Up @@ -65,13 +69,17 @@ public CodeAnalysisState(
CodeAnalysisConsoleService console,
IMessageBus messageBus,
SolutionsState solutionsState,
UserAssemblyStore userAssemblyStore)
UserAssemblyStore userAssemblyStore,
NuGetState nuGetState,
INuGetStorageService nuGetStorageService)
{
_workerFactory = workerFactory;
_console = console;
_messageBus = messageBus;
_solutionsState = solutionsState;
_userAssemblyStore = userAssemblyStore;
_nuGetState = nuGetState;
_nuGetStorageService = nuGetStorageService;

_userAssemblyStore.OnAssemblyUpdated += HandleUserAssemblyUpdated;
}
Expand Down Expand Up @@ -130,6 +138,8 @@ public async Task<List<Diagnostic>> GetDiagnosticsAsync(Solution solution, strin
if (Disabled || !_workerReady || solution == null || _workerProxy == null)
return [];

solution.NuGetReferences = await LoadNuGetReferencesAsync();

var request = new DiagnosticRequestWrapper
{
Solution = solution,
Expand All @@ -145,6 +155,35 @@ public async Task<List<Diagnostic>> GetDiagnosticsAsync(Solution solution, strin

return diagnostics?.ToList() ?? [];
}

private async Task<List<NuGetReference>> LoadNuGetReferencesAsync()
{
var references = new List<NuGetReference>();

foreach (var package in _nuGetState.InstalledPackages)
{
foreach (var assemblyName in package.AssemblyNames)
{
var assemblyData = await _nuGetStorageService.GetAssemblyDataAsync(
package.Id,
package.Version,
assemblyName);

if (assemblyData != null)
{
references.Add(new NuGetReference
{
PackageId = package.Id,
AssemblyName = assemblyName,
AssemblyData = assemblyData
});
_console.AddLog($"Loaded NuGet assembly: {assemblyName} from {package.Id}", ConsoleSeverity.Debug);
}
}
}

return references;
}

public async Task UpdateDocumentAsync(string path, string fullContent)
{
Expand Down
Loading
Loading