summaryrefslogtreecommitdiffstats
path: root/vendor/git2/examples/blame.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/git2/examples/blame.rs')
-rw-r--r--vendor/git2/examples/blame.rs104
1 files changed, 104 insertions, 0 deletions
diff --git a/vendor/git2/examples/blame.rs b/vendor/git2/examples/blame.rs
new file mode 100644
index 0000000..7cb1b69
--- /dev/null
+++ b/vendor/git2/examples/blame.rs
@@ -0,0 +1,104 @@
+/*
+ * libgit2 "blame" example - shows how to use the blame API
+ *
+ * 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::{BlameOptions, Repository};
+use std::io::{BufRead, BufReader};
+use std::path::Path;
+use structopt::StructOpt;
+
+#[derive(StructOpt)]
+#[allow(non_snake_case)]
+struct Args {
+ #[structopt(name = "path")]
+ arg_path: String,
+ #[structopt(name = "spec")]
+ arg_spec: Option<String>,
+ #[structopt(short = "M")]
+ /// find line moves within and across files
+ flag_M: bool,
+ #[structopt(short = "C")]
+ /// find line copies within and across files
+ flag_C: bool,
+ #[structopt(short = "F")]
+ /// follow only the first parent commits
+ flag_F: bool,
+}
+
+fn run(args: &Args) -> Result<(), git2::Error> {
+ let repo = Repository::open(".")?;
+ let path = Path::new(&args.arg_path[..]);
+
+ // Prepare our blame options
+ let mut opts = BlameOptions::new();
+ opts.track_copies_same_commit_moves(args.flag_M)
+ .track_copies_same_commit_copies(args.flag_C)
+ .first_parent(args.flag_F);
+
+ let mut commit_id = "HEAD".to_string();
+
+ // Parse spec
+ if let Some(spec) = args.arg_spec.as_ref() {
+ let revspec = repo.revparse(spec)?;
+
+ let (oldest, newest) = if revspec.mode().contains(git2::RevparseMode::SINGLE) {
+ (None, revspec.from())
+ } else if revspec.mode().contains(git2::RevparseMode::RANGE) {
+ (revspec.from(), revspec.to())
+ } else {
+ (None, None)
+ };
+
+ if let Some(commit) = oldest {
+ opts.oldest_commit(commit.id());
+ }
+
+ if let Some(commit) = newest {
+ opts.newest_commit(commit.id());
+ if !commit.id().is_zero() {
+ commit_id = format!("{}", commit.id())
+ }
+ }
+ }
+
+ let spec = format!("{}:{}", commit_id, path.display());
+ let blame = repo.blame_file(path, Some(&mut opts))?;
+ let object = repo.revparse_single(&spec[..])?;
+ let blob = repo.find_blob(object.id())?;
+ let reader = BufReader::new(blob.content());
+
+ for (i, line) in reader.lines().enumerate() {
+ if let (Ok(line), Some(hunk)) = (line, blame.get_line(i + 1)) {
+ let sig = hunk.final_signature();
+ println!(
+ "{} {} <{}> {}",
+ hunk.final_commit_id(),
+ String::from_utf8_lossy(sig.name_bytes()),
+ String::from_utf8_lossy(sig.email_bytes()),
+ line
+ );
+ }
+ }
+
+ Ok(())
+}
+
+fn main() {
+ let args = Args::from_args();
+ match run(&args) {
+ Ok(()) => {}
+ Err(e) => println!("error: {}", e),
+ }
+}