fix(tui): split effective_home_dir into a leaf so skill_cli can resolve it

tests/skill_cli.rs pulls network_policy.rs and skills/install.rs into the
test binary via #[path] includes, so `crate::` there is the test binary's
root rather than the lib. #4757 replaced dirs::home_dir() with
crate::config::effective_home_dir() in both files, leaving two E0433s and
a broken test build on every platform:

    error[E0433]: cannot find `config` in `crate`
      --> crates/tui/tests/../src/network_policy.rs:324:27
      --> crates/tui/tests/../src/skills/install.rs:64:12

The obvious fix — include config/paths.rs behind a `mod config` shim —
does not work. Integration test binaries compile with cfg(test) set, so
paths.rs brings its `crate::test_support` call with it, and test_support
brings `crate::config_persistence` behind that. Shimming each layer would
put three stand-ins for production code in the test, including a fake
env mutex, which is a worse test than none.

effective_home_dir was already a leaf over std/dirs; it just shared a file
with the cfg(test)-gated env_config_path. Move it to config/home.rs, which
has no crate:: references at all, and re-export from paths.rs so
config::effective_home_dir and every `use paths::{...}` caller resolve
unchanged. The test binary includes that one file and gets the real
implementation rather than a divergent shim.

skill_cli is the only affected test binary; the other #[path]-including
tests pull files with no crate::config references.

Signed-off-by: Claude <noreply@anthropic.com>
This commit is contained in:
Claude
2026-07-25 04:32:02 +00:00
parent 0c47f84046
commit 189c93965a
4 changed files with 75 additions and 31 deletions
+1
View File
@@ -5797,6 +5797,7 @@ fn root_deepseek_model_is_foreign_to_direct_provider(provider: ApiProvider, mode
// `pub(crate)` entry points are re-exported so external `crate::config::`
// callers resolve unchanged; the remaining helpers are imported privately for
// the workspace-trust/config-load logic that stays in this file (#3311).
mod home;
mod paths;
use paths::{
canonicalize_or_keep, codewhale_home_dir, default_config_path, default_managed_config_path,
+60
View File
@@ -0,0 +1,60 @@
//! Home-directory resolution, kept as a dependency-free leaf.
//!
//! This is one function that could live in `paths.rs` — and did, until #4757
//! made it the crate-wide replacement for `dirs::home_dir()`. Two of the new
//! call sites (`network_policy.rs`, `skills/install.rs`) are pulled into the
//! `skill_cli` integration test via `#[path]` includes, where `crate::` means
//! the test binary's root rather than the lib. Anything they reach for has to
//! be includable there too.
//!
//! `paths.rs` is not: its `env_config_path` calls `crate::test_support` under
//! `#[cfg(test)]`, and integration test binaries compile *with* `cfg(test)`
//! set, so including it drags in `test_support` — and then
//! `config_persistence` behind that. Splitting this function out keeps the
//! includable surface to `std` + `dirs` with no `crate::` references at all,
//! so the test binary picks up production behavior verbatim instead of a
//! divergent shim.
//!
//! `paths.rs` re-exports this so `config::effective_home_dir` and every
//! existing `use paths::{...}` caller resolve unchanged.
use std::path::PathBuf;
/// Resolve the user's home directory, preferring the environment over the
/// platform lookup so tests can fake it consistently across OSes (#4757).
///
/// `HOME` and `USERPROFILE` are checked first (empty values are treated as
/// unset, since an empty home is never a usable path), then the Windows
/// `HOMEDRIVE`/`HOMEPATH` pair, and only then `dirs::home_dir()`. Keeping the
/// OS lookup last is what makes a faked environment win in tests while
/// production still falls back to the real thing.
pub(crate) fn effective_home_dir() -> Option<PathBuf> {
if let Some(path) = std::env::var_os("HOME") {
let path = PathBuf::from(path);
if !path.as_os_str().is_empty() {
return Some(path);
}
}
if let Some(path) = std::env::var_os("USERPROFILE") {
let path = PathBuf::from(path);
if !path.as_os_str().is_empty() {
return Some(path);
}
}
#[cfg(windows)]
{
if let (Some(drive), Some(homepath)) =
(std::env::var_os("HOMEDRIVE"), std::env::var_os("HOMEPATH"))
{
let mut path = PathBuf::from(drive);
path.push(homepath);
if !path.as_os_str().is_empty() {
return Some(path);
}
}
}
dirs::home_dir()
}
+5 -31
View File
@@ -13,6 +13,11 @@
use std::path::{Path, PathBuf};
/// Re-exported so `config::effective_home_dir` and every `use paths::{...}`
/// caller resolve unchanged. It lives in `home.rs` because this module is not
/// includable from an integration test binary — see that file's header.
pub(crate) use super::home::effective_home_dir;
pub(crate) fn default_config_path() -> Option<PathBuf> {
env_config_path().or_else(home_config_path)
}
@@ -24,37 +29,6 @@ pub(crate) fn codewhale_home_dir() -> Option<PathBuf> {
})
}
pub(crate) fn effective_home_dir() -> Option<PathBuf> {
if let Some(path) = std::env::var_os("HOME") {
let path = PathBuf::from(path);
if !path.as_os_str().is_empty() {
return Some(path);
}
}
if let Some(path) = std::env::var_os("USERPROFILE") {
let path = PathBuf::from(path);
if !path.as_os_str().is_empty() {
return Some(path);
}
}
#[cfg(windows)]
{
if let (Some(drive), Some(homepath)) =
(std::env::var_os("HOMEDRIVE"), std::env::var_os("HOMEPATH"))
{
let mut path = PathBuf::from(drive);
path.push(homepath);
if !path.as_os_str().is_empty() {
return Some(path);
}
}
}
dirs::home_dir()
}
pub(crate) fn home_config_path() -> Option<PathBuf> {
if let Some(home) = codewhale_home_dir() {
return Some(home.join("config.toml"));
+9
View File
@@ -25,6 +25,15 @@ use tiny_http::{Method, Response, Server};
#[path = "../src/network_policy.rs"]
mod network_policy;
// Both `network_policy` and `install` resolve the home directory through
// `crate::config::effective_home_dir()` (#4757). `config/home.rs` is a leaf
// over `std`/`dirs` with no `crate::` references, so including it here gives
// this binary the real implementation; naming it `config` matches how those
// two files address it in the lib.
#[path = "../src/config/home.rs"]
#[allow(dead_code)]
mod config;
#[path = "../src/skills/package_digest.rs"]
#[allow(dead_code)]
mod package_digest;