Skip to content

Commit 88bb1c4

Browse files
committed
wip!: blame + deletion based no-history derivation
1 parent 509bb33 commit 88bb1c4

3 files changed

Lines changed: 82 additions & 4 deletions

File tree

src/commands.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ pub mod diff;
33
pub mod init;
44
pub mod list;
55

6-
pub use derive::derive;
6+
pub use derive::{derive, derive_no_history};
77
pub use diff::diff;
88
pub use init::init;
99
pub use list::list;

src/commands/derive.rs

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
use anyhow::{Context, Result};
2-
use git2::{Diff, Index, IndexEntry, IndexTime, Oid, Repository, Signature, Sort, Tree};
2+
use git2::{
3+
BlameOptions, Diff, Index, IndexEntry, IndexTime, Oid, Repository, Signature, Sort, Status,
4+
Tree, TreeWalkResult,
5+
};
36
use regex::Regex;
7+
use std::fs::File;
8+
use std::io::{BufRead, BufReader};
49
use std::path::{Path, PathBuf};
510

611
use std::collections::{HashMap, HashSet};
@@ -263,6 +268,67 @@ pub fn derive(repo: &Repository, name: &str, features: &[String]) -> Result<()>
263268
Ok(())
264269
}
265270

271+
pub fn derive_no_history(repo: &Repository, name: &str, features: &[String]) -> Result<()> {
272+
let statuses = repo.statuses(None)?;
273+
for entry in statuses.iter() {
274+
let s = entry.status();
275+
if s != Status::CURRENT {
276+
println!("Repository is not clean!");
277+
return Ok(());
278+
}
279+
}
280+
281+
let target_features: HashSet<String> = features.iter().cloned().collect();
282+
let head = repo.head()?;
283+
let tree = head.peel_to_tree()?;
284+
285+
tree.walk(git2::TreeWalkMode::PreOrder, |root, entry| {
286+
if let Some(name) = entry.name() {
287+
let path = Path::new(root).join(name);
288+
}
289+
TreeWalkResult::Ok
290+
})?;
291+
Ok(())
292+
}
293+
294+
fn process_file(
295+
repo: &Repository,
296+
name: &PathBuf,
297+
target_features: &HashSet<String>,
298+
) -> Result<()> {
299+
let file = File::open(name)?;
300+
let reader = BufReader::new(file);
301+
let mut lines: Vec<String> = reader.lines().collect::<Result<_, _>>()?;
302+
303+
let mut commit_cache: HashMap<Oid, bool> = HashMap::new();
304+
305+
let mut blame_opts = BlameOptions::new();
306+
let blame = repo.blame_file(Path::new(name), Some(&mut blame_opts))?;
307+
308+
for (i, line) in lines.iter().enumerate() {
309+
let line_no = i + 1;
310+
311+
let hunk = blame
312+
.get_line(line_no)
313+
.context("Cant get line info in hunk")?;
314+
315+
let oid = hunk.final_commit_id();
316+
317+
commit_cache.entry(oid).or_insert_with(|| {
318+
let commit = repo.find_commit(oid).unwrap();
319+
let summary = commit.summary().unwrap();
320+
if let Some(feature) = extract_scope(summary)
321+
&& target_features.contains(feature)
322+
{
323+
return true;
324+
}
325+
false
326+
});
327+
}
328+
329+
Ok(())
330+
}
331+
266332
// TODO: building each time can be expensive. Look for an alternative
267333
fn extract_scope(commit: &str) -> Option<&str> {
268334
let re = Regex::new(r"^(?P<type>[a-z]+)(?:\((?P<scope>[^)]+)\))?(?P<breaking>!)?:").unwrap();

src/main.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ enum Commands {
2222
/// The set of features to use for the derivation
2323
#[arg(short, long = "feature", required = true)]
2424
features: Vec<String>,
25+
/// use the no-history derivation
26+
#[arg(long = "history")]
27+
history: bool,
2528
},
2629
/// List the commits exist in the target branch but not in the current branch
2730
Diff {
@@ -47,8 +50,17 @@ fn main() -> Result<()> {
4750
Commands::Init => {
4851
commands::init(&repo).context("Failed to initialize VMS support")?;
4952
}
50-
Commands::Derive { name, features } => {
51-
commands::derive(&repo, &name, &features).context("Failed to derive variant")?;
53+
Commands::Derive {
54+
name,
55+
features,
56+
history,
57+
} => {
58+
if history {
59+
commands::derive(&repo, &name, &features).context("Failed to derive variant")?;
60+
} else {
61+
commands::derive_no_history(&repo, &name, &features)
62+
.context("Failed to derive variant")?;
63+
}
5264
}
5365
Commands::Diff { target, reverse } => {
5466
commands::diff(&repo, &target, reverse).context(format!(

0 commit comments

Comments
 (0)