#!/bin/bash # Universal Installer for Nushell Plugins # Downloads and installs the latest release of nushell plugins for your platform set -e # Configuration REPO_OWNER="YOUR_ORG" # Replace with actual GitHub org/user REPO_NAME="nushell-plugins" GITHUB_REPO="${REPO_OWNER}/${REPO_NAME}" BASE_URL="https://github.com/${GITHUB_REPO}" API_URL="https://api.github.com/repos/${GITHUB_REPO}" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Default values INSTALL_DIR="/usr/local/bin" VERSION="" PLATFORM="" FORCE=false DRY_RUN=false QUIET=false TEMP_DIR="" # Functions log() { if [ "$QUIET" != "true" ]; then echo -e "${BLUE}[INFO]${NC} $1" fi } warn() { echo -e "${YELLOW}[WARN]${NC} $1" >&2 } error() { echo -e "${RED}[ERROR]${NC} $1" >&2 } success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } usage() { cat << EOF Universal Installer for Nushell Plugins USAGE: $0 [OPTIONS] OPTIONS: -d, --install-dir DIR Installation directory (default: /usr/local/bin) -v, --version VERSION Specific version to install (default: latest) -p, --platform PLATFORM Force specific platform (auto-detected by default) -f, --force Force installation even if already installed --dry-run Show what would be done without doing it --quiet Suppress non-essential output -h, --help Show this help message EXAMPLES: # Install latest version to default location $0 # Install to custom directory $0 --install-dir ~/.local/bin # Install specific version $0 --version v1.2.3 # Force specific platform $0 --platform linux-amd64 PLATFORMS: linux-amd64 Linux x86_64 linux-arm64 Linux ARM64 darwin-amd64 macOS Intel darwin-arm64 macOS Apple Silicon windows-amd64 Windows x86_64 REQUIREMENTS: - curl or wget - tar (for Unix-like systems) - nushell (nu command should be available) - Write permissions to installation directory MORE INFO: Repository: ${BASE_URL} Releases: ${BASE_URL}/releases EOF } # Platform detection detect_platform() { local os="" local arch="" # Detect OS case "$(uname -s)" in Linux*) os="linux" ;; Darwin*) os="darwin" ;; CYGWIN*|MINGW*|MSYS*) os="windows" ;; *) error "Unsupported operating system: $(uname -s)" exit 1 ;; esac # Detect architecture case "$(uname -m)" in x86_64|amd64) arch="amd64" ;; aarch64|arm64) arch="arm64" ;; armv7l) arch="arm32" ;; *) error "Unsupported architecture: $(uname -m)" exit 1 ;; esac echo "${os}-${arch}" } # Check if command exists command_exists() { command -v "$1" >/dev/null 2>&1 } # Check prerequisites check_prerequisites() { log "Checking prerequisites..." # Check for download tools if ! command_exists curl && ! command_exists wget; then error "Neither curl nor wget found. Please install one of them." exit 1 fi # Check for tar (Unix-like systems) if [ "$PLATFORM" != "windows-amd64" ] && ! command_exists tar; then error "tar command not found. Please install tar." exit 1 fi # Check for nushell if ! command_exists nu; then warn "nushell (nu) not found in PATH. You'll need to install nushell to use these plugins." warn "Visit: https://www.nushell.sh/book/installation.html" fi # Check write permissions if [ ! -w "$(dirname "$INSTALL_DIR")" ]; then error "No write permission to $(dirname "$INSTALL_DIR")" error "Try running with sudo or choose a different directory with --install-dir" exit 1 fi } # Download file download_file() { local url="$1" local output="$2" log "Downloading: $url" if command_exists curl; then curl -L --fail --progress-bar "$url" -o "$output" elif command_exists wget; then wget --progress=bar:force:noscroll "$url" -O "$output" else error "No download tool available" exit 1 fi } # Get latest release info get_latest_release() { local api_url="${API_URL}/releases/latest" log "Fetching latest release information..." if command_exists curl; then curl -s "$api_url" elif command_exists wget; then wget -qO- "$api_url" else error "No download tool available" exit 1 fi } # Get specific release info get_release_info() { local version="$1" local api_url="${API_URL}/releases/tags/${version}" log "Fetching release information for ${version}..." if command_exists curl; then curl -s "$api_url" elif command_exists wget; then wget -qO- "$api_url" else error "No download tool available" exit 1 fi } # Parse JSON (simple parsing for our needs) parse_json_value() { local json="$1" local key="$2" echo "$json" | sed -n "s/.*\"$key\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" | head -1 } # Find download URL for platform find_download_url() { local release_json="$1" local platform="$2" # Look for asset with platform name echo "$release_json" | grep -o '"browser_download_url":"[^"]*"' | \ grep "$platform" | \ head -1 | \ sed 's/"browser_download_url":"\([^"]*\)"/\1/' } # Extract archive extract_archive() { local archive="$1" local dest_dir="$2" log "Extracting archive to $dest_dir..." case "$archive" in *.tar.gz) tar -xzf "$archive" -C "$dest_dir" ;; *.zip) if command_exists unzip; then unzip -q "$archive" -d "$dest_dir" else error "unzip command not found. Please install unzip to extract .zip files." exit 1 fi ;; *) error "Unsupported archive format: $archive" exit 1 ;; esac } # Install plugins install_plugins() { local extract_dir="$1" log "Installing plugins to $INSTALL_DIR..." # Find the extracted directory (might be nested) local plugin_dir="" if [ -d "$extract_dir" ]; then # Look for nu_plugin_* files directly or in subdirectories plugin_dir=$(find "$extract_dir" -name "nu_plugin_*" -type f -executable | head -1 | xargs dirname) if [ -z "$plugin_dir" ]; then # Try to find a directory with plugins plugin_dir=$(find "$extract_dir" -type d -name "*nushell-plugins*" | head -1) if [ -z "$plugin_dir" ]; then plugin_dir="$extract_dir" fi fi fi if [ ! -d "$plugin_dir" ]; then error "Could not find plugin directory in extracted archive" exit 1 fi log "Found plugins in: $plugin_dir" # Create install directory if it doesn't exist mkdir -p "$INSTALL_DIR" # Copy plugin binaries local installed_count=0 for plugin in "$plugin_dir"/nu_plugin_*; do if [ -f "$plugin" ] && [ -x "$plugin" ]; then local plugin_name=$(basename "$plugin") local dest_path="$INSTALL_DIR/$plugin_name" if [ "$DRY_RUN" = "true" ]; then log "Would install: $plugin_name -> $dest_path" else log "Installing: $plugin_name" cp "$plugin" "$dest_path" chmod +x "$dest_path" fi installed_count=$((installed_count + 1)) fi done if [ $installed_count -eq 0 ]; then error "No plugin binaries found to install" exit 1 fi success "Installed $installed_count plugins" # Copy installation script if available if [ -f "$plugin_dir/install_nu_plugins.nu" ] && [ "$DRY_RUN" != "true" ]; then log "Running nushell installation script..." if command_exists nu; then cd "$plugin_dir" nu install_nu_plugins.nu --bin-path "$INSTALL_DIR" || { warn "Installation script failed, but binaries were copied" } else warn "Nushell not available, skipping automatic plugin registration" fi fi } # Cleanup temporary files cleanup() { if [ -n "$TEMP_DIR" ] && [ -d "$TEMP_DIR" ]; then log "Cleaning up temporary files..." rm -rf "$TEMP_DIR" fi } # Main installation function main() { # Set up cleanup trap trap cleanup EXIT log "Nushell Plugins Universal Installer" log "Repository: $GITHUB_REPO" # Auto-detect platform if not specified if [ -z "$PLATFORM" ]; then PLATFORM=$(detect_platform) log "Detected platform: $PLATFORM" else log "Using specified platform: $PLATFORM" fi # Check prerequisites check_prerequisites # Get release information local release_json="" if [ -z "$VERSION" ]; then log "Getting latest release..." release_json=$(get_latest_release) VERSION=$(parse_json_value "$release_json" "tag_name") else log "Getting release $VERSION..." release_json=$(get_release_info "$VERSION") fi if [ -z "$release_json" ] || [ "$release_json" = "null" ]; then error "Failed to get release information" exit 1 fi log "Version: $VERSION" # Find download URL local download_url=$(find_download_url "$release_json" "$PLATFORM") if [ -z "$download_url" ]; then error "No download found for platform: $PLATFORM" error "Available platforms can be found at: ${BASE_URL}/releases/tag/${VERSION}" exit 1 fi log "Download URL: $download_url" if [ "$DRY_RUN" = "true" ]; then log "DRY RUN: Would download and install from $download_url" log "DRY RUN: Would install to $INSTALL_DIR" return 0 fi # Create temporary directory TEMP_DIR=$(mktemp -d) local archive_name=$(basename "$download_url") local archive_path="$TEMP_DIR/$archive_name" # Download archive download_file "$download_url" "$archive_path" # Verify download if [ ! -f "$archive_path" ]; then error "Download failed: $archive_path not found" exit 1 fi # Extract archive extract_archive "$archive_path" "$TEMP_DIR" # Install plugins install_plugins "$TEMP_DIR" success "Installation completed successfully!" # Show next steps echo "" echo "🎉 Nushell plugins have been installed to: $INSTALL_DIR" echo "" echo "📝 Next steps:" echo " 1. Make sure $INSTALL_DIR is in your PATH" echo " 2. In nushell, register plugins with:" # List installed plugins for plugin in "$INSTALL_DIR"/nu_plugin_*; do if [ -f "$plugin" ] && [ -x "$plugin" ]; then echo " plugin add $plugin" fi done echo "" echo "💡 Or run this one-liner in nushell:" echo " ls $INSTALL_DIR/nu_plugin_* | each { |plugin| plugin add \$plugin.name }" echo "" echo "🔗 More info: ${BASE_URL}" } # Parse command line arguments while [[ $# -gt 0 ]]; do case $1 in -d|--install-dir) INSTALL_DIR="$2" shift 2 ;; -v|--version) VERSION="$2" shift 2 ;; -p|--platform) PLATFORM="$2" shift 2 ;; -f|--force) FORCE=true shift ;; --dry-run) DRY_RUN=true shift ;; --quiet) QUIET=true shift ;; -h|--help) usage exit 0 ;; *) error "Unknown option: $1" usage exit 1 ;; esac done # Run main function main