diff options
| author | JJ Liebig <jonathan.liebig@gmail.com> | 2026-09-11 20:36:06 +0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-11 18:36:06 +0200 |
| commit | eba7758cedd1bd3a86c527b8a458075e8ef1efc2 (patch) | |
| tree | 4e0bebbd92134a17261bde13dbea3b4ae53e159b /src/config/write.rs | |
| parent | c7a7cc454ac116467ce48365e075eb8ce53e458c (diff) | |
fix(config): keep utf8 bom from breaking config reads and writes (#3962)
* fix(config): keep utf8 bom from breaking config reads and writes
refs #3678
* fix(config): only strip displaced boms when config is invalid
refs #3678
* fix(config): strip only boms the toml parser rejects
refs #3678
Diffstat (limited to 'src/config/write.rs')
| -rw-r--r-- | src/config/write.rs | 40 |
1 files changed, 37 insertions, 3 deletions
diff --git a/src/config/write.rs b/src/config/write.rs index 75244583..f34ec2f6 100644 --- a/src/config/write.rs +++ b/src/config/write.rs @@ -55,9 +55,9 @@ pub(crate) fn update_file_at( std::fs::create_dir_all(parent) .map_err(|error| format!("failed to create config directory: {error}"))?; } - let content = match std::fs::read_to_string(path) { - Ok(content) => content, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => String::new(), + let content = match super::io::read_optional_config(path) { + Ok(Some(content)) => content, + Ok(None) => String::new(), Err(error) => { return Err(format!( "failed to read config before saving {description}: {error}" @@ -73,3 +73,37 @@ pub(crate) fn write_edit(edit: ConfigEdit<'_>) -> Result<(), String> { edit.apply(content) }) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn update_file_at_does_not_move_a_leading_bom_into_the_file() { + let dir = std::env::temp_dir().join(format!("herdr-config-bom-{}", std::process::id())); + std::fs::create_dir_all(&dir).unwrap(); + let path = dir.join("config.toml"); + std::fs::write( + &path, + b"\xEF\xBB\xBF[terminal]\ndefault_shell = \"pwsh.exe\"\n", + ) + .unwrap(); + + update_file_at(&path, "onboarding setting", |content| { + crate::config::upsert_top_level_bool(content, "onboarding", false) + }) + .unwrap(); + + let written = std::fs::read_to_string(&path).unwrap(); + let _ = std::fs::remove_dir_all(dir); + + assert!( + !written.contains('\u{feff}'), + "unexpected BOM in {written:?}" + ); + assert!( + toml::from_str::<toml::Value>(&written).is_ok(), + "written config is not valid TOML: {written:?}" + ); + } +} |
