add registry control
This commit is contained in:
parent
3b477113e1
commit
7b15aebef2
@ -4,7 +4,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import p.studio.compiler.exceptions.BuildException;
|
||||
import p.studio.compiler.messages.BuilderPipelineConfig;
|
||||
import p.studio.compiler.models.BuilderPipelineContext;
|
||||
import p.studio.compiler.workspaces.stages.DependencyPipelineStage;
|
||||
import p.studio.compiler.workspaces.stages.ResolvePipelineStage;
|
||||
import p.studio.utilities.logs.LogAggregator;
|
||||
import p.studio.utilities.structures.ReadOnlyCollection;
|
||||
|
||||
@ -16,7 +16,7 @@ public class BuilderPipelineService {
|
||||
|
||||
static {
|
||||
final var stages = List.<PipelineStage>of(
|
||||
new DependencyPipelineStage()
|
||||
new ResolvePipelineStage()
|
||||
);
|
||||
INSTANCE = new BuilderPipelineService(stages);
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
@Slf4j
|
||||
public class DependencyPipelineStage implements PipelineStage {
|
||||
public class ResolvePipelineStage implements PipelineStage {
|
||||
@Override
|
||||
public BuildingIssues run(final BuilderPipelineContext ctx, LogAggregator logs) {
|
||||
final Path rootCanonPath;
|
||||
@ -14,7 +14,7 @@ public record PrometeuManifestDTO(
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = DependencyDeclaration.Local.class),
|
||||
@JsonSubTypes.Type(value = DependencyDeclaration.Git.class)
|
||||
@JsonSubTypes.Type(value = DependencyDeclaration.Registry.class)
|
||||
})
|
||||
public interface DependencyDeclaration {
|
||||
record Local(String path) implements DependencyDeclaration {
|
||||
@ -24,13 +24,12 @@ public record PrometeuManifestDTO(
|
||||
}
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
record Git(String url, String rev) implements DependencyDeclaration {
|
||||
@JsonCreator
|
||||
public Git(@JsonProperty("url") final String url, @JsonProperty("rev") final String rev) {
|
||||
this.url = url;
|
||||
this.rev = rev;
|
||||
}
|
||||
}
|
||||
record Registry(String name, String version) implements DependencyDeclaration {
|
||||
@JsonCreator
|
||||
public Registry(@JsonProperty("name") final String name, @JsonProperty("version") final String version) {
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
package p.studio.compiler.messages;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
public record DependencyConfig(
|
||||
boolean explain,
|
||||
|
||||
@ -32,7 +32,7 @@ public final class DependencyContext {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public static DependencyContext basedOn(DependencyConfig config) {
|
||||
public static DependencyContext basedOn(final DependencyConfig config) {
|
||||
return new DependencyContext(config);
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,6 @@ import p.studio.compiler.models.DependencyContext;
|
||||
import p.studio.compiler.models.ResolvedWorkspace;
|
||||
import p.studio.compiler.workspaces.phases.*;
|
||||
import p.studio.utilities.logs.LogAggregator;
|
||||
import p.studio.utilities.structures.ReadOnlyCollection;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@ -12,6 +12,8 @@ import p.studio.compiler.models.PrometeuManifest;
|
||||
import p.studio.compiler.utilities.PrometeuManifestUtils;
|
||||
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;
|
||||
|
||||
@ -26,6 +28,7 @@ public class DiscoverPhase implements DependencyPhase {
|
||||
public BuildingIssues run(final DependencyContext ctx) {
|
||||
final Map<Path, ProjectInfoId> projectIndexByDirectory = new HashMap<>();
|
||||
final BuildingIssues issues = BuildingIssues.empty();
|
||||
// Discovers projects; registers them; adds dependencies to queue
|
||||
while (!ctx.pending.isEmpty()) {
|
||||
final var rootPathCanon = ctx.pending.pollFirst();
|
||||
|
||||
@ -51,7 +54,7 @@ public class DiscoverPhase implements DependencyPhase {
|
||||
}
|
||||
|
||||
final var prometeuManifestDTO = PrometeuManifestUtils.INSTANCE.read(manifestPathCanon);
|
||||
final var manifestMaybe = map(rootPathCanon, prometeuManifestDTO, issues);
|
||||
final var manifestMaybe = map(ctx.mainProjectRootPathCanon, prometeuManifestDTO, issues);
|
||||
|
||||
if (manifestMaybe.isEmpty()) {
|
||||
continue;
|
||||
@ -123,29 +126,46 @@ public class DiscoverPhase implements DependencyPhase {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
final var registryMaybe = RegistryStore.INSTANCE.load(rootProjectCanonPath);
|
||||
if (registryMaybe.isEmpty()) {
|
||||
issues.add(builder -> builder
|
||||
.error(true)
|
||||
.message("[DEPS]: failed to load registry from " + rootProjectCanonPath));
|
||||
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 local -> {
|
||||
|
||||
case PrometeuManifestDTO.DependencyDeclaration.Local loc -> {
|
||||
// Resolves local dependency path; reports canonicalization errors
|
||||
final var pathResolve = rootProjectCanonPath.resolve(loc.path());
|
||||
try {
|
||||
final Path dependencyPathCanon = rootProjectCanonPath.resolve(local.path()).toRealPath();
|
||||
deps.add(new DependencyReference(dependencyPathCanon));
|
||||
final Path pathCanon = pathResolve.toRealPath();
|
||||
deps.add(new DependencyReference(pathCanon));
|
||||
} catch (IOException e) {
|
||||
issues.add(builder -> builder
|
||||
.error(true)
|
||||
.message("[DEPS]: failed to canonicalize dependency path: " + local.path() + " from (" + rootProjectCanonPath + ")")
|
||||
.message("[DEPS]: failed to canonicalize dependency path: " + pathResolve)
|
||||
.exception(e));
|
||||
}
|
||||
}
|
||||
|
||||
case PrometeuManifestDTO.DependencyDeclaration.Git git -> issues.add(builder -> builder
|
||||
.error(true)
|
||||
.message("[DEPS]: git dependencies are not supported yet: " + git.url() + " from (" + rootProjectCanonPath + ")"));
|
||||
case PrometeuManifestDTO.DependencyDeclaration.Registry reg -> {
|
||||
// Looks up the registry for a dependency path; reports missing path errors
|
||||
final var ref = new ProjectRef(reg.name(), reg.version());
|
||||
registry.optional(ref).ifPresent(pathCanon -> deps.add(new DependencyReference(pathCanon)));
|
||||
}
|
||||
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deps;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
package p.studio.registry.models;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public record ProjectRef(String name, String version) {
|
||||
public static Optional<ProjectRef> parse(final String value) {
|
||||
final var ps = value.split("@");
|
||||
if (ps.length != 2) return Optional.empty();
|
||||
final var name = ps[0];
|
||||
final var version = ps[1];
|
||||
return Optional.of(new ProjectRef(name, version));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package p.studio.registry.models;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Registry {
|
||||
private final Map<ProjectRef, Path> pathByDependency;
|
||||
|
||||
public Registry(final Map<ProjectRef, Path> pathByDependency) {
|
||||
this.pathByDependency = pathByDependency;
|
||||
}
|
||||
|
||||
public Optional<Path> optional(final ProjectRef projectRef) {
|
||||
return Optional.ofNullable(pathByDependency.get(projectRef));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package p.studio.registry.utilities;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import p.studio.registry.models.ProjectRef;
|
||||
import p.studio.registry.models.Registry;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class RegistryStore {
|
||||
public static final RegistryStore INSTANCE = new RegistryStore();
|
||||
|
||||
private final static ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Optional<Registry> load(final Path projectRootPathCanon) {
|
||||
final var registryPath = projectRootPathCanon
|
||||
.resolve(".workspace/repos/registry.json");
|
||||
|
||||
final Map<String, String> map;
|
||||
{
|
||||
final var file = registryPath.toFile();
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
try {
|
||||
map = mapper.readValue(file, new TypeReference<>() {});
|
||||
} catch (Exception e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
final Map<ProjectRef, Path> repos = new HashMap<>();
|
||||
for (final var entry : map.entrySet()) {
|
||||
final var pathCanon = canonicalize(projectRootPathCanon, entry.getValue());
|
||||
if (pathCanon.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
ProjectRef.parse(entry.getKey()).ifPresent(ref -> repos.put(ref, pathCanon.get()));
|
||||
}
|
||||
|
||||
if (map.size() != repos.size()) {
|
||||
return Optional.empty(); // mal formatted registry file
|
||||
}
|
||||
|
||||
return Optional.of(new Registry(repos));
|
||||
}
|
||||
|
||||
private static Optional<Path> canonicalize(
|
||||
final Path projectRootPathCanon,
|
||||
final String value) {
|
||||
try {
|
||||
final var pathResolve = projectRootPathCanon.resolve(value);
|
||||
return Optional.of(pathResolve.toRealPath());
|
||||
} catch (IOException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -23,11 +23,13 @@ public enum I18n {
|
||||
WORKSPACE_BUILDER("workspace.builder"),
|
||||
WORKSPACE_BUILDER_LOGS("workspace.builder.logs"),
|
||||
WORKSPACE_BUILDER_BUTTON_RUN("workspace.builder.button.run"),
|
||||
WORKSPACE_BUILDER_BUTTON_CLEAR("workspace.builder.button.clear"),
|
||||
|
||||
WORKSPACE_ASSETS("workspace.assets"),
|
||||
WORKSPACE_DEBUG("workspace.debug");
|
||||
WORKSPACE_DEBUG("workspace.debug"),
|
||||
|
||||
|
||||
;
|
||||
|
||||
@Getter
|
||||
private final String key;
|
||||
|
||||
@ -17,6 +17,7 @@ public class BuilderWorkspace implements Workspace {
|
||||
private final BorderPane root = new BorderPane();
|
||||
private final TextArea logs = new TextArea();
|
||||
private final Button buildButton = new Button();
|
||||
private final Button clearButton = new Button();
|
||||
|
||||
@Override
|
||||
public WorkspaceId id() {
|
||||
@ -50,11 +51,16 @@ public class BuilderWorkspace implements Workspace {
|
||||
private ToolBar buildToolBar() {
|
||||
buildButton.textProperty().bind(Container.i18n().bind(I18n.WORKSPACE_BUILDER_BUTTON_RUN));
|
||||
buildButton.setOnAction(e -> {
|
||||
logs.clear();
|
||||
final var logAggregator = LogAggregator.with(logs::appendText);
|
||||
final var config = new BuilderPipelineConfig(false, "../test-projects/main");
|
||||
BuilderPipelineService.INSTANCE.run(config, logAggregator);
|
||||
});
|
||||
return new ToolBar(buildButton);
|
||||
|
||||
clearButton.textProperty().bind(Container.i18n().bind(I18n.WORKSPACE_BUILDER_BUTTON_CLEAR));
|
||||
clearButton.setOnAction(e -> logs.clear());
|
||||
|
||||
return new ToolBar(buildButton, clearButton);
|
||||
}
|
||||
|
||||
private StackPane buildProjectArea() {
|
||||
|
||||
@ -15,6 +15,7 @@ workspace.code=Code
|
||||
workspace.builder=Builder
|
||||
workspace.builder.logs=Logs
|
||||
workspace.builder.button.run=Build
|
||||
workspace.builder.button.clear=Clear
|
||||
|
||||
workspace.assets=Assets
|
||||
workspace.debug=Debug
|
||||
@ -11,9 +11,12 @@ menu.help=Ajuda
|
||||
toolbar.play=Executar
|
||||
toolbar.stop=Parar
|
||||
toolbar.export=Exportar
|
||||
|
||||
workspace.code=Código
|
||||
workspace.builder=Construtor
|
||||
workspace.builder.logs=Logs
|
||||
workspace.builder.button.run=Construir
|
||||
workspace.builder.button.clear=Limpar
|
||||
|
||||
workspace.assets=Assets
|
||||
workspace.debug=Depurar
|
||||
@ -4,10 +4,12 @@
|
||||
"language": "pbs",
|
||||
"dependencies": [
|
||||
{
|
||||
"path": "../dep2"
|
||||
"name": "dep2",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"path": "../sdk"
|
||||
"name": "sdk",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -4,7 +4,8 @@
|
||||
"language": "pbs",
|
||||
"dependencies": [
|
||||
{
|
||||
"path": "../sdk"
|
||||
"name": "sdk",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
5
test-projects/main/.workspace/repos/registry.json
Normal file
5
test-projects/main/.workspace/repos/registry.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"dep1@1.0.0": ".workspace/repos/dep1/1.0.0",
|
||||
"dep2@1.0.0": ".workspace/repos/dep2/1.0.0",
|
||||
"sdk@1.0.0": ".workspace/repos/sdk/1.0.0"
|
||||
}
|
||||
@ -4,10 +4,12 @@
|
||||
"language": "pbs",
|
||||
"dependencies": [
|
||||
{
|
||||
"path": "../dep1"
|
||||
"name": "dep1",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"path": "../sdk"
|
||||
"name": "sdk",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user