aws-lambda-layer-cli 1.4.1 → 2.0.2

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  # AWS Lambda Layer CLI Tool
4
4
  # Install: sudo ./scripts/install.sh
5
- # Usage: aws-lambda-layer zip --nodejs express,axios -n my-layer
5
+ # Usage: aws-lambda-layer-cli zip --nodejs express,axios -n my-layer
6
6
 
7
7
  set -e
8
8
  set -u
@@ -26,7 +26,7 @@ STRIKETHROUGH='\033[9m'
26
26
 
27
27
  # Paths
28
28
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
29
- INSTALL_DIR="/usr/local/lib/aws-lambda-layer"
29
+ INSTALL_DIR="/usr/local/lib/aws-lambda-layer-cli"
30
30
 
31
31
  # Determine script locations (prefer relative to script, fallback to global install)
32
32
  if [ -f "$SCRIPT_DIR/create_nodejs_layer.sh" ]; then
@@ -54,16 +54,18 @@ show_help() {
54
54
  printf "${BLUE}${BOLD}AWS Lambda Layer CLI Tool - ${version}${NC}\n\n"
55
55
 
56
56
  printf "${BLUE}Usage:${NC}\n"
57
- printf " aws-lambda-layer ${GREEN}zip${NC} ${YELLOW}--nodejs${NC} <packages> [options]\n"
58
- printf " aws-lambda-layer ${GREEN}zip${NC} ${YELLOW}--python${NC} <packages> [options]\n"
59
- printf " aws-lambda-layer ${GREEN}publish${NC} ${YELLOW}--nodejs${NC} <packages> [options]\n"
60
- printf " aws-lambda-layer ${GREEN}publish${NC} ${YELLOW}--python${NC} <packages> [options]\n"
61
- printf " aws-lambda-layer ${GREEN}help${NC}\n"
62
- printf " aws-lambda-layer [options]\n\n"
57
+ printf " aws-lambda-layer-cli ${GREEN}zip${NC} ${YELLOW}--nodejs${NC} <packages> [options]\n"
58
+ printf " aws-lambda-layer-cli ${GREEN}zip${NC} ${YELLOW}--python${NC} <packages> [options]\n"
59
+ printf " aws-lambda-layer-cli ${GREEN}publish${NC} ${YELLOW}--nodejs${NC} <packages> [options]\n"
60
+ printf " aws-lambda-layer-cli ${GREEN}publish${NC} ${YELLOW}--python${NC} <packages> [options]\n"
61
+ printf " aws-lambda-layer-cli ${GREEN}help${NC}\n"
62
+ printf " aws-lambda-layer-cli [options]\n\n"
63
63
 
64
64
  printf "${BLUE}Commands:${NC}\n"
65
65
  printf " ${GREEN}zip${NC} Create and package a Lambda layer as zip file\n"
66
66
  printf " ${GREEN}publish${NC} Create and publish a Lambda layer to AWS (uses IAM credentials)\n"
67
+ printf " ${GREEN}completion${NC} Generate shell completion scripts\n"
68
+ printf " ${GREEN}uninstall${NC} Uninstall the tool and remove all files\n"
67
69
  printf " ${GREEN}help${NC} Show this help message\n\n"
68
70
 
69
71
  printf "${BLUE}Runtime Options:${NC}\n"
@@ -80,6 +82,7 @@ show_help() {
80
82
  printf " ${YELLOW}--profile${NC} AWS CLI profile to use (default: default profile)\n"
81
83
  printf " ${YELLOW}--region${NC} AWS region (e.g., us-east-1, ap-east-1)\n"
82
84
  printf "${BLUE}Other Options:${NC}\n"
85
+ printf " ${YELLOW}--version, -v${NC} Show tool version information\n"
83
86
  printf " ${YELLOW}--node-version${NC} Node.js version (default: 24)\n"
84
87
  printf " ${YELLOW}--python-version${NC} Python version (default: 3.14)\n"
85
88
  printf " ${YELLOW}--no-uv${NC} Use pip/venv instead of uv\n\n"
@@ -89,12 +92,12 @@ show_help() {
89
92
  printf " Python: numpy==1.26.0, pandas>=2.1.0, requests~=2.31.0\n\n"
90
93
 
91
94
  printf "${MAGENTA}${UNDERLINE}Examples:${NC}\n"
92
- printf " aws-lambda-layer ${GREEN}zip${NC} ${YELLOW}--nodejs${NC} express,lodash\n"
93
- printf " aws-lambda-layer ${GREEN}zip${NC} ${YELLOW}--python${NC} \"numpy==1.26.0,pandas>=2.1.0\"\n"
94
- printf " aws-lambda-layer ${GREEN}publish${NC} ${YELLOW}--nodejs${NC} express@4.18.2 ${YELLOW}--description${NC} \"Express layer\"\n"
95
- printf " aws-lambda-layer ${GREEN}publish${NC} ${YELLOW}--python${NC} numpy==1.26.0 ${YELLOW}--description${NC} \"NumPy layer\"\n"
96
- printf " aws-lambda-layer ${GREEN}publish${NC} ${YELLOW}--nodejs${NC} date-fns,uuid ${YELLOW}--name${NC} utility-layer ${YELLOW}--description${NC} \"Utility packages\"\n"
97
- printf " aws-lambda-layer ${GREEN}publish${NC} ${YELLOW}--nodejs${NC} express@4.18.2 ${YELLOW}--profile${NC} production ${YELLOW}--region${NC} ap-east-1 ${YELLOW}--description${NC} \"Express layer\"\n\n"
95
+ printf " aws-lambda-layer-cli ${GREEN}zip${NC} ${YELLOW}--nodejs${NC} express,lodash\n"
96
+ printf " aws-lambda-layer-cli ${GREEN}zip${NC} ${YELLOW}--python${NC} \"numpy==1.26.0,pandas>=2.1.0\"\n"
97
+ printf " aws-lambda-layer-cli ${GREEN}publish${NC} ${YELLOW}--nodejs${NC} express@4.18.2 ${YELLOW}--description${NC} \"Express layer\"\n"
98
+ printf " aws-lambda-layer-cli ${GREEN}publish${NC} ${YELLOW}--python${NC} numpy==1.26.0 ${YELLOW}--description${NC} \"NumPy layer\"\n"
99
+ printf " aws-lambda-layer-cli ${GREEN}publish${NC} ${YELLOW}--nodejs${NC} date-fns,uuid ${YELLOW}--name${NC} utility-layer ${YELLOW}--description${NC} \"Utility packages\"\n"
100
+ printf " aws-lambda-layer-cli ${GREEN}publish${NC} ${YELLOW}--nodejs${NC} express@4.18.2 ${YELLOW}--profile${NC} production ${YELLOW}--region${NC} ap-east-1 ${YELLOW}--description${NC} \"Express layer\"\n\n"
98
101
 
99
102
  printf "${YELLOW}${BOLD}Requirements for publish command:${NC}\n"
100
103
  printf " - AWS CLI installed and configured\n"
@@ -458,7 +461,12 @@ handle_publish() {
458
461
  done
459
462
 
460
463
  # Parse runtime flag from remaining arguments
461
- set -- "${new_args[@]}"
464
+ if [ ${#new_args[@]} -eq 0 ]; then
465
+ set --
466
+ else
467
+ set -- "${new_args[@]}"
468
+ fi
469
+
462
470
  case "${1:-}" in
463
471
  --nodejs|--node|-n)
464
472
  runtime="nodejs"
@@ -753,6 +761,86 @@ handle_publish() {
753
761
  printf "📁 Zip file saved: ${CYAN}$output_dir/$zip_file${NC}\n"
754
762
  }
755
763
 
764
+ # Handle completion command
765
+ handle_completion() {
766
+ local shell=""
767
+ local show_help=false
768
+
769
+ if [ $# -eq 0 ]; then
770
+ show_help=true
771
+ fi
772
+
773
+ while [[ $# -gt 0 ]]; do
774
+ case "$1" in
775
+ --zsh)
776
+ shell="zsh"
777
+ shift
778
+ ;;
779
+ --bash)
780
+ shell="bash"
781
+ shift
782
+ ;;
783
+ --help|-h)
784
+ show_help=true
785
+ shift
786
+ ;;
787
+ *)
788
+ shift
789
+ ;;
790
+ esac
791
+ done
792
+
793
+ if [ "$show_help" = true ] || [ -z "$shell" ]; then
794
+ printf "${BLUE}Usage:${NC}\n"
795
+ printf " aws-lambda-layer-cli ${GREEN}completion${NC} [options]\n\n"
796
+ printf "${BLUE}Options:${NC}\n"
797
+ printf " ${YELLOW}--zsh${NC} Output zsh completion script\n"
798
+ printf " ${YELLOW}--bash${NC} Output bash completion script\n\n"
799
+ printf "${MAGENTA}${UNDERLINE}Examples:${NC}\n"
800
+ printf " # Load completion in current shell\n"
801
+ printf " source <(aws-lambda-layer-cli ${GREEN}completion${NC} ${YELLOW}--bash${NC})\n\n"
802
+ printf " # Add to .zshrc\n"
803
+ printf " aws-lambda-layer-cli ${GREEN}completion${NC} ${YELLOW}--zsh${NC} >> ~/.zshrc\n"
804
+ return 0
805
+ fi
806
+
807
+ # Find completion directory
808
+ # If running from source: ../completion
809
+ # If installed: $INSTALL_DIR/completion
810
+ local completion_dir=""
811
+ if [ -d "$SCRIPT_DIR/../completion" ]; then
812
+ completion_dir="$SCRIPT_DIR/../completion"
813
+ elif [ -d "$INSTALL_DIR/completion" ]; then
814
+ completion_dir="$INSTALL_DIR/completion"
815
+ else
816
+ printf "${RED}Error: Completion directory not found${NC}\n" >&2
817
+ return 1
818
+ fi
819
+
820
+ if [ "$shell" = "zsh" ]; then
821
+ local file="$completion_dir/aws-lambda-layer-completion.zsh"
822
+ if [ -f "$file" ]; then
823
+ # Remove the auto-execution line if present
824
+ sed 's/_aws-lambda-layer "\$@"//g' "$file"
825
+ printf "\n# Register completion\n"
826
+ printf "if type compdef &>/dev/null; then\n"
827
+ printf " compdef _aws-lambda-layer aws-lambda-layer\n"
828
+ printf "fi\n"
829
+ else
830
+ printf "${RED}Error: Completion script not found for zsh${NC}\n" >&2
831
+ return 1
832
+ fi
833
+ else
834
+ local file="$completion_dir/aws-lambda-layer-completion.bash"
835
+ if [ -f "$file" ]; then
836
+ cat "$file"
837
+ else
838
+ printf "${RED}Error: Completion script not found for bash${NC}\n" >&2
839
+ return 1
840
+ fi
841
+ fi
842
+ }
843
+
756
844
  # Function to convert file paths for compatibility across environments
757
845
  convert_path() {
758
846
  local input_path="$1"
@@ -786,6 +874,25 @@ convert_path() {
786
874
  esac
787
875
  }
788
876
 
877
+ # Handle uninstall
878
+ handle_uninstall() {
879
+ local uninstall_script="$SCRIPT_DIR/uninstall.sh"
880
+
881
+ # Check if uninstall script exists in script dir
882
+ if [ ! -f "$uninstall_script" ]; then
883
+ # Check install dir
884
+ uninstall_script="$INSTALL_DIR/uninstall.sh"
885
+ fi
886
+
887
+ if [ -f "$uninstall_script" ]; then
888
+ exec "$uninstall_script" "$@"
889
+ else
890
+ printf "${RED}Error: Uninstall script not found${NC}\n" >&2
891
+ printf "Please run the uninstall script manually or remove the installation directory.\n" >&2
892
+ exit 1
893
+ fi
894
+ }
895
+
789
896
  # Main command parsing
790
897
  main() {
791
898
  if [ $# -eq 0 ]; then
@@ -802,6 +909,14 @@ main() {
802
909
  shift
803
910
  handle_publish "$@"
804
911
  ;;
912
+ uninstall)
913
+ shift
914
+ handle_uninstall "$@"
915
+ ;;
916
+ completion)
917
+ shift
918
+ handle_completion "$@"
919
+ ;;
805
920
  help|--help|-h)
806
921
  show_help
807
922
  ;;
@@ -809,9 +924,9 @@ main() {
809
924
  show_version
810
925
  ;;
811
926
  *)
812
- printf "${RED}Error: Unknown command '$1'${NC}\n"
813
- printf "Available commands: zip, publish\n"
814
- printf "Use --help for more information\n"
927
+ printf "${RED}Error: Unknown command '$1'${NC}\n" >&2
928
+ printf "Available commands: zip, publish\n" >&2
929
+ printf "Use --help for more information\n" >&2
815
930
  exit 1
816
931
  ;;
817
932
  esac
@@ -5,6 +5,7 @@ set -e
5
5
  BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
6
6
  BUILD_DIR="$BASE_DIR/aws_lambda_layer_cli"
7
7
  ASSETS_DIR="$BUILD_DIR/assets"
8
+ COMPLETION_DIR="$BUILD_DIR/completion"
8
9
 
9
10
  echo "Preparing PyPI package structure..."
10
11
 
@@ -13,6 +14,7 @@ rm -rf "$BUILD_DIR" "$BASE_DIR/dist" "$BASE_DIR/build" "$BASE_DIR/aws_lambda_lay
13
14
 
14
15
  # Create package directories
15
16
  mkdir -p "$ASSETS_DIR"
17
+ mkdir -p "$COMPLETION_DIR"
16
18
 
17
19
  # Copy Python package files
18
20
  cp "$BASE_DIR/scripts/pypi_resources/__init__.py" "$BUILD_DIR/"
@@ -20,18 +22,24 @@ cp "$BASE_DIR/scripts/pypi_resources/cli.py" "$BUILD_DIR/"
20
22
  cp "$BASE_DIR/VERSION.txt" "$BUILD_DIR/"
21
23
 
22
24
  # Copy assets (bash scripts)
23
- cp "$BASE_DIR/scripts/aws-lambda-layer" "$ASSETS_DIR/"
25
+ cp "$BASE_DIR/scripts/aws-lambda-layer-cli" "$ASSETS_DIR/"
24
26
  cp "$BASE_DIR/scripts/create_nodejs_layer.sh" "$ASSETS_DIR/"
25
27
  cp "$BASE_DIR/scripts/create_python_layer.sh" "$ASSETS_DIR/"
28
+ cp "$BASE_DIR/scripts/uninstall.sh" "$ASSETS_DIR/"
26
29
 
27
- # Create __init__.py for assets package
30
+ # Copy completion files
31
+ cp "$BASE_DIR/completion/aws-lambda-layer-completion.bash" "$COMPLETION_DIR/"
32
+ cp "$BASE_DIR/completion/aws-lambda-layer-completion.zsh" "$COMPLETION_DIR/"
33
+
34
+ # Create __init__.py for assets and completion packages
28
35
  touch "$ASSETS_DIR/__init__.py"
36
+ touch "$COMPLETION_DIR/__init__.py"
29
37
 
30
38
  echo "Building PyPI package..."
31
39
  cd "$BASE_DIR"
32
40
  python3 -m build
33
41
 
34
42
  echo "Cleaning up temporary package files..."
35
- rm -rf "$BUILD_DIR" "$BASE_DIR/aws_lambda_layer_cli.egg-info" "$BASE_DIR/build"
43
+ # rm -rf "$BUILD_DIR" "$BASE_DIR/aws_lambda_layer_cli.egg-info" "$BASE_DIR/build"
36
44
 
37
45
  echo "Build complete! Artifacts are in dist/"
@@ -3,32 +3,70 @@ const { execSync } = require('child_process');
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const os = require('os');
6
+ const readline = require('readline');
6
7
 
7
- try {
8
- const isWindows = os.platform() === 'win32';
9
- const scriptPath = isWindows ? path.join('scripts', 'install.ps1') : path.join('scripts', 'install.sh');
10
- const fullPath = path.join(__dirname, '..', scriptPath);
8
+ const isWindows = os.platform() === 'win32';
9
+ const scriptPath = isWindows ? path.join('scripts', 'install.ps1') : path.join('scripts', 'install.sh');
10
+ const fullPath = path.join(__dirname, '..', scriptPath);
11
11
 
12
- if (!fs.existsSync(fullPath)) {
13
- console.error(`Installation script not found: ${fullPath}`);
12
+ if (!fs.existsSync(fullPath)) {
13
+ console.error(`Installation script not found: ${fullPath}`);
14
+ process.exit(1);
15
+ }
16
+
17
+ function runInstall(useSudo) {
18
+ try {
19
+ const cmd = useSudo ? `sudo bash "${fullPath}"` : `bash "${fullPath}"`;
20
+ execSync(cmd, { stdio: 'inherit' });
21
+ console.log('✓ Installation completed successfully');
22
+ process.exit(0);
23
+ } catch (error) {
24
+ console.error('✗ Installation failed:', error.message);
14
25
  process.exit(1);
15
26
  }
27
+ }
16
28
 
17
- if (isWindows) {
18
- // Run PowerShell script with proper execution policy
29
+ if (isWindows) {
30
+ try {
19
31
  execSync(`powershell -ExecutionPolicy Bypass -File "${fullPath}"`, {
20
32
  stdio: 'inherit',
21
33
  shell: true
22
34
  });
35
+ console.log('✓ Installation completed successfully');
36
+ } catch (error) {
37
+ console.error('✗ Installation failed:', error.message);
38
+ process.exit(1);
39
+ }
40
+ } else {
41
+ const isRoot = process.getuid && process.getuid() === 0;
42
+
43
+ if (isRoot) {
44
+ console.log('Running installation with root privileges...');
45
+ runInstall(false);
23
46
  } else {
24
- // Run bash script
25
- execSync(`bash "${fullPath}"`, {
26
- stdio: 'inherit'
47
+ console.log('Installation requires root privileges for system-wide components...');
48
+ // Check if interactive
49
+ if (!process.stdin.isTTY) {
50
+ console.log('Non-interactive environment detected. Skipping system-wide installation steps requiring sudo.');
51
+ process.exit(0);
52
+ }
53
+
54
+ const rl = readline.createInterface({
55
+ input: process.stdin,
56
+ output: process.stdout
57
+ });
58
+
59
+ console.log('\nThis package includes optional system-wide components (shell completion, helper scripts).');
60
+ console.log('Installing them requires root privileges (sudo).');
61
+
62
+ rl.question('Do you want to install these components? [y/N] ', (answer) => {
63
+ rl.close();
64
+ if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
65
+ runInstall(true);
66
+ } else {
67
+ console.log('Skipping system-wide installation.');
68
+ process.exit(0);
69
+ }
27
70
  });
28
71
  }
29
-
30
- console.log('✓ Installation completed successfully');
31
- } catch (error) {
32
- console.error('✗ Installation failed:', error.message);
33
- process.exit(1);
34
72
  }