1
+ #! /bin/sh
2
+
3
+ # ================================================================#
4
+ # GitSSH Auto-Installer
5
+ # Automatically clones and installs GitSSH from GitHub
6
+ # POSIX Compliant - Fixed for curl | sh usage
7
+ # ================================================================#
8
+
9
+ set -e # Exit on any error
10
+
11
+ # Configuration
12
+ REPO_URL=" https://github.com/gitssh-cli/gitssh"
13
+ TEMP_DIR=" /tmp/gitssh-install-$$ "
14
+ INSTALL_DIR=" $TEMP_DIR /gitssh"
15
+
16
+ # ================================================================#
17
+ # UTILITY FUNCTIONS
18
+ # ================================================================#
19
+
20
+ show_banner () {
21
+ cat << 'EOF '
22
+ ╔═══════════════════════════════════════════════════════════════╗
23
+ ║ ║
24
+ ║ ██████╗ ███████╗███████╗██╗ ██╗ ║
25
+ ║ ██╔════╝ ██╗ ██╗ ██╔════╝██╔════╝██║ ██║ ║
26
+ ║ ██║ ███╗══╝████║███████╗███████╗███████║ ║
27
+ ║ ██║ ██║██║ ██║ ╚════██║╚════██║██╔══██║ ║
28
+ ║ ██████╔╝██║ ██║ ███████║███████║██║ ██║ ║
29
+ ║ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝v0.1.0-Oz ║
30
+ ║ <-POSIX Compliant-> ║
31
+ ║ ║
32
+ ╚═══════════════════════════════════════════════════════════════╝
33
+ Manage Multiple SSH Git and GitHub Account Sessions With Ease!
34
+
35
+ EOF
36
+ }
37
+
38
+ show_progress () {
39
+ current=" $1 "
40
+ total=" $2 "
41
+ message=" $3 "
42
+ width=50
43
+
44
+ # POSIX arithmetic
45
+ percentage=$(( current * 100 / total))
46
+ filled=$(( current * width / total))
47
+ empty=$(( width - filled))
48
+
49
+ printf " \r\033[0;34m[\033[0m"
50
+
51
+ # Print filled portion
52
+ i=0
53
+ while [ $i -lt $filled ]; do
54
+ printf " █"
55
+ i=$(( i + 1 ))
56
+ done
57
+
58
+ # Print empty portion
59
+ i=0
60
+ while [ $i -lt $empty ]; do
61
+ printf " "
62
+ i=$(( i + 1 ))
63
+ done
64
+
65
+ printf " \033[0;34m] %d%% - %s\033[0m" " $percentage " " $message "
66
+
67
+ if [ " $current " -eq " $total " ]; then
68
+ printf " \n"
69
+ fi
70
+ }
71
+
72
+ log_info () {
73
+ printf " \033[0;34m[INFO]\033[0m %s\n" " $1 "
74
+ }
75
+
76
+ log_success () {
77
+ printf " \033[0;32m[SUCCESS]\033[0m %s\n" " $1 "
78
+ }
79
+
80
+ log_error () {
81
+ printf " \033[0;31m[ERROR]\033[0m %s\n" " $1 " >&2
82
+ }
83
+
84
+ log_warning () {
85
+ printf " \033[1;33m[WARNING]\033[0m %s\n" " $1 "
86
+ }
87
+
88
+ cleanup_on_error () {
89
+ if [ -d " $TEMP_DIR " ]; then
90
+ log_info " Cleaning up temporary files due to error..."
91
+ rm -rf " $TEMP_DIR "
92
+ fi
93
+ }
94
+
95
+ cleanup_final () {
96
+ if [ -d " $TEMP_DIR " ]; then
97
+ log_info " Cleaning up temporary files..."
98
+ rm -rf " $TEMP_DIR "
99
+ fi
100
+ }
101
+
102
+ check_dependencies () {
103
+ missing_deps=" "
104
+
105
+ # Check for git
106
+ if ! command -v git > /dev/null 2>&1 ; then
107
+ missing_deps=" $missing_deps git"
108
+ fi
109
+
110
+ # Check for chmod
111
+ if ! command -v chmod > /dev/null 2>&1 ; then
112
+ missing_deps=" $missing_deps chmod"
113
+ fi
114
+
115
+ if [ -n " $missing_deps " ]; then
116
+ log_error " Missing required dependencies:$missing_deps "
117
+ log_error " Please install them and try again."
118
+ exit 1
119
+ fi
120
+ }
121
+
122
+ # POSIX Compliant sleep alternative using read with timeout where available
123
+ posix_sleep () {
124
+ duration=" $1 "
125
+ # Try different sleep methods
126
+ if command -v sleep > /dev/null 2>&1 ; then
127
+ sleep " $duration "
128
+ elif command -v ping > /dev/null 2>&1 ; then
129
+ # Use ping as timer (works on most systems)
130
+ ping -c 1 -W " ${duration} 000" 127.0.0.1 > /dev/null 2>&1 || true
131
+ else
132
+ # Fallback: busy wait (not ideal but POSIX Compliant)
133
+ start_time=$( date +%s)
134
+ while [ $(( $(date +% s) - start_time)) -lt " $duration " ]; do
135
+ continue
136
+ done
137
+ fi
138
+ }
139
+
140
+ # Function to detect if we're running via pipe (curl | sh)
141
+ is_piped_execution () {
142
+ # Check if stdin is a pipe
143
+ [ ! -t 0 ]
144
+ }
145
+
146
+ # Function to read user input that works with both direct execution and piped execution
147
+ read_user_input () {
148
+ printf " \033[1;33mContinue anyway? (y/N): \033[0m"
149
+
150
+ if is_piped_execution; then
151
+ # When piped, read from terminal directly via /dev/tty
152
+ if [ -r /dev/tty ]; then
153
+ read response < /dev/tty
154
+ else
155
+ # If /dev/tty is not available, try other methods
156
+ if command -v tty > /dev/null 2>&1 ; then
157
+ tty_device=$( tty)
158
+ if [ " $tty_device " != " not a tty" ] && [ -r " $tty_device " ]; then
159
+ read response < " $tty_device "
160
+ else
161
+ # Fallback: assume 'y' for automated environments
162
+ log_warning " No terminal available, proceeding automatically..."
163
+ response=" y"
164
+ fi
165
+ else
166
+ # Final fallback
167
+ log_warning " No terminal available, proceeding automatically..."
168
+ response=" y"
169
+ fi
170
+ fi
171
+ else
172
+ # Normal execution - read from stdin
173
+ read response
174
+ fi
175
+
176
+ echo " $response "
177
+ }
178
+
179
+ # Function to wait for user confirmation that works with piped execution
180
+ wait_for_confirmation () {
181
+ if is_piped_execution; then
182
+ # When piped, read from terminal directly
183
+ printf " \033[1;33mPress Enter to continue with installation...\033[0m"
184
+ if [ -r /dev/tty ]; then
185
+ # Read a single line from the terminal
186
+ head -n 1 < /dev/tty > /dev/null
187
+ else
188
+ # If no terminal available, add a short delay and continue
189
+ log_warning " No terminal available for confirmation, continuing automatically..."
190
+ posix_sleep 2
191
+ fi
192
+ else
193
+ # Normal execution
194
+ printf " \033[1;33mPress Enter to continue with installation...\033[0m"
195
+ read dummy
196
+ fi
197
+ }
198
+
199
+ # ================================================================#
200
+ # MAIN INSTALLATION PROCESS
201
+ # ================================================================#
202
+
203
+ main () {
204
+ # Set up cleanup trap ONLY for errors and interrupts (not normal exit)
205
+ trap cleanup_on_error INT TERM
206
+
207
+ # Show banner
208
+ show_banner
209
+
210
+ # Check dependencies
211
+ log_info " Checking system dependencies..."
212
+ check_dependencies
213
+ show_progress 1 6 " Dependencies checked"
214
+ posix_sleep 1
215
+
216
+ # Create temporary directory
217
+ log_info " Creating temporary directory..."
218
+ mkdir -p " $TEMP_DIR "
219
+ show_progress 2 6 " Temporary directory created"
220
+ posix_sleep 1
221
+
222
+ # Clone repository
223
+ log_info " Cloning GitSSH repository..."
224
+ if git clone " $REPO_URL " " $INSTALL_DIR " > /dev/null 2>&1 ; then
225
+ show_progress 3 6 " Repository cloned successfully"
226
+ else
227
+ show_progress 3 6 " Repository clone failed"
228
+ log_error " Failed to clone repository from $REPO_URL "
229
+ log_error " Please check your internet connection and try again."
230
+ cleanup_on_error
231
+ exit 1
232
+ fi
233
+ posix_sleep 1
234
+
235
+ # Change to install directory
236
+ log_info " Entering installation directory..."
237
+ cd " $INSTALL_DIR "
238
+ show_progress 4 6 " Changed to install directory"
239
+ posix_sleep 1
240
+
241
+ # Make install script executable
242
+ log_info " Making install script executable..."
243
+ if [ -f " install" ]; then
244
+ chmod +x install
245
+ show_progress 5 6 " Install script made executable"
246
+ else
247
+ show_progress 5 6 " Install script not found"
248
+ log_error " Install script not found in repository"
249
+ log_error " Expected file: $INSTALL_DIR /install"
250
+ cleanup_on_error
251
+ exit 1
252
+ fi
253
+ posix_sleep 1
254
+
255
+ # Complete preparation
256
+ show_progress 6 6 " Installation preparation complete"
257
+ printf " \n"
258
+
259
+ # Run installer
260
+ log_success " Repository downloaded and prepared successfully!"
261
+ printf " \n"
262
+ log_info " Starting GitSSH installation..."
263
+
264
+ # Use the new confirmation function that handles piped execution
265
+ wait_for_confirmation
266
+
267
+ # Clear the trap before running installer (so installer can manage its own cleanup)
268
+ trap - INT TERM
269
+
270
+ # Execute the install script with proper stdin handling
271
+ if is_piped_execution; then
272
+ # When script was piped, we need to ensure the install script can also access terminal
273
+ if [ -r /dev/tty ]; then
274
+ # Redirect the install script's stdin to the terminal
275
+ ./install < /dev/tty
276
+ else
277
+ # If no terminal, run without interactive input
278
+ log_warning " Running installation in non-interactive mode..."
279
+ ./install
280
+ fi
281
+ else
282
+ # Normal execution
283
+ ./install
284
+ fi
285
+
286
+ # Always cleanup after install script finishes, regardless of outcome
287
+ cleanup_final
288
+ }
289
+
290
+ # ================================================================#
291
+ # ENTRY POINT
292
+ # ================================================================#
293
+
294
+ # Check if running as root (optional warning)
295
+ if [ " $( id -u) " -eq 0 ]; then
296
+ log_warning " Running as root. GitSSH is typically installed for individual users."
297
+
298
+ # Use the new input function that handles piped execution
299
+ response=$( read_user_input)
300
+
301
+ case " $response " in
302
+ [yY]|[yY][eE][sS])
303
+ log_info " Proceeding with root installation..."
304
+ ;;
305
+ * )
306
+ log_info " Installation cancelled."
307
+ exit 0
308
+ ;;
309
+ esac
310
+ fi
311
+
312
+ # Run main installation
313
+ main " $@ "
0 commit comments