implements PLN-0010 builder pipeline entrypoints
This commit is contained in:
parent
df8a98488a
commit
c467a2642f
@ -9,4 +9,4 @@
|
|||||||
{"type":"discussion","id":"DSC-0008","status":"done","ticket":"pbs-low-level-asset-manager-surface","title":"PBS Low-Level Asset Manager Surface for Runtime AssetManager","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["compiler","pbs","runtime","asset-manager","host-abi","stdlib","asset"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0023","file":"discussion/lessons/DSC-0008-pbs-low-level-asset-manager-surface/LSN-0023-lowassets-runtime-aligned-sdk-surface.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
|
{"type":"discussion","id":"DSC-0008","status":"done","ticket":"pbs-low-level-asset-manager-surface","title":"PBS Low-Level Asset Manager Surface for Runtime AssetManager","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["compiler","pbs","runtime","asset-manager","host-abi","stdlib","asset"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0023","file":"discussion/lessons/DSC-0008-pbs-low-level-asset-manager-surface/LSN-0023-lowassets-runtime-aligned-sdk-surface.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
|
||||||
{"type":"discussion","id":"DSC-0009","status":"open","ticket":"studio-debugger-workspace-integration","title":"Integrate ../debugger into Studio as a dedicated workspace","created_at":"2026-03-30","updated_at":"2026-03-30","tags":["studio","debugger","workspace","integration","shell"],"agendas":[{"id":"AGD-0009","file":"AGD-0009-studio-debugger-workspace-integration.md","status":"open","created_at":"2026-03-30","updated_at":"2026-03-30"}],"decisions":[],"plans":[],"lessons":[]}
|
{"type":"discussion","id":"DSC-0009","status":"open","ticket":"studio-debugger-workspace-integration","title":"Integrate ../debugger into Studio as a dedicated workspace","created_at":"2026-03-30","updated_at":"2026-03-30","tags":["studio","debugger","workspace","integration","shell"],"agendas":[{"id":"AGD-0009","file":"AGD-0009-studio-debugger-workspace-integration.md","status":"open","created_at":"2026-03-30","updated_at":"2026-03-30"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0010","status":"open","ticket":"studio-code-editor-workspace-foundations","title":"Establish Code Editor workspace foundations in Studio without LSP","created_at":"2026-03-30","updated_at":"2026-03-30","tags":["studio","editor","workspace","multi-frontend","lsp-deferred"],"agendas":[{"id":"AGD-0010","file":"AGD-0010-studio-code-editor-workspace-foundations.md","status":"open","created_at":"2026-03-30","updated_at":"2026-03-30"}],"decisions":[],"plans":[],"lessons":[]}
|
{"type":"discussion","id":"DSC-0010","status":"open","ticket":"studio-code-editor-workspace-foundations","title":"Establish Code Editor workspace foundations in Studio without LSP","created_at":"2026-03-30","updated_at":"2026-03-30","tags":["studio","editor","workspace","multi-frontend","lsp-deferred"],"agendas":[{"id":"AGD-0010","file":"AGD-0010-studio-code-editor-workspace-foundations.md","status":"open","created_at":"2026-03-30","updated_at":"2026-03-30"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0011","status":"open","ticket":"compiler-analyze-compile-build-pipeline-split","title":"Split compiler pipeline into analyze, compile, and build entrypoints","created_at":"2026-03-30","updated_at":"2026-03-30","tags":["compiler","pipeline","artifacts","build","analysis"],"agendas":[{"id":"AGD-0011","file":"AGD-0011-compiler-analyze-compile-build-pipeline-split.md","status":"accepted","created_at":"2026-03-30","updated_at":"2026-03-30"}],"decisions":[{"id":"DEC-0007","file":"DEC-0007-compiler-analyze-compile-build-pipeline-split.md","status":"in_progress","created_at":"2026-03-30","updated_at":"2026-03-30","ref_agenda":"AGD-0011"}],"plans":[{"id":"PLN-0009","file":"PLN-0009-compiler-pipeline-spec-and-contract-propagation.md","status":"done","created_at":"2026-03-30","updated_at":"2026-03-30","ref_decisions":["DEC-0007"]},{"id":"PLN-0010","file":"PLN-0010-refactor-builder-pipeline-service-into-entrypoints.md","status":"review","created_at":"2026-03-30","updated_at":"2026-03-30","ref_decisions":["DEC-0007"]},{"id":"PLN-0011","file":"PLN-0011-migrate-callsites-and-tests-to-build-compile-analyze.md","status":"review","created_at":"2026-03-30","updated_at":"2026-03-30","ref_decisions":["DEC-0007"]}],"lessons":[]}
|
{"type":"discussion","id":"DSC-0011","status":"open","ticket":"compiler-analyze-compile-build-pipeline-split","title":"Split compiler pipeline into analyze, compile, and build entrypoints","created_at":"2026-03-30","updated_at":"2026-03-30","tags":["compiler","pipeline","artifacts","build","analysis"],"agendas":[{"id":"AGD-0011","file":"AGD-0011-compiler-analyze-compile-build-pipeline-split.md","status":"accepted","created_at":"2026-03-30","updated_at":"2026-03-30"}],"decisions":[{"id":"DEC-0007","file":"DEC-0007-compiler-analyze-compile-build-pipeline-split.md","status":"in_progress","created_at":"2026-03-30","updated_at":"2026-03-30","ref_agenda":"AGD-0011"}],"plans":[{"id":"PLN-0009","file":"PLN-0009-compiler-pipeline-spec-and-contract-propagation.md","status":"done","created_at":"2026-03-30","updated_at":"2026-03-30","ref_decisions":["DEC-0007"]},{"id":"PLN-0010","file":"PLN-0010-refactor-builder-pipeline-service-into-entrypoints.md","status":"done","created_at":"2026-03-30","updated_at":"2026-03-30","ref_decisions":["DEC-0007"]},{"id":"PLN-0011","file":"PLN-0011-migrate-callsites-and-tests-to-build-compile-analyze.md","status":"review","created_at":"2026-03-30","updated_at":"2026-03-30","ref_decisions":["DEC-0007"]}],"lessons":[]}
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
id: PLN-0010
|
id: PLN-0010
|
||||||
ticket: compiler-analyze-compile-build-pipeline-split
|
ticket: compiler-analyze-compile-build-pipeline-split
|
||||||
title: Refactor BuilderPipelineService into explicit analyze, compile, and build entrypoints
|
title: Refactor BuilderPipelineService into explicit analyze, compile, and build entrypoints
|
||||||
status: review
|
status: done
|
||||||
created: 2026-03-30
|
created: 2026-03-30
|
||||||
completed:
|
completed: 2026-03-30
|
||||||
tags:
|
tags:
|
||||||
- compiler
|
- compiler
|
||||||
- pipeline
|
- pipeline
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package p.studio.compiler;
|
package p.studio.compiler;
|
||||||
|
|
||||||
import p.studio.compiler.messages.BuilderPipelineConfig;
|
import p.studio.compiler.messages.BuilderPipelineConfig;
|
||||||
|
import p.studio.compiler.models.BuilderPipelineContext;
|
||||||
import p.studio.compiler.workspaces.BuilderPipelineService;
|
import p.studio.compiler.workspaces.BuilderPipelineService;
|
||||||
import p.studio.utilities.PConstants;
|
import p.studio.utilities.PConstants;
|
||||||
import p.studio.utilities.logs.LogAggregator;
|
import p.studio.utilities.logs.LogAggregator;
|
||||||
@ -9,6 +10,7 @@ public class Compile {
|
|||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
final var logAggregator = LogAggregator.stdout();
|
final var logAggregator = LogAggregator.stdout();
|
||||||
final var config = new BuilderPipelineConfig(false, "test-projects/%s".formatted(PConstants.PROJECT));
|
final var config = new BuilderPipelineConfig(false, "test-projects/%s".formatted(PConstants.PROJECT));
|
||||||
BuilderPipelineService.INSTANCE.run(config, logAggregator);
|
final var context = BuilderPipelineContext.fromConfig(config);
|
||||||
|
BuilderPipelineService.INSTANCE.build(context, logAggregator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,28 @@
|
|||||||
package p.studio.compiler.messages;
|
package p.studio.compiler.messages;
|
||||||
|
|
||||||
|
import p.studio.compiler.utilities.SourceProviderFactory;
|
||||||
|
|
||||||
public record BuilderPipelineConfig(
|
public record BuilderPipelineConfig(
|
||||||
boolean explain,
|
boolean explain,
|
||||||
String rootProjectPath,
|
String rootProjectPath,
|
||||||
String vmProfile) {
|
String vmProfile,
|
||||||
|
SourceProviderFactory sourceProviderFactory) {
|
||||||
|
|
||||||
public BuilderPipelineConfig(
|
public BuilderPipelineConfig(
|
||||||
final boolean explain,
|
final boolean explain,
|
||||||
final String rootProjectPath) {
|
final String rootProjectPath) {
|
||||||
this(explain, rootProjectPath, "core-v1");
|
this(explain, rootProjectPath, "core-v1", SourceProviderFactory.filesystem());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BuilderPipelineConfig(
|
||||||
|
final boolean explain,
|
||||||
|
final String rootProjectPath,
|
||||||
|
final String vmProfile) {
|
||||||
|
this(explain, rootProjectPath, vmProfile, SourceProviderFactory.filesystem());
|
||||||
}
|
}
|
||||||
|
|
||||||
public BuilderPipelineConfig {
|
public BuilderPipelineConfig {
|
||||||
vmProfile = vmProfile == null || vmProfile.isBlank() ? "core-v1" : vmProfile;
|
vmProfile = vmProfile == null || vmProfile.isBlank() ? "core-v1" : vmProfile;
|
||||||
|
sourceProviderFactory = sourceProviderFactory == null ? SourceProviderFactory.filesystem() : sourceProviderFactory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
package p.studio.compiler.models;
|
||||||
|
|
||||||
|
import p.studio.compiler.messages.BuildingIssue;
|
||||||
|
import p.studio.compiler.source.tables.FileTable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record AnalysisSnapshot(
|
||||||
|
List<BuildingIssue> diagnostics,
|
||||||
|
ResolvedWorkspace resolvedWorkspace,
|
||||||
|
FileTable fileTable,
|
||||||
|
IRBackend irBackend) {
|
||||||
|
public AnalysisSnapshot {
|
||||||
|
diagnostics = List.copyOf(diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package p.studio.compiler.models;
|
||||||
|
|
||||||
|
import p.studio.compiler.messages.BuildingIssue;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record BuildResult(
|
||||||
|
CompileResult compileResult,
|
||||||
|
List<BuildingIssue> diagnostics,
|
||||||
|
Path bytecodeArtifactPath) {
|
||||||
|
public BuildResult {
|
||||||
|
diagnostics = List.copyOf(diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -30,7 +30,11 @@ public class BuilderPipelineContext {
|
|||||||
this.sourceProviderFactory = factory;
|
this.sourceProviderFactory = factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BuilderPipelineContext fromConfig(final BuilderPipelineConfig config) {
|
||||||
|
return new BuilderPipelineContext(config, config.sourceProviderFactory());
|
||||||
|
}
|
||||||
|
|
||||||
public static BuilderPipelineContext compilerContext(final BuilderPipelineConfig config) {
|
public static BuilderPipelineContext compilerContext(final BuilderPipelineConfig config) {
|
||||||
return new BuilderPipelineContext(config, SourceProviderFactory.filesystem());
|
return fromConfig(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,21 @@
|
|||||||
|
package p.studio.compiler.models;
|
||||||
|
|
||||||
|
import p.studio.compiler.backend.bytecode.BytecodeModule;
|
||||||
|
import p.studio.compiler.backend.irvm.IRVMProgram;
|
||||||
|
import p.studio.compiler.messages.BuildingIssue;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record CompileResult(
|
||||||
|
AnalysisSnapshot analysisSnapshot,
|
||||||
|
List<BuildingIssue> diagnostics,
|
||||||
|
IRVMProgram irvm,
|
||||||
|
IRVMProgram optimizedIrvm,
|
||||||
|
BytecodeModule bytecodeModule,
|
||||||
|
byte[] bytecodeBytes) {
|
||||||
|
public CompileResult {
|
||||||
|
diagnostics = List.copyOf(diagnostics);
|
||||||
|
bytecodeBytes = bytecodeBytes == null ? null : Arrays.copyOf(bytecodeBytes, bytecodeBytes.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,12 +2,16 @@ package p.studio.compiler.workspaces;
|
|||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import p.studio.compiler.exceptions.BuildException;
|
import p.studio.compiler.exceptions.BuildException;
|
||||||
import p.studio.compiler.messages.BuilderPipelineConfig;
|
import p.studio.compiler.messages.BuildingIssue;
|
||||||
import p.studio.compiler.models.BuilderPipelineContext;
|
import p.studio.compiler.models.BuilderPipelineContext;
|
||||||
|
import p.studio.compiler.models.AnalysisSnapshot;
|
||||||
|
import p.studio.compiler.models.BuildResult;
|
||||||
|
import p.studio.compiler.models.CompileResult;
|
||||||
import p.studio.compiler.workspaces.stages.*;
|
import p.studio.compiler.workspaces.stages.*;
|
||||||
import p.studio.utilities.logs.LogAggregator;
|
import p.studio.utilities.logs.LogAggregator;
|
||||||
import p.studio.utilities.structures.ReadOnlyCollection;
|
import p.studio.utilities.structures.ReadOnlyCollection;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -35,29 +39,90 @@ public class BuilderPipelineService {
|
|||||||
this.stages = stages;
|
this.stages = stages;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run(
|
public AnalysisSnapshot analyze(
|
||||||
final BuilderPipelineConfig config,
|
final BuilderPipelineContext ctx,
|
||||||
final LogAggregator logs) {
|
final LogAggregator logs) {
|
||||||
final var ctx = BuilderPipelineContext.compilerContext(config);
|
final var diagnostics = runToTerminal(ctx, logs, FrontendPhasePipelineStage.class);
|
||||||
|
return new AnalysisSnapshot(
|
||||||
|
diagnostics,
|
||||||
|
ctx.resolvedWorkspace,
|
||||||
|
ctx.fileTable,
|
||||||
|
ctx.irBackend);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompileResult compile(
|
||||||
|
final BuilderPipelineContext ctx,
|
||||||
|
final LogAggregator logs) {
|
||||||
|
final var diagnostics = runToTerminal(ctx, logs, VerifyBytecodePipelineStage.class);
|
||||||
|
final var analysisSnapshot = new AnalysisSnapshot(
|
||||||
|
diagnostics,
|
||||||
|
ctx.resolvedWorkspace,
|
||||||
|
ctx.fileTable,
|
||||||
|
ctx.irBackend);
|
||||||
|
return new CompileResult(
|
||||||
|
analysisSnapshot,
|
||||||
|
diagnostics,
|
||||||
|
ctx.irvm,
|
||||||
|
ctx.optimizedIrvm,
|
||||||
|
ctx.bytecodeModule,
|
||||||
|
ctx.bytecodeBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BuildResult build(
|
||||||
|
final BuilderPipelineContext ctx,
|
||||||
|
final LogAggregator logs) {
|
||||||
|
final var diagnostics = runToTerminal(ctx, logs, WriteBytecodeArtifactPipelineStage.class);
|
||||||
|
final var analysisSnapshot = new AnalysisSnapshot(
|
||||||
|
diagnostics,
|
||||||
|
ctx.resolvedWorkspace,
|
||||||
|
ctx.fileTable,
|
||||||
|
ctx.irBackend);
|
||||||
|
final var compileResult = new CompileResult(
|
||||||
|
analysisSnapshot,
|
||||||
|
diagnostics,
|
||||||
|
ctx.irvm,
|
||||||
|
ctx.optimizedIrvm,
|
||||||
|
ctx.bytecodeModule,
|
||||||
|
ctx.bytecodeBytes);
|
||||||
|
return new BuildResult(
|
||||||
|
compileResult,
|
||||||
|
diagnostics,
|
||||||
|
ctx.bytecodeArtifactPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<BuildingIssue> runToTerminal(
|
||||||
|
final BuilderPipelineContext ctx,
|
||||||
|
final LogAggregator logs,
|
||||||
|
final Class<? extends PipelineStage> terminalStage) {
|
||||||
|
final var diagnostics = new ArrayList<BuildingIssue>();
|
||||||
|
var completed = false;
|
||||||
for (final var builderPipelineStage : stages) {
|
for (final var builderPipelineStage : stages) {
|
||||||
final var issues = builderPipelineStage.run(ctx, logs);
|
final var issues = builderPipelineStage.run(ctx, logs);
|
||||||
var error = false;
|
diagnostics.addAll(issues.asCollection());
|
||||||
if (ReadOnlyCollection.isNotEmpty(issues)) {
|
printIssues(issues, logs);
|
||||||
for (final var issue : issues) {
|
if (issues.hasErrors()) {
|
||||||
if (issue.isError()) {
|
|
||||||
error = true;
|
|
||||||
logs.using(log).error(issue.getMessage(), issue.getException());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
logs.using(log).warn(issue.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (error) {
|
|
||||||
throw new BuildException("issues found on pipeline stage: " + builderPipelineStage.getClass().getSimpleName());
|
throw new BuildException("issues found on pipeline stage: " + builderPipelineStage.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
|
if (terminalStage.isInstance(builderPipelineStage)) {
|
||||||
|
completed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!completed) {
|
||||||
|
throw new BuildException("terminal stage not found on builder pipeline: " + terminalStage.getSimpleName());
|
||||||
|
}
|
||||||
|
logs.using(log).info("builder pipeline completed successfully through " + terminalStage.getSimpleName());
|
||||||
|
return List.copyOf(diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
logs.using(log).info("builder pipeline completed successfully");
|
private void printIssues(
|
||||||
|
final ReadOnlyCollection<BuildingIssue> issues,
|
||||||
|
final LogAggregator logs) {
|
||||||
|
if (ReadOnlyCollection.isEmpty(issues)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (final var issue : issues) {
|
||||||
|
issue.print(logs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package p.studio.compiler.integration;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import p.studio.compiler.messages.BuilderPipelineConfig;
|
import p.studio.compiler.messages.BuilderPipelineConfig;
|
||||||
|
import p.studio.compiler.models.BuilderPipelineContext;
|
||||||
import p.studio.compiler.workspaces.BuilderPipelineService;
|
import p.studio.compiler.workspaces.BuilderPipelineService;
|
||||||
import p.studio.utilities.logs.LogAggregator;
|
import p.studio.utilities.logs.LogAggregator;
|
||||||
|
|
||||||
@ -14,26 +15,76 @@ import static org.junit.jupiter.api.Assertions.*;
|
|||||||
class MainProjectPipelineIntegrationTest {
|
class MainProjectPipelineIntegrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldCompileMainProjectAndWriteProgramBytecode() throws IOException {
|
void analyzeShouldNotWriteProgramBytecode() throws IOException {
|
||||||
|
final var projectRoot = projectRoot();
|
||||||
|
final var outputPath = resetOutput(projectRoot);
|
||||||
|
final var logs = bufferedLogs();
|
||||||
|
final var context = BuilderPipelineContext.fromConfig(new BuilderPipelineConfig(false, projectRoot.toString()));
|
||||||
|
|
||||||
|
final var snapshot = assertDoesNotThrow(
|
||||||
|
() -> BuilderPipelineService.INSTANCE.analyze(context, logs),
|
||||||
|
() -> "analyze unexpectedly failed for " + projectRoot);
|
||||||
|
|
||||||
|
assertNotNull(snapshot.resolvedWorkspace(), "analyze must expose resolved workspace");
|
||||||
|
assertNotNull(snapshot.fileTable(), "analyze must expose file table");
|
||||||
|
assertNotNull(snapshot.irBackend(), "analyze must expose frontend semantic result");
|
||||||
|
assertFalse(Files.exists(outputPath), "analyze must not write output: " + outputPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void compileShouldProduceInMemoryBytecodeWithoutWritingProgramBytecode() throws IOException {
|
||||||
|
final var projectRoot = projectRoot();
|
||||||
|
final var outputPath = resetOutput(projectRoot);
|
||||||
|
final var logs = bufferedLogs();
|
||||||
|
final var context = BuilderPipelineContext.fromConfig(new BuilderPipelineConfig(false, projectRoot.toString()));
|
||||||
|
|
||||||
|
final var result = assertDoesNotThrow(
|
||||||
|
() -> BuilderPipelineService.INSTANCE.compile(context, logs),
|
||||||
|
() -> "compile unexpectedly failed for " + projectRoot);
|
||||||
|
|
||||||
|
assertNotNull(result.analysisSnapshot(), "compile must retain analysis snapshot");
|
||||||
|
assertNotNull(result.bytecodeModule(), "compile must expose bytecode module");
|
||||||
|
assertNotNull(result.bytecodeBytes(), "compile must expose bytecode bytes");
|
||||||
|
assertTrue(result.bytecodeBytes().length > 0, "compile must expose non-empty bytecode bytes");
|
||||||
|
assertFalse(Files.exists(outputPath), "compile must not write output: " + outputPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void buildShouldWriteProgramBytecode() throws IOException {
|
||||||
final var repoRoot = findRepoRoot(Path.of("").toAbsolutePath().normalize());
|
final var repoRoot = findRepoRoot(Path.of("").toAbsolutePath().normalize());
|
||||||
final var projectRoot = repoRoot.resolve("test-projects").resolve("main");
|
final var projectRoot = repoRoot.resolve("test-projects").resolve("main");
|
||||||
|
final var outputPath = resetOutput(projectRoot);
|
||||||
|
final var logs = bufferedLogs();
|
||||||
|
final var context = BuilderPipelineContext.fromConfig(new BuilderPipelineConfig(false, projectRoot.toString()));
|
||||||
|
|
||||||
|
final var result = assertDoesNotThrow(
|
||||||
|
() -> BuilderPipelineService.INSTANCE.build(context, logs),
|
||||||
|
() -> "build unexpectedly failed for " + projectRoot);
|
||||||
|
assertEquals(outputPath, result.bytecodeArtifactPath(), "build must expose written artifact path");
|
||||||
|
assertTrue(Files.exists(outputPath), "build did not write output: " + outputPath);
|
||||||
|
assertTrue(Files.size(outputPath) > 0, "build wrote empty bytecode file: " + outputPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path projectRoot() {
|
||||||
|
final var repoRoot = findRepoRoot(Path.of("").toAbsolutePath().normalize());
|
||||||
|
return repoRoot.resolve("test-projects").resolve("main");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path resetOutput(final Path projectRoot) throws IOException {
|
||||||
final var outputPath = projectRoot.resolve("build").resolve("program.pbx");
|
final var outputPath = projectRoot.resolve("build").resolve("program.pbx");
|
||||||
Files.createDirectories(outputPath.getParent());
|
Files.createDirectories(outputPath.getParent());
|
||||||
Files.deleteIfExists(outputPath);
|
Files.deleteIfExists(outputPath);
|
||||||
|
return outputPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LogAggregator bufferedLogs() {
|
||||||
final var logsOut = new StringBuilder();
|
final var logsOut = new StringBuilder();
|
||||||
final var logs = LogAggregator.with(line -> {
|
return LogAggregator.with(line -> {
|
||||||
logsOut.append(line);
|
logsOut.append(line);
|
||||||
if (!line.endsWith("\n")) {
|
if (!line.endsWith("\n")) {
|
||||||
logsOut.append('\n');
|
logsOut.append('\n');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
assertDoesNotThrow(
|
|
||||||
() -> BuilderPipelineService.INSTANCE.run(new BuilderPipelineConfig(false, projectRoot.toString()), logs),
|
|
||||||
logsOut::toString);
|
|
||||||
assertTrue(Files.exists(outputPath), "pipeline did not write output: " + outputPath + "\n" + logsOut);
|
|
||||||
assertTrue(Files.size(outputPath) > 0, "pipeline wrote empty bytecode file: " + outputPath + "\n" + logsOut);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path findRepoRoot(final Path start) {
|
private Path findRepoRoot(final Path start) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user