Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Aug 24, 2025

This PR optimizes the PluginLoader to significantly reduce build times by checking for plugin DLL existence and versions before running dotnet restore.

Problem

The current implementation always runs dotnet restore during plugin loading, which can be slow depending on cache state, number of packages, and projects. This happens even when all required plugin DLLs are already present and valid.

Solution

Reversed the execution order to check DLLs first, then conditionally restore only when needed:

Before:

dotnet restore → check for DLLs → load plugins

After:

check DLLs → dotnet restore (only if needed) → load plugins

Key Features

Smart Restoration Logic

  • NuGet plugins: Validates both DLL existence and file version against csproj package version
  • Project references: Checks DLL existence only (no version validation needed)
  • Conditional restore: Only runs dotnet restore when plugin DLLs are missing or outdated

Version Checking

For NuGet packages, the implementation uses FileVersionInfo to compare the DLL's file version with the package version specified in the csproj. This ensures that after package updates, the correct DLL versions are restored.

Backward Compatibility

  • No breaking changes to public APIs
  • Same behavior when DLLs are missing (still runs restore and builds)
  • All existing functionality preserved

Performance Benefits

  • Fast path: When all plugin DLLs are present and valid, skips expensive restore operation
  • Clear logging: Debug messages indicate when restore is skipped vs. executed:
    • "All plugin DLLs are present and valid, skipping dotnet restore"
    • "Some plugin DLLs are missing or outdated, running dotnet restore"

Implementation Details

Added helper methods for cleaner code organization:

  • GetNuGetPluginInfo() - Extracts NuGet plugin information from csproj
  • GetProjectRefPluginInfo() - Extracts project reference plugin information
  • IsNuGetPluginValid() - Validates NuGet plugin DLL existence and version
  • AreAllPluginsValid() - Validates all plugins before deciding whether to restore

Testing

Comprehensive test coverage with 8 passing tests:

  • Unit tests for all new helper methods
  • Integration tests verifying end-to-end optimization behavior
  • Tests for both missing and present plugin scenarios

Fixes #51.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI changed the title [WIP] Restore on bake causes slow builds Optimize PluginLoader to check DLLs before running dotnet restore Aug 24, 2025
Copilot AI requested a review from matt-goldman August 24, 2025 08:00
@github-actions github-actions bot added preview Triggers a release of preview version of Nuget packages enhancement New feature or request Blake.BuildTools labels Aug 24, 2025
Copy link
Owner

@matt-goldman matt-goldman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@matt-goldman matt-goldman marked this pull request as ready for review August 24, 2025 21:58
Copilot AI review requested due to automatic review settings August 24, 2025 21:58
@matt-goldman matt-goldman added release Triggers a release of a production version of Nuget packages Blake.CLI and removed preview Triggers a release of preview version of Nuget packages labels Aug 24, 2025
@matt-goldman matt-goldman merged commit ddf3f11 into main Aug 24, 2025
4 of 5 checks passed
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR optimizes the PluginLoader to reduce build times by checking for plugin DLL existence and versions before running dotnet restore. The optimization reverses the execution order to validate plugins first, then conditionally restore only when needed.

Key changes:

  • Introduces smart restoration logic that validates both NuGet and project reference plugins before deciding whether to run dotnet restore
  • Adds version checking for NuGet packages using FileVersionInfo to ensure correct DLL versions
  • Maintains backward compatibility while providing significant performance improvements for the common case where all plugins are already present and valid

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/Blake.BuildTools/Utils/PluginLoader.cs Core optimization implementation with new helper methods for plugin validation and conditional restore logic
tests/Blake.BuildTools.Tests/Utils/PluginLoaderTests.cs Comprehensive test coverage for new helper methods and integration scenarios

Comment on lines +173 to +176
if (fileVersion.StartsWith(plugin.Version))
{
return true;
}
Copy link

Copilot AI Aug 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using StartsWith for version comparison is unreliable and could lead to false positives. For example, version '1.0' would incorrectly match file version '1.0.1.2' or '1.00.0'. Consider using System.Version for proper semantic version comparison or exact string matching.

Suggested change
if (fileVersion.StartsWith(plugin.Version))
{
return true;
}
// Compare versions component-wise for leniency, but avoid false positives
if (Version.TryParse(plugin.Version, out var expectedVersion) && Version.TryParse(fileVersion, out var actualVersion))
{
// Compare only as many components as are present in plugin.Version
bool matches = true;
if (expectedVersion.Major != actualVersion.Major) matches = false;
if (expectedVersion.Minor != -1 && expectedVersion.Minor != actualVersion.Minor) matches = false;
if (expectedVersion.Build != -1 && expectedVersion.Build != actualVersion.Build) matches = false;
if (expectedVersion.Revision != -1 && expectedVersion.Revision != actualVersion.Revision) matches = false;
if (matches)
{
return true;
}
}
else
{
// Fallback: exact string match
if (fileVersion == plugin.Version)
{
return true;
}
}

Copilot uses AI. Check for mistakes.
Comment on lines +182 to +185
catch (Exception ex)
{
logger?.LogDebug(ex, "Error checking version for NuGet plugin: {dllPath}", plugin.DllPath);
return false; // Assume invalid if we can't check version
Copy link

Copilot AI Aug 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment suggests assuming invalid when version checking fails, but this could cause unnecessary restores on systems where FileVersionInfo.GetVersionInfo consistently fails due to file format issues. Consider logging the specific exception type and potentially having different fallback behavior for different exception types.

Suggested change
catch (Exception ex)
{
logger?.LogDebug(ex, "Error checking version for NuGet plugin: {dllPath}", plugin.DllPath);
return false; // Assume invalid if we can't check version
catch (NotSupportedException ex)
{
logger?.LogWarning(ex, "File format not supported when checking version for NuGet plugin: {dllPath}. Assuming valid.", plugin.DllPath);
return true; // Assume valid if file format is not supported
}
catch (Exception ex)
{
logger?.LogError(ex, "Unexpected error checking version for NuGet plugin: {dllPath}. Assuming invalid.", plugin.DllPath);
return false; // Assume invalid for other exceptions

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Blake.BuildTools Blake.CLI enhancement New feature or request release Triggers a release of a production version of Nuget packages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Restore on bake causes slow builds

2 participants