Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
Comment thread
ChrisonSimtian marked this conversation as resolved.
Outdated
using Fallout.Common.Execution;
using Fallout.Common.IO;
using Fallout.Common.Utilities;

namespace Fallout.Build.Execution.Extensions;

/// <summary>
/// Emits <c>build-graph.json</c> into the temporary directory on every build initialization,
/// giving editor tooling (the VS Code extension) a machine-readable projection of the target
/// graph: names, descriptions, the default/listed flags, the declaring type, and the four
/// relation kinds. Best-effort — a serialization failure never fails the build.
/// </summary>
internal class SerializeBuildGraphAttribute : BuildExtensionAttributeBase, IOnBuildInitialized
{
private const string GraphFileName = "build-graph.json";

/// <summary>Schema version consumers gate on; bump only on a breaking shape change.</summary>
private const int SchemaVersion = 1;

private static readonly JsonSerializerOptions serializerOptions =
new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true,
};
Comment thread
ChrisonSimtian marked this conversation as resolved.
Outdated

private AbsolutePath GraphFile => Build.TemporaryDirectory / GraphFileName;

public void OnBuildInitialized(
IReadOnlyCollection<ExecutableTarget> executableTargets,
IReadOnlyCollection<ExecutableTarget> executionPlan)
{
try
{
var model = new BuildGraphModel(
SchemaVersion,
ResolveFalloutVersion(),
executableTargets
.OrderBy(x => x.Name, StringComparer.Ordinal)
.Select(ToModel)
.ToList());

GraphFile.WriteJson(model, serializerOptions );
Comment thread
ChrisonSimtian marked this conversation as resolved.
Outdated
}
catch (Exception exception)
{
// Emission is a convenience for editor tooling — never let it break a build.
Serilog.Log.Verbose(exception, "Failed to emit {GraphFileName}", GraphFileName);
}
}

private static TargetModel ToModel(ExecutableTarget target)
=> new(
target.Name,
target.Description,
target.Member?.DeclaringType?.Name,
target.IsDefault,
target.Listed,
SortedNames(target.ExecutionDependencies),
SortedNames(target.OrderDependencies),
SortedNames(target.TriggerDependencies),
SortedNames(target.Triggers));

// Sorted for deterministic output — the graph carries no execution order, so the display
// order is irrelevant to consumers and a stable ordering avoids spurious file churn.
private static IReadOnlyList<string> SortedNames(IEnumerable<ExecutableTarget> targets)
=> targets.Select(x => x.Name).OrderBy(x => x, StringComparer.Ordinal).ToList();

// Mirrors Fallout.Migrate: the informational version up to the build-metadata separator,
// so the pin aligns with the running tool. Null for local/dev builds without a `+` suffix.
private static string ResolveFalloutVersion()
Comment thread
ChrisonSimtian marked this conversation as resolved.
Outdated
{
var informational = typeof(SerializeBuildGraphAttribute).Assembly
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
?.InformationalVersion;
if (string.IsNullOrEmpty(informational))
Comment thread
ChrisonSimtian marked this conversation as resolved.
Outdated
return null;

var plusIndex = informational.IndexOf('+');
return plusIndex == -1 ? informational : informational[..plusIndex];
Comment thread
ChrisonSimtian marked this conversation as resolved.
Outdated
}

private sealed record BuildGraphModel(
int Version,
string FalloutVersion,
IReadOnlyList<TargetModel> Targets);

private sealed record TargetModel(
string Name,
string Description,
string DeclaredIn,
bool Default,
bool Listed,
IReadOnlyList<string> DependsOn,
IReadOnlyList<string> After,
IReadOnlyList<string> TriggeredBy,
IReadOnlyList<string> Triggers);
}
1 change: 1 addition & 0 deletions src/Fallout.Build/FalloutBuild.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ namespace Fallout.Common;
// [SaveBuildProfile(Priority = 30)]
// [LoadBuildProfiles(Priority = 25)]
// After logo
[SerializeBuildGraph(Priority = 20)]
[HandlePlanRequests(Priority = 10)]
[HandleHelpRequests(Priority = 5)]
[Telemetry]
Expand Down
Loading