diff --git a/core/esmf-aspect-model-java-generator/src/test-shared/java/org/eclipse/esmf/test/shared/compiler/JavaCompiler.java b/core/esmf-aspect-model-java-generator/src/test-shared/java/org/eclipse/esmf/test/shared/compiler/JavaCompiler.java index b6982cc72..7c34b2be6 100644 --- a/core/esmf-aspect-model-java-generator/src/test-shared/java/org/eclipse/esmf/test/shared/compiler/JavaCompiler.java +++ b/core/esmf-aspect-model-java-generator/src/test-shared/java/org/eclipse/esmf/test/shared/compiler/JavaCompiler.java @@ -100,25 +100,6 @@ protected Class findClass( final String name ) { private static Class defineAndLoad( final QualifiedName className, final ClassLoader classLoader ) { try { return (Class) classLoader.loadClass( className.toString() ); - // final List compilerOptions = List.of( "-classpath", System.getProperty( "java.class.path" ) ); - // compiler.getTask( null, manager, diagnosticListener, compilerOptions, null, compilerInput ).call(); - // return loadOrder.stream().collect( Collectors.toMap( Function.identity(), qualifiedName -> - // defineAndLoad( qualifiedName, manager ) ) ); - // } catch ( IOException e ) { - // throw new RuntimeException( e ); - // } - // } - // - // @SuppressWarnings( "unchecked" ) - // private static Class defineAndLoad( final QualifiedName className, final InMemoryClassFileManager manager ) { - // try { - // return (Class) new ClassLoader() { - // @Override - // protected Class findClass( final String name ) { - // final byte[] classBytes = manager.getOutput( name ).getBytes(); - // return defineClass( name, classBytes, 0, classBytes.length ); - // } - // }.loadClass( className.toString() ); } catch ( final ClassNotFoundException exception ) { throw new RuntimeException( exception ); } diff --git a/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/AspectModelResolver.java b/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/AspectModelResolver.java index 843acdf06..093d1d3b2 100644 --- a/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/AspectModelResolver.java +++ b/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/AspectModelResolver.java @@ -508,7 +508,6 @@ public static Try fileToUrn( final File inputFile ) { * @return the URN of the model element that corresponds to the file name and its location inside the models root */ public static AspectModelUrn urnFromModel( final VersionedModel model, final File file ) { - // TODO replace File file to URI uri final String aspectName = FilenameUtils.removeExtension( file.getName() ); return Streams.stream( model.getRawModel().listSubjects() ).filter( s -> aspectName.equals( s.getLocalName() ) ) .findFirst() diff --git a/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/GroupStrategy.java b/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/GroupStrategy.java index bf944e540..87d5c4b36 100644 --- a/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/GroupStrategy.java +++ b/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/GroupStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Robert Bosch Manufacturing Solutions GmbH + * Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH * * See the AUTHORS file(s) distributed with this work for additional * information regarding authorship. diff --git a/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/ResolutionStrategy.java b/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/ResolutionStrategy.java index 35f50952c..180154d31 100644 --- a/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/ResolutionStrategy.java +++ b/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/ResolutionStrategy.java @@ -17,10 +17,10 @@ import java.net.URI; import java.util.function.Function; +import org.apache.jena.rdf.model.Model; import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn; import io.vavr.control.Try; -import org.apache.jena.rdf.model.Model; /** * Represents one way to load and resolve an Aspect model from a given source. @@ -37,5 +37,7 @@ default Try applyUri( URI uri ) { return Try.of( () -> AspectModelUrn.fromUrn( uri ) ).flatMap( this ); } - InputStream read( URI uri ) throws Exception; + default InputStream read( URI uri ) throws Exception { + return uri.toURL().openStream(); + } } diff --git a/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/fs/StructuredModelsRoot.java b/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/fs/StructuredModelsRoot.java index aa70f74a0..299cbdb4d 100644 --- a/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/fs/StructuredModelsRoot.java +++ b/core/esmf-aspect-model-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/fs/StructuredModelsRoot.java @@ -15,7 +15,6 @@ import java.io.File; import java.net.URI; -import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; @@ -52,7 +51,7 @@ public StructuredModelsRoot( final URI resource ) { private static Try forUri( final URI uri ) { return getModelRoot( uri ) - .orElse( () -> Try.failure( new ModelResolutionException( "Could not locate models root directory for " + uri ) ) ); + .recoverWith( x -> Try.failure( new ModelResolutionException( "Could not locate models root directory for " + uri, x ) ) ); } @Override @@ -81,13 +80,8 @@ public static Try getModelRoot( final URI input ) { } private static Try findModelsRootFromUrl( URI input ) { - return Try.of( input::toURL ) - //change path to parent - .mapTry( url -> { - var path = Paths.get( url.getPath(), "..", "..", "..", "." ); - return new URL( url.getProtocol(), url.getHost(), url.getPort(), path.toString() ); - } ) - .mapTry( URL::toURI ); + return Try.of(() -> input.resolve( "../.." ) ) + .map( URI::normalize ); } private static Try findModelsRoot( File file ) { diff --git a/pom.xml b/pom.xml index 3e8808ae9..e7c45227a 100644 --- a/pom.xml +++ b/pom.xml @@ -69,6 +69,7 @@ core/esmf-test-aspect-models core/esmf-test-resources tools/esmf-aspect-model-maven-plugin + tools/esmf-aspect-model-github-resolver tools/samm-cli documentation @@ -104,6 +105,11 @@ esmf-aspect-model-resolver ${project.version} + + org.eclipse.esmf + esmf-aspect-model-github-resolver + ${project.version} + org.eclipse.esmf esmf-aspect-meta-model-types diff --git a/tools/esmf-aspect-model-github-resolver/README.md b/tools/esmf-aspect-model-github-resolver/README.md new file mode 100644 index 000000000..1fc441ced --- /dev/null +++ b/tools/esmf-aspect-model-github-resolver/README.md @@ -0,0 +1,3 @@ +# Aspect Model GitHub Resolver + +The plugin for the Aspect Model Resolver provides functionality to resolve aspect models from GitHub. diff --git a/tools/esmf-aspect-model-github-resolver/pom.xml b/tools/esmf-aspect-model-github-resolver/pom.xml new file mode 100644 index 000000000..be4bf80a2 --- /dev/null +++ b/tools/esmf-aspect-model-github-resolver/pom.xml @@ -0,0 +1,85 @@ + + + + + + org.eclipse.esmf + esmf-sdk-parent + DEV-SNAPSHOT + ../../pom.xml + + 4.0.0 + + esmf-aspect-model-github-resolver + ESMF Aspect Model GitHub Resolver + jar + + + + org.eclipse.esmf + esmf-aspect-model-resolver + + + org.apache.jena + jena-core + + + org.eclipse.esmf + esmf-aspect-model-urn + + + org.eclipse.esmf + esmf-semantic-aspect-meta-model + + + org.eclipse.esmf + esmf-aspect-meta-model-resolver + + + + + org.junit.jupiter + junit-jupiter + test + + + org.assertj + assertj-core + test + + + org.assertj + assertj-vavr + test + + + org.eclipse.esmf + esmf-test-aspect-models + test + + + org.eclipse.esmf + esmf-test-resources + test + + + org.mockito + mockito-core + 5.10.0 + test + + + diff --git a/tools/esmf-aspect-model-github-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/github/GitHubResolutionStrategy.java b/tools/esmf-aspect-model-github-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/github/GitHubResolutionStrategy.java new file mode 100644 index 000000000..cba00af62 --- /dev/null +++ b/tools/esmf-aspect-model-github-resolver/src/main/java/org/eclipse/esmf/aspectmodel/resolver/github/GitHubResolutionStrategy.java @@ -0,0 +1,104 @@ +package org.eclipse.esmf.aspectmodel.resolver.github; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; + +import org.apache.jena.rdf.model.Model; +import org.eclipse.esmf.aspectmodel.resolver.AspectModelResolver; +import org.eclipse.esmf.aspectmodel.resolver.ResolutionStrategy; +import org.eclipse.esmf.aspectmodel.resolver.fs.StructuredModelsRoot; +import org.eclipse.esmf.aspectmodel.resolver.services.TurtleLoader; +import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn; + +import io.vavr.control.Try; + +public class GitHubResolutionStrategy implements ResolutionStrategy { + private final StructuredModelsRoot root; + + public static void install() { + AspectModelResolver.register( null, uri -> Try.of( () -> new GitHubResolutionStrategy( uri ) ) ); + } + + public GitHubResolutionStrategy( URI baseUri ) { + if ( !isUrl( baseUri ) || !isGithubUrl( baseUri ) ) + throw new UnsupportedOperationException( "GitHub resolution strategy does not support URN: " + baseUri ); + else { + this.root = new StructuredModelsRoot( transformGithubUrlToContentLink( baseUri ).mapTry( URL::toURI ).get() ); + } + } + + @Override + public Try apply( AspectModelUrn urn ) { + return applyUri( root.determineAspectModelFile( urn ) ); + } + + @Override + public Try applyUri( URI uri ) { + return AspectModelUrn.from( uri ).flatMap( this::apply ) + .recoverWith( __ -> + toURL( uri ).flatMap( GitHubResolutionStrategy::loadModel ) + ) + .orElse( Try.failure( new UnsupportedOperationException( "GitHub resolution strategy does not support URI: " + uri ) ) ); + } + + @Override + public InputStream read( URI uri ) { + return Try.success( uri ) + .filter( GitHubResolutionStrategy::isGithubUrl ) + .flatMap( GitHubResolutionStrategy::toURL ) + .flatMap( GitHubResolutionStrategy::read ) + .getOrElse( (InputStream) null ); + } + + static Try toURL( URI uri ) { + if ( isGithubUrl( uri ) ) + return transformGithubUrlToContentLink( uri ); + else + return Try.of( uri::toURL ); + } + + static boolean isUrl( URI uri ) { + try { + //noinspection ResultOfMethodCallIgnored + uri.toURL(); + return true; + } catch ( MalformedURLException e ) { + return false; + } + } + + static boolean isGithubUrl( URI uri ) { + try { + String host = uri.toURL().getHost(); + return "github.com".equals( host ) + || "raw.githubusercontent.com".equals( host ); + } catch ( Exception e ) { + return false; + } + } + + static Try loadModel( URL link ) { + return read( link ) + .flatMap( TurtleLoader::loadTurtle ); + } + + static Try read( URL link ) { + return Try.withResources( link::openStream ) + .of( InputStream::readAllBytes ) + .map( ByteArrayInputStream::new ); + } + + static Try transformGithubUrlToContentLink( URI githubUrl ) { + String url = githubUrl.toString() + .replace( "github.com", "raw.githubusercontent.com" ) + .replace( "/blob/", "/" ); + return Try.of( () -> new URL( url ) ); + } + + public String toString() { + return "GitHubStrategy(root=" + root + ')'; + } +} diff --git a/tools/esmf-aspect-model-github-resolver/src/test/java/org/eclipse/esmf/aspectmodel/resolver/github/GitHubResolutionStrategyTest.java b/tools/esmf-aspect-model-github-resolver/src/test/java/org/eclipse/esmf/aspectmodel/resolver/github/GitHubResolutionStrategyTest.java new file mode 100644 index 000000000..f421aeb83 --- /dev/null +++ b/tools/esmf-aspect-model-github-resolver/src/test/java/org/eclipse/esmf/aspectmodel/resolver/github/GitHubResolutionStrategyTest.java @@ -0,0 +1,124 @@ +package org.eclipse.esmf.aspectmodel.resolver.github; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.io.IOException; +import java.net.URI; +import java.net.URL; +import java.nio.charset.Charset; + +import org.apache.commons.io.IOUtils; +import org.apache.jena.rdf.model.Model; +import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn; +import org.eclipse.esmf.samm.KnownVersion; +import org.eclipse.esmf.test.TestAspect; +import org.eclipse.esmf.test.TestModel; +import org.eclipse.esmf.test.TestResources; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import io.vavr.control.Try; + +class GitHubResolutionStrategyTest { + + private static final String GITHUB_URL = "https://github.com/eclipse-esmf/esmf-semantic-aspect-meta-model/blob/main/esmf-semantic-aspect-meta-model/" + + "src/test/resources/samm_2_0_0/aspect-shape/"; + private static final String GITHUB_CTX_URL = GitHubResolutionStrategy.transformGithubUrlToContentLink( URI.create( GITHUB_URL ) ).get().toString(); + private static final String GITHUB_FILE = "org.eclipse.esmf.test/1.0.0/TestAspect.ttl"; + private static final AspectModelUrn aspectModelUrn = AspectModelUrn.fromUrn( + "urn:samm:org.eclipse.esmf.test:1.0.0#TestAspect" ); + + private static String testModelContent; + private URL testUrl; + + private GitHubResolutionStrategy strategy; + + @BeforeAll + static void beforeAll() { + TestModel testModel = TestAspect.ASPECT_WITH_ENTITY; + testModelContent = TestModel.modelToString( TestResources.getModelWithoutResolution( testModel, KnownVersion.getLatest() ).getRawModel() ); + } + + @BeforeEach + void setUp() throws IOException { + testUrl = mock( URL.class ); + when( testUrl.getHost() ).thenReturn( "github.com" ); + // when( testUrl.toURI() ).thenReturn( URI.create( GITHUB_URL + GITHUB_FILE ) + when( testUrl.openStream() ).then( __ -> IOUtils.toInputStream( testModelContent, Charset.defaultCharset() ) ); + + strategy = new GitHubResolutionStrategy( URI.create( GITHUB_URL + GITHUB_FILE ) ); + } + + @Test + void applyReturnsModelWhenRootIsNotNullAndUrnIsSupported() { + try ( var __ = overrideGitHubUrlTransformation() ) { + + Try result = strategy.apply( aspectModelUrn ); + + assertThat( result.isSuccess() ).as( result.toString() ).isTrue(); + } + } + + @Test + void applyUriReturnsModelWhenUriIsAspectModelUrn() { + try ( var __ = overrideGitHubUrlTransformation() ) { + + Try result = strategy.applyUri( aspectModelUrn.getUrn() ); + + assertTrue( result.isSuccess() ); + } + } + + @Test + void applyUriReturnsFailureWhenUriIsNotAspectModelUrn() { + Try result = strategy.applyUri( URI.create( "https://github.com" ) ); + assertTrue( result.isFailure() ); + } + + @Test + void readReturnsInputStreamWhenUriIsGithubUrl() throws IOException { + try ( var __ = overrideGitHubUrlTransformation() ) { + try ( var is = strategy.read( URI.create( GITHUB_URL + GITHUB_FILE ) ) ) { + assertThat( is ).hasContent( testModelContent ); + } + } + } + + @Test + void readReturnsNullWhenUriIsNotGithubUrl() { + assertNull( strategy.read( URI.create( "https://notgithub.com" ) ) ); + } + + @Test + void toStringReturnsExpectedFormat() { + assertThat( strategy.toString() ) + .contains( "GitHubStrategy(root=" ) + .contains( GitHubResolutionStrategy.transformGithubUrlToContentLink( URI.create( GITHUB_URL ) ).get().toString() ) + .doesNotContain( GITHUB_FILE ); + } + + private MockedStatic overrideGitHubUrlTransformation() { + MockedStatic mocked = mockStatic( GitHubResolutionStrategy.class ); + + when( GitHubResolutionStrategy.transformGithubUrlToContentLink( + eq( URI.create( GITHUB_URL + GITHUB_FILE ) ) ) ) + .thenReturn( Try.success( testUrl ) ); + + when( GitHubResolutionStrategy.transformGithubUrlToContentLink( + eq( URI.create( GITHUB_CTX_URL + GITHUB_FILE ) ) ) ) + .thenReturn( Try.success( testUrl ) ); + + //tradeoff + when( GitHubResolutionStrategy.toURL( any() ) ).thenCallRealMethod(); + when( GitHubResolutionStrategy.isUrl( any() ) ).thenCallRealMethod(); + when( GitHubResolutionStrategy.isGithubUrl( any() ) ).thenCallRealMethod(); + when( GitHubResolutionStrategy.loadModel( any( URL.class ) ) ).thenCallRealMethod(); + when( GitHubResolutionStrategy.read( any( URL.class ) ) ).thenCallRealMethod(); + + return mocked; + } +} \ No newline at end of file diff --git a/tools/samm-cli/pom.xml b/tools/samm-cli/pom.xml index 4e2799014..6569ed71d 100644 --- a/tools/samm-cli/pom.xml +++ b/tools/samm-cli/pom.xml @@ -45,6 +45,10 @@ org.eclipse.esmf esmf-aspect-model-starter + + org.eclipse.esmf + esmf-aspect-model-github-resolver + com.fasterxml.jackson.core jackson-databind diff --git a/tools/samm-cli/src/main/java/org/eclipse/esmf/AbstractCommand.java b/tools/samm-cli/src/main/java/org/eclipse/esmf/AbstractCommand.java index 4ebf6f732..daddff2dc 100644 --- a/tools/samm-cli/src/main/java/org/eclipse/esmf/AbstractCommand.java +++ b/tools/samm-cli/src/main/java/org/eclipse/esmf/AbstractCommand.java @@ -13,6 +13,7 @@ package org.eclipse.esmf; +import static org.apache.commons.lang3.StringUtils.isBlank; import static org.eclipse.esmf.aspectmodel.resolver.AspectModelResolver.*; import java.io.File; @@ -68,14 +69,12 @@ protected Try loadAndResolveModel( final URI input, final Extern return versionedModel; } - protected boolean isFile( final URI uri ) { - return "file".equalsIgnoreCase( uri.getScheme() ); - } - protected File toFile( URI uri ) { - return isFile( uri ) + return "file".equalsIgnoreCase( uri.getScheme() ) ? new File( uri ) - : null; + : isBlank( uri.getScheme() ) + ? new File( uri.getPath() ) + : null; } protected AspectContext loadModelOrFail( final URI modelUri, final ExternalResolverMixin resolverConfig ) { diff --git a/tools/samm-cli/src/main/java/org/eclipse/esmf/SammCli.java b/tools/samm-cli/src/main/java/org/eclipse/esmf/SammCli.java index bf6af05f2..37b5e263c 100644 --- a/tools/samm-cli/src/main/java/org/eclipse/esmf/SammCli.java +++ b/tools/samm-cli/src/main/java/org/eclipse/esmf/SammCli.java @@ -19,6 +19,7 @@ import org.eclipse.esmf.aas.AasCommand; import org.eclipse.esmf.aspect.AspectCommand; +import org.eclipse.esmf.aspectmodel.resolver.github.GitHubResolutionStrategy; import org.fusesource.jansi.AnsiConsole; import picocli.CommandLine; @@ -88,6 +89,7 @@ int runWithExceptionHandler( final CommandLine.IExecutionExceptionHandler except public static void main( final String[] argv ) { NativeImageHelpers.ensureRequiredEnvironment(); + GitHubResolutionStrategy.install(); // The disabling color switch needs to be checked before PicoCLI initialization boolean disableColor = false; diff --git a/tools/samm-cli/src/main/java/org/eclipse/esmf/aspect/AspectCommand.java b/tools/samm-cli/src/main/java/org/eclipse/esmf/aspect/AspectCommand.java index 0e40d888d..ec6d469b2 100644 --- a/tools/samm-cli/src/main/java/org/eclipse/esmf/aspect/AspectCommand.java +++ b/tools/samm-cli/src/main/java/org/eclipse/esmf/aspect/AspectCommand.java @@ -13,6 +13,8 @@ package org.eclipse.esmf.aspect; +import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS; + import java.io.File; import java.net.URI; @@ -20,6 +22,7 @@ import org.eclipse.esmf.LoggingMixin; import org.eclipse.esmf.exception.SubCommandException; +import io.vavr.control.Try; import picocli.CommandLine; @CommandLine.Command( name = AspectCommand.COMMAND_NAME, @@ -49,16 +52,14 @@ public class AspectCommand extends AbstractCommand { public URI getInput() { if ( inputUri == null ) { - var file = new File( input ); - if ( file.exists() ) - inputUri = file.toURI(); - else { - try { - inputUri = URI.create( input ); - } catch ( final IllegalArgumentException e ) { - throw new SubCommandException( "The file does not exist or invalid input URI: " + input ); - } - } + inputUri = Try.success( input ) + .map( File::new ) + .filter( File::exists ) + .map( File::toURI ) + .orElse( Try.success( input ).map( in -> IS_OS_WINDOWS ? in.replaceAll( "\\\\", "/" ) : in ) + .map( URI::create ) ) + .recoverWith( e -> Try.failure( new SubCommandException( "The file does not exist or invalid input URI: " + input, e ) ) ) + .get(); } return inputUri; diff --git a/tools/samm-cli/src/main/java/org/eclipse/esmf/aspect/AspectMigrateCommand.java b/tools/samm-cli/src/main/java/org/eclipse/esmf/aspect/AspectMigrateCommand.java index 1555dd5b2..0b1157bb5 100644 --- a/tools/samm-cli/src/main/java/org/eclipse/esmf/aspect/AspectMigrateCommand.java +++ b/tools/samm-cli/src/main/java/org/eclipse/esmf/aspect/AspectMigrateCommand.java @@ -13,7 +13,8 @@ package org.eclipse.esmf.aspect; -import static org.eclipse.esmf.aspectmodel.resolver.AspectModelResolver.*; +import static org.eclipse.esmf.aspectmodel.resolver.AspectModelResolver.loadButNotResolveModel; +import static org.eclipse.esmf.aspectmodel.resolver.AspectModelResolver.uriToUrn; import java.io.File; import java.io.PrintWriter; diff --git a/tools/samm-cli/src/main/java/org/eclipse/esmf/exception/SubCommandException.java b/tools/samm-cli/src/main/java/org/eclipse/esmf/exception/SubCommandException.java index 1ef8e6207..8c09347d9 100644 --- a/tools/samm-cli/src/main/java/org/eclipse/esmf/exception/SubCommandException.java +++ b/tools/samm-cli/src/main/java/org/eclipse/esmf/exception/SubCommandException.java @@ -19,6 +19,10 @@ public class SubCommandException extends RuntimeException { public SubCommandException( final String subCommandName ) { this.subCommandName = subCommandName; } + public SubCommandException( final String subCommandName , final Throwable cause ) { + super( cause ); + this.subCommandName = subCommandName; + } public String getSubCommandName() { return subCommandName; diff --git a/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliTest.java b/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliTest.java index e2b37475a..e8f077247 100644 --- a/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliTest.java +++ b/tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliTest.java @@ -913,7 +913,7 @@ private String resolverCommand() { ? ".bat" : ".sh" ) ).getCanonicalPath(); final String modelsRoot = new File( System.getProperty( "user.dir" ) + "/target/classes/valid" ).getCanonicalPath(); final String metaModelVersion = KnownVersion.getLatest().toString().toLowerCase(); - return resolverScript + " " + modelsRoot + " " + metaModelVersion+ " "; + return resolverScript + " " + modelsRoot + " " + metaModelVersion + " "; } catch ( final IOException exception ) { throw new RuntimeException( exception ); }