diff options
Diffstat (limited to 'vendor/git2/examples')
-rw-r--r-- | vendor/git2/examples/add.rs | 81 | ||||
-rw-r--r-- | vendor/git2/examples/blame.rs | 104 | ||||
-rw-r--r-- | vendor/git2/examples/cat-file.rs | 149 | ||||
-rw-r--r-- | vendor/git2/examples/clone.rs | 126 | ||||
-rw-r--r-- | vendor/git2/examples/diff.rs | 368 | ||||
-rw-r--r-- | vendor/git2/examples/fetch.rs | 127 | ||||
-rw-r--r-- | vendor/git2/examples/init.rs | 145 | ||||
-rw-r--r-- | vendor/git2/examples/log.rs | 310 | ||||
-rw-r--r-- | vendor/git2/examples/ls-remote.rs | 51 | ||||
-rw-r--r-- | vendor/git2/examples/pull.rs | 208 | ||||
-rw-r--r-- | vendor/git2/examples/rev-list.rs | 105 | ||||
-rw-r--r-- | vendor/git2/examples/rev-parse.rs | 60 | ||||
-rw-r--r-- | vendor/git2/examples/status.rs | 441 | ||||
-rw-r--r-- | vendor/git2/examples/tag.rs | 127 |
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), + } +} |