debian_watch/
traits.rs

1use crate::types::*;
2
3/// Common trait for all watch file format versions
4pub trait WatchFileFormat {
5    /// The type used to represent individual watch entries
6    type Entry: WatchEntry;
7
8    /// Returns the version of the watch file (1-5)
9    fn version(&self) -> u32;
10
11    /// Returns an iterator over all entries in the watch file
12    fn entries(&self) -> Box<dyn Iterator<Item = Self::Entry> + '_>;
13
14    /// Convert the watch file back to its string representation
15    fn to_string(&self) -> String;
16}
17
18/// Common trait for watch file entries across all formats
19pub trait WatchEntry {
20    /// Returns the URL of the entry
21    fn url(&self) -> String;
22
23    /// Returns the matching pattern of the entry
24    fn matching_pattern(&self) -> Option<String>;
25
26    /// Returns the version policy
27    fn version_policy(&self) -> Result<Option<crate::VersionPolicy>, ParseError>;
28
29    /// Returns the script of the entry
30    fn script(&self) -> Option<String>;
31
32    /// Get the value of a generic option by key
33    fn get_option(&self, key: &str) -> Option<String>;
34
35    /// Check if an option is set
36    fn has_option(&self, key: &str) -> bool;
37
38    // Commonly used options - delegated to get_option() but typed
39
40    /// The name of the secondary source tarball
41    fn component(&self) -> Option<String> {
42        self.get_option("component")
43    }
44
45    /// Component type
46    fn ctype(&self) -> Result<Option<ComponentType>, ParseError> {
47        self.get_option("ctype").map(|s| s.parse()).transpose()
48    }
49
50    /// Compression method
51    fn compression(&self) -> Result<Option<Compression>, ParseError> {
52        self.get_option("compression")
53            .map(|s| s.parse())
54            .transpose()
55    }
56
57    /// Repack the tarball
58    fn repack(&self) -> bool {
59        self.has_option("repack")
60    }
61
62    /// Repack suffix
63    fn repacksuffix(&self) -> Option<String> {
64        self.get_option("repacksuffix")
65    }
66
67    /// Retrieve the mode of the watch file entry
68    fn mode(&self) -> Result<Mode, ParseError> {
69        Ok(self
70            .get_option("mode")
71            .map(|s| s.parse())
72            .transpose()?
73            .unwrap_or_default())
74    }
75
76    /// Return the git pretty mode
77    fn pretty(&self) -> Result<Pretty, ParseError> {
78        Ok(self
79            .get_option("pretty")
80            .map(|s| s.parse())
81            .transpose()?
82            .unwrap_or_default())
83    }
84
85    /// Set the date string used by the pretty option
86    fn date(&self) -> String {
87        self.get_option("date").unwrap_or_else(|| "%Y%m%d".into())
88    }
89
90    /// Return the git export mode
91    fn gitexport(&self) -> Result<GitExport, ParseError> {
92        Ok(self
93            .get_option("gitexport")
94            .map(|s| s.parse())
95            .transpose()?
96            .unwrap_or_default())
97    }
98
99    /// Return the git mode
100    fn gitmode(&self) -> Result<GitMode, ParseError> {
101        Ok(self
102            .get_option("gitmode")
103            .map(|s| s.parse())
104            .transpose()?
105            .unwrap_or_default())
106    }
107
108    /// Return the pgp mode
109    fn pgpmode(&self) -> Result<PgpMode, ParseError> {
110        Ok(self
111            .get_option("pgpmode")
112            .map(|s| s.parse())
113            .transpose()?
114            .unwrap_or_default())
115    }
116
117    /// Return the search mode
118    fn searchmode(&self) -> Result<SearchMode, ParseError> {
119        Ok(self
120            .get_option("searchmode")
121            .map(|s| s.parse())
122            .transpose()?
123            .unwrap_or_default())
124    }
125
126    /// Return the decompression mode
127    fn decompress(&self) -> bool {
128        self.has_option("decompress")
129    }
130
131    /// Whether to disable all site specific special case code
132    fn bare(&self) -> bool {
133        self.has_option("bare")
134    }
135
136    /// Set the user-agent string
137    fn user_agent(&self) -> Option<String> {
138        self.get_option("user-agent")
139    }
140
141    /// Use PASV mode for the FTP connection
142    fn passive(&self) -> Option<bool> {
143        if self.has_option("passive") || self.has_option("pasv") {
144            Some(true)
145        } else if self.has_option("active") || self.has_option("nopasv") {
146            Some(false)
147        } else {
148            None
149        }
150    }
151
152    /// Extra options to use with the unzip command
153    fn unzipoptions(&self) -> Option<String> {
154        self.get_option("unzipopt")
155    }
156
157    /// Normalize the downloaded web page string
158    fn dversionmangle(&self) -> Option<String> {
159        self.get_option("dversionmangle")
160    }
161
162    /// Mangle the upstream version
163    fn uversionmangle(&self) -> Option<String> {
164        self.get_option("uversionmangle")
165    }
166
167    /// Mangle the download URL
168    fn downloadurlmangle(&self) -> Option<String> {
169        self.get_option("downloadurlmangle")
170    }
171
172    /// Mangle the filename
173    fn filenamemangle(&self) -> Option<String> {
174        self.get_option("filenamemangle")
175    }
176
177    /// Mangle the PGP signature URL
178    fn pgpsigurlmangle(&self) -> Option<String> {
179        self.get_option("pgpsigurlmangle")
180    }
181
182    /// Mangle the oversionmangle
183    fn oversionmangle(&self) -> Option<String> {
184        self.get_option("oversionmangle")
185    }
186
187    /// Mangle the page content
188    fn pagemangle(&self) -> Option<String> {
189        self.get_option("pagemangle")
190    }
191
192    /// Mangle the directory version
193    fn dirversionmangle(&self) -> Option<String> {
194        self.get_option("dirversionmangle")
195    }
196
197    /// Mangle the version
198    fn versionmangle(&self) -> Option<String> {
199        self.get_option("versionmangle")
200    }
201
202    /// Decode hrefs before matching
203    fn hrefdecode(&self) -> Option<bool> {
204        self.get_option("hrefdecode")
205            .map(|s| s == "1" || s == "yes")
206    }
207
208    /// Replace all substitutions and return the resulting URL
209    fn format_url(&self, package: impl FnOnce() -> String) -> Result<url::Url, url::ParseError> {
210        crate::parse::subst(self.url().as_str(), package).parse()
211    }
212}