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",
|
"fehler",
|
||||||
"git2",
|
"git2",
|
||||||
"globset",
|
"globset",
|
||||||
|
"ignore",
|
||||||
|
"lexiclean",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
|
@ -376,6 +378,7 @@ dependencies = [
|
||||||
"strum_macros",
|
"strum_macros",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"url",
|
"url",
|
||||||
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -12,6 +12,7 @@ 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"
|
||||||
|
ignore = "0.4.14"
|
||||||
libc = "0.2.69"
|
libc = "0.2.69"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
pretty_env_logger = "0.4.0"
|
pretty_env_logger = "0.4.0"
|
||||||
|
@ -22,6 +23,8 @@ structopt = "0.3.12"
|
||||||
strum = "0.18.0"
|
strum = "0.18.0"
|
||||||
strum_macros = "0.18.0"
|
strum_macros = "0.18.0"
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
walkdir = "2.3.1"
|
||||||
|
lexiclean = "0.0.1"
|
||||||
|
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1.0.106"
|
version = "1.0.106"
|
||||||
|
|
|
@ -6,7 +6,7 @@ pub(crate) use std::{
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io,
|
io,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf, StripPrefixError},
|
||||||
process::{self, Command, ExitStatus, Stdio},
|
process::{self, Command, ExitStatus, Stdio},
|
||||||
str,
|
str,
|
||||||
};
|
};
|
||||||
|
@ -16,6 +16,8 @@ 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, Oid, Repository};
|
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 libc::EXIT_FAILURE;
|
||||||
pub(crate) use log::info;
|
pub(crate) use log::info;
|
||||||
pub(crate) use regex::Regex;
|
pub(crate) use regex::Regex;
|
||||||
|
@ -26,6 +28,7 @@ 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;
|
||||||
|
pub(crate) use walkdir::WalkDir;
|
||||||
|
|
||||||
// modules
|
// modules
|
||||||
pub(crate) use crate::error;
|
pub(crate) use crate::error;
|
||||||
|
|
|
@ -52,6 +52,12 @@ pub(crate) enum Error {
|
||||||
},
|
},
|
||||||
#[snafu(display("I/O error at `{}`: {}", path.display(), source))]
|
#[snafu(display("I/O error at `{}`: {}", path.display(), source))]
|
||||||
Filesystem { path: PathBuf, source: io::Error },
|
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))]
|
#[snafu(display("Git error: {}", source))]
|
||||||
Git { source: git2::Error },
|
Git { source: git2::Error },
|
||||||
#[snafu(display("Regex compilation error: {}", source))]
|
#[snafu(display("Regex compilation error: {}", source))]
|
||||||
|
@ -67,6 +73,12 @@ pub(crate) enum Error {
|
||||||
TemplateRender { source: askama::Error },
|
TemplateRender { source: askama::Error },
|
||||||
#[snafu(display("Failed to get workdir for repo at `{}`", repo.display()))]
|
#[snafu(display("Failed to get workdir for repo at `{}`", repo.display()))]
|
||||||
Workdir { repo: PathBuf },
|
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 {
|
impl From<regex::Error> for Error {
|
||||||
|
@ -86,3 +98,15 @@ impl From<cargo_toml::Error> for Error {
|
||||||
Self::CargoToml { source }
|
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 {
|
pub(crate) enum Opt {
|
||||||
#[structopt(about("Update all generated docs"))]
|
#[structopt(about("Update all generated docs"))]
|
||||||
All,
|
All,
|
||||||
|
#[structopt(about("Generate book"))]
|
||||||
|
Book,
|
||||||
#[structopt(about("Generate the changelog"))]
|
#[structopt(about("Generate the changelog"))]
|
||||||
Changelog,
|
Changelog,
|
||||||
#[structopt(about("Print a commit template to standard output"))]
|
#[structopt(about("Print a commit template to standard output"))]
|
||||||
|
@ -12,10 +14,10 @@ pub(crate) enum Opt {
|
||||||
CommitTypes,
|
CommitTypes,
|
||||||
#[structopt(about("Generate completion scripts"))]
|
#[structopt(about("Generate completion scripts"))]
|
||||||
CompletionScripts,
|
CompletionScripts,
|
||||||
|
#[structopt(about("Diff generated content between commits"))]
|
||||||
|
Diff,
|
||||||
#[structopt(about("Generate readme"))]
|
#[structopt(about("Generate readme"))]
|
||||||
Readme,
|
Readme,
|
||||||
#[structopt(about("Generate book"))]
|
|
||||||
Book,
|
|
||||||
#[structopt(about("Generate man pages"))]
|
#[structopt(about("Generate man pages"))]
|
||||||
Man,
|
Man,
|
||||||
}
|
}
|
||||||
|
@ -70,15 +72,19 @@ impl Opt {
|
||||||
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::Diff => Self::diff(&project)?,
|
||||||
|
Self::All => Self::all(&project)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[throws]
|
||||||
|
pub(crate) fn all(project: &Project) {
|
||||||
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)?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[throws]
|
#[throws]
|
||||||
pub(crate) fn changelog(project: &Project) {
|
pub(crate) fn changelog(project: &Project) {
|
||||||
|
@ -109,6 +115,91 @@ impl Opt {
|
||||||
.status_into_result()?
|
.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]
|
#[throws]
|
||||||
pub(crate) fn readme(project: &Project) {
|
pub(crate) fn readme(project: &Project) {
|
||||||
info!("Generating readme…");
|
info!("Generating readme…");
|
||||||
|
|
Loading…
Reference in New Issue
Block a user