From 92a1f92d912cdb5f68da8c1e5e3a4d1ebfd282db Mon Sep 17 00:00:00 2001 From: joseferminj Date: Thu, 22 Jan 2015 00:44:51 -0500 Subject: Add TargetDirectory field to Checkout options. TargetDirectory field indicates a alternative checkout path to workdir. --- checkout.go | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'checkout.go') diff --git a/checkout.go b/checkout.go index 9c7188e..06d010c 100644 --- a/checkout.go +++ b/checkout.go @@ -7,6 +7,7 @@ import "C" import ( "os" "runtime" + "unsafe" ) type CheckoutStrategy uint @@ -31,11 +32,12 @@ const ( ) 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 + 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 } func (opts *CheckoutOpts) toC() *C.git_checkout_options { @@ -60,17 +62,29 @@ 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()) - + if opts.TargetDirectory != "" { + ptr.target_directory = C.CString(opts.TargetDirectory) + } return ptr } +func freeCheckoutOpts(ptr *C.git_checkout_options) { + if ptr == nil { + return + } + C.free(unsafe.Pointer(ptr.target_directory)) +} + // Updates files in the index and the working tree to match the content of // the commit pointed at by HEAD. opts may be nil. func (v *Repository) CheckoutHead(opts *CheckoutOpts) error { runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_checkout_head(v.ptr, opts.toC()) + cOpts := opts.toC() + defer freeCheckoutOpts(cOpts) + + ret := C.git_checkout_head(v.ptr, cOpts) if ret < 0 { return MakeGitError(ret) } @@ -90,7 +104,10 @@ func (v *Repository) CheckoutIndex(index *Index, opts *CheckoutOpts) error { runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_checkout_index(v.ptr, iptr, opts.toC()) + cOpts := opts.toC() + defer freeCheckoutOpts(cOpts) + + ret := C.git_checkout_index(v.ptr, iptr, cOpts) if ret < 0 { return MakeGitError(ret) } @@ -102,7 +119,10 @@ func (v *Repository) CheckoutTree(tree *Tree, opts *CheckoutOpts) error { runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_checkout_tree(v.ptr, tree.ptr, opts.toC()) + cOpts := opts.toC() + defer freeCheckoutOpts(cOpts) + + ret := C.git_checkout_tree(v.ptr, tree.ptr, cOpts) if ret < 0 { return MakeGitError(ret) } -- cgit v1.2.3 From eec61815fbc963d0f81a95a9be4b061145541095 Mon Sep 17 00:00:00 2001 From: Mark Probst Date: Wed, 4 Mar 2015 11:31:41 -0800 Subject: Fix typos in constants --- checkout.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'checkout.go') diff --git a/checkout.go b/checkout.go index 06d010c..72a1fe3 100644 --- a/checkout.go +++ b/checkout.go @@ -20,10 +20,10 @@ const ( CheckoutAllowConflicts CheckoutStrategy = C.GIT_CHECKOUT_ALLOW_CONFLICTS // Allow checkout to make safe updates even if conflicts are found CheckoutRemoveUntracked CheckoutStrategy = C.GIT_CHECKOUT_REMOVE_UNTRACKED // Remove untracked files not in index (that are not ignored) CheckoutRemoveIgnored CheckoutStrategy = C.GIT_CHECKOUT_REMOVE_IGNORED // Remove ignored files not in index - CheckotUpdateOnly CheckoutStrategy = C.GIT_CHECKOUT_UPDATE_ONLY // Only update existing files, don't create new ones + CheckoutUpdateOnly CheckoutStrategy = C.GIT_CHECKOUT_UPDATE_ONLY // Only update existing files, don't create new ones 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 - CheckooutDisablePathspecMatch CheckoutStrategy = C.GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH // Treat pathspec as simple list of exact match file paths + CheckoutDisablePathspecMatch CheckoutStrategy = C.GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH // Treat pathspec as simple list of exact match file paths CheckoutSkipUnmerged CheckoutStrategy = C.GIT_CHECKOUT_SKIP_UNMERGED // Allow checkout to skip unmerged files (NOT IMPLEMENTED) CheckoutUserOurs CheckoutStrategy = C.GIT_CHECKOUT_USE_OURS // For unmerged files, checkout stage 2 from index (NOT IMPLEMENTED) CheckoutUseTheirs CheckoutStrategy = C.GIT_CHECKOUT_USE_THEIRS // For unmerged files, checkout stage 3 from index (NOT IMPLEMENTED) -- cgit v1.2.3 From c78b4d665e406af7e8cba608f65ac2171d3917b6 Mon Sep 17 00:00:00 2001 From: Mark Probst Date: Wed, 4 Mar 2015 11:38:19 -0800 Subject: Cherrypick --- checkout.go | 13 ++++++++++ cherrypick.go | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ cherrypick_test.go | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ git_test.go | 6 ++++- 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 cherrypick.go create mode 100644 cherrypick_test.go (limited to 'checkout.go') diff --git a/checkout.go b/checkout.go index 72a1fe3..6eb6098 100644 --- a/checkout.go +++ b/checkout.go @@ -40,6 +40,19 @@ type CheckoutOpts struct { TargetDirectory string // Alternative checkout path to workdir } +func checkoutOptionsFromC(c *C.git_checkout_options) CheckoutOpts { + opts := CheckoutOpts{} + opts.Strategy = CheckoutStrategy(c.checkout_strategy) + opts.DisableFilters = c.disable_filters != 0 + opts.DirMode = os.FileMode(c.dir_mode) + opts.FileMode = os.FileMode(c.file_mode) + opts.FileOpenFlags = int(c.file_open_flags) + if c.target_directory != nil { + opts.TargetDirectory = C.GoString(c.target_directory) + } + return opts +} + func (opts *CheckoutOpts) toC() *C.git_checkout_options { if opts == nil { return nil diff --git a/cherrypick.go b/cherrypick.go new file mode 100644 index 0000000..afc1b7e --- /dev/null +++ b/cherrypick.go @@ -0,0 +1,73 @@ +package git + +/* +#include +*/ +import "C" +import ( + "runtime" +) + +type CherrypickOptions struct { + Version uint + Mainline uint + MergeOpts MergeOptions + CheckoutOpts CheckoutOpts +} + +func cherrypickOptionsFromC(c *C.git_cherrypick_options) CherrypickOptions { + opts := CherrypickOptions{ + Version: uint(c.version), + Mainline: uint(c.mainline), + MergeOpts: mergeOptionsFromC(&c.merge_opts), + CheckoutOpts: checkoutOptionsFromC(&c.checkout_opts), + } + return opts +} + +func (opts *CherrypickOptions) toC() *C.git_cherrypick_options { + if opts == nil { + return nil + } + c := C.git_cherrypick_options{} + c.version = C.uint(opts.Version) + c.mainline = C.uint(opts.Mainline) + c.merge_opts = *opts.MergeOpts.toC() + c.checkout_opts = *opts.CheckoutOpts.toC() + return &c +} + +func freeCherrypickOpts(ptr *C.git_cherrypick_options) { + if ptr == nil { + return + } + freeCheckoutOpts(&ptr.checkout_opts) +} + +func DefaultCherrypickOptions() (CherrypickOptions, error) { + c := C.git_cherrypick_options{} + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ecode := C.git_cherrypick_init_options(&c, C.GIT_CHERRYPICK_OPTIONS_VERSION) + if ecode < 0 { + return CherrypickOptions{}, MakeGitError(ecode) + } + defer freeCherrypickOpts(&c) + return cherrypickOptionsFromC(&c), nil +} + +func (v *Repository) Cherrypick(commit *Commit, opts CherrypickOptions) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + cOpts := opts.toC() + defer freeCherrypickOpts(cOpts) + + ecode := C.git_cherrypick(v.ptr, commit.cast_ptr, cOpts) + if ecode < 0 { + return MakeGitError(ecode) + } + return nil +} diff --git a/cherrypick_test.go b/cherrypick_test.go new file mode 100644 index 0000000..c867cf9 --- /dev/null +++ b/cherrypick_test.go @@ -0,0 +1,73 @@ +package git + +import ( + "io/ioutil" + "testing" +) + +func checkout(t *testing.T, repo *Repository, commit *Commit) { + tree, err := commit.Tree() + if err != nil { + t.Fatal(err) + } + + err = repo.CheckoutTree(tree, &CheckoutOpts{Strategy: CheckoutSafe}) + if err != nil { + t.Fatal(err) + } + + err = repo.SetHeadDetached(commit.Id(), commit.Author(), "checkout") + if err != nil { + t.Fatal(err) + } +} + +const content = "Herro, Worrd!" + +func readReadme(t *testing.T, repo *Repository) string { + bytes, err := ioutil.ReadFile(pathInRepo(repo, "README")) + if err != nil { + t.Fatal(err) + } + return string(bytes) +} + +func TestCherrypick(t *testing.T) { + repo := createTestRepo(t) + c1, _ := seedTestRepo(t, repo) + c2, _ := updateReadme(t, repo, content) + + commit1, err := repo.LookupCommit(c1) + if err != nil { + t.Fatal(err) + } + commit2, err := repo.LookupCommit(c2) + if err != nil { + t.Fatal(err) + } + + checkout(t, repo, commit1) + + if readReadme(t, repo) == content { + t.Fatalf("README has wrong content after checking out initial commit") + } + + opts, err := DefaultCherrypickOptions() + if err != nil { + t.Fatal(err) + } + + err = repo.Cherrypick(commit2, opts) + if err != nil { + t.Fatal(err) + } + + if readReadme(t, repo) != content { + t.Fatalf("README has wrong contents after cherry-picking") + } + + state := repo.State() + if state != RepositoryStateCherrypick { + t.Fatal("Incorrect repository state: ", state) + } +} diff --git a/git_test.go b/git_test.go index 56adeed..b9cf0a9 100644 --- a/git_test.go +++ b/git_test.go @@ -57,6 +57,10 @@ func seedTestRepo(t *testing.T, repo *Repository) (*Oid, *Oid) { return commitId, treeId } +func pathInRepo(repo *Repository, name string) string { + return path.Join(path.Dir(path.Dir(repo.Path())), name) +} + func updateReadme(t *testing.T, repo *Repository, content string) (*Oid, *Oid) { loc, err := time.LoadLocation("Europe/Berlin") checkFatal(t, err) @@ -67,7 +71,7 @@ func updateReadme(t *testing.T, repo *Repository, content string) (*Oid, *Oid) { } tmpfile := "README" - err = ioutil.WriteFile(path.Join(path.Dir(path.Dir(repo.Path())), tmpfile), []byte(content), 0644) + err = ioutil.WriteFile(pathInRepo(repo, tmpfile), []byte(content), 0644) checkFatal(t, err) idx, err := repo.Index() -- cgit v1.2.3