tugger_debian/
changelog.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5/*! Defines types representing debian/changelog files.
6
7See https://www.debian.org/doc/debian-policy/ch-source.html#debian-changelog-debian-changelog
8for the specification.
9*/
10
11use {
12    chrono::{DateTime, Local},
13    std::{borrow::Cow, io::Write},
14};
15
16#[derive(Clone, Debug)]
17pub struct ChangelogEntry<'a> {
18    pub package: Cow<'a, str>,
19    pub version: Cow<'a, str>,
20    pub distributions: Vec<Cow<'a, str>>,
21    pub urgency: Cow<'a, str>,
22    pub details: Cow<'a, str>,
23    pub maintainer_name: Cow<'a, str>,
24    pub maintainer_email: Cow<'a, str>,
25    pub date: DateTime<Local>,
26}
27
28impl<'a> ChangelogEntry<'a> {
29    /// Serialize the changelog entry to a writer.
30    ///
31    /// This incurs multiple `.write()` calls. So a buffered writer is
32    /// recommended if performance matters.
33    pub fn write<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
34        /*
35        package (version) distribution(s); urgency=urgency
36          [optional blank line(s), stripped]
37          * change details
38          more change details
39          [blank line(s), included in output of dpkg-parsechangelog]
40          * even more change details
41          [optional blank line(s), stripped]
42         -- maintainer name <email address>[two spaces]  date
43        */
44        writer.write_all(self.package.as_bytes())?;
45        writer.write_all(b" (")?;
46        writer.write_all(self.version.as_bytes())?;
47        writer.write_all(b") ")?;
48        writer.write_all(self.distributions.join(" ").as_bytes())?;
49        writer.write_all(b"; urgency=")?;
50        writer.write_all(self.urgency.as_bytes())?;
51        writer.write_all(b"\n\n")?;
52        writer.write_all(self.details.as_bytes())?;
53        writer.write_all(b"\n")?;
54        writer.write_all(b"-- ")?;
55        writer.write_all(self.maintainer_name.as_bytes())?;
56        writer.write_all(b" <")?;
57        writer.write_all(self.maintainer_email.as_bytes())?;
58        writer.write_all(b">  ")?;
59        writer.write_all(self.date.to_rfc2822().as_bytes())?;
60        writer.write_all(b"\n\n")?;
61
62        Ok(())
63    }
64}
65
66/// Represents a complete `debian/changelog` file.
67///
68/// Changelogs are an ordered series of `ChangelogEntry` items.
69#[derive(Default)]
70pub struct Changelog<'a> {
71    entries: Vec<ChangelogEntry<'a>>,
72}
73
74impl<'a> Changelog<'a> {
75    /// Add an entry to this changelog.
76    pub fn add_entry<'b: 'a>(&mut self, entry: ChangelogEntry<'b>) {
77        self.entries.push(entry)
78    }
79
80    /// Serialize the changelog to a writer.
81    ///
82    /// Use of a buffered writer is encouraged if performance is a concern.
83    pub fn write<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
84        for entry in &self.entries {
85            entry.write(writer)?;
86        }
87
88        Ok(())
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use {super::*, anyhow::Result};
95
96    #[test]
97    fn test_write() -> Result<()> {
98        let mut changelog = Changelog::default();
99        changelog.add_entry(ChangelogEntry {
100            package: "mypackage".into(),
101            version: "0.1".into(),
102            distributions: vec!["mydist".into()],
103            urgency: "low".into(),
104            details: "details".into(),
105            maintainer_name: "maintainer".into(),
106            maintainer_email: "me@example.com".into(),
107            date: DateTime::from_utc(
108                chrono::NaiveDateTime::from_timestamp(1420000000, 0),
109                chrono::TimeZone::from_offset(&chrono::FixedOffset::west(3600 * 7)),
110            ),
111        });
112
113        let mut buf = vec![];
114        changelog.write(&mut buf)?;
115
116        let s = String::from_utf8(buf)?;
117        assert_eq!(s, "mypackage (0.1) mydist; urgency=low\n\ndetails\n-- maintainer <me@example.com>  Tue, 30 Dec 2014 21:26:40 -0700\n\n");
118
119        Ok(())
120    }
121}