Skip to content

Commit 5183ed2

Browse files
Address PR #77 review threads: cache resilience, variant dedupe, docs, and perf schema
1 parent 34de022 commit 5183ed2

4 files changed

Lines changed: 109 additions & 7 deletions

File tree

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,21 @@ If the command returns results, the font is installed. If it returns nothing, th
8787

8888
When you run `Install-NerdFont` again without `-Force`, fonts that are already installed in the requested scope are skipped. Downloaded archives are also cached per Nerd Fonts release so retries and repeated installs do not need to fetch the same ZIP again.
8989

90+
Cache locations:
91+
92+
- Windows: `%LOCALAPPDATA%/PSModule/NerdFonts/cache`
93+
- macOS and Linux: `$HOME/.cache/PSModule/NerdFonts`
94+
95+
You can inspect the active cache path in PowerShell with:
96+
97+
```powershell
98+
if ($IsWindows) {
99+
Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'PSModule/NerdFonts/cache'
100+
} else {
101+
Join-Path $HOME '.cache/PSModule/NerdFonts'
102+
}
103+
```
104+
90105
### Update an installed NerdFont
91106

92107
Individual font files do not embed a NerdFonts release version, so there is no direct way to check whether an installed

scripts/perf-results.jsonl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
{"Iteration":"1.0.33-pre006-variant-all","Scenario":"Single-Hack","DurationMs":1171,"DurationS":1.17,"Timestamp":"2026-05-17T14:05:52.0905786+02:00","Error":null,"Module":"1.0.33"}
2323
{"Iteration":"1.0.33-pre006-variant-all","Scenario":"Subset-Hack+FiraCode+JetBrainsMono","DurationMs":6096,"DurationS":6.1,"Timestamp":"2026-05-17T14:06:02.0498948+02:00","Error":null,"Module":"1.0.33"}
2424
{"Iteration":"1.0.33-pre006-variant-all","Scenario":"Subset-AlreadyInstalled","DurationMs":35,"DurationS":0.04,"Timestamp":"2026-05-17T14:06:02.1490854+02:00","Error":null,"Module":"1.0.33"}
25-
{"timestampUtc":"2026-05-17T12:06:18.1677417Z","iteration":"1.0.33-pre006-variant-mono","scenario":"Subset-Mono","durationSeconds":1.62,"moduleVersion":"1.0.33-pre006"}
25+
{"Iteration":"1.0.33-pre006-variant-mono","Scenario":"Subset-Mono","DurationMs":1620,"DurationS":1.62,"Timestamp":"2026-05-17T12:06:18.1677417Z","Error":null,"Module":"1.0.33"}
2626
{"Iteration":"1.0.33-pre007-parallel","Scenario":"Single-Hack","DurationMs":615,"DurationS":0.61,"Timestamp":"2026-05-17T14:32:21.0280298+02:00","Error":null,"Module":"1.0.33"}
2727
{"Iteration":"1.0.33-pre007-parallel","Scenario":"Subset-Hack+FiraCode+JetBrainsMono","DurationMs":3695,"DurationS":3.7,"Timestamp":"2026-05-17T14:32:24.9507727+02:00","Error":null,"Module":"1.0.33"}
2828
{"Iteration":"1.0.33-pre007-parallel","Scenario":"Subset-AlreadyInstalled","DurationMs":16,"DurationS":0.02,"Timestamp":"2026-05-17T14:32:25.0140743+02:00","Error":null,"Module":"1.0.33"}

src/functions/public/Install-NerdFont.ps1

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ Please run the command again with elevated rights (Run as Administrator) or prov
147147

148148
Add-Type -AssemblyName System.Net.Http -ErrorAction SilentlyContinue
149149
$httpClient = [System.Net.Http.HttpClient]::new()
150-
$httpClient.Timeout = [TimeSpan]::FromMinutes(5)
150+
# Keep request lifetime unbounded for large archives on slower links.
151+
$httpClient.Timeout = [System.Threading.Timeout]::InfiniteTimeSpan
151152
$pending = [System.Collections.Generic.List[object]]::new()
152153
$readyToInstall = [System.Collections.Generic.List[object]]::new()
153154
$throttle = [Math]::Max(1, [Environment]::ProcessorCount)
@@ -206,10 +207,6 @@ Please run the command again with elevated rights (Run as Administrator) or prov
206207
try {
207208
$bytes = $t.Task.GetAwaiter().GetResult()
208209
[System.IO.File]::WriteAllBytes($t.Q.DownloadPath, $bytes)
209-
if (-not (Test-Path -LiteralPath $t.Q.CacheTagDir)) {
210-
$null = New-Item -ItemType Directory -Path $t.Q.CacheTagDir -Force
211-
}
212-
[System.IO.File]::WriteAllBytes($t.Q.CachedFile, $bytes)
213210
$readyToInstall.Add($t.Q)
214211
} catch {
215212
Write-Error "[$($t.Q.Name)] - Download failed: $($_.Exception.Message)"
@@ -230,6 +227,18 @@ Please run the command again with elevated rights (Run as Administrator) or prov
230227
$null = New-Item -ItemType Directory -Path $extractPath
231228
}
232229
[System.IO.Compression.ZipFile]::ExtractToDirectory($downloadPath, $extractPath, $true)
230+
231+
if (-not $p.FromCache -and (Test-Path -LiteralPath $downloadPath)) {
232+
try {
233+
if (-not (Test-Path -LiteralPath $p.CacheTagDir)) {
234+
$null = New-Item -ItemType Directory -Path $p.CacheTagDir -Force
235+
}
236+
Copy-Item -LiteralPath $downloadPath -Destination $p.CachedFile -Force
237+
} catch {
238+
Write-Warning "[$fontName] - Download succeeded but cache write failed: $($_.Exception.Message)"
239+
}
240+
}
241+
233242
Remove-Item -Path $downloadPath -Force
234243
}
235244

@@ -262,7 +271,22 @@ Please run the command again with elevated rights (Run as Administrator) or prov
262271
$removed++
263272
}
264273
}
265-
Write-Verbose "[$fontName] - Variant '$Variant' kept $($keep.Count) files, removed $removed"
274+
275+
# Nerd Fonts archives sometimes contain duplicate matching files in
276+
# compatibility subfolders. Keep a single file per filename.
277+
$remaining = @(Get-ChildItem -Path $extractPath -Recurse -File -Include '*.ttf', '*.otf')
278+
$preferred = $remaining | Sort-Object
279+
@{ Expression = { if ($_.FullName -match '(?i)[\\/]Windows Compatible[\\/]') { 1 } else { 0 } } },
280+
@{ Expression = { $_.FullName.Length } }
281+
$seenFileNames = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
282+
$duplicateRemoved = 0
283+
foreach ($file in $preferred) {
284+
if ($seenFileNames.Add($file.Name)) { continue }
285+
Remove-Item -LiteralPath $file.FullName -Force -ErrorAction SilentlyContinue
286+
$duplicateRemoved++
287+
}
288+
289+
Write-Verbose "[$fontName] - Variant '$Variant' kept $($keep.Count) files, removed $removed and deduplicated $duplicateRemoved duplicates"
266290
}
267291

268292
Write-Verbose "[$fontName] - Install to [$Scope]"

tests/NerdFonts.Tests.ps1

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,5 +121,68 @@ Describe 'Module' {
121121
$script:NerdFonts = $originalFonts
122122
}
123123
}
124+
125+
It 'Install-NerdFont - Deduplicates variant files from cached archives' {
126+
. (Join-Path -Path $PSScriptRoot -ChildPath '..\src\functions\public\Install-NerdFont.ps1')
127+
128+
$originalFonts = $script:NerdFonts
129+
$fontName = 'DuplicateMonoTest'
130+
$cacheRoot = if ($IsWindows) {
131+
Join-Path -Path ([Environment]::GetFolderPath('LocalApplicationData')) -ChildPath 'PSModule/NerdFonts/cache'
132+
} else {
133+
Join-Path -Path $HOME -ChildPath '.cache/PSModule/NerdFonts'
134+
}
135+
$cacheTagDir = Join-Path -Path $cacheRoot -ChildPath 'v3.4.0'
136+
$zipPath = Join-Path -Path $cacheTagDir -ChildPath 'DuplicateMonoTest.zip'
137+
138+
try {
139+
if (-not (Test-Path -LiteralPath $cacheTagDir)) {
140+
$null = New-Item -ItemType Directory -Path $cacheTagDir -Force
141+
}
142+
143+
$zipRoot = Join-Path -Path $TestDrive -ChildPath 'dup-zip'
144+
$primaryDir = Join-Path -Path $zipRoot -ChildPath 'Primary'
145+
$compatDir = Join-Path -Path $zipRoot -ChildPath 'Windows Compatible'
146+
$null = New-Item -ItemType Directory -Path $primaryDir -Force
147+
$null = New-Item -ItemType Directory -Path $compatDir -Force
148+
149+
$fileName = 'DuplicateMonoTestNerdFontMono-Regular.ttf'
150+
Set-Content -Path (Join-Path -Path $primaryDir -ChildPath $fileName) -Value 'primary'
151+
Set-Content -Path (Join-Path -Path $compatDir -ChildPath $fileName) -Value 'compat'
152+
153+
Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction SilentlyContinue
154+
if (Test-Path -LiteralPath $zipPath) {
155+
Remove-Item -LiteralPath $zipPath -Force
156+
}
157+
[System.IO.Compression.ZipFile]::CreateFromDirectory($zipRoot, $zipPath)
158+
159+
$script:NerdFonts = @(
160+
[pscustomobject]@{
161+
Name = $fontName
162+
URL = 'https://github.com/ryanoasis/nerd-fonts/releases/download/v3.4.0/DuplicateMonoTest.zip'
163+
}
164+
)
165+
166+
Mock Get-Font { @() }
167+
Mock Install-Font {
168+
param([string]$Path)
169+
$script:InstalledFontFiles = @(
170+
Get-ChildItem -Path $Path -Recurse -File -Include '*.ttf', '*.otf' |
171+
Select-Object -ExpandProperty Name
172+
)
173+
}
174+
175+
{ Install-NerdFont -Name $fontName -Variant Mono -ErrorAction Stop } | Should -Not -Throw
176+
Should -Invoke Install-Font -Times 1 -Exactly
177+
$script:InstalledFontFiles.Count | Should -Be 1
178+
($script:InstalledFontFiles | Select-Object -Unique).Count | Should -Be 1
179+
} finally {
180+
if (Test-Path -LiteralPath $zipPath) {
181+
Remove-Item -LiteralPath $zipPath -Force -ErrorAction SilentlyContinue
182+
}
183+
$script:NerdFonts = $originalFonts
184+
Remove-Variable -Name InstalledFontFiles -Scope Script -ErrorAction SilentlyContinue
185+
}
186+
}
124187
}
125188
}

0 commit comments

Comments
 (0)