# ignite-gg-9830 WIP
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/3a2c39f2 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/3a2c39f2 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/3a2c39f2 Branch: refs/heads/ignite-286 Commit: 3a2c39f21500ee21bbb66ef73c5b62f724126a25 Parents: ce0d9dc Author: Andrey <anovi...@gridgain.com> Authored: Thu Apr 23 13:43:08 2015 +0700 Committer: Andrey <anovi...@gridgain.com> Committed: Thu Apr 23 16:37:43 2015 +0700 ---------------------------------------------------------------------- .../node/VisorNodeEventsCollectorTask.java | 52 +- .../internal/visor/util/VisorEventMapper.java | 13 + .../internal/visor/util/VisorTaskUtils.java | 2 +- .../ignite/visor/commands/VisorConsole.scala | 308 ++++++----- .../visor/commands/VisorConsoleCommand.scala | 77 --- .../ignite/visor/commands/VisorTextTable.scala | 541 ------------------ .../visor/commands/ack/VisorAckCommand.scala | 26 +- .../commands/alert/VisorAlertCommand.scala | 35 +- .../commands/cache/VisorCacheClearCommand.scala | 12 +- .../commands/cache/VisorCacheCommand.scala | 13 +- .../commands/cache/VisorCacheScanCommand.scala | 7 +- .../commands/cache/VisorCacheSwapCommand.scala | 8 +- .../commands/common/VisorConsoleCommand.scala | 66 +++ .../visor/commands/common/VisorTextTable.scala | 543 +++++++++++++++++++ .../config/VisorConfigurationCommand.scala | 132 ++--- .../commands/deploy/VisorDeployCommand.scala | 47 +- .../commands/disco/VisorDiscoveryCommand.scala | 48 +- .../commands/events/VisorEventsCommand.scala | 298 +++++----- .../visor/commands/gc/VisorGcCommand.scala | 111 ++-- .../visor/commands/kill/VisorKillCommand.scala | 53 +- .../visor/commands/node/VisorNodeCommand.scala | 47 +- .../visor/commands/ping/VisorPingCommand.scala | 41 +- .../commands/start/VisorStartCommand.scala | 34 +- .../commands/tasks/VisorTasksCommand.scala | 38 +- .../commands/top/VisorTopologyCommand.scala | 36 +- .../visor/commands/vvm/VisorVvmCommand.scala | 32 +- .../scala/org/apache/ignite/visor/visor.scala | 106 ++-- .../ignite/visor/VisorTextTableSpec.scala | 3 +- 28 files changed, 1228 insertions(+), 1501 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeEventsCollectorTask.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeEventsCollectorTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeEventsCollectorTask.java index ef4415a..a5f64d9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeEventsCollectorTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/node/VisorNodeEventsCollectorTask.java @@ -17,7 +17,6 @@ package org.apache.ignite.internal.visor.node; -import org.apache.ignite.cluster.*; import org.apache.ignite.compute.*; import org.apache.ignite.events.*; import org.apache.ignite.internal.processors.task.*; @@ -172,7 +171,7 @@ public class VisorNodeEventsCollectorTask extends VisorMultiNodeTask<VisorNodeEv /** * Job for task returns events data. */ - private static class VisorNodeEventsCollectorJob extends VisorJob<VisorNodeEventsCollectorTaskArg, + protected static class VisorNodeEventsCollectorJob extends VisorJob<VisorNodeEventsCollectorTaskArg, Collection<? extends VisorGridEvent>> { /** */ private static final long serialVersionUID = 0L; @@ -183,7 +182,7 @@ public class VisorNodeEventsCollectorTask extends VisorMultiNodeTask<VisorNodeEv * @param arg Job argument. * @param debug Debug flag. */ - private VisorNodeEventsCollectorJob(VisorNodeEventsCollectorTaskArg arg, boolean debug) { + protected VisorNodeEventsCollectorJob(VisorNodeEventsCollectorTaskArg arg, boolean debug) { super(arg, debug); } @@ -260,6 +259,10 @@ public class VisorNodeEventsCollectorTask extends VisorMultiNodeTask<VisorNodeEv return true; } + protected IgniteClosure<Event, VisorGridEvent> eventMapper() { + return EVT_MAPPER; + } + /** {@inheritDoc} */ @Override protected Collection<? extends VisorGridEvent> run(final VisorNodeEventsCollectorTaskArg arg) { final long startEvtTime = arg.timeArgument() == null ? 0L : System.currentTimeMillis() - arg.timeArgument(); @@ -286,46 +289,19 @@ public class VisorNodeEventsCollectorTask extends VisorMultiNodeTask<VisorNodeEv Long maxOrder = startEvtOrder; - for (Event e : evts) { - int tid = e.type(); - IgniteUuid id = e.id(); - String name = e.name(); - UUID nid = e.node().id(); - long t = e.timestamp(); - String msg = e.message(); - String shortDisplay = e.shortDisplay(); + IgniteClosure<Event, VisorGridEvent> mapper = eventMapper(); + for (Event e : evts) { maxOrder = Math.max(maxOrder, e.localOrder()); - if (e instanceof TaskEvent) { - TaskEvent te = (TaskEvent)e; + VisorGridEvent visorEvt = mapper.apply(e); - res.add(new VisorGridTaskEvent(tid, id, name, nid, t, msg, shortDisplay, - te.taskName(), te.taskClassName(), te.taskSessionId(), te.internal())); - } - else if (e instanceof JobEvent) { - JobEvent je = (JobEvent)e; - - res.add(new VisorGridJobEvent(tid, id, name, nid, t, msg, shortDisplay, - je.taskName(), je.taskClassName(), je.taskSessionId(), je.jobId())); - } - else if (e instanceof DeploymentEvent) { - DeploymentEvent de = (DeploymentEvent)e; - - res.add(new VisorGridDeploymentEvent(tid, id, name, nid, t, msg, shortDisplay, de.alias())); - } - else if (e instanceof DiscoveryEvent) { - DiscoveryEvent de = (DiscoveryEvent)e; - - ClusterNode node = de.eventNode(); - - String addr = F.first(node.addresses()); - - res.add(new VisorGridDiscoveryEvent(tid, id, name, nid, t, msg, shortDisplay, - node.id(), addr, node.isDaemon())); - } + if (visorEvt != null) + res.add(visorEvt); else - res.add(new VisorGridEvent(tid, id, name, nid, t, msg, shortDisplay)); + res.add(new VisorGridEvent( + e.type(), e.id(), e.name(), e.node().id(), e.timestamp(), e.message(), e.shortDisplay() + )); } // Update latest order in node local, if not empty. http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorEventMapper.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorEventMapper.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorEventMapper.java index 3cc7035..b9ff1aa 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorEventMapper.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorEventMapper.java @@ -17,7 +17,9 @@ package org.apache.ignite.internal.visor.util; +import org.apache.ignite.cluster.*; import org.apache.ignite.events.*; +import org.apache.ignite.internal.util.typedef.*; import org.apache.ignite.internal.visor.event.*; import org.apache.ignite.lang.*; @@ -65,6 +67,17 @@ public class VisorEventMapper implements IgniteClosure<Event, VisorGridEvent> { return new VisorGridDeploymentEvent(type, id, name, nid, ts, msg, shortDisplay, de.alias()); } + if (evt instanceof DiscoveryEvent) { + DiscoveryEvent de = (DiscoveryEvent)evt; + + ClusterNode node = de.eventNode(); + + String addr = F.first(node.addresses()); + + return new VisorGridDiscoveryEvent(type, id, name, nid, ts, msg, shortDisplay, + node.id(), addr, node.isDaemon()); + } + return null; } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorTaskUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorTaskUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorTaskUtils.java index 450b1da..7cfc18f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorTaskUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/util/VisorTaskUtils.java @@ -331,7 +331,7 @@ public class VisorTaskUtils { }; /** Mapper from grid event to Visor data transfer object. */ - private static final VisorEventMapper EVT_MAPPER = new VisorEventMapper(); + public static final VisorEventMapper EVT_MAPPER = new VisorEventMapper(); /** * Grabs local events and detects if events was lost since last poll. http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala index bc815b3..daca942 100644 --- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala +++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala @@ -17,10 +17,13 @@ package org.apache.ignite.visor.commands +import org.apache.ignite.IgniteSystemProperties._ import org.apache.ignite.internal.IgniteVersionUtils._ import org.apache.ignite.internal.util.scala.impl import org.apache.ignite.internal.util.{IgniteUtils => U} import org.apache.ignite.startup.cmdline.AboutDialog +import org.apache.ignite.visor.visor +import org.apache.ignite.visor.visor._ import jline.TerminalSupport import jline.console.ConsoleReader @@ -35,201 +38,181 @@ import java.text.SimpleDateFormat import scala.io._ -// Built-in commands. -// Note the importing of implicit conversions. -import org.apache.ignite.visor.commands.ack.VisorAckCommand -import org.apache.ignite.visor.commands.alert.VisorAlertCommand -import org.apache.ignite.visor.commands.cache.{VisorCacheClearCommand, VisorCacheCommand, VisorCacheSwapCommand} -import org.apache.ignite.visor.commands.config.VisorConfigurationCommand -import org.apache.ignite.visor.commands.deploy.VisorDeployCommand -import org.apache.ignite.visor.commands.disco.VisorDiscoveryCommand -import org.apache.ignite.visor.commands.events.VisorEventsCommand -import org.apache.ignite.visor.commands.gc.VisorGcCommand -import org.apache.ignite.visor.commands.kill.VisorKillCommand -import org.apache.ignite.visor.commands.node.VisorNodeCommand -import org.apache.ignite.visor.commands.ping.VisorPingCommand -import org.apache.ignite.visor.commands.start.VisorStartCommand -import org.apache.ignite.visor.commands.tasks.VisorTasksCommand -import org.apache.ignite.visor.commands.top.VisorTopologyCommand -import org.apache.ignite.visor.commands.vvm.VisorVvmCommand -import org.apache.ignite.visor.visor -import org.apache.ignite.visor.visor._ - /** * Command line Visor. */ -object VisorConsole extends App { +class VisorConsole { /** Version number. */ - private final val VISOR_VER = VER_STR - - /** Release date. */ - private final val VISOR_RELEASE_DATE = RELEASE_DATE_STR + protected def version() = VER_STR /** Copyright. */ - private final val VISOR_COPYRIGHT = COPYRIGHT - - /** Release date (another format). */ - private final val releaseDate = new SimpleDateFormat("ddMMyyyy").parse(VISOR_RELEASE_DATE) - - // Pre-initialize built-in commands. - VisorAckCommand - VisorAlertCommand - VisorCacheCommand - VisorCacheClearCommand - VisorCacheSwapCommand - VisorConfigurationCommand - VisorDeployCommand - VisorDiscoveryCommand - VisorEventsCommand - VisorGcCommand - VisorKillCommand - VisorNodeCommand - VisorPingCommand - VisorTopologyCommand - VisorStartCommand - VisorTasksCommand - VisorVvmCommand - - // Setting up Mac OS specific system menu. - customizeUI() - - // Wrap line symbol for user input. - private val wrapLine = if (U.isWindows) "^" else "\\" - - private val emptyArg = "^([a-zA-z!?]+)$".r - private val varArg = "^([a-zA-z!?]+)\\s+(.+)$".r + protected def copyright() = COPYRIGHT - private var line: String = null + /** Release date. */ + protected def releaseDate() = new SimpleDateFormat("ddMMyyyy").parse(RELEASE_DATE_STR) - private val buf = new StringBuilder + /** Program name. */ + protected val progName = sys.props.getOrElse(IGNITE_PROG_NAME, "ignitevisorcmd") - line = args.mkString(" ") + /** + * Built-in commands. + */ + protected def addCommands() { + // Note the importing of implicit conversions. + org.apache.ignite.visor.commands.ack.VisorAckCommand + org.apache.ignite.visor.commands.alert.VisorAlertCommand + org.apache.ignite.visor.commands.cache.VisorCacheClearCommand + org.apache.ignite.visor.commands.cache.VisorCacheCommand + org.apache.ignite.visor.commands.cache.VisorCacheSwapCommand + org.apache.ignite.visor.commands.config.VisorConfigurationCommand + org.apache.ignite.visor.commands.deploy.VisorDeployCommand + org.apache.ignite.visor.commands.disco.VisorDiscoveryCommand + org.apache.ignite.visor.commands.events.VisorEventsCommand + org.apache.ignite.visor.commands.gc.VisorGcCommand + org.apache.ignite.visor.commands.kill.VisorKillCommand + org.apache.ignite.visor.commands.node.VisorNodeCommand + org.apache.ignite.visor.commands.ping.VisorPingCommand + org.apache.ignite.visor.commands.start.VisorStartCommand + org.apache.ignite.visor.commands.tasks.VisorTasksCommand + org.apache.ignite.visor.commands.top.VisorTopologyCommand + org.apache.ignite.visor.commands.vvm.VisorVvmCommand + } - val argLst = parseArgs(args.mkString(" ")) + protected def parse(args: String) = { + val argLst = parseArgs(args) - val batchFile = argValue("b", argLst) - val batchCommand = argValue("e", argLst) + if (hasArgFlag("?", argLst) || hasArgFlag("help", argLst)) { + println("Usage:") + println(s" $progName [?]|[{-v}{-np}]|[{-b=<batch commands file path>} {-e=command1;command2}]") + println(" Where:") + println(" ?, /help, -help - show this message.") + println(" -v - verbose mode (quiet by default).") + println(" -np - no pause on exit (pause by default)") + println(" -b - batch mode with file)") + println(" -e - batch mode with commands)") - if (batchFile.isDefined && batchCommand.isDefined) { - visor.warn( - "Illegal options can't contains both command file and commands", - "Usage: ignitevisorcmd {-b=<batch commands file path>} {-e=command1;command2}" - ) + visor.quit() + } - visor.quit() + argLst } - var batchStream: Option[String] = None - - batchFile.foreach(name => { - val f = U.resolveIgnitePath(name) + protected def buildReader(argLst: ArgList) = { + val batchFile = argValue("b", argLst) + val batchCommand = argValue("e", argLst) - if (f == null) { + if (batchFile.isDefined && batchCommand.isDefined) { visor.warn( - "Can't find batch commands file: " + name, - "Usage: ignitevisorcmd {-b=<batch command file path>} {-e=command1;command2}" + "Illegal options can't contains both command file and commands", + s"Usage: $progName {-b=<batch commands file path>} {-e=command1;command2}" ) visor.quit() } - batchStream = Some(Source.fromFile(f).getLines().mkString("\n")) - }) + var batchStream: Option[String] = None - batchCommand.foreach(commands => batchStream = Some(commands.replaceAll(";", "\n"))) + batchFile.foreach(name => { + val f = U.resolveIgnitePath(name) - val inputStream = batchStream match { - case Some(cmd) => new ByteArrayInputStream((cmd + "\nquit\n").getBytes("UTF-8")) - case None => new FileInputStream(FileDescriptor.in) - } + if (f == null) { + visor.warn( + "Can't find batch commands file: " + name, + s"Usage: $progName {-b=<batch command file path>} {-e=command1;command2}" + ) - // Workaround for IDEA terminal. - val term = try { - Class.forName("com.intellij.rt.execution.application.AppMain") + visor.quit() + } - new TerminalSupport(true) {} - } catch { - case ignored: ClassNotFoundException => null - } + batchStream = Some(Source.fromFile(f).getLines().mkString("\n")) + }) - private val reader = new ConsoleReader(inputStream, System.out, term) + batchCommand.foreach(commands => batchStream = Some(commands.replaceAll(";", "\n"))) - reader.addCompleter(new VisorCommandCompleter(visor.commands)) - reader.addCompleter(new VisorFileNameCompleter()) + val inputStream = batchStream match { + case Some(cmd) => new ByteArrayInputStream((cmd + "\nquit\n").getBytes("UTF-8")) + case None => new FileInputStream(FileDescriptor.in) + } - private def isHelp(arg: String): Boolean = { - val s = arg.trim.toLowerCase + // Workaround for IDEA terminal. + val term = try { + Class.forName("com.intellij.rt.execution.application.AppMain") - "?" == s || s.endsWith("help") - } + new TerminalSupport(false) {} + } catch { + case ignored: ClassNotFoundException => null + } + + val reader = new ConsoleReader(inputStream, System.out, term) + + reader.addCompleter(new VisorCommandCompleter(visor.commands)) + reader.addCompleter(new VisorFileNameCompleter()) - if (args.length > 0 && isHelp(args(0))) { - println("Usage:") - println(" ignitevisorcmd [?]|[{-v}{-np}]|[{-b=<batch commands file path>} {-e=command1;command2}]") - println(" Where:") - println(" ?, /help, -help - show this message.") - println(" -v - verbose mode (quiet by default).") - println(" -np - no pause on exit (pause by default)") - println(" -b - batch mode with file)") - println(" -e - batch mode with commands)") - - System.exit(0) + reader } - welcomeMessage() + protected def mainLoop(reader: ConsoleReader) { + welcomeMessage() - private var ok = true + var ok = true - while (ok) { - line = reader.readLine("visor> ") + // Wrap line symbol for user input. + val wrapLine = if (U.isWindows) "^" else "\\" - ok = line != null + val emptyArg = "^([a-zA-z!?]+)$".r + val varArg = "^([a-zA-z!?]+)\\s+(.+)$".r - if (ok) { - line = line.trim + var line: String = null - if (line.endsWith(wrapLine)) { - buf.append(line.dropRight(1)) - } - else { - if (buf.size != 0) { - buf.append(line) + val buf = new StringBuilder + + while (ok) { + line = reader.readLine("visor> ") + + ok = line != null - line = buf.toString() + if (ok) { + line = line.trim - buf.clear() + if (line.endsWith(wrapLine)) { + buf.append(line.dropRight(1)) } + else { + if (buf.size != 0) { + buf.append(line) + + line = buf.toString() + + buf.clear() + } - try { - line match { - case emptyArg(c) => - visor.searchCmd(c) match { - case Some(cmdHolder) => cmdHolder.impl.invoke() - case _ => adviseToHelp(c) - } - case varArg(c, args) => - visor.searchCmd(c) match { - case Some(cmdHolder) => cmdHolder.impl.invoke(args.trim) - case _ => adviseToHelp(c) - } - case s if "".equals(s.trim) => // Ignore empty user input. - case _ => adviseToHelp(line) + try { + line match { + case emptyArg(c) => + visor.searchCmd(c) match { + case Some(cmdHolder) => cmdHolder.emptyArgs() + case _ => adviseToHelp(c) + } + case varArg(c, a) => + visor.searchCmd(c) match { + case Some(cmdHolder) => cmdHolder.withArgs(a.trim) + case _ => adviseToHelp(c) + } + case s if "".equals(s.trim) => // Ignore empty user input. + case _ => adviseToHelp(line) + } + } catch { + case ignore: Exception => adviseToHelp(line) } - } catch { - case ignore: Exception => adviseToHelp(line) } } } } - def terminalWidth() = reader.getTerminal.getWidth - - def consoleReader() = reader - /** * Prints standard 'Invalid command' error message. */ - private def adviseToHelp(input: String) { + protected def adviseToHelp(input: String) { visor.warn( "Invalid command name: '" + input + "'", "Type 'help' to print commands list." @@ -239,20 +222,31 @@ object VisorConsole extends App { /** * Print banner, hint message on start. */ - private def welcomeMessage() { - visor.status() + protected def welcomeMessage() { + println("___ _________________________ ________" + NL + + "__ | / /____ _/__ ___/__ __ \\___ __ \\" + NL + + "__ | / / __ / _____ \\ _ / / /__ /_/ /" + NL + + "__ |/ / __/ / ____/ / / /_/ / _ _, _/" + NL + + "_____/ /___/ /____/ \\____/ /_/ |_|" + NL + + NL + + "ADMIN CONSOLE" + NL + + copyright()) + + nl() + + status() println("\nType 'help' for more information.") println("Type 'open' to join the grid.") println("Type 'quit' to quit form Visor console.") - visor.nl() + nl() } /** - * Setting up mac os specific menu. + * Setting up Mac OS specific system menu. */ - private def customizeUI() { + protected def addAboutDialog() { def urlIcon(iconName: String) = { val iconPath = "org/apache/ignite/startup/cmdline/" + iconName @@ -281,7 +275,7 @@ object VisorConsole extends App { new java.lang.reflect.InvocationHandler { def invoke(proxy: Any, mth: java.lang.reflect.Method, args: Array[Object]) = { AboutDialog.centerShow("Visor - Ignite Shell Console", bannerIconUrl.toExternalForm, - VISOR_VER, releaseDate, VISOR_COPYRIGHT) + version(), releaseDate(), copyright()) null } @@ -296,6 +290,20 @@ object VisorConsole extends App { } } +object VisorConsole extends VisorConsole with App { + addAboutDialog() + + addCommands() + + private val argLst = parse(args.mkString(" ")) + + private val reader = buildReader(argLst) + + scala.Console.withIn(reader.getInput) { + mainLoop(reader) + } +} + /** * Visor command list completer. * http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsoleCommand.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsoleCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsoleCommand.scala deleted file mode 100644 index 7192a87..0000000 --- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsoleCommand.scala +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.visor.commands - -import org.apache.ignite.internal.util.scala.impl -import org.apache.ignite.visor.visor - -/** - * Command implementation. - */ -trait VisorConsoleCommand { - /** - * Command without arguments. - */ - def invoke() - - /** - * Command with arguments. - * - * @param args - arguments as string. - */ - def invoke(args: String) -} - -/** - * Singleton companion object. - */ -object VisorConsoleCommand { - /** - * Create `VisorConsoleCommand`. - * - * @param emptyArgs Function to execute in case of no args passed to command. - * @param withArgs Function to execute in case of some args passed to command. - * @return New instance of `VisorConsoleCommand`. - */ - def apply(emptyArgs: () => Unit, withArgs: (String) => Unit) = { - new VisorConsoleCommand { - @impl def invoke() = emptyArgs.apply() - - @impl def invoke(args: String) = withArgs.apply(args) - } - } - - /** - * Create `VisorConsoleCommand`. - * - * @param emptyArgs Function to execute in case of no args passed to command. - * @return New instance of `VisorConsoleCommand`. - */ - def apply(emptyArgs: () => Unit) = { - new VisorConsoleCommand { - @impl def invoke() = emptyArgs.apply() - - @impl def invoke(args: String) { - visor.warn( - "Invalid arguments for command without arguments.", - "Type 'help' to print commands list." - ) - } - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorTextTable.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorTextTable.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorTextTable.scala deleted file mode 100644 index 5cb40b9..0000000 --- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorTextTable.scala +++ /dev/null @@ -1,541 +0,0 @@ -/* - * 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.visor.commands - -import org.apache.ignite.internal.util.GridStringBuilder -import org.apache.ignite.visor.commands.VisorTextTable._ - -import scala.collection.Traversable - -/** - * ==Overview== - * Provides `ASCII`-based table with minimal styling support. - */ -class VisorTextTable { - /** - * Cell style. - */ - private sealed class Style( - var leftPad: Int = 1, // >= 0 - var rightPad: Int = 1, // >= 0 - var align: String = "center" // center, left, right - ) { - assert(leftPad >= 0) - assert(rightPad >= 0) - assert(align != null) - - /** - * Gets overall padding (left + right). - */ - def padding: Int = - leftPad + rightPad - } - - /** - * Cell style. - */ - private object Style { - /** - * - * @param sty Style. - */ - def apply(sty: String): Style = { - assert(sty != null) - - val cs = new Style - - if (!sty.isEmpty) { - for (e <- sty.split(',')) { - val a = e.split(":") - - assert(a.length == 2, "Invalid cell style: " + e.trim) - - val a0 = a(0).trim - val a1 = a(1).trim - - a0 match { - case "leftPad" => cs.leftPad = a1.toInt - case "rightPad" => cs.rightPad = a1.toInt - case "align" => cs.align = a1 - case _ => assert(false, "Invalid style: " + e.trim) - } - } - } - - cs - } - } - - /** - * Cell holder. - */ - private sealed case class Cell(style: Style, lines: Seq[String]) { - assert(style != null) - assert(lines != null) - - /** - * Cell's calculated width including padding. - */ - lazy val width = - if (height > 0) - style.padding + lines.max(Ordering.by[String, Int](_.length)).length - else - style.padding - - /** - * Gets height of the cell. - */ - def height: Int = lines.length - } - - /** - * Margin holder. - */ - private sealed case class Margin( - top: Int = 0, - right: Int = 0, - bottom: Int = 0, - left: Int = 0) { - assert(top >= 0) - assert(right >= 0) - assert(bottom >= 0) - assert(left >= 0) - } - - /** */ - private val NL = '\n' - - /** Headers. */ - private val hdr = collection.mutable.ArrayBuffer.empty[Cell] - - /** Rows. */ - private val rows = collection.mutable.ArrayBuffer.empty[Seq[Cell]] - - /** Current row, if any. */ - private var curRow: collection.mutable.ArrayBuffer[Cell] = null - - /** Table's margin, if any. */ - private var margin: Margin = Margin() - - /** Default row cell style, if any. */ - private var rowSty: String = "align:left" - - /** Default header cell style, if any. */ - private var hdrSty: String = "align:center" - - /** - * Flag indicating whether or not to draw inside horizontal lines - * between individual rows. - */ - var insideBorder = false - - /** - * Flag indicating whether of not to automatically draw horizontal lines - * for multiline rows. - */ - var autoBorder = true - - /** - * Maximum width of the cell. If any line in the cell exceeds this width - * it will be cut in two or more lines. - * - * '''NOTE''': it doesn't include into account the padding. Only the actual - * string length is counted. - */ - var maxCellWidth = Int.MaxValue - - /** - * - * @param ch Char. - * @param len Dash length. - */ - private def dash(ch: Char, len: Int): String = { - assert(len >= 0) - - new String().padTo(len, ch) - } - - /** - * - * @param s String. - * @param len Dash length. - */ - private def dash(s: String, len: Int): String = { - assert(len >= 0) - - var i = 0 - - val sb = new GridStringBuilder(s.length * len) - - while (i < len) { - sb.a(s) - - i += 1 - } - - sb.toString - } - - /** - * - * @param len Length. - */ - private def blank(len: Int): String = - dash(' ', len) - - /** - * Sets table's margin. - * - * @param top Top margin. - * @param right Right margin. - * @param bottom Bottom margin. - * @param left Left margin. - */ - def margin(top: Int = 0, right: Int = 0, bottom: Int = 0, left: Int = 0) { - assert(top >= 0) - assert(right >= 0) - assert(bottom >= 0) - assert(left >= 0) - - margin = Margin(top, right, bottom, left) - } - - /** - * Starts data row. - */ - def startRow() { - assert(curRow == null) - - curRow = collection.mutable.ArrayBuffer.empty[Cell] - } - - /** - * Ends data row. - */ - def endRow() { - assert(curRow.nonEmpty) - - rows += curRow - - curRow = null - } - - /** - * Adds row (one or more row cells). - * - * @param cells Row cells. For multi-line cells - use `Seq(...)`. - */ - def +=(cells: Any*): VisorTextTable = { - startRow() - - cells foreach { - case s: scala.collection.Iterable[Any] => addRowCell(s.toSeq: _*) - case p: Product => addRowCell(p.productIterator.toSeq: _*) - case a => addRowCell(a) - } - - endRow() - - this - } - - /** - * Adds header (one or more header cells). - * - * @param cells Header cells. For multi-line cells - use `Seq(...)`. - */ - def #=(cells: Any*): VisorTextTable = { - cells foreach { - case s: scala.collection.Iterable[Any] => addHeaderCell(s.toSeq: _*) - case p: Product => addHeaderCell(p.productIterator.toSeq: _*) - case a => addHeaderCell(a) - } - - this - } - - /** - * Adds single header cell. - * - * @param lines One or more cell lines. - */ - def addHeaderCell(lines: Any*): VisorTextTable = { - assert(lines != null) - assert(lines.length > 0) - - // Break up long line into multiple ones - if necessary. - val lst = lines flatten(_.toString.grouped(maxCellWidth)) - - hdr += Cell(Style(hdrSty), lst) - - this - } - - /** - * Gets current row style. - */ - def rowStyle = - rowSty - - /** - * Sets current row style. - * - * @param rowSty Row style to set. - */ - def rowStyle(rowSty: String) { - this.rowSty = rowSty - } - - /** - * Gets current header style. - */ - def headerStyle = - rowSty - - /** - * Sets current header style. - * - * @param hdrSty Header style to set. - */ - def headerStyle(hdrSty: String) { - this.hdrSty = hdrSty - } - - /** - * Adds single row cell. - * - * @param lines One or more row cells. Multiple lines will be printed on separate lines. - */ - def addRowCell(lines: Any*): VisorTextTable = { - assert(lines != null) - assert(lines.length >= 0) - assert(curRow != null) - - // Break up long line into multiple ones - if necessary. - val lst = lines flatten { - case it: Traversable[_] => it.flatten(_.toString.grouped(maxCellWidth)) - case null => Seq("") - case obj => obj.toString.grouped(maxCellWidth) - } - - curRow += Cell(Style(rowSty), lst) - - this - } - - /** - * - * @param txt Text to align. - * @param width Width already accounts for padding. - * @param sty Style. - */ - private def aligned(txt: String, width: Int, sty: Style): String = { - assert(txt != null) - assert(width > 0) - assert(sty != null) - assert(txt.length <= width) - - val d = width - txt.length - - val styTxt = txt - - sty.align.trim match { - case "center" => - blank(d / 2) + styTxt + blank(d / 2 + d % 2) - case "left" => - blank(sty.leftPad) + styTxt + blank(d - sty.leftPad) - case "right" => - blank(d - sty.rightPad) + styTxt + blank(sty.rightPad) - case _ => - throw new AssertionError("Invalid align option in: " + sty) - } - } - - /** - * Renders this table. - */ - def render() { - // Make sure table is not empty. - if (hdr.isEmpty && rows.isEmpty) - return - - var colsNum = -1 - - val isHdr = hdr.nonEmpty - - if (isHdr) - colsNum = hdr.size - - // Calc number of columns and make sure all rows are even. - for (r <- rows) - if (colsNum == -1) - colsNum = r.size - else if (colsNum != r.size) - assert(false, "Table with uneven rows.") - - assert(colsNum > 0) - - // At this point all rows in the table have the - // the same number of columns. - - val colWs = new Array[Int](colsNum) // Column widths. - val rowHs = new Array[Int](rows.length) // Row heights. - - // Header height. - var hdrH = 0 - - // Initialize column widths with header row (if any). - for (i <- 0 until hdr.size) { - val c = hdr(i) - - colWs(i) = c.width - - hdrH = math.max(hdrH, c.height) - } - - // Calc row heights and column widths. - for (i <- 0 until rows.length; j <- 0 until colsNum) { - val c = rows(i)(j) - - rowHs(i) = math.max(rowHs(i), c.height) - colWs(j) = math.max(colWs(j), c.width) - } - - // Table width without the border. - val tblW = colWs.sum + colsNum - 1 - - val tbl = new GridStringBuilder() - - // Top margin. - for (i <- 0 until margin.top) - tbl.a(" ").a(NL) - - // Print header, if any. - if (isHdr) { - tbl.a(blank(margin.left)).a(HDR_CRS).a(dash(HDR_HOR, tblW)).a(HDR_CRS).a(blank(margin.right)).a(NL) - - for (i <- 0 until hdrH) { - // Left margin and '|'. - tbl.a(blank(margin.left)).a(HDR_VER) - - for (j <- 0 until hdr.size) { - val c = hdr(j) - - if (i >= 0 && i < c.height) - tbl.a(aligned(c.lines(i), colWs(j), c.style)) - else - tbl.a(blank(colWs(j))) - - tbl.a(HDR_VER) // '|' - } - - // Right margin. - tbl.a(blank(margin.right)).a(NL) - } - - tbl.a(blank(margin.left)).a(HDR_CRS).a(dash(HDR_HOR, tblW)).a(HDR_CRS).a(blank(margin.right)).a(NL) - } - else - tbl.a(blank(margin.left)).a(ROW_CRS).a(dash(ROW_HOR, tblW)).a(ROW_CRS).a(blank(margin.right)).a(NL) - - // Print rows, if any. - if (rows.nonEmpty) { - val horLine = (i: Int) => { - // Left margin and '+' - tbl.a(blank(margin.left)).a(ROW_CRS) - - for (k <- 0 until rows(i).size) - tbl.a(dash(ROW_HOR, colWs(k))).a(ROW_CRS) - - // Right margin. - tbl.a(blank(margin.right)).a(NL) - } - - for (i <- 0 until rows.size) { - val r = rows(i) - - val rowH = rowHs(i) - - if (i > 0 && ((rowH > 1 && autoBorder) || insideBorder) && rowHs(i - 1) == 1) - horLine(i) - - for (j <- 0 until rowH) { - // Left margin and '|' - tbl.a(blank(margin.left)).a(ROW_VER) - - for (k <- 0 until r.size) { - val c = r(k) - val w = colWs(k) - - if (j < c.height) - tbl.a(aligned(c.lines(j), w, c.style)) - else - tbl.a(blank(w)) - - tbl.a(ROW_VER) // '|' - } - - // Right margin. - tbl.a(blank(margin.right)).a(NL) - } - - if (i < rows.size - 1 && ((rowH > 1 && autoBorder) || insideBorder)) - horLine(i) - } - - tbl.a(blank(margin.left)).a(ROW_CRS).a(dash(ROW_HOR, tblW)).a(ROW_CRS).a(blank(margin.right)).a(NL) - } - - // Bottom margin. - for (i <- 1 to margin.bottom) - tbl.a(" ").a(NL) - - print(tbl.toString) - } - - def nonEmpty = rows.nonEmpty -} - -/** - * Static context. - */ -object VisorTextTable { - /** Table header horizontal line. */ - private val HDR_HOR = "=" - - /** Table header vertical line. */ - private val HDR_VER = "|" - - /** Table header crossroad line. */ - private val HDR_CRS = "+" - - /** Table row horizontal line. */ - private val ROW_HOR = '-' - - /** Table row vertical line. */ - private val ROW_VER = '|' - - /** Table row crossroad line. */ - private val ROW_CRS = "+" - - /** - * Creates new Visor text table. - */ - def apply() = - new VisorTextTable -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/ack/VisorAckCommand.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/ack/VisorAckCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/ack/VisorAckCommand.scala index a8e2802..2e3659d 100644 --- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/ack/VisorAckCommand.scala +++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/ack/VisorAckCommand.scala @@ -18,8 +18,9 @@ package org.apache.ignite.visor.commands.ack import org.apache.ignite.cluster.ClusterGroupEmptyException +import org.apache.ignite.internal.util.scala.impl import org.apache.ignite.visor.VisorTag -import org.apache.ignite.visor.commands.VisorConsoleCommand +import org.apache.ignite.visor.commands.common.VisorConsoleCommand import org.apache.ignite.visor.visor._ import org.apache.ignite.internal.visor.misc.VisorAckTask @@ -61,18 +62,8 @@ import scala.language.implicitConversions * Prints local node ID on all nodes in the topology. * }}} */ -class VisorAckCommand { - /** - * Prints error message and advise. - * - * @param errMsgs Error messages. - */ - private def scold(errMsgs: Any*) { - assert(errMsgs != null) - - warn(errMsgs: _*) - warn("Type 'help ack' to see how to use this command.") - } +class VisorAckCommand extends VisorConsoleCommand { + @impl protected val name = "ack" /** * ===Command=== @@ -115,6 +106,9 @@ class VisorAckCommand { * Companion object that does initialization of the command. */ object VisorAckCommand { + /** Singleton command. */ + private val cmd = new VisorAckCommand + // Adds command's help to visor. addHelp( name = "ack", @@ -133,12 +127,10 @@ object VisorAckCommand { "ack Howdy!" -> "Prints 'Howdy!' on all nodes in the topology." ), - ref = VisorConsoleCommand(cmd.ack, cmd.ack) + emptyArgs = cmd.ack, + withArgs = cmd.ack ) - /** Singleton command. */ - private val cmd = new VisorAckCommand - /** * Singleton. */ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/alert/VisorAlertCommand.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/alert/VisorAlertCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/alert/VisorAlertCommand.scala index f94f481..9e2aec0 100644 --- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/alert/VisorAlertCommand.scala +++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/alert/VisorAlertCommand.scala @@ -21,16 +21,16 @@ import org.apache.ignite._ import org.apache.ignite.cluster.ClusterNode import org.apache.ignite.events.EventType._ import org.apache.ignite.events.{DiscoveryEvent, Event} +import org.apache.ignite.internal.util.scala.impl import org.apache.ignite.internal.util.{IgniteUtils => U} import org.apache.ignite.lang.IgnitePredicate +import org.apache.ignite.visor.VisorTag +import org.apache.ignite.visor.commands.common.{VisorConsoleCommand, VisorTextTable} +import org.apache.ignite.visor.visor._ import java.util.UUID import java.util.concurrent.atomic._ -import org.apache.ignite.visor.VisorTag -import org.apache.ignite.visor.commands.{VisorConsoleCommand, VisorTextTable} -import org.apache.ignite.visor.visor._ - import scala.collection.immutable._ import scala.language.implicitConversions import scala.util.control.Breaks._ @@ -119,7 +119,9 @@ import scala.util.control.Breaks._ * Notify every 15 min if grid has >= 4 CPUs and > 50% CPU load. * }}} */ -class VisorAlertCommand { +class VisorAlertCommand extends VisorConsoleCommand { + @impl protected val name = "alert" + /** Default alert frequency. */ val DFLT_FREQ = 15L * 60L @@ -142,18 +144,6 @@ class VisorAlertCommand { private var lsnr: IgnitePredicate[Event] = null /** - * Prints error message and advise. - * - * @param errMsgs Error messages. - */ - private def scold(errMsgs: Any*) { - assert(errMsgs != null) - - warn(errMsgs: _*) - warn("Type 'help alert' to see how to use this command.") - } - - /** * ===Command=== * Lists all registered alerts. * @@ -297,7 +287,7 @@ class VisorAlertCommand { break() case e: Exception => - scold(e.getMessage) + scold(e) break() } @@ -667,6 +657,9 @@ sealed private case class VisorStats( * Companion object that does initialization of the command. */ object VisorAlertCommand { + /** Singleton command. */ + private val cmd = new VisorAlertCommand + addHelp( name = "alert", shortInfo = "Alerts for user-defined events.", @@ -746,12 +739,10 @@ object VisorAlertCommand { "alert -r -t=900 -cc=gte4 -cl=gt50" -> "Notify every 15 min if grid has >= 4 CPUs and > 50% CPU load." ), - ref = VisorConsoleCommand(cmd.alert, cmd.alert) + emptyArgs = cmd.alert, + withArgs = cmd.alert ) - /** Singleton command. */ - private val cmd = new VisorAlertCommand - addCloseCallback(() => { cmd.reset() }) http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheClearCommand.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheClearCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheClearCommand.scala index 2588551..67aaa14 100644 --- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheClearCommand.scala +++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheClearCommand.scala @@ -17,14 +17,12 @@ package org.apache.ignite.visor.commands.cache -import org.apache.ignite.internal.visor.cache.VisorCacheClearTask -import org.apache.ignite.internal.visor.util.VisorTaskUtils._ - import org.apache.ignite.cluster.{ClusterGroupEmptyException, ClusterNode} +import org.apache.ignite.visor.commands.common.VisorTextTable +import org.apache.ignite.visor.visor._ -import org.apache.ignite.visor.commands.VisorTextTable -import org.apache.ignite.visor.visor -import visor._ +import org.apache.ignite.internal.visor.cache.VisorCacheClearTask +import org.apache.ignite.internal.visor.util.VisorTaskUtils._ import scala.language.reflectiveCalls @@ -115,7 +113,7 @@ class VisorCacheClearCommand { } catch { case e: ClusterGroupEmptyException => scold(messageNodeNotFound(node, cacheName)) - case e: Throwable => scold(e.getMessage) + case e: Throwable => scold(e) } } } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala index 2115535..8583637 100644 --- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala +++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala @@ -23,7 +23,7 @@ import org.apache.ignite.internal.util.typedef._ import org.apache.ignite.lang.IgniteBiTuple import org.apache.ignite.visor.VisorTag import org.apache.ignite.visor.commands.cache.VisorCacheCommand._ -import org.apache.ignite.visor.commands.{VisorConsoleCommand, VisorTextTable} +import org.apache.ignite.visor.commands.common.VisorTextTable import org.apache.ignite.visor.visor._ import org.jetbrains.annotations._ @@ -521,7 +521,7 @@ class VisorCacheCommand { } catch { case e: IgniteException => - scold(e.getMessage) + scold(e) null } @@ -662,6 +662,9 @@ class VisorCacheCommand { * Companion object that does initialization of the command. */ object VisorCacheCommand { + /** Singleton command */ + private val cmd = new VisorCacheCommand + addHelp( name = "cache", shortInfo = "Prints cache statistics, clears cache, prints list of all entries from cache.", @@ -777,7 +780,8 @@ object VisorCacheCommand { "cache -swap -c=@c0" -> "Swaps entries in cache with name taken from 'c0' memory variable.", "cache -stop -c=@c0" -> "Stop cache with name taken from 'c0' memory variable." ), - ref = VisorConsoleCommand(cmd.cache, cmd.cache) + emptyArgs = cmd.cache, + withArgs = cmd.cache ) /** Default cache name to show on screen. */ @@ -786,9 +790,6 @@ object VisorCacheCommand { /** Default cache key. */ protected val DFLT_CACHE_KEY = DFLT_CACHE_NAME + "-" + UUID.randomUUID().toString - /** Singleton command */ - private val cmd = new VisorCacheCommand - /** * Singleton. */ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheScanCommand.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheScanCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheScanCommand.scala index 2ff0262..d40ec8d 100644 --- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheScanCommand.scala +++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheScanCommand.scala @@ -19,7 +19,7 @@ package org.apache.ignite.visor.commands.cache import org.apache.ignite.cluster.{ClusterGroupEmptyException, ClusterNode} import org.apache.ignite.lang.IgniteBiTuple -import org.apache.ignite.visor.commands._ +import org.apache.ignite.visor.commands.common.VisorTextTable import org.apache.ignite.visor.visor._ import org.apache.ignite.internal.visor.query._ @@ -138,9 +138,8 @@ class VisorCacheScanCommand { val firstPage = try - val grp = groupForDataNode(node, cacheName) - - executeRandom(grp, classOf[VisorQueryTask], new VisorQueryArg(cacheName, "SCAN", pageSize)) match { + executeRandom(groupForDataNode(node, cacheName), + classOf[VisorQueryTask], new VisorQueryArg(cacheName, "SCAN", pageSize)) match { case x if x.get1() != null => error(x.get1()) http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheSwapCommand.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheSwapCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheSwapCommand.scala index f43d668..cd01dfe 100644 --- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheSwapCommand.scala +++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheSwapCommand.scala @@ -18,7 +18,7 @@ package org.apache.ignite.visor.commands.cache import org.apache.ignite.cluster.{ClusterGroupEmptyException, ClusterNode} -import org.apache.ignite.visor.commands.VisorTextTable +import org.apache.ignite.visor.commands.common.VisorTextTable import org.apache.ignite.visor.visor._ import java.util.Collections @@ -106,7 +106,9 @@ class VisorCacheSwapCommand { t #=("Node ID8(@)", "Entries Swapped", "Cache Size Before", "Cache Size After") - for (node <- grp.nodes(); nid <- node.id()) { + for (node <- grp.nodes()) { + val nid = node.id() + val r = executeOne(nid, classOf[VisorCacheSwapBackupsTask], Collections.singleton(cacheName)). get(cacheName) @@ -124,7 +126,7 @@ class VisorCacheSwapCommand { } catch { case e: ClusterGroupEmptyException => scold(messageNodeNotFound(node, cacheName)) - case e: Throwable => scold(e.getMessage) + case e: Throwable => scold(e) } } } http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/common/VisorConsoleCommand.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/common/VisorConsoleCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/common/VisorConsoleCommand.scala new file mode 100644 index 0000000..e20b901 --- /dev/null +++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/common/VisorConsoleCommand.scala @@ -0,0 +1,66 @@ +/* + * + * * 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.visor.commands.common + +/** + * Command implementation. + */ +trait VisorConsoleCommand { + protected def name: String + + /** + * Prints properly formatted error message like: + * {{{ + * (wrn) <visor>: warning message + * }}} + * + * @param warnMsgs Error messages to print. If `null` - this function is no-op. + */ + protected def warn(warnMsgs: Any*) { + assert(warnMsgs != null) + + warnMsgs.foreach{ + case ex: Throwable => println(s"(wrn) <visor>: ${ex.getMessage}") + case line => println(s"(wrn) <visor>: $line") + } + } + + /** + * Prints standard 'not connected' warn message. + */ + protected def adviseToConnect() { + warn( + "Visor is disconnected.", + "Type 'open' to connect Visor console or 'help open' to get help." + ) + } + + /** + * Prints warn message and advise. + * + * @param warnMsgs Warning messages. + */ + protected def scold(warnMsgs: Any*) { + assert(warnMsgs != null) + + warn(warnMsgs: _*) + warn(s"Type 'help $name' to see how to use this command.") + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/common/VisorTextTable.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/common/VisorTextTable.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/common/VisorTextTable.scala new file mode 100644 index 0000000..e6fe35f --- /dev/null +++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/common/VisorTextTable.scala @@ -0,0 +1,543 @@ +/* + * + * * 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.visor.commands.common + +import org.apache.ignite.internal.util.GridStringBuilder +import org.apache.ignite.visor.commands.common.VisorTextTable._ + +import scala.collection.Traversable + +/** + * ==Overview== + * Provides `ASCII`-based table with minimal styling support. + */ +class VisorTextTable { + /** + * Cell style. + */ + private sealed class Style( + var leftPad: Int = 1, // >= 0 + var rightPad: Int = 1, // >= 0 + var align: String = "center" // center, left, right + ) { + assert(leftPad >= 0) + assert(rightPad >= 0) + assert(align != null) + + /** + * Gets overall padding (left + right). + */ + def padding: Int = + leftPad + rightPad + } + + /** + * Cell style. + */ + private object Style { + /** + * + * @param sty Style. + */ + def apply(sty: String): Style = { + assert(sty != null) + + val cs = new Style + + if (!sty.isEmpty) { + for (e <- sty.split(',')) { + val a = e.split(":") + + assert(a.length == 2, "Invalid cell style: " + e.trim) + + val a0 = a(0).trim + val a1 = a(1).trim + + a0 match { + case "leftPad" => cs.leftPad = a1.toInt + case "rightPad" => cs.rightPad = a1.toInt + case "align" => cs.align = a1 + case _ => assert(false, "Invalid style: " + e.trim) + } + } + } + + cs + } + } + + /** + * Cell holder. + */ + private sealed case class Cell(style: Style, lines: Seq[String]) { + assert(style != null) + assert(lines != null) + + /** + * Cell's calculated width including padding. + */ + lazy val width = + if (height > 0) + style.padding + lines.max(Ordering.by[String, Int](_.length)).length + else + style.padding + + /** + * Gets height of the cell. + */ + def height: Int = lines.length + } + + /** + * Margin holder. + */ + private sealed case class Margin( + top: Int = 0, + right: Int = 0, + bottom: Int = 0, + left: Int = 0) { + assert(top >= 0) + assert(right >= 0) + assert(bottom >= 0) + assert(left >= 0) + } + + /** */ + private val NL = '\n' + + /** Headers. */ + private val hdr = collection.mutable.ArrayBuffer.empty[Cell] + + /** Rows. */ + private val rows = collection.mutable.ArrayBuffer.empty[Seq[Cell]] + + /** Current row, if any. */ + private var curRow: collection.mutable.ArrayBuffer[Cell] = null + + /** Table's margin, if any. */ + private var margin: Margin = Margin() + + /** Default row cell style, if any. */ + private var rowSty: String = "align:left" + + /** Default header cell style, if any. */ + private var hdrSty: String = "align:center" + + /** + * Flag indicating whether or not to draw inside horizontal lines + * between individual rows. + */ + var insideBorder = false + + /** + * Flag indicating whether of not to automatically draw horizontal lines + * for multiline rows. + */ + var autoBorder = true + + /** + * Maximum width of the cell. If any line in the cell exceeds this width + * it will be cut in two or more lines. + * + * '''NOTE''': it doesn't include into account the padding. Only the actual + * string length is counted. + */ + var maxCellWidth = Int.MaxValue + + /** + * + * @param ch Char. + * @param len Dash length. + */ + private def dash(ch: Char, len: Int): String = { + assert(len >= 0) + + new String().padTo(len, ch) + } + + /** + * + * @param s String. + * @param len Dash length. + */ + private def dash(s: String, len: Int): String = { + assert(len >= 0) + + var i = 0 + + val sb = new GridStringBuilder(s.length * len) + + while (i < len) { + sb.a(s) + + i += 1 + } + + sb.toString + } + + /** + * + * @param len Length. + */ + private def blank(len: Int): String = + dash(' ', len) + + /** + * Sets table's margin. + * + * @param top Top margin. + * @param right Right margin. + * @param bottom Bottom margin. + * @param left Left margin. + */ + def margin(top: Int = 0, right: Int = 0, bottom: Int = 0, left: Int = 0) { + assert(top >= 0) + assert(right >= 0) + assert(bottom >= 0) + assert(left >= 0) + + margin = Margin(top, right, bottom, left) + } + + /** + * Starts data row. + */ + def startRow() { + assert(curRow == null) + + curRow = collection.mutable.ArrayBuffer.empty[Cell] + } + + /** + * Ends data row. + */ + def endRow() { + assert(curRow.nonEmpty) + + rows += curRow + + curRow = null + } + + /** + * Adds row (one or more row cells). + * + * @param cells Row cells. For multi-line cells - use `Seq(...)`. + */ + def +=(cells: Any*): VisorTextTable = { + startRow() + + cells foreach { + case s: scala.collection.Iterable[Any] => addRowCell(s.toSeq: _*) + case p: Product => addRowCell(p.productIterator.toSeq: _*) + case a => addRowCell(a) + } + + endRow() + + this + } + + /** + * Adds header (one or more header cells). + * + * @param cells Header cells. For multi-line cells - use `Seq(...)`. + */ + def #=(cells: Any*): VisorTextTable = { + cells foreach { + case s: scala.collection.Iterable[Any] => addHeaderCell(s.toSeq: _*) + case p: Product => addHeaderCell(p.productIterator.toSeq: _*) + case a => addHeaderCell(a) + } + + this + } + + /** + * Adds single header cell. + * + * @param lines One or more cell lines. + */ + def addHeaderCell(lines: Any*): VisorTextTable = { + assert(lines != null) + assert(lines.length > 0) + + // Break up long line into multiple ones - if necessary. + val lst = lines flatten(_.toString.grouped(maxCellWidth)) + + hdr += Cell(Style(hdrSty), lst) + + this + } + + /** + * Gets current row style. + */ + def rowStyle = + rowSty + + /** + * Sets current row style. + * + * @param rowSty Row style to set. + */ + def rowStyle(rowSty: String) { + this.rowSty = rowSty + } + + /** + * Gets current header style. + */ + def headerStyle = + rowSty + + /** + * Sets current header style. + * + * @param hdrSty Header style to set. + */ + def headerStyle(hdrSty: String) { + this.hdrSty = hdrSty + } + + /** + * Adds single row cell. + * + * @param lines One or more row cells. Multiple lines will be printed on separate lines. + */ + def addRowCell(lines: Any*): VisorTextTable = { + assert(lines != null) + assert(lines.length >= 0) + assert(curRow != null) + + // Break up long line into multiple ones - if necessary. + val lst = lines flatten { + case it: Traversable[_] => it.flatten(_.toString.grouped(maxCellWidth)) + case null => Seq("") + case obj => obj.toString.grouped(maxCellWidth) + } + + curRow += Cell(Style(rowSty), lst) + + this + } + + /** + * + * @param txt Text to align. + * @param width Width already accounts for padding. + * @param sty Style. + */ + private def aligned(txt: String, width: Int, sty: Style): String = { + assert(txt != null) + assert(width > 0) + assert(sty != null) + assert(txt.length <= width) + + val d = width - txt.length + + val styTxt = txt + + sty.align.trim match { + case "center" => + blank(d / 2) + styTxt + blank(d / 2 + d % 2) + case "left" => + blank(sty.leftPad) + styTxt + blank(d - sty.leftPad) + case "right" => + blank(d - sty.rightPad) + styTxt + blank(sty.rightPad) + case _ => + throw new AssertionError("Invalid align option in: " + sty) + } + } + + /** + * Renders this table. + */ + def render() { + // Make sure table is not empty. + if (hdr.isEmpty && rows.isEmpty) + return + + var colsNum = -1 + + val isHdr = hdr.nonEmpty + + if (isHdr) + colsNum = hdr.size + + // Calc number of columns and make sure all rows are even. + for (r <- rows) + if (colsNum == -1) + colsNum = r.size + else if (colsNum != r.size) + assert(false, "Table with uneven rows.") + + assert(colsNum > 0) + + // At this point all rows in the table have the + // the same number of columns. + + val colWs = new Array[Int](colsNum) // Column widths. + val rowHs = new Array[Int](rows.length) // Row heights. + + // Header height. + var hdrH = 0 + + // Initialize column widths with header row (if any). + for (i <- 0 until hdr.size) { + val c = hdr(i) + + colWs(i) = c.width + + hdrH = math.max(hdrH, c.height) + } + + // Calc row heights and column widths. + for (i <- 0 until rows.length; j <- 0 until colsNum) { + val c = rows(i)(j) + + rowHs(i) = math.max(rowHs(i), c.height) + colWs(j) = math.max(colWs(j), c.width) + } + + // Table width without the border. + val tblW = colWs.sum + colsNum - 1 + + val tbl = new GridStringBuilder() + + // Top margin. + for (i <- 0 until margin.top) + tbl.a(" ").a(NL) + + // Print header, if any. + if (isHdr) { + tbl.a(blank(margin.left)).a(HDR_CRS).a(dash(HDR_HOR, tblW)).a(HDR_CRS).a(blank(margin.right)).a(NL) + + for (i <- 0 until hdrH) { + // Left margin and '|'. + tbl.a(blank(margin.left)).a(HDR_VER) + + for (j <- 0 until hdr.size) { + val c = hdr(j) + + if (i >= 0 && i < c.height) + tbl.a(aligned(c.lines(i), colWs(j), c.style)) + else + tbl.a(blank(colWs(j))) + + tbl.a(HDR_VER) // '|' + } + + // Right margin. + tbl.a(blank(margin.right)).a(NL) + } + + tbl.a(blank(margin.left)).a(HDR_CRS).a(dash(HDR_HOR, tblW)).a(HDR_CRS).a(blank(margin.right)).a(NL) + } + else + tbl.a(blank(margin.left)).a(ROW_CRS).a(dash(ROW_HOR, tblW)).a(ROW_CRS).a(blank(margin.right)).a(NL) + + // Print rows, if any. + if (rows.nonEmpty) { + val horLine = (i: Int) => { + // Left margin and '+' + tbl.a(blank(margin.left)).a(ROW_CRS) + + for (k <- 0 until rows(i).size) + tbl.a(dash(ROW_HOR, colWs(k))).a(ROW_CRS) + + // Right margin. + tbl.a(blank(margin.right)).a(NL) + } + + for (i <- 0 until rows.size) { + val r = rows(i) + + val rowH = rowHs(i) + + if (i > 0 && ((rowH > 1 && autoBorder) || insideBorder) && rowHs(i - 1) == 1) + horLine(i) + + for (j <- 0 until rowH) { + // Left margin and '|' + tbl.a(blank(margin.left)).a(ROW_VER) + + for (k <- 0 until r.size) { + val c = r(k) + val w = colWs(k) + + if (j < c.height) + tbl.a(aligned(c.lines(j), w, c.style)) + else + tbl.a(blank(w)) + + tbl.a(ROW_VER) // '|' + } + + // Right margin. + tbl.a(blank(margin.right)).a(NL) + } + + if (i < rows.size - 1 && ((rowH > 1 && autoBorder) || insideBorder)) + horLine(i) + } + + tbl.a(blank(margin.left)).a(ROW_CRS).a(dash(ROW_HOR, tblW)).a(ROW_CRS).a(blank(margin.right)).a(NL) + } + + // Bottom margin. + for (i <- 1 to margin.bottom) + tbl.a(" ").a(NL) + + print(tbl.toString) + } + + def nonEmpty = rows.nonEmpty +} + +/** + * Static context. + */ +object VisorTextTable { + /** Table header horizontal line. */ + private val HDR_HOR = "=" + + /** Table header vertical line. */ + private val HDR_VER = "|" + + /** Table header crossroad line. */ + private val HDR_CRS = "+" + + /** Table row horizontal line. */ + private val ROW_HOR = '-' + + /** Table row vertical line. */ + private val ROW_VER = '|' + + /** Table row crossroad line. */ + private val ROW_CRS = "+" + + /** + * Creates new Visor text table. + */ + def apply() = + new VisorTextTable +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/config/VisorConfigurationCommand.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/config/VisorConfigurationCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/config/VisorConfigurationCommand.scala index 447667a..e6e3782 100644 --- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/config/VisorConfigurationCommand.scala +++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/config/VisorConfigurationCommand.scala @@ -18,18 +18,19 @@ package org.apache.ignite.visor.commands.config import org.apache.ignite._ -import org.apache.ignite.cluster.ClusterNode +import org.apache.ignite.internal.util.scala.impl import org.apache.ignite.internal.util.{IgniteUtils => U} -import org.apache.ignite.internal.visor.util.VisorTaskUtils._ import org.apache.ignite.lang.IgniteBiTuple - -import java.lang.System._ - import org.apache.ignite.visor.VisorTag import org.apache.ignite.visor.commands.cache.VisorCacheCommand -import org.apache.ignite.visor.commands.{VisorConsoleCommand, VisorTextTable} +import org.apache.ignite.visor.commands.common.{VisorConsoleCommand, VisorTextTable} import org.apache.ignite.visor.visor._ +import java.lang.System._ + +import org.apache.ignite.internal.visor.node.VisorNodeConfigurationCollectorTask +import org.apache.ignite.internal.visor.util.VisorTaskUtils._ + import scala.collection.JavaConversions._ import scala.language.implicitConversions import scala.util.control.Breaks._ @@ -38,16 +39,6 @@ import scala.util.control.Breaks._ * ==Overview== * Visor 'config' command implementation. * - * ==Importing== - * When using this command from Scala code (not from REPL) you need to make sure to - * properly import all necessary typed and implicit conversions: - * <ex> - * import org.apache.ignite.visor._ - * import commands.config.VisorConfigurationCommand._ - * </ex> - * Note that `VisorConfigurationCommand` object contains necessary implicit conversions so that - * this command would be available via `visor` keyword. - * * ==Help== * {{{ * +-------------------------------------+ @@ -79,18 +70,8 @@ import scala.util.control.Breaks._ * Starts command in interactive mode. * }}} */ -class VisorConfigurationCommand { - /** - * Prints error message and advise. - * - * @param errMsgs Error messages. - */ - private def scold(errMsgs: Any*) { - assert(errMsgs != null) - - warn(errMsgs: _*) - warn("Type 'help config' to see how to use this command.") - } +class VisorConfigurationCommand extends VisorConsoleCommand { + @impl protected val name = "config" /** * ===Command=== @@ -101,13 +82,13 @@ class VisorConfigurationCommand { * Starts command in interactive mode. */ def config() { - if (!isConnected) - adviseToConnect() - else + if (isConnected) askForNode("Select node from:") match { case Some(id) => config("-id=" + id) case None => () } + else + adviseToConnect() } /** @@ -130,63 +111,28 @@ class VisorConfigurationCommand { val argLst = parseArgs(args) - val id8 = argValue("id8", argLst) - val id = argValue("id", argLst) - - var node: ClusterNode = null - - if (id8.isEmpty && id.isEmpty) { - scold("One of -id8 or -id is required.") - - break() - } - - if (id8.isDefined && id.isDefined) { - scold("Only one of -id8 or -id is allowed.") - - break() - } - - if (id8.isDefined) { - val ns = nodeById8(id8.get) - - if (ns.isEmpty) { - scold("Unknown 'id8' value: " + id8.get) - - break() - } - else if (ns.size != 1) { - scold("'id8' resolves to more than one node (use full 'id' instead): " + id8.get) + val nid = parseNode(argLst) match { + case Left(msg) => + scold(msg) break() - } - else - node = ns.head - } - else if (id.isDefined) - try { - node = ignite.cluster.node(java.util.UUID.fromString(id.get)) - if (node == null) { - scold("'id' does not match any node: " + id.get) + case Right(None) => + scold("One of -id8 or -id is required.") - break() - } - } - catch { - case e: IllegalArgumentException => - scold("Invalid node 'id': " + id.get) + break() - break() - } + case Right(Some(n)) => + assert(n != null) - assert(node != null) + n.id() + } val cfg = try - nodeConfiguration(node.id()) + executeOne(nid, classOf[VisorNodeConfigurationCollectorTask], null) catch { case e: IgniteException => - scold(e.getMessage) + scold(e) break() } @@ -390,11 +336,11 @@ class VisorConfigurationCommand { println("\nNo system properties defined.") try - cacheConfigurations(node.id).foreach(cacheCfg => + cacheConfigurations(nid).foreach(cacheCfg => VisorCacheCommand.showCacheConfiguration("\nCache '" + escapeName(cacheCfg.name()) + "':", cacheCfg)) catch { case e: IgniteException => - scold(e.getMessage) + scold(e) } } } @@ -405,11 +351,10 @@ class VisorConfigurationCommand { * @param value String. * @return List of strings. */ - def compactProperty(name: String, value: String): List[String] = { + private[this] def compactProperty(name: String, value: String): List[String] = { val ps = getProperty("path.separator") - // Split all values having path separator into multiple - // lines (with few exceptions...). + // Split all values having path separator into multiple lines (with few exceptions...). val lst = if (name != "path.separator" && value.indexOf(ps) != -1 && value.indexOf("http:") == -1 && value.length() > 80) @@ -428,12 +373,15 @@ class VisorConfigurationCommand { * Companion object that does initialization of the command. */ object VisorConfigurationCommand { + /** Singleton command. */ + private val cmd = new VisorConfigurationCommand + addHelp( - name = "config", + name = cmd.name, shortInfo = "Prints node configuration.", spec = List( - "config", - "config {-id=<node-id>|id8=<node-id8>}" + cmd.name, + s"${cmd.name} {-id=<node-id>|id8=<node-id8>}" ), args = List( "-id=<node-id>" -> List( @@ -447,19 +395,17 @@ object VisorConfigurationCommand { ) ), examples = List( - "config -id8=12345678" -> + s"${cmd.name} -id8=12345678" -> "Prints configuration for node with '12345678' id8.", - "config -id8=@n0" -> + s"${cmd.name} -id8=@n0" -> "Prints configuration for node with id8 taken from '@n0' memory variable.", - "config" -> + cmd.name -> "Starts command in interactive mode." ), - ref = VisorConsoleCommand(cmd.config, cmd.config) + emptyArgs = cmd.config, + withArgs = cmd.config ) - /** Singleton command. */ - private val cmd = new VisorConfigurationCommand - /** * Singleton. */ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/3a2c39f2/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/deploy/VisorDeployCommand.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/deploy/VisorDeployCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/deploy/VisorDeployCommand.scala index 3856672..ac6a1dc 100644 --- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/deploy/VisorDeployCommand.scala +++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/deploy/VisorDeployCommand.scala @@ -18,9 +18,13 @@ package org.apache.ignite.visor.commands.deploy import org.apache.ignite.internal.util.io.GridFilenameUtils +import org.apache.ignite.internal.util.lang.{GridFunc => F} +import org.apache.ignite.internal.util.scala.impl import org.apache.ignite.internal.util.typedef.X import org.apache.ignite.internal.util.{IgniteUtils => U} -import org.apache.ignite.internal.util.lang.{GridFunc => F} +import org.apache.ignite.visor.VisorTag +import org.apache.ignite.visor.commands.common.VisorConsoleCommand +import org.apache.ignite.visor.visor._ import com.jcraft.jsch._ @@ -28,10 +32,6 @@ import java.io._ import java.net.UnknownHostException import java.util.concurrent._ -import org.apache.ignite.visor.VisorTag -import org.apache.ignite.visor.commands.VisorConsoleCommand -import org.apache.ignite.visor.visor._ - import scala.language.{implicitConversions, reflectiveCalls} import scala.util.control.Breaks._ @@ -308,7 +308,9 @@ private case class VisorCopier( * Copies file or directory to remote host (private key authentication). * }}} */ -class VisorDeployCommand { +class VisorDeployCommand extends VisorConsoleCommand { + @impl protected val name: String = "deploy" + /** Default port. */ private val DFLT_PORT = 22 @@ -316,20 +318,6 @@ class VisorDeployCommand { private val RANGE_SMB = "~" /** - * Prints error message and advise. - * - * @param errMsgs Error messages. - */ - private def scold(errMsgs: Any*) { - assert(errMsgs != null) - - nl() - - warn(errMsgs: _*) - warn("Type 'help deploy' to see how to use this command.") - } - - /** * Catch point for missing arguments case. */ def deploy() { @@ -367,7 +355,7 @@ class VisorDeployCommand { try hosts ++= mkHosts(h, dfltUname, dfltPasswd, key.isDefined) catch { - case e: IllegalArgumentException => scold(e.getMessage).^^ + case e: IllegalArgumentException => scold(e).^^ } }) @@ -524,15 +512,18 @@ class VisorDeployCommand { * Companion object that does initialization of the command. */ object VisorDeployCommand { + /** Singleton command. */ + private val cmd = new VisorDeployCommand + addHelp( - name = "deploy", + name = cmd.name, shortInfo = "Copies file or folder to remote host.", longInfo = List( "Copies file or folder to remote host.", "Command relies on SFTP protocol." ), spec = List( - "deploy -h={<username>{:<password>}@}<host>{:<port>} {-u=<username>}", + s"${cmd.name} -h={<username>{:<password>}@}<host>{:<port>} {-u=<username>}", " {-p=<password>} {-k=<path>} -s=<path> {-d<path>}" ), args = List( @@ -568,17 +559,15 @@ object VisorDeployCommand { ) ), examples = List( - "deploy -h=uname:passwd@host -s=/local/path -d=/remote/path" -> + s"${cmd.name} -h=uname:passwd@host -s=/local/path -d=/remote/path" -> "Copies file or folder to remote host (password authentication).", - "deploy -h=uname@host -k=ssh-key.pem -s=/local/path -d=/remote/path" -> + s"${cmd.name} -h=uname@host -k=ssh-key.pem -s=/local/path -d=/remote/path" -> "Copies file or folder to remote host (private key authentication)." ), - ref = VisorConsoleCommand(cmd.deploy, cmd.deploy) + emptyArgs = cmd.deploy, + withArgs = cmd.deploy ) - /** Singleton command. */ - private val cmd = new VisorDeployCommand - /** * Singleton. */