watchexec/crates/events/src/event.rs

237 lines
6.1 KiB
Rust
Raw Normal View History

2021-08-22 12:06:12 +02:00
use std::{
collections::HashMap,
2021-09-02 21:57:59 +02:00
fmt,
2021-08-22 12:06:12 +02:00
path::{Path, PathBuf},
};
2021-08-16 11:49:12 +02:00
2023-03-18 09:32:24 +01:00
use watchexec_signals::Signal;
2021-09-02 22:14:04 +02:00
2023-03-18 09:32:24 +01:00
#[cfg(feature = "serde")]
use crate::serde_formats::{SerdeEvent, SerdeTag};
2021-08-17 11:41:13 +02:00
2023-03-18 09:32:24 +01:00
use crate::{filekind::FileEventKind, FileType, Keyboard, ProcessEnd};
2021-12-06 12:50:33 +01:00
2021-08-16 11:49:12 +02:00
/// An event, as far as watchexec cares about.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
2023-03-18 09:32:24 +01:00
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(from = "SerdeEvent", into = "SerdeEvent"))]
2021-08-16 11:49:12 +02:00
pub struct Event {
2021-10-16 12:47:00 +02:00
/// Structured, classified information which can be used to filter or classify the event.
2021-09-13 09:34:40 +02:00
pub tags: Vec<Tag>,
2021-10-16 12:47:00 +02:00
/// Arbitrary other information, cannot be used for filtering.
2021-08-16 11:49:12 +02:00
pub metadata: HashMap<String, Vec<String>>,
}
/// Something which can be used to filter or qualify an event.
2021-08-16 11:49:12 +02:00
#[derive(Clone, Debug, Eq, PartialEq)]
2023-03-18 09:32:24 +01:00
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(from = "SerdeTag", into = "SerdeTag"))]
2021-08-16 11:49:12 +02:00
#[non_exhaustive]
2021-09-13 09:34:40 +02:00
pub enum Tag {
2021-10-16 12:47:00 +02:00
/// The event is about a path or file in the filesystem.
2021-10-12 17:06:39 +02:00
Path {
2021-10-16 12:47:00 +02:00
/// Path to the file or directory.
2021-10-12 17:06:39 +02:00
path: PathBuf,
2021-10-16 12:47:00 +02:00
/// Optional file type, if known.
2021-10-12 17:06:39 +02:00
file_type: Option<FileType>,
},
2021-10-16 12:47:00 +02:00
/// Kind of a filesystem event (create, remove, modify, etc).
2021-12-06 12:50:33 +01:00
FileEventKind(FileEventKind),
2021-10-16 12:47:00 +02:00
/// The general source of the event.
2021-08-16 11:49:12 +02:00
Source(Source),
2021-10-16 12:47:00 +02:00
2023-03-18 09:32:24 +01:00
/// The event is about a keyboard input.
Keyboard(Keyboard),
2021-10-16 12:47:00 +02:00
/// The event was caused by a particular process.
2021-08-16 11:49:12 +02:00
Process(u32),
2021-10-16 12:47:00 +02:00
/// The event is about a signal being delivered to the main process.
2023-03-18 09:32:24 +01:00
Signal(Signal),
2021-10-16 12:47:00 +02:00
/// The event is about a subprocess ending.
ProcessCompletion(Option<ProcessEnd>),
2023-03-18 09:32:24 +01:00
#[cfg(feature = "serde")]
/// The event is unknown (or not yet implemented).
Unknown,
2021-08-16 11:49:12 +02:00
}
impl Tag {
2021-10-16 12:47:00 +02:00
/// The name of the variant.
2023-01-06 14:53:49 +01:00
#[must_use]
pub const fn discriminant_name(&self) -> &'static str {
match self {
2023-01-06 14:53:49 +01:00
Self::Path { .. } => "Path",
Self::FileEventKind(_) => "FileEventKind",
Self::Source(_) => "Source",
Self::Keyboard(_) => "Keyboard",
Self::Process(_) => "Process",
Self::Signal(_) => "Signal",
Self::ProcessCompletion(_) => "ProcessCompletion",
2023-03-18 09:32:24 +01:00
#[cfg(feature = "serde")]
Self::Unknown => "Unknown",
}
}
}
2021-08-16 11:49:12 +02:00
/// The general origin of the event.
2021-10-16 12:47:00 +02:00
///
/// This is set by the event source. Note that not all of these are currently used.
2021-08-16 11:49:12 +02:00
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2023-03-18 09:32:24 +01:00
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
2021-08-16 11:49:12 +02:00
#[non_exhaustive]
pub enum Source {
2021-10-16 12:47:00 +02:00
/// Event comes from a file change.
2021-08-16 11:49:12 +02:00
Filesystem,
2021-10-16 12:47:00 +02:00
/// Event comes from a keyboard input.
2021-08-16 11:49:12 +02:00
Keyboard,
2021-10-16 12:47:00 +02:00
/// Event comes from a mouse click.
2021-08-16 11:49:12 +02:00
Mouse,
2021-10-16 12:47:00 +02:00
/// Event comes from the OS.
2021-08-17 11:41:13 +02:00
Os,
2021-10-16 12:47:00 +02:00
/// Event is time based.
2021-08-16 11:49:12 +02:00
Time,
2021-10-16 12:47:00 +02:00
/// Event is internal to Watchexec.
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
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",
}
)
}
}
/// The priority of the event in the queue.
///
/// In the event queue, events are inserted with a priority, such that more important events are
/// delivered ahead of others. This is especially important when there is a large amount of events
/// generated and relatively slow filtering, as events can become noticeably delayed, and may give
/// the impression of stalling.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
2023-03-18 09:32:24 +01:00
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum Priority {
/// Low priority
///
/// Used for:
/// - process completion events
Low,
/// Normal priority
///
/// Used for:
/// - filesystem events
Normal,
/// High priority
///
/// Used for:
/// - signals to main process, except Interrupt and Terminate
High,
/// Urgent events bypass filtering entirely.
///
/// Used for:
/// - Interrupt and Terminate signals to main process
Urgent,
}
impl Default for Priority {
fn default() -> Self {
Self::Normal
}
}
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.
2023-01-06 14:53:49 +01:00
#[must_use]
2021-09-28 11:22:33 +02:00
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.
2023-01-06 14:53:49 +01:00
#[must_use]
2021-09-28 11:22:33 +02:00
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-10-16 05:26:29 +02:00
pub fn paths(&self) -> impl Iterator<Item = (&Path, Option<&FileType>)> {
2021-09-13 09:34:40 +02:00
self.tags.iter().filter_map(|p| match p {
2021-10-16 05:26:29 +02:00
Tag::Path { path, file_type } => Some((path.as_path(), file_type.as_ref())),
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.
2023-03-18 09:32:24 +01:00
pub fn signals(&self) -> impl Iterator<Item = Signal> + '_ {
2021-09-13 09:34:40 +02:00
self.tags.iter().filter_map(|p| match p {
Tag::Signal(s) => Some(*s),
_ => 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.
pub fn completions(&self) -> impl Iterator<Item = Option<ProcessEnd>> + '_ {
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 {
2023-01-06 14:53:49 +01:00
write!(f, " filetype={ft}")?;
2021-10-12 17:06:39 +02:00
}
}
2023-01-06 14:53:49 +01:00
Tag::FileEventKind(kind) => write!(f, " kind={kind:?}")?,
Tag::Source(s) => write!(f, " source={s:?}")?,
Tag::Keyboard(k) => write!(f, " keyboard={k:?}")?,
Tag::Process(p) => write!(f, " process={p}")?,
Tag::Signal(s) => write!(f, " signal={s:?}")?,
2021-09-13 09:34:40 +02:00
Tag::ProcessCompletion(None) => write!(f, " command-completed")?,
2023-01-06 14:53:49 +01:00
Tag::ProcessCompletion(Some(c)) => write!(f, " command-completed({c:?})")?,
2023-03-18 09:32:24 +01:00
#[cfg(feature = "serde")]
Tag::Unknown => write!(f, " unknown")?,
2021-09-02 21:57:59 +02:00
}
}
if !self.metadata.is_empty() {
write!(f, " meta: {:?}", self.metadata)?;
}
Ok(())
}
}