summaryrefslogtreecommitdiffstats
path: root/vendor/git2/examples
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/git2/examples')
-rw-r--r--vendor/git2/examples/add.rs81
-rw-r--r--vendor/git2/examples/blame.rs104
-rw-r--r--vendor/git2/examples/cat-file.rs149
-rw-r--r--vendor/git2/examples/clone.rs126
-rw-r--r--vendor/git2/examples/diff.rs368
-rw-r--r--vendor/git2/examples/fetch.rs127
-rw-r--r--vendor/git2/examples/init.rs145
-rw-r--r--vendor/git2/examples/log.rs310
-rw-r--r--vendor/git2/examples/ls-remote.rs51
-rw-r--r--vendor/git2/examples/pull.rs208
-rw-r--r--vendor/git2/examples/rev-list.rs105
-rw-r--r--vendor/git2/examples/rev-parse.rs60
-rw-r--r--vendor/git2/examples/status.rs441
-rw-r--r--vendor/git2/examples/tag.rs127
14 files changed, 2402 insertions, 0 deletions
diff --git a/vendor/git2/examples/add.rs b/vendor/git2/examples/add.rs
new file mode 100644
index 0000000..25e972c
--- /dev/null
+++ b/vendor/git2/examples/add.rs
@@ -0,0 +1,81 @@
+/*
+ * libgit2 "add" example - shows how to modify the index
+ *
+ * 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)]
+#![allow(trivial_casts)]
+
+use git2::Repository;
+use std::path::Path;
+use structopt::StructOpt;
+
+#[derive(StructOpt)]
+struct Args {
+ #[structopt(name = "spec")]
+ arg_spec: Vec<String>,
+ #[structopt(name = "dry_run", short = "n", long)]
+ /// dry run
+ flag_dry_run: bool,
+ #[structopt(name = "verbose", short, long)]
+ /// be verbose
+ flag_verbose: bool,
+ #[structopt(name = "update", short, long)]
+ /// update tracked files
+ flag_update: bool,
+}
+
+fn run(args: &Args) -> Result<(), git2::Error> {
+ let repo = Repository::open(&Path::new("."))?;
+ let mut index = repo.index()?;
+
+ let cb = &mut |path: &Path, _matched_spec: &[u8]| -> i32 {
+ let status = repo.status_file(path).unwrap();
+
+ let ret = if status.contains(git2::Status::WT_MODIFIED)
+ || status.contains(git2::Status::WT_NEW)
+ {
+ println!("add '{}'", path.display());
+ 0
+ } else {
+ 1
+ };
+
+ if args.flag_dry_run {
+ 1
+ } else {
+ ret
+ }
+ };
+ let cb = if args.flag_verbose || args.flag_update {
+ Some(cb as &mut git2::IndexMatchedPath)
+ } else {
+ None
+ };
+
+ if args.flag_update {
+ index.update_all(args.arg_spec.iter(), cb)?;
+ } else {
+ index.add_all(args.arg_spec.iter(), git2::IndexAddOption::DEFAULT, cb)?;
+ }
+
+ index.write()?;
+ Ok(())
+}
+
+fn main() {
+ let args = Args::from_args();
+ match run(&args) {
+ Ok(()) => {}
+ Err(e) => println!("error: {}", e),
+ }
+}
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),
+ }
+}
diff --git a/vendor/git2/examples/cat-file.rs b/vendor/git2/examples/cat-file.rs
new file mode 100644
index 0000000..0ce21b3
--- /dev/null
+++ b/vendor/git2/examples/cat-file.rs
@@ -0,0 +1,149 @@
+/*
+ * libgit2 "cat-file" example - shows how to print data from the ODB
+ *
+ * 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 std::io::{self, Write};
+
+use git2::{Blob, Commit, ObjectType, Repository, Signature, Tag, Tree};
+use structopt::StructOpt;
+
+#[derive(StructOpt)]
+struct Args {
+ #[structopt(name = "object")]
+ arg_object: String,
+ #[structopt(short = "t")]
+ /// show the object type
+ flag_t: bool,
+ #[structopt(short = "s")]
+ /// show the object size
+ flag_s: bool,
+ #[structopt(short = "e")]
+ /// suppress all output
+ flag_e: bool,
+ #[structopt(short = "p")]
+ /// pretty print the contents of the object
+ flag_p: bool,
+ #[structopt(name = "quiet", short, long)]
+ /// suppress output
+ flag_q: bool,
+ #[structopt(name = "verbose", short, long)]
+ flag_v: bool,
+ #[structopt(name = "dir", long = "git-dir")]
+ /// use the specified directory as the base directory
+ flag_git_dir: Option<String>,
+}
+
+fn run(args: &Args) -> Result<(), git2::Error> {
+ let path = args.flag_git_dir.as_ref().map(|s| &s[..]).unwrap_or(".");
+ let repo = Repository::open(path)?;
+
+ let obj = repo.revparse_single(&args.arg_object)?;
+ if args.flag_v && !args.flag_q {
+ println!("{} {}\n--", obj.kind().unwrap().str(), obj.id());
+ }
+
+ if args.flag_t {
+ println!("{}", obj.kind().unwrap().str());
+ } else if args.flag_s || args.flag_e {
+ /* ... */
+ } else if args.flag_p {
+ match obj.kind() {
+ Some(ObjectType::Blob) => {
+ show_blob(obj.as_blob().unwrap());
+ }
+ Some(ObjectType::Commit) => {
+ show_commit(obj.as_commit().unwrap());
+ }
+ Some(ObjectType::Tag) => {
+ show_tag(obj.as_tag().unwrap());
+ }
+ Some(ObjectType::Tree) => {
+ show_tree(obj.as_tree().unwrap());
+ }
+ Some(ObjectType::Any) | None => println!("unknown {}", obj.id()),
+ }
+ }
+ Ok(())
+}
+
+fn show_blob(blob: &Blob) {
+ io::stdout().write_all(blob.content()).unwrap();
+}
+
+fn show_commit(commit: &Commit) {
+ println!("tree {}", commit.tree_id());
+ for parent in commit.parent_ids() {
+ println!("parent {}", parent);
+ }
+ show_sig("author", Some(commit.author()));
+ show_sig("committer", Some(commit.committer()));
+ if let Some(msg) = commit.message() {
+ println!("\n{}", msg);
+ }
+}
+
+fn show_tag(tag: &Tag) {
+ println!("object {}", tag.target_id());
+ println!("type {}", tag.target_type().unwrap().str());
+ println!("tag {}", tag.name().unwrap());
+ show_sig("tagger", tag.tagger());
+
+ if let Some(msg) = tag.message() {
+ println!("\n{}", msg);
+ }
+}
+
+fn show_tree(tree: &Tree) {
+ for entry in tree.iter() {
+ println!(
+ "{:06o} {} {}\t{}",
+ entry.filemode(),
+ entry.kind().unwrap().str(),
+ entry.id(),
+ entry.name().unwrap()
+ );
+ }
+}
+
+fn show_sig(header: &str, sig: Option<Signature>) {
+ let sig = match sig {
+ Some(s) => s,
+ None => return,
+ };
+ let offset = sig.when().offset_minutes();
+ let (sign, offset) = if offset < 0 {
+ ('-', -offset)
+ } else {
+ ('+', offset)
+ };
+ let (hours, minutes) = (offset / 60, offset % 60);
+ println!(
+ "{} {} {} {}{:02}{:02}",
+ header,
+ sig,
+ sig.when().seconds(),
+ sign,
+ hours,
+ minutes
+ );
+}
+
+fn main() {
+ let args = Args::from_args();
+ match run(&args) {
+ Ok(()) => {}
+ Err(e) => println!("error: {}", e),
+ }
+}
diff --git a/vendor/git2/examples/clone.rs b/vendor/git2/examples/clone.rs
new file mode 100644
index 0000000..5af7322
--- /dev/null
+++ b/vendor/git2/examples/clone.rs
@@ -0,0 +1,126 @@
+/*
+ * libgit2 "clone" example
+ *
+ * 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::build::{CheckoutBuilder, RepoBuilder};
+use git2::{FetchOptions, Progress, RemoteCallbacks};
+use std::cell::RefCell;
+use std::io::{self, Write};
+use std::path::{Path, PathBuf};
+use structopt::StructOpt;
+
+#[derive(StructOpt)]
+struct Args {
+ #[structopt(name = "url")]
+ arg_url: String,
+ #[structopt(name = "path")]
+ arg_path: String,
+}
+
+struct State {
+ progress: Option<Progress<'static>>,
+ total: usize,
+ current: usize,
+ path: Option<PathBuf>,
+ newline: bool,
+}
+
+fn print(state: &mut State) {
+ let stats = state.progress.as_ref().unwrap();
+ let network_pct = (100 * stats.received_objects()) / stats.total_objects();
+ let index_pct = (100 * stats.indexed_objects()) / stats.total_objects();
+ let co_pct = if state.total > 0 {
+ (100 * state.current) / state.total
+ } else {
+ 0
+ };
+ let kbytes = stats.received_bytes() / 1024;
+ if stats.received_objects() == stats.total_objects() {
+ if !state.newline {
+ println!();
+ state.newline = true;
+ }
+ print!(
+ "Resolving deltas {}/{}\r",
+ stats.indexed_deltas(),
+ stats.total_deltas()
+ );
+ } else {
+ print!(
+ "net {:3}% ({:4} kb, {:5}/{:5}) / idx {:3}% ({:5}/{:5}) \
+ / chk {:3}% ({:4}/{:4}) {}\r",
+ network_pct,
+ kbytes,
+ stats.received_objects(),
+ stats.total_objects(),
+ index_pct,
+ stats.indexed_objects(),
+ stats.total_objects(),
+ co_pct,
+ state.current,
+ state.total,
+ state
+ .path
+ .as_ref()
+ .map(|s| s.to_string_lossy().into_owned())
+ .unwrap_or_default()
+ )
+ }
+ io::stdout().flush().unwrap();
+}
+
+fn run(args: &Args) -> Result<(), git2::Error> {
+ let state = RefCell::new(State {
+ progress: None,
+ total: 0,
+ current: 0,
+ path: None,
+ newline: false,
+ });
+ let mut cb = RemoteCallbacks::new();
+ cb.transfer_progress(|stats| {
+ let mut state = state.borrow_mut();
+ state.progress = Some(stats.to_owned());
+ print(&mut *state);
+ true
+ });
+
+ let mut co = CheckoutBuilder::new();
+ co.progress(|path, cur, total| {
+ let mut state = state.borrow_mut();
+ state.path = path.map(|p| p.to_path_buf());
+ state.current = cur;
+ state.total = total;
+ print(&mut *state);
+ });
+
+ let mut fo = FetchOptions::new();
+ fo.remote_callbacks(cb);
+ RepoBuilder::new()
+ .fetch_options(fo)
+ .with_checkout(co)
+ .clone(&args.arg_url, Path::new(&args.arg_path))?;
+ println!();
+
+ Ok(())
+}
+
+fn main() {
+ let args = Args::from_args();
+ match run(&args) {
+ Ok(()) => {}
+ Err(e) => println!("error: {}", e),
+ }
+}
diff --git a/vendor/git2/examples/diff.rs b/vendor/git2/examples/diff.rs
new file mode 100644
index 0000000..62f165d
--- /dev/null
+++ b/vendor/git2/examples/diff.rs
@@ -0,0 +1,368 @@
+/*
+ * libgit2 "diff" example - shows how to use the diff 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::{Blob, Diff, DiffOptions, Error, Object, ObjectType, Oid, Repository};
+use git2::{DiffDelta, DiffFindOptions, DiffFormat, DiffHunk, DiffLine};
+use std::str;
+use structopt::StructOpt;
+
+#[derive(StructOpt)]
+#[allow(non_snake_case)]
+struct Args {
+ #[structopt(name = "from_oid")]
+ arg_from_oid: Option<String>,
+ #[structopt(name = "to_oid")]
+ arg_to_oid: Option<String>,
+ #[structopt(name = "blobs", long)]
+ /// treat from_oid and to_oid as blob ids
+ flag_blobs: bool,
+ #[structopt(name = "patch", short, long)]
+ /// show output in patch format
+ flag_patch: bool,
+ #[structopt(name = "cached", long)]
+ /// use staged changes as diff
+ flag_cached: bool,
+ #[structopt(name = "nocached", long)]
+ /// do not use staged changes
+ flag_nocached: bool,
+ #[structopt(name = "name-only", long)]
+ /// show only names of changed files
+ flag_name_only: bool,
+ #[structopt(name = "name-status", long)]
+ /// show only names and status changes
+ flag_name_status: bool,
+ #[structopt(name = "raw", long)]
+ /// generate the raw format
+ flag_raw: bool,
+ #[structopt(name = "format", long)]
+ /// specify format for stat summary
+ flag_format: Option<String>,
+ #[structopt(name = "color", long)]
+ /// use color output
+ flag_color: bool,
+ #[structopt(name = "no-color", long)]
+ /// never use color output
+ flag_no_color: bool,
+ #[structopt(short = "R")]
+ /// swap two inputs
+ flag_R: bool,
+ #[structopt(name = "text", short = "a", long)]
+ /// treat all files as text
+ flag_text: bool,
+ #[structopt(name = "ignore-space-at-eol", long)]
+ /// ignore changes in whitespace at EOL
+ flag_ignore_space_at_eol: bool,
+ #[structopt(name = "ignore-space-change", short = "b", long)]
+ /// ignore changes in amount of whitespace
+ flag_ignore_space_change: bool,
+ #[structopt(name = "ignore-all-space", short = "w", long)]
+ /// ignore whitespace when comparing lines
+ flag_ignore_all_space: bool,
+ #[structopt(name = "ignored", long)]
+ /// show untracked files
+ flag_ignored: bool,
+ #[structopt(name = "untracked", long)]
+ /// generate diff using the patience algorithm
+ flag_untracked: bool,
+ #[structopt(name = "patience", long)]
+ /// show ignored files as well
+ flag_patience: bool,
+ #[structopt(name = "minimal", long)]
+ /// spend extra time to find smallest diff
+ flag_minimal: bool,
+ #[structopt(name = "stat", long)]
+ /// generate a diffstat
+ flag_stat: bool,
+ #[structopt(name = "numstat", long)]
+ /// similar to --stat, but more machine friendly
+ flag_numstat: bool,
+ #[structopt(name = "shortstat", long)]
+ /// only output last line of --stat
+ flag_shortstat: bool,
+ #[structopt(name = "summary", long)]
+ /// output condensed summary of header info
+ flag_summary: bool,
+ #[structopt(name = "find-renames", short = "M", long)]
+ /// set threshold for finding renames (default 50)
+ flag_find_renames: Option<u16>,
+ #[structopt(name = "find-copies", short = "C", long)]
+ /// set threshold for finding copies (default 50)
+ flag_find_copies: Option<u16>,
+ #[structopt(name = "find-copies-harder", long)]
+ /// inspect unmodified files for sources of copies
+ flag_find_copies_harder: bool,
+ #[structopt(name = "break_rewrites", short = "B", long)]
+ /// break complete rewrite changes into pairs
+ flag_break_rewrites: bool,
+ #[structopt(name = "unified", short = "U", long)]
+ /// lints of context to show
+ flag_unified: Option<u32>,
+ #[structopt(name = "inter-hunk-context", long)]
+ /// maximum lines of change between hunks
+ flag_inter_hunk_context: Option<u32>,
+ #[structopt(name = "abbrev", long)]
+ /// length to abbreviate commits to
+ flag_abbrev: Option<u16>,
+ #[structopt(name = "src-prefix", long)]
+ /// show given source prefix instead of 'a/'
+ flag_src_prefix: Option<String>,
+ #[structopt(name = "dst-prefix", long)]
+ /// show given destination prefix instead of 'b/'
+ flag_dst_prefix: Option<String>,
+ #[structopt(name = "path", long = "git-dir")]
+ /// path to git repository to use
+ flag_git_dir: Option<String>,
+}
+
+const RESET: &str = "\u{1b}[m";
+const BOLD: &str = "\u{1b}[1m";
+const RED: &str = "\u{1b}[31m";
+const GREEN: &str = "\u{1b}[32m";
+const CYAN: &str = "\u{1b}[36m";
+
+#[derive(PartialEq, Eq, Copy, Clone)]
+enum Cache {
+ Normal,
+ Only,
+ None,
+}
+
+fn line_color(line: &DiffLine) -> Option<&'static str> {
+ match line.origin() {
+ '+' => Some(GREEN),
+ '-' => Some(RED),
+ '>' => Some(GREEN),
+ '<' => Some(RED),
+ 'F' => Some(BOLD),
+ 'H' => Some(CYAN),
+ _ => None,
+ }
+}
+
+fn print_diff_line(
+ _delta: DiffDelta,
+ _hunk: Option<DiffHunk>,
+ line: DiffLine,
+ args: &Args,
+) -> bool {
+ if args.color() {
+ print!("{}", RESET);
+ if let Some(color) = line_color(&line) {
+ print!("{}", color);
+ }
+ }
+ match line.origin() {
+ '+' | '-' | ' ' => print!("{}", line.origin()),
+ _ => {}
+ }
+ print!("{}", str::from_utf8(line.content()).unwrap());
+ true
+}
+
+fn run(args: &Args) -> Result<(), Error> {
+ let path = args.flag_git_dir.as_ref().map(|s| &s[..]).unwrap_or(".");
+ let repo = Repository::open(path)?;
+
+ // Prepare our diff options based on the arguments given
+ let mut opts = DiffOptions::new();
+ opts.reverse(args.flag_R)
+ .force_text(args.flag_text)
+ .ignore_whitespace_eol(args.flag_ignore_space_at_eol)
+ .ignore_whitespace_change(args.flag_ignore_space_change)
+ .ignore_whitespace(args.flag_ignore_all_space)
+ .include_ignored(args.flag_ignored)
+ .include_untracked(args.flag_untracked)
+ .patience(args.flag_patience)
+ .minimal(args.flag_minimal);
+ if let Some(amt) = args.flag_unified {
+ opts.context_lines(amt);
+ }
+ if let Some(amt) = args.flag_inter_hunk_context {
+ opts.interhunk_lines(amt);
+ }
+ if let Some(amt) = args.flag_abbrev {
+ opts.id_abbrev(amt);
+ }
+ if let Some(ref s) = args.flag_src_prefix {
+ opts.old_prefix(&s);
+ }
+ if let Some(ref s) = args.flag_dst_prefix {
+ opts.new_prefix(&s);
+ }
+ if let Some("diff-index") = args.flag_format.as_ref().map(|s| &s[..]) {
+ opts.id_abbrev(40);
+ }
+
+ if args.flag_blobs {
+ let b1 = resolve_blob(&repo, args.arg_from_oid.as_ref())?;
+ let b2 = resolve_blob(&repo, args.arg_to_oid.as_ref())?;
+ repo.diff_blobs(
+ b1.as_ref(),
+ None,
+ b2.as_ref(),
+ None,
+ Some(&mut opts),
+ None,
+ None,
+ None,
+ Some(&mut |d, h, l| print_diff_line(d, h, l, args)),
+ )?;
+ if args.color() {
+ print!("{}", RESET);
+ }
+ return Ok(());
+ }
+
+ // Prepare the diff to inspect
+ let t1 = tree_to_treeish(&repo, args.arg_from_oid.as_ref())?;
+ let t2 = tree_to_treeish(&repo, args.arg_to_oid.as_ref())?;
+ let head = tree_to_treeish(&repo, Some(&"HEAD".to_string()))?.unwrap();
+ let mut diff = match (t1, t2, args.cache()) {
+ (Some(t1), Some(t2), _) => {
+ repo.diff_tree_to_tree(t1.as_tree(), t2.as_tree(), Some(&mut opts))?
+ }
+ (t1, None, Cache::None) => {
+ let t1 = t1.unwrap_or(head);
+ repo.diff_tree_to_workdir(t1.as_tree(), Some(&mut opts))?
+ }
+ (t1, None, Cache::Only) => {
+ let t1 = t1.unwrap_or(head);
+ repo.diff_tree_to_index(t1.as_tree(), None, Some(&mut opts))?
+ }
+ (Some(t1), None, _) => {
+ repo.diff_tree_to_workdir_with_index(t1.as_tree(), Some(&mut opts))?
+ }
+ (None, None, _) => repo.diff_index_to_workdir(None, Some(&mut opts))?,
+ (None, Some(_), _) => unreachable!(),
+ };
+
+ // Apply rename and copy detection if requested
+ if args.flag_break_rewrites
+ || args.flag_find_copies_harder
+ || args.flag_find_renames.is_some()
+ || args.flag_find_copies.is_some()
+ {
+ let mut opts = DiffFindOptions::new();
+ if let Some(t) = args.flag_find_renames {
+ opts.rename_threshold(t);
+ opts.renames(true);
+ }
+ if let Some(t) = args.flag_find_copies {
+ opts.copy_threshold(t);
+ opts.copies(true);
+ }
+ opts.copies_from_unmodified(args.flag_find_copies_harder)
+ .rewrites(args.flag_break_rewrites);
+ diff.find_similar(Some(&mut opts))?;
+ }
+
+ // Generate simple output
+ let stats = args.flag_stat | args.flag_numstat | args.flag_shortstat | args.flag_summary;
+ if stats {
+ print_stats(&diff, args)?;
+ }
+ if args.flag_patch || !stats {
+ diff.print(args.diff_format(), |d, h, l| print_diff_line(d, h, l, args))?;
+ if args.color() {
+ print!("{}", RESET);
+ }
+ }
+
+ Ok(())
+}
+
+fn print_stats(diff: &Diff, args: &Args) -> Result<(), Error> {
+ let stats = diff.stats()?;
+ let mut format = git2::DiffStatsFormat::NONE;
+ if args.flag_stat {
+ format |= git2::DiffStatsFormat::FULL;
+ }
+ if args.flag_shortstat {
+ format |= git2::DiffStatsFormat::SHORT;
+ }
+ if args.flag_numstat {
+ format |= git2::DiffStatsFormat::NUMBER;
+ }
+ if args.flag_summary {
+ format |= git2::DiffStatsFormat::INCLUDE_SUMMARY;
+ }
+ let buf = stats.to_buf(format, 80)?;
+ print!("{}", str::from_utf8(&*buf).unwrap());
+ Ok(())
+}
+
+fn tree_to_treeish<'a>(
+ repo: &'a Repository,
+ arg: Option<&String>,
+) -> Result<Option<Object<'a>>, Error> {
+ let arg = match arg {
+ Some(s) => s,
+ None => return Ok(None),
+ };
+ let obj = repo.revparse_single(arg)?;
+ let tree = obj.peel(ObjectType::Tree)?;
+ Ok(Some(tree))
+}
+
+fn resolve_blob<'a>(repo: &'a Repository, arg: Option<&String>) -> Result<Option<Blob<'a>>, Error> {
+ let arg = match arg {
+ Some(s) => Oid::from_str(s)?,
+ None => return Ok(None),
+ };
+ repo.find_blob(arg).map(|b| Some(b))
+}
+
+impl Args {
+ fn cache(&self) -> Cache {
+ if self.flag_cached {
+ Cache::Only
+ } else if self.flag_nocached {
+ Cache::None
+ } else {
+ Cache::Normal
+ }
+ }
+ fn color(&self) -> bool {
+ self.flag_color && !self.flag_no_color
+ }
+ fn diff_format(&self) -> DiffFormat {
+ if self.flag_patch {
+ DiffFormat::Patch
+ } else if self.flag_name_only {
+ DiffFormat::NameOnly
+ } else if self.flag_name_status {
+ DiffFormat::NameStatus
+ } else if self.flag_raw {
+ DiffFormat::Raw
+ } else {
+ match self.flag_format.as_ref().map(|s| &s[..]) {
+ Some("name") => DiffFormat::NameOnly,
+ Some("name-status") => DiffFormat::NameStatus,
+ Some("raw") => DiffFormat::Raw,
+ Some("diff-index") => DiffFormat::Raw,
+ _ => DiffFormat::Patch,
+ }
+ }
+ }
+}
+
+fn main() {
+ let args = Args::from_args();
+ match run(&args) {
+ Ok(()) => {}
+ Err(e) => println!("error: {}", e),
+ }
+}
diff --git a/vendor/git2/examples/fetch.rs b/vendor/git2/examples/fetch.rs
new file mode 100644
index 0000000..64374a6
--- /dev/null
+++ b/vendor/git2/examples/fetch.rs
@@ -0,0 +1,127 @@
+/*
+ * libgit2 "fetch" example - shows how to fetch remote data
+ *
+ * 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::{AutotagOption, FetchOptions, RemoteCallbacks, Repository};
+use std::io::{self, Write};
+use std::str;
+use structopt::StructOpt;
+
+#[derive(StructOpt)]
+struct Args {
+ #[structopt(name = "remote")]
+ arg_remote: Option<String>,
+}
+
+fn run(args: &Args) -> Result<(), git2::Error> {
+ let repo = Repository::open(".")?;
+ let remote = args.arg_remote.as_ref().map(|s| &s[..]).unwrap_or("origin");
+
+ // Figure out whether it's a named remote or a URL
+ println!("Fetching {} for repo", remote);
+ let mut cb = RemoteCallbacks::new();
+ let mut remote = repo
+ .find_remote(remote)
+ .or_else(|_| repo.remote_anonymous(remote))?;
+ cb.sideband_progress(|data| {
+ print!("remote: {}", str::from_utf8(data).unwrap());
+ io::stdout().flush().unwrap();
+ true
+ });
+
+ // This callback gets called for each remote-tracking branch that gets
+ // updated. The message we output depends on whether it's a new one or an
+ // update.
+ cb.update_tips(|refname, a, b| {
+ if a.is_zero() {
+ println!("[new] {:20} {}", b, refname);
+ } else {
+ println!("[updated] {:10}..{:10} {}", a, b, refname);
+ }
+ true
+ });
+
+ // Here we show processed and total objects in the pack and the amount of
+ // received data. Most frontends will probably want to show a percentage and
+ // the download rate.
+ cb.transfer_progress(|stats| {
+ if stats.received_objects() == stats.total_objects() {
+ print!(
+ "Resolving deltas {}/{}\r",
+ stats.indexed_deltas(),
+ stats.total_deltas()
+ );
+ } else if stats.total_objects() > 0 {
+ print!(
+ "Received {}/{} objects ({}) in {} bytes\r",
+ stats.received_objects(),
+ stats.total_objects(),
+ stats.indexed_objects(),
+ stats.received_bytes()
+ );
+ }
+ io::stdout().flush().unwrap();
+ true
+ });
+
+ // Download the packfile and index it. This function updates the amount of
+ // received data and the indexer stats which lets you inform the user about
+ // progress.
+ let mut fo = FetchOptions::new();
+ fo.remote_callbacks(cb);
+ remote.download(&[] as &[&str], Some(&mut fo))?;
+
+ {
+ // If there are local objects (we got a thin pack), then tell the user
+ // how many objects we saved from having to cross the network.
+ let stats = remote.stats();
+ if stats.local_objects() > 0 {
+ println!(
+ "\rReceived {}/{} objects in {} bytes (used {} local \
+ objects)",
+ stats.indexed_objects(),
+ stats.total_objects(),
+ stats.received_bytes(),
+ stats.local_objects()
+ );
+ } else {
+ println!(
+ "\rReceived {}/{} objects in {} bytes",
+ stats.indexed_objects(),
+ stats.total_objects(),
+ stats.received_bytes()
+ );
+ }
+ }
+
+ // Disconnect the underlying connection to prevent from idling.
+ remote.disconnect()?;
+
+ // Update the references in the remote's namespace to point to the right
+ // commits. This may be needed even if there was no packfile to download,
+ // which can happen e.g. when the branches have been changed but all the
+ // needed objects are available locally.
+ remote.update_tips(None, true, AutotagOption::Unspecified, None)?;
+
+ Ok(())
+}
+
+fn main() {
+ let args = Args::from_args();
+ match run(&args) {
+ Ok(()) => {}
+ Err(e) => println!("error: {}", e),
+ }
+}
diff --git a/vendor/git2/examples/init.rs b/vendor/git2/examples/init.rs
new file mode 100644
index 0000000..3e447cb
--- /dev/null
+++ b/vendor/git2/examples/init.rs
@@ -0,0 +1,145 @@
+/*
+ * libgit2 "init" example - shows how to initialize a new repo
+ *
+ * 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::{Error, Repository, RepositoryInitMode, RepositoryInitOptions};
+use std::path::{Path, PathBuf};
+use structopt::StructOpt;
+
+#[derive(StructOpt)]
+struct Args {
+ #[structopt(name = "directory")]
+ arg_directory: String,
+ #[structopt(name = "quiet", short, long)]
+ /// don't print information to stdout
+ flag_quiet: bool,
+ #[structopt(name = "bare", long)]
+ /// initialize a new bare repository
+ flag_bare: bool,
+ #[structopt(name = "dir", long = "template")]
+ /// use <dir> as an initialization template
+ flag_template: Option<String>,
+ #[structopt(name = "separate-git-dir", long)]
+ /// use <dir> as the .git directory
+ flag_separate_git_dir: Option<String>,
+ #[structopt(name = "initial-commit", long)]
+ /// create an initial empty commit
+ flag_initial_commit: bool,
+ #[structopt(name = "perms", long = "shared")]
+ /// permissions to create the repository with
+ flag_shared: Option<String>,
+}
+
+fn run(args: &Args) -> Result<(), Error> {
+ let mut path = PathBuf::from(&args.arg_directory);
+ let repo = if !args.flag_bare
+ && args.flag_template.is_none()
+ && args.flag_shared.is_none()
+ && args.flag_separate_git_dir.is_none()
+ {
+ Repository::init(&path)?
+ } else {
+ let mut opts = RepositoryInitOptions::new();
+ opts.bare(args.flag_bare);
+ if let Some(ref s) = args.flag_template {
+ opts.template_path(Path::new(s));
+ }
+
+ // If you specified a separate git directory, then initialize
+ // the repository at that path and use the second path as the
+ // working directory of the repository (with a git-link file)
+ if let Some(ref s) = args.flag_separate_git_dir {
+ opts.workdir_path(&path);
+ path = PathBuf::from(s);
+ }
+
+ if let Some(ref s) = args.flag_shared {
+ opts.mode(parse_shared(s)?);
+ }
+ Repository::init_opts(&path, &opts)?
+ };
+
+ // Print a message to stdout like "git init" does
+ if !args.flag_quiet {
+ if args.flag_bare || args.flag_separate_git_dir.is_some() {
+ path = repo.path().to_path_buf();
+ } else {
+ path = repo.workdir().unwrap().to_path_buf();
+ }
+ println!("Initialized empty Git repository in {}", path.display());
+ }
+
+ if args.flag_initial_commit {
+ create_initial_commit(&repo)?;
+ println!("Created empty initial commit");
+ }
+
+ Ok(())
+}
+
+/// Unlike regular "git init", this example shows how to create an initial empty
+/// commit in the repository. This is the helper function that does that.
+fn create_initial_commit(repo: &Repository) -> Result<(), Error> {
+ // First use the config to initialize a commit signature for the user.
+ let sig = repo.signature()?;
+
+ // Now let's create an empty tree for this commit
+ let tree_id = {
+ let mut index = repo.index()?;
+
+ // Outside of this example, you could call index.add_path()
+ // here to put actual files into the index. For our purposes, we'll
+ // leave it empty for now.
+
+ index.write_tree()?
+ };
+
+ let tree = repo.find_tree(tree_id)?;
+
+ // Ready to create the initial commit.
+ //
+ // Normally creating a commit would involve looking up the current HEAD
+ // commit and making that be the parent of the initial commit, but here this
+ // is the first commit so there will be no parent.
+ repo.commit(Some("HEAD"), &sig, &sig, "Initial commit", &tree, &[])?;
+
+ Ok(())
+}
+
+fn parse_shared(shared: &str) -> Result<RepositoryInitMode, Error> {
+ match shared {
+ "false" | "umask" => Ok(git2::RepositoryInitMode::SHARED_UMASK),
+ "true" | "group" => Ok(git2::RepositoryInitMode::SHARED_GROUP),
+ "all" | "world" => Ok(git2::RepositoryInitMode::SHARED_ALL),
+ _ => {
+ if shared.starts_with('0') {
+ match u32::from_str_radix(&shared[1..], 8).ok() {
+ Some(n) => Ok(RepositoryInitMode::from_bits_truncate(n)),
+ None => Err(Error::from_str("invalid octal value for --shared")),
+ }
+ } else {
+ Err(Error::from_str("unknown value for --shared"))
+ }
+ }
+ }
+}
+
+fn main() {
+ let args = Args::from_args();
+ match run(&args) {
+ Ok(()) => {}
+ Err(e) => println!("error: {}", e),
+ }
+}
diff --git a/vendor/git2/examples/log.rs b/vendor/git2/examples/log.rs
new file mode 100644
index 0000000..ad3bb35
--- /dev/null
+++ b/vendor/git2/examples/log.rs
@@ -0,0 +1,310 @@
+/*
+ * 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),
+ }
+}
diff --git a/vendor/git2/examples/ls-remote.rs b/vendor/git2/examples/ls-remote.rs
new file mode 100644
index 0000000..1808459
--- /dev/null
+++ b/vendor/git2/examples/ls-remote.rs
@@ -0,0 +1,51 @@
+/*
+ * libgit2 "ls-remote" example
+ *
+ * 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::{Direction, Repository};
+use structopt::StructOpt;
+
+#[derive(StructOpt)]
+struct Args {
+ #[structopt(name = "remote")]
+ arg_remote: String,
+}
+
+fn run(args: &Args) -> Result<(), git2::Error> {
+ let repo = Repository::open(".")?;
+ let remote = &args.arg_remote;
+ let mut remote = repo
+ .find_remote(remote)
+ .or_else(|_| repo.remote_anonymous(remote))?;
+
+ // Connect to the remote and call the printing function for each of the
+ // remote references.
+ let connection = remote.connect_auth(Direction::Fetch, None, None)?;
+
+ // Get the list of references on the remote and print out their name next to
+ // what they point to.
+ for head in connection.list()?.iter() {
+ println!("{}\t{}", head.oid(), head.name());
+ }
+ Ok(())
+}
+
+fn main() {
+ let args = Args::from_args();
+ match run(&args) {
+ Ok(()) => {}
+ Err(e) => println!("error: {}", e),
+ }
+}
diff --git a/vendor/git2/examples/pull.rs b/vendor/git2/examples/pull.rs
new file mode 100644
index 0000000..61251b4
--- /dev/null
+++ b/vendor/git2/examples/pull.rs
@@ -0,0 +1,208 @@
+/*
+ * libgit2 "pull" example - shows how to pull remote data into a local branch.
+ *
+ * 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/>.
+ */
+
+use git2::Repository;
+use std::io::{self, Write};
+use std::str;
+use structopt::StructOpt;
+
+#[derive(StructOpt)]
+struct Args {
+ arg_remote: Option<String>,
+ arg_branch: Option<String>,
+}
+
+fn do_fetch<'a>(
+ repo: &'a git2::Repository,
+ refs: &[&str],
+ remote: &'a mut git2::Remote,
+) -> Result<git2::AnnotatedCommit<'a>, git2::Error> {
+ let mut cb = git2::RemoteCallbacks::new();
+
+ // Print out our transfer progress.
+ cb.transfer_progress(|stats| {
+ if stats.received_objects() == stats.total_objects() {
+ print!(
+ "Resolving deltas {}/{}\r",
+ stats.indexed_deltas(),
+ stats.total_deltas()
+ );
+ } else if stats.total_objects() > 0 {
+ print!(
+ "Received {}/{} objects ({}) in {} bytes\r",
+ stats.received_objects(),
+ stats.total_objects(),
+ stats.indexed_objects(),
+ stats.received_bytes()
+ );
+ }
+ io::stdout().flush().unwrap();
+ true
+ });
+
+ let mut fo = git2::FetchOptions::new();
+ fo.remote_callbacks(cb);
+ // Always fetch all tags.
+ // Perform a download and also update tips
+ fo.download_tags(git2::AutotagOption::All);
+ println!("Fetching {} for repo", remote.name().unwrap());
+ remote.fetch(refs, Some(&mut fo), None)?;
+
+ // If there are local objects (we got a thin pack), then tell the user
+ // how many objects we saved from having to cross the network.
+ let stats = remote.stats();
+ if stats.local_objects() > 0 {
+ println!(
+ "\rReceived {}/{} objects in {} bytes (used {} local \
+ objects)",
+ stats.indexed_objects(),
+ stats.total_objects(),
+ stats.received_bytes(),
+ stats.local_objects()
+ );
+ } else {
+ println!(
+ "\rReceived {}/{} objects in {} bytes",
+ stats.indexed_objects(),
+ stats.total_objects(),
+ stats.received_bytes()
+ );
+ }
+
+ let fetch_head = repo.find_reference("FETCH_HEAD")?;
+ Ok(repo.reference_to_annotated_commit(&fetch_head)?)
+}
+
+fn fast_forward(
+ repo: &Repository,
+ lb: &mut git2::Reference,
+ rc: &git2::AnnotatedCommit,
+) -> Result<(), git2::Error> {
+ let name = match lb.name() {
+ Some(s) => s.to_string(),
+ None => String::from_utf8_lossy(lb.name_bytes()).to_string(),
+ };
+ let msg = format!("Fast-Forward: Setting {} to id: {}", name, rc.id());
+ println!("{}", msg);
+ lb.set_target(rc.id(), &msg)?;
+ repo.set_head(&name)?;
+ repo.checkout_head(Some(
+ git2::build::CheckoutBuilder::default()
+ // For some reason the force is required to make the working directory actually get updated
+ // I suspect we should be adding some logic to handle dirty working directory states
+ // but this is just an example so maybe not.
+ .force(),
+ ))?;
+ Ok(())
+}
+
+fn normal_merge(
+ repo: &Repository,
+ local: &git2::AnnotatedCommit,
+ remote: &git2::AnnotatedCommit,
+) -> Result<(), git2::Error> {
+ let local_tree = repo.find_commit(local.id())?.tree()?;
+ let remote_tree = repo.find_commit(remote.id())?.tree()?;
+ let ancestor = repo
+ .find_commit(repo.merge_base(local.id(), remote.id())?)?
+ .tree()?;
+ let mut idx = repo.merge_trees(&ancestor, &local_tree, &remote_tree, None)?;
+
+ if idx.has_conflicts() {
+ println!("Merge conflicts detected...");
+ repo.checkout_index(Some(&mut idx), None)?;
+ return Ok(());
+ }
+ let result_tree = repo.find_tree(idx.write_tree_to(repo)?)?;
+ // now create the merge commit
+ let msg = format!("Merge: {} into {}", remote.id(), local.id());
+ let sig = repo.signature()?;
+ let local_commit = repo.find_commit(local.id())?;
+ let remote_commit = repo.find_commit(remote.id())?;
+ // Do our merge commit and set current branch head to that commit.
+ let _merge_commit = repo.commit(
+ Some("HEAD"),
+ &sig,
+ &sig,
+ &msg,
+ &result_tree,
+ &[&local_commit, &remote_commit],
+ )?;
+ // Set working tree to match head.
+ repo.checkout_head(None)?;
+ Ok(())
+}
+
+fn do_merge<'a>(
+ repo: &'a Repository,
+ remote_branch: &str,
+ fetch_commit: git2::AnnotatedCommit<'a>,
+) -> Result<(), git2::Error> {
+ // 1. do a merge analysis
+ let analysis = repo.merge_analysis(&[&fetch_commit])?;
+
+ // 2. Do the appropriate merge
+ if analysis.0.is_fast_forward() {
+ println!("Doing a fast forward");
+ // do a fast forward
+ let refname = format!("refs/heads/{}", remote_branch);
+ match repo.find_reference(&refname) {
+ Ok(mut r) => {
+ fast_forward(repo, &mut r, &fetch_commit)?;
+ }
+ Err(_) => {
+ // The branch doesn't exist so just set the reference to the
+ // commit directly. Usually this is because you are pulling
+ // into an empty repository.
+ repo.reference(
+ &refname,
+ fetch_commit.id(),
+ true,
+ &format!("Setting {} to {}", remote_branch, fetch_commit.id()),
+ )?;
+ repo.set_head(&refname)?;
+ repo.checkout_head(Some(
+ git2::build::CheckoutBuilder::default()
+ .allow_conflicts(true)
+ .conflict_style_merge(true)
+ .force(),
+ ))?;
+ }
+ };
+ } else if analysis.0.is_normal() {
+ // do a normal merge
+ let head_commit = repo.reference_to_annotated_commit(&repo.head()?)?;
+ normal_merge(&repo, &head_commit, &fetch_commit)?;
+ } else {
+ println!("Nothing to do...");
+ }
+ Ok(())
+}
+
+fn run(args: &Args) -> Result<(), git2::Error> {
+ let remote_name = args.arg_remote.as_ref().map(|s| &s[..]).unwrap_or("origin");
+ let remote_branch = args.arg_branch.as_ref().map(|s| &s[..]).unwrap_or("master");
+ let repo = Repository::open(".")?;
+ let mut remote = repo.find_remote(remote_name)?;
+ let fetch_commit = do_fetch(&repo, &[remote_branch], &mut remote)?;
+ do_merge(&repo, &remote_branch, fetch_commit)
+}
+
+fn main() {
+ let args = Args::from_args();
+ match run(&args) {
+ Ok(()) => {}
+ Err(e) => println!("error: {}", e),
+ }
+}
diff --git a/vendor/git2/examples/rev-list.rs b/vendor/git2/examples/rev-list.rs
new file mode 100644
index 0000000..9b49877
--- /dev/null
+++ b/vendor/git2/examples/rev-list.rs
@@ -0,0 +1,105 @@
+/*
+ * libgit2 "rev-list" example - shows how to transform a rev-spec into a list
+ * of commit ids
+ *
+ * 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::{Error, Oid, Repository, Revwalk};
+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 = "not")]
+ /// don't show <spec>
+ flag_not: Vec<String>,
+ #[structopt(name = "spec", last = true)]
+ arg_spec: Vec<String>,
+}
+
+fn run(args: &Args) -> Result<(), git2::Error> {
+ let repo = Repository::open(".")?;
+ let mut revwalk = repo.revwalk()?;
+
+ 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
+ },
+ )?;
+
+ let specs = args
+ .flag_not
+ .iter()
+ .map(|s| (s, true))
+ .chain(args.arg_spec.iter().map(|s| (s, false)))
+ .map(|(spec, hide)| {
+ if spec.starts_with('^') {
+ (&spec[1..], !hide)
+ } else {
+ (&spec[..], hide)
+ }
+ });
+ for (spec, hide) in specs {
+ let id = if spec.contains("..") {
+ let revspec = repo.revparse(spec)?;
+ if revspec.mode().contains(git2::RevparseMode::MERGE_BASE) {
+ return Err(Error::from_str("merge bases not implemented"));
+ }
+ push(&mut revwalk, revspec.from().unwrap().id(), !hide)?;
+ revspec.to().unwrap().id()
+ } else {
+ repo.revparse_single(spec)?.id()
+ };
+ push(&mut revwalk, id, hide)?;
+ }
+
+ for id in revwalk {
+ let id = id?;
+ println!("{}", id);
+ }
+ Ok(())
+}
+
+fn push(revwalk: &mut Revwalk, id: Oid, hide: bool) -> Result<(), Error> {
+ if hide {
+ revwalk.hide(id)
+ } else {
+ revwalk.push(id)
+ }
+}
+
+fn main() {
+ let args = Args::from_args();
+ match run(&args) {
+ Ok(()) => {}
+ Err(e) => println!("error: {}", e),
+ }
+}
diff --git a/vendor/git2/examples/rev-parse.rs b/vendor/git2/examples/rev-parse.rs
new file mode 100644
index 0000000..a465f15
--- /dev/null
+++ b/vendor/git2/examples/rev-parse.rs
@@ -0,0 +1,60 @@
+/*
+ * libgit2 "rev-parse" example - shows how to parse revspecs
+ *
+ * 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::Repository;
+use structopt::StructOpt;
+
+#[derive(StructOpt)]
+struct Args {
+ #[structopt(name = "spec")]
+ arg_spec: String,
+ #[structopt(name = "dir", long = "git-dir")]
+ /// directory of the git repository to check
+ flag_git_dir: Option<String>,
+}
+
+fn run(args: &Args) -> Result<(), git2::Error> {
+ let path = args.flag_git_dir.as_ref().map(|s| &s[..]).unwrap_or(".");
+ let repo = Repository::open(path)?;
+
+ let revspec = repo.revparse(&args.arg_spec)?;
+
+ if revspec.mode().contains(git2::RevparseMode::SINGLE) {
+ println!("{}", revspec.from().unwrap().id());
+ } else if revspec.mode().contains(git2::RevparseMode::RANGE) {
+ let to = revspec.to().unwrap();
+ let from = revspec.from().unwrap();
+ println!("{}", to.id());
+
+ if revspec.mode().contains(git2::RevparseMode::MERGE_BASE) {
+ let base = repo.merge_base(from.id(), to.id())?;
+ println!("{}", base);
+ }
+
+ println!("^{}", from.id());
+ } else {
+ return Err(git2::Error::from_str("invalid results from revparse"));
+ }
+ Ok(())
+}
+
+fn main() {
+ let args = Args::from_args();
+ match run(&args) {
+ Ok(()) => {}
+ Err(e) => println!("error: {}", e),
+ }
+}
diff --git a/vendor/git2/examples/status.rs b/vendor/git2/examples/status.rs
new file mode 100644
index 0000000..4f7bc79
--- /dev/null
+++ b/vendor/git2/examples/status.rs
@@ -0,0 +1,441 @@
+/*
+ * libgit2 "status" example - shows how to use the status APIs
+ *
+ * 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::{Error, ErrorCode, Repository, StatusOptions, SubmoduleIgnore};
+use std::str;
+use std::time::Duration;
+use structopt::StructOpt;
+
+#[derive(StructOpt)]
+struct Args {
+ arg_spec: Vec<String>,
+ #[structopt(name = "long", long)]
+ /// show longer statuses (default)
+ _flag_long: bool,
+ /// show short statuses
+ #[structopt(name = "short", long)]
+ flag_short: bool,
+ #[structopt(name = "porcelain", long)]
+ /// ??
+ flag_porcelain: bool,
+ #[structopt(name = "branch", short, long)]
+ /// show branch information
+ flag_branch: bool,
+ #[structopt(name = "z", short)]
+ /// ??
+ flag_z: bool,
+ #[structopt(name = "ignored", long)]
+ /// show ignored files as well
+ flag_ignored: bool,
+ #[structopt(name = "opt-modules", long = "untracked-files")]
+ /// setting for showing untracked files [no|normal|all]
+ flag_untracked_files: Option<String>,
+ #[structopt(name = "opt-files", long = "ignore-submodules")]
+ /// setting for ignoring submodules [all]
+ flag_ignore_submodules: Option<String>,
+ #[structopt(name = "dir", long = "git-dir")]
+ /// git directory to analyze
+ flag_git_dir: Option<String>,
+ #[structopt(name = "repeat", long)]
+ /// repeatedly show status, sleeping inbetween
+ flag_repeat: bool,
+ #[structopt(name = "list-submodules", long)]
+ /// show submodules
+ flag_list_submodules: bool,
+}
+
+#[derive(Eq, PartialEq)]
+enum Format {
+ Long,
+ Short,
+ Porcelain,
+}
+
+fn run(args: &Args) -> Result<(), Error> {
+ let path = args.flag_git_dir.clone().unwrap_or_else(|| ".".to_string());
+ let repo = Repository::open(&path)?;
+ if repo.is_bare() {
+ return Err(Error::from_str("cannot report status on bare repository"));
+ }
+
+ let mut opts = StatusOptions::new();
+ opts.include_ignored(args.flag_ignored);
+ match args.flag_untracked_files.as_ref().map(|s| &s[..]) {
+ Some("no") => {
+ opts.include_untracked(false);
+ }
+ Some("normal") => {
+ opts.include_untracked(true);
+ }
+ Some("all") => {
+ opts.include_untracked(true).recurse_untracked_dirs(true);
+ }
+ Some(_) => return Err(Error::from_str("invalid untracked-files value")),
+ None => {}
+ }
+ match args.flag_ignore_submodules.as_ref().map(|s| &s[..]) {
+ Some("all") => {
+ opts.exclude_submodules(true);
+ }
+ Some(_) => return Err(Error::from_str("invalid ignore-submodules value")),
+ None => {}
+ }
+ opts.include_untracked(!args.flag_ignored);
+ for spec in &args.arg_spec {
+ opts.pathspec(spec);
+ }
+
+ loop {
+ if args.flag_repeat {
+ println!("\u{1b}[H\u{1b}[2J");
+ }
+
+ let statuses = repo.statuses(Some(&mut opts))?;
+
+ if args.flag_branch {
+ show_branch(&repo, &args.format())?;
+ }
+ if args.flag_list_submodules {
+ print_submodules(&repo)?;
+ }
+
+ if args.format() == Format::Long {
+ print_long(&statuses);
+ } else {
+ print_short(&repo, &statuses);
+ }
+
+ if args.flag_repeat {
+ std::thread::sleep(Duration::new(10, 0));
+ } else {
+ return Ok(());
+ }
+ }
+}
+
+fn show_branch(repo: &Repository, format: &Format) -> Result<(), Error> {
+ let head = match repo.head() {
+ Ok(head) => Some(head),
+ Err(ref e) if e.code() == ErrorCode::UnbornBranch || e.code() == ErrorCode::NotFound => {
+ None
+ }
+ Err(e) => return Err(e),
+ };
+ let head = head.as_ref().and_then(|h| h.shorthand());
+
+ if format == &Format::Long {
+ println!(
+ "# On branch {}",
+ head.unwrap_or("Not currently on any branch")
+ );
+ } else {
+ println!("## {}", head.unwrap_or("HEAD (no branch)"));
+ }
+ Ok(())
+}
+
+fn print_submodules(repo: &Repository) -> Result<(), Error> {
+ let modules = repo.submodules()?;
+ println!("# Submodules");
+ for sm in &modules {
+ println!(
+ "# - submodule '{}' at {}",
+ sm.name().unwrap(),
+ sm.path().display()
+ );
+ }
+ Ok(())
+}
+
+// This function print out an output similar to git's status command in long
+// form, including the command-line hints.
+fn print_long(statuses: &git2::Statuses) {
+ let mut header = false;
+ let mut rm_in_workdir = false;
+ let mut changes_in_index = false;
+ let mut changed_in_workdir = false;
+
+ // Print index changes
+ for entry in statuses
+ .iter()
+ .filter(|e| e.status() != git2::Status::CURRENT)
+ {
+ if entry.status().contains(git2::Status::WT_DELETED) {
+ rm_in_workdir = true;
+ }
+ let istatus = match entry.status() {
+ s if s.contains(git2::Status::INDEX_NEW) => "new file: ",
+ s if s.contains(git2::Status::INDEX_MODIFIED) => "modified: ",
+ s if s.contains(git2::Status::INDEX_DELETED) => "deleted: ",
+ s if s.contains(git2::Status::INDEX_RENAMED) => "renamed: ",
+ s if s.contains(git2::Status::INDEX_TYPECHANGE) => "typechange:",
+ _ => continue,
+ };
+ if !header {
+ println!(
+ "\
+# Changes to be committed:
+# (use \"git reset HEAD <file>...\" to unstage)
+#"
+ );
+ header = true;
+ }
+
+ let old_path = entry.head_to_index().unwrap().old_file().path();
+ let new_path = entry.head_to_index().unwrap().new_file().path();
+ match (old_path, new_path) {
+ (Some(old), Some(new)) if old != new => {
+ println!("#\t{} {} -> {}", istatus, old.display(), new.display());
+ }
+ (old, new) => {
+ println!("#\t{} {}", istatus, old.or(new).unwrap().display());
+ }
+ }
+ }
+
+ if header {
+ changes_in_index = true;
+ println!("#");
+ }
+ header = false;
+
+ // Print workdir changes to tracked files
+ for entry in statuses.iter() {
+ // With `Status::OPT_INCLUDE_UNMODIFIED` (not used in this example)
+ // `index_to_workdir` may not be `None` even if there are no differences,
+ // in which case it will be a `Delta::Unmodified`.
+ if entry.status() == git2::Status::CURRENT || entry.index_to_workdir().is_none() {
+ continue;
+ }
+
+ let istatus = match entry.status() {
+ s if s.contains(git2::Status::WT_MODIFIED) => "modified: ",
+ s if s.contains(git2::Status::WT_DELETED) => "deleted: ",
+ s if s.contains(git2::Status::WT_RENAMED) => "renamed: ",
+ s if s.contains(git2::Status::WT_TYPECHANGE) => "typechange:",
+ _ => continue,
+ };
+
+ if !header {
+ println!(
+ "\
+# Changes not staged for commit:
+# (use \"git add{} <file>...\" to update what will be committed)
+# (use \"git checkout -- <file>...\" to discard changes in working directory)
+#\
+ ",
+ if rm_in_workdir { "/rm" } else { "" }
+ );
+ header = true;
+ }
+
+ let old_path = entry.index_to_workdir().unwrap().old_file().path();
+ let new_path = entry.index_to_workdir().unwrap().new_file().path();
+ match (old_path, new_path) {
+ (Some(old), Some(new)) if old != new => {
+ println!("#\t{} {} -> {}", istatus, old.display(), new.display());
+ }
+ (old, new) => {
+ println!("#\t{} {}", istatus, old.or(new).unwrap().display());
+ }
+ }
+ }
+
+ if header {
+ changed_in_workdir = true;
+ println!("#");
+ }
+ header = false;
+
+ // Print untracked files
+ for entry in statuses
+ .iter()
+ .filter(|e| e.status() == git2::Status::WT_NEW)
+ {
+ if !header {
+ println!(
+ "\
+# Untracked files
+# (use \"git add <file>...\" to include in what will be committed)
+#"
+ );
+ header = true;
+ }
+ let file = entry.index_to_workdir().unwrap().old_file().path().unwrap();
+ println!("#\t{}", file.display());
+ }
+ header = false;
+
+ // Print ignored files
+ for entry in statuses
+ .iter()
+ .filter(|e| e.status() == git2::Status::IGNORED)
+ {
+ if !header {
+ println!(
+ "\
+# Ignored files
+# (use \"git add -f <file>...\" to include in what will be committed)
+#"
+ );
+ header = true;
+ }
+ let file = entry.index_to_workdir().unwrap().old_file().path().unwrap();
+ println!("#\t{}", file.display());
+ }
+
+ if !changes_in_index && changed_in_workdir {
+ println!(
+ "no changes added to commit (use \"git add\" and/or \
+ \"git commit -a\")"
+ );
+ }
+}
+
+// This version of the output prefixes each path with two status columns and
+// shows submodule status information.
+fn print_short(repo: &Repository, statuses: &git2::Statuses) {
+ for entry in statuses
+ .iter()
+ .filter(|e| e.status() != git2::Status::CURRENT)
+ {
+ let mut istatus = match entry.status() {
+ s if s.contains(git2::Status::INDEX_NEW) => 'A',
+ s if s.contains(git2::Status::INDEX_MODIFIED) => 'M',
+ s if s.contains(git2::Status::INDEX_DELETED) => 'D',
+ s if s.contains(git2::Status::INDEX_RENAMED) => 'R',
+ s if s.contains(git2::Status::INDEX_TYPECHANGE) => 'T',
+ _ => ' ',
+ };
+ let mut wstatus = match entry.status() {
+ s if s.contains(git2::Status::WT_NEW) => {
+ if istatus == ' ' {
+ istatus = '?';
+ }
+ '?'
+ }
+ s if s.contains(git2::Status::WT_MODIFIED) => 'M',
+ s if s.contains(git2::Status::WT_DELETED) => 'D',
+ s if s.contains(git2::Status::WT_RENAMED) => 'R',
+ s if s.contains(git2::Status::WT_TYPECHANGE) => 'T',
+ _ => ' ',
+ };
+
+ if entry.status().contains(git2::Status::IGNORED) {
+ istatus = '!';
+ wstatus = '!';
+ }
+ if istatus == '?' && wstatus == '?' {
+ continue;
+ }
+ let mut extra = "";
+
+ // A commit in a tree is how submodules are stored, so let's go take a
+ // look at its status.
+ //
+ // TODO: check for GIT_FILEMODE_COMMIT
+ let status = entry.index_to_workdir().and_then(|diff| {
+ let ignore = SubmoduleIgnore::Unspecified;
+ diff.new_file()
+ .path_bytes()
+ .and_then(|s| str::from_utf8(s).ok())
+ .and_then(|name| repo.submodule_status(name, ignore).ok())
+ });
+ if let Some(status) = status {
+ if status.contains(git2::SubmoduleStatus::WD_MODIFIED) {
+ extra = " (new commits)";
+ } else if status.contains(git2::SubmoduleStatus::WD_INDEX_MODIFIED)
+ || status.contains(git2::SubmoduleStatus::WD_WD_MODIFIED)
+ {
+ extra = " (modified content)";
+ } else if status.contains(git2::SubmoduleStatus::WD_UNTRACKED) {
+ extra = " (untracked content)";
+ }
+ }
+
+ let (mut a, mut b, mut c) = (None, None, None);
+ if let Some(diff) = entry.head_to_index() {
+ a = diff.old_file().path();
+ b = diff.new_file().path();
+ }
+ if let Some(diff) = entry.index_to_workdir() {
+ a = a.or_else(|| diff.old_file().path());
+ b = b.or_else(|| diff.old_file().path());
+ c = diff.new_file().path();
+ }
+
+ match (istatus, wstatus) {
+ ('R', 'R') => println!(
+ "RR {} {} {}{}",
+ a.unwrap().display(),
+ b.unwrap().display(),
+ c.unwrap().display(),
+ extra
+ ),
+ ('R', w) => println!(
+ "R{} {} {}{}",
+ w,
+ a.unwrap().display(),
+ b.unwrap().display(),
+ extra
+ ),
+ (i, 'R') => println!(
+ "{}R {} {}{}",
+ i,
+ a.unwrap().display(),
+ c.unwrap().display(),
+ extra
+ ),
+ (i, w) => println!("{}{} {}{}", i, w, a.unwrap().display(), extra),
+ }
+ }
+
+ for entry in statuses
+ .iter()
+ .filter(|e| e.status() == git2::Status::WT_NEW)
+ {
+ println!(
+ "?? {}",
+ entry
+ .index_to_workdir()
+ .unwrap()
+ .old_file()
+ .path()
+ .unwrap()
+ .display()
+ );
+ }
+}
+
+impl Args {
+ fn format(&self) -> Format {
+ if self.flag_short {
+ Format::Short
+ } else if self.flag_porcelain || self.flag_z {
+ Format::Porcelain
+ } else {
+ Format::Long
+ }
+ }
+}
+
+fn main() {
+ let args = Args::from_args();
+ match run(&args) {
+ Ok(()) => {}
+ Err(e) => println!("error: {}", e),
+ }
+}
diff --git a/vendor/git2/examples/tag.rs b/vendor/git2/examples/tag.rs
new file mode 100644
index 0000000..c44c288
--- /dev/null
+++ b/vendor/git2/examples/tag.rs
@@ -0,0 +1,127 @@
+/*
+ * libgit2 "tag" example - shows how to list, create and delete tags
+ *
+ * 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, Error, Repository, Tag};
+use std::str;
+use structopt::StructOpt;
+
+#[derive(StructOpt)]
+struct Args {
+ arg_tagname: Option<String>,
+ arg_object: Option<String>,
+ arg_pattern: Option<String>,
+ #[structopt(name = "n", short)]
+ /// specify number of lines from the annotation to print
+ flag_n: Option<u32>,
+ #[structopt(name = "force", short, long)]
+ /// replace an existing tag with the given name
+ flag_force: bool,
+ #[structopt(name = "list", short, long)]
+ /// list tags with names matching the pattern given
+ flag_list: bool,
+ #[structopt(name = "tag", short, long = "delete")]
+ /// delete the tag specified
+ flag_delete: Option<String>,
+ #[structopt(name = "msg", short, long = "message")]
+ /// message for a new tag
+ flag_message: Option<String>,
+}
+
+fn run(args: &Args) -> Result<(), Error> {
+ let repo = Repository::open(".")?;
+
+ if let Some(ref name) = args.arg_tagname {
+ let target = args.arg_object.as_ref().map(|s| &s[..]).unwrap_or("HEAD");
+ let obj = repo.revparse_single(target)?;
+
+ if let Some(ref message) = args.flag_message {
+ let sig = repo.signature()?;
+ repo.tag(name, &obj, &sig, message, args.flag_force)?;
+ } else {
+ repo.tag_lightweight(name, &obj, args.flag_force)?;
+ }
+ } else if let Some(ref name) = args.flag_delete {
+ let obj = repo.revparse_single(name)?;
+ let id = obj.short_id()?;
+ repo.tag_delete(name)?;
+ println!(
+ "Deleted tag '{}' (was {})",
+ name,
+ str::from_utf8(&*id).unwrap()
+ );
+ } else if args.flag_list {
+ let pattern = args.arg_pattern.as_ref().map(|s| &s[..]).unwrap_or("*");
+ for name in repo.tag_names(Some(pattern))?.iter() {
+ let name = name.unwrap();
+ let obj = repo.revparse_single(name)?;
+
+ if let Some(tag) = obj.as_tag() {
+ print_tag(tag, args);
+ } else if let Some(commit) = obj.as_commit() {
+ print_commit(commit, name, args);
+ } else {
+ print_name(name);
+ }
+ }
+ }
+ Ok(())
+}
+
+fn print_tag(tag: &Tag, args: &Args) {
+ print!("{:<16}", tag.name().unwrap());
+ if args.flag_n.is_some() {
+ print_list_lines(tag.message(), args);
+ } else {
+ println!();
+ }
+}
+
+fn print_commit(commit: &Commit, name: &str, args: &Args) {
+ print!("{:<16}", name);
+ if args.flag_n.is_some() {
+ print_list_lines(commit.message(), args);
+ } else {
+ println!();
+ }
+}
+
+fn print_name(name: &str) {
+ println!("{}", name);
+}
+
+fn print_list_lines(message: Option<&str>, args: &Args) {
+ let message = match message {
+ Some(s) => s,
+ None => return,
+ };
+ let mut lines = message.lines().filter(|l| !l.trim().is_empty());
+ if let Some(first) = lines.next() {
+ print!("{}", first);
+ }
+ println!();
+
+ for line in lines.take(args.flag_n.unwrap_or(0) as usize) {
+ print!(" {}", line);
+ }
+}
+
+fn main() {
+ let args = Args::from_args();
+ match run(&args) {
+ Ok(()) => {}
+ Err(e) => println!("error: {}", e),
+ }
+}