Skip to content

Commit

Permalink
Generate top-level chapters even if empty; #1
Browse files Browse the repository at this point in the history
  • Loading branch information
msuchane committed Jun 27, 2024
1 parent 682d4d9 commit 3e4cd24
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 31 deletions.
59 changes: 49 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,22 +188,61 @@ impl Document {
// Make sure that the output directory exists.
fs::create_dir_all(generated_dir)?;

for module in modules {
let out_file = generated_dir.join(&module.file_name);
Self::write_chapters(modules, summary, generated_dir)?;

// Save the appendix.
let summary_file = generated_dir.join("ref_list-of-tickets-by-component.adoc");
log::debug!("Writing file: {}", summary_file.display());
fs::write(summary_file, summary).wrap_err("Failed to write generated summary appendix.")?;

Ok(())
}

fn write_chapters(modules: &[Module], summary: &str, generated_dir: &Path) -> Result<()> {
for chapter in modules {
let out_file = generated_dir.join(&chapter.file_name());
log::debug!("Writing file: {}", out_file.display());
fs::write(out_file, &module.text).wrap_err("Failed to write generated module.")?;

let text = match chapter {
Module::WithContent { text, .. } => text,
Module::Blank { .. } => "",
};

fs::write(out_file, text).wrap_err("Failed to write generated module.")?;

// If the currently processed module is an assembly,
// recursively descend into the assembly and write its included modules.
if let Some(included_modules) = &module.included_modules {
Self::write_variant(included_modules, summary, generated_dir)?;
if let Module::WithContent {
included_modules, ..
} = chapter
{
if let Some(included_modules) = included_modules {
Self::write_modules(included_modules, summary, generated_dir)?;
}
}
}

// Save the appendix.
let summary_file = generated_dir.join("ref_list-of-tickets-by-component.adoc");
log::debug!("Writing file: {}", summary_file.display());
fs::write(summary_file, summary)
.wrap_err("Failed to write generated summary appendix.")?;
Ok(())
}

fn write_modules(modules: &[Module], summary: &str, generated_dir: &Path) -> Result<()> {
for module in modules {
if let Module::WithContent {
file_name,
text,
included_modules,
} = module
{
let out_file = generated_dir.join(file_name);
log::debug!("Writing file: {}", out_file.display());
fs::write(out_file, text).wrap_err("Failed to write generated module.")?;

// If the currently processed module is an assembly,
// recursively descend into the assembly and write its included modules.
if let Some(included_modules) = included_modules {
Self::write_modules(included_modules, summary, generated_dir)?;
}
}
}

Ok(())
Expand Down
65 changes: 44 additions & 21 deletions src/templating.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,33 @@ pub enum DocumentVariant {

/// The representation of a module, before being finally rendered.
#[derive(Clone, Debug, PartialEq)]
pub struct Module {
pub file_name: String,
pub text: String,
pub included_modules: Option<Vec<Self>>,
pub enum Module {
WithContent {
file_name: String,
text: String,
included_modules: Option<Vec<Self>>,
},
Blank {
file_name: String,
},
}

impl Module {
/// The AsciiDoc include statement to include this module elsewhere.
pub fn include_statement(&self) -> String {
format!("include::{}[leveloffset=+1]", &self.file_name)
format!("include::{}[leveloffset=+1]", self.file_name())
}
pub fn file_name(&self) -> &str {
match self {
Self::WithContent { file_name, .. } => file_name,
Self::Blank { file_name, .. } => file_name,
}
}
fn has_content(&self) -> bool {
match self {
Self::WithContent { .. } => true,
Self::Blank { .. } => false,
}
}
}

Expand Down Expand Up @@ -201,15 +218,15 @@ impl config::Section {
/// Convert the section into either a leaf module, or into an assembly and all
/// the modules that it includes, recursively.
///
/// Returns `None` if the module or assembly captured no release notes at all.
/// Returns `Blank` if the module or assembly captured no release notes at all.
fn modules(
&self,
tickets: &[&AbstractTicket],
prefix: Option<&str>,
variant: DocumentVariant,
with_priv_footnote: bool,
ticket_stats: &mut HashMap<Rc<TicketId>, u32>,
) -> Option<Module> {
) -> Module {
let matching_tickets: Vec<&AbstractTicket> = tickets
.iter()
.filter(|&&t| self.matches_ticket(t))
Expand All @@ -228,7 +245,7 @@ impl config::Section {
let file_name = format!("assembly_{module_id}.adoc");
let included_modules: Vec<Module> = sections
.iter()
.filter_map(|s| {
.map(|s| {
s.modules(
&matching_tickets,
Some(&module_id),
Expand All @@ -237,10 +254,11 @@ impl config::Section {
ticket_stats,
)
})
.filter(|module| module.has_content())
.collect();
// If the assembly receives no modules, because all its modules are empty, return None.
// If the assembly receives no modules, because all its modules are empty, return Blank.
if included_modules.is_empty() {
None
Module::Blank { file_name }
} else {
let include_statements: Vec<String> = included_modules
.iter()
Expand All @@ -259,28 +277,33 @@ impl config::Section {
.render()
.expect("Failed to render an assembly template.");

Some(Module {
Module::WithContent {
file_name,
text,
included_modules: Some(included_modules),
})
}
}
// If the section includes no sections, treat it as a leaf, reference module.
} else {
// If the module receives no release notes and its body is empty, return None.
// If the module receives no release notes and its body is empty, return Blank.
// Otherwise, return the module formatted with its release notes.
self.render(
let text = self.render(
&module_id,
tickets,
variant,
with_priv_footnote,
ticket_stats,
)
.map(|text| Module {
file_name: format!("ref_{module_id}.adoc"),
text,
included_modules: None,
})
);
let file_name = format!("ref_{module_id}.adoc");
if let Some(text) = text {
Module::WithContent {
file_name,
text,
included_modules: None,
}
} else {
Module::Blank { file_name }
}
}
}

Expand Down Expand Up @@ -369,7 +392,7 @@ pub fn format_document(
let chapters: Vec<_> = template
.chapters
.iter()
.filter_map(|section| {
.map(|section| {
section.modules(
tickets,
None,
Expand Down

0 comments on commit 3e4cd24

Please sign in to comment.