Skip to content

Commit

Permalink
Add bin/gen command to diff generated content
Browse files Browse the repository at this point in the history
The following command will print a diff between HEAD and HEAD^:

    cargo run --package gen diff

type: development
  • Loading branch information
casey committed Apr 30, 2020
1 parent 3422668 commit 8dfdbe4
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 10 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions bin/gen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down
5 changes: 4 additions & 1 deletion bin/gen/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand All @@ -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;
Expand All @@ -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;
Expand Down
24 changes: 24 additions & 0 deletions bin/gen/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))]
Expand All @@ -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 {
Expand All @@ -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 }
}
}
109 changes: 100 additions & 9 deletions bin/gen/src/opt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand All @@ -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,
}
Expand Down Expand Up @@ -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…");
Expand Down Expand Up @@ -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…");
Expand Down

0 comments on commit 8dfdbe4

Please sign in to comment.