From e8a52f717dc799b34ceeb1c27c2b8219391dff6a Mon Sep 17 00:00:00 2001 From: undergroundwires Date: Mon, 2 Oct 2023 14:33:55 +0200 Subject: [PATCH] win, linux: improve VSCode setting robustness #196 This commit enhances the robustness of setting VSCode configurations, ensuring consistent and reliable operation even in edge cases, such as when the settings file is empty. This commit also uniforms behavior of Linux and Windows modification of VSCode settings. On Windows: - Move parameters to on top of scripts to be able to easily test the scripts using PowerShell without compiling. - Add a check to exit the script with an error message if the attempt to parse the JSON content fails. - Omit the `OutString` cmdlet from the pipeline in the script for converting JSON file content to a PowerShell object. `Out-String` is unnecessary in this context because `Get-Content` already outputs the file content as a string array, which `ConvertFrom-Json` effectively. Additionally, using `Out-String` could potentially introduce issues by concatenating file content into a single string, causing `ConvertFrom-Json` to fail when processing pretty-printed JSON. By removing `Out-String`, the script is streamlined and potential errors are avoided. - Add logic to handle empty settings file. Add an additional check for empty settings file, if the file is empty, the script writes a default empty JSON object (`{}`) to the file. The operation is logged to ensure transparency, notifying the user of the action taken. This change removes fails due to empty setting files. - When reverting, do not fail if the setting file is missing because it means that default settings are already in-place. - When reverting, show informative message if the key does not exist or does not have the value set by privacy.sexy and do not take any further action. - If the desired value is already set, show a message for it and skip updating the setting file. On Linux: - Handles empty `settings.json` similarly to Windows. - Add more user friendly error if JSON file cannot be parsed. --- src/application/collections/linux.yaml | 23 ++++++-- src/application/collections/windows.yaml | 72 +++++++++++++++++++----- 2 files changed, 78 insertions(+), 17 deletions(-) diff --git a/src/application/collections/linux.yaml b/src/application/collections/linux.yaml index c1c25ab9..9bb002f1 100644 --- a/src/application/collections/linux.yaml +++ b/src/application/collections/linux.yaml @@ -3183,7 +3183,7 @@ functions: parameters: code: |- from pathlib import Path - import os, json + import os, json, sys property_name = '{{ $setting }}' target = json.loads('{{ $jsonValue }}') home_dir = f'/home/{os.getenv("SUDO_USER", os.getenv("USER"))}' @@ -3200,7 +3200,15 @@ functions: continue print(f'Reading file at "{settings_file}".') file_content = file.read_text() - json_object = json.loads(file_content) + if not file_content.strip(): + print('Settings file is empty. Treating it as default empty JSON object.') + file_content = '{}' + json_object = None + try: + json_object = json.loads(file_content) + except json.JSONDecodeError: + print(f'Error, invalid JSON format in the settings file: "{settings_file}".', file=sys.stderr) + continue if property_name not in json_object: print(f'Settings "{property_name}" is not configured.') else: @@ -3215,7 +3223,7 @@ functions: print(f'Successfully configured "{property_name}" to {json.dumps(target)}.') revertCode: |- from pathlib import Path - import os, json + import os, json, sys property_name = '{{ $setting }}' target = json.loads('{{ $jsonValue }}') home_dir = f'/home/{os.getenv("SUDO_USER", os.getenv("USER"))}' @@ -3232,7 +3240,14 @@ functions: continue print(f'Reading file at "{settings_file}".') file_content = file.read_text() - json_object = json.loads(file_content) + if not file_content.strip(): + print(f'Skipping, no need to revert because settings file is empty: "{settings_file}".') + continue + try: + json_object = json.loads(file_content) + except json.JSONDecodeError: + print(f'Error, invalid JSON format in the settings file: "{settings_file}".', file=sys.stderr) + continue if property_name not in json_object: print(f'Skipping, "{property_name}" is not configured.') continue diff --git a/src/application/collections/windows.yaml b/src/application/collections/windows.yaml index 4947d328..1f382778 100644 --- a/src/application/collections/windows.yaml +++ b/src/application/collections/windows.yaml @@ -7919,22 +7919,68 @@ functions: function: RunPowerShell parameters: code: |- - $jsonfile = "$env:APPDATA\Code\User\settings.json" - if (!(Test-Path $jsonfile -PathType Leaf)) { - Write-Host "No updates. Settings file was not at $jsonfile" + $settingKey='{{ $setting }}' + $settingValue={{ $powerShellValue }} + $jsonFilePath = "$($env:APPDATA)\Code\User\settings.json" + if (!(Test-Path $jsonFilePath -PathType Leaf)) { + Write-Host "Skipping, no updates. Settings file was not at `"$jsonFilePath`"." exit 0 } - $json = Get-Content $jsonfile | Out-String | ConvertFrom-Json - $json | Add-Member -Type NoteProperty -Name '{{ $setting }}' -Value {{ $powerShellValue }} -Force - $json | ConvertTo-Json | Set-Content $jsonfile - revertCode: |- - $jsonfile = "$env:APPDATA\Code\User\settings.json" - if (!(Test-Path $jsonfile -PathType Leaf)) { - Write-Error "Settings file could not be found at $jsonfile" -ErrorAction Stop + try { + $fileContent = Get-Content $jsonFilePath -ErrorAction Stop + } catch { + throw "Error, failed to read the settings file: `"$jsonFilePath`". Error: $_" } - $json = Get-Content $jsonfile | ConvertFrom-Json - $json.PSObject.Properties.Remove('{{ $setting }}') - $json | ConvertTo-Json | Set-Content $jsonfile + if ([string]::IsNullOrWhiteSpace($fileContent)) { + Write-Host "Settings file is empty. Treating it as default empty JSON object." + $fileContent = "{}" + } + try { + $json = $fileContent | ConvertFrom-Json + } catch { + throw "Error, invalid JSON format in the settings file: `"$jsonFilePath`". Error: $_" + } + $existingValue = $json.$settingKey + if ($existingValue -eq $settingValue) { + Write-Host "Skipping, `"$settingKey`" is already configured as `"$settingValue`"." + exit 0 + } + $json | Add-Member -Type NoteProperty -Name $settingKey -Value $settingValue -Force + $json | ConvertTo-Json | Set-Content $jsonFilePath + Write-Host "Successfully applied the setting to the file: `"$jsonFilePath`"." + revertCode: |- + $settingKey='{{ $setting }}' + $settingValue={{ $powerShellValue }} + $jsonFilePath = "$($env:APPDATA)\Code\User\settings.json" + if (!(Test-Path $jsonFilePath -PathType Leaf)) { + Write-Host "Skipping, no need to revert because settings file is not found: `"$jsonFilePath`"." + exit 0 + } + try { + $fileContent = Get-Content $jsonFilePath -ErrorAction Stop + } catch { + throw "Error, failed to read the settings file: `"$jsonFilePath`". Error: $_" + } + if ([string]::IsNullOrWhiteSpace($fileContent)) { + Write-Host "Skipping, no need to revert because settings file is empty: `"$jsonFilePath`"." + exit 0 + } + try { + $json = $fileContent | ConvertFrom-Json + } catch { + throw "Error, invalid JSON format in the settings file: `"$jsonFilePath`". Error: $_" + } + if (!$json.PSObject.Properties[$settingKey]) { + Write-Host "Skipping, no need to revert because setting `"$settingKey`" does not exist." + exit 0 + } + if ($json.$settingKey -ne $settingValue) { + Write-Host "Skipping, setting (`"$settingKey`") has different configuration than `"$settingValue`": `"$($json.$settingKey)`"." + exit 0 + } + $json.PSObject.Properties.Remove($settingKey) + $json | ConvertTo-Json | Set-Content $jsonFilePath + Write-Host "Successfully reverted the setting from file: `"$jsonFilePath`"." - name: RunPowerShell parameters: