Skip to content

Commit 88cf8ee

Browse files
enhance(install): prefer /usr/local/bin and posix compliance
Always install to /usr/local/bin and improve posix compliance so other shells can be used
1 parent 2a55679 commit 88cf8ee

1 file changed

Lines changed: 86 additions & 43 deletions

File tree

get-cli.sh

Lines changed: 86 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
#!/bin/bash
1+
#!/bin/sh
22

33
# Get Pangolin - Cross-platform installation script
4-
# Usage:
5-
# curl -fsSL https://raw.githubusercontent.com/fosrl/cli/refs/heads/main/get-cli.sh | bash
4+
# Usage: curl -fsSL https://raw.githubusercontent.com/fosrl/cli/refs/heads/main/get-cli.sh | sh
65

76
set -e
87

@@ -18,20 +17,20 @@ GITHUB_API_URL="https://api.github.com/repos/${REPO}/releases/latest"
1817

1918
# Output helpers
2019
print_status() {
21-
echo -e "${GREEN}[INFO]${NC} $1"
20+
printf '%b[INFO]%b %s\n' "${GREEN}" "${NC}" "$1"
2221
}
2322

2423
print_warning() {
25-
echo -e "${YELLOW}[WARN]${NC} $1"
24+
printf '%b[WARN]%b %s\n' "${YELLOW}" "${NC}" "$1"
2625
}
2726

2827
print_error() {
29-
echo -e "${RED}[ERROR]${NC} $1"
28+
printf '%b[ERROR]%b %s\n' "${RED}" "${NC}" "$1"
3029
}
3130

3231
# Fetch latest version from GitHub API
3332
get_latest_version() {
34-
local latest_info
33+
latest_info=""
3534
if command -v curl >/dev/null 2>&1; then
3635
latest_info=$(curl -fsSL "$GITHUB_API_URL" 2>/dev/null)
3736
elif command -v wget >/dev/null 2>&1; then
@@ -46,20 +45,20 @@ get_latest_version() {
4645
exit 1
4746
fi
4847

49-
local version
50-
version=$(echo "$latest_info" | grep '"tag_name"' | head -1 | sed 's/.*"tag_name": *"\([^"]*\)".*/\1/')
48+
version=$(printf '%s' "$latest_info" | grep '"tag_name"' | head -1 | sed 's/.*"tag_name": *"\([^"]*\)".*/\1/')
5149
if [ -z "$version" ]; then
5250
print_error "Could not parse version from GitHub API response"
5351
exit 1
5452
fi
5553

56-
version=$(echo "$version" | sed 's/^v//')
57-
echo "$version"
54+
version=$(printf '%s' "$version" | sed 's/^v//')
55+
printf '%s' "$version"
5856
}
5957

6058
# Detect OS and architecture
6159
detect_platform() {
62-
local os arch
60+
os=""
61+
arch=""
6362
case "$(uname -s)" in
6463
Linux*) os="linux" ;;
6564
Darwin*) os="darwin" ;;
@@ -89,39 +88,66 @@ detect_platform() {
8988
*) print_error "Unsupported architecture: $(uname -m)"; exit 1 ;;
9089
esac
9190

92-
echo "${os}_${arch}"
91+
printf '%s_%s' "$os" "$arch"
9392
}
9493

9594
# Determine installation directory
9695
get_install_dir() {
97-
if [ "$OS" = "windows" ]; then
98-
echo "$HOME/bin"
99-
else
100-
if echo "$PATH" | grep -q "/usr/local/bin" && [ -w "/usr/local/bin" ]; then
96+
case "$PLATFORM" in
97+
*windows*)
98+
echo "$HOME/bin"
99+
;;
100+
*)
101+
# Prefer /usr/local/bin for system-wide installation
101102
echo "/usr/local/bin"
103+
;;
104+
esac
105+
}
106+
107+
# Check if we need sudo for installation
108+
needs_sudo() {
109+
install_dir="$1"
110+
if [ -w "$install_dir" ] 2>/dev/null; then
111+
return 1 # No sudo needed
112+
else
113+
return 0 # Sudo needed
114+
fi
115+
}
116+
117+
# Get the appropriate command prefix (sudo or empty)
118+
get_sudo_cmd() {
119+
install_dir="$1"
120+
if needs_sudo "$install_dir"; then
121+
if command -v sudo >/dev/null 2>&1; then
122+
echo "sudo"
102123
else
103-
echo "$HOME/.local/bin"
124+
print_error "Cannot write to ${install_dir} and sudo is not available."
125+
print_error "Please run this script as root or install sudo."
126+
exit 1
104127
fi
128+
else
129+
echo ""
105130
fi
106131
}
107132

108133
# Download and install Pangolin
109134
install_pangolin() {
110-
local platform="$1"
111-
local install_dir="$2"
112-
local asset_name="pangolin-cli_${platform}"
113-
local exe_suffix=""
114-
local final_name="pangolin"
115-
116-
if [[ "$platform" == *"windows"* ]]; then
117-
asset_name="${asset_name}.exe"
118-
exe_suffix=".exe"
119-
final_name="pangolin.exe"
120-
fi
135+
platform="$1"
136+
install_dir="$2"
137+
sudo_cmd="$3"
138+
asset_name="pangolin-cli_${platform}"
139+
final_name="pangolin"
140+
141+
case "$platform" in
142+
*windows*)
143+
asset_name="${asset_name}.exe"
144+
final_name="pangolin.exe"
145+
;;
146+
esac
121147

122-
local download_url="${BASE_URL}/${asset_name}"
123-
local temp_file="/tmp/${final_name}"
124-
local final_path="${install_dir}/${final_name}"
148+
download_url="${BASE_URL}/${asset_name}"
149+
temp_file="/tmp/${final_name}"
150+
final_path="${install_dir}/${final_name}"
125151

126152
print_status "Downloading Pangolin from ${download_url}"
127153

@@ -134,12 +160,22 @@ install_pangolin() {
134160
exit 1
135161
fi
136162

137-
mkdir -p "$install_dir"
138-
mv "$temp_file" "$final_path"
139-
chmod +x "$final_path"
163+
# Make executable before moving
164+
chmod +x "$temp_file"
165+
166+
# Create install directory if it doesn't exist and move binary
167+
if [ -n "$sudo_cmd" ]; then
168+
$sudo_cmd mkdir -p "$install_dir"
169+
print_status "Using sudo to install to ${install_dir}"
170+
$sudo_cmd mv "$temp_file" "$final_path"
171+
else
172+
mkdir -p "$install_dir"
173+
mv "$temp_file" "$final_path"
174+
fi
140175

141176
print_status "Pangolin installed to ${final_path}"
142177

178+
# Check if install directory is in PATH
143179
if ! echo "$PATH" | grep -q "$install_dir"; then
144180
print_warning "Install directory ${install_dir} is not in your PATH."
145181
print_warning "Add it with:"
@@ -149,17 +185,18 @@ install_pangolin() {
149185

150186
# Verify installation
151187
verify_installation() {
152-
local install_dir="$1"
153-
local exe_suffix=""
188+
install_dir="$1"
189+
exe_suffix=""
154190

155-
if [[ "$PLATFORM" == *"windows"* ]]; then
156-
exe_suffix=".exe"
157-
fi
191+
case "$PLATFORM" in
192+
*windows*) exe_suffix=".exe" ;;
193+
esac
194+
195+
pangolin_path="${install_dir}/pangolin${exe_suffix}"
158196

159-
local pangolin_path="${install_dir}/pangolin${exe_suffix}"
160197
if [ -x "$pangolin_path" ]; then
161198
print_status "Installation successful!"
162-
print_status "pangolin version: $("$pangolin_path" version 2>/dev/null || echo "unknown")"
199+
print_status "pangolin version: $("$pangolin_path" version 2>/dev/null || printf 'unknown')"
163200
return 0
164201
else
165202
print_error "Installation failed. Binary not found or not executable."
@@ -183,7 +220,13 @@ main() {
183220
INSTALL_DIR=$(get_install_dir)
184221
print_status "Install directory: ${INSTALL_DIR}"
185222

186-
install_pangolin "$PLATFORM" "$INSTALL_DIR"
223+
# Check if we need sudo
224+
SUDO_CMD=$(get_sudo_cmd "$INSTALL_DIR")
225+
if [ -n "$SUDO_CMD" ]; then
226+
print_status "Root privileges required for installation to ${INSTALL_DIR}"
227+
fi
228+
229+
install_pangolin "$PLATFORM" "$INSTALL_DIR" "$SUDO_CMD"
187230

188231
if verify_installation "$INSTALL_DIR"; then
189232
print_status "Pangolin is ready to use!"

0 commit comments

Comments
 (0)