Merge remote-tracking branch 'upstream/master' into git_index_add_frombuffer
This commit is contained in:
commit
c20008416a
|
@ -0,0 +1,89 @@
|
|||
name: git2go CI
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- release-*
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
|
||||
build-legacy:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go: [ '1.9', '1.10' ]
|
||||
name: Go ${{ matrix.go }}
|
||||
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
id: go
|
||||
- name: Check out code into the GOPATH
|
||||
uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 1
|
||||
path: src/github.com/${{ github.repository }}
|
||||
- name: Build
|
||||
env:
|
||||
GOPATH: /home/runner/work/git2go
|
||||
run: |
|
||||
git submodule update --init
|
||||
make build-libgit2-static
|
||||
go get --tags "static" github.com/${{ github.repository }}/...
|
||||
go build --tags "static" github.com/${{ github.repository }}/...
|
||||
- name: Test
|
||||
env:
|
||||
GOPATH: /home/runner/work/git2go
|
||||
run: make test-static
|
||||
|
||||
build-static:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go: [ '1.11', '1.12', '1.13' ]
|
||||
name: Go ${{ matrix.go }}
|
||||
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
id: go
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v1
|
||||
- name: Build
|
||||
run: |
|
||||
git submodule update --init
|
||||
make build-libgit2-static
|
||||
- name: Test
|
||||
run: make test-static
|
||||
|
||||
build-dynamic:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
name: Go (dynamic)
|
||||
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: '1.13'
|
||||
id: go
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v1
|
||||
- name: Build
|
||||
run: |
|
||||
git submodule update --init
|
||||
make build-libgit2-dynamic
|
||||
- name: Test
|
||||
run: make test-dynamic
|
|
@ -0,0 +1,2 @@
|
|||
/static-build/
|
||||
/dynamic-build/
|
19
.travis.yml
19
.travis.yml
|
@ -1,18 +1,29 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.7
|
||||
- 1.8
|
||||
- "1.9"
|
||||
- "1.10"
|
||||
- "1.11"
|
||||
- "1.12"
|
||||
- "1.13"
|
||||
- tip
|
||||
|
||||
script: make test-static
|
||||
install:
|
||||
- make build-libgit2-static
|
||||
- go get --tags "static" ./...
|
||||
|
||||
script:
|
||||
- make test-static
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
|
||||
git:
|
||||
submodules: true
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /v\d+/
|
||||
- next
|
||||
- /release-.*/
|
||||
|
|
51
Makefile
51
Makefile
|
@ -1,18 +1,53 @@
|
|||
default: test
|
||||
|
||||
test: build-libgit2
|
||||
# System library
|
||||
# ==============
|
||||
# This uses whatever version of libgit2 can be found in the system.
|
||||
test:
|
||||
go run script/check-MakeGitError-thread-lock.go
|
||||
go test ./...
|
||||
go test --count=1 ./...
|
||||
|
||||
install: build-libgit2
|
||||
install:
|
||||
go install ./...
|
||||
|
||||
build-libgit2:
|
||||
# Bundled dynamic library
|
||||
# =======================
|
||||
# In order to avoid having to manipulate `git_dynamic.go`, which would prevent
|
||||
# the system-wide libgit2.so from being used in a sort of ergonomic way, this
|
||||
# instead moves the complexity of overriding the paths so that the built
|
||||
# libraries can be found by the build and tests.
|
||||
.PHONY: build-libgit2-dynamic
|
||||
build-libgit2-dynamic:
|
||||
./script/build-libgit2-dynamic.sh
|
||||
|
||||
dynamic-build/install/lib/libgit2.so:
|
||||
./script/build-libgit2-dynamic.sh
|
||||
|
||||
test-dynamic: dynamic-build/install/lib/libgit2.so
|
||||
PKG_CONFIG_PATH=dynamic-build/install/lib/pkgconfig \
|
||||
go run script/check-MakeGitError-thread-lock.go
|
||||
PKG_CONFIG_PATH=dynamic-build/install/lib/pkgconfig \
|
||||
LD_LIBRARY_PATH=dynamic-build/install/lib \
|
||||
go test --count=1 ./...
|
||||
|
||||
install-dynamic: dynamic-build/install/lib/libgit2.so
|
||||
PKG_CONFIG_PATH=dynamic-build/install/lib/pkgconfig \
|
||||
go install ./...
|
||||
|
||||
# Bundled static library
|
||||
# ======================
|
||||
# This is mostly used in tests, but can also be used to provide a
|
||||
# statically-linked library with the bundled version of libgit2.
|
||||
.PHONY: build-libgit2-static
|
||||
build-libgit2-static:
|
||||
./script/build-libgit2-static.sh
|
||||
|
||||
install-static: build-libgit2
|
||||
go install --tags "static" ./...
|
||||
static-build/install/lib/libgit2.a:
|
||||
./script/build-libgit2-static.sh
|
||||
|
||||
test-static: build-libgit2
|
||||
test-static: static-build/install/lib/libgit2.a
|
||||
go run script/check-MakeGitError-thread-lock.go
|
||||
go test --tags "static" ./...
|
||||
go test --count=1 --tags "static" ./...
|
||||
|
||||
install-static: static-build/install/lib/libgit2.a
|
||||
go install --tags "static" ./...
|
||||
|
|
12
README.md
12
README.md
|
@ -35,9 +35,9 @@ If using `master` or building a branch statically, we need to build libgit2 firs
|
|||
Run `go get -d github.com/libgit2/git2go` to download the code and go to your `$GOPATH/src/github.com/libgit2/git2go` directory. From there, we need to build the C code and put it into the resulting go binary.
|
||||
|
||||
git submodule update --init # get libgit2
|
||||
make install
|
||||
make install-static
|
||||
|
||||
will compile libgit2, link it into git2go and install it.
|
||||
will compile libgit2, link it into git2go and install it. The `master` branch is set up to follow the specific libgit2 version that is vendored, so trying dynamic linking may or may not work depending on the exact versions involved.
|
||||
|
||||
Parallelism and network operations
|
||||
----------------------------------
|
||||
|
@ -47,19 +47,19 @@ libgit2 may use OpenSSL and LibSSH2 for performing encrypted network connections
|
|||
Running the tests
|
||||
-----------------
|
||||
|
||||
For the stable version, `go test` will work as usual. For the `next` branch, similarly to installing, running the tests requires building a local libgit2 library, so the Makefile provides a wrapper that makes sure it's built
|
||||
For the stable version, `go test` will work as usual. For the `master` branch, similarly to installing, running the tests requires building a local libgit2 library, so the Makefile provides a wrapper that makes sure it's built
|
||||
|
||||
make test
|
||||
make test-static
|
||||
|
||||
Alternatively, you can build the library manually first and then run the tests
|
||||
|
||||
./script/build-libgit2-static.sh
|
||||
go test -v
|
||||
go test -v --tags "static" ./...
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
M to the I to the T. See the LICENSE file if you've never seen a MIT license before.
|
||||
M to the I to the T. See the LICENSE file if you've never seen an MIT license before.
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
|
2
blob.go
2
blob.go
|
@ -48,7 +48,7 @@ func (repo *Repository) CreateBlobFromBuffer(data []byte) (*Oid, error) {
|
|||
var size C.size_t
|
||||
|
||||
// Go 1.6 added some increased checking of passing pointer to
|
||||
// C, but its check depends on its expectations of waht we
|
||||
// C, but its check depends on its expectations of what we
|
||||
// pass to the C function, so unless we take the address of
|
||||
// its contents at the call site itself, it can fail when
|
||||
// 'data' is a slice of a slice.
|
||||
|
|
|
@ -208,7 +208,7 @@ func (repo *Repository) RemoteName(canonicalBranchName string) (string, error) {
|
|||
if ret < 0 {
|
||||
return "", MakeGitError(ret)
|
||||
}
|
||||
defer C.git_buf_free(&nameBuf)
|
||||
defer C.git_buf_dispose(&nameBuf)
|
||||
|
||||
return C.GoString(nameBuf.ptr), nil
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ func (repo *Repository) UpstreamName(canonicalBranchName string) (string, error)
|
|||
if ret < 0 {
|
||||
return "", MakeGitError(ret)
|
||||
}
|
||||
defer C.git_buf_free(&nameBuf)
|
||||
defer C.git_buf_dispose(&nameBuf)
|
||||
|
||||
return C.GoString(nameBuf.ptr), nil
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ const (
|
|||
CheckoutDontUpdateIndex CheckoutStrategy = C.GIT_CHECKOUT_DONT_UPDATE_INDEX // Normally checkout updates index entries as it goes; this stops that
|
||||
CheckoutNoRefresh CheckoutStrategy = C.GIT_CHECKOUT_NO_REFRESH // Don't refresh index/config/etc before doing checkout
|
||||
CheckoutSkipUnmerged CheckoutStrategy = C.GIT_CHECKOUT_SKIP_UNMERGED // Allow checkout to skip unmerged files
|
||||
CheckoutUserOurs CheckoutStrategy = C.GIT_CHECKOUT_USE_OURS // For unmerged files, checkout stage 2 from index
|
||||
CheckoutUseOurs CheckoutStrategy = C.GIT_CHECKOUT_USE_OURS // For unmerged files, checkout stage 2 from index
|
||||
CheckoutUseTheirs CheckoutStrategy = C.GIT_CHECKOUT_USE_THEIRS // For unmerged files, checkout stage 3 from index
|
||||
CheckoutDisablePathspecMatch CheckoutStrategy = C.GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH // Treat pathspec as simple list of exact match file paths
|
||||
CheckoutSkipLockedDirectories CheckoutStrategy = C.GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES // Ignore directories in use, they will be left empty
|
||||
|
|
10
commit.go
10
commit.go
|
@ -28,6 +28,12 @@ func (c *Commit) Message() string {
|
|||
return ret
|
||||
}
|
||||
|
||||
func (c *Commit) MessageEncoding() string {
|
||||
ret := C.GoString(C.git_commit_message_encoding(c.cast_ptr))
|
||||
runtime.KeepAlive(c)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c *Commit) RawMessage() string {
|
||||
ret := C.GoString(C.git_commit_message_raw(c.cast_ptr))
|
||||
runtime.KeepAlive(c)
|
||||
|
@ -37,10 +43,10 @@ func (c *Commit) RawMessage() string {
|
|||
func (c *Commit) ExtractSignature() (string, string, error) {
|
||||
|
||||
var c_signed C.git_buf
|
||||
defer C.git_buf_free(&c_signed)
|
||||
defer C.git_buf_dispose(&c_signed)
|
||||
|
||||
var c_signature C.git_buf
|
||||
defer C.git_buf_free(&c_signature)
|
||||
defer C.git_buf_dispose(&c_signature)
|
||||
|
||||
oid := c.Id()
|
||||
repo := C.git_commit_owner(c.cast_ptr)
|
||||
|
|
14
config.go
14
config.go
|
@ -77,7 +77,7 @@ func (c *Config) AddFile(path string, level ConfigLevel, force bool) error {
|
|||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_config_add_file_ondisk(c.ptr, cpath, C.git_config_level_t(level), cbool(force))
|
||||
ret := C.git_config_add_file_ondisk(c.ptr, cpath, C.git_config_level_t(level), nil, cbool(force))
|
||||
runtime.KeepAlive(c)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
|
@ -134,7 +134,7 @@ func (c *Config) LookupString(name string) (string, error) {
|
|||
if ret < 0 {
|
||||
return "", MakeGitError(ret)
|
||||
}
|
||||
defer C.git_buf_free(&valBuf)
|
||||
defer C.git_buf_dispose(&valBuf)
|
||||
|
||||
return C.GoString(valBuf.ptr), nil
|
||||
}
|
||||
|
@ -344,7 +344,7 @@ func (c *Config) OpenLevel(parent *Config, level ConfigLevel) (*Config, error) {
|
|||
}
|
||||
|
||||
// OpenOndisk creates a new config instance containing a single on-disk file
|
||||
func OpenOndisk(parent *Config, path string) (*Config, error) {
|
||||
func OpenOndisk(path string) (*Config, error) {
|
||||
cpath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cpath))
|
||||
|
||||
|
@ -390,7 +390,7 @@ func (iter *ConfigIterator) Free() {
|
|||
|
||||
func ConfigFindGlobal() (string, error) {
|
||||
var buf C.git_buf
|
||||
defer C.git_buf_free(&buf)
|
||||
defer C.git_buf_dispose(&buf)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
@ -405,7 +405,7 @@ func ConfigFindGlobal() (string, error) {
|
|||
|
||||
func ConfigFindSystem() (string, error) {
|
||||
var buf C.git_buf
|
||||
defer C.git_buf_free(&buf)
|
||||
defer C.git_buf_dispose(&buf)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
@ -420,7 +420,7 @@ func ConfigFindSystem() (string, error) {
|
|||
|
||||
func ConfigFindXDG() (string, error) {
|
||||
var buf C.git_buf
|
||||
defer C.git_buf_free(&buf)
|
||||
defer C.git_buf_dispose(&buf)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
@ -438,7 +438,7 @@ func ConfigFindXDG() (string, error) {
|
|||
// Look for the file in %PROGRAMDATA%\Git\config used by portable git.
|
||||
func ConfigFindProgramdata() (string, error) {
|
||||
var buf C.git_buf
|
||||
defer C.git_buf_free(&buf)
|
||||
defer C.git_buf_dispose(&buf)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
|
|
@ -13,7 +13,7 @@ func setupConfig() (*Config, error) {
|
|||
err error
|
||||
)
|
||||
|
||||
c, err = OpenOndisk(nil, tempConfig)
|
||||
c, err = OpenOndisk(tempConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@ package git
|
|||
|
||||
/*
|
||||
#include <git2.h>
|
||||
#include <git2/sys/cred.h>
|
||||
|
||||
git_credtype_t _go_git_cred_credtype(git_cred *cred);
|
||||
*/
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
@ -27,7 +30,7 @@ func (o *Cred) HasUsername() bool {
|
|||
}
|
||||
|
||||
func (o *Cred) Type() CredType {
|
||||
return (CredType)(o.ptr.credtype)
|
||||
return (CredType)(C._go_git_cred_credtype(o.ptr))
|
||||
}
|
||||
|
||||
func credFromC(ptr *C.git_cred) *Cred {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// Code generated by "stringer -type Delta -trimprefix Delta -tags static"; DO NOT EDIT.
|
||||
|
||||
package git
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[DeltaUnmodified-0]
|
||||
_ = x[DeltaAdded-1]
|
||||
_ = x[DeltaDeleted-2]
|
||||
_ = x[DeltaModified-3]
|
||||
_ = x[DeltaRenamed-4]
|
||||
_ = x[DeltaCopied-5]
|
||||
_ = x[DeltaIgnored-6]
|
||||
_ = x[DeltaUntracked-7]
|
||||
_ = x[DeltaTypeChange-8]
|
||||
_ = x[DeltaUnreadable-9]
|
||||
_ = x[DeltaConflicted-10]
|
||||
}
|
||||
|
||||
const _Delta_name = "UnmodifiedAddedDeletedModifiedRenamedCopiedIgnoredUntrackedTypeChangeUnreadableConflicted"
|
||||
|
||||
var _Delta_index = [...]uint8{0, 10, 15, 22, 30, 37, 43, 50, 59, 69, 79, 89}
|
||||
|
||||
func (i Delta) String() string {
|
||||
if i < 0 || i >= Delta(len(_Delta_index)-1) {
|
||||
return "Delta(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _Delta_name[_Delta_index[i]:_Delta_index[i+1]]
|
||||
}
|
|
@ -212,7 +212,7 @@ func (result *DescribeResult) Format(opts *DescribeFormatOptions) (string, error
|
|||
if ecode < 0 {
|
||||
return "", MakeGitError(ecode)
|
||||
}
|
||||
defer C.git_buf_free(&resultBuf)
|
||||
defer C.git_buf_dispose(&resultBuf)
|
||||
|
||||
return C.GoString(resultBuf.ptr), nil
|
||||
}
|
||||
|
|
40
diff.go
40
diff.go
|
@ -39,6 +39,8 @@ const (
|
|||
DeltaConflicted Delta = C.GIT_DELTA_CONFLICTED
|
||||
)
|
||||
|
||||
//go:generate stringer -type Delta -trimprefix Delta -tags static
|
||||
|
||||
type DiffLineType int
|
||||
|
||||
const (
|
||||
|
@ -54,6 +56,8 @@ const (
|
|||
DiffLineBinary DiffLineType = C.GIT_DIFF_LINE_BINARY
|
||||
)
|
||||
|
||||
//go:generate stringer -type DiffLineType -trimprefix DiffLine -tags static
|
||||
|
||||
type DiffFile struct {
|
||||
Path string
|
||||
Oid *Oid
|
||||
|
@ -246,7 +250,7 @@ const (
|
|||
func (stats *DiffStats) String(format DiffStatsFormat,
|
||||
width uint) (string, error) {
|
||||
buf := C.git_buf{}
|
||||
defer C.git_buf_free(&buf)
|
||||
defer C.git_buf_dispose(&buf)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
@ -284,7 +288,7 @@ type diffForEachData struct {
|
|||
Error error
|
||||
}
|
||||
|
||||
type DiffForEachFileCallback func(DiffDelta, float64) (DiffForEachHunkCallback, error)
|
||||
type DiffForEachFileCallback func(delta DiffDelta, progress float64) (DiffForEachHunkCallback, error)
|
||||
|
||||
type DiffDetail int
|
||||
|
||||
|
@ -405,6 +409,36 @@ func (diff *Diff) Patch(deltaIndex int) (*Patch, error) {
|
|||
return newPatchFromC(patchPtr), nil
|
||||
}
|
||||
|
||||
type DiffFormat int
|
||||
|
||||
const (
|
||||
DiffFormatPatch DiffFormat = C.GIT_DIFF_FORMAT_PATCH
|
||||
DiffFormatPatchHeader DiffFormat = C.GIT_DIFF_FORMAT_PATCH_HEADER
|
||||
DiffFormatRaw DiffFormat = C.GIT_DIFF_FORMAT_RAW
|
||||
DiffFormatNameOnly DiffFormat = C.GIT_DIFF_FORMAT_NAME_ONLY
|
||||
DiffFormatNameStatus DiffFormat = C.GIT_DIFF_FORMAT_NAME_STATUS
|
||||
)
|
||||
|
||||
func (diff *Diff) ToBuf(format DiffFormat) ([]byte, error) {
|
||||
if diff.ptr == nil {
|
||||
return nil, ErrInvalid
|
||||
}
|
||||
|
||||
diffBuf := C.git_buf{}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ecode := C.git_diff_to_buf(&diffBuf, diff.ptr, C.git_diff_format_t(format))
|
||||
runtime.KeepAlive(diff)
|
||||
if ecode < 0 {
|
||||
return nil, MakeGitError(ecode)
|
||||
}
|
||||
defer C.git_buf_free(&diffBuf)
|
||||
|
||||
return C.GoBytes(unsafe.Pointer(diffBuf.ptr), C.int(diffBuf.size)), nil
|
||||
}
|
||||
|
||||
type DiffOptionsFlag int
|
||||
|
||||
const (
|
||||
|
@ -437,6 +471,8 @@ const (
|
|||
DiffShowUnmodified DiffOptionsFlag = C.GIT_DIFF_SHOW_UNMODIFIED
|
||||
DiffPatience DiffOptionsFlag = C.GIT_DIFF_PATIENCE
|
||||
DiffMinimal DiffOptionsFlag = C.GIT_DIFF_MINIMAL
|
||||
DiffShowBinary DiffOptionsFlag = C.GIT_DIFF_SHOW_BINARY
|
||||
DiffIndentHeuristic DiffOptionsFlag = C.GIT_DIFF_INDENT_HEURISTIC
|
||||
)
|
||||
|
||||
type DiffNotifyCallback func(diffSoFar *Diff, deltaToAdd DiffDelta, matchedPathspec string) error
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
// Code generated by "stringer -type DiffLineType -trimprefix DiffLine -tags static"; DO NOT EDIT.
|
||||
|
||||
package git
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[DiffLineContext-32]
|
||||
_ = x[DiffLineAddition-43]
|
||||
_ = x[DiffLineDeletion-45]
|
||||
_ = x[DiffLineContextEOFNL-61]
|
||||
_ = x[DiffLineAddEOFNL-62]
|
||||
_ = x[DiffLineDelEOFNL-60]
|
||||
_ = x[DiffLineFileHdr-70]
|
||||
_ = x[DiffLineHunkHdr-72]
|
||||
_ = x[DiffLineBinary-66]
|
||||
}
|
||||
|
||||
const (
|
||||
_DiffLineType_name_0 = "Context"
|
||||
_DiffLineType_name_1 = "Addition"
|
||||
_DiffLineType_name_2 = "Deletion"
|
||||
_DiffLineType_name_3 = "DelEOFNLContextEOFNLAddEOFNL"
|
||||
_DiffLineType_name_4 = "Binary"
|
||||
_DiffLineType_name_5 = "FileHdr"
|
||||
_DiffLineType_name_6 = "HunkHdr"
|
||||
)
|
||||
|
||||
var (
|
||||
_DiffLineType_index_3 = [...]uint8{0, 8, 20, 28}
|
||||
)
|
||||
|
||||
func (i DiffLineType) String() string {
|
||||
switch {
|
||||
case i == 32:
|
||||
return _DiffLineType_name_0
|
||||
case i == 43:
|
||||
return _DiffLineType_name_1
|
||||
case i == 45:
|
||||
return _DiffLineType_name_2
|
||||
case 60 <= i && i <= 62:
|
||||
i -= 60
|
||||
return _DiffLineType_name_3[_DiffLineType_index_3[i]:_DiffLineType_index_3[i+1]]
|
||||
case i == 66:
|
||||
return _DiffLineType_name_4
|
||||
case i == 70:
|
||||
return _DiffLineType_name_5
|
||||
case i == 72:
|
||||
return _DiffLineType_name_6
|
||||
default:
|
||||
return "DiffLineType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
}
|
16
git.go
16
git.go
|
@ -189,22 +189,16 @@ func (oid *Oid) Cmp(oid2 *Oid) int {
|
|||
}
|
||||
|
||||
func (oid *Oid) Copy() *Oid {
|
||||
ret := new(Oid)
|
||||
copy(ret[:], oid[:])
|
||||
return ret
|
||||
ret := *oid
|
||||
return &ret
|
||||
}
|
||||
|
||||
func (oid *Oid) Equal(oid2 *Oid) bool {
|
||||
return bytes.Equal(oid[:], oid2[:])
|
||||
return *oid == *oid2
|
||||
}
|
||||
|
||||
func (oid *Oid) IsZero() bool {
|
||||
for _, a := range oid {
|
||||
if a != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
return *oid == Oid{}
|
||||
}
|
||||
|
||||
func (oid *Oid) NCmp(oid2 *Oid, n uint) int {
|
||||
|
@ -309,7 +303,7 @@ func Discover(start string, across_fs bool, ceiling_dirs []string) (string, erro
|
|||
defer C.free(unsafe.Pointer(cstart))
|
||||
|
||||
var buf C.git_buf
|
||||
defer C.git_buf_free(&buf)
|
||||
defer C.git_buf_dispose(&buf)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
|
|
@ -6,8 +6,8 @@ package git
|
|||
#include <git2.h>
|
||||
#cgo pkg-config: libgit2
|
||||
|
||||
#if LIBGIT2_VER_MAJOR != 0 || LIBGIT2_VER_MINOR != 25
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 v0.25"
|
||||
#if LIBGIT2_VER_MAJOR != 0 || LIBGIT2_VER_MINOR != 28
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 v0.28"
|
||||
#endif
|
||||
|
||||
*/
|
||||
|
|
|
@ -3,14 +3,13 @@
|
|||
package git
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I${SRCDIR}/vendor/libgit2/include
|
||||
#cgo LDFLAGS: -L${SRCDIR}/vendor/libgit2/build/ -lgit2
|
||||
#cgo windows LDFLAGS: -lwinhttp
|
||||
#cgo !windows pkg-config: --static ${SRCDIR}/vendor/libgit2/build/libgit2.pc
|
||||
#cgo windows CFLAGS: -I${SRCDIR}/static-build/install/include/
|
||||
#cgo windows LDFLAGS: -L${SRCDIR}/static-build/install/lib/ -lgit2 -lwinhttp
|
||||
#cgo !windows pkg-config: --static ${SRCDIR}/static-build/install/lib/pkgconfig/libgit2.pc
|
||||
#include <git2.h>
|
||||
|
||||
#if LIBGIT2_VER_MAJOR != 0 || LIBGIT2_VER_MINOR != 25
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 v0.25"
|
||||
#if LIBGIT2_VER_MAJOR != 0 || LIBGIT2_VER_MINOR != 28
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 v0.28"
|
||||
#endif
|
||||
|
||||
*/
|
||||
|
|
14
index.go
14
index.go
|
@ -147,6 +147,20 @@ func (v *Index) Path() string {
|
|||
return ret
|
||||
}
|
||||
|
||||
// Clear clears the index object in memory; changes must be explicitly
|
||||
// written to disk for them to take effect persistently
|
||||
func (v *Index) Clear() error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
err := C.git_index_clear(v.ptr)
|
||||
runtime.KeepAlive(v)
|
||||
if err < 0 {
|
||||
return MakeGitError(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add adds or replaces the given entry to the index, making a copy of
|
||||
// the data
|
||||
func (v *Index) Add(entry *IndexEntry) error {
|
||||
|
|
|
@ -3,6 +3,7 @@ package git
|
|||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
@ -59,14 +60,29 @@ func TestIndexWriteTreeTo(t *testing.T) {
|
|||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
|
||||
repo2 := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo2)
|
||||
idx, err := NewIndex()
|
||||
checkFatal(t, err)
|
||||
|
||||
idx, err := repo.Index()
|
||||
odb, err := repo.Odb()
|
||||
checkFatal(t, err)
|
||||
err = idx.AddByPath("README")
|
||||
|
||||
content, err := ioutil.ReadFile(path.Join(repo.Workdir(), "README"))
|
||||
checkFatal(t, err)
|
||||
treeId, err := idx.WriteTreeTo(repo2)
|
||||
|
||||
id, err := odb.Write(content, ObjectBlob)
|
||||
checkFatal(t, err)
|
||||
|
||||
err = idx.Add(&IndexEntry{
|
||||
Mode: FilemodeBlob,
|
||||
Uid: 0,
|
||||
Gid: 0,
|
||||
Size: uint32(len(content)),
|
||||
Id: id,
|
||||
Path: "README",
|
||||
})
|
||||
checkFatal(t, err)
|
||||
|
||||
treeId, err := idx.WriteTreeTo(repo)
|
||||
checkFatal(t, err)
|
||||
|
||||
if treeId.String() != "b7119b11e8ef7a1a5a34d3ac87f5b075228ac81e" {
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
package git
|
||||
|
||||
/*
|
||||
#include <git2.h>
|
||||
#include <git2/sys/mempack.h>
|
||||
|
||||
extern int git_mempack_new(git_odb_backend **out);
|
||||
extern int git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_backend *backend);
|
||||
extern int git_mempack_reset(git_odb_backend *backend);
|
||||
extern void _go_git_odb_backend_free(git_odb_backend *backend);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Mempack is a custom ODB backend that permits packing object in-memory.
|
||||
type Mempack struct {
|
||||
ptr *C.git_odb_backend
|
||||
}
|
||||
|
||||
// NewMempack creates a new mempack instance and registers it to the ODB.
|
||||
func NewMempack(odb *Odb) (mempack *Mempack, err error) {
|
||||
mempack = new(Mempack)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_mempack_new(&mempack.ptr)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
ret = C.git_odb_add_backend(odb.ptr, mempack.ptr, C.int(999))
|
||||
runtime.KeepAlive(odb)
|
||||
if ret < 0 {
|
||||
// Since git_odb_add_alternate() takes ownership of the ODB backend, the
|
||||
// only case in which we free the mempack's memory is if it fails to be
|
||||
// added to the ODB.
|
||||
C._go_git_odb_backend_free(mempack.ptr)
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
return mempack, nil
|
||||
}
|
||||
|
||||
// Dump dumps all the queued in-memory writes to a packfile.
|
||||
//
|
||||
// It is the caller's responsibility to ensure that the generated packfile is
|
||||
// available to the repository (e.g. by writing it to disk, or doing something
|
||||
// crazy like distributing it across several copies of the repository over a
|
||||
// network).
|
||||
//
|
||||
// Once the generated packfile is available to the repository, call
|
||||
// Mempack.Reset to cleanup the memory store.
|
||||
//
|
||||
// Calling Mempack.Reset before the packfile has been written to disk will
|
||||
// result in an inconsistent repository (the objects in the memory store won't
|
||||
// be accessible).
|
||||
func (mempack *Mempack) Dump(repository *Repository) ([]byte, error) {
|
||||
buf := C.git_buf{}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_mempack_dump(&buf, repository.ptr, mempack.ptr)
|
||||
runtime.KeepAlive(repository)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
defer C.git_buf_dispose(&buf)
|
||||
|
||||
return C.GoBytes(unsafe.Pointer(buf.ptr), C.int(buf.size)), nil
|
||||
}
|
||||
|
||||
// Reset resets the memory packer by clearing all the queued objects.
|
||||
//
|
||||
// This assumes that Mempack.Dump has been called before to store all the
|
||||
// queued objects into a single packfile.
|
||||
func (mempack *Mempack) Reset() error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_mempack_reset(mempack.ptr)
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMempack(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
odb, err := NewOdb()
|
||||
checkFatal(t, err)
|
||||
|
||||
repo, err := NewRepositoryWrapOdb(odb)
|
||||
checkFatal(t, err)
|
||||
|
||||
mempack, err := NewMempack(odb)
|
||||
checkFatal(t, err)
|
||||
|
||||
id, err := odb.Write([]byte("hello, world!"), ObjectBlob)
|
||||
checkFatal(t, err)
|
||||
|
||||
expectedId, err := NewOid("30f51a3fba5274d53522d0f19748456974647b4f")
|
||||
checkFatal(t, err)
|
||||
if !expectedId.Equal(id) {
|
||||
t.Errorf("mismatched id. expected %v, got %v", expectedId.String(), id.String())
|
||||
}
|
||||
|
||||
// The object should be available from the odb.
|
||||
{
|
||||
obj, err := odb.Read(expectedId)
|
||||
checkFatal(t, err)
|
||||
defer obj.Free()
|
||||
}
|
||||
|
||||
data, err := mempack.Dump(repo)
|
||||
checkFatal(t, err)
|
||||
|
||||
expectedData := []byte{
|
||||
0x50, 0x41, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x9d, 0x08, 0x82, 0x3b, 0xd8, 0xa8, 0xea, 0xb5, 0x10, 0xad, 0x6a,
|
||||
0xc7, 0x5c, 0x82, 0x3c, 0xfd, 0x3e, 0xd3, 0x1e,
|
||||
}
|
||||
if !bytes.Equal(expectedData, data) {
|
||||
t.Errorf("mismatched mempack data. expected %v, got %v", expectedData, data)
|
||||
}
|
||||
|
||||
mempack.Reset()
|
||||
|
||||
// After the reset, the object should now be unavailable.
|
||||
{
|
||||
obj, err := odb.Read(expectedId)
|
||||
if err == nil {
|
||||
t.Errorf("object %s unexpectedly found", obj.Id().String())
|
||||
obj.Free()
|
||||
} else if !IsErrorCode(err, ErrNotFound) {
|
||||
t.Errorf("unexpected error %v", err)
|
||||
}
|
||||
}
|
||||
}
|
31
merge.go
31
merge.go
|
@ -132,7 +132,7 @@ func (mo *MergeOptions) toC() *C.git_merge_options {
|
|||
}
|
||||
return &C.git_merge_options{
|
||||
version: C.uint(mo.Version),
|
||||
flags: C.git_merge_flag_t(mo.TreeFlags),
|
||||
flags: C.uint32_t(mo.TreeFlags),
|
||||
rename_threshold: C.uint(mo.RenameThreshold),
|
||||
target_limit: C.uint(mo.TargetLimit),
|
||||
file_favor: C.git_merge_file_favor_t(mo.FileFavor),
|
||||
|
@ -344,9 +344,29 @@ type MergeFileFlags int
|
|||
const (
|
||||
MergeFileDefault MergeFileFlags = C.GIT_MERGE_FILE_DEFAULT
|
||||
|
||||
MergeFileStyleMerge MergeFileFlags = C.GIT_MERGE_FILE_STYLE_MERGE
|
||||
MergeFileStyleDiff MergeFileFlags = C.GIT_MERGE_FILE_STYLE_DIFF3
|
||||
// Create standard conflicted merge files
|
||||
MergeFileStyleMerge MergeFileFlags = C.GIT_MERGE_FILE_STYLE_MERGE
|
||||
|
||||
// Create diff3-style files
|
||||
MergeFileStyleDiff MergeFileFlags = C.GIT_MERGE_FILE_STYLE_DIFF3
|
||||
|
||||
// Condense non-alphanumeric regions for simplified diff file
|
||||
MergeFileStyleSimplifyAlnum MergeFileFlags = C.GIT_MERGE_FILE_SIMPLIFY_ALNUM
|
||||
|
||||
// Ignore all whitespace
|
||||
MergeFileIgnoreWhitespace MergeFileFlags = C.GIT_MERGE_FILE_IGNORE_WHITESPACE
|
||||
|
||||
// Ignore changes in amount of whitespace
|
||||
MergeFileIgnoreWhitespaceChange MergeFileFlags = C.GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE
|
||||
|
||||
// Ignore whitespace at end of line
|
||||
MergeFileIgnoreWhitespaceEOL MergeFileFlags = C.GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL
|
||||
|
||||
// Use the "patience diff" algorithm
|
||||
MergeFileDiffPatience MergeFileFlags = C.GIT_MERGE_FILE_DIFF_PATIENCE
|
||||
|
||||
// Take extra time to find minimal diff
|
||||
MergeFileDiffMinimal MergeFileFlags = C.GIT_MERGE_FILE_DIFF_MINIMAL
|
||||
)
|
||||
|
||||
type MergeFileOptions struct {
|
||||
|
@ -355,6 +375,7 @@ type MergeFileOptions struct {
|
|||
TheirLabel string
|
||||
Favor MergeFileFavor
|
||||
Flags MergeFileFlags
|
||||
MarkerSize uint16
|
||||
}
|
||||
|
||||
func mergeFileOptionsFromC(c C.git_merge_file_options) MergeFileOptions {
|
||||
|
@ -364,6 +385,7 @@ func mergeFileOptionsFromC(c C.git_merge_file_options) MergeFileOptions {
|
|||
TheirLabel: C.GoString(c.their_label),
|
||||
Favor: MergeFileFavor(c.favor),
|
||||
Flags: MergeFileFlags(c.flags),
|
||||
MarkerSize: uint16(c.marker_size),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -372,7 +394,8 @@ func populateCMergeFileOptions(c *C.git_merge_file_options, options MergeFileOpt
|
|||
c.our_label = C.CString(options.OurLabel)
|
||||
c.their_label = C.CString(options.TheirLabel)
|
||||
c.favor = C.git_merge_file_favor_t(options.Favor)
|
||||
c.flags = C.git_merge_file_flag_t(options.Flags)
|
||||
c.flags = C.uint32_t(options.Flags)
|
||||
c.marker_size = C.ushort(options.MarkerSize)
|
||||
}
|
||||
|
||||
func freeCMergeFileOptions(c *C.git_merge_file_options) {
|
||||
|
|
2
note.go
2
note.go
|
@ -132,7 +132,7 @@ func (c *NoteCollection) DefaultRef() (string, error) {
|
|||
}
|
||||
|
||||
ret := C.GoString(buf.ptr)
|
||||
C.git_buf_free(&buf)
|
||||
C.git_buf_dispose(&buf)
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
|
20
object.go
20
object.go
|
@ -13,12 +13,12 @@ import (
|
|||
type ObjectType int
|
||||
|
||||
const (
|
||||
ObjectAny ObjectType = C.GIT_OBJ_ANY
|
||||
ObjectBad ObjectType = C.GIT_OBJ_BAD
|
||||
ObjectCommit ObjectType = C.GIT_OBJ_COMMIT
|
||||
ObjectTree ObjectType = C.GIT_OBJ_TREE
|
||||
ObjectBlob ObjectType = C.GIT_OBJ_BLOB
|
||||
ObjectTag ObjectType = C.GIT_OBJ_TAG
|
||||
ObjectAny ObjectType = C.GIT_OBJECT_ANY
|
||||
ObjectInvalid ObjectType = C.GIT_OBJECT_INVALID
|
||||
ObjectCommit ObjectType = C.GIT_OBJECT_COMMIT
|
||||
ObjectTree ObjectType = C.GIT_OBJECT_TREE
|
||||
ObjectBlob ObjectType = C.GIT_OBJECT_BLOB
|
||||
ObjectTag ObjectType = C.GIT_OBJECT_TAG
|
||||
)
|
||||
|
||||
type Object struct {
|
||||
|
@ -35,8 +35,8 @@ func (t ObjectType) String() string {
|
|||
switch t {
|
||||
case ObjectAny:
|
||||
return "Any"
|
||||
case ObjectBad:
|
||||
return "Bad"
|
||||
case ObjectInvalid:
|
||||
return "Invalid"
|
||||
case ObjectCommit:
|
||||
return "Commit"
|
||||
case ObjectTree:
|
||||
|
@ -67,7 +67,7 @@ func (o *Object) ShortId() (string, error) {
|
|||
if ecode < 0 {
|
||||
return "", MakeGitError(ecode)
|
||||
}
|
||||
defer C.git_buf_free(&resultBuf)
|
||||
defer C.git_buf_dispose(&resultBuf)
|
||||
return C.GoString(resultBuf.ptr), nil
|
||||
}
|
||||
|
||||
|
@ -217,7 +217,7 @@ func (o *Object) Peel(t ObjectType) (*Object, error) {
|
|||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
err := C.git_object_peel(&cobj, o.ptr, C.git_otype(t))
|
||||
err := C.git_object_peel(&cobj, o.ptr, C.git_object_t(t))
|
||||
runtime.KeepAlive(o)
|
||||
if err < 0 {
|
||||
return nil, MakeGitError(err)
|
||||
|
|
|
@ -108,7 +108,7 @@ func TestObjectOwner(t *testing.T) {
|
|||
|
||||
func checkShortId(t *testing.T, Id, shortId string) {
|
||||
if len(shortId) < 7 || len(shortId) >= len(Id) {
|
||||
t.Fatalf("bad shortId lenght %d", len(shortId))
|
||||
t.Fatalf("bad shortId length %d", len(shortId))
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(Id, shortId) {
|
||||
|
|
46
odb.go
46
odb.go
|
@ -8,6 +8,7 @@ extern void _go_git_odb_backend_free(git_odb_backend *backend);
|
|||
*/
|
||||
import "C"
|
||||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
@ -60,12 +61,12 @@ func (v *Odb) ReadHeader(oid *Oid) (uint64, ObjectType, error) {
|
|||
defer runtime.UnlockOSThread()
|
||||
|
||||
var sz C.size_t
|
||||
var cotype C.git_otype
|
||||
var cotype C.git_object_t
|
||||
|
||||
ret := C.git_odb_read_header(&sz, &cotype, v.ptr, oid.toC())
|
||||
runtime.KeepAlive(v)
|
||||
if ret < 0 {
|
||||
return 0, C.GIT_OBJ_BAD, MakeGitError(ret)
|
||||
return 0, ObjectInvalid, MakeGitError(ret)
|
||||
}
|
||||
|
||||
return uint64(sz), ObjectType(cotype), nil
|
||||
|
@ -80,15 +81,19 @@ func (v *Odb) Exists(oid *Oid) bool {
|
|||
|
||||
func (v *Odb) Write(data []byte, otype ObjectType) (oid *Oid, err error) {
|
||||
oid = new(Oid)
|
||||
var cptr unsafe.Pointer
|
||||
if len(data) > 0 {
|
||||
cptr = unsafe.Pointer(&data[0])
|
||||
}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_odb_write(oid.toC(), v.ptr, cptr, C.size_t(len(data)), C.git_otype(otype))
|
||||
var size C.size_t
|
||||
if len(data) > 0 {
|
||||
size = C.size_t(len(data))
|
||||
} else {
|
||||
data = []byte{0}
|
||||
size = C.size_t(0)
|
||||
}
|
||||
|
||||
ret := C.git_odb_write(oid.toC(), v.ptr, unsafe.Pointer(&data[0]), size, C.git_object_t(otype))
|
||||
runtime.KeepAlive(v)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
|
@ -164,13 +169,19 @@ func (v *Odb) ForEach(callback OdbForEachCallback) error {
|
|||
// Hash determines the object-ID (sha1) of a data buffer.
|
||||
func (v *Odb) Hash(data []byte, otype ObjectType) (oid *Oid, err error) {
|
||||
oid = new(Oid)
|
||||
header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
|
||||
ptr := unsafe.Pointer(header.Data)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_odb_hash(oid.toC(), ptr, C.size_t(header.Len), C.git_otype(otype))
|
||||
var size C.size_t
|
||||
if len(data) > 0 {
|
||||
size = C.size_t(len(data))
|
||||
} else {
|
||||
data = []byte{0}
|
||||
size = C.size_t(0)
|
||||
}
|
||||
|
||||
ret := C.git_odb_hash(oid.toC(), unsafe.Pointer(&data[0]), size, C.git_object_t(otype))
|
||||
runtime.KeepAlive(data)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
|
@ -182,17 +193,21 @@ func (v *Odb) Hash(data []byte, otype ObjectType) (oid *Oid, err error) {
|
|||
// contents of the object.
|
||||
func (v *Odb) NewReadStream(id *Oid) (*OdbReadStream, error) {
|
||||
stream := new(OdbReadStream)
|
||||
var ctype C.git_object_t
|
||||
var csize C.size_t
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_odb_open_rstream(&stream.ptr, v.ptr, id.toC())
|
||||
ret := C.git_odb_open_rstream(&stream.ptr, &csize, &ctype, v.ptr, id.toC())
|
||||
runtime.KeepAlive(v)
|
||||
runtime.KeepAlive(id)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
stream.Size = uint64(csize)
|
||||
stream.Type = ObjectType(ctype)
|
||||
runtime.SetFinalizer(stream, (*OdbReadStream).Free)
|
||||
return stream, nil
|
||||
}
|
||||
|
@ -206,7 +221,7 @@ func (v *Odb) NewWriteStream(size int64, otype ObjectType) (*OdbWriteStream, err
|
|||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_odb_open_wstream(&stream.ptr, v.ptr, C.git_off_t(size), C.git_otype(otype))
|
||||
ret := C.git_odb_open_wstream(&stream.ptr, v.ptr, C.git_object_size_t(size), C.git_object_t(otype))
|
||||
runtime.KeepAlive(v)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
|
@ -264,7 +279,9 @@ func (object *OdbObject) Data() (data []byte) {
|
|||
}
|
||||
|
||||
type OdbReadStream struct {
|
||||
ptr *C.git_odb_stream
|
||||
ptr *C.git_odb_stream
|
||||
Size uint64
|
||||
Type ObjectType
|
||||
}
|
||||
|
||||
// Read reads from the stream
|
||||
|
@ -281,6 +298,9 @@ func (stream *OdbReadStream) Read(data []byte) (int, error) {
|
|||
if ret < 0 {
|
||||
return 0, MakeGitError(ret)
|
||||
}
|
||||
if ret == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
header.Len = int(ret)
|
||||
|
||||
|
|
49
odb_test.go
49
odb_test.go
|
@ -1,12 +1,14 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOdbReadHeader(t *testing.T) {
|
||||
func TestOdbRead(t *testing.T) {
|
||||
t.Parallel()
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
|
@ -26,13 +28,27 @@ func TestOdbReadHeader(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("ReadHeader: %v", err)
|
||||
}
|
||||
|
||||
|
||||
if sz != uint64(len(data)) {
|
||||
t.Errorf("ReadHeader got size %d, want %d", sz, len(data))
|
||||
}
|
||||
if typ != ObjectBlob {
|
||||
t.Errorf("ReadHeader got object type %s", typ)
|
||||
}
|
||||
|
||||
obj, err := odb.Read(id)
|
||||
if err != nil {
|
||||
t.Fatalf("Read: %v", err)
|
||||
}
|
||||
if !bytes.Equal(obj.Data(), data) {
|
||||
t.Errorf("Read got wrong data")
|
||||
}
|
||||
if sz := obj.Len(); sz != uint64(len(data)) {
|
||||
t.Errorf("Read got size %d, want %d", sz, len(data))
|
||||
}
|
||||
if typ := obj.Type(); typ != ObjectBlob {
|
||||
t.Errorf("Read got object type %s", typ)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOdbStream(t *testing.T) {
|
||||
|
@ -47,22 +63,29 @@ func TestOdbStream(t *testing.T) {
|
|||
|
||||
str := "hello, world!"
|
||||
|
||||
stream, error := odb.NewWriteStream(int64(len(str)), ObjectBlob)
|
||||
writeStream, error := odb.NewWriteStream(int64(len(str)), ObjectBlob)
|
||||
checkFatal(t, error)
|
||||
n, error := io.WriteString(stream, str)
|
||||
n, error := io.WriteString(writeStream, str)
|
||||
checkFatal(t, error)
|
||||
if n != len(str) {
|
||||
t.Fatalf("Bad write length %v != %v", n, len(str))
|
||||
}
|
||||
|
||||
error = stream.Close()
|
||||
error = writeStream.Close()
|
||||
checkFatal(t, error)
|
||||
|
||||
expectedId, error := NewOid("30f51a3fba5274d53522d0f19748456974647b4f")
|
||||
checkFatal(t, error)
|
||||
if stream.Id.Cmp(expectedId) != 0 {
|
||||
if writeStream.Id.Cmp(expectedId) != 0 {
|
||||
t.Fatal("Wrong data written")
|
||||
}
|
||||
|
||||
readStream, error := odb.NewReadStream(&writeStream.Id)
|
||||
checkFatal(t, error)
|
||||
data, error := ioutil.ReadAll(readStream)
|
||||
if str != string(data) {
|
||||
t.Fatalf("Wrong data read %v != %v", str, string(data))
|
||||
}
|
||||
}
|
||||
|
||||
func TestOdbHash(t *testing.T) {
|
||||
|
@ -82,14 +105,16 @@ committer John Doe <john@doe.com> 1390682018 +0000
|
|||
|
||||
Initial commit.`
|
||||
|
||||
oid, error := odb.Hash([]byte(str), ObjectCommit)
|
||||
checkFatal(t, error)
|
||||
for _, data := range [][]byte{[]byte(str), doublePointerBytes()} {
|
||||
oid, error := odb.Hash(data, ObjectCommit)
|
||||
checkFatal(t, error)
|
||||
|
||||
coid, error := odb.Write([]byte(str), ObjectCommit)
|
||||
checkFatal(t, error)
|
||||
coid, error := odb.Write(data, ObjectCommit)
|
||||
checkFatal(t, error)
|
||||
|
||||
if oid.Cmp(coid) != 0 {
|
||||
t.Fatal("Hash and write Oids are different")
|
||||
if oid.Cmp(coid) != 0 {
|
||||
t.Fatal("Hash and write Oids are different")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,6 +85,19 @@ func (pb *Packbuilder) InsertTree(id *Oid) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (pb *Packbuilder) InsertWalk(walk *RevWalk) error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_packbuilder_insert_walk(pb.ptr, walk.ptr)
|
||||
runtime.KeepAlive(pb)
|
||||
runtime.KeepAlive(walk)
|
||||
if ret != 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pb *Packbuilder) ObjectCount() uint32 {
|
||||
ret := uint32(C.git_packbuilder_object_count(pb.ptr))
|
||||
runtime.KeepAlive(pb)
|
||||
|
|
4
patch.go
4
patch.go
|
@ -51,7 +51,7 @@ func (patch *Patch) String() (string, error) {
|
|||
if ecode < 0 {
|
||||
return "", MakeGitError(ecode)
|
||||
}
|
||||
defer C.git_buf_free(&buf)
|
||||
defer C.git_buf_dispose(&buf)
|
||||
|
||||
return C.GoString(buf.ptr), nil
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ func (v *Repository) PatchFromBuffers(oldPath, newPath string, oldBuf, newBuf []
|
|||
var patchPtr *C.git_patch
|
||||
|
||||
oldPtr := toPointer(oldBuf)
|
||||
newPtr := (*C.char)(toPointer(newBuf))
|
||||
newPtr := toPointer(newBuf)
|
||||
|
||||
cOldPath := C.CString(oldPath)
|
||||
defer C.free(unsafe.Pointer(cOldPath))
|
||||
|
|
23
rebase.go
23
rebase.go
|
@ -6,6 +6,7 @@ package git
|
|||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
@ -16,6 +17,8 @@ type RebaseOperationType uint
|
|||
const (
|
||||
// RebaseOperationPick The given commit is to be cherry-picked. The client should commit the changes and continue if there are no conflicts.
|
||||
RebaseOperationPick RebaseOperationType = C.GIT_REBASE_OPERATION_PICK
|
||||
// RebaseOperationReword The given commit is to be cherry-picked, but the client should prompt the user to provide an updated commit message.
|
||||
RebaseOperationReword RebaseOperationType = C.GIT_REBASE_OPERATION_REWORD
|
||||
// RebaseOperationEdit The given commit is to be cherry-picked, but the client should stop to allow the user to edit the changes before committing them.
|
||||
RebaseOperationEdit RebaseOperationType = C.GIT_REBASE_OPERATION_EDIT
|
||||
// RebaseOperationSquash The given commit is to be squashed into the previous commit. The commit message will be merged with the previous message.
|
||||
|
@ -26,11 +29,29 @@ const (
|
|||
RebaseOperationExec RebaseOperationType = C.GIT_REBASE_OPERATION_EXEC
|
||||
)
|
||||
|
||||
func (t RebaseOperationType) String() string {
|
||||
switch t {
|
||||
case RebaseOperationPick:
|
||||
return "pick"
|
||||
case RebaseOperationReword:
|
||||
return "reword"
|
||||
case RebaseOperationEdit:
|
||||
return "edit"
|
||||
case RebaseOperationSquash:
|
||||
return "squash"
|
||||
case RebaseOperationFixup:
|
||||
return "fixup"
|
||||
case RebaseOperationExec:
|
||||
return "exec"
|
||||
}
|
||||
return fmt.Sprintf("RebaseOperationType(%d)", t)
|
||||
}
|
||||
|
||||
// Special value indicating that there is no currently active operation
|
||||
var RebaseNoOperation uint = ^uint(0)
|
||||
|
||||
// Error returned if there is no current rebase operation
|
||||
var ErrRebaseNoOperation = errors.New("o current rebase operation")
|
||||
var ErrRebaseNoOperation = errors.New("no current rebase operation")
|
||||
|
||||
// RebaseOperation describes a single instruction/operation to be performed during the rebase.
|
||||
type RebaseOperation struct {
|
||||
|
|
11
reference.go
11
reference.go
|
@ -284,7 +284,7 @@ func (v *Reference) Peel(t ObjectType) (*Object, error) {
|
|||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
err := C.git_reference_peel(&cobj, v.ptr, C.git_otype(t))
|
||||
err := C.git_reference_peel(&cobj, v.ptr, C.git_object_t(t))
|
||||
runtime.KeepAlive(v)
|
||||
if err < 0 {
|
||||
return nil, MakeGitError(err)
|
||||
|
@ -301,7 +301,7 @@ func (v *Reference) Owner() *Repository {
|
|||
}
|
||||
}
|
||||
|
||||
// Cmp compares both references, retursn 0 on equality, otherwise a
|
||||
// Cmp compares v to ref2. It returns 0 on equality, otherwise a
|
||||
// stable sorting.
|
||||
func (v *Reference) Cmp(ref2 *Reference) int {
|
||||
ret := int(C.git_reference_cmp(v.ptr, ref2.ptr))
|
||||
|
@ -310,13 +310,14 @@ func (v *Reference) Cmp(ref2 *Reference) int {
|
|||
return ret
|
||||
}
|
||||
|
||||
// Shorthand ret :=s a "human-readable" short reference name
|
||||
// Shorthand returns a "human-readable" short reference name.
|
||||
func (v *Reference) Shorthand() string {
|
||||
ret := C.GoString(C.git_reference_shorthand(v.ptr))
|
||||
runtime.KeepAlive(v)
|
||||
return ret
|
||||
}
|
||||
|
||||
// Name returns the full name of v.
|
||||
func (v *Reference) Name() string {
|
||||
ret := C.GoString(C.git_reference_name(v.ptr))
|
||||
runtime.KeepAlive(v)
|
||||
|
@ -455,10 +456,12 @@ func (v *ReferenceIterator) Next() (*Reference, error) {
|
|||
}
|
||||
|
||||
func newReferenceIteratorFromC(ptr *C.git_reference_iterator, r *Repository) *ReferenceIterator {
|
||||
return &ReferenceIterator{
|
||||
iter := &ReferenceIterator{
|
||||
ptr: ptr,
|
||||
repo: r,
|
||||
}
|
||||
runtime.SetFinalizer(iter, (*ReferenceIterator).Free)
|
||||
return iter
|
||||
}
|
||||
|
||||
// Free the reference iterator
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package git
|
||||
|
||||
/*
|
||||
#include <git2.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <git2.h>
|
||||
#include <git2/sys/cred.h>
|
||||
|
||||
extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks);
|
||||
|
||||
*/
|
||||
|
|
|
@ -3,6 +3,8 @@ package git
|
|||
/*
|
||||
#include <git2.h>
|
||||
#include <git2/sys/repository.h>
|
||||
#include <git2/sys/commit.h>
|
||||
#include <string.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
|
@ -19,10 +21,10 @@ type Repository struct {
|
|||
Remotes RemoteCollection
|
||||
// Submodules represents the collection of submodules and can
|
||||
// be used to add, remove and configure submodules in this
|
||||
// repostiory.
|
||||
// repository.
|
||||
Submodules SubmoduleCollection
|
||||
// References represents the collection of references and can
|
||||
// be used to create, remove or update refernces for this repository.
|
||||
// be used to create, remove or update references for this repository.
|
||||
References ReferenceCollection
|
||||
// Notes represents the collection of notes and can be used to
|
||||
// read, write and delete notes from this repository.
|
||||
|
@ -174,7 +176,7 @@ func (v *Repository) lookupType(id *Oid, t ObjectType) (*Object, error) {
|
|||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_object_lookup(&ptr, v.ptr, id.toC(), C.git_otype(t))
|
||||
ret := C.git_object_lookup(&ptr, v.ptr, id.toC(), C.git_object_t(t))
|
||||
runtime.KeepAlive(id)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
|
@ -192,6 +194,7 @@ func (v *Repository) LookupTree(id *Oid) (*Tree, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer obj.Free()
|
||||
|
||||
return obj.AsTree()
|
||||
}
|
||||
|
@ -201,6 +204,7 @@ func (v *Repository) LookupCommit(id *Oid) (*Commit, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer obj.Free()
|
||||
|
||||
return obj.AsCommit()
|
||||
}
|
||||
|
@ -210,6 +214,7 @@ func (v *Repository) LookupBlob(id *Oid) (*Blob, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer obj.Free()
|
||||
|
||||
return obj.AsBlob()
|
||||
}
|
||||
|
@ -219,6 +224,7 @@ func (v *Repository) LookupTag(id *Oid) (*Tag, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer obj.Free()
|
||||
|
||||
return obj.AsTag()
|
||||
}
|
||||
|
@ -389,6 +395,74 @@ func (v *Repository) CreateCommit(
|
|||
return oid, nil
|
||||
}
|
||||
|
||||
func (v *Repository) CreateCommitFromIds(
|
||||
refname string, author, committer *Signature,
|
||||
message string, tree *Oid, parents ...*Oid) (*Oid, error) {
|
||||
|
||||
oid := new(Oid)
|
||||
|
||||
var cref *C.char
|
||||
if refname == "" {
|
||||
cref = nil
|
||||
} else {
|
||||
cref = C.CString(refname)
|
||||
defer C.free(unsafe.Pointer(cref))
|
||||
}
|
||||
|
||||
cmsg := C.CString(message)
|
||||
defer C.free(unsafe.Pointer(cmsg))
|
||||
|
||||
var parentsarg **C.git_oid = nil
|
||||
|
||||
nparents := len(parents)
|
||||
if nparents > 0 {
|
||||
// All this awful pointer arithmetic is needed to avoid passing a Go
|
||||
// pointer to Go pointer into C. Other methods (like CreateCommits) are
|
||||
// fine without this workaround because they are just passing Go pointers
|
||||
// to C pointers, but arrays-of-pointers-to-git_oid are a bit special since
|
||||
// both the array and the objects are allocated from Go.
|
||||
var emptyOidPtr *C.git_oid
|
||||
sizeofOidPtr := unsafe.Sizeof(emptyOidPtr)
|
||||
parentsarg = (**C.git_oid)(C.calloc(C.size_t(uintptr(nparents)), C.size_t(sizeofOidPtr)))
|
||||
defer C.free(unsafe.Pointer(parentsarg))
|
||||
parentsptr := uintptr(unsafe.Pointer(parentsarg))
|
||||
for _, v := range parents {
|
||||
*(**C.git_oid)(unsafe.Pointer(parentsptr)) = v.toC()
|
||||
parentsptr += sizeofOidPtr
|
||||
}
|
||||
}
|
||||
|
||||
authorSig, err := author.toC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer C.git_signature_free(authorSig)
|
||||
|
||||
committerSig, err := committer.toC()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer C.git_signature_free(committerSig)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_commit_create_from_ids(
|
||||
oid.toC(), v.ptr, cref,
|
||||
authorSig, committerSig,
|
||||
nil, cmsg, tree.toC(), C.size_t(nparents), parentsarg)
|
||||
|
||||
runtime.KeepAlive(v)
|
||||
runtime.KeepAlive(oid)
|
||||
runtime.KeepAlive(tree)
|
||||
runtime.KeepAlive(parents)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
return oid, nil
|
||||
}
|
||||
|
||||
func (v *Odb) Free() {
|
||||
runtime.SetFinalizer(v, nil)
|
||||
C.git_odb_free(v.ptr)
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCreateCommitFromIds(t *testing.T) {
|
||||
t.Parallel()
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
|
||||
loc, err := time.LoadLocation("Europe/Berlin")
|
||||
checkFatal(t, err)
|
||||
sig := &Signature{
|
||||
Name: "Rand Om Hacker",
|
||||
Email: "random@hacker.com",
|
||||
When: time.Date(2013, 03, 06, 14, 30, 0, 0, loc),
|
||||
}
|
||||
|
||||
idx, err := repo.Index()
|
||||
checkFatal(t, err)
|
||||
err = idx.AddByPath("README")
|
||||
checkFatal(t, err)
|
||||
err = idx.Write()
|
||||
checkFatal(t, err)
|
||||
treeId, err := idx.WriteTree()
|
||||
checkFatal(t, err)
|
||||
|
||||
message := "This is a commit\n"
|
||||
tree, err := repo.LookupTree(treeId)
|
||||
checkFatal(t, err)
|
||||
expectedCommitId, err := repo.CreateCommit("HEAD", sig, sig, message, tree)
|
||||
checkFatal(t, err)
|
||||
|
||||
commitId, err := repo.CreateCommitFromIds("", sig, sig, message, treeId)
|
||||
checkFatal(t, err)
|
||||
|
||||
if !expectedCommitId.Equal(commitId) {
|
||||
t.Errorf("mismatched commit ids, expected %v, got %v", expectedCommitId.String(), commitId.String())
|
||||
}
|
||||
}
|
|
@ -8,6 +8,8 @@ import (
|
|||
func TestResetToCommit(t *testing.T) {
|
||||
t.Parallel()
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
|
||||
seedTestRepo(t, repo)
|
||||
// create commit to reset to
|
||||
commitId, _ := updateReadme(t, repo, "testing reset")
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
package git
|
||||
|
||||
/*
|
||||
#include <git2.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// RevertOptions contains options for performing a revert
|
||||
type RevertOptions struct {
|
||||
Mainline uint
|
||||
MergeOpts MergeOptions
|
||||
CheckoutOpts CheckoutOpts
|
||||
}
|
||||
|
||||
func (opts *RevertOptions) toC() *C.git_revert_options {
|
||||
return &C.git_revert_options{
|
||||
version: C.GIT_REVERT_OPTIONS_VERSION,
|
||||
mainline: C.uint(opts.Mainline),
|
||||
merge_opts: *opts.MergeOpts.toC(),
|
||||
checkout_opts: *opts.CheckoutOpts.toC(),
|
||||
}
|
||||
}
|
||||
|
||||
func revertOptionsFromC(opts *C.git_revert_options) RevertOptions {
|
||||
return RevertOptions{
|
||||
Mainline: uint(opts.mainline),
|
||||
MergeOpts: mergeOptionsFromC(&opts.merge_opts),
|
||||
CheckoutOpts: checkoutOptionsFromC(&opts.checkout_opts),
|
||||
}
|
||||
}
|
||||
|
||||
func freeRevertOptions(opts *C.git_revert_options) {
|
||||
freeCheckoutOpts(&opts.checkout_opts)
|
||||
}
|
||||
|
||||
// DefaultRevertOptions initialises a RevertOptions struct with default values
|
||||
func DefaultRevertOptions() (RevertOptions, error) {
|
||||
opts := C.git_revert_options{}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ecode := C.git_revert_init_options(&opts, C.GIT_REVERT_OPTIONS_VERSION)
|
||||
if ecode < 0 {
|
||||
return RevertOptions{}, MakeGitError(ecode)
|
||||
}
|
||||
|
||||
defer freeRevertOptions(&opts)
|
||||
return revertOptionsFromC(&opts), nil
|
||||
}
|
||||
|
||||
// Revert the provided commit leaving the index updated with the results of the revert
|
||||
func (r *Repository) Revert(commit *Commit, revertOptions *RevertOptions) error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
var cOpts *C.git_revert_options
|
||||
|
||||
if revertOptions != nil {
|
||||
cOpts = revertOptions.toC()
|
||||
defer freeRevertOptions(cOpts)
|
||||
}
|
||||
|
||||
ecode := C.git_revert(r.ptr, commit.cast_ptr, cOpts)
|
||||
runtime.KeepAlive(r)
|
||||
runtime.KeepAlive(commit)
|
||||
|
||||
if ecode < 0 {
|
||||
return MakeGitError(ecode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RevertCommit reverts the provided commit against "ourCommit"
|
||||
// The returned index contains the result of the revert and should be freed
|
||||
func (r *Repository) RevertCommit(revertCommit *Commit, ourCommit *Commit, mainline uint, mergeOptions *MergeOptions) (*Index, error) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
var cOpts *C.git_merge_options
|
||||
|
||||
if mergeOptions != nil {
|
||||
cOpts = mergeOptions.toC()
|
||||
}
|
||||
|
||||
var index *C.git_index
|
||||
|
||||
ecode := C.git_revert_commit(&index, r.ptr, revertCommit.cast_ptr, ourCommit.cast_ptr, C.uint(mainline), cOpts)
|
||||
runtime.KeepAlive(revertCommit)
|
||||
runtime.KeepAlive(ourCommit)
|
||||
|
||||
if ecode < 0 {
|
||||
return nil, MakeGitError(ecode)
|
||||
}
|
||||
|
||||
return newIndexFromC(index, r), nil
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
expectedRevertedReadmeContents = "foo\n"
|
||||
)
|
||||
|
||||
func TestRevert(t *testing.T) {
|
||||
t.Parallel()
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
|
||||
seedTestRepo(t, repo)
|
||||
commitID, _ := updateReadme(t, repo, content)
|
||||
|
||||
commit, err := repo.LookupCommit(commitID)
|
||||
checkFatal(t, err)
|
||||
|
||||
revertOptions, err := DefaultRevertOptions()
|
||||
checkFatal(t, err)
|
||||
|
||||
err = repo.Revert(commit, &revertOptions)
|
||||
checkFatal(t, err)
|
||||
|
||||
actualReadmeContents := readReadme(t, repo)
|
||||
|
||||
if actualReadmeContents != expectedRevertedReadmeContents {
|
||||
t.Fatalf(`README has incorrect contents after revert. Expected: "%v", Actual: "%v"`,
|
||||
expectedRevertedReadmeContents, actualReadmeContents)
|
||||
}
|
||||
|
||||
state := repo.State()
|
||||
if state != RepositoryStateRevert {
|
||||
t.Fatalf("Incorrect repository state. Expected: %v, Actual: %v", RepositoryStateRevert, state)
|
||||
}
|
||||
|
||||
err = repo.StateCleanup()
|
||||
checkFatal(t, err)
|
||||
|
||||
state = repo.State()
|
||||
if state != RepositoryStateNone {
|
||||
t.Fatalf("Incorrect repository state. Expected: %v, Actual: %v", RepositoryStateNone, state)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRevertCommit(t *testing.T) {
|
||||
t.Parallel()
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
|
||||
seedTestRepo(t, repo)
|
||||
commitID, _ := updateReadme(t, repo, content)
|
||||
|
||||
commit, err := repo.LookupCommit(commitID)
|
||||
checkFatal(t, err)
|
||||
|
||||
revertOptions, err := DefaultRevertOptions()
|
||||
checkFatal(t, err)
|
||||
|
||||
index, err := repo.RevertCommit(commit, commit, 0, &revertOptions.MergeOpts)
|
||||
checkFatal(t, err)
|
||||
defer index.Free()
|
||||
|
||||
err = repo.CheckoutIndex(index, &revertOptions.CheckoutOpts)
|
||||
checkFatal(t, err)
|
||||
|
||||
actualReadmeContents := readReadme(t, repo)
|
||||
|
||||
if actualReadmeContents != expectedRevertedReadmeContents {
|
||||
t.Fatalf(`README has incorrect contents after revert. Expected: "%v", Actual: "%v"`,
|
||||
expectedRevertedReadmeContents, actualReadmeContents)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
exec "$(dirname "$0")/build-libgit2.sh" --dynamic
|
|
@ -1,19 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
set -e
|
||||
|
||||
VENDORED_PATH=vendor/libgit2
|
||||
|
||||
cd $VENDORED_PATH &&
|
||||
mkdir -p install/lib &&
|
||||
mkdir -p build &&
|
||||
cd build &&
|
||||
cmake -DTHREADSAFE=ON \
|
||||
-DBUILD_CLAR=OFF \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DCMAKE_C_FLAGS=-fPIC \
|
||||
-DCMAKE_BUILD_TYPE="RelWithDebInfo" \
|
||||
-DCMAKE_INSTALL_PREFIX=../install \
|
||||
.. &&
|
||||
|
||||
cmake --build .
|
||||
exec "$(dirname "$0")/build-libgit2.sh" --static
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Since CMake cannot build the static and dynamic libraries in the same
|
||||
# directory, this script helps build both static and dynamic versions of it and
|
||||
# have the common flags in one place instead of split between two places.
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$#" -eq "0" ]; then
|
||||
echo "Usage: $0 <--dynamic|--static>">&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && echo "${PWD}")"
|
||||
VENDORED_PATH="${ROOT}/vendor/libgit2"
|
||||
|
||||
case "$1" in
|
||||
--static)
|
||||
BUILD_PATH="${ROOT}/static-build"
|
||||
BUILD_SHARED_LIBS=OFF
|
||||
;;
|
||||
|
||||
--dynamic)
|
||||
BUILD_PATH="${ROOT}/dynamic-build"
|
||||
BUILD_SHARED_LIBS=ON
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Usage: $0 <--dynamic|--static>">&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
mkdir -p "${BUILD_PATH}/build" "${BUILD_PATH}/install/lib"
|
||||
|
||||
cd "${BUILD_PATH}/build" &&
|
||||
cmake -DTHREADSAFE=ON \
|
||||
-DBUILD_CLAR=OFF \
|
||||
-DBUILD_SHARED_LIBS"=${BUILD_SHARED_LIBS}" \
|
||||
-DREGEX_BACKEND=builtin \
|
||||
-DCMAKE_C_FLAGS=-fPIC \
|
||||
-DCMAKE_BUILD_TYPE="RelWithDebInfo" \
|
||||
-DCMAKE_INSTALL_PREFIX="${BUILD_PATH}/install" \
|
||||
"${VENDORED_PATH}" &&
|
||||
|
||||
exec cmake --build . --target install
|
|
@ -31,7 +31,7 @@ import (
|
|||
|
||||
func SearchPath(level ConfigLevel) (string, error) {
|
||||
var buf C.git_buf
|
||||
defer C.git_buf_free(&buf)
|
||||
defer C.git_buf_dispose(&buf)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
|
|
@ -26,7 +26,7 @@ func newSignatureFromC(sig *C.git_signature) *Signature {
|
|||
}
|
||||
}
|
||||
|
||||
// the offset in mintes, which is what git wants
|
||||
// Offset returns the time zone offset of v.When in minutes, which is what git wants.
|
||||
func (v *Signature) Offset() int {
|
||||
_, offset := v.When.Zone()
|
||||
return offset / 60
|
||||
|
|
2
stash.go
2
stash.go
|
@ -171,7 +171,7 @@ func (opts *StashApplyOptions) toC() (
|
|||
|
||||
optsC = &C.git_stash_apply_options{
|
||||
version: C.GIT_STASH_APPLY_OPTIONS_VERSION,
|
||||
flags: C.git_stash_apply_flags(opts.Flags),
|
||||
flags: C.uint32_t(opts.Flags),
|
||||
}
|
||||
populateCheckoutOpts(&optsC.checkout_options, &opts.CheckoutOptions)
|
||||
if opts.ProgressCallback != nil {
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
type SubmoduleUpdateOptions struct {
|
||||
*CheckoutOpts
|
||||
*FetchOptions
|
||||
CloneCheckoutStrategy CheckoutStrategy
|
||||
}
|
||||
|
||||
// Submodule
|
||||
|
@ -369,7 +368,6 @@ func populateSubmoduleUpdateOptions(ptr *C.git_submodule_update_options, opts *S
|
|||
|
||||
populateCheckoutOpts(&ptr.checkout_opts, opts.CheckoutOpts)
|
||||
populateFetchOptions(&ptr.fetch_opts, opts.FetchOptions)
|
||||
ptr.clone_checkout_strategy = C.uint(opts.CloneCheckoutStrategy)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
12
tag.go
12
tag.go
|
@ -21,26 +21,26 @@ func (t *Tag) AsObject() *Object {
|
|||
return &t.Object
|
||||
}
|
||||
|
||||
func (t Tag) Message() string {
|
||||
func (t *Tag) Message() string {
|
||||
ret := C.GoString(C.git_tag_message(t.cast_ptr))
|
||||
runtime.KeepAlive(t)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (t Tag) Name() string {
|
||||
func (t *Tag) Name() string {
|
||||
ret := C.GoString(C.git_tag_name(t.cast_ptr))
|
||||
runtime.KeepAlive(t)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (t Tag) Tagger() *Signature {
|
||||
func (t *Tag) Tagger() *Signature {
|
||||
cast_ptr := C.git_tag_tagger(t.cast_ptr)
|
||||
ret := newSignatureFromC(cast_ptr)
|
||||
runtime.KeepAlive(t)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (t Tag) Target() *Object {
|
||||
func (t *Tag) Target() *Object {
|
||||
var ptr *C.git_object
|
||||
ret := C.git_tag_target(&ptr, t.cast_ptr)
|
||||
runtime.KeepAlive(t)
|
||||
|
@ -51,13 +51,13 @@ func (t Tag) Target() *Object {
|
|||
return allocObject(ptr, t.repo)
|
||||
}
|
||||
|
||||
func (t Tag) TargetId() *Oid {
|
||||
func (t *Tag) TargetId() *Oid {
|
||||
ret := newOidFromC(C.git_tag_target_id(t.cast_ptr))
|
||||
runtime.KeepAlive(t)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (t Tag) TargetType() ObjectType {
|
||||
func (t *Tag) TargetType() ObjectType {
|
||||
ret := ObjectType(C.git_tag_target_type(t.cast_ptr))
|
||||
runtime.KeepAlive(t)
|
||||
return ret
|
||||
|
|
30
tree.go
30
tree.go
|
@ -47,17 +47,18 @@ func newTreeEntry(entry *C.git_tree_entry) *TreeEntry {
|
|||
}
|
||||
}
|
||||
|
||||
func (t Tree) EntryByName(filename string) *TreeEntry {
|
||||
func (t *Tree) EntryByName(filename string) *TreeEntry {
|
||||
cname := C.CString(filename)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
entry := C.git_tree_entry_byname(t.cast_ptr, cname)
|
||||
runtime.KeepAlive(t)
|
||||
if entry == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return newTreeEntry(entry)
|
||||
goEntry := newTreeEntry(entry)
|
||||
runtime.KeepAlive(t)
|
||||
return goEntry
|
||||
}
|
||||
|
||||
// EntryById performs a lookup for a tree entry with the given SHA value.
|
||||
|
@ -66,23 +67,24 @@ func (t Tree) EntryByName(filename string) *TreeEntry {
|
|||
// free it, but you must not use it after the Tree is freed.
|
||||
//
|
||||
// Warning: this must examine every entry in the tree, so it is not fast.
|
||||
func (t Tree) EntryById(id *Oid) *TreeEntry {
|
||||
func (t *Tree) EntryById(id *Oid) *TreeEntry {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
entry := C.git_tree_entry_byid(t.cast_ptr, id.toC())
|
||||
runtime.KeepAlive(t)
|
||||
runtime.KeepAlive(id)
|
||||
if entry == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return newTreeEntry(entry)
|
||||
goEntry := newTreeEntry(entry)
|
||||
runtime.KeepAlive(t)
|
||||
return goEntry
|
||||
}
|
||||
|
||||
// EntryByPath looks up an entry by its full path, recursing into
|
||||
// deeper trees if necessary (i.e. if there are slashes in the path)
|
||||
func (t Tree) EntryByPath(path string) (*TreeEntry, error) {
|
||||
func (t *Tree) EntryByPath(path string) (*TreeEntry, error) {
|
||||
cpath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cpath))
|
||||
var entry *C.git_tree_entry
|
||||
|
@ -100,17 +102,18 @@ func (t Tree) EntryByPath(path string) (*TreeEntry, error) {
|
|||
return newTreeEntry(entry), nil
|
||||
}
|
||||
|
||||
func (t Tree) EntryByIndex(index uint64) *TreeEntry {
|
||||
func (t *Tree) EntryByIndex(index uint64) *TreeEntry {
|
||||
entry := C.git_tree_entry_byindex(t.cast_ptr, C.size_t(index))
|
||||
runtime.KeepAlive(t)
|
||||
if entry == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return newTreeEntry(entry)
|
||||
goEntry := newTreeEntry(entry)
|
||||
runtime.KeepAlive(t)
|
||||
return goEntry
|
||||
}
|
||||
|
||||
func (t Tree) EntryCount() uint64 {
|
||||
func (t *Tree) EntryCount() uint64 {
|
||||
num := C.git_tree_entrycount(t.cast_ptr)
|
||||
runtime.KeepAlive(t)
|
||||
return uint64(num)
|
||||
|
@ -119,9 +122,8 @@ func (t Tree) EntryCount() uint64 {
|
|||
type TreeWalkCallback func(string, *TreeEntry) int
|
||||
|
||||
//export CallbackGitTreeWalk
|
||||
func CallbackGitTreeWalk(_root *C.char, _entry unsafe.Pointer, ptr unsafe.Pointer) C.int {
|
||||
func CallbackGitTreeWalk(_root *C.char, entry *C.git_tree_entry, ptr unsafe.Pointer) C.int {
|
||||
root := C.GoString(_root)
|
||||
entry := (*C.git_tree_entry)(_entry)
|
||||
|
||||
if callback, ok := pointerHandles.Get(ptr).(TreeWalkCallback); ok {
|
||||
return C.int(callback(root, newTreeEntry(entry)))
|
||||
|
@ -130,7 +132,7 @@ func CallbackGitTreeWalk(_root *C.char, _entry unsafe.Pointer, ptr unsafe.Pointe
|
|||
}
|
||||
}
|
||||
|
||||
func (t Tree) Walk(callback TreeWalkCallback) error {
|
||||
func (t *Tree) Walk(callback TreeWalkCallback) error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit df4dfaadcf709646ebab2e57e3589952cf1ac809
|
||||
Subproject commit ee3307a183e39d602b25fa94831c6fc09e7c1b61
|
|
@ -2,6 +2,7 @@
|
|||
#include <git2.h>
|
||||
#include <git2/sys/odb_backend.h>
|
||||
#include <git2/sys/refdb_backend.h>
|
||||
#include <git2/sys/cred.h>
|
||||
|
||||
typedef int (*gogit_submodule_cbk)(git_submodule *sm, const char *name, void *payload);
|
||||
|
||||
|
@ -180,4 +181,8 @@ void _go_git_writestream_free(git_writestream *stream)
|
|||
stream->free(stream);
|
||||
}
|
||||
|
||||
git_credtype_t _go_git_cred_credtype(git_cred *cred) {
|
||||
return cred->credtype;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
Loading…
Reference in New Issue