Improve bin/gen error messages
Create an error enum with actual error messages. type: development
This commit is contained in:
parent
e396b7f071
commit
342266853e
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -27,12 +27,6 @@ dependencies = [
|
||||||
"winapi 0.3.8",
|
"winapi 0.3.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyhow"
|
|
||||||
version = "1.0.28"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d9a60d744a80c30fcb657dfe2c1b22bcb3e814c1a1e3674f32bf5820b570fbff"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "array-init"
|
name = "array-init"
|
||||||
version = "0.0.4"
|
version = "0.0.4"
|
||||||
|
@ -364,18 +358,19 @@ checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||||
name = "gen"
|
name = "gen"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"askama",
|
"askama",
|
||||||
"cargo_toml",
|
"cargo_toml",
|
||||||
"chrono",
|
"chrono",
|
||||||
"fehler",
|
"fehler",
|
||||||
"git2",
|
"git2",
|
||||||
"globset",
|
"globset",
|
||||||
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
|
"snafu",
|
||||||
"structopt",
|
"structopt",
|
||||||
"strum",
|
"strum",
|
||||||
"strum_macros",
|
"strum_macros",
|
||||||
|
|
|
@ -6,17 +6,18 @@ edition = "2018"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.28"
|
|
||||||
askama = "0.9.0"
|
askama = "0.9.0"
|
||||||
cargo_toml = "0.8.0"
|
cargo_toml = "0.8.0"
|
||||||
chrono = "0.4.11"
|
chrono = "0.4.11"
|
||||||
fehler = "1.0.0"
|
fehler = "1.0.0"
|
||||||
git2 = "0.13.1"
|
git2 = "0.13.1"
|
||||||
globset = "0.4.5"
|
globset = "0.4.5"
|
||||||
|
libc = "0.2.69"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
pretty_env_logger = "0.4.0"
|
pretty_env_logger = "0.4.0"
|
||||||
regex = "1.3.6"
|
regex = "1.3.6"
|
||||||
serde_yaml = "0.8.11"
|
serde_yaml = "0.8.11"
|
||||||
|
snafu = "0.6.0"
|
||||||
structopt = "0.3.12"
|
structopt = "0.3.12"
|
||||||
strum = "0.18.0"
|
strum = "0.18.0"
|
||||||
strum_macros = "0.18.0"
|
strum_macros = "0.18.0"
|
||||||
|
|
|
@ -16,7 +16,7 @@ impl Changelog {
|
||||||
loop {
|
loop {
|
||||||
let summary_bytes = current
|
let summary_bytes = current
|
||||||
.summary_bytes()
|
.summary_bytes()
|
||||||
.ok_or_else(|| anyhow!("Commit had no summary"))?;
|
.ok_or_else(|| Error::CommitSummery { hash: current.id() })?;
|
||||||
|
|
||||||
let summary = String::from_utf8_lossy(summary_bytes);
|
let summary = String::from_utf8_lossy(summary_bytes);
|
||||||
|
|
||||||
|
@ -47,7 +47,10 @@ impl Changelog {
|
||||||
match current.parent_count() {
|
match current.parent_count() {
|
||||||
0 => break,
|
0 => break,
|
||||||
1 => current = current.parent(0)?,
|
1 => current = current.parent(0)?,
|
||||||
_ => throw!(anyhow!("Commit had multiple parents!")),
|
other => throw!(Error::CommitParents {
|
||||||
|
hash: current.id(),
|
||||||
|
parents: other
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
use crate::common::*;
|
use crate::common::*;
|
||||||
|
|
||||||
|
#[allow(redundant_semicolons)]
|
||||||
pub(crate) trait CommandExt {
|
pub(crate) trait CommandExt {
|
||||||
#[throws]
|
#[throws]
|
||||||
fn out(&mut self) -> String;
|
fn out(&mut self) -> String;
|
||||||
|
|
||||||
|
#[throws]
|
||||||
|
fn status_into_result(&mut self);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandExt for Command {
|
impl CommandExt for Command {
|
||||||
|
@ -13,12 +17,36 @@ impl CommandExt for Command {
|
||||||
let output = self
|
let output = self
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::inherit())
|
.stderr(Stdio::inherit())
|
||||||
.output()?;
|
.output()
|
||||||
|
.context(error::CommandInvoke {
|
||||||
|
command: format!("{:?}", self),
|
||||||
|
})?;
|
||||||
|
|
||||||
output.status.into_result()?;
|
if !output.status.success() {
|
||||||
|
throw!(Error::CommandStatus {
|
||||||
|
command: format!("{:?}", self),
|
||||||
|
exit_status: output.status,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let text = String::from_utf8(output.stdout)?;
|
let text = String::from_utf8(output.stdout).context(error::CommandDecode {
|
||||||
|
command: format!("{:?}", self),
|
||||||
|
})?;
|
||||||
|
|
||||||
text
|
text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[throws]
|
||||||
|
fn status_into_result(&mut self) {
|
||||||
|
let status = self.status().context(error::CommandInvoke {
|
||||||
|
command: format!("{:?}", self),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
throw!(Error::CommandStatus {
|
||||||
|
command: format!("{:?}", self),
|
||||||
|
exit_status: status
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,36 +4,40 @@ pub(crate) use std::{
|
||||||
env,
|
env,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
|
io,
|
||||||
|
ops::Deref,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::{Command, ExitStatus, Stdio},
|
process::{self, Command, ExitStatus, Stdio},
|
||||||
str,
|
str,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) use anyhow::{anyhow, Error};
|
|
||||||
pub(crate) use askama::Template;
|
pub(crate) use askama::Template;
|
||||||
pub(crate) use cargo_toml::Manifest;
|
pub(crate) use cargo_toml::Manifest;
|
||||||
pub(crate) use chrono::{DateTime, NaiveDateTime, Utc};
|
pub(crate) use chrono::{DateTime, NaiveDateTime, Utc};
|
||||||
pub(crate) use fehler::{throw, throws};
|
pub(crate) use fehler::{throw, throws};
|
||||||
pub(crate) use git2::{Commit, Repository};
|
pub(crate) use git2::{Commit, Oid, Repository};
|
||||||
|
pub(crate) use libc::EXIT_FAILURE;
|
||||||
pub(crate) use log::info;
|
pub(crate) use log::info;
|
||||||
pub(crate) use regex::Regex;
|
pub(crate) use regex::Regex;
|
||||||
pub(crate) use serde::{Deserialize, Serialize};
|
pub(crate) use serde::{Deserialize, Serialize};
|
||||||
|
pub(crate) use snafu::{ResultExt, Snafu};
|
||||||
|
pub(crate) use std::string::FromUtf8Error;
|
||||||
pub(crate) use structopt::StructOpt;
|
pub(crate) use structopt::StructOpt;
|
||||||
pub(crate) use strum::VariantNames;
|
pub(crate) use strum::VariantNames;
|
||||||
pub(crate) use strum_macros::{EnumVariantNames, IntoStaticStr};
|
pub(crate) use strum_macros::{EnumVariantNames, IntoStaticStr};
|
||||||
pub(crate) use url::Url;
|
pub(crate) use url::Url;
|
||||||
|
|
||||||
|
// modules
|
||||||
|
pub(crate) use crate::error;
|
||||||
|
|
||||||
// traits
|
// traits
|
||||||
pub(crate) use crate::{
|
pub(crate) use crate::{command_ext::CommandExt, row::Row, slug::Slug, template_ext::TemplateExt};
|
||||||
command_ext::CommandExt, exit_status_ext::ExitStatusExt, row::Row, slug::Slug,
|
|
||||||
template_ext::TemplateExt,
|
|
||||||
};
|
|
||||||
|
|
||||||
// structs and enums
|
// structs and enums
|
||||||
pub(crate) use crate::{
|
pub(crate) use crate::{
|
||||||
bin::Bin, changelog::Changelog, config::Config, entry::Entry, example::Example, faq::Faq,
|
bin::Bin, changelog::Changelog, config::Config, entry::Entry, error::Error, example::Example,
|
||||||
faq_entry::FaqEntry, introduction::Introduction, kind::Kind, metadata::Metadata, opt::Opt,
|
faq::Faq, faq_entry::FaqEntry, introduction::Introduction, kind::Kind, metadata::Metadata,
|
||||||
package::Package, project::Project, readme::Readme, reference::Reference,
|
opt::Opt, package::Package, project::Project, readme::Readme, reference::Reference,
|
||||||
reference_section::ReferenceSection, release::Release, subcommand::Subcommand, summary::Summary,
|
reference_section::ReferenceSection, release::Release, subcommand::Subcommand, summary::Summary,
|
||||||
table::Table,
|
table::Table,
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,8 @@ pub(crate) struct Config {
|
||||||
impl Config {
|
impl Config {
|
||||||
#[throws]
|
#[throws]
|
||||||
pub(crate) fn load(root: &Path) -> Config {
|
pub(crate) fn load(root: &Path) -> Config {
|
||||||
let file = File::open(root.join(PATH))?;
|
let path = root.join(PATH);
|
||||||
serde_yaml::from_reader(file)?
|
let file = File::open(&path).context(error::Filesystem { path: &path })?;
|
||||||
|
serde_yaml::from_reader(file).context(error::ConfigDeserialize { path })?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
88
bin/gen/src/error.rs
Normal file
88
bin/gen/src/error.rs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
use crate::common::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Snafu)]
|
||||||
|
#[snafu(visibility(pub(crate)))]
|
||||||
|
pub(crate) enum Error {
|
||||||
|
#[snafu(display("Failed to deserialize `Cargo.toml`: {}", source))]
|
||||||
|
CargoToml { source: cargo_toml::Error },
|
||||||
|
#[snafu(display("Failed to decode command `{}` output: {}", command, source))]
|
||||||
|
CommandDecode {
|
||||||
|
command: String,
|
||||||
|
source: FromUtf8Error,
|
||||||
|
},
|
||||||
|
#[snafu(display("Failed to invoke command `{}` output: {}", command, source))]
|
||||||
|
CommandInvoke { command: String, source: io::Error },
|
||||||
|
#[snafu(display("Command `{}` failed: {}", command, exit_status))]
|
||||||
|
CommandStatus {
|
||||||
|
command: String,
|
||||||
|
exit_status: ExitStatus,
|
||||||
|
},
|
||||||
|
#[snafu(display(
|
||||||
|
"Failed to deserialize commit metadata: {}\n{}\n{}",
|
||||||
|
source,
|
||||||
|
hash,
|
||||||
|
message
|
||||||
|
))]
|
||||||
|
CommitMetadataDeserialize {
|
||||||
|
hash: Oid,
|
||||||
|
message: String,
|
||||||
|
source: serde_yaml::Error,
|
||||||
|
},
|
||||||
|
#[snafu(display("Commit missing metadata:\n{}\n{}", hash, message))]
|
||||||
|
CommitMetadataMissing { hash: Oid, message: String },
|
||||||
|
#[snafu(display("Commit has `{}` parents: {}", hash, parents))]
|
||||||
|
CommitParents { hash: Oid, parents: usize },
|
||||||
|
#[snafu(display("Commit has no summery: {}", hash))]
|
||||||
|
CommitSummery { hash: Oid },
|
||||||
|
#[snafu(display("Failed to deserialize config from `{}`: {}", path.display(), source))]
|
||||||
|
ConfigDeserialize {
|
||||||
|
path: PathBuf,
|
||||||
|
source: serde_yaml::Error,
|
||||||
|
},
|
||||||
|
#[snafu(display("Failed to get current dir: {}", source))]
|
||||||
|
CurrentDir { source: io::Error },
|
||||||
|
#[snafu(display(
|
||||||
|
"Example commands `{}` don't match bin commands `{}`",
|
||||||
|
example.iter().map(|command| command.deref()).collect::<Vec<&str>>().join(","),
|
||||||
|
bin.iter().map(|command| command.deref()).collect::<Vec<&str>>().join(","),
|
||||||
|
))]
|
||||||
|
ExampleCommands {
|
||||||
|
example: BTreeSet<String>,
|
||||||
|
bin: BTreeSet<String>,
|
||||||
|
},
|
||||||
|
#[snafu(display("I/O error at `{}`: {}", path.display(), source))]
|
||||||
|
Filesystem { path: PathBuf, source: io::Error },
|
||||||
|
#[snafu(display("Git error: {}", source))]
|
||||||
|
Git { source: git2::Error },
|
||||||
|
#[snafu(display("Regex compilation error: {}", source))]
|
||||||
|
Regex { source: regex::Error },
|
||||||
|
#[snafu(display("Failed to find repository from `{}`: {}", start_dir.display(), source))]
|
||||||
|
RepositoryDiscover {
|
||||||
|
start_dir: PathBuf,
|
||||||
|
source: git2::Error,
|
||||||
|
},
|
||||||
|
#[snafu(display("Failed to create tempdir: {}", source))]
|
||||||
|
Tempdir { source: io::Error },
|
||||||
|
#[snafu(display("Failed to render template: {}", source))]
|
||||||
|
TemplateRender { source: askama::Error },
|
||||||
|
#[snafu(display("Failed to get workdir for repo at `{}`", repo.display()))]
|
||||||
|
Workdir { repo: PathBuf },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<regex::Error> for Error {
|
||||||
|
fn from(source: regex::Error) -> Self {
|
||||||
|
Self::Regex { source }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<git2::Error> for Error {
|
||||||
|
fn from(source: git2::Error) -> Self {
|
||||||
|
Self::Git { source }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<cargo_toml::Error> for Error {
|
||||||
|
fn from(source: cargo_toml::Error) -> Self {
|
||||||
|
Self::CargoToml { source }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
use crate::common::*;
|
|
||||||
|
|
||||||
pub(crate) trait ExitStatusExt {
|
|
||||||
fn into_result(self) -> anyhow::Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExitStatusExt for ExitStatus {
|
|
||||||
#[throws]
|
|
||||||
fn into_result(self) {
|
|
||||||
if !self.success() {
|
|
||||||
throw!(anyhow!(self));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,8 +9,8 @@ mod command_ext;
|
||||||
mod common;
|
mod common;
|
||||||
mod config;
|
mod config;
|
||||||
mod entry;
|
mod entry;
|
||||||
|
mod error;
|
||||||
mod example;
|
mod example;
|
||||||
mod exit_status_ext;
|
|
||||||
mod faq;
|
mod faq;
|
||||||
mod faq_entry;
|
mod faq_entry;
|
||||||
mod introduction;
|
mod introduction;
|
||||||
|
@ -30,11 +30,11 @@ mod summary;
|
||||||
mod table;
|
mod table;
|
||||||
mod template_ext;
|
mod template_ext;
|
||||||
|
|
||||||
#[throws]
|
|
||||||
fn main() {
|
fn main() {
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
|
|
||||||
let project = Project::load()?;
|
if let Err(error) = Opt::from_args().run() {
|
||||||
|
eprintln!("{}", error);
|
||||||
Opt::from_args().run(&project)?;
|
process::exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,11 +19,17 @@ impl Metadata {
|
||||||
|
|
||||||
let blank = message
|
let blank = message
|
||||||
.rfind(BLANK)
|
.rfind(BLANK)
|
||||||
.ok_or_else(|| anyhow!("Commit message missing metadata: {}", message))?;
|
.ok_or_else(|| Error::CommitMetadataMissing {
|
||||||
|
hash: commit.id(),
|
||||||
|
message: message.to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
let yaml = &message[blank + BLANK.len()..];
|
let yaml = &message[blank + BLANK.len()..];
|
||||||
|
|
||||||
let metadata = serde_yaml::from_str(yaml)?;
|
let metadata = serde_yaml::from_str(yaml).context(error::CommitMetadataDeserialize {
|
||||||
|
hash: commit.id(),
|
||||||
|
message,
|
||||||
|
})?;
|
||||||
|
|
||||||
metadata
|
metadata
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,27 +35,29 @@ fn blank(path: impl AsRef<Path>, title: &str) {
|
||||||
title
|
title
|
||||||
);
|
);
|
||||||
|
|
||||||
fs::write(path, text)?;
|
fs::write(&path, text).context(error::Filesystem { path })?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[throws]
|
#[throws]
|
||||||
fn clean_dir(dir: impl AsRef<Path>) {
|
fn clean_dir(path: impl AsRef<Path>) {
|
||||||
let dir = dir.as_ref();
|
let path = path.as_ref();
|
||||||
|
|
||||||
info!("Cleaning `{}`…", dir.display());
|
info!("Cleaning `{}`…", path.display());
|
||||||
|
|
||||||
if dir.is_dir() {
|
if path.is_dir() {
|
||||||
fs::remove_dir_all(dir)?;
|
fs::remove_dir_all(path).context(error::Filesystem { path: &path })?;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::create_dir_all(dir)?;
|
fs::create_dir_all(path).context(error::Filesystem { path: &path })?;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Opt {
|
impl Opt {
|
||||||
#[throws]
|
#[throws]
|
||||||
pub(crate) fn run(self, project: &Project) {
|
pub(crate) fn run(self) {
|
||||||
|
let project = Project::load()?;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::Changelog => Self::changelog(project)?,
|
Self::Changelog => Self::changelog(&project)?,
|
||||||
Self::CommitTemplate => {
|
Self::CommitTemplate => {
|
||||||
println!("{}", Metadata::default().to_string());
|
println!("{}", Metadata::default().to_string());
|
||||||
}
|
}
|
||||||
|
@ -64,16 +66,16 @@ impl Opt {
|
||||||
println!("{}", kind)
|
println!("{}", kind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::CompletionScripts => Self::completion_scripts(project)?,
|
Self::CompletionScripts => Self::completion_scripts(&project)?,
|
||||||
Self::Readme => Self::readme(project)?,
|
Self::Readme => Self::readme(&project)?,
|
||||||
Self::Book => Self::book(project)?,
|
Self::Book => Self::book(&project)?,
|
||||||
Self::Man => Self::man(project)?,
|
Self::Man => Self::man(&project)?,
|
||||||
Self::All => {
|
Self::All => {
|
||||||
Self::changelog(project)?;
|
Self::changelog(&project)?;
|
||||||
Self::completion_scripts(project)?;
|
Self::completion_scripts(&project)?;
|
||||||
Self::readme(project)?;
|
Self::readme(&project)?;
|
||||||
Self::book(project)?;
|
Self::book(&project)?;
|
||||||
Self::man(project)?;
|
Self::man(&project)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,9 +85,9 @@ impl Opt {
|
||||||
info!("Generating changelog…");
|
info!("Generating changelog…");
|
||||||
let changelog = Changelog::new(&project)?;
|
let changelog = Changelog::new(&project)?;
|
||||||
|
|
||||||
let dst = project.root.join("CHANGELOG.md");
|
let path = project.root.join("CHANGELOG.md");
|
||||||
|
|
||||||
fs::write(dst, changelog.to_string())?;
|
fs::write(&path, changelog.to_string()).context(error::Filesystem { path })?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[throws]
|
#[throws]
|
||||||
|
@ -104,20 +106,21 @@ impl Opt {
|
||||||
"--dir",
|
"--dir",
|
||||||
completions
|
completions
|
||||||
)
|
)
|
||||||
.status()?
|
.status_into_result()?
|
||||||
.into_result()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[throws]
|
#[throws]
|
||||||
pub(crate) fn readme(project: &Project) {
|
pub(crate) fn readme(project: &Project) {
|
||||||
info!("Generating readme…");
|
info!("Generating readme…");
|
||||||
|
|
||||||
let template = project.root.join("bin/gen/templates/README.md");
|
let template = project.root.join("bin/gen/templates/README.md");
|
||||||
|
|
||||||
let readme = Readme::load(&project.config, &template)?;
|
let readme = Readme::load(&project.config, &template)?;
|
||||||
|
|
||||||
let text = readme.render_newline()?;
|
let text = readme.render_newline()?;
|
||||||
|
|
||||||
fs::write(project.root.join("README.md"), text)?;
|
let path = project.root.join("README.md");
|
||||||
|
fs::write(&path, text).context(error::Filesystem { path })?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[throws]
|
#[throws]
|
||||||
|
@ -137,35 +140,20 @@ impl Opt {
|
||||||
|
|
||||||
let dst = commands.join(format!("{}.md", subcommand.slug()));
|
let dst = commands.join(format!("{}.md", subcommand.slug()));
|
||||||
|
|
||||||
fs::write(dst, page)?;
|
fs::write(&dst, page).context(error::Filesystem { path: dst })?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let references = project.root.join("book/src/references/");
|
clean_dir(&project.root.join("book/src/references/"))?;
|
||||||
clean_dir(&references)?;
|
|
||||||
|
|
||||||
for section in &project.config.references {
|
for section in &project.config.references {
|
||||||
let text = section.render_newline()?;
|
section.render_to(project.root.join("book/src").join(section.path()))?;
|
||||||
|
|
||||||
let path = project.root.join("book/src").join(section.path());
|
|
||||||
|
|
||||||
fs::write(path, text)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let faq = Faq::new(&project.config.faq);
|
Faq::new(&project.config.faq).render_to(project.root.join("book/src/faq.md"))?;
|
||||||
|
|
||||||
fs::write(project.root.join("book/src/faq.md"), faq.render_newline()?)?;
|
Summary::new(project).render_to(project.root.join("book/src/SUMMARY.md"))?;
|
||||||
|
|
||||||
let summary = Summary::new(project);
|
Introduction::new(&project.config).render_to(project.root.join("book/src/introduction.md"))?;
|
||||||
|
|
||||||
let text = summary.render_newline()?;
|
|
||||||
|
|
||||||
fs::write(project.root.join("book/src/SUMMARY.md"), text)?;
|
|
||||||
|
|
||||||
let introduction = Introduction::new(&project.config);
|
|
||||||
|
|
||||||
let text = introduction.render_newline()?;
|
|
||||||
|
|
||||||
fs::write(project.root.join("book/src/introduction.md"), text)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[throws]
|
#[throws]
|
||||||
|
@ -182,7 +170,7 @@ impl Opt {
|
||||||
|
|
||||||
info!("Writing man page to `{}`", dst.display());
|
info!("Writing man page to `{}`", dst.display());
|
||||||
|
|
||||||
fs::write(dst, man)?;
|
fs::write(&dst, man).context(error::Filesystem { path: dst })?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,15 @@ pub(crate) struct Project {
|
||||||
impl Project {
|
impl Project {
|
||||||
#[throws]
|
#[throws]
|
||||||
pub(crate) fn load() -> Self {
|
pub(crate) fn load() -> Self {
|
||||||
let repo = Repository::discover(env::current_dir()?)?;
|
let start_dir = env::current_dir().context(error::CurrentDir)?;
|
||||||
|
|
||||||
|
let repo = Repository::discover(&start_dir).context(error::RepositoryDiscover { start_dir })?;
|
||||||
|
|
||||||
let root = repo
|
let root = repo
|
||||||
.workdir()
|
.workdir()
|
||||||
.ok_or_else(|| anyhow!("Repository at `{}` had no workdir", repo.path().display()))?
|
.ok_or_else(|| Error::Workdir {
|
||||||
|
repo: repo.path().to_owned(),
|
||||||
|
})?
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
|
||||||
let config = Config::load(&root)?;
|
let config = Config::load(&root)?;
|
||||||
|
@ -34,17 +38,10 @@ impl Project {
|
||||||
.collect::<BTreeSet<String>>();
|
.collect::<BTreeSet<String>>();
|
||||||
|
|
||||||
if example_commands != bin_commands {
|
if example_commands != bin_commands {
|
||||||
println!("Example commands:");
|
throw!(Error::ExampleCommands {
|
||||||
for command in example_commands {
|
example: example_commands,
|
||||||
println!("{}", command);
|
bin: bin_commands
|
||||||
}
|
});
|
||||||
|
|
||||||
println!("…don't match bin commands:");
|
|
||||||
for command in bin_commands {
|
|
||||||
println!("{}", command);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw!(anyhow!(""));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Project {
|
Project {
|
||||||
|
|
|
@ -12,7 +12,7 @@ const HEADING_PATTERN: &str = "(?m)^(?P<MARKER>#+) (?P<TEXT>.*)$";
|
||||||
impl Readme {
|
impl Readme {
|
||||||
#[throws]
|
#[throws]
|
||||||
pub(crate) fn load(config: &Config, template: &Path) -> Readme {
|
pub(crate) fn load(config: &Config, template: &Path) -> Readme {
|
||||||
let text = fs::read_to_string(template)?;
|
let text = fs::read_to_string(template).context(error::Filesystem { path: template })?;
|
||||||
|
|
||||||
let header_re = Regex::new(HEADING_PATTERN)?;
|
let header_re = Regex::new(HEADING_PATTERN)?;
|
||||||
|
|
||||||
|
|
|
@ -72,11 +72,13 @@ impl Subcommand {
|
||||||
name, description
|
name, description
|
||||||
);
|
);
|
||||||
|
|
||||||
let tmp = tempfile::tempdir()?;
|
let tmp = tempfile::tempdir().context(error::Tempdir)?;
|
||||||
|
|
||||||
let include_path = tmp.path().join("include");
|
let include_path = tmp.path().join("include");
|
||||||
|
|
||||||
fs::write(&include_path, include)?;
|
fs::write(&include_path, include).context(error::Filesystem {
|
||||||
|
path: &include_path,
|
||||||
|
})?;
|
||||||
|
|
||||||
let version = cmd!(&self.bin, "--version")
|
let version = cmd!(&self.bin, "--version")
|
||||||
.out()?
|
.out()?
|
||||||
|
|
|
@ -3,12 +3,23 @@ use crate::common::*;
|
||||||
pub(crate) trait TemplateExt {
|
pub(crate) trait TemplateExt {
|
||||||
#[throws]
|
#[throws]
|
||||||
fn render_newline(&self) -> String;
|
fn render_newline(&self) -> String;
|
||||||
|
|
||||||
|
#[throws]
|
||||||
|
fn render_to(&self, path: impl AsRef<Path>) {
|
||||||
|
let path = path.as_ref();
|
||||||
|
let text = self.render_newline()?;
|
||||||
|
fs::write(&path, text).context(error::Filesystem { path })?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Template> TemplateExt for T {
|
impl<T: Template> TemplateExt for T {
|
||||||
#[throws]
|
#[throws]
|
||||||
fn render_newline(&self) -> String {
|
fn render_newline(&self) -> String {
|
||||||
let mut text = self.render()?.trim().to_owned();
|
let mut text = self
|
||||||
|
.render()
|
||||||
|
.context(error::TemplateRender)?
|
||||||
|
.trim()
|
||||||
|
.to_owned();
|
||||||
text.push('\n');
|
text.push('\n');
|
||||||
text
|
text
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user