feat: integrate config file loading into CLI#9
Conversation
Wired up ConfigManager from Task 5 into CLI handlers: Config File Loading: - Load config from discovered locations (.ccsync, .ccsync.local, XDG) - Support --config flag to specify custom config file - Support --no-config flag to skip all config files - Graceful fallback to defaults if config loading fails CLI Precedence: - Config files loaded first - CLI flags override config file settings - CLI conflict strategy overrides config - CLI type filters override config include patterns - CLI dry-run flag overrides config Code Quality: - Created SyncOptions struct to avoid excessive bool parameters - Refactored execute() signatures to use SyncOptions - Proper error handling with fallback to defaults Config files now support: - ignore patterns (gitignore-style) - include patterns - conflict_strategy - dry_run - preserve_symlinks - Direction and type-specific rules (from Task 5) All 109 tests pass, zero clippy warnings.
Added section explaining config file support: - Example .ccsync file with common options - Config file precedence order - Available config options (ignore, include, conflict_strategy, etc.) - How to use --config and --no-config flags - Note that CLI flags always override config files Makes config file feature discoverable to users.
Removed 'dry_run = false' line which looked like it was enabling dry-run by default when it actually disables it. This was confusing. The config example now shows only commonly used options without the misleading dry_run setting.
Pull Request Review: Config File IntegrationSummaryThis PR successfully integrates config file loading into CLI commands with a solid foundation. The introduction of the ✅ Strengths1. Excellent RefactoringThe
Example (crates/ccsync-cli/src/commands/common.rs:4-16): #[allow(clippy::struct_excessive_bools)]
pub struct SyncOptions<'a> {
pub verbose: bool,
pub dry_run: bool,
pub yes_all: bool,
pub config_path: Option<&'a std::path::Path>,
pub no_config: bool,
}2. Graceful Error HandlingConfig loading failures fallback to defaults (to_local.rs:43-49, to_global.rs:43-49): ConfigManager::load(options.config_path).unwrap_or_else(|e| {
if options.verbose {
eprintln!("Warning: Failed to load config files: {e}");
eprintln!("Using default configuration");
}
Config::default()
})3. Security ConsiderationsThe underlying 4. DocumentationThe README additions are clear and provide good examples of config file usage. ❌ Critical Issues1. Missing Test CoverageThe PR claims "109/109 tests passing" but provides no new tests for the new functionality: Missing tests:
Recommendation: Add integration tests in #[test]
fn test_config_flag() {
// Test --config <path> loads custom config
}
#[test]
fn test_no_config_flag() {
// Test --no-config bypasses all config files
}
#[test]
fn test_cli_overrides_config() {
// Test that CLI flags override config file settings
}2. Significant Code Duplication (DRY Violation)Both
Recommendation: Extract to shared module: // crates/ccsync-cli/src/commands/common.rs
impl SyncOptions<'_> {
pub fn load_and_merge_config(
&self,
types: &[ConfigType],
conflict: &ConflictMode,
) -> anyhow::Result<Config> {
let mut config = if self.no_config {
Config::default()
} else {
ConfigManager::load(self.config_path)
.unwrap_or_else(|_| Config::default())
};
Self::merge_cli_flags(&mut config, types, conflict, self.dry_run);
Ok(config)
}
// Move merge_cli_flags, convert_conflict_mode, build_type_patterns here
}3. Incorrect Array Merge BehaviorThe PR description claims "Config files merged with additive behavior for arrays" but the code replaces the entire Current behavior (to_local.rs:122-125): // Handle type filters (CLI patterns override config patterns)
if !types.is_empty() {
config.include = Self::build_type_patterns(types); // ❌ Replaces, not adds
}Expected behavior: if !types.is_empty() {
let type_patterns = Self::build_type_patterns(types);
// Add to existing patterns rather than replacing
config.include.extend(type_patterns);
}Impact: Users cannot combine config file include patterns with CLI type filters. This contradicts the documented behavior.
|
Critical fixes from code review: - Fix array merge behavior: CLI --type patterns now extend config patterns instead of replacing them (additive behavior) - Add mutual exclusivity between --config and --no-config flags using clap's conflicts_with attribute - Fail hard when user explicitly specifies --config but file cannot be loaded (previously fell through to defaults) Refactoring improvements: - Extract duplicated config loading logic to SyncOptions::load_config() shared method in common.rs - Remove unused ConfigManager imports from command files - Add .ccsync.local to .gitignore for user-specific local overrides Maintains full test compatibility (109/109 passing) and proper precedence rules (CLI > config files).
Code Review: PR #9 - Config File Loading IntegrationThank you for this well-structured PR! The integration of config file loading is clean and follows good Rust practices. Here's my detailed review: ✅ StrengthsExcellent Code Quality
Good Architecture
🔴 Critical Issues1. Unused CLI Flags (High Priority)Three CLI flags are defined but never used: // cli.rs:26-42
pub global_path: Option<PathBuf>, // ❌ UNUSED
pub local_path: Option<PathBuf>, // ❌ UNUSED
pub preserve_symlinks: bool, // ❌ UNUSEDImpact: Users see these in Recommendation: Either implement them, remove them, or mark as "not yet implemented" in help text. 2. Significant Code Duplication (High Priority)Identical methods duplicated in
Recommendation: Move to // In common.rs
impl<'a> SyncOptions<'a> {
pub fn get_global_path() -> anyhow::Result<PathBuf> { ... }
pub fn get_local_path() -> anyhow::Result<PathBuf> { ... }
pub fn merge_cli_flags(&self, config: &mut Config, ...) { ... }
}
|
Summary
Integrates config file loading from Task 5 into CLI commands. Config files are now automatically discovered, loaded, and merged with CLI flags.
Features
Config File Support
--config <path>to specify custom config file--no-configto skip all config filesConfig File Locations (in precedence order):
--config <path>- Custom config via CLI flag.ccsync.local- Project-local (gitignored).ccsync- Project config (committed)~/.config/ccsync/config.toml- Global XDG configPrecedence Rules
Supported Config Options
Code Quality Improvements
Refactoring: SyncOptions Struct
SyncOptionsstruct to avoid excessive boolean parametersBefore:
After:
Error Handling
Documentation
Test Results
-D warningsImplementation
New Module:
crates/ccsync-cli/src/commands/common.rsSyncOptionsstruct for execution parametersModified:
to_local.rs,to_global.rs- Integrated ConfigManagermain.rs- Creates SyncOptions from CLI flagsREADME.md- Added configuration documentationCloses #5 (Config file loading integration)