-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathinstall-cli.sh
More file actions
executable file
·406 lines (363 loc) · 15.6 KB
/
install-cli.sh
File metadata and controls
executable file
·406 lines (363 loc) · 15.6 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
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
#!/usr/bin/env bash
set -euo pipefail
# HDP Cairo CLI installer
# - Checks for Rust and uv (prompts with installation instructions if missing)
# - Clones or updates the repo at $HOME/.local/share/hdp
# - Initializes and updates submodules, sets up Python env with uv, activates venv
# - Builds the hdp-cli binary and symlinks it into $HOME/.local/bin
# - Supports installing specific versions via VERSION environment variable (e.g., VERSION=v1.0.12)
# - Supports --clean flag for full cargo clean (without flag, only cleans build script outputs)
# - Supports --local flag to build from existing local repository without pulling from GitHub
# Colors for better readability
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
WHITE='\033[1;37m'
GRAY='\033[0;37m'
BOLD='\033[1m'
NC='\033[0m' # No Color
# Icons
CHECK="✓"
CROSS="✗"
ARROW="➤"
INFO="ℹ"
WARNING="⚠"
ERROR="✗"
SUCCESS="✓"
REPO_URL="https://github.com/HerodotusDev/hdp-cairo"
REPO_DIR="$HOME/.local/share/hdp"
BIN_NAME="hdp-cli"
ALIAS_NAME="hdp"
TARGET_BIN="$REPO_DIR/target/release/$BIN_NAME"
LOCAL_BIN_DIR="$HOME/.local/bin"
SYMLINK_PATH="$LOCAL_BIN_DIR/$ALIAS_NAME"
command_exists() {
command -v "$1" >/dev/null 2>&1
}
prompt_install() {
local name="$1"
local install_hint="$2"
echo
echo -e "${RED}${ERROR}${NC} ${BOLD}$name${NC} is not installed."
echo
echo -e "${YELLOW}${ARROW}${NC} To install ${BOLD}$name${NC}, please run:"
echo -e " ${CYAN}$install_hint${NC}"
echo
echo -e "${YELLOW}${ARROW}${NC} After installation, please restart your terminal or run:"
echo -e " ${CYAN}source ~/.bashrc${NC} # or ~/.zshrc depending on your shell"
echo
echo -e "${YELLOW}${ARROW}${NC} Then run this installer again."
echo
exit 1
}
ensure_rust() {
if command_exists rustc || command_exists cargo || command_exists rustup; then
return 0
fi
prompt_install "Rust" "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"
}
ensure_uv() {
if command_exists uv; then
return 0
fi
prompt_install "uv" "curl -LsSf https://astral.sh/uv/install.sh | sh"
}
ensure_path_bootstrap() {
# Ensure current shell can see freshly installed tools without requiring restart
if [ -d "$HOME/.cargo/bin" ] && ! echo ":$PATH:" | grep -q ":$HOME/.cargo/bin:"; then
export PATH="$HOME/.cargo/bin:$PATH"
fi
if [ -d "$LOCAL_BIN_DIR" ] && ! echo ":$PATH:" | grep -q ":$LOCAL_BIN_DIR:"; then
export PATH="$LOCAL_BIN_DIR:$PATH"
fi
}
validate_version() {
local version="$1"
if [ -z "$version" ]; then
return 0 # No version specified, use latest
fi
# Check if version exists on GitHub
echo -e "${BLUE}${INFO}${NC} Checking if version ${CYAN}$version${NC} exists..."
if ! curl -s -f "https://api.github.com/repos/HerodotusDev/hdp-cairo/releases/tags/$version" >/dev/null 2>&1; then
echo -e "${RED}${ERROR}${NC} Version ${CYAN}$version${NC} not found on GitHub releases"
echo -e "${YELLOW}${ARROW}${NC} Please check available releases at: ${CYAN}https://github.com/HerodotusDev/hdp-cairo/releases${NC}"
exit 1
fi
echo -e "${GREEN}${SUCCESS}${NC} Version ${CYAN}$version${NC} found"
}
check_old_installation() {
if [ -d "$REPO_DIR" ] && [ ! -d "$REPO_DIR/.git" ]; then
echo -e "${YELLOW}${WARNING}${NC} Old installation detected at ${CYAN}$REPO_DIR${NC} (no git repository found)"
return 0
fi
return 1
}
check_local_repo() {
if [ ! -d "$REPO_DIR/.git" ]; then
echo -e "${RED}${ERROR}${NC} No HDP repository found at ${CYAN}$REPO_DIR${NC}"
echo -e "${YELLOW}${ARROW}${NC} The ${BOLD}--local${NC} flag requires an existing repository."
echo -e "${YELLOW}${ARROW}${NC} Please run the installer without ${BOLD}--local${NC} to clone the repository first, or ensure the repository exists at ${CYAN}$REPO_DIR${NC}"
exit 1
fi
echo -e "${GREEN}${SUCCESS}${NC} Found local repository at ${CYAN}$REPO_DIR${NC}"
}
cleanup_old_installation() {
echo
echo -e "${YELLOW}${WARNING}${NC} An old installation of HDP CLI was found that needs to be removed."
echo -e "${YELLOW}${WARNING}${NC} This will delete the following:"
if [ -d "$REPO_DIR" ]; then
echo -e " ${CYAN}•${NC} Directory: ${CYAN}$REPO_DIR${NC}"
fi
if [ -e "$SYMLINK_PATH" ]; then
echo -e " ${CYAN}•${NC} Binary/symlink: ${CYAN}$SYMLINK_PATH${NC}"
fi
echo
echo -e "${YELLOW}${ARROW}${NC} Do you want to remove the old installation and proceed with a fresh install? (y/N)"
read -r response
case "$response" in
[yY]|[yY][eE][sS])
echo -e "${BLUE}${INFO}${NC} Cleaning up old installation..."
# Remove the old hdp directory
if [ -d "$REPO_DIR" ]; then
echo -e "${BLUE}${INFO}${NC} Removing old directory: ${CYAN}$REPO_DIR${NC}"
rm -rf "$REPO_DIR"
fi
# Remove the old symlink or binary
if [ -e "$SYMLINK_PATH" ]; then
echo -e "${BLUE}${INFO}${NC} Removing old symlink/binary: ${CYAN}$SYMLINK_PATH${NC}"
rm -f "$SYMLINK_PATH"
fi
echo -e "${GREEN}${SUCCESS}${NC} Old installation cleaned up successfully"
;;
*)
echo -e "${RED}${ERROR}${NC} Installation cancelled. Please remove the old installation manually and run this script again."
exit 1
;;
esac
}
clone_or_update_repo() {
local version="${VERSION:-}"
if [ -d "$REPO_DIR/.git" ]; then
echo -e "${BLUE}${INFO}${NC} Repository already exists at ${CYAN}$REPO_DIR${NC}..."
if [ -n "$version" ]; then
echo -e "${BLUE}${INFO}${NC} Checking out version ${CYAN}$version${NC}..."
git -C "$REPO_DIR" fetch --all --tags
if ! git -C "$REPO_DIR" checkout "$version" 2>/dev/null; then
echo -e "${RED}${ERROR}${NC} Failed to checkout version ${CYAN}$version${NC}"
echo -e "${YELLOW}${ARROW}${NC} The version might not exist or the repository might be in a dirty state"
exit 1
fi
else
echo -e "${BLUE}${INFO}${NC} Updating to latest version..."
git -C "$REPO_DIR" fetch --all --tags
if ! git -C "$REPO_DIR" pull --ff-only origin main; then
echo -e "${RED}${ERROR}${NC} Failed to update repository. The repository has local changes that conflict with remote changes."
echo -e "${YELLOW}${ARROW}${NC} Please resolve conflicts manually:"
echo -e " ${CYAN}cd $REPO_DIR${NC}"
echo -e " ${CYAN}git stash${NC} # to save your local changes"
echo -e " ${CYAN}git pull origin main${NC} # to update from main branch"
echo -e " ${CYAN}git stash pop${NC} # to restore your changes (if desired)"
echo -e "${YELLOW}${ARROW}${NC} Then run this installer again."
exit 1
fi
fi
else
mkdir -p "$(dirname "$REPO_DIR")"
echo -e "${BLUE}${INFO}${NC} Cloning ${CYAN}$REPO_URL${NC} into ${CYAN}$REPO_DIR${NC}..."
git clone "$REPO_URL" "$REPO_DIR"
if [ -n "$version" ]; then
echo -e "${BLUE}${INFO}${NC} Checking out version ${CYAN}$version${NC}..."
if ! git -C "$REPO_DIR" checkout "$version" 2>/dev/null; then
echo -e "${RED}${ERROR}${NC} Failed to checkout version ${CYAN}$version${NC}"
echo -e "${YELLOW}${ARROW}${NC} The version might not exist"
exit 1
fi
fi
fi
}
init_submodules() {
echo -e "${BLUE}${INFO}${NC} Initializing and updating submodules..."
git -C "$REPO_DIR" submodule update --init --recursive
}
setup_python_env() {
echo -e "${BLUE}${INFO}${NC} Setting up Python environment with ${BOLD}uv${NC}..."
(cd "$REPO_DIR" && uv sync)
# Activate the virtual environment in a subshell for any tooling that expects it
if [ -f "$REPO_DIR/.venv/bin/activate" ]; then
# shellcheck disable=SC1091
. "$REPO_DIR/.venv/bin/activate"
fi
}
clean_build_artifacts() {
local clean_mode="$1"
if [ "$clean_mode" = true ]; then
echo -e "${BLUE}${INFO}${NC} Performing full clean (${BOLD}cargo clean${NC})..."
(cd "$REPO_DIR" && cargo clean)
else
echo -e "${BLUE}${INFO}${NC} Cleaning build script output directories..."
# Find all "out/cairo" directories, then remove their parent "out" directory
# (e.g., find target/release/build/sound_run-*/out/cairo, then remove the "out" parent)
if [ -d "$REPO_DIR/target/release/build" ]; then
local cleaned_count=0
# Recursively find all "out/cairo" directories within target/release/build
# -type d: only directories
# -path "*/out/cairo": matches paths ending with /out/cairo
# -print0: null-delimited output for safe handling of paths with spaces
while IFS= read -r -d '' cairo_dir; do
# Get the parent "out" directory by removing "/out/cairo" from the path
local out_dir="${cairo_dir%/out/cairo}"
echo -e "${BLUE}${INFO}${NC} Removing ${CYAN}$out_dir${NC}..."
rm -rf "$out_dir"
cleaned_count=$((cleaned_count + 1))
done < <(find "$REPO_DIR/target/release/build" -type d -path "*/out/cairo" -print0 2>/dev/null || true)
if [ "$cleaned_count" -eq 0 ]; then
echo -e "${BLUE}${INFO}${NC} No build script output directories found to clean"
else
echo -e "${GREEN}${SUCCESS}${NC} Cleaned ${CYAN}$cleaned_count${NC} build script output directory(ies)"
fi
else
echo -e "${BLUE}${INFO}${NC} No target/release/build directory found"
fi
fi
}
build_cli() {
local clean_mode="${1:-false}"
clean_build_artifacts "$clean_mode"
echo -e "${BLUE}${INFO}${NC} Building ${BOLD}$BIN_NAME${NC} (release)..."
# Default build uses the repo toolchain. To enable STWO prover input support:
# - set STWO=1 (or STWO=true) when running this installer, or
# - rebuild later with: cargo build --release --bin hdp-cli --features stwo
local stwo_mode="${STWO:-false}"
if [ "$stwo_mode" = "1" ] || [ "$stwo_mode" = "true" ]; then
echo -e "${BLUE}${INFO}${NC} STWO mode enabled: building with --features stwo"
(cd "$REPO_DIR" && cargo build --release --bin "$BIN_NAME" --features stwo)
else
(cd "$REPO_DIR" && cargo build --release --bin "$BIN_NAME")
fi
}
ensure_symlink() {
mkdir -p "$LOCAL_BIN_DIR"
if [ -L "$SYMLINK_PATH" ]; then
echo -e "${GREEN}${SUCCESS}${NC} Symlink already exists: ${CYAN}$SYMLINK_PATH${NC}"
return 0
fi
if [ -e "$SYMLINK_PATH" ] && [ ! -L "$SYMLINK_PATH" ]; then
echo -e "${YELLOW}${WARNING}${NC} A non-symlink file already exists at ${CYAN}$SYMLINK_PATH${NC}. Skipping symlink creation."
return 0
fi
if [ ! -f "$TARGET_BIN" ]; then
echo -e "${RED}${ERROR}${NC} Expected binary not found at ${CYAN}$TARGET_BIN${NC}"
exit 1
fi
echo -e "${BLUE}${INFO}${NC} Creating symlink ${CYAN}$SYMLINK_PATH${NC} -> ${CYAN}$TARGET_BIN${NC}"
ln -s "$TARGET_BIN" "$SYMLINK_PATH"
}
print_path_hint() {
if ! echo ":$PATH:" | grep -q ":$LOCAL_BIN_DIR:"; then
echo
echo -e "${YELLOW}${WARNING}${NC} Note: ${CYAN}$LOCAL_BIN_DIR${NC} is not in your PATH. Consider adding this to your shell profile:"
echo -e " ${CYAN}export PATH=\"$LOCAL_BIN_DIR:\$PATH\"${NC}"
fi
}
main() {
local clean_mode=false
local local_mode=false
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-c|--clean)
clean_mode=true
shift
;;
-l|--local)
local_mode=true
shift
;;
-h|--help)
echo "Usage: $0 [--clean] [--local]"
echo
echo "Options:"
echo " -c | --clean Perform full cargo clean before building (slower but more thorough)"
echo " Without this flag, only removes build script output directories"
echo " -l | --local Build from existing local repository without pulling from GitHub"
echo " Fails if repository doesn't exist at $REPO_DIR"
echo
echo "Environment variables:"
echo " VERSION Install a specific version (e.g., VERSION=v1.0.12)"
echo " Ignored when using --local"
exit 0
;;
*)
echo -e "${RED}${ERROR}${NC} Unknown option: ${BOLD}$1${NC}"
echo -e "${YELLOW}${ARROW}${NC} Use ${CYAN}--help${NC} for usage information"
exit 1
;;
esac
done
echo -e "${PURPLE}${BOLD}╔══════════════════════════════════════╗${NC}"
echo -e "${PURPLE}${BOLD}║ HDP Cairo CLI Installer ║${NC}"
echo -e "${PURPLE}${BOLD}╚══════════════════════════════════════╝${NC}"
echo
# Basic prerequisites
for dep in git curl; do
if ! command_exists "$dep"; then
echo -e "${RED}${ERROR}${NC} Required dependency ${BOLD}'$dep'${NC} is not installed. Please install it and rerun."
exit 1
fi
done
ensure_rust
ensure_uv
ensure_path_bootstrap
if [ "$local_mode" = true ]; then
echo -e "${BLUE}${INFO}${NC} Local mode: building from existing repository"
check_local_repo
# Skip version validation and repo cloning/updating in local mode
else
# Validate version if specified
if [ -n "${VERSION:-}" ]; then
validate_version "$VERSION"
echo -e "${BLUE}${INFO}${NC} Installing version: ${CYAN}$VERSION${NC}"
else
echo -e "${BLUE}${INFO}${NC} Installing latest version"
fi
# Check for old installation and clean up if necessary
if check_old_installation; then
cleanup_old_installation
fi
clone_or_update_repo
fi
init_submodules
setup_python_env
build_cli "$clean_mode"
ensure_symlink
print_path_hint
echo
echo -e "${GREEN}${SUCCESS}${NC} ${BOLD}Installation/update complete!${NC} You can run ${BOLD}'$ALIAS_NAME'${NC} if $LOCAL_BIN_DIR is in PATH."
echo
echo -e "${GRAY}${BOLD}╔══════════════════════════════════════╗${NC}"
echo -e "${GRAY}${BOLD}║ Developer Info ║${NC}"
echo -e "${GRAY}${BOLD}╚══════════════════════════════════════╝${NC}"
echo
echo -e "${BLUE}${INFO}${NC} You can work on HDP, debug, or make changes in the HDP folder:"
echo -e " ${CYAN}$REPO_DIR${NC}"
echo
echo -e "${YELLOW}${ARROW}${NC} Once you run ${BOLD}cargo build --release${NC}, the symlink will automatically make your version available everywhere using ${BOLD}hdp${NC}"
echo -e "${YELLOW}${ARROW}${NC} For STWO prover input support, rebuild with: ${BOLD}cargo +nightly build --release --bin hdp-cli --features stwo${NC}"
echo -e "${YELLOW}${ARROW}${NC} You can change branches, update the repo, add prints, or modify code as you please"
echo -e "${YELLOW}${ARROW}${NC} The symlink always points to your latest built version"
echo -e "${YELLOW}${ARROW}${NC} You can also symlink this repo into your project for easier access to debugging"
echo -e "${YELLOW}${ARROW}${NC} To do this, run ${CYAN}hdp link${NC} in your Scarb project directory, and import directly from there"
echo
echo -e "${BLUE}${INFO}${NC} To install a specific version in the future, use:"
echo -e " ${CYAN}VERSION=vX.X.X curl -fsSL https://raw.githubusercontent.com/HerodotusDev/hdp-cairo/main/install-cli.sh | bash${NC}"
echo -e "${BLUE}${INFO}${NC} Available versions can be found at: ${CYAN}https://github.com/HerodotusDev/hdp-cairo/releases${NC}"
echo
echo -e "${YELLOW}${BOLD}╔══════════════════════════════════════╗${NC}"
echo -e "${YELLOW}${BOLD}║ IMPORTANT ║${NC}"
echo -e "${YELLOW}${BOLD}╚══════════════════════════════════════╝${NC}"
"$SYMLINK_PATH" env-info
}
main "$@"