diff --git a/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/workspaces/BuilderPipelineService.java b/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/workspaces/BuilderPipelineService.java index ae326484..ef29c13c 100644 --- a/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/workspaces/BuilderPipelineService.java +++ b/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/workspaces/BuilderPipelineService.java @@ -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.of( - new DependencyPipelineStage() + new ResolvePipelineStage() ); INSTANCE = new BuilderPipelineService(stages); } diff --git a/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/workspaces/stages/DependencyPipelineStage.java b/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/workspaces/stages/ResolvePipelineStage.java similarity index 95% rename from prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/workspaces/stages/DependencyPipelineStage.java rename to prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/workspaces/stages/ResolvePipelineStage.java index 03669d11..bbecddc7 100644 --- a/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/workspaces/stages/DependencyPipelineStage.java +++ b/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/workspaces/stages/ResolvePipelineStage.java @@ -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; diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/dtos/PrometeuManifestDTO.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/dtos/PrometeuManifestDTO.java index b1c08cf0..33cb7b6f 100644 --- a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/dtos/PrometeuManifestDTO.java +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/dtos/PrometeuManifestDTO.java @@ -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; + } + } } } \ No newline at end of file diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/messages/DependencyConfig.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/messages/DependencyConfig.java index 64860d68..5c42431b 100644 --- a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/messages/DependencyConfig.java +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/messages/DependencyConfig.java @@ -1,7 +1,6 @@ package p.studio.compiler.messages; import java.nio.file.Path; -import java.util.List; public record DependencyConfig( boolean explain, diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/models/DependencyContext.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/models/DependencyContext.java index 9d5f1bab..d6e77b1e 100644 --- a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/models/DependencyContext.java +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/models/DependencyContext.java @@ -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); } diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyService.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyService.java index 7d3d247c..edb19106 100644 --- a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyService.java +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/DependencyService.java @@ -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; diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/DiscoverPhase.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/DiscoverPhase.java index 50b8340e..e99d2c79 100644 --- a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/DiscoverPhase.java +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/compiler/workspaces/phases/DiscoverPhase.java @@ -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 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(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; } } diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/registry/models/ProjectRef.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/registry/models/ProjectRef.java new file mode 100644 index 00000000..04ffbc1e --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/registry/models/ProjectRef.java @@ -0,0 +1,13 @@ +package p.studio.registry.models; + +import java.util.Optional; + +public record ProjectRef(String name, String version) { + public static Optional 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)); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/registry/models/Registry.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/registry/models/Registry.java new file mode 100644 index 00000000..fe3d3ad6 --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/registry/models/Registry.java @@ -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 pathByDependency; + + public Registry(final Map pathByDependency) { + this.pathByDependency = pathByDependency; + } + + public Optional optional(final ProjectRef projectRef) { + return Optional.ofNullable(pathByDependency.get(projectRef)); + } +} diff --git a/prometeu-compiler/prometeu-deps/src/main/java/p/studio/registry/utilities/RegistryStore.java b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/registry/utilities/RegistryStore.java new file mode 100644 index 00000000..61c98cad --- /dev/null +++ b/prometeu-compiler/prometeu-deps/src/main/java/p/studio/registry/utilities/RegistryStore.java @@ -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 load(final Path projectRootPathCanon) { + final var registryPath = projectRootPathCanon + .resolve(".workspace/repos/registry.json"); + + final Map 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 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 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(); + } + } +} diff --git a/prometeu-studio/src/main/java/p/studio/utilities/i18n/I18n.java b/prometeu-studio/src/main/java/p/studio/utilities/i18n/I18n.java index 4431eda4..dc057e84 100644 --- a/prometeu-studio/src/main/java/p/studio/utilities/i18n/I18n.java +++ b/prometeu-studio/src/main/java/p/studio/utilities/i18n/I18n.java @@ -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; diff --git a/prometeu-studio/src/main/java/p/studio/workspaces/builder/BuilderWorkspace.java b/prometeu-studio/src/main/java/p/studio/workspaces/builder/BuilderWorkspace.java index c2ea35f5..7654b1b3 100644 --- a/prometeu-studio/src/main/java/p/studio/workspaces/builder/BuilderWorkspace.java +++ b/prometeu-studio/src/main/java/p/studio/workspaces/builder/BuilderWorkspace.java @@ -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() { diff --git a/prometeu-studio/src/main/resources/i18n/messages.properties b/prometeu-studio/src/main/resources/i18n/messages.properties index 93ee6ab4..548275b2 100644 --- a/prometeu-studio/src/main/resources/i18n/messages.properties +++ b/prometeu-studio/src/main/resources/i18n/messages.properties @@ -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 \ No newline at end of file diff --git a/prometeu-studio/src/main/resources/i18n/messages_pt_BR.properties b/prometeu-studio/src/main/resources/i18n/messages_pt_BR.properties index 41e530f5..93a5b826 100644 --- a/prometeu-studio/src/main/resources/i18n/messages_pt_BR.properties +++ b/prometeu-studio/src/main/resources/i18n/messages_pt_BR.properties @@ -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 \ No newline at end of file diff --git a/test-projects/dep1/prometeu.json b/test-projects/main/.workspace/repos/dep1/1.0.0/prometeu.json similarity index 54% rename from test-projects/dep1/prometeu.json rename to test-projects/main/.workspace/repos/dep1/1.0.0/prometeu.json index 425ac304..84303c7d 100644 --- a/test-projects/dep1/prometeu.json +++ b/test-projects/main/.workspace/repos/dep1/1.0.0/prometeu.json @@ -4,10 +4,12 @@ "language": "pbs", "dependencies": [ { - "path": "../dep2" + "name": "dep2", + "version": "1.0.0" }, { - "path": "../sdk" + "name": "sdk", + "version": "1.0.0" } ] } \ No newline at end of file diff --git a/test-projects/dep2/prometeu.json b/test-projects/main/.workspace/repos/dep2/1.0.0/prometeu.json similarity index 68% rename from test-projects/dep2/prometeu.json rename to test-projects/main/.workspace/repos/dep2/1.0.0/prometeu.json index 26d62f9d..6dc9feb3 100644 --- a/test-projects/dep2/prometeu.json +++ b/test-projects/main/.workspace/repos/dep2/1.0.0/prometeu.json @@ -4,7 +4,8 @@ "language": "pbs", "dependencies": [ { - "path": "../sdk" + "name": "sdk", + "version": "1.0.0" } ] } \ No newline at end of file diff --git a/test-projects/main/.workspace/repos/registry.json b/test-projects/main/.workspace/repos/registry.json new file mode 100644 index 00000000..f30c506a --- /dev/null +++ b/test-projects/main/.workspace/repos/registry.json @@ -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" +} \ No newline at end of file diff --git a/test-projects/sdk/prometeu.json b/test-projects/main/.workspace/repos/sdk/1.0.0/prometeu.json similarity index 100% rename from test-projects/sdk/prometeu.json rename to test-projects/main/.workspace/repos/sdk/1.0.0/prometeu.json diff --git a/test-projects/main/prometeu.json b/test-projects/main/prometeu.json index 484a513a..d7f84553 100644 --- a/test-projects/main/prometeu.json +++ b/test-projects/main/prometeu.json @@ -4,10 +4,12 @@ "language": "pbs", "dependencies": [ { - "path": "../dep1" + "name": "dep1", + "version": "1.0.0" }, { - "path": "../sdk" + "name": "sdk", + "version": "1.0.0" } ] } \ No newline at end of file