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
179 changes: 126 additions & 53 deletions samcli/cli/cli_config_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,45 +10,60 @@
import logging
import os
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional

import click

from samcli.cli.context import get_cmd_names
from samcli.commands.exceptions import ConfigException
from samcli.lib.config.samconfig import DEFAULT_CONFIG_FILE_NAME, DEFAULT_ENV, SamConfig

__all__ = ("TomlProvider", "configuration_option", "get_ctx_defaults")
__all__ = ("ConfigProvider", "configuration_option", "get_ctx_defaults")

LOG = logging.getLogger(__name__)


class TomlProvider:
class ConfigProvider:
"""
A parser for toml configuration files
A parser for sam configuration files
"""

def __init__(self, section=None, cmd_names=None):
"""
The constructor for TomlProvider class
:param section: section defined in the configuration file nested within `cmd`
:param cmd_names: cmd_name defined in the configuration file
The constructor for ConfigProvider class

Parameters
----------
section
The section defined in the configuration file nested within `cmd`
cmd_names
The cmd_name defined in the configuration file
"""
self.section = section
self.cmd_names = cmd_names

def __call__(self, config_path, config_env, cmd_names):
def __call__(self, config_path: Path, config_env: str, cmd_names: List[str]) -> dict:
"""
Get resolved config based on the `file_path` for the configuration file,
`config_env` targeted inside the config file and corresponding `cmd_name`
as denoted by `click`.

:param config_path: The path of configuration file.
:param config_env: The name of the sectional config_env within configuration file.
:param list cmd_names: sam command name as defined by click
:returns dictionary containing the configuration parameters under specified config_env
Parameters
----------
config_path: Path
The path of configuration file.
config_env: str
The name of the sectional config_env within configuration file.
cmd_names: List[str]
The sam command name as defined by click.

Returns
-------
dict
A dictionary containing the configuration parameters under specified config_env.
"""

resolved_config = {}
resolved_config: dict = {}

# Use default sam config file name if config_path only contain the directory
config_file_path = (
Expand Down Expand Up @@ -105,27 +120,47 @@ def __call__(self, config_path, config_env, cmd_names):
return resolved_config


def configuration_callback(cmd_name, option_name, saved_callback, provider, ctx, param, value):
def configuration_callback(
cmd_name: str,
option_name: str,
saved_callback: Optional[Callable],
provider: Callable,
ctx: click.Context,
param: click.Parameter,
value,
):
"""
Callback for reading the config file.

Also takes care of calling user specified custom callback afterwards.

:param cmd_name: `sam` command name derived from click.
:param option_name: The name of the option. This is used for error messages.
:param saved_callback: User-specified callback to be called later.
:param provider: A callable that parses the configuration file and returns a dictionary
Parameters
----------
cmd_name: str
The `sam` command name derived from click.
option_name: str
The name of the option. This is used for error messages.
saved_callback: Optional[Callable]
User-specified callback to be called later.
provider: Callable
A callable that parses the configuration file and returns a dictionary
of the configuration parameters. Will be called as
`provider(file_path, config_env, cmd_name)`.
:param ctx: Click context
:param param: Click parameter
:param value: Specified value for config_env
:returns specified callback or the specified value for config_env.
ctx: click.Context
Click context
param: click.Parameter
Click parameter
value
Specified value for config_env

Returns
-------
The specified callback or the specified value for config_env.
"""

# ctx, param and value are default arguments for click specified callbacks.
ctx.default_map = ctx.default_map or {}
cmd_name = cmd_name or ctx.info_name
cmd_name = cmd_name or str(ctx.info_name)
param.default = None
config_env_name = ctx.params.get("config_env") or DEFAULT_ENV

Expand Down Expand Up @@ -154,21 +189,35 @@ def configuration_callback(cmd_name, option_name, saved_callback, provider, ctx,
return saved_callback(ctx, param, config_env_name) if saved_callback else config_env_name


def get_ctx_defaults(cmd_name, provider, ctx, config_env_name, config_file=None):
def get_ctx_defaults(
cmd_name: str, provider: Callable, ctx: click.Context, config_env_name: str, config_file: Optional[str] = None
) -> Any:
"""
Get the set of the parameters that are needed to be set into the click command.

This function also figures out the command name by looking up current click context's parent
and constructing the parsed command name that is used in default configuration file.
If a given cmd_name is start-api, the parsed name is "local_start_api".
provider is called with `config_file`, `config_env_name` and `parsed_cmd_name`.

:param cmd_name: `sam` command name
:param provider: provider to be called for reading configuration file
:param ctx: Click context
:param config_env_name: config-env within configuration file, sam configuration file will be relative to the
supplied original template if its path is not specified
:param config_file: configuration file name
:return: dictionary of defaults for parameters
Parameters
----------
cmd_name: str
The `sam` command name.
provider: Callable
The provider to be called for reading configuration file.
ctx: click.Context
Click context
config_env_name: str
The config-env within configuration file, sam configuration file will be relative to the
supplied original template if its path is not specified.
config_file: Optional[str]
The configuration file name.

Returns
-------
Any
A dictionary of defaults for parameters.
"""

return provider(config_file, config_env_name, get_cmd_names(cmd_name, ctx))
Expand All @@ -180,30 +229,38 @@ def configuration_option(*param_decls, **attrs):
"""
Adds configuration file support to a click application.

NOTE: This decorator should be added to the top of parameter chain, right below click.command, before
any options are declared.

Example:
>>> @click.command("hello")
@configuration_option(provider=TomlProvider(section="parameters"))
@click.option('--name', type=click.String)
def hello(name):
print("Hello " + name)

This will create a hidden click option whose callback function loads configuration parameters from default
configuration environment [default] in default configuration file [samconfig.toml] in the template file
directory.
:param preconfig_decorator_list: A list of click option decorator which need to place before this function. For
exmple, if we want to add option "--config-file" and "--config-env" to allow customized configuration file

Note
----
This decorator should be added to the top of parameter chain, right below click.command, before
any options are declared.

Example
-------
>>> @click.command("hello")
@configuration_option(provider=ConfigProvider(section="parameters"))
@click.option('--name', type=click.String)
def hello(name):
print("Hello " + name)

Parameters
----------
preconfig_decorator_list: list
A list of click option decorator which need to place before this function. For
example, if we want to add option "--config-file" and "--config-env" to allow customized configuration file
and configuration environment, we will use configuration_option as below:
@configuration_option(
preconfig_decorator_list=[decorator_customize_config_file, decorator_customize_config_env],
provider=TomlProvider(section=CONFIG_SECTION),
provider=ConfigProvider(section=CONFIG_SECTION),
)
By default, we enable these two options.
:param provider: A callable that parses the configuration file and returns a dictionary
provider: Callable
A callable that parses the configuration file and returns a dictionary
of the configuration parameters. Will be called as
`provider(file_path, config_env, cmd_name)
`provider(file_path, config_env, cmd_name)`
"""

def decorator_configuration_setup(f):
Expand Down Expand Up @@ -240,14 +297,22 @@ def decorator(f):
return composed_decorator(decorator_list)


def decorator_customize_config_file(f):
def decorator_customize_config_file(f: Callable) -> Callable:
"""
CLI option to customize configuration file name. By default it is 'samconfig.toml' in project directory.
Ex: --config-file samconfig.toml
:param f: Callback function passed by Click
:return: Callback function

Parameters
----------
f: Callable
Callback function passed by Click

Returns
-------
Callable
A Callback function
"""
config_file_attrs = {}
config_file_attrs: Dict[str, Any] = {}
config_file_param_decls = ("--config-file",)
config_file_attrs["help"] = "Configuration file containing default parameter values."
config_file_attrs["default"] = "samconfig.toml"
Expand All @@ -258,14 +323,22 @@ def decorator_customize_config_file(f):
return click.option(*config_file_param_decls, **config_file_attrs)(f)


def decorator_customize_config_env(f):
def decorator_customize_config_env(f: Callable) -> Callable:
"""
CLI option to customize configuration environment name. By default it is 'default'.
Ex: --config-env default
:param f: Callback function passed by Click
:return: Callback function

Parameters
----------
f: Callable
Callback function passed by Click

Returns
-------
Callable
A Callback function
"""
config_env_attrs = {}
config_env_attrs: Dict[str, Any] = {}
config_env_param_decls = ("--config-env",)
config_env_attrs["help"] = "Environment name specifying default parameter values in the configuration file."
config_env_attrs["default"] = "default"
Expand Down
2 changes: 1 addition & 1 deletion samcli/commands/_utils/custom_options/hook_name_option.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def _get_customer_input_beta_features_option(default_map, experimental_entry, op
if beta_features is not None:
return beta_features

# Get the beta-features flag value from the SamConfig toml file if provided.
# Get the beta-features flag value from the SamConfig file if provided.
beta_features = default_map.get("beta_features")
if beta_features is not None:
return beta_features
Expand Down
4 changes: 2 additions & 2 deletions samcli/commands/build/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from samcli.cli.main import pass_context, common_options as cli_framework_options, aws_creds_options, print_cmdline_args
from samcli.commands.build.core.command import BuildCommand
from samcli.lib.telemetry.metric import track_command
from samcli.cli.cli_config_file import configuration_option, TomlProvider
from samcli.cli.cli_config_file import configuration_option, ConfigProvider
from samcli.lib.utils.version_checker import check_newer_version
from samcli.commands.build.click_container import ContainerOptions
from samcli.commands.build.utils import MountMode
Expand Down Expand Up @@ -68,7 +68,7 @@
short_help=HELP_TEXT,
context_settings={"max_content_width": 120},
)
@configuration_option(provider=TomlProvider(section="parameters"))
@configuration_option(provider=ConfigProvider(section="parameters"))
@hook_name_click_option(
force_prepare=True,
invalid_coexist_options=["t", "template-file", "template", "parameter-overrides"],
Expand Down
6 changes: 3 additions & 3 deletions samcli/commands/delete/delete_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import click
from click import confirm, prompt

from samcli.cli.cli_config_file import TomlProvider
from samcli.cli.cli_config_file import ConfigProvider
from samcli.cli.context import Context
from samcli.commands.delete.exceptions import CfDeleteFailedStatusError
from samcli.lib.bootstrap.companion_stack.companion_stack_builder import CompanionStack
Expand Down Expand Up @@ -82,8 +82,8 @@ def parse_config_file(self):
"""
Read the provided config file if it exists and assign the options values.
"""
toml_provider = TomlProvider(CONFIG_SECTION, [CONFIG_COMMAND])
config_options = toml_provider(
config_provider = ConfigProvider(CONFIG_SECTION, [CONFIG_COMMAND])
config_options = config_provider(
config_path=self.config_file, config_env=self.config_env, cmd_names=[CONFIG_COMMAND]
)
if not config_options:
Expand Down
4 changes: 2 additions & 2 deletions samcli/commands/deploy/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import click

from samcli.cli.cli_config_file import TomlProvider, configuration_option
from samcli.cli.cli_config_file import ConfigProvider, configuration_option
from samcli.cli.main import aws_creds_options, common_options, pass_context, print_cmdline_args
from samcli.commands._utils.cdk_support_decorators import unsupported_command_cdk
from samcli.commands._utils.click_mutex import ClickMutex
Expand Down Expand Up @@ -75,7 +75,7 @@
description=DESCRIPTION,
requires_credentials=True,
)
@configuration_option(provider=TomlProvider(section=CONFIG_SECTION))
@configuration_option(provider=ConfigProvider(section=CONFIG_SECTION))
@click.option(
"--guided",
"-g",
Expand Down
4 changes: 2 additions & 2 deletions samcli/commands/init/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import click

from samcli.cli.cli_config_file import TomlProvider, configuration_option
from samcli.cli.cli_config_file import ConfigProvider, configuration_option
from samcli.cli.main import common_options, pass_context, print_cmdline_args
from samcli.commands._utils.click_mutex import ClickMutex
from samcli.commands.init.core.command import InitCommand
Expand Down Expand Up @@ -112,7 +112,7 @@ def wrapped(*args, **kwargs):
description=DESCRIPTION,
requires_credentials=False,
)
@configuration_option(provider=TomlProvider(section="parameters"))
@configuration_option(provider=ConfigProvider(section="parameters"))
@click.option(
"--no-interactive",
is_flag=True,
Expand Down
4 changes: 2 additions & 2 deletions samcli/commands/list/endpoints/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import click

from samcli.cli.cli_config_file import TomlProvider, configuration_option
from samcli.cli.cli_config_file import ConfigProvider, configuration_option
from samcli.cli.main import aws_creds_options, common_options, pass_context, print_cmdline_args
from samcli.commands._utils.command_exception_handler import command_exception_handler
from samcli.commands._utils.options import parameter_override_option, template_option_without_build
Expand All @@ -21,7 +21,7 @@


@click.command(name="endpoints", help=HELP_TEXT)
@configuration_option(provider=TomlProvider(section="parameters"))
@configuration_option(provider=ConfigProvider(section="parameters"))
@parameter_override_option
@stack_name_option
@output_option
Expand Down
Loading