|
| 1 | +#!/bin/bash |
| 2 | +# Lash CLI Installer |
| 3 | +# Builds and installs the Lash CLI globally via Cargo |
| 4 | + |
| 5 | +set -e |
| 6 | + |
| 7 | +# Colors for output |
| 8 | +RED='\033[0;31m' |
| 9 | +GREEN='\033[0;32m' |
| 10 | +YELLOW='\033[0;33m' |
| 11 | +BLUE='\033[0;34m' |
| 12 | +CYAN='\033[0;36m' |
| 13 | +BOLD='\033[1m' |
| 14 | +DIM='\033[2m' |
| 15 | +NC='\033[0m' # No Color |
| 16 | + |
| 17 | +# Paths |
| 18 | +CARGO_BIN="$HOME/.cargo/bin" |
| 19 | +LASH_BINARY="$CARGO_BIN/lash" |
| 20 | +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
| 21 | +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" |
| 22 | + |
| 23 | +# Print the Lash banner |
| 24 | +print_banner() { |
| 25 | + echo "" |
| 26 | + echo -e "${CYAN}${BOLD}┓ ┓${NC}" |
| 27 | + echo -e "${CYAN}${BOLD}┃ ┏┓┏┣┓${NC}" |
| 28 | + echo -e "${CYAN}${BOLD}┗┛┗┻┛┛┗${NC}" |
| 29 | + echo -e "${DIM}Minimalist task tracker for devs and agents${NC}" |
| 30 | + echo "" |
| 31 | +} |
| 32 | + |
| 33 | +# Print usage |
| 34 | +usage() { |
| 35 | + echo -e "${BOLD}Usage:${NC} $0 [COMMAND]" |
| 36 | + echo "" |
| 37 | + echo -e "${BOLD}Commands:${NC}" |
| 38 | + echo -e " ${GREEN}install${NC} Build and install Lash globally ${DIM}(default)${NC}" |
| 39 | + echo -e " ${YELLOW}reinstall${NC} Force reinstall even if version unchanged" |
| 40 | + echo -e " ${RED}uninstall${NC} Remove Lash from system" |
| 41 | + echo -e " ${BLUE}status${NC} Check current installation status" |
| 42 | + echo -e " ${CYAN}help${NC} Show this help message" |
| 43 | + echo "" |
| 44 | + echo -e "${BOLD}Locations:${NC}" |
| 45 | + echo -e " ${DIM}Binary:${NC} $LASH_BINARY" |
| 46 | + echo -e " ${DIM}Source:${NC} $PROJECT_ROOT/crates/lash-cli" |
| 47 | + echo "" |
| 48 | +} |
| 49 | + |
| 50 | +# Check if ~/.cargo/bin is in PATH |
| 51 | +check_path() { |
| 52 | + if [[ ":$PATH:" != *":$CARGO_BIN:"* ]]; then |
| 53 | + echo -e "${YELLOW}⚠️ Warning:${NC} $CARGO_BIN is not in your PATH" |
| 54 | + echo "" |
| 55 | + echo -e "${DIM}Add this to your shell config (~/.bashrc, ~/.zshrc, etc.):${NC}" |
| 56 | + echo -e " ${CYAN}export PATH=\"\$HOME/.cargo/bin:\$PATH\"${NC}" |
| 57 | + echo "" |
| 58 | + return 1 |
| 59 | + fi |
| 60 | + return 0 |
| 61 | +} |
| 62 | + |
| 63 | +# Install Lash |
| 64 | +do_install() { |
| 65 | + local force_flag="" |
| 66 | + if [ "$1" = "--force" ]; then |
| 67 | + force_flag="--force" |
| 68 | + echo -e "${YELLOW}🔄 Reinstalling Lash...${NC}" |
| 69 | + else |
| 70 | + echo -e "${GREEN}📦 Installing Lash...${NC}" |
| 71 | + fi |
| 72 | + echo "" |
| 73 | + |
| 74 | + # Change to project root |
| 75 | + cd "$PROJECT_ROOT" |
| 76 | + |
| 77 | + echo -e "${DIM}Building release binary from crates/lash-cli...${NC}" |
| 78 | + echo -e "${DIM}This compiles with optimizations (LTO enabled) - may take a minute.${NC}" |
| 79 | + echo "" |
| 80 | + |
| 81 | + # Run cargo install |
| 82 | + cargo install --path crates/lash-cli $force_flag |
| 83 | + |
| 84 | + echo "" |
| 85 | + |
| 86 | + # Verify installation |
| 87 | + if [ -x "$LASH_BINARY" ]; then |
| 88 | + echo -e "${GREEN}✅ Installation successful!${NC}" |
| 89 | + echo "" |
| 90 | + |
| 91 | + # Check PATH |
| 92 | + if check_path; then |
| 93 | + echo -e "${DIM}Verifying installation...${NC}" |
| 94 | + echo "" |
| 95 | + "$LASH_BINARY" --version |
| 96 | + echo "" |
| 97 | + echo -e "${GREEN}🎉 Lash is ready to use!${NC}" |
| 98 | + echo -e "${DIM}Try: lash --help${NC}" |
| 99 | + else |
| 100 | + echo "" |
| 101 | + echo -e "${DIM}After updating your PATH, verify with:${NC}" |
| 102 | + echo -e " ${CYAN}lash --version${NC}" |
| 103 | + fi |
| 104 | + else |
| 105 | + echo -e "${RED}❌ Installation failed - binary not found${NC}" |
| 106 | + exit 1 |
| 107 | + fi |
| 108 | +} |
| 109 | + |
| 110 | +# Uninstall Lash |
| 111 | +do_uninstall() { |
| 112 | + echo -e "${RED}🗑️ Uninstalling Lash...${NC}" |
| 113 | + echo "" |
| 114 | + |
| 115 | + if [ -x "$LASH_BINARY" ]; then |
| 116 | + echo -e "${DIM}Removing binary from $CARGO_BIN...${NC}" |
| 117 | + cargo uninstall lash-cli 2>/dev/null || rm -f "$LASH_BINARY" |
| 118 | + echo "" |
| 119 | + echo -e "${GREEN}✅ Lash has been uninstalled${NC}" |
| 120 | + |
| 121 | + # Verify removal |
| 122 | + if command -v lash &> /dev/null; then |
| 123 | + echo -e "${YELLOW}⚠️ Note: 'lash' still found in PATH (maybe a different installation?)${NC}" |
| 124 | + echo -e "${DIM}Location: $(which lash)${NC}" |
| 125 | + else |
| 126 | + echo -e "${DIM}Verified: 'which lash' returns nothing${NC}" |
| 127 | + fi |
| 128 | + else |
| 129 | + echo -e "${YELLOW}⚠️ Lash is not installed at $LASH_BINARY${NC}" |
| 130 | + |
| 131 | + # Check if it's installed elsewhere |
| 132 | + if command -v lash &> /dev/null; then |
| 133 | + echo -e "${DIM}Found lash elsewhere: $(which lash)${NC}" |
| 134 | + fi |
| 135 | + fi |
| 136 | +} |
| 137 | + |
| 138 | +# Check installation status |
| 139 | +do_status() { |
| 140 | + echo -e "${BLUE}🔍 Checking Lash installation status...${NC}" |
| 141 | + echo "" |
| 142 | + |
| 143 | + # Check binary |
| 144 | + echo -e "${BOLD}Binary:${NC}" |
| 145 | + if [ -x "$LASH_BINARY" ]; then |
| 146 | + echo -e " ${GREEN}✓${NC} Found at $LASH_BINARY" |
| 147 | + local version=$("$LASH_BINARY" --version 2>/dev/null || echo "unknown") |
| 148 | + echo -e " ${DIM}Version: $version${NC}" |
| 149 | + else |
| 150 | + echo -e " ${RED}✗${NC} Not found at $LASH_BINARY" |
| 151 | + fi |
| 152 | + echo "" |
| 153 | + |
| 154 | + # Check PATH |
| 155 | + echo -e "${BOLD}PATH:${NC}" |
| 156 | + if check_path 2>/dev/null; then |
| 157 | + echo -e " ${GREEN}✓${NC} $CARGO_BIN is in PATH" |
| 158 | + else |
| 159 | + echo -e " ${YELLOW}✗${NC} $CARGO_BIN is not in PATH" |
| 160 | + fi |
| 161 | + echo "" |
| 162 | + |
| 163 | + # Check which lash |
| 164 | + echo -e "${BOLD}which lash:${NC}" |
| 165 | + if command -v lash &> /dev/null; then |
| 166 | + echo -e " ${GREEN}✓${NC} $(which lash)" |
| 167 | + else |
| 168 | + echo -e " ${RED}✗${NC} Not found in PATH" |
| 169 | + fi |
| 170 | + echo "" |
| 171 | + |
| 172 | + # Check source |
| 173 | + echo -e "${BOLD}Source:${NC}" |
| 174 | + if [ -f "$PROJECT_ROOT/crates/lash-cli/Cargo.toml" ]; then |
| 175 | + echo -e " ${GREEN}✓${NC} Found at $PROJECT_ROOT/crates/lash-cli" |
| 176 | + else |
| 177 | + echo -e " ${RED}✗${NC} Source not found (are you in the lash repo?)" |
| 178 | + fi |
| 179 | +} |
| 180 | + |
| 181 | +# Main |
| 182 | +print_banner |
| 183 | + |
| 184 | +case "${1:-install}" in |
| 185 | + install) |
| 186 | + do_install |
| 187 | + ;; |
| 188 | + reinstall|force|--force) |
| 189 | + do_install --force |
| 190 | + ;; |
| 191 | + uninstall|remove) |
| 192 | + do_uninstall |
| 193 | + ;; |
| 194 | + status|check) |
| 195 | + do_status |
| 196 | + ;; |
| 197 | + help|--help|-h) |
| 198 | + usage |
| 199 | + ;; |
| 200 | + *) |
| 201 | + echo -e "${RED}❌ Unknown command: $1${NC}" |
| 202 | + echo "" |
| 203 | + usage |
| 204 | + exit 1 |
| 205 | + ;; |
| 206 | +esac |
0 commit comments