@@ -456,14 +456,31 @@ function Sync-PathFromBash {
456456 [switch ]$Login ,
457457 [switch ]$Prepend ,
458458 [switch ]$IncludeNonexistent ,
459- [bool ]$ReturnObject = $true
459+ [bool ]$ReturnObject = $true ,
460+ [int ]$CacheSeconds = 300 ,
461+ [switch ]$ThrowOnFailure
460462 )
461463
462464 try {
463465 $start = [DateTime ]::UtcNow
464466 Write-Information " 正在从 Bash 登录 Shell 中获取 PATH..."
465467 $bashPathOutput = ' '
466468 $source = ' '
469+ $cacheDir = Join-Path $HOME " .cache/powershellScripts"
470+ $cacheFile = Join-Path $cacheDir " bash_path.json"
471+ $useCache = $CacheSeconds -gt 0 -and (Test-Path - LiteralPath $cacheFile )
472+ if ($useCache ) {
473+ try {
474+ $cache = Get-Content - LiteralPath $cacheFile - Raw | ConvertFrom-Json
475+ $ageSec = ([DateTime ]::UtcNow - [DateTime ]$cache.timestamp ).TotalSeconds
476+ $isLoginCache = ($cache.source -like ' bash-login*' )
477+ $isNoLoginCache = ($cache.source -like ' bash-nologin*' )
478+ if ($ageSec -le $CacheSeconds -and (($Login -and $isLoginCache ) -or ((-not $Login ) -and $isNoLoginCache ))) {
479+ $bashPathOutput = [string ]$cache.path
480+ $source = [string ]$cache.source + ' -cache'
481+ }
482+ } catch { }
483+ }
467484 if ($Login ) {
468485 $bashPathOutput = bash - lc ' echo $PATH'
469486 $source = ' bash-login'
@@ -472,8 +489,8 @@ function Sync-PathFromBash {
472489 $bashPathOutput = bash - c ' source /etc/profile >/dev/null 2>&1; echo $PATH'
473490 $source = ' bash-profile-fallback'
474491 if ($LASTEXITCODE -ne 0 -or [string ]::IsNullOrWhiteSpace($bashPathOutput )) {
475- Write-Warning " 无法从 Bash 获取 PATH。Bash 可能未安装或存在配置错误。"
476- return
492+ $msg = " 无法从 Bash 获取 PATH。Bash 可能未安装或存在配置错误。"
493+ if ( $ThrowOnFailure ) { throw $msg } else { Write-Warning $msg ; return }
477494 }
478495 }
479496 }
@@ -485,32 +502,49 @@ function Sync-PathFromBash {
485502 $bashPathOutput = bash -- noprofile -- norc - c ' source ~/.bashrc 2>/dev/null; echo $PATH'
486503 $source = ' bash-nologin-bashrc-fallback'
487504 if ($LASTEXITCODE -ne 0 -or [string ]::IsNullOrWhiteSpace($bashPathOutput )) {
488- Write-Warning " 无法从非登录模式获取 PATH。请检查 Bash 安装或 .bashrc 配置。"
489- return
505+ $msg = " 无法从非登录模式获取 PATH。请检查 Bash 安装或 .bashrc 配置。"
506+ if ( $ThrowOnFailure ) { throw $msg } else { Write-Warning $msg ; return }
490507 }
491508 }
492509 }
493510
494511 $bashPathOutput = $bashPathOutput.Trim ()
512+ if ($CacheSeconds -gt 0 -and -not [string ]::IsNullOrWhiteSpace($bashPathOutput ) -and -not ($source -like ' *-cache' )) {
513+ try {
514+ if (-not (Test-Path - LiteralPath $cacheDir )) { New-Item - ItemType Directory - Path $cacheDir - Force | Out-Null }
515+ @ { path = $bashPathOutput ; source = $source ; timestamp = [DateTime ]::UtcNow } | ConvertTo-Json | Set-Content - LiteralPath $cacheFile - Encoding UTF8
516+ } catch { }
517+ }
495518 $separator = [System.IO.Path ]::PathSeparator
496519
497- $bashPaths = $bashPathOutput.Split ($separator , [System.StringSplitOptions ]::RemoveEmptyEntries) | ForEach-Object { $_.Trim () } | Where-Object { $_ -ne ' ' } | Select-Object - Unique
498- $psPaths = $env: PATH.Split ($separator , [System.StringSplitOptions ]::RemoveEmptyEntries) | ForEach-Object { $_.Trim () } | Where-Object { $_ -ne ' ' } | Select-Object - Unique
520+ $bashPathsRaw = $bashPathOutput.Split ($separator , [System.StringSplitOptions ]::RemoveEmptyEntries)
521+ $psPathsRaw = $env: PATH.Split ($separator , [System.StringSplitOptions ]::RemoveEmptyEntries)
522+ $bashSet = [System.Collections.Generic.HashSet [string ]]::new()
523+ $psSetAll = [System.Collections.Generic.HashSet [string ]]::new()
524+ foreach ($x in $bashPathsRaw ) { $t = $x.Trim (); if ($t.Length -gt 0 ) { [void ]$bashSet.Add ($t ) } }
525+ foreach ($x in $psPathsRaw ) { $t = $x.Trim (); if ($t.Length -gt 0 ) { [void ]$psSetAll.Add ($t ) } }
526+ $bashPaths = $bashSet.GetEnumerator () | ForEach-Object { $_ }
527+ $psPaths = $psSetAll.GetEnumerator () | ForEach-Object { $_ }
499528
500529 Write-Information " 从 Bash 中找到的路径: $ ( $bashPaths.Count ) 个"
501530 Write-Information " 当前 PowerShell 中的路径: $ ( $psPaths.Count ) 个"
502531
503- $psSet = [System.Collections.Generic.HashSet [string ]]::new()
504- foreach ($p in $psPaths ) { [void ]$psSet.Add ($p ) }
532+ $psSet = $psSetAll
505533 $missingPaths = [System.Collections.Generic.List [string ]]::new()
506534 foreach ($p in $bashPaths ) { if (-not $psSet.Contains ($p )) { $missingPaths.Add ($p ) } }
507535
508536 if ($missingPaths.Count -gt 0 ) {
509537 Write-Information " 发现 $ ( $missingPaths.Count ) 个需要从 Bash 同步的路径。"
510538 Write-Verbose (" 缺失路径: " + ($missingPaths -join $separator ))
511539
512- $pathsToApply = if ($IncludeNonexistent ) { $missingPaths } else { $missingPaths | Where-Object { Test-Path - LiteralPath $_ - PathType Container } }
513- $skippedPaths = if ($IncludeNonexistent ) { @ () } else { $missingPaths | Where-Object { -not (Test-Path - LiteralPath $_ - PathType Container) } }
540+ if ($IncludeNonexistent ) {
541+ $pathsToApply = $missingPaths
542+ $skippedPaths = @ ()
543+ } else {
544+ $pathsToApply = [System.Collections.Generic.List [string ]]::new()
545+ $skippedPaths = [System.Collections.Generic.List [string ]]::new()
546+ foreach ($mp in $missingPaths ) { if (Test-Path - LiteralPath $mp - PathType Container) { [void ]$pathsToApply.Add ($mp ) } else { [void ]$skippedPaths.Add ($mp ) } }
547+ }
514548
515549 if ($pathsToApply.Count -gt 0 ) {
516550 foreach ($path in $pathsToApply ) { Write-Verbose " 将添加: $path " }
0 commit comments