-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathsetup.sh
More file actions
executable file
·314 lines (279 loc) · 11.5 KB
/
setup.sh
File metadata and controls
executable file
·314 lines (279 loc) · 11.5 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
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
#!/usr/bin/env bash
# setup.sh — Symlink commands into ~/.local/bin (no aliases), then re-exec login shell.
# Optional: set MLH_INSTALL_USR_LOCAL=1 to also link into /usr/local/bin (needs sudo).
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PLUGINS_DIR="$ROOT_DIR/plugins"
LOCAL_BIN="$HOME/.local/bin"
BASHRC="$HOME/.bashrc"
PROFILE="$HOME/.profile"
MLH_CONFIG_DIR="$HOME/.mylinuxhelper"
MLH_CONFIG_FILE="$MLH_CONFIG_DIR/mlh.conf"
# Colors for output
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Track if bashrc was updated (for notification at end)
BASHRC_UPDATED=0
# Load MLH configuration
BOOKMARK_ALIAS=""
if [ -f "$MLH_CONFIG_FILE" ]; then
# shellcheck source=/dev/null
source "$MLH_CONFIG_FILE" 2>/dev/null || true
else
# Config file doesn't exist - create it from example if available
EXAMPLE_CONFIG="$ROOT_DIR/docs/config/mlh.conf.example"
if [ -f "$EXAMPLE_CONFIG" ]; then
mkdir -p "$MLH_CONFIG_DIR"
cp "$EXAMPLE_CONFIG" "$MLH_CONFIG_FILE"
echo "Created config file: $MLH_CONFIG_FILE"
echo " (copied from example with default BOOKMARK_ALIAS=bm)"
# shellcheck source=/dev/null
source "$MLH_CONFIG_FILE" 2>/dev/null || true
fi
fi
# 1) Ensure ~/.local/bin exists and added to PATH for future shells
mkdir -p "$LOCAL_BIN"
# shellcheck disable=SC2016
ADD_LINE='export PATH="$HOME/.local/bin:$PATH"'
grep -Fq "$ADD_LINE" "$BASHRC" 2>/dev/null || {
echo "$ADD_LINE" >>"$BASHRC"
echo "Added ~/.local/bin to PATH in ~/.bashrc"
}
grep -Fq "$ADD_LINE" "$PROFILE" 2>/dev/null || {
echo "$ADD_LINE" >>"$PROFILE"
echo "Added ~/.local/bin to PATH in ~/.profile"
}
# 1b) Add mlh wrapper function to ensure current session history is visible
MLH_WRAPPER_MARKER="# MyLinuxHelper - mlh wrapper function"
if ! grep -Fq "$MLH_WRAPPER_MARKER" "$BASHRC" 2>/dev/null; then
cat >>"$BASHRC" <<'EOF'
# MyLinuxHelper - mlh wrapper function
# This wrapper ensures current session history is visible to mlh history command
mlh() {
# If using mlh history, save current session history first
if [ "$1" = "history" ]; then
history -a 2>/dev/null || true
fi
# Call the actual mlh script
command mlh "$@"
}
EOF
echo "Added mlh wrapper function to ~/.bashrc"
BASHRC_UPDATED=1
fi
# 1c) Add bookmark wrapper function for cd functionality
BOOKMARK_WRAPPER_MARKER="# MyLinuxHelper - bookmark wrapper function"
if ! grep -Fq "$BOOKMARK_WRAPPER_MARKER" "$BASHRC" 2>/dev/null; then
cat >>"$BASHRC" <<'EOF'
# MyLinuxHelper - bookmark wrapper function
# This wrapper enables 'cd' functionality by evaluating the output
bookmark() {
local cmd="$1"
# Special handling for interactive list - use unique temp file per invocation
# PR branch: bookmark list defaults to interactive mode (no -i flag needed)
# Handle both explicit -i flag and default interactive mode
if [ "$cmd" = "list" ]; then
# Check if this is non-interactive mode (explicit -n flag)
if [ "$2" = "-n" ] || [ "$2" = "--non-interactive" ]; then
# Non-interactive mode - just pass through
command bookmark "$@"
return $?
fi
# Check if second argument is a number (limit) - this is also non-interactive
# shellcheck disable=SC2076
if [ -n "$2" ] && [[ "$2" =~ ^[0-9]+$ ]]; then
# Number limit - non-interactive mode, pass through
command bookmark "$@"
return $?
fi
# All other cases: default interactive mode, explicit -i flag, or category filter
# All of these should use interactive mode with cd support
# Use unique temp file per invocation (more reliable than fixed path)
# This ensures no race conditions between multiple invocations
local tmp_cd_file
local user_name
user_name="${USER:-$(id -un)}"
tmp_cd_file=$(mktemp "/tmp/bookmark-cd-${user_name}-XXXXXX" 2>/dev/null) || {
# Fallback to fixed path if mktemp fails
tmp_cd_file="/tmp/bookmark-cd-${user_name}"
rm -f "$tmp_cd_file"
}
# Export temp file path to plugin via environment variable
# Plugin will check this and use it if available
export MLH_BOOKMARK_CD_FILE="$tmp_cd_file"
# Clean up any leftover sequence files from previous sessions
# This is important for Ctrl+C interrupted sessions
rm -f "${tmp_cd_file}".* 2>/dev/null || true
# Run interactive mode - each invocation works independently
# User selects one bookmark, interactive mode exits, cd happens
command bookmark "$@"
local exit_code=$?
# Wait a bit for plugin to finish writing
sleep 0.1
# Source the sequence file (plugin writes .1 for first selection)
if [ -f "${tmp_cd_file}.1" ]; then
source "${tmp_cd_file}.1" 2>/dev/null || true
fi
# Clean up all temp files (base + sequences) and unset env var
rm -f "$tmp_cd_file" "${tmp_cd_file}".* 2>/dev/null || true
unset MLH_BOOKMARK_CD_FILE
return $exit_code
fi
# For jumping to bookmarks (number or name), eval the output to enable cd
# shellcheck disable=SC2076
if [[ "$cmd" =~ ^[0-9]+$ ]] || ( [ -n "$cmd" ] && [ "$cmd" != "." ] && [ "$cmd" != "list" ] && [ "$cmd" != "mv" ] && [ "$cmd" != "--help" ] && [ "$cmd" != "-h" ] && [ "$cmd" != "--version" ] && [ "$cmd" != "-v" ] ); then
# This might be a bookmark name/number - check if it produces a cd command
local output
output=$(command bookmark "$@" 2>&1)
if echo "$output" | grep -q "^cd "; then
# Extract and execute the cd command
# shellcheck disable=SC2294
eval "$(echo "$output" | grep "^cd ")"
# Show the rest of the output (without the cd line)
echo "$output" | grep -v "^cd " >&2
else
# Not a jump command, just show the output
echo "$output"
return $?
fi
else
# For other commands (save, list, mv, help), just pass through
command bookmark "$@"
fi
}
EOF
echo "Added bookmark wrapper function to ~/.bashrc"
BASHRC_UPDATED=1
fi
# 1d) Add bookmark alias wrapper if configured
if [ -n "${BOOKMARK_ALIAS:-}" ]; then
# Validate alias name (alphanumeric only, no spaces or special chars)
# shellcheck disable=SC2076
if [[ ! "$BOOKMARK_ALIAS" =~ ^[a-zA-Z0-9_]+$ ]]; then
echo -e "${YELLOW}Warning: Invalid alias name '$BOOKMARK_ALIAS' in config (must be alphanumeric)${NC}"
BOOKMARK_ALIAS=""
else
# Check for command conflicts - but allow our own symlink
# Functions take precedence over commands, so we can safely add the function
# even if a symlink exists (the function will be called first)
conflicting_cmd=""
if command -v "$BOOKMARK_ALIAS" >/dev/null 2>&1; then
conflicting_cmd=$(command -v "$BOOKMARK_ALIAS")
# Check if it's our own symlink - if so, it's OK to add the function
if [ -L "$conflicting_cmd" ]; then
symlink_target=$(readlink -f "$conflicting_cmd" 2>/dev/null || readlink "$conflicting_cmd" 2>/dev/null || echo "")
# If symlink points to our plugin, it's OK - function will override it
if echo "$symlink_target" | grep -q "mlh-bookmark.sh"; then
conflicting_cmd=""
fi
fi
# If it's a real command (not our symlink), warn but still allow function
# Function will take precedence, but user should know about the conflict
if [ -n "$conflicting_cmd" ]; then
echo -e "${YELLOW}Warning: Command '$BOOKMARK_ALIAS' exists at '$conflicting_cmd'${NC}"
echo -e "${YELLOW}Function will take precedence, but consider removing the conflicting command${NC}"
fi
fi
# Add the wrapper function (functions take precedence over commands/symlinks)
ALIAS_WRAPPER_MARKER="# MyLinuxHelper - $BOOKMARK_ALIAS alias wrapper"
if ! grep -Fq "$ALIAS_WRAPPER_MARKER" "$BASHRC" 2>/dev/null; then
cat >>"$BASHRC" <<EOF
# MyLinuxHelper - $BOOKMARK_ALIAS alias wrapper
# Shortcut alias for bookmark command (delegates to bookmark function for cd support)
# NOTE: This function takes precedence over the symlink, enabling cd functionality
$BOOKMARK_ALIAS() {
bookmark "\$@"
}
EOF
echo "Added $BOOKMARK_ALIAS alias wrapper to ~/.bashrc"
BASHRC_UPDATED=1
fi
fi
fi
# 2) Make scripts executable
echo "Granting execute permission to all plugin scripts..."
find "$PLUGINS_DIR" -type f -name "*.sh" -exec chmod +x {} \;
chmod +x "$ROOT_DIR/install.sh"
# 3) Create/refresh symlinks in ~/.local/bin
declare -A LINKS=(
["$LOCAL_BIN/bookmark"]="$PLUGINS_DIR/mlh-bookmark.sh"
["$LOCAL_BIN/i"]="$ROOT_DIR/install.sh"
["$LOCAL_BIN/isjsonvalid"]="$PLUGINS_DIR/isjsonvalid.sh"
["$LOCAL_BIN/ll"]="$PLUGINS_DIR/ll.sh"
["$LOCAL_BIN/linux"]="$PLUGINS_DIR/linux.sh"
["$LOCAL_BIN/mlh"]="$PLUGINS_DIR/mlh.sh"
["$LOCAL_BIN/search"]="$PLUGINS_DIR/search.sh"
)
# Add bookmark alias symlink if configured
if [ -n "${BOOKMARK_ALIAS:-}" ]; then
LINKS["$LOCAL_BIN/$BOOKMARK_ALIAS"]="$PLUGINS_DIR/mlh-bookmark.sh"
fi
for link in "${!LINKS[@]}"; do
target="${LINKS[$link]}"
rm -f "$link"
ln -s "$target" "$link"
echo "Linked: $(basename "$link") → $target"
done
# 4) (Optional) /usr/local/bin fallback — only if explicitly requested
if [ "${MLH_INSTALL_USR_LOCAL:-0}" = "1" ] && command -v sudo >/dev/null 2>&1; then
echo "Linking into /usr/local/bin (requested via MLH_INSTALL_USR_LOCAL=1)..."
declare -A ULINKS=(
["/usr/local/bin/bookmark"]="$PLUGINS_DIR/mlh-bookmark.sh"
["/usr/local/bin/i"]="$ROOT_DIR/install.sh"
["/usr/local/bin/isjsonvalid"]="$PLUGINS_DIR/isjsonvalid.sh"
["/usr/local/bin/ll"]="$PLUGINS_DIR/ll.sh"
["/usr/local/bin/linux"]="$PLUGINS_DIR/linux.sh"
["/usr/local/bin/mlh"]="$PLUGINS_DIR/mlh.sh"
["/usr/local/bin/search"]="$PLUGINS_DIR/search.sh"
)
# Add bookmark alias to usr/local if configured
if [ -n "${BOOKMARK_ALIAS:-}" ]; then
ULINKS["/usr/local/bin/$BOOKMARK_ALIAS"]="$PLUGINS_DIR/mlh-bookmark.sh"
fi
for link in "${!ULINKS[@]}"; do
target="${ULINKS[$link]}"
sudo rm -f "$link" 2>/dev/null || true
sudo ln -s "$target" "$link" 2>/dev/null || true
done
fi
# 5) If current session still can't see commands, re-exec a fresh login shell
need_reload=0
for bin in i isjsonvalid ll linux mlh search; do
if ! command -v "$bin" >/dev/null 2>&1; then
need_reload=1
break
fi
done
echo "✅ Setup complete. Commands: i, isjsonvalid, ll, linux, mlh, search${BOOKMARK_ALIAS:+, $BOOKMARK_ALIAS}"
echo ""
echo "Examples:"
echo " linux mycontainer # Create ephemeral container (default)"
echo " linux -p mycontainer # Create permanent container"
echo " linux -s mycontainer # Stop container"
echo ""
echo " mlh docker in mycontainer # Enter running container by name pattern"
echo " mlh history # Show command history (numbered)"
echo " mlh history 10 # Show last 10 commands"
echo " search myfile # Search for files in current directory"
echo " i nginx # Install package using system package manager"
echo ""
echo " isjsonvalid data.json # Quick JSON validation (Yes/No)"
echo " isjsonvalid -d data.json # Detailed JSON validation"
echo " mlh json --isvalid data.json # Detailed JSON validation"
echo " mlh json get name from users.json # Search JSON with fuzzy matching"
echo ""
echo " ll /var/log # List directory contents with details"
# Show warning if bashrc was updated
if [ "$BASHRC_UPDATED" -eq 1 ]; then
echo ""
echo -e "${YELLOW}⚠️ Important: Shell configuration updated!${NC}"
echo -e "${YELLOW} Run this command to apply changes in current session:${NC}"
echo -e "${CYAN} source ~/.bashrc${NC}"
echo ""
fi
if [ "$need_reload" -eq 1 ] && [ -t 1 ] && [ -z "${MLH_RELOADED:-}" ]; then
echo "↻ Opening a fresh login shell so commands are available immediately..."
export MLH_RELOADED=1
exec "${SHELL:-/bin/bash}" -l
fi