debian_watch/
lib.rs

1#![deny(missing_docs)]
2//! Formatting-preserving parser and editor for Debian watch files
3//!
4//! # Example
5//!
6//! ```rust
7//! let wf = debian_watch::WatchFile::new(None);
8//! assert_eq!(wf.version(), debian_watch::DEFAULT_VERSION);
9//! assert_eq!("", wf.to_string());
10//!
11//! let wf = debian_watch::WatchFile::new(Some(4));
12//! assert_eq!(wf.version(), 4);
13//! assert_eq!("version=4\n", wf.to_string());
14//!
15//! let wf: debian_watch::WatchFile = r#"version=4
16//! opts=foo=blah https://foo.com/bar .*/v?(\d\S+)\.tar\.gz
17//! "#.parse().unwrap();
18//! assert_eq!(wf.version(), 4);
19//! assert_eq!(wf.entries().collect::<Vec<_>>().len(), 1);
20//! let entry = wf.entries().next().unwrap();
21//! assert_eq!(entry.opts(), maplit::hashmap! {
22//!    "foo".to_string() => "blah".to_string(),
23//! });
24//! assert_eq!(&entry.url(), "https://foo.com/bar");
25//! assert_eq!(entry.matching_pattern().as_deref(), Some(".*/v?(\\d\\S+)\\.tar\\.gz"));
26//! ```
27
28mod lex;
29mod parse;
30
31/// Any watch files without a version are assumed to be
32/// version 1.
33pub const DEFAULT_VERSION: u32 = 1;
34
35mod types;
36
37pub use types::*;
38
39/// Let's start with defining all kinds of tokens and
40/// composite nodes.
41#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
42#[allow(non_camel_case_types, missing_docs, clippy::upper_case_acronyms)]
43#[repr(u16)]
44pub(crate) enum SyntaxKind {
45    KEY = 0,
46    VALUE,
47    EQUALS,
48    QUOTE,
49    COMMA,
50    CONTINUATION,
51    NEWLINE,
52    WHITESPACE, // whitespaces is explicit
53    COMMENT,    // comments
54    ERROR,      // as well as errors
55
56    // composite nodes
57    ROOT,             // The entire file
58    VERSION,          // "version=x\n"
59    ENTRY,            // "opts=foo=blah https://foo.com/bar .*/v?(\d\S+)\.tar\.gz\n"
60    OPTS_LIST,        // "opts=foo=blah"
61    OPTION,           // "foo=blah"
62    OPTION_SEPARATOR, // "," (comma separator between options)
63    URL,              // "https://foo.com/bar"
64    MATCHING_PATTERN, // ".*/v?(\d\S+)\.tar\.gz"
65    VERSION_POLICY,   // "debian"
66    SCRIPT,           // "uupdate"
67}
68
69/// Convert our `SyntaxKind` into the rowan `SyntaxKind`.
70impl From<SyntaxKind> for rowan::SyntaxKind {
71    fn from(kind: SyntaxKind) -> Self {
72        Self(kind as u16)
73    }
74}
75
76pub use crate::parse::Entry;
77pub use crate::parse::WatchFile;
78
79#[cfg(test)]
80mod tests {
81    #[test]
82    fn test_create_watchfile() {
83        let wf = super::WatchFile::new(None);
84        assert_eq!(wf.version(), super::DEFAULT_VERSION);
85
86        assert_eq!("", wf.to_string());
87
88        let wf = super::WatchFile::new(Some(4));
89        assert_eq!(wf.version(), 4);
90
91        assert_eq!("version=4\n", wf.to_string());
92    }
93
94    #[test]
95    fn test_set_version() {
96        let mut wf = super::WatchFile::new(Some(4));
97        assert_eq!(wf.version(), 4);
98
99        wf.set_version(5);
100        assert_eq!(wf.version(), 5);
101        assert_eq!("version=5\n", wf.to_string());
102
103        // Test setting version on a file without version
104        let mut wf = super::WatchFile::new(None);
105        assert_eq!(wf.version(), super::DEFAULT_VERSION);
106
107        wf.set_version(4);
108        assert_eq!(wf.version(), 4);
109        assert_eq!("version=4\n", wf.to_string());
110    }
111
112    #[test]
113    fn test_set_version_on_parsed() {
114        // Test that parsed WatchFiles can be mutated
115        let mut wf: super::WatchFile = "version=4\n".parse().unwrap();
116        assert_eq!(wf.version(), 4);
117
118        wf.set_version(5);
119        assert_eq!(wf.version(), 5);
120        assert_eq!("version=5\n", wf.to_string());
121
122        // Test setting version on a parsed file without version
123        let mut wf: super::WatchFile = "".parse().unwrap();
124        assert_eq!(wf.version(), super::DEFAULT_VERSION);
125
126        wf.set_version(4);
127        assert_eq!(wf.version(), 4);
128        assert_eq!("version=4\n", wf.to_string());
129    }
130}