Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Topic command #1147

Merged
merged 13 commits into from
Apr 16, 2015
154 changes: 154 additions & 0 deletions awscli/clidocs.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import logging
import os
from bcdoc.docevents import DOC_EVENTS
from botocore import xform_name

from awscli import SCALAR_TYPES
from awscli.argprocess import ParamShorthandDocGen
from awscli.topictags import TopicTagDB

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -161,6 +163,20 @@ def doc_option(self, arg_name, help_command, **kwargs):
doc.style.dedent()
doc.style.new_paragraph()

def doc_relateditems_start(self, help_command, **kwargs):
if help_command.related_items:
doc = help_command.doc
doc.style.h2('See Also')

def doc_relateditem(self, help_command, related_item, **kwargs):
doc = help_command.doc
doc.write('* ')
doc.style.sphinx_reference_label(
label='cli:%s' % related_item,
text=related_item
)
doc.write('\n')


class ProviderDocumentEventHandler(CLIDocumentEventHandler):

Expand Down Expand Up @@ -485,3 +501,141 @@ def _do_doc_member_for_output(self, doc, member_name, member_shape, stack):
self._doc_member_for_output(doc, '', member_shape.member, stack)
doc.style.dedent()
doc.style.new_paragraph()


class TopicListerDocumentEventHandler(CLIDocumentEventHandler):
DESCRIPTION = (
'This is the AWS CLI Topic Guide. It gives access to a set '
'of topics that provide a deeper understanding of the CLI. To access '
'the list of topics from the command line, run ``aws help topics``. '
'To access a specific topic from the command line, run '
'``aws help [topicname]``, where ``topicname`` is the name of the '
'topic as it appears in the output from ``aws help topics``.')

def __init__(self, help_command):
self.help_command = help_command
self.register(help_command.session, help_command.event_class)
self.help_command.doc.translation_map = self.build_translation_map()
self._topic_tag_db = TopicTagDB()
self._topic_tag_db.load_json_index()

def doc_breadcrumbs(self, help_command, **kwargs):
doc = help_command.doc
if doc.target != 'man':
doc.write('[ ')
doc.style.sphinx_reference_label(label='cli:aws', text='aws')
doc.write(' ]')

def doc_title(self, help_command, **kwargs):
doc = help_command.doc
doc.style.new_paragraph()
doc.style.link_target_definition(
refname='cli:aws help %s' % self.help_command.name,
link='')
doc.style.h1('AWS CLI Topic Guide')

def doc_description(self, help_command, **kwargs):
doc = help_command.doc
doc.style.h2('Description')
doc.include_doc_string(self.DESCRIPTION)
doc.style.new_paragraph()

def doc_synopsis_start(self, help_command, **kwargs):
pass

def doc_synopsis_end(self, help_command, **kwargs):
pass

def doc_options_start(self, help_command, **kwargs):
pass

def doc_options_end(self, help_command, **kwargs):
pass

def doc_subitems_start(self, help_command, **kwargs):
doc = help_command.doc
doc.style.h2('Available Topics')

categories = self._topic_tag_db.query('category')
topic_names = self._topic_tag_db.get_all_topic_names()

# Sort the categories
category_names = sorted(categories.keys())
for category_name in category_names:
doc.style.h3(category_name)
doc.style.new_paragraph()
# Write out the topic and a description for each topic under
# each category.
for topic_name in sorted(categories[category_name]):
description = self._topic_tag_db.get_tag_single_value(
topic_name, 'description')
doc.write('* ')
doc.style.sphinx_reference_label(
label='cli:aws help %s' % topic_name,
text=topic_name
)
doc.write(': %s\n' % description)
# Add a hidden toctree to make sure everything is connected in
# the document.
doc.style.hidden_toctree()
for topic_name in topic_names:
doc.style.hidden_tocitem(topic_name)


class TopicDocumentEventHandler(TopicListerDocumentEventHandler):

def doc_breadcrumbs(self, help_command, **kwargs):
doc = help_command.doc
if doc.target != 'man':
doc.write('[ ')
doc.style.sphinx_reference_label(label='cli:aws', text='aws')
doc.write(' . ')
doc.style.sphinx_reference_label(
label='cli:aws help topics',
text='topics'
)
doc.write(' ]')

def doc_title(self, help_command, **kwargs):
doc = help_command.doc
doc.style.new_paragraph()
doc.style.link_target_definition(
refname='cli:aws help %s' % self.help_command.name,
link='')
title = self._topic_tag_db.get_tag_single_value(
help_command.name, 'title')
print(title)
print('here')
doc.style.h1(title)

def doc_description(self, help_command, **kwargs):
doc = help_command.doc
topic_filename = os.path.join(self._topic_tag_db.topic_dir,
help_command.name + '.rst')
contents = self._remove_tags_from_content(topic_filename)
doc.writeln(contents)
doc.style.new_paragraph()

def _remove_tags_from_content(self, filename):
with open(filename, 'r') as f:
lines = f.readlines()

content_begin_index = 0
for i, line in enumerate(lines):
# If a line is encountered that does not begin with the tag
# end the search for tags and mark where tags end.
if not self._line_has_tag(line):
content_begin_index = i
break

# Join all of the non-tagged lines back together.
return ''.join(lines[content_begin_index:])

def _line_has_tag(self, line):
for tag in self._topic_tag_db.valid_tags:
if line.startswith(':' + tag + ':'):
return True
return False

def doc_subitems_start(self, help_command, **kwargs):
pass
2 changes: 1 addition & 1 deletion awscli/clidriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ def __call__(self, args, parsed_globals):
parsed_args, remaining = operation_parser.parse_known_args(args)
if parsed_args.help == 'help':
op_help = self.create_help_command()
return op_help(parsed_args, parsed_globals)
return op_help(remaining, parsed_globals)
elif parsed_args.help:
remaining.append(parsed_args.help)
if remaining:
Expand Down
2 changes: 1 addition & 1 deletion awscli/data/cli.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"description": "The AWS Command Line Interface is a unified tool to manage your AWS services.",
"synopsis": "aws [options] <command> <subcommand> [parameters]",
"help_usage": "Use *aws command help* for information on a specific command.",
"help_usage": "Use *aws command help* for information on a specific command. Use *aws help topics* to view a list of available help topics.",
"options": {
"debug": {
"action": "store_true",
Expand Down
80 changes: 79 additions & 1 deletion awscli/help.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@
from awscli.clidocs import ProviderDocumentEventHandler
from awscli.clidocs import ServiceDocumentEventHandler
from awscli.clidocs import OperationDocumentEventHandler
from awscli.clidocs import TopicListerDocumentEventHandler
from awscli.clidocs import TopicDocumentEventHandler
from awscli.argprocess import ParamShorthand
from awscli.argparser import ArgTableArgParser
from awscli.topictags import TopicTagDB


LOG = logging.getLogger('awscli.help')
Expand Down Expand Up @@ -184,7 +188,8 @@ def __init__(self, session, obj, command_table, arg_table):
if arg_table is None:
arg_table = {}
self.arg_table = arg_table
self.related_items = []
self._subcommand_table = {}
self._related_items = []
self.renderer = get_renderer()
self.doc = ReSTDocument(target='man')

Expand Down Expand Up @@ -213,7 +218,24 @@ def name(self):
"""
pass

@property
def subcommand_table(self):
"""These are the commands that may follow after the help command"""
return self._subcommand_table

@property
def related_items(self):
"""This is list of items that are related to the help command"""
return self._related_items

def __call__(self, args, parsed_globals):
if args:
subcommand_parser = ArgTableArgParser({}, self.subcommand_table)
parsed, remaining = subcommand_parser.parse_known_args(args)
if getattr(parsed, 'subcommand', None) is not None:
return self.subcommand_table[parsed.subcommand](remaining,
parsed_globals)

# Create an event handler for a Provider Document
instance = self.EventHandlerClass(self)
# Now generate all of the events for a Provider document.
Expand All @@ -239,6 +261,9 @@ def __init__(self, session, command_table, arg_table,
self.description = description
self.synopsis = synopsis
self.help_usage = usage
self._subcommand_table = None
self._topic_tag_db = None
self._related_items = ['aws help topics']

@property
def event_class(self):
Expand All @@ -248,6 +273,28 @@ def event_class(self):
def name(self):
return self.obj.name

@property
def subcommand_table(self):
if self._subcommand_table is None:
if self._topic_tag_db is None:
self._topic_tag_db = TopicTagDB()
self._topic_tag_db.load_json_index()
self._subcommand_table = self._create_subcommand_table()
return self._subcommand_table

def _create_subcommand_table(self):
subcommand_table = {}
# Add the ``aws help topics`` command to the ``topic_table``
topic_lister_command = TopicListerCommand(self.session)
subcommand_table['topics'] = topic_lister_command
topic_names = self._topic_tag_db.get_all_topic_names()

# Add all of the possible topics to the ``topic_table``
for topic_name in topic_names:
topic_help_command = TopicHelpCommand(self.session, topic_name)
subcommand_table[topic_name] = topic_help_command
return subcommand_table


class ServiceHelpCommand(HelpCommand):
"""Implements service level help.
Expand Down Expand Up @@ -298,3 +345,34 @@ def event_class(self):
@property
def name(self):
return self._name


class TopicListerCommand(HelpCommand):
EventHandlerClass = TopicListerDocumentEventHandler

def __init__(self, session):
super(TopicListerCommand, self).__init__(session, None, {}, {})

@property
def event_class(self):
return 'topics'

@property
def name(self):
return 'topics'


class TopicHelpCommand(HelpCommand):
EventHandlerClass = TopicDocumentEventHandler

def __init__(self, session, topic_name):
super(TopicHelpCommand, self).__init__(session, None, {}, {})
self._topic_name = topic_name

@property
def event_class(self):
return 'topics.' + self.name

@property
def name(self):
return self._topic_name
2 changes: 1 addition & 1 deletion awscli/topics/return-codes.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
:title: AWS CLI Return Codes
:description: Describes the various return codes of the AWS CLI
:category: General Topics, S3, Troubleshooting
:category: General
:related command: s3, s3 cp, s3 sync, s3 mv, s3 rm

These are the following return codes returned at the end of execution
Expand Down
4 changes: 1 addition & 3 deletions awscli/topics/topic-tags.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
},
"return-codes": {
"category": [
"General Topics",
"S3",
"Troubleshooting"
"General"
],
"description": [
"Describes the various return codes of the AWS CLI"
Expand Down
4 changes: 4 additions & 0 deletions awscli/topictags.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ def topic_dir(self):
def topic_dir(self, value):
self._topic_dir = value

@property
def valid_tags(self):
return self.VALID_TAGS

def load_json_index(self):
"""Loads a JSON file into the tag dictionary."""
with open(self.index_file, 'r') as f:
Expand Down
1 change: 1 addition & 0 deletions doc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ help:
clean:
-rm -rf $(BUILDDIR)/*
-rm -rf $(SOURCEDIR)/reference
-rm -rf $(SOURCEDIR)/topic
-rm -rf $(SOURCEDIR)/tutorial/services.rst

html:
Expand Down
Loading