diff --git a/awscli/customizations/commands.py b/awscli/customizations/commands.py index afddc25f1beb..d9cd09921fb4 100644 --- a/awscli/customizations/commands.py +++ b/awscli/customizations/commands.py @@ -1,7 +1,9 @@ -import bcdoc.docevents +import os +import bcdoc.docevents from botocore.compat import OrderedDict +import awscli from awscli.clidocs import CLIDocumentEventHandler from awscli.argparser import ArgTableArgParser from awscli.clidriver import CLICommand @@ -55,6 +57,22 @@ class BasicCommand(CLICommand): # The command_class must subclass from ``BasicCommand``. SUBCOMMANDS = [] + FROM_FILE = object() + # You can set the DESCRIPTION, SYNOPSIS, and EXAMPLES to FROM_FILE + # and we'll automatically read in that data from the file. + # This is useful if you have a lot of content and would prefer to keep + # the docs out of the class definition. For example: + # + # DESCRIPTION = FROM_FILE + # + # will set the DESCRIPTION value to the contents of + # awscli/examples//_description.rst + # The naming conventions for these attributes are: + # + # DESCRIPTION = awscli/examples//_description.rst + # SYNOPSIS = awscli/examples//_synopsis.rst + # EXAMPLES = awscli/examples//_examples.rst + # At this point, the only other thing you have to implement is a _run_main # method (see the method for more information). @@ -135,14 +153,37 @@ def __init__(self, session, command_object, command_table, arg_table, # These are public attributes that are mapped from the command # object. These are used by the BasicDocHandler below. - self.description = command_object.DESCRIPTION - self.synopsis = command_object.SYNOPSIS - self.examples = command_object.EXAMPLES + self._description = command_object.DESCRIPTION + self._synopsis = command_object.SYNOPSIS + self._examples = command_object.EXAMPLES @property def name(self): return self.obj.NAME + @property + def description(self): + return self._get_doc_contents('_description') + + @property + def synopsis(self): + return self._get_doc_contents('_synopsis') + + @property + def examples(self): + return self._get_doc_contents('_examples') + + def _get_doc_contents(self, attr_name): + value = getattr(self, attr_name) + if value is BasicCommand.FROM_FILE: + doc_path = os.path.join( + os.path.abspath(os.path.dirname(awscli.__file__)), 'examples', + self.name, attr_name + '.rst') + with open(doc_path) as f: + return f.read() + else: + return value + def __call__(self, args, parsed_globals): # Create an event handler for a Provider Document instance = self.EventHandlerClass(self) diff --git a/awscli/customizations/configure.py b/awscli/customizations/configure.py index 812b09ad1956..9f0f53f1fabb 100644 --- a/awscli/customizations/configure.py +++ b/awscli/customizations/configure.py @@ -273,21 +273,7 @@ def _lookup_config(self, name): class ConfigureCommand(BasicCommand): NAME = 'configure' - DESCRIPTION = ( - 'Configure AWS CLI configuration data. If this command ' - 'is run with no arguments, you will be prompted for configuration ' - 'values such as your AWS Access Key Id and you AWS Secret Access ' - 'Key. You can configure a specific profile using the ``--profile`` ' - 'argument. If your config file does not exist (the default location ' - 'is ``~/.aws/config``), it will be automatically created for you. ' - 'To keep an existing value, hit enter when prompted for the value.\n\n' - 'When you are prompted for information, the current value will be ' - 'displayed in ``[brackets]``. If the config item has no value, it ' - 'be displayed as ``[None]``.\n\n' - 'Note that the ``configure`` command only work with values from the ' - 'config file. It does not use any configuration values from ' - 'environment variables or the IAM role.\n' - ) + DESCRIPTION = BasicCommand.FROM_FILE SYNOPSIS = ('aws configure [--profile profile-name]') EXAMPLES = ( 'To create a new configuration::\n' diff --git a/awscli/examples/configure/_description.rst b/awscli/examples/configure/_description.rst new file mode 100644 index 000000000000..040dd5b88e8c --- /dev/null +++ b/awscli/examples/configure/_description.rst @@ -0,0 +1,28 @@ +Configure AWS CLI configuration data. If this command is run with no +arguments, you will be prompted for configuration values such as your AWS +Access Key Id and you AWS Secret Access Key. You can configure a specific +profile using the ``--profile`` argument. If your config file does not exist +(the default location is ``~/.aws/config``), it will be automatically created +for you. To keep an existing value, hit enter when prompted for the value. +When you are prompted for information, the current value will be displayed in +``[brackets]``. If the config item has no value, it be displayed as +``[None]``. Note that the ``configure`` command only work with values from the +config file. It does not use any configuration values from environment +variables or the IAM role. + +======================= +Configuration Variables +======================= + +The following configuration variables are supported in the config file: + +* **aws_access_key_id** - The AWS access key part of your credentials +* **aws_secret_access_key** - The AWS secret access key part of your credentials +* **aws_security_token** - The security token part of your credentials (session tokens only) +* **metadata_service_timeout** - The number of seconds to wait until the metadata service + request times out. This is used if you are using an IAM role to provide + your credentials. +* **metadata_service_num_attempts** - The number of attempts to try to retrieve + credentials. If you know for certain you will be using an IAM role on an + Amazon EC2 instance, you can set this value to ensure any intermittent + failures are retried. By default this value is 1. diff --git a/tests/unit/docs/test_help_output.py b/tests/unit/docs/test_help_output.py index 83c3768d32d2..7c076c7c0a7e 100644 --- a/tests/unit/docs/test_help_output.py +++ b/tests/unit/docs/test_help_output.py @@ -262,3 +262,14 @@ def test_create_image_renames(self): self.driver.main(['ec2', 'create-image', 'help']) self.assert_not_contains('no-no-reboot') self.assert_contains('--reboot') + +class TestCustomCommandDocsFromFile(BaseAWSHelpOutputTest): + def test_description_from_rst_file(self): + # The description for the configure command + # is in _description.rst. We're verifying that we + # can read those contents properly. + self.driver.main(['configure', 'help']) + # These are a few options that are documented in the help output. + self.assert_contains('metadata_service_timeout') + self.assert_contains('metadata_service_num_attempts') + self.assert_contains('aws_access_key_id')