implements packer PR-02 workspace registry foundation
This commit is contained in:
parent
f0cc439b84
commit
42e7331d62
@ -0,0 +1,118 @@
|
|||||||
|
package p.packer.foundation;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import p.packer.api.PackerProjectContext;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public final class FileSystemPackerRegistryRepository implements PackerRegistryRepository {
|
||||||
|
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||||
|
private static final int REGISTRY_SCHEMA_VERSION = 1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PackerRegistryState load(PackerProjectContext project) {
|
||||||
|
final Path registryPath = PackerWorkspacePaths.registryPath(project);
|
||||||
|
if (!Files.isRegularFile(registryPath)) {
|
||||||
|
return emptyState();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final RegistryDocument document = MAPPER.readValue(registryPath.toFile(), RegistryDocument.class);
|
||||||
|
final int schemaVersion = document.schemaVersion <= 0 ? REGISTRY_SCHEMA_VERSION : document.schemaVersion;
|
||||||
|
final List<PackerRegistryEntry> entries = new ArrayList<>();
|
||||||
|
if (document.assets != null) {
|
||||||
|
for (RegistryAssetDocument asset : document.assets) {
|
||||||
|
if (asset == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
entries.add(new PackerRegistryEntry(asset.assetId, asset.assetUuid, normalizeRoot(asset.root)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
validateEntries(entries);
|
||||||
|
final int nextAssetId = document.nextAssetId > 0
|
||||||
|
? document.nextAssetId
|
||||||
|
: entries.stream().mapToInt(PackerRegistryEntry::assetId).max().orElse(0) + 1;
|
||||||
|
return new PackerRegistryState(
|
||||||
|
schemaVersion,
|
||||||
|
nextAssetId,
|
||||||
|
entries.stream().sorted(Comparator.comparingInt(PackerRegistryEntry::assetId)).toList());
|
||||||
|
} catch (IOException exception) {
|
||||||
|
throw new PackerRegistryException("Unable to load registry: " + registryPath, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(PackerProjectContext project, PackerRegistryState state) {
|
||||||
|
final Path registryDirectory = PackerWorkspacePaths.registryDirectory(project);
|
||||||
|
final Path registryPath = PackerWorkspacePaths.registryPath(project);
|
||||||
|
validateEntries(state.assets());
|
||||||
|
try {
|
||||||
|
Files.createDirectories(registryDirectory);
|
||||||
|
final RegistryDocument document = new RegistryDocument();
|
||||||
|
document.schemaVersion = state.schemaVersion();
|
||||||
|
document.nextAssetId = state.nextAssetId();
|
||||||
|
document.assets = state.assets().stream()
|
||||||
|
.map(entry -> new RegistryAssetDocument(entry.assetId(), entry.assetUuid(), entry.root()))
|
||||||
|
.toList();
|
||||||
|
MAPPER.writerWithDefaultPrettyPrinter().writeValue(registryPath.toFile(), document);
|
||||||
|
} catch (IOException exception) {
|
||||||
|
throw new PackerRegistryException("Unable to save registry: " + registryPath, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PackerRegistryState emptyState() {
|
||||||
|
return new PackerRegistryState(REGISTRY_SCHEMA_VERSION, 1, List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateEntries(List<PackerRegistryEntry> entries) {
|
||||||
|
final Set<Integer> assetIds = new HashSet<>();
|
||||||
|
final Set<String> assetUuids = new HashSet<>();
|
||||||
|
final Set<String> roots = new HashSet<>();
|
||||||
|
for (PackerRegistryEntry entry : entries) {
|
||||||
|
if (!assetIds.add(entry.assetId())) {
|
||||||
|
throw new PackerRegistryException("Duplicate asset_id in registry: " + entry.assetId());
|
||||||
|
}
|
||||||
|
if (!assetUuids.add(entry.assetUuid())) {
|
||||||
|
throw new PackerRegistryException("Duplicate asset_uuid in registry: " + entry.assetUuid());
|
||||||
|
}
|
||||||
|
if (!roots.add(entry.root())) {
|
||||||
|
throw new PackerRegistryException("Duplicate asset root in registry: " + entry.root());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeRoot(String root) {
|
||||||
|
if (root == null || root.isBlank()) {
|
||||||
|
throw new PackerRegistryException("Registry asset root must not be blank");
|
||||||
|
}
|
||||||
|
return root.trim().replace('\\', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
private static final class RegistryDocument {
|
||||||
|
@JsonProperty("schema_version")
|
||||||
|
public int schemaVersion;
|
||||||
|
|
||||||
|
@JsonProperty("next_asset_id")
|
||||||
|
public int nextAssetId;
|
||||||
|
|
||||||
|
@JsonProperty("assets")
|
||||||
|
public List<RegistryAssetDocument> assets = List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
private record RegistryAssetDocument(
|
||||||
|
@JsonProperty("asset_id") int assetId,
|
||||||
|
@JsonProperty("asset_uuid") String assetUuid,
|
||||||
|
@JsonProperty("root") String root) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
package p.packer.foundation;
|
||||||
|
|
||||||
|
import p.packer.api.PackerProjectContext;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public final class PackerIdentityAllocator {
|
||||||
|
public PackerRegistryEntry allocate(
|
||||||
|
PackerProjectContext project,
|
||||||
|
PackerRegistryState state,
|
||||||
|
Path assetRoot) {
|
||||||
|
Objects.requireNonNull(project, "project");
|
||||||
|
Objects.requireNonNull(state, "state");
|
||||||
|
final Path normalizedAssetRoot = Objects.requireNonNull(assetRoot, "assetRoot").toAbsolutePath().normalize();
|
||||||
|
final String relativeRoot = PackerWorkspacePaths.relativeAssetRoot(project, normalizedAssetRoot);
|
||||||
|
final boolean alreadyRegistered = state.assets().stream().anyMatch(entry -> entry.root().equals(relativeRoot));
|
||||||
|
if (alreadyRegistered) {
|
||||||
|
throw new PackerRegistryException("Asset root is already registered: " + relativeRoot);
|
||||||
|
}
|
||||||
|
return new PackerRegistryEntry(state.nextAssetId(), UUID.randomUUID().toString(), relativeRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackerRegistryState append(PackerRegistryState state, PackerRegistryEntry entry) {
|
||||||
|
Objects.requireNonNull(state, "state");
|
||||||
|
Objects.requireNonNull(entry, "entry");
|
||||||
|
final List<PackerRegistryEntry> updated = state.assets().stream()
|
||||||
|
.collect(java.util.stream.Collectors.toCollection(java.util.ArrayList::new));
|
||||||
|
updated.add(entry);
|
||||||
|
updated.sort(Comparator.comparingInt(PackerRegistryEntry::assetId));
|
||||||
|
return new PackerRegistryState(state.schemaVersion(), entry.assetId() + 1, updated);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package p.packer.foundation;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public record PackerRegistryEntry(
|
||||||
|
int assetId,
|
||||||
|
String assetUuid,
|
||||||
|
String root) {
|
||||||
|
|
||||||
|
public PackerRegistryEntry {
|
||||||
|
assetUuid = Objects.requireNonNull(assetUuid, "assetUuid").trim();
|
||||||
|
root = Objects.requireNonNull(root, "root").trim();
|
||||||
|
if (assetId <= 0) {
|
||||||
|
throw new IllegalArgumentException("assetId must be positive");
|
||||||
|
}
|
||||||
|
if (assetUuid.isBlank() || root.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("assetUuid and root must not be blank");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package p.packer.foundation;
|
||||||
|
|
||||||
|
public final class PackerRegistryException extends RuntimeException {
|
||||||
|
public PackerRegistryException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackerRegistryException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
package p.packer.foundation;
|
||||||
|
|
||||||
|
import p.packer.api.PackerProjectContext;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public final class PackerRegistryLookup {
|
||||||
|
public Optional<PackerRegistryEntry> findByAssetId(PackerRegistryState state, int assetId) {
|
||||||
|
Objects.requireNonNull(state, "state");
|
||||||
|
return state.assets().stream().filter(entry -> entry.assetId() == assetId).findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<PackerRegistryEntry> findByAssetUuid(PackerRegistryState state, String assetUuid) {
|
||||||
|
Objects.requireNonNull(state, "state");
|
||||||
|
final String normalized = Objects.requireNonNull(assetUuid, "assetUuid").trim();
|
||||||
|
return state.assets().stream().filter(entry -> entry.assetUuid().equals(normalized)).findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<PackerRegistryEntry> findByRoot(PackerProjectContext project, PackerRegistryState state, Path assetRoot) {
|
||||||
|
Objects.requireNonNull(project, "project");
|
||||||
|
Objects.requireNonNull(state, "state");
|
||||||
|
final String relativeRoot = PackerWorkspacePaths.relativeAssetRoot(project, Objects.requireNonNull(assetRoot, "assetRoot"));
|
||||||
|
return state.assets().stream().filter(entry -> entry.root().equals(relativeRoot)).findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path resolveExistingRoot(PackerProjectContext project, PackerRegistryEntry entry) {
|
||||||
|
Objects.requireNonNull(project, "project");
|
||||||
|
Objects.requireNonNull(entry, "entry");
|
||||||
|
final Path assetRoot = PackerWorkspacePaths.assetRoot(project, entry.root());
|
||||||
|
if (!Files.isDirectory(assetRoot)) {
|
||||||
|
throw new PackerRegistryException("Registered asset root does not exist: " + entry.root());
|
||||||
|
}
|
||||||
|
return assetRoot;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package p.packer.foundation;
|
||||||
|
|
||||||
|
import p.packer.api.PackerProjectContext;
|
||||||
|
|
||||||
|
public interface PackerRegistryRepository {
|
||||||
|
PackerRegistryState load(PackerProjectContext project);
|
||||||
|
|
||||||
|
void save(PackerProjectContext project, PackerRegistryState state);
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
package p.packer.foundation;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public record PackerRegistryState(
|
||||||
|
int schemaVersion,
|
||||||
|
int nextAssetId,
|
||||||
|
List<PackerRegistryEntry> assets) {
|
||||||
|
|
||||||
|
public PackerRegistryState {
|
||||||
|
if (schemaVersion <= 0) {
|
||||||
|
throw new IllegalArgumentException("schemaVersion must be positive");
|
||||||
|
}
|
||||||
|
if (nextAssetId <= 0) {
|
||||||
|
throw new IllegalArgumentException("nextAssetId must be positive");
|
||||||
|
}
|
||||||
|
assets = List.copyOf(Objects.requireNonNull(assets, "assets"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackerRegistryState withAssets(List<PackerRegistryEntry> entries, int nextId) {
|
||||||
|
return new PackerRegistryState(
|
||||||
|
schemaVersion,
|
||||||
|
nextId,
|
||||||
|
entries.stream()
|
||||||
|
.sorted(Comparator.comparingInt(PackerRegistryEntry::assetId))
|
||||||
|
.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
package p.packer.foundation;
|
||||||
|
|
||||||
|
import p.packer.api.PackerOperationStatus;
|
||||||
|
import p.packer.api.PackerProjectContext;
|
||||||
|
import p.packer.api.workspace.InitWorkspaceRequest;
|
||||||
|
import p.packer.api.workspace.InitWorkspaceResult;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public final class PackerWorkspaceFoundation {
|
||||||
|
private final PackerRegistryRepository registryRepository;
|
||||||
|
private final PackerIdentityAllocator identityAllocator;
|
||||||
|
private final PackerRegistryLookup registryLookup;
|
||||||
|
|
||||||
|
public PackerWorkspaceFoundation() {
|
||||||
|
this(new FileSystemPackerRegistryRepository(), new PackerIdentityAllocator(), new PackerRegistryLookup());
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackerWorkspaceFoundation(
|
||||||
|
PackerRegistryRepository registryRepository,
|
||||||
|
PackerIdentityAllocator identityAllocator,
|
||||||
|
PackerRegistryLookup registryLookup) {
|
||||||
|
this.registryRepository = Objects.requireNonNull(registryRepository, "registryRepository");
|
||||||
|
this.identityAllocator = Objects.requireNonNull(identityAllocator, "identityAllocator");
|
||||||
|
this.registryLookup = Objects.requireNonNull(registryLookup, "registryLookup");
|
||||||
|
}
|
||||||
|
|
||||||
|
public InitWorkspaceResult initWorkspace(InitWorkspaceRequest request) {
|
||||||
|
final PackerProjectContext project = Objects.requireNonNull(request, "request").project();
|
||||||
|
try {
|
||||||
|
Files.createDirectories(PackerWorkspacePaths.assetsRoot(project));
|
||||||
|
Files.createDirectories(PackerWorkspacePaths.registryDirectory(project));
|
||||||
|
final PackerRegistryState registryState = registryRepository.load(project);
|
||||||
|
registryRepository.save(project, registryState);
|
||||||
|
return new InitWorkspaceResult(
|
||||||
|
PackerOperationStatus.SUCCESS,
|
||||||
|
"Workspace initialized for packer control.",
|
||||||
|
PackerWorkspacePaths.registryPath(project),
|
||||||
|
List.of());
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new PackerRegistryException("Unable to initialize workspace for " + project.projectId(), exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackerRegistryState loadRegistry(PackerProjectContext project) {
|
||||||
|
return registryRepository.load(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveRegistry(PackerProjectContext project, PackerRegistryState state) {
|
||||||
|
registryRepository.save(project, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackerRegistryEntry allocateIdentity(PackerProjectContext project, PackerRegistryState state, java.nio.file.Path assetRoot) {
|
||||||
|
return identityAllocator.allocate(project, state, assetRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackerRegistryState appendAllocatedEntry(PackerRegistryState state, PackerRegistryEntry entry) {
|
||||||
|
return identityAllocator.append(state, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackerRegistryLookup lookup() {
|
||||||
|
return registryLookup;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package p.packer.foundation;
|
||||||
|
|
||||||
|
import p.packer.api.PackerProjectContext;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public final class PackerWorkspacePaths {
|
||||||
|
private static final String ASSETS_DIR = "assets";
|
||||||
|
private static final String PROMETEU_DIR = ".prometeu";
|
||||||
|
private static final String REGISTRY_FILE = "index.json";
|
||||||
|
|
||||||
|
private PackerWorkspacePaths() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Path assetsRoot(PackerProjectContext project) {
|
||||||
|
return Objects.requireNonNull(project, "project").rootPath().resolve(ASSETS_DIR).toAbsolutePath().normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Path registryDirectory(PackerProjectContext project) {
|
||||||
|
return assetsRoot(project).resolve(PROMETEU_DIR).toAbsolutePath().normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Path registryPath(PackerProjectContext project) {
|
||||||
|
return registryDirectory(project).resolve(REGISTRY_FILE).toAbsolutePath().normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Path assetRoot(PackerProjectContext project, String relativeRoot) {
|
||||||
|
return assetsRoot(project).resolve(relativeRoot).toAbsolutePath().normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String relativeAssetRoot(PackerProjectContext project, Path assetRoot) {
|
||||||
|
return assetsRoot(project).relativize(assetRoot.toAbsolutePath().normalize()).toString().replace('\\', '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
package p.packer.foundation;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
import p.packer.api.PackerProjectContext;
|
||||||
|
import p.packer.api.workspace.InitWorkspaceRequest;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
final class PackerWorkspaceFoundationTest {
|
||||||
|
@TempDir
|
||||||
|
Path tempDir;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void initWorkspaceCreatesAssetsControlStructureAndRegistry() throws Exception {
|
||||||
|
final PackerWorkspaceFoundation foundation = new PackerWorkspaceFoundation();
|
||||||
|
final PackerProjectContext project = project(tempDir.resolve("main"));
|
||||||
|
|
||||||
|
final var result = foundation.initWorkspace(new InitWorkspaceRequest(project));
|
||||||
|
|
||||||
|
assertEquals(Path.of("assets/.prometeu/index.json"), project.rootPath().relativize(result.registryPath()));
|
||||||
|
assertTrue(Files.isDirectory(project.rootPath().resolve("assets")));
|
||||||
|
assertTrue(Files.isDirectory(project.rootPath().resolve("assets/.prometeu")));
|
||||||
|
assertTrue(Files.isRegularFile(project.rootPath().resolve("assets/.prometeu/index.json")));
|
||||||
|
final String registryJson = Files.readString(project.rootPath().resolve("assets/.prometeu/index.json"));
|
||||||
|
assertTrue(registryJson.contains("\"schema_version\""));
|
||||||
|
assertTrue(registryJson.contains("\"next_asset_id\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void registryRoundTripPreservesAllocatorAndEntries() throws Exception {
|
||||||
|
final Path projectRoot = tempDir.resolve("main");
|
||||||
|
final PackerWorkspaceFoundation foundation = new PackerWorkspaceFoundation();
|
||||||
|
final PackerProjectContext project = project(projectRoot);
|
||||||
|
foundation.initWorkspace(new InitWorkspaceRequest(project));
|
||||||
|
|
||||||
|
final PackerRegistryState state = new PackerRegistryState(
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
java.util.List.of(
|
||||||
|
new PackerRegistryEntry(1, "uuid-1", "ui/atlas"),
|
||||||
|
new PackerRegistryEntry(2, "uuid-2", "audio/ui_sounds")));
|
||||||
|
foundation.saveRegistry(project, state);
|
||||||
|
|
||||||
|
final PackerRegistryState reloaded = foundation.loadRegistry(project);
|
||||||
|
|
||||||
|
assertEquals(1, reloaded.schemaVersion());
|
||||||
|
assertEquals(3, reloaded.nextAssetId());
|
||||||
|
assertEquals(2, reloaded.assets().size());
|
||||||
|
assertEquals("audio/ui_sounds", reloaded.assets().get(1).root());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void allocatorIsMonotonicAndPersistedAcrossSaveLoad() throws Exception {
|
||||||
|
final Path projectRoot = tempDir.resolve("main");
|
||||||
|
final PackerWorkspaceFoundation foundation = new PackerWorkspaceFoundation();
|
||||||
|
final PackerProjectContext project = project(projectRoot);
|
||||||
|
foundation.initWorkspace(new InitWorkspaceRequest(project));
|
||||||
|
Files.createDirectories(projectRoot.resolve("assets/ui/atlas"));
|
||||||
|
|
||||||
|
final PackerRegistryEntry entry = foundation.allocateIdentity(project, foundation.loadRegistry(project), projectRoot.resolve("assets/ui/atlas"));
|
||||||
|
final PackerRegistryState updated = foundation.appendAllocatedEntry(foundation.loadRegistry(project), entry);
|
||||||
|
foundation.saveRegistry(project, updated);
|
||||||
|
|
||||||
|
final PackerRegistryState reloaded = foundation.loadRegistry(project);
|
||||||
|
|
||||||
|
assertEquals(2, reloaded.nextAssetId());
|
||||||
|
assertEquals(1, reloaded.assets().size());
|
||||||
|
assertEquals(1, reloaded.assets().getFirst().assetId());
|
||||||
|
assertEquals("ui/atlas", reloaded.assets().getFirst().root());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void duplicateRootsFailClearly() throws Exception {
|
||||||
|
final Path projectRoot = tempDir.resolve("main");
|
||||||
|
Files.createDirectories(projectRoot.resolve("assets/.prometeu"));
|
||||||
|
Files.writeString(projectRoot.resolve("assets/.prometeu/index.json"), """
|
||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"next_asset_id": 3,
|
||||||
|
"assets": [
|
||||||
|
{ "asset_id": 1, "asset_uuid": "uuid-1", "root": "ui/atlas" },
|
||||||
|
{ "asset_id": 2, "asset_uuid": "uuid-2", "root": "ui/atlas" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
final FileSystemPackerRegistryRepository repository = new FileSystemPackerRegistryRepository();
|
||||||
|
|
||||||
|
final PackerRegistryException exception = assertThrows(PackerRegistryException.class, () -> repository.load(project(projectRoot)));
|
||||||
|
|
||||||
|
assertTrue(exception.getMessage().contains("Duplicate asset root"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void malformedRegistryFailsClearly() throws Exception {
|
||||||
|
final Path projectRoot = tempDir.resolve("main");
|
||||||
|
Files.createDirectories(projectRoot.resolve("assets/.prometeu"));
|
||||||
|
Files.writeString(projectRoot.resolve("assets/.prometeu/index.json"), "{ nope ");
|
||||||
|
final FileSystemPackerRegistryRepository repository = new FileSystemPackerRegistryRepository();
|
||||||
|
|
||||||
|
final PackerRegistryException exception = assertThrows(PackerRegistryException.class, () -> repository.load(project(projectRoot)));
|
||||||
|
|
||||||
|
assertTrue(exception.getMessage().contains("Unable to load registry"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void lookupResolvesByIdUuidAndRootAndFailsOnMissingRoot() throws Exception {
|
||||||
|
final Path projectRoot = tempDir.resolve("main");
|
||||||
|
final PackerWorkspaceFoundation foundation = new PackerWorkspaceFoundation();
|
||||||
|
final PackerProjectContext project = project(projectRoot);
|
||||||
|
foundation.initWorkspace(new InitWorkspaceRequest(project));
|
||||||
|
Files.createDirectories(projectRoot.resolve("assets/ui/atlas"));
|
||||||
|
final PackerRegistryState state = new PackerRegistryState(
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
java.util.List.of(new PackerRegistryEntry(1, "uuid-1", "ui/atlas")));
|
||||||
|
|
||||||
|
final PackerRegistryLookup lookup = foundation.lookup();
|
||||||
|
|
||||||
|
assertTrue(lookup.findByAssetId(state, 1).isPresent());
|
||||||
|
assertTrue(lookup.findByAssetUuid(state, "uuid-1").isPresent());
|
||||||
|
assertTrue(lookup.findByRoot(project, state, projectRoot.resolve("assets/ui/atlas")).isPresent());
|
||||||
|
assertEquals(projectRoot.resolve("assets/ui/atlas").toAbsolutePath().normalize(), lookup.resolveExistingRoot(project, state.assets().getFirst()));
|
||||||
|
|
||||||
|
Files.delete(projectRoot.resolve("assets/ui/atlas"));
|
||||||
|
final PackerRegistryException exception = assertThrows(PackerRegistryException.class, () -> lookup.resolveExistingRoot(project, state.assets().getFirst()));
|
||||||
|
assertTrue(exception.getMessage().contains("does not exist"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private PackerProjectContext project(Path root) {
|
||||||
|
return new PackerProjectContext("main", root);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user