Skip to main content

debian_watch/
lib.rs

1#![deny(missing_docs)]
2//! Formatting-preserving parser and editor for Debian watch files
3//!
4//! # Example
5//!
6//! ```rust,ignore
7//! // For line-based formats (v1-4):
8//! // Note: This example requires the "linebased" feature (enabled by default)
9//! let wf = debian_watch::linebased::WatchFile::new(None);
10//! assert_eq!(wf.version(), debian_watch::DEFAULT_VERSION);
11//! assert_eq!("", wf.to_string());
12//!
13//! let wf = debian_watch::linebased::WatchFile::new(Some(4));
14//! assert_eq!(wf.version(), 4);
15//! assert_eq!("version=4\n", wf.to_string());
16//!
17//! let wf: debian_watch::linebased::WatchFile = r#"version=4
18//! opts=foo=blah https://foo.com/bar .*/v?(\d\S+)\.tar\.gz
19//! "#.parse().unwrap();
20//! assert_eq!(wf.version(), 4);
21//! assert_eq!(wf.entries().collect::<Vec<_>>().len(), 1);
22//! let entry = wf.entries().next().unwrap();
23//! assert_eq!(entry.opts(), maplit::hashmap! {
24//!    "foo".to_string() => "blah".to_string(),
25//! });
26//! assert_eq!(&entry.url(), "https://foo.com/bar");
27//! assert_eq!(entry.matching_pattern().as_deref(), Some(".*/v?(\\d\\S+)\\.tar\\.gz"));
28//! ```
29
30#[cfg(feature = "linebased")]
31mod lex;
32#[cfg(feature = "linebased")]
33/// Line-based watch file format parser (versions 1-4)
34pub mod linebased;
35
36#[cfg(all(feature = "deb822", feature = "linebased"))]
37mod convert;
38#[cfg(feature = "deb822")]
39pub mod deb822;
40#[cfg(all(feature = "discover", any(feature = "linebased", feature = "deb822")))]
41pub mod discover;
42pub mod mangle;
43#[cfg(feature = "pgp")]
44pub mod pgp;
45pub mod release;
46pub mod search;
47#[cfg(feature = "deb822")]
48pub mod templates;
49
50/// Any watch files without a version are assumed to be
51/// version 1.
52pub const DEFAULT_VERSION: u32 = 1;
53
54#[cfg(any(feature = "linebased", feature = "deb822"))]
55pub mod parse;
56pub mod subst;
57mod types;
58/// Default user agent string used for HTTP requests
59pub const DEFAULT_USER_AGENT: &str = concat!("debian-watch-rs/", env!("CARGO_PKG_VERSION"));
60
61pub use release::Release;
62pub use types::*;
63
64/// Let's start with defining all kinds of tokens and
65/// composite nodes.
66#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
67#[allow(non_camel_case_types, missing_docs, clippy::upper_case_acronyms)]
68#[repr(u16)]
69pub enum SyntaxKind {
70    KEY = 0,
71    VALUE,
72    EQUALS,
73    QUOTE,
74    COMMA,
75    CONTINUATION,
76    NEWLINE,
77    WHITESPACE, // whitespaces is explicit
78    COMMENT,    // comments
79    ERROR,      // as well as errors
80
81    // composite nodes
82    ROOT,             // The entire file
83    VERSION,          // "version=x\n"
84    ENTRY,            // "opts=foo=blah https://foo.com/bar .*/v?(\d\S+)\.tar\.gz\n"
85    OPTS_LIST,        // "opts=foo=blah"
86    OPTION,           // "foo=blah"
87    OPTION_SEPARATOR, // "," (comma separator between options)
88    URL,              // "https://foo.com/bar"
89    MATCHING_PATTERN, // ".*/v?(\d\S+)\.tar\.gz"
90    VERSION_POLICY,   // "debian"
91    SCRIPT,           // "uupdate"
92}
93
94/// Convert our `SyntaxKind` into the rowan `SyntaxKind`.
95impl From<SyntaxKind> for rowan::SyntaxKind {
96    fn from(kind: SyntaxKind) -> Self {
97        Self(kind as u16)
98    }
99}
100
101// Only export traits - specific implementations are in their modules
102// Users access linebased types via debian_watch::linebased::WatchFile
103// Users access deb822 types via debian_watch::deb822::WatchFile
104
105#[cfg(all(feature = "deb822", feature = "linebased"))]
106pub use crate::convert::{convert_to_v5, ConversionError};
107
108#[cfg(all(test, feature = "linebased"))]
109mod tests {
110    use crate::linebased::WatchFile;
111
112    #[test]
113    fn test_create_watchfile() {
114        let wf = WatchFile::new(None);
115        assert_eq!(wf.version(), super::DEFAULT_VERSION);
116
117        assert_eq!("", wf.to_string());
118
119        let wf = WatchFile::new(Some(4));
120        assert_eq!(wf.version(), 4);
121
122        assert_eq!("version=4\n", wf.to_string());
123    }
124
125    #[test]
126    fn test_set_version() {
127        let mut wf = WatchFile::new(Some(4));
128        assert_eq!(wf.version(), 4);
129
130        wf.set_version(5);
131        assert_eq!(wf.version(), 5);
132        assert_eq!("version=5\n", wf.to_string());
133
134        // Test setting version on a file without version
135        let mut wf = WatchFile::new(None);
136        assert_eq!(wf.version(), super::DEFAULT_VERSION);
137
138        wf.set_version(4);
139        assert_eq!(wf.version(), 4);
140        assert_eq!("version=4\n", wf.to_string());
141    }
142
143    #[test]
144    fn test_set_version_on_parsed() {
145        // Test that parsed WatchFiles can be mutated
146        let mut wf: WatchFile = "version=4\n".parse().unwrap();
147        assert_eq!(wf.version(), 4);
148
149        wf.set_version(5);
150        assert_eq!(wf.version(), 5);
151        assert_eq!("version=5\n", wf.to_string());
152
153        // Test setting version on a parsed file without version
154        let mut wf: WatchFile = "".parse().unwrap();
155        assert_eq!(wf.version(), super::DEFAULT_VERSION);
156
157        wf.set_version(4);
158        assert_eq!(wf.version(), 4);
159        assert_eq!("version=4\n", wf.to_string());
160    }
161}