Skip to main content

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