summaryrefslogtreecommitdiffstats
path: root/extra/git2/examples/log.rs
diff options
context:
space:
mode:
Diffstat (limited to 'extra/git2/examples/log.rs')
-rw-r--r--extra/git2/examples/log.rs310
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),
- }
-}