@@ -159,14 +159,18 @@ __launchpad_update_path() {
159
159
__launchpad_update_library_paths_fast() {
160
160
local env_dir="$1"
161
161
162
+ # Prevent zsh nomatch warnings inside this function (restores on return)
163
+ if [[ -n "$ZSH_VERSION" ]]; then
164
+ setopt localoptions nonomatch
165
+ fi
166
+
162
167
if [[ ! -d "$env_dir" ]]; then
168
+ # nothing to do
163
169
return 0
164
170
fi
165
171
166
172
# Build library paths from direct lib directories only (fast path)
167
173
local lib_paths=""
168
-
169
- # Add direct lib directories only
170
174
for lib_dir in "$env_dir/lib" "$env_dir/lib64"; do
171
175
if [[ -d "$lib_dir" ]]; then
172
176
if [[ -z "$lib_paths" ]]; then
@@ -177,52 +181,6 @@ __launchpad_update_library_paths_fast() {
177
181
fi
178
182
done
179
183
180
- # Add package-specific library directories with validation
181
- # Only include packages with actual working libraries
182
- # Prioritize source-built packages over pre-built binaries
183
- if [[ -d "$env_dir" ]]; then
184
- # First pass: Add source-built packages (like our PHP) with priority
185
- for domain_dir in "$env_dir"/*.org "$env_dir"/*.net "$env_dir"/*.com "$env_dir"/*.sh "$env_dir"/*.io; do
186
- if [[ -d "$domain_dir" ]]; then
187
- local domain_name=$(basename "$domain_dir")
188
-
189
- # Find version directories and validate they have proper libraries
190
- for version_dir in "$domain_dir"/v*; do
191
- if [[ -d "$version_dir" ]]; then
192
- for lib_subdir in "$version_dir/lib" "$version_dir/lib64"; do
193
- if [[ -d "$lib_subdir" ]]; then
194
- # Validate that this lib directory has actual library files
195
- # Skip if it only contains broken/placeholder files
196
- local has_valid_libs=false
197
-
198
- # Check for common library patterns that indicate a working installation
199
- if [[ -n "$(find "$lib_subdir" -name "*.dylib" -size +100c 2>/dev/null | head -1)" ]] || \
200
- [[ -n "$(find "$lib_subdir" -name "*.so*" -size +100c 2>/dev/null | head -1)" ]] || \
201
- [[ -n "$(find "$lib_subdir" -name "*.a" -size +100c 2>/dev/null | head -1)" ]]; then
202
- has_valid_libs=true
203
- fi
204
-
205
- # Special case: If this is a source-built package (like our PHP), always include it
206
- if [[ "$domain_name" == "php.net" ]] && [[ -f "$version_dir/bin/php" ]]; then
207
- has_valid_libs=true
208
- fi
209
-
210
- # Add to library paths if it has valid libraries
211
- if [[ "$has_valid_libs" == "true" ]]; then
212
- if [[ -z "$lib_paths" ]]; then
213
- lib_paths="$lib_subdir"
214
- else
215
- lib_paths="$lib_paths:$lib_subdir"
216
- fi
217
- fi
218
- fi
219
- done
220
- fi
221
- done
222
- fi
223
- done
224
- fi
225
-
226
184
# Set up library path environment variables if we have paths
227
185
if [[ -n "$lib_paths" ]]; then
228
186
# Store original values if not already stored
@@ -641,53 +599,110 @@ __launchpad_chpwd() {
641
599
return 0
642
600
fi
643
601
602
+ # Avoid zsh glob nomatch errors inside this handler
603
+ if [[ -n "$ZSH_VERSION" ]]; then
604
+ setopt localoptions nonomatch
605
+ fi
606
+
644
607
# Ultra-fast activation: compute environment path and check if ready
645
- local project_hash
646
- project_hash=$(echo -n "$project_dir" | sha256sum 2>/dev/null | cut -d' ' -f1 | cut -c1-8) || project_hash="default"
608
+ # Resolve to physical path and compute MD5 (matches generateProjectHash in dump.ts)
609
+ local real_project_dir
610
+ real_project_dir=$(cd "$project_dir" 2>/dev/null && pwd -P || echo "$project_dir")
611
+ local project_basename
612
+ project_basename=$(basename "$real_project_dir")
613
+ local md5hash
614
+ if command -v md5 >/dev/null 2>&1; then
615
+ md5hash=$(md5 -q -s "$real_project_dir" 2>/dev/null || md5 -q "$real_project_dir" 2>/dev/null)
616
+ fi
617
+ if [[ -z "$md5hash" ]] && command -v md5sum >/dev/null 2>&1; then
618
+ md5hash=$(printf "%s" "$real_project_dir" | md5sum 2>/dev/null | awk '{print $1}')
619
+ fi
620
+ if [[ -z "$md5hash" ]] && command -v openssl >/dev/null 2>&1; then
621
+ md5hash=$(printf "%s" "$real_project_dir" | openssl md5 2>/dev/null | awk '{print $2}')
622
+ fi
623
+ if [[ -z "$md5hash" ]]; then
624
+ md5hash="00000000"
625
+ fi
626
+ local project_hash="\${project_basename}_$(echo "$md5hash" | cut -c1-8)"
647
627
local env_dir="$HOME/.local/share/launchpad/envs/$project_hash"
648
628
649
- # Check persistent cache first (instant activation)
650
- local cache_file="$__launchpad_persistent_cache_dir/env_cache_$(echo -n "$env_dir" | sha256sum 2>/dev/null | cut -d' ' -f1 | cut -c1-16)"
629
+ # Fallback: if md5-based env dir doesn't exist, try to locate legacy env by basename prefix
630
+ if [[ ! -d "$env_dir/bin" ]]; then
631
+ local envs_root="$HOME/.local/share/launchpad/envs"
632
+ if [[ -d "$envs_root" ]]; then
633
+ local found_env=""
634
+ # Iterate safely (no globs) and match prefix
635
+ for candidate in "$envs_root"/*; do
636
+ if [[ -d "$candidate" ]]; then
637
+ local base=$(basename "$candidate")
638
+ case "$base" in
639
+ "\${project_basename}_"*)
640
+ if [[ -d "$candidate/bin" ]]; then
641
+ found_env="$candidate"
642
+ # Prefer one that has .launchpad_ready
643
+ if [[ -f "$candidate/.launchpad_ready" ]]; then
644
+ env_dir="$candidate"
645
+ break
646
+ fi
647
+ fi
648
+ ;;
649
+ esac
650
+ fi
651
+ done
652
+ if [[ -z "$env_dir" || ! -d "$env_dir/bin" ]]; then
653
+ if [[ -n "$found_env" ]]; then
654
+ env_dir="$found_env"
655
+ fi
656
+ fi
657
+ fi
658
+ fi
659
+
660
+ # Persistent cache: check before slow operations
661
+ local cache_file="$__launchpad_persistent_cache_dir/env_cache_$(printf "%s" "$env_dir" | md5sum 2>/dev/null | awk '{print $1}' | cut -c1-16)"
651
662
local current_time=$(date +%s)
652
663
local cache_duration=1800 # 30 minutes for shell integration
653
-
654
- # Use longer cache durations for test environments
664
+ # Use longer cache durations for test/development environments
655
665
if [[ "$project_dir" == *"test"* || "$project_dir" == *"launchpad"* || "$NODE_ENV" == "test" ]]; then
656
666
cache_duration=3600 # 1 hour for test and development environments
657
667
fi
658
-
659
668
if [[ -f "$cache_file" ]]; then
660
669
local cache_file_time=$(stat -c %Y "$cache_file" 2>/dev/null || stat -f %m "$cache_file" 2>/dev/null || echo 0)
661
670
if [[ $((current_time - cache_file_time)) -lt $cache_duration && -d "$env_dir/bin" ]]; then
662
- # Instant activation from persistent cache
671
+ # Instant activation from persistent cache (no filesystem scans)
663
672
export PATH="$env_dir/bin:$LAUNCHPAD_ORIGINAL_PATH"
664
673
__launchpad_update_library_paths_fast "$env_dir"
665
674
__launchpad_ensure_global_path_fast
666
675
__launchpad_ensure_system_path
667
676
hash -r 2>/dev/null || true
668
-
669
- if [[ "\$\{LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } \}" != "false" ]]; then
670
- printf "${ activationMessage } \\n" >&2
677
+ if [[ "\${LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } }" != "false" ]]; then
678
+ printf "${ activationMessage } \n" >&2
671
679
fi
672
680
return 0
673
681
fi
674
682
fi
675
683
684
+ # Check readiness markers explicitly (used by tests and fast path)
685
+ if [[ -d "$env_dir/pkgs" || -f "$env_dir/.launchpad_ready" ]]; then
686
+ __lp_markers_ready=1
687
+ else
688
+ __lp_markers_ready=0
689
+ fi
690
+
676
691
# If environment exists and has binaries, activate quickly
677
692
# use glob expansion which is faster than ls
678
- if [[ -d "$env_dir/bin" ]] && [[ -n $(echo "$env_dir/bin"/*) && $(echo "$env_dir/bin"/*) != "$env_dir/bin/*" ]] && [[ -d "$env_dir/pkgs" || -f "$env_dir/.launchpad_ready " ]]; then
693
+ if [[ -d "$env_dir/bin" ]] && [[ $__lp_markers_ready -eq 1 || $(echo "$env_dir/bin"/*) != "$env_dir/bin/*" ]]; then
679
694
export PATH="$env_dir/bin:$LAUNCHPAD_ORIGINAL_PATH"
680
695
__launchpad_update_library_paths_fast "$env_dir"
681
696
__launchpad_ensure_global_path_fast
682
697
__launchpad_ensure_system_path
683
698
hash -r 2>/dev/null || true
684
699
685
- # Update persistent cache
686
- mkdir -p "$(dirname "$cache_file")" 2>/dev/null
687
- touch "$cache_file" 2>/dev/null
700
+ # Update persistent cache for instant future activation
701
+ mkdir -p "$(dirname "$cache_file")" 2>/dev/null || true
702
+ touch "$cache_file" 2>/dev/null || true
688
703
689
- if [[ "\$\ {LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } \ }" != "false" ]]; then
690
- printf "${ activationMessage } \\ n" >&2
704
+ if [[ "\${LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } }" != "false" ]]; then
705
+ printf "${ activationMessage } \n" >&2
691
706
fi
692
707
return 0
693
708
fi
@@ -696,11 +711,7 @@ __launchpad_chpwd() {
696
711
697
712
# Mark setup as in progress
698
713
__launchpad_setup_in_progress="$project_dir"
699
-
700
- # Show immediate feedback
701
- if [[ "\$\{LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } \}" != "false" ]]; then
702
- printf "🔧 Setting up environment for \\033[3m$(basename "$project_dir")\\033[0m...\\r" >&2
703
- fi
714
+ # Suppress transient progress to keep prompt responsive; only final activation prints
704
715
705
716
# Optimize environment setup with shorter timeout and shell-only mode
706
717
local env_output
@@ -709,17 +720,11 @@ __launchpad_chpwd() {
709
720
# Ensure global dependencies are available first
710
721
__launchpad_setup_global_deps
711
722
712
- # Run environment setup without timeout - let it take as long as needed
723
+ # Run environment setup without timeout - let it take as long as needed
713
724
local temp_file=$(mktemp)
714
725
715
- # Run with real-time progress display - show progress on stderr, capture shell code on stdout
716
- if [[ "\$\{LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } \}" != "false" ]]; then
717
- # Show progress in real-time while capturing output
718
- ${ launchpadBinary } dev "$project_dir" --shell > "$temp_file"
719
- else
720
- # Quiet mode - suppress all output
721
- ${ launchpadBinary } dev "$project_dir" --shell --quiet > "$temp_file" 2>/dev/null
722
- fi
726
+ # Always run shell-mode setup quietly for speed; capture only the shell code
727
+ ${ launchpadBinary } dev "$project_dir" --shell --quiet > "$temp_file" 2>/dev/null
723
728
setup_exit_code=$?
724
729
725
730
# Extract shell code from output
@@ -731,7 +736,7 @@ __launchpad_chpwd() {
731
736
732
737
if [[ $setup_exit_code -eq 130 ]]; then
733
738
# User interrupted with Ctrl+C
734
- if [[ "\$\ {LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } \ }" != "false" ]]; then
739
+ if [[ "\${LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } }" != "false" ]]; then
735
740
printf "\\r\\033[K⚠️ Environment setup cancelled\\n" >&2
736
741
fi
737
742
return 130
@@ -753,11 +758,14 @@ __launchpad_chpwd() {
753
758
# Clear command hash table to ensure commands are found in new PATH
754
759
hash -r 2>/dev/null || true
755
760
756
- # Create persistent cache file for instant future activation
757
- touch "$cache_file" 2>/dev/null
761
+ # Mark environment ready for instant future activation (both cache and marker)
762
+ mkdir -p "$env_dir" 2>/dev/null || true
763
+ touch "$env_dir/.launchpad_ready" 2>/dev/null || true
764
+ mkdir -p "$(dirname "$cache_file")" 2>/dev/null || true
765
+ touch "$cache_file" 2>/dev/null || true
758
766
759
767
# Show clean activation message
760
- if [[ "\$\ {LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } \ }" != "false" ]]; then
768
+ if [[ "\${LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } }" != "false" ]]; then
761
769
printf "\\r\\033[K${ activationMessage } \\n" >&2
762
770
fi
763
771
else
@@ -769,12 +777,12 @@ __launchpad_chpwd() {
769
777
__launchpad_ensure_system_path
770
778
hash -r 2>/dev/null || true
771
779
772
- if [[ "\$\ {LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } \ }" != "false" ]]; then
780
+ if [[ "\${LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } }" != "false" ]]; then
773
781
printf "\\r\\033[K${ activationMessage } \\n" >&2
774
782
fi
775
783
else
776
784
# Clear any progress message on failure
777
- if [[ "\$\ {LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } \ }" != "false" ]]; then
785
+ if [[ "\${LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } }" != "false" ]]; then
778
786
printf "\\r\\033[K" >&2
779
787
fi
780
788
fi
@@ -817,7 +825,7 @@ __launchpad_chpwd() {
817
825
unset LAUNCHPAD_ORIGINAL_LD_LIBRARY_PATH
818
826
819
827
# Show deactivation message
820
- if [[ "\$\ {LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } \ }" != "false" ]]; then
828
+ if [[ "\${LAUNCHPAD_SHOW_ENV_MESSAGES:-${ showMessages } }" != "false" ]]; then
821
829
printf "${ deactivationMessage } \\n" >&2
822
830
fi
823
831
@@ -916,9 +924,7 @@ __launchpad_source_hooks_dir() {
916
924
fi
917
925
}
918
926
919
- # One-time setup on shell initialization
920
- __launchpad_setup_global_deps
921
- __launchpad_ensure_global_path_fast
927
+ # One-time setup on shell initialization (no global setup)
922
928
__launchpad_source_hooks_dir "$HOME/.config/launchpad/hooks/init.d"
923
929
924
930
# Clear command hash table on initial load
0 commit comments