implements PR-10a bank composition details dto projection
This commit is contained in:
parent
1c17562cc9
commit
49d83e3ff8
@ -15,6 +15,7 @@ public record PackerAssetDetailsDTO(
|
||||
List<OutputCodecCatalog> availableOutputCodecs,
|
||||
Map<OutputCodecCatalog, List<PackerCodecConfigurationFieldDTO>> codecConfigurationFieldsByCodec,
|
||||
List<PackerCodecConfigurationFieldDTO> metadataFields,
|
||||
PackerBankCompositionDetailsDTO bankComposition,
|
||||
Map<String, List<Path>> inputsByRole,
|
||||
List<PackerDiagnosticDTO> diagnostics) {
|
||||
|
||||
@ -25,6 +26,7 @@ public record PackerAssetDetailsDTO(
|
||||
availableOutputCodecs = List.copyOf(Objects.requireNonNull(availableOutputCodecs, "availableOutputCodecs"));
|
||||
codecConfigurationFieldsByCodec = Map.copyOf(Objects.requireNonNull(codecConfigurationFieldsByCodec, "codecConfigurationFieldsByCodec"));
|
||||
metadataFields = List.copyOf(Objects.requireNonNull(metadataFields, "metadataFields"));
|
||||
bankComposition = Objects.requireNonNull(bankComposition, "bankComposition");
|
||||
inputsByRole = Map.copyOf(Objects.requireNonNull(inputsByRole, "inputsByRole"));
|
||||
diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics"));
|
||||
}
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
package p.packer.dtos;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public record PackerBankCompositionDetailsDTO(
|
||||
List<PackerBankCompositionFileDTO> availableFiles,
|
||||
List<PackerBankCompositionFileDTO> selectedFiles,
|
||||
long measuredBankSizeBytes) {
|
||||
|
||||
public PackerBankCompositionDetailsDTO {
|
||||
availableFiles = List.copyOf(Objects.requireNonNull(availableFiles, "availableFiles"));
|
||||
selectedFiles = List.copyOf(Objects.requireNonNull(selectedFiles, "selectedFiles"));
|
||||
if (measuredBankSizeBytes < 0L) {
|
||||
throw new IllegalArgumentException("measuredBankSizeBytes must be non-negative");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package p.packer.dtos;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public record PackerBankCompositionFileDTO(
|
||||
String path,
|
||||
String displayName,
|
||||
long size,
|
||||
long lastModified,
|
||||
String fingerprint,
|
||||
Map<String, Object> metadata) {
|
||||
|
||||
public PackerBankCompositionFileDTO {
|
||||
path = Objects.requireNonNull(path, "path").trim();
|
||||
displayName = Objects.requireNonNull(displayName, "displayName").trim();
|
||||
if (path.isBlank()) {
|
||||
throw new IllegalArgumentException("path must not be blank");
|
||||
}
|
||||
if (displayName.isBlank()) {
|
||||
throw new IllegalArgumentException("displayName must not be blank");
|
||||
}
|
||||
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")));
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,7 @@ public record PackerAssetDetails(
|
||||
List<OutputCodecCatalog> availableOutputCodecs,
|
||||
Map<OutputCodecCatalog, List<PackerCodecConfigurationField>> codecConfigurationFieldsByCodec,
|
||||
List<PackerCodecConfigurationField> metadataFields,
|
||||
PackerBankCompositionDetails bankComposition,
|
||||
Map<String, List<Path>> inputsByRole,
|
||||
List<PackerDiagnostic> diagnostics) {
|
||||
|
||||
@ -25,6 +26,7 @@ public record PackerAssetDetails(
|
||||
availableOutputCodecs = List.copyOf(Objects.requireNonNull(availableOutputCodecs, "availableOutputCodecs"));
|
||||
codecConfigurationFieldsByCodec = Map.copyOf(Objects.requireNonNull(codecConfigurationFieldsByCodec, "codecConfigurationFieldsByCodec"));
|
||||
metadataFields = List.copyOf(Objects.requireNonNull(metadataFields, "metadataFields"));
|
||||
bankComposition = Objects.requireNonNull(bankComposition, "bankComposition");
|
||||
inputsByRole = Map.copyOf(Objects.requireNonNull(inputsByRole, "inputsByRole"));
|
||||
diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics"));
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
package p.packer.models;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public record PackerBankCompositionDetails(
|
||||
List<PackerBankCompositionFile> availableFiles,
|
||||
List<PackerBankCompositionFile> selectedFiles,
|
||||
long measuredBankSizeBytes) {
|
||||
|
||||
public static final PackerBankCompositionDetails EMPTY = new PackerBankCompositionDetails(List.of(), List.of(), 0L);
|
||||
|
||||
public PackerBankCompositionDetails {
|
||||
availableFiles = List.copyOf(Objects.requireNonNull(availableFiles, "availableFiles"));
|
||||
selectedFiles = List.copyOf(Objects.requireNonNull(selectedFiles, "selectedFiles"));
|
||||
if (measuredBankSizeBytes < 0L) {
|
||||
throw new IllegalArgumentException("measuredBankSizeBytes must be non-negative");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package p.packer.models;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public record PackerBankCompositionFile(
|
||||
String path,
|
||||
String displayName,
|
||||
long size,
|
||||
long lastModified,
|
||||
String fingerprint,
|
||||
Map<String, Object> metadata) {
|
||||
|
||||
public PackerBankCompositionFile {
|
||||
path = Objects.requireNonNull(path, "path").trim();
|
||||
displayName = Objects.requireNonNull(displayName, "displayName").trim();
|
||||
if (path.isBlank()) {
|
||||
throw new IllegalArgumentException("path must not be blank");
|
||||
}
|
||||
if (displayName.isBlank()) {
|
||||
throw new IllegalArgumentException("displayName must not be blank");
|
||||
}
|
||||
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")));
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,7 @@ import p.packer.messages.diagnostics.PackerDiagnosticSeverity;
|
||||
import p.packer.models.*;
|
||||
import p.packer.repositories.PackerRuntimeRegistry;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
@ -77,6 +78,7 @@ public final class PackerAssetDetailsService {
|
||||
outputContract.availableCodecs(),
|
||||
outputContract.codecConfigurationFieldsByCodec(),
|
||||
metadataFields(outputContract.metadataFields(), declaration.outputMetadata()),
|
||||
resolveBankCompositionDetails(runtimeAsset, declaration),
|
||||
resolveInputs(resolved.assetRoot(), declaration.inputsByRole()),
|
||||
diagnostics);
|
||||
return new GetAssetDetailsResult(
|
||||
@ -116,6 +118,7 @@ public final class PackerAssetDetailsService {
|
||||
List.of(OutputCodecCatalog.NONE),
|
||||
Map.of(OutputCodecCatalog.NONE, List.of()),
|
||||
List.of(),
|
||||
PackerBankCompositionDetails.EMPTY,
|
||||
Map.of(),
|
||||
diagnostics);
|
||||
return new GetAssetDetailsResult(
|
||||
@ -135,6 +138,72 @@ public final class PackerAssetDetailsService {
|
||||
return Map.copyOf(resolved);
|
||||
}
|
||||
|
||||
private PackerBankCompositionDetails resolveBankCompositionDetails(
|
||||
final PackerRuntimeAsset runtimeAsset,
|
||||
final PackerAssetDeclaration declaration) {
|
||||
final var walkProjection = runtimeAsset.walkProjection();
|
||||
final Map<String, PackerRuntimeWalkFile> walkFilesByPath = new LinkedHashMap<>();
|
||||
walkProjection.buildCandidateFiles().forEach(file -> walkFilesByPath.put(file.relativePath(), file));
|
||||
|
||||
final List<PackerBankCompositionFile> availableFiles = walkProjection.buildCandidateFiles().stream()
|
||||
.filter(file -> file.diagnostics().stream().noneMatch(PackerDiagnostic::blocking))
|
||||
.map(this::toBankCompositionFile)
|
||||
.toList();
|
||||
|
||||
final List<PackerBankCompositionFile> selectedFiles = flattenSelectedInputPaths(declaration.inputsByRole()).stream()
|
||||
.map(path -> resolveSelectedBankFile(runtimeAsset.assetRoot(), path, walkFilesByPath))
|
||||
.flatMap(Optional::stream)
|
||||
.toList();
|
||||
|
||||
return new PackerBankCompositionDetails(
|
||||
availableFiles,
|
||||
selectedFiles,
|
||||
walkProjection.measuredBankSizeBytes());
|
||||
}
|
||||
|
||||
private List<String> flattenSelectedInputPaths(Map<String, List<String>> inputsByRole) {
|
||||
final List<String> selected = new ArrayList<>();
|
||||
inputsByRole.values().forEach(selected::addAll);
|
||||
return List.copyOf(selected);
|
||||
}
|
||||
|
||||
private Optional<PackerBankCompositionFile> resolveSelectedBankFile(
|
||||
Path assetRoot,
|
||||
String relativePath,
|
||||
Map<String, PackerRuntimeWalkFile> walkFilesByPath) {
|
||||
final PackerRuntimeWalkFile runtimeWalkFile = walkFilesByPath.get(relativePath);
|
||||
if (runtimeWalkFile != null) {
|
||||
return Optional.of(toBankCompositionFile(runtimeWalkFile));
|
||||
}
|
||||
|
||||
final Path filePath = assetRoot.resolve(relativePath).toAbsolutePath().normalize();
|
||||
if (!Files.isRegularFile(filePath)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
try {
|
||||
return Optional.of(new PackerBankCompositionFile(
|
||||
relativePath,
|
||||
filePath.getFileName().toString(),
|
||||
Files.size(filePath),
|
||||
Files.getLastModifiedTime(filePath).toMillis(),
|
||||
null,
|
||||
Map.of()));
|
||||
} catch (Exception exception) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private PackerBankCompositionFile toBankCompositionFile(PackerRuntimeWalkFile file) {
|
||||
return new PackerBankCompositionFile(
|
||||
file.relativePath(),
|
||||
Path.of(file.relativePath()).getFileName().toString(),
|
||||
file.size(),
|
||||
file.lastModified(),
|
||||
file.fingerprint(),
|
||||
file.metadata());
|
||||
}
|
||||
|
||||
private List<PackerCodecConfigurationField> metadataFields(
|
||||
List<PackerCodecConfigurationField> definitions,
|
||||
Map<String, String> outputMetadata) {
|
||||
|
||||
@ -31,10 +31,28 @@ public final class PackerReadMessageMapper {
|
||||
details.availableOutputCodecs(),
|
||||
toCodecConfigurationFieldsByCodecDTO(details.codecConfigurationFieldsByCodec()),
|
||||
toCodecConfigurationFieldDTOs(details.metadataFields()),
|
||||
toBankCompositionDetailsDTO(details.bankComposition()),
|
||||
details.inputsByRole(),
|
||||
toDiagnosticDTOs(details.diagnostics()));
|
||||
}
|
||||
|
||||
private static PackerBankCompositionDetailsDTO toBankCompositionDetailsDTO(PackerBankCompositionDetails details) {
|
||||
return new PackerBankCompositionDetailsDTO(
|
||||
details.availableFiles().stream().map(PackerReadMessageMapper::toBankCompositionFileDTO).toList(),
|
||||
details.selectedFiles().stream().map(PackerReadMessageMapper::toBankCompositionFileDTO).toList(),
|
||||
details.measuredBankSizeBytes());
|
||||
}
|
||||
|
||||
private static PackerBankCompositionFileDTO toBankCompositionFileDTO(PackerBankCompositionFile file) {
|
||||
return new PackerBankCompositionFileDTO(
|
||||
file.path(),
|
||||
file.displayName(),
|
||||
file.size(),
|
||||
file.lastModified(),
|
||||
file.fingerprint(),
|
||||
file.metadata());
|
||||
}
|
||||
|
||||
public static List<PackerAssetSummaryDTO> toAssetSummaryDTOs(List<PackerAssetSummary> summaries) {
|
||||
return summaries.stream().map(PackerReadMessageMapper::toAssetSummaryDTO).toList();
|
||||
}
|
||||
|
||||
@ -18,6 +18,8 @@ import p.packer.repositories.PackerRuntimeLoader;
|
||||
import p.packer.repositories.PackerRuntimeRegistry;
|
||||
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;
|
||||
@ -45,10 +47,39 @@ final class PackerAssetDetailsServiceTest {
|
||||
assertEquals("TILES/indexed_v1", result.details().outputFormat().displayName());
|
||||
assertEquals(List.of(OutputCodecCatalog.NONE), result.details().availableOutputCodecs());
|
||||
assertEquals(List.of(), result.details().codecConfigurationFieldsByCodec().get(OutputCodecCatalog.NONE));
|
||||
assertNotNull(result.details().bankComposition());
|
||||
assertTrue(result.details().bankComposition().selectedFiles().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
|
||||
void projectsBankCompositionAvailableAndSelectedFiles() throws Exception {
|
||||
final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("managed-bank-composition"));
|
||||
final Path assetRoot = projectRoot.resolve("assets/ui/atlas");
|
||||
final BufferedImage tile = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
|
||||
ImageIO.write(tile, "png", assetRoot.resolve("confirm.png").toFile());
|
||||
ImageIO.write(tile, "png", assetRoot.resolve("cancel.png").toFile());
|
||||
final Path manifestPath = assetRoot.resolve("asset.json");
|
||||
|
||||
final ObjectMapper mapper = new ObjectMapper();
|
||||
final ObjectNode manifest = (ObjectNode) mapper.readTree(manifestPath.toFile());
|
||||
final ObjectNode inputs = manifest.putObject("inputs");
|
||||
inputs.putArray("sprites").add("confirm.png");
|
||||
mapper.writerWithDefaultPrettyPrinter().writeValue(manifestPath.toFile(), manifest);
|
||||
|
||||
final PackerAssetDetailsService service = service();
|
||||
final var result = service.getAssetDetails(new GetAssetDetailsRequest(project(projectRoot), AssetReference.forAssetId(1)));
|
||||
|
||||
assertEquals(PackerOperationStatus.SUCCESS, result.status());
|
||||
assertTrue(result.details().bankComposition().availableFiles().stream()
|
||||
.anyMatch(file -> file.path().equals("confirm.png")));
|
||||
assertTrue(result.details().bankComposition().selectedFiles().stream()
|
||||
.anyMatch(file -> file.path().equals("confirm.png")));
|
||||
assertTrue(result.details().bankComposition().availableFiles().stream()
|
||||
.allMatch(file -> !file.displayName().isBlank()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnsUnregisteredDetailsForValidUnregisteredRootReference() throws Exception {
|
||||
final Path projectRoot = copyFixture("workspaces/orphan-valid", tempDir.resolve("orphan"));
|
||||
|
||||
@ -18,6 +18,8 @@ import p.studio.utilities.i18n.I18n;
|
||||
import p.studio.workspaces.assets.details.contract.AssetDetailsContractControl;
|
||||
import p.studio.workspaces.assets.details.summary.AssetDetailsSummaryControl;
|
||||
import p.studio.workspaces.assets.messages.AssetWorkspaceAssetAction;
|
||||
import p.studio.workspaces.assets.messages.AssetWorkspaceBankCompositionDetails;
|
||||
import p.studio.workspaces.assets.messages.AssetWorkspaceBankCompositionFile;
|
||||
import p.studio.workspaces.assets.messages.AssetWorkspaceAssetDetails;
|
||||
import p.studio.workspaces.assets.messages.AssetWorkspaceDetailsStatus;
|
||||
import p.studio.workspaces.assets.messages.AssetWorkspaceDetailsViewState;
|
||||
@ -417,6 +419,24 @@ public final class AssetDetailsControl extends VBox implements StudioEventAware
|
||||
details.availableOutputCodecs(),
|
||||
details.codecConfigurationFieldsByCodec(),
|
||||
details.metadataFields(),
|
||||
mapBankComposition(details.bankComposition()),
|
||||
Map.copyOf(details.inputsByRole()));
|
||||
}
|
||||
|
||||
private AssetWorkspaceBankCompositionDetails mapBankComposition(p.packer.dtos.PackerBankCompositionDetailsDTO details) {
|
||||
return new AssetWorkspaceBankCompositionDetails(
|
||||
details.availableFiles().stream().map(this::mapBankCompositionFile).toList(),
|
||||
details.selectedFiles().stream().map(this::mapBankCompositionFile).toList(),
|
||||
details.measuredBankSizeBytes());
|
||||
}
|
||||
|
||||
private AssetWorkspaceBankCompositionFile mapBankCompositionFile(p.packer.dtos.PackerBankCompositionFileDTO file) {
|
||||
return new AssetWorkspaceBankCompositionFile(
|
||||
file.path(),
|
||||
file.displayName(),
|
||||
file.size(),
|
||||
file.lastModified(),
|
||||
file.fingerprint(),
|
||||
file.metadata());
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ public record AssetWorkspaceAssetDetails(
|
||||
List<OutputCodecCatalog> availableOutputCodecs,
|
||||
Map<OutputCodecCatalog, List<PackerCodecConfigurationFieldDTO>> codecConfigurationFieldsByCodec,
|
||||
List<PackerCodecConfigurationFieldDTO> metadataFields,
|
||||
AssetWorkspaceBankCompositionDetails bankComposition,
|
||||
Map<String, List<Path>> inputsByRole) {
|
||||
|
||||
public AssetWorkspaceAssetDetails {
|
||||
@ -27,6 +28,7 @@ public record AssetWorkspaceAssetDetails(
|
||||
availableOutputCodecs = List.copyOf(Objects.requireNonNull(availableOutputCodecs, "availableOutputCodecs"));
|
||||
codecConfigurationFieldsByCodec = Map.copyOf(Objects.requireNonNull(codecConfigurationFieldsByCodec, "codecConfigurationFieldsByCodec"));
|
||||
metadataFields = List.copyOf(Objects.requireNonNull(metadataFields, "metadataFields"));
|
||||
bankComposition = Objects.requireNonNull(bankComposition, "bankComposition");
|
||||
inputsByRole = Map.copyOf(Objects.requireNonNull(inputsByRole, "inputsByRole"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
package p.studio.workspaces.assets.messages;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public record AssetWorkspaceBankCompositionDetails(
|
||||
List<AssetWorkspaceBankCompositionFile> availableFiles,
|
||||
List<AssetWorkspaceBankCompositionFile> selectedFiles,
|
||||
long measuredBankSizeBytes) {
|
||||
|
||||
public static final AssetWorkspaceBankCompositionDetails EMPTY =
|
||||
new AssetWorkspaceBankCompositionDetails(List.of(), List.of(), 0L);
|
||||
|
||||
public AssetWorkspaceBankCompositionDetails {
|
||||
availableFiles = List.copyOf(Objects.requireNonNull(availableFiles, "availableFiles"));
|
||||
selectedFiles = List.copyOf(Objects.requireNonNull(selectedFiles, "selectedFiles"));
|
||||
if (measuredBankSizeBytes < 0L) {
|
||||
throw new IllegalArgumentException("measuredBankSizeBytes must be non-negative");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package p.studio.workspaces.assets.messages;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public record AssetWorkspaceBankCompositionFile(
|
||||
String path,
|
||||
String displayName,
|
||||
long size,
|
||||
long lastModified,
|
||||
String fingerprint,
|
||||
Map<String, Object> metadata) {
|
||||
|
||||
public AssetWorkspaceBankCompositionFile {
|
||||
path = Objects.requireNonNull(path, "path").trim();
|
||||
displayName = Objects.requireNonNull(displayName, "displayName").trim();
|
||||
if (path.isBlank()) {
|
||||
throw new IllegalArgumentException("path must not be blank");
|
||||
}
|
||||
if (displayName.isBlank()) {
|
||||
throw new IllegalArgumentException("displayName must not be blank");
|
||||
}
|
||||
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")));
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user