jdk-man.psm1
|
# jdk-man.psm1 — Windows JDK version manager (PowerShell 7+ module) $script:ConfigDir = Join-Path $env:LOCALAPPDATA 'jdk-man' $script:ConfigPath = Join-Path $script:ConfigDir 'jdk-config.json' # ── Config I/O (.NET methods, UTF-8 no-BOM) ────────────────────────── function Get-JdkConfig { if (-not (Test-Path $script:ConfigPath)) { $null = New-Item -Path $script:ConfigDir -ItemType Directory -Force [System.IO.File]::WriteAllText($script:ConfigPath, '{}', [System.Text.UTF8Encoding]::new($false)) Write-Host "Created config: $script:ConfigPath" -ForegroundColor Gray return @{} } try { $content = [System.IO.File]::ReadAllText($script:ConfigPath, [System.Text.UTF8Encoding]::new($false)) if ([string]::IsNullOrWhiteSpace($content)) { return @{} } $hash = $content | ConvertFrom-Json -AsHashtable foreach ($k in @($hash.Keys)) { if ($hash[$k] -isnot [string]) { Write-Warning "Invalid entry for version '$k' in config, removing." $hash.Remove($k) } } return $hash } catch { Write-Warning "Failed to parse config, resetting to empty. Error: $_" [System.IO.File]::WriteAllText($script:ConfigPath, '{}', [System.Text.UTF8Encoding]::new($false)) return @{} } } function Set-JdkConfig([hashtable]$Hash) { $json = $Hash | ConvertTo-Json -Compress [System.IO.File]::WriteAllText($script:ConfigPath, $json, [System.Text.UTF8Encoding]::new($false)) } # ── PATH helpers ────────────────────────────────────────────────────── function Update-SessionPath([string]$NewBin, [hashtable]$Config) { $knownBins = foreach ($p in $Config.Values) { $bin = Join-Path $p 'bin' if ($bin -ne $NewBin) { $bin } } $variablePatterns = @('%JAVA_HOME%\bin', '%JAVA_HOME%/bin') $filtered = ($env:Path -split ';') | Where-Object { $item = $_ if (-not $item) { return $false } if ($item -in $knownBins) { return $false } foreach ($pat in $variablePatterns) { if ($item -like $pat) { return $false } } $true } $env:Path = "$NewBin;$($filtered -join ';')" } function Ensure-UserPathHasJavaBin { $userPath = [Environment]::GetEnvironmentVariable('Path', 'User') $target = '%JAVA_HOME%\bin' $entries = if ($userPath) { $userPath -split ';' } else { @() } if ($entries -contains $target) { Write-Host "[User] %JAVA_HOME%\bin already in user PATH" -ForegroundColor Gray return } $newPath = if ([string]::IsNullOrEmpty($userPath)) { $target } else { "$target;$($userPath.Trim(';'))" } [Environment]::SetEnvironmentVariable('Path', $newPath, 'User') Write-Host "[User] Added %JAVA_HOME%\bin to beginning of user PATH" -ForegroundColor Green } # ── Main entry point ───────────────────────────────────────────────── function jdk { <# .SYNOPSIS Windows JDK version manager. .DESCRIPTION Manage multiple JDK installations: list available versions, switch for the current session, set a persistent default, add new JDKs, and remove old ones. Configuration is stored in $env:LOCALAPPDATA\jdk-man\jdk-config.json. .PARAMETER Command Subcommand to run: list, use, default, add, remove. .PARAMETER Version JDK version key as registered in config (e.g. "8", "17", "21"). .PARAMETER RemainingArgs Extra positional arguments. For "add", this is the JDK root path. .EXAMPLE jdk list List all configured JDK versions with status. .EXAMPLE jdk use 17 Switch JAVA_HOME and PATH for the current session only. .EXAMPLE jdk default 21 Permanently set user-level JAVA_HOME and ensure %JAVA_HOME%\bin is in user PATH. .EXAMPLE jdk add 17 D:\sdk\jdk\jdk-17.0.18+8 Register a JDK installation and optionally set it as default. .EXAMPLE jdk remove 8 Remove a JDK version from config. #> param( [Parameter(Position = 0)] [string]$Command, [Parameter(Position = 1)] [string]$Version, [Parameter(ValueFromRemainingArguments)] [string[]]$RemainingArgs ) if (-not $Command) { Get-Help jdk return } $config = Get-JdkConfig switch ($Command.ToLower()) { 'list' { if ($config.Count -eq 0) { Write-Host "No JDK versions configured. Use 'jdk add <version> <path>' to add one." -ForegroundColor Yellow return } Write-Host "Available JDK versions (from $script:ConfigPath):" foreach ($kv in $config.GetEnumerator() | Sort-Object Key) { $path = $kv.Value $exists = Test-Path "$path\bin\java.exe" $status = if ($exists) { '[OK]' } else { '[MISSING]' } $mark = if ($env:JAVA_HOME -eq $path) { '*' } else { ' ' } Write-Host "$mark $($kv.Key) - $path $status" } } 'use' { if (-not $Version) { throw "Usage: jdk use <version>" } $path = $config[$Version] if (-not $path) { throw "Unknown version '$Version'. Available: $($config.Keys -join ', ')" } if (-not (Test-Path "$path\bin\java.exe")) { throw "JDK $Version not found at '$path'" } $env:JAVA_HOME = $path Update-SessionPath "$path\bin" $config Write-Host "[Session] Switched to JDK $Version : $path" -ForegroundColor Green Write-Host '' java -version } 'default' { if (-not $Version) { throw "Usage: jdk default <version>" } $path = $config[$Version] if (-not $path) { throw "Unknown version '$Version'. Available: $($config.Keys -join ', ')" } if (-not (Test-Path "$path\bin\java.exe")) { throw "JDK $Version not found at '$path'" } [Environment]::SetEnvironmentVariable('JAVA_HOME', $path, 'User') Ensure-UserPathHasJavaBin $env:JAVA_HOME = $path Update-SessionPath "$path\bin" $config Write-Host "[User] JAVA_HOME permanently set to JDK $Version : $path" -ForegroundColor Yellow java -version } 'add' { $pathArg = $RemainingArgs[0] if (-not $Version -or -not $pathArg) { throw "Usage: jdk add <version> <path>" } $pathArg = $pathArg.TrimEnd('\') if (-not (Test-Path "$pathArg\bin\java.exe")) { throw "Invalid path: '$pathArg' does not contain bin\java.exe" } if ($config.ContainsKey($Version)) { Write-Warning "Version '$Version' already exists with path '$($config[$Version])'. Overwriting." } $config[$Version] = $pathArg Set-JdkConfig $config Write-Host "[Config] Added/updated version $Version -> $pathArg" -ForegroundColor Green $answer = Read-Host "Set JDK $Version as default? (y/N)" if ($answer -match '^[yY]') { [Environment]::SetEnvironmentVariable('JAVA_HOME', $pathArg, 'User') Ensure-UserPathHasJavaBin $env:JAVA_HOME = $pathArg Update-SessionPath "$pathArg\bin" $config Write-Host "[User] JAVA_HOME permanently set to JDK $Version : $pathArg" -ForegroundColor Yellow java -version } } 'remove' { if (-not $Version) { throw "Usage: jdk remove <version>" } if (-not $config.ContainsKey($Version)) { throw "Unknown version '$Version'. Available: $($config.Keys -join ', ')" } if ($env:JAVA_HOME -eq $config[$Version]) { Write-Warning "Version '$Version' is the current JAVA_HOME. It will be removed from config but JAVA_HOME will not be changed." } $config.Remove($Version) Set-JdkConfig $config Write-Host "[Config] Removed version $Version" -ForegroundColor Green } default { Write-Warning "Unknown command '$Command'." Get-Help jdk } } } # ── Tab completion ──────────────────────────────────────────────────── Register-ArgumentCompleter -CommandName jdk -ParameterName Version -ScriptBlock { param($wordToComplete, $commandAst, $cursorPosition) $cfgPath = Join-Path $env:LOCALAPPDATA 'jdk-man\jdk-config.json' if (-not (Test-Path $cfgPath)) { return } $content = [System.IO.File]::ReadAllText($cfgPath, [System.Text.UTF8Encoding]::new($false)) if ([string]::IsNullOrWhiteSpace($content)) { return } ($content | ConvertFrom-Json -AsHashtable).Keys | Where-Object { $_ -like "$wordToComplete*" } | Sort-Object | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } } Export-ModuleMember -Function jdk |