Skip to content

Commit 8fbe14b

Browse files
committed
Merge pull request #126 from joshtriplett/git_repository_open_ext
Add binding for git_repository_open_ext
2 parents 0828909 + 5589a1a commit 8fbe14b

File tree

4 files changed

+98
-2
lines changed

4 files changed

+98
-2
lines changed

libgit2-sys/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,14 @@ git_enum! {
820820
}
821821
}
822822

823+
git_enum! {
824+
pub enum git_repository_open_flag_t {
825+
GIT_REPOSITORY_OPEN_NO_SEARCH = (1 << 0),
826+
GIT_REPOSITORY_OPEN_CROSS_FS = (1 << 1),
827+
GIT_REPOSITORY_OPEN_BARE = (1 << 2),
828+
}
829+
}
830+
823831
#[repr(C)]
824832
pub struct git_repository_init_options {
825833
pub version: c_uint,
@@ -1382,6 +1390,10 @@ extern {
13821390
pub fn git_repository_free(repo: *mut git_repository);
13831391
pub fn git_repository_open(repo: *mut *mut git_repository,
13841392
path: *const c_char) -> c_int;
1393+
pub fn git_repository_open_ext(repo: *mut *mut git_repository,
1394+
path: *const c_char,
1395+
flags: c_uint,
1396+
ceiling_dirs: *const c_char) -> c_int;
13851397
pub fn git_repository_init(repo: *mut *mut git_repository,
13861398
path: *const c_char,
13871399
is_bare: c_uint) -> c_int;

src/error.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::env::JoinPathsError;
12
use std::ffi::{CStr, NulError};
23
use std::error;
34
use std::fmt;
@@ -214,6 +215,12 @@ impl From<NulError> for Error {
214215
}
215216
}
216217

218+
impl From<JoinPathsError> for Error {
219+
fn from(e: JoinPathsError) -> Error {
220+
Error::from_str(error::Error::description(&e))
221+
}
222+
}
223+
217224

218225
#[cfg(test)]
219226
mod tests {

src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,20 @@ Flags for APIs that add files matching pathspec
410410
}
411411
}
412412

413+
bitflags! {
414+
#[doc = "
415+
Flags for `Repository::open_ext`
416+
"]
417+
flags RepositoryOpenFlags: u32 {
418+
/// Only open the specified path; don't walk upward searching.
419+
const REPOSITORY_OPEN_NO_SEARCH = raw::GIT_REPOSITORY_OPEN_NO_SEARCH as u32,
420+
/// Search across filesystem boundaries.
421+
const REPOSITORY_OPEN_CROSS_FS = raw::GIT_REPOSITORY_OPEN_CROSS_FS as u32,
422+
/// Force opening as bare repository, and defer loading its config.
423+
const REPOSITORY_OPEN_BARE = raw::GIT_REPOSITORY_OPEN_BARE as u32,
424+
}
425+
}
426+
413427
bitflags! {
414428
#[doc = "
415429
Flags for the return value of `Repository::revparse`

src/repo.rs

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
use std::ffi::{CStr, CString};
1+
use std::env;
2+
use std::ffi::{CStr, CString, OsStr};
23
use std::iter::IntoIterator;
34
use std::mem;
45
use std::path::Path;
56
use std::str;
67
use libc::{c_int, c_char, size_t, c_void, c_uint};
78

8-
use {raw, Revspec, Error, init, Object, RepositoryState, Remote, Buf};
9+
use {raw, Revspec, Error, init, Object, RepositoryOpenFlags, RepositoryState, Remote, Buf};
910
use {ResetType, Signature, Reference, References, Submodule, Blame, BlameOptions};
1011
use {Branches, BranchType, Index, Config, Oid, Blob, Branch, Commit, Tree};
1112
use {AnnotatedCommit, MergeOptions, SubmoduleIgnore, SubmoduleStatus};
@@ -59,6 +60,43 @@ impl Repository {
5960
}
6061
}
6162

63+
/// Find and open an existing repository, with additional options.
64+
///
65+
/// If flags contains REPOSITORY_OPEN_NO_SEARCH, the path must point
66+
/// directly to a repository; otherwise, this may point to a subdirectory
67+
/// of a repository, and `open_ext` will search up through parent
68+
/// directories.
69+
///
70+
/// If flags contains REPOSITORY_OPEN_CROSS_FS, the search through parent
71+
/// directories will not cross a filesystem boundary (detected when the
72+
/// stat st_dev field changes).
73+
///
74+
/// If flags contains REPOSITORY_OPEN_BARE, force opening the repository as
75+
/// bare even if it isn't, ignoring any working directory, and defer
76+
/// loading the repository configuration for performance.
77+
///
78+
/// ceiling_dirs specifies a list of paths that the search through parent
79+
/// directories will stop before entering. Use the functions in std::env
80+
/// to construct or manipulate such a path list.
81+
pub fn open_ext<P, O, I>(path: P,
82+
flags: RepositoryOpenFlags,
83+
ceiling_dirs: I)
84+
-> Result<Repository, Error>
85+
where P: AsRef<Path>, O: AsRef<OsStr>, I: IntoIterator<Item=O> {
86+
init();
87+
let path = try!(path.as_ref().into_c_string());
88+
let ceiling_dirs_os = try!(env::join_paths(ceiling_dirs));
89+
let ceiling_dirs = try!(ceiling_dirs_os.into_c_string());
90+
let mut ret = 0 as *mut raw::git_repository;
91+
unsafe {
92+
try_call!(raw::git_repository_open_ext(&mut ret,
93+
path,
94+
flags.bits() as c_uint,
95+
ceiling_dirs));
96+
Ok(Binding::from_raw(ret))
97+
}
98+
}
99+
62100
/// Attempt to open an already-existing repository at or above `path`
63101
///
64102
/// This starts at `path` and looks up the filesystem hierarchy
@@ -1663,6 +1701,7 @@ impl RepositoryInitOptions {
16631701

16641702
#[cfg(test)]
16651703
mod tests {
1704+
use std::ffi::OsStr;
16661705
use std::fs;
16671706
use std::path::Path;
16681707
use tempdir::TempDir;
@@ -1754,6 +1793,30 @@ mod tests {
17541793
::test::realpath(&td.path().join("")).unwrap());
17551794
}
17561795

1796+
#[test]
1797+
fn smoke_open_ext() {
1798+
let td = TempDir::new("test").unwrap();
1799+
let subdir = td.path().join("subdir");
1800+
fs::create_dir(&subdir).unwrap();
1801+
Repository::init(td.path()).unwrap();
1802+
1803+
let repo = Repository::open_ext(&subdir, ::RepositoryOpenFlags::empty(), &[] as &[&OsStr]).unwrap();
1804+
assert!(!repo.is_bare());
1805+
assert_eq!(::test::realpath(&repo.path()).unwrap(),
1806+
::test::realpath(&td.path().join(".git")).unwrap());
1807+
1808+
let repo = Repository::open_ext(&subdir, ::REPOSITORY_OPEN_BARE, &[] as &[&OsStr]).unwrap();
1809+
assert!(repo.is_bare());
1810+
assert_eq!(::test::realpath(&repo.path()).unwrap(),
1811+
::test::realpath(&td.path().join(".git")).unwrap());
1812+
1813+
let err = Repository::open_ext(&subdir, ::REPOSITORY_OPEN_NO_SEARCH, &[] as &[&OsStr]).err().unwrap();
1814+
assert_eq!(err.code(), ::ErrorCode::NotFound);
1815+
1816+
let err = Repository::open_ext(&subdir, ::RepositoryOpenFlags::empty(), &[&subdir]).err().unwrap();
1817+
assert_eq!(err.code(), ::ErrorCode::NotFound);
1818+
}
1819+
17571820
fn graph_repo_init() -> (TempDir, Repository) {
17581821
let (_td, repo) = ::test::repo_init();
17591822
{

0 commit comments

Comments
 (0)