Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ http = "1.3.1"
byte-unit = "5.1.6"
color-backtrace = "0.7.0"
ignore = "0.4.23"
imara-diff = "0.1.8"
imara-diff = "0.2.0"
indicatif = "0.17.11"
infer = "0.19.0"
path-absolutize = "3.1.1"
Expand Down
10 changes: 5 additions & 5 deletions common/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
//! Configuration management for the Mono and Mega application
//! This module provides functionality to load, parse, and manage configuration settings

use std::rc::Rc;
use std::path::PathBuf;
use std::cell::RefCell;
use std::collections::HashMap;
use std::path::PathBuf;
use std::rc::Rc;

pub use config as c;
use c::{ConfigError, FileFormat};
pub use config as c;

use config::{Source, ValueKind};
use config::builder::DefaultState;
use config::{Source, ValueKind};
use serde::{Deserialize, Deserializer, Serialize};

use callisto::sea_orm_active_enums::StorageTypeEnum;
Expand Down Expand Up @@ -77,7 +77,7 @@ pub fn mega_cache() -> PathBuf {
.unwrap()
.to_string()
});

PathBuf::from(cache_dir)
}

Expand Down
7 changes: 5 additions & 2 deletions libra/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ serde_json = { workspace = true }
sha1 = { workspace = true }
similar = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "rt", "macros"] }
tokio-util = {workspace = true, features = ["io"] }
tokio-util = { workspace = true, features = ["io"] }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
wax = { workspace = true }
Expand All @@ -60,5 +60,8 @@ pager = { workspace = true }
tempfile = { workspace = true }
serial_test = { workspace = true }
tokio = { workspace = true, features = ["macros", "process"] }
testcontainers = { workspace = true, features = ["http_wait","reusable-containers"] }
testcontainers = { workspace = true, features = [
"http_wait",
"reusable-containers",
] }
reqwest = { workspace = true, features = ["blocking"] }
142 changes: 131 additions & 11 deletions libra/src/command/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{
};

use clap::Parser;
use imara_diff::{intern::InternedInput, Algorithm, UnifiedDiffBuilder};
use imara_diff::{Algorithm, BasicLineDiffPrinter, Diff, InternedInput, UnifiedDiffConfig};
use mercury::{
hash::SHA1,
internal::{
Expand Down Expand Up @@ -50,6 +50,11 @@ pub struct DiffArgs {
#[clap(help = "Files to compare")]
pathspec: Vec<String>,

/// choose the exact diff algorithm default value is histogram
/// support myers and myersMinimal
#[clap(long, default_value = "histogram", value_parser=["histogram", "myers", "myersMinimal"])]
pub algorithm: Option<String>,

// Print the result to file
#[clap(long, value_name = "FILENAME")]
pub output: Option<String>,
Expand Down Expand Up @@ -124,7 +129,14 @@ pub async fn execute(args: DiffArgs) {

let mut buf: Vec<u8> = Vec::new();
// filter files, cross old and new files, and pathspec
diff(old_blobs, new_blobs, paths.into_iter().collect(), &mut buf).await;
diff(
old_blobs,
new_blobs,
args.algorithm.unwrap_or_default(),
paths.into_iter().collect(),
&mut buf,
)
.await;

match w {
Some(ref mut file) => {
Expand Down Expand Up @@ -155,6 +167,7 @@ pub async fn execute(args: DiffArgs) {
pub async fn diff(
old_blobs: Vec<(PathBuf, SHA1)>,
new_blobs: Vec<(PathBuf, SHA1)>,
algorithm: String,
filter: Vec<PathBuf>,
w: &mut dyn io::Write,
) {
Expand Down Expand Up @@ -252,7 +265,7 @@ pub async fn diff(
};
writeln!(w, "--- {}", old_prefix).unwrap();
writeln!(w, "+++ {}", new_prefix).unwrap();
imara_diff_result(&old_text, &new_text, w);
imara_diff_result(&old_text, &new_text, algorithm.as_str(), w);
}
_ => {
// TODO: Handle non-UTF-8 data as binary for now; consider optimization in the future.
Expand Down Expand Up @@ -352,21 +365,39 @@ fn similar_diff_result(old: &str, new: &str, w: &mut dyn io::Write) {
}
}

fn imara_diff_result(old: &str, new: &str, w: &mut dyn io::Write) {
fn imara_diff_result(old: &str, new: &str, algorithm: &str, w: &mut dyn io::Write) {
let input = InternedInput::new(old, new);
let diff = imara_diff::diff(
Algorithm::Histogram,
&input,
UnifiedDiffBuilder::new(&input),
);
write!(w, "{}", diff).unwrap();

let algo = match algorithm {
"myers" => Algorithm::Myers,
"myersMinimal" => Algorithm::MyersMinimal,
// default is the histogram algo
_ => Algorithm::Histogram,
};
tracing::debug!("libra [diff]: choose the algorithm: {:?}", algo);

let mut diff = Diff::compute(algo, &input);

// did the postprocess_lines
diff.postprocess_lines(&input);

let result = diff
.unified_diff(
&BasicLineDiffPrinter(&input.interner),
UnifiedDiffConfig::default(),
&input,
)
.to_string();

write!(w, "{}", result).unwrap();
}

#[cfg(test)]
mod test {
use crate::utils::test;
use serial_test::serial;
use std::fs;
use std::time::Instant;
use tempfile::tempdir;

use super::*;
Expand All @@ -378,7 +409,6 @@ mod test {
let args = DiffArgs::try_parse_from(["diff", "--old", "old", "--new", "new", "paths"]);
assert!(args.is_ok());
let args = args.unwrap();
// println!("{:?}", args);
assert_eq!(args.old, Some("old".to_string()));
assert_eq!(args.new, Some("new".to_string()));
assert_eq!(args.pathspec, vec!["paths".to_string()]);
Expand Down Expand Up @@ -407,6 +437,26 @@ mod test {
assert!(args.is_err());
assert!(args.err().unwrap().kind() == clap::error::ErrorKind::MissingRequiredArgument);
}
{
// --algorithm arg
let args = DiffArgs::try_parse_from([
"diff",
"--old",
"old",
"--new",
"new",
"--algorithm",
"myers",
"target paths",
])
.unwrap();
assert_eq!(args.algorithm, Some("myers".to_string()));
}
{
// --algorithm arg with default value
let args = DiffArgs::try_parse_from(["diff", "--old", "old", "target paths"]).unwrap();
assert_eq!(args.algorithm, Some("histogram".to_string()));
}
}

#[test]
Expand Down Expand Up @@ -440,4 +490,74 @@ mod test {
assert_eq!(blob.len(), 1);
assert_eq!(blob[0].0, PathBuf::from("not_ignore"));
}

#[test]
fn test_diff_algorithms_correctness_and_efficiency() {
let old = r#"function foo() {
if (condition) {
doSomething();
doSomethingElse();
andAnotherThing();
} else {
alternative();
}
}"#;

let new = r#"function foo() {
if (condition) {
// Added comment
doSomething();
// Modified this line
modifiedSomethingElse();
andAnotherThing();
} else {
alternative();
}

// Added new block
addedNewFunctionality();
}"#;
let mut outputs = Vec::new();

let algos = ["histogram", "myers", "myersMinimal"];

// test the different algo benchmark
for algo in algos {
let mut buf = Vec::new();
let start = Instant::now();
imara_diff_result(old, new, algo, &mut buf);
let elapse = start.elapsed();
let ouput = String::from_utf8(buf).expect("Invalid UTF-8 in diff ouput");

println!("libra diff algorithm: {:?} Spend Time: {:?}", algo, elapse);
assert!(
!ouput.is_empty(),
"libra diff algorithm: {} produce a empty output",
algo
);
assert!(
ouput.contains("@@"),
"libra diff algorithm: {}, ouput missing diff markers",
algo
);

outputs.push((algo, ouput));
}

// check the line counter difference
for (algo, output) in outputs {
let plus_line = output.lines().filter(|line| line.starts_with("+")).count();
let minus_line = output.lines().filter(|line| line.starts_with("-")).count();
assert_eq!(
plus_line, 6,
"libra diff algorithm {}, expect plus_line: 6, got {} ",
algo, plus_line
);
assert_eq!(
minus_line, 1,
"libra diff algorithm {}, expect minus_line: 1, got {} ",
algo, minus_line
);
}
}
}
Loading