Skip to main content

git_harvest/changelog/
fragment.rs

1/*********************** GNU General Public License 3.0 ***********************\
2|                                                                              |
3|  Copyright (C) 2026 Kevin Matthes                                            |
4|                                                                              |
5|  This program is free software: you can redistribute it and/or modify        |
6|  it under the terms of the GNU General Public License as published by        |
7|  the Free Software Foundation, either version 3 of the License, or           |
8|  (at your option) any later version.                                         |
9|                                                                              |
10|  This program is distributed in the hope that it will be useful,             |
11|  but WITHOUT ANY WARRANTY; without even the implied warranty of              |
12|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               |
13|  GNU General Public License for more details.                                |
14|                                                                              |
15|  You should have received a copy of the GNU General Public License           |
16|  along with this program.  If not, see <https://www.gnu.org/licenses/>.      |
17|                                                                              |
18\******************************************************************************/
19
20//! One harvested fragment:  the changes of a single branch, not yet assembled.
21
22/// The changes harvested from one branch, written to `changelog.d/`.
23///
24/// A fragment is the pending state of one line of work.  Pass two merges
25/// every fragment in `changelog.d/` into a [`crate::Section`] and deletes
26/// them.  `changes` maps a bucket name to its entries.
27#[derive(
28    Clone, Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize,
29)]
30pub struct Fragment {
31    /// Link labels used by this fragment, mapped to their targets.
32    pub references: std::collections::BTreeMap<String, String>,
33
34    /// The harvested entries, keyed by bucket.
35    pub changes: std::collections::BTreeMap<String, Vec<crate::Entry>>,
36}
37
38impl Fragment {
39    /// Whether the fragment holds no entries at all.
40    pub fn is_empty(&self) -> bool {
41        self.changes.values().all(std::vec::Vec::is_empty)
42    }
43
44    /// File `entry` under `bucket`, preserving harvest order.
45    pub fn record(&mut self, bucket: &str, entry: crate::Entry) {
46        self.changes
47            .entry(bucket.to_owned())
48            .or_default()
49            .push(entry);
50    }
51
52    /// Serialise the fragment to pretty RON, indented two spaces.
53    ///
54    /// # Errors
55    ///
56    /// Returns [`sysexits::ExitCode::Software`] if the fragment cannot be
57    /// represented as RON — which should not happen for a value built by this
58    /// crate — after printing the reason to standard error.
59    pub fn to_ron(&self) -> sysexits::Result<String> {
60        let pretty = ron::ser::PrettyConfig::new().indentor("  ".to_owned());
61
62        match ron::ser::to_string_pretty(self, pretty) {
63            Ok(body) => Ok(format!("{body}\n")),
64            Err(reason) => {
65                eprintln!(
66                    "git-harvest:  cannot serialise the fragment:  {reason}"
67                );
68                Err(sysexits::ExitCode::Software)
69            }
70        }
71    }
72}
73
74/******************************************************************************/