zagens_runtime/cli/
context.rs1use std::path::{Path, PathBuf};
4
5use anyhow::Result;
6
7use super::args::Cli;
8use super::setup::merge_project_config;
9use crate::config::Config;
10
11#[derive(Debug, Clone)]
12pub struct CliContext {
13 pub config: Config,
14 pub workspace: PathBuf,
15}
16
17pub fn resolve_workspace(cli: &Cli) -> PathBuf {
18 if let Some(w) = &cli.workspace {
19 return w.clone();
20 }
21 let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
22 escape_build_dir(&cwd).unwrap_or(cwd)
26}
27
28fn escape_build_dir(path: &Path) -> Option<PathBuf> {
32 let in_target = path.components().any(|c| c.as_os_str() == "target");
33 if !in_target {
34 return None;
35 }
36 let mut candidate = path.to_path_buf();
37 loop {
38 let parent = candidate.parent()?;
39 if parent == candidate {
40 return None;
41 }
42 let looks_like_root = parent.join("Cargo.toml").exists()
43 || parent.join(".git").exists()
44 || parent.join("package.json").exists();
45 if looks_like_root {
46 return Some(parent.to_path_buf());
47 }
48 candidate = parent.to_path_buf();
49 }
50}
51
52pub fn load_cli_context(cli: &Cli) -> Result<CliContext> {
53 let profile = cli
54 .profile
55 .clone()
56 .or_else(|| std::env::var("DEEPSEEK_PROFILE").ok());
57 let mut config = Config::load(cli.config.clone(), profile.as_deref())?;
58 cli.feature_toggles.apply(&mut config)?;
59 let workspace = resolve_workspace(cli);
60 if !cli.no_project_config {
61 merge_project_config(&mut config, &workspace);
62 }
63 Ok(CliContext { config, workspace })
64}
65
66pub fn config_path_for_report(cli: &Cli) -> PathBuf {
67 cli.config.clone().unwrap_or_else(default_config_path)
68}
69
70pub fn default_config_path() -> PathBuf {
71 std::env::var("DEEPSEEK_CONFIG_PATH")
72 .ok()
73 .map(PathBuf::from)
74 .unwrap_or_else(|| {
75 zagens_config::user_data_path("config.toml")
76 .unwrap_or_else(|_| PathBuf::from("config.toml"))
77 })
78}
79
80pub fn display_path(path: &Path) -> String {
81 crate::utils::display_path(path)
82}