cascade_cli/config/
mod.rs

1pub mod auth;
2pub mod settings;
3
4pub use auth::{AuthConfig, AuthManager};
5pub use settings::{BitbucketConfig, CascadeConfig, CascadeSettings, GitConfig, Settings};
6
7use crate::errors::{CascadeError, Result};
8use crate::git::GitRepository;
9use std::fs;
10use std::path::{Path, PathBuf};
11
12/// Get the Cascade configuration directory (~/.cascade/)
13pub fn get_config_dir() -> Result<PathBuf> {
14    let home_dir =
15        dirs::home_dir().ok_or_else(|| CascadeError::config("Could not find home directory"))?;
16    let config_dir = home_dir.join(".cascade");
17
18    // Validate the path to ensure it's within the home directory
19    crate::utils::path_validation::validate_config_path(&config_dir, &home_dir)
20}
21
22/// Get the Cascade configuration directory for a specific repository
23pub fn get_repo_config_dir(repo_path: &Path) -> Result<PathBuf> {
24    // Validate that repo_path is a real directory
25    let canonical_repo = repo_path.canonicalize().map_err(|e| {
26        CascadeError::config(format!("Invalid repository path '{repo_path:?}': {e}"))
27    })?;
28
29    let config_dir = canonical_repo.join(".cascade");
30
31    // Validate that config dir would be within the repo directory
32    crate::utils::path_validation::validate_config_path(&config_dir, &canonical_repo)
33}
34
35/// Ensure the configuration directory exists
36pub fn ensure_config_dir(config_dir: &Path) -> Result<()> {
37    if !config_dir.exists() {
38        fs::create_dir_all(config_dir)
39            .map_err(|e| CascadeError::config(format!("Failed to create config directory: {e}")))?;
40    }
41
42    // Create subdirectories
43    let stacks_dir = config_dir.join("stacks");
44    if !stacks_dir.exists() {
45        fs::create_dir_all(&stacks_dir)
46            .map_err(|e| CascadeError::config(format!("Failed to create stacks directory: {e}")))?;
47    }
48
49    let cache_dir = config_dir.join("cache");
50    if !cache_dir.exists() {
51        fs::create_dir_all(&cache_dir)
52            .map_err(|e| CascadeError::config(format!("Failed to create cache directory: {e}")))?;
53    }
54
55    Ok(())
56}
57
58/// Check if a repository is initialized for Cascade
59pub fn is_repo_initialized(repo_path: &Path) -> bool {
60    match get_repo_config_dir(repo_path) {
61        Ok(config_dir) => config_dir.exists() && config_dir.join("config.json").exists(),
62        Err(_) => false,
63    }
64}
65
66/// Initialize a repository for Cascade
67pub fn initialize_repo(repo_path: &Path, bitbucket_url: Option<String>) -> Result<()> {
68    let config_dir = get_repo_config_dir(repo_path)?;
69    ensure_config_dir(&config_dir)?;
70
71    // Create default configuration with detected default branch
72    let mut settings = Settings::default_for_repo(bitbucket_url);
73
74    // Detect the actual default branch from the repository
75    if let Ok(git_repo) = GitRepository::open(repo_path) {
76        if let Ok(detected_branch) = git_repo.detect_main_branch() {
77            tracing::info!("Detected default branch: {}", detected_branch);
78            settings.git.default_branch = detected_branch;
79        } else {
80            tracing::warn!(
81                "Could not detect default branch, using fallback: {}",
82                settings.git.default_branch
83            );
84        }
85    } else {
86        tracing::warn!(
87            "Could not open git repository, using fallback default branch: {}",
88            settings.git.default_branch
89        );
90    }
91
92    settings.save_to_file(&config_dir.join("config.json"))?;
93
94    tracing::info!("Initialized Cascade repository at {}", repo_path.display());
95    Ok(())
96}