From bb4d2927a972bf6ef6fa611b03502ebb8610f08f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Garc=C3=ADa-Dom=C3=ADnguez?= Date: Wed, 22 May 2024 10:49:03 +0100 Subject: [PATCH] Add support for URI-to-path mappings --- README.md | 35 +++++++++ build.gradle | 1 + .../emfatic/cli/Ecore2EmfaticCommand.java | 71 ++++++++++++++++--- .../emfatic/cli/Ecore2EmfaticCommandTest.java | 26 +++++-- .../platformImport/example/Trees.ecore | 11 +++ .../platformImport/example2/ColoredTree.ecore | 12 ++++ 6 files changed, 142 insertions(+), 14 deletions(-) create mode 100644 src/test/resources/platformImport/example/Trees.ecore create mode 100644 src/test/resources/platformImport/example2/ColoredTree.ecore diff --git a/README.md b/README.md index ea5568d..a2606f3 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,20 @@ To build and test the Java and native binary versions of the project, run: Note that for the native binaries, you will need [GraalVM](https://www.graalvm.org/) 17 or newer. It is recommended to use [SDKMAN](https://sdkman.io/) for installing and managing JDKs. +## Running + +To produce Emfatic sources from an `.ecore` file, using the all-in-one JAR file in `build/libs/*-all.jar`: + +```sh +java -jar path/to/Ecore2Emfatic-VERSION-all.jar path/to/your.ecore +``` + +When using one of the native binaries, this can be simplified to: + +```sh +path/to/Ecore2Emfatic path/to/your.ecore +``` + ## Using native binaries as a Git filter In order to compute differences between `.ecore` file versions using a Git `textconv`, first add the native binary to your path. @@ -51,3 +65,24 @@ index 84da8c9..f611dd1 100644 + private = 3; } ``` + +## Providing URI mappings + +If your `.ecore` files import other metamodels through URIs, you can provide mappings from URIs to specific `.ecore` files or folders via the `--from` and `--to` options: + +```sh +path/to/Ecore2Emfatic --from platform:/resource --to path/to/base/folder your.ecore +``` + +You can specify multiple pairs of `--from` and `--to` options, as in: + +```sh +path/to/Ecore2Emfatic --from A --to B --from C --to D your.ecore +``` + +If you are using this tool as a `textconv` filter via Git, you would need to provide these options in your repository's configuration. +For example: + +```sh +git config diff.ecore.textconv "Ecore2Emfatic --from A --to B" +``` diff --git a/build.gradle b/build.gradle index 2a0ed21..22a84ef 100644 --- a/build.gradle +++ b/build.gradle @@ -18,6 +18,7 @@ dependencies { implementation("io.micronaut.serde:micronaut-serde-jackson") implementation("org.eclipse.emfatic:org.eclipse.emfatic.core:1.1.0") implementation("org.eclipse.platform:org.eclipse.core.resources:3.13.700") + testImplementation('org.hamcrest:hamcrest:2.2') runtimeOnly("ch.qos.logback:logback-classic") } diff --git a/src/main/java/org/eclipse/emfatic/cli/Ecore2EmfaticCommand.java b/src/main/java/org/eclipse/emfatic/cli/Ecore2EmfaticCommand.java index 29dbe73..2287172 100644 --- a/src/main/java/org/eclipse/emfatic/cli/Ecore2EmfaticCommand.java +++ b/src/main/java/org/eclipse/emfatic/cli/Ecore2EmfaticCommand.java @@ -23,23 +23,37 @@ import io.micronaut.configuration.picocli.PicocliRunner; import io.micronaut.core.annotation.TypeHint; +import picocli.CommandLine.ArgGroup; import picocli.CommandLine.Command; +import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + @TypeHint(value = { - EEnumLiteral[].class, - EParameter[].class, - EStringToStringMapEntryImpl[].class, - ETypeParameter[].class + EEnumLiteral[].class, + EParameter[].class, + EStringToStringMapEntryImpl[].class, + ETypeParameter[].class }) -@Command( - name = "Ecore2Emfatic", - description = "Generates Emfatic sources from an .ecore file", - mixinStandardHelpOptions = true -) +@Command(name = "Ecore2Emfatic", description = "Generates Emfatic sources from an .ecore file", mixinStandardHelpOptions = true) public class Ecore2EmfaticCommand implements Runnable { - @Parameters(index="0") + static class URIMapping { + @Option(names = { "-f", "--from" }) + String from; + + @Option(names = { "-t", "--to"}) + String to; + } + + @ArgGroup(exclusive = false, multiplicity = "0..*") + private List uriMappings; + + @Parameters(index = "0") private String pathToFile; public static void main(String[] args) throws Exception { @@ -54,7 +68,44 @@ public void run() { ResourceSet rs = new ResourceSetImpl(); rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", new XMIResourceFactoryImpl()); + Map uriMap = rs.getURIConverter().getURIMap(); + if (uriMappings != null) { + applyURIMappingsTo(uriMap); + } + Resource r = rs.getResource(URI.createFileURI(pathToFile), true); System.out.println(new Writer().write(r, null, null)); } + + protected void applyURIMappingsTo(Map uriMap) { + for (URIMapping mapping : uriMappings) { + if (mapping.from == null) { + throw new IllegalArgumentException("Missing from"); + } + if (mapping.to == null) { + throw new IllegalArgumentException("Missing to"); + } + + try { + File fTargetPath = new File(mapping.to).getCanonicalFile(); + String sPath = fTargetPath.getAbsolutePath(); + if (fTargetPath.isDirectory()) { + // If the target is a directory, ensure both source and target URIs are "prefix" URIs + // (i.e. that they end in a slash) + if (!mapping.from.endsWith("/")) { + mapping.from += "/"; + } + if (!sPath.endsWith("/")) { + sPath += "/"; + } + } + + URI mappedURI = URI.createURI(mapping.from, true); + URI fileURI = URI.createFileURI(sPath); + uriMap.put(mappedURI, fileURI); + } catch (IOException e) { + throw new IllegalArgumentException("Could not compute canonical path for " + mapping.to); + } + } + } } diff --git a/src/test/java/org/eclipse/emfatic/cli/Ecore2EmfaticCommandTest.java b/src/test/java/org/eclipse/emfatic/cli/Ecore2EmfaticCommandTest.java index 26380f9..1bd9d91 100644 --- a/src/test/java/org/eclipse/emfatic/cli/Ecore2EmfaticCommandTest.java +++ b/src/test/java/org/eclipse/emfatic/cli/Ecore2EmfaticCommandTest.java @@ -12,24 +12,42 @@ import io.micronaut.configuration.picocli.PicocliRunner; import io.micronaut.context.ApplicationContext; import io.micronaut.context.env.Environment; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertTrue; - public class Ecore2EmfaticCommandTest { @Test - public void testWithCommandLineOption() throws Exception { + public void testStandaloneMetamodel() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); try (ApplicationContext ctx = ApplicationContext.run(Environment.CLI, Environment.TEST)) { String[] args = new String[] { "src/test/resources/OO.ecore" }; PicocliRunner.run(Ecore2EmfaticCommand.class, ctx, args); - assertTrue(baos.toString().contains("PackageableElement")); + assertThat("Should see a PackageableElement in the output", + baos.toString(), containsString("PackageableElement")); + } + } + + @Test + public void testMetamodelWithPlatformImport() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + System.setOut(new PrintStream(baos)); + + try (ApplicationContext ctx = ApplicationContext.run(Environment.CLI, Environment.TEST)) { + String[] args = new String[] { + "--from=platform:/resource", + "--to=src/test/resources/platformImport", + "src/test/resources/platformImport/example2/ColoredTree.ecore" + }; + PicocliRunner.run(Ecore2EmfaticCommand.class, ctx, args); + assertThat("Should see 'extends Trees.Tree' in the output", + baos.toString(), containsString("extends Trees.Tree")); } } } diff --git a/src/test/resources/platformImport/example/Trees.ecore b/src/test/resources/platformImport/example/Trees.ecore new file mode 100644 index 0000000..8e05870 --- /dev/null +++ b/src/test/resources/platformImport/example/Trees.ecore @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/src/test/resources/platformImport/example2/ColoredTree.ecore b/src/test/resources/platformImport/example2/ColoredTree.ecore new file mode 100644 index 0000000..d2c37cd --- /dev/null +++ b/src/test/resources/platformImport/example2/ColoredTree.ecore @@ -0,0 +1,12 @@ + + + + + + + + + + +