blob: e37a96d53a993cd7dc0f10ca97fbf57ec01e22e4 [file] [log] [blame]
package git
/*
#include <git2.h>
*/
import "C"
import (
"runtime"
"unsafe"
)
type Status int
const (
StatusCurrent Status = C.GIT_STATUS_CURRENT
StatusIndexNew Status = C.GIT_STATUS_INDEX_NEW
StatusIndexModified Status = C.GIT_STATUS_INDEX_MODIFIED
StatusIndexDeleted Status = C.GIT_STATUS_INDEX_DELETED
StatusIndexRenamed Status = C.GIT_STATUS_INDEX_RENAMED
StatusIndexTypeChange Status = C.GIT_STATUS_INDEX_TYPECHANGE
StatusWtNew Status = C.GIT_STATUS_WT_NEW
StatusWtModified Status = C.GIT_STATUS_WT_MODIFIED
StatusWtDeleted Status = C.GIT_STATUS_WT_DELETED
StatusWtTypeChange Status = C.GIT_STATUS_WT_TYPECHANGE
StatusWtRenamed Status = C.GIT_STATUS_WT_RENAMED
StatusIgnored Status = C.GIT_STATUS_IGNORED
StatusConflicted Status = C.GIT_STATUS_CONFLICTED
)
type StatusEntry struct {
Status Status
HeadToIndex DiffDelta
IndexToWorkdir DiffDelta
}
func statusEntryFromC(statusEntry *C.git_status_entry) StatusEntry {
var headToIndex DiffDelta = DiffDelta{}
var indexToWorkdir DiffDelta = DiffDelta{}
// Based on the libgit2 status example, head_to_index can be null in some cases
if statusEntry.head_to_index != nil {
headToIndex = diffDeltaFromC(statusEntry.head_to_index)
}
if statusEntry.index_to_workdir != nil {
indexToWorkdir = diffDeltaFromC(statusEntry.index_to_workdir)
}
return StatusEntry{
Status: Status(statusEntry.status),
HeadToIndex: headToIndex,
IndexToWorkdir: indexToWorkdir,
}
}
type StatusList struct {
ptr *C.git_status_list
r *Repository
}
func newStatusListFromC(ptr *C.git_status_list, r *Repository) *StatusList {
if ptr == nil {
return nil
}
statusList := &StatusList{
ptr: ptr,
r: r,
}
runtime.SetFinalizer(statusList, (*StatusList).Free)
return statusList
}
func (statusList *StatusList) Free() {
if statusList.ptr == nil {
return
}
runtime.SetFinalizer(statusList, nil)
C.git_status_list_free(statusList.ptr)
statusList.ptr = nil
}
func (statusList *StatusList) ByIndex(index int) (StatusEntry, error) {
if statusList.ptr == nil {
return StatusEntry{}, ErrInvalid
}
ptr := C.git_status_byindex(statusList.ptr, C.size_t(index))
entry := statusEntryFromC(ptr)
runtime.KeepAlive(statusList)
return entry, nil
}
func (statusList *StatusList) EntryCount() (int, error) {
if statusList.ptr == nil {
return -1, ErrInvalid
}
ret := int(C.git_status_list_entrycount(statusList.ptr))
runtime.KeepAlive(statusList)
return ret, nil
}
type StatusOpt int
const (
StatusOptIncludeUntracked StatusOpt = C.GIT_STATUS_OPT_INCLUDE_UNTRACKED
StatusOptIncludeIgnored StatusOpt = C.GIT_STATUS_OPT_INCLUDE_IGNORED
StatusOptIncludeUnmodified StatusOpt = C.GIT_STATUS_OPT_INCLUDE_UNMODIFIED
StatusOptExcludeSubmodules StatusOpt = C.GIT_STATUS_OPT_EXCLUDE_SUBMODULES
StatusOptRecurseUntrackedDirs StatusOpt = C.GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS
StatusOptDisablePathspecMatch StatusOpt = C.GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH
StatusOptRecurseIgnoredDirs StatusOpt = C.GIT_STATUS_OPT_RECURSE_IGNORED_DIRS
StatusOptRenamesHeadToIndex StatusOpt = C.GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
StatusOptRenamesIndexToWorkdir StatusOpt = C.GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
StatusOptSortCaseSensitively StatusOpt = C.GIT_STATUS_OPT_SORT_CASE_SENSITIVELY
StatusOptSortCaseInsensitively StatusOpt = C.GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY
StatusOptRenamesFromRewrites StatusOpt = C.GIT_STATUS_OPT_RENAMES_FROM_REWRITES
StatusOptNoRefresh StatusOpt = C.GIT_STATUS_OPT_NO_REFRESH
StatusOptUpdateIndex StatusOpt = C.GIT_STATUS_OPT_UPDATE_INDEX
)
type StatusShow int
const (
StatusShowIndexAndWorkdir StatusShow = C.GIT_STATUS_SHOW_INDEX_AND_WORKDIR
StatusShowIndexOnly StatusShow = C.GIT_STATUS_SHOW_INDEX_ONLY
StatusShowWorkdirOnly StatusShow = C.GIT_STATUS_SHOW_WORKDIR_ONLY
)
type StatusOptions struct {
Show StatusShow
Flags StatusOpt
Pathspec []string
}
func (v *Repository) StatusList(opts *StatusOptions) (*StatusList, error) {
var ptr *C.git_status_list
var copts *C.git_status_options
if opts != nil {
cpathspec := C.git_strarray{}
if opts.Pathspec != nil {
cpathspec.count = C.size_t(len(opts.Pathspec))
cpathspec.strings = makeCStringsFromStrings(opts.Pathspec)
defer freeStrarray(&cpathspec)
}
copts = &C.git_status_options{
version: C.GIT_STATUS_OPTIONS_VERSION,
show: C.git_status_show_t(opts.Show),
flags: C.uint(opts.Flags),
pathspec: cpathspec,
}
} else {
copts = &C.git_status_options{}
ret := C.git_status_init_options(copts, C.GIT_STATUS_OPTIONS_VERSION)
if ret < 0 {
return nil, MakeGitError(ret)
}
}
runtime.LockOSThread()
defer runtime.UnlockOSThread()
ret := C.git_status_list_new(&ptr, v.ptr, copts)
if ret < 0 {
return nil, MakeGitError(ret)
}
return newStatusListFromC(ptr, v), nil
}
func (v *Repository) StatusFile(path string) (Status, error) {
var statusFlags C.uint
cPath := C.CString(path)
defer C.free(unsafe.Pointer(cPath))
runtime.LockOSThread()
defer runtime.UnlockOSThread()
ret := C.git_status_file(&statusFlags, v.ptr, cPath)
runtime.KeepAlive(v)
if ret < 0 {
return 0, MakeGitError(ret)
}
return Status(statusFlags), nil
}