diff options
Diffstat (limited to 'extra/git2/examples/log.rs')
-rw-r--r-- | extra/git2/examples/log.rs | 310 |
1 files changed, 0 insertions, 310 deletions
diff --git a/extra/git2/examples/log.rs b/extra/git2/examples/log.rs deleted file mode 100644 index ad3bb354d..000000000 --- a/extra/git2/examples/log.rs +++ /dev/null @@ -1,310 +0,0 @@ -/* - * libgit2 "log" example - shows how to walk history and get commit info - * - * Written by the libgit2 contributors - * - * To the extent possible under law, the author(s) have dedicated all copyright - * and related and neighboring rights to this software to the public domain - * worldwide. This software is distributed without any warranty. - * - * You should have received a copy of the CC0 Public Domain Dedication along - * with this software. If not, see - * <http://creativecommons.org/publicdomain/zero/1.0/>. - */ - -#![deny(warnings)] - -use git2::{Commit, DiffOptions, ObjectType, Repository, Signature, Time}; -use git2::{DiffFormat, Error, Pathspec}; -use std::str; -use structopt::StructOpt; - -#[derive(StructOpt)] -struct Args { - #[structopt(name = "topo-order", long)] - /// sort commits in topological order - flag_topo_order: bool, - #[structopt(name = "date-order", long)] - /// sort commits in date order - flag_date_order: bool, - #[structopt(name = "reverse", long)] - /// sort commits in reverse - flag_reverse: bool, - #[structopt(name = "author", long)] - /// author to sort by - flag_author: Option<String>, - #[structopt(name = "committer", long)] - /// committer to sort by - flag_committer: Option<String>, - #[structopt(name = "pat", long = "grep")] - /// pattern to filter commit messages by - flag_grep: Option<String>, - #[structopt(name = "dir", long = "git-dir")] - /// alternative git directory to use - flag_git_dir: Option<String>, - #[structopt(name = "skip", long)] - /// number of commits to skip - flag_skip: Option<usize>, - #[structopt(name = "max-count", short = "n", long)] - /// maximum number of commits to show - flag_max_count: Option<usize>, - #[structopt(name = "merges", long)] - /// only show merge commits - flag_merges: bool, - #[structopt(name = "no-merges", long)] - /// don't show merge commits - flag_no_merges: bool, - #[structopt(name = "no-min-parents", long)] - /// don't require a minimum number of parents - flag_no_min_parents: bool, - #[structopt(name = "no-max-parents", long)] - /// don't require a maximum number of parents - flag_no_max_parents: bool, - #[structopt(name = "max-parents")] - /// specify a maximum number of parents for a commit - flag_max_parents: Option<usize>, - #[structopt(name = "min-parents")] - /// specify a minimum number of parents for a commit - flag_min_parents: Option<usize>, - #[structopt(name = "patch", long, short)] - /// show commit diff - flag_patch: bool, - #[structopt(name = "commit")] - arg_commit: Vec<String>, - #[structopt(name = "spec", last = true)] - arg_spec: Vec<String>, -} - -fn run(args: &Args) -> Result<(), Error> { - let path = args.flag_git_dir.as_ref().map(|s| &s[..]).unwrap_or("."); - let repo = Repository::open(path)?; - let mut revwalk = repo.revwalk()?; - - // Prepare the revwalk based on CLI parameters - let base = if args.flag_reverse { - git2::Sort::REVERSE - } else { - git2::Sort::NONE - }; - revwalk.set_sorting( - base | if args.flag_topo_order { - git2::Sort::TOPOLOGICAL - } else if args.flag_date_order { - git2::Sort::TIME - } else { - git2::Sort::NONE - }, - )?; - for commit in &args.arg_commit { - if commit.starts_with('^') { - let obj = repo.revparse_single(&commit[1..])?; - revwalk.hide(obj.id())?; - continue; - } - let revspec = repo.revparse(commit)?; - if revspec.mode().contains(git2::RevparseMode::SINGLE) { - revwalk.push(revspec.from().unwrap().id())?; - } else { - let from = revspec.from().unwrap().id(); - let to = revspec.to().unwrap().id(); - revwalk.push(to)?; - if revspec.mode().contains(git2::RevparseMode::MERGE_BASE) { - let base = repo.merge_base(from, to)?; - let o = repo.find_object(base, Some(ObjectType::Commit))?; - revwalk.push(o.id())?; - } - revwalk.hide(from)?; - } - } - if args.arg_commit.is_empty() { - revwalk.push_head()?; - } - - // Prepare our diff options and pathspec matcher - let (mut diffopts, mut diffopts2) = (DiffOptions::new(), DiffOptions::new()); - for spec in &args.arg_spec { - diffopts.pathspec(spec); - diffopts2.pathspec(spec); - } - let ps = Pathspec::new(args.arg_spec.iter())?; - - // Filter our revwalk based on the CLI parameters - macro_rules! filter_try { - ($e:expr) => { - match $e { - Ok(t) => t, - Err(e) => return Some(Err(e)), - } - }; - } - let revwalk = revwalk - .filter_map(|id| { - let id = filter_try!(id); - let commit = filter_try!(repo.find_commit(id)); - let parents = commit.parents().len(); - if parents < args.min_parents() { - return None; - } - if let Some(n) = args.max_parents() { - if parents >= n { - return None; - } - } - if !args.arg_spec.is_empty() { - match commit.parents().len() { - 0 => { - let tree = filter_try!(commit.tree()); - let flags = git2::PathspecFlags::NO_MATCH_ERROR; - if ps.match_tree(&tree, flags).is_err() { - return None; - } - } - _ => { - let m = commit.parents().all(|parent| { - match_with_parent(&repo, &commit, &parent, &mut diffopts) - .unwrap_or(false) - }); - if !m { - return None; - } - } - } - } - if !sig_matches(&commit.author(), &args.flag_author) { - return None; - } - if !sig_matches(&commit.committer(), &args.flag_committer) { - return None; - } - if !log_message_matches(commit.message(), &args.flag_grep) { - return None; - } - Some(Ok(commit)) - }) - .skip(args.flag_skip.unwrap_or(0)) - .take(args.flag_max_count.unwrap_or(!0)); - - // print! - for commit in revwalk { - let commit = commit?; - print_commit(&commit); - if !args.flag_patch || commit.parents().len() > 1 { - continue; - } - let a = if commit.parents().len() == 1 { - let parent = commit.parent(0)?; - Some(parent.tree()?) - } else { - None - }; - let b = commit.tree()?; - let diff = repo.diff_tree_to_tree(a.as_ref(), Some(&b), Some(&mut diffopts2))?; - diff.print(DiffFormat::Patch, |_delta, _hunk, line| { - match line.origin() { - ' ' | '+' | '-' => print!("{}", line.origin()), - _ => {} - } - print!("{}", str::from_utf8(line.content()).unwrap()); - true - })?; - } - - Ok(()) -} - -fn sig_matches(sig: &Signature, arg: &Option<String>) -> bool { - match *arg { - Some(ref s) => { - sig.name().map(|n| n.contains(s)).unwrap_or(false) - || sig.email().map(|n| n.contains(s)).unwrap_or(false) - } - None => true, - } -} - -fn log_message_matches(msg: Option<&str>, grep: &Option<String>) -> bool { - match (grep, msg) { - (&None, _) => true, - (&Some(_), None) => false, - (&Some(ref s), Some(msg)) => msg.contains(s), - } -} - -fn print_commit(commit: &Commit) { - println!("commit {}", commit.id()); - - if commit.parents().len() > 1 { - print!("Merge:"); - for id in commit.parent_ids() { - print!(" {:.8}", id); - } - println!(); - } - - let author = commit.author(); - println!("Author: {}", author); - print_time(&author.when(), "Date: "); - println!(); - - for line in String::from_utf8_lossy(commit.message_bytes()).lines() { - println!(" {}", line); - } - println!(); -} - -fn print_time(time: &Time, prefix: &str) { - let (offset, sign) = match time.offset_minutes() { - n if n < 0 => (-n, '-'), - n => (n, '+'), - }; - let (hours, minutes) = (offset / 60, offset % 60); - let ts = time::Timespec::new(time.seconds() + (time.offset_minutes() as i64) * 60, 0); - let time = time::at(ts); - - println!( - "{}{} {}{:02}{:02}", - prefix, - time.strftime("%a %b %e %T %Y").unwrap(), - sign, - hours, - minutes - ); -} - -fn match_with_parent( - repo: &Repository, - commit: &Commit, - parent: &Commit, - opts: &mut DiffOptions, -) -> Result<bool, Error> { - let a = parent.tree()?; - let b = commit.tree()?; - let diff = repo.diff_tree_to_tree(Some(&a), Some(&b), Some(opts))?; - Ok(diff.deltas().len() > 0) -} - -impl Args { - fn min_parents(&self) -> usize { - if self.flag_no_min_parents { - return 0; - } - self.flag_min_parents - .unwrap_or(if self.flag_merges { 2 } else { 0 }) - } - - fn max_parents(&self) -> Option<usize> { - if self.flag_no_max_parents { - return None; - } - self.flag_max_parents - .or(if self.flag_no_merges { Some(1) } else { None }) - } -} - -fn main() { - let args = Args::from_args(); - match run(&args) { - Ok(()) => {} - Err(e) => println!("error: {}", e), - } -} |