Source code for aws_lbd_art_builder_uv.layer.local_builder
# -*- coding: utf-8 -*-"""UV-based local Lambda layer builder.:class:`UvLambdaLayerLocalBuilder` runs ``uv sync`` directly on the hostmachine to install dependencies into a Lambda-compatible layer structure.See ``docs/source/99-Maintainer-Guide/03-Build-Lambda-Layer-using-UV-in-Container``for the containerized variant's architecture guide."""importsubprocessimportdataclassesfrompathlibimportPathfromfunctoolsimportcached_propertyfromfunc_args.apiimportREQimportaws_lbd_art_builder_core.apiasaws_lbd_art_builder_corefrom..pathsimportpath_enum
[docs]@dataclasses.dataclass(frozen=True)classUvLambdaLayerLocalBuilder(aws_lbd_art_builder_core.layer_api.BaseLogger):""" Build a Lambda layer using uv on the local machine. Runs ``uv sync --frozen --no-dev --no-install-project --link-mode=copy`` on the host, then moves ``site-packages/`` into ``artifacts/python/``. The local builder does not require ``py_ver_major`` / ``py_ver_minor`` because it always uses the host's current Python — there is no way to target a different Python version without a container. The container builder requires them to select the correct AWS SAM base image. .. note:: Local builds produce host-native binaries. For packages with C extensions, use :class:`UvLambdaLayerContainerBuilder` instead. """# fmt: offpath_pyproject_toml:Path=dataclasses.field(default=REQ)credentials:aws_lbd_art_builder_core.layer_api.Credentials|None=dataclasses.field(default=None)skip_prompt:bool=dataclasses.field(default=False)# path_bin_uv defaults to None, which means "use whatever 'uv' is on# PATH". This covers the common case where uv is globally installed.# An explicit path is only needed when uv lives in a non-standard# location (e.g. a CI environment with a custom tool cache).path_bin_uv:Path|None=dataclasses.field(default=None)# fmt: on@cached_propertydefpath_layout(self)->aws_lbd_art_builder_core.layer_api.LayerPathLayout:returnaws_lbd_art_builder_core.layer_api.LayerPathLayout(path_pyproject_toml=self.path_pyproject_toml,)defrun(self):self.log_header("Start local Lambda layer build workflow")self.step_1_preflight_check()self.step_2_prepare_environment()self.step_3_execute_build()self.step_4_finalize_artifacts()# --- Step 1 ---------------------------------------------------------------defstep_1_preflight_check(self):self.log_header("Step 1 - Preflight Check")self.step_1_1_print_info()defstep_1_1_print_info(self):# fmt: offself.log_sub_header("Step 1.1 - Print Build Info")self.log_detail(f"path_pyproject_toml = {self.path_pyproject_toml}")self.log_detail(f"dir_repo = {self.path_layout.dir_repo}")self.log_detail(f"dir_build_layer = {self.path_layout.dir_build_lambda_layer}")self.log_detail(f"path_bin_uv = {self.path_bin_uv}")# fmt: on# --- Step 2 ---------------------------------------------------------------defstep_2_prepare_environment(self):self.log_header("Step 2 - Prepare Environment")self.step_2_1_setup_build_dir()self.step_2_2_prepare_uv_stuff()
[docs]defstep_2_1_setup_build_dir(self):""" Delete ``build/lambda/layer/`` and recreate the directory structure. """self.log_sub_header("Step 2.1 - Setup Build Directory")dir=self.path_layout.dir_build_lambda_layerself.log_detail(f"Clean existing build directory: {dir}")self.path_layout.clean(skip_prompt=self.skip_prompt)self.path_layout.mkdirs()
[docs]defstep_2_2_prepare_uv_stuff(self):""" Copy ``pyproject.toml`` and ``uv.lock`` to ``build/lambda/layer/repo/``. """self.log_sub_header("Step 2.2 - Prepare UV stuff")self.path_layout.copy_pyproject_toml(printer=self.log_detail)self.path_layout.copy_file(p_src=self.path_layout.dir_project_root/"uv.lock",p_dst=self.path_layout.dir_repo/"uv.lock",printer=self.log_detail,)
[docs]defstep_3_execute_build(self):""" Credentials are set up here in Step 3 (right before ``uv sync``) rather than in Step 2, because ``uv_login()`` sets process-level environment variables. Doing it in Step 2 would pollute the env during directory setup, and if Step 2 failed, the env vars would be left dangling. Keeping credential setup adjacent to the command that needs them minimizes the window of exposure. (In the container builder, credentials are written to a JSON file in Step 2 because the container is a separate process — writing a file is a prepare action, not an execute action.) """self.log_header("Step 3 - Execute Build")self.step_3_1_uv_login()self.step_3_2_run_uv_sync()
[docs]defstep_3_1_uv_login(self):""" Set ``UV_INDEX_{NAME}_USERNAME/PASSWORD`` env vars for private repos. """self.log_sub_header("Step 3.1 - Setting up UV credentials")ifself.credentialsisnotNone:key_user,key_pass=self.credentials.uv_login()self.log_detail(f"Set environment variable {key_user}")self.log_detail(f"Set environment variable {key_pass}")else:self.log_detail("No UV credentials provided, skipping UV login step")