implements packer PR-09 event lane and studio adapter
This commit is contained in:
parent
682a0e72b5
commit
1c418a454b
@ -6,6 +6,10 @@ import p.packer.api.building.PackerBuildRequest;
|
|||||||
import p.packer.api.building.PackerBuildResult;
|
import p.packer.api.building.PackerBuildResult;
|
||||||
import p.packer.api.building.PackerBuildService;
|
import p.packer.api.building.PackerBuildService;
|
||||||
import p.packer.api.diagnostics.PackerDiagnostic;
|
import p.packer.api.diagnostics.PackerDiagnostic;
|
||||||
|
import p.packer.api.events.PackerEventKind;
|
||||||
|
import p.packer.api.events.PackerEventSink;
|
||||||
|
import p.packer.api.events.PackerProgress;
|
||||||
|
import p.packer.events.PackerOperationEventEmitter;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -27,13 +31,19 @@ public final class FileSystemPackerBuildService implements PackerBuildService {
|
|||||||
private static final int PRELUDE_SIZE = 24;
|
private static final int PRELUDE_SIZE = 24;
|
||||||
|
|
||||||
private final PackerBuildPlanner buildPlanner;
|
private final PackerBuildPlanner buildPlanner;
|
||||||
|
private final PackerEventSink eventSink;
|
||||||
|
|
||||||
public FileSystemPackerBuildService() {
|
public FileSystemPackerBuildService() {
|
||||||
this(new PackerBuildPlanner());
|
this(new PackerBuildPlanner(), PackerEventSink.noop());
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileSystemPackerBuildService(PackerBuildPlanner buildPlanner) {
|
public FileSystemPackerBuildService(PackerBuildPlanner buildPlanner) {
|
||||||
|
this(buildPlanner, PackerEventSink.noop());
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileSystemPackerBuildService(PackerBuildPlanner buildPlanner, PackerEventSink eventSink) {
|
||||||
this.buildPlanner = Objects.requireNonNull(buildPlanner, "buildPlanner");
|
this.buildPlanner = Objects.requireNonNull(buildPlanner, "buildPlanner");
|
||||||
|
this.eventSink = Objects.requireNonNull(eventSink, "eventSink");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -43,14 +53,17 @@ public final class FileSystemPackerBuildService implements PackerBuildService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PackerBuildResult build(PackerBuildRequest request) {
|
public PackerBuildResult build(PackerBuildRequest request) {
|
||||||
final Path buildDirectory = Objects.requireNonNull(request, "request").project().rootPath().resolve("build");
|
final PackerBuildRequest buildRequest = Objects.requireNonNull(request, "request");
|
||||||
|
final PackerOperationEventEmitter events = new PackerOperationEventEmitter(buildRequest.project(), eventSink);
|
||||||
|
final Path buildDirectory = buildRequest.project().rootPath().resolve("build");
|
||||||
final Path assetsArchive = buildDirectory.resolve("assets.pa").toAbsolutePath().normalize();
|
final Path assetsArchive = buildDirectory.resolve("assets.pa").toAbsolutePath().normalize();
|
||||||
final Path assetTableJson = buildDirectory.resolve("asset_table.json").toAbsolutePath().normalize();
|
final Path assetTableJson = buildDirectory.resolve("asset_table.json").toAbsolutePath().normalize();
|
||||||
final Path preloadJson = buildDirectory.resolve("preload.json").toAbsolutePath().normalize();
|
final Path preloadJson = buildDirectory.resolve("preload.json").toAbsolutePath().normalize();
|
||||||
final Path metadataJson = buildDirectory.resolve("asset_table_metadata.json").toAbsolutePath().normalize();
|
final Path metadataJson = buildDirectory.resolve("asset_table_metadata.json").toAbsolutePath().normalize();
|
||||||
|
events.emit(PackerEventKind.BUILD_STARTED, "Build started.", new PackerProgress(0.0d, false), List.of());
|
||||||
final PackerBuildPlanResult planResult = buildPlanner.plan(request.project());
|
final PackerBuildPlanResult planResult = buildPlanner.plan(buildRequest.project());
|
||||||
if (planResult.plan() == null) {
|
if (planResult.plan() == null) {
|
||||||
|
events.emit(PackerEventKind.BUILD_FINISHED, planResult.summary(), new PackerProgress(1.0d, false), List.of());
|
||||||
return new PackerBuildResult(
|
return new PackerBuildResult(
|
||||||
PackerOperationStatus.FAILED,
|
PackerOperationStatus.FAILED,
|
||||||
planResult.summary(),
|
planResult.summary(),
|
||||||
@ -61,11 +74,18 @@ public final class FileSystemPackerBuildService implements PackerBuildService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(buildDirectory);
|
Files.createDirectories(buildDirectory);
|
||||||
|
final String previousCacheKey = loadPreviousCacheKey(metadataJson);
|
||||||
|
events.emit(
|
||||||
|
previousCacheKey != null && previousCacheKey.equals(planResult.plan().cacheKey()) ? PackerEventKind.CACHE_HIT : PackerEventKind.CACHE_MISS,
|
||||||
|
previousCacheKey != null && previousCacheKey.equals(planResult.plan().cacheKey()) ? "Build cache hit." : "Build cache miss.",
|
||||||
|
List.of());
|
||||||
final EmittedArchive archive = emitArchive(planResult.plan());
|
final EmittedArchive archive = emitArchive(planResult.plan());
|
||||||
|
events.emit(PackerEventKind.PROGRESS_UPDATED, "Build archive prepared.", new PackerProgress(0.5d, false), List.of());
|
||||||
Files.write(assetsArchive, archive.bytes());
|
Files.write(assetsArchive, archive.bytes());
|
||||||
Files.writeString(assetTableJson, archive.assetTableJson(), StandardCharsets.UTF_8);
|
Files.writeString(assetTableJson, archive.assetTableJson(), StandardCharsets.UTF_8);
|
||||||
Files.writeString(preloadJson, archive.preloadJson(), StandardCharsets.UTF_8);
|
Files.writeString(preloadJson, archive.preloadJson(), StandardCharsets.UTF_8);
|
||||||
Files.writeString(metadataJson, archive.metadataJson(), StandardCharsets.UTF_8);
|
Files.writeString(metadataJson, archive.metadataJson(), StandardCharsets.UTF_8);
|
||||||
|
events.emit(PackerEventKind.BUILD_FINISHED, "Build finished.", new PackerProgress(1.0d, false), List.of());
|
||||||
return new PackerBuildResult(
|
return new PackerBuildResult(
|
||||||
planResult.status(),
|
planResult.status(),
|
||||||
"Build emitted " + planResult.plan().assets().size() + " assets.",
|
"Build emitted " + planResult.plan().assets().size() + " assets.",
|
||||||
@ -149,6 +169,20 @@ public final class FileSystemPackerBuildService implements PackerBuildService {
|
|||||||
return new EmittedArchive(archiveBytes, assetTableJson, preloadJson, metadataJson);
|
return new EmittedArchive(archiveBytes, assetTableJson, preloadJson, metadataJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private String loadPreviousCacheKey(Path metadataJson) {
|
||||||
|
if (!Files.isRegularFile(metadataJson)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return ((Map<String, Object>) new com.fasterxml.jackson.databind.ObjectMapper().readValue(Files.readString(metadataJson), Map.class))
|
||||||
|
.getOrDefault("cache_key", "")
|
||||||
|
.toString();
|
||||||
|
} catch (IOException exception) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private record EmittedArchive(
|
private record EmittedArchive(
|
||||||
byte[] bytes,
|
byte[] bytes,
|
||||||
String assetTableJson,
|
String assetTableJson,
|
||||||
|
|||||||
@ -11,9 +11,13 @@ import p.packer.api.doctor.PackerDoctorMode;
|
|||||||
import p.packer.api.doctor.PackerDoctorRequest;
|
import p.packer.api.doctor.PackerDoctorRequest;
|
||||||
import p.packer.api.doctor.PackerDoctorResult;
|
import p.packer.api.doctor.PackerDoctorResult;
|
||||||
import p.packer.api.doctor.PackerDoctorService;
|
import p.packer.api.doctor.PackerDoctorService;
|
||||||
|
import p.packer.api.events.PackerEventKind;
|
||||||
|
import p.packer.api.events.PackerEventSink;
|
||||||
|
import p.packer.api.events.PackerProgress;
|
||||||
import p.packer.api.workspace.GetAssetDetailsRequest;
|
import p.packer.api.workspace.GetAssetDetailsRequest;
|
||||||
import p.packer.api.workspace.ListAssetsRequest;
|
import p.packer.api.workspace.ListAssetsRequest;
|
||||||
import p.packer.declarations.PackerAssetDetailsService;
|
import p.packer.declarations.PackerAssetDetailsService;
|
||||||
|
import p.packer.events.PackerOperationEventEmitter;
|
||||||
import p.packer.workspace.FileSystemPackerWorkspaceService;
|
import p.packer.workspace.FileSystemPackerWorkspaceService;
|
||||||
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@ -27,16 +31,25 @@ import java.util.Set;
|
|||||||
public final class FileSystemPackerDoctorService implements PackerDoctorService {
|
public final class FileSystemPackerDoctorService implements PackerDoctorService {
|
||||||
private final FileSystemPackerWorkspaceService workspaceService;
|
private final FileSystemPackerWorkspaceService workspaceService;
|
||||||
private final PackerAssetDetailsService detailsService;
|
private final PackerAssetDetailsService detailsService;
|
||||||
|
private final PackerEventSink eventSink;
|
||||||
|
|
||||||
public FileSystemPackerDoctorService() {
|
public FileSystemPackerDoctorService() {
|
||||||
this(new FileSystemPackerWorkspaceService(), new PackerAssetDetailsService());
|
this(new FileSystemPackerWorkspaceService(), new PackerAssetDetailsService(), PackerEventSink.noop());
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileSystemPackerDoctorService(
|
public FileSystemPackerDoctorService(
|
||||||
FileSystemPackerWorkspaceService workspaceService,
|
FileSystemPackerWorkspaceService workspaceService,
|
||||||
PackerAssetDetailsService detailsService) {
|
PackerAssetDetailsService detailsService) {
|
||||||
|
this(workspaceService, detailsService, PackerEventSink.noop());
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileSystemPackerDoctorService(
|
||||||
|
FileSystemPackerWorkspaceService workspaceService,
|
||||||
|
PackerAssetDetailsService detailsService,
|
||||||
|
PackerEventSink eventSink) {
|
||||||
this.workspaceService = Objects.requireNonNull(workspaceService, "workspaceService");
|
this.workspaceService = Objects.requireNonNull(workspaceService, "workspaceService");
|
||||||
this.detailsService = Objects.requireNonNull(detailsService, "detailsService");
|
this.detailsService = Objects.requireNonNull(detailsService, "detailsService");
|
||||||
|
this.eventSink = Objects.requireNonNull(eventSink, "eventSink");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -48,6 +61,7 @@ public final class FileSystemPackerDoctorService implements PackerDoctorService
|
|||||||
public PackerDoctorResult doctor(PackerDoctorRequest request) {
|
public PackerDoctorResult doctor(PackerDoctorRequest request) {
|
||||||
final PackerDoctorRequest doctorRequest = Objects.requireNonNull(request, "request");
|
final PackerDoctorRequest doctorRequest = Objects.requireNonNull(request, "request");
|
||||||
final PackerProjectContext project = doctorRequest.project();
|
final PackerProjectContext project = doctorRequest.project();
|
||||||
|
final PackerOperationEventEmitter events = new PackerOperationEventEmitter(project, eventSink);
|
||||||
final var snapshot = workspaceService.listAssets(new ListAssetsRequest(project));
|
final var snapshot = workspaceService.listAssets(new ListAssetsRequest(project));
|
||||||
final List<PackerDiagnostic> diagnostics = new ArrayList<>();
|
final List<PackerDiagnostic> diagnostics = new ArrayList<>();
|
||||||
final Set<String> safeFixes = new LinkedHashSet<>();
|
final Set<String> safeFixes = new LinkedHashSet<>();
|
||||||
@ -57,10 +71,13 @@ public final class FileSystemPackerDoctorService implements PackerDoctorService
|
|||||||
addDiagnostic(diagnostics, seenDiagnostics, diagnostic);
|
addDiagnostic(diagnostics, seenDiagnostics, diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int totalAssets = snapshot.assets().size();
|
||||||
|
int inspected = 0;
|
||||||
for (var asset : snapshot.assets()) {
|
for (var asset : snapshot.assets()) {
|
||||||
if (!includeAsset(doctorRequest.mode(), asset.state())) {
|
if (!includeAsset(doctorRequest.mode(), asset.state())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
inspected += 1;
|
||||||
final String assetReference = asset.identity().assetId() == null
|
final String assetReference = asset.identity().assetId() == null
|
||||||
? relativeAssetRoot(project, asset.identity().assetRoot())
|
? relativeAssetRoot(project, asset.identity().assetRoot())
|
||||||
: Integer.toString(asset.identity().assetId());
|
: Integer.toString(asset.identity().assetId());
|
||||||
@ -102,6 +119,11 @@ public final class FileSystemPackerDoctorService implements PackerDoctorService
|
|||||||
input,
|
input,
|
||||||
managed));
|
managed));
|
||||||
}));
|
}));
|
||||||
|
events.emit(
|
||||||
|
PackerEventKind.PROGRESS_UPDATED,
|
||||||
|
"Doctor inspected asset: " + asset.identity().assetName(),
|
||||||
|
new PackerProgress(totalAssets == 0 ? 1.0d : inspected / (double) totalAssets, false),
|
||||||
|
List.of(asset.identity().assetName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
final long blockingCount = diagnostics.stream().filter(PackerDiagnostic::blocking).count();
|
final long blockingCount = diagnostics.stream().filter(PackerDiagnostic::blocking).count();
|
||||||
@ -113,6 +135,7 @@ public final class FileSystemPackerDoctorService implements PackerDoctorService
|
|||||||
: diagnostics.isEmpty()
|
: diagnostics.isEmpty()
|
||||||
? "Doctor found no diagnostics."
|
? "Doctor found no diagnostics."
|
||||||
: "Doctor found " + diagnostics.size() + " diagnostics with no blockers.";
|
: "Doctor found " + diagnostics.size() + " diagnostics with no blockers.";
|
||||||
|
events.emit(PackerEventKind.DIAGNOSTICS_UPDATED, summary, List.of());
|
||||||
return new PackerDoctorResult(status, summary, diagnostics, List.copyOf(safeFixes));
|
return new PackerDoctorResult(status, summary, diagnostics, List.copyOf(safeFixes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,49 @@
|
|||||||
|
package p.packer.events;
|
||||||
|
|
||||||
|
import p.packer.api.PackerProjectContext;
|
||||||
|
import p.packer.api.events.PackerEvent;
|
||||||
|
import p.packer.api.events.PackerEventKind;
|
||||||
|
import p.packer.api.events.PackerEventSink;
|
||||||
|
import p.packer.api.events.PackerProgress;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public final class PackerOperationEventEmitter {
|
||||||
|
private final PackerProjectContext project;
|
||||||
|
private final PackerEventSink sink;
|
||||||
|
private final String operationId;
|
||||||
|
private long sequence;
|
||||||
|
|
||||||
|
public PackerOperationEventEmitter(PackerProjectContext project, PackerEventSink sink) {
|
||||||
|
this(project, sink, UUID.randomUUID().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackerOperationEventEmitter(PackerProjectContext project, PackerEventSink sink, String operationId) {
|
||||||
|
this.project = Objects.requireNonNull(project, "project");
|
||||||
|
this.sink = Objects.requireNonNull(sink, "sink");
|
||||||
|
this.operationId = Objects.requireNonNull(operationId, "operationId").trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String operationId() {
|
||||||
|
return operationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void emit(PackerEventKind kind, String summary, List<String> affectedAssets) {
|
||||||
|
emit(kind, summary, null, affectedAssets);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void emit(PackerEventKind kind, String summary, PackerProgress progress, List<String> affectedAssets) {
|
||||||
|
sink.publish(new PackerEvent(
|
||||||
|
project.projectId(),
|
||||||
|
operationId,
|
||||||
|
sequence++,
|
||||||
|
Objects.requireNonNull(kind, "kind"),
|
||||||
|
Instant.now(),
|
||||||
|
Objects.requireNonNull(summary, "summary"),
|
||||||
|
progress,
|
||||||
|
affectedAssets == null ? List.of() : List.copyOf(affectedAssets)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -81,10 +81,11 @@ public final class FileSystemPackerMutationService implements PackerMutationServ
|
|||||||
throw new PackerMutationException("Cannot apply mutation preview with blockers");
|
throw new PackerMutationException("Cannot apply mutation preview with blockers");
|
||||||
}
|
}
|
||||||
final PackerMutationResult result = writeCoordinator.withWriteLock(project, () -> applyLocked(preview));
|
final PackerMutationResult result = writeCoordinator.withWriteLock(project, () -> applyLocked(preview));
|
||||||
emit(project, result.operationId(), 1L, PackerEventKind.ACTION_APPLIED, result.summary(), affectedAssets(preview));
|
emit(project, result.operationId(), 1L, PackerEventKind.ASSET_CHANGED, "Asset state changed.", affectedAssets(preview));
|
||||||
|
emit(project, result.operationId(), 2L, PackerEventKind.ACTION_APPLIED, result.summary(), affectedAssets(preview));
|
||||||
return result;
|
return result;
|
||||||
} catch (RuntimeException exception) {
|
} catch (RuntimeException exception) {
|
||||||
emit(project, preview.operationId(), 1L, PackerEventKind.ACTION_FAILED, rootCauseMessage(exception), affectedAssets(preview));
|
emit(project, preview.operationId(), 2L, PackerEventKind.ACTION_FAILED, rootCauseMessage(exception), affectedAssets(preview));
|
||||||
throw exception;
|
throw exception;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,9 @@ import p.packer.api.assets.PackerAssetSummary;
|
|||||||
import p.packer.api.diagnostics.PackerDiagnostic;
|
import p.packer.api.diagnostics.PackerDiagnostic;
|
||||||
import p.packer.api.diagnostics.PackerDiagnosticCategory;
|
import p.packer.api.diagnostics.PackerDiagnosticCategory;
|
||||||
import p.packer.api.diagnostics.PackerDiagnosticSeverity;
|
import p.packer.api.diagnostics.PackerDiagnosticSeverity;
|
||||||
|
import p.packer.api.events.PackerEventKind;
|
||||||
|
import p.packer.api.events.PackerEventSink;
|
||||||
|
import p.packer.api.events.PackerProgress;
|
||||||
import p.packer.api.workspace.GetAssetDetailsRequest;
|
import p.packer.api.workspace.GetAssetDetailsRequest;
|
||||||
import p.packer.api.workspace.GetAssetDetailsResult;
|
import p.packer.api.workspace.GetAssetDetailsResult;
|
||||||
import p.packer.api.workspace.InitWorkspaceRequest;
|
import p.packer.api.workspace.InitWorkspaceRequest;
|
||||||
@ -23,6 +26,7 @@ import p.packer.foundation.PackerRegistryEntry;
|
|||||||
import p.packer.foundation.PackerRegistryState;
|
import p.packer.foundation.PackerRegistryState;
|
||||||
import p.packer.foundation.PackerWorkspaceFoundation;
|
import p.packer.foundation.PackerWorkspaceFoundation;
|
||||||
import p.packer.foundation.PackerWorkspacePaths;
|
import p.packer.foundation.PackerWorkspacePaths;
|
||||||
|
import p.packer.events.PackerOperationEventEmitter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@ -34,17 +38,26 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
private final PackerWorkspaceFoundation workspaceFoundation;
|
private final PackerWorkspaceFoundation workspaceFoundation;
|
||||||
private final PackerAssetDeclarationParser parser;
|
private final PackerAssetDeclarationParser parser;
|
||||||
private final PackerAssetDetailsService detailsService;
|
private final PackerAssetDetailsService detailsService;
|
||||||
|
private final PackerEventSink eventSink;
|
||||||
|
|
||||||
public FileSystemPackerWorkspaceService() {
|
public FileSystemPackerWorkspaceService() {
|
||||||
this(new PackerWorkspaceFoundation(), new PackerAssetDeclarationParser());
|
this(new PackerWorkspaceFoundation(), new PackerAssetDeclarationParser(), PackerEventSink.noop());
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileSystemPackerWorkspaceService(
|
public FileSystemPackerWorkspaceService(
|
||||||
PackerWorkspaceFoundation workspaceFoundation,
|
PackerWorkspaceFoundation workspaceFoundation,
|
||||||
PackerAssetDeclarationParser parser) {
|
PackerAssetDeclarationParser parser) {
|
||||||
|
this(workspaceFoundation, parser, PackerEventSink.noop());
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileSystemPackerWorkspaceService(
|
||||||
|
PackerWorkspaceFoundation workspaceFoundation,
|
||||||
|
PackerAssetDeclarationParser parser,
|
||||||
|
PackerEventSink eventSink) {
|
||||||
this.workspaceFoundation = Objects.requireNonNull(workspaceFoundation, "workspaceFoundation");
|
this.workspaceFoundation = Objects.requireNonNull(workspaceFoundation, "workspaceFoundation");
|
||||||
this.parser = Objects.requireNonNull(parser, "parser");
|
this.parser = Objects.requireNonNull(parser, "parser");
|
||||||
this.detailsService = new PackerAssetDetailsService(workspaceFoundation, parser);
|
this.detailsService = new PackerAssetDetailsService(workspaceFoundation, parser);
|
||||||
|
this.eventSink = Objects.requireNonNull(eventSink, "eventSink");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -60,6 +73,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
@Override
|
@Override
|
||||||
public ListAssetsResult listAssets(ListAssetsRequest request) {
|
public ListAssetsResult listAssets(ListAssetsRequest request) {
|
||||||
final PackerProjectContext project = Objects.requireNonNull(request, "request").project();
|
final PackerProjectContext project = Objects.requireNonNull(request, "request").project();
|
||||||
|
final PackerOperationEventEmitter events = new PackerOperationEventEmitter(project, eventSink);
|
||||||
final Path assetsRoot = PackerWorkspacePaths.assetsRoot(project);
|
final Path assetsRoot = PackerWorkspacePaths.assetsRoot(project);
|
||||||
final PackerRegistryState registry = workspaceFoundation.loadRegistry(project);
|
final PackerRegistryState registry = workspaceFoundation.loadRegistry(project);
|
||||||
final Map<Path, PackerRegistryEntry> registryByRoot = new HashMap<>();
|
final Map<Path, PackerRegistryEntry> registryByRoot = new HashMap<>();
|
||||||
@ -74,14 +88,23 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
if (Files.isDirectory(assetsRoot)) {
|
if (Files.isDirectory(assetsRoot)) {
|
||||||
try (Stream<Path> paths = Files.find(assetsRoot, Integer.MAX_VALUE, (path, attrs) ->
|
try (Stream<Path> paths = Files.find(assetsRoot, Integer.MAX_VALUE, (path, attrs) ->
|
||||||
attrs.isRegularFile() && path.getFileName().toString().equals("asset.json"))) {
|
attrs.isRegularFile() && path.getFileName().toString().equals("asset.json"))) {
|
||||||
paths.forEach(assetManifestPath -> {
|
final List<Path> manifests = paths.toList();
|
||||||
|
final int total = manifests.size();
|
||||||
|
for (int index = 0; index < manifests.size(); index += 1) {
|
||||||
|
final Path assetManifestPath = manifests.get(index);
|
||||||
final Path assetRoot = assetManifestPath.getParent().toAbsolutePath().normalize();
|
final Path assetRoot = assetManifestPath.getParent().toAbsolutePath().normalize();
|
||||||
discoveredRoots.add(assetRoot);
|
discoveredRoots.add(assetRoot);
|
||||||
final PackerRegistryEntry registryEntry = registryByRoot.get(assetRoot);
|
final PackerRegistryEntry registryEntry = registryByRoot.get(assetRoot);
|
||||||
final PackerAssetDeclarationParseResult parsed = parser.parse(assetManifestPath);
|
final PackerAssetDeclarationParseResult parsed = parser.parse(assetManifestPath);
|
||||||
diagnostics.addAll(parsed.diagnostics());
|
diagnostics.addAll(parsed.diagnostics());
|
||||||
assets.add(buildSummary(assetRoot, registryEntry, parsed));
|
final PackerAssetSummary summary = buildSummary(assetRoot, registryEntry, parsed);
|
||||||
});
|
assets.add(summary);
|
||||||
|
events.emit(
|
||||||
|
PackerEventKind.ASSET_DISCOVERED,
|
||||||
|
"Discovered asset: " + summary.identity().assetName(),
|
||||||
|
new PackerProgress(total == 0 ? 1.0d : (index + 1) / (double) total, false),
|
||||||
|
List.of(summary.identity().assetName()));
|
||||||
|
}
|
||||||
} catch (IOException exception) {
|
} catch (IOException exception) {
|
||||||
diagnostics.add(new PackerDiagnostic(
|
diagnostics.add(new PackerDiagnostic(
|
||||||
PackerDiagnosticSeverity.ERROR,
|
PackerDiagnosticSeverity.ERROR,
|
||||||
@ -110,6 +133,9 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
final PackerOperationStatus status = diagnostics.stream().anyMatch(PackerDiagnostic::blocking)
|
final PackerOperationStatus status = diagnostics.stream().anyMatch(PackerDiagnostic::blocking)
|
||||||
? PackerOperationStatus.PARTIAL
|
? PackerOperationStatus.PARTIAL
|
||||||
: PackerOperationStatus.SUCCESS;
|
: PackerOperationStatus.SUCCESS;
|
||||||
|
if (!diagnostics.isEmpty()) {
|
||||||
|
events.emit(PackerEventKind.DIAGNOSTICS_UPDATED, "Asset scan diagnostics updated.", List.of());
|
||||||
|
}
|
||||||
return new ListAssetsResult(
|
return new ListAssetsResult(
|
||||||
status,
|
status,
|
||||||
"Packer asset snapshot ready.",
|
"Packer asset snapshot ready.",
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import org.junit.jupiter.api.io.TempDir;
|
|||||||
import p.packer.api.PackerOperationStatus;
|
import p.packer.api.PackerOperationStatus;
|
||||||
import p.packer.api.PackerProjectContext;
|
import p.packer.api.PackerProjectContext;
|
||||||
import p.packer.api.building.PackerBuildRequest;
|
import p.packer.api.building.PackerBuildRequest;
|
||||||
|
import p.packer.api.events.PackerEvent;
|
||||||
|
import p.packer.api.events.PackerEventKind;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
@ -14,6 +16,7 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
@ -72,6 +75,21 @@ final class FileSystemPackerBuildServiceTest {
|
|||||||
assertTrue(result.companionArtifacts().isEmpty());
|
assertTrue(result.companionArtifacts().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void emitsBuildLifecycleAndCacheEvents() throws Exception {
|
||||||
|
final Path projectRoot = createProject(tempDir.resolve("events"));
|
||||||
|
final List<PackerEvent> events = new CopyOnWriteArrayList<>();
|
||||||
|
final FileSystemPackerBuildService service = new FileSystemPackerBuildService(new PackerBuildPlanner(), events::add);
|
||||||
|
|
||||||
|
service.build(new PackerBuildRequest(new PackerProjectContext("events", projectRoot), false));
|
||||||
|
service.build(new PackerBuildRequest(new PackerProjectContext("events", projectRoot), false));
|
||||||
|
|
||||||
|
assertEquals(PackerEventKind.BUILD_STARTED, events.getFirst().kind());
|
||||||
|
assertTrue(events.stream().anyMatch(event -> event.kind() == PackerEventKind.CACHE_MISS));
|
||||||
|
assertTrue(events.stream().anyMatch(event -> event.kind() == PackerEventKind.CACHE_HIT));
|
||||||
|
assertTrue(events.stream().anyMatch(event -> event.kind() == PackerEventKind.BUILD_FINISHED));
|
||||||
|
}
|
||||||
|
|
||||||
private ParsedArchive parseArchive(Path archivePath) throws Exception {
|
private ParsedArchive parseArchive(Path archivePath) throws Exception {
|
||||||
final byte[] bytes = Files.readAllBytes(archivePath);
|
final byte[] bytes = Files.readAllBytes(archivePath);
|
||||||
final ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
final ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
||||||
|
|||||||
@ -7,9 +7,13 @@ import p.packer.api.PackerProjectContext;
|
|||||||
import p.packer.api.diagnostics.PackerDiagnosticCategory;
|
import p.packer.api.diagnostics.PackerDiagnosticCategory;
|
||||||
import p.packer.api.doctor.PackerDoctorMode;
|
import p.packer.api.doctor.PackerDoctorMode;
|
||||||
import p.packer.api.doctor.PackerDoctorRequest;
|
import p.packer.api.doctor.PackerDoctorRequest;
|
||||||
|
import p.packer.api.events.PackerEvent;
|
||||||
|
import p.packer.api.events.PackerEventKind;
|
||||||
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
@ -81,6 +85,24 @@ final class FileSystemPackerDoctorServiceTest {
|
|||||||
assertTrue(result.safeFixes().isEmpty());
|
assertTrue(result.safeFixes().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void emitsDiagnosticsLifecycleEvents() throws Exception {
|
||||||
|
final Path projectRoot = createManagedProjectWithMissingInput();
|
||||||
|
final List<PackerEvent> events = new CopyOnWriteArrayList<>();
|
||||||
|
final FileSystemPackerDoctorService service = new FileSystemPackerDoctorService(
|
||||||
|
new p.packer.workspace.FileSystemPackerWorkspaceService(),
|
||||||
|
new p.packer.declarations.PackerAssetDetailsService(),
|
||||||
|
events::add);
|
||||||
|
|
||||||
|
service.doctor(new PackerDoctorRequest(
|
||||||
|
new PackerProjectContext("main", projectRoot),
|
||||||
|
PackerDoctorMode.MANAGED_WORLD,
|
||||||
|
false));
|
||||||
|
|
||||||
|
assertTrue(events.stream().anyMatch(event -> event.kind() == PackerEventKind.PROGRESS_UPDATED));
|
||||||
|
assertEquals(PackerEventKind.DIAGNOSTICS_UPDATED, events.getLast().kind());
|
||||||
|
}
|
||||||
|
|
||||||
private Path createManagedProjectWithMissingInput() throws Exception {
|
private Path createManagedProjectWithMissingInput() throws Exception {
|
||||||
final Path projectRoot = tempDir.resolve("managed-missing-input");
|
final Path projectRoot = tempDir.resolve("managed-missing-input");
|
||||||
final Path assetRoot = projectRoot.resolve("assets/ui/atlas");
|
final Path assetRoot = projectRoot.resolve("assets/ui/atlas");
|
||||||
|
|||||||
@ -50,9 +50,10 @@ final class FileSystemPackerMutationServiceTest {
|
|||||||
assertTrue(Files.isDirectory(preview.targetAssetRoot()));
|
assertTrue(Files.isDirectory(preview.targetAssetRoot()));
|
||||||
final String registryJson = Files.readString(projectRoot.resolve("assets/.prometeu/index.json"));
|
final String registryJson = Files.readString(projectRoot.resolve("assets/.prometeu/index.json"));
|
||||||
assertFalse(registryJson.contains("\"root\" : \"ui/atlas\""));
|
assertFalse(registryJson.contains("\"root\" : \"ui/atlas\""));
|
||||||
assertEquals(List.of(PackerEventKind.PREVIEW_READY, PackerEventKind.ACTION_APPLIED), events.stream().map(PackerEvent::kind).toList());
|
assertEquals(List.of(PackerEventKind.PREVIEW_READY, PackerEventKind.ASSET_CHANGED, PackerEventKind.ACTION_APPLIED), events.stream().map(PackerEvent::kind).toList());
|
||||||
assertEquals(preview.operationId(), events.getFirst().operationId());
|
assertEquals(preview.operationId(), events.getFirst().operationId());
|
||||||
assertEquals(preview.operationId(), events.get(1).operationId());
|
assertEquals(preview.operationId(), events.get(1).operationId());
|
||||||
|
assertEquals(preview.operationId(), events.get(2).operationId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@ -5,12 +5,16 @@ import org.junit.jupiter.api.io.TempDir;
|
|||||||
import p.packer.api.PackerOperationStatus;
|
import p.packer.api.PackerOperationStatus;
|
||||||
import p.packer.api.PackerProjectContext;
|
import p.packer.api.PackerProjectContext;
|
||||||
import p.packer.api.assets.PackerAssetState;
|
import p.packer.api.assets.PackerAssetState;
|
||||||
|
import p.packer.api.events.PackerEvent;
|
||||||
|
import p.packer.api.events.PackerEventKind;
|
||||||
import p.packer.api.workspace.ListAssetsRequest;
|
import p.packer.api.workspace.ListAssetsRequest;
|
||||||
import p.packer.testing.PackerFixtureLocator;
|
import p.packer.testing.PackerFixtureLocator;
|
||||||
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
@ -54,6 +58,22 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
assertTrue(result.assets().getFirst().hasDiagnostics());
|
assertTrue(result.assets().getFirst().hasDiagnostics());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void emitsDiscoveryAndDiagnosticsEventsDuringScan() throws Exception {
|
||||||
|
final Path projectRoot = copyFixture("workspaces/read-invalid", tempDir.resolve("events"));
|
||||||
|
final List<PackerEvent> events = new CopyOnWriteArrayList<>();
|
||||||
|
final FileSystemPackerWorkspaceService service = new FileSystemPackerWorkspaceService(
|
||||||
|
new p.packer.foundation.PackerWorkspaceFoundation(),
|
||||||
|
new p.packer.declarations.PackerAssetDeclarationParser(),
|
||||||
|
events::add);
|
||||||
|
|
||||||
|
service.listAssets(new ListAssetsRequest(project(projectRoot)));
|
||||||
|
|
||||||
|
assertTrue(events.stream().anyMatch(event -> event.kind() == PackerEventKind.ASSET_DISCOVERED));
|
||||||
|
assertTrue(events.stream().anyMatch(event -> event.kind() == PackerEventKind.DIAGNOSTICS_UPDATED));
|
||||||
|
assertTrue(events.stream().allMatch(event -> event.sequence() >= 0L));
|
||||||
|
}
|
||||||
|
|
||||||
private PackerProjectContext project(Path root) {
|
private PackerProjectContext project(Path root) {
|
||||||
return new PackerProjectContext("main", root);
|
return new PackerProjectContext("main", root);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,18 @@ public final class StudioActivityEventMapper {
|
|||||||
Optional.of(new StudioActivityEntry("Assets", "Action applied: " + applied.action().name().toLowerCase(), StudioActivityEntrySeverity.SUCCESS, false));
|
Optional.of(new StudioActivityEntry("Assets", "Action applied: " + applied.action().name().toLowerCase(), StudioActivityEntrySeverity.SUCCESS, false));
|
||||||
case StudioAssetsMutationFailedEvent failed ->
|
case StudioAssetsMutationFailedEvent failed ->
|
||||||
Optional.of(new StudioActivityEntry("Assets", failed.message(), StudioActivityEntrySeverity.ERROR, true));
|
Optional.of(new StudioActivityEntry("Assets", failed.message(), StudioActivityEntrySeverity.ERROR, true));
|
||||||
|
case StudioPackerOperationEvent packerEvent ->
|
||||||
|
Optional.of(new StudioActivityEntry("Assets", packerEvent.summary(), severity(packerEvent), packerEvent.kind() == p.packer.api.events.PackerEventKind.ACTION_FAILED));
|
||||||
default -> Optional.empty();
|
default -> Optional.empty();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static StudioActivityEntrySeverity severity(StudioPackerOperationEvent event) {
|
||||||
|
return switch (event.kind()) {
|
||||||
|
case BUILD_FINISHED, CACHE_HIT -> StudioActivityEntrySeverity.SUCCESS;
|
||||||
|
case DIAGNOSTICS_UPDATED, CACHE_MISS, BUILD_STARTED, ASSET_DISCOVERED, ASSET_CHANGED, PROGRESS_UPDATED -> StudioActivityEntrySeverity.INFO;
|
||||||
|
case ACTION_FAILED -> StudioActivityEntrySeverity.ERROR;
|
||||||
|
default -> StudioActivityEntrySeverity.INFO;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,6 +59,7 @@ public final class StudioActivityFeedControl extends VBox implements StudioContr
|
|||||||
subscriptions.add(eventBus.subscribe(StudioAssetsMutationPreviewReadyEvent.class, this::onEvent));
|
subscriptions.add(eventBus.subscribe(StudioAssetsMutationPreviewReadyEvent.class, this::onEvent));
|
||||||
subscriptions.add(eventBus.subscribe(StudioAssetsMutationAppliedEvent.class, this::onEvent));
|
subscriptions.add(eventBus.subscribe(StudioAssetsMutationAppliedEvent.class, this::onEvent));
|
||||||
subscriptions.add(eventBus.subscribe(StudioAssetsMutationFailedEvent.class, this::onEvent));
|
subscriptions.add(eventBus.subscribe(StudioAssetsMutationFailedEvent.class, this::onEvent));
|
||||||
|
subscriptions.add(eventBus.subscribe(StudioPackerOperationEvent.class, this::onPackerOperation));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -114,6 +115,23 @@ public final class StudioActivityFeedControl extends VBox implements StudioContr
|
|||||||
clearProgress();
|
clearProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onPackerOperation(StudioPackerOperationEvent event) {
|
||||||
|
onEvent(event);
|
||||||
|
if (event.progress() != null) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
progressLabel.setText(event.summary());
|
||||||
|
progressBar.setVisible(true);
|
||||||
|
progressBar.setManaged(true);
|
||||||
|
progressBar.setProgress(event.indeterminate() ? ProgressBar.INDETERMINATE_PROGRESS : event.progress());
|
||||||
|
});
|
||||||
|
if (event.kind() == p.packer.api.events.PackerEventKind.BUILD_FINISHED) {
|
||||||
|
clearProgress();
|
||||||
|
}
|
||||||
|
} else if (event.kind() == p.packer.api.events.PackerEventKind.BUILD_FINISHED) {
|
||||||
|
clearProgress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void clearProgress() {
|
private void clearProgress() {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
progressLabel.setText(Container.i18n().text(I18n.ACTIVITY_PROGRESS_IDLE));
|
progressLabel.setText(Container.i18n().text(I18n.ACTIVITY_PROGRESS_IDLE));
|
||||||
|
|||||||
@ -0,0 +1,39 @@
|
|||||||
|
package p.studio.events;
|
||||||
|
|
||||||
|
import p.packer.api.events.PackerEvent;
|
||||||
|
import p.packer.api.events.PackerEventKind;
|
||||||
|
import p.packer.api.events.PackerEventSink;
|
||||||
|
import p.studio.projects.ProjectReference;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public final class StudioPackerEventAdapter implements PackerEventSink {
|
||||||
|
private final StudioWorkspaceEventBus eventBus;
|
||||||
|
private final ProjectReference projectReference;
|
||||||
|
|
||||||
|
public StudioPackerEventAdapter(StudioWorkspaceEventBus eventBus, ProjectReference projectReference) {
|
||||||
|
this.eventBus = Objects.requireNonNull(eventBus, "eventBus");
|
||||||
|
this.projectReference = Objects.requireNonNull(projectReference, "projectReference");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void publish(PackerEvent event) {
|
||||||
|
final PackerEvent packerEvent = Objects.requireNonNull(event, "event");
|
||||||
|
if (ignore(packerEvent.kind())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
eventBus.publish(new StudioPackerOperationEvent(
|
||||||
|
projectReference,
|
||||||
|
packerEvent.operationId(),
|
||||||
|
packerEvent.kind(),
|
||||||
|
packerEvent.summary(),
|
||||||
|
packerEvent.progress() == null ? null : packerEvent.progress().value(),
|
||||||
|
packerEvent.progress() == null || packerEvent.progress().indeterminate()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean ignore(PackerEventKind kind) {
|
||||||
|
return kind == PackerEventKind.PREVIEW_READY
|
||||||
|
|| kind == PackerEventKind.ACTION_APPLIED
|
||||||
|
|| kind == PackerEventKind.ACTION_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package p.studio.events;
|
||||||
|
|
||||||
|
import p.packer.api.events.PackerEventKind;
|
||||||
|
import p.studio.projects.ProjectReference;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public record StudioPackerOperationEvent(
|
||||||
|
ProjectReference project,
|
||||||
|
String operationId,
|
||||||
|
PackerEventKind kind,
|
||||||
|
String summary,
|
||||||
|
Double progress,
|
||||||
|
boolean indeterminate) implements StudioEvent {
|
||||||
|
|
||||||
|
public StudioPackerOperationEvent {
|
||||||
|
Objects.requireNonNull(project, "project");
|
||||||
|
operationId = Objects.requireNonNull(operationId, "operationId").trim();
|
||||||
|
Objects.requireNonNull(kind, "kind");
|
||||||
|
summary = Objects.requireNonNull(summary, "summary").trim();
|
||||||
|
if (operationId.isBlank() || summary.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("operationId and summary must not be blank");
|
||||||
|
}
|
||||||
|
if (progress != null && !indeterminate && (progress < 0.0d || progress > 1.0d)) {
|
||||||
|
throw new IllegalArgumentException("progress must be between 0.0 and 1.0 when determinate");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,6 +15,9 @@ import p.studio.projects.ProjectReference;
|
|||||||
import p.studio.utilities.i18n.I18n;
|
import p.studio.utilities.i18n.I18n;
|
||||||
import p.studio.workspaces.Workspace;
|
import p.studio.workspaces.Workspace;
|
||||||
import p.studio.workspaces.WorkspaceId;
|
import p.studio.workspaces.WorkspaceId;
|
||||||
|
import p.packer.declarations.PackerAssetDeclarationParser;
|
||||||
|
import p.packer.foundation.PackerWorkspaceFoundation;
|
||||||
|
import p.packer.workspace.FileSystemPackerWorkspaceService;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@ -58,7 +61,7 @@ public final class AssetWorkspace implements Workspace {
|
|||||||
public AssetWorkspace(ProjectReference projectReference) {
|
public AssetWorkspace(ProjectReference projectReference) {
|
||||||
this(
|
this(
|
||||||
projectReference,
|
projectReference,
|
||||||
new PackerBackedAssetWorkspaceService(),
|
null,
|
||||||
defaultWorkspaceBus(),
|
defaultWorkspaceBus(),
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
@ -76,8 +79,13 @@ public final class AssetWorkspace implements Workspace {
|
|||||||
StudioWorkspaceEventBus workspaceBus,
|
StudioWorkspaceEventBus workspaceBus,
|
||||||
AssetWorkspaceMutationService mutationService) {
|
AssetWorkspaceMutationService mutationService) {
|
||||||
this.projectReference = Objects.requireNonNull(projectReference, "projectReference");
|
this.projectReference = Objects.requireNonNull(projectReference, "projectReference");
|
||||||
this.assetWorkspaceService = Objects.requireNonNull(assetWorkspaceService, "assetWorkspaceService");
|
|
||||||
this.workspaceBus = Objects.requireNonNull(workspaceBus, "workspaceBus");
|
this.workspaceBus = Objects.requireNonNull(workspaceBus, "workspaceBus");
|
||||||
|
this.assetWorkspaceService = assetWorkspaceService == null
|
||||||
|
? new PackerBackedAssetWorkspaceService(new FileSystemPackerWorkspaceService(
|
||||||
|
new PackerWorkspaceFoundation(),
|
||||||
|
new PackerAssetDeclarationParser(),
|
||||||
|
new StudioPackerEventAdapter(this.workspaceBus, this.projectReference)))
|
||||||
|
: Objects.requireNonNull(assetWorkspaceService, "assetWorkspaceService");
|
||||||
this.mutationService = mutationService == null
|
this.mutationService = mutationService == null
|
||||||
? new PackerBackedAssetWorkspaceMutationService(this.workspaceBus)
|
? new PackerBackedAssetWorkspaceMutationService(this.workspaceBus)
|
||||||
: Objects.requireNonNull(mutationService, "mutationService");
|
: Objects.requireNonNull(mutationService, "mutationService");
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
package p.studio.controls.shell;
|
package p.studio.controls.shell;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import p.packer.api.events.PackerEventKind;
|
||||||
import p.studio.events.StudioAssetsMutationAppliedEvent;
|
import p.studio.events.StudioAssetsMutationAppliedEvent;
|
||||||
import p.studio.events.StudioAssetsMutationFailedEvent;
|
import p.studio.events.StudioAssetsMutationFailedEvent;
|
||||||
import p.studio.events.StudioAssetsMutationPreviewReadyEvent;
|
import p.studio.events.StudioAssetsMutationPreviewReadyEvent;
|
||||||
|
import p.studio.events.StudioPackerOperationEvent;
|
||||||
import p.studio.events.StudioAssetsWorkspaceRefreshFailedEvent;
|
import p.studio.events.StudioAssetsWorkspaceRefreshFailedEvent;
|
||||||
import p.studio.events.StudioAssetsWorkspaceRefreshedEvent;
|
import p.studio.events.StudioAssetsWorkspaceRefreshedEvent;
|
||||||
import p.studio.events.StudioProjectOpenedEvent;
|
import p.studio.events.StudioProjectOpenedEvent;
|
||||||
@ -83,6 +85,17 @@ final class StudioActivityEventMapperTest {
|
|||||||
assertEquals("Apply failed", entry.message());
|
assertEquals("Apply failed", entry.message());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void mapsPackerBuildEventToActivityEntry() {
|
||||||
|
final StudioActivityEntry entry = StudioActivityEventMapper
|
||||||
|
.map(new StudioPackerOperationEvent(project(), "op-1", PackerEventKind.BUILD_FINISHED, "Build finished.", 1.0d, false))
|
||||||
|
.orElseThrow();
|
||||||
|
|
||||||
|
assertEquals("Assets", entry.source());
|
||||||
|
assertEquals(StudioActivityEntrySeverity.SUCCESS, entry.severity());
|
||||||
|
assertEquals("Build finished.", entry.message());
|
||||||
|
}
|
||||||
|
|
||||||
private ProjectReference project() {
|
private ProjectReference project() {
|
||||||
return new ProjectReference("Main", "1.0.0", "pbs", 1, Path.of("/tmp/main"));
|
return new ProjectReference("Main", "1.0.0", "pbs", 1, Path.of("/tmp/main"));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,68 @@
|
|||||||
|
package p.studio.events;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import p.packer.api.events.PackerEvent;
|
||||||
|
import p.packer.api.events.PackerEventKind;
|
||||||
|
import p.packer.api.events.PackerProgress;
|
||||||
|
import p.studio.projects.ProjectReference;
|
||||||
|
import p.studio.workspaces.WorkspaceId;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
final class StudioPackerEventAdapterTest {
|
||||||
|
@Test
|
||||||
|
void forwardsBuildEventsIntoStudioOperationEvents() {
|
||||||
|
final StudioEventBus globalBus = new StudioEventBus();
|
||||||
|
final List<StudioPackerOperationEvent> events = new ArrayList<>();
|
||||||
|
globalBus.subscribe(StudioPackerOperationEvent.class, events::add);
|
||||||
|
final StudioPackerEventAdapter adapter = new StudioPackerEventAdapter(
|
||||||
|
new StudioWorkspaceEventBus(WorkspaceId.ASSETS, globalBus),
|
||||||
|
project());
|
||||||
|
|
||||||
|
adapter.publish(new PackerEvent(
|
||||||
|
"main",
|
||||||
|
"op-1",
|
||||||
|
0L,
|
||||||
|
PackerEventKind.BUILD_STARTED,
|
||||||
|
Instant.now(),
|
||||||
|
"Build started.",
|
||||||
|
new PackerProgress(0.25d, false),
|
||||||
|
List.of("ui_atlas")));
|
||||||
|
|
||||||
|
assertEquals(1, events.size());
|
||||||
|
assertEquals(PackerEventKind.BUILD_STARTED, events.getFirst().kind());
|
||||||
|
assertEquals(0.25d, events.getFirst().progress());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void ignoresMutationLifecycleEventsAlreadyHandledByTypedStudioEvents() {
|
||||||
|
final StudioEventBus globalBus = new StudioEventBus();
|
||||||
|
final List<StudioPackerOperationEvent> events = new ArrayList<>();
|
||||||
|
globalBus.subscribe(StudioPackerOperationEvent.class, events::add);
|
||||||
|
final StudioPackerEventAdapter adapter = new StudioPackerEventAdapter(
|
||||||
|
new StudioWorkspaceEventBus(WorkspaceId.ASSETS, globalBus),
|
||||||
|
project());
|
||||||
|
|
||||||
|
adapter.publish(new PackerEvent(
|
||||||
|
"main",
|
||||||
|
"op-1",
|
||||||
|
0L,
|
||||||
|
PackerEventKind.PREVIEW_READY,
|
||||||
|
Instant.now(),
|
||||||
|
"Preview ready.",
|
||||||
|
null,
|
||||||
|
List.of("ui_atlas")));
|
||||||
|
|
||||||
|
assertTrue(events.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProjectReference project() {
|
||||||
|
return new ProjectReference("Main", "1.0.0", "pbs", 1, Path.of("/tmp/main"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user