841 lines
24 KiB
PowerShell
841 lines
24 KiB
PowerShell
![]() |
# Universal Nushell + Plugins Bootstrap Installer for Windows
|
|||
|
# PowerShell script that installs Nushell and plugins without any prerequisites
|
|||
|
#
|
|||
|
# This script:
|
|||
|
# - Detects Windows platform (x86_64/arm64)
|
|||
|
# - Downloads or builds Nushell + plugins
|
|||
|
# - Installs to user location (%USERPROFILE%\.local\bin) or system (C:\Program Files\Nushell)
|
|||
|
# - Updates PATH in system/user environment
|
|||
|
# - Creates initial Nushell configuration
|
|||
|
# - Registers all plugins automatically
|
|||
|
# - Verifies installation
|
|||
|
|
|||
|
param(
|
|||
|
[switch]$System,
|
|||
|
[switch]$User = $true,
|
|||
|
[switch]$NoPath,
|
|||
|
[switch]$NoConfig,
|
|||
|
[switch]$NoPlugins,
|
|||
|
[switch]$BuildFromSource,
|
|||
|
[switch]$Verify,
|
|||
|
[switch]$Uninstall,
|
|||
|
[string]$Version = "",
|
|||
|
[switch]$Help
|
|||
|
)
|
|||
|
|
|||
|
# Configuration
|
|||
|
$RepoUrl = "https://github.com/your-org/nushell-plugins"
|
|||
|
$BinaryRepoUrl = "$RepoUrl/releases/download"
|
|||
|
$InstallDirUser = "$env:USERPROFILE\.local\bin"
|
|||
|
$InstallDirSystem = "${env:ProgramFiles}\Nushell\bin"
|
|||
|
$ConfigDir = "$env:USERPROFILE\.config\nushell"
|
|||
|
$TempDir = "$env:TEMP\nushell-install-$(Get-Random)"
|
|||
|
|
|||
|
# Colors for output
|
|||
|
$Colors = @{
|
|||
|
Red = "Red"
|
|||
|
Green = "Green"
|
|||
|
Yellow = "Yellow"
|
|||
|
Blue = "Blue"
|
|||
|
Magenta = "Magenta"
|
|||
|
Cyan = "Cyan"
|
|||
|
}
|
|||
|
|
|||
|
# Logging functions
|
|||
|
function Write-LogInfo {
|
|||
|
param([string]$Message)
|
|||
|
Write-Host "ℹ️ $Message" -ForegroundColor $Colors.Blue
|
|||
|
}
|
|||
|
|
|||
|
function Write-LogSuccess {
|
|||
|
param([string]$Message)
|
|||
|
Write-Host "✅ $Message" -ForegroundColor $Colors.Green
|
|||
|
}
|
|||
|
|
|||
|
function Write-LogWarn {
|
|||
|
param([string]$Message)
|
|||
|
Write-Host "⚠️ $Message" -ForegroundColor $Colors.Yellow
|
|||
|
}
|
|||
|
|
|||
|
function Write-LogError {
|
|||
|
param([string]$Message)
|
|||
|
Write-Host "❌ $Message" -ForegroundColor $Colors.Red
|
|||
|
}
|
|||
|
|
|||
|
function Write-LogHeader {
|
|||
|
param([string]$Message)
|
|||
|
Write-Host ""
|
|||
|
Write-Host "🚀 $Message" -ForegroundColor $Colors.Magenta
|
|||
|
Write-Host ("=" * $Message.Length) -ForegroundColor $Colors.Magenta
|
|||
|
}
|
|||
|
|
|||
|
# Usage information
|
|||
|
function Show-Usage {
|
|||
|
@"
|
|||
|
Nushell + Plugins Bootstrap Installer for Windows
|
|||
|
|
|||
|
USAGE:
|
|||
|
# Download and run:
|
|||
|
Invoke-WebRequest -Uri "install-url/install.ps1" | Invoke-Expression
|
|||
|
|
|||
|
# Or download and run with parameters:
|
|||
|
.\install.ps1 [-System] [-User] [-NoPath] [-NoConfig] [-NoPlugins] [-BuildFromSource] [-Verify] [-Uninstall] [-Version <version>] [-Help]
|
|||
|
|
|||
|
PARAMETERS:
|
|||
|
-System Install to system directory (C:\Program Files\Nushell, requires admin)
|
|||
|
-User Install to user directory (~\.local\bin) [default]
|
|||
|
-NoPath Don't modify PATH environment variable
|
|||
|
-NoConfig Don't create initial nushell configuration
|
|||
|
-NoPlugins Install only nushell, skip plugins
|
|||
|
-BuildFromSource Build from source instead of downloading binaries
|
|||
|
-Verify Verify installation after completion
|
|||
|
-Uninstall Remove nushell and plugins
|
|||
|
-Version <version> Install specific version (default: latest)
|
|||
|
-Help Show this help message
|
|||
|
|
|||
|
EXAMPLES:
|
|||
|
# Default installation (user directory, with plugins)
|
|||
|
.\install.ps1
|
|||
|
|
|||
|
# System installation (requires admin)
|
|||
|
.\install.ps1 -System
|
|||
|
|
|||
|
# Install without plugins
|
|||
|
.\install.ps1 -NoPlugins
|
|||
|
|
|||
|
# Build from source
|
|||
|
.\install.ps1 -BuildFromSource
|
|||
|
|
|||
|
# Install specific version
|
|||
|
.\install.ps1 -Version "v0.107.1"
|
|||
|
"@
|
|||
|
}
|
|||
|
|
|||
|
# Platform detection
|
|||
|
function Get-Platform {
|
|||
|
$arch = $env:PROCESSOR_ARCHITECTURE
|
|||
|
switch ($arch) {
|
|||
|
"AMD64" { return "windows-x86_64" }
|
|||
|
"ARM64" { return "windows-aarch64" }
|
|||
|
default {
|
|||
|
Write-LogError "Unsupported architecture: $arch"
|
|||
|
exit 1
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Check if running as administrator
|
|||
|
function Test-Admin {
|
|||
|
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|||
|
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
|
|||
|
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
|||
|
}
|
|||
|
|
|||
|
# Check if command exists
|
|||
|
function Test-Command {
|
|||
|
param([string]$Command)
|
|||
|
try {
|
|||
|
Get-Command $Command -ErrorAction Stop | Out-Null
|
|||
|
return $true
|
|||
|
} catch {
|
|||
|
return $false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Check dependencies for building from source
|
|||
|
function Test-BuildDependencies {
|
|||
|
$missing = @()
|
|||
|
|
|||
|
if (-not (Test-Command "git")) {
|
|||
|
$missing += "git"
|
|||
|
}
|
|||
|
|
|||
|
if (-not (Test-Command "cargo")) {
|
|||
|
$missing += "cargo"
|
|||
|
}
|
|||
|
|
|||
|
if (-not (Test-Command "rustc")) {
|
|||
|
$missing += "rust"
|
|||
|
}
|
|||
|
|
|||
|
if ($missing.Count -gt 0) {
|
|||
|
Write-LogError "Missing build dependencies: $($missing -join ', ')"
|
|||
|
Write-LogInfo "Please install these tools or use binary installation instead"
|
|||
|
return $false
|
|||
|
}
|
|||
|
|
|||
|
return $true
|
|||
|
}
|
|||
|
|
|||
|
# Download file with progress
|
|||
|
function Get-FileWithProgress {
|
|||
|
param(
|
|||
|
[string]$Url,
|
|||
|
[string]$OutputPath,
|
|||
|
[string]$Description = "file"
|
|||
|
)
|
|||
|
|
|||
|
Write-LogInfo "Downloading $Description..."
|
|||
|
|
|||
|
try {
|
|||
|
$webClient = New-Object System.Net.WebClient
|
|||
|
$webClient.DownloadFile($Url, $OutputPath)
|
|||
|
Write-LogSuccess "Downloaded $Description"
|
|||
|
return $true
|
|||
|
} catch {
|
|||
|
Write-LogError "Failed to download $Description from $Url"
|
|||
|
Write-LogError $_.Exception.Message
|
|||
|
return $false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Extract archive
|
|||
|
function Expand-Archive {
|
|||
|
param(
|
|||
|
[string]$ArchivePath,
|
|||
|
[string]$DestinationPath
|
|||
|
)
|
|||
|
|
|||
|
Write-LogInfo "Extracting archive..."
|
|||
|
|
|||
|
try {
|
|||
|
if ($ArchivePath -like "*.zip") {
|
|||
|
Expand-Archive -Path $ArchivePath -DestinationPath $DestinationPath -Force
|
|||
|
} elseif ($ArchivePath -like "*.tar.gz") {
|
|||
|
# Use tar if available (Windows 10 build 17063 and later)
|
|||
|
if (Test-Command "tar") {
|
|||
|
& tar -xzf $ArchivePath -C $DestinationPath
|
|||
|
} else {
|
|||
|
throw "tar command not found for .tar.gz extraction"
|
|||
|
}
|
|||
|
} else {
|
|||
|
throw "Unsupported archive format: $ArchivePath"
|
|||
|
}
|
|||
|
Write-LogSuccess "Extracted archive"
|
|||
|
return $true
|
|||
|
} catch {
|
|||
|
Write-LogError "Failed to extract $ArchivePath"
|
|||
|
Write-LogError $_.Exception.Message
|
|||
|
return $false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Get latest release version
|
|||
|
function Get-LatestVersion {
|
|||
|
try {
|
|||
|
$response = Invoke-RestMethod -Uri "https://api.github.com/repos/your-org/nushell-plugins/releases/latest"
|
|||
|
return $response.tag_name
|
|||
|
} catch {
|
|||
|
Write-LogWarn "Could not detect latest version, using v0.107.1"
|
|||
|
return "v0.107.1"
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Download and install binaries
|
|||
|
function Install-FromBinaries {
|
|||
|
param(
|
|||
|
[string]$Platform,
|
|||
|
[string]$Version,
|
|||
|
[string]$InstallDir,
|
|||
|
[bool]$IncludePlugins
|
|||
|
)
|
|||
|
|
|||
|
Write-LogHeader "Installing from Pre-built Binaries"
|
|||
|
|
|||
|
# Create temporary directory
|
|||
|
New-Item -ItemType Directory -Path $TempDir -Force | Out-Null
|
|||
|
Set-Location $TempDir
|
|||
|
|
|||
|
# Determine archive name and URL
|
|||
|
$archiveFormat = if ($Platform -like "*windows*") { "zip" } else { "tar.gz" }
|
|||
|
$archiveName = "nushell-plugins-$Platform-$Version.$archiveFormat"
|
|||
|
$downloadUrl = "$BinaryRepoUrl/$Version/$archiveName"
|
|||
|
|
|||
|
# Download archive
|
|||
|
if (-not (Get-FileWithProgress -Url $downloadUrl -OutputPath $archiveName -Description "Nushell distribution")) {
|
|||
|
Write-LogWarn "Binary download failed, trying alternative..."
|
|||
|
# Try without version prefix
|
|||
|
$archiveName = "nushell-plugins-$Platform.$archiveFormat"
|
|||
|
$downloadUrl = "$BinaryRepoUrl/latest/$archiveName"
|
|||
|
if (-not (Get-FileWithProgress -Url $downloadUrl -OutputPath $archiveName -Description "Nushell distribution (latest)")) {
|
|||
|
Write-LogError "Failed to download binaries"
|
|||
|
return $false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Extract archive
|
|||
|
if (-not (Expand-Archive -ArchivePath $archiveName -DestinationPath ".")) {
|
|||
|
return $false
|
|||
|
}
|
|||
|
|
|||
|
# Find extracted directory
|
|||
|
$extractDir = Get-ChildItem -Directory | Select-Object -First 1
|
|||
|
if (-not $extractDir) {
|
|||
|
Write-LogError "No extracted directory found"
|
|||
|
return $false
|
|||
|
}
|
|||
|
|
|||
|
Write-LogInfo "Installing binaries to $InstallDir..."
|
|||
|
|
|||
|
# Create install directory
|
|||
|
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
|
|||
|
|
|||
|
# Install nushell binary
|
|||
|
$nuBinary = "nu.exe"
|
|||
|
$nuSourcePath = Join-Path $extractDir.FullName $nuBinary
|
|||
|
|
|||
|
if (Test-Path $nuSourcePath) {
|
|||
|
Copy-Item $nuSourcePath -Destination $InstallDir
|
|||
|
Write-LogSuccess "Installed nushell binary"
|
|||
|
} else {
|
|||
|
Write-LogError "Nushell binary not found in archive"
|
|||
|
return $false
|
|||
|
}
|
|||
|
|
|||
|
# Install plugins if requested
|
|||
|
if ($IncludePlugins) {
|
|||
|
$pluginFiles = Get-ChildItem -Path $extractDir.FullName -Name "nu_plugin_*.exe"
|
|||
|
$pluginCount = 0
|
|||
|
|
|||
|
foreach ($pluginFile in $pluginFiles) {
|
|||
|
$pluginSourcePath = Join-Path $extractDir.FullName $pluginFile
|
|||
|
Copy-Item $pluginSourcePath -Destination $InstallDir
|
|||
|
$pluginCount++
|
|||
|
}
|
|||
|
|
|||
|
if ($pluginCount -gt 0) {
|
|||
|
Write-LogSuccess "Installed $pluginCount plugins"
|
|||
|
} else {
|
|||
|
Write-LogWarn "No plugins found in archive"
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Copy configuration files if they exist
|
|||
|
$configSourceDir = Join-Path $extractDir.FullName "config"
|
|||
|
if (Test-Path $configSourceDir) {
|
|||
|
New-Item -ItemType Directory -Path $ConfigDir -Force | Out-Null
|
|||
|
Copy-Item -Path "$configSourceDir\*" -Destination $ConfigDir -Recurse -Force
|
|||
|
Write-LogSuccess "Installed configuration files"
|
|||
|
}
|
|||
|
|
|||
|
return $true
|
|||
|
}
|
|||
|
|
|||
|
# Build and install from source
|
|||
|
function Install-FromSource {
|
|||
|
param(
|
|||
|
[string]$InstallDir,
|
|||
|
[bool]$IncludePlugins
|
|||
|
)
|
|||
|
|
|||
|
Write-LogHeader "Building from Source"
|
|||
|
|
|||
|
# Check dependencies
|
|||
|
if (-not (Test-BuildDependencies)) {
|
|||
|
return $false
|
|||
|
}
|
|||
|
|
|||
|
# Create temporary directory
|
|||
|
New-Item -ItemType Directory -Path $TempDir -Force | Out-Null
|
|||
|
Set-Location $TempDir
|
|||
|
|
|||
|
# Clone repository
|
|||
|
Write-LogInfo "Cloning repository..."
|
|||
|
try {
|
|||
|
& git clone --recursive $RepoUrl nushell-plugins
|
|||
|
Set-Location nushell-plugins
|
|||
|
} catch {
|
|||
|
Write-LogError "Failed to clone repository"
|
|||
|
return $false
|
|||
|
}
|
|||
|
|
|||
|
# Build nushell
|
|||
|
Write-LogInfo "Building nushell..."
|
|||
|
try {
|
|||
|
if (Test-Command "just") {
|
|||
|
& just build-nushell
|
|||
|
} else {
|
|||
|
# Fallback to manual build
|
|||
|
Set-Location nushell
|
|||
|
& cargo build --release --features "plugin,network,sqlite,trash-support,rustls-tls"
|
|||
|
Set-Location ..
|
|||
|
}
|
|||
|
} catch {
|
|||
|
Write-LogError "Failed to build nushell"
|
|||
|
return $false
|
|||
|
}
|
|||
|
|
|||
|
# Build plugins if requested
|
|||
|
if ($IncludePlugins) {
|
|||
|
Write-LogInfo "Building plugins..."
|
|||
|
try {
|
|||
|
if (Test-Command "just") {
|
|||
|
& just build
|
|||
|
} else {
|
|||
|
# Build plugins manually
|
|||
|
$pluginDirs = Get-ChildItem -Directory -Name "nu_plugin_*" | Where-Object { $_ -ne "nushell" }
|
|||
|
foreach ($pluginDir in $pluginDirs) {
|
|||
|
Write-LogInfo "Building $pluginDir..."
|
|||
|
Set-Location $pluginDir
|
|||
|
try {
|
|||
|
& cargo build --release
|
|||
|
Write-LogSuccess "Built $pluginDir"
|
|||
|
} catch {
|
|||
|
Write-LogWarn "Failed to build $pluginDir"
|
|||
|
}
|
|||
|
Set-Location ..
|
|||
|
}
|
|||
|
}
|
|||
|
} catch {
|
|||
|
Write-LogWarn "Failed to build some plugins"
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Install binaries
|
|||
|
Write-LogInfo "Installing binaries to $InstallDir..."
|
|||
|
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
|
|||
|
|
|||
|
# Install nushell
|
|||
|
$nuBinary = "nushell\target\release\nu.exe"
|
|||
|
if (Test-Path $nuBinary) {
|
|||
|
Copy-Item $nuBinary -Destination "$InstallDir\nu.exe"
|
|||
|
Write-LogSuccess "Installed nushell binary"
|
|||
|
} else {
|
|||
|
Write-LogError "Nushell binary not found"
|
|||
|
return $false
|
|||
|
}
|
|||
|
|
|||
|
# Install plugins
|
|||
|
if ($IncludePlugins) {
|
|||
|
$pluginCount = 0
|
|||
|
$pluginDirs = Get-ChildItem -Directory -Name "nu_plugin_*" | Where-Object { $_ -ne "nushell" }
|
|||
|
|
|||
|
foreach ($pluginDir in $pluginDirs) {
|
|||
|
$pluginBinary = "$pluginDir\target\release\$pluginDir.exe"
|
|||
|
if (Test-Path $pluginBinary) {
|
|||
|
Copy-Item $pluginBinary -Destination "$InstallDir\$pluginDir.exe"
|
|||
|
$pluginCount++
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ($pluginCount -gt 0) {
|
|||
|
Write-LogSuccess "Installed $pluginCount plugins"
|
|||
|
} else {
|
|||
|
Write-LogWarn "No plugins were built successfully"
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return $true
|
|||
|
}
|
|||
|
|
|||
|
# Register plugins with nushell
|
|||
|
function Register-Plugins {
|
|||
|
param(
|
|||
|
[string]$InstallDir
|
|||
|
)
|
|||
|
|
|||
|
$nuBinary = Join-Path $InstallDir "nu.exe"
|
|||
|
|
|||
|
if (-not (Test-Path $nuBinary)) {
|
|||
|
Write-LogError "Nushell binary not found: $nuBinary"
|
|||
|
return $false
|
|||
|
}
|
|||
|
|
|||
|
Write-LogHeader "Registering Plugins"
|
|||
|
|
|||
|
# Find all plugin binaries
|
|||
|
$pluginFiles = Get-ChildItem -Path $InstallDir -Name "nu_plugin_*.exe"
|
|||
|
$pluginCount = 0
|
|||
|
|
|||
|
foreach ($pluginFile in $pluginFiles) {
|
|||
|
$pluginPath = Join-Path $InstallDir $pluginFile
|
|||
|
$pluginName = [System.IO.Path]::GetFileNameWithoutExtension($pluginFile)
|
|||
|
|
|||
|
Write-LogInfo "Registering $pluginName..."
|
|||
|
|
|||
|
try {
|
|||
|
& $nuBinary -c "plugin add '$pluginPath'"
|
|||
|
Write-LogSuccess "Registered $pluginName"
|
|||
|
$pluginCount++
|
|||
|
} catch {
|
|||
|
Write-LogWarn "Failed to register $pluginName"
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ($pluginCount -gt 0) {
|
|||
|
Write-LogSuccess "Successfully registered $pluginCount plugins"
|
|||
|
} else {
|
|||
|
Write-LogWarn "No plugins were registered"
|
|||
|
}
|
|||
|
|
|||
|
return $true
|
|||
|
}
|
|||
|
|
|||
|
# Update PATH environment variable
|
|||
|
function Update-PathEnvironment {
|
|||
|
param(
|
|||
|
[string]$InstallDir,
|
|||
|
[bool]$SystemInstall
|
|||
|
)
|
|||
|
|
|||
|
Write-LogHeader "Updating PATH Environment"
|
|||
|
|
|||
|
# Determine scope
|
|||
|
$scope = if ($SystemInstall) { "Machine" } else { "User" }
|
|||
|
|
|||
|
try {
|
|||
|
# Get current PATH
|
|||
|
$currentPath = [Environment]::GetEnvironmentVariable("PATH", $scope)
|
|||
|
|
|||
|
# Check if already in PATH
|
|||
|
if ($currentPath -split ';' -contains $InstallDir) {
|
|||
|
Write-LogInfo "PATH already contains $InstallDir"
|
|||
|
return $true
|
|||
|
}
|
|||
|
|
|||
|
# Add to PATH
|
|||
|
$newPath = "$InstallDir;$currentPath"
|
|||
|
[Environment]::SetEnvironmentVariable("PATH", $newPath, $scope)
|
|||
|
|
|||
|
# Update current session
|
|||
|
$env:PATH = "$InstallDir;$env:PATH"
|
|||
|
|
|||
|
Write-LogSuccess "Updated PATH environment variable"
|
|||
|
Write-LogInfo "Restart your terminal to apply changes globally"
|
|||
|
|
|||
|
return $true
|
|||
|
} catch {
|
|||
|
Write-LogError "Failed to update PATH environment variable"
|
|||
|
Write-LogError $_.Exception.Message
|
|||
|
return $false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Create initial nushell configuration
|
|||
|
function New-NushellConfig {
|
|||
|
Write-LogHeader "Creating Nushell Configuration"
|
|||
|
|
|||
|
# Create config directory
|
|||
|
New-Item -ItemType Directory -Path $ConfigDir -Force | Out-Null
|
|||
|
|
|||
|
# Create basic config.nu if it doesn't exist
|
|||
|
$configFile = Join-Path $ConfigDir "config.nu"
|
|||
|
if (-not (Test-Path $configFile)) {
|
|||
|
@"
|
|||
|
# Nushell Configuration
|
|||
|
# Created by nushell-plugins installer
|
|||
|
|
|||
|
# Set up basic configuration
|
|||
|
`$env.config = {
|
|||
|
show_banner: false
|
|||
|
edit_mode: emacs
|
|||
|
shell_integration: true
|
|||
|
|
|||
|
table: {
|
|||
|
mode: rounded
|
|||
|
index_mode: always
|
|||
|
show_empty: true
|
|||
|
padding: { left: 1, right: 1 }
|
|||
|
}
|
|||
|
|
|||
|
completions: {
|
|||
|
case_sensitive: false
|
|||
|
quick: true
|
|||
|
partial: true
|
|||
|
algorithm: "prefix"
|
|||
|
}
|
|||
|
|
|||
|
history: {
|
|||
|
max_size: 10000
|
|||
|
sync_on_enter: true
|
|||
|
file_format: "plaintext"
|
|||
|
}
|
|||
|
|
|||
|
filesize: {
|
|||
|
metric: false
|
|||
|
format: "auto"
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Load custom commands and aliases
|
|||
|
# Add your custom configuration below
|
|||
|
"@ | Out-File -FilePath $configFile -Encoding utf8
|
|||
|
Write-LogSuccess "Created config.nu"
|
|||
|
} else {
|
|||
|
Write-LogInfo "config.nu already exists, skipping"
|
|||
|
}
|
|||
|
|
|||
|
# Create basic env.nu if it doesn't exist
|
|||
|
$envFile = Join-Path $ConfigDir "env.nu"
|
|||
|
if (-not (Test-Path $envFile)) {
|
|||
|
@"
|
|||
|
# Nushell Environment Configuration
|
|||
|
# Created by nushell-plugins installer
|
|||
|
|
|||
|
# Environment variables
|
|||
|
`$env.EDITOR = "notepad"
|
|||
|
`$env.BROWSER = "msedge"
|
|||
|
|
|||
|
# Nushell specific environment
|
|||
|
`$env.NU_LIB_DIRS = [
|
|||
|
(`$nu.config-path | path dirname | path join "scripts")
|
|||
|
]
|
|||
|
|
|||
|
`$env.NU_PLUGIN_DIRS = [
|
|||
|
(`$nu.config-path | path dirname | path join "plugins")
|
|||
|
]
|
|||
|
|
|||
|
# Add your custom environment variables below
|
|||
|
"@ | Out-File -FilePath $envFile -Encoding utf8
|
|||
|
Write-LogSuccess "Created env.nu"
|
|||
|
} else {
|
|||
|
Write-LogInfo "env.nu already exists, skipping"
|
|||
|
}
|
|||
|
|
|||
|
# Create directories
|
|||
|
$scriptsDir = Join-Path $ConfigDir "scripts"
|
|||
|
$pluginsDir = Join-Path $ConfigDir "plugins"
|
|||
|
New-Item -ItemType Directory -Path $scriptsDir -Force | Out-Null
|
|||
|
New-Item -ItemType Directory -Path $pluginsDir -Force | Out-Null
|
|||
|
|
|||
|
return $true
|
|||
|
}
|
|||
|
|
|||
|
# Verify installation
|
|||
|
function Test-Installation {
|
|||
|
param(
|
|||
|
[string]$InstallDir
|
|||
|
)
|
|||
|
|
|||
|
$nuBinary = Join-Path $InstallDir "nu.exe"
|
|||
|
|
|||
|
Write-LogHeader "Verifying Installation"
|
|||
|
|
|||
|
# Check if nushell binary exists
|
|||
|
if (-not (Test-Path $nuBinary)) {
|
|||
|
Write-LogError "Nushell binary not found: $nuBinary"
|
|||
|
return $false
|
|||
|
}
|
|||
|
|
|||
|
# Test nushell version
|
|||
|
Write-LogInfo "Testing nushell binary..."
|
|||
|
try {
|
|||
|
$versionOutput = & $nuBinary --version
|
|||
|
Write-LogSuccess "Nushell version: $versionOutput"
|
|||
|
} catch {
|
|||
|
Write-LogError "Failed to run nushell binary"
|
|||
|
Write-LogError $_.Exception.Message
|
|||
|
return $false
|
|||
|
}
|
|||
|
|
|||
|
# Test basic nushell command
|
|||
|
Write-LogInfo "Testing basic nushell functionality..."
|
|||
|
try {
|
|||
|
$testOutput = & $nuBinary -c "echo 'Hello from Nushell'"
|
|||
|
if ($testOutput -eq "Hello from Nushell") {
|
|||
|
Write-LogSuccess "Basic nushell functionality works"
|
|||
|
} else {
|
|||
|
Write-LogWarn "Unexpected output from basic test"
|
|||
|
}
|
|||
|
} catch {
|
|||
|
Write-LogError "Basic nushell functionality failed"
|
|||
|
return $false
|
|||
|
}
|
|||
|
|
|||
|
# List registered plugins
|
|||
|
Write-LogInfo "Checking registered plugins..."
|
|||
|
try {
|
|||
|
$pluginOutput = & $nuBinary -c "plugin list"
|
|||
|
$pluginCount = ($pluginOutput | Select-String "nu_plugin_").Count
|
|||
|
if ($pluginCount -gt 0) {
|
|||
|
Write-LogSuccess "Found $pluginCount registered plugins"
|
|||
|
} else {
|
|||
|
Write-LogWarn "No plugins are registered"
|
|||
|
}
|
|||
|
} catch {
|
|||
|
Write-LogWarn "Could not check plugin status"
|
|||
|
}
|
|||
|
|
|||
|
# Check PATH
|
|||
|
Write-LogInfo "Checking PATH configuration..."
|
|||
|
try {
|
|||
|
$nuInPath = Get-Command nu -ErrorAction SilentlyContinue
|
|||
|
if ($nuInPath) {
|
|||
|
Write-LogSuccess "Nushell is available in PATH"
|
|||
|
} else {
|
|||
|
Write-LogWarn "Nushell is not in PATH. You may need to restart your terminal."
|
|||
|
}
|
|||
|
} catch {
|
|||
|
Write-LogWarn "Could not verify PATH configuration"
|
|||
|
}
|
|||
|
|
|||
|
Write-LogSuccess "Installation verification complete!"
|
|||
|
return $true
|
|||
|
}
|
|||
|
|
|||
|
# Uninstall function
|
|||
|
function Uninstall-Nushell {
|
|||
|
Write-LogHeader "Uninstalling Nushell"
|
|||
|
|
|||
|
$removedFiles = 0
|
|||
|
|
|||
|
# Remove from user directory
|
|||
|
if (Test-Path $InstallDirUser) {
|
|||
|
$userBinaries = Get-ChildItem -Path $InstallDirUser -Name "nu.exe", "nu_plugin_*.exe" -ErrorAction SilentlyContinue
|
|||
|
foreach ($binary in $userBinaries) {
|
|||
|
$filePath = Join-Path $InstallDirUser $binary
|
|||
|
Remove-Item $filePath -Force -ErrorAction SilentlyContinue
|
|||
|
Write-LogSuccess "Removed $binary from $InstallDirUser"
|
|||
|
$removedFiles++
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Remove from system directory (if accessible)
|
|||
|
if ((Test-Admin) -and (Test-Path $InstallDirSystem)) {
|
|||
|
$systemBinaries = Get-ChildItem -Path $InstallDirSystem -Name "nu.exe", "nu_plugin_*.exe" -ErrorAction SilentlyContinue
|
|||
|
foreach ($binary in $systemBinaries) {
|
|||
|
$filePath = Join-Path $InstallDirSystem $binary
|
|||
|
Remove-Item $filePath -Force -ErrorAction SilentlyContinue
|
|||
|
Write-LogSuccess "Removed $binary from $InstallDirSystem"
|
|||
|
$removedFiles++
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Option to remove configuration
|
|||
|
$response = Read-Host "Remove nushell configuration directory ($ConfigDir)? [y/N]"
|
|||
|
if ($response -match "^[yY]") {
|
|||
|
if (Test-Path $ConfigDir) {
|
|||
|
Remove-Item $ConfigDir -Recurse -Force -ErrorAction SilentlyContinue
|
|||
|
Write-LogSuccess "Removed configuration directory"
|
|||
|
}
|
|||
|
} else {
|
|||
|
Write-LogInfo "Configuration directory preserved"
|
|||
|
}
|
|||
|
|
|||
|
if ($removedFiles -gt 0) {
|
|||
|
Write-LogSuccess "Uninstallation complete ($removedFiles files removed)"
|
|||
|
Write-LogWarn "You may need to manually remove PATH entries from your environment variables"
|
|||
|
} else {
|
|||
|
Write-LogWarn "No nushell files found to remove"
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Main installation function
|
|||
|
function Main {
|
|||
|
# Handle help
|
|||
|
if ($Help) {
|
|||
|
Show-Usage
|
|||
|
exit 0
|
|||
|
}
|
|||
|
|
|||
|
# Handle uninstall
|
|||
|
if ($Uninstall) {
|
|||
|
Uninstall-Nushell
|
|||
|
exit 0
|
|||
|
}
|
|||
|
|
|||
|
# Show header
|
|||
|
Write-LogHeader "Nushell + Plugins Installer for Windows"
|
|||
|
Write-LogInfo "Universal bootstrap installer for Nushell and plugins"
|
|||
|
Write-LogInfo ""
|
|||
|
|
|||
|
# Detect platform
|
|||
|
$platform = Get-Platform
|
|||
|
Write-LogInfo "Detected platform: $platform"
|
|||
|
|
|||
|
# Determine installation directory and check privileges
|
|||
|
if ($System) {
|
|||
|
$installDir = $InstallDirSystem
|
|||
|
if (-not (Test-Admin)) {
|
|||
|
Write-LogError "System installation requires administrator privileges"
|
|||
|
Write-LogInfo "Run PowerShell as Administrator or use -User for user installation"
|
|||
|
exit 1
|
|||
|
}
|
|||
|
} else {
|
|||
|
$installDir = $InstallDirUser
|
|||
|
}
|
|||
|
|
|||
|
Write-LogInfo "Installing to: $installDir"
|
|||
|
|
|||
|
# Get version if not specified
|
|||
|
if (-not $Version) {
|
|||
|
$Version = Get-LatestVersion
|
|||
|
}
|
|||
|
Write-LogInfo "Version: $Version"
|
|||
|
|
|||
|
# Cleanup function
|
|||
|
$cleanup = {
|
|||
|
if (Test-Path $TempDir) {
|
|||
|
Remove-Item $TempDir -Recurse -Force -ErrorAction SilentlyContinue
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
# Install based on method
|
|||
|
if ($BuildFromSource) {
|
|||
|
if (-not (Install-FromSource -InstallDir $installDir -IncludePlugins (-not $NoPlugins))) {
|
|||
|
Write-LogError "Source installation failed"
|
|||
|
exit 1
|
|||
|
}
|
|||
|
} else {
|
|||
|
if (-not (Install-FromBinaries -Platform $platform -Version $Version -InstallDir $installDir -IncludePlugins (-not $NoPlugins))) {
|
|||
|
Write-LogError "Binary installation failed"
|
|||
|
exit 1
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Register plugins
|
|||
|
if (-not $NoPlugins) {
|
|||
|
Register-Plugins -InstallDir $installDir
|
|||
|
}
|
|||
|
|
|||
|
# Update PATH
|
|||
|
if (-not $NoPath) {
|
|||
|
Update-PathEnvironment -InstallDir $installDir -SystemInstall $System
|
|||
|
}
|
|||
|
|
|||
|
# Create configuration
|
|||
|
if (-not $NoConfig) {
|
|||
|
New-NushellConfig
|
|||
|
}
|
|||
|
|
|||
|
# Verify installation
|
|||
|
if ($Verify) {
|
|||
|
if (-not (Test-Installation -InstallDir $installDir)) {
|
|||
|
Write-LogError "Installation verification failed"
|
|||
|
exit 1
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Final success message
|
|||
|
Write-LogHeader "Installation Complete!"
|
|||
|
Write-LogSuccess "Nushell has been successfully installed to $installDir"
|
|||
|
|
|||
|
if (-not $NoPlugins) {
|
|||
|
Write-LogSuccess "Plugins have been registered with Nushell"
|
|||
|
}
|
|||
|
|
|||
|
if (-not $NoPath) {
|
|||
|
Write-LogInfo "To use Nushell, restart your terminal or start a new PowerShell session"
|
|||
|
}
|
|||
|
|
|||
|
Write-LogInfo ""
|
|||
|
Write-LogInfo "Try running: nu --version"
|
|||
|
Write-LogInfo "Or start Nushell with: nu"
|
|||
|
|
|||
|
if (-not $NoPlugins) {
|
|||
|
Write-LogInfo "Check plugins with: nu -c 'plugin list'"
|
|||
|
}
|
|||
|
|
|||
|
Write-LogInfo ""
|
|||
|
Write-LogInfo "For more information, visit: https://nushell.sh"
|
|||
|
Write-LogInfo ""
|
|||
|
Write-LogSuccess "Happy shell scripting! 🚀"
|
|||
|
|
|||
|
} finally {
|
|||
|
& $cleanup
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
# Run main function
|
|||
|
Main
|