You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by ad...@apache.org on 2017/04/04 01:02:50 UTC
kudu git commit: KUDU-1708. Document Kudu command-line tools
Repository: kudu
Updated Branches:
refs/heads/master 7206041f9 -> 2407c2cb1
KUDU-1708. Document Kudu command-line tools
- Adds helpxml flag support to the kudu binary
- Adds doc script and xslt to convert xml to asciidoc
Change-Id: I9f484f772cbaeb385687d83a2665ae4d7292aaf5
Reviewed-on: http://gerrit.cloudera.org:8080/6525
Reviewed-by: Adar Dembo <ad...@cloudera.com>
Tested-by: Adar Dembo <ad...@cloudera.com>
Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/2407c2cb
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/2407c2cb
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/2407c2cb
Branch: refs/heads/master
Commit: 2407c2cb1e413c705ceb2b9479fe74d9cc432883
Parents: 7206041
Author: Grant Henke <gr...@gmail.com>
Authored: Thu Mar 30 22:43:32 2017 -0500
Committer: Adar Dembo <ad...@cloudera.com>
Committed: Tue Apr 4 01:02:23 2017 +0000
----------------------------------------------------------------------
docs/command_line_tools_reference.adoc | 36 +++++
docs/support/jekyll-templates/document.html.erb | 1 +
docs/support/scripts/make_docs.sh | 24 ++++
docs/support/xsl/tool_to_asciidoc.xsl | 142 +++++++++++++++++++
src/kudu/tools/CMakeLists.txt | 3 +-
src/kudu/tools/kudu-tool-test.cc | 35 +++++
src/kudu/tools/tool_action-test.cc | 117 +++++++++++++++
src/kudu/tools/tool_action.cc | 97 ++++++++++++-
src/kudu/tools/tool_action.h | 6 +
src/kudu/tools/tool_main.cc | 59 +++++---
10 files changed, 496 insertions(+), 24 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/kudu/blob/2407c2cb/docs/command_line_tools_reference.adoc
----------------------------------------------------------------------
diff --git a/docs/command_line_tools_reference.adoc b/docs/command_line_tools_reference.adoc
new file mode 100644
index 0000000..5456d6e
--- /dev/null
+++ b/docs/command_line_tools_reference.adoc
@@ -0,0 +1,36 @@
+// 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.
+
+[[command_line_tools_reference]]
+= Apache Kudu Command Line Tools Reference
+
+:author: Kudu Team
+:imagesdir: ./images
+:icons: font
+:toc: left
+:toclevels: 2
+:doctype: book
+:backend: html5
+:sectlinks:
+:experimental:
+
+// The contents of this file are generated from the output of the `--helpxml`
+// flag for the kudu tool, during the build of the documentation.
+// Do not edit this file or the included files manually.
+
+// This gets replaced by the script that builds the docs
+@@TOOLS_REFERENCE@@
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/kudu/blob/2407c2cb/docs/support/jekyll-templates/document.html.erb
----------------------------------------------------------------------
diff --git a/docs/support/jekyll-templates/document.html.erb b/docs/support/jekyll-templates/document.html.erb
index 7d18c04..a96b68a 100644
--- a/docs/support/jekyll-templates/document.html.erb
+++ b/docs/support/jekyll-templates/document.html.erb
@@ -97,6 +97,7 @@ end %>
:transaction_semantics, "Kudu Transaction Semantics",
:contributing, "Contributing to Kudu",
:configuration_reference, "Kudu Configuration Reference",
+ :command_line_tools_reference, "Kudu Command Line Tools Reference",
:known_issues, "Known Issues and Limitations",
:export_control, "Export Control Notice"
]
http://git-wip-us.apache.org/repos/asf/kudu/blob/2407c2cb/docs/support/scripts/make_docs.sh
----------------------------------------------------------------------
diff --git a/docs/support/scripts/make_docs.sh b/docs/support/scripts/make_docs.sh
index dcbc1f8..c449c5a 100755
--- a/docs/support/scripts/make_docs.sh
+++ b/docs/support/scripts/make_docs.sh
@@ -167,6 +167,30 @@ cp $SOURCE_ROOT/docs/configuration_reference* $GEN_DOC_DIR/
sed -i "s#@@CONFIGURATION_REFERENCE@@#${INCLUSIONS_SUPPORTED}#" ${GEN_DOC_DIR}/configuration_reference.adoc
sed -i "s#@@CONFIGURATION_REFERENCE@@#${INCLUSIONS_UNSUPPORTED}#" ${GEN_DOC_DIR}/configuration_reference_unsupported.adoc
+# Create tool references
+echo "Running kudu --helpxml"
+(
+ # Reset environment to avoid affecting the default flag values.
+ for var in $(env | awk -F= '{print $1}' | egrep -i 'KUDU|GLOG'); do
+ echo "unset $var"
+ eval "unset $var"
+ done
+
+ # Create the XML file.
+ # This command exits with a nonzero value.
+ $BUILD_ROOT/bin/kudu --helpxml > ${GEN_DOC_DIR}/kudu.xml || true
+)
+
+# Create the supported config reference
+xsltproc \
+-o $GEN_DOC_DIR/command_line_tools.adoc \
+ $SOURCE_ROOT/docs/support/xsl/tool_to_asciidoc.xsl \
+${GEN_DOC_DIR}/kudu.xml
+
+# Add the includes to the cli tools reference files, replacing the template lines
+cp $SOURCE_ROOT/docs/command_line_tools_reference.adoc $GEN_DOC_DIR/
+sed -i "s#@@TOOLS_REFERENCE@@#include::command_line_tools.adoc[leveloffset=+1]\n#" ${GEN_DOC_DIR}/command_line_tools_reference.adoc
+
# If we're generating the web site, pass the template which causes us
# to generate Jekyll templates instead of full HTML.
if [ -n "$SITE" ]; then
http://git-wip-us.apache.org/repos/asf/kudu/blob/2407c2cb/docs/support/xsl/tool_to_asciidoc.xsl
----------------------------------------------------------------------
diff --git a/docs/support/xsl/tool_to_asciidoc.xsl b/docs/support/xsl/tool_to_asciidoc.xsl
new file mode 100644
index 0000000..1d36cf3
--- /dev/null
+++ b/docs/support/xsl/tool_to_asciidoc.xsl
@@ -0,0 +1,142 @@
+<?xml version="1.0"?>
+<!--
+
+Licensed 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.
+-->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:output method="text"/>
+
+<!-- Normalize space -->
+<xsl:template match="text()">
+ <xsl:if test="normalize-space(.)">
+ <xsl:value-of select="normalize-space(.)"/>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="AllModes">
+<!-- Inject the license text into the header -->
+////
+//
+// 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.
+////
+
+:author: Kudu Team
+:imagesdir: ./images
+:icons: font
+:toc: left
+:toclevels: 1
+:doctype: book
+:backend: html5
+:sectlinks:
+:experimental:
+
+= Command Hierarchy
+<xsl:apply-templates select="mode" mode="toc"/>
+
+= Command Details
+<xsl:apply-templates select="mode" mode="content"/>
+
+</xsl:template>
+
+<!-- Table of contents template -->
+<xsl:template match="mode|action" mode="toc">
+<xsl:variable name="depth" select="count(ancestor::*)"/>
+<xsl:variable name="ref"><xsl:if test="../name"><xsl:value-of select="../name"/>-</xsl:if><xsl:value-of select="name"/></xsl:variable>
+<!-- Print bullets at mode/action depth -->
+<xsl:for-each select="(//node())[$depth >= position()]">*</xsl:for-each> <<<xsl:value-of select="$ref"/>,<xsl:value-of select="name"/>>>
+<xsl:apply-templates select="mode|action" mode="toc"/>
+</xsl:template>
+
+<!-- Content for mode template -->
+<xsl:template match="mode" mode="content">
+<xsl:variable name="depth" select="count(ancestor::*) + 1"/>
+<!-- Create unique anchor with the parent name and name -->
+<xsl:variable name="anchor"><xsl:if test="../name"><xsl:value-of select="../name"/>-</xsl:if><xsl:value-of select="name"/></xsl:variable>
+[[<xsl:value-of select="$anchor"/>]]
+<!-- Print header level at mode depth -->
+<xsl:for-each select="(//node())[$depth >= position()]">=</xsl:for-each> `<xsl:value-of select="name"/>`: <xsl:value-of select="description"/>
+{empty} +
+<xsl:apply-templates select="mode|action" mode="content"/>
+</xsl:template>
+
+<!-- Content for action template -->
+<xsl:template match="action" mode="content">
+<xsl:variable name="depth" select="count(ancestor::*) + 1"/>
+<!-- Create unique anchor with the parent name and name -->
+<xsl:variable name="anchor"><xsl:if test="../name"><xsl:value-of select="../name"/>-</xsl:if><xsl:value-of select="name"/></xsl:variable>
+[[<xsl:value-of select="$anchor"/>]]
+<!-- Print header level at action depth -->
+<xsl:for-each select="(//node())[$depth >= position()]">=</xsl:for-each> `<xsl:value-of select="name"/>`: <xsl:value-of select="description"/>{nbsp}
+<xsl:if test="extra_description != ''"><xsl:value-of select="extra_description"/> +</xsl:if>
+*Usage:* +
+`<xsl:value-of select="usage"/>`
+{empty} +
+*Arguments:*
+[frame="topbot",options="header"]
+|===
+| Name | Description | Type | Default
+<xsl:for-each select="argument">
+<!-- escape pipe character in description for use in tables -->
+<xsl:variable name="escaped_description">
+ <xsl:call-template name="string-replace-all">
+ <xsl:with-param name="text" select="description" />
+ <xsl:with-param name="replace" select="'|'" />
+ <xsl:with-param name="by" select="'\|'" />
+ </xsl:call-template>
+</xsl:variable>
+| <xsl:value-of select="name"/><xsl:if test="contains(kind, 'variadic')">...</xsl:if><xsl:if test="contains(kind, 'optional')"> (optional)</xsl:if>
+| <xsl:value-of select="$escaped_description"/>
+| <xsl:value-of select="type"/>
+| <xsl:choose><xsl:when test="default_value != ''">`<xsl:value-of select="default_value"/>`</xsl:when><xsl:otherwise>none</xsl:otherwise></xsl:choose>
+</xsl:for-each>
+|===
+{empty} +
+</xsl:template>
+
+<!-- Template to support string replacement in XSLT 1.0) -->
+<xsl:template name="string-replace-all">
+<xsl:param name="text" />
+<xsl:param name="replace" />
+<xsl:param name="by" />
+<xsl:choose>
+ <xsl:when test="contains($text, $replace)">
+ <xsl:value-of select="substring-before($text,$replace)" />
+ <xsl:value-of select="$by" />
+ <xsl:call-template name="string-replace-all">
+ <xsl:with-param name="text" select="substring-after($text,$replace)" />
+ <xsl:with-param name="replace" select="$replace" />
+ <xsl:with-param name="by" select="$by" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$text" />
+ </xsl:otherwise>
+</xsl:choose>
+</xsl:template>
+</xsl:stylesheet>
http://git-wip-us.apache.org/repos/asf/kudu/blob/2407c2cb/src/kudu/tools/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/tools/CMakeLists.txt b/src/kudu/tools/CMakeLists.txt
index c38d2da..0f75fca 100644
--- a/src/kudu/tools/CMakeLists.txt
+++ b/src/kudu/tools/CMakeLists.txt
@@ -32,6 +32,7 @@ set(LINK_LIBS
add_library(kudu_tools_util
color.cc
data_gen_util.cc
+ tool_action.cc
tool_action_common.cc
)
target_link_libraries(kudu_tools_util
@@ -56,7 +57,6 @@ target_link_libraries(ksck
)
add_executable(kudu
- tool_action.cc
tool_action_cluster.cc
tool_action_fs.cc
tool_action_local_replica.cc
@@ -112,3 +112,4 @@ ADD_KUDU_TEST_DEPENDENCIES(kudu-tool-test
ADD_KUDU_TEST(kudu-ts-cli-test)
ADD_KUDU_TEST_DEPENDENCIES(kudu-ts-cli-test
kudu)
+ADD_KUDU_TEST(tool_action-test)
http://git-wip-us.apache.org/repos/asf/kudu/blob/2407c2cb/src/kudu/tools/kudu-tool-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/kudu-tool-test.cc b/src/kudu/tools/kudu-tool-test.cc
index 68c4493..e082cf9 100644
--- a/src/kudu/tools/kudu-tool-test.cc
+++ b/src/kudu/tools/kudu-tool-test.cc
@@ -277,6 +277,41 @@ void ToolTest::StartMiniCluster(int num_masters,
ASSERT_OK(mini_cluster_->Start());
}
+TEST_F(ToolTest, TestHelpXML) {
+ string stdout;
+ string stderr;
+ Status s = RunTool("--helpxml", &stdout, &stderr, nullptr, nullptr);
+
+ ASSERT_TRUE(s.IsRuntimeError());
+ ASSERT_FALSE(stdout.empty());
+ ASSERT_TRUE(stderr.empty());
+
+ // All wrapped in AllModes node
+ ASSERT_STR_MATCHES(stdout, "<\\?xml version=\"1.0\"\\?><AllModes>.*</AllModes>");
+
+ // Verify all modes are output
+ const vector<string> modes = {
+ "cluster",
+ "fs",
+ "local_replica",
+ "master",
+ "pbc",
+ "remote_replica",
+ "table",
+ "tablet",
+ "test",
+ "tserver",
+ "wal",
+ "dump",
+ "cmeta",
+ "change_config"
+ };
+
+ for (const auto& mode : modes) {
+ ASSERT_STR_MATCHES(stdout, Substitute(".*<mode><name>$0</name>.*</mode>.*", mode));
+ }
+}
+
TEST_F(ToolTest, TestTopLevelHelp) {
const vector<string> kTopLevelRegexes = {
"cluster.*Kudu cluster",
http://git-wip-us.apache.org/repos/asf/kudu/blob/2407c2cb/src/kudu/tools/tool_action-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action-test.cc b/src/kudu/tools/tool_action-test.cc
new file mode 100644
index 0000000..76c2255
--- /dev/null
+++ b/src/kudu/tools/tool_action-test.cc
@@ -0,0 +1,117 @@
+// 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.
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <gflags/gflags.h>
+#include <gtest/gtest.h>
+
+#include "kudu/tools/tool_action.h"
+
+// gflags for optional action parameters
+DEFINE_bool(opt_bool, false, "obd");
+DEFINE_string(opt_string, "", "osd");
+
+namespace kudu {
+namespace tools {
+
+using std::string;
+using std::stringstream;
+using std::unique_ptr;
+using std::vector;
+
+TEST(ToolActionTest, TestActionBuildHelpXML) {
+ unique_ptr<Action> action =
+ ActionBuilder("sample", nullptr)
+ .Description("d")
+ .ExtraDescription("ed")
+ .AddRequiredParameter({ "required", "rpd" })
+ .AddRequiredVariadicParameter({ "variadic", "vpd" })
+ .AddOptionalParameter("opt_string")
+ .AddOptionalParameter("opt_bool")
+ .Build();
+
+ string xml = action->BuildHelpXML(vector<Mode*>());
+ SCOPED_TRACE(xml);
+
+ stringstream ss;
+ ss << "<action>";
+ ss << "<name>sample</name>";
+ ss << "<description>d</description>";
+ ss << "<extra_description>ed</extra_description>";
+ ss << "<argument><kind>required</kind><name>required</name>"
+ "<description>rpd</description><type>string</type></argument>";
+ ss << "<argument><kind>variadic</kind><name>variadic</name>"
+ "<description>vpd</description><type>string</type></argument>";
+ ss << "<argument><kind>optional</kind><name>opt_string</name>"
+ "<description>osd</description><type>string</type>"
+ "<default_value></default_value></argument>";
+ ss << "<argument><kind>optional</kind><name>opt_bool</name>"
+ "<description>obd</description><type>bool</type>"
+ "<default_value>false</default_value></argument>";
+ ss << "<usage> sample &lt;required&gt; &lt;variadic&gt;... "
+ "[-opt_string=&lt;string&gt;] [-opt_bool]</usage>";
+ ss << "</action>";
+ string expected_xml = ss.str();
+
+ ASSERT_EQ(expected_xml, xml);
+}
+
+TEST(ToolActionTest, TestModeBuildHelpXML) {
+ unique_ptr<Action> action =
+ ActionBuilder("action", nullptr)
+ .Description("ad")
+ .AddRequiredParameter({ "required", "rpd" })
+ .Build();
+
+ unique_ptr<Mode> submode = ModeBuilder("submode")
+ .Description("subd")
+ .AddAction(std::move(action))
+ .Build();
+
+ unique_ptr<Mode> mode = ModeBuilder("mode")
+ .Description("md")
+ .AddMode(std::move(submode))
+ .Build();
+
+ vector<Mode*> chain = { mode.get() };
+
+ string xml = mode->BuildHelpXML(chain);
+ SCOPED_TRACE(xml);
+
+ stringstream ss;
+ ss << "<mode><name>mode</name>";
+ ss << "<description>md</description>";
+ ss << "<mode><name>submode</name>";
+ ss << "<description>subd</description>";
+ ss << "<action><name>action</name>";
+ ss << "<description>ad</description><extra_description></extra_description>";
+ ss << "<argument><kind>required</kind><name>required</name>"
+ "<description>rpd</description><type>string</type></argument>";
+ ss << "<usage>mode submode action &lt;required&gt;</usage>";
+ ss << "</action>";
+ ss << "</mode>";
+ ss << "</mode>";
+ string expected_xml = ss.str();
+
+ ASSERT_EQ(expected_xml, xml);
+}
+
+} // namespace tools
+} // namespace kudu
http://git-wip-us.apache.org/repos/asf/kudu/blob/2407c2cb/src/kudu/tools/tool_action.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action.cc b/src/kudu/tools/tool_action.cc
index 1a920fc..a88849e 100644
--- a/src/kudu/tools/tool_action.cc
+++ b/src/kudu/tools/tool_action.cc
@@ -28,6 +28,7 @@
#include "kudu/gutil/strings/join.h"
#include "kudu/gutil/strings/split.h"
#include "kudu/gutil/strings/substitute.h"
+#include "kudu/util/url-coding.h"
using std::string;
using std::unique_ptr;
@@ -61,8 +62,7 @@ string FakeDescribeOneFlag(const ActionArgsDescriptor::Arg& arg) {
}
string BuildUsageString(const vector<Mode*>& chain) {
- string modes = JoinMapped(chain, [](Mode* a){ return a->name(); }, " ");
- return Substitute("Usage: $0", modes);
+ return JoinMapped(chain, [](Mode* a){ return a->name(); }, " ");
}
@@ -145,7 +145,8 @@ unique_ptr<Mode> ModeBuilder::Build() {
// Get help for this mode, passing in its parent mode chain.
string Mode::BuildHelp(const vector<Mode*>& chain) const {
string msg;
- msg += Substitute("$0 <command> [<args>]\n\n", BuildUsageString(chain));
+ msg += Substitute("Usage: $0 <command> [<args>]\n\n",
+ BuildUsageString(chain));
msg += "<command> can be one of the following:\n";
vector<pair<string, string>> line_pairs;
@@ -170,6 +171,25 @@ string Mode::BuildHelp(const vector<Mode*>& chain) const {
return msg;
}
+string Mode::BuildHelpXML(const vector<Mode*>& chain) const {
+ string xml;
+ xml += "<mode>";
+ xml += Substitute("<name>$0</name>", name());
+ xml += Substitute("<description>$0</description>",
+ EscapeForHtmlToString(description()));
+ for (const auto& a : actions()) {
+ xml += a->BuildHelpXML(chain);
+ }
+
+ for (const auto& m : modes()) {
+ vector<Mode*> m_chain(chain);
+ m_chain.push_back(m.get());
+ xml += m->BuildHelpXML(m_chain);
+ }
+ xml += "</mode>";
+ return xml;
+}
+
ActionBuilder::ActionBuilder(const string& name, const ActionRunner& runner)
: name_(name),
runner_(runner) {
@@ -228,7 +248,7 @@ Status Action::Run(const vector<Mode*>& chain,
}
string Action::BuildHelp(const vector<Mode*>& chain) const {
- string usage_msg = Substitute("$0 $1", BuildUsageString(chain), name());
+ string usage_msg = Substitute("Usage: $0 $1", BuildUsageString(chain), name());
string desc_msg;
for (const auto& param : args_.required) {
usage_msg += Substitute(" <$0>", param.name);
@@ -278,5 +298,74 @@ string Action::BuildHelp(const vector<Mode*>& chain) const {
return msg;
}
+string Action::BuildHelpXML(const vector<Mode*>& chain) const {
+ string usage = Substitute("$0 $1", BuildUsageString(chain), name());
+ string xml;
+ xml += "<action>";
+ xml += Substitute("<name>$0</name>", name());
+ xml += Substitute("<description>$0</description>",
+ EscapeForHtmlToString(description()));
+ xml += Substitute("<extra_description>$0</extra_description>",
+ EscapeForHtmlToString(extra_description()
+ .get_value_or("")));
+ for (const auto& r : args().required) {
+ usage += Substitute(" <$0>", r.name);
+ xml += "<argument>";
+ xml += "<kind>required</kind>";
+ xml += Substitute("<name>$0</name>", r.name);
+ xml += Substitute("<description>$0</description>",
+ EscapeForHtmlToString(r.description));
+ xml += "<type>string</type>";
+ xml += "</argument>";
+ }
+
+ if (args().variadic) {
+ const ActionArgsDescriptor::Arg& v = args().variadic.get();
+ usage += Substitute(" <$0>...", v.name);
+ xml += "<argument>";
+ xml += "<kind>variadic</kind>";
+ xml += Substitute("<name>$0</name>", v.name);
+ xml += Substitute("<description>$0</description>",
+ EscapeForHtmlToString(v.description));
+ xml += "<type>string</type>";
+ xml += "</argument>";
+ }
+
+ for (const auto& o : args().optional) {
+ google::CommandLineFlagInfo gflag_info =
+ google::GetCommandLineFlagInfoOrDie(o.c_str());
+
+ if (gflag_info.type == "bool") {
+ if (gflag_info.default_value == "false") {
+ usage += Substitute(" [-$0]", o);
+ } else {
+ usage += Substitute(" [-no$0]", o);
+ }
+ } else {
+ string noun;
+ string::size_type last_underscore_idx = o.rfind('_');
+ if (last_underscore_idx != string::npos &&
+ last_underscore_idx != o.size() - 1) {
+ noun = o.substr(last_underscore_idx + 1);
+ } else {
+ noun = o;
+ }
+ usage += Substitute(" [-$0=<$1>]", o, noun);
+ }
+
+ xml += "<argument>";
+ xml += "<kind>optional</kind>";
+ xml += Substitute("<name>$0</name>", gflag_info.name);
+ xml += Substitute("<description>$0</description>", gflag_info.description);
+ xml += Substitute("<type>$0</type>", gflag_info.type);
+ xml += Substitute("<default_value>$0</default_value>",
+ gflag_info.default_value);
+ xml += "</argument>";
+ }
+ xml += Substitute("<usage>$0</usage>", EscapeForHtmlToString(usage));
+ xml += "</action>";
+ return xml;
+}
+
} // namespace tools
} // namespace kudu
http://git-wip-us.apache.org/repos/asf/kudu/blob/2407c2cb/src/kudu/tools/tool_action.h
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_action.h b/src/kudu/tools/tool_action.h
index 082f0d0..522b895 100644
--- a/src/kudu/tools/tool_action.h
+++ b/src/kudu/tools/tool_action.h
@@ -107,6 +107,9 @@ class Mode {
// Returns the help for this mode given its parent mode chain.
std::string BuildHelp(const std::vector<Mode*>& chain) const;
+ // Returns the help xml for this mode and all child modes
+ std::string BuildHelpXML(const std::vector<Mode*>& chain) const;
+
const std::string& name() const { return name_; }
const std::string& description() const { return description_; }
@@ -242,6 +245,9 @@ class Action {
// Returns the help for this action given its parent mode chain.
std::string BuildHelp(const std::vector<Mode*>& chain) const;
+ // Returns the help xml for this action
+ std::string BuildHelpXML(const std::vector<Mode*>& chain) const;
+
// Runs the operation represented by this action, given a parent mode chain
// and marshaled command line arguments.
Status Run(const std::vector<Mode*>& chain,
http://git-wip-us.apache.org/repos/asf/kudu/blob/2407c2cb/src/kudu/tools/tool_main.cc
----------------------------------------------------------------------
diff --git a/src/kudu/tools/tool_main.cc b/src/kudu/tools/tool_main.cc
index dc90db6..3aeb8f7 100644
--- a/src/kudu/tools/tool_main.cc
+++ b/src/kudu/tools/tool_main.cc
@@ -32,6 +32,7 @@
#include "kudu/tools/tool_action.h"
#include "kudu/util/flags.h"
#include "kudu/util/logging.h"
+#include "kudu/util/path_util.h"
#include "kudu/util/status.h"
DECLARE_bool(help);
@@ -41,6 +42,7 @@ DECLARE_bool(helpxml);
DECLARE_string(helpmatch);
DECLARE_string(helpon);
+using std::cout;
using std::cerr;
using std::deque;
using std::endl;
@@ -53,6 +55,23 @@ using strings::Substitute;
namespace kudu {
namespace tools {
+unique_ptr<Mode> RootMode(const string& name) {
+ return ModeBuilder(name)
+ .Description("Kudu Command Line Tools") // root mode description isn't printed
+ .AddMode(BuildClusterMode())
+ .AddMode(BuildFsMode())
+ .AddMode(BuildLocalReplicaMode())
+ .AddMode(BuildMasterMode())
+ .AddMode(BuildPbcMode())
+ .AddMode(BuildRemoteReplicaMode())
+ .AddMode(BuildTableMode())
+ .AddMode(BuildTabletMode())
+ .AddMode(BuildTestMode())
+ .AddMode(BuildTServerMode())
+ .AddMode(BuildWalMode())
+ .Build();
+}
+
Status MarshalArgs(const vector<Mode*>& chain,
Action* action,
deque<string> input,
@@ -109,27 +128,24 @@ int DispatchCommand(const vector<Mode*>& chain,
}
// Replace hyphens with underscores in a string and return a copy.
-string HyphensToUnderscores(string str) {
+static string HyphensToUnderscores(string str) {
std::replace(str.begin(), str.end(), '-', '_');
return str;
}
-int RunTool(int argc, char** argv, bool show_help) {
- unique_ptr<Mode> root = ModeBuilder(argv[0])
- .Description("doesn't matter") // root mode description isn't printed
- .AddMode(BuildClusterMode())
- .AddMode(BuildFsMode())
- .AddMode(BuildLocalReplicaMode())
- .AddMode(BuildMasterMode())
- .AddMode(BuildPbcMode())
- .AddMode(BuildRemoteReplicaMode())
- .AddMode(BuildTableMode())
- .AddMode(BuildTabletMode())
- .AddMode(BuildTestMode())
- .AddMode(BuildTServerMode())
- .AddMode(BuildWalMode())
- .Build();
+void DumpToolXML(const string& path) {
+ unique_ptr<Mode> root = RootMode(BaseName(path));
+ cout << "<?xml version=\"1.0\"?>";
+ cout << "<AllModes>";
+ for (const auto& mode : root->modes()) {
+ vector<Mode*> chain = { root.get(), mode.get() };
+ cout << mode->BuildHelpXML(chain);
+ }
+ cout << "</AllModes>" << endl;
+}
+int RunTool(int argc, char** argv, bool show_help) {
+ unique_ptr<Mode> root = RootMode(argv[0]);
// Initialize arg parsing state.
vector<Mode*> chain = { root.get() };
@@ -202,18 +218,23 @@ static bool ParseCommandLineFlags(int* argc, char*** argv) {
// Inspired by https://github.com/gflags/gflags/issues/43#issuecomment-168280647.
bool show_help = false;
gflags::ParseCommandLineNonHelpFlags(argc, argv, true);
+
+ // Leverage existing helpxml flag to print mode/action xml.
+ if (FLAGS_helpxml) {
+ kudu::tools::DumpToolXML(*argv[0]);
+ exit(1);
+ }
+
if (FLAGS_help ||
FLAGS_helpshort ||
!FLAGS_helpon.empty() ||
!FLAGS_helpmatch.empty() ||
- FLAGS_helppackage ||
- FLAGS_helpxml) {
+ FLAGS_helppackage) {
FLAGS_help = false;
FLAGS_helpshort = false;
FLAGS_helpon = "";
FLAGS_helpmatch = "";
FLAGS_helppackage = false;
- FLAGS_helpxml = false;
show_help = true;
}
kudu::HandleCommonFlags();