Skip to content

Commit 3541e61

Browse files
committed
✨ [feat] Enhance cache building with multi-threading support
- 📝 Added documentation for the new `-Parallel` switch in `New-ColorScriptCache` to enable parallel cache builds on multi-core systems. - 🛠️ Implemented the `-Threads` parameter (alias for `-ThrottleLimit`) to control the number of concurrent workers during cache builds. - ⚡ Improved performance by allowing cache builds to run in parallel, defaulting to the number of logical processors if `-Threads` is not specified. - 📝 Updated help files in multiple languages to reflect the new features and version updates. - 🧪 Added tests to verify the functionality of the new parallel cache building feature, ensuring it returns correct metadata for successful and failed cache operations. - 🧪 Included tests for the `-Parallel` and `-Threads` parameters to confirm they work as expected. Signed-off-by: Nick2bad4u <20943337+Nick2bad4u@users.noreply.github.com>
1 parent ed4c182 commit 3541e61

24 files changed

Lines changed: 648 additions & 117 deletions

ColorScripts-Enhanced/ColorScripts-Enhanced.psd1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
RootModule = 'ColorScripts-Enhanced.psm1'
1212

1313
# Version number of this module.
14-
ModuleVersion = '2025.11.06.1527'
14+
ModuleVersion = '2025.11.06.2009'
1515

1616
# Supported PSEditions
1717
CompatiblePSEditions = @('Desktop', 'Core')
@@ -211,7 +211,7 @@ PERFECT FOR
211211

212212
# ReleaseNotes of this module
213213
ReleaseNotes = @'
214-
Version 2025.11.06.1527:
214+
Version 2025.11.06.2009:
215215
- Enhanced caching system with OS-wide cache in AppData
216216
- 6-19x performance improvement
217217
- Cache stored in centralized location
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
function Invoke-ColorScriptCacheOperation {
2+
[CmdletBinding()]
3+
param(
4+
[Parameter(Mandatory)][string]$ScriptName,
5+
[Parameter(Mandatory)][string]$ScriptPath
6+
)
7+
8+
$resultRecord = $null
9+
$warningMessage = $null
10+
$updated = 0
11+
$failed = 0
12+
13+
try {
14+
$cacheResult = Build-ScriptCache -ScriptPath $ScriptPath
15+
}
16+
catch {
17+
if (-not $script:CacheDir) {
18+
Initialize-CacheDirectory
19+
}
20+
$cacheResult = [pscustomobject]@{
21+
ScriptName = $ScriptName
22+
CacheFile = Join-Path -Path $script:CacheDir -ChildPath ("{0}.cache" -f $ScriptName)
23+
Success = $false
24+
ExitCode = $null
25+
StdOut = ''
26+
StdErr = $_.Exception.Message
27+
}
28+
}
29+
30+
if ($cacheResult.Success) {
31+
$updated = 1
32+
$status = 'Updated'
33+
$message = $script:Messages.StatusCached
34+
$cacheExists = $true
35+
}
36+
else {
37+
$failed = 1
38+
$status = 'Failed'
39+
40+
if ($cacheResult.StdErr) {
41+
$message = $cacheResult.StdErr
42+
}
43+
elseif ($null -ne $cacheResult.ExitCode) {
44+
$message = $script:Messages.ScriptExitedWithCode -f $cacheResult.ExitCode
45+
}
46+
else {
47+
$message = 'Cache build failed.'
48+
}
49+
50+
$warningMessage = "Failed to cache ${ScriptName}: $message"
51+
$cacheExists = $false
52+
}
53+
54+
$resultRecord = [pscustomobject]@{
55+
Name = if ($cacheResult.ScriptName) { $cacheResult.ScriptName } else { $ScriptName }
56+
ScriptPath = $ScriptPath
57+
CacheFile = $cacheResult.CacheFile
58+
Status = $status
59+
Message = $message
60+
CacheExists = $cacheExists
61+
ExitCode = $cacheResult.ExitCode
62+
StdOut = $cacheResult.StdOut
63+
StdErr = $cacheResult.StdErr
64+
}
65+
66+
return [pscustomobject]@{
67+
Result = $resultRecord
68+
Updated = $updated
69+
Failed = $failed
70+
Warning = $warningMessage
71+
}
72+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
function Test-ConsoleSupportsVirtualTerminal {
2+
[CmdletBinding()]
3+
[OutputType([bool])]
4+
param()
5+
6+
if (-not $script:IsWindows) {
7+
return $true
8+
}
9+
10+
$ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
11+
$STD_OUTPUT_HANDLE = -11
12+
13+
if (-not $script:DelegateSyncRoot) {
14+
$script:DelegateSyncRoot = New-Object System.Object
15+
}
16+
17+
try {
18+
Invoke-ModuleSynchronized $script:DelegateSyncRoot {
19+
if (-not ('ColorScriptsEnhanced.ConsoleNative' -as [Type])) {
20+
$typeDefinition = @(
21+
'using System;',
22+
'using System.Runtime.InteropServices;',
23+
'',
24+
'namespace ColorScriptsEnhanced {',
25+
' internal static class ConsoleNative {',
26+
' [DllImport("kernel32.dll", SetLastError = true)]',
27+
' internal static extern IntPtr GetStdHandle(int nStdHandle);',
28+
'',
29+
' [DllImport("kernel32.dll", SetLastError = true)]',
30+
' internal static extern bool GetConsoleMode(IntPtr hConsoleHandle, out int lpMode);',
31+
'',
32+
' [DllImport("kernel32.dll", SetLastError = true)]',
33+
' internal static extern bool SetConsoleMode(IntPtr hConsoleHandle, int dwMode);',
34+
' }',
35+
'}'
36+
) -join [Environment]::NewLine
37+
38+
Add-Type -TypeDefinition $typeDefinition -ErrorAction Stop
39+
}
40+
}
41+
}
42+
catch {
43+
return $false
44+
}
45+
46+
try {
47+
$handle = [ColorScriptsEnhanced.ConsoleNative]::GetStdHandle($STD_OUTPUT_HANDLE)
48+
if ($handle -eq [IntPtr]::Zero) {
49+
return $false
50+
}
51+
52+
$mode = 0
53+
if (-not [ColorScriptsEnhanced.ConsoleNative]::GetConsoleMode($handle, [ref]$mode)) {
54+
return $false
55+
}
56+
57+
if (($mode -band $ENABLE_VIRTUAL_TERMINAL_PROCESSING) -ne 0) {
58+
return $true
59+
}
60+
61+
if ([ColorScriptsEnhanced.ConsoleNative]::SetConsoleMode($handle, $mode -bor $ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
62+
$updatedMode = 0
63+
if ([ColorScriptsEnhanced.ConsoleNative]::GetConsoleMode($handle, [ref]$updatedMode)) {
64+
return (($updatedMode -band $ENABLE_VIRTUAL_TERMINAL_PROCESSING) -ne 0)
65+
}
66+
}
67+
}
68+
catch {
69+
return $false
70+
}
71+
72+
return $false
73+
}

ColorScripts-Enhanced/Private/Write-ColorScriptInformation.ps1

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ function Write-ColorScriptInformation {
1313

1414
$output = if ($null -ne $Message) { [string]$Message } else { '' }
1515

16+
$preferConsoleOutput = $PreferConsole.IsPresent
1617
$forceAnsiEnv = $env:COLOR_SCRIPTS_ENHANCED_FORCE_ANSI
17-
$forceAnsi = $PreferConsole.IsPresent
18-
if (-not $forceAnsi -and -not [string]::IsNullOrWhiteSpace($forceAnsiEnv)) {
18+
$forceAnsi = $false
19+
if (-not [string]::IsNullOrWhiteSpace($forceAnsiEnv)) {
1920
if ($forceAnsiEnv -match '^(?i)(1|true|yes|force|ansi|color)$') {
2021
$forceAnsi = $true
2122
}
@@ -29,62 +30,76 @@ function Write-ColorScriptInformation {
2930
$wroteToConsole = $false
3031

3132
if (-not $NoAnsiOutput.IsPresent) {
32-
$shouldTryConsole = $forceAnsi
33+
$shouldUseConsole = $preferConsoleOutput -or $forceAnsi
3334

34-
if (-not $shouldTryConsole) {
35+
if (-not $shouldUseConsole) {
3536
try {
36-
$shouldTryConsole = -not (Test-ConsoleOutputRedirected)
37+
$shouldUseConsole = -not (Test-ConsoleOutputRedirected)
3738
}
3839
catch {
39-
$shouldTryConsole = $false
40+
$shouldUseConsole = $false
4041
}
4142
}
4243

43-
if ($shouldTryConsole) {
44+
$supportsVirtualTerminal = $true
45+
try {
46+
$supportsVirtualTerminal = Test-ConsoleSupportsVirtualTerminal
47+
}
48+
catch {
49+
$supportsVirtualTerminal = $false
50+
}
51+
52+
$shouldRenderWithAnsi = $shouldUseConsole -and ($forceAnsi -or $supportsVirtualTerminal)
53+
54+
if ($shouldUseConsole) {
55+
$colorSet = $false
56+
$originalColor = $null
57+
4458
try {
45-
Write-RenderedText -Text $output -NoAnsiOutput:$false
59+
if (-not $shouldRenderWithAnsi -and -not [string]::IsNullOrWhiteSpace($Color)) {
60+
$consoleColor = $null
61+
if ([System.Enum]::TryParse([System.ConsoleColor], $Color, $true, [ref]$consoleColor)) {
62+
$originalColor = [Console]::ForegroundColor
63+
[Console]::ForegroundColor = $consoleColor
64+
$colorSet = $true
65+
}
66+
}
67+
68+
Write-RenderedText -Text $output -NoAnsiOutput:(!$shouldRenderWithAnsi)
4669
$wroteToConsole = $true
4770
}
4871
catch {
4972
$wroteToConsole = $false
5073
}
74+
finally {
75+
if ($colorSet -and $null -ne $originalColor) {
76+
[Console]::ForegroundColor = $originalColor
77+
}
78+
}
5179
}
5280

5381
if (-not $wroteToConsole -and -not [string]::IsNullOrWhiteSpace($Color)) {
5482
$consoleColor = $null
5583
if ([System.Enum]::TryParse([System.ConsoleColor], $Color, $true, [ref]$consoleColor)) {
84+
$originalColor = $null
5685
try {
5786
$originalColor = [Console]::ForegroundColor
5887
[Console]::ForegroundColor = $consoleColor
59-
& $script:ConsoleWriteDelegate $sanitizedOutput
60-
61-
$requiresNewLine = $true
62-
if ($sanitizedOutput) {
63-
$requiresNewLine = -not $sanitizedOutput.EndsWith("`n")
64-
}
65-
66-
if ($requiresNewLine) {
67-
& $script:ConsoleWriteDelegate ([Environment]::NewLine)
68-
}
69-
88+
Write-RenderedText -Text $output -NoAnsiOutput
7089
$wroteToConsole = $true
7190
}
7291
catch {
7392
$wroteToConsole = $false
7493
}
7594
finally {
76-
try {
95+
if ($null -ne $originalColor) {
7796
[Console]::ForegroundColor = $originalColor
7897
}
79-
catch {
80-
Write-ModuleTrace ("Failed to restore console color: {0}" -f $_.Exception.Message)
81-
}
8298
}
8399
}
84100
}
85101
}
86102

87103
$informationAction = if ($wroteToConsole) { 'SilentlyContinue' } else { 'Continue' }
88-
89104
Write-Information -MessageData $sanitizedOutput -InformationAction $informationAction -Tags 'ColorScripts'
90105
}

0 commit comments

Comments
 (0)