mod document;
mod metadata;
pub use document::{
PackageMetadata, Release, ensure_releases_section, recent_releases, update_document,
update_document_with_releases, update_releases_section,
};
pub mod readme {
use bake::{Context, Error, Result};
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use super::{metadata::read_project_package, recent_releases, update_document_with_releases};
trait TemporaryFile: Write {
fn set_permissions(&self, permissions: fs::Permissions) -> std::io::Result<()>;
fn sync_all(&self) -> std::io::Result<()>;
}
impl TemporaryFile for fs::File {
fn set_permissions(&self, permissions: fs::Permissions) -> std::io::Result<()> {
fs::File::set_permissions(self, permissions)
}
fn sync_all(&self) -> std::io::Result<()> {
fs::File::sync_all(self)
}
}
fn prepare_temporary_file(
file: &mut impl TemporaryFile,
path: &std::path::Path,
document: &str,
) -> Result<()> {
file.write_all(document.as_bytes())?;
file.set_permissions(fs::metadata(path)?.permissions())?;
file.sync_all()?;
Ok(())
}
fn write_document_atomically(path: &std::path::Path, document: &str) -> Result<()> {
let directory = path
.parent()
.expect("a canonical readme file path should have a parent directory");
let mut temporary = tempfile::NamedTempFile::new_in(directory)?;
prepare_temporary_file(temporary.as_file_mut(), path, document)?;
temporary
.persist(path)
.map_err(|error| Error::from(error.error))?;
Ok(())
}
#[bake::task]
pub fn update(
context: &mut Context,
#[bake(
default = "readme.md",
help = "readme file relative to the project root."
)]
path: PathBuf,
) -> Result<()> {
let path = context.root().join(path).canonicalize()?;
let document = fs::read_to_string(&path)
.map_err(|error| Error::new(format!("{}: {error}", path.display())))?;
let package = read_project_package(context)?;
let release_path = context.root().join("releases.md");
let releases = if release_path.is_file() {
let release_document = fs::read_to_string(&release_path)
.map_err(|error| Error::new(format!("{}: {error}", release_path.display())))?;
recent_releases(&release_document)
} else {
Vec::new()
};
let updated = update_document_with_releases(&document, package.as_ref(), &releases);
if updated == document {
return Ok(());
}
write_document_atomically(&path, &updated)
}
#[cfg(test)]
#[path = "readme_tests.rs"]
mod tests;
}