aws-lambda-layer-cli 2.0.4 → 2.1.3
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.
- package/README.md +7 -6
- package/package.json +1 -1
- package/scripts/aws-lambda-layer-cli +7 -5
- package/scripts/create_python_layer.sh +121 -54
- package/scripts/create_wheel_layer.sh +221 -0
- package/scripts/install.ps1 +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A command-line tool for creating and publishing AWS Lambda layers for Node.js an
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- Create and publish Lambda layers for Node.js (npm) and Python (
|
|
7
|
+
- Create and publish Lambda layers for Node.js (npm) and Python (pip)
|
|
8
8
|
- Automatic version management and smart naming
|
|
9
9
|
- Direct publishing to AWS with IAM credentials and region support
|
|
10
10
|
- Support for multiple packages in a single layer
|
|
@@ -50,9 +50,10 @@ aws-lambda-layer-cli <command> [options]
|
|
|
50
50
|
| `--description` | Layer description (publish only) |
|
|
51
51
|
| `--profile` | AWS CLI profile (publish only) |
|
|
52
52
|
| `--region` | AWS region (publish only) |
|
|
53
|
+
| `--architecture, -a` | Target architecture (`x86_64` or `arm64`) |
|
|
54
|
+
| `--platform` | Target platform tag (Python only, e.g. `manylinux_2_28_aarch64`) |
|
|
53
55
|
| `--node-version` | Node.js version (default: 24) |
|
|
54
56
|
| `--python-version` | Python version (default: 3.14) |
|
|
55
|
-
| `--no-uv` | Use pip/venv instead of uv |
|
|
56
57
|
| `-v, --version` | Show version |
|
|
57
58
|
|
|
58
59
|
## Examples
|
|
@@ -68,11 +69,11 @@ aws-lambda-layer-cli publish --nodejs lodash --profile prod --region us-east-1 -
|
|
|
68
69
|
|
|
69
70
|
### Python
|
|
70
71
|
```bash
|
|
71
|
-
# Create local zip with specific python version
|
|
72
|
-
aws-lambda-layer-cli zip --python numpy==1.26.0,pandas --python-version 3.12
|
|
72
|
+
# Create local zip with specific python version and architecture
|
|
73
|
+
aws-lambda-layer-cli zip --python numpy==1.26.0,pandas --python-version 3.12 --architecture arm64
|
|
73
74
|
|
|
74
|
-
# Publish to AWS
|
|
75
|
-
aws-lambda-layer-cli publish --python requests --name web-layer
|
|
75
|
+
# Publish to AWS with explicit platform tag (e.g. Amazon Linux 2023 / manylinux_2_28)
|
|
76
|
+
aws-lambda-layer-cli publish --python requests --name web-layer --platform manylinux_2_28_x86_64
|
|
76
77
|
```
|
|
77
78
|
|
|
78
79
|
## Shell Completion
|
package/package.json
CHANGED
|
@@ -47,7 +47,7 @@ COMPLETION_DIR="/etc/bash_completion.d"
|
|
|
47
47
|
# Show help
|
|
48
48
|
show_help() {
|
|
49
49
|
local version_file="$SCRIPT_DIR/VERSION.txt"
|
|
50
|
-
local version="2.
|
|
50
|
+
local version="2.1.3"
|
|
51
51
|
if [ -f "$version_file" ]; then
|
|
52
52
|
version=$(cat "$version_file")
|
|
53
53
|
fi
|
|
@@ -85,7 +85,8 @@ show_help() {
|
|
|
85
85
|
printf " ${YELLOW}--version, -v${NC} Show tool version information\n"
|
|
86
86
|
printf " ${YELLOW}--node-version${NC} Node.js version (default: 24)\n"
|
|
87
87
|
printf " ${YELLOW}--python-version${NC} Python version (default: 3.14)\n"
|
|
88
|
-
printf " ${YELLOW}--
|
|
88
|
+
printf " ${YELLOW}--architecture, -a${NC} Target architecture (x86_64, arm64)\n"
|
|
89
|
+
printf " ${YELLOW}--platform${NC} Target platform tag (Python only)\n\n"
|
|
89
90
|
|
|
90
91
|
printf "${MAGENTA}${UNDERLINE}Package Version Examples:${NC}\n"
|
|
91
92
|
printf " Node.js: express@^4.0.0, lodash@~4.17.0, axios@>=1.6.0\n"
|
|
@@ -113,7 +114,7 @@ show_version() {
|
|
|
113
114
|
echo "v$version"
|
|
114
115
|
else
|
|
115
116
|
# Fallback if VERSION file is missing (e.g. during development or if moved)
|
|
116
|
-
echo "v2.
|
|
117
|
+
echo "v2.1.3"
|
|
117
118
|
fi
|
|
118
119
|
}
|
|
119
120
|
|
|
@@ -251,7 +252,7 @@ get_aws_account_info() {
|
|
|
251
252
|
# Determine compatible runtimes for AWS
|
|
252
253
|
get_compatible_runtimes() {
|
|
253
254
|
local runtime="$1"
|
|
254
|
-
local version="2.
|
|
255
|
+
local version="2.1.3"
|
|
255
256
|
|
|
256
257
|
case "$runtime" in
|
|
257
258
|
nodejs)
|
|
@@ -659,7 +660,8 @@ handle_publish() {
|
|
|
659
660
|
fi
|
|
660
661
|
|
|
661
662
|
# Extract Python version for compatible runtimes
|
|
662
|
-
|
|
663
|
+
# Pattern matches "Python version: X.Y" or "Python Version: X.Y"
|
|
664
|
+
local python_version=$(grep -i "Python.*version: [0-9.]*" "build.log" | awk '{print $NF}' | tail -1)
|
|
663
665
|
if [ -z "$python_version" ]; then
|
|
664
666
|
python_version="3.14"
|
|
665
667
|
fi
|
|
@@ -19,8 +19,11 @@ LAYER_NAME=""
|
|
|
19
19
|
PYTHON_VERSION="3.14" # Default to Python 3.14
|
|
20
20
|
PYTHON_VERSION_SPECIFIED=false
|
|
21
21
|
VENV_DIR="python"
|
|
22
|
-
USE_UV=true
|
|
23
22
|
ORIGINAL_DIR=$(pwd)
|
|
23
|
+
PLATFORM="" # Optional platform targeting
|
|
24
|
+
IMPLEMENTATION="cp"
|
|
25
|
+
ABI=""
|
|
26
|
+
ARCHITECTURE="x86_64" # Default architecture
|
|
24
27
|
|
|
25
28
|
# Colors for output
|
|
26
29
|
RED='\033[0;31m'
|
|
@@ -137,26 +140,58 @@ while [[ $# -gt 0 ]]; do
|
|
|
137
140
|
validate_python_version "$PYTHON_VERSION"
|
|
138
141
|
shift
|
|
139
142
|
;;
|
|
140
|
-
--
|
|
141
|
-
|
|
143
|
+
--platform)
|
|
144
|
+
if [[ -n "${2:-}" && "${2:-}" != -* ]]; then
|
|
145
|
+
PLATFORM="$2"
|
|
146
|
+
shift 2
|
|
147
|
+
else
|
|
148
|
+
printf "${RED}Error: $1 requires an argument${NC}\n"
|
|
149
|
+
printf "Example: $1 manylinux_2_28_x86_64\n"
|
|
150
|
+
exit 1
|
|
151
|
+
fi
|
|
152
|
+
;;
|
|
153
|
+
--platform=*)
|
|
154
|
+
PLATFORM="${1#*=}"
|
|
155
|
+
shift
|
|
156
|
+
;;
|
|
157
|
+
-a|--architecture)
|
|
158
|
+
if [[ -n "${2:-}" && "${2:-}" != -* ]]; then
|
|
159
|
+
ARCHITECTURE="$2"
|
|
160
|
+
shift 2
|
|
161
|
+
else
|
|
162
|
+
printf "${RED}Error: $1 requires an argument${NC}\n"
|
|
163
|
+
printf "Example: $1 arm64\n"
|
|
164
|
+
exit 1
|
|
165
|
+
fi
|
|
166
|
+
;;
|
|
167
|
+
--architecture=*)
|
|
168
|
+
ARCHITECTURE="${1#*=}"
|
|
142
169
|
shift
|
|
143
170
|
;;
|
|
144
171
|
-h|--help)
|
|
145
172
|
cat << 'EOF'
|
|
146
|
-
Python Lambda Layer Creator
|
|
173
|
+
Python Lambda Layer Creator
|
|
147
174
|
|
|
148
175
|
Usage:
|
|
149
176
|
./create_python_layer.sh -i numpy==1.26.0,pandas==2.1.3
|
|
150
177
|
./create_python_layer.sh --packages=numpy==1.26.0,pandas,boto3==1.34.0 -n my-layer.zip
|
|
151
|
-
./create_python_layer.sh -i flask==3.0.0 --no-uv
|
|
152
178
|
|
|
153
179
|
Options:
|
|
154
180
|
-i, --packages Comma-separated list of Python packages (with optional versions)
|
|
155
181
|
-n, --name Name of the output zip file
|
|
156
182
|
--python-version Python version (default: 3.14)
|
|
157
|
-
--
|
|
183
|
+
--platform Target platform tag (optional, overrides architecture)
|
|
184
|
+
-a, --architecture Target architecture (x86_64 or arm64, default: x86_64)
|
|
158
185
|
-h, --help Show this help message
|
|
159
186
|
|
|
187
|
+
Supported Platforms (optional):
|
|
188
|
+
manylinux2014_x86_64 # Amazon Linux 2, RHEL 7+ (older)
|
|
189
|
+
manylinux2014_aarch64 # ARM64 architecture
|
|
190
|
+
manylinux_2_28_x86_64 # Amazon Linux 2023, RHEL 8+ (newer)
|
|
191
|
+
manylinux_2_28_aarch64 # ARM64 with newer glibc
|
|
192
|
+
linux_x86_64 # Generic Linux
|
|
193
|
+
linux_aarch64 # Generic ARM64 Linux
|
|
194
|
+
|
|
160
195
|
Version Specification:
|
|
161
196
|
Package versions can be specified using standard Python version specifiers:
|
|
162
197
|
numpy==1.26.0 # Exact version
|
|
@@ -167,9 +202,14 @@ Version Specification:
|
|
|
167
202
|
Django!=3.2.0 # Version exclusion
|
|
168
203
|
|
|
169
204
|
Examples:
|
|
205
|
+
# Basic usage
|
|
170
206
|
./create_python_layer.sh -i numpy==1.26.0
|
|
171
|
-
|
|
172
|
-
|
|
207
|
+
|
|
208
|
+
# With platform targeting for Amazon Linux 2023
|
|
209
|
+
./create_python_layer.sh -i requests==2.31.0,boto3==1.34.0 --python-version=3.13 --platform=manylinux_2_28_x86_64
|
|
210
|
+
|
|
211
|
+
# With platform targeting for ARM64
|
|
212
|
+
./create_python_layer.sh --packages=pandas==2.1.3,scikit-learn==1.3.0 --platform=manylinux_2_28_aarch64 -n ml-layer.zip
|
|
173
213
|
EOF
|
|
174
214
|
exit 0
|
|
175
215
|
;;
|
|
@@ -189,14 +229,6 @@ if [ -z "$PACKAGES" ]; then
|
|
|
189
229
|
exit 1
|
|
190
230
|
fi
|
|
191
231
|
|
|
192
|
-
# Check if uv is available safely
|
|
193
|
-
if [ "$USE_UV" = true ]; then
|
|
194
|
-
if ! command -v uv >/dev/null 2>&1; then
|
|
195
|
-
printf "${YELLOW}Warning: uv not found, falling back to pip/venv${NC}\n"
|
|
196
|
-
USE_UV=false
|
|
197
|
-
fi
|
|
198
|
-
fi
|
|
199
|
-
|
|
200
232
|
# Check dependencies
|
|
201
233
|
if ! command -v zip &> /dev/null; then
|
|
202
234
|
printf "${RED}Error: 'zip' command is not installed${NC}\n"
|
|
@@ -236,12 +268,29 @@ if [ "$PACKAGES" != "$SANITIZED_PACKAGES" ]; then
|
|
|
236
268
|
PACKAGES="$SANITIZED_PACKAGES"
|
|
237
269
|
fi
|
|
238
270
|
|
|
271
|
+
# Normalize Architecture
|
|
272
|
+
AWS_ARCH="$ARCHITECTURE"
|
|
273
|
+
if [ "$ARCHITECTURE" = "arm64" ]; then
|
|
274
|
+
ARCHITECTURE="aarch64"
|
|
275
|
+
AWS_ARCH="arm64"
|
|
276
|
+
elif [ "$ARCHITECTURE" = "amd64" ]; then
|
|
277
|
+
ARCHITECTURE="x86_64"
|
|
278
|
+
AWS_ARCH="x86_64"
|
|
279
|
+
elif [ "$ARCHITECTURE" = "x86_64" ]; then
|
|
280
|
+
AWS_ARCH="x86_64"
|
|
281
|
+
elif [ "$ARCHITECTURE" = "aarch64" ]; then
|
|
282
|
+
AWS_ARCH="arm64"
|
|
283
|
+
fi
|
|
284
|
+
|
|
239
285
|
printf "${BLUE}=========================================${NC}\n"
|
|
240
286
|
printf "${GREEN}Python Lambda Layer Creator${NC}\n"
|
|
241
287
|
printf "${BLUE}=========================================${NC}\n"
|
|
242
288
|
printf "Packages: $PACKAGES\n"
|
|
243
289
|
printf "Python version: $PYTHON_VERSION\n"
|
|
244
|
-
printf "
|
|
290
|
+
printf "Target Architecture: $AWS_ARCH\n"
|
|
291
|
+
if [ -n "$PLATFORM" ]; then
|
|
292
|
+
printf "Platform: $PLATFORM\n"
|
|
293
|
+
fi
|
|
245
294
|
if [ -n "$LAYER_NAME" ]; then
|
|
246
295
|
printf "Output name: $LAYER_NAME\n"
|
|
247
296
|
fi
|
|
@@ -277,20 +326,12 @@ if ! command -v "$TARGET_PYTHON" >/dev/null 2>&1; then
|
|
|
277
326
|
fi
|
|
278
327
|
fi
|
|
279
328
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
printf "${RED}Error: Failed to create venv with uv${NC}\n"
|
|
284
|
-
exit 1
|
|
285
|
-
fi
|
|
329
|
+
printf " Using venv module...\n"
|
|
330
|
+
if command -v "$TARGET_PYTHON" >/dev/null 2>&1; then
|
|
331
|
+
"$TARGET_PYTHON" -m venv "$VENV_DIR"
|
|
286
332
|
else
|
|
287
|
-
printf "
|
|
288
|
-
|
|
289
|
-
"$TARGET_PYTHON" -m venv "$VENV_DIR"
|
|
290
|
-
else
|
|
291
|
-
printf "${RED}Error: $TARGET_PYTHON not found${NC}\n"
|
|
292
|
-
exit 1
|
|
293
|
-
fi
|
|
333
|
+
printf "${RED}Error: $TARGET_PYTHON not found${NC}\n"
|
|
334
|
+
exit 1
|
|
294
335
|
fi
|
|
295
336
|
|
|
296
337
|
# Activate virtual environment
|
|
@@ -307,15 +348,53 @@ set -u
|
|
|
307
348
|
|
|
308
349
|
# Step 3: Install packages with versions
|
|
309
350
|
printf "[3/7] Installing packages...\n"
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
351
|
+
|
|
352
|
+
# Auto-detect platform if not specified
|
|
353
|
+
if [ -z "$PLATFORM" ]; then
|
|
354
|
+
# Calculate major/minor version
|
|
355
|
+
# PYTHON_VERSION is like 3.14 or 3.14.2
|
|
356
|
+
PY_VER_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1)
|
|
357
|
+
PY_VER_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2)
|
|
358
|
+
|
|
359
|
+
# Default to manylinux2014 (Amazon Linux 2)
|
|
360
|
+
PLATFORM_PREFIX="manylinux2014"
|
|
361
|
+
|
|
362
|
+
# Legacy: We previously checked for AL2023 (manylinux_2_28) here, but forcing it
|
|
363
|
+
# causes issues with packages like NumPy that publish manylinux2014 or manylinux_2_17 wheels.
|
|
364
|
+
# Since AL2023 is backward compatible with manylinux2014, we stick to that for max compatibility.
|
|
365
|
+
|
|
366
|
+
PLATFORM="${PLATFORM_PREFIX}_${ARCHITECTURE}"
|
|
367
|
+
printf "Auto-detected platform: $PLATFORM (Python $PYTHON_VERSION, Arch $ARCHITECTURE)\n"
|
|
368
|
+
fi
|
|
369
|
+
|
|
370
|
+
# Prepare platform-specific options
|
|
371
|
+
INSTALL_OPTS=()
|
|
372
|
+
if [ -n "$PLATFORM" ]; then
|
|
373
|
+
# Calculate ABI tag based on Python version (e.g., 3.12 -> cp312)
|
|
374
|
+
# We use cut instead of potentially fragile regex
|
|
375
|
+
PY_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1)
|
|
376
|
+
PY_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2)
|
|
377
|
+
ABI="cp${PY_MAJOR}${PY_MINOR}"
|
|
378
|
+
|
|
379
|
+
INSTALL_OPTS+=("--platform" "$PLATFORM")
|
|
380
|
+
INSTALL_OPTS+=("--implementation" "$IMPLEMENTATION")
|
|
381
|
+
INSTALL_OPTS+=("--python-version" "$PYTHON_VERSION")
|
|
382
|
+
INSTALL_OPTS+=("--abi" "$ABI")
|
|
383
|
+
INSTALL_OPTS+=("--only-binary=:all:")
|
|
384
|
+
printf " Using platform-specific installation: $PLATFORM\n"
|
|
385
|
+
printf " ABI tag: $ABI\n"
|
|
386
|
+
fi
|
|
387
|
+
|
|
388
|
+
printf " Installing with pip...\n"
|
|
389
|
+
# Convert to array for safe expansion
|
|
390
|
+
IFS=',' read -ra PKG_ARRAY <<< "$PACKAGES"
|
|
391
|
+
if [ ${#INSTALL_OPTS[@]} -gt 0 ]; then
|
|
392
|
+
# When using platform specific options, we must specify --target
|
|
393
|
+
# We use the site-packages directory of the current venv
|
|
394
|
+
SITE_PACKAGES=$(python -c "import site; print(site.getsitepackages()[0])")
|
|
395
|
+
printf " Targeting site-packages: $SITE_PACKAGES\n"
|
|
396
|
+
pip install "${PKG_ARRAY[@]}" "${INSTALL_OPTS[@]}" --target "$SITE_PACKAGES"
|
|
315
397
|
else
|
|
316
|
-
printf " Installing with pip...\n"
|
|
317
|
-
# Convert to array for safe expansion
|
|
318
|
-
IFS=',' read -ra PKG_ARRAY <<< "$PACKAGES"
|
|
319
398
|
pip install "${PKG_ARRAY[@]}"
|
|
320
399
|
fi
|
|
321
400
|
|
|
@@ -333,11 +412,7 @@ if [ -z "$LAYER_NAME" ]; then
|
|
|
333
412
|
printf " Single package: $PKG_NAME\n"
|
|
334
413
|
|
|
335
414
|
# Extract version from installed package
|
|
336
|
-
|
|
337
|
-
PKG_INFO=$(uv pip show "$PKG_NAME" 2>/dev/null || true)
|
|
338
|
-
else
|
|
339
|
-
PKG_INFO=$(pip show "$PKG_NAME" 2>/dev/null || true)
|
|
340
|
-
fi
|
|
415
|
+
PKG_INFO=$(pip show "$PKG_NAME" 2>/dev/null || true)
|
|
341
416
|
|
|
342
417
|
if [ -n "$PKG_INFO" ]; then
|
|
343
418
|
# Use safer extraction methods
|
|
@@ -400,11 +475,7 @@ fi
|
|
|
400
475
|
|
|
401
476
|
# Step 5: Show installed packages
|
|
402
477
|
printf "[5/7] Listing installed packages...\n"
|
|
403
|
-
|
|
404
|
-
uv pip list --format freeze
|
|
405
|
-
else
|
|
406
|
-
pip list --format freeze
|
|
407
|
-
fi
|
|
478
|
+
pip list --format freeze
|
|
408
479
|
|
|
409
480
|
# Deactivate virtual environment
|
|
410
481
|
set +u
|
|
@@ -433,7 +504,7 @@ printf "${GREEN}✅ SUCCESS: Python Lambda Layer Created${NC}\n"
|
|
|
433
504
|
printf "${BLUE}=========================================${NC}\n"
|
|
434
505
|
printf "📁 File: $ORIGINAL_DIR/$LAYER_NAME\n"
|
|
435
506
|
printf "🐍 Python Version: $PYTHON_VERSION\n"
|
|
436
|
-
printf "⚡ Tool:
|
|
507
|
+
printf "⚡ Tool: pip/venv\n"
|
|
437
508
|
printf "📦 Size: $(du -h "$ORIGINAL_DIR/$LAYER_NAME" | cut -f1)\n"
|
|
438
509
|
printf "📊 Package Count: $PACKAGE_COUNT\n"
|
|
439
510
|
|
|
@@ -446,11 +517,7 @@ for pkg_full in "${PKG_ARRAY[@]}"; do
|
|
|
446
517
|
pkg_name=$(extract_package_name "$pkg_full")
|
|
447
518
|
|
|
448
519
|
# Get installed version from pip show or metadata
|
|
449
|
-
|
|
450
|
-
installed_ver=$(find . -type f -name "METADATA" -path "*/${pkg_name}-*.dist-info/METADATA" -exec grep -h "^Version:" {} \; | head -1 | cut -d' ' -f2)
|
|
451
|
-
else
|
|
452
|
-
installed_ver=$(find . -type f -name "METADATA" -path "*/${pkg_name}-*.dist-info/METADATA" -exec grep -h "^Version:" {} \; | head -1 | cut -d' ' -f2)
|
|
453
|
-
fi
|
|
520
|
+
installed_ver=$(find . -type f -name "METADATA" -path "*/${pkg_name}-*.dist-info/METADATA" -exec grep -h "^Version:" {} \; | head -1 | cut -d' ' -f2)
|
|
454
521
|
|
|
455
522
|
if [ -n "$installed_ver" ]; then
|
|
456
523
|
if [ -n "$INSTALLED_PKGS" ]; then
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Python Lambda Layer Creator from Wheel
|
|
4
|
+
# Usage:
|
|
5
|
+
# ./create_wheel_layer.sh -w mypackage.whl
|
|
6
|
+
# ./create_wheel_layer.sh -w mypackage.whl -i "pandas,boto3" -n my-layer.zip
|
|
7
|
+
|
|
8
|
+
set -e
|
|
9
|
+
set -u
|
|
10
|
+
|
|
11
|
+
# Default values
|
|
12
|
+
WHEEL_FILE=""
|
|
13
|
+
PACKAGES=""
|
|
14
|
+
LAYER_NAME=""
|
|
15
|
+
PYTHON_VERSION="3.12"
|
|
16
|
+
PLATFORM="manylinux2014_x86_64"
|
|
17
|
+
IMPLEMENTATION="cp"
|
|
18
|
+
ABI="cp312" # Default ABI tag
|
|
19
|
+
|
|
20
|
+
# Colors
|
|
21
|
+
RED='\033[0;31m'
|
|
22
|
+
GREEN='\033[0;32m'
|
|
23
|
+
YELLOW='\033[1;33m'
|
|
24
|
+
NC='\033[0m'
|
|
25
|
+
|
|
26
|
+
# Parse arguments
|
|
27
|
+
while [[ $# -gt 0 ]]; do
|
|
28
|
+
case "$1" in
|
|
29
|
+
-w|--wheel)
|
|
30
|
+
if [[ -n "${2:-}" && "${2:-}" != -* ]]; then
|
|
31
|
+
WHEEL_FILE="$2"
|
|
32
|
+
shift 2
|
|
33
|
+
else
|
|
34
|
+
printf "${RED}Error: $1 requires an argument${NC}\n"
|
|
35
|
+
exit 1
|
|
36
|
+
fi
|
|
37
|
+
;;
|
|
38
|
+
--wheel=*)
|
|
39
|
+
WHEEL_FILE="${1#*=}"
|
|
40
|
+
shift
|
|
41
|
+
;;
|
|
42
|
+
-i|--packages)
|
|
43
|
+
if [[ -n "${2:-}" && "${2:-}" != -* ]]; then
|
|
44
|
+
PACKAGES="$2"
|
|
45
|
+
shift 2
|
|
46
|
+
else
|
|
47
|
+
printf "${RED}Error: $1 requires an argument${NC}\n"
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
;;
|
|
51
|
+
--packages=*)
|
|
52
|
+
PACKAGES="${1#*=}"
|
|
53
|
+
shift
|
|
54
|
+
;;
|
|
55
|
+
-n|--name)
|
|
56
|
+
if [[ -n "${2:-}" && "${2:-}" != -* ]]; then
|
|
57
|
+
LAYER_NAME="$2"
|
|
58
|
+
shift 2
|
|
59
|
+
else
|
|
60
|
+
printf "${RED}Error: $1 requires an argument${NC}\n"
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
;;
|
|
64
|
+
--name=*)
|
|
65
|
+
LAYER_NAME="${1#*=}"
|
|
66
|
+
shift
|
|
67
|
+
;;
|
|
68
|
+
--python-version)
|
|
69
|
+
if [[ -n "${2:-}" && "${2:-}" != -* ]]; then
|
|
70
|
+
PYTHON_VERSION="$2"
|
|
71
|
+
shift 2
|
|
72
|
+
else
|
|
73
|
+
printf "${RED}Error: $1 requires an argument${NC}\n"
|
|
74
|
+
exit 1
|
|
75
|
+
fi
|
|
76
|
+
;;
|
|
77
|
+
--python-version=*)
|
|
78
|
+
PYTHON_VERSION="${1#*=}"
|
|
79
|
+
shift
|
|
80
|
+
;;
|
|
81
|
+
--platform)
|
|
82
|
+
if [[ -n "${2:-}" && "${2:-}" != -* ]]; then
|
|
83
|
+
PLATFORM="$2"
|
|
84
|
+
shift 2
|
|
85
|
+
else
|
|
86
|
+
printf "${RED}Error: $1 requires an argument${NC}\n"
|
|
87
|
+
exit 1
|
|
88
|
+
fi
|
|
89
|
+
;;
|
|
90
|
+
--platform=*)
|
|
91
|
+
PLATFORM="${1#*=}"
|
|
92
|
+
shift
|
|
93
|
+
;;
|
|
94
|
+
-h|--help)
|
|
95
|
+
cat << 'EOF'
|
|
96
|
+
Usage: ./create_wheel_layer.sh -w <wheel_file> [-i <packages>] [-n <zip_name>]
|
|
97
|
+
|
|
98
|
+
Options:
|
|
99
|
+
-w, --wheel Path to .whl file
|
|
100
|
+
-i, --packages Additional packages (comma or space separated)
|
|
101
|
+
-n, --name Output zip filename
|
|
102
|
+
--python-version Target Python version (default: 3.12)
|
|
103
|
+
--platform Target platform (default: manylinux2014_x86_64)
|
|
104
|
+
|
|
105
|
+
Supported Platforms:
|
|
106
|
+
manylinux2014_x86_64 # Amazon Linux 2, RHEL 7+ (older)
|
|
107
|
+
manylinux2014_aarch64 # ARM64 architecture
|
|
108
|
+
manylinux_2_28_x86_64 # Amazon Linux 2023, RHEL 8+ (newer)
|
|
109
|
+
manylinux_2_28_aarch64 # ARM64 with newer glibc
|
|
110
|
+
linux_x86_64 # Generic Linux
|
|
111
|
+
linux_aarch64 # Generic ARM64 Linux
|
|
112
|
+
|
|
113
|
+
Python Version Support:
|
|
114
|
+
3.8, 3.9, 3.10, 3.11, 3.12, 3.13, 3.14
|
|
115
|
+
|
|
116
|
+
Examples:
|
|
117
|
+
# Build for Amazon Linux 2 (Python 3.12)
|
|
118
|
+
./create_wheel_layer.sh -w mypackage.whl --python-version=3.12 --platform=manylinux2014_x86_64
|
|
119
|
+
|
|
120
|
+
# Build for Amazon Linux 2023 (Python 3.13)
|
|
121
|
+
./create_wheel_layer.sh -w mypackage.whl --python-version=3.13 --platform=manylinux_2_28_x86_64
|
|
122
|
+
|
|
123
|
+
# Build with additional packages for ARM64
|
|
124
|
+
./create_wheel_layer.sh -w mypackage.whl -i "numpy,pandas" --platform=manylinux_2_28_aarch64
|
|
125
|
+
EOF
|
|
126
|
+
exit 0
|
|
127
|
+
;;
|
|
128
|
+
*)
|
|
129
|
+
printf "${RED}Unknown option: $1${NC}\n"
|
|
130
|
+
exit 1
|
|
131
|
+
;;
|
|
132
|
+
esac
|
|
133
|
+
done
|
|
134
|
+
|
|
135
|
+
# Validation
|
|
136
|
+
if [ -z "$WHEEL_FILE" ]; then
|
|
137
|
+
printf "${RED}Error: Wheel file is required (-w)${NC}\n"
|
|
138
|
+
exit 1
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
if [ ! -f "$WHEEL_FILE" ]; then
|
|
142
|
+
printf "${RED}Error: File $WHEEL_FILE not found${NC}\n"
|
|
143
|
+
exit 1
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
# Determine ABI tag based on Python version
|
|
147
|
+
PY_MAJOR_MINOR=$(echo "$PYTHON_VERSION" | sed 's/\([0-9]\+\)\.\([0-9]\+\).*/\1\2/')
|
|
148
|
+
ABI="cp${PY_MAJOR_MINOR}"
|
|
149
|
+
|
|
150
|
+
if [ -z "$LAYER_NAME" ]; then
|
|
151
|
+
BASENAME=$(basename "$WHEEL_FILE" .whl)
|
|
152
|
+
LAYER_NAME="${BASENAME}_layer.zip"
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
# Setup workspace
|
|
156
|
+
LAYER_DIR="layer_build_$(date +%s)"
|
|
157
|
+
ORIGINAL_DIR=$(pwd)
|
|
158
|
+
|
|
159
|
+
# Convert relative paths to absolute
|
|
160
|
+
if [[ "$WHEEL_FILE" != /* ]]; then
|
|
161
|
+
WHEEL_FILE="$ORIGINAL_DIR/$WHEEL_FILE"
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
printf "${GREEN}Creating Lambda layer from wheel...${NC}\n"
|
|
165
|
+
printf "Wheel: $WHEEL_FILE\n"
|
|
166
|
+
if [ -n "$PACKAGES" ]; then
|
|
167
|
+
printf "Extra Packages: $PACKAGES\n"
|
|
168
|
+
fi
|
|
169
|
+
printf "Platform: $PLATFORM\n"
|
|
170
|
+
printf "Python: $PYTHON_VERSION\n"
|
|
171
|
+
|
|
172
|
+
mkdir -p "$LAYER_DIR/python"
|
|
173
|
+
|
|
174
|
+
# Install
|
|
175
|
+
printf "${GREEN}Installing packages...${NC}\n"
|
|
176
|
+
CMD=("pip" "install" "$WHEEL_FILE")
|
|
177
|
+
|
|
178
|
+
if [ -n "$PACKAGES" ]; then
|
|
179
|
+
# Replace commas with spaces
|
|
180
|
+
PKG_SPACE=$(echo "$PACKAGES" | tr ',' ' ')
|
|
181
|
+
# Split into array
|
|
182
|
+
read -ra PKG_ARRAY <<< "$PKG_SPACE"
|
|
183
|
+
CMD+=("${PKG_ARRAY[@]}")
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
CMD+=("--target" "$LAYER_DIR/python")
|
|
187
|
+
CMD+=("--platform" "$PLATFORM")
|
|
188
|
+
CMD+=("--implementation" "$IMPLEMENTATION")
|
|
189
|
+
CMD+=("--python-version" "$PYTHON_VERSION")
|
|
190
|
+
CMD+=("--abi" "$ABI")
|
|
191
|
+
CMD+=("--only-binary=:all:")
|
|
192
|
+
CMD+=("--upgrade")
|
|
193
|
+
|
|
194
|
+
echo "Running: ${CMD[*]}"
|
|
195
|
+
if ! "${CMD[@]}"; then
|
|
196
|
+
printf "${RED}Installation failed${NC}\n"
|
|
197
|
+
rm -rf "$LAYER_DIR"
|
|
198
|
+
exit 1
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
# Cleanup
|
|
202
|
+
printf "${GREEN}Removing cache and metadata...${NC}\n"
|
|
203
|
+
find "$LAYER_DIR" -type d -name "__pycache__" -exec rm -rf {} +
|
|
204
|
+
# Removing dist-info might break some packages (entry points, metadata), but user requested space saving
|
|
205
|
+
# Making it optional or just following user's script. Following user script:
|
|
206
|
+
find "$LAYER_DIR" -type d -name "*.dist-info" -exec rm -rf {} +
|
|
207
|
+
|
|
208
|
+
# Zip
|
|
209
|
+
printf "${GREEN}Zipping to $LAYER_NAME...${NC}\n"
|
|
210
|
+
cd "$LAYER_DIR"
|
|
211
|
+
if zip -r "$ORIGINAL_DIR/$LAYER_NAME" python > /dev/null; then
|
|
212
|
+
printf "${GREEN}✅ Done! Created $LAYER_NAME${NC}\n"
|
|
213
|
+
else
|
|
214
|
+
printf "${RED}Error creating zip file${NC}\n"
|
|
215
|
+
cd "$ORIGINAL_DIR"
|
|
216
|
+
rm -rf "$LAYER_DIR"
|
|
217
|
+
exit 1
|
|
218
|
+
fi
|
|
219
|
+
|
|
220
|
+
cd "$ORIGINAL_DIR"
|
|
221
|
+
rm -rf "$LAYER_DIR"
|
package/scripts/install.ps1
CHANGED
|
@@ -44,7 +44,7 @@ if ([string]::IsNullOrEmpty($InstallDir)) {
|
|
|
44
44
|
# Configuration
|
|
45
45
|
$RepoUrl = "https://github.com/yukcw/aws-lambda-layer-cli"
|
|
46
46
|
$ToolName = "aws-lambda-layer-cli"
|
|
47
|
-
$Version = "2.
|
|
47
|
+
$Version = "2.1.3" # Fallback version
|
|
48
48
|
|
|
49
49
|
# Colors for output
|
|
50
50
|
$Green = "Green"
|