From 0ad3cfffdfe3efca81fe3272926c961c43be7c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Mon, 15 Sep 2025 13:05:44 +0200 Subject: [PATCH] use indexmap for channel table - fix channels reordered --- Cargo.lock | 2 ++ Cargo.toml | 1 + src/config.rs | 6 +++--- src/store.rs | 15 ++++++++------- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 51a4a8e..3aea402 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -171,6 +171,7 @@ dependencies = [ "clap", "colored", "faccess", + "indexmap", "inquire", "regex", "serde", @@ -339,6 +340,7 @@ checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" dependencies = [ "equivalent", "hashbrown", + "serde", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 88bb078..081d5bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ anyhow = "1" colored = "3" faccess = "0.2" chrono = "0.4" +indexmap = { version = "2.11", features = ["serde"] } # input diff --git a/src/config.rs b/src/config.rs index 17a27a9..3db6e50 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,6 @@ +use indexmap::IndexMap; use serde::{Deserialize, Serialize}; use smart_default::SmartDefault; -use std::collections::HashMap; /// e.g. default, stable, eap pub type ChannelName = String; @@ -75,10 +75,10 @@ pub struct Config { /// To specify a regex, enclose it in slashes, e.g. /rel\/foo/ /// /// If you have a naming schema like e.g. `beta/1.0` where only the prefix stays the same, you may use e.g. `^beta/.*` - #[default(HashMap::from([ + #[default(IndexMap::from([ ("default".to_string(), "/^(?:main|master)$/".to_string()) ]))] - pub channels: HashMap, + pub channels: IndexMap, /// Regex pattern to extract issue number from a branch name. /// There should be one capture group that is the number. diff --git a/src/store.rs b/src/store.rs index 721557d..abef6df 100644 --- a/src/store.rs +++ b/src/store.rs @@ -5,10 +5,10 @@ use colored::Colorize; use faccess::PathExt; use serde::{Deserialize, Serialize}; use std::borrow::Cow; -use std::collections::HashMap; use std::fs::{OpenOptions, read_to_string}; use std::io::{BufRead, BufReader, Write}; use std::path::{Path, PathBuf}; +use indexmap::IndexMap; const DIR_ENTRIES: &str = "entries"; const DIR_CHANNELS: &str = "channels"; @@ -20,7 +20,7 @@ pub struct Store<'a> { /// Path to the changelog directory store_path: PathBuf, /// Loaded version history for all channels - versions: HashMap, + versions: IndexMap, } impl<'a> Store<'a> { @@ -51,7 +51,7 @@ impl<'a> Store<'a> { let mut store = Self { store_path, ctx, - versions: HashMap::new(), + versions: IndexMap::new(), }; store.ensure_internal_subdirs_exist()?; @@ -241,7 +241,7 @@ pub struct Release { impl Release { /// Render the entry into a Markdown fragment, using h2 (##) as the title, h3 (###) for sections pub fn render(&self, entries_dir: impl AsRef, config: &Config) -> anyhow::Result { - let mut entries_per_section = HashMap::::new(); + let mut entries_per_section = IndexMap::::new(); let entries_dir = entries_dir.as_ref(); let unnamed = "".to_string(); @@ -261,6 +261,7 @@ impl Release { let mut current_section = unnamed.clone(); for line in reader.lines() { let line = line?; + let line = line.trim_end(); if line.trim().is_empty() { continue; } @@ -273,7 +274,7 @@ impl Release { buffer.push('\n'); buffer.push_str(&line); } else { - entries_per_section.insert(current_section.clone(), line); + entries_per_section.insert(current_section.clone(), line.to_string()); } } } @@ -282,12 +283,12 @@ impl Release { let mut reordered_sections = Vec::<(String, String)>::new(); // First the unlabelled section (this is probably junk, but it was entered by the user, so keep it) - if let Some(unlabelled) = entries_per_section.remove("") { + if let Some(unlabelled) = entries_per_section.swap_remove("") { reordered_sections.push(("".to_string(), unlabelled)); } for section_name in [unnamed].iter().chain(config.sections.iter()) { - if let Some(content) = entries_per_section.remove(section_name) { + if let Some(content) = entries_per_section.swap_remove(section_name) { reordered_sections.push((section_name.clone(), content)); } }