mirror of
https://github.com/lukaszraczylo/filepuff-mcp.git
synced 2026-06-05 22:23:50 +00:00
b8d868115c
- [x] Add Elixir documentation extraction (@doc and @moduledoc attributes) - [x] Add Elixir symbol extraction (modules, functions, macros, structs, protocols) - [x] Add tree-sitter Elixir language parser integration - [x] Add Elixir language detection for .ex and .exs file extensions - [x] Add Elixir symbol extraction tests - [x] Update language support table in README - [x] Improve install script with package manager detection and LSP installation - [x] Fix shell script portability (replace echo -e with printf) - [x] Fix checksum verification in install script for macOS/Linux compatibility
389 lines
11 KiB
Bash
Executable File
389 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# MCP Filepuff Installation Script
|
|
# Downloads and installs the latest version of mcp-filepuff
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# GitHub repository information
|
|
REPO="lukaszraczylo/filepuff-mcp"
|
|
BINARY_NAME="mcp-filepuff"
|
|
|
|
# Installation directory (will try ~/.local/bin first, then /usr/local/bin)
|
|
INSTALL_DIR="${INSTALL_DIR:-$HOME/.local/bin}"
|
|
|
|
# Functions
|
|
print_info() {
|
|
printf "${GREEN}[INFO]${NC} %s\n" "$1"
|
|
}
|
|
|
|
print_warn() {
|
|
printf "${YELLOW}[WARN]${NC} %s\n" "$1"
|
|
}
|
|
|
|
print_error() {
|
|
printf "${RED}[ERROR]${NC} %s\n" "$1" >&2
|
|
}
|
|
|
|
detect_platform() {
|
|
local os
|
|
local arch
|
|
|
|
# Detect OS
|
|
case "$(uname -s)" in
|
|
Linux*) os="linux" ;;
|
|
Darwin*) os="darwin" ;;
|
|
MINGW*|MSYS*|CYGWIN*)
|
|
print_error "Windows is not directly supported. Please use WSL2."
|
|
exit 1
|
|
;;
|
|
*)
|
|
print_error "Unsupported operating system: $(uname -s)"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# Detect architecture
|
|
case "$(uname -m)" in
|
|
x86_64|amd64) arch="amd64" ;;
|
|
arm64|aarch64) arch="arm64" ;;
|
|
*)
|
|
print_error "Unsupported architecture: $(uname -m)"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# Warn about unsupported combinations
|
|
if [ "$os" = "linux" ] && [ "$arch" = "arm64" ]; then
|
|
print_error "Linux ARM64 builds are not currently available due to CGO cross-compilation complexity"
|
|
print_error "Please build from source: https://github.com/lukaszraczylo/filepuff-mcp#build-from-source"
|
|
exit 1
|
|
fi
|
|
|
|
echo "${os}_${arch}"
|
|
}
|
|
|
|
check_dependencies() {
|
|
local missing_deps=()
|
|
|
|
# Check for required commands
|
|
for cmd in curl tar; do
|
|
if ! command -v "$cmd" &> /dev/null; then
|
|
missing_deps+=("$cmd")
|
|
fi
|
|
done
|
|
|
|
if [ ${#missing_deps[@]} -ne 0 ]; then
|
|
print_error "Missing required dependencies: ${missing_deps[*]}"
|
|
print_error "Please install them and try again."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
detect_package_manager() {
|
|
if command -v brew &> /dev/null; then
|
|
echo "brew"
|
|
elif command -v apt-get &> /dev/null; then
|
|
echo "apt"
|
|
elif command -v yum &> /dev/null; then
|
|
echo "yum"
|
|
elif command -v pacman &> /dev/null; then
|
|
echo "pacman"
|
|
elif command -v apk &> /dev/null; then
|
|
echo "apk"
|
|
else
|
|
echo "unknown"
|
|
fi
|
|
}
|
|
|
|
install_prerequisites() {
|
|
local pkg_mgr="$1"
|
|
local install_lsp="${2:-false}"
|
|
|
|
print_info "Checking prerequisites..."
|
|
|
|
# Check if ripgrep is installed
|
|
if ! command -v rg &> /dev/null; then
|
|
print_warn "ripgrep not found - required for file search functionality"
|
|
|
|
case "$pkg_mgr" in
|
|
brew)
|
|
print_info "Installing ripgrep via Homebrew..."
|
|
brew install ripgrep
|
|
;;
|
|
apt)
|
|
print_info "Installing ripgrep via apt..."
|
|
sudo apt-get update && sudo apt-get install -y ripgrep
|
|
;;
|
|
yum)
|
|
print_info "Installing ripgrep via yum..."
|
|
sudo yum install -y ripgrep
|
|
;;
|
|
pacman)
|
|
print_info "Installing ripgrep via pacman..."
|
|
sudo pacman -S --noconfirm ripgrep
|
|
;;
|
|
apk)
|
|
print_info "Installing ripgrep via apk..."
|
|
sudo apk add --no-cache ripgrep
|
|
;;
|
|
unknown)
|
|
print_error "Could not detect package manager"
|
|
print_error "Please install ripgrep manually: https://github.com/BurntSushi/ripgrep"
|
|
exit 1
|
|
;;
|
|
esac
|
|
else
|
|
print_info "✓ ripgrep is already installed"
|
|
fi
|
|
|
|
if [ "$install_lsp" = "true" ]; then
|
|
print_info "Installing LSP servers for enhanced IDE features..."
|
|
|
|
# Install gopls (Go LSP)
|
|
if command -v go &> /dev/null && ! command -v gopls &> /dev/null; then
|
|
print_info "Installing gopls (Go language server)..."
|
|
go install golang.org/x/tools/gopls@latest
|
|
fi
|
|
|
|
# Install typescript-language-server (TypeScript/JavaScript)
|
|
if command -v npm &> /dev/null && ! command -v typescript-language-server &> /dev/null; then
|
|
print_info "Installing typescript-language-server..."
|
|
npm install -g typescript-language-server typescript
|
|
fi
|
|
|
|
# Install pylsp (Python LSP)
|
|
if command -v pip3 &> /dev/null && ! python3 -c "import pylsp" 2>/dev/null; then
|
|
print_info "Installing python-lsp-server..."
|
|
pip3 install python-lsp-server
|
|
fi
|
|
|
|
# Install clangd (C/C++)
|
|
if ! command -v clangd &> /dev/null; then
|
|
case "$pkg_mgr" in
|
|
brew)
|
|
print_info "Installing clangd via Homebrew..."
|
|
brew install llvm
|
|
;;
|
|
apt)
|
|
print_info "Installing clangd via apt..."
|
|
sudo apt-get install -y clangd
|
|
;;
|
|
yum)
|
|
print_info "Installing clangd via yum..."
|
|
sudo yum install -y clang-tools-extra
|
|
;;
|
|
pacman)
|
|
print_info "Installing clangd via pacman..."
|
|
sudo pacman -S --noconfirm clang
|
|
;;
|
|
esac
|
|
fi
|
|
fi
|
|
}
|
|
|
|
get_latest_version() {
|
|
local version
|
|
version=$(curl -sSf "https://api.github.com/repos/${REPO}/releases/latest" | grep '"tag_name"' | cut -d'"' -f4)
|
|
|
|
if [ -z "$version" ]; then
|
|
print_error "Failed to fetch latest version from GitHub"
|
|
exit 1
|
|
fi
|
|
|
|
echo "$version"
|
|
}
|
|
|
|
download_and_install() {
|
|
local version="$1"
|
|
local platform="$2"
|
|
local tmpdir
|
|
|
|
tmpdir=$(mktemp -d)
|
|
trap 'rm -rf "$tmpdir"' EXIT
|
|
|
|
print_info "Downloading mcp-filepuff ${version} for ${platform}..."
|
|
|
|
# Construct download URLs
|
|
local archive_name="mcp-filepuff_${version#v}_${platform}.tar.gz"
|
|
local archive_url="https://github.com/${REPO}/releases/download/${version}/${archive_name}"
|
|
local checksum_url="https://github.com/${REPO}/releases/download/${version}/checksums.txt"
|
|
|
|
# Download archive
|
|
if ! curl -sSfL "$archive_url" -o "$tmpdir/$archive_name"; then
|
|
print_error "Failed to download $archive_url"
|
|
exit 1
|
|
fi
|
|
|
|
# Download checksums
|
|
if ! curl -sSfL "$checksum_url" -o "$tmpdir/checksums.txt"; then
|
|
print_warn "Failed to download checksums, skipping verification"
|
|
else
|
|
print_info "Verifying checksum..."
|
|
cd "$tmpdir"
|
|
|
|
# Extract expected checksum for our archive
|
|
local expected_checksum
|
|
expected_checksum=$(grep "$archive_name" checksums.txt | awk '{print $1}')
|
|
|
|
if [ -z "$expected_checksum" ]; then
|
|
print_warn "Checksum not found for $archive_name, skipping verification"
|
|
else
|
|
# Calculate actual checksum (use shasum on macOS, sha256sum on Linux)
|
|
local actual_checksum
|
|
if command -v sha256sum &> /dev/null; then
|
|
actual_checksum=$(sha256sum "$archive_name" | awk '{print $1}')
|
|
elif command -v shasum &> /dev/null; then
|
|
actual_checksum=$(shasum -a 256 "$archive_name" | awk '{print $1}')
|
|
else
|
|
print_warn "No checksum utility found, skipping verification"
|
|
cd - > /dev/null
|
|
return
|
|
fi
|
|
|
|
if [ "$expected_checksum" = "$actual_checksum" ]; then
|
|
print_info "Checksum verification passed"
|
|
else
|
|
print_error "Checksum verification failed"
|
|
print_error "Expected: $expected_checksum"
|
|
print_error "Actual: $actual_checksum"
|
|
exit 1
|
|
fi
|
|
fi
|
|
cd - > /dev/null
|
|
fi
|
|
|
|
# Extract archive
|
|
print_info "Extracting archive..."
|
|
tar -xzf "$tmpdir/$archive_name" -C "$tmpdir"
|
|
|
|
# Ensure install directory exists
|
|
if [ ! -d "$INSTALL_DIR" ]; then
|
|
print_info "Creating installation directory: $INSTALL_DIR"
|
|
mkdir -p "$INSTALL_DIR"
|
|
fi
|
|
|
|
# Install binary
|
|
print_info "Installing to $INSTALL_DIR/$BINARY_NAME..."
|
|
if [ -w "$INSTALL_DIR" ]; then
|
|
cp "$tmpdir/$BINARY_NAME" "$INSTALL_DIR/$BINARY_NAME"
|
|
chmod +x "$INSTALL_DIR/$BINARY_NAME"
|
|
else
|
|
print_warn "No write permission to $INSTALL_DIR, trying with sudo..."
|
|
sudo cp "$tmpdir/$BINARY_NAME" "$INSTALL_DIR/$BINARY_NAME"
|
|
sudo chmod +x "$INSTALL_DIR/$BINARY_NAME"
|
|
fi
|
|
|
|
print_info "Installation complete!"
|
|
}
|
|
|
|
check_path() {
|
|
if ! echo "$PATH" | grep -q "$INSTALL_DIR"; then
|
|
print_warn "$INSTALL_DIR is not in your PATH"
|
|
print_warn "Add it to your PATH by adding this line to your shell profile:"
|
|
echo ""
|
|
echo " export PATH=\"\$PATH:$INSTALL_DIR\""
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
verify_installation() {
|
|
if command -v "$BINARY_NAME" &> /dev/null; then
|
|
local installed_version
|
|
installed_version=$("$BINARY_NAME" -version 2>&1 || echo "unknown")
|
|
print_info "Successfully installed: $installed_version"
|
|
else
|
|
print_warn "Binary installed but not found in PATH"
|
|
print_info "You can run it directly: $INSTALL_DIR/$BINARY_NAME"
|
|
fi
|
|
}
|
|
|
|
main() {
|
|
print_info "MCP Filepuff Installation Script"
|
|
echo ""
|
|
|
|
# Parse command line arguments
|
|
local install_lsp="false"
|
|
local skip_prereqs="false"
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--with-lsp)
|
|
install_lsp="true"
|
|
shift
|
|
;;
|
|
--skip-prereqs)
|
|
skip_prereqs="true"
|
|
shift
|
|
;;
|
|
--help)
|
|
echo "Usage: install.sh [OPTIONS]"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --with-lsp Install LSP servers (gopls, typescript-language-server, pylsp, clangd)"
|
|
echo " --skip-prereqs Skip prerequisite installation (ripgrep, LSP servers)"
|
|
echo " --help Show this help message"
|
|
exit 0
|
|
;;
|
|
*)
|
|
print_error "Unknown option: $1"
|
|
print_error "Use --help for usage information"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Check dependencies
|
|
check_dependencies
|
|
|
|
# Detect platform
|
|
local platform
|
|
platform=$(detect_platform)
|
|
print_info "Detected platform: $platform"
|
|
|
|
# Detect package manager
|
|
local pkg_mgr
|
|
pkg_mgr=$(detect_package_manager)
|
|
print_info "Detected package manager: $pkg_mgr"
|
|
echo ""
|
|
|
|
# Install prerequisites unless skipped
|
|
if [ "$skip_prereqs" != "true" ]; then
|
|
install_prerequisites "$pkg_mgr" "$install_lsp"
|
|
echo ""
|
|
fi
|
|
|
|
# Get latest version
|
|
local version
|
|
version=$(get_latest_version)
|
|
print_info "Latest version: $version"
|
|
echo ""
|
|
|
|
# Download and install
|
|
download_and_install "$version" "$platform"
|
|
echo ""
|
|
|
|
# Check PATH
|
|
check_path
|
|
|
|
# Verify installation
|
|
verify_installation
|
|
echo ""
|
|
|
|
print_info "To get started, run: $BINARY_NAME --help"
|
|
|
|
if [ "$install_lsp" != "true" ]; then
|
|
echo ""
|
|
print_info "Tip: Run with --with-lsp to install LSP servers for enhanced IDE features"
|
|
fi
|
|
}
|
|
|
|
# Run main function
|
|
main "$@"
|