Exemplo n.º 1
0
    def __enter__(self) -> "BuildContext":

        self._stacks = SamLocalStackProvider.get_stacks(
            self._template_file, parameter_overrides=self._parameter_overrides
        )
        self._template_dict = SamLocalStackProvider.find_root_stack(self.stacks).template_dict

        self._function_provider = SamFunctionProvider(self.stacks)
        self._layer_provider = SamLayerProvider(self.stacks)

        if not self._base_dir:
            # Base directory, if not provided, is the directory containing the template
            self._base_dir = str(pathlib.Path(self._template_file).resolve().parent)

        self._build_dir = self._setup_build_dir(self._build_dir, self._clean)

        if self._cached:
            cache_path = pathlib.Path(self._cache_dir)
            cache_path.mkdir(mode=self._BUILD_DIR_PERMISSIONS, parents=True, exist_ok=True)
            self._cache_dir = str(cache_path.resolve())

        if self._use_container:
            self._container_manager = ContainerManager(
                docker_network_id=self._docker_network, skip_pull_image=self._skip_pull_image
            )

        return self
Exemplo n.º 2
0
    def __enter__(self):
        """
        Performs some basic checks and returns itself when everything is ready to invoke a Lambda function.

        :returns InvokeContext: Returns this object
        """

        stacks = self._get_stacks()
        self._template_dict = SamLocalStackProvider.find_root_stack(
            stacks).template_dict
        self._function_provider = SamFunctionProvider(stacks)

        self._env_vars_value = self._get_env_vars_value(self._env_vars_file)
        self._container_env_vars_value = self._get_env_vars_value(
            self._container_env_vars_file)
        self._log_file_handle = self._setup_log_file(self._log_file)

        # in case of warm containers && debugging is enabled && if debug-function property is not provided, so
        # if the provided template only contains one lambda function, so debug-function will be set to this function
        # if the template contains multiple functions, a warning message "that the debugging option will be ignored"
        # will be printed
        if self._containers_mode == ContainersMode.WARM and self._debug_ports and not self._debug_function:
            if len(self._function_provider.functions) == 1:
                self._debug_function = list(
                    self._function_provider.functions.keys())[0]
            else:
                LOG.info(
                    "Warning: you supplied debugging options but you did not specify the --debug-function option."
                    " To specify which function you want to debug, please use the --debug-function <function-name>"
                )
                # skipp the debugging
                self._debug_ports = None

        self._debug_context = self._get_debug_context(
            self._debug_ports,
            self._debug_args,
            self._debugger_path,
            self._container_env_vars_value,
            self._debug_function,
        )

        self._container_manager = self._get_container_manager(
            self._docker_network, self._skip_pull_image, self._shutdown)

        if not self._container_manager.is_docker_reachable:
            raise InvokeContextException(
                "Running AWS SAM projects locally requires Docker. Have you got it installed and running?"
            )

        # initialize all lambda function containers upfront
        if self._containers_initializing_mode == ContainersInitializationMode.EAGER:
            self._initialize_all_functions_containers()

        return self
Exemplo n.º 3
0
def do_cli(  # pylint: disable=too-many-locals, too-many-statements
    function_identifier: Optional[str],
    template: str,
    base_dir: Optional[str],
    build_dir: str,
    cache_dir: str,
    clean: bool,
    use_container: bool,
    cached: bool,
    parallel: bool,
    manifest_path: Optional[str],
    docker_network: Optional[str],
    skip_pull_image: bool,
    parameter_overrides: Dict,
    mode: Optional[str],
    container_env_var: Optional[Tuple[str]],
    container_env_var_file: Optional[str],
    build_image: Optional[Tuple[str]],
) -> None:
    """
    Implementation of the ``cli`` method
    """

    from samcli.commands.exceptions import UserException

    from samcli.commands.build.build_context import BuildContext
    from samcli.lib.build.app_builder import (
        ApplicationBuilder,
        BuildError,
        UnsupportedBuilderLibraryVersionError,
        ContainerBuildNotSupported,
    )
    from samcli.lib.build.workflow_config import UnsupportedRuntimeException
    from samcli.local.lambdafn.exceptions import FunctionNotFound
    from samcli.commands._utils.template import move_template
    from samcli.lib.build.build_graph import InvalidBuildGraphException

    LOG.debug("'build' command is called")
    if cached:
        LOG.info("Starting Build use cache")
    if use_container:
        LOG.info("Starting Build inside a container")

    processed_env_vars = _process_env_var(container_env_var)
    processed_build_images = _process_image_options(build_image)

    with BuildContext(
            function_identifier,
            template,
            base_dir,
            build_dir,
            cache_dir,
            cached,
            clean=clean,
            manifest_path=manifest_path,
            use_container=use_container,
            parameter_overrides=parameter_overrides,
            docker_network=docker_network,
            skip_pull_image=skip_pull_image,
            mode=mode,
            container_env_var=processed_env_vars,
            container_env_var_file=container_env_var_file,
            build_images=processed_build_images,
    ) as ctx:
        try:
            builder = ApplicationBuilder(
                ctx.resources_to_build,
                ctx.build_dir,
                ctx.base_dir,
                ctx.cache_dir,
                ctx.cached,
                ctx.is_building_specific_resource,
                manifest_path_override=ctx.manifest_path_override,
                container_manager=ctx.container_manager,
                mode=ctx.mode,
                parallel=parallel,
                container_env_var=processed_env_vars,
                container_env_var_file=container_env_var_file,
                build_images=processed_build_images,
            )
        except FunctionNotFound as ex:
            raise UserException(str(ex),
                                wrapped_from=ex.__class__.__name__) from ex

        try:
            artifacts = builder.build()

            stack_output_template_path_by_stack_path = {
                stack.stack_path: stack.get_output_template_path(ctx.build_dir)
                for stack in ctx.stacks
            }
            for stack in ctx.stacks:
                modified_template = builder.update_template(
                    stack,
                    artifacts,
                    stack_output_template_path_by_stack_path,
                )
                move_template(stack.location,
                              stack.get_output_template_path(ctx.build_dir),
                              modified_template)

            click.secho("\nBuild Succeeded", fg="green")

            # try to use relpath so the command is easier to understand, however,
            # under Windows, when SAM and (build_dir or output_template_path) are
            # on different drive, relpath() fails.
            root_stack = SamLocalStackProvider.find_root_stack(ctx.stacks)
            out_template_path = root_stack.get_output_template_path(
                ctx.build_dir)
            try:
                build_dir_in_success_message = os.path.relpath(ctx.build_dir)
                output_template_path_in_success_message = os.path.relpath(
                    out_template_path)
            except ValueError:
                LOG.debug(
                    "Failed to retrieve relpath - using the specified path as-is instead"
                )
                build_dir_in_success_message = ctx.build_dir
                output_template_path_in_success_message = out_template_path

            msg = gen_success_msg(
                build_dir_in_success_message,
                output_template_path_in_success_message,
                os.path.abspath(
                    ctx.build_dir) == os.path.abspath(DEFAULT_BUILD_DIR),
            )

            click.secho(msg, fg="yellow")

        except (
                UnsupportedRuntimeException,
                BuildError,
                BuildInsideContainerError,
                UnsupportedBuilderLibraryVersionError,
                ContainerBuildNotSupported,
                InvalidBuildGraphException,
        ) as ex:
            click.secho("\nBuild Failed", fg="red")

            # Some Exceptions have a deeper wrapped exception that needs to be surfaced
            # from deeper than just one level down.
            deep_wrap = getattr(ex, "wrapped_from", None)
            wrapped_from = deep_wrap if deep_wrap else ex.__class__.__name__
            raise UserException(str(ex), wrapped_from=wrapped_from) from ex