some refactor and expanded tables functionality

This commit is contained in:
bQUARKz 2026-02-26 06:23:37 +00:00
parent 9170104a12
commit 47a077bffc
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
15 changed files with 322 additions and 166 deletions

View File

@ -25,7 +25,7 @@ public class BuildingIssueSink extends ReadOnlyCollection<BuildingIssue> {
return this; return this;
} }
public BuildingIssueSink report(final BuildingIssueSink issues) { public BuildingIssueSink merge(final BuildingIssueSink issues) {
hasErrors |= issues.hasErrors(); hasErrors |= issues.hasErrors();
collection.addAll(issues.collection); collection.addAll(issues.collection);
return this; return this;

View File

@ -3,11 +3,13 @@ package p.studio.compiler.source.tables;
import p.studio.compiler.source.identifiers.SourceIdentifier; import p.studio.compiler.source.identifiers.SourceIdentifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
public abstract class DenseTable<IDENTIFIER extends SourceIdentifier, VALUE> { public abstract class DenseTable<IDENTIFIER extends SourceIdentifier, VALUE>
implements DenseTableReader<IDENTIFIER, VALUE>, DenseTableWriter<IDENTIFIER, VALUE> {
private final List<VALUE> values = new ArrayList<>(); private final List<VALUE> values = new ArrayList<>();
private final Function<Integer, IDENTIFIER> identifierGenerator; private final Function<Integer, IDENTIFIER> identifierGenerator;
@ -15,19 +17,65 @@ public abstract class DenseTable<IDENTIFIER extends SourceIdentifier, VALUE> {
this.identifierGenerator = Objects.requireNonNull(identifierGenerator); this.identifierGenerator = Objects.requireNonNull(identifierGenerator);
} }
@Override
public final int size() { return values.size(); } public final int size() { return values.size(); }
public final VALUE get(IDENTIFIER id) { @Override
return values.get(id.getIndex()); public final VALUE get(final IDENTIFIER identifier) {
return values.get(identifier.getIndex());
} }
public IDENTIFIER register(VALUE value) { @Override
public IDENTIFIER register(final VALUE value) {
final int idx = values.size(); final int idx = values.size();
values.add(value); values.add(value);
return identifierGenerator.apply(idx); return identifierGenerator.apply(idx);
} }
protected void clear() { @Override
public void clear() {
values.clear(); values.clear();
} }
@Override
public Iterable<IDENTIFIER> identifiers() {
return () -> new Iterator<>() {
private int current = 0;
@Override
public boolean hasNext() {
return current < values.size();
}
@Override
public IDENTIFIER next() {
return identifierGenerator.apply(current++);
}
};
}
@Override
public Iterable<VALUE> values() {
return () -> new Iterator<>() {
private int current = 0;
@Override
public boolean hasNext() {
return current < values.size();
}
@Override
public VALUE next() {
final var identifier = identifierGenerator.apply(current++);
return get(identifier);
}
};
}
@Override
public Iterator<IDENTIFIER> iterator() {
return identifiers().iterator();
}
} }

View File

@ -0,0 +1,10 @@
package p.studio.compiler.source.tables;
import p.studio.compiler.source.identifiers.SourceIdentifier;
public interface DenseTableReader<IDENTIFIER extends SourceIdentifier, VALUE> extends Iterable<IDENTIFIER> {
int size();
VALUE get(IDENTIFIER identifier);
Iterable<IDENTIFIER> identifiers();
Iterable<VALUE> values();
}

View File

@ -0,0 +1,8 @@
package p.studio.compiler.source.tables;
import p.studio.compiler.source.identifiers.SourceIdentifier;
public interface DenseTableWriter<IDENTIFIER extends SourceIdentifier, VALUE> {
IDENTIFIER register(VALUE value);
void clear();
}

View File

@ -8,7 +8,7 @@ import p.studio.utilities.structures.ReadOnlyList;
import java.util.*; import java.util.*;
public class FileTable extends InternTable<FileId, SourceHandle> { public class FileTable extends InternTable<FileId, SourceHandle> implements FileTableReader {
private final Map<ProjectId, Set<FileId>> projectFiles = new HashMap<>(); private final Map<ProjectId, Set<FileId>> projectFiles = new HashMap<>();
@ -23,6 +23,7 @@ public class FileTable extends InternTable<FileId, SourceHandle> {
return fileId; return fileId;
} }
@Override
public ReadOnlyList<FileId> getFiles(final ProjectId projectId) { public ReadOnlyList<FileId> getFiles(final ProjectId projectId) {
final var fileIds = projectFiles.get(projectId); final var fileIds = projectFiles.get(projectId);
if (CollectionUtils.isEmpty(fileIds)) { if (CollectionUtils.isEmpty(fileIds)) {

View File

@ -0,0 +1,10 @@
package p.studio.compiler.source.tables;
import p.studio.compiler.models.SourceHandle;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.source.identifiers.ProjectId;
import p.studio.utilities.structures.ReadOnlyList;
public interface FileTableReader extends DenseTableReader<FileId, SourceHandle> {
ReadOnlyList<FileId> getFiles(ProjectId projectId);
}

View File

@ -8,11 +8,12 @@ import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
public abstract class InternTable<IDENTIFIER extends SourceIdentifier, VALUE> public abstract class InternTable<IDENTIFIER extends SourceIdentifier, VALUE>
extends DenseTable<IDENTIFIER, VALUE> { extends DenseTable<IDENTIFIER, VALUE>
implements InternTableReader<IDENTIFIER, VALUE> {
private final Map<VALUE, IDENTIFIER> identifierByValue = new HashMap<>(); private final Map<VALUE, IDENTIFIER> identifierByValue = new HashMap<>();
public InternTable(Function<Integer, IDENTIFIER> identifierGenerator) { public InternTable(final Function<Integer, IDENTIFIER> identifierGenerator) {
super(identifierGenerator); super(identifierGenerator);
} }
@ -21,17 +22,19 @@ public abstract class InternTable<IDENTIFIER extends SourceIdentifier, VALUE>
return identifierByValue.computeIfAbsent(value, super::register); return identifierByValue.computeIfAbsent(value, super::register);
} }
public Optional<IDENTIFIER> optional(final VALUE value) {
return Optional.ofNullable(identifierByValue.get(value));
}
@Override @Override
public void clear() { public void clear() {
super.clear(); super.clear();
identifierByValue.clear(); identifierByValue.clear();
} }
public boolean containsKey(VALUE value) { @Override
public Optional<IDENTIFIER> optional(final VALUE value) {
return Optional.ofNullable(identifierByValue.get(value));
}
@Override
public boolean containsKey(final VALUE value) {
return identifierByValue.containsKey(value); return identifierByValue.containsKey(value);
} }
} }

View File

@ -0,0 +1,10 @@
package p.studio.compiler.source.tables;
import p.studio.compiler.source.identifiers.SourceIdentifier;
import java.util.Optional;
public interface InternTableReader<IDENTIFIER extends SourceIdentifier, VALUE> extends DenseTableReader<IDENTIFIER, VALUE> {
Optional<IDENTIFIER> optional(VALUE value);
boolean containsKey(VALUE value);
}

View File

@ -8,7 +8,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
public class ProjectTable extends DenseTable<ProjectId, ProjectDescriptor> { public class ProjectTable extends DenseTable<ProjectId, ProjectDescriptor> implements ProjectTableReader {
private final Map<Path, ProjectId> projectIdByPath = new HashMap<>(); private final Map<Path, ProjectId> projectIdByPath = new HashMap<>();
@ -27,11 +27,13 @@ public class ProjectTable extends DenseTable<ProjectId, ProjectDescriptor> {
projectIdByPath.clear(); projectIdByPath.clear();
} }
public Optional<ProjectDescriptor> optional(Path pathCanon) { @Override
public Optional<ProjectDescriptor> optional(final Path pathCanon) {
return optionalId(pathCanon).map(this::get); return optionalId(pathCanon).map(this::get);
} }
public Optional<ProjectId> optionalId(Path pathCanon) { @Override
public Optional<ProjectId> optionalId(final Path pathCanon) {
return Optional.ofNullable(projectIdByPath.get(pathCanon)); return Optional.ofNullable(projectIdByPath.get(pathCanon));
} }
} }

View File

@ -0,0 +1,12 @@
package p.studio.compiler.source.tables;
import p.studio.compiler.models.ProjectDescriptor;
import p.studio.compiler.source.identifiers.ProjectId;
import java.nio.file.Path;
import java.util.Optional;
public interface ProjectTableReader extends DenseTableReader<ProjectId, ProjectDescriptor> {
Optional<ProjectDescriptor> optional(Path pathCanon);
Optional<ProjectId> optionalId(Path pathCanon);
}

View File

@ -1,21 +1,57 @@
package p.studio.compiler.utilities; package p.studio.compiler.utilities;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.StringUtils;
import p.studio.compiler.FrontendRegistryService;
import p.studio.compiler.dtos.PrometeuManifestDTO; import p.studio.compiler.dtos.PrometeuManifestDTO;
import p.studio.compiler.messages.BuildingIssueSink;
import p.studio.compiler.models.PrometeuManifest;
import p.studio.compiler.workspaces.phases.DependencyResolver;
import p.studio.utilities.structures.ReadOnlyCollection;
import p.studio.utilities.structures.ReadOnlyList;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Optional;
@UtilityClass
public final class PrometeuManifestUtils { public final class PrometeuManifestUtils {
public static final PrometeuManifestUtils INSTANCE = new PrometeuManifestUtils();
private final ObjectMapper mapper = new ObjectMapper(); private final static ObjectMapper MAPPER = new ObjectMapper();
public PrometeuManifestDTO read(Path manifestPath) { static PrometeuManifestDTO read(Path manifestPath) {
try { try {
return mapper.readValue(manifestPath.toFile(), PrometeuManifestDTO.class); return MAPPER.readValue(manifestPath.toFile(), PrometeuManifestDTO.class);
} catch (IOException e) { } catch (IOException e) {
throw new IllegalStateException("failed to read manifest " + manifestPath, e); throw new IllegalStateException("failed to read manifest " + manifestPath, e);
} }
} }
public static Optional<PrometeuManifest> buildManifest(
final Path mainProjectRootPathCanon,
final Path manifestPathCanon,
final BuildingIssueSink issues) {
final var issuesLocal = BuildingIssueSink.empty();
final PrometeuManifestDTO dto = read(manifestPathCanon);
if (StringUtils.isBlank(dto.name())) {
issuesLocal.report(builder -> builder
.error(true)
.message("[DEPS]: manifest missing 'name': " + manifestPathCanon));
}
if (StringUtils.isBlank(dto.version())) {
issuesLocal.report(builder -> builder
.error(true)
.message("[DEPS]: manifest missing 'version': " + manifestPathCanon));
}
final var language = StringUtils.isBlank(dto.language())
? FrontendRegistryService.getDefaultFrontendSpec().getLanguageId()
: dto.language();
final var dependencies = DependencyResolver.resolveDependencies(mainProjectRootPathCanon, dto.dependencies(), issuesLocal);
if (ReadOnlyCollection.isNotEmpty(issuesLocal)) {
issues.merge(issuesLocal);
return Optional.empty();
}
return Optional.of(new PrometeuManifest(dto.name(), dto.version(), language, ReadOnlyList.wrap(dependencies)));
}
} }

View File

@ -0,0 +1,86 @@
package p.studio.compiler.workspaces.phases;
import lombok.experimental.UtilityClass;
import org.apache.commons.collections4.CollectionUtils;
import p.studio.compiler.dtos.PrometeuManifestDTO;
import p.studio.compiler.messages.BuildingIssueSink;
import p.studio.compiler.workspaces.DependencyReference;
import p.studio.registry.models.ProjectRef;
import p.studio.registry.models.Registry;
import p.studio.registry.utilities.RegistryStore;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@UtilityClass
public final class DependencyResolver {
public static List<DependencyReference> resolveDependencies(
final Path mainProjectRootPathCanon,
final List<PrometeuManifestDTO.DependencyDeclaration> dependencies,
final BuildingIssueSink issues) {
if (CollectionUtils.isEmpty(dependencies)) {
return List.of();
}
final var registryMaybe = RegistryStore.INSTANCE.load(mainProjectRootPathCanon);
if (registryMaybe.isEmpty()) {
issues.report(builder -> builder
.error(true)
.message("[DEPS]: failed to load registry from " + mainProjectRootPathCanon));
return List.of();
}
final var registry = registryMaybe.get();
final var deps = new ArrayList<DependencyReference>(dependencies.size());
for (var dependency : dependencies) {
// Resolves each dependency based on its declaration type
switch (dependency) {
case PrometeuManifestDTO.DependencyDeclaration.Local loc -> resolveLocal(loc, mainProjectRootPathCanon, issues, deps);
case PrometeuManifestDTO.DependencyDeclaration.Registry reg -> resolveRegistry(reg, registry, issues, deps);
default -> issues.report(builder -> builder
.error(true)
.message("[DEPS]: unknown dependency declaration type: " + dependency.getClass().getSimpleName()));
}
}
return deps;
}
// Resolves local dependency path; reports canonicalization errors
private static void resolveLocal(
final PrometeuManifestDTO.DependencyDeclaration.Local loc,
final Path rootProjectCanonPath,
final BuildingIssueSink issues,
final List<DependencyReference> deps) {
final var pathResolve = rootProjectCanonPath.resolve(loc.path());
try {
final Path pathCanon = pathResolve.toRealPath();
deps.add(new DependencyReference(pathCanon));
} catch (IOException e) {
issues.report(builder -> builder
.error(true)
.message("[DEPS]: failed to canonicalize dependency path: " + pathResolve)
.exception(e));
}
}
// Looks up the registry for a dependency path; reports missing path errors
private static void resolveRegistry(
final PrometeuManifestDTO.DependencyDeclaration.Registry reg,
final Registry registry,
final BuildingIssueSink issues,
final List<DependencyReference> deps) {
final var ref = new ProjectRef(reg.name(), reg.version());
final var canonPath = registry.optional(ref);
if (canonPath.isEmpty()) {
issues.report(builder -> builder
.error(true)
.message("[DEPS]: registry dependency not found: " + ref));
return;
}
deps.add(new DependencyReference(canonPath.get()));
}
}

View File

@ -1,180 +1,106 @@
package p.studio.compiler.workspaces.phases; package p.studio.compiler.workspaces.phases;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import p.studio.compiler.FrontendRegistryService; import p.studio.compiler.FrontendRegistryService;
import p.studio.compiler.dtos.PrometeuManifestDTO;
import p.studio.compiler.messages.BuildingIssueSink; import p.studio.compiler.messages.BuildingIssueSink;
import p.studio.compiler.models.DependencyContext; import p.studio.compiler.models.DependencyContext;
import p.studio.compiler.models.ProjectInfo; import p.studio.compiler.models.ProjectInfo;
import p.studio.compiler.models.ProjectInfoId; import p.studio.compiler.models.ProjectInfoId;
import p.studio.compiler.models.PrometeuManifest;
import p.studio.compiler.utilities.PrometeuManifestUtils; import p.studio.compiler.utilities.PrometeuManifestUtils;
import p.studio.compiler.workspaces.DependencyPhase; import p.studio.compiler.workspaces.DependencyPhase;
import p.studio.compiler.workspaces.DependencyReference;
import p.studio.registry.models.ProjectRef;
import p.studio.registry.utilities.RegistryStore;
import p.studio.utilities.structures.ReadOnlyCollection;
import p.studio.utilities.structures.ReadOnlyList;
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.util.*; import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
public class DiscoverPhase implements DependencyPhase { public class DiscoverPhase implements DependencyPhase {
@Override @Override
public BuildingIssueSink run(final DependencyContext ctx) { public BuildingIssueSink run(final DependencyContext ctx) {
final Map<Path, ProjectInfoId> projectIndexByDirectory = new HashMap<>(); final var projectsSeen = new HashSet<Path>();
final BuildingIssueSink issues = BuildingIssueSink.empty(); final var issues = BuildingIssueSink.empty();
// Discovers projects; registers them; adds dependencies to queue // Discovers projects; registers them; adds dependencies to queue
while (!ctx.pending.isEmpty()) { while (!ctx.pending.isEmpty()) {
final var rootPathCanon = ctx.pending.pollFirst(); final var rootPathCanon = ctx.pending.pollFirst();
if (projectsSeen.contains(rootPathCanon)) {
if (projectIndexByDirectory.containsKey(rootPathCanon)) {
continue; continue;
} }
discoverOne(ctx, rootPathCanon, issues).ifPresent(projectInfoId -> {
final Path manifestPathCanon; projectsSeen.add(rootPathCanon);
try { final var projectInfo = ctx.projectInfoTable.get(projectInfoId);
manifestPathCanon = rootPathCanon.resolve("prometeu.json").toRealPath(); projectInfo.manifest.dependencies().forEach(dep -> ctx.pending.add(dep.canonPath()));
} catch (IOException e) { ctx.projectNameAndVersions
issues.report(builder -> builder .computeIfAbsent(projectInfo.manifest.name(), ignored -> new HashSet<>())
.error(true) .add(projectInfo.manifest.version());
.message("[DEPS]: manifest canonPath does not exist: " + rootPathCanon) });
.exception(e));
continue;
} }
if (!Files.exists(manifestPathCanon) || !Files.isRegularFile(manifestPathCanon)) {
issues.report(builder -> builder
.error(true)
.message("[DEPS]: manifest not found: expected a file " + manifestPathCanon));
continue;
}
final var prometeuManifestDTO = PrometeuManifestUtils.INSTANCE.read(manifestPathCanon);
final var manifestMaybe = map(ctx.mainProjectRootPathCanon, prometeuManifestDTO, issues);
if (manifestMaybe.isEmpty()) {
continue;
}
final var manifest = manifestMaybe.get();
final var frontendSpec = FrontendRegistryService.getFrontendSpec(manifest.language());
if (frontendSpec.isEmpty()) {
issues.report(builder -> builder
.error(true)
.message("[DEPS]: unknown language " + manifest.language() + " for project " + manifest.name()));
continue;
}
if (Objects.isNull(ctx.frontendSpec)) {
ctx.frontendSpec = frontendSpec.get();
} else if (!ctx.frontendSpec.getLanguageId().equals(frontendSpec.get().getLanguageId())) {
issues.report(builder -> builder
.error(true)
.message(String.format("[DEPS]: inconsistent language: [ %s ] has \"%s\" but should be \"%s\"",
manifest.name(), frontendSpec.get().getLanguageId(), ctx.frontendSpec.getLanguageId())));
continue;
}
final var projectInfo = ProjectInfo
.builder()
.rootDirectory(rootPathCanon)
.manifestPath(manifestPathCanon)
.manifest(manifest)
.build();
final var projectInfoId = ctx.projectInfoTable.register(projectInfo);
projectIndexByDirectory.put(rootPathCanon, projectInfoId);
manifest.dependencies().forEach(depRef -> ctx.pending.add(depRef.canonPath()));
ctx.projectNameAndVersions.computeIfAbsent(manifest.name(), ignore -> new HashSet<>()).add(manifest.version());
}
return issues; return issues;
} }
public static Optional<PrometeuManifest> map( private Optional<ProjectInfoId> discoverOne(
final Path rootPath, final DependencyContext ctx,
final PrometeuManifestDTO dto, final Path rootPathCanon,
final BuildingIssueSink issues) { final BuildingIssueSink issues) {
final var manifestPathCanon = canonicalizeManifestPath(rootPathCanon, issues);
if (StringUtils.isBlank(dto.name())) { if (manifestPathCanon.isEmpty()) {
issues.report(builder -> builder
.error(true)
.message("[DEPS]: manifest missing 'name': " + rootPath));
}
if (StringUtils.isBlank(dto.version())) {
issues.report(builder -> builder
.error(true)
.message("[DEPS]: manifest missing 'version': " + rootPath));
}
final var language = StringUtils.isBlank(dto.language())
? FrontendRegistryService.getDefaultFrontendSpec().getLanguageId()
: dto.language();
final var dependencies = resolveDependencies(rootPath, dto.dependencies(), issues);
if (ReadOnlyCollection.isNotEmpty(issues)) {
return Optional.empty(); return Optional.empty();
} }
final var manifest = PrometeuManifestUtils.buildManifest(ctx.mainProjectRootPathCanon, manifestPathCanon.get(), issues);
return Optional.of(new PrometeuManifest(dto.name(), dto.version(), language, ReadOnlyList.wrap(dependencies))); if (manifest.isEmpty()) {
return Optional.empty();
} }
final var frontendSpec = FrontendRegistryService.getFrontendSpec(manifest.get().language());
private static List<DependencyReference> resolveDependencies( // Returns empty when language is unknown
final Path rootProjectCanonPath, if (frontendSpec.isEmpty()) {
final List<PrometeuManifestDTO.DependencyDeclaration> dependencies,
final BuildingIssueSink issues) {
if (CollectionUtils.isEmpty(dependencies)) {
return List.of();
}
final var registryMaybe = RegistryStore.INSTANCE.load(rootProjectCanonPath);
if (registryMaybe.isEmpty()) {
issues.report(builder -> builder issues.report(builder -> builder
.error(true) .error(true)
.message("[DEPS]: failed to load registry from " + rootProjectCanonPath)); .message("[DEPS]: unknown language " + manifest.get().language() + " for project " + manifest.get().name()));
return List.of(); return Optional.empty();
}
// Enforces consistent language across projects
if (Objects.isNull(ctx.frontendSpec)) {
ctx.frontendSpec = frontendSpec.get();
} else if (!ctx.frontendSpec.getLanguageId().equals(frontendSpec.get().getLanguageId())) {
// Reports language inconsistency across projects
issues.report(builder -> builder
.error(true)
.message(String.format("[DEPS]: inconsistent language: [ %s ] has \"%s\" but should be \"%s\"",
manifest.get().name(), frontendSpec.get().getLanguageId(), ctx.frontendSpec.getLanguageId())));
return Optional.empty();
}
final var projectInfo = ProjectInfo
.builder()
.rootDirectory(rootPathCanon)
.manifestPath(manifestPathCanon.get())
.manifest(manifest.get())
.build();
final var projectInfoId = ctx.projectInfoTable.register(projectInfo);
return Optional.of(projectInfoId);
} }
final var registry = registryMaybe.get();
final var deps = new ArrayList<DependencyReference>(dependencies.size()); private static Optional<Path> canonicalizeManifestPath(
for (var dependency : dependencies) { final Path rootPathCanon,
final BuildingIssueSink issues) {
// Resolves each dependency based on its declaration type final var manifestPath = rootPathCanon.resolve("prometeu.json");
switch (dependency) { final Path manifestPathCanon;
// Resolves manifest path; reports errors on failure
case PrometeuManifestDTO.DependencyDeclaration.Local loc -> {
// Resolves local dependency path; reports canonicalization errors
final var pathResolve = rootProjectCanonPath.resolve(loc.path());
try { try {
final Path pathCanon = pathResolve.toRealPath(); manifestPathCanon = manifestPath.toRealPath();
deps.add(new DependencyReference(pathCanon));
} catch (IOException e) { } catch (IOException e) {
issues.report(builder -> builder issues.report(builder -> builder
.error(true) .error(true)
.message("[DEPS]: failed to canonicalize dependency path: " + pathResolve) .message("[DEPS]: manifest canonPath does not exist: " + manifestPath)
.exception(e)); .exception(e));
} return Optional.empty();
} }
if (!Files.isRegularFile(manifestPathCanon)) {
case PrometeuManifestDTO.DependencyDeclaration.Registry reg -> { issues.report(builder -> builder
// Looks up the registry for a dependency path; reports missing path errors .error(true)
final var ref = new ProjectRef(reg.name(), reg.version()); .message("[DEPS]: manifest not found: expected a file " + manifestPathCanon));
registry.optional(ref).ifPresent(pathCanon -> deps.add(new DependencyReference(pathCanon))); return Optional.empty();
} }
return Optional.of(manifestPathCanon);
default -> {
}
}
}
return deps;
} }
} }

View File

@ -25,8 +25,7 @@ public final class WireProjectsPhase implements DependencyPhase {
final BuildingIssueSink issues = BuildingIssueSink.empty(); final BuildingIssueSink issues = BuildingIssueSink.empty();
for (int index = 0; index < ctx.projectInfoTable.size(); index++) { for (final var projectInfo : ctx.projectInfoTable.values()) {
final var projectInfo = ctx.projectInfoTable.get(new ProjectInfoId(index));
final var projectDescriptor = buildProjectDescriptor(ctx, projectInfo, issues); final var projectDescriptor = buildProjectDescriptor(ctx, projectInfo, issues);
final var projectId = ctx.projectTable.register(projectDescriptor); final var projectId = ctx.projectTable.register(projectDescriptor);
ctx.projectIds.add(projectId); ctx.projectIds.add(projectId);
@ -82,7 +81,7 @@ public final class WireProjectsPhase implements DependencyPhase {
} }
if (sourceRootIssues.size() == ctx.frontendSpec.getSourceRoots().size()) { if (sourceRootIssues.size() == ctx.frontendSpec.getSourceRoots().size()) {
// no source roots were found at all // no source roots were found at all
issues.report(sourceRootIssues); issues.merge(sourceRootIssues);
} }
return ProjectDescriptor return ProjectDescriptor

View File

@ -10,4 +10,9 @@ public record ProjectRef(String name, String version) {
final var version = ps[1]; final var version = ps[1];
return Optional.of(new ProjectRef(name, version)); return Optional.of(new ProjectRef(name, version));
} }
@Override
public String toString() {
return name + "@" + version;
}
} }