2021-08-19 10:44:02 +02:00
|
|
|
//! Synthetic event type, derived from inputs, triggers actions.
|
|
|
|
//!
|
2021-08-16 11:49:12 +02:00
|
|
|
//! Fundamentally, events in watchexec have three purposes:
|
|
|
|
//!
|
|
|
|
//! 1. To trigger the launch, restart, or other interruption of a process;
|
|
|
|
//! 2. To be filtered upon according to whatever set of criteria is desired;
|
|
|
|
//! 3. To carry information about what caused the event, which may be provided to the process.
|
|
|
|
|
2021-08-22 12:06:12 +02:00
|
|
|
use std::{
|
|
|
|
collections::HashMap,
|
2021-09-02 21:57:59 +02:00
|
|
|
fmt,
|
2021-10-12 17:06:39 +02:00
|
|
|
fs::FileType,
|
2021-08-22 12:06:12 +02:00
|
|
|
path::{Path, PathBuf},
|
2021-09-02 19:22:15 +02:00
|
|
|
process::ExitStatus,
|
2021-08-22 12:06:12 +02:00
|
|
|
};
|
2021-08-16 11:49:12 +02:00
|
|
|
|
2021-09-02 22:14:04 +02:00
|
|
|
use notify::EventKind;
|
|
|
|
|
2021-10-15 14:13:16 +02:00
|
|
|
use crate::signal::source::MainSignal;
|
2021-08-17 11:41:13 +02:00
|
|
|
|
2021-08-16 11:49:12 +02:00
|
|
|
/// An event, as far as watchexec cares about.
|
2021-08-24 12:20:44 +02:00
|
|
|
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
2021-08-16 11:49:12 +02:00
|
|
|
pub struct Event {
|
2021-09-13 09:34:40 +02:00
|
|
|
pub tags: Vec<Tag>,
|
2021-08-16 11:49:12 +02:00
|
|
|
pub metadata: HashMap<String, Vec<String>>,
|
|
|
|
}
|
|
|
|
|
2021-09-02 19:22:15 +02:00
|
|
|
/// Something which can be used to filter or qualify an event.
|
2021-08-16 11:49:12 +02:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
|
|
#[non_exhaustive]
|
2021-09-13 09:34:40 +02:00
|
|
|
pub enum Tag {
|
2021-10-12 17:06:39 +02:00
|
|
|
Path {
|
|
|
|
path: PathBuf,
|
|
|
|
file_type: Option<FileType>,
|
|
|
|
},
|
2021-09-02 22:14:04 +02:00
|
|
|
FileEventKind(EventKind),
|
2021-08-16 11:49:12 +02:00
|
|
|
Source(Source),
|
|
|
|
Process(u32),
|
2021-10-15 14:13:16 +02:00
|
|
|
Signal(MainSignal),
|
2021-09-02 19:22:15 +02:00
|
|
|
ProcessCompletion(Option<ExitStatus>),
|
2021-08-16 11:49:12 +02:00
|
|
|
}
|
|
|
|
|
2021-09-27 13:54:33 +02:00
|
|
|
impl Tag {
|
|
|
|
pub const fn discriminant_name(&self) -> &'static str {
|
|
|
|
match self {
|
2021-10-12 17:06:39 +02:00
|
|
|
Tag::Path { .. } => "Path",
|
2021-09-27 13:54:33 +02:00
|
|
|
Tag::FileEventKind(_) => "FileEventKind",
|
|
|
|
Tag::Source(_) => "Source",
|
|
|
|
Tag::Process(_) => "Process",
|
|
|
|
Tag::Signal(_) => "Signal",
|
|
|
|
Tag::ProcessCompletion(_) => "ProcessCompletion",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-16 11:49:12 +02:00
|
|
|
/// The general origin of the event.
|
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub enum Source {
|
|
|
|
Filesystem,
|
|
|
|
Keyboard,
|
|
|
|
Mouse,
|
2021-08-17 11:41:13 +02:00
|
|
|
Os,
|
2021-08-16 11:49:12 +02:00
|
|
|
Time,
|
2021-09-02 21:57:45 +02:00
|
|
|
Internal,
|
2021-08-16 11:49:12 +02:00
|
|
|
}
|
2021-08-22 12:06:12 +02:00
|
|
|
|
2021-09-27 13:54:33 +02:00
|
|
|
impl fmt::Display for Source {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2021-09-28 11:22:33 +02:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"{}",
|
|
|
|
match self {
|
|
|
|
Self::Filesystem => "filesystem",
|
|
|
|
Self::Keyboard => "keyboard",
|
|
|
|
Self::Mouse => "mouse",
|
|
|
|
Self::Os => "os",
|
|
|
|
Self::Time => "time",
|
|
|
|
Self::Internal => "internal",
|
|
|
|
}
|
|
|
|
)
|
2021-09-27 13:54:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-22 12:06:12 +02:00
|
|
|
impl Event {
|
2021-09-28 11:22:33 +02:00
|
|
|
/// Returns true if the event has an Internal source tag.
|
|
|
|
pub fn is_internal(&self) -> bool {
|
|
|
|
self.tags
|
|
|
|
.iter()
|
|
|
|
.any(|tag| matches!(tag, Tag::Source(Source::Internal)))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the event has no tags.
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.tags.is_empty()
|
|
|
|
}
|
|
|
|
|
2021-09-13 09:34:40 +02:00
|
|
|
/// Return all paths in the event's tags.
|
2021-08-22 12:06:12 +02:00
|
|
|
pub fn paths(&self) -> impl Iterator<Item = &Path> {
|
2021-09-13 09:34:40 +02:00
|
|
|
self.tags.iter().filter_map(|p| match p {
|
2021-10-12 17:06:39 +02:00
|
|
|
Tag::Path { path, .. } => Some(path.as_path()),
|
2021-08-22 12:06:12 +02:00
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
}
|
2021-09-02 23:25:06 +02:00
|
|
|
|
2021-09-13 09:34:40 +02:00
|
|
|
/// Return all signals in the event's tags.
|
2021-10-15 14:13:16 +02:00
|
|
|
pub fn signals(&self) -> impl Iterator<Item = MainSignal> + '_ {
|
2021-09-13 09:34:40 +02:00
|
|
|
self.tags.iter().filter_map(|p| match p {
|
|
|
|
Tag::Signal(s) => Some(*s),
|
2021-08-22 16:35:03 +02:00
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
}
|
2021-09-02 23:25:06 +02:00
|
|
|
|
2021-09-13 09:34:40 +02:00
|
|
|
/// Return all process completions in the event's tags.
|
2021-09-02 23:25:06 +02:00
|
|
|
pub fn completions(&self) -> impl Iterator<Item = Option<ExitStatus>> + '_ {
|
2021-09-13 09:34:40 +02:00
|
|
|
self.tags.iter().filter_map(|p| match p {
|
|
|
|
Tag::ProcessCompletion(s) => Some(*s),
|
2021-09-02 23:25:06 +02:00
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
}
|
2021-08-22 12:06:12 +02:00
|
|
|
}
|
2021-09-02 21:57:59 +02:00
|
|
|
|
|
|
|
impl fmt::Display for Event {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
write!(f, "Event")?;
|
2021-09-13 09:34:40 +02:00
|
|
|
for p in &self.tags {
|
2021-09-02 21:57:59 +02:00
|
|
|
match p {
|
2021-10-12 17:06:39 +02:00
|
|
|
Tag::Path { path, file_type } => {
|
|
|
|
write!(f, " path={}", path.display())?;
|
|
|
|
if let Some(ft) = file_type {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
" filetype={}",
|
|
|
|
if ft.is_file() {
|
|
|
|
"file"
|
|
|
|
} else if ft.is_dir() {
|
|
|
|
"dir"
|
|
|
|
} else if ft.is_symlink() {
|
|
|
|
"symlink"
|
|
|
|
} else {
|
|
|
|
"special"
|
|
|
|
}
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
}
|
2021-09-13 09:34:40 +02:00
|
|
|
Tag::FileEventKind(kind) => write!(f, " kind={:?}", kind)?,
|
|
|
|
Tag::Source(s) => write!(f, " source={:?}", s)?,
|
|
|
|
Tag::Process(p) => write!(f, " process={}", p)?,
|
|
|
|
Tag::Signal(s) => write!(f, " signal={:?}", s)?,
|
|
|
|
Tag::ProcessCompletion(None) => write!(f, " command-completed")?,
|
|
|
|
Tag::ProcessCompletion(Some(c)) => write!(f, " command-completed({})", c)?,
|
2021-09-02 21:57:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !self.metadata.is_empty() {
|
|
|
|
write!(f, " meta: {:?}", self.metadata)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|