From 16c3ea98671be8aad26e906285143b296e2b66bd Mon Sep 17 00:00:00 2001 From: Tw93 Date: Sun, 22 Mar 2026 14:39:25 +0800 Subject: [PATCH] fix(windows): stabilize install and prerelease versioning --- .gitattributes | 3 ++ .github/workflows/release-windows.yml | 12 ++--- .gitignore | 2 + VERSION | 1 + install.ps1 | 15 ++++-- lib/clean/dev.ps1 | 61 +++++++++++++++++++++ lib/core/common.ps1 | 5 +- lib/core/tui_binaries.ps1 | 76 +++++++++++++++++++-------- lib/core/version.ps1 | 41 +++++++++++++++ mole.ps1 | 7 ++- scripts/build-exe.ps1 | 14 ++--- scripts/build-msi.ps1 | 14 ++--- scripts/build-release.ps1 | 14 ++--- 13 files changed, 211 insertions(+), 54 deletions(-) create mode 100644 .gitattributes create mode 100644 VERSION create mode 100644 lib/core/version.ps1 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b148563 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +* text=auto eol=lf +*.ps1 text eol=lf +*.cmd text eol=crlf diff --git a/.github/workflows/release-windows.yml b/.github/workflows/release-windows.yml index 8e2b66e..af26f48 100644 --- a/.github/workflows/release-windows.yml +++ b/.github/workflows/release-windows.yml @@ -47,13 +47,11 @@ jobs: $version = "${{ github.ref }}" -replace '^refs/tags/[Vv]', '' $version = $version -replace '-windows$', '' } else { - $content = Get-Content mole.ps1 -Raw - if ($content -match '\$script:MOLE_VER\s*=\s*"([^"]+)"') { - $version = $Matches[1] - } else { - Write-Error "Could not detect version" - exit 1 - } + $version = (Get-Content VERSION -Raw).Trim() + } + if (-not $version) { + Write-Error "Could not detect version" + exit 1 } Write-Host "Version: $version" "VERSION=$version" >> $env:GITHUB_OUTPUT diff --git a/.gitignore b/.gitignore index 1486866..76aff12 100644 --- a/.gitignore +++ b/.gitignore @@ -89,3 +89,5 @@ mole_guidelines.md run_tests.ps1 session.json journal/2026-03-11-safe-remove-design.md +mole.cmd +mo.cmd diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..5e57fb8 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.29.0 diff --git a/install.ps1 b/install.ps1 index 70c312f..cd6e903 100644 --- a/install.ps1 +++ b/install.ps1 @@ -19,14 +19,17 @@ Set-StrictMode -Version Latest # Configuration # ============================================================================ -$script:VERSION = "1.0.0" $script:SourceDir = if ($MyInvocation.MyCommand.Path) { Split-Path -Parent $MyInvocation.MyCommand.Path } else { $PSScriptRoot } +$script:CoreDir = Join-Path $script:SourceDir "lib\core" $script:ShortcutName = "Mole" +. (Join-Path $script:CoreDir "version.ps1") +$script:VERSION = Get-MoleVersionString -RootDir $script:SourceDir + # Colors (using [char]27 for PowerShell 5.1 compatibility) $script:ESC = [char]27 $script:Colors = @{ @@ -39,7 +42,7 @@ $script:Colors = @{ NC = "$($script:ESC)[0m" } -. (Join-Path $script:SourceDir "lib\core\tui_binaries.ps1") +. (Join-Path $script:CoreDir "tui_binaries.ps1") # ============================================================================ # Helpers @@ -258,7 +261,13 @@ function Ensure-OptionalTuiTools { foreach ($tool in $tools) { $destination = Join-Path $RootDir $tool.Output - $binPath = Ensure-TuiBinary -Name $tool.Name -WindowsDir $RootDir -DestinationPath $destination -SourcePath $tool.Source -Version $version + try { + $binPath = Ensure-TuiBinary -Name $tool.Name -WindowsDir $RootDir -DestinationPath $destination -SourcePath $tool.Source -Version $version + } + catch { + Write-MoleWarning "Skipping $($tool.Name).exe after a non-fatal setup error: $_" + $binPath = $null + } if ($binPath) { Write-Success "Ready: $($tool.Name).exe" } diff --git a/lib/clean/dev.ps1 b/lib/clean/dev.ps1 index 1aff033..0547a91 100644 --- a/lib/clean/dev.ps1 +++ b/lib/clean/dev.ps1 @@ -259,6 +259,64 @@ function Clear-GoCaches { } } +function Get-MiseCachePath { + <# + .SYNOPSIS + Resolve the mise cache directory without touching installs/plugins + #> + + if (-not [string]::IsNullOrWhiteSpace($env:MISE_CACHE_DIR)) { + return $env:MISE_CACHE_DIR + } + + if (-not (Get-Command mise -ErrorAction SilentlyContinue)) { + return $null + } + + try { + $cachePath = (& mise cache path 2>$null | Select-Object -First 1) + if ($LASTEXITCODE -eq 0 -and -not [string]::IsNullOrWhiteSpace($cachePath)) { + return $cachePath.Trim() + } + } + catch { + Write-Debug "mise cache path failed: $_" + } + + return $null +} + +function Clear-MiseCache { + <# + .SYNOPSIS + Clean mise internal cache only + .DESCRIPTION + Respects MISE_CACHE_DIR and never removes the installs/plugins data tree. + #> + + $hasMise = [bool](Get-Command mise -ErrorAction SilentlyContinue) + $cachePath = Get-MiseCachePath + $clearedByCommand = $false + + if ($hasMise -and -not (Test-DryRunMode)) { + try { + $null = & mise cache clear 2>&1 + if ($LASTEXITCODE -eq 0) { + Write-Success "mise cache" + Set-SectionActivity + $clearedByCommand = $true + } + } + catch { + Write-Debug "mise cache clear failed: $_" + } + } + + if (-not $clearedByCommand -and $cachePath -and (Test-Path $cachePath)) { + Clear-DirectoryContents -Path $cachePath -Description "mise cache" + } +} + # ============================================================================ # Rust Ecosystem # ============================================================================ @@ -701,6 +759,9 @@ function Invoke-DevToolsCleanup { # Go ecosystem Clear-GoCaches + + # mise cache + Clear-MiseCache # Rust ecosystem Clear-RustCaches diff --git a/lib/core/common.ps1 b/lib/core/common.ps1 index 2cef321..21589a3 100644 --- a/lib/core/common.ps1 +++ b/lib/core/common.ps1 @@ -16,6 +16,9 @@ $script:MOLE_CORE_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path $script:MOLE_LIB_DIR = Split-Path -Parent $script:MOLE_CORE_DIR $script:MOLE_ROOT_DIR = Split-Path -Parent $script:MOLE_LIB_DIR +# Version helpers are standalone and safe to load before the other core modules. +. "$script:MOLE_CORE_DIR\version.ps1" + # ============================================================================ # Load Core Modules # ============================================================================ @@ -36,7 +39,7 @@ $script:MOLE_ROOT_DIR = Split-Path -Parent $script:MOLE_LIB_DIR # Version Information # ============================================================================ -$script:MOLE_VERSION = "1.0.0" +$script:MOLE_VERSION = Get-MoleVersionString -RootDir $script:MOLE_ROOT_DIR $script:MOLE_BUILD_DATE = "2026-01-07" function Get-MoleVersion { diff --git a/lib/core/tui_binaries.ps1 b/lib/core/tui_binaries.ps1 index 2874501..b92ec88 100644 --- a/lib/core/tui_binaries.ps1 +++ b/lib/core/tui_binaries.ps1 @@ -9,6 +9,9 @@ if ((Get-Variable -Name 'MOLE_TUI_BINARIES_LOADED' -Scope Script -ErrorAction Si } $script:MOLE_TUI_BINARIES_LOADED = $true +$script:MOLE_TUI_CORE_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path +. "$script:MOLE_TUI_CORE_DIR\version.ps1" + $script:MoleGitHubRepo = "tw93/Mole" $script:MoleGitHubApiRoot = "https://api.github.com/repos/$($script:MoleGitHubRepo)" $script:MoleGitHubHeaders = @{ @@ -19,17 +22,7 @@ $script:MoleGitHubHeaders = @{ function Get-MoleVersionFromScriptFile { param([string]$WindowsDir) - $moleScript = Join-Path $WindowsDir "mole.ps1" - if (-not (Test-Path $moleScript)) { - return $null - } - - $content = Get-Content $moleScript -Raw - if ($content -match '\$script:MOLE_VER\s*=\s*"([^"]+)"') { - return $Matches[1] - } - - return $null + return Get-MoleVersionString -RootDir $WindowsDir } function Get-TuiBinaryAssetName { @@ -136,18 +129,50 @@ function Build-TuiBinary { Write-Host "Building $Name tool..." -ForegroundColor Cyan + $stdoutPath = Join-Path $env:TEMP "mole-$Name-build.stdout.log" + $stderrPath = Join-Path $env:TEMP "mole-$Name-build.stderr.log" + + foreach ($path in @($stdoutPath, $stderrPath)) { + if (Test-Path $path) { + Remove-Item $path -Force -ErrorAction SilentlyContinue + } + } + Push-Location $WindowsDir try { - $result = & go build -o "$DestinationPath" $SourcePath 2>&1 - if ($LASTEXITCODE -ne 0) { - Write-Host "Failed to build $Name tool: $result" -ForegroundColor Red - return $false - } + $process = Start-Process -FilePath "go" ` + -ArgumentList @("build", "-o", $DestinationPath, $SourcePath) ` + -NoNewWindow ` + -Wait ` + -PassThru ` + -RedirectStandardOutput $stdoutPath ` + -RedirectStandardError $stderrPath + } + catch { + Write-Host "Failed to start go build for $Name tool: $_" -ForegroundColor Red + return $false } finally { Pop-Location } + $buildOutput = @() + foreach ($path in @($stdoutPath, $stderrPath)) { + if (Test-Path $path) { + $content = (Get-Content $path -Raw).Trim() + if ($content) { + $buildOutput += $content + } + Remove-Item $path -Force -ErrorAction SilentlyContinue + } + } + + if ($process.ExitCode -ne 0) { + $message = if ($buildOutput.Count -gt 0) { $buildOutput -join [Environment]::NewLine } else { "go build exited with code $($process.ExitCode)" } + Write-Host "Failed to build $Name tool: $message" -ForegroundColor Red + return $false + } + return $true } @@ -169,15 +194,24 @@ function Ensure-TuiBinary { $Version = Get-MoleVersionFromScriptFile -WindowsDir $WindowsDir } - if (Restore-PrebuiltTuiBinary -Name $Name -WindowsDir $WindowsDir -DestinationPath $DestinationPath -Version $Version) { - return $DestinationPath + try { + if (Restore-PrebuiltTuiBinary -Name $Name -WindowsDir $WindowsDir -DestinationPath $DestinationPath -Version $Version) { + return $DestinationPath + } + } + catch { + Write-Host "Failed to restore prebuilt $Name tool: $_" -ForegroundColor Yellow } if (Get-Command go -ErrorAction SilentlyContinue) { - if (Build-TuiBinary -Name $Name -WindowsDir $WindowsDir -DestinationPath $DestinationPath -SourcePath $SourcePath) { - return $DestinationPath + try { + if (Build-TuiBinary -Name $Name -WindowsDir $WindowsDir -DestinationPath $DestinationPath -SourcePath $SourcePath) { + return $DestinationPath + } + } + catch { + Write-Host "Failed to prepare $Name tool: $_" -ForegroundColor Yellow } - return $null } return $null diff --git a/lib/core/version.ps1 b/lib/core/version.ps1 new file mode 100644 index 0000000..e7262a2 --- /dev/null +++ b/lib/core/version.ps1 @@ -0,0 +1,41 @@ +# Mole - Version helpers +# Provides a single source of truth for the Windows version string. + +#Requires -Version 5.1 +Set-StrictMode -Version Latest + +if ((Get-Variable -Name 'MOLE_VERSION_HELPERS_LOADED' -Scope Script -ErrorAction SilentlyContinue) -and $script:MOLE_VERSION_HELPERS_LOADED) { + return +} +$script:MOLE_VERSION_HELPERS_LOADED = $true + +$script:MoleDefaultVersion = "1.29.0" + +function Get-MoleVersionFilePath { + param([string]$RootDir) + + if ([string]::IsNullOrWhiteSpace($RootDir)) { + return $null + } + + return Join-Path $RootDir "VERSION" +} + +function Get-MoleVersionString { + param( + [string]$RootDir, + [string]$DefaultVersion = $script:MoleDefaultVersion + ) + + $versionFile = Get-MoleVersionFilePath -RootDir $RootDir + if (-not $versionFile -or -not (Test-Path $versionFile)) { + return $DefaultVersion + } + + $version = (Get-Content $versionFile -Raw).Trim() + if ([string]::IsNullOrWhiteSpace($version)) { + return $DefaultVersion + } + + return $version +} diff --git a/mole.ps1 b/mole.ps1 index 53c0914..12b73d5 100644 --- a/mole.ps1 +++ b/mole.ps1 @@ -24,6 +24,12 @@ Set-StrictMode -Version Latest $script:MOLE_ROOT = Split-Path -Parent $MyInvocation.MyCommand.Path $script:MOLE_BIN = Join-Path $script:MOLE_ROOT "bin" $script:MOLE_LIB = Join-Path $script:MOLE_ROOT "lib" +$script:MOLE_CORE = Join-Path $script:MOLE_LIB "core" + +# Read the version before loading the rest of the runtime so every entrypoint +# resolves the same release tag. +. "$script:MOLE_CORE\version.ps1" +$script:MOLE_VER = Get-MoleVersionString -RootDir $script:MOLE_ROOT # Import core . "$script:MOLE_LIB\core\common.ps1" @@ -32,7 +38,6 @@ $script:MOLE_LIB = Join-Path $script:MOLE_ROOT "lib" # Version Info # ============================================================================ -$script:MOLE_VER = "1.0.0" $script:MOLE_BUILD = "2026-01-07" function Show-Version { diff --git a/scripts/build-exe.ps1 b/scripts/build-exe.ps1 index 8170093..d0f6d47 100644 --- a/scripts/build-exe.ps1 +++ b/scripts/build-exe.ps1 @@ -20,15 +20,15 @@ Set-StrictMode -Version Latest $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $projectRoot = Split-Path -Parent $scriptDir $releaseDir = Join-Path $projectRoot "release" +$versionFile = Join-Path $projectRoot "VERSION" -# Read version from mole.ps1 if not provided +# Read version from VERSION if not provided if (-not $Version) { - $moleScript = Join-Path $projectRoot "mole.ps1" - $content = Get-Content $moleScript -Raw - if ($content -match '\$script:MOLE_VER\s*=\s*"([^"]+)"') { - $Version = $Matches[1] - } else { - Write-Host "Error: Could not detect version from mole.ps1" -ForegroundColor Red + if (Test-Path $versionFile) { + $Version = (Get-Content $versionFile -Raw).Trim() + } + if (-not $Version) { + Write-Host "Error: Could not detect version from VERSION" -ForegroundColor Red exit 1 } } diff --git a/scripts/build-msi.ps1 b/scripts/build-msi.ps1 index 72174dc..5580f41 100644 --- a/scripts/build-msi.ps1 +++ b/scripts/build-msi.ps1 @@ -21,15 +21,15 @@ $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $projectRoot = Split-Path -Parent $scriptDir $releaseDir = Join-Path $projectRoot "release" $wixSource = Join-Path $scriptDir "mole-installer.wxs" +$versionFile = Join-Path $projectRoot "VERSION" -# Read version from mole.ps1 if not provided +# Read version from VERSION if not provided if (-not $Version) { - $moleScript = Join-Path $projectRoot "mole.ps1" - $content = Get-Content $moleScript -Raw - if ($content -match '\$script:MOLE_VER\s*=\s*"([^"]+)"') { - $Version = $Matches[1] - } else { - Write-Host "Error: Could not detect version from mole.ps1" -ForegroundColor Red + if (Test-Path $versionFile) { + $Version = (Get-Content $versionFile -Raw).Trim() + } + if (-not $Version) { + Write-Host "Error: Could not detect version from VERSION" -ForegroundColor Red exit 1 } } diff --git a/scripts/build-release.ps1 b/scripts/build-release.ps1 index 1fbf7ea..49a5d3d 100644 --- a/scripts/build-release.ps1 +++ b/scripts/build-release.ps1 @@ -23,15 +23,15 @@ $projectRoot = Split-Path -Parent $scriptDir $releaseDir = Join-Path $projectRoot "release" $binDir = Join-Path $projectRoot "bin" $cmdDir = Join-Path $projectRoot "cmd" +$versionFile = Join-Path $projectRoot "VERSION" -# Read version from mole.ps1 if not provided +# Read version from VERSION if not provided if (-not $Version) { - $moleScript = Join-Path $projectRoot "mole.ps1" - $content = Get-Content $moleScript -Raw - if ($content -match '\$script:MOLE_VER\s*=\s*"([^"]+)"') { - $Version = $Matches[1] - } else { - Write-Host "Error: Could not detect version from mole.ps1" -ForegroundColor Red + if (Test-Path $versionFile) { + $Version = (Get-Content $versionFile -Raw).Trim() + } + if (-not $Version) { + Write-Host "Error: Could not detect version from VERSION" -ForegroundColor Red exit 1 } }