Skip to content

Commit e86688f

Browse files
committed
Add bindings for git_reference_name_is_valid, git_remote_name_is_valid & git_tag_name_is_valid
1 parent 49879e9 commit e86688f

File tree

5 files changed

+91
-2
lines changed

5 files changed

+91
-2
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
target
22
Cargo.lock
33
src/main.rs
4+
.idea

libgit2-sys/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2247,6 +2247,7 @@ extern "C" {
22472247
) -> c_int;
22482248
pub fn git_remote_get_refspec(remote: *const git_remote, n: size_t) -> *const git_refspec;
22492249
pub fn git_remote_is_valid_name(remote_name: *const c_char) -> c_int;
2250+
pub fn git_remote_name_is_valid(valid: *mut c_int, remote_name: *const c_char) -> c_int;
22502251
pub fn git_remote_list(out: *mut git_strarray, repo: *mut git_repository) -> c_int;
22512252
pub fn git_remote_rename(
22522253
problems: *mut git_strarray,
@@ -2398,6 +2399,7 @@ extern "C" {
23982399
pub fn git_reference_is_remote(r: *const git_reference) -> c_int;
23992400
pub fn git_reference_is_tag(r: *const git_reference) -> c_int;
24002401
pub fn git_reference_is_valid_name(name: *const c_char) -> c_int;
2402+
pub fn git_reference_name_is_valid(valid: *mut c_int, refname: *const c_char) -> c_int;
24012403
pub fn git_reference_lookup(
24022404
out: *mut *mut git_reference,
24032405
repo: *mut git_repository,
@@ -3209,6 +3211,7 @@ extern "C" {
32093211
pub fn git_tag_target(target_out: *mut *mut git_object, tag: *const git_tag) -> c_int;
32103212
pub fn git_tag_target_id(tag: *const git_tag) -> *const git_oid;
32113213
pub fn git_tag_target_type(tag: *const git_tag) -> git_object_t;
3214+
pub fn git_tag_name_is_valid(valid: *mut c_int, tag_name: *const c_char) -> c_int;
32123215

32133216
// checkout
32143217
pub fn git_checkout_head(repo: *mut git_repository, opts: *const git_checkout_options)

src/reference.rs

+27-2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,17 @@ impl<'repo> Reference<'repo> {
6565
unsafe { raw::git_reference_is_valid_name(refname.as_ptr()) == 1 }
6666
}
6767

68+
/// Ensure the reference name is well-formed.
69+
pub fn name_is_valid(refname: &str) -> Result<bool, Error> {
70+
crate::init();
71+
let refname = CString::new(refname)?;
72+
let mut valid: libc::c_int = 0;
73+
unsafe {
74+
try_call!(raw::git_reference_name_is_valid(&mut valid, refname.as_ptr()));
75+
}
76+
Ok(valid == 1)
77+
}
78+
6879
/// Normalize reference name and check validity.
6980
///
7081
/// This will normalize the reference name by collapsing runs of adjacent
@@ -463,13 +474,27 @@ mod tests {
463474
use crate::{ObjectType, Reference, ReferenceType};
464475

465476
#[test]
466-
fn smoke() {
477+
fn is_valid_name() {
467478
assert!(Reference::is_valid_name("refs/foo"));
468479
assert!(!Reference::is_valid_name("foo"));
469480
}
470481

471482
#[test]
472-
fn smoke2() {
483+
fn name_is_valid() {
484+
assert_eq!(Reference::name_is_valid("refs/foo").unwrap(), true);
485+
assert_eq!(Reference::name_is_valid("FOO_BAR").unwrap(), true);
486+
487+
assert_eq!(Reference::name_is_valid("foo").unwrap(), false);
488+
assert_eq!(Reference::name_is_valid("_FOO_BAR").unwrap(), false);
489+
490+
assert_eq!(
491+
Reference::name_is_valid("ab\012").err().unwrap().to_string(),
492+
"data contained a nul byte that could not be represented as a string"
493+
);
494+
}
495+
496+
#[test]
497+
fn smoke() {
473498
let (_td, repo) = crate::test::repo_init();
474499
let mut head = repo.head().unwrap();
475500
assert!(head.is_branch());

src/remote.rs

+21
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,17 @@ impl<'repo> Remote<'repo> {
9595
unsafe { raw::git_remote_is_valid_name(remote_name.as_ptr()) == 1 }
9696
}
9797

98+
/// Ensure the remote name is well-formed.
99+
pub fn name_is_valid(remote_name: &str) -> Result<bool, Error> {
100+
crate::init();
101+
let remote_name = CString::new(remote_name)?;
102+
let mut valid: libc::c_int = 0;
103+
unsafe {
104+
try_call!(raw::git_remote_name_is_valid(&mut valid, remote_name.as_ptr()));
105+
}
106+
Ok(valid == 1)
107+
}
108+
98109
/// Create a detached remote
99110
///
100111
/// Create a remote with the given url in-memory. You can use this
@@ -856,6 +867,16 @@ mod tests {
856867
assert!(!Remote::is_valid_name("\x01"));
857868
}
858869

870+
#[test]
871+
fn name_is_valid() {
872+
assert_eq!(Remote::name_is_valid("foobar").unwrap(), true);
873+
assert_eq!(Remote::name_is_valid("\x01").unwrap(), false);
874+
assert_eq!(
875+
Remote::name_is_valid("ab\012").err().unwrap().to_string(),
876+
"data contained a nul byte that could not be represented as a string"
877+
);
878+
}
879+
859880
#[test]
860881
fn transfer_cb() {
861882
let (td, _repo) = crate::test::repo_init();

src/tag.rs

+39
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::ffi::CString;
12
use std::marker;
23
use std::mem;
34
use std::ptr;
@@ -15,6 +16,20 @@ pub struct Tag<'repo> {
1516
}
1617

1718
impl<'repo> Tag<'repo> {
19+
20+
/// Determine whether a tag name is valid, meaning that (when prefixed with refs/tags/) that
21+
/// it is a valid reference name, and that any additional tag name restrictions are imposed
22+
/// (eg, it cannot start with a -).
23+
pub fn name_is_valid(tag_name: &str) -> Result<bool, Error> {
24+
crate::init();
25+
let tag_name = CString::new(tag_name)?;
26+
let mut valid: libc::c_int = 0;
27+
unsafe {
28+
try_call!(raw::git_tag_name_is_valid(&mut valid, tag_name.as_ptr()));
29+
}
30+
Ok(valid == 1)
31+
}
32+
1833
/// Get the id (SHA1) of a repository tag
1934
pub fn id(&self) -> Oid {
2035
unsafe { Binding::from_raw(raw::git_tag_id(&*self.raw)) }
@@ -141,6 +156,30 @@ impl<'repo> Drop for Tag<'repo> {
141156

142157
#[cfg(test)]
143158
mod tests {
159+
use crate::Tag;
160+
161+
// Reference -- https://git-scm.com/docs/git-check-ref-format
162+
#[test]
163+
fn name_is_valid() {
164+
assert_eq!(Tag::name_is_valid("blah_blah").unwrap(), true);
165+
assert_eq!(Tag::name_is_valid("v1.2.3").unwrap(), true);
166+
assert_eq!(Tag::name_is_valid("my/tag").unwrap(), true);
167+
assert_eq!(Tag::name_is_valid("@").unwrap(), true);
168+
169+
assert_eq!(Tag::name_is_valid("-foo").unwrap(), false);
170+
assert_eq!(Tag::name_is_valid("foo:bar").unwrap(), false);
171+
assert_eq!(Tag::name_is_valid("foo^bar").unwrap(), false);
172+
assert_eq!(Tag::name_is_valid("foo.").unwrap(), false);
173+
assert_eq!(Tag::name_is_valid("@{").unwrap(), false);
174+
assert_eq!(Tag::name_is_valid("as\\cd").unwrap(), false);
175+
176+
177+
assert_eq!(
178+
Tag::name_is_valid("ab\012").err().unwrap().to_string(),
179+
"data contained a nul byte that could not be represented as a string"
180+
);
181+
}
182+
144183
#[test]
145184
fn smoke() {
146185
let (_td, repo) = crate::test::repo_init();

0 commit comments

Comments
 (0)