chore: include User layer in ConfigLayerStack even if config.toml is empty

This commit is contained in:
Michael Bolin
2025-12-22 15:57:49 -08:00
parent 8e900c210c
commit 0161ecef18
3 changed files with 33 additions and 10 deletions

View File

@@ -237,6 +237,8 @@ pub enum ConfigLayerSource {
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase")]
User {
/// This is the path to the user's config.toml file, though it is not
/// guaranteed to exist.
file: AbsolutePathBuf,
},

View File

@@ -101,7 +101,7 @@ pub async fn load_config_layers_state(
// exists, but is malformed, then this error should be propagated to the
// user.
let user_file = AbsolutePathBuf::resolve_path_against_base(CONFIG_TOML_FILE, codex_home)?;
match tokio::fs::read_to_string(&user_file).await {
let user_layer = match tokio::fs::read_to_string(&user_file).await {
Ok(contents) => {
let user_config: TomlValue = toml::from_str(&contents).map_err(|e| {
io::Error::new(
@@ -123,13 +123,18 @@ pub async fn load_config_layers_state(
})?;
let user_config =
resolve_relative_paths_in_config_toml(user_config, user_config_parent)?;
layers.push(ConfigLayerEntry::new(
ConfigLayerSource::User { file: user_file },
user_config,
));
ConfigLayerEntry::new(ConfigLayerSource::User { file: user_file }, user_config)
}
Err(e) => {
if e.kind() != io::ErrorKind::NotFound {
if e.kind() == io::ErrorKind::NotFound {
// If there is no config.toml file, record an empty entry
// for this user layer, as this may still have subfolders
// that are significant in the overall ConfigLayerStack.
ConfigLayerEntry::new(
ConfigLayerSource::User { file: user_file },
TomlValue::Table(toml::map::Map::new()),
)
} else {
return Err(io::Error::new(
e.kind(),
format!(
@@ -139,7 +144,8 @@ pub async fn load_config_layers_state(
));
}
}
}
};
layers.push(user_layer);
if let Some(cwd) = cwd {
let mut merged_so_far = TomlValue::Table(toml::map::Map::new());

View File

@@ -88,9 +88,24 @@ async fn returns_empty_when_all_layers_missing() {
)
.await
.expect("load layers");
assert!(
layers.get_user_layer().is_none(),
"no user layer when CODEX_HOME/config.toml does not exist"
let user_layer = layers
.get_user_layer()
.expect("expected a user layer even when CODEX_HOME/config.toml does not exist");
assert_eq!(
&ConfigLayerEntry {
name: super::ConfigLayerSource::User {
file: AbsolutePathBuf::resolve_path_against_base(CONFIG_TOML_FILE, tmp.path())
.expect("resolve user config.toml path")
},
config: TomlValue::Table(toml::map::Map::new()),
version: version_for_toml(&TomlValue::Table(toml::map::Map::new())),
},
user_layer,
);
assert_eq!(
user_layer.config,
TomlValue::Table(toml::map::Map::new()),
"expected empty config for user layer when config.toml does not exist"
);
let binding = layers.effective_config();