diesel_migration_test/
main.rs1use std::collections::BTreeMap;
5use std::fmt;
6
7use anyhow::Context;
8use camino::Utf8PathBuf;
9use clap::Parser;
10use console::{Style, style};
11use similar::{ChangeTag, TextDiff};
12
13#[derive(Parser, Debug)]
15#[command(version, about, long_about = None)]
16struct Args {
17 #[arg(long, env = "SCHEMA_PATH")]
18 schema_path: Utf8PathBuf,
19
20 #[arg(long, env = "SCHEMA_RESULT_PATH")]
21 schema_result_path: Utf8PathBuf,
22
23 #[arg(long, env = "SCHEMA_PATCH_PATH")]
24 schema_patch_path: Utf8PathBuf,
25
26 #[arg(long, env = "SCHEMA_PATCH_RESULT_PATH")]
27 schema_patch_result_path: Utf8PathBuf,
28}
29
30struct Line(Option<usize>);
31
32impl fmt::Display for Line {
33 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34 match self.0 {
35 None => write!(f, " "),
36 Some(idx) => write!(f, "{:<4}", idx + 1),
37 }
38 }
39}
40
41fn get_result(path: &std::path::Path) -> anyhow::Result<String> {
42 let result = std::fs::read_to_string(path).context("read results")?;
43 let result: BTreeMap<Utf8PathBuf, String> = serde_json::from_str(&result).context("parse results")?;
44 result.into_values().next().context("get result")
45}
46
47fn main() -> anyhow::Result<()> {
48 let args = Args::parse();
49
50 let runfiles = runfiles::Runfiles::create().expect("failed to create runfiles");
51 let schema_path = runfiles::rlocation!(&runfiles, &args.schema_path).expect("failed to get schema file");
52 let schema_result_path = runfiles::rlocation!(&runfiles, &args.schema_result_path).expect("failed to get result path");
53 let schema_patch_path =
54 runfiles::rlocation!(&runfiles, &args.schema_patch_path).expect("failed to get schema patch path");
55 let schema_patch_result_path =
56 runfiles::rlocation!(&runfiles, &args.schema_patch_result_path).expect("failed to get schema patch result path");
57
58 let schema = std::fs::read_to_string(&schema_path).context("read schema file")?;
59 let schema_patch = std::fs::read_to_string(&schema_patch_path).context("read schema patch file")?;
60 let schema_result = get_result(&schema_result_path)?;
61 let schema_patch_result = get_result(&schema_patch_result_path)?;
62
63 let mut diff_found = false;
64 if schema_result != schema {
65 println!("Difference found in {}", args.schema_path);
66 println!("{}", diff(&schema, &schema_result));
67 diff_found = true;
68 }
69 if schema_patch_result != schema_patch {
70 println!("Difference found in {}", args.schema_patch_path);
71 println!("{}", diff(&schema_patch, &schema_patch_result));
72 diff_found = true;
73 }
74
75 if diff_found {
76 std::process::exit(1)
77 }
78
79 Ok(())
80}
81
82pub(crate) fn diff(old: &str, new: &str) -> String {
83 use std::fmt::Write;
84
85 let diff = TextDiff::from_lines(old, new);
86 let mut output = String::new();
87
88 for (idx, group) in diff.grouped_ops(3).iter().enumerate() {
89 if idx > 0 {
90 writeln!(&mut output, "{0:─^1$}┼{0:─^2$}", "─", 9, 120).unwrap();
91 }
92 for op in group {
93 for change in diff.iter_inline_changes(op) {
94 let (sign, s) = match change.tag() {
95 ChangeTag::Delete => ("-", Style::new().red()),
96 ChangeTag::Insert => ("+", Style::new().green()),
97 ChangeTag::Equal => (" ", Style::new().dim()),
98 };
99 write!(
100 &mut output,
101 "{}{} │{}",
102 style(Line(change.old_index())).dim(),
103 style(Line(change.new_index())).dim(),
104 s.apply_to(sign).bold(),
105 )
106 .unwrap();
107 for (_, value) in change.iter_strings_lossy() {
108 write!(&mut output, "{}", s.apply_to(value)).unwrap();
109 }
110 if change.missing_newline() {
111 writeln!(&mut output).unwrap();
112 }
113 }
114 }
115 }
116
117 output
118}