From 209f88cb309910d03e62964eb69c4a9e22aa0e9e Mon Sep 17 00:00:00 2001 From: "Peter J. Mello" Date: Sat, 28 Feb 2026 18:36:50 -0800 Subject: [PATCH] Handle dependencies better and refactor for reproducibility This is a general refactoring seeking several simultaneous outcomes: * More tolerant (i.e. sane) dependency resolution * Apply implicit environment assumptions explicitly for interpreter to manage * Use of best practices wherever possible, specifically regarding: - Grammatical voice for runtime output messages - Scripting safety conventions for determinative behavior Setting global requirement on PowerShell Core makes the expectation of interpreter expressed in #36 much easier to understand and moves the source of guidance for it from local documentation to the runtime shell. Shifting from 'RequiresVersion' arguments to 'ModuleVersion' allows newer versions of modules to satisfy dependency constraints and adding the GUID makes the execution of third-party code more secure from namespace clobbering, be it incidental or malicious. Activating StrictMode at Script scope in PowerShell Core operations is loosely equivalent to the boilerplate `set -euo pipefail` incantation ubiquitously employed in POSIX shell scripts where potentially damaging activity will occur. Version 3 converts these "code smells" from warnings or recoverable errors to fatal errors: * Using method syntax (parentheses and commas) for function calls * References to: - Uninitialized variables - Non-existent object properties - Invalid/out-of-bounds collection indexes Best comprehension and accuracy for user-consumed runtime messages that announce actions before they are undertaken requires the use of gerund forms or third-person present tense for action verbs. The liberal use of the terminal ellipsis in such strings is a widely-understood rubric that reinforces the nature of the announcements as preemptive rather than conclusory. Resolves: #36 Resolves: #52 --- src/functions/public/Install-NerdFont.ps1 | 85 ++++++++++++----------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/src/functions/public/Install-NerdFont.ps1 b/src/functions/public/Install-NerdFont.ps1 index bece478..106330d 100644 --- a/src/functions/public/Install-NerdFont.ps1 +++ b/src/functions/public/Install-NerdFont.ps1 @@ -1,5 +1,8 @@ -#Requires -Modules @{ ModuleName = 'Fonts'; RequiredVersion = '1.1.21' } -#Requires -Modules @{ ModuleName = 'Admin'; RequiredVersion = '1.1.6' } +#Requires -PSEdition Core +#Requires -Modules @{ ModuleName = 'Admin'; ModuleVersion = '1.1.6'; GUID = '70660c5c-30db-4787-861e-0a626ca8683c' } +#Requires -Modules @{ ModuleName = 'Fonts'; ModuleVersion = '1.1.21'; GUID = 'b6e7e61f-f8f5-4b0a-9fdd-f74a3311be0d' } + +Set-StrictMode -Version 3.0 function Install-NerdFont { <# @@ -57,77 +60,79 @@ function Install-NerdFont { ParameterSetName = 'All', Mandatory )] - [switch] $All, + [switch] ${All}, [Parameter()] [ValidateSet('CurrentUser', 'AllUsers')] - [string] $Scope = 'CurrentUser', + [string] ${Scope} = 'CurrentUser', # Force will overwrite existing fonts [Parameter()] - [switch] $Force + [switch] ${Force} ) begin { - if ($Scope -eq 'AllUsers' -and -not (IsAdmin)) { - $errorMessage = @' -Administrator rights are required to install fonts. -Please run the command again with elevated rights (Run as Administrator) or provide '-Scope CurrentUser' to your command." + if (${Scope} -eq 'AllUsers' -and -not (IsAdmin)) { + ${errorMessage} = @' +Administrator privileges are required to install system-wide fonts. + +Please run this command again with elevated permissions ("Run as Administrator") or append '-Scope CurrentUser' to it for a user-level install. '@ - throw $errorMessage + throw ${errorMessage} } - $nerdFontsToInstall = @() + ${nerdFontsToInstall} = @() - $guid = (New-Guid).Guid - $tempPath = Join-Path -Path $HOME -ChildPath "NerdFonts-$guid" - if (-not (Test-Path -Path $tempPath -PathType Container)) { - Write-Verbose "Create folder [$tempPath]" - $null = New-Item -Path $tempPath -ItemType Directory + ${tempPath} = Join-Path -Path ${Env:TEMP} -ChildPath "NerdFonts-$([Convert]::ToString((Get-Random 16777216),16).PadLeft(6,'0'))" + if (-not (Test-Path -Path ${tempPath} -PathType Container)) { + Write-Verbose "Creating temporary download directory [${tempPath}]…" + ${null} = New-Item -Path ${tempPath} -ItemType Directory } } process { - if ($All) { - $nerdFontsToInstall = $script:NerdFonts + if (${All}) { + ${nerdFontsToInstall} = ${script:NerdFonts} } else { - foreach ($fontName in $Name) { - $nerdFontsToInstall += $script:NerdFonts | Where-Object { $_.Name -like $fontName } + foreach (${fontName} in ${Name}) { + ${nerdFontsToInstall} += ${script:NerdFonts} | Where-Object { + $_.Name -like ${fontName} + } } } - Write-Verbose "[$Scope] - Installing [$($nerdFontsToInstall.count)] fonts" + Write-Verbose "[${Scope}] - Installing [$(${nerdFontsToInstall}.count)] fonts…" - foreach ($nerdFont in $nerdFontsToInstall) { - $URL = $nerdFont.URL - $fontName = $nerdFont.Name - $downloadFileName = Split-Path -Path $URL -Leaf - $downloadPath = Join-Path -Path $tempPath -ChildPath $downloadFileName + foreach (${nerdFont} in ${nerdFontsToInstall}) { + ${URL} = ${nerdFont}.URL + ${fontName} = ${nerdFont}.Name + ${downloadFileName} = Split-Path -Path ${URL} -Leaf + ${downloadPath} = Join-Path -Path ${tempPath} -ChildPath ${downloadFileName} - Write-Verbose "[$fontName] - Downloading to [$downloadPath]" - if ($PSCmdlet.ShouldProcess("[$fontName] to [$downloadPath]", 'Download')) { - Invoke-WebRequest -Uri $URL -OutFile $downloadPath -RetryIntervalSec 5 -MaximumRetryCount 5 + Write-Verbose "[${fontName}] - Downloading to [${downloadPath}]…" + if (${PSCmdlet}.ShouldProcess("[${fontName}] to [${downloadPath}]", 'Download')) { + Invoke-WebRequest -Uri ${URL} -OutFile ${downloadPath} -RetryIntervalSec 5 -MaximumRetryCount 5 } - $extractPath = Join-Path -Path $tempPath -ChildPath $fontName - Write-Verbose "[$fontName] - Extract to [$extractPath]" - if ($PSCmdlet.ShouldProcess("[$fontName] to [$extractPath]", 'Extract')) { - Expand-Archive -Path $downloadPath -DestinationPath $extractPath -Force - Remove-Item -Path $downloadPath -Force + ${extractPath} = Join-Path -Path ${tempPath} -ChildPath ${fontName} + Write-Verbose "[${fontName}] - Extracting archive to [${extractPath}]…" + if (${PSCmdlet}.ShouldProcess("[${fontName}] to [${extractPath}]", 'Extract')) { + Expand-Archive -Path ${downloadPath} -DestinationPath ${extractPath} -Force + Remove-Item -Path ${downloadPath} -Force } - Write-Verbose "[$fontName] - Install to [$Scope]" - if ($PSCmdlet.ShouldProcess("[$fontName] to [$Scope]", 'Install font')) { - Install-Font -Path $extractPath -Scope $Scope -Force:$Force - Remove-Item -Path $extractPath -Force -Recurse + Write-Verbose "[${fontName}] - Installing for [${Scope}]…" + if (${PSCmdlet}.ShouldProcess("[${fontName}] to [${Scope}]", 'Install font')) { + Install-Font -Path ${extractPath} -Scope ${Scope} -Force:${Force} + Remove-Item -Path ${extractPath} -Force -Recurse } } } end { - Write-Verbose "Remove folder [$tempPath]" + Write-Verbose "Removing temporary download directory [${tempPath}]…" } clean { - Remove-Item -Path $tempPath -Force + Remove-Item -Path ${tempPath} -Force } }