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

Document preview services #1345

Merged
merged 5 commits into from
May 27, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 58 additions & 36 deletions awscli/customizations/preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,32 +33,15 @@
import sys
import textwrap

from awscli.clidriver import CLICommand


logger = logging.getLogger(__name__)

# Mapping of service name to help text to print
# when a user tries to invoke a service marked as preview.
CLOUDSEARCH_HELP = """
CloudSearch has a specialized command line tool available at
http://aws.amazon.com/tools#cli. The AWS CLI does not yet
support all of the features of the CloudSearch CLI. Until these features
are added to the AWS CLI, you may have a more complete
experience using the CloudSearch CLI.
"""


GENERAL_HELP = """
This service is only available as a preview service.
"""


PREVIEW_SERVICES = {
'cloudfront': GENERAL_HELP,
'sdb': GENERAL_HELP,
'efs': GENERAL_HELP,
}
PREVIEW_SERVICES = [
'cloudfront',
'sdb',
'efs',
]


def register_preview_commands(events):
Expand All @@ -70,15 +53,48 @@ def mark_as_preview(command_table, session, **kwargs):
# explicitly enabled in the config file.
allowed_services = _get_allowed_services(session)
for preview_service in PREVIEW_SERVICES:
is_enabled = False
if preview_service in allowed_services:
# Then we don't need to swap it as a preview
# service, the user has specifically asked to
# enable this service.
logger.debug("Preview service enabled through config file: %s",
preview_service)
continue
command_table[preview_service] = PreviewModeCommand(
preview_service, PREVIEW_SERVICES[preview_service])
is_enabled = True
original_command = command_table[preview_service]
preview_cls = type(
'PreviewCommand',
(PreviewModeCommandMixin, original_command.__class__), {})
command_table[preview_service] = preview_cls(
cli_name=original_command.name,
session=session,
service_name=original_command.service_model.service_name,
is_enabled=is_enabled)
# We also want to register a handler that will update the
# description in the docs to say that this is a preview service.
session.get_component('event_emitter').register_last(
'doc-description.%s' % preview_service,
update_description_with_preview)


def update_description_with_preview(help_command, **kwargs):
style = help_command.doc.style
style.start_note()
style.bold(PreviewModeCommandMixin.HELP_SNIPPET.strip())
# bcdoc does not currently allow for what I'd like to do
# which is have a code block like:
#
# ::
# [preview]
# service=true
#
# aws configure set preview.service true
#
# So for now we're just going to add the configure command
# to enable this.
style.doc.write("You can enable this service by running: ")
style.code("aws configure set preview.%s true" % help_command.name)
style.end_note()


def _get_allowed_services(session):
Expand All @@ -93,14 +109,9 @@ def _get_allowed_services(session):
return allowed


class PreviewModeCommand(CLICommand):
# This is a hidden attribute that tells the doc system
# not to document this command in the provider help.
# This is an internal implementation detail.
_UNDOCUMENTED = True

class PreviewModeCommandMixin(object):
ENABLE_DOCS = textwrap.dedent("""\
However, if you'd like to use a basic set of {service} commands with the
However, if you'd like to use the "aws {service}" commands with the
AWS CLI, you can enable this service by adding the following to your CLI
config file:

Expand All @@ -112,13 +123,24 @@ class PreviewModeCommand(CLICommand):
aws configure set preview.{service} true

""")
HELP_SNIPPET = "This service is only available as a preview service.\n"

def __init__(self, service_name, service_help):
self._service_name = service_name
self._service_help = service_help
def __init__(self, *args, **kwargs):
self._is_enabled = kwargs.pop('is_enabled')
super(PreviewModeCommandMixin, self).__init__(*args, **kwargs)

def __call__(self, args, parsed_globals):
sys.stderr.write(self._service_help)
if self._is_enabled or self._is_help_command(args):
return super(PreviewModeCommandMixin, self).__call__(
args, parsed_globals)
else:
return self._display_opt_in_message()

def _is_help_command(self, args):
return args and args[-1] == 'help'

def _display_opt_in_message(self):
sys.stderr.write(self.HELP_SNIPPET)
sys.stderr.write("\n")
# Then let them know how to enable this service.
sys.stderr.write(self.ENABLE_DOCS.format(service=self._service_name))
Expand Down
38 changes: 22 additions & 16 deletions tests/unit/customizations/test_preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,33 +40,39 @@ def test_invoke_preview_mode_service(self):
# ever mark cloudfront as not being a preview service
# by default.
self.assertIn('cloudfront', preview.PREVIEW_SERVICES)
rc = self.driver.main('cloudfront help'.split())
rc = self.driver.main('cloudfront list-distributions'.split())
self.assertEqual(rc, 1)
self.assertIn(preview.PREVIEW_SERVICES['cloudfront'],
self.assertIn(preview.PreviewModeCommandMixin.HELP_SNIPPET,
self.stderr.getvalue())

@mock.patch('awscli.help.get_renderer')
def test_preview_service_off(self, get_renderer):
def test_preview_service_not_true(self):
# If it's not "true" then we still make it a preview service.
self.full_config['preview'] = {'cloudfront': 'false'}
rc = self.driver.main('cloudfront list-distributions'.split())
self.assertEqual(rc, 1)
self.assertIn(preview.PreviewModeCommandMixin.HELP_SNIPPET,
self.stderr.getvalue())

def test_preview_service_enabled_makes_call(self):
self.full_config['preview'] = {'cloudfront': 'true'}
self.assert_params_for_cmd('cloudfront list-distributions', params={})

@mock.patch('awscli.help.get_renderer')
def test_can_still_document_preview_service(self, get_renderer):
# Even if a service is still marked as being in preview,
# you can still pull up its documentation.
self.full_config['preview'] = {'cloudfront': 'false'}
renderer = mock.Mock()
get_renderer.return_value = renderer
self.driver.main('cloudfront help'.split())
# In this case, the normal help processing should have occurred
# and we check that we rendered the contents.
self.assertTrue(renderer.render.called)

def test_preview_service_not_true(self):
# If it's not "true" then we still make it a preview service.
self.full_config['preview'] = {'cloudfront': 'false'}
rc = self.driver.main('cloudfront help'.split())
self.assertEqual(rc, 1)
self.assertIn(preview.PREVIEW_SERVICES['cloudfront'],
self.stderr.getvalue())

@mock.patch('awscli.help.get_renderer')
def test_preview_mode_not_in_provider_help(self, renderer):
def test_preview_mode_is_in_provider_help(self, renderer):
self.driver.main(['help'])
contents = renderer.return_value.render.call_args
# The preview services should not be in the help output.
contents = renderer.return_value.render.call_args[0][0]
# The preview services should still be in the help output.
for service in preview.PREVIEW_SERVICES:
self.assertNotIn(service, contents)
self.assertIn(service, contents.decode('utf-8'))
33 changes: 17 additions & 16 deletions tests/unit/test_completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,23 @@
'--query', '--no-sign-request']

COMPLETIONS = [
('aws ', -1, set(['autoscaling', 'cloudformation', 'cloudhsm',
'cloudsearch', 'cloudsearchdomain', 'cloudtrail',
'cloudwatch', 'cognito-identity', 'cognito-sync',
'configservice', 'configure', 'datapipeline', 'deploy',
'directconnect', 'ds', 'dynamodb', 'glacier', 'ec2',
'ecs', 'elasticache', 'elasticbeanstalk',
'elastictranscoder', 'elb', 'emr', 'iam',
'importexport', 'kinesis', 'kms', 'lambda', 'logs',
'machinelearning', 'opsworks', 'rds', 'redshift',
'route53', 'route53domains', 's3', 's3api', 'ses',
'sns', 'sqs', 'storagegateway', 'sts', 'ssm', 'support',
'swf', 'workspaces'])),
('aws cloud', -1, set(['cloudformation', 'cloudhsm', 'cloudsearch',
'cloudsearchdomain', 'cloudtrail', 'cloudwatch'])),
('aws cloudf', -1, set(['cloudformation'])),
('aws cloudfr', -1, set([])),
('aws ', -1, set(['autoscaling', 'cloudformation', 'cloudfront',
'cloudhsm', 'cloudsearch', 'cloudsearchdomain',
'cloudtrail', 'cloudwatch', 'cognito-identity',
'cognito-sync', 'configservice', 'configure',
'datapipeline', 'deploy', 'directconnect', 'ds',
'dynamodb', 'glacier', 'ec2', 'ecs', 'efs',
'elasticache', 'elasticbeanstalk', 'elastictranscoder',
'elb', 'emr', 'iam', 'importexport', 'kinesis', 'kms',
'lambda', 'logs', 'machinelearning', 'opsworks', 'rds',
'redshift', 'route53', 'route53domains', 's3', 's3api',
'sdb', 'ses', 'sns', 'sqs', 'storagegateway', 'sts',
'ssm', 'support', 'swf', 'workspaces'])),
('aws cloud', -1, set(['cloudformation', 'cloudfront', 'cloudhsm',
'cloudsearch', 'cloudsearchdomain', 'cloudtrail',
'cloudwatch'])),
('aws cloudf', -1, set(['cloudformation', 'cloudfront',])),
('aws cloudfr', -1, set(['cloudfront'])),
('aws foobar', -1, set([])),
('aws --', -1, set(GLOBALOPTS)),
('aws --re', -1, set(['--region'])),
Expand Down