diff options
Diffstat (limited to 'vendor/git2/src/lib.rs')
-rw-r--r-- | vendor/git2/src/lib.rs | 1668 |
1 files changed, 1668 insertions, 0 deletions
diff --git a/vendor/git2/src/lib.rs b/vendor/git2/src/lib.rs new file mode 100644 index 0000000..3dd6fe9 --- /dev/null +++ b/vendor/git2/src/lib.rs @@ -0,0 +1,1668 @@ +//! # libgit2 bindings for Rust +//! +//! This library contains bindings to the [libgit2][1] C library which is used +//! to manage git repositories. The library itself is a work in progress and is +//! likely lacking some bindings here and there, so be warned. +//! +//! [1]: https://libgit2.github.com/ +//! +//! The git2-rs library strives to be as close to libgit2 as possible, but also +//! strives to make using libgit2 as safe as possible. All resource management +//! is automatic as well as adding strong types to all interfaces (including +//! `Result`) +//! +//! ## Creating a `Repository` +//! +//! The `Repository` is the source from which almost all other objects in git-rs +//! are spawned. A repository can be created through opening, initializing, or +//! cloning. +//! +//! ### Initializing a new repository +//! +//! The `init` method will create a new repository, assuming one does not +//! already exist. +//! +//! ```no_run +//! # #![allow(unstable)] +//! use git2::Repository; +//! +//! let repo = match Repository::init("/path/to/a/repo") { +//! Ok(repo) => repo, +//! Err(e) => panic!("failed to init: {}", e), +//! }; +//! ``` +//! +//! ### Opening an existing repository +//! +//! ```no_run +//! # #![allow(unstable)] +//! use git2::Repository; +//! +//! let repo = match Repository::open("/path/to/a/repo") { +//! Ok(repo) => repo, +//! Err(e) => panic!("failed to open: {}", e), +//! }; +//! ``` +//! +//! ### Cloning an existing repository +//! +//! ```no_run +//! # #![allow(unstable)] +//! use git2::Repository; +//! +//! let url = "https://github.com/alexcrichton/git2-rs"; +//! let repo = match Repository::clone(url, "/path/to/a/repo") { +//! Ok(repo) => repo, +//! Err(e) => panic!("failed to clone: {}", e), +//! }; +//! ``` +//! +//! To clone using SSH, refer to [RepoBuilder](./build/struct.RepoBuilder.html). +//! +//! ## Working with a `Repository` +//! +//! All derivative objects, references, etc are attached to the lifetime of the +//! source `Repository`, to ensure that they do not outlive the repository +//! itself. + +#![doc(html_root_url = "https://docs.rs/git2/0.18")] +#![allow(trivial_numeric_casts, trivial_casts)] +#![deny(missing_docs)] +#![warn(rust_2018_idioms)] +#![cfg_attr(test, deny(warnings))] + +use bitflags::bitflags; +use libgit2_sys as raw; + +use std::ffi::{CStr, CString}; +use std::fmt; +use std::str; +use std::sync::Once; + +pub use crate::apply::{ApplyLocation, ApplyOptions}; +pub use crate::attr::AttrValue; +pub use crate::blame::{Blame, BlameHunk, BlameIter, BlameOptions}; +pub use crate::blob::{Blob, BlobWriter}; +pub use crate::branch::{Branch, Branches}; +pub use crate::buf::Buf; +pub use crate::cherrypick::CherrypickOptions; +pub use crate::commit::{Commit, Parents}; +pub use crate::config::{Config, ConfigEntries, ConfigEntry}; +pub use crate::cred::{Cred, CredentialHelper}; +pub use crate::describe::{Describe, DescribeFormatOptions, DescribeOptions}; +pub use crate::diff::{Deltas, Diff, DiffDelta, DiffFile, DiffOptions}; +pub use crate::diff::{DiffBinary, DiffBinaryFile, DiffBinaryKind, DiffPatchidOptions}; +pub use crate::diff::{DiffFindOptions, DiffHunk, DiffLine, DiffLineType, DiffStats}; +pub use crate::email::{Email, EmailCreateOptions}; +pub use crate::error::Error; +pub use crate::index::{ + Index, IndexConflict, IndexConflicts, IndexEntries, IndexEntry, IndexMatchedPath, +}; +pub use crate::indexer::{Indexer, IndexerProgress, Progress}; +pub use crate::mailmap::Mailmap; +pub use crate::mempack::Mempack; +pub use crate::merge::{AnnotatedCommit, MergeOptions}; +pub use crate::message::{ + message_prettify, message_trailers_bytes, message_trailers_strs, MessageTrailersBytes, + MessageTrailersBytesIterator, MessageTrailersStrs, MessageTrailersStrsIterator, + DEFAULT_COMMENT_CHAR, +}; +pub use crate::note::{Note, Notes}; +pub use crate::object::Object; +pub use crate::odb::{Odb, OdbObject, OdbPackwriter, OdbReader, OdbWriter}; +pub use crate::oid::Oid; +pub use crate::packbuilder::{PackBuilder, PackBuilderStage}; +pub use crate::patch::Patch; +pub use crate::pathspec::{Pathspec, PathspecFailedEntries, PathspecMatchList}; +pub use crate::pathspec::{PathspecDiffEntries, PathspecEntries}; +pub use crate::proxy_options::ProxyOptions; +pub use crate::push_update::PushUpdate; +pub use crate::rebase::{Rebase, RebaseOperation, RebaseOperationType, RebaseOptions}; +pub use crate::reference::{Reference, ReferenceNames, References}; +pub use crate::reflog::{Reflog, ReflogEntry, ReflogIter}; +pub use crate::refspec::Refspec; +pub use crate::remote::{ + FetchOptions, PushOptions, Refspecs, Remote, RemoteConnection, RemoteHead, RemoteRedirect, +}; +pub use crate::remote_callbacks::{CertificateCheckStatus, Credentials, RemoteCallbacks}; +pub use crate::remote_callbacks::{TransportMessage, UpdateTips}; +pub use crate::repo::{Repository, RepositoryInitOptions}; +pub use crate::revert::RevertOptions; +pub use crate::revspec::Revspec; +pub use crate::revwalk::Revwalk; +pub use crate::signature::Signature; +pub use crate::stash::{StashApplyOptions, StashApplyProgressCb, StashCb, StashSaveOptions}; +pub use crate::status::{StatusEntry, StatusIter, StatusOptions, StatusShow, Statuses}; +pub use crate::submodule::{Submodule, SubmoduleUpdateOptions}; +pub use crate::tag::Tag; +pub use crate::time::{IndexTime, Time}; +pub use crate::tracing::{trace_set, TraceLevel}; +pub use crate::transaction::Transaction; +pub use crate::tree::{Tree, TreeEntry, TreeIter, TreeWalkMode, TreeWalkResult}; +pub use crate::treebuilder::TreeBuilder; +pub use crate::util::IntoCString; +pub use crate::version::Version; +pub use crate::worktree::{Worktree, WorktreeAddOptions, WorktreeLockStatus, WorktreePruneOptions}; + +// Create a convinience method on bitflag struct which checks the given flag +macro_rules! is_bit_set { + ($name:ident, $flag:expr) => { + #[allow(missing_docs)] + pub fn $name(&self) -> bool { + self.intersects($flag) + } + }; +} + +/// An enumeration of possible errors that can happen when working with a git +/// repository. +// Note: We omit a few native error codes, as they are unlikely to be propagated +// to the library user. Currently: +// +// * GIT_EPASSTHROUGH +// * GIT_ITEROVER +// * GIT_RETRY +#[derive(PartialEq, Eq, Clone, Debug, Copy)] +pub enum ErrorCode { + /// Generic error + GenericError, + /// Requested object could not be found + NotFound, + /// Object exists preventing operation + Exists, + /// More than one object matches + Ambiguous, + /// Output buffer too short to hold data + BufSize, + /// User-generated error + User, + /// Operation not allowed on bare repository + BareRepo, + /// HEAD refers to branch with no commits + UnbornBranch, + /// Merge in progress prevented operation + Unmerged, + /// Reference was not fast-forwardable + NotFastForward, + /// Name/ref spec was not in a valid format + InvalidSpec, + /// Checkout conflicts prevented operation + Conflict, + /// Lock file prevented operation + Locked, + /// Reference value does not match expected + Modified, + /// Authentication error + Auth, + /// Server certificate is invalid + Certificate, + /// Patch/merge has already been applied + Applied, + /// The requested peel operation is not possible + Peel, + /// Unexpected EOF + Eof, + /// Invalid operation or input + Invalid, + /// Uncommitted changes in index prevented operation + Uncommitted, + /// Operation was not valid for a directory + Directory, + /// A merge conflict exists and cannot continue + MergeConflict, + /// Hashsum mismatch in object + HashsumMismatch, + /// Unsaved changes in the index would be overwritten + IndexDirty, + /// Patch application failed + ApplyFail, + /// The object is not owned by the current user + Owner, +} + +/// An enumeration of possible categories of things that can have +/// errors when working with a git repository. +#[derive(PartialEq, Eq, Clone, Debug, Copy)] +pub enum ErrorClass { + /// Uncategorized + None, + /// Out of memory or insufficient allocated space + NoMemory, + /// Syscall or standard system library error + Os, + /// Invalid input + Invalid, + /// Error resolving or manipulating a reference + Reference, + /// ZLib failure + Zlib, + /// Bad repository state + Repository, + /// Bad configuration + Config, + /// Regex failure + Regex, + /// Bad object + Odb, + /// Invalid index data + Index, + /// Error creating or obtaining an object + Object, + /// Network error + Net, + /// Error manipulating a tag + Tag, + /// Invalid value in tree + Tree, + /// Hashing or packing error + Indexer, + /// Error from SSL + Ssl, + /// Error involving submodules + Submodule, + /// Threading error + Thread, + /// Error manipulating a stash + Stash, + /// Checkout failure + Checkout, + /// Invalid FETCH_HEAD + FetchHead, + /// Merge failure + Merge, + /// SSH failure + Ssh, + /// Error manipulating filters + Filter, + /// Error reverting commit + Revert, + /// Error from a user callback + Callback, + /// Error cherry-picking commit + CherryPick, + /// Can't describe object + Describe, + /// Error during rebase + Rebase, + /// Filesystem-related error + Filesystem, + /// Invalid patch data + Patch, + /// Error involving worktrees + Worktree, + /// Hash library error or SHA-1 collision + Sha1, + /// HTTP error + Http, +} + +/// A listing of the possible states that a repository can be in. +#[derive(PartialEq, Eq, Clone, Debug, Copy)] +#[allow(missing_docs)] +pub enum RepositoryState { + Clean, + Merge, + Revert, + RevertSequence, + CherryPick, + CherryPickSequence, + Bisect, + Rebase, + RebaseInteractive, + RebaseMerge, + ApplyMailbox, + ApplyMailboxOrRebase, +} + +/// An enumeration of the possible directions for a remote. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Direction { + /// Data will be fetched (read) from this remote. + Fetch, + /// Data will be pushed (written) to this remote. + Push, +} + +/// An enumeration of the operations that can be performed for the `reset` +/// method on a `Repository`. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ResetType { + /// Move the head to the given commit. + Soft, + /// Soft plus reset the index to the commit. + Mixed, + /// Mixed plus changes in the working tree are discarded. + Hard, +} + +/// An enumeration all possible kinds objects may have. +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub enum ObjectType { + /// Any kind of git object + Any, + /// An object which corresponds to a git commit + Commit, + /// An object which corresponds to a git tree + Tree, + /// An object which corresponds to a git blob + Blob, + /// An object which corresponds to a git tag + Tag, +} + +/// An enumeration of all possible kinds of references. +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub enum ReferenceType { + /// A reference which points at an object id. + Direct, + + /// A reference which points at another reference. + Symbolic, +} + +/// An enumeration for the possible types of branches +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum BranchType { + /// A local branch not on a remote. + Local, + /// A branch for a remote. + Remote, +} + +/// An enumeration of the possible priority levels of a config file. +/// +/// The levels corresponding to the escalation logic (higher to lower) when +/// searching for config entries. +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum ConfigLevel { + /// System-wide on Windows, for compatibility with portable git + ProgramData = 1, + /// System-wide configuration file, e.g. /etc/gitconfig + System, + /// XDG-compatible configuration file, e.g. ~/.config/git/config + XDG, + /// User-specific configuration, e.g. ~/.gitconfig + Global, + /// Repository specific config, e.g. $PWD/.git/config + Local, + /// Application specific configuration file + App, + /// Highest level available + Highest = -1, +} + +/// Merge file favor options for `MergeOptions` instruct the file-level +/// merging functionality how to deal with conflicting regions of the files. +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum FileFavor { + /// When a region of a file is changed in both branches, a conflict will be + /// recorded in the index so that git_checkout can produce a merge file with + /// conflict markers in the working directory. This is the default. + Normal, + /// When a region of a file is changed in both branches, the file created + /// in the index will contain the "ours" side of any conflicting region. + /// The index will not record a conflict. + Ours, + /// When a region of a file is changed in both branches, the file created + /// in the index will contain the "theirs" side of any conflicting region. + /// The index will not record a conflict. + Theirs, + /// When a region of a file is changed in both branches, the file created + /// in the index will contain each unique line from each side, which has + /// the result of combining both files. The index will not record a conflict. + Union, +} + +bitflags! { + /// Orderings that may be specified for Revwalk iteration. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct Sort: u32 { + /// Sort the repository contents in no particular ordering. + /// + /// This sorting is arbitrary, implementation-specific, and subject to + /// change at any time. This is the default sorting for new walkers. + const NONE = raw::GIT_SORT_NONE as u32; + + /// Sort the repository contents in topological order (children before + /// parents). + /// + /// This sorting mode can be combined with time sorting. + const TOPOLOGICAL = raw::GIT_SORT_TOPOLOGICAL as u32; + + /// Sort the repository contents by commit time. + /// + /// This sorting mode can be combined with topological sorting. + const TIME = raw::GIT_SORT_TIME as u32; + + /// Iterate through the repository contents in reverse order. + /// + /// This sorting mode can be combined with any others. + const REVERSE = raw::GIT_SORT_REVERSE as u32; + } +} + +impl Sort { + is_bit_set!(is_none, Sort::NONE); + is_bit_set!(is_topological, Sort::TOPOLOGICAL); + is_bit_set!(is_time, Sort::TIME); + is_bit_set!(is_reverse, Sort::REVERSE); +} + +bitflags! { + /// Types of credentials that can be requested by a credential callback. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct CredentialType: u32 { + #[allow(missing_docs)] + const USER_PASS_PLAINTEXT = raw::GIT_CREDTYPE_USERPASS_PLAINTEXT as u32; + #[allow(missing_docs)] + const SSH_KEY = raw::GIT_CREDTYPE_SSH_KEY as u32; + #[allow(missing_docs)] + const SSH_MEMORY = raw::GIT_CREDTYPE_SSH_MEMORY as u32; + #[allow(missing_docs)] + const SSH_CUSTOM = raw::GIT_CREDTYPE_SSH_CUSTOM as u32; + #[allow(missing_docs)] + const DEFAULT = raw::GIT_CREDTYPE_DEFAULT as u32; + #[allow(missing_docs)] + const SSH_INTERACTIVE = raw::GIT_CREDTYPE_SSH_INTERACTIVE as u32; + #[allow(missing_docs)] + const USERNAME = raw::GIT_CREDTYPE_USERNAME as u32; + } +} + +impl CredentialType { + is_bit_set!(is_user_pass_plaintext, CredentialType::USER_PASS_PLAINTEXT); + is_bit_set!(is_ssh_key, CredentialType::SSH_KEY); + is_bit_set!(is_ssh_memory, CredentialType::SSH_MEMORY); + is_bit_set!(is_ssh_custom, CredentialType::SSH_CUSTOM); + is_bit_set!(is_default, CredentialType::DEFAULT); + is_bit_set!(is_ssh_interactive, CredentialType::SSH_INTERACTIVE); + is_bit_set!(is_username, CredentialType::USERNAME); +} + +impl Default for CredentialType { + fn default() -> Self { + CredentialType::DEFAULT + } +} + +bitflags! { + /// Flags for the `flags` field of an IndexEntry. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct IndexEntryFlag: u16 { + /// Set when the `extended_flags` field is valid. + const EXTENDED = raw::GIT_INDEX_ENTRY_EXTENDED as u16; + /// "Assume valid" flag + const VALID = raw::GIT_INDEX_ENTRY_VALID as u16; + } +} + +impl IndexEntryFlag { + is_bit_set!(is_extended, IndexEntryFlag::EXTENDED); + is_bit_set!(is_valid, IndexEntryFlag::VALID); +} + +bitflags! { + /// Flags for the `extended_flags` field of an IndexEntry. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct IndexEntryExtendedFlag: u16 { + /// An "intent to add" entry from "git add -N" + const INTENT_TO_ADD = raw::GIT_INDEX_ENTRY_INTENT_TO_ADD as u16; + /// Skip the associated worktree file, for sparse checkouts + const SKIP_WORKTREE = raw::GIT_INDEX_ENTRY_SKIP_WORKTREE as u16; + + #[allow(missing_docs)] + const UPTODATE = raw::GIT_INDEX_ENTRY_UPTODATE as u16; + } +} + +impl IndexEntryExtendedFlag { + is_bit_set!(is_intent_to_add, IndexEntryExtendedFlag::INTENT_TO_ADD); + is_bit_set!(is_skip_worktree, IndexEntryExtendedFlag::SKIP_WORKTREE); + is_bit_set!(is_up_to_date, IndexEntryExtendedFlag::UPTODATE); +} + +bitflags! { + /// Flags for APIs that add files matching pathspec + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct IndexAddOption: u32 { + #[allow(missing_docs)] + const DEFAULT = raw::GIT_INDEX_ADD_DEFAULT as u32; + #[allow(missing_docs)] + const FORCE = raw::GIT_INDEX_ADD_FORCE as u32; + #[allow(missing_docs)] + const DISABLE_PATHSPEC_MATCH = + raw::GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH as u32; + #[allow(missing_docs)] + const CHECK_PATHSPEC = raw::GIT_INDEX_ADD_CHECK_PATHSPEC as u32; + } +} + +impl IndexAddOption { + is_bit_set!(is_default, IndexAddOption::DEFAULT); + is_bit_set!(is_force, IndexAddOption::FORCE); + is_bit_set!( + is_disable_pathspec_match, + IndexAddOption::DISABLE_PATHSPEC_MATCH + ); + is_bit_set!(is_check_pathspec, IndexAddOption::CHECK_PATHSPEC); +} + +impl Default for IndexAddOption { + fn default() -> Self { + IndexAddOption::DEFAULT + } +} + +bitflags! { + /// Flags for `Repository::open_ext` + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct RepositoryOpenFlags: u32 { + /// Only open the specified path; don't walk upward searching. + const NO_SEARCH = raw::GIT_REPOSITORY_OPEN_NO_SEARCH as u32; + /// Search across filesystem boundaries. + const CROSS_FS = raw::GIT_REPOSITORY_OPEN_CROSS_FS as u32; + /// Force opening as bare repository, and defer loading its config. + const BARE = raw::GIT_REPOSITORY_OPEN_BARE as u32; + /// Don't try appending `/.git` to the specified repository path. + const NO_DOTGIT = raw::GIT_REPOSITORY_OPEN_NO_DOTGIT as u32; + /// Respect environment variables like `$GIT_DIR`. + const FROM_ENV = raw::GIT_REPOSITORY_OPEN_FROM_ENV as u32; + } +} + +impl RepositoryOpenFlags { + is_bit_set!(is_no_search, RepositoryOpenFlags::NO_SEARCH); + is_bit_set!(is_cross_fs, RepositoryOpenFlags::CROSS_FS); + is_bit_set!(is_bare, RepositoryOpenFlags::BARE); + is_bit_set!(is_no_dotgit, RepositoryOpenFlags::NO_DOTGIT); + is_bit_set!(is_from_env, RepositoryOpenFlags::FROM_ENV); +} + +bitflags! { + /// Flags for the return value of `Repository::revparse` + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct RevparseMode: u32 { + /// The spec targeted a single object + const SINGLE = raw::GIT_REVPARSE_SINGLE as u32; + /// The spec targeted a range of commits + const RANGE = raw::GIT_REVPARSE_RANGE as u32; + /// The spec used the `...` operator, which invokes special semantics. + const MERGE_BASE = raw::GIT_REVPARSE_MERGE_BASE as u32; + } +} + +impl RevparseMode { + is_bit_set!(is_no_single, RevparseMode::SINGLE); + is_bit_set!(is_range, RevparseMode::RANGE); + is_bit_set!(is_merge_base, RevparseMode::MERGE_BASE); +} + +bitflags! { + /// The results of `merge_analysis` indicating the merge opportunities. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct MergeAnalysis: u32 { + /// No merge is possible. + const ANALYSIS_NONE = raw::GIT_MERGE_ANALYSIS_NONE as u32; + /// A "normal" merge; both HEAD and the given merge input have diverged + /// from their common ancestor. The divergent commits must be merged. + const ANALYSIS_NORMAL = raw::GIT_MERGE_ANALYSIS_NORMAL as u32; + /// All given merge inputs are reachable from HEAD, meaning the + /// repository is up-to-date and no merge needs to be performed. + const ANALYSIS_UP_TO_DATE = raw::GIT_MERGE_ANALYSIS_UP_TO_DATE as u32; + /// The given merge input is a fast-forward from HEAD and no merge + /// needs to be performed. Instead, the client can check out the + /// given merge input. + const ANALYSIS_FASTFORWARD = raw::GIT_MERGE_ANALYSIS_FASTFORWARD as u32; + /// The HEAD of the current repository is "unborn" and does not point to + /// a valid commit. No merge can be performed, but the caller may wish + /// to simply set HEAD to the target commit(s). + const ANALYSIS_UNBORN = raw::GIT_MERGE_ANALYSIS_UNBORN as u32; + } +} + +impl MergeAnalysis { + is_bit_set!(is_none, MergeAnalysis::ANALYSIS_NONE); + is_bit_set!(is_normal, MergeAnalysis::ANALYSIS_NORMAL); + is_bit_set!(is_up_to_date, MergeAnalysis::ANALYSIS_UP_TO_DATE); + is_bit_set!(is_fast_forward, MergeAnalysis::ANALYSIS_FASTFORWARD); + is_bit_set!(is_unborn, MergeAnalysis::ANALYSIS_UNBORN); +} + +bitflags! { + /// The user's stated preference for merges. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct MergePreference: u32 { + /// No configuration was found that suggests a preferred behavior for + /// merge. + const NONE = raw::GIT_MERGE_PREFERENCE_NONE as u32; + /// There is a `merge.ff=false` configuration setting, suggesting that + /// the user does not want to allow a fast-forward merge. + const NO_FAST_FORWARD = raw::GIT_MERGE_PREFERENCE_NO_FASTFORWARD as u32; + /// There is a `merge.ff=only` configuration setting, suggesting that + /// the user only wants fast-forward merges. + const FASTFORWARD_ONLY = raw::GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY as u32; + } +} + +impl MergePreference { + is_bit_set!(is_none, MergePreference::NONE); + is_bit_set!(is_no_fast_forward, MergePreference::NO_FAST_FORWARD); + is_bit_set!(is_fastforward_only, MergePreference::FASTFORWARD_ONLY); +} + +bitflags! { + /// Flags controlling the behavior of ODB lookup operations + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct OdbLookupFlags: u32 { + /// Don't call `git_odb_refresh` if the lookup fails. Useful when doing + /// a batch of lookup operations for objects that may legitimately not + /// exist. When using this flag, you may wish to manually call + /// `git_odb_refresh` before processing a batch of objects. + const NO_REFRESH = raw::GIT_ODB_LOOKUP_NO_REFRESH as u32; + } +} + +#[cfg(test)] +#[macro_use] +mod test; +#[macro_use] +mod panic; +mod attr; +mod call; +mod util; + +pub mod build; +pub mod cert; +pub mod oid_array; +pub mod opts; +pub mod string_array; +pub mod transport; + +mod apply; +mod blame; +mod blob; +mod branch; +mod buf; +mod cherrypick; +mod commit; +mod config; +mod cred; +mod describe; +mod diff; +mod email; +mod error; +mod index; +mod indexer; +mod mailmap; +mod mempack; +mod merge; +mod message; +mod note; +mod object; +mod odb; +mod oid; +mod packbuilder; +mod patch; +mod pathspec; +mod proxy_options; +mod push_update; +mod rebase; +mod reference; +mod reflog; +mod refspec; +mod remote; +mod remote_callbacks; +mod repo; +mod revert; +mod revspec; +mod revwalk; +mod signature; +mod stash; +mod status; +mod submodule; +mod tag; +mod tagforeach; +mod time; +mod tracing; +mod transaction; +mod tree; +mod treebuilder; +mod version; +mod worktree; + +fn init() { + static INIT: Once = Once::new(); + + INIT.call_once(|| { + openssl_env_init(); + }); + + raw::init(); +} + +#[cfg(all( + unix, + not(target_os = "macos"), + not(target_os = "ios"), + feature = "https" +))] +fn openssl_env_init() { + // Currently, libgit2 leverages OpenSSL for SSL support when cloning + // repositories over HTTPS. This means that we're picking up an OpenSSL + // dependency on non-Windows platforms (where it has its own HTTPS + // subsystem). As a result, we need to link to OpenSSL. + // + // Now actually *linking* to OpenSSL isn't so hard. We just need to make + // sure to use pkg-config to discover any relevant system dependencies for + // differences between distributions like CentOS and Ubuntu. The actual + // trickiness comes about when we start *distributing* the resulting + // binaries. Currently Cargo is distributed in binary form as nightlies, + // which means we're distributing a binary with OpenSSL linked in. + // + // For historical reasons, the Linux nightly builder is running a CentOS + // distribution in order to have as much ABI compatibility with other + // distributions as possible. Sadly, however, this compatibility does not + // extend to OpenSSL. Currently OpenSSL has two major versions, 0.9 and 1.0, + // which are incompatible (many ABI differences). The CentOS builder we + // build on has version 1.0, as do most distributions today. Some still have + // 0.9, however. This means that if we are to distribute the binaries built + // by the CentOS machine, we would only be compatible with OpenSSL 1.0 and + // we would fail to run (a dynamic linker error at runtime) on systems with + // only 9.8 installed (hopefully). + // + // But wait, the plot thickens! Apparently CentOS has dubbed their OpenSSL + // library as `libssl.so.10`, notably the `10` is included at the end. On + // the other hand Ubuntu, for example, only distributes `libssl.so`. This + // means that the binaries created at CentOS are hard-wired to probe for a + // file called `libssl.so.10` at runtime (using the LD_LIBRARY_PATH), which + // will not be found on ubuntu. The conclusion of this is that binaries + // built on CentOS cannot be distributed to Ubuntu and run successfully. + // + // There are a number of sneaky things we could do, including, but not + // limited to: + // + // 1. Create a shim program which runs "just before" cargo runs. The + // responsibility of this shim program would be to locate `libssl.so`, + // whatever it's called, on the current system, make sure there's a + // symlink *somewhere* called `libssl.so.10`, and then set up + // LD_LIBRARY_PATH and run the actual cargo. + // + // This approach definitely seems unconventional, and is borderline + // overkill for this problem. It's also dubious if we can find a + // libssl.so reliably on the target system. + // + // 2. Somehow re-work the CentOS installation so that the linked-against + // library is called libssl.so instead of libssl.so.10 + // + // The problem with this approach is that systems with 0.9 installed will + // start to silently fail, due to also having libraries called libssl.so + // (probably symlinked under a more appropriate version). + // + // 3. Compile Cargo against both OpenSSL 1.0 *and* OpenSSL 0.9, and + // distribute both. Also make sure that the linked-against name of the + // library is `libssl.so`. At runtime we determine which version is + // installed, and we then the appropriate binary. + // + // This approach clearly has drawbacks in terms of infrastructure and + // feasibility. + // + // 4. Build a nightly of Cargo for each distribution we'd like to support. + // You would then pick the appropriate Cargo nightly to install locally. + // + // So, with all this in mind, the decision was made to *statically* link + // OpenSSL. This solves any problem of relying on a downstream OpenSSL + // version being available. This does, however, open a can of worms related + // to security issues. It's generally a good idea to dynamically link + // OpenSSL as you'll get security updates over time without having to do + // anything (the system administrator will update the local openssl + // package). By statically linking, we're forfeiting this feature. + // + // The conclusion was made it is likely appropriate for the Cargo nightlies + // to statically link OpenSSL, but highly encourage distributions and + // packagers of Cargo to dynamically link OpenSSL. Packagers are targeting + // one system and are distributing to only that system, so none of the + // problems mentioned above would arise. + // + // In order to support this, a new package was made: openssl-static-sys. + // This package currently performs a fairly simple task: + // + // 1. Run pkg-config to discover where openssl is installed. + // 2. If openssl is installed in a nonstandard location, *and* static copies + // of the libraries are available, copy them to $OUT_DIR. + // + // This library will bring in libssl.a and libcrypto.a into the local build, + // allowing them to be picked up by this crate. This allows us to configure + // our own buildbots to have pkg-config point to these local pre-built + // copies of a static OpenSSL (with very few dependencies) while allowing + // most other builds of Cargo to naturally dynamically link OpenSSL. + // + // So in summary, if you're with me so far, we've statically linked OpenSSL + // to the Cargo binary (or any binary, for that matter) and we're ready to + // distribute it to *all* linux distributions. Remember that our original + // intent for openssl was for HTTPS support, which implies that we need some + // for of CA certificate store to validate certificates. This is normally + // installed in a standard system location. + // + // Unfortunately, as one might imagine, OpenSSL is configured for where this + // standard location is at *build time*, but it often varies widely + // per-system. Consequently, it was discovered that OpenSSL will respect the + // SSL_CERT_FILE and SSL_CERT_DIR environment variables in order to assist + // in discovering the location of this file (hurray!). + // + // So, finally getting to the point, this function solely exists to support + // our static builds of OpenSSL by probing for the "standard system + // location" of certificates and setting relevant environment variable to + // point to them. + // + // Ah, and as a final note, this is only a problem on Linux, not on OS X. On + // OS X the OpenSSL binaries are stable enough that we can just rely on + // dynamic linkage (plus they have some weird modifications to OpenSSL which + // means we wouldn't want to link statically). + openssl_probe::init_ssl_cert_env_vars(); +} + +#[cfg(any( + windows, + target_os = "macos", + target_os = "ios", + not(feature = "https") +))] +fn openssl_env_init() {} + +unsafe fn opt_bytes<'a, T>(_anchor: &'a T, c: *const libc::c_char) -> Option<&'a [u8]> { + if c.is_null() { + None + } else { + Some(CStr::from_ptr(c).to_bytes()) + } +} + +fn opt_cstr<T: IntoCString>(o: Option<T>) -> Result<Option<CString>, Error> { + match o { + Some(s) => s.into_c_string().map(Some), + None => Ok(None), + } +} + +impl ObjectType { + /// Convert an object type to its string representation. + pub fn str(&self) -> &'static str { + unsafe { + let ptr = call!(raw::git_object_type2string(*self)) as *const _; + let data = CStr::from_ptr(ptr).to_bytes(); + str::from_utf8(data).unwrap() + } + } + + /// Determine if the given git_object_t is a valid loose object type. + pub fn is_loose(&self) -> bool { + unsafe { call!(raw::git_object_typeisloose(*self)) == 1 } + } + + /// Convert a raw git_object_t to an ObjectType + pub fn from_raw(raw: raw::git_object_t) -> Option<ObjectType> { + match raw { + raw::GIT_OBJECT_ANY => Some(ObjectType::Any), + raw::GIT_OBJECT_COMMIT => Some(ObjectType::Commit), + raw::GIT_OBJECT_TREE => Some(ObjectType::Tree), + raw::GIT_OBJECT_BLOB => Some(ObjectType::Blob), + raw::GIT_OBJECT_TAG => Some(ObjectType::Tag), + _ => None, + } + } + + /// Convert this kind into its raw representation + pub fn raw(&self) -> raw::git_object_t { + call::convert(self) + } + + /// Convert a string object type representation to its object type. + pub fn from_str(s: &str) -> Option<ObjectType> { + let raw = unsafe { call!(raw::git_object_string2type(CString::new(s).unwrap())) }; + ObjectType::from_raw(raw) + } +} + +impl fmt::Display for ObjectType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.str().fmt(f) + } +} + +impl ReferenceType { + /// Convert an object type to its string representation. + pub fn str(&self) -> &'static str { + match self { + ReferenceType::Direct => "direct", + ReferenceType::Symbolic => "symbolic", + } + } + + /// Convert a raw git_reference_t to a ReferenceType. + pub fn from_raw(raw: raw::git_reference_t) -> Option<ReferenceType> { + match raw { + raw::GIT_REFERENCE_DIRECT => Some(ReferenceType::Direct), + raw::GIT_REFERENCE_SYMBOLIC => Some(ReferenceType::Symbolic), + _ => None, + } + } +} + +impl fmt::Display for ReferenceType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.str().fmt(f) + } +} + +impl ConfigLevel { + /// Converts a raw configuration level to a ConfigLevel + pub fn from_raw(raw: raw::git_config_level_t) -> ConfigLevel { + match raw { + raw::GIT_CONFIG_LEVEL_PROGRAMDATA => ConfigLevel::ProgramData, + raw::GIT_CONFIG_LEVEL_SYSTEM => ConfigLevel::System, + raw::GIT_CONFIG_LEVEL_XDG => ConfigLevel::XDG, + raw::GIT_CONFIG_LEVEL_GLOBAL => ConfigLevel::Global, + raw::GIT_CONFIG_LEVEL_LOCAL => ConfigLevel::Local, + raw::GIT_CONFIG_LEVEL_APP => ConfigLevel::App, + raw::GIT_CONFIG_HIGHEST_LEVEL => ConfigLevel::Highest, + n => panic!("unknown config level: {}", n), + } + } +} + +impl SubmoduleIgnore { + /// Converts a [`raw::git_submodule_ignore_t`] to a [`SubmoduleIgnore`] + pub fn from_raw(raw: raw::git_submodule_ignore_t) -> Self { + match raw { + raw::GIT_SUBMODULE_IGNORE_UNSPECIFIED => SubmoduleIgnore::Unspecified, + raw::GIT_SUBMODULE_IGNORE_NONE => SubmoduleIgnore::None, + raw::GIT_SUBMODULE_IGNORE_UNTRACKED => SubmoduleIgnore::Untracked, + raw::GIT_SUBMODULE_IGNORE_DIRTY => SubmoduleIgnore::Dirty, + raw::GIT_SUBMODULE_IGNORE_ALL => SubmoduleIgnore::All, + n => panic!("unknown submodule ignore rule: {}", n), + } + } +} + +impl SubmoduleUpdate { + /// Converts a [`raw::git_submodule_update_t`] to a [`SubmoduleUpdate`] + pub fn from_raw(raw: raw::git_submodule_update_t) -> Self { + match raw { + raw::GIT_SUBMODULE_UPDATE_CHECKOUT => SubmoduleUpdate::Checkout, + raw::GIT_SUBMODULE_UPDATE_REBASE => SubmoduleUpdate::Rebase, + raw::GIT_SUBMODULE_UPDATE_MERGE => SubmoduleUpdate::Merge, + raw::GIT_SUBMODULE_UPDATE_NONE => SubmoduleUpdate::None, + raw::GIT_SUBMODULE_UPDATE_DEFAULT => SubmoduleUpdate::Default, + n => panic!("unknown submodule update strategy: {}", n), + } + } +} + +bitflags! { + /// Status flags for a single file + /// + /// A combination of these values will be returned to indicate the status of + /// a file. Status compares the working directory, the index, and the + /// current HEAD of the repository. The `STATUS_INDEX_*` set of flags + /// represents the status of file in the index relative to the HEAD, and the + /// `STATUS_WT_*` set of flags represent the status of the file in the + /// working directory relative to the index. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct Status: u32 { + #[allow(missing_docs)] + const CURRENT = raw::GIT_STATUS_CURRENT as u32; + + #[allow(missing_docs)] + const INDEX_NEW = raw::GIT_STATUS_INDEX_NEW as u32; + #[allow(missing_docs)] + const INDEX_MODIFIED = raw::GIT_STATUS_INDEX_MODIFIED as u32; + #[allow(missing_docs)] + const INDEX_DELETED = raw::GIT_STATUS_INDEX_DELETED as u32; + #[allow(missing_docs)] + const INDEX_RENAMED = raw::GIT_STATUS_INDEX_RENAMED as u32; + #[allow(missing_docs)] + const INDEX_TYPECHANGE = raw::GIT_STATUS_INDEX_TYPECHANGE as u32; + + #[allow(missing_docs)] + const WT_NEW = raw::GIT_STATUS_WT_NEW as u32; + #[allow(missing_docs)] + const WT_MODIFIED = raw::GIT_STATUS_WT_MODIFIED as u32; + #[allow(missing_docs)] + const WT_DELETED = raw::GIT_STATUS_WT_DELETED as u32; + #[allow(missing_docs)] + const WT_TYPECHANGE = raw::GIT_STATUS_WT_TYPECHANGE as u32; + #[allow(missing_docs)] + const WT_RENAMED = raw::GIT_STATUS_WT_RENAMED as u32; + + #[allow(missing_docs)] + const IGNORED = raw::GIT_STATUS_IGNORED as u32; + #[allow(missing_docs)] + const CONFLICTED = raw::GIT_STATUS_CONFLICTED as u32; + } +} + +impl Status { + is_bit_set!(is_index_new, Status::INDEX_NEW); + is_bit_set!(is_index_modified, Status::INDEX_MODIFIED); + is_bit_set!(is_index_deleted, Status::INDEX_DELETED); + is_bit_set!(is_index_renamed, Status::INDEX_RENAMED); + is_bit_set!(is_index_typechange, Status::INDEX_TYPECHANGE); + is_bit_set!(is_wt_new, Status::WT_NEW); + is_bit_set!(is_wt_modified, Status::WT_MODIFIED); + is_bit_set!(is_wt_deleted, Status::WT_DELETED); + is_bit_set!(is_wt_typechange, Status::WT_TYPECHANGE); + is_bit_set!(is_wt_renamed, Status::WT_RENAMED); + is_bit_set!(is_ignored, Status::IGNORED); + is_bit_set!(is_conflicted, Status::CONFLICTED); +} + +bitflags! { + /// Mode options for RepositoryInitOptions + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct RepositoryInitMode: u32 { + /// Use permissions configured by umask - the default + const SHARED_UMASK = raw::GIT_REPOSITORY_INIT_SHARED_UMASK as u32; + /// Use `--shared=group` behavior, chmod'ing the new repo to be + /// group writable and \"g+sx\" for sticky group assignment + const SHARED_GROUP = raw::GIT_REPOSITORY_INIT_SHARED_GROUP as u32; + /// Use `--shared=all` behavior, adding world readability. + const SHARED_ALL = raw::GIT_REPOSITORY_INIT_SHARED_ALL as u32; + } +} + +impl RepositoryInitMode { + is_bit_set!(is_shared_umask, RepositoryInitMode::SHARED_UMASK); + is_bit_set!(is_shared_group, RepositoryInitMode::SHARED_GROUP); + is_bit_set!(is_shared_all, RepositoryInitMode::SHARED_ALL); +} + +/// What type of change is described by a `DiffDelta`? +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Delta { + /// No changes + Unmodified, + /// Entry does not exist in old version + Added, + /// Entry does not exist in new version + Deleted, + /// Entry content changed between old and new + Modified, + /// Entry was renamed between old and new + Renamed, + /// Entry was copied from another old entry + Copied, + /// Entry is ignored item in workdir + Ignored, + /// Entry is untracked item in workdir + Untracked, + /// Type of entry changed between old and new + Typechange, + /// Entry is unreadable + Unreadable, + /// Entry in the index is conflicted + Conflicted, +} + +/// Valid modes for index and tree entries. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum FileMode { + /// Unreadable + Unreadable, + /// Tree + Tree, + /// Blob + Blob, + /// Group writable blob. Obsolete mode kept for compatibility reasons + BlobGroupWritable, + /// Blob executable + BlobExecutable, + /// Link + Link, + /// Commit + Commit, +} + +impl From<FileMode> for i32 { + fn from(mode: FileMode) -> i32 { + match mode { + FileMode::Unreadable => raw::GIT_FILEMODE_UNREADABLE as i32, + FileMode::Tree => raw::GIT_FILEMODE_TREE as i32, + FileMode::Blob => raw::GIT_FILEMODE_BLOB as i32, + FileMode::BlobGroupWritable => raw::GIT_FILEMODE_BLOB_GROUP_WRITABLE as i32, + FileMode::BlobExecutable => raw::GIT_FILEMODE_BLOB_EXECUTABLE as i32, + FileMode::Link => raw::GIT_FILEMODE_LINK as i32, + FileMode::Commit => raw::GIT_FILEMODE_COMMIT as i32, + } + } +} + +impl From<FileMode> for u32 { + fn from(mode: FileMode) -> u32 { + match mode { + FileMode::Unreadable => raw::GIT_FILEMODE_UNREADABLE as u32, + FileMode::Tree => raw::GIT_FILEMODE_TREE as u32, + FileMode::Blob => raw::GIT_FILEMODE_BLOB as u32, + FileMode::BlobGroupWritable => raw::GIT_FILEMODE_BLOB_GROUP_WRITABLE as u32, + FileMode::BlobExecutable => raw::GIT_FILEMODE_BLOB_EXECUTABLE as u32, + FileMode::Link => raw::GIT_FILEMODE_LINK as u32, + FileMode::Commit => raw::GIT_FILEMODE_COMMIT as u32, + } + } +} + +bitflags! { + /// Return codes for submodule status. + /// + /// A combination of these flags will be returned to describe the status of a + /// submodule. Depending on the "ignore" property of the submodule, some of + /// the flags may never be returned because they indicate changes that are + /// supposed to be ignored. + /// + /// Submodule info is contained in 4 places: the HEAD tree, the index, config + /// files (both .git/config and .gitmodules), and the working directory. Any + /// or all of those places might be missing information about the submodule + /// depending on what state the repo is in. We consider all four places to + /// build the combination of status flags. + /// + /// There are four values that are not really status, but give basic info + /// about what sources of submodule data are available. These will be + /// returned even if ignore is set to "ALL". + /// + /// * IN_HEAD - superproject head contains submodule + /// * IN_INDEX - superproject index contains submodule + /// * IN_CONFIG - superproject gitmodules has submodule + /// * IN_WD - superproject workdir has submodule + /// + /// The following values will be returned so long as ignore is not "ALL". + /// + /// * INDEX_ADDED - in index, not in head + /// * INDEX_DELETED - in head, not in index + /// * INDEX_MODIFIED - index and head don't match + /// * WD_UNINITIALIZED - workdir contains empty directory + /// * WD_ADDED - in workdir, not index + /// * WD_DELETED - in index, not workdir + /// * WD_MODIFIED - index and workdir head don't match + /// + /// The following can only be returned if ignore is "NONE" or "UNTRACKED". + /// + /// * WD_INDEX_MODIFIED - submodule workdir index is dirty + /// * WD_WD_MODIFIED - submodule workdir has modified files + /// + /// Lastly, the following will only be returned for ignore "NONE". + /// + /// * WD_UNTRACKED - workdir contains untracked files + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct SubmoduleStatus: u32 { + #[allow(missing_docs)] + const IN_HEAD = raw::GIT_SUBMODULE_STATUS_IN_HEAD as u32; + #[allow(missing_docs)] + const IN_INDEX = raw::GIT_SUBMODULE_STATUS_IN_INDEX as u32; + #[allow(missing_docs)] + const IN_CONFIG = raw::GIT_SUBMODULE_STATUS_IN_CONFIG as u32; + #[allow(missing_docs)] + const IN_WD = raw::GIT_SUBMODULE_STATUS_IN_WD as u32; + #[allow(missing_docs)] + const INDEX_ADDED = raw::GIT_SUBMODULE_STATUS_INDEX_ADDED as u32; + #[allow(missing_docs)] + const INDEX_DELETED = raw::GIT_SUBMODULE_STATUS_INDEX_DELETED as u32; + #[allow(missing_docs)] + const INDEX_MODIFIED = raw::GIT_SUBMODULE_STATUS_INDEX_MODIFIED as u32; + #[allow(missing_docs)] + const WD_UNINITIALIZED = + raw::GIT_SUBMODULE_STATUS_WD_UNINITIALIZED as u32; + #[allow(missing_docs)] + const WD_ADDED = raw::GIT_SUBMODULE_STATUS_WD_ADDED as u32; + #[allow(missing_docs)] + const WD_DELETED = raw::GIT_SUBMODULE_STATUS_WD_DELETED as u32; + #[allow(missing_docs)] + const WD_MODIFIED = raw::GIT_SUBMODULE_STATUS_WD_MODIFIED as u32; + #[allow(missing_docs)] + const WD_INDEX_MODIFIED = + raw::GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED as u32; + #[allow(missing_docs)] + const WD_WD_MODIFIED = raw::GIT_SUBMODULE_STATUS_WD_WD_MODIFIED as u32; + #[allow(missing_docs)] + const WD_UNTRACKED = raw::GIT_SUBMODULE_STATUS_WD_UNTRACKED as u32; + } +} + +impl SubmoduleStatus { + is_bit_set!(is_in_head, SubmoduleStatus::IN_HEAD); + is_bit_set!(is_in_index, SubmoduleStatus::IN_INDEX); + is_bit_set!(is_in_config, SubmoduleStatus::IN_CONFIG); + is_bit_set!(is_in_wd, SubmoduleStatus::IN_WD); + is_bit_set!(is_index_added, SubmoduleStatus::INDEX_ADDED); + is_bit_set!(is_index_deleted, SubmoduleStatus::INDEX_DELETED); + is_bit_set!(is_index_modified, SubmoduleStatus::INDEX_MODIFIED); + is_bit_set!(is_wd_uninitialized, SubmoduleStatus::WD_UNINITIALIZED); + is_bit_set!(is_wd_added, SubmoduleStatus::WD_ADDED); + is_bit_set!(is_wd_deleted, SubmoduleStatus::WD_DELETED); + is_bit_set!(is_wd_modified, SubmoduleStatus::WD_MODIFIED); + is_bit_set!(is_wd_wd_modified, SubmoduleStatus::WD_WD_MODIFIED); + is_bit_set!(is_wd_untracked, SubmoduleStatus::WD_UNTRACKED); +} + +/// Submodule ignore values +/// +/// These values represent settings for the `submodule.$name.ignore` +/// configuration value which says how deeply to look at the working +/// directory when getting the submodule status. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum SubmoduleIgnore { + /// Use the submodule's configuration + Unspecified, + /// Any change or untracked file is considered dirty + None, + /// Only dirty if tracked files have changed + Untracked, + /// Only dirty if HEAD has moved + Dirty, + /// Never dirty + All, +} + +/// Submodule update values +/// +/// These values represent settings for the `submodule.$name.update` +/// configuration value which says how to handle `git submodule update` +/// for this submodule. The value is usually set in the ".gitmodules" +/// file and copied to ".git/config" when the submodule is initialized. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum SubmoduleUpdate { + /// The default; when a submodule is updated, checkout the new detached + /// HEAD to the submodule directory. + Checkout, + /// Update by rebasing the current checked out branch onto the commit from + /// the superproject. + Rebase, + /// Update by merging the commit in the superproject into the current + /// checkout out branch of the submodule. + Merge, + /// Do not update this submodule even when the commit in the superproject + /// is updated. + None, + /// Not used except as static initializer when we don't want any particular + /// update rule to be specified. + Default, +} + +bitflags! { + /// ... + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct PathspecFlags: u32 { + /// Use the default pathspec matching configuration. + const DEFAULT = raw::GIT_PATHSPEC_DEFAULT as u32; + /// Force matching to ignore case, otherwise matching will use native + /// case sensitivity of the platform filesystem. + const IGNORE_CASE = raw::GIT_PATHSPEC_IGNORE_CASE as u32; + /// Force case sensitive matches, otherwise match will use the native + /// case sensitivity of the platform filesystem. + const USE_CASE = raw::GIT_PATHSPEC_USE_CASE as u32; + /// Disable glob patterns and just use simple string comparison for + /// matching. + const NO_GLOB = raw::GIT_PATHSPEC_NO_GLOB as u32; + /// Means that match functions return the error code `NotFound` if no + /// matches are found. By default no matches is a success. + const NO_MATCH_ERROR = raw::GIT_PATHSPEC_NO_MATCH_ERROR as u32; + /// Means that the list returned should track which patterns matched + /// which files so that at the end of the match we can identify patterns + /// that did not match any files. + const FIND_FAILURES = raw::GIT_PATHSPEC_FIND_FAILURES as u32; + /// Means that the list returned does not need to keep the actual + /// matching filenames. Use this to just test if there were any matches + /// at all or in combination with `PATHSPEC_FAILURES` to validate a + /// pathspec. + const FAILURES_ONLY = raw::GIT_PATHSPEC_FAILURES_ONLY as u32; + } +} + +impl PathspecFlags { + is_bit_set!(is_default, PathspecFlags::DEFAULT); + is_bit_set!(is_ignore_case, PathspecFlags::IGNORE_CASE); + is_bit_set!(is_use_case, PathspecFlags::USE_CASE); + is_bit_set!(is_no_glob, PathspecFlags::NO_GLOB); + is_bit_set!(is_no_match_error, PathspecFlags::NO_MATCH_ERROR); + is_bit_set!(is_find_failures, PathspecFlags::FIND_FAILURES); + is_bit_set!(is_failures_only, PathspecFlags::FAILURES_ONLY); +} + +impl Default for PathspecFlags { + fn default() -> Self { + PathspecFlags::DEFAULT + } +} + +bitflags! { + /// Types of notifications emitted from checkouts. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct CheckoutNotificationType: u32 { + /// Notification about a conflict. + const CONFLICT = raw::GIT_CHECKOUT_NOTIFY_CONFLICT as u32; + /// Notification about a dirty file. + const DIRTY = raw::GIT_CHECKOUT_NOTIFY_DIRTY as u32; + /// Notification about an updated file. + const UPDATED = raw::GIT_CHECKOUT_NOTIFY_UPDATED as u32; + /// Notification about an untracked file. + const UNTRACKED = raw::GIT_CHECKOUT_NOTIFY_UNTRACKED as u32; + /// Notification about an ignored file. + const IGNORED = raw::GIT_CHECKOUT_NOTIFY_IGNORED as u32; + } +} + +impl CheckoutNotificationType { + is_bit_set!(is_conflict, CheckoutNotificationType::CONFLICT); + is_bit_set!(is_dirty, CheckoutNotificationType::DIRTY); + is_bit_set!(is_updated, CheckoutNotificationType::UPDATED); + is_bit_set!(is_untracked, CheckoutNotificationType::UNTRACKED); + is_bit_set!(is_ignored, CheckoutNotificationType::IGNORED); +} + +/// Possible output formats for diff data +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum DiffFormat { + /// full git diff + Patch, + /// just the headers of the patch + PatchHeader, + /// like git diff --raw + Raw, + /// like git diff --name-only + NameOnly, + /// like git diff --name-status + NameStatus, + /// git diff as used by git patch-id + PatchId, +} + +bitflags! { + /// Formatting options for diff stats + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct DiffStatsFormat: raw::git_diff_stats_format_t { + /// Don't generate any stats + const NONE = raw::GIT_DIFF_STATS_NONE; + /// Equivalent of `--stat` in git + const FULL = raw::GIT_DIFF_STATS_FULL; + /// Equivalent of `--shortstat` in git + const SHORT = raw::GIT_DIFF_STATS_SHORT; + /// Equivalent of `--numstat` in git + const NUMBER = raw::GIT_DIFF_STATS_NUMBER; + /// Extended header information such as creations, renames and mode + /// changes, equivalent of `--summary` in git + const INCLUDE_SUMMARY = raw::GIT_DIFF_STATS_INCLUDE_SUMMARY; + } +} + +impl DiffStatsFormat { + is_bit_set!(is_none, DiffStatsFormat::NONE); + is_bit_set!(is_full, DiffStatsFormat::FULL); + is_bit_set!(is_short, DiffStatsFormat::SHORT); + is_bit_set!(is_number, DiffStatsFormat::NUMBER); + is_bit_set!(is_include_summary, DiffStatsFormat::INCLUDE_SUMMARY); +} + +/// Automatic tag following options. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum AutotagOption { + /// Use the setting from the remote's configuration + Unspecified, + /// Ask the server for tags pointing to objects we're already downloading + Auto, + /// Don't ask for any tags beyond the refspecs + None, + /// Ask for all the tags + All, +} + +/// Configuration for how pruning is done on a fetch +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum FetchPrune { + /// Use the setting from the configuration + Unspecified, + /// Force pruning on + On, + /// Force pruning off + Off, +} + +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum StashApplyProgress { + /// None + None, + /// Loading the stashed data from the object database + LoadingStash, + /// The stored index is being analyzed + AnalyzeIndex, + /// The modified files are being analyzed + AnalyzeModified, + /// The untracked and ignored files are being analyzed + AnalyzeUntracked, + /// The untracked files are being written to disk + CheckoutUntracked, + /// The modified files are being written to disk + CheckoutModified, + /// The stash was applied successfully + Done, +} + +bitflags! { + #[allow(missing_docs)] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct StashApplyFlags: u32 { + #[allow(missing_docs)] + const DEFAULT = raw::GIT_STASH_APPLY_DEFAULT as u32; + /// Try to reinstate not only the working tree's changes, + /// but also the index's changes. + const REINSTATE_INDEX = raw::GIT_STASH_APPLY_REINSTATE_INDEX as u32; + } +} + +impl StashApplyFlags { + is_bit_set!(is_default, StashApplyFlags::DEFAULT); + is_bit_set!(is_reinstate_index, StashApplyFlags::REINSTATE_INDEX); +} + +impl Default for StashApplyFlags { + fn default() -> Self { + StashApplyFlags::DEFAULT + } +} + +bitflags! { + #[allow(missing_docs)] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct StashFlags: u32 { + #[allow(missing_docs)] + const DEFAULT = raw::GIT_STASH_DEFAULT as u32; + /// All changes already added to the index are left intact in + /// the working directory + const KEEP_INDEX = raw::GIT_STASH_KEEP_INDEX as u32; + /// All untracked files are also stashed and then cleaned up + /// from the working directory + const INCLUDE_UNTRACKED = raw::GIT_STASH_INCLUDE_UNTRACKED as u32; + /// All ignored files are also stashed and then cleaned up from + /// the working directory + const INCLUDE_IGNORED = raw::GIT_STASH_INCLUDE_IGNORED as u32; + /// All changes in the index and working directory are left intact + const KEEP_ALL = raw::GIT_STASH_KEEP_ALL as u32; + } +} + +impl StashFlags { + is_bit_set!(is_default, StashFlags::DEFAULT); + is_bit_set!(is_keep_index, StashFlags::KEEP_INDEX); + is_bit_set!(is_include_untracked, StashFlags::INCLUDE_UNTRACKED); + is_bit_set!(is_include_ignored, StashFlags::INCLUDE_IGNORED); +} + +impl Default for StashFlags { + fn default() -> Self { + StashFlags::DEFAULT + } +} + +bitflags! { + #[allow(missing_docs)] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct AttrCheckFlags: u32 { + /// Check the working directory, then the index. + const FILE_THEN_INDEX = raw::GIT_ATTR_CHECK_FILE_THEN_INDEX as u32; + /// Check the index, then the working directory. + const INDEX_THEN_FILE = raw::GIT_ATTR_CHECK_INDEX_THEN_FILE as u32; + /// Check the index only. + const INDEX_ONLY = raw::GIT_ATTR_CHECK_INDEX_ONLY as u32; + /// Do not use the system gitattributes file. + const NO_SYSTEM = raw::GIT_ATTR_CHECK_NO_SYSTEM as u32; + } +} + +impl Default for AttrCheckFlags { + fn default() -> Self { + AttrCheckFlags::FILE_THEN_INDEX + } +} + +bitflags! { + #[allow(missing_docs)] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct DiffFlags: u32 { + /// File(s) treated as binary data. + const BINARY = raw::GIT_DIFF_FLAG_BINARY as u32; + /// File(s) treated as text data. + const NOT_BINARY = raw::GIT_DIFF_FLAG_NOT_BINARY as u32; + /// `id` value is known correct. + const VALID_ID = raw::GIT_DIFF_FLAG_VALID_ID as u32; + /// File exists at this side of the delta. + const EXISTS = raw::GIT_DIFF_FLAG_EXISTS as u32; + } +} + +impl DiffFlags { + is_bit_set!(is_binary, DiffFlags::BINARY); + is_bit_set!(is_not_binary, DiffFlags::NOT_BINARY); + is_bit_set!(has_valid_id, DiffFlags::VALID_ID); + is_bit_set!(exists, DiffFlags::EXISTS); +} + +bitflags! { + /// Options for [`Reference::normalize_name`]. + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct ReferenceFormat: u32 { + /// No particular normalization. + const NORMAL = raw::GIT_REFERENCE_FORMAT_NORMAL as u32; + /// Control whether one-level refname are accepted (i.e., refnames that + /// do not contain multiple `/`-separated components). Those are + /// expected to be written only using uppercase letters and underscore + /// (e.g. `HEAD`, `FETCH_HEAD`). + const ALLOW_ONELEVEL = raw::GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL as u32; + /// Interpret the provided name as a reference pattern for a refspec (as + /// used with remote repositories). If this option is enabled, the name + /// is allowed to contain a single `*` in place of a full pathname + /// components (e.g., `foo/*/bar` but not `foo/bar*`). + const REFSPEC_PATTERN = raw::GIT_REFERENCE_FORMAT_REFSPEC_PATTERN as u32; + /// Interpret the name as part of a refspec in shorthand form so the + /// `ALLOW_ONELEVEL` naming rules aren't enforced and `main` becomes a + /// valid name. + const REFSPEC_SHORTHAND = raw::GIT_REFERENCE_FORMAT_REFSPEC_SHORTHAND as u32; + } +} + +impl ReferenceFormat { + is_bit_set!(is_allow_onelevel, ReferenceFormat::ALLOW_ONELEVEL); + is_bit_set!(is_refspec_pattern, ReferenceFormat::REFSPEC_PATTERN); + is_bit_set!(is_refspec_shorthand, ReferenceFormat::REFSPEC_SHORTHAND); +} + +impl Default for ReferenceFormat { + fn default() -> Self { + ReferenceFormat::NORMAL + } +} + +#[cfg(test)] +mod tests { + use super::{FileMode, ObjectType}; + + #[test] + fn convert() { + assert_eq!(ObjectType::Blob.str(), "blob"); + assert_eq!(ObjectType::from_str("blob"), Some(ObjectType::Blob)); + assert!(ObjectType::Blob.is_loose()); + } + + #[test] + fn convert_filemode() { + assert_eq!(i32::from(FileMode::Blob), 0o100644); + assert_eq!(i32::from(FileMode::BlobGroupWritable), 0o100664); + assert_eq!(i32::from(FileMode::BlobExecutable), 0o100755); + assert_eq!(u32::from(FileMode::Blob), 0o100644); + assert_eq!(u32::from(FileMode::BlobGroupWritable), 0o100664); + assert_eq!(u32::from(FileMode::BlobExecutable), 0o100755); + } + + #[test] + fn bitflags_partial_eq() { + use super::{ + AttrCheckFlags, CheckoutNotificationType, CredentialType, DiffFlags, DiffStatsFormat, + IndexAddOption, IndexEntryExtendedFlag, IndexEntryFlag, MergeAnalysis, MergePreference, + OdbLookupFlags, PathspecFlags, ReferenceFormat, RepositoryInitMode, + RepositoryOpenFlags, RevparseMode, Sort, StashApplyFlags, StashFlags, Status, + SubmoduleStatus, + }; + + assert_eq!( + AttrCheckFlags::FILE_THEN_INDEX, + AttrCheckFlags::FILE_THEN_INDEX + ); + assert_eq!( + CheckoutNotificationType::CONFLICT, + CheckoutNotificationType::CONFLICT + ); + assert_eq!( + CredentialType::USER_PASS_PLAINTEXT, + CredentialType::USER_PASS_PLAINTEXT + ); + assert_eq!(DiffFlags::BINARY, DiffFlags::BINARY); + assert_eq!( + DiffStatsFormat::INCLUDE_SUMMARY, + DiffStatsFormat::INCLUDE_SUMMARY + ); + assert_eq!( + IndexAddOption::CHECK_PATHSPEC, + IndexAddOption::CHECK_PATHSPEC + ); + assert_eq!( + IndexEntryExtendedFlag::INTENT_TO_ADD, + IndexEntryExtendedFlag::INTENT_TO_ADD + ); + assert_eq!(IndexEntryFlag::EXTENDED, IndexEntryFlag::EXTENDED); + assert_eq!( + MergeAnalysis::ANALYSIS_FASTFORWARD, + MergeAnalysis::ANALYSIS_FASTFORWARD + ); + assert_eq!( + MergePreference::FASTFORWARD_ONLY, + MergePreference::FASTFORWARD_ONLY + ); + assert_eq!(OdbLookupFlags::NO_REFRESH, OdbLookupFlags::NO_REFRESH); + assert_eq!(PathspecFlags::FAILURES_ONLY, PathspecFlags::FAILURES_ONLY); + assert_eq!( + ReferenceFormat::ALLOW_ONELEVEL, + ReferenceFormat::ALLOW_ONELEVEL + ); + assert_eq!( + RepositoryInitMode::SHARED_ALL, + RepositoryInitMode::SHARED_ALL + ); + assert_eq!(RepositoryOpenFlags::CROSS_FS, RepositoryOpenFlags::CROSS_FS); + assert_eq!(RevparseMode::RANGE, RevparseMode::RANGE); + assert_eq!(Sort::REVERSE, Sort::REVERSE); + assert_eq!( + StashApplyFlags::REINSTATE_INDEX, + StashApplyFlags::REINSTATE_INDEX + ); + assert_eq!(StashFlags::INCLUDE_IGNORED, StashFlags::INCLUDE_IGNORED); + assert_eq!(Status::WT_MODIFIED, Status::WT_MODIFIED); + assert_eq!(SubmoduleStatus::WD_ADDED, SubmoduleStatus::WD_ADDED); + } +} |