From 5abacce2f7d3788bad51fbecd72312a3c13a56e2 Mon Sep 17 00:00:00 2001 From: Daniil Demidko Date: Thu, 4 Apr 2024 15:39:21 +0600 Subject: [PATCH] production ready release --- Cargo.lock | 70 +++++++++++---------------------------------- Cargo.toml | 5 ++-- src/diff_printer.rs | 52 +++++++++++++++++++++++++++++++++ src/main.rs | 66 +++++++++++++++++++++++++----------------- 4 files changed, 110 insertions(+), 83 deletions(-) create mode 100644 src/diff_printer.rs diff --git a/Cargo.lock b/Cargo.lock index 7cfebd0..ccbba3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,22 +2,12 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - [[package]] name = "archdiff" -version = "2024.3.12" +version = "2024.4.4" dependencies = [ "git2", - "regex", - "similar", + "itertools", ] [[package]] @@ -36,6 +26,12 @@ dependencies = [ "libc", ] +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -70,6 +66,15 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "jobserver" version = "0.1.28" @@ -131,12 +136,6 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" -[[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - [[package]] name = "openssl-probe" version = "0.1.5" @@ -167,41 +166,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[package]] -name = "regex" -version = "1.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" - -[[package]] -name = "similar" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" - [[package]] name = "tinyvec" version = "1.6.0" diff --git a/Cargo.toml b/Cargo.toml index 030aa57..8ce77eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "archdiff" -version = "2024.3.12" +version = "2024.4.4" edition = "2021" [profile.release] @@ -9,5 +9,4 @@ panic = "abort" [dependencies] git2 = "0.18.3" -regex = "1.10.4" -similar = "2.5.0" +itertools = "0.12.1" diff --git a/src/diff_printer.rs b/src/diff_printer.rs new file mode 100644 index 0000000..0ccd3b1 --- /dev/null +++ b/src/diff_printer.rs @@ -0,0 +1,52 @@ +use std::str; + +pub struct DiffPrinter { + buf: String, + changes: bool, + was_real_print: bool, +} + +impl DiffPrinter { + pub fn new() -> Self { + Self { + buf: String::new(), + changes: false, + was_real_print: false, + } + } + + pub fn println(&mut self, diff: &str) { + if is_new_file(diff) { + self.flush() + } + if has_changes(diff) { + self.changes = true + } + self.buf += diff; + self.buf += "\n" + } + + pub fn flush(&mut self) { + if self.changes { + if self.was_real_print { + println!(); + } + println!("{}", self.buf.trim_end()); + self.was_real_print = true + } + self.changes = false; + self.buf.clear() + } +} + +fn has_changes(diff: &str) -> bool { + if is_new_file(diff) { + // мы не можем знать об изменениях в api по заголовку файла + return false; + } + diff.starts_with("+") || diff.starts_with("-") +} + +fn is_new_file(diff: &str) -> bool { + diff.starts_with("---") || diff.starts_with("+++") +} diff --git a/src/main.rs b/src/main.rs index 6dc7785..49afccc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,31 +1,34 @@ use std::env::args; -use std::fmt::Debug; -use std::ops::Not; use std::str; use DiffFormat::Patch; use DiffLineType::{AddEOFNL, Addition, Binary, Context, ContextEOFNL, DeleteEOFNL, Deletion, FileHeader, HunkHeader}; use git2::{Diff, DiffDelta, DiffFindOptions, DiffFormat, DiffHunk, DiffLine, DiffLineType, Object, ObjectType, Repository}; -use similar::DiffableStr; +use itertools::Itertools; + +use crate::diff_printer::DiffPrinter; + +mod diff_printer; fn main() { let help = "Usage: archdiff [OLD_BRANCH] [NEW_BRANCH]"; let old_branch = args().nth(1).expect(help); let new_branch = args().nth(2).expect(help); let repo = open_current_repo(); - diff_branches(&repo, &old_branch, &new_branch) - .print(Patch, print_diff_line) - .unwrap(); + let diff = diff_branches(&repo, &old_branch, &new_branch); + let mut printer = DiffPrinter::new(); + diff.print(Patch, |d, h, l| print_diff_line(d, h, l, &mut printer)).unwrap(); + printer.flush(); } -pub fn open_current_repo() -> Repository { +fn open_current_repo() -> Repository { match Repository::open(".") { Ok(repo) => repo, Err(e) => panic!("Failed to open repo: {}", e.message()) } } -pub fn diff_branches<'a>(repo: &'a Repository, old_branch: &str, new_branch: &str) -> Diff<'a> { +fn diff_branches<'a>(repo: &'a Repository, old_branch: &str, new_branch: &str) -> Diff<'a> { let old_obj = make_tree_object(repo, old_branch); let old_tree = old_obj.as_tree(); let new_obj = make_tree_object(repo, new_branch); @@ -40,7 +43,7 @@ pub fn diff_branches<'a>(repo: &'a Repository, old_branch: &str, new_branch: &st diff } -pub fn print_diff_line(delta: DiffDelta, _hunk: Option, line: DiffLine) -> bool { +fn print_diff_line(delta: DiffDelta, _hunk: Option, line: DiffLine, printer: &mut DiffPrinter) -> bool { let diff_type = line.origin_value(); if is_unsupported_file(&delta) { @@ -51,18 +54,17 @@ pub fn print_diff_line(delta: DiffDelta, _hunk: Option, line: DiffLine } let line = line.content(); - let line = str::from_utf8(line).unwrap(); + let line = str::from_utf8(line).unwrap().trim_end(); if diff_type == FileHeader { - print!("{}", line); - return true; - } - if diff_type == HunkHeader { - print!("{}", trim_hunk_header(line)); + printer.println(&trim_file_header(line)); return true; } if is_java_api(line) { - println!("{}{}", prefix(diff_type), trim_java_api(line)); + let prefix = prefix(diff_type); + let line = trim_java_api(line); + let line = format!("{}{}", prefix, line); + printer.println(&line) } true } @@ -76,15 +78,6 @@ fn prefix(diff: DiffLineType) -> char { } } -fn trim_hunk_header(line: &str) -> &str { - if line.starts_with("@@") { - let line = line.trim_start_matches("@@"); - let idx = line.find("@@").unwrap() + 2; - return &line[idx..]; - } - line -} - fn is_java_api(line: &str) -> bool { let line = line.trim_start(); if line.starts_with("public") { @@ -97,7 +90,25 @@ fn is_java_api(line: &str) -> bool { } fn trim_java_api(line: &str) -> &str { - line.trim_end_matches(" {\n") + line.trim_end() + .trim_end_matches("=") + .trim_end_matches("{") + .trim_end() +} + +fn trim_file_header(line: &str) -> String { + let lines = line.lines().collect_vec(); + let new_file = lines.len() - 1; + let old_file = new_file - 1; + let old_file = lines[old_file]; + let new_file = lines[new_file]; + if old_file.ends_with("/dev/null") { + return new_file.to_string(); + } + if new_file.ends_with("/dev/null") { + return old_file.to_string(); + } + format!("{}\n{}", old_file, new_file) } fn is_unsupported_file(delta: &DiffDelta) -> bool { @@ -116,6 +127,7 @@ fn is_unsupported_diff(diff: DiffLineType) -> bool { AddEOFNL => true, DeleteEOFNL => true, Binary => true, + HunkHeader => true, _ => false } } @@ -136,4 +148,4 @@ mod tests { let header = trim_hunk_header(&header); assert_eq!(header, " class Test {") } -} \ No newline at end of file +}