implements PR-027 runtime walkresult and cache integration
This commit is contained in:
parent
1442adc7b3
commit
b4733a0e49
@ -53,6 +53,9 @@ public enum OutputFormatCatalog {
|
|||||||
return UNKNOWN;
|
return UNKNOWN;
|
||||||
}
|
}
|
||||||
final String normalized = manifestValue.trim().toLowerCase(Locale.ROOT);
|
final String normalized = manifestValue.trim().toLowerCase(Locale.ROOT);
|
||||||
|
if ("sound/bank_v1".equals(normalized)) {
|
||||||
|
return SOUND_V1;
|
||||||
|
}
|
||||||
for (OutputFormatCatalog candidate : values()) {
|
for (OutputFormatCatalog candidate : values()) {
|
||||||
if (candidate == UNKNOWN) {
|
if (candidate == UNKNOWN) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@ -2,7 +2,9 @@ package p.packer;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import p.packer.events.PackerEventSink;
|
import p.packer.events.PackerEventSink;
|
||||||
|
import p.packer.repositories.FileSystemPackerCacheRepository;
|
||||||
import p.packer.repositories.PackerAssetWalker;
|
import p.packer.repositories.PackerAssetWalker;
|
||||||
|
import p.packer.repositories.PackerRuntimeAssetMaterializer;
|
||||||
import p.packer.repositories.PackerRuntimeLoader;
|
import p.packer.repositories.PackerRuntimeLoader;
|
||||||
import p.packer.repositories.PackerRuntimeRegistry;
|
import p.packer.repositories.PackerRuntimeRegistry;
|
||||||
import p.packer.services.*;
|
import p.packer.services.*;
|
||||||
@ -29,7 +31,13 @@ public final class Packer implements Closeable {
|
|||||||
final var workspaceFoundation = new PackerWorkspaceFoundation(mapper);
|
final var workspaceFoundation = new PackerWorkspaceFoundation(mapper);
|
||||||
final var declarationParser = new PackerAssetDeclarationParser(mapper);
|
final var declarationParser = new PackerAssetDeclarationParser(mapper);
|
||||||
final var assetWalker = new PackerAssetWalker(mapper);
|
final var assetWalker = new PackerAssetWalker(mapper);
|
||||||
final var runtimeLoader = new PackerRuntimeLoader(workspaceFoundation, declarationParser, assetWalker);
|
final var cacheRepository = new FileSystemPackerCacheRepository(mapper);
|
||||||
|
final var assetMaterializer = new PackerRuntimeAssetMaterializer(assetWalker);
|
||||||
|
final var runtimeLoader = new PackerRuntimeLoader(
|
||||||
|
workspaceFoundation,
|
||||||
|
declarationParser,
|
||||||
|
cacheRepository,
|
||||||
|
assetMaterializer);
|
||||||
final var runtimeRegistry = new PackerRuntimeRegistry(runtimeLoader);
|
final var runtimeRegistry = new PackerRuntimeRegistry(runtimeLoader);
|
||||||
final var assetReferenceResolver = new PackerAssetReferenceResolver(workspaceFoundation.lookup());
|
final var assetReferenceResolver = new PackerAssetReferenceResolver(workspaceFoundation.lookup());
|
||||||
final var assetDetailsService = new PackerAssetDetailsService(runtimeRegistry, assetReferenceResolver);
|
final var assetDetailsService = new PackerAssetDetailsService(runtimeRegistry, assetReferenceResolver);
|
||||||
@ -37,7 +45,7 @@ public final class Packer implements Closeable {
|
|||||||
runtimeRegistry,
|
runtimeRegistry,
|
||||||
assetReferenceResolver,
|
assetReferenceResolver,
|
||||||
workspaceFoundation.lookup());
|
workspaceFoundation.lookup());
|
||||||
final var runtimePatchService = new PackerRuntimePatchService(declarationParser);
|
final var runtimePatchService = new PackerRuntimePatchService(declarationParser, assetMaterializer);
|
||||||
final var writeCoordinator = new PackerProjectWriteCoordinator();
|
final var writeCoordinator = new PackerProjectWriteCoordinator();
|
||||||
return new Packer(new FileSystemPackerWorkspaceService(
|
return new Packer(new FileSystemPackerWorkspaceService(
|
||||||
mapper,
|
mapper,
|
||||||
@ -46,6 +54,7 @@ public final class Packer implements Closeable {
|
|||||||
assetActionReadService,
|
assetActionReadService,
|
||||||
runtimePatchService,
|
runtimePatchService,
|
||||||
runtimeRegistry,
|
runtimeRegistry,
|
||||||
|
cacheRepository,
|
||||||
writeCoordinator,
|
writeCoordinator,
|
||||||
resolvedEventSink), runtimeRegistry, writeCoordinator);
|
resolvedEventSink), runtimeRegistry, writeCoordinator);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,32 @@
|
|||||||
package p.packer.models;
|
package p.packer.models;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public record PackerRuntimeAsset(
|
public record PackerRuntimeAsset(
|
||||||
|
Path assetRoot,
|
||||||
|
Path manifestPath,
|
||||||
|
Optional<PackerRegistryEntry> registryEntry,
|
||||||
|
PackerAssetDeclarationParseResult parsedDeclaration,
|
||||||
|
PackerRuntimeWalkProjection walkProjection,
|
||||||
|
List<PackerDiagnostic> walkDiagnostics) {
|
||||||
|
|
||||||
|
public PackerRuntimeAsset(
|
||||||
Path assetRoot,
|
Path assetRoot,
|
||||||
Path manifestPath,
|
Path manifestPath,
|
||||||
Optional<PackerRegistryEntry> registryEntry,
|
Optional<PackerRegistryEntry> registryEntry,
|
||||||
PackerAssetDeclarationParseResult parsedDeclaration) {
|
PackerAssetDeclarationParseResult parsedDeclaration) {
|
||||||
|
this(assetRoot, manifestPath, registryEntry, parsedDeclaration, PackerRuntimeWalkProjection.EMPTY, List.of());
|
||||||
|
}
|
||||||
|
|
||||||
public PackerRuntimeAsset {
|
public PackerRuntimeAsset {
|
||||||
assetRoot = Objects.requireNonNull(assetRoot, "assetRoot").toAbsolutePath().normalize();
|
assetRoot = Objects.requireNonNull(assetRoot, "assetRoot").toAbsolutePath().normalize();
|
||||||
manifestPath = Objects.requireNonNull(manifestPath, "manifestPath").toAbsolutePath().normalize();
|
manifestPath = Objects.requireNonNull(manifestPath, "manifestPath").toAbsolutePath().normalize();
|
||||||
registryEntry = Objects.requireNonNull(registryEntry, "registryEntry");
|
registryEntry = Objects.requireNonNull(registryEntry, "registryEntry");
|
||||||
parsedDeclaration = Objects.requireNonNull(parsedDeclaration, "parsedDeclaration");
|
parsedDeclaration = Objects.requireNonNull(parsedDeclaration, "parsedDeclaration");
|
||||||
|
walkProjection = Objects.requireNonNull(walkProjection, "walkProjection");
|
||||||
|
walkDiagnostics = List.copyOf(Objects.requireNonNull(walkDiagnostics, "walkDiagnostics"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,9 +4,17 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public record PackerRuntimeSnapshot(
|
public record PackerRuntimeSnapshot(
|
||||||
|
long generation,
|
||||||
|
PackerRegistryState registry,
|
||||||
|
List<PackerRuntimeAsset> assets,
|
||||||
|
PackerWorkspaceCacheState cacheState) {
|
||||||
|
|
||||||
|
public PackerRuntimeSnapshot(
|
||||||
long generation,
|
long generation,
|
||||||
PackerRegistryState registry,
|
PackerRegistryState registry,
|
||||||
List<PackerRuntimeAsset> assets) {
|
List<PackerRuntimeAsset> assets) {
|
||||||
|
this(generation, registry, assets, PackerWorkspaceCacheState.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
public PackerRuntimeSnapshot {
|
public PackerRuntimeSnapshot {
|
||||||
if (generation <= 0L) {
|
if (generation <= 0L) {
|
||||||
@ -14,5 +22,6 @@ public record PackerRuntimeSnapshot(
|
|||||||
}
|
}
|
||||||
registry = Objects.requireNonNull(registry, "registry");
|
registry = Objects.requireNonNull(registry, "registry");
|
||||||
assets = List.copyOf(Objects.requireNonNull(assets, "assets"));
|
assets = List.copyOf(Objects.requireNonNull(assets, "assets"));
|
||||||
|
cacheState = Objects.requireNonNull(cacheState, "cacheState");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
package p.packer.models;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public record PackerRuntimeWalkFile(
|
||||||
|
String relativePath,
|
||||||
|
String mimeType,
|
||||||
|
long size,
|
||||||
|
long lastModified,
|
||||||
|
String fingerprint,
|
||||||
|
Map<String, Object> metadata,
|
||||||
|
List<PackerDiagnostic> diagnostics) {
|
||||||
|
|
||||||
|
public PackerRuntimeWalkFile {
|
||||||
|
relativePath = Objects.requireNonNull(relativePath, "relativePath");
|
||||||
|
mimeType = mimeType == null || mimeType.isBlank() ? null : mimeType;
|
||||||
|
if (size < 0L) {
|
||||||
|
throw new IllegalArgumentException("size must be non-negative");
|
||||||
|
}
|
||||||
|
if (lastModified < 0L) {
|
||||||
|
throw new IllegalArgumentException("lastModified must be non-negative");
|
||||||
|
}
|
||||||
|
fingerprint = fingerprint == null || fingerprint.isBlank() ? null : fingerprint;
|
||||||
|
metadata = Map.copyOf(new LinkedHashMap<>(Objects.requireNonNull(metadata, "metadata")));
|
||||||
|
diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package p.packer.models;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public record PackerRuntimeWalkProjection(
|
||||||
|
List<String> availableFiles,
|
||||||
|
List<PackerRuntimeWalkFile> buildCandidateFiles,
|
||||||
|
long measuredBankSizeBytes) {
|
||||||
|
public static final PackerRuntimeWalkProjection EMPTY = new PackerRuntimeWalkProjection(List.of(), List.of(), 0L);
|
||||||
|
|
||||||
|
public PackerRuntimeWalkProjection {
|
||||||
|
availableFiles = List.copyOf(Objects.requireNonNull(availableFiles, "availableFiles"));
|
||||||
|
buildCandidateFiles = List.copyOf(Objects.requireNonNull(buildCandidateFiles, "buildCandidateFiles"));
|
||||||
|
if (measuredBankSizeBytes < 0L) {
|
||||||
|
throw new IllegalArgumentException("measuredBankSizeBytes must be non-negative");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,9 +14,6 @@ import p.packer.models.PackerWalkResult;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.HexFormat;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -132,12 +129,7 @@ public abstract class PackerAbstractBankWalker<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String computeFingerprint(final PackerFileProbe fileProbe) {
|
protected String computeFingerprint(final PackerFileProbe fileProbe) {
|
||||||
try {
|
return PackerFileFingerprint.sha256(fileProbe);
|
||||||
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
|
||||||
return HexFormat.of().formatHex(digest.digest(fileProbe.content()));
|
|
||||||
} catch (NoSuchAlgorithmException exception) {
|
|
||||||
throw new IllegalStateException("SHA-256 fingerprint is unavailable", exception);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<PackerFileCacheEntry> resolvePriorFileCache(
|
private Optional<PackerFileCacheEntry> resolvePriorFileCache(
|
||||||
|
|||||||
@ -146,7 +146,7 @@ public class PackerAssetWalker {
|
|||||||
return RequirementBuildResult.fail("Missing sample rate for sound bank");
|
return RequirementBuildResult.fail("Missing sample rate for sound bank");
|
||||||
}
|
}
|
||||||
final var sampleRate = Integer.parseInt(sampleRateStr);
|
final var sampleRate = Integer.parseInt(sampleRateStr);
|
||||||
final var channelsStr = metadata.get("");
|
final var channelsStr = metadata.get("channels");
|
||||||
if (StringUtils.isBlank(channelsStr)) {
|
if (StringUtils.isBlank(channelsStr)) {
|
||||||
return RequirementBuildResult.fail("Missing channels for sound bank");
|
return RequirementBuildResult.fail("Missing channels for sound bank");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,21 @@
|
|||||||
|
package p.packer.repositories;
|
||||||
|
|
||||||
|
import p.packer.models.PackerFileProbe;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.HexFormat;
|
||||||
|
|
||||||
|
final class PackerFileFingerprint {
|
||||||
|
private PackerFileFingerprint() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static String sha256(final PackerFileProbe fileProbe) {
|
||||||
|
try {
|
||||||
|
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||||
|
return HexFormat.of().formatHex(digest.digest(fileProbe.content()));
|
||||||
|
} catch (NoSuchAlgorithmException exception) {
|
||||||
|
throw new IllegalStateException("SHA-256 fingerprint is unavailable", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,110 @@
|
|||||||
|
package p.packer.repositories;
|
||||||
|
|
||||||
|
import p.packer.models.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public final class PackerRuntimeAssetMaterializer {
|
||||||
|
private final PackerAssetWalker assetWalker;
|
||||||
|
|
||||||
|
public PackerRuntimeAssetMaterializer(PackerAssetWalker assetWalker) {
|
||||||
|
this.assetWalker = Objects.requireNonNull(assetWalker, "assetWalker");
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackerRuntimeAssetMaterialization materialize(
|
||||||
|
Path assetRoot,
|
||||||
|
Path manifestPath,
|
||||||
|
Optional<PackerRegistryEntry> registryEntry,
|
||||||
|
PackerAssetDeclarationParseResult parseResult,
|
||||||
|
Optional<PackerAssetCacheEntry> priorAssetCache) {
|
||||||
|
final Path normalizedAssetRoot = Objects.requireNonNull(assetRoot, "assetRoot").toAbsolutePath().normalize();
|
||||||
|
final Path normalizedManifestPath = Objects.requireNonNull(manifestPath, "manifestPath").toAbsolutePath().normalize();
|
||||||
|
final Optional<PackerRegistryEntry> safeRegistryEntry = Objects.requireNonNull(registryEntry, "registryEntry");
|
||||||
|
final PackerAssetDeclarationParseResult safeParseResult = Objects.requireNonNull(parseResult, "parseResult");
|
||||||
|
final Optional<PackerAssetCacheEntry> safePriorAssetCache = Objects.requireNonNull(priorAssetCache, "priorAssetCache");
|
||||||
|
|
||||||
|
if (safeRegistryEntry.isEmpty() || !safeParseResult.valid()) {
|
||||||
|
return new PackerRuntimeAssetMaterialization(
|
||||||
|
new PackerRuntimeAsset(
|
||||||
|
normalizedAssetRoot,
|
||||||
|
normalizedManifestPath,
|
||||||
|
safeRegistryEntry,
|
||||||
|
safeParseResult,
|
||||||
|
PackerRuntimeWalkProjection.EMPTY,
|
||||||
|
List.of()),
|
||||||
|
Optional.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<String> availableFiles = listAvailableFiles(normalizedAssetRoot);
|
||||||
|
final PackerWalkResult walkResult = assetWalker.walk(
|
||||||
|
normalizedAssetRoot,
|
||||||
|
safeParseResult.declaration(),
|
||||||
|
safePriorAssetCache);
|
||||||
|
final List<PackerRuntimeWalkFile> buildCandidateFiles = walkResult.probeResults().stream()
|
||||||
|
.map(probeResult -> toRuntimeWalkFile(normalizedAssetRoot, probeResult))
|
||||||
|
.sorted(Comparator.comparing(PackerRuntimeWalkFile::relativePath, String.CASE_INSENSITIVE_ORDER))
|
||||||
|
.toList();
|
||||||
|
final long measuredBankSizeBytes = buildCandidateFiles.stream()
|
||||||
|
.mapToLong(PackerRuntimeWalkFile::size)
|
||||||
|
.sum();
|
||||||
|
final PackerRuntimeWalkProjection walkProjection = new PackerRuntimeWalkProjection(
|
||||||
|
availableFiles,
|
||||||
|
buildCandidateFiles,
|
||||||
|
measuredBankSizeBytes);
|
||||||
|
final PackerRuntimeAsset runtimeAsset = new PackerRuntimeAsset(
|
||||||
|
normalizedAssetRoot,
|
||||||
|
normalizedManifestPath,
|
||||||
|
safeRegistryEntry,
|
||||||
|
safeParseResult,
|
||||||
|
walkProjection,
|
||||||
|
walkResult.diagnostics());
|
||||||
|
final PackerAssetCacheEntry assetCacheEntry = new PackerAssetCacheEntry(
|
||||||
|
safeRegistryEntry.get().assetId(),
|
||||||
|
buildCandidateFiles.stream()
|
||||||
|
.map(file -> new PackerFileCacheEntry(
|
||||||
|
file.relativePath(),
|
||||||
|
file.mimeType(),
|
||||||
|
file.size(),
|
||||||
|
file.lastModified(),
|
||||||
|
file.fingerprint(),
|
||||||
|
file.metadata()))
|
||||||
|
.toList());
|
||||||
|
return new PackerRuntimeAssetMaterialization(runtimeAsset, Optional.of(assetCacheEntry));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> listAvailableFiles(Path assetRoot) {
|
||||||
|
try (var paths = Files.list(assetRoot)
|
||||||
|
.filter(Files::isRegularFile)
|
||||||
|
.filter(path -> !path.getFileName().toString().equalsIgnoreCase("asset.json"))
|
||||||
|
.map(path -> assetRoot.relativize(path.toAbsolutePath().normalize()).toString().replace('\\', '/'))
|
||||||
|
.sorted(String.CASE_INSENSITIVE_ORDER)) {
|
||||||
|
return paths.toList();
|
||||||
|
} catch (IOException exception) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PackerRuntimeWalkFile toRuntimeWalkFile(Path assetRoot, PackerProbeResult probeResult) {
|
||||||
|
final PackerFileProbe fileProbe = probeResult.fileProbe();
|
||||||
|
return new PackerRuntimeWalkFile(
|
||||||
|
assetRoot.relativize(fileProbe.path().toAbsolutePath().normalize()).toString().replace('\\', '/'),
|
||||||
|
fileProbe.mimeType(),
|
||||||
|
fileProbe.size(),
|
||||||
|
fileProbe.lastModified(),
|
||||||
|
PackerFileFingerprint.sha256(fileProbe),
|
||||||
|
probeResult.metadata(),
|
||||||
|
probeResult.diagnostics());
|
||||||
|
}
|
||||||
|
|
||||||
|
public record PackerRuntimeAssetMaterialization(
|
||||||
|
PackerRuntimeAsset runtimeAsset,
|
||||||
|
Optional<PackerAssetCacheEntry> assetCacheEntry) {
|
||||||
|
public PackerRuntimeAssetMaterialization {
|
||||||
|
runtimeAsset = Objects.requireNonNull(runtimeAsset, "runtimeAsset");
|
||||||
|
assetCacheEntry = Objects.requireNonNull(assetCacheEntry, "assetCacheEntry");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,8 +2,10 @@ package p.packer.repositories;
|
|||||||
|
|
||||||
import p.packer.messages.InitWorkspaceRequest;
|
import p.packer.messages.InitWorkspaceRequest;
|
||||||
import p.packer.messages.PackerProjectContext;
|
import p.packer.messages.PackerProjectContext;
|
||||||
|
import p.packer.models.PackerAssetCacheEntry;
|
||||||
import p.packer.models.PackerRuntimeAsset;
|
import p.packer.models.PackerRuntimeAsset;
|
||||||
import p.packer.models.PackerRuntimeSnapshot;
|
import p.packer.models.PackerRuntimeSnapshot;
|
||||||
|
import p.packer.models.PackerWorkspaceCacheState;
|
||||||
import p.packer.services.PackerAssetDeclarationParser;
|
import p.packer.services.PackerAssetDeclarationParser;
|
||||||
import p.packer.services.PackerWorkspaceFoundation;
|
import p.packer.services.PackerWorkspaceFoundation;
|
||||||
import p.packer.PackerWorkspacePaths;
|
import p.packer.PackerWorkspacePaths;
|
||||||
@ -18,15 +20,18 @@ import java.util.stream.Collectors;
|
|||||||
public final class PackerRuntimeLoader implements PackerRuntimeSnapshotLoader {
|
public final class PackerRuntimeLoader implements PackerRuntimeSnapshotLoader {
|
||||||
private final PackerWorkspaceFoundation workspaceFoundation;
|
private final PackerWorkspaceFoundation workspaceFoundation;
|
||||||
private final PackerAssetDeclarationParser parser;
|
private final PackerAssetDeclarationParser parser;
|
||||||
private final PackerAssetWalker assetWalker;
|
private final FileSystemPackerCacheRepository cacheRepository;
|
||||||
|
private final PackerRuntimeAssetMaterializer assetMaterializer;
|
||||||
|
|
||||||
public PackerRuntimeLoader(
|
public PackerRuntimeLoader(
|
||||||
final PackerWorkspaceFoundation workspaceFoundation,
|
final PackerWorkspaceFoundation workspaceFoundation,
|
||||||
final PackerAssetDeclarationParser parser,
|
final PackerAssetDeclarationParser parser,
|
||||||
final PackerAssetWalker assetWalker) {
|
final FileSystemPackerCacheRepository cacheRepository,
|
||||||
|
final PackerRuntimeAssetMaterializer assetMaterializer) {
|
||||||
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.assetWalker = Objects.requireNonNull(assetWalker, "assetWalker");
|
this.cacheRepository = Objects.requireNonNull(cacheRepository, "cacheRepository");
|
||||||
|
this.assetMaterializer = Objects.requireNonNull(assetMaterializer, "assetMaterializer");
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAssetJson(Path path, BasicFileAttributes attrs) {
|
private boolean isAssetJson(Path path, BasicFileAttributes attrs) {
|
||||||
@ -39,6 +44,7 @@ public final class PackerRuntimeLoader implements PackerRuntimeSnapshotLoader {
|
|||||||
workspaceFoundation.initWorkspace(new InitWorkspaceRequest(safeProject));
|
workspaceFoundation.initWorkspace(new InitWorkspaceRequest(safeProject));
|
||||||
|
|
||||||
final var registry = workspaceFoundation.loadRegistry(safeProject);
|
final var registry = workspaceFoundation.loadRegistry(safeProject);
|
||||||
|
final PackerWorkspaceCacheState priorCacheState = loadPriorCacheState(safeProject);
|
||||||
final var registryByRoot = registry
|
final var registryByRoot = registry
|
||||||
.assets()
|
.assets()
|
||||||
.stream()
|
.stream()
|
||||||
@ -47,6 +53,7 @@ public final class PackerRuntimeLoader implements PackerRuntimeSnapshotLoader {
|
|||||||
entry -> entry));
|
entry -> entry));
|
||||||
|
|
||||||
final List<PackerRuntimeAsset> assets = new ArrayList<>();
|
final List<PackerRuntimeAsset> assets = new ArrayList<>();
|
||||||
|
final List<PackerAssetCacheEntry> refreshedCacheEntries = new ArrayList<>();
|
||||||
final var assetsRoot = PackerWorkspacePaths.assetsRoot(safeProject);
|
final var assetsRoot = PackerWorkspacePaths.assetsRoot(safeProject);
|
||||||
if (Files.isDirectory(assetsRoot)) {
|
if (Files.isDirectory(assetsRoot)) {
|
||||||
try (final var paths = Files.find(assetsRoot, Integer.MAX_VALUE, this::isAssetJson)) {
|
try (final var paths = Files.find(assetsRoot, Integer.MAX_VALUE, this::isAssetJson)) {
|
||||||
@ -58,12 +65,16 @@ public final class PackerRuntimeLoader implements PackerRuntimeSnapshotLoader {
|
|||||||
final var assetRoot = manifestPath.getParent();
|
final var assetRoot = manifestPath.getParent();
|
||||||
final var registryEntry = Optional.ofNullable(registryByRoot.get(assetRoot));
|
final var registryEntry = Optional.ofNullable(registryByRoot.get(assetRoot));
|
||||||
final var parseResult = parser.parse(manifestPath);
|
final var parseResult = parser.parse(manifestPath);
|
||||||
if (parseResult.valid()) {
|
final Optional<PackerAssetCacheEntry> priorAssetCache = registryEntry
|
||||||
final var walkResult = assetWalker.walk(assetRoot, parseResult.declaration());
|
.flatMap(entry -> priorCacheState.findAsset(entry.assetId()));
|
||||||
|
final var materialized = assetMaterializer.materialize(
|
||||||
}
|
assetRoot,
|
||||||
final var runtimeAsset = new PackerRuntimeAsset(assetRoot, manifestPath, registryEntry, parseResult);
|
manifestPath,
|
||||||
assets.add(runtimeAsset);
|
registryEntry,
|
||||||
|
parseResult,
|
||||||
|
priorAssetCache);
|
||||||
|
assets.add(materialized.runtimeAsset());
|
||||||
|
materialized.assetCacheEntry().ifPresent(refreshedCacheEntries::add);
|
||||||
}
|
}
|
||||||
} catch (IOException exception) {
|
} catch (IOException exception) {
|
||||||
throw new p.packer.exceptions.PackerRegistryException(
|
throw new p.packer.exceptions.PackerRegistryException(
|
||||||
@ -72,6 +83,20 @@ public final class PackerRuntimeLoader implements PackerRuntimeSnapshotLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PackerRuntimeSnapshot(generation, registry, assets);
|
final PackerWorkspaceCacheState refreshedCacheState = new PackerWorkspaceCacheState(
|
||||||
|
PackerWorkspaceCacheState.CURRENT_SCHEMA_VERSION,
|
||||||
|
refreshedCacheEntries.stream()
|
||||||
|
.sorted(Comparator.comparingInt(PackerAssetCacheEntry::assetId))
|
||||||
|
.toList());
|
||||||
|
cacheRepository.save(safeProject, refreshedCacheState);
|
||||||
|
return new PackerRuntimeSnapshot(generation, registry, assets, refreshedCacheState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PackerWorkspaceCacheState loadPriorCacheState(PackerProjectContext project) {
|
||||||
|
try {
|
||||||
|
return cacheRepository.load(project);
|
||||||
|
} catch (p.packer.exceptions.PackerRegistryException exception) {
|
||||||
|
return PackerWorkspaceCacheState.EMPTY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import p.packer.messages.assets.*;
|
|||||||
import p.packer.messages.diagnostics.PackerDiagnosticCategory;
|
import p.packer.messages.diagnostics.PackerDiagnosticCategory;
|
||||||
import p.packer.messages.diagnostics.PackerDiagnosticSeverity;
|
import p.packer.messages.diagnostics.PackerDiagnosticSeverity;
|
||||||
import p.packer.models.*;
|
import p.packer.models.*;
|
||||||
|
import p.packer.repositories.FileSystemPackerCacheRepository;
|
||||||
import p.packer.repositories.PackerRuntimeRegistry;
|
import p.packer.repositories.PackerRuntimeRegistry;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -28,6 +29,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
private final PackerAssetActionReadService actionReadService;
|
private final PackerAssetActionReadService actionReadService;
|
||||||
private final PackerRuntimePatchService runtimePatchService;
|
private final PackerRuntimePatchService runtimePatchService;
|
||||||
private final PackerRuntimeRegistry runtimeRegistry;
|
private final PackerRuntimeRegistry runtimeRegistry;
|
||||||
|
private final FileSystemPackerCacheRepository cacheRepository;
|
||||||
private final PackerProjectWriteCoordinator writeCoordinator;
|
private final PackerProjectWriteCoordinator writeCoordinator;
|
||||||
private final PackerEventSink eventSink;
|
private final PackerEventSink eventSink;
|
||||||
|
|
||||||
@ -38,6 +40,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
PackerAssetActionReadService actionReadService,
|
PackerAssetActionReadService actionReadService,
|
||||||
PackerRuntimePatchService runtimePatchService,
|
PackerRuntimePatchService runtimePatchService,
|
||||||
PackerRuntimeRegistry runtimeRegistry,
|
PackerRuntimeRegistry runtimeRegistry,
|
||||||
|
FileSystemPackerCacheRepository cacheRepository,
|
||||||
PackerProjectWriteCoordinator writeCoordinator,
|
PackerProjectWriteCoordinator writeCoordinator,
|
||||||
PackerEventSink eventSink) {
|
PackerEventSink eventSink) {
|
||||||
this.mapper = Objects.requireNonNull(mapper, "mapper");
|
this.mapper = Objects.requireNonNull(mapper, "mapper");
|
||||||
@ -46,6 +49,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
this.actionReadService = Objects.requireNonNull(actionReadService, "actionReadService");
|
this.actionReadService = Objects.requireNonNull(actionReadService, "actionReadService");
|
||||||
this.runtimePatchService = Objects.requireNonNull(runtimePatchService, "runtimePatchService");
|
this.runtimePatchService = Objects.requireNonNull(runtimePatchService, "runtimePatchService");
|
||||||
this.runtimeRegistry = Objects.requireNonNull(runtimeRegistry, "runtimeRegistry");
|
this.runtimeRegistry = Objects.requireNonNull(runtimeRegistry, "runtimeRegistry");
|
||||||
|
this.cacheRepository = Objects.requireNonNull(cacheRepository, "cacheRepository");
|
||||||
this.writeCoordinator = Objects.requireNonNull(writeCoordinator, "writeCoordinator");
|
this.writeCoordinator = Objects.requireNonNull(writeCoordinator, "writeCoordinator");
|
||||||
this.eventSink = Objects.requireNonNull(eventSink, "eventSink");
|
this.eventSink = Objects.requireNonNull(eventSink, "eventSink");
|
||||||
}
|
}
|
||||||
@ -84,6 +88,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
final var registryEntry = registryByRoot.get(assetRoot);
|
final var registryEntry = registryByRoot.get(assetRoot);
|
||||||
final var parsed = runtimeAsset.parsedDeclaration();
|
final var parsed = runtimeAsset.parsedDeclaration();
|
||||||
diagnostics.addAll(parsed.diagnostics());
|
diagnostics.addAll(parsed.diagnostics());
|
||||||
|
diagnostics.addAll(runtimeAsset.walkDiagnostics());
|
||||||
diagnostics.addAll(identityMismatchDiagnostics(registryEntry, parsed, assetManifestPath));
|
diagnostics.addAll(identityMismatchDiagnostics(registryEntry, parsed, assetManifestPath));
|
||||||
final var summary = buildSummary(project, assetRoot, registryEntry, parsed);
|
final var summary = buildSummary(project, assetRoot, registryEntry, parsed);
|
||||||
assets.add(summary);
|
assets.add(summary);
|
||||||
@ -220,13 +225,14 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
writeManifest(manifestPath, request, entry.assetUuid());
|
writeManifest(manifestPath, request, entry.assetUuid());
|
||||||
final PackerRegistryState updated = workspaceFoundation.appendAllocatedEntry(registry, entry);
|
final PackerRegistryState updated = workspaceFoundation.appendAllocatedEntry(registry, entry);
|
||||||
workspaceFoundation.saveRegistry(project, updated);
|
workspaceFoundation.saveRegistry(project, updated);
|
||||||
runtimeRegistry.update(project, (snapshot, generation) -> runtimePatchService.afterCreateAsset(
|
final var runtime = runtimeRegistry.update(project, (snapshot, generation) -> runtimePatchService.afterCreateAsset(
|
||||||
snapshot,
|
snapshot,
|
||||||
generation,
|
generation,
|
||||||
updated,
|
updated,
|
||||||
entry,
|
entry,
|
||||||
assetRoot,
|
assetRoot,
|
||||||
manifestPath));
|
manifestPath));
|
||||||
|
saveRuntimeCache(project, runtime.snapshot());
|
||||||
final CreateAssetResult result = new CreateAssetResult(
|
final CreateAssetResult result = new CreateAssetResult(
|
||||||
PackerOperationStatus.SUCCESS,
|
PackerOperationStatus.SUCCESS,
|
||||||
"Asset created: " + relativeAssetRoot,
|
"Asset created: " + relativeAssetRoot,
|
||||||
@ -270,12 +276,13 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
declaration.assetUuid());
|
declaration.assetUuid());
|
||||||
final PackerRegistryState updated = workspaceFoundation.appendAllocatedEntry(registry, entry);
|
final PackerRegistryState updated = workspaceFoundation.appendAllocatedEntry(registry, entry);
|
||||||
workspaceFoundation.saveRegistry(project, updated);
|
workspaceFoundation.saveRegistry(project, updated);
|
||||||
runtimeRegistry.update(project, (currentSnapshot, generation) -> runtimePatchService.afterRegisterAsset(
|
final var runtime = runtimeRegistry.update(project, (currentSnapshot, generation) -> runtimePatchService.afterRegisterAsset(
|
||||||
currentSnapshot,
|
currentSnapshot,
|
||||||
generation,
|
generation,
|
||||||
updated,
|
updated,
|
||||||
entry,
|
entry,
|
||||||
assetRoot));
|
assetRoot));
|
||||||
|
saveRuntimeCache(project, runtime.snapshot());
|
||||||
final RegisterAssetResult result = new RegisterAssetResult(
|
final RegisterAssetResult result = new RegisterAssetResult(
|
||||||
PackerOperationStatus.SUCCESS,
|
PackerOperationStatus.SUCCESS,
|
||||||
"Asset registered: " + relativeAssetRoot,
|
"Asset registered: " + relativeAssetRoot,
|
||||||
@ -316,11 +323,12 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
if (!updatedRegistry.equals(registry)) {
|
if (!updatedRegistry.equals(registry)) {
|
||||||
workspaceFoundation.saveRegistry(project, updatedRegistry);
|
workspaceFoundation.saveRegistry(project, updatedRegistry);
|
||||||
}
|
}
|
||||||
runtimeRegistry.update(project, (currentSnapshot, generation) -> runtimePatchService.afterDeleteAsset(
|
final var runtime = runtimeRegistry.update(project, (currentSnapshot, generation) -> runtimePatchService.afterDeleteAsset(
|
||||||
currentSnapshot,
|
currentSnapshot,
|
||||||
generation,
|
generation,
|
||||||
updatedRegistry,
|
updatedRegistry,
|
||||||
assetRoot));
|
assetRoot));
|
||||||
|
saveRuntimeCache(project, runtime.snapshot());
|
||||||
final DeleteAssetResult result = new DeleteAssetResult(
|
final DeleteAssetResult result = new DeleteAssetResult(
|
||||||
PackerOperationStatus.SUCCESS,
|
PackerOperationStatus.SUCCESS,
|
||||||
"Asset deleted: " + relativeAssetRoot,
|
"Asset deleted: " + relativeAssetRoot,
|
||||||
@ -372,7 +380,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
if (!updatedRegistry.equals(registry)) {
|
if (!updatedRegistry.equals(registry)) {
|
||||||
workspaceFoundation.saveRegistry(project, updatedRegistry);
|
workspaceFoundation.saveRegistry(project, updatedRegistry);
|
||||||
}
|
}
|
||||||
runtimeRegistry.update(project, (currentSnapshot, generation) -> runtimePatchService.afterMoveAsset(
|
final var runtime = runtimeRegistry.update(project, (currentSnapshot, generation) -> runtimePatchService.afterMoveAsset(
|
||||||
currentSnapshot,
|
currentSnapshot,
|
||||||
generation,
|
generation,
|
||||||
updatedRegistry,
|
updatedRegistry,
|
||||||
@ -380,6 +388,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
sourceRoot,
|
sourceRoot,
|
||||||
targetRoot,
|
targetRoot,
|
||||||
targetManifestPath));
|
targetManifestPath));
|
||||||
|
saveRuntimeCache(project, runtime.snapshot());
|
||||||
final AssetReference canonicalReference = updatedEntry
|
final AssetReference canonicalReference = updatedEntry
|
||||||
.map(packerRegistryEntry -> AssetReference.forAssetId(packerRegistryEntry.assetId()))
|
.map(packerRegistryEntry -> AssetReference.forAssetId(packerRegistryEntry.assetId()))
|
||||||
.orElseGet(() -> AssetReference.forRelativeAssetRoot(targetRelativeRoot));
|
.orElseGet(() -> AssetReference.forRelativeAssetRoot(targetRelativeRoot));
|
||||||
@ -558,6 +567,10 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
return PackerWorkspacePaths.relativeAssetRoot(project, assetRoot).replace('\\', '/');
|
return PackerWorkspacePaths.relativeAssetRoot(project, assetRoot).replace('\\', '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveRuntimeCache(PackerProjectContext project, PackerRuntimeSnapshot snapshot) {
|
||||||
|
cacheRepository.save(project, snapshot.cacheState());
|
||||||
|
}
|
||||||
|
|
||||||
private PackerRegistryState removeRegistryEntry(
|
private PackerRegistryState removeRegistryEntry(
|
||||||
PackerRegistryState registry,
|
PackerRegistryState registry,
|
||||||
PackerRegistryEntry entry) {
|
PackerRegistryEntry entry) {
|
||||||
@ -628,12 +641,13 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
try {
|
try {
|
||||||
patchManifestContract(manifest, request);
|
patchManifestContract(manifest, request);
|
||||||
mapper.writerWithDefaultPrettyPrinter().writeValue(manifestPath.toFile(), manifest);
|
mapper.writerWithDefaultPrettyPrinter().writeValue(manifestPath.toFile(), manifest);
|
||||||
runtimeRegistry.update(project, (currentSnapshot, generation) -> runtimePatchService.afterUpdateAssetContract(
|
final var runtime = runtimeRegistry.update(project, (currentSnapshot, generation) -> runtimePatchService.afterUpdateAssetContract(
|
||||||
currentSnapshot,
|
currentSnapshot,
|
||||||
generation,
|
generation,
|
||||||
assetRoot,
|
assetRoot,
|
||||||
manifestPath,
|
manifestPath,
|
||||||
evaluation.resolved().registryEntry()));
|
evaluation.resolved().registryEntry()));
|
||||||
|
saveRuntimeCache(project, runtime.snapshot());
|
||||||
return new UpdateAssetContractResponse(true, null);
|
return new UpdateAssetContractResponse(true, null);
|
||||||
} catch (IOException exception) {
|
} catch (IOException exception) {
|
||||||
return new UpdateAssetContractResponse(false, "Unable to update asset contract: " + exception.getMessage());
|
return new UpdateAssetContractResponse(false, "Unable to update asset contract: " + exception.getMessage());
|
||||||
|
|||||||
@ -42,6 +42,7 @@ public final class PackerAssetDetailsService {
|
|||||||
final var manifestPath = runtimeAsset.manifestPath();
|
final var manifestPath = runtimeAsset.manifestPath();
|
||||||
final var parsed = runtimeAsset.parsedDeclaration();
|
final var parsed = runtimeAsset.parsedDeclaration();
|
||||||
diagnostics.addAll(parsed.diagnostics());
|
diagnostics.addAll(parsed.diagnostics());
|
||||||
|
diagnostics.addAll(runtimeAsset.walkDiagnostics());
|
||||||
if (!parsed.valid()) {
|
if (!parsed.valid()) {
|
||||||
return failureResult(project, request.assetReference(), resolved, diagnostics);
|
return failureResult(project, request.assetReference(), resolved, diagnostics);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,21 @@
|
|||||||
package p.packer.services;
|
package p.packer.services;
|
||||||
|
|
||||||
import p.packer.models.*;
|
import p.packer.models.*;
|
||||||
|
import p.packer.repositories.PackerRuntimeAssetMaterializer;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public final class PackerRuntimePatchService {
|
public final class PackerRuntimePatchService {
|
||||||
private final PackerAssetDeclarationParser declarationParser;
|
private final PackerAssetDeclarationParser declarationParser;
|
||||||
|
private final PackerRuntimeAssetMaterializer assetMaterializer;
|
||||||
|
|
||||||
public PackerRuntimePatchService(PackerAssetDeclarationParser declarationParser) {
|
public PackerRuntimePatchService(
|
||||||
|
PackerAssetDeclarationParser declarationParser,
|
||||||
|
PackerRuntimeAssetMaterializer assetMaterializer) {
|
||||||
this.declarationParser = Objects.requireNonNull(declarationParser, "declarationParser");
|
this.declarationParser = Objects.requireNonNull(declarationParser, "declarationParser");
|
||||||
|
this.assetMaterializer = Objects.requireNonNull(assetMaterializer, "assetMaterializer");
|
||||||
}
|
}
|
||||||
|
|
||||||
public PackerRuntimeSnapshot afterCreateAsset(
|
public PackerRuntimeSnapshot afterCreateAsset(
|
||||||
@ -23,13 +29,19 @@ public final class PackerRuntimePatchService {
|
|||||||
final List<PackerRuntimeAsset> updatedAssets = new ArrayList<>(snapshot.assets().stream()
|
final List<PackerRuntimeAsset> updatedAssets = new ArrayList<>(snapshot.assets().stream()
|
||||||
.filter(candidate -> !candidate.assetRoot().equals(assetRoot.toAbsolutePath().normalize()))
|
.filter(candidate -> !candidate.assetRoot().equals(assetRoot.toAbsolutePath().normalize()))
|
||||||
.toList());
|
.toList());
|
||||||
updatedAssets.add(new PackerRuntimeAsset(
|
final var materialized = assetMaterializer.materialize(
|
||||||
assetRoot,
|
assetRoot,
|
||||||
manifestPath,
|
manifestPath,
|
||||||
Optional.of(entry),
|
Optional.of(entry),
|
||||||
parsed));
|
parsed,
|
||||||
|
snapshot.cacheState().findAsset(entry.assetId()));
|
||||||
|
updatedAssets.add(materialized.runtimeAsset());
|
||||||
updatedAssets.sort(Comparator.comparing(asset -> asset.assetRoot().toString(), String.CASE_INSENSITIVE_ORDER));
|
updatedAssets.sort(Comparator.comparing(asset -> asset.assetRoot().toString(), String.CASE_INSENSITIVE_ORDER));
|
||||||
return new PackerRuntimeSnapshot(generation, updatedRegistry, updatedAssets);
|
return new PackerRuntimeSnapshot(
|
||||||
|
generation,
|
||||||
|
updatedRegistry,
|
||||||
|
updatedAssets,
|
||||||
|
mergeCacheState(snapshot.cacheState(), updatedRegistry, materialized.assetCacheEntry()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public PackerRuntimeSnapshot afterRegisterAsset(
|
public PackerRuntimeSnapshot afterRegisterAsset(
|
||||||
@ -40,13 +52,17 @@ public final class PackerRuntimePatchService {
|
|||||||
Path assetRoot) {
|
Path assetRoot) {
|
||||||
final List<PackerRuntimeAsset> updatedAssets = new ArrayList<>();
|
final List<PackerRuntimeAsset> updatedAssets = new ArrayList<>();
|
||||||
boolean patched = false;
|
boolean patched = false;
|
||||||
|
Optional<PackerAssetCacheEntry> refreshedCacheEntry = Optional.empty();
|
||||||
for (PackerRuntimeAsset asset : snapshot.assets()) {
|
for (PackerRuntimeAsset asset : snapshot.assets()) {
|
||||||
if (asset.assetRoot().equals(assetRoot.toAbsolutePath().normalize())) {
|
if (asset.assetRoot().equals(assetRoot.toAbsolutePath().normalize())) {
|
||||||
updatedAssets.add(new PackerRuntimeAsset(
|
final var materialized = assetMaterializer.materialize(
|
||||||
asset.assetRoot(),
|
asset.assetRoot(),
|
||||||
asset.manifestPath(),
|
asset.manifestPath(),
|
||||||
Optional.of(entry),
|
Optional.of(entry),
|
||||||
asset.parsedDeclaration()));
|
asset.parsedDeclaration(),
|
||||||
|
snapshot.cacheState().findAsset(entry.assetId()));
|
||||||
|
updatedAssets.add(materialized.runtimeAsset());
|
||||||
|
refreshedCacheEntry = materialized.assetCacheEntry();
|
||||||
patched = true;
|
patched = true;
|
||||||
} else {
|
} else {
|
||||||
updatedAssets.add(asset);
|
updatedAssets.add(asset);
|
||||||
@ -55,7 +71,11 @@ public final class PackerRuntimePatchService {
|
|||||||
if (!patched) {
|
if (!patched) {
|
||||||
throw new IllegalStateException("Unable to patch runtime snapshot for unregistered asset: " + assetRoot);
|
throw new IllegalStateException("Unable to patch runtime snapshot for unregistered asset: " + assetRoot);
|
||||||
}
|
}
|
||||||
return new PackerRuntimeSnapshot(generation, updatedRegistry, updatedAssets);
|
return new PackerRuntimeSnapshot(
|
||||||
|
generation,
|
||||||
|
updatedRegistry,
|
||||||
|
updatedAssets,
|
||||||
|
mergeCacheState(snapshot.cacheState(), updatedRegistry, refreshedCacheEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
public PackerRuntimeSnapshot afterDeleteAsset(
|
public PackerRuntimeSnapshot afterDeleteAsset(
|
||||||
@ -66,7 +86,11 @@ public final class PackerRuntimePatchService {
|
|||||||
final List<PackerRuntimeAsset> updatedAssets = snapshot.assets().stream()
|
final List<PackerRuntimeAsset> updatedAssets = snapshot.assets().stream()
|
||||||
.filter(asset -> !asset.assetRoot().equals(assetRoot.toAbsolutePath().normalize()))
|
.filter(asset -> !asset.assetRoot().equals(assetRoot.toAbsolutePath().normalize()))
|
||||||
.toList();
|
.toList();
|
||||||
return new PackerRuntimeSnapshot(generation, updatedRegistry, updatedAssets);
|
return new PackerRuntimeSnapshot(
|
||||||
|
generation,
|
||||||
|
updatedRegistry,
|
||||||
|
updatedAssets,
|
||||||
|
pruneCacheState(snapshot.cacheState(), updatedRegistry));
|
||||||
}
|
}
|
||||||
|
|
||||||
public PackerRuntimeSnapshot afterMoveAsset(
|
public PackerRuntimeSnapshot afterMoveAsset(
|
||||||
@ -80,13 +104,17 @@ public final class PackerRuntimePatchService {
|
|||||||
final PackerAssetDeclarationParseResult parsed = declarationParser.parse(targetManifestPath);
|
final PackerAssetDeclarationParseResult parsed = declarationParser.parse(targetManifestPath);
|
||||||
final List<PackerRuntimeAsset> updatedAssets = new ArrayList<>();
|
final List<PackerRuntimeAsset> updatedAssets = new ArrayList<>();
|
||||||
boolean patched = false;
|
boolean patched = false;
|
||||||
|
Optional<PackerAssetCacheEntry> refreshedCacheEntry = Optional.empty();
|
||||||
for (PackerRuntimeAsset asset : snapshot.assets()) {
|
for (PackerRuntimeAsset asset : snapshot.assets()) {
|
||||||
if (asset.assetRoot().equals(sourceRoot.toAbsolutePath().normalize())) {
|
if (asset.assetRoot().equals(sourceRoot.toAbsolutePath().normalize())) {
|
||||||
updatedAssets.add(new PackerRuntimeAsset(
|
final var materialized = assetMaterializer.materialize(
|
||||||
targetRoot,
|
targetRoot,
|
||||||
targetManifestPath,
|
targetManifestPath,
|
||||||
updatedRegistryEntry,
|
updatedRegistryEntry,
|
||||||
parsed));
|
parsed,
|
||||||
|
updatedRegistryEntry.flatMap(entry -> snapshot.cacheState().findAsset(entry.assetId())));
|
||||||
|
updatedAssets.add(materialized.runtimeAsset());
|
||||||
|
refreshedCacheEntry = materialized.assetCacheEntry();
|
||||||
patched = true;
|
patched = true;
|
||||||
} else {
|
} else {
|
||||||
updatedAssets.add(asset);
|
updatedAssets.add(asset);
|
||||||
@ -96,7 +124,11 @@ public final class PackerRuntimePatchService {
|
|||||||
throw new IllegalStateException("Unable to patch runtime snapshot for moved asset: " + sourceRoot);
|
throw new IllegalStateException("Unable to patch runtime snapshot for moved asset: " + sourceRoot);
|
||||||
}
|
}
|
||||||
updatedAssets.sort(Comparator.comparing(asset -> asset.assetRoot().toString(), String.CASE_INSENSITIVE_ORDER));
|
updatedAssets.sort(Comparator.comparing(asset -> asset.assetRoot().toString(), String.CASE_INSENSITIVE_ORDER));
|
||||||
return new PackerRuntimeSnapshot(generation, updatedRegistry, updatedAssets);
|
return new PackerRuntimeSnapshot(
|
||||||
|
generation,
|
||||||
|
updatedRegistry,
|
||||||
|
updatedAssets,
|
||||||
|
mergeCacheState(snapshot.cacheState(), updatedRegistry, refreshedCacheEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
public PackerRuntimeSnapshot afterUpdateAssetContract(
|
public PackerRuntimeSnapshot afterUpdateAssetContract(
|
||||||
@ -108,26 +140,69 @@ public final class PackerRuntimePatchService {
|
|||||||
final PackerAssetDeclarationParseResult parsed = declarationParser.parse(manifestPath);
|
final PackerAssetDeclarationParseResult parsed = declarationParser.parse(manifestPath);
|
||||||
final List<PackerRuntimeAsset> updatedAssets = new ArrayList<>();
|
final List<PackerRuntimeAsset> updatedAssets = new ArrayList<>();
|
||||||
boolean patched = false;
|
boolean patched = false;
|
||||||
|
Optional<PackerAssetCacheEntry> refreshedCacheEntry = Optional.empty();
|
||||||
for (PackerRuntimeAsset asset : snapshot.assets()) {
|
for (PackerRuntimeAsset asset : snapshot.assets()) {
|
||||||
if (asset.assetRoot().equals(assetRoot.toAbsolutePath().normalize())) {
|
if (asset.assetRoot().equals(assetRoot.toAbsolutePath().normalize())) {
|
||||||
updatedAssets.add(new PackerRuntimeAsset(
|
final var materialized = assetMaterializer.materialize(
|
||||||
asset.assetRoot(),
|
asset.assetRoot(),
|
||||||
asset.manifestPath(),
|
asset.manifestPath(),
|
||||||
asset.registryEntry(),
|
asset.registryEntry(),
|
||||||
parsed));
|
parsed,
|
||||||
|
asset.registryEntry().flatMap(entry -> snapshot.cacheState().findAsset(entry.assetId())));
|
||||||
|
updatedAssets.add(materialized.runtimeAsset());
|
||||||
|
refreshedCacheEntry = materialized.assetCacheEntry();
|
||||||
patched = true;
|
patched = true;
|
||||||
} else {
|
} else {
|
||||||
updatedAssets.add(asset);
|
updatedAssets.add(asset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!patched) {
|
if (!patched) {
|
||||||
updatedAssets.add(new PackerRuntimeAsset(
|
final var materialized = assetMaterializer.materialize(
|
||||||
assetRoot,
|
assetRoot,
|
||||||
manifestPath,
|
manifestPath,
|
||||||
registryEntry,
|
registryEntry,
|
||||||
parsed));
|
parsed,
|
||||||
|
registryEntry.flatMap(entry -> snapshot.cacheState().findAsset(entry.assetId())));
|
||||||
|
updatedAssets.add(materialized.runtimeAsset());
|
||||||
|
refreshedCacheEntry = materialized.assetCacheEntry();
|
||||||
updatedAssets.sort(Comparator.comparing(asset -> asset.assetRoot().toString(), String.CASE_INSENSITIVE_ORDER));
|
updatedAssets.sort(Comparator.comparing(asset -> asset.assetRoot().toString(), String.CASE_INSENSITIVE_ORDER));
|
||||||
}
|
}
|
||||||
return new PackerRuntimeSnapshot(generation, snapshot.registry(), updatedAssets);
|
return new PackerRuntimeSnapshot(
|
||||||
|
generation,
|
||||||
|
snapshot.registry(),
|
||||||
|
updatedAssets,
|
||||||
|
mergeCacheState(snapshot.cacheState(), snapshot.registry(), refreshedCacheEntry));
|
||||||
|
}
|
||||||
|
|
||||||
|
private PackerWorkspaceCacheState mergeCacheState(
|
||||||
|
PackerWorkspaceCacheState currentCacheState,
|
||||||
|
PackerRegistryState registry,
|
||||||
|
Optional<PackerAssetCacheEntry> refreshedCacheEntry) {
|
||||||
|
final Map<Integer, PackerAssetCacheEntry> byAssetId = new LinkedHashMap<>();
|
||||||
|
currentCacheState.assets().forEach(entry -> byAssetId.put(entry.assetId(), entry));
|
||||||
|
refreshedCacheEntry.ifPresent(entry -> byAssetId.put(entry.assetId(), entry));
|
||||||
|
return pruneCacheEntries(byAssetId, registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PackerWorkspaceCacheState pruneCacheState(
|
||||||
|
PackerWorkspaceCacheState currentCacheState,
|
||||||
|
PackerRegistryState registry) {
|
||||||
|
final Map<Integer, PackerAssetCacheEntry> byAssetId = new LinkedHashMap<>();
|
||||||
|
currentCacheState.assets().forEach(entry -> byAssetId.put(entry.assetId(), entry));
|
||||||
|
return pruneCacheEntries(byAssetId, registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PackerWorkspaceCacheState pruneCacheEntries(
|
||||||
|
Map<Integer, PackerAssetCacheEntry> byAssetId,
|
||||||
|
PackerRegistryState registry) {
|
||||||
|
final Set<Integer> activeAssetIds = registry.assets().stream()
|
||||||
|
.map(PackerRegistryEntry::assetId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
return new PackerWorkspaceCacheState(
|
||||||
|
PackerWorkspaceCacheState.CURRENT_SCHEMA_VERSION,
|
||||||
|
byAssetId.values().stream()
|
||||||
|
.filter(entry -> activeAssetIds.contains(entry.assetId()))
|
||||||
|
.sorted(Comparator.comparingInt(PackerAssetCacheEntry::assetId))
|
||||||
|
.toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,9 @@ import p.packer.events.PackerEvent;
|
|||||||
import p.packer.events.PackerEventKind;
|
import p.packer.events.PackerEventKind;
|
||||||
import p.packer.messages.*;
|
import p.packer.messages.*;
|
||||||
import p.packer.messages.assets.*;
|
import p.packer.messages.assets.*;
|
||||||
|
import p.packer.repositories.FileSystemPackerCacheRepository;
|
||||||
import p.packer.repositories.PackerAssetWalker;
|
import p.packer.repositories.PackerAssetWalker;
|
||||||
|
import p.packer.repositories.PackerRuntimeAssetMaterializer;
|
||||||
import p.packer.repositories.PackerRuntimeLoader;
|
import p.packer.repositories.PackerRuntimeLoader;
|
||||||
import p.packer.repositories.PackerRuntimeRegistry;
|
import p.packer.repositories.PackerRuntimeRegistry;
|
||||||
import p.packer.repositories.PackerRuntimeSnapshotLoader;
|
import p.packer.repositories.PackerRuntimeSnapshotLoader;
|
||||||
@ -138,7 +140,8 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
assertEquals(PackerAssetState.REGISTERED, detailsResult.details().summary().state());
|
assertEquals(PackerAssetState.REGISTERED, detailsResult.details().summary().state());
|
||||||
assertEquals("new_atlas", detailsResult.details().summary().identity().assetName());
|
assertEquals("new_atlas", detailsResult.details().summary().identity().assetName());
|
||||||
assertNotNull(detailsResult.details().summary().identity().assetUuid());
|
assertNotNull(detailsResult.details().summary().identity().assetUuid());
|
||||||
assertTrue(detailsResult.diagnostics().isEmpty());
|
assertTrue(detailsResult.diagnostics().stream().noneMatch(diagnostic -> diagnostic.blocking()));
|
||||||
|
assertTrue(detailsResult.diagnostics().stream().anyMatch(diagnostic -> diagnostic.message().contains("Output metadata for tile bank cannot be empty")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -679,11 +682,14 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
final var mapper = new ObjectMapper();
|
final var mapper = new ObjectMapper();
|
||||||
final var foundation = new p.packer.services.PackerWorkspaceFoundation(mapper);
|
final var foundation = new p.packer.services.PackerWorkspaceFoundation(mapper);
|
||||||
final var parser = new p.packer.services.PackerAssetDeclarationParser(mapper);
|
final var parser = new p.packer.services.PackerAssetDeclarationParser(mapper);
|
||||||
|
final var assetWalker = new PackerAssetWalker(mapper);
|
||||||
|
final var cacheRepository = new FileSystemPackerCacheRepository(mapper);
|
||||||
|
final var assetMaterializer = new PackerRuntimeAssetMaterializer(assetWalker);
|
||||||
final var runtimeRegistry = new PackerRuntimeRegistry(loader);
|
final var runtimeRegistry = new PackerRuntimeRegistry(loader);
|
||||||
final var resolver = new p.packer.services.PackerAssetReferenceResolver(foundation.lookup());
|
final var resolver = new p.packer.services.PackerAssetReferenceResolver(foundation.lookup());
|
||||||
final var detailsService = new p.packer.services.PackerAssetDetailsService(runtimeRegistry, resolver);
|
final var detailsService = new p.packer.services.PackerAssetDetailsService(runtimeRegistry, resolver);
|
||||||
final var actionReadService = new p.packer.services.PackerAssetActionReadService(runtimeRegistry, resolver, foundation.lookup());
|
final var actionReadService = new p.packer.services.PackerAssetActionReadService(runtimeRegistry, resolver, foundation.lookup());
|
||||||
final var runtimePatchService = new p.packer.services.PackerRuntimePatchService(parser);
|
final var runtimePatchService = new p.packer.services.PackerRuntimePatchService(parser, assetMaterializer);
|
||||||
final var writeCoordinator = new p.packer.services.PackerProjectWriteCoordinator();
|
final var writeCoordinator = new p.packer.services.PackerProjectWriteCoordinator();
|
||||||
return new FileSystemPackerWorkspaceService(
|
return new FileSystemPackerWorkspaceService(
|
||||||
new ObjectMapper(),
|
new ObjectMapper(),
|
||||||
@ -692,6 +698,7 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
actionReadService,
|
actionReadService,
|
||||||
runtimePatchService,
|
runtimePatchService,
|
||||||
runtimeRegistry,
|
runtimeRegistry,
|
||||||
|
cacheRepository,
|
||||||
writeCoordinator,
|
writeCoordinator,
|
||||||
eventSink);
|
eventSink);
|
||||||
}
|
}
|
||||||
@ -701,7 +708,9 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
final var foundation = new p.packer.services.PackerWorkspaceFoundation(mapper);
|
final var foundation = new p.packer.services.PackerWorkspaceFoundation(mapper);
|
||||||
final var parser = new p.packer.services.PackerAssetDeclarationParser(mapper);
|
final var parser = new p.packer.services.PackerAssetDeclarationParser(mapper);
|
||||||
final var assetWalker = new PackerAssetWalker(mapper);
|
final var assetWalker = new PackerAssetWalker(mapper);
|
||||||
return new CountingLoader(new PackerRuntimeLoader(foundation, parser, assetWalker));
|
final var cacheRepository = new FileSystemPackerCacheRepository(mapper);
|
||||||
|
final var assetMaterializer = new PackerRuntimeAssetMaterializer(assetWalker);
|
||||||
|
return new CountingLoader(new PackerRuntimeLoader(foundation, parser, cacheRepository, assetMaterializer));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class CountingLoader implements PackerRuntimeSnapshotLoader {
|
private static final class CountingLoader implements PackerRuntimeSnapshotLoader {
|
||||||
|
|||||||
@ -11,7 +11,9 @@ import p.packer.messages.PackerProjectContext;
|
|||||||
import p.packer.messages.assets.OutputCodecCatalog;
|
import p.packer.messages.assets.OutputCodecCatalog;
|
||||||
import p.packer.messages.assets.PackerAssetState;
|
import p.packer.messages.assets.PackerAssetState;
|
||||||
import p.packer.messages.assets.PackerBuildParticipation;
|
import p.packer.messages.assets.PackerBuildParticipation;
|
||||||
|
import p.packer.repositories.FileSystemPackerCacheRepository;
|
||||||
import p.packer.repositories.PackerAssetWalker;
|
import p.packer.repositories.PackerAssetWalker;
|
||||||
|
import p.packer.repositories.PackerRuntimeAssetMaterializer;
|
||||||
import p.packer.repositories.PackerRuntimeLoader;
|
import p.packer.repositories.PackerRuntimeLoader;
|
||||||
import p.packer.repositories.PackerRuntimeRegistry;
|
import p.packer.repositories.PackerRuntimeRegistry;
|
||||||
import p.packer.testing.PackerFixtureLocator;
|
import p.packer.testing.PackerFixtureLocator;
|
||||||
@ -43,7 +45,8 @@ final class PackerAssetDetailsServiceTest {
|
|||||||
assertEquals("TILES/indexed_v1", result.details().outputFormat().displayName());
|
assertEquals("TILES/indexed_v1", result.details().outputFormat().displayName());
|
||||||
assertEquals(List.of(OutputCodecCatalog.NONE), result.details().availableOutputCodecs());
|
assertEquals(List.of(OutputCodecCatalog.NONE), result.details().availableOutputCodecs());
|
||||||
assertEquals(List.of(), result.details().codecConfigurationFieldsByCodec().get(OutputCodecCatalog.NONE));
|
assertEquals(List.of(), result.details().codecConfigurationFieldsByCodec().get(OutputCodecCatalog.NONE));
|
||||||
assertTrue(result.diagnostics().isEmpty());
|
assertTrue(result.diagnostics().stream().noneMatch(diagnostic -> diagnostic.blocking()));
|
||||||
|
assertTrue(result.diagnostics().stream().anyMatch(diagnostic -> diagnostic.message().contains("Output metadata for tile bank cannot be empty")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -137,7 +140,13 @@ final class PackerAssetDetailsServiceTest {
|
|||||||
final var foundation = new PackerWorkspaceFoundation(mapper);
|
final var foundation = new PackerWorkspaceFoundation(mapper);
|
||||||
final var parser = new PackerAssetDeclarationParser(mapper);
|
final var parser = new PackerAssetDeclarationParser(mapper);
|
||||||
final var assetWalker = new PackerAssetWalker(mapper);
|
final var assetWalker = new PackerAssetWalker(mapper);
|
||||||
final var runtimeRegistry = new PackerRuntimeRegistry(new PackerRuntimeLoader(foundation, parser, assetWalker));
|
final var cacheRepository = new FileSystemPackerCacheRepository(mapper);
|
||||||
|
final var assetMaterializer = new PackerRuntimeAssetMaterializer(assetWalker);
|
||||||
|
final var runtimeRegistry = new PackerRuntimeRegistry(new PackerRuntimeLoader(
|
||||||
|
foundation,
|
||||||
|
parser,
|
||||||
|
cacheRepository,
|
||||||
|
assetMaterializer));
|
||||||
final var resolver = new PackerAssetReferenceResolver(foundation.lookup());
|
final var resolver = new PackerAssetReferenceResolver(foundation.lookup());
|
||||||
return new PackerAssetDetailsService(runtimeRegistry, resolver);
|
return new PackerAssetDetailsService(runtimeRegistry, resolver);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,80 @@
|
|||||||
|
package p.packer.services;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
import p.packer.messages.PackerProjectContext;
|
||||||
|
import p.packer.repositories.FileSystemPackerCacheRepository;
|
||||||
|
import p.packer.repositories.PackerAssetWalker;
|
||||||
|
import p.packer.repositories.PackerRuntimeAssetMaterializer;
|
||||||
|
import p.packer.repositories.PackerRuntimeLoader;
|
||||||
|
import p.packer.testing.PackerFixtureLocator;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
final class PackerRuntimePatchServiceTest {
|
||||||
|
@TempDir
|
||||||
|
Path tempDir;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void afterUpdateAssetContractRefreshesOneAssetProjectionAndCacheState() throws Exception {
|
||||||
|
final ObjectMapper mapper = new ObjectMapper();
|
||||||
|
final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("managed"));
|
||||||
|
writeTilePng(projectRoot.resolve("assets/ui/atlas/tile.png"));
|
||||||
|
final var foundation = new PackerWorkspaceFoundation(mapper);
|
||||||
|
final var parser = new PackerAssetDeclarationParser(mapper);
|
||||||
|
final var assetWalker = new PackerAssetWalker(mapper);
|
||||||
|
final var cacheRepository = new FileSystemPackerCacheRepository(mapper);
|
||||||
|
final var assetMaterializer = new PackerRuntimeAssetMaterializer(assetWalker);
|
||||||
|
final var loader = new PackerRuntimeLoader(foundation, parser, cacheRepository, assetMaterializer);
|
||||||
|
final var patchService = new PackerRuntimePatchService(parser, assetMaterializer);
|
||||||
|
final var project = new PackerProjectContext("main", projectRoot);
|
||||||
|
|
||||||
|
final var initialSnapshot = loader.load(project, 1L);
|
||||||
|
final var registryEntry = initialSnapshot.registry().assets().getFirst();
|
||||||
|
final var updatedSnapshot = patchService.afterUpdateAssetContract(
|
||||||
|
initialSnapshot,
|
||||||
|
2L,
|
||||||
|
projectRoot.resolve("assets/ui/atlas"),
|
||||||
|
projectRoot.resolve("assets/ui/atlas/asset.json"),
|
||||||
|
Optional.of(registryEntry));
|
||||||
|
|
||||||
|
assertTrue(updatedSnapshot.cacheState().findAsset(registryEntry.assetId()).isPresent());
|
||||||
|
assertEquals(1, updatedSnapshot.assets().getFirst().walkProjection().buildCandidateFiles().size());
|
||||||
|
assertEquals("tile.png", updatedSnapshot.assets().getFirst().walkProjection().buildCandidateFiles().getFirst().relativePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path copyFixture(String relativePath, Path targetRoot) throws Exception {
|
||||||
|
final Path sourceRoot = PackerFixtureLocator.fixtureRoot(relativePath);
|
||||||
|
try (var stream = Files.walk(sourceRoot)) {
|
||||||
|
for (Path source : stream.sorted(Comparator.naturalOrder()).toList()) {
|
||||||
|
final Path target = targetRoot.resolve(sourceRoot.relativize(source).toString());
|
||||||
|
if (Files.isDirectory(source)) {
|
||||||
|
Files.createDirectories(target);
|
||||||
|
} else {
|
||||||
|
Files.createDirectories(target.getParent());
|
||||||
|
Files.copy(source, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return targetRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeTilePng(Path path) throws Exception {
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
final BufferedImage image = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
for (int y = 0; y < 16; y += 1) {
|
||||||
|
for (int x = 0; x < 16; x += 1) {
|
||||||
|
image.setRGB(x, y, 0xFFFF0000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImageIO.write(image, "png", path.toFile());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,15 +3,21 @@ package p.packer.services;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
import p.packer.PackerWorkspacePaths;
|
||||||
import p.packer.messages.PackerProjectContext;
|
import p.packer.messages.PackerProjectContext;
|
||||||
|
import p.packer.repositories.FileSystemPackerCacheRepository;
|
||||||
import p.packer.repositories.PackerAssetWalker;
|
import p.packer.repositories.PackerAssetWalker;
|
||||||
|
import p.packer.repositories.PackerRuntimeAssetMaterializer;
|
||||||
import p.packer.repositories.PackerRuntimeLoader;
|
import p.packer.repositories.PackerRuntimeLoader;
|
||||||
import p.packer.repositories.PackerRuntimeRegistry;
|
import p.packer.repositories.PackerRuntimeRegistry;
|
||||||
import p.packer.testing.PackerFixtureLocator;
|
import p.packer.testing.PackerFixtureLocator;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
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 static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
@ -66,6 +72,24 @@ final class PackerRuntimeRegistryTest {
|
|||||||
assertEquals(2, refreshed.snapshot().assets().size());
|
assertEquals(2, refreshed.snapshot().assets().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void runtimeSnapshotRetainsWalkProjectionAndPersistsCacheForRegisteredAssets() throws Exception {
|
||||||
|
final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("cache"));
|
||||||
|
writeTilePng(projectRoot.resolve("assets/ui/atlas/tile.png"));
|
||||||
|
final PackerRuntimeRegistry registry = runtimeRegistry();
|
||||||
|
final PackerProjectContext project = project(projectRoot);
|
||||||
|
|
||||||
|
final PackerProjectRuntime runtime = registry.getOrLoad(project);
|
||||||
|
|
||||||
|
assertTrue(Files.isRegularFile(PackerWorkspacePaths.cachePath(project)));
|
||||||
|
assertTrue(runtime.snapshot().cacheState().findAsset(1).isPresent());
|
||||||
|
final var runtimeAsset = runtime.snapshot().assets().getFirst();
|
||||||
|
assertEquals(List.of("tile.png"), runtimeAsset.walkProjection().availableFiles());
|
||||||
|
assertEquals(1, runtimeAsset.walkProjection().buildCandidateFiles().size());
|
||||||
|
assertEquals("tile.png", runtimeAsset.walkProjection().buildCandidateFiles().getFirst().relativePath());
|
||||||
|
assertTrue(runtimeAsset.walkProjection().measuredBankSizeBytes() > 0L);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void disposeMarksRuntimeInactiveAndRemovesItFromRegistry() throws Exception {
|
void disposeMarksRuntimeInactiveAndRemovesItFromRegistry() throws Exception {
|
||||||
final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("dispose"));
|
final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("dispose"));
|
||||||
@ -85,7 +109,13 @@ final class PackerRuntimeRegistryTest {
|
|||||||
final var foundation = new PackerWorkspaceFoundation(mapper);
|
final var foundation = new PackerWorkspaceFoundation(mapper);
|
||||||
final var parser = new PackerAssetDeclarationParser(mapper);
|
final var parser = new PackerAssetDeclarationParser(mapper);
|
||||||
final var assetWalker = new PackerAssetWalker(mapper);
|
final var assetWalker = new PackerAssetWalker(mapper);
|
||||||
return new PackerRuntimeRegistry(new PackerRuntimeLoader(foundation, parser, assetWalker));
|
final var cacheRepository = new FileSystemPackerCacheRepository(mapper);
|
||||||
|
final var assetMaterializer = new PackerRuntimeAssetMaterializer(assetWalker);
|
||||||
|
return new PackerRuntimeRegistry(new PackerRuntimeLoader(
|
||||||
|
foundation,
|
||||||
|
parser,
|
||||||
|
cacheRepository,
|
||||||
|
assetMaterializer));
|
||||||
}
|
}
|
||||||
|
|
||||||
private PackerProjectContext project(Path root) {
|
private PackerProjectContext project(Path root) {
|
||||||
@ -107,4 +137,15 @@ final class PackerRuntimeRegistryTest {
|
|||||||
}
|
}
|
||||||
return targetRoot;
|
return targetRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeTilePng(Path path) throws Exception {
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
final BufferedImage image = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
for (int y = 0; y < 16; y += 1) {
|
||||||
|
for (int x = 0; x < 16; x += 1) {
|
||||||
|
image.setRGB(x, y, 0xFFFF0000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImageIO.write(image, "png", path.toFile());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user