1pub mod args;
2
3use crate::callback::event_manager::EventManager;
4use crate::callback::filter_manager::FilterManager;
5use crate::types::{ClientConfigLocation, S3Credentials, StoragePath};
6use aws_sdk_s3::types::RequestPayer;
7use aws_smithy_types::checksum_config::RequestChecksumCalculation;
8use chrono::{DateTime, Utc};
9use fancy_regex::Regex;
10
11#[derive(Debug, Clone)]
70pub struct Config {
71 pub target: StoragePath,
72 pub show_no_progress: bool,
73 pub target_client_config: Option<ClientConfig>,
74 pub force_retry_config: ForceRetryConfig,
75 pub tracing_config: Option<TracingConfig>,
76 pub worker_size: u16,
77 pub warn_as_error: bool,
78 pub dry_run: bool,
79 pub rate_limit_objects: Option<u32>,
80 pub max_parallel_listings: u16,
81 pub object_listing_queue_size: u32,
82 pub max_parallel_listing_max_depth: u16,
83 pub allow_parallel_listings_in_express_one_zone: bool,
84 pub filter_config: FilterConfig,
85 pub max_keys: i32,
86 pub auto_complete_shell: Option<clap_complete::shells::Shell>,
87 pub event_callback_lua_script: Option<String>,
88 pub filter_callback_lua_script: Option<String>,
89 pub allow_lua_os_library: bool,
90 pub allow_lua_unsafe_vm: bool,
91 pub lua_vm_memory_limit: usize,
92 pub lua_callback_timeout_milliseconds: u64,
93 pub if_match: bool,
94 pub max_delete: Option<u64>,
95 pub filter_manager: FilterManager,
97 pub event_manager: EventManager,
98 pub batch_size: u16,
100 pub delete_all_versions: bool,
101 pub force: bool,
102 pub test_user_defined_callback: bool,
104}
105
106impl Config {
107 pub fn for_target(bucket: &str, prefix: &str) -> Self {
127 Config {
128 target: StoragePath::S3 {
129 bucket: bucket.to_string(),
130 prefix: prefix.to_string(),
131 },
132 force: true,
133 ..Config::default()
134 }
135 }
136}
137
138impl Default for Config {
139 fn default() -> Self {
144 Config {
145 target: StoragePath::S3 {
146 bucket: String::new(),
147 prefix: String::new(),
148 },
149 show_no_progress: false,
150 target_client_config: None,
151 force_retry_config: ForceRetryConfig::default(),
152 tracing_config: None,
153 worker_size: 16,
154 warn_as_error: false,
155 dry_run: false,
156 rate_limit_objects: None,
157 max_parallel_listings: 16,
158 object_listing_queue_size: 200_000,
159 max_parallel_listing_max_depth: 2,
160 allow_parallel_listings_in_express_one_zone: false,
161 filter_config: FilterConfig::default(),
162 max_keys: 1000,
163 auto_complete_shell: None,
164 event_callback_lua_script: None,
165 filter_callback_lua_script: None,
166 allow_lua_os_library: false,
167 allow_lua_unsafe_vm: false,
168 lua_vm_memory_limit: 64 * 1024 * 1024,
169 lua_callback_timeout_milliseconds: 10_000,
170 if_match: false,
171 max_delete: None,
172 filter_manager: FilterManager::new(),
173 event_manager: EventManager::new(),
174 batch_size: 200,
175 delete_all_versions: false,
176 force: false,
177 test_user_defined_callback: false,
178 }
179 }
180}
181
182impl Default for ForceRetryConfig {
183 fn default() -> Self {
184 ForceRetryConfig {
185 force_retry_count: 0,
186 force_retry_interval_milliseconds: 1000,
187 }
188 }
189}
190
191#[derive(Debug, Clone)]
196pub struct ClientConfig {
197 pub client_config_location: ClientConfigLocation,
198 pub credential: S3Credentials,
199 pub region: Option<String>,
200 pub endpoint_url: Option<String>,
201 pub force_path_style: bool,
202 pub accelerate: bool,
203 pub request_payer: Option<RequestPayer>,
204 pub retry_config: RetryConfig,
205 pub cli_timeout_config: CLITimeoutConfig,
206 pub disable_stalled_stream_protection: bool,
207 pub request_checksum_calculation: RequestChecksumCalculation,
208}
209
210#[derive(Debug, Clone)]
214pub struct RetryConfig {
215 pub aws_max_attempts: u32,
216 pub initial_backoff_milliseconds: u64,
217}
218
219#[derive(Debug, Clone)]
223pub struct CLITimeoutConfig {
224 pub operation_timeout_milliseconds: Option<u64>,
225 pub operation_attempt_timeout_milliseconds: Option<u64>,
226 pub connect_timeout_milliseconds: Option<u64>,
227 pub read_timeout_milliseconds: Option<u64>,
228}
229
230#[derive(Debug, Clone, Copy)]
235pub struct TracingConfig {
236 pub tracing_level: log::Level,
237 pub json_tracing: bool,
238 pub aws_sdk_tracing: bool,
239 pub span_events_tracing: bool,
240 pub disable_color_tracing: bool,
241}
242
243#[derive(Debug, Clone, Copy)]
248pub struct ForceRetryConfig {
249 pub force_retry_count: u32,
250 pub force_retry_interval_milliseconds: u64,
251}
252
253#[derive(Debug, Clone, Default)]
258pub struct FilterConfig {
259 pub before_time: Option<DateTime<Utc>>,
260 pub after_time: Option<DateTime<Utc>>,
261 pub include_regex: Option<Regex>,
262 pub exclude_regex: Option<Regex>,
263 pub include_content_type_regex: Option<Regex>,
264 pub exclude_content_type_regex: Option<Regex>,
265 pub include_metadata_regex: Option<Regex>,
266 pub exclude_metadata_regex: Option<Regex>,
267 pub include_tag_regex: Option<Regex>,
268 pub exclude_tag_regex: Option<Regex>,
269 pub larger_size: Option<u64>,
270 pub smaller_size: Option<u64>,
271 pub keep_latest_only: bool,
272}
273
274#[cfg(test)]
275mod tests {
276 use super::*;
277 use crate::test_utils::init_dummy_tracing_subscriber;
278
279 #[test]
280 fn retry_config_creation() {
281 init_dummy_tracing_subscriber();
282
283 let retry_config = RetryConfig {
284 aws_max_attempts: 3,
285 initial_backoff_milliseconds: 100,
286 };
287 assert_eq!(retry_config.aws_max_attempts, 3);
288 assert_eq!(retry_config.initial_backoff_milliseconds, 100);
289 }
290
291 #[test]
292 fn cli_timeout_config_creation() {
293 init_dummy_tracing_subscriber();
294
295 let timeout_config = CLITimeoutConfig {
296 operation_timeout_milliseconds: Some(30000),
297 operation_attempt_timeout_milliseconds: Some(10000),
298 connect_timeout_milliseconds: Some(5000),
299 read_timeout_milliseconds: Some(5000),
300 };
301 assert_eq!(timeout_config.operation_timeout_milliseconds, Some(30000));
302 assert_eq!(
303 timeout_config.operation_attempt_timeout_milliseconds,
304 Some(10000)
305 );
306 }
307
308 #[test]
309 fn cli_timeout_config_no_timeouts() {
310 init_dummy_tracing_subscriber();
311
312 let timeout_config = CLITimeoutConfig {
313 operation_timeout_milliseconds: None,
314 operation_attempt_timeout_milliseconds: None,
315 connect_timeout_milliseconds: None,
316 read_timeout_milliseconds: None,
317 };
318 assert!(timeout_config.operation_timeout_milliseconds.is_none());
319 }
320
321 #[test]
322 fn tracing_config_creation() {
323 init_dummy_tracing_subscriber();
324
325 let tracing_config = TracingConfig {
326 tracing_level: log::Level::Info,
327 json_tracing: false,
328 aws_sdk_tracing: false,
329 span_events_tracing: false,
330 disable_color_tracing: false,
331 };
332 assert_eq!(tracing_config.tracing_level, log::Level::Info);
333 assert!(!tracing_config.json_tracing);
334 }
335
336 #[test]
337 fn force_retry_config_creation() {
338 init_dummy_tracing_subscriber();
339
340 let force_retry = ForceRetryConfig {
341 force_retry_count: 3,
342 force_retry_interval_milliseconds: 1000,
343 };
344 assert_eq!(force_retry.force_retry_count, 3);
345 assert_eq!(force_retry.force_retry_interval_milliseconds, 1000);
346 }
347
348 #[test]
349 fn filter_config_default() {
350 init_dummy_tracing_subscriber();
351
352 let filter_config = FilterConfig::default();
353 assert!(filter_config.before_time.is_none());
354 assert!(filter_config.after_time.is_none());
355 assert!(filter_config.include_regex.is_none());
356 assert!(filter_config.exclude_regex.is_none());
357 assert!(filter_config.larger_size.is_none());
358 assert!(filter_config.smaller_size.is_none());
359 }
360
361 #[test]
367 fn config_for_target_sets_bucket_and_prefix() {
368 init_dummy_tracing_subscriber();
369
370 let config = Config::for_target("my-bucket", "logs/2024/");
371 let StoragePath::S3 { bucket, prefix } = &config.target;
372 assert_eq!(bucket, "my-bucket");
373 assert_eq!(prefix, "logs/2024/");
374 }
375
376 #[test]
377 fn config_for_target_sets_force_true() {
378 let config = Config::for_target("bucket", "prefix/");
380 assert!(config.force);
381 }
382
383 #[test]
384 fn config_for_target_uses_default_worker_and_batch_size() {
385 let config = Config::for_target("bucket", "");
386 assert_eq!(config.worker_size, 16);
387 assert_eq!(config.batch_size, 200);
388 }
389
390 #[test]
391 fn config_for_target_has_sensible_defaults() {
392 let config = Config::for_target("bucket", "prefix/");
393 assert!(!config.dry_run);
394 assert!(!config.delete_all_versions);
395 assert!(!config.if_match);
396 assert!(config.max_delete.is_none());
397 assert!(config.tracing_config.is_none());
398 assert!(config.target_client_config.is_none());
399 assert!(config.rate_limit_objects.is_none());
400 assert!(!config.warn_as_error);
401 assert!(!config.test_user_defined_callback);
402 }
403
404 #[test]
405 fn config_default_has_empty_target() {
406 let config = Config::default();
407 let StoragePath::S3 { bucket, prefix } = &config.target;
408 assert!(bucket.is_empty());
409 assert!(prefix.is_empty());
410 }
411
412 #[test]
413 fn config_default_does_not_set_force() {
414 let config = Config::default();
416 assert!(!config.force);
417 }
418
419 #[test]
420 fn config_default_field_values() {
421 let config = Config::default();
422 assert_eq!(config.worker_size, 16);
423 assert_eq!(config.batch_size, 200);
424 assert!(!config.show_no_progress);
425 assert!(!config.dry_run);
426 assert!(!config.warn_as_error);
427 assert_eq!(config.max_parallel_listings, 16);
428 assert_eq!(config.object_listing_queue_size, 200_000);
429 assert_eq!(config.max_parallel_listing_max_depth, 2);
430 assert!(!config.allow_parallel_listings_in_express_one_zone);
431 assert_eq!(config.max_keys, 1000);
432 assert!(config.auto_complete_shell.is_none());
433 assert!(config.event_callback_lua_script.is_none());
434 assert!(config.filter_callback_lua_script.is_none());
435 assert!(!config.allow_lua_os_library);
436 assert!(!config.allow_lua_unsafe_vm);
437 assert_eq!(config.lua_vm_memory_limit, 64 * 1024 * 1024);
438 assert_eq!(config.lua_callback_timeout_milliseconds, 10_000);
439 assert!(!config.if_match);
440 assert!(!config.delete_all_versions);
441 }
442
443 #[test]
444 fn force_retry_config_default_values() {
445 let frc = ForceRetryConfig::default();
446 assert_eq!(frc.force_retry_count, 0);
447 assert_eq!(frc.force_retry_interval_milliseconds, 1000);
448 }
449}