just playing with tangled
1// Copyright 2022 The Jujutsu Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::collections::HashSet;
16use std::path::Path;
17use std::path::PathBuf;
18use std::process::exit;
19
20use clap::Parser;
21use itertools::Itertools as _;
22
23/// A fake diff-editor, useful for testing
24#[derive(Parser, Debug)]
25#[clap()]
26struct Args {
27 /// Path to the "before" directory
28 before: PathBuf,
29
30 /// Path to the "after" directory
31 after: PathBuf,
32
33 /// Ignored argument
34 #[arg(long)]
35 _ignore: Vec<String>,
36}
37
38fn files_recursively(p: &Path) -> HashSet<String> {
39 let mut files = HashSet::new();
40 if !p.is_dir() {
41 files.insert(p.file_name().unwrap().to_str().unwrap().to_string());
42 } else {
43 for dir_entry in std::fs::read_dir(p).unwrap() {
44 let dir_entry = dir_entry.unwrap();
45 let base_name = dir_entry.file_name().to_str().unwrap().to_string();
46 if !dir_entry.path().is_dir() {
47 files.insert(base_name);
48 } else {
49 for sub_path in files_recursively(&dir_entry.path()) {
50 files.insert(format!("{base_name}/{sub_path}"));
51 }
52 }
53 }
54 }
55 files
56}
57
58fn main() {
59 let args: Args = Args::parse();
60 let edit_script_path = PathBuf::from(std::env::var_os("DIFF_EDIT_SCRIPT").unwrap());
61 let edit_script = String::from_utf8(std::fs::read(&edit_script_path).unwrap()).unwrap();
62 for instruction in edit_script.split('\0') {
63 let (command, payload) = instruction.split_once('\n').unwrap_or((instruction, ""));
64 let parts = command.split(' ').collect_vec();
65 match parts.as_slice() {
66 [""] => {}
67 ["fail"] => exit(1),
68 ["files-before", ..] => {
69 let expected = parts[1..].iter().copied().map(str::to_string).collect();
70 let actual = files_recursively(&args.before);
71 if actual != expected {
72 eprintln!(
73 "fake-diff-editor: unexpected files before. EXPECTED: {:?} ACTUAL: {:?}",
74 expected.iter().sorted().collect_vec(),
75 actual.iter().sorted().collect_vec(),
76 );
77 exit(1)
78 }
79 }
80 ["files-after", ..] => {
81 let expected = parts[1..].iter().copied().map(str::to_string).collect();
82 let actual = files_recursively(&args.after);
83 if actual != expected {
84 eprintln!(
85 "fake-diff-editor: unexpected files after. EXPECTED: {:?} ACTUAL: {:?}",
86 expected.iter().sorted().collect_vec(),
87 actual.iter().sorted().collect_vec(),
88 );
89 exit(1)
90 }
91 }
92 ["print", message] => {
93 println!("{message}");
94 }
95 ["print-files-before"] => {
96 for base_name in files_recursively(&args.before).iter().sorted() {
97 println!("{base_name}");
98 }
99 }
100 ["print-files-after"] => {
101 for base_name in files_recursively(&args.after).iter().sorted() {
102 println!("{base_name}");
103 }
104 }
105 ["rm", file] => {
106 std::fs::remove_file(args.after.join(file)).unwrap();
107 }
108 ["reset", file] => {
109 if args.before.join(file).exists() {
110 std::fs::copy(args.before.join(file), args.after.join(file)).unwrap();
111 } else {
112 std::fs::remove_file(args.after.join(file)).unwrap();
113 }
114 }
115 ["dump", file, dest] => {
116 let dest_path = edit_script_path.parent().unwrap().join(dest);
117 std::fs::copy(args.after.join(file), dest_path).unwrap();
118 }
119 ["write", file] => {
120 std::fs::write(args.after.join(file), payload).unwrap();
121 }
122 _ => {
123 eprintln!("fake-diff-editor: unexpected command: {command}");
124 exit(1)
125 }
126 }
127 }
128}