-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRENAME_ME
More file actions
285 lines (240 loc) · 9.56 KB
/
RENAME_ME
File metadata and controls
285 lines (240 loc) · 9.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#!/bin/bash
# --- Configuration ----------------------
APP_NAME="RENAME_ME"
APP_DIR="RENAME_ME"
DOWNLOAD_URL="https://example.com/releases/.../rename-me-latest.tgz"
# ----------------------------------------
# Should we install the wrapper scripts into the user's shared bin directory?
INSTALL_BIN=no
# Do we enable the install feature? (ie passing the single argument '__INSTALL' to this script)
ENABLE_INSTALL=yes
# Do we enable the uninstall feature? (ie passing the single argument '__UNINSTALL' to this script)
ENABLE_UNINSTALL=yes
# The update period in days (e.g., 3 means check if the last_checked file is older than 3 days)
UPDATE_PERIOD=3
# Logging level (0-ERROR, 1-WARN, 2-INFO, 3-DEBUG, empty disables logging)
LOG_LEVEL=1
# ----------------------------------------
HOME_DIR="$HOME"
SHARED_BIN="$HOME_DIR/.local/bin"
# Function to load configuration variables from a file
function load_config() {
local config_file="$1"
if [ -f "$config_file" ]; then
#LOG "Loading configuration from $config_file..."
source "$config_file" 2>/dev/null
fi
}
# Helper functions for logging
function LOG_ERROR() {
if [[ -n "$LOG_LEVEL" && "0" -le "$LOG_LEVEL" ]]; then
echo "\033[31mERROR\033[0m: $1"
fi
}
function LOG_WARN() {
if [[ -n "$LOG_LEVEL" && "1" -le "$LOG_LEVEL" ]]; then
echo -e "[\033[33m$APPNM WARN\033[0m] $1"
fi
}
function LOG_INFO() {
if [[ -n "$LOG_LEVEL" && "2" -le "$LOG_LEVEL" ]]; then
echo "[$APPNM INFO] $1"
fi
}
# --- Core Logic Functions ---
function install_bin() {
# Copy application script(s) to shared bin
LOG_INFO "Making application available in shared bin directory: $SHARED_BIN"
mkdir -p "$SHARED_BIN"
# We always copy the Bash script (it should exist), even on Windows
cp -a "$APP_SCRIPT" "$SHARED_BIN/$APPNM"
if [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]]; then
# On Windows we also copy the batch file (if it exists)
if [[ -f "$APP_SCRIPT.cmd" ]]; then
cp -a "$APP_SCRIPT.cmd" "$SHARED_BIN/$APPNM.cmd"
fi
fi
# Warn user when the app is not available in their PATH
if [ ! -x "$(command -v "$APPNM")" ]; then
LOG_WARN "'$SHARED_BIN' is not in your PATH. You may want to add it to run '$APPNM' from anywhere."
fi
}
function unpack_and_install() {
# Unpack and clean up
LOG_INFO "Unpacking application..."
# Remove existing installation directory if it exists before unpacking
rm -rf "$TMP_DIR"
# Create a temporary directory for unpacking
mkdir -p "$TMP_DIR"
if ! tar -xzf "$ARCHIVE_FILE" -C "$TMP_DIR"; then
LOG_ERROR "Failed to unpack archive $ARCHIVE_FILE"
rm -rf "$TMP_DIR"
return 1
fi
# Move all contents of temp_install to NEW_DIR
LOG_INFO "Moving contents to $HAP_DIR"
mkdir -p "$APP_HOME"
mv "$TMP_DIR" "$NEW_DIR"
# Replace the old app directory with the new one atomically
mv "$HAP_DIR" "$BAK_DIR" 2>/dev/null || true
mv "$NEW_DIR" "$HAP_DIR"
rm -rf "$BAK_DIR"
# Let's make sure the application script is executable
if [[ -f "$APP_SCRIPT" ]]; then
chmod +x "$APP_SCRIPT" 2>/dev/null || true
fi
if [[ "$INSTALL_BIN" == "yes" ]]; then
install_bin
fi
# Clean up the temporary directory
rm -rf "$TMP_DIR"
# Create/update the last_checked file
touch "$LAST_CHECKED_FILE"
LOG_INFO "Installation complete in $APP_HOME"
}
function download_and_install() {
# Check file age: older than $UPDATE_PERIOD days?
# find command exits 0 and prints if a file matching criteria is found.
# -mtime +N means modification time is older than N full 24-hour periods.
if [ ! -f "$LAST_CHECKED_FILE" ] || [ -n "$(find "$LAST_CHECKED_FILE" -mtime +$UPDATE_PERIOD -print -quit 2>/dev/null)" ]; then
LOG_INFO "Checking for updates [last check older than $UPDATE_PERIOD days or file missing]..."
# Setup directories
mkdir -p "$CCH_DIR" || { LOG_ERROR "Could not create cache directory $CCH_DIR"; return 1; }
# Conditional Download
# -z "$ARCHIVE_FILE" tells curl to only download if the remote file is newer than the local one.
# --remote-time (-r) ensures the new file uses the remote timestamp.
# Use -w "%{http_code}" to capture the status code
HTTP_CODE=$(curl -w "%{http_code}" -sSL --remote-time -z "$ARCHIVE_FILE" "$DLURL" -o "$ARCHIVE_FILE")
LOG_INFO "Received HTTP code: $HTTP_CODE"
# Check for successful download (HTTP 200) or successful conditional skip (HTTP 304 Not Modified)
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
# Download successful
LOG_INFO "New release downloaded"
# Unpack the new release
unpack_and_install
return $?
elif [ "$HTTP_CODE" -eq 304 ]; then
# Conditional download skipped (304 Not Modified)
LOG_INFO "No new release available [304 Not Modified]"
else
# Other error or redirection
LOG_INFO "Conditional download failed or returned unexpected status code: $HTTP_CODE. Skipping update"
return 1
fi
# Update last_checked timestamp regardless of success/failure of the update attempt
touch "$LAST_CHECKED_FILE"
LOG_INFO "Download/update check complete"
else
LOG_INFO "Skipping update check [last check within $UPDATE_PERIOD days]"
fi
}
function install_app() {
LOG_INFO "Check for executable $APP_SCRIPT"
if [ ! -f "$APP_SCRIPT" ]; then
LOG_INFO "Application not found. Starting download and install..."
download_and_install
if [[ $? -ne 0 ]]; then
LOG_ERROR "Installation of application failed!"
exit 1
fi
else
LOG_INFO "Application found. Check if there is an update to install..."
download_and_install
fi
}
function uninstall_app() {
LOG_INFO "Uninstalling application $APPNM..."
# Remove APP_HOME/bootstrap
rm -rf "$HAP_DIR" 2>/dev/null || true
# Remove APP_HOME if it's now empty
rmdir "$APP_HOME" 2>/dev/null || true
# Remove the application's cache folder entirely
rm -rf "$CACHE_HOME" 2>/dev/null || true
# Remove shared bin scripts if installed
if [[ "$INSTALL_BIN" == "yes" ]]; then
rm -f "$SHARED_BIN/$APPNM" 2>/dev/null || true
rm -f "$SHARED_BIN/$APPNM.cmd" 2>/dev/null || true
fi
LOG_INFO "Uninstallation complete."
}
function perform() {
local action="$1"
local APPNM="$2"
local APPDR="$3"
local DLURL="$4"
# Define essential directories
APP_HOME="$HOME_DIR/.local/share/$APPDR"
CONFIG_HOME="$HOME_DIR/.config/$APPDR"
CACHE_HOME="$HOME_DIR/.cache/$APPDR"
# Load user-wide configuration (if exists)
load_config "$CONFIG_HOME/bootstrap.cfg"
# Load local configuration (if exists)
load_config "./.$APPDR/bootstrap.cfg"
# INSTALL_BIN can be overridden by the user environment variable BS_INSTALL_BIN
INSTALL_BIN=${BS_INSTALL_BIN:-$INSTALL_BIN}
# ENABLE_INSTALL can be overridden by the user environment variable BS_ENABLE_INSTALL
ENABLE_INSTALL=${BS_ENABLE_INSTALL:-$ENABLE_INSTALL}
# ENABLE_UNINSTALL can be overridden by the user environment variable BS_ENABLE_UNINSTALL
ENABLE_UNINSTALL=${BS_ENABLE_UNINSTALL:-$ENABLE_UNINSTALL}
# LOG_LEVEL can be overridden by the user environment variable BS_LOG_LEVEL
LOG_LEVEL=${BS_LOG_LEVEL:-$LOG_LEVEL}
HAP_DIR="$APP_HOME/bootstrap"
BAK_DIR="$HAP_DIR._bak_"
NEW_DIR="$HAP_DIR._new_"
BIN_DIR="$HAP_DIR/bin"
CCH_DIR="$CACHE_HOME/bootstrap"
TMP_DIR="$CCH_DIR/temp_install"
APP_SCRIPT="$BIN_DIR/$APPNM"
ARCHIVE_FILE="$CCH_DIR/release.tgz"
LAST_CHECKED_FILE="$CCH_DIR/last_checked"
case "$action" in
install_app)
install_app
;;
install_bin)
if [[ "$ENABLE_INSTALL" == "yes" ]]; then
install_bin
exit 0
fi
;;
uninstall_app)
if [[ "$ENABLE_UNINSTALL" == "yes" ]]; then
uninstall_app
exit 0
fi
;;
esac
}
# Check if install of scripts was requested
if [[ "$#" -eq 1 && "$1" == "__INSTALL" ]]; then
perform "install_bin" "$APP_NAME" "$APP_DIR" "$DOWNLOAD_URL"
fi
# Check if uninstall was requested
if [[ "$#" -eq 1 && "$1" == "__UNINSTALL" ]]; then
perform "uninstall_app" "$APP_NAME" "$APP_DIR" "$DOWNLOAD_URL"
fi
# Installation/Update Check
perform "install_app" "$APP_NAME" "$APP_DIR" "$DOWNLOAD_URL"
# Execution Handover
# Check if the currently executing script is NOT the application itself
APPNM="$APP_NAME"
APP_SCRIPT="$HOME_DIR/.local/share/$APP_DIR/bootstrap/bin/$APP_NAME"
CURRENT_SCRIPT_PATH=$(realpath "$0")
BIN_EXE_PATH1=$(realpath "$APP_SCRIPT")
BIN_EXE_PATH2=$(realpath "$SHARED_BIN/$APP_NAME")
if [[ "$CURRENT_SCRIPT_PATH" != "$BIN_EXE_PATH1" && "$CURRENT_SCRIPT_PATH" != "$BIN_EXE_PATH2" ]]; then
LOG_INFO "Handing over execution to the installed application: $APP_SCRIPT"
exec "$APP_SCRIPT" "$@"
fi
##########################################
# BELOW THIS POINT YOU PUT YOUR OWN CODE #
##########################################
# Your application's main logic or final execution step would go here if this script
# *is* the final executable. Otherwise you can call out to other scripts or binaries as needed.
LOG_INFO "This would be your application."
# For simplicity, we just print a success message and exit.
echo "------------------------------------"
echo "This is application: $APP_NAME"
echo "Arguments received : $*"
echo "------------------------------------"
exit 0