You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vk...@apache.org on 2020/12/26 22:39:56 UTC

[ignite-3] branch ignite-3.0.0-alpha1 updated: IGNITE-13905 Support of cli extensions inside mvn modules (#18)

This is an automated email from the ASF dual-hosted git repository.

vkulichenko pushed a commit to branch ignite-3.0.0-alpha1
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/ignite-3.0.0-alpha1 by this push:
     new 7ed18c5  IGNITE-13905 Support of cli extensions inside mvn modules (#18)
7ed18c5 is described below

commit 7ed18c5367eb4c2ae10a34f36809c5123c0c44d1
Author: Kirill Gusakov <kg...@gmail.com>
AuthorDate: Sun Dec 27 01:35:35 2020 +0300

    IGNITE-13905 Support of cli extensions inside mvn modules (#18)
---
 .../cli/builtins/module/MavenArtifactResolver.java |  24 ++++-
 .../ignite/cli/builtins/module/ModuleManager.java  |  34 ++++++-
 .../ignite/cli/builtins/module/ModuleStorage.java  |  11 ++
 .../apache/ignite/cli/IgniteCliInterfaceTest.java  |  17 ++++
 .../cli/builtins/init/InitIgniteCommandTest.java   |  20 ++++
 .../ignite/cli/builtins/init/ModuleMangerTest.java | 112 +++++++++++++++++++++
 6 files changed, 212 insertions(+), 6 deletions(-)

diff --git a/modules/cli/src/main/java/org/apache/ignite/cli/builtins/module/MavenArtifactResolver.java b/modules/cli/src/main/java/org/apache/ignite/cli/builtins/module/MavenArtifactResolver.java
index 809d1ef..8f2cc47 100644
--- a/modules/cli/src/main/java/org/apache/ignite/cli/builtins/module/MavenArtifactResolver.java
+++ b/modules/cli/src/main/java/org/apache/ignite/cli/builtins/module/MavenArtifactResolver.java
@@ -63,6 +63,8 @@ public class MavenArtifactResolver {
     private final SystemPathResolver pathResolver;
     private PrintWriter out;
 
+    private static final String FILE_ARTIFACT_PATTERN = "[artifact](-[classifier]).[revision].[ext]";
+
     @Inject
     public MavenArtifactResolver(SystemPathResolver pathResolver) {
         this.pathResolver = pathResolver;
@@ -126,7 +128,7 @@ public class MavenArtifactResolver {
                         new RetrieveOptions()
                                 // this is from the envelop module
                                 .setConfs(new String[]{"default"})
-                                .setDestArtifactPattern(mavenRoot.toFile().getAbsolutePath() + "/[artifact](-[classifier]).[revision].[ext]")
+                                .setDestArtifactPattern(mavenRoot.resolve("[artifact](-[classifier]).[revision].[ext]").toFile().getAbsolutePath())
                 );
 
                 return new ResolveResult(
@@ -140,6 +142,24 @@ public class MavenArtifactResolver {
         }
     }
 
+    /**
+     * Get artifact file name by artifactId and version
+     *
+     * Note: Current implementation doesn't support artifacts with classifiers or non-jar packaging
+     * @param artfactId
+     * @param version
+     * @return
+     */
+    public static String fileNameByArtifactPattern(
+        String artfactId,
+        String version) {
+       return FILE_ARTIFACT_PATTERN
+           .replace("[artifact]", artfactId)
+           .replace("(-[classifier])", "")
+           .replace("[revision]", version)
+           .replace("[ext]", "jar");
+    }
+
     private Ivy ivyInstance(List<URL> repositories) {
         File tmpDir = null;
         try {
@@ -158,7 +178,7 @@ public class MavenArtifactResolver {
 
         IvySettings ivySettings = new IvySettings();
         ivySettings.setDefaultCache(tmpDir);
-        ivySettings.setDefaultCacheArtifactPattern("[artifact](-[classifier]).[revision].[ext]");
+        ivySettings.setDefaultCacheArtifactPattern(FILE_ARTIFACT_PATTERN);
 
         ChainResolver chainResolver = new ChainResolver();
         chainResolver.setName("chainResolver");
diff --git a/modules/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleManager.java b/modules/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleManager.java
index 823fe22..5fa9758 100644
--- a/modules/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleManager.java
+++ b/modules/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleManager.java
@@ -17,13 +17,16 @@
 
 package org.apache.ignite.cli.builtins.module;
 
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.net.URL;
 import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.jar.JarInputStream;
 import java.util.stream.Collectors;
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -44,6 +47,7 @@ public class ModuleManager {
     private final List<StandardModuleDefinition> modules;
 
     public static final String INTERNAL_MODULE_PREFIX = "_";
+    public static final String CLI_MODULE_MANIFEST_HEADER = "Apache-Ignite-CLI-Module";
 
     private PrintWriter out;
     private ColorScheme cs;
@@ -85,10 +89,11 @@ public class ModuleManager {
                 String mvnName = String.join(":", mavenCoordinates.groupId,
                     mavenCoordinates.artifactId, mavenCoordinates.version);
 
+                var isCliModule = isRootArtifactCliModule(mavenCoordinates.artifactId, mavenCoordinates.version, resolveResult.artifacts());
                 moduleStorage.saveModule(new ModuleStorage.ModuleDefinition(
                     mvnName,
-                    resolveResult.artifacts(),
-                    new ArrayList<>(),
+                    (isCliModule)? Collections.emptyList() : resolveResult.artifacts(),
+                    (isCliModule)? resolveResult.artifacts() : Collections.emptyList(),
                     ModuleStorage.SourceType.Maven,
                     name
                 ));
@@ -174,12 +179,23 @@ public class ModuleManager {
         return modules;
     }
 
+    private boolean isRootArtifactCliModule(String artifactId, String version, List<Path> artifacts) throws IOException {
+       var rootJarArtifactOpt = artifacts.stream()
+           .filter(p -> MavenArtifactResolver.fileNameByArtifactPattern(artifactId, version).equals(p.getFileName().toString()))
+           .findFirst();
+       if (rootJarArtifactOpt.isPresent()) {
+           try (var input = new FileInputStream(rootJarArtifactOpt.get().toFile())) {
+               var jarStream = new JarInputStream(input);
+               var manifest = jarStream.getManifest();
+               return "true".equals(manifest.getMainAttributes().getValue(CLI_MODULE_MANIFEST_HEADER));
+           }
+       } else return false;
+    }
+
     private boolean isStandardModuleName(String name) {
         return readBuiltinModules().stream().anyMatch(m -> m.name.equals(name));
     }
 
-
-
     private static List<StandardModuleDefinition> readBuiltinModules() {
         com.typesafe.config.ConfigObject config = ConfigFactory.load("builtin_modules.conf").getObject("modules");
         List<StandardModuleDefinition> modules = new ArrayList<>();
@@ -195,4 +211,14 @@ public class ModuleManager {
         return modules;
     }
 
+    private static class IgniteArtifacts {
+        private List<Path> serverArtifacts;
+        private List<Path> cliArtifacts;
+
+        public IgniteArtifacts(List<Path> serverArtifacts, List<Path> cliArtifacts) {
+            this.serverArtifacts = serverArtifacts;
+            this.cliArtifacts = cliArtifacts;
+        }
+    }
+
 }
diff --git a/modules/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleStorage.java b/modules/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleStorage.java
index 1e953ca..c8fb456 100644
--- a/modules/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleStorage.java
+++ b/modules/cli/src/main/java/org/apache/ignite/cli/builtins/module/ModuleStorage.java
@@ -95,6 +95,17 @@ public class ModuleStorage {
     public static class ModuleDefinition {
         public final String name;
         public final List<Path> artifacts;
+
+        @Override public String toString() {
+            return "ModuleDefinition{" +
+                "name='" + name + '\'' +
+                ", artifacts=" + artifacts +
+                ", cliArtifacts=" + cliArtifacts +
+                ", type=" + type +
+                ", source='" + source + '\'' +
+                '}';
+        }
+
         public final List<Path> cliArtifacts;
         public final SourceType type;
         public final String source;
diff --git a/modules/cli/src/test/java/org/apache/ignite/cli/IgniteCliInterfaceTest.java b/modules/cli/src/test/java/org/apache/ignite/cli/IgniteCliInterfaceTest.java
index 7703307..498df94 100644
--- a/modules/cli/src/test/java/org/apache/ignite/cli/IgniteCliInterfaceTest.java
+++ b/modules/cli/src/test/java/org/apache/ignite/cli/IgniteCliInterfaceTest.java
@@ -1,3 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package org.apache.ignite.cli;
 
 import java.io.ByteArrayOutputStream;
diff --git a/modules/cli/src/test/java/org/apache/ignite/cli/builtins/init/InitIgniteCommandTest.java b/modules/cli/src/test/java/org/apache/ignite/cli/builtins/init/InitIgniteCommandTest.java
index 52aa308..0c2c10e 100644
--- a/modules/cli/src/test/java/org/apache/ignite/cli/builtins/init/InitIgniteCommandTest.java
+++ b/modules/cli/src/test/java/org/apache/ignite/cli/builtins/init/InitIgniteCommandTest.java
@@ -1,7 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package org.apache.ignite.cli.builtins.init;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.nio.file.Files;
@@ -9,6 +27,7 @@ import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.jar.Manifest;
 import javax.inject.Inject;
 import io.micronaut.test.annotation.MockBean;
 import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
@@ -22,6 +41,7 @@ import org.junit.jupiter.api.io.TempDir;
 import org.mockito.junit.jupiter.MockitoExtension;
 import picocli.CommandLine.Help.ColorScheme;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
diff --git a/modules/cli/src/test/java/org/apache/ignite/cli/builtins/init/ModuleMangerTest.java b/modules/cli/src/test/java/org/apache/ignite/cli/builtins/init/ModuleMangerTest.java
new file mode 100644
index 0000000..130c294
--- /dev/null
+++ b/modules/cli/src/test/java/org/apache/ignite/cli/builtins/init/ModuleMangerTest.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.cli.builtins.init;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.jar.Attributes;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import javax.inject.Inject;
+import io.micronaut.test.annotation.MockBean;
+import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
+import org.apache.ignite.cli.IgnitePaths;
+import org.apache.ignite.cli.builtins.module.MavenArtifactResolver;
+import org.apache.ignite.cli.builtins.module.ModuleManager;
+import org.apache.ignite.cli.builtins.module.ModuleStorage;
+import org.apache.ignite.cli.builtins.module.ResolveResult;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
+import org.mockito.junit.jupiter.MockitoExtension;
+import picocli.CommandLine;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+@MicronautTest
+public class ModuleMangerTest {
+
+    @Inject MavenArtifactResolver mavenArtifactResolver;
+    @Inject ModuleManager moduleManager;
+    @Inject ModuleStorage moduleStorage;
+
+    @TempDir Path artifactsDir;
+    @TempDir Path homeDir;
+
+    @Test
+    void testCliModuleInstallation() throws IOException {
+       var rootArtifact = generateJar("test-module", "1.0", true);
+       var depArtifact = generateJar("dep-artifact", "0.1", false);
+       when(mavenArtifactResolver.resolve(any(), any(), any(), any(), any())).thenReturn(
+           new ResolveResult(Arrays.asList(rootArtifact, depArtifact)));
+
+       var ignitePaths = new IgnitePaths(homeDir.resolve("bin"), homeDir.resolve("work"), "n/a");
+       moduleManager.setOut(new PrintWriter(System.out));
+       moduleManager.setColorScheme(CommandLine.Help.defaultColorScheme(CommandLine.Help.Ansi.AUTO));
+       moduleManager.addModule("mvn:any-group:test-module:1.0", ignitePaths, Collections.emptyList());
+
+       verify(moduleStorage).saveModule(argThat(m ->
+           m.cliArtifacts.equals(Arrays.asList(rootArtifact, depArtifact)) &&
+                m.artifacts.equals(Collections.emptyList())));
+    }
+
+    @Test
+    void testServerModuleInstallation() throws IOException {
+        var rootArtifact = generateJar("test-module", "1.0", false);
+        var depArtifact = generateJar("dep-artifact", "0.1", false);
+        when(mavenArtifactResolver.resolve(any(), any(), any(), any(), any())).thenReturn(
+            new ResolveResult(Arrays.asList(rootArtifact, depArtifact)));
+
+        var ignitePaths = new IgnitePaths(homeDir.resolve("bin"), homeDir.resolve("work"), "n/a");
+        moduleManager.setOut(new PrintWriter(System.out));
+        moduleManager.setColorScheme(CommandLine.Help.defaultColorScheme(CommandLine.Help.Ansi.AUTO));
+        moduleManager.addModule("mvn:any-group:test-module:1.0", ignitePaths, Collections.emptyList());
+
+        verify(moduleStorage).saveModule(argThat(m ->
+            m.artifacts.equals(Arrays.asList(rootArtifact, depArtifact)) &&
+                m.cliArtifacts.equals(Collections.emptyList())));
+    }
+
+    @MockBean(MavenArtifactResolver.class) MavenArtifactResolver mavenArtifactResolver() {
+        return mock(MavenArtifactResolver.class);
+    }
+
+    @MockBean(ModuleStorage.class) ModuleStorage moduleStorage() {
+        return mock(ModuleStorage.class);
+    }
+
+    private Path generateJar(String artifactId, String version, boolean isCliModule) throws IOException {
+        Manifest manifest = new Manifest();
+        manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
+        var jarPath = artifactsDir.resolve(MavenArtifactResolver.fileNameByArtifactPattern(artifactId, version));
+        if (isCliModule)
+            manifest.getMainAttributes().put(new Attributes.Name(ModuleManager.CLI_MODULE_MANIFEST_HEADER), "true");
+        var target = new JarOutputStream(new FileOutputStream(jarPath.toString()), manifest);
+        target.close();
+        return jarPath;
+    }
+}