Skip to content
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
45 changes: 45 additions & 0 deletions samcli/cli/lazy_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""
LazyGroup implementation for Click CLI performance optimization
"""

import importlib

import click
from click import ClickException


class LazyGroup(click.Group):
def __init__(self, *args, lazy_subcommands=None, **kwargs):
super().__init__(*args, **kwargs)
# lazy_subcommands is a map of the form:
# {command-name} -> {module-name}.{command-object-name}
self.lazy_subcommands = lazy_subcommands or {}

def list_commands(self, ctx):
base = super().list_commands(ctx)
lazy = sorted(self.lazy_subcommands.keys())
return base + lazy

def get_command(self, ctx, cmd_name):
if cmd_name in self.lazy_subcommands:
return self._lazy_load(cmd_name)
return super().get_command(ctx, cmd_name)

def _lazy_load(self, cmd_name):
# lazily loading a command, first get the module name and attribute name
import_path = self.lazy_subcommands[cmd_name]
modname, cmd_object_name = import_path.rsplit(".", 1)
# do the import
try:
mod = importlib.import_module(modname)
except ImportError as e:
raise ClickException(f"Failed to load command '{cmd_name}': {str(e)}")
# get the Command object from that module
try:
cmd_object = getattr(mod, cmd_object_name)
except AttributeError:
raise ClickException(f"Command '{cmd_name}' not found in module '{modname}'")
# check the result to make debugging easier
if not isinstance(cmd_object, click.Command):
raise ClickException(f"Lazy loading of {import_path} failed by returning a non-command object")
return cmd_object
19 changes: 9 additions & 10 deletions samcli/commands/list/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@

import click

from samcli.commands.list.endpoints.command import cli as testable_resources_cli
from samcli.commands.list.resources.command import cli as resources_cli
from samcli.commands.list.stack_outputs.command import cli as stack_outputs_cli
from samcli.cli.lazy_group import LazyGroup


@click.group()
@click.group(
cls=LazyGroup,
lazy_subcommands={
"endpoints": "samcli.commands.list.endpoints.command.cli",
"resources": "samcli.commands.list.resources.command.cli",
"stack-outputs": "samcli.commands.list.stack_outputs.command.cli",
},
)
def cli():
"""
Get local and deployed state of serverless application.
"""


# Add individual commands under this group
cli.add_command(resources_cli)
cli.add_command(stack_outputs_cli)
cli.add_command(testable_resources_cli)
22 changes: 10 additions & 12 deletions samcli/commands/local/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,19 @@

import click

from .generate_event.cli import cli as generate_event_cli
from .invoke.cli import cli as invoke_cli
from .start_api.cli import cli as start_api_cli
from .start_lambda.cli import cli as start_lambda_cli
from samcli.cli.lazy_group import LazyGroup


@click.group()
@click.group(
cls=LazyGroup,
lazy_subcommands={
"invoke": "samcli.commands.local.invoke.cli.cli",
Comment thread
bchampp marked this conversation as resolved.
"start-api": "samcli.commands.local.start_api.cli.cli",
"start-lambda": "samcli.commands.local.start_lambda.cli.cli",
"generate-event": "samcli.commands.local.generate_event.cli.cli",
},
)
def cli():
"""
Run your Serverless application locally for quick development & testing
"""


# Add individual commands under this group
cli.add_command(invoke_cli)
cli.add_command(start_api_cli)
cli.add_command(generate_event_cli)
cli.add_command(start_lambda_cli)
16 changes: 8 additions & 8 deletions samcli/commands/pipeline/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@

import click

from .bootstrap.cli import cli as bootstrap_cli
from .init.cli import cli as init_cli
from samcli.cli.lazy_group import LazyGroup


@click.group()
@click.group(
cls=LazyGroup,
lazy_subcommands={
"bootstrap": "samcli.commands.pipeline.bootstrap.cli.cli",
"init": "samcli.commands.pipeline.init.cli.cli",
},
)
def cli() -> None:
"""
Manage the continuous delivery of the application
"""


# Add individual commands under this group
cli.add_command(bootstrap_cli)
cli.add_command(init_cli)
16 changes: 8 additions & 8 deletions samcli/commands/remote/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@

import click

from samcli.commands.remote.invoke.cli import cli as invoke_cli
from samcli.commands.remote.test_event.test_event import cli as event_cli
from samcli.cli.lazy_group import LazyGroup


@click.group()
@click.group(
cls=LazyGroup,
lazy_subcommands={
"invoke": "samcli.commands.remote.invoke.cli.cli",
"test-event": "samcli.commands.remote.test_event.test_event.cli",
},
)
def cli():
"""
Interact with your Serverless application in the cloud for quick development & testing
"""


# Add individual commands under this group
cli.add_command(invoke_cli)
cli.add_command(event_cli)
22 changes: 11 additions & 11 deletions samcli/commands/remote/test_event/test_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@

import click

from samcli.commands.remote.test_event.delete.cli import cli as delete_cli
from samcli.commands.remote.test_event.get.cli import cli as get_cli
from samcli.commands.remote.test_event.list.cli import cli as list_cli
from samcli.commands.remote.test_event.put.cli import cli as put_cli
from samcli.cli.lazy_group import LazyGroup


@click.group("test-event")
@click.group(
"test-event",
cls=LazyGroup,
lazy_subcommands={
"delete": "samcli.commands.remote.test_event.delete.cli.cli",
"get": "samcli.commands.remote.test_event.get.cli.cli",
"put": "samcli.commands.remote.test_event.put.cli.cli",
"list": "samcli.commands.remote.test_event.list.cli.cli",
},
)
def cli():
"""
Manage remote test events
"""


cli.add_command(delete_cli)
cli.add_command(get_cli)
cli.add_command(put_cli)
cli.add_command(list_cli)
23 changes: 14 additions & 9 deletions schema/make_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,18 +186,23 @@ def retrieve_command_structure(package_name: str) -> List[SamCliCommandSchema]:
subcommands within the package.
"""
module = importlib.import_module(package_name)

def create_command_schema(module, subcommand):
cmd_name = SamConfig.to_key([module.__name__.split(".")[-1], str(subcommand.name)])
return SamCliCommandSchema(
cmd_name,
clean_text(subcommand.help or subcommand.short_help or ""),
get_params_from_command(subcommand),
)

command = []

if isinstance(module.cli, click.core.Group): # command has subcommands (e.g. local invoke)
for subcommand in module.cli.commands.values():
cmd_name = SamConfig.to_key([module.__name__.split(".")[-1], str(subcommand.name)])
command.append(
SamCliCommandSchema(
cmd_name,
clean_text(subcommand.help or subcommand.short_help or ""),
get_params_from_command(subcommand),
)
)
ctx = click.Context(module.cli)
for subcommand_name in module.cli.list_commands(ctx):
subcommand = module.cli.get_command(ctx, subcommand_name)
if subcommand:
command.append(create_command_schema(module, subcommand))
else:
cmd_name = SamConfig.to_key([module.__name__.split(".")[-1]])
command.append(
Expand Down
98 changes: 49 additions & 49 deletions schema/samcli.json
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,21 @@
"parameters"
]
},
"local_generate_event": {
"title": "Local Generate Event command",
"description": "Generate events for Lambda functions.",
"properties": {
"parameters": {
"title": "Parameters for the local generate event command",
"description": "Available parameters for the local generate event command:\n* ",
"type": "object",
"properties": {}
}
},
"required": [
"parameters"
]
},
"local_invoke": {
"title": "Local Invoke command",
"description": "Invoke AWS serverless functions locally.",
Expand Down Expand Up @@ -835,21 +850,6 @@
"parameters"
]
},
"local_generate_event": {
"title": "Local Generate Event command",
"description": "Generate events for Lambda functions.",
"properties": {
"parameters": {
"title": "Parameters for the local generate event command",
"description": "Available parameters for the local generate event command:\n* ",
"type": "object",
"properties": {}
}
},
"required": [
"parameters"
]
},
"local_start_lambda": {
"title": "Local Start Lambda command",
"description": "Emulate AWS serverless functions locally.",
Expand Down Expand Up @@ -2040,13 +2040,13 @@
"parameters"
]
},
"list_resources": {
"title": "List Resources command",
"description": "Get a list of resources that will be deployed to CloudFormation.\n\nIf a stack name is provided, the corresponding physical IDs of each\nresource will be mapped to the logical ID of each resource.",
"list_endpoints": {
"title": "List Endpoints command",
"description": "Get a summary of the cloud endpoints in the stack.\n\nThis command will show both the cloud and local endpoints that can\nbe used with sam local and sam sync. Currently the endpoint resources\nare Lambda functions and API Gateway API resources.",
"properties": {
"parameters": {
"title": "Parameters for the list resources command",
"description": "Available parameters for the list resources command:\n* parameter_overrides:\nString that contains AWS CloudFormation parameter overrides encoded as key=value pairs.\n* stack_name:\nName of corresponding deployed stack.(Not including a stack name will only show local resources defined in the template.)\n* output:\nOutput the results from the command in a given output format (json or table).\n* template_file:\nAWS SAM template file.\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* save_params:\nSave the parameters provided via the command line to the configuration file.",
"title": "Parameters for the list endpoints command",
"description": "Available parameters for the list endpoints command:\n* parameter_overrides:\nString that contains AWS CloudFormation parameter overrides encoded as key=value pairs.\n* stack_name:\nName of corresponding deployed stack.(Not including a stack name will only show local resources defined in the template.)\n* output:\nOutput the results from the command in a given output format (json or table).\n* template_file:\nAWS SAM template file.\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* save_params:\nSave the parameters provided via the command line to the configuration file.",
"type": "object",
"properties": {
"parameter_overrides": {
Expand Down Expand Up @@ -2113,19 +2113,30 @@
"parameters"
]
},
"list_stack_outputs": {
"title": "List Stack Outputs command",
"description": "Get the stack outputs as defined in the SAM/CloudFormation template.",
"list_resources": {
"title": "List Resources command",
"description": "Get a list of resources that will be deployed to CloudFormation.\n\nIf a stack name is provided, the corresponding physical IDs of each\nresource will be mapped to the logical ID of each resource.",
"properties": {
"parameters": {
"title": "Parameters for the list stack outputs command",
"description": "Available parameters for the list stack outputs command:\n* stack_name:\nName of corresponding deployed stack.\n* output:\nOutput the results from the command in a given output format (json or table).\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* save_params:\nSave the parameters provided via the command line to the configuration file.",
"title": "Parameters for the list resources command",
"description": "Available parameters for the list resources command:\n* parameter_overrides:\nString that contains AWS CloudFormation parameter overrides encoded as key=value pairs.\n* stack_name:\nName of corresponding deployed stack.(Not including a stack name will only show local resources defined in the template.)\n* output:\nOutput the results from the command in a given output format (json or table).\n* template_file:\nAWS SAM template file.\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* save_params:\nSave the parameters provided via the command line to the configuration file.",
"type": "object",
"properties": {
"parameter_overrides": {
"title": "parameter_overrides",
"type": [
"array",
"string"
],
"description": "String that contains AWS CloudFormation parameter overrides encoded as key=value pairs.",
"items": {
"type": "string"
}
},
"stack_name": {
"title": "stack_name",
"type": "string",
"description": "Name of corresponding deployed stack."
"description": "Name of corresponding deployed stack.(Not including a stack name will only show local resources defined in the template.)"
},
"output": {
"title": "output",
Expand All @@ -2137,6 +2148,12 @@
"table"
]
},
"template_file": {
"title": "template_file",
"type": "string",
"description": "AWS SAM template file.",
"default": "template.[yaml|yml|json]"
},
"profile": {
"title": "profile",
"type": "string",
Expand Down Expand Up @@ -2169,30 +2186,19 @@
"parameters"
]
},
"list_endpoints": {
"title": "List Endpoints command",
"description": "Get a summary of the cloud endpoints in the stack.\n\nThis command will show both the cloud and local endpoints that can\nbe used with sam local and sam sync. Currently the endpoint resources\nare Lambda functions and API Gateway API resources.",
"list_stack_outputs": {
"title": "List Stack Outputs command",
"description": "Get the stack outputs as defined in the SAM/CloudFormation template.",
"properties": {
"parameters": {
"title": "Parameters for the list endpoints command",
"description": "Available parameters for the list endpoints command:\n* parameter_overrides:\nString that contains AWS CloudFormation parameter overrides encoded as key=value pairs.\n* stack_name:\nName of corresponding deployed stack.(Not including a stack name will only show local resources defined in the template.)\n* output:\nOutput the results from the command in a given output format (json or table).\n* template_file:\nAWS SAM template file.\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* save_params:\nSave the parameters provided via the command line to the configuration file.",
"title": "Parameters for the list stack outputs command",
"description": "Available parameters for the list stack outputs command:\n* stack_name:\nName of corresponding deployed stack.\n* output:\nOutput the results from the command in a given output format (json or table).\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* save_params:\nSave the parameters provided via the command line to the configuration file.",
"type": "object",
"properties": {
"parameter_overrides": {
"title": "parameter_overrides",
"type": [
"array",
"string"
],
"description": "String that contains AWS CloudFormation parameter overrides encoded as key=value pairs.",
"items": {
"type": "string"
}
},
"stack_name": {
"title": "stack_name",
"type": "string",
"description": "Name of corresponding deployed stack.(Not including a stack name will only show local resources defined in the template.)"
"description": "Name of corresponding deployed stack."
},
"output": {
"title": "output",
Expand All @@ -2204,12 +2210,6 @@
"table"
]
},
"template_file": {
"title": "template_file",
"type": "string",
"description": "AWS SAM template file.",
"default": "template.[yaml|yml|json]"
},
"profile": {
"title": "profile",
"type": "string",
Expand Down
Loading
Loading