1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
use std::sync::Arc;
use crate::{cli::commands::sync::SyncArgs, config_build};
config_build! {
SyncConfig<crate::cli::commands::sync::SyncArgs> {
// Force update without prompts
force: bool => {
cli: |args: &SyncArgs| {
// Check both main args and subcommand args
if args.force {
Some(true)
} else if let Some(crate::cli::commands::sync::SyncSubcommand::Update { force, .. }) = &args.command {
Some(*force)
} else {
None
}
},
env: "GUARDY_SYNC_FORCE",
default: false,
},
// Auto-update files without confirmation
auto_update: bool => {
env: "GUARDY_SYNC_AUTO_UPDATE",
default: false,
},
// Interactive mode (prompts for confirmation)
interactive: bool => {
cli: |args: &SyncArgs| {
// If force is true, interactive should be false
if args.force {
Some(false)
} else if let Some(crate::cli::commands::sync::SyncSubcommand::Update { force, .. }) = &args.command {
Some(!force)
} else {
None
}
},
env: "GUARDY_SYNC_INTERACTIVE",
default: true,
},
// Always show diff before updating (used in interactive mode)
show_diff: bool => {
env: "GUARDY_SYNC_SHOW_DIFF",
default: true,
},
// Git operation timeout in seconds
git_timeout_seconds: u32 => {
env: "GUARDY_SYNC_GIT_TIMEOUT",
default: 30,
},
// Number of context lines to show in diffs
diff_context_lines: u8 => {
env: "GUARDY_SYNC_DIFF_CONTEXT",
default: 3,
},
// Cache directory path (relative to project root)
cache_dir: String => {
env: "GUARDY_SYNC_CACHE_DIR",
default: ".guardy/cache".to_string(),
},
// Single repo URL (from CLI/ENV/file)
repo: Option<String> => {
cli: |args: &SyncArgs| {
args.repo.clone().or_else(|| {
if let Some(crate::cli::commands::sync::SyncSubcommand::Update { repo, .. }) = &args.command {
repo.clone()
} else {
None
}
})
},
env: "GUARDY_SYNC_REPO",
default: None,
},
// Single repo version (from CLI/ENV/file)
version: Option<String> => {
cli: |args: &SyncArgs| {
args.version.clone().or_else(|| {
if let Some(crate::cli::commands::sync::SyncSubcommand::Update { version, .. }) = &args.command {
version.clone()
} else {
None
}
})
},
env: "GUARDY_SYNC_VERSION",
default: None,
},
// Single repo source path (from CLI/ENV/file)
source_path: Option<String> => {
cli: |args: &SyncArgs| {
args.source_path.clone().or_else(|| {
if let Some(crate::cli::commands::sync::SyncSubcommand::Update { source_path, .. }) = &args.command {
source_path.clone()
} else {
None
}
})
},
env: "GUARDY_SYNC_SOURCE_PATH",
default: None,
},
// Single repo destination path (from CLI/ENV/file)
dest_path: Option<String> => {
cli: |args: &SyncArgs| {
args.dest_path.clone().or_else(|| {
if let Some(crate::cli::commands::sync::SyncSubcommand::Update { dest_path, .. }) = &args.command {
dest_path.clone()
} else {
None
}
})
},
env: "GUARDY_SYNC_DEST_PATH",
default: None,
},
// Single repo include patterns (from CLI/ENV/file)
include: Vec<String> => {
cli: |args: &SyncArgs| {
let mut patterns = args.include.clone();
if let Some(crate::cli::commands::sync::SyncSubcommand::Update { include, .. }) = &args.command {
patterns.extend(include.clone());
}
if patterns.is_empty() { None } else { Some(patterns) }
},
env: "GUARDY_SYNC_INCLUDE",
default: Vec::new(),
},
// Single repo exclude patterns (from CLI/ENV/file)
exclude: Vec<String> => {
cli: |args: &SyncArgs| {
let mut patterns = args.exclude.clone();
if let Some(crate::cli::commands::sync::SyncSubcommand::Update { exclude, .. }) = &args.command {
patterns.extend(exclude.clone());
}
if patterns.is_empty() { None } else { Some(patterns) }
},
env: "GUARDY_SYNC_EXCLUDE",
default: Vec::new(),
},
// Repository configurations loaded from file (complex nested structures)
repolist: Arc<Vec<RepoConfig>> => {
default: Arc::new(Vec::new()),
},
}
}
// Repository configuration structure for sync functionality
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct RepoConfig {
pub name: Arc<str>,
pub repo: Arc<str>,
pub version: Arc<str>,
pub source_path: Arc<str>,
pub dest_path: Arc<str>,
#[serde(default)]
pub include: Vec<String>,
#[serde(default)]
pub exclude: Vec<String>,
#[serde(default)]
pub protected: bool,
}