diff options
| -rw-r--r-- | .travis.yml | 6 | ||||
| -rw-r--r-- | branch.go | 4 | ||||
| -rw-r--r-- | checkout.go | 86 | ||||
| -rw-r--r-- | clone.go | 1 | ||||
| -rw-r--r-- | credentials.go | 24 | ||||
| -rw-r--r-- | index.go | 16 | ||||
| -rw-r--r-- | index_test.go | 40 | ||||
| -rw-r--r-- | odb.go | 4 | ||||
| -rw-r--r-- | refdb.go | 5 | ||||
| -rw-r--r-- | remote.go | 29 | ||||
| -rw-r--r-- | walk.go | 4 | ||||
| -rw-r--r-- | wrapper.c | 6 |
12 files changed, 204 insertions, 21 deletions
diff --git a/.travis.yml b/.travis.yml index fb68ca9..d9130bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,3 +13,9 @@ go: matrix: allow_failures: - go: tip + +branches: + only: + - master + - /v\d+/ + - next @@ -73,6 +73,10 @@ func (i *BranchIterator) ForEach(f BranchIteratorFunc) error { } } + if err != nil && IsErrorCode(err, ErrIterOver) { + return nil + } + return err } diff --git a/checkout.go b/checkout.go index a2e312b..f5822c9 100644 --- a/checkout.go +++ b/checkout.go @@ -2,6 +2,8 @@ package git /* #include <git2.h> + +extern void _go_git_populate_checkout_cb(git_checkout_options *opts); */ import "C" import ( @@ -10,9 +12,18 @@ import ( "unsafe" ) +type CheckoutNotifyType uint type CheckoutStrategy uint const ( + CheckoutNotifyNone CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_NONE + CheckoutNotifyConflict CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_CONFLICT + CheckoutNotifyDirty CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_DIRTY + CheckoutNotifyUpdated CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_UPDATED + CheckoutNotifyUntracked CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_UNTRACKED + CheckoutNotifyIgnored CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_IGNORED + CheckoutNotifyAll CheckoutNotifyType = C.GIT_CHECKOUT_NOTIFY_ALL + CheckoutNone CheckoutStrategy = C.GIT_CHECKOUT_NONE // Dry run, no actual updates CheckoutSafe CheckoutStrategy = C.GIT_CHECKOUT_SAFE // Allow safe updates that cannot overwrite uncommitted data CheckoutForce CheckoutStrategy = C.GIT_CHECKOUT_FORCE // Allow all updates to force working directory to look like index @@ -37,15 +48,21 @@ const ( CheckoutUpdateSubmodulesIfChanged CheckoutStrategy = C.GIT_CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED // Recursively checkout submodules if HEAD moved in super repo (NOT IMPLEMENTED) ) +type CheckoutNotifyCallback func(why CheckoutNotifyType, path string, baseline, target, workdir DiffFile) ErrorCode +type CheckoutProgressCallback func(path string, completed, total uint) ErrorCode + type CheckoutOpts struct { - Strategy CheckoutStrategy // Default will be a dry run - DisableFilters bool // Don't apply filters like CRLF conversion - DirMode os.FileMode // Default is 0755 - FileMode os.FileMode // Default is 0644 or 0755 as dictated by blob - FileOpenFlags int // Default is O_CREAT | O_TRUNC | O_WRONLY - TargetDirectory string // Alternative checkout path to workdir - Paths []string - Baseline *Tree + Strategy CheckoutStrategy // Default will be a dry run + DisableFilters bool // Don't apply filters like CRLF conversion + DirMode os.FileMode // Default is 0755 + FileMode os.FileMode // Default is 0644 or 0755 as dictated by blob + FileOpenFlags int // Default is O_CREAT | O_TRUNC | O_WRONLY + NotifyFlags CheckoutNotifyType // Default will be none + NotifyCallback CheckoutNotifyCallback + ProgressCallback CheckoutProgressCallback + TargetDirectory string // Alternative checkout path to workdir + Paths []string + Baseline *Tree } func checkoutOptionsFromC(c *C.git_checkout_options) CheckoutOpts { @@ -55,6 +72,13 @@ func checkoutOptionsFromC(c *C.git_checkout_options) CheckoutOpts { opts.DirMode = os.FileMode(c.dir_mode) opts.FileMode = os.FileMode(c.file_mode) opts.FileOpenFlags = int(c.file_open_flags) + opts.NotifyFlags = CheckoutNotifyType(c.notify_flags) + if c.notify_payload != nil { + opts.NotifyCallback = pointerHandles.Get(c.notify_payload).(*CheckoutOpts).NotifyCallback + } + if c.progress_payload != nil { + opts.ProgressCallback = pointerHandles.Get(c.progress_payload).(*CheckoutOpts).ProgressCallback + } if c.target_directory != nil { opts.TargetDirectory = C.GoString(c.target_directory) } @@ -70,6 +94,38 @@ func (opts *CheckoutOpts) toC() *C.git_checkout_options { return &c } +//export checkoutNotifyCallback +func checkoutNotifyCallback(why C.git_checkout_notify_t, cpath *C.char, cbaseline, ctarget, cworkdir, data unsafe.Pointer) int { + if data == nil { + return 0 + } + path := C.GoString(cpath) + var baseline, target, workdir DiffFile + if cbaseline != nil { + baseline = diffFileFromC((*C.git_diff_file)(cbaseline)) + } + if ctarget != nil { + target = diffFileFromC((*C.git_diff_file)(ctarget)) + } + if cworkdir != nil { + workdir = diffFileFromC((*C.git_diff_file)(cworkdir)) + } + opts := pointerHandles.Get(data).(*CheckoutOpts) + if opts.NotifyCallback == nil { + return 0 + } + return int(opts.NotifyCallback(CheckoutNotifyType(why), path, baseline, target, workdir)) +} + +//export checkoutProgressCallback +func checkoutProgressCallback(path *C.char, completed_steps, total_steps C.size_t, data unsafe.Pointer) int { + opts := pointerHandles.Get(data).(*CheckoutOpts) + if opts.ProgressCallback == nil { + return 0 + } + return int(opts.ProgressCallback(C.GoString(path), uint(completed_steps), uint(total_steps))) +} + // Convert the CheckoutOpts struct to the corresponding // C-struct. Returns a pointer to ptr, or nil if opts is nil, in order // to help with what to pass. @@ -83,6 +139,17 @@ func populateCheckoutOpts(ptr *C.git_checkout_options, opts *CheckoutOpts) *C.gi ptr.disable_filters = cbool(opts.DisableFilters) ptr.dir_mode = C.uint(opts.DirMode.Perm()) ptr.file_mode = C.uint(opts.FileMode.Perm()) + ptr.notify_flags = C.uint(opts.NotifyFlags) + if opts.NotifyCallback != nil || opts.ProgressCallback != nil { + C._go_git_populate_checkout_cb(ptr) + } + payload := pointerHandles.Track(opts) + if opts.NotifyCallback != nil { + ptr.notify_payload = payload + } + if opts.ProgressCallback != nil { + ptr.progress_payload = payload + } if opts.TargetDirectory != "" { ptr.target_directory = C.CString(opts.TargetDirectory) } @@ -106,6 +173,9 @@ func freeCheckoutOpts(ptr *C.git_checkout_options) { if ptr.paths.count > 0 { freeStrarray(&ptr.paths) } + if ptr.notify_payload != nil { + pointerHandles.Untrack(ptr.notify_payload) + } } // Updates files in the index and the working tree to match the content of @@ -41,7 +41,6 @@ func Clone(url string, path string, options *CloneOptions) (*Repository, error) var ptr *C.git_repository ret := C.git_clone(&ptr, curl, cpath, copts) - freeCheckoutOpts(&copts.checkout_opts) if ret < 0 { return nil, MakeGitError(ret) diff --git a/credentials.go b/credentials.go index bb0ec41..4e42b6e 100644 --- a/credentials.go +++ b/credentials.go @@ -44,13 +44,15 @@ func NewCredUserpassPlaintext(username string, password string) (int, Cred) { return int(ret), cred } -func NewCredSshKey(username string, publickey string, privatekey string, passphrase string) (int, Cred) { +// NewCredSshKey creates new ssh credentials reading the public and private keys +// from the file system. +func NewCredSshKey(username string, publicKeyPath string, privateKeyPath string, passphrase string) (int, Cred) { cred := Cred{} cusername := C.CString(username) defer C.free(unsafe.Pointer(cusername)) - cpublickey := C.CString(publickey) + cpublickey := C.CString(publicKeyPath) defer C.free(unsafe.Pointer(cpublickey)) - cprivatekey := C.CString(privatekey) + cprivatekey := C.CString(privateKeyPath) defer C.free(unsafe.Pointer(cprivatekey)) cpassphrase := C.CString(passphrase) defer C.free(unsafe.Pointer(cpassphrase)) @@ -58,6 +60,22 @@ func NewCredSshKey(username string, publickey string, privatekey string, passphr return int(ret), cred } +// NewCredSshKeyFromMemory creates new ssh credentials using the publicKey and privateKey +// arguments as the values for the public and private keys. +func NewCredSshKeyFromMemory(username string, publicKey string, privateKey string, passphrase string) (int, Cred) { + cred := Cred{} + cusername := C.CString(username) + defer C.free(unsafe.Pointer(cusername)) + cpublickey := C.CString(publicKey) + defer C.free(unsafe.Pointer(cpublickey)) + cprivatekey := C.CString(privateKey) + defer C.free(unsafe.Pointer(cprivatekey)) + cpassphrase := C.CString(passphrase) + defer C.free(unsafe.Pointer(cpassphrase)) + ret := C.git_cred_ssh_key_memory_new(&cred.ptr, cusername, cpublickey, cprivatekey, cpassphrase) + return int(ret), cred +} + func NewCredSshKeyFromAgent(username string) (int, Cred) { cred := Cred{} cusername := C.CString(username) @@ -278,6 +278,22 @@ func (v *Index) RemoveByPath(path string) error { return nil } +// RemoveDirectory removes all entries from the index under a given directory. +func (v *Index) RemoveDirectory(dir string, stage int) error { + cstr := C.CString(dir) + defer C.free(unsafe.Pointer(cstr)) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_index_remove_directory(v.ptr, cstr, C.int(stage)) + if ret < 0 { + return MakeGitError(ret) + } + + return nil +} + func (v *Index) WriteTreeTo(repo *Repository) (*Oid, error) { oid := new(Oid) diff --git a/index_test.go b/index_test.go index 600b8b1..f47dace 100644 --- a/index_test.go +++ b/index_test.go @@ -109,6 +109,46 @@ func TestIndexAddAndWriteTreeTo(t *testing.T) { } } +func TestIndexRemoveDirectory(t *testing.T) { + repo := createTestRepo(t) + defer cleanupTestRepo(t, repo) + + odb, err := repo.Odb() + checkFatal(t, err) + + blobID, err := odb.Write([]byte("fou\n"), ObjectBlob) + checkFatal(t, err) + + idx, err := NewIndex() + checkFatal(t, err) + + entryCount := idx.EntryCount() + if entryCount != 0 { + t.Fatal("Index should count 0 entry") + } + + entry := IndexEntry{ + Path: "path/to/LISEZ_MOI", + Id: blobID, + Mode: FilemodeBlob, + } + + err = idx.Add(&entry) + checkFatal(t, err) + + entryCount = idx.EntryCount() + if entryCount != 1 { + t.Fatal("Index should count 1 entry") + } + + err = idx.RemoveDirectory("path", 0) + + entryCount = idx.EntryCount() + if entryCount != 0 { + t.Fatal("Index should count 0 entry") + } +} + func TestIndexAddAllNoCallback(t *testing.T) { t.Parallel() repo := createTestRepo(t) @@ -36,8 +36,8 @@ func NewOdb() (odb *Odb, err error) { return odb, nil } -func NewOdbBackendFromC(ptr *C.git_odb_backend) (backend *OdbBackend) { - backend = &OdbBackend{ptr} +func NewOdbBackendFromC(ptr unsafe.Pointer) (backend *OdbBackend) { + backend = &OdbBackend{(*C.git_odb_backend)(ptr)} return backend } @@ -9,6 +9,7 @@ extern void _go_git_refdb_backend_free(git_refdb_backend *backend); import "C" import ( "runtime" + "unsafe" ) type Refdb struct { @@ -34,8 +35,8 @@ func (v *Repository) NewRefdb() (refdb *Refdb, err error) { return refdb, nil } -func NewRefdbBackendFromC(ptr *C.git_refdb_backend) (backend *RefdbBackend) { - backend = &RefdbBackend{ptr} +func NewRefdbBackendFromC(ptr unsafe.Pointer) (backend *RefdbBackend) { + backend = &RefdbBackend{(*C.git_refdb_backend)(ptr)} return backend } @@ -239,7 +239,7 @@ func completionCallback(completion_type C.git_remote_completion_type, data unsaf func credentialsCallback(_cred **C.git_cred, _url *C.char, _username_from_url *C.char, allowed_types uint, data unsafe.Pointer) int { callbacks, _ := pointerHandles.Get(data).(*RemoteCallbacks) if callbacks.CredentialsCallback == nil { - return 0 + return C.GIT_PASSTHROUGH } url := C.GoString(_url) username_from_url := C.GoString(_username_from_url) @@ -492,6 +492,26 @@ func (o *Remote) PushUrl() string { return C.GoString(C.git_remote_pushurl(o.ptr)) } +func (c *RemoteCollection) Rename(remote, newname string) ([]string, error) { + cproblems := C.git_strarray{} + defer freeStrarray(&cproblems) + cnewname := C.CString(newname) + defer C.free(unsafe.Pointer(cnewname)) + cremote := C.CString(remote) + defer C.free(unsafe.Pointer(cremote)) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_remote_rename(&cproblems, c.repo.ptr, cremote, cnewname) + if ret < 0 { + return []string{}, MakeGitError(ret) + } + + problems := makeStringsFromCStrings(cproblems.strings, int(cproblems.count)) + return problems, nil +} + func (c *RemoteCollection) SetUrl(remote, url string) error { curl := C.CString(url) defer C.free(unsafe.Pointer(curl)) @@ -730,6 +750,13 @@ func (o *Remote) Connect(direction ConnectDirection, callbacks *RemoteCallbacks, return nil } +func (o *Remote) Disconnect() { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + C.git_remote_disconnect(o.ptr) +} + func (o *Remote) Ls(filterRefs ...string) ([]RemoteHead, error) { var refs **C.git_remote_head @@ -173,10 +173,6 @@ func (v *RevWalk) Iterate(fun RevWalkIterator) (err error) { return nil } if err != nil { - if err.(GitError).Code == ErrIterOver { - err = nil - } - return err } @@ -10,6 +10,12 @@ void _go_git_populate_remote_cb(git_clone_options *opts) opts->remote_cb = (git_remote_create_cb)remoteCreateCallback; } +void _go_git_populate_checkout_cb(git_checkout_options *opts) +{ + opts->notify_cb = (git_checkout_notify_cb)checkoutNotifyCallback; + opts->progress_cb = (git_checkout_progress_cb)checkoutProgressCallback; +} + int _go_git_visit_submodule(git_repository *repo, void *fct) { return git_submodule_foreach(repo, (gogit_submodule_cbk)&SubmoduleVisitor, fct); |
