-
Notifications
You must be signed in to change notification settings - Fork 318
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This add support for the parse, access, and transform functions for refspec objects.
- Loading branch information
Showing
2 changed files
with
224 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
package git | ||
|
||
/* | ||
#include <git2.h> | ||
*/ | ||
import "C" | ||
import ( | ||
"runtime" | ||
"unsafe" | ||
) | ||
|
||
type Refspec struct { | ||
doNotCompare | ||
ptr *C.git_refspec | ||
} | ||
|
||
// ParseRefspec parses a given refspec string | ||
func ParseRefspec(input string, isFetch bool) (*Refspec, error) { | ||
var ptr *C.git_refspec | ||
|
||
cinput := C.CString(input) | ||
defer C.free(unsafe.Pointer(cinput)) | ||
|
||
runtime.LockOSThread() | ||
defer runtime.UnlockOSThread() | ||
|
||
ret := C.git_refspec_parse(&ptr, cinput, cbool(isFetch)) | ||
if ret < 0 { | ||
return nil, MakeGitError(ret) | ||
} | ||
|
||
spec := &Refspec{ptr: ptr} | ||
runtime.SetFinalizer(spec, (*Refspec).Free) | ||
return spec, nil | ||
} | ||
|
||
// Free releases a refspec object which has been created by ParseRefspec | ||
func (s *Refspec) Free() { | ||
runtime.SetFinalizer(s, nil) | ||
C.git_refspec_free(s.ptr) | ||
} | ||
|
||
// Direction returns the refspec's direction | ||
func (s *Refspec) Direction() ConnectDirection { | ||
direction := C.git_refspec_direction(s.ptr) | ||
return ConnectDirection(direction) | ||
} | ||
|
||
// Src returns the refspec's source specifier | ||
func (s *Refspec) Src() string { | ||
var ret string | ||
cstr := C.git_refspec_src(s.ptr) | ||
|
||
if cstr != nil { | ||
ret = C.GoString(cstr) | ||
} | ||
|
||
runtime.KeepAlive(s) | ||
return ret | ||
} | ||
|
||
// Dst returns the refspec's destination specifier | ||
func (s *Refspec) Dst() string { | ||
var ret string | ||
cstr := C.git_refspec_dst(s.ptr) | ||
|
||
if cstr != nil { | ||
ret = C.GoString(cstr) | ||
} | ||
|
||
runtime.KeepAlive(s) | ||
return ret | ||
} | ||
|
||
// Force returns the refspec's force-update setting | ||
func (s *Refspec) Force() bool { | ||
force := C.git_refspec_force(s.ptr) | ||
return force != 0 | ||
} | ||
|
||
// String returns the refspec's string representation | ||
func (s *Refspec) String() string { | ||
var ret string | ||
cstr := C.git_refspec_string(s.ptr) | ||
|
||
if cstr != nil { | ||
ret = C.GoString(cstr) | ||
} | ||
|
||
runtime.KeepAlive(s) | ||
return ret | ||
} | ||
|
||
// SrcMatches checks if a refspec's source descriptor matches a reference | ||
func (s *Refspec) SrcMatches(refname string) bool { | ||
cname := C.CString(refname) | ||
defer C.free(unsafe.Pointer(cname)) | ||
|
||
matches := C.git_refspec_src_matches(s.ptr, cname) | ||
return matches != 0 | ||
} | ||
|
||
// SrcMatches checks if a refspec's destination descriptor matches a reference | ||
func (s *Refspec) DstMatches(refname string) bool { | ||
cname := C.CString(refname) | ||
defer C.free(unsafe.Pointer(cname)) | ||
|
||
matches := C.git_refspec_dst_matches(s.ptr, cname) | ||
return matches != 0 | ||
} | ||
|
||
// Transform a reference to its target following the refspec's rules | ||
func (s *Refspec) Transform(refname string) (string, error) { | ||
buf := C.git_buf{} | ||
|
||
cname := C.CString(refname) | ||
defer C.free(unsafe.Pointer(cname)) | ||
|
||
runtime.LockOSThread() | ||
defer runtime.UnlockOSThread() | ||
|
||
ret := C.git_refspec_transform(&buf, s.ptr, cname) | ||
if ret < 0 { | ||
return "", MakeGitError(ret) | ||
} | ||
defer C.git_buf_dispose(&buf) | ||
|
||
return C.GoString(buf.ptr), nil | ||
} | ||
|
||
// Rtransform converts a target reference to its source reference following the | ||
// refspec's rules | ||
func (s *Refspec) Rtransform(refname string) (string, error) { | ||
buf := C.git_buf{} | ||
|
||
cname := C.CString(refname) | ||
defer C.free(unsafe.Pointer(cname)) | ||
|
||
runtime.LockOSThread() | ||
defer runtime.UnlockOSThread() | ||
|
||
ret := C.git_refspec_rtransform(&buf, s.ptr, cname) | ||
if ret < 0 { | ||
return "", MakeGitError(ret) | ||
} | ||
defer C.git_buf_dispose(&buf) | ||
|
||
return C.GoString(buf.ptr), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package git | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestRefspec(t *testing.T) { | ||
t.Parallel() | ||
|
||
const ( | ||
input = "+refs/heads/*:refs/remotes/origin/*" | ||
mainLocal = "refs/heads/main" | ||
mainRemote = "refs/remotes/origin/main" | ||
) | ||
|
||
refspec, err := ParseRefspec(input, true) | ||
checkFatal(t, err) | ||
|
||
// Accessors | ||
|
||
s := refspec.String() | ||
if s != input { | ||
t.Errorf("expected string %q, got %q", input, s) | ||
} | ||
|
||
if d := refspec.Direction(); d != ConnectDirectionFetch { | ||
t.Errorf("expected fetch refspec, got direction %v", d) | ||
} | ||
|
||
if pat, expected := refspec.Src(), "refs/heads/*"; pat != expected { | ||
t.Errorf("expected refspec src %q, got %q", expected, pat) | ||
} | ||
|
||
if pat, expected := refspec.Dst(), "refs/remotes/origin/*"; pat != expected { | ||
t.Errorf("expected refspec dst %q, got %q", expected, pat) | ||
} | ||
|
||
if !refspec.Force() { | ||
t.Error("expected refspec force flag") | ||
} | ||
|
||
// SrcMatches | ||
|
||
if !refspec.SrcMatches(mainLocal) { | ||
t.Errorf("refspec source did not match %q", mainLocal) | ||
} | ||
|
||
if refspec.SrcMatches("refs/tags/v1.0") { | ||
t.Error("refspec source matched under refs/tags") | ||
} | ||
|
||
// DstMatches | ||
|
||
if !refspec.DstMatches(mainRemote) { | ||
t.Errorf("refspec destination did not match %q", mainRemote) | ||
} | ||
|
||
if refspec.DstMatches("refs/tags/v1.0") { | ||
t.Error("refspec destination matched under refs/tags") | ||
} | ||
|
||
// Transforms | ||
|
||
fromLocal, err := refspec.Transform(mainLocal) | ||
checkFatal(t, err) | ||
if fromLocal != mainRemote { | ||
t.Errorf("transform by refspec returned %s; expected %s", fromLocal, mainRemote) | ||
} | ||
|
||
fromRemote, err := refspec.Rtransform(mainRemote) | ||
checkFatal(t, err) | ||
if fromRemote != mainLocal { | ||
t.Errorf("rtransform by refspec returned %s; expected %s", fromRemote, mainLocal) | ||
} | ||
} |