- Зачем: - нужно убрать line-ending noise в репозитории и сделать Windows-слой безопаснее для запуска без установленного pwsh. - Что: - добавлена `.gitattributes` с LF-базой для текста и CRLF-исключениями для `.bat` и `.cmd`. - `README.md` нормализован в LF и quick start дополнен явной установкой PowerShell 7. - `chezmoi`-скрипты переведены на guard, совместимый с PowerShell 5.1, а запись `settings.json` переведена на `utf8BOM`. - Проверка: - `git diff --check`. - `powershell.exe -NoProfile -ExecutionPolicy Bypass -File chezmoi\\.chezmoiscripts\\run_before_10-migrate-gitconfig.ps1`. - `powershell.exe -NoProfile -ExecutionPolicy Bypass -File chezmoi\\.chezmoiscripts\\run_20-configure-windows-terminal.ps1`. - `chezmoi -S C:\\Users\\dmitry\\dotfiles\\chezmoi apply --dry-run --verbose`.
268 lines
8.1 KiB
PowerShell
268 lines
8.1 KiB
PowerShell
if (-not ($IsWindows -or $PSVersionTable.PSEdition -eq 'Desktop')) {
|
|
return
|
|
}
|
|
|
|
$settingsPath = Join-Path $env:LOCALAPPDATA 'Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json'
|
|
if (-not (Test-Path -LiteralPath $settingsPath)) {
|
|
Write-Warning "Windows Terminal settings not found: $settingsPath"
|
|
return
|
|
}
|
|
|
|
$PowerShellGuid = '{574e775e-4f2a-5b96-ac1e-a2962a402336}'
|
|
$LegacyPowerShellGuid = '{61c54bbd-c2c6-5271-96e7-009a87ff44bf}'
|
|
$changed = $false
|
|
|
|
function Get-JsonPropertyValue {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
$Object,
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Name
|
|
)
|
|
|
|
$Property = $Object.PSObject.Properties[$Name]
|
|
if ($null -eq $Property) {
|
|
return $null
|
|
}
|
|
|
|
return $Property.Value
|
|
}
|
|
|
|
function Test-JsonValueEqual {
|
|
param(
|
|
$Left,
|
|
$Right
|
|
)
|
|
|
|
if ($null -eq $Left -and $null -eq $Right) {
|
|
return $true
|
|
}
|
|
|
|
if ($null -eq $Left -or $null -eq $Right) {
|
|
return $false
|
|
}
|
|
|
|
if (
|
|
$Left -is [System.Collections.IEnumerable] -and
|
|
-not ($Left -is [string])
|
|
) {
|
|
return (ConvertTo-Json $Left -Depth 100 -Compress) -eq (ConvertTo-Json $Right -Depth 100 -Compress)
|
|
}
|
|
|
|
return $Left -eq $Right
|
|
}
|
|
|
|
function Set-JsonPropertyValue {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
$Object,
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Name,
|
|
$Value
|
|
)
|
|
|
|
$Property = $Object.PSObject.Properties[$Name]
|
|
if ($null -eq $Property) {
|
|
$Object | Add-Member -NotePropertyName $Name -NotePropertyValue $Value
|
|
$script:changed = $true
|
|
return
|
|
}
|
|
|
|
if (-not (Test-JsonValueEqual -Left $Property.Value -Right $Value)) {
|
|
$Property.Value = $Value
|
|
$script:changed = $true
|
|
}
|
|
}
|
|
|
|
function Test-IsPowerShell7Profile {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
$Profile
|
|
)
|
|
|
|
$Source = [string](Get-JsonPropertyValue -Object $Profile -Name source)
|
|
$Name = [string](Get-JsonPropertyValue -Object $Profile -Name name)
|
|
$CommandLine = [string](Get-JsonPropertyValue -Object $Profile -Name commandline)
|
|
|
|
if ($Source -eq 'Windows.Terminal.PowershellCore') {
|
|
return $true
|
|
}
|
|
|
|
if ($CommandLine -match '(?i)(^|[\\/ ])pwsh(?:\.exe)?(?:\s|$)') {
|
|
return $true
|
|
}
|
|
|
|
return $Name -match '^(PowerShell|PowerShell 7)$'
|
|
}
|
|
|
|
function Test-IsDisposablePowerShell7Profile {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
$Profile
|
|
)
|
|
|
|
$Source = [string](Get-JsonPropertyValue -Object $Profile -Name source)
|
|
$Name = [string](Get-JsonPropertyValue -Object $Profile -Name name)
|
|
$CommandLine = [string](Get-JsonPropertyValue -Object $Profile -Name commandline)
|
|
|
|
return (
|
|
$Name -match '^(PowerShell|PowerShell 7)$' -and
|
|
(
|
|
$Source -eq 'Windows.Terminal.PowershellCore' -or
|
|
$CommandLine -match '(?i)(^|[\\/ ])pwsh(?:\.exe)?(?:\s|$)'
|
|
)
|
|
)
|
|
}
|
|
|
|
try {
|
|
$originalSettings = Get-Content -LiteralPath $settingsPath -Raw
|
|
$settings = $originalSettings | ConvertFrom-Json
|
|
}
|
|
catch {
|
|
Write-Warning "Failed to read Windows Terminal settings: $settingsPath"
|
|
Write-Warning $_
|
|
return
|
|
}
|
|
|
|
if ($null -eq (Get-JsonPropertyValue -Object $settings -Name profiles)) {
|
|
$settings | Add-Member -NotePropertyName profiles -NotePropertyValue ([pscustomobject]@{
|
|
defaults = [pscustomobject]@{}
|
|
list = @()
|
|
})
|
|
$changed = $true
|
|
}
|
|
|
|
if ($null -eq (Get-JsonPropertyValue -Object $settings.profiles -Name list)) {
|
|
$settings.profiles | Add-Member -NotePropertyName list -NotePropertyValue @()
|
|
$changed = $true
|
|
}
|
|
|
|
$profiles = @($settings.profiles.list)
|
|
$powerShell7CandidateIndices = New-Object System.Collections.Generic.List[int]
|
|
$legacyPowerShellIndex = $null
|
|
|
|
for ($i = 0; $i -lt $profiles.Count; $i++) {
|
|
$profile = $profiles[$i]
|
|
$guid = [string](Get-JsonPropertyValue -Object $profile -Name guid)
|
|
$source = [string](Get-JsonPropertyValue -Object $profile -Name source)
|
|
$commandLine = [string](Get-JsonPropertyValue -Object $profile -Name commandline)
|
|
|
|
if (Test-IsPowerShell7Profile -Profile $profile) {
|
|
[void]$powerShell7CandidateIndices.Add($i)
|
|
}
|
|
|
|
if (
|
|
$guid -eq $LegacyPowerShellGuid -or
|
|
$commandLine -match '(?i)WindowsPowerShell\\v1\.0\\powershell\.exe'
|
|
) {
|
|
$legacyPowerShellIndex = $i
|
|
}
|
|
|
|
if ($source -eq 'Windows.Terminal.Azure') {
|
|
Set-JsonPropertyValue -Object $profile -Name hidden -Value $true
|
|
}
|
|
}
|
|
|
|
$powerShell7Index = $null
|
|
foreach ($candidateIndex in $powerShell7CandidateIndices) {
|
|
$candidate = $profiles[$candidateIndex]
|
|
if ([string](Get-JsonPropertyValue -Object $candidate -Name source) -eq 'Windows.Terminal.PowershellCore') {
|
|
$powerShell7Index = $candidateIndex
|
|
break
|
|
}
|
|
}
|
|
|
|
if ($null -eq $powerShell7Index -and $powerShell7CandidateIndices.Count -gt 0) {
|
|
$powerShell7Index = $powerShell7CandidateIndices[0]
|
|
}
|
|
|
|
if ($null -eq $powerShell7Index) {
|
|
$profiles += [pscustomobject]@{
|
|
commandline = 'pwsh.exe'
|
|
guid = $PowerShellGuid
|
|
hidden = $false
|
|
name = 'PowerShell 7'
|
|
startingDirectory = '%USERPROFILE%'
|
|
}
|
|
$powerShell7Index = $profiles.Count - 1
|
|
$changed = $true
|
|
}
|
|
|
|
$powerShell7Profile = $profiles[$powerShell7Index]
|
|
if ([string]::IsNullOrWhiteSpace([string](Get-JsonPropertyValue -Object $powerShell7Profile -Name guid))) {
|
|
Set-JsonPropertyValue -Object $powerShell7Profile -Name guid -Value $PowerShellGuid
|
|
}
|
|
if ($null -eq (Get-JsonPropertyValue -Object $powerShell7Profile -Name commandline) -and [string](Get-JsonPropertyValue -Object $powerShell7Profile -Name source) -ne 'Windows.Terminal.PowershellCore') {
|
|
Set-JsonPropertyValue -Object $powerShell7Profile -Name commandline -Value 'pwsh.exe'
|
|
}
|
|
Set-JsonPropertyValue -Object $powerShell7Profile -Name name -Value 'PowerShell 7'
|
|
Set-JsonPropertyValue -Object $powerShell7Profile -Name hidden -Value $false
|
|
Set-JsonPropertyValue -Object $powerShell7Profile -Name startingDirectory -Value '%USERPROFILE%'
|
|
Set-JsonPropertyValue -Object $settings -Name defaultProfile -Value ([string](Get-JsonPropertyValue -Object $powerShell7Profile -Name guid))
|
|
|
|
if ($null -ne $legacyPowerShellIndex) {
|
|
$legacyPowerShellProfile = $profiles[$legacyPowerShellIndex]
|
|
Set-JsonPropertyValue -Object $legacyPowerShellProfile -Name name -Value 'Windows PowerShell 5.1 (Legacy)'
|
|
Set-JsonPropertyValue -Object $legacyPowerShellProfile -Name hidden -Value $false
|
|
}
|
|
|
|
$removedIndices = New-Object System.Collections.Generic.HashSet[int]
|
|
foreach ($candidateIndex in $powerShell7CandidateIndices) {
|
|
if ($candidateIndex -eq $powerShell7Index) {
|
|
continue
|
|
}
|
|
|
|
if (Test-IsDisposablePowerShell7Profile -Profile $profiles[$candidateIndex]) {
|
|
if ($removedIndices.Add($candidateIndex)) {
|
|
$changed = $true
|
|
}
|
|
}
|
|
}
|
|
|
|
$orderedProfiles = New-Object System.Collections.Generic.List[object]
|
|
$addedIndices = New-Object System.Collections.Generic.HashSet[int]
|
|
|
|
function Add-ProfileByIndex {
|
|
param(
|
|
[int]$Index
|
|
)
|
|
|
|
if ($Index -lt 0) {
|
|
return
|
|
}
|
|
|
|
if ($removedIndices.Contains($Index)) {
|
|
return
|
|
}
|
|
|
|
if ($addedIndices.Add($Index)) {
|
|
$orderedProfiles.Add($profiles[$Index])
|
|
}
|
|
}
|
|
|
|
Add-ProfileByIndex -Index $powerShell7Index
|
|
if ($null -ne $legacyPowerShellIndex) {
|
|
Add-ProfileByIndex -Index $legacyPowerShellIndex
|
|
}
|
|
|
|
for ($i = 0; $i -lt $profiles.Count; $i++) {
|
|
Add-ProfileByIndex -Index $i
|
|
}
|
|
|
|
$orderedProfilesArray = @($orderedProfiles.ToArray())
|
|
if ((ConvertTo-Json $profiles -Depth 100 -Compress) -ne (ConvertTo-Json $orderedProfilesArray -Depth 100 -Compress)) {
|
|
$changed = $true
|
|
}
|
|
$settings.profiles.list = $orderedProfilesArray
|
|
|
|
if (-not $changed) {
|
|
Write-Host 'Windows Terminal settings already match the managed baseline.'
|
|
return
|
|
}
|
|
|
|
$backupPath = '{0}.bak-{1}' -f $settingsPath, (Get-Date -Format 'yyyyMMdd-HHmmss')
|
|
Copy-Item -LiteralPath $settingsPath -Destination $backupPath -Force
|
|
$settings | ConvertTo-Json -Depth 100 | Set-Content -LiteralPath $settingsPath -Encoding utf8BOM
|
|
Write-Host "Updated Windows Terminal settings: $settingsPath"
|
|
Write-Host "Backup saved to: $backupPath"
|