diesel_migration_patcher/
main.rs1use std::collections::BTreeMap;
2use std::io::Write;
3use std::process::Stdio;
4
5use camino::Utf8PathBuf;
6use clap::Parser;
7
8#[derive(clap::Parser)]
9struct Args {
10 #[clap(long, env = "OUTPUT_FILE")]
11 output_file: Utf8PathBuf,
12
13 #[clap(long, env = "SCHEMA_FILE")]
14 schema_file: Utf8PathBuf,
15
16 #[clap(long, env = "TEMP_DIR")]
17 temp_dir: Utf8PathBuf,
18
19 #[clap(long, env = "SCHEMA_PATCH_FILE")]
20 schema_patch_file: Utf8PathBuf,
21
22 #[clap(long, env = "SCHEMA_FILE_RESULTS")]
23 schema_file_results: Utf8PathBuf,
24
25 #[clap(long, env = "PATCH_BINARY")]
26 patch_binary: Utf8PathBuf,
27
28 #[clap(long, env = "DIFF_BINARY")]
29 diff_binary: Utf8PathBuf,
30}
31
32fn main() {
33 let args = Args::parse();
34
35 env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
36
37 std::fs::create_dir_all(&args.temp_dir).expect("failed to create temp dir");
38
39 let results = std::fs::read_to_string(&args.schema_file_results).expect("failed to read results");
40 let results: BTreeMap<Utf8PathBuf, String> = serde_json::from_str(&results).expect("failed to parse results");
41 let unedited_file = results.get(&args.schema_file).expect("failed to get unedited file").clone();
42
43 let unedited = args.temp_dir.join("unedited.rs");
44
45 std::fs::write(&unedited, &unedited_file).expect("failed to write unedited file");
46
47 let reverse_patch = std::process::Command::new(args.patch_binary)
50 .arg("--follow-symlinks")
51 .arg("-R")
52 .arg("-i")
53 .arg(&args.schema_patch_file)
54 .arg("-o")
55 .arg("-")
56 .arg(&unedited)
57 .output()
58 .expect("failed to reverse patch");
59
60 if !reverse_patch.status.success() {
61 std::io::stderr()
62 .write_all(&reverse_patch.stderr)
63 .expect("failed to write stderr");
64 std::io::stderr()
65 .write_all(&reverse_patch.stdout)
66 .expect("failed to write stdout");
67 panic!("failed to reverse patch");
68 }
69
70 let reverse_patch_output = String::from_utf8(reverse_patch.stdout).expect("failed to read reverse patch output");
71
72 let mut diff = std::process::Command::new(args.diff_binary)
73 .arg("-u")
74 .arg(format!("--label=a/{}", args.schema_file))
75 .arg(format!("--label=b/{}", args.schema_file.with_extension("unpatched.rs")))
76 .arg("-")
77 .arg(&args.schema_file)
78 .stdin(Stdio::piped())
79 .stdout(Stdio::piped())
80 .stderr(Stdio::piped())
81 .spawn()
82 .expect("failed to generate diff");
83
84 let mut stdin = diff.stdin.take().unwrap();
85 std::thread::spawn(move || {
86 stdin
87 .write_all(reverse_patch_output.as_bytes())
88 .expect("failed to write stdin");
89 });
90
91 let output = diff.wait_with_output().expect("failed to wait for output");
92 if output.status.code().is_none_or(|c| c != 0 && c != 1) {
93 std::io::stderr().write_all(&output.stderr).expect("failed to write stderr");
94 std::io::stderr().write_all(&output.stdout).expect("failed to write stdout");
95 panic!("failed to generate diff");
96 }
97
98 let content = String::from_utf8(output.stdout).expect("failed to convert stdout to utf8");
99 let json = serde_json::to_string(&BTreeMap::from_iter([(args.schema_patch_file, content)]))
100 .expect("failed to serialize output");
101 std::fs::write(args.output_file, json).expect("failed to write diff");
102}