Skip to content

Commit ea9376a

Browse files
committed
Add ed-formatted diff
1 parent 582259a commit ea9376a

File tree

15 files changed

+521
-30
lines changed

15 files changed

+521
-30
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/target
22
/lib/normal-diff/target
3+
/lib/ed-diff/target
34
/lib/context-diff/target
45
/lib/unified-diff/target
56
Cargo.lock

Cargo.toml

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,6 @@ members = [
33
"lib/unified-diff",
44
"lib/context-diff",
55
"lib/normal-diff",
6-
"bin/diff",
6+
"lib/ed-diff",
7+
"bin/diffutils",
78
]
8-
9-
[package]
10-
name = "diffutils"
11-
version = "0.3.0"
12-
authors = ["Michael Howell <[email protected]>"]
13-
edition = "2018"
14-
15-
[dependencies]
16-
context-diff = { path = "lib/context-diff", version = "0.3.0" }
17-
normal-diff = { path = "lib/normal-diff", version = "0.3.0" }
18-
unified-diff = { path = "lib/unified-diff", version = "0.3.0" }
19-
20-
[[bin]]
21-
name = "diffutils"
22-
path = "bin/main.rs"

bin/diffutils/Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "diffutils"
3+
version = "0.3.0"
4+
edition = "2018"
5+
description = "A CLI app for generating diff files"
6+
license = "MIT OR Apache-2.0"
7+
repository = "https://github.com/notriddle/diffutils"
8+
9+
[[bin]]
10+
name = "diffutils"
11+
path = "main.rs"
12+
13+
[dependencies]
14+
unified-diff = { path = "../../lib/unified-diff/" }
15+
context-diff = { path = "../../lib/context-diff/" }
16+
normal-diff = { path = "../../lib/normal-diff/" }
17+
ed-diff = { path = "../../lib/ed-diff/" }
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ fn main() -> Result<(), String> {
4444
&to.to_string_lossy(),
4545
context_count,
4646
),
47+
Format::Ed => ed_diff::diff(
48+
&from_content,
49+
&to_content,
50+
)?,
4751
};
4852
io::stdout().write_all(&result).unwrap();
4953
Ok(())
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub enum Format {
55
Normal,
66
Unified,
77
Context,
8+
Ed,
89
}
910

1011
#[cfg(unix)]
@@ -73,6 +74,12 @@ pub fn parse_params<I: IntoIterator<Item = OsString>>(opts: I) -> Result<Params,
7374
}
7475
format = Some(Format::Context);
7576
}
77+
b'e' => {
78+
if format.is_some() && format != Some(Format::Ed) {
79+
return Err(format!("Conflicting output style options"));
80+
}
81+
format = Some(Format::Ed);
82+
}
7683
b'u' => {
7784
if format.is_some() && format != Some(Format::Unified) {
7885
return Err(format!("Conflicting output style options"));
@@ -151,6 +158,18 @@ mod tests {
151158
);
152159
}
153160
#[test]
161+
fn basics_ed() {
162+
assert_eq!(
163+
Ok(Params {
164+
from: os("foo"),
165+
to: os("bar"),
166+
format: Format::Ed,
167+
context_count: 3,
168+
}),
169+
parse_params([os("diff"), os("-e"), os("foo"), os("bar")].iter().cloned())
170+
);
171+
}
172+
#[test]
154173
fn context_count() {
155174
assert_eq!(
156175
Ok(Params {

lib/context-diff/Cargo.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
[package]
22
name = "context-diff"
33
version = "0.3.0"
4-
authors = [
5-
"Michael Howell <[email protected]>",
6-
"The Rust Project Developers"
7-
]
84
edition = "2018"
95
description = "An implementation of the GNU unified diff format"
106
license = "MIT OR Apache-2.0"

lib/ed-diff/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "ed-diff"
3+
version = "0.3.0"
4+
edition = "2018"
5+
description = "An implementation of the GNU unified diff format"
6+
license = "MIT OR Apache-2.0"
7+
repository = "https://github.com/notriddle/diffutils"
8+
exclude = [ "fuzz" ]
9+
10+
[dependencies]
11+
diff = "0.1.10"

lib/ed-diff/fuzz/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
target
3+
corpus
4+
artifacts

lib/ed-diff/fuzz/Cargo.toml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
[package]
3+
name = "ed-diff-fuzz"
4+
version = "0.0.0"
5+
publish = false
6+
edition = "2018"
7+
8+
[package.metadata]
9+
cargo-fuzz = true
10+
11+
[dependencies]
12+
libfuzzer-sys = "0.3"
13+
14+
[dependencies.ed-diff]
15+
path = ".."
16+
17+
# Prevent this from interfering with workspaces
18+
[workspace]
19+
members = ["."]
20+
21+
[[bin]]
22+
name = "fuzz_ed"
23+
path = "fuzz_targets/fuzz_ed.rs"
24+
test = false
25+
doc = false
26+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#![no_main]
2+
#[macro_use] extern crate libfuzzer_sys;
3+
extern crate ed_diff;
4+
5+
use std::fs::{self, File};
6+
use std::io::Write;
7+
use std::process::Command;
8+
9+
fuzz_target!(|x: (Vec<u8>, Vec<u8>)| {
10+
let (mut from, mut to) = x;
11+
from.push(b'\n');
12+
to.push(b'\n');
13+
if let Ok(s) = String::from_utf8(from.clone()) {
14+
if !s.is_ascii() { return }
15+
if s.find(|x| x < ' ' && x != '\n').is_some() { return }
16+
} else {
17+
return
18+
}
19+
if let Ok(s) = String::from_utf8(to.clone()) {
20+
if !s.is_ascii() { return }
21+
if s.find(|x| x < ' ' && x != '\n').is_some() { return }
22+
} else {
23+
return
24+
}
25+
let diff = ed_diff::diff_w(&from, &to, "target/fuzz.file").unwrap();
26+
File::create("target/fuzz.file.original")
27+
.unwrap()
28+
.write_all(&from)
29+
.unwrap();
30+
File::create("target/fuzz.file.expected")
31+
.unwrap()
32+
.write_all(&to)
33+
.unwrap();
34+
File::create("target/fuzz.file")
35+
.unwrap()
36+
.write_all(&from)
37+
.unwrap();
38+
File::create("target/fuzz.ed")
39+
.unwrap()
40+
.write_all(&diff)
41+
.unwrap();
42+
let output = Command::new("ed")
43+
.arg("target/fuzz.file")
44+
.stdin(File::open("target/fuzz.ed").unwrap())
45+
.output()
46+
.unwrap();
47+
if !output.status.success() {
48+
panic!("STDOUT:\n{}\nSTDERR:\n{}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr));
49+
}
50+
let result = fs::read("target/fuzz.file").unwrap();
51+
if result != to {
52+
panic!("STDOUT:\n{}\nSTDERR:\n{}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr));
53+
}
54+
});
55+

0 commit comments

Comments
 (0)