async_inotify/
app.rs

1use std::ffi::OsString;
2
3use clap::{Arg, ArgAction, Command};
4use inotify::WatchMask;
5
6/// Anotify
7/// todo
8pub struct Anotify {
9    /// inotify::WatchMask, the event mask to watched
10    pub mask: WatchMask,
11
12    /// the regex to fliter file name
13    pub regex: Option<String>,
14
15    /// does it watch sub dir
16    pub recursive: bool,
17
18    /// all pathes to be watched
19    pub targets: Vec<OsString>,
20}
21
22fn app() -> Command {
23    let cmd = Command::new("anotify")
24        .author("CC")
25        .arg(
26            Arg::new("access")
27                .long("access")
28                .short('a')
29                .action(ArgAction::SetTrue)
30                .help("File was accessed"),
31        )
32        .arg(
33            Arg::new("attrib")
34                .long("attrib")
35                .short('A')
36                .action(ArgAction::SetTrue)
37                .help("Metadata (permissions, timestamps, …) changed"),
38        )
39        .arg(
40            Arg::new("close_write")
41                .long("close_write")
42                .short('x')
43                .action(ArgAction::SetTrue)
44                .help("File opened for writing was closed"),
45        )
46        .arg(
47            Arg::new("close_nowrite")
48                .long("close_nowrite")
49                .short('q')
50                .action(ArgAction::SetTrue)
51                .help("File or directory not opened for writing was closed"),
52        )
53        .arg(
54            Arg::new("create")
55                .long("create")
56                .short('c')
57                .action(ArgAction::SetTrue)
58                .help("File/directory created in watched directory"),
59        )
60        .arg(
61            Arg::new("delete")
62                .long("delete")
63                .short('d')
64                .action(ArgAction::SetTrue)
65                .help("File/directory deleted from watched directory"),
66        )
67        .arg(
68            Arg::new("delete_self")
69                .long("delete_self")
70                .short('D')
71                .action(ArgAction::SetTrue)
72                .help("Watched file/directory was deleted"),
73        )
74        .arg(
75            Arg::new("modify")
76                .long("modify")
77                .short('m')
78                .action(ArgAction::SetTrue)
79                .help("File was modified"),
80        )
81        .arg(
82            Arg::new("move_self")
83                .long("move_self")
84                .short('S')
85                .action(ArgAction::SetTrue)
86                .help("Watched file/directory was moved"),
87        )
88        .arg(
89            Arg::new("moved_from")
90                .long("moved_from")
91                .short('F')
92                .action(ArgAction::SetTrue)
93                .help("File was renamed/moved; watched directory contained old name"),
94        )
95        .arg(
96            Arg::new("moved_to")
97                .long("moved_to")
98                .short('T')
99                .action(ArgAction::SetTrue)
100                .help("File was renamed/moved; watched directory contains new name"),
101        )
102        .arg(
103            Arg::new("open")
104                .long("open")
105                .short('o')
106                .action(ArgAction::SetTrue)
107                .help("File or directory was opened"),
108        )
109        .arg(
110            Arg::new("move")
111                .long("move")
112                .short('M')
113                .action(ArgAction::SetTrue)
114                .help("Watch for all move events"),
115        )
116        .arg(
117            Arg::new("close")
118                .long("close")
119                .short('Q')
120                .action(ArgAction::SetTrue)
121                .help("Watch for all close events"),
122        )
123        .arg(
124            Arg::new("all")
125                .long("all")
126                .action(ArgAction::SetTrue)
127                .help("Watch for all events"),
128        )
129        .arg(
130            Arg::new("dont_follow")
131                .long("dont_follow")
132                .action(ArgAction::SetTrue)
133                .help("Don’t dereference the path if it is a symbolic link"),
134        )
135        .arg(
136            Arg::new("excl_unlink")
137                .long("excl_unlink")
138                .action(ArgAction::SetTrue)
139                .help("Filter events for directory entries that have been unlinked"),
140        )
141        .arg(
142            Arg::new("mask_add")
143                .long("mask_add")
144                .action(ArgAction::SetTrue)
145                .help("If a watch for the inode exists, amend it instead of replacing it"),
146        )
147        .arg(
148            Arg::new("oneshot")
149                .long("oneshot")
150                .action(ArgAction::SetTrue)
151                .help("Only receive one event, then remove the watch"),
152        )
153        .arg(
154            Arg::new("dir")
155                .long("dir")
156                .action(ArgAction::SetTrue)
157                .help("Only watch path, if it is a directory"),
158        )
159        .arg(
160            Arg::new("recursive")
161                .short('R')
162                .long("recursive")
163                .action(ArgAction::SetTrue)
164                .help("Recursive monitor a path"),
165        )
166        .arg(
167            Arg::new("regex")
168                .short('E')
169                .long("regex")
170                .action(ArgAction::Set)
171                .help("Use regex to match file name, only matched will report"),
172        )
173        .arg(
174            Arg::new("target")
175                .action(ArgAction::Append)
176                .default_value("./"),
177        );
178
179    cmd
180}
181
182pub fn parse() -> crate::Result<Anotify> {
183    let _args = app().get_matches();
184    let mut mask = WatchMask::empty();
185
186    // access
187    if *_args.get_one::<bool>("access").unwrap() {
188        mask |= WatchMask::ACCESS;
189    }
190
191    // attrib
192    if *_args.get_one::<bool>("attrib").unwrap() {
193        mask |= WatchMask::ATTRIB;
194    }
195
196    // close write
197    if *_args.get_one::<bool>("close_write").unwrap() {
198        mask |= WatchMask::CLOSE_WRITE;
199    }
200
201    // close nowrite
202    if *_args.get_one::<bool>("close_nowrite").unwrap() {
203        mask |= WatchMask::CLOSE_NOWRITE;
204    }
205
206    // create
207    if *_args.get_one::<bool>("create").unwrap() {
208        mask |= WatchMask::CREATE;
209    }
210
211    // delete
212    if *_args.get_one::<bool>("delete").unwrap() {
213        mask |= WatchMask::DELETE;
214    }
215
216    // delete self
217    if *_args.get_one::<bool>("delete_self").unwrap() {
218        mask |= WatchMask::DELETE_SELF;
219    }
220
221    // modify
222    if *_args.get_one::<bool>("modify").unwrap() {
223        mask |= WatchMask::MODIFY;
224    }
225
226    // move self
227    if *_args.get_one::<bool>("move_self").unwrap() {
228        mask |= WatchMask::MOVE_SELF;
229    }
230
231    // move from
232    if *_args.get_one::<bool>("moved_from").unwrap() {
233        mask |= WatchMask::MOVED_FROM;
234    }
235
236    // move to
237    if *_args.get_one::<bool>("moved_to").unwrap() {
238        mask |= WatchMask::MOVED_TO;
239    }
240
241    // open
242    if *_args.get_one::<bool>("open").unwrap() {
243        mask |= WatchMask::OPEN;
244    }
245
246    // all events
247    if *_args.get_one::<bool>("all").unwrap() {
248        mask |= WatchMask::ALL_EVENTS;
249    }
250
251    // move events
252    if *_args.get_one::<bool>("move").unwrap() {
253        mask |= WatchMask::MOVE;
254    }
255
256    // move events
257    if *_args.get_one::<bool>("close").unwrap() {
258        mask |= WatchMask::CLOSE;
259    }
260
261    // don't follow events
262    if *_args.get_one::<bool>("dont_follow").unwrap() {
263        mask |= WatchMask::DONT_FOLLOW;
264    }
265
266    // excl unlink
267    if *_args.get_one::<bool>("excl_unlink").unwrap() {
268        mask |= WatchMask::EXCL_UNLINK;
269    }
270
271    // mask add
272    if *_args.get_one::<bool>("mask_add").unwrap() {
273        mask |= WatchMask::MASK_ADD;
274    }
275
276    // oneshot
277    if *_args.get_one::<bool>("oneshot").unwrap() {
278        mask |= WatchMask::ONESHOT;
279    }
280
281    // only dir
282    if *_args.get_one::<bool>("dir").unwrap() {
283        mask |= WatchMask::ONLYDIR;
284    }
285
286    if mask.is_empty() {
287        return Err("Error: You must point at least one EVENT".into());
288    }
289
290    let mut recursive = false;
291    if *_args.get_one::<bool>("recursive").unwrap() {
292        recursive = true;
293    }
294
295    let mut regex = None;
296    if let Some(_regex) = _args.get_one::<String>("regex") {
297        regex = Some(String::from(_regex));
298    }
299
300    let mut targets: Vec<OsString> = vec![];
301    let mut target = _args.get_many::<String>("target").unwrap();
302    while let Some(_target) = target.next() {
303        targets.push(_target.into());
304    }
305
306    Ok(Anotify {
307        mask,
308        recursive,
309        regex,
310        targets,
311    })
312}