aws_lbd_art_builder_uv 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aws_lbd_art_builder_uv-0.1.1/AUTHORS.rst +15 -0
- aws_lbd_art_builder_uv-0.1.1/LICENSE.txt +21 -0
- aws_lbd_art_builder_uv-0.1.1/PKG-INFO +142 -0
- aws_lbd_art_builder_uv-0.1.1/README.rst +85 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv/__init__.py +1 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv/api.py +3 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv/layer/__init__.py +2 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv/layer/_build_in_container.py +183 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv/layer/api.py +19 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv/layer/container_builder.py +177 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv/layer/local_builder.py +173 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv/layer/validate.py +193 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv/paths.py +63 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv/vendor/__init__.py +2 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv/vendor/pytest_cov_helper.py +148 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv.egg-info/PKG-INFO +142 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv.egg-info/SOURCES.txt +21 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv.egg-info/dependency_links.txt +1 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv.egg-info/requires.txt +35 -0
- aws_lbd_art_builder_uv-0.1.1/aws_lbd_art_builder_uv.egg-info/top_level.txt +1 -0
- aws_lbd_art_builder_uv-0.1.1/pyproject.toml +139 -0
- aws_lbd_art_builder_uv-0.1.1/setup.cfg +4 -0
- aws_lbd_art_builder_uv-0.1.1/tests/test_api.py +18 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
.. _about_author:
|
|
2
|
+
|
|
3
|
+
About the Author
|
|
4
|
+
------------------------------------------------------------------------------
|
|
5
|
+
::
|
|
6
|
+
|
|
7
|
+
(\ (\
|
|
8
|
+
( -.-)o
|
|
9
|
+
o_(")(")
|
|
10
|
+
|
|
11
|
+
**Sanhe Hu** is a seasoned software engineer with a deep passion for Python development since 2010. As an author and maintainer of `150+ open-source Python projects <https://pypi.org/user/machugwu/>`_, with over `15 million monthly downloads <https://github.com/MacHu-GWU>`_, I bring a wealth of experience to the table. As a Senior Solution Architect and Subject Matter Expert in AI, Data, Amazon Web Services, Cloud Engineering, DevOps, I thrive on helping clients with platform design, enterprise architecture, and strategic roadmaps.
|
|
12
|
+
|
|
13
|
+
Talk is cheap, show me the code:
|
|
14
|
+
|
|
15
|
+
- My Github: https://github.com/MacHu-GWU
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sanhe Hu <husanhe@email.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aws_lbd_art_builder_uv
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: AWS Lambda Artifact UV Builder
|
|
5
|
+
Author-email: Sanhe Hu <husanhe@email.com>
|
|
6
|
+
Maintainer-email: Sanhe Hu <husanhe@email.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project
|
|
9
|
+
Project-URL: Documentation, https://aws-lbd-art-builder-uv.readthedocs.io/en/latest/
|
|
10
|
+
Project-URL: Repository, https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project
|
|
11
|
+
Project-URL: Issues, https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project/issues
|
|
12
|
+
Project-URL: Changelog, https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project/blob/main/release-history.rst
|
|
13
|
+
Project-URL: Download, https://pypi.org/pypi/aws-lbd-art-builder-uv#files
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Natural Language :: English
|
|
17
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
18
|
+
Classifier: Operating System :: MacOS
|
|
19
|
+
Classifier: Operating System :: Unix
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Requires-Python: <4.0,>=3.11
|
|
26
|
+
Description-Content-Type: text/x-rst
|
|
27
|
+
License-File: LICENSE.txt
|
|
28
|
+
License-File: AUTHORS.rst
|
|
29
|
+
Requires-Dist: aws-lbd-art-builder-core<1.0.0,>=0.1.4
|
|
30
|
+
Provides-Extra: upload
|
|
31
|
+
Requires-Dist: aws-lbd-art-builder-core[upload]; extra == "upload"
|
|
32
|
+
Provides-Extra: publish
|
|
33
|
+
Requires-Dist: aws-lbd-art-builder-core[publish]; extra == "publish"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: rich<14.0.0,>=13.8.1; extra == "dev"
|
|
36
|
+
Provides-Extra: test
|
|
37
|
+
Requires-Dist: pytest<9.0.0,>=8.2.2; extra == "test"
|
|
38
|
+
Requires-Dist: pytest-cov<7.0.0,>=6.0.0; extra == "test"
|
|
39
|
+
Requires-Dist: moto<6.0.0,>=5.1.10; extra == "test"
|
|
40
|
+
Requires-Dist: aws-lbd-art-builder-core[publish,upload]; extra == "test"
|
|
41
|
+
Provides-Extra: doc
|
|
42
|
+
Requires-Dist: Sphinx<8.0.0,>=7.4.7; extra == "doc"
|
|
43
|
+
Requires-Dist: sphinx-copybutton<1.0.0,>=0.5.2; extra == "doc"
|
|
44
|
+
Requires-Dist: sphinx-design<1.0.0,>=0.6.1; extra == "doc"
|
|
45
|
+
Requires-Dist: sphinx-jinja<3.0.0,>=2.0.2; extra == "doc"
|
|
46
|
+
Requires-Dist: furo==2024.8.6; extra == "doc"
|
|
47
|
+
Requires-Dist: pygments<3.0.0,>=2.18.0; extra == "doc"
|
|
48
|
+
Requires-Dist: ipython<8.19.0,>=8.18.1; extra == "doc"
|
|
49
|
+
Requires-Dist: nbsphinx<1.0.0,>=0.8.12; extra == "doc"
|
|
50
|
+
Requires-Dist: rstobj==2.0.0; extra == "doc"
|
|
51
|
+
Requires-Dist: docfly==3.0.3; extra == "doc"
|
|
52
|
+
Provides-Extra: mise
|
|
53
|
+
Requires-Dist: PyGithub<3.0.0,>=2.8.0; extra == "mise"
|
|
54
|
+
Requires-Dist: httpx<1.0.0,>=0.28.0; extra == "mise"
|
|
55
|
+
Requires-Dist: tomli<3.0.0,>=2.0.0; python_version < "3.11" and extra == "mise"
|
|
56
|
+
Dynamic: license-file
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
.. image:: https://readthedocs.org/projects/aws-lbd-art-builder-uv/badge/?version=latest
|
|
60
|
+
:target: https://aws-lbd-art-builder-uv.readthedocs.io/en/latest/
|
|
61
|
+
:alt: Documentation Status
|
|
62
|
+
|
|
63
|
+
.. image:: https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project/actions/workflows/main.yml/badge.svg
|
|
64
|
+
:target: https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project/actions?query=workflow:CI
|
|
65
|
+
|
|
66
|
+
.. image:: https://codecov.io/gh/MacHu-GWU/aws_lbd_art_builder_uv-project/branch/main/graph/badge.svg
|
|
67
|
+
:target: https://codecov.io/gh/MacHu-GWU/aws_lbd_art_builder_uv-project
|
|
68
|
+
|
|
69
|
+
.. image:: https://img.shields.io/pypi/v/aws-lbd-art-builder-uv.svg
|
|
70
|
+
:target: https://pypi.python.org/pypi/aws-lbd-art-builder-uv
|
|
71
|
+
|
|
72
|
+
.. image:: https://img.shields.io/pypi/l/aws-lbd-art-builder-uv.svg
|
|
73
|
+
:target: https://pypi.python.org/pypi/aws-lbd-art-builder-uv
|
|
74
|
+
|
|
75
|
+
.. image:: https://img.shields.io/pypi/pyversions/aws-lbd-art-builder-uv.svg
|
|
76
|
+
:target: https://pypi.python.org/pypi/aws-lbd-art-builder-uv
|
|
77
|
+
|
|
78
|
+
.. image:: https://img.shields.io/badge/✍️_Release_History!--None.svg?style=social&logo=github
|
|
79
|
+
:target: https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project/blob/main/release-history.rst
|
|
80
|
+
|
|
81
|
+
.. image:: https://img.shields.io/badge/⭐_Star_me_on_GitHub!--None.svg?style=social&logo=github
|
|
82
|
+
:target: https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project
|
|
83
|
+
|
|
84
|
+
------
|
|
85
|
+
|
|
86
|
+
.. image:: https://img.shields.io/badge/Link-API-blue.svg
|
|
87
|
+
:target: https://aws-lbd-art-builder-uv.readthedocs.io/en/latest/py-modindex.html
|
|
88
|
+
|
|
89
|
+
.. image:: https://img.shields.io/badge/Link-Install-blue.svg
|
|
90
|
+
:target: `install`_
|
|
91
|
+
|
|
92
|
+
.. image:: https://img.shields.io/badge/Link-GitHub-blue.svg
|
|
93
|
+
:target: https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project
|
|
94
|
+
|
|
95
|
+
.. image:: https://img.shields.io/badge/Link-Submit_Issue-blue.svg
|
|
96
|
+
:target: https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project/issues
|
|
97
|
+
|
|
98
|
+
.. image:: https://img.shields.io/badge/Link-Request_Feature-blue.svg
|
|
99
|
+
:target: https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project/issues
|
|
100
|
+
|
|
101
|
+
.. image:: https://img.shields.io/badge/Link-Download-blue.svg
|
|
102
|
+
:target: https://pypi.org/pypi/aws-lbd-art-builder-uv#files
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
Welcome to ``aws_lbd_art_builder_uv`` Documentation
|
|
106
|
+
==============================================================================
|
|
107
|
+
.. image:: https://aws-lbd-art-builder-uv.readthedocs.io/en/latest/_static/aws_lbd_art_builder_uv-logo.png
|
|
108
|
+
:target: https://aws-lbd-art-builder-uv.readthedocs.io/en/latest/
|
|
109
|
+
|
|
110
|
+
``aws_lbd_art_builder_uv`` is the **uv** backend for `aws_lbd_art_builder_core <https://github.com/MacHu-GWU/aws_lbd_art_builder_core-project>`_, providing automated AWS Lambda layer builds using `uv <https://docs.astral.sh/uv/>`_ as the package manager.
|
|
111
|
+
|
|
112
|
+
It offers two builders:
|
|
113
|
+
|
|
114
|
+
- **UvLambdaLayerLocalBuilder** — runs ``uv sync`` directly on the host machine. Fast, no Docker required. Best for pure-Python dependencies.
|
|
115
|
+
- **UvLambdaLayerContainerBuilder** — runs ``uv sync`` inside an `AWS SAM Docker image <https://gallery.ecr.aws/sam>`_ to produce Linux-compatible binaries. Required when your layer includes packages with C extensions (e.g. ``numpy``, ``pandas``).
|
|
116
|
+
|
|
117
|
+
Both builders follow a 4-step workflow: **Preflight Check → Prepare Environment → Execute Build → Finalize Artifacts**. The output is a ``artifacts/python/`` directory ready to be zipped and published as a Lambda layer. Combine with ``aws_lbd_art_builder_core``'s package, upload, and publish steps for a complete deployment pipeline.
|
|
118
|
+
|
|
119
|
+
Features:
|
|
120
|
+
|
|
121
|
+
- Reproducible builds via ``uv sync --frozen`` with lock files
|
|
122
|
+
- Private PyPI index support (e.g. AWS CodeArtifact) via credential injection
|
|
123
|
+
- Artifact validation — verify installed packages match ``pyproject.toml`` dependencies
|
|
124
|
+
- Pure-stdlib container script — no pip install needed inside the container
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
.. _install:
|
|
128
|
+
|
|
129
|
+
Install
|
|
130
|
+
------------------------------------------------------------------------------
|
|
131
|
+
|
|
132
|
+
``aws_lbd_art_builder_uv`` is released on PyPI, so all you need is to:
|
|
133
|
+
|
|
134
|
+
.. code-block:: console
|
|
135
|
+
|
|
136
|
+
$ pip install aws-lbd-art-builder-uv
|
|
137
|
+
|
|
138
|
+
To upgrade to latest version:
|
|
139
|
+
|
|
140
|
+
.. code-block:: console
|
|
141
|
+
|
|
142
|
+
$ pip install --upgrade aws-lbd-art-builder-uv
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
|
|
2
|
+
.. image:: https://readthedocs.org/projects/aws-lbd-art-builder-uv/badge/?version=latest
|
|
3
|
+
:target: https://aws-lbd-art-builder-uv.readthedocs.io/en/latest/
|
|
4
|
+
:alt: Documentation Status
|
|
5
|
+
|
|
6
|
+
.. image:: https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project/actions/workflows/main.yml/badge.svg
|
|
7
|
+
:target: https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project/actions?query=workflow:CI
|
|
8
|
+
|
|
9
|
+
.. image:: https://codecov.io/gh/MacHu-GWU/aws_lbd_art_builder_uv-project/branch/main/graph/badge.svg
|
|
10
|
+
:target: https://codecov.io/gh/MacHu-GWU/aws_lbd_art_builder_uv-project
|
|
11
|
+
|
|
12
|
+
.. image:: https://img.shields.io/pypi/v/aws-lbd-art-builder-uv.svg
|
|
13
|
+
:target: https://pypi.python.org/pypi/aws-lbd-art-builder-uv
|
|
14
|
+
|
|
15
|
+
.. image:: https://img.shields.io/pypi/l/aws-lbd-art-builder-uv.svg
|
|
16
|
+
:target: https://pypi.python.org/pypi/aws-lbd-art-builder-uv
|
|
17
|
+
|
|
18
|
+
.. image:: https://img.shields.io/pypi/pyversions/aws-lbd-art-builder-uv.svg
|
|
19
|
+
:target: https://pypi.python.org/pypi/aws-lbd-art-builder-uv
|
|
20
|
+
|
|
21
|
+
.. image:: https://img.shields.io/badge/✍️_Release_History!--None.svg?style=social&logo=github
|
|
22
|
+
:target: https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project/blob/main/release-history.rst
|
|
23
|
+
|
|
24
|
+
.. image:: https://img.shields.io/badge/⭐_Star_me_on_GitHub!--None.svg?style=social&logo=github
|
|
25
|
+
:target: https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project
|
|
26
|
+
|
|
27
|
+
------
|
|
28
|
+
|
|
29
|
+
.. image:: https://img.shields.io/badge/Link-API-blue.svg
|
|
30
|
+
:target: https://aws-lbd-art-builder-uv.readthedocs.io/en/latest/py-modindex.html
|
|
31
|
+
|
|
32
|
+
.. image:: https://img.shields.io/badge/Link-Install-blue.svg
|
|
33
|
+
:target: `install`_
|
|
34
|
+
|
|
35
|
+
.. image:: https://img.shields.io/badge/Link-GitHub-blue.svg
|
|
36
|
+
:target: https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project
|
|
37
|
+
|
|
38
|
+
.. image:: https://img.shields.io/badge/Link-Submit_Issue-blue.svg
|
|
39
|
+
:target: https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project/issues
|
|
40
|
+
|
|
41
|
+
.. image:: https://img.shields.io/badge/Link-Request_Feature-blue.svg
|
|
42
|
+
:target: https://github.com/MacHu-GWU/aws_lbd_art_builder_uv-project/issues
|
|
43
|
+
|
|
44
|
+
.. image:: https://img.shields.io/badge/Link-Download-blue.svg
|
|
45
|
+
:target: https://pypi.org/pypi/aws-lbd-art-builder-uv#files
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
Welcome to ``aws_lbd_art_builder_uv`` Documentation
|
|
49
|
+
==============================================================================
|
|
50
|
+
.. image:: https://aws-lbd-art-builder-uv.readthedocs.io/en/latest/_static/aws_lbd_art_builder_uv-logo.png
|
|
51
|
+
:target: https://aws-lbd-art-builder-uv.readthedocs.io/en/latest/
|
|
52
|
+
|
|
53
|
+
``aws_lbd_art_builder_uv`` is the **uv** backend for `aws_lbd_art_builder_core <https://github.com/MacHu-GWU/aws_lbd_art_builder_core-project>`_, providing automated AWS Lambda layer builds using `uv <https://docs.astral.sh/uv/>`_ as the package manager.
|
|
54
|
+
|
|
55
|
+
It offers two builders:
|
|
56
|
+
|
|
57
|
+
- **UvLambdaLayerLocalBuilder** — runs ``uv sync`` directly on the host machine. Fast, no Docker required. Best for pure-Python dependencies.
|
|
58
|
+
- **UvLambdaLayerContainerBuilder** — runs ``uv sync`` inside an `AWS SAM Docker image <https://gallery.ecr.aws/sam>`_ to produce Linux-compatible binaries. Required when your layer includes packages with C extensions (e.g. ``numpy``, ``pandas``).
|
|
59
|
+
|
|
60
|
+
Both builders follow a 4-step workflow: **Preflight Check → Prepare Environment → Execute Build → Finalize Artifacts**. The output is a ``artifacts/python/`` directory ready to be zipped and published as a Lambda layer. Combine with ``aws_lbd_art_builder_core``'s package, upload, and publish steps for a complete deployment pipeline.
|
|
61
|
+
|
|
62
|
+
Features:
|
|
63
|
+
|
|
64
|
+
- Reproducible builds via ``uv sync --frozen`` with lock files
|
|
65
|
+
- Private PyPI index support (e.g. AWS CodeArtifact) via credential injection
|
|
66
|
+
- Artifact validation — verify installed packages match ``pyproject.toml`` dependencies
|
|
67
|
+
- Pure-stdlib container script — no pip install needed inside the container
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
.. _install:
|
|
71
|
+
|
|
72
|
+
Install
|
|
73
|
+
------------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
``aws_lbd_art_builder_uv`` is released on PyPI, so all you need is to:
|
|
76
|
+
|
|
77
|
+
.. code-block:: console
|
|
78
|
+
|
|
79
|
+
$ pip install aws-lbd-art-builder-uv
|
|
80
|
+
|
|
81
|
+
To upgrade to latest version:
|
|
82
|
+
|
|
83
|
+
.. code-block:: console
|
|
84
|
+
|
|
85
|
+
$ pip install --upgrade aws-lbd-art-builder-uv
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Container-side Lambda layer build script (pure stdlib, Python 3.11+).
|
|
5
|
+
|
|
6
|
+
This script runs **inside** the Docker container launched by
|
|
7
|
+
:class:`~aws_lbd_art_builder_uv.layer.container_builder.UvLambdaLayerContainerBuilder`.
|
|
8
|
+
No third-party packages are needed — only ``uv`` (installed at runtime).
|
|
9
|
+
|
|
10
|
+
**Why pure stdlib?** This script is copied into a bare AWS SAM Docker image
|
|
11
|
+
that has nothing pre-installed except Python itself. If we imported any
|
|
12
|
+
third-party library here, we would have to install it inside the container
|
|
13
|
+
first, adding complexity and build time. Keeping this script stdlib-only
|
|
14
|
+
means the only external tool we need to fetch is ``uv``.
|
|
15
|
+
|
|
16
|
+
The host mounts ``{project_root}/build/lambda/layer/`` → ``/var/task/``.
|
|
17
|
+
Layout inside the container::
|
|
18
|
+
|
|
19
|
+
/var/task/ ← mount point
|
|
20
|
+
├── build_lambda_layer_in_container.py ← this script (renamed copy)
|
|
21
|
+
├── private-repository-credentials.json ← optional credentials
|
|
22
|
+
└── repo/
|
|
23
|
+
├── pyproject.toml
|
|
24
|
+
├── uv.lock
|
|
25
|
+
└── .venv/ ← created by uv sync
|
|
26
|
+
|
|
27
|
+
The host-side step 4 moves ``repo/.venv/lib/pythonX.Y/site-packages/``
|
|
28
|
+
into ``artifacts/python/`` after the container exits.
|
|
29
|
+
|
|
30
|
+
See ``docs/source/99-Maintainer-Guide/03-Build-Lambda-Layer-using-UV-in-Container``
|
|
31
|
+
for the full architecture guide.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
import os
|
|
35
|
+
import sys
|
|
36
|
+
import json
|
|
37
|
+
import argparse
|
|
38
|
+
import subprocess
|
|
39
|
+
from pathlib import Path
|
|
40
|
+
from datetime import datetime
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# --- Logging helpers (match the host-side BaseLogger format) ------------------
|
|
44
|
+
def _log_sub_header(title: str): # pragma: no cover
|
|
45
|
+
print("")
|
|
46
|
+
print("+----- " + title)
|
|
47
|
+
print("|")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _log(msg: str): # pragma: no cover
|
|
51
|
+
print("| " + msg)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def parse_args(): # pragma: no cover
|
|
55
|
+
parser = argparse.ArgumentParser(
|
|
56
|
+
description="Build Lambda layer using uv inside a Docker container.",
|
|
57
|
+
)
|
|
58
|
+
parser.add_argument(
|
|
59
|
+
"--dir-task",
|
|
60
|
+
default="/var/task",
|
|
61
|
+
help="The mount point inside the container. Default: /var/task",
|
|
62
|
+
)
|
|
63
|
+
return parser.parse_args()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def main(): # pragma: no cover
|
|
67
|
+
args = parse_args()
|
|
68
|
+
dir_task = Path(args.dir_task)
|
|
69
|
+
|
|
70
|
+
# --- Derived paths ---------------------------------------------------------
|
|
71
|
+
dir_repo = dir_task / "repo"
|
|
72
|
+
path_credentials = dir_task / "private-repository-credentials.json"
|
|
73
|
+
|
|
74
|
+
# --------------------------------------------------------------------------
|
|
75
|
+
# Step 1 — Verify container execution environment
|
|
76
|
+
# --------------------------------------------------------------------------
|
|
77
|
+
_log_sub_header("Container Step 1 - Verify Environment")
|
|
78
|
+
_log(f"dir_task = {dir_task}")
|
|
79
|
+
_log(f"dir_repo = {dir_repo}")
|
|
80
|
+
if not dir_repo.exists():
|
|
81
|
+
raise EnvironmentError(
|
|
82
|
+
f"{dir_repo} does not exist. "
|
|
83
|
+
f"This script expects the host to mount build/lambda/layer/ to {dir_task}."
|
|
84
|
+
)
|
|
85
|
+
_log("Verification OK.")
|
|
86
|
+
|
|
87
|
+
# --------------------------------------------------------------------------
|
|
88
|
+
# Step 2 — Install uv
|
|
89
|
+
#
|
|
90
|
+
# Why install uv at runtime via curl instead of pre-baking it into the
|
|
91
|
+
# Docker image? Because we use the official AWS SAM base image directly
|
|
92
|
+
# (e.g. public.ecr.aws/sam/build-python3.12) to guarantee binary
|
|
93
|
+
# compatibility with the real Lambda runtime. Building a custom image
|
|
94
|
+
# that bundles uv would add a maintenance burden (rebuild on every SAM
|
|
95
|
+
# image update) and defeat the purpose of using the official image.
|
|
96
|
+
# The curl install takes only a few seconds and always gets the latest uv.
|
|
97
|
+
# --------------------------------------------------------------------------
|
|
98
|
+
_log_sub_header("Container Step 2 - Install uv")
|
|
99
|
+
st = datetime.now()
|
|
100
|
+
subprocess.run(
|
|
101
|
+
"curl -LsSf https://astral.sh/uv/install.sh | sh",
|
|
102
|
+
shell=True,
|
|
103
|
+
check=True,
|
|
104
|
+
)
|
|
105
|
+
elapsed = (datetime.now() - st).total_seconds()
|
|
106
|
+
_log(f"install uv elapsed: {elapsed:.2f} seconds")
|
|
107
|
+
|
|
108
|
+
path_bin_uv = Path("/root/.local/bin/uv")
|
|
109
|
+
|
|
110
|
+
# --------------------------------------------------------------------------
|
|
111
|
+
# Step 3 — Setup private repository credentials (optional)
|
|
112
|
+
#
|
|
113
|
+
# Credentials are set up inside the container (not passed via docker env
|
|
114
|
+
# vars) because sensitive tokens should not appear in ``docker run``
|
|
115
|
+
# command lines, which are visible in process listings. Instead, the
|
|
116
|
+
# host dumps a JSON file into the bind-mounted directory, and this
|
|
117
|
+
# script reads it.
|
|
118
|
+
# --------------------------------------------------------------------------
|
|
119
|
+
_log_sub_header("Container Step 3 - Setup Credentials")
|
|
120
|
+
if path_credentials.exists():
|
|
121
|
+
with open(path_credentials, "r") as f:
|
|
122
|
+
cred = json.load(f)
|
|
123
|
+
index_name = cred["index_name"]
|
|
124
|
+
username = cred["username"]
|
|
125
|
+
password = cred["password"]
|
|
126
|
+
# uv expects env vars in the form UV_INDEX_{NAME}_USERNAME where
|
|
127
|
+
# {NAME} is the index name uppercased with hyphens replaced by
|
|
128
|
+
# underscores. This is the uv convention for per-index auth.
|
|
129
|
+
# See: https://docs.astral.sh/uv/configuration/indexes/
|
|
130
|
+
upper_name = index_name.upper().replace("-", "_")
|
|
131
|
+
key_user = f"UV_INDEX_{upper_name}_USERNAME"
|
|
132
|
+
key_pass = f"UV_INDEX_{upper_name}_PASSWORD"
|
|
133
|
+
os.environ[key_user] = username
|
|
134
|
+
os.environ[key_pass] = password
|
|
135
|
+
_log(f"Loaded credentials for private repository: {index_name}")
|
|
136
|
+
_log(f"Set environment variable {key_user}")
|
|
137
|
+
_log(f"Set environment variable {key_pass}")
|
|
138
|
+
else:
|
|
139
|
+
_log("No private repository credentials found, using public PyPI only.")
|
|
140
|
+
|
|
141
|
+
# --------------------------------------------------------------------------
|
|
142
|
+
# Step 4 — Run uv sync
|
|
143
|
+
# --------------------------------------------------------------------------
|
|
144
|
+
_log_sub_header("Container Step 4 - Run 'uv sync'")
|
|
145
|
+
st = datetime.now()
|
|
146
|
+
# Flag rationale:
|
|
147
|
+
# --frozen : use the exact versions from uv.lock without
|
|
148
|
+
# re-resolving, ensuring reproducible builds.
|
|
149
|
+
# --no-dev : exclude dev dependencies (pytest, sphinx, etc.)
|
|
150
|
+
# that have no place in a Lambda layer.
|
|
151
|
+
# --no-install-project : skip installing the project package itself;
|
|
152
|
+
# the Lambda layer only needs the *dependencies*.
|
|
153
|
+
# The project code is deployed separately as the
|
|
154
|
+
# Lambda function handler.
|
|
155
|
+
# --link-mode=copy : copy files instead of symlinking. Lambda layers
|
|
156
|
+
# are zipped and uploaded — symlinks would break
|
|
157
|
+
# because the link targets don't exist in the
|
|
158
|
+
# Lambda execution environment.
|
|
159
|
+
subprocess.run(
|
|
160
|
+
[
|
|
161
|
+
str(path_bin_uv),
|
|
162
|
+
"sync",
|
|
163
|
+
"--frozen",
|
|
164
|
+
"--no-dev",
|
|
165
|
+
"--no-install-project",
|
|
166
|
+
"--link-mode=copy",
|
|
167
|
+
],
|
|
168
|
+
cwd=str(dir_repo),
|
|
169
|
+
check=True,
|
|
170
|
+
)
|
|
171
|
+
elapsed = (datetime.now() - st).total_seconds()
|
|
172
|
+
_log(f"uv sync elapsed: {elapsed:.2f} seconds")
|
|
173
|
+
|
|
174
|
+
major, minor = sys.version_info[:2]
|
|
175
|
+
dir_site_packages = (
|
|
176
|
+
dir_repo / ".venv" / "lib" / f"python{major}.{minor}" / "site-packages"
|
|
177
|
+
)
|
|
178
|
+
_log(f"Dependencies installed at: {dir_site_packages}")
|
|
179
|
+
_log("Container-side build completed successfully!")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
if __name__ == "__main__": # pragma: no cover
|
|
183
|
+
main()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
# From this package
|
|
4
|
+
# from .builder import UvLambdaLayerLocalBuilder
|
|
5
|
+
# from .builder import UvLambdaLayerContainerBuilder
|
|
6
|
+
from .local_builder import UvLambdaLayerLocalBuilder
|
|
7
|
+
from .container_builder import UvLambdaLayerContainerBuilder
|
|
8
|
+
from .validate import validate_artifacts
|
|
9
|
+
|
|
10
|
+
# Re-export from core for end-user convenience
|
|
11
|
+
from aws_lbd_art_builder_core.layer.api import Credentials
|
|
12
|
+
from aws_lbd_art_builder_core.layer.api import LayerPathLayout
|
|
13
|
+
from aws_lbd_art_builder_core.layer.api import LayerS3Layout
|
|
14
|
+
from aws_lbd_art_builder_core.layer.api import move_to_dir_python
|
|
15
|
+
from aws_lbd_art_builder_core.layer.api import default_ignore_package_list
|
|
16
|
+
from aws_lbd_art_builder_core.layer.api import create_layer_zip_file
|
|
17
|
+
from aws_lbd_art_builder_core.layer.api import upload_layer_zip_to_s3
|
|
18
|
+
from aws_lbd_art_builder_core.layer.api import LambdaLayerVersionPublisher
|
|
19
|
+
from aws_lbd_art_builder_core.layer.api import LayerDeployment
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
UV-based containerized Lambda layer builder.
|
|
5
|
+
|
|
6
|
+
:class:`UvLambdaLayerContainerBuilder` orchestrates a Docker-based build
|
|
7
|
+
that runs ``uv sync`` inside an official AWS SAM image.
|
|
8
|
+
|
|
9
|
+
See ``docs/source/99-Maintainer-Guide/03-Build-Lambda-Layer-using-UV-in-Container``
|
|
10
|
+
for the full architecture guide.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import subprocess
|
|
14
|
+
import dataclasses
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
import aws_lbd_art_builder_core.api as aws_lbd_art_builder_core
|
|
18
|
+
|
|
19
|
+
from ..paths import path_enum
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclasses.dataclass(frozen=True)
|
|
23
|
+
class UvLambdaLayerContainerBuilder(
|
|
24
|
+
aws_lbd_art_builder_core.layer_api.BaseLambdaLayerContainerBuilder,
|
|
25
|
+
): # pragma: no cover
|
|
26
|
+
"""
|
|
27
|
+
Build a Lambda layer using uv inside a Docker container.
|
|
28
|
+
|
|
29
|
+
**Mount scheme**: ``{project_root}/build/lambda/layer/`` → ``/var/task/``
|
|
30
|
+
|
|
31
|
+
The container script (``_build_in_container.py``) is pure stdlib — no
|
|
32
|
+
third-party packages are installed inside the container except ``uv``.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
# fmt: off
|
|
36
|
+
path_script: Path = dataclasses.field(default=path_enum.path_build_in_container_script)
|
|
37
|
+
# credentials is optional because most projects only need public PyPI.
|
|
38
|
+
# When private repositories are needed, the caller passes a Credentials
|
|
39
|
+
# object that gets serialized to JSON and read inside the container.
|
|
40
|
+
credentials: aws_lbd_art_builder_core.layer_api.Credentials | None = dataclasses.field(default=None)
|
|
41
|
+
skip_prompt: bool = dataclasses.field(default=False)
|
|
42
|
+
# fmt: on
|
|
43
|
+
|
|
44
|
+
def run(self):
|
|
45
|
+
self.step_1_preflight_check()
|
|
46
|
+
self.step_2_prepare_environment()
|
|
47
|
+
self.step_3_execute_build()
|
|
48
|
+
self.step_4_finalize_artifacts()
|
|
49
|
+
|
|
50
|
+
# --- Step 1 ---------------------------------------------------------------
|
|
51
|
+
def step_1_preflight_check(self):
|
|
52
|
+
self.log_header("Step 1 - Preflight Check")
|
|
53
|
+
self.step_1_1_print_info()
|
|
54
|
+
self.step_1_2_check()
|
|
55
|
+
|
|
56
|
+
def step_1_1_print_info(self):
|
|
57
|
+
# fmt: off
|
|
58
|
+
self.log_sub_header("Step 1.1 - Print Build Info")
|
|
59
|
+
self.log_detail(f"path_pyproject_toml = {self.path_pyproject_toml}")
|
|
60
|
+
self.log_detail(f"py_ver_major = {self.py_ver_major}")
|
|
61
|
+
self.log_detail(f"py_ver_minor = {self.py_ver_minor}")
|
|
62
|
+
self.log_detail(f"is_arm = {self.is_arm}")
|
|
63
|
+
self.log_detail(f"path_script = {self.path_script}")
|
|
64
|
+
self.log_detail(f"dir_repo = {self.path_layout.dir_repo}")
|
|
65
|
+
self.log_detail(f"dir_build_layer = {self.path_layout.dir_build_lambda_layer}")
|
|
66
|
+
# fmt: on
|
|
67
|
+
|
|
68
|
+
def step_1_2_check(self):
|
|
69
|
+
"""
|
|
70
|
+
Check that ``uv.lock`` exists before starting the build.
|
|
71
|
+
|
|
72
|
+
Container builds are slow and resource-heavy (pulling Docker images,
|
|
73
|
+
spinning up a container). Failing early on a missing lock file
|
|
74
|
+
saves minutes of wasted time. The local builder skips this check
|
|
75
|
+
because local builds are fast enough that discovering the missing
|
|
76
|
+
lock file at ``uv sync`` time is acceptable.
|
|
77
|
+
"""
|
|
78
|
+
self.log_sub_header("Step 1.2 - Check")
|
|
79
|
+
path_uv_lock = self.path_layout.dir_project_root / "uv.lock"
|
|
80
|
+
self.log_detail(f"Check if '{path_uv_lock}' exists ...")
|
|
81
|
+
if path_uv_lock.exists():
|
|
82
|
+
self.log_detail("Exists!")
|
|
83
|
+
else:
|
|
84
|
+
raise FileNotFoundError(
|
|
85
|
+
f"UV lock file not found: {path_uv_lock}, "
|
|
86
|
+
f"cannot proceed with uv-based build. "
|
|
87
|
+
f"Please run 'uv lock' to generate the lock file."
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# --- Step 2 ---------------------------------------------------------------
|
|
91
|
+
def step_2_prepare_environment(self):
|
|
92
|
+
self.log_header("Step 2 - Prepare Environment")
|
|
93
|
+
self.step_2_1_setup_build_dir()
|
|
94
|
+
self.step_2_2_copy_build_script()
|
|
95
|
+
self.step_2_3_setup_private_repository_credential()
|
|
96
|
+
self.step_2_4_prepare_uv_stuff()
|
|
97
|
+
|
|
98
|
+
def step_2_1_setup_build_dir(self):
|
|
99
|
+
"""
|
|
100
|
+
Delete ``build/lambda/layer/`` and recreate the directory structure.
|
|
101
|
+
"""
|
|
102
|
+
self.log_sub_header("Step 2.1 - Setup Build Directory")
|
|
103
|
+
dir = self.path_layout.dir_build_lambda_layer
|
|
104
|
+
self.log_detail(f"Clean existing build directory: {dir}")
|
|
105
|
+
self.path_layout.clean(skip_prompt=self.skip_prompt)
|
|
106
|
+
self.path_layout.mkdirs()
|
|
107
|
+
|
|
108
|
+
def step_2_2_copy_build_script(self):
|
|
109
|
+
"""
|
|
110
|
+
Copy ``_build_in_container.py`` →
|
|
111
|
+
``build/lambda/layer/build_lambda_layer_in_container.py``.
|
|
112
|
+
"""
|
|
113
|
+
self.log_sub_header("Step 2.2 - Copy Build Script")
|
|
114
|
+
p_dst = self.path_layout.path_build_lambda_layer_in_container_script_in_local
|
|
115
|
+
self.path_layout.copy_file(
|
|
116
|
+
p_src=self.path_script,
|
|
117
|
+
p_dst=p_dst,
|
|
118
|
+
printer=self.log_detail,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
def step_2_3_setup_private_repository_credential(self):
|
|
122
|
+
"""
|
|
123
|
+
Dump credentials JSON to ``build/lambda/layer/private-repository-credentials.json``
|
|
124
|
+
for the container script to read.
|
|
125
|
+
"""
|
|
126
|
+
self.log_sub_header("Step 2.3 - Setup Private Repository Credential")
|
|
127
|
+
if not isinstance(
|
|
128
|
+
self.credentials, aws_lbd_art_builder_core.layer_api.Credentials
|
|
129
|
+
):
|
|
130
|
+
self.log_detail("No private repository credentials provided, skip.")
|
|
131
|
+
return
|
|
132
|
+
p = (
|
|
133
|
+
self.path_layout.dir_build_lambda_layer
|
|
134
|
+
/ "private-repository-credentials.json"
|
|
135
|
+
)
|
|
136
|
+
self.log_detail(f"Dump private repository credentials to {p}")
|
|
137
|
+
self.credentials.dump(path=p)
|
|
138
|
+
|
|
139
|
+
def step_2_4_prepare_uv_stuff(self):
|
|
140
|
+
"""
|
|
141
|
+
Copy ``pyproject.toml`` and ``uv.lock`` to ``build/lambda/layer/repo/``.
|
|
142
|
+
"""
|
|
143
|
+
self.log_sub_header("Step 2.4 - Prepare UV stuff")
|
|
144
|
+
self.path_layout.copy_pyproject_toml(printer=self.log_detail)
|
|
145
|
+
self.path_layout.copy_file(
|
|
146
|
+
p_src=self.path_layout.dir_project_root / "uv.lock",
|
|
147
|
+
p_dst=self.path_layout.dir_repo / "uv.lock",
|
|
148
|
+
printer=self.log_detail,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# --- Step 3 ---------------------------------------------------------------
|
|
152
|
+
def step_3_execute_build(self):
|
|
153
|
+
self.log_header("Step 3 - Execute Build")
|
|
154
|
+
self.step_3_1_docker_run()
|
|
155
|
+
|
|
156
|
+
def step_3_1_docker_run(self):
|
|
157
|
+
self.log_sub_header("Step 3.1 - Docker Run")
|
|
158
|
+
subprocess.run(self.docker_run_args, check=True)
|
|
159
|
+
|
|
160
|
+
# --- Step 4 ---------------------------------------------------------------
|
|
161
|
+
def step_4_finalize_artifacts(self):
|
|
162
|
+
"""
|
|
163
|
+
Move ``repo/.venv/lib/pythonX.Y/site-packages/`` →
|
|
164
|
+
``artifacts/python/`` on the host.
|
|
165
|
+
"""
|
|
166
|
+
self.log_header("Step 4 - Finalize Artifacts")
|
|
167
|
+
self.step_4_1_move_site_packages_to_python()
|
|
168
|
+
|
|
169
|
+
def step_4_1_move_site_packages_to_python(self):
|
|
170
|
+
self.log_sub_header("Step 4.1 - Move site-packages to python/")
|
|
171
|
+
dir_source = self.path_layout.dir_build_lambda_layer_repo_venv_site_packages
|
|
172
|
+
dir_target = self.path_layout.dir_python
|
|
173
|
+
self.log_detail(f"Move '{dir_source}' to '{dir_target}'")
|
|
174
|
+
aws_lbd_art_builder_core.layer_api.move_to_dir_python(
|
|
175
|
+
dir_site_packages=dir_source,
|
|
176
|
+
dir_python=dir_target,
|
|
177
|
+
)
|