add_determinism/linkdupes/
config.rs1use clap::Parser;
4
5use anyhow::Result;
6use log::{info, LevelFilter};
7use std::ops::Add;
8use std::path::PathBuf;
9use std::time;
10
11use crate::{setup, simplelog};
12
13#[derive(Debug, Parser)]
14#[command(version, about, long_about = None)]
15struct Options {
16 #[arg(value_name = "path")]
18 pub inputs: Vec<PathBuf>,
19
20 #[arg(long)]
22 pub brp: bool,
23
24 #[arg(short, long, action = clap::ArgAction::Count)]
26 pub verbose: u8,
27
28 #[arg(short = 'n', long)]
30 pub dry_run: bool,
31
32 #[arg(long)]
34 pub ignore_mtime: bool,
35
36 #[arg(long)]
38 pub ignore_mode: bool,
39
40 #[arg(long)]
42 pub ignore_owner: bool,
43
44 #[arg(long)]
46 pub ignore_selinux_context: bool,
47
48 #[arg(long)]
50 pub print_selinux_contexts: bool,
51}
52
53pub struct Config {
54 #[allow(dead_code)]
55 pub root: Option<PathBuf>, pub inputs: Vec<PathBuf>,
58 pub fatal_errors: bool,
59 pub _verbose: u8,
60 pub dry_run: bool,
61 pub ignore_mtime: bool,
62 pub ignore_mode: bool,
63 pub ignore_owner: bool,
64 pub source_date_epoch: Option<time::SystemTime>,
65 pub print_selinux_contexts: bool,
66
67 #[cfg(feature = "selinux")]
68 pub selinux_labels: Option<selinux::label::Labeler<selinux::label::back_end::File>>,
69}
70
71impl Config {
72 pub fn make() -> Result<Self> {
73 let mut root = None;
74
75 let options = Options::parse();
76
77 let log_level = match options.verbose {
79 0 => LevelFilter::Warn,
80 1 => LevelFilter::Info,
81 2 => LevelFilter::Debug,
82 3.. => LevelFilter::Trace,
83 };
84
85 simplelog::init(log_level, false)?;
86
87 let source_date_epoch = setup::source_date_epoch()?.map(
89 |s| time::UNIX_EPOCH.add(time::Duration::new(s as u64, 0))
90 );
91
92 if options.brp {
94 root = Some(setup::brp_check(None, &options.inputs)?);
95 }
96
97 #[cfg(feature = "selinux")]
98 let selinux_labels = if options.ignore_selinux_context {
99 None
100 } else {
101 Some(selinux::label::Labeler::new(&[], false)?)
102 };
103
104 if options.inputs.is_empty() && !options.brp {
106 info!("No arguments specified, nothing to do. 😎");
107 }
108
109 Ok(Self {
110 root,
111 inputs: options.inputs,
112 fatal_errors: options.brp,
113 _verbose: options.verbose,
114 dry_run: options.dry_run,
115 ignore_mtime: options.ignore_mtime,
116 ignore_mode: options.ignore_mode,
117 ignore_owner: options.ignore_owner,
118 source_date_epoch,
119 print_selinux_contexts: options.print_selinux_contexts,
120
121 #[cfg(feature = "selinux")]
122 selinux_labels,
123 })
124 }
125
126 #[allow(dead_code)]
127 pub const fn empty() -> Self {
129 Self {
130 root: None,
131 inputs: vec![],
132 fatal_errors: false,
133 _verbose: 0,
134 dry_run: false,
135 ignore_mtime: false,
136 ignore_mode: false,
137 ignore_owner: false,
138 source_date_epoch: None,
139 print_selinux_contexts: false,
140
141 #[cfg(feature = "selinux")]
142 selinux_labels: None,
143 }
144 }
145}