11#! /usr/bin/env bash
22
3+ # -------------------------------------------------------------------------------#
34# #Requires: coreutils + curl
4-
55# #Usage
66# bash <(curl -qfsSL "https://raw.githubusercontent.com/pkgforge/devscripts/main/Linux/install_bins_curl.sh")
77# #Vars
88# INSTALL_DIR="/tmp" "${other vars}" bash <(curl -qfsSL "https://raw.githubusercontent.com/pkgforge/devscripts/main/Linux/install_bins_curl.sh")
9+ # -------------------------------------------------------------------------------#
910
1011# -------------------------------------------------------------------------------#
1112if [[ " ${DEBUG} " = " 1" ]] || [[ " ${DEBUG} " = " ON" ]]; then
2122declare -a PARALLEL_PIDS=()
2223declare -A INSTALL_STATUS=()
2324MAX_PARALLEL_JOBS=${MAX_PARALLEL_JOBS:- 10}
25+ # -------------------------------------------------------------------------------#
26+
27+ # -------------------------------------------------------------------------------#
28+ # Signal handling for immediate exit
29+ cleanup_on_exit () {
30+ local exit_code=${1:- 130}
31+ # echo -e "\n[!] Interrupted! Cleaning up background processes..."
32+
33+ # Kill all background jobs from this script
34+ if [[ ${# PARALLEL_PIDS[@]} -gt 0 ]]; then
35+ echo " [!] Terminating ${# PARALLEL_PIDS[@]} background jobs..."
36+ for pid in " ${PARALLEL_PIDS[@]} " ; do
37+ if kill -0 " ${pid} " 2> /dev/null; then
38+ kill -TERM " ${pid} " 2> /dev/null || true
39+ fi
40+ done
41+
42+ # Give processes a moment to terminate gracefully
43+ sleep 0.5
44+
45+ # Force kill any remaining processes
46+ for pid in " ${PARALLEL_PIDS[@]} " ; do
47+ if kill -0 " ${pid} " 2> /dev/null; then
48+ kill -KILL " ${pid} " 2> /dev/null || true
49+ fi
50+ done
51+ fi
52+
53+ # Clean up temporary files
54+ rm -f " /tmp/symlinks_$$ " 2> /dev/null || true
55+ rm -f " /tmp/install_dirs_$$ .lock" 2> /dev/null || true
56+
57+ # Kill any curl processes that might be hanging
58+ pkill -f " curl.*bin\.pkgforge\.dev" 2> /dev/null || true
59+
60+ # echo "[!] Cleanup completed. Exiting..."
61+ exit ${exit_code}
62+ }
63+
64+ # Set up signal traps
65+ trap ' cleanup_on_exit 130' SIGINT SIGTERM
66+ trap ' cleanup_on_exit 1' EXIT
67+ # -------------------------------------------------------------------------------#
2468
69+ # -------------------------------------------------------------------------------#
2570# Setup directories and permissions
2671setup_dirs () {
2772 # Check if running as root or have passwordless sudo
@@ -81,7 +126,9 @@ setup_dirs() {
81126 ) 200> " ${temp_lock} "
82127 rm -f " ${temp_lock} " 2> /dev/null || true
83128}
129+ # -------------------------------------------------------------------------------#
84130
131+ # -------------------------------------------------------------------------------#
85132# Setup source URL based on architecture
86133setup_source () {
87134 if [[ -z ${INSTALL_SRC:- } ]]; then
@@ -101,7 +148,9 @@ setup_source() {
101148 echo -e " \n[+] Using Bins from (Specified) :: ${INSTALL_SRC} \n"
102149 fi
103150}
151+ # -------------------------------------------------------------------------------#
104152
153+ # -------------------------------------------------------------------------------#
105154# Setup parallel execution strategy
106155setup_strategy () {
107156 if [[ ${PARALLEL:- 0} == " 1" ]]; then
@@ -112,7 +161,9 @@ setup_strategy() {
112161 echo -e " \n[+] Installing in Sequential (Slow) Mode [Re Run : export PARALLEL=1 for Speed]\n"
113162 fi
114163}
164+ # -------------------------------------------------------------------------------#
115165
166+ # -------------------------------------------------------------------------------#
116167# Wait for background jobs to complete and manage job limit
117168wait_for_jobs () {
118169 local max_jobs=${1:- ${MAX_PARALLEL_JOBS} }
@@ -133,23 +184,37 @@ wait_for_jobs() {
133184 fi
134185 done
135186}
187+ # -------------------------------------------------------------------------------#
136188
189+ # -------------------------------------------------------------------------------#
137190# Wait for all background jobs to complete
138191wait_all_jobs () {
139192 echo " [+] Waiting for all downloads to complete..."
140193 for pid in " ${PARALLEL_PIDS[@]} " ; do
194+ # Check if we're being interrupted
195+ if ! kill -0 " ${pid} " 2> /dev/null; then
196+ continue
197+ fi
141198 wait " ${pid} " 2> /dev/null || true
142199 done
143200 PARALLEL_PIDS=()
144201}
202+ # -------------------------------------------------------------------------------#
145203
204+ # -------------------------------------------------------------------------------#
146205# Install binary to single location
147206install_bin () {
148207 local src_name=" ${1} "
149208 local dest_dir=" ${2} "
150209 local dest_name=" ${3:- ${1} } "
151210
152- if eval " ${INSTALL_PRE} " " ${INSTALL_SRC} /${src_name} " -o " ${dest_dir} /${dest_name} " ; then
211+ # Add timeout to curl commands to prevent hanging
212+ local install_cmd=" ${INSTALL_PRE} "
213+ if [[ ! ${install_cmd} =~ timeout ]]; then
214+ install_cmd=" timeout -k 30s 120s ${install_cmd} "
215+ fi
216+
217+ if eval " ${install_cmd} " " ${INSTALL_SRC} /${src_name} " -o " ${dest_dir} /${dest_name} " ; then
153218 eval " ${INSTALL_POST} " " ${dest_dir} /${dest_name} "
154219 INSTALL_STATUS[" ${src_name} " ]=" success"
155220 return 0
@@ -159,7 +224,9 @@ install_bin() {
159224 return 1
160225 fi
161226}
227+ # -------------------------------------------------------------------------------#
162228
229+ # -------------------------------------------------------------------------------#
163230# Parallel wrapper for install_bin
164231install_bin_parallel () {
165232 local src_name=" ${1} "
@@ -169,14 +236,19 @@ install_bin_parallel() {
169236 if [[ ${USE_PARALLEL} == " 1" ]]; then
170237 wait_for_jobs " ${MAX_PARALLEL_JOBS} "
171238 (
239+ # Set up signal handling in subshell
240+ trap ' exit 130' SIGINT SIGTERM
172241 install_bin " ${src_name} " " ${dest_dir} " " ${dest_name} "
173242 ) &
174- PARALLEL_PIDS+=($! )
243+ local bg_pid=$!
244+ PARALLEL_PIDS+=(" ${bg_pid} " )
175245 else
176246 install_bin " ${src_name} " " ${dest_dir} " " ${dest_name} "
177247 fi
178248}
249+ # -------------------------------------------------------------------------------#
179250
251+ # -------------------------------------------------------------------------------#
180252# Create symlink for binary (with file existence check)
181253symlink_bin () {
182254 local target_path=" ${1} "
@@ -204,7 +276,9 @@ symlink_bin() {
204276 return 1
205277 fi
206278}
279+ # -------------------------------------------------------------------------------#
207280
281+ # -------------------------------------------------------------------------------#
208282# Install binary to multiple locations with symlinks
209283install_bin_multi () {
210284 local src_name=" ${1} "
@@ -221,7 +295,9 @@ install_bin_multi() {
221295 echo " ${INSTALL_DIR} /${dest_name} :${INSTALL_DIR_LOCALH} /${dest_name} " >> " /tmp/symlinks_$$ "
222296 fi
223297}
298+ # -------------------------------------------------------------------------------#
224299
300+ # -------------------------------------------------------------------------------#
225301# Create all symlinks after downloads complete
226302create_symlinks () {
227303 if [[ -f " /tmp/symlinks_$$ " ]]; then
@@ -235,7 +311,9 @@ create_symlinks() {
235311 rm -f " /tmp/symlinks_$$ "
236312 fi
237313}
314+ # -------------------------------------------------------------------------------#
238315
316+ # -------------------------------------------------------------------------------#
239317# Main installation function
240318install_all_bins () {
241319 local bins=(
@@ -400,7 +478,9 @@ install_all_bins() {
400478 echo -e " \n[!] Failed to install: ${failed_list[*]} "
401479 fi
402480}
481+ # -------------------------------------------------------------------------------#
403482
483+ # -------------------------------------------------------------------------------#
404484# Main execution
405485main () {
406486 setup_dirs
@@ -450,7 +530,15 @@ main() {
450530
451531 # Cleanup
452532 rm -f " /tmp/symlinks_$$ " 2> /dev/null || true
533+
534+ # Remove the EXIT trap since we completed successfully
535+ trap - EXIT
453536}
537+ # -------------------------------------------------------------------------------#
454538
539+ # -------------------------------------------------------------------------------#
455540# Execute main function
456- main " $@ "
541+ if [[ " ${BASH_SOURCE[0]} " == " ${0} " ]]; then
542+ main " $@ "
543+ fi
544+ # -------------------------------------------------------------------------------#
0 commit comments