Add bin/gen
command to diff generated content
The following command will print a diff between HEAD and HEAD^: cargo run --package gen diff type: development
This commit is contained in:
parent
342266853e
commit
8dfdbe43df
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -364,6 +364,8 @@ dependencies = [
|
|||
"fehler",
|
||||
"git2",
|
||||
"globset",
|
||||
"ignore",
|
||||
"lexiclean",
|
||||
"libc",
|
||||
"log",
|
||||
"pretty_env_logger",
|
||||
|
@ -376,6 +378,7 @@ dependencies = [
|
|||
"strum_macros",
|
||||
"tempfile",
|
||||
"url",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -12,6 +12,7 @@ chrono = "0.4.11"
|
|||
fehler = "1.0.0"
|
||||
git2 = "0.13.1"
|
||||
globset = "0.4.5"
|
||||
ignore = "0.4.14"
|
||||
libc = "0.2.69"
|
||||
log = "0.4.8"
|
||||
pretty_env_logger = "0.4.0"
|
||||
|
@ -22,6 +23,8 @@ structopt = "0.3.12"
|
|||
strum = "0.18.0"
|
||||
strum_macros = "0.18.0"
|
||||
tempfile = "3.1.0"
|
||||
walkdir = "2.3.1"
|
||||
lexiclean = "0.0.1"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.106"
|
||||
|
|
|
@ -6,7 +6,7 @@ pub(crate) use std::{
|
|||
fs::{self, File},
|
||||
io,
|
||||
ops::Deref,
|
||||
path::{Path, PathBuf},
|
||||
path::{Path, PathBuf, StripPrefixError},
|
||||
process::{self, Command, ExitStatus, Stdio},
|
||||
str,
|
||||
};
|
||||
|
@ -16,6 +16,8 @@ pub(crate) use cargo_toml::Manifest;
|
|||
pub(crate) use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
pub(crate) use fehler::{throw, throws};
|
||||
pub(crate) use git2::{Commit, Oid, Repository};
|
||||
pub(crate) use ignore::overrides::OverrideBuilder;
|
||||
pub(crate) use lexiclean::Lexiclean;
|
||||
pub(crate) use libc::EXIT_FAILURE;
|
||||
pub(crate) use log::info;
|
||||
pub(crate) use regex::Regex;
|
||||
|
@ -26,6 +28,7 @@ pub(crate) use structopt::StructOpt;
|
|||
pub(crate) use strum::VariantNames;
|
||||
pub(crate) use strum_macros::{EnumVariantNames, IntoStaticStr};
|
||||
pub(crate) use url::Url;
|
||||
pub(crate) use walkdir::WalkDir;
|
||||
|
||||
// modules
|
||||
pub(crate) use crate::error;
|
||||
|
|
|
@ -52,6 +52,12 @@ pub(crate) enum Error {
|
|||
},
|
||||
#[snafu(display("I/O error at `{}`: {}", path.display(), source))]
|
||||
Filesystem { path: PathBuf, source: io::Error },
|
||||
#[snafu(display("I/O error copying `{}` to `{}`: {}", src.display(), dst.display(), source))]
|
||||
FilesystemCopy {
|
||||
src: PathBuf,
|
||||
dst: PathBuf,
|
||||
source: io::Error,
|
||||
},
|
||||
#[snafu(display("Git error: {}", source))]
|
||||
Git { source: git2::Error },
|
||||
#[snafu(display("Regex compilation error: {}", source))]
|
||||
|
@ -67,6 +73,12 @@ pub(crate) enum Error {
|
|||
TemplateRender { source: askama::Error },
|
||||
#[snafu(display("Failed to get workdir for repo at `{}`", repo.display()))]
|
||||
Workdir { repo: PathBuf },
|
||||
#[snafu(display("Failed to build overrides: {}", source))]
|
||||
Ignore { source: ignore::Error },
|
||||
#[snafu(display("Failed to traverse worktree: {}", source))]
|
||||
Walkdir { source: walkdir::Error },
|
||||
#[snafu(display("Failed to strip path prefix: {}", source))]
|
||||
StripPrefix { source: StripPrefixError },
|
||||
}
|
||||
|
||||
impl From<regex::Error> for Error {
|
||||
|
@ -86,3 +98,15 @@ impl From<cargo_toml::Error> for Error {
|
|||
Self::CargoToml { source }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ignore::Error> for Error {
|
||||
fn from(source: ignore::Error) -> Self {
|
||||
Self::Ignore { source }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<walkdir::Error> for Error {
|
||||
fn from(source: walkdir::Error) -> Self {
|
||||
Self::Walkdir { source }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ use crate::common::*;
|
|||
pub(crate) enum Opt {
|
||||
#[structopt(about("Update all generated docs"))]
|
||||
All,
|
||||
#[structopt(about("Generate book"))]
|
||||
Book,
|
||||
#[structopt(about("Generate the changelog"))]
|
||||
Changelog,
|
||||
#[structopt(about("Print a commit template to standard output"))]
|
||||
|
@ -12,10 +14,10 @@ pub(crate) enum Opt {
|
|||
CommitTypes,
|
||||
#[structopt(about("Generate completion scripts"))]
|
||||
CompletionScripts,
|
||||
#[structopt(about("Diff generated content between commits"))]
|
||||
Diff,
|
||||
#[structopt(about("Generate readme"))]
|
||||
Readme,
|
||||
#[structopt(about("Generate book"))]
|
||||
Book,
|
||||
#[structopt(about("Generate man pages"))]
|
||||
Man,
|
||||
}
|
||||
|
@ -70,16 +72,20 @@ impl Opt {
|
|||
Self::Readme => Self::readme(&project)?,
|
||||
Self::Book => Self::book(&project)?,
|
||||
Self::Man => Self::man(&project)?,
|
||||
Self::All => {
|
||||
Self::changelog(&project)?;
|
||||
Self::completion_scripts(&project)?;
|
||||
Self::readme(&project)?;
|
||||
Self::book(&project)?;
|
||||
Self::man(&project)?;
|
||||
}
|
||||
Self::Diff => Self::diff(&project)?,
|
||||
Self::All => Self::all(&project)?,
|
||||
}
|
||||
}
|
||||
|
||||
#[throws]
|
||||
pub(crate) fn all(project: &Project) {
|
||||
Self::changelog(&project)?;
|
||||
Self::completion_scripts(&project)?;
|
||||
Self::readme(&project)?;
|
||||
Self::book(&project)?;
|
||||
Self::man(&project)?;
|
||||
}
|
||||
|
||||
#[throws]
|
||||
pub(crate) fn changelog(project: &Project) {
|
||||
info!("Generating changelog…");
|
||||
|
@ -109,6 +115,91 @@ impl Opt {
|
|||
.status_into_result()?
|
||||
}
|
||||
|
||||
#[throws]
|
||||
pub(crate) fn diff(project: &Project) {
|
||||
let tmp = tempfile::tempdir().context(error::Tempdir)?;
|
||||
|
||||
let generated = &[
|
||||
"/CHANGELOG.md",
|
||||
"/README.md",
|
||||
"/book/src/SUMMARY.md",
|
||||
"/book/src/bittorrent.md",
|
||||
"/book/src/commands.md",
|
||||
"/book/src/commands/*",
|
||||
"/book/src/faq.md",
|
||||
"/book/src/introduction.md",
|
||||
"/book/src/references.md",
|
||||
"/book/src/references/*",
|
||||
"/completions/*",
|
||||
"/man/*",
|
||||
];
|
||||
|
||||
let gen = |name: &str| -> Result<(), Error> {
|
||||
cmd!("cargo", "run", "--package", "gen", "all").status_into_result()?;
|
||||
|
||||
let dir = tmp.path().join(name);
|
||||
|
||||
fs::create_dir(&dir).context(error::Filesystem { path: &dir })?;
|
||||
|
||||
let mut builder = OverrideBuilder::new(&project.root);
|
||||
|
||||
for pattern in generated {
|
||||
builder.add(pattern)?;
|
||||
}
|
||||
|
||||
let overrides = builder.build()?;
|
||||
|
||||
for result in WalkDir::new(&project.root) {
|
||||
let entry = result?;
|
||||
|
||||
let src = entry.path();
|
||||
|
||||
if src.is_dir() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !overrides.matched(&src, false).is_whitelist() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let relative = src
|
||||
.strip_prefix(&project.root)
|
||||
.context(error::StripPrefix)?;
|
||||
|
||||
let dst = dir.join(relative);
|
||||
|
||||
let dst_dir = dst.join("..").lexiclean();
|
||||
|
||||
fs::create_dir_all(&dst_dir).context(error::Filesystem { path: dst_dir })?;
|
||||
|
||||
fs::copy(&src, &dst).context(error::FilesystemCopy { src, dst })?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
||||
const HEAD: &str = "HEAD";
|
||||
|
||||
gen(HEAD)?;
|
||||
|
||||
let head = project.repo.head()?.peel_to_commit()?;
|
||||
|
||||
let parent = head.parent(0)?;
|
||||
|
||||
let parent_hash = parent.id().to_string();
|
||||
|
||||
cmd!("git", "checkout", &parent_hash).status_into_result()?;
|
||||
|
||||
gen(&parent_hash)?;
|
||||
|
||||
cmd!("diff", "-r", parent_hash, HEAD)
|
||||
.current_dir(tmp.path())
|
||||
.status_into_result()
|
||||
.ok();
|
||||
|
||||
cmd!("git", "checkout", &head.id().to_string()).status_into_result()?;
|
||||
}
|
||||
|
||||
#[throws]
|
||||
pub(crate) fn readme(project: &Project) {
|
||||
info!("Generating readme…");
|
||||
|
|
Loading…
Reference in New Issue
Block a user