You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sk...@apache.org on 2021/03/22 11:47:35 UTC

[ignite-3] branch main updated: IGNITE-14114 Added Spinner ui element. Fixes #48

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

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


The following commit(s) were added to refs/heads/main by this push:
     new ba5467c  IGNITE-14114 Added Spinner ui element. Fixes #48
ba5467c is described below

commit ba5467c8a39e78e3b97ee12c0801bd8000b8029b
Author: Kirill Gusakov <kg...@gmail.com>
AuthorDate: Mon Mar 22 14:39:43 2021 +0300

    IGNITE-14114 Added Spinner ui element. Fixes #48
    
    Signed-off-by: Slava Koptilin <sl...@gmail.com>
---
 .../ignite/cli/builtins/node/NodeManager.java      | 17 ++---
 .../apache/ignite/cli/spec/NodeCommandSpec.java    |  2 -
 .../java/org/apache/ignite/cli/ui/ProgressBar.java | 28 +------
 .../java/org/apache/ignite/cli/ui/Spinner.java     | 72 +++++++++++++++++
 .../apache/ignite/cli/IgniteCliInterfaceTest.java  | 26 ++++---
 .../java/org/apache/ignite/cli/ui/SpinnerTest.java | 89 ++++++++++++++++++++++
 .../org/apache/ignite/cli/ui/package-info.java     | 21 +++++
 7 files changed, 207 insertions(+), 48 deletions(-)

diff --git a/modules/cli/src/main/java/org/apache/ignite/cli/builtins/node/NodeManager.java b/modules/cli/src/main/java/org/apache/ignite/cli/builtins/node/NodeManager.java
index 4d4d74b..ec93d8d 100644
--- a/modules/cli/src/main/java/org/apache/ignite/cli/builtins/node/NodeManager.java
+++ b/modules/cli/src/main/java/org/apache/ignite/cli/builtins/node/NodeManager.java
@@ -33,8 +33,8 @@ import java.util.stream.Stream;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.apache.ignite.cli.IgniteCLIException;
-import org.apache.ignite.cli.ui.ProgressBar;
 import org.apache.ignite.cli.builtins.module.ModuleRegistry;
+import org.apache.ignite.cli.ui.Spinner;
 import org.jline.terminal.Terminal;
 
 /**
@@ -54,9 +54,6 @@ public class NodeManager {
     /** Module registry. **/
     private final ModuleRegistry moduleRegistry;
 
-    /** System terminal. **/
-    private final Terminal terminal;
-
     /**
      * Creates node manager.
      *
@@ -66,7 +63,6 @@ public class NodeManager {
     @Inject
     public NodeManager(ModuleRegistry moduleRegistry, Terminal terminal) {
         this.moduleRegistry = moduleRegistry;
-        this.terminal = terminal;
     }
 
     /**
@@ -112,10 +108,9 @@ public class NodeManager {
 
             Process p = pb.start();
 
-            try (var bar = new ProgressBar(out, 100, terminal.getWidth())) {
-                bar.stepPeriodically(300);
+            try (var spinner = new Spinner(out, "Starting a new Ignite node")) {
 
-                if (!waitForStart("Apache Ignite started successfully!", logFile, NODE_START_TIMEOUT)) {
+                if (!waitForStart("Apache Ignite started successfully!", logFile, NODE_START_TIMEOUT, spinner)) {
                     p.destroyForcibly();
 
                     throw new IgniteCLIException("Node wasn't started during timeout period "
@@ -148,11 +143,13 @@ public class NodeManager {
     private static boolean waitForStart(
         String started,
         Path file,
-        Duration timeout
+        Duration timeout,
+        Spinner spinner
     ) throws IOException, InterruptedException {
         var start = System.currentTimeMillis();
 
         while ((System.currentTimeMillis() - start) < timeout.toMillis()) {
+            spinner.spin();
             LockSupport.parkNanos(LOG_FILE_POLL_INTERVAL.toNanos());
 
             var content = Files.readString(file);
@@ -212,7 +209,7 @@ public class NodeManager {
     }
 
     /**
-     * @param worksDir Ignite installation work dir.
+     * @param logDir Ignite installation work dir.
      * @param pidsDir Dir with nodes pids.
      * @return List of running nodes.
      */
diff --git a/modules/cli/src/main/java/org/apache/ignite/cli/spec/NodeCommandSpec.java b/modules/cli/src/main/java/org/apache/ignite/cli/spec/NodeCommandSpec.java
index 1ba83fe..fdcf9c2 100644
--- a/modules/cli/src/main/java/org/apache/ignite/cli/spec/NodeCommandSpec.java
+++ b/modules/cli/src/main/java/org/apache/ignite/cli/spec/NodeCommandSpec.java
@@ -74,8 +74,6 @@ public class NodeCommandSpec extends CategorySpec {
             PrintWriter out = spec.commandLine().getOut();
             ColorScheme cs = spec.commandLine().getColorScheme();
 
-            out.println("Starting a new Ignite node...");
-
             NodeManager.RunningNode node = nodeMgr.start(consistentId, ignitePaths.logDir,
                 ignitePaths.cliPidsDir(),
                 configPath,
diff --git a/modules/cli/src/main/java/org/apache/ignite/cli/ui/ProgressBar.java b/modules/cli/src/main/java/org/apache/ignite/cli/ui/ProgressBar.java
index c7dc044..55950ce 100644
--- a/modules/cli/src/main/java/org/apache/ignite/cli/ui/ProgressBar.java
+++ b/modules/cli/src/main/java/org/apache/ignite/cli/ui/ProgressBar.java
@@ -18,9 +18,8 @@
 package org.apache.ignite.cli.ui;
 
 import java.io.PrintWriter;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
+import java.time.Duration;
+import java.util.concurrent.locks.LockSupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import picocli.CommandLine.Help.Ansi;
@@ -44,9 +43,6 @@ public class ProgressBar implements AutoCloseable {
     /** Target width of bar in symbols. */
     private final int targetBarWidth;
 
-    /** Execute. */
-    private ScheduledExecutorService exec;
-
     /**
      * Creates a new progress bar.
      *
@@ -88,28 +84,10 @@ public class ProgressBar implements AutoCloseable {
         out.flush();
     }
 
-    /**
-     * Performs a single step every N milliseconds.
-     *
-     * @param interval Interval in milliseconds.
-     */
-    public void stepPeriodically(long interval) {
-        if (exec == null) {
-            exec = Executors.newSingleThreadScheduledExecutor();
-
-            exec.scheduleAtFixedRate(this::step, interval, interval, TimeUnit.MILLISECONDS);
-        }
-    }
-
     /** {@inheritDoc} */
     @Override public void close() {
         while (curr < max) {
-            try {
-                Thread.sleep(10);
-            }
-            catch (InterruptedException ignored) {
-                break;
-            }
+            LockSupport.parkNanos(Duration.ofMillis(10).toNanos());
 
             step();
         }
diff --git a/modules/cli/src/main/java/org/apache/ignite/cli/ui/Spinner.java b/modules/cli/src/main/java/org/apache/ignite/cli/ui/Spinner.java
new file mode 100644
index 0000000..4b35add
--- /dev/null
+++ b/modules/cli/src/main/java/org/apache/ignite/cli/ui/Spinner.java
@@ -0,0 +1,72 @@
+/*
+ * 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.ui;
+
+import java.io.PrintWriter;
+
+/**
+ * Simple ASCII spinner.
+ * It should be used for processes with unknown duration instead of {@link ProgressBar}
+ */
+public class Spinner implements AutoCloseable {
+    /** Writer for display spinner. */
+    private final PrintWriter out;
+
+    /** Text prefix for spinner. */
+    private final String spinnerPrefixText;
+
+    /** Spinner cycle counter. */
+    private int spinnerCnt;
+
+    /**
+     * @param out Writer to display spinner.
+     */
+    public Spinner(PrintWriter out) {
+        this(out, "");
+    }
+
+    /**
+     * @param out Writer to display spinner.
+     * @param spinnerPrefixText Spinner prefix text.
+     */
+    public Spinner(PrintWriter out, String spinnerPrefixText) {
+        this.out = out;
+        this.spinnerPrefixText = spinnerPrefixText;
+    }
+
+    /**
+     * Spin one more time.
+     */
+    public void spin() {
+        out.print("\r" + spinnerPrefixText + ".".repeat(1 + spinnerCnt % 3) + " ".repeat(2 - spinnerCnt % 3));
+        out.flush();
+
+        // Reset counter to protect it from overflow.
+        spinnerCnt = 1 + spinnerCnt % 3;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override public void close() {
+        out.print("\r" + spinnerPrefixText + "...");
+        out.println();
+
+        out.flush();
+    }
+}
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 31e454f..1946f2d 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
@@ -327,18 +327,22 @@ public class IgniteCliInterfaceTest extends AbstractCliTest {
             var exitCode = cli.execute(("node start " + nodeName + " --config conf.json").split(" "));
 
             Assertions.assertEquals(0, exitCode);
-            verify(nodeMgr).start(nodeName, ignitePaths.logDir, ignitePaths.cliPidsDir(), Path.of("conf.json"),
+
+            verify(nodeMgr).start(
+                nodeName,
+                ignitePaths.logDir,
+                ignitePaths.cliPidsDir(),
+                Path.of("conf.json"),
                 cli.getOut());
-            assertEquals("Starting a new Ignite node...\n\nNode is successfully started. To stop, type " +
-                    cli.getColorScheme().commandText("ignite node stop ") +
-                    cli.getColorScheme().parameterText(nodeName) + "\n\n" +
-                    "+---------------+---------+\n" +
-                    cli.getColorScheme().text("| @|bold Consistent ID|@ | node1   |\n") +
-                    "+---------------+---------+\n" +
-                    cli.getColorScheme().text("| @|bold PID|@           | 1       |\n") +
-                    "+---------------+---------+\n" +
-                    cli.getColorScheme().text("| @|bold Log File|@      | logfile |\n") +
-                    "+---------------+---------+\n",
+
+            assertEquals("\nNode is successfully started. To stop, type ignite node stop " + nodeName + "\n\n" +
+                "+---------------+---------+\n" +
+                "| Consistent ID | node1   |\n" +
+                "+---------------+---------+\n" +
+                "| PID           | 1       |\n" +
+                "+---------------+---------+\n" +
+                "| Log File      | logfile |\n" +
+                "+---------------+---------+\n",
                 out.toString());
         }
 
diff --git a/modules/cli/src/test/java/org/apache/ignite/cli/ui/SpinnerTest.java b/modules/cli/src/test/java/org/apache/ignite/cli/ui/SpinnerTest.java
new file mode 100644
index 0000000..9e7f5ee
--- /dev/null
+++ b/modules/cli/src/test/java/org/apache/ignite/cli/ui/SpinnerTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.ui;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ *
+ */
+public class SpinnerTest {
+    /** */
+    private PrintWriter out;
+
+    /** */
+    private ByteArrayOutputStream outputStream;
+
+    /**
+     *
+     */
+    @BeforeEach
+    public void setUp() {
+        outputStream = new ByteArrayOutputStream();
+        out = new PrintWriter(outputStream);
+    }
+
+    /**
+     *
+     */
+    @AfterEach
+    public void tearDown() throws IOException {
+        out.close();
+        outputStream.close();
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void testSpinner() {
+        var spinner = new Spinner(out, "Waiting");
+
+        spinner.spin();
+        assertEquals("\rWaiting.  ", outputStream.toString());
+
+        spinner.spin();
+        assertEquals("\rWaiting.  \rWaiting.. ", outputStream.toString());
+
+        spinner.spin();
+        assertEquals("\rWaiting.  \rWaiting.. \rWaiting...", outputStream.toString());
+
+        spinner.spin();
+        assertEquals("\rWaiting.  \rWaiting.. \rWaiting...\rWaiting.  ", outputStream.toString());
+    }
+
+    /**
+     *
+     */
+    @Test
+    public void testSpinnerClose() {
+        var spinner = new Spinner(out, "Waiting");
+
+        spinner.spin();
+        spinner.close();
+
+        assertEquals("\rWaiting.  \rWaiting..." + System.lineSeparator(), outputStream.toString());
+    }
+}
diff --git a/modules/cli/src/test/java/org/apache/ignite/cli/ui/package-info.java b/modules/cli/src/test/java/org/apache/ignite/cli/ui/package-info.java
new file mode 100644
index 0000000..fa2c3ba
--- /dev/null
+++ b/modules/cli/src/test/java/org/apache/ignite/cli/ui/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Contains tests for Ignite CLI UI elements.
+ */
+package org.apache.ignite.cli.ui;