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