debian_watch/
types.rs

1use std::str::FromStr;
2
3/// Error type for parsing watch file types
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct ParseError {
6    /// The name of the type being parsed
7    pub type_name: &'static str,
8    /// The invalid value that caused the error
9    pub value: String,
10}
11
12impl std::fmt::Display for ParseError {
13    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
14        write!(f, "Invalid {} value: '{}'", self.type_name, self.value)
15    }
16}
17
18impl std::error::Error for ParseError {}
19
20/// The type of the component
21pub enum ComponentType {
22    /// Perl component
23    Perl,
24
25    /// NodeJS component
26    NodeJS,
27}
28
29impl std::fmt::Display for ComponentType {
30    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
31        match self {
32            ComponentType::Perl => f.write_str("perl"),
33            ComponentType::NodeJS => f.write_str("nodejs"),
34        }
35    }
36}
37
38impl FromStr for ComponentType {
39    type Err = ParseError;
40
41    fn from_str(s: &str) -> Result<Self, Self::Err> {
42        match s {
43            "perl" => Ok(ComponentType::Perl),
44            "nodejs" => Ok(ComponentType::NodeJS),
45            _ => Err(ParseError {
46                type_name: "ComponentType",
47                value: s.to_string(),
48            }),
49        }
50    }
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
54/// Compression type
55pub enum Compression {
56    /// Gzip compression
57    Gzip,
58
59    /// Xz compression
60    Xz,
61
62    /// Bzip2 compression
63    Bzip2,
64
65    /// Lzma compression
66    Lzma,
67
68    #[default]
69    /// Default compression
70    Default,
71}
72
73impl std::fmt::Display for Compression {
74    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
75        match self {
76            Compression::Gzip => f.write_str("gzip"),
77            Compression::Xz => f.write_str("xz"),
78            Compression::Bzip2 => f.write_str("bzip2"),
79            Compression::Lzma => f.write_str("lzma"),
80            Compression::Default => f.write_str("default"),
81        }
82    }
83}
84
85impl FromStr for Compression {
86    type Err = ParseError;
87
88    fn from_str(s: &str) -> Result<Self, Self::Err> {
89        match s {
90            "gz" | "gzip" => Ok(Compression::Gzip),
91            "xz" => Ok(Compression::Xz),
92            "bz2" | "bzip2" => Ok(Compression::Bzip2),
93            "lzma" => Ok(Compression::Lzma),
94            "default" => Ok(Compression::Default),
95            _ => Err(ParseError {
96                type_name: "Compression",
97                value: s.to_string(),
98            }),
99        }
100    }
101}
102
103#[derive(Debug, Clone, PartialEq, Eq, Hash)]
104/// How to generate upstream version string from git tags
105pub enum Pretty {
106    /// Use git describe to generate the version string
107    Describe,
108
109    /// Use a custom pattern to generate the version string
110    Pattern(String),
111}
112
113impl Default for Pretty {
114    fn default() -> Self {
115        Pretty::Pattern("0.0~git%cd.h%".to_string())
116    }
117}
118
119impl std::fmt::Display for Pretty {
120    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
121        match self {
122            Pretty::Describe => f.write_str("describe"),
123            Pretty::Pattern(pattern) => f.write_str(pattern),
124        }
125    }
126}
127
128impl FromStr for Pretty {
129    type Err = ParseError;
130
131    fn from_str(s: &str) -> Result<Self, Self::Err> {
132        if s == "describe" {
133            Ok(Pretty::Describe)
134        } else {
135            Ok(Pretty::Pattern(s.to_string()))
136        }
137    }
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
141/// Git export mode
142pub enum GitExport {
143    #[default]
144    /// Export only files in the .orig.tar archive that are not ignored by the upstream.
145    Default,
146
147    /// Export all files in the .orig.tar archive, ignoring any export-ignore git attributes
148    /// defined by the upstream.
149    All,
150}
151
152impl std::fmt::Display for GitExport {
153    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
154        match self {
155            GitExport::Default => f.write_str("default"),
156            GitExport::All => f.write_str("all"),
157        }
158    }
159}
160
161impl FromStr for GitExport {
162    type Err = ParseError;
163
164    fn from_str(s: &str) -> Result<Self, Self::Err> {
165        match s {
166            "default" => Ok(GitExport::Default),
167            "all" => Ok(GitExport::All),
168            _ => Err(ParseError {
169                type_name: "GitExport",
170                value: s.to_string(),
171            }),
172        }
173    }
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
177/// Git clone operation mode
178pub enum GitMode {
179    #[default]
180    /// Clone the git repository in shallow mode
181    Shallow,
182
183    /// Clone the git repository in full mode
184    Full,
185}
186
187impl std::fmt::Display for GitMode {
188    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
189        match self {
190            GitMode::Shallow => f.write_str("shallow"),
191            GitMode::Full => f.write_str("full"),
192        }
193    }
194}
195
196impl FromStr for GitMode {
197    type Err = ParseError;
198
199    fn from_str(s: &str) -> Result<Self, Self::Err> {
200        match s {
201            "shallow" => Ok(GitMode::Shallow),
202            "full" => Ok(GitMode::Full),
203            _ => Err(ParseError {
204                type_name: "GitMode",
205                value: s.to_string(),
206            }),
207        }
208    }
209}
210
211#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
212/// PGP verification mode
213pub enum PgpMode {
214    /// check possible URLs for the signature file and autogenerate a ``pgpsigurlmangle`` rule to
215    /// use it
216    Auto,
217
218    #[default]
219    /// Use pgpsigurlmangle=rules to generate the candidate upstream signature file URL string from
220    /// the upstream tarball URL.
221    ///
222    /// If the specified pgpsigurlmangle is missing, uscan checks possible URLs for the signature
223    /// file and suggests adding a pgpsigurlmangle rule.
224    ///
225    Default,
226
227    /// Use pgpsigurlmangle=rules to generate the candidate upstream signature file URL string from the upstream tarball URL.
228    Mangle,
229
230    /// Verify this downloaded tarball file with the signature file specified in the next watch
231    /// line. The next watch line must be pgpmode=previous. Otherwise, no verification occurs.
232    Next,
233
234    /// Verify the downloaded tarball file specified in the previous watch line with this signature
235    /// file.  The previous watch line must be pgpmode=next.
236    Previous,
237
238    /// Verify the downloaded file foo.ext with its self signature and extract its content tarball
239    /// file as foo.
240    SelfSignature,
241
242    /// Verify tag signature if mode=git.
243    GitTag,
244}
245
246impl std::fmt::Display for PgpMode {
247    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
248        match self {
249            PgpMode::Auto => f.write_str("auto"),
250            PgpMode::Default => f.write_str("default"),
251            PgpMode::Mangle => f.write_str("mangle"),
252            PgpMode::Next => f.write_str("next"),
253            PgpMode::Previous => f.write_str("previous"),
254            PgpMode::SelfSignature => f.write_str("self"),
255            PgpMode::GitTag => f.write_str("gittag"),
256        }
257    }
258}
259impl FromStr for PgpMode {
260    type Err = ParseError;
261
262    fn from_str(s: &str) -> Result<Self, Self::Err> {
263        match s {
264            "auto" => Ok(PgpMode::Auto),
265            "default" => Ok(PgpMode::Default),
266            "mangle" => Ok(PgpMode::Mangle),
267            "next" => Ok(PgpMode::Next),
268            "previous" => Ok(PgpMode::Previous),
269            "self" => Ok(PgpMode::SelfSignature),
270            "gittag" => Ok(PgpMode::GitTag),
271            _ => Err(ParseError {
272                type_name: "PgpMode",
273                value: s.to_string(),
274            }),
275        }
276    }
277}
278
279#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
280/// How to search for the upstream tarball
281pub enum SearchMode {
282    #[default]
283    /// Search for the upstream tarball in the HTML page
284    Html,
285
286    /// Search for the upstream tarball in the plain text page
287    Plain,
288}
289
290impl std::fmt::Display for SearchMode {
291    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
292        match self {
293            SearchMode::Html => f.write_str("html"),
294            SearchMode::Plain => f.write_str("plain"),
295        }
296    }
297}
298
299impl FromStr for SearchMode {
300    type Err = ParseError;
301
302    fn from_str(s: &str) -> Result<Self, Self::Err> {
303        match s {
304            "html" => Ok(SearchMode::Html),
305            "plain" => Ok(SearchMode::Plain),
306            _ => Err(ParseError {
307                type_name: "SearchMode",
308                value: s.to_string(),
309            }),
310        }
311    }
312}
313
314#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
315/// Archive download mode
316pub enum Mode {
317    #[default]
318    /// downloads the specified tarball from the archive URL on the web. Automatically internal
319    /// mode value is updated to either http or ftp by URL.
320    LWP,
321
322    /// Access  the  upstream git archive directly with the git command and packs the source tree
323    /// with the specified tag via matching-pattern into spkg-version.tar.xz.
324    Git,
325
326    /// Access the upstream Subversion archive directly with the svn command and packs the source
327    /// tree.
328    Svn,
329}
330
331impl std::fmt::Display for Mode {
332    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
333        match self {
334            Mode::LWP => f.write_str("lwp"),
335            Mode::Git => f.write_str("git"),
336            Mode::Svn => f.write_str("svn"),
337        }
338    }
339}
340
341impl FromStr for Mode {
342    type Err = ParseError;
343
344    fn from_str(s: &str) -> Result<Self, Self::Err> {
345        match s {
346            "lwp" => Ok(Mode::LWP),
347            "git" => Ok(Mode::Git),
348            "svn" => Ok(Mode::Svn),
349            _ => Err(ParseError {
350                type_name: "Mode",
351                value: s.to_string(),
352            }),
353        }
354    }
355}
356
357#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
358/// The version policy to use when downloading upstream tarballs
359pub enum VersionPolicy {
360    #[default]
361    /// Requires the downloading upstream tarball to be newer than the version obtained from debian/changelog
362    Debian,
363
364    /// Requires the upstream tarball to be newer than specified version
365    Version(debversion::Version),
366
367    /// Requires the downloaded version of the secondary tarballs to be exactly the same as the one for the first upstream tarball downloaded
368    Same,
369
370    /// Restricts the version of the seignature file (used with pgpmode=previous)
371    Previous,
372
373    /// Does not restrict the version of the secondary tarballs
374    Ignore,
375
376    /// Requires the downloading upstream tarball to be newer than the version obtained from
377    /// debian/changelog. Package version is the concatenation of all "group" upstream version.
378    Group,
379
380    /// Requires the downloading upstream tarball to be newer than the version obtained from
381    /// debian/changelog. Package version is the concatenation of the version of the main tarball,
382    /// followed by a checksum of all the tarballs using the checksum version system. At least the
383    /// main upstream source has to be declared as group.
384    Checksum,
385}
386
387impl std::fmt::Display for VersionPolicy {
388    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
389        match self {
390            VersionPolicy::Debian => write!(f, "debian"),
391            VersionPolicy::Version(v) => write!(f, "version-{}", v),
392            VersionPolicy::Same => write!(f, "same"),
393            VersionPolicy::Previous => write!(f, "previous"),
394            VersionPolicy::Ignore => write!(f, "ignore"),
395            VersionPolicy::Group => write!(f, "group"),
396            VersionPolicy::Checksum => write!(f, "checksum"),
397        }
398    }
399}
400
401impl std::str::FromStr for VersionPolicy {
402    type Err = ParseError;
403
404    fn from_str(s: &str) -> Result<Self, Self::Err> {
405        match s {
406            "debian" => Ok(VersionPolicy::Debian),
407            "same" => Ok(VersionPolicy::Same),
408            "previous" => Ok(VersionPolicy::Previous),
409            "ignore" => Ok(VersionPolicy::Ignore),
410            "group" => Ok(VersionPolicy::Group),
411            "checksum" => Ok(VersionPolicy::Checksum),
412            s if s.starts_with("version-") => {
413                let v = s.trim_start_matches("version-");
414                Ok(VersionPolicy::Version(
415                    v.parse::<debversion::Version>().map_err(|_| ParseError {
416                        type_name: "VersionPolicy",
417                        value: s.to_string(),
418                    })?,
419                ))
420            }
421            _ => Err(ParseError {
422                type_name: "VersionPolicy",
423                value: s.to_string(),
424            }),
425        }
426    }
427}
428
429#[cfg(test)]
430mod version_policy_tests {
431    use super::VersionPolicy;
432    use std::str::FromStr;
433
434    #[test]
435    fn test_version_policy_to_string() {
436        assert_eq!("debian", VersionPolicy::Debian.to_string());
437        assert_eq!("same", VersionPolicy::Same.to_string());
438        assert_eq!("previous", VersionPolicy::Previous.to_string());
439        assert_eq!("ignore", VersionPolicy::Ignore.to_string());
440        assert_eq!("group", VersionPolicy::Group.to_string());
441        assert_eq!("checksum", VersionPolicy::Checksum.to_string());
442        assert_eq!(
443            "version-1.2.3",
444            VersionPolicy::Version("1.2.3".parse().unwrap()).to_string()
445        );
446    }
447
448    #[test]
449    fn test_version_policy_from_str() {
450        assert_eq!(
451            VersionPolicy::Debian,
452            VersionPolicy::from_str("debian").unwrap()
453        );
454        assert_eq!(
455            VersionPolicy::Same,
456            VersionPolicy::from_str("same").unwrap()
457        );
458        assert_eq!(
459            VersionPolicy::Previous,
460            VersionPolicy::from_str("previous").unwrap()
461        );
462        assert_eq!(
463            VersionPolicy::Ignore,
464            VersionPolicy::from_str("ignore").unwrap()
465        );
466        assert_eq!(
467            VersionPolicy::Group,
468            VersionPolicy::from_str("group").unwrap()
469        );
470        assert_eq!(
471            VersionPolicy::Checksum,
472            VersionPolicy::from_str("checksum").unwrap()
473        );
474        assert_eq!(
475            VersionPolicy::Version("1.2.3".parse().unwrap()),
476            VersionPolicy::from_str("version-1.2.3").unwrap()
477        );
478    }
479}