aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--_examples/clone/main.go6
-rw-r--r--common.go19
-rw-r--r--config/config.go73
-rw-r--r--config/config_test.go41
-rw-r--r--config/modules.go19
-rw-r--r--config/refspec.go12
-rw-r--r--cshared/README.md79
-rw-r--r--cshared/auth_method_cshared.go192
-rw-r--r--cshared/blame_cshared.go49
-rw-r--r--cshared/commit_cshared.go223
-rw-r--r--cshared/file_cshared.go135
-rw-r--r--cshared/objects.go190
-rw-r--r--cshared/objects_cshared.go109
-rw-r--r--cshared/remote_cshared.go191
-rw-r--r--cshared/repository_cshared.go232
-rw-r--r--cshared/std_cshared.go143
-rw-r--r--cshared/tag_cshared.go188
-rw-r--r--cshared/tree_cshared.go169
-rw-r--r--options.go67
-rw-r--r--plumbing/format/index/encoder.go9
-rw-r--r--plumbing/format/index/encoder_test.go10
-rw-r--r--plumbing/format/index/index.go13
-rw-r--r--plumbing/object/file.go2
-rw-r--r--plumbing/object/file_test.go28
-rw-r--r--plumbing/object/tree.go5
-rw-r--r--plumbing/object/tree_test.go41
-rw-r--r--remote.go9
-rw-r--r--remote_test.go3
-rw-r--r--repository.go121
-rw-r--r--repository_test.go105
-rw-r--r--storage/filesystem/internal/dotgit/dotgit.go13
-rw-r--r--storage/filesystem/internal/dotgit/dotgit_test.go8
-rw-r--r--storage/filesystem/module.go14
-rw-r--r--storage/filesystem/storage.go11
-rw-r--r--storage/filesystem/storage_test.go9
-rw-r--r--storage/memory/storage.go16
-rw-r--r--storage/storer.go26
-rw-r--r--storage/test/storage_suite.go16
-rw-r--r--submodule.go174
-rw-r--r--submodule_test.go164
-rw-r--r--worktree.go159
-rw-r--r--worktree_test.go30
42 files changed, 1092 insertions, 2031 deletions
diff --git a/_examples/clone/main.go b/_examples/clone/main.go
index 7d173a6..bcdb6a9 100644
--- a/_examples/clone/main.go
+++ b/_examples/clone/main.go
@@ -14,11 +14,11 @@ func main() {
directory := os.Args[2]
// Clone the given repository to the given directory
- Info("git clone %s %s", url, directory)
+ Info("git clone %s %s --recursive", url, directory)
r, err := git.PlainClone(directory, false, &git.CloneOptions{
- URL: url,
- Depth: 1,
+ URL: url,
+ RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
})
CheckIfError(err)
diff --git a/common.go b/common.go
index 1a05dc3..f837a26 100644
--- a/common.go
+++ b/common.go
@@ -1,23 +1,8 @@
package git
-import (
- "strings"
+import "strings"
- "srcd.works/go-git.v4/config"
- "srcd.works/go-git.v4/plumbing/storer"
-)
-
-// Storer is a generic storage of objects, references and any information
-// related to a particular repository. The package srcd.works/go-git.v4/storage
-// contains two implementation a filesystem base implementation (such as `.git`)
-// and a memory implementations being ephemeral
-type Storer interface {
- storer.EncodedObjectStorer
- storer.ReferenceStorer
- storer.ShallowStorer
- storer.IndexStorer
- config.ConfigStorer
-}
+const defaultDotGitPath = ".git"
// countLines returns the number of lines in a string à la git, this is
// The newline character is assumed to be '\n'. The empty string
diff --git a/config/config.go b/config/config.go
index 866ae8e..259ebf9 100644
--- a/config/config.go
+++ b/config/config.go
@@ -32,14 +32,19 @@ var (
// Config contains the repository configuration
// ftp://www.kernel.org/pub/software/scm/git/docs/git-config.html#FILES
type Config struct {
- // Core variables
Core struct {
// IsBare if true this repository is assumed to be bare and has no
- // working directory associated with it
+ // working directory associated with it.
IsBare bool
+ // Worktree is the path to the root of the working tree.
+ Worktree string
}
- // Remote list of repository remotes
+ // Remotes list of repository remotes, the key of the map is the name
+ // of the remote, should equal to RemoteConfig.Name.
Remotes map[string]*RemoteConfig
+ // Submodules list of repository submodules, the key of the map is the name
+ // of the submodule, should equal to Submodule.Name.
+ Submodules map[string]*Submodule
// contains the raw information of a config file, the main goal is preserve
// the parsed information from the original format, to avoid missing
@@ -47,15 +52,16 @@ type Config struct {
raw *format.Config
}
-// NewConfig returns a new empty Config
+// NewConfig returns a new empty Config.
func NewConfig() *Config {
return &Config{
- Remotes: make(map[string]*RemoteConfig, 0),
- raw: format.New(),
+ Remotes: make(map[string]*RemoteConfig, 0),
+ Submodules: make(map[string]*Submodule, 0),
+ raw: format.New(),
}
}
-// Validate validates the fields and sets the default values
+// Validate validates the fields and sets the default values.
func (c *Config) Validate() error {
for name, r := range c.Remotes {
if r.Name != name {
@@ -71,14 +77,16 @@ func (c *Config) Validate() error {
}
const (
- remoteSection = "remote"
- coreSection = "core"
- fetchKey = "fetch"
- urlKey = "url"
- bareKey = "bare"
+ remoteSection = "remote"
+ submoduleSection = "submodule"
+ coreSection = "core"
+ fetchKey = "fetch"
+ urlKey = "url"
+ bareKey = "bare"
+ worktreeKey = "worktree"
)
-// Unmarshal parses a git-config file and stores it
+// Unmarshal parses a git-config file and stores it.
func (c *Config) Unmarshal(b []byte) error {
r := bytes.NewBuffer(b)
d := format.NewDecoder(r)
@@ -89,6 +97,7 @@ func (c *Config) Unmarshal(b []byte) error {
}
c.unmarshalCore()
+ c.unmarshalSubmodules()
return c.unmarshalRemotes()
}
@@ -97,6 +106,8 @@ func (c *Config) unmarshalCore() {
if s.Options.Get(bareKey) == "true" {
c.Core.IsBare = true
}
+
+ c.Core.Worktree = s.Options.Get(worktreeKey)
}
func (c *Config) unmarshalRemotes() error {
@@ -113,10 +124,21 @@ func (c *Config) unmarshalRemotes() error {
return nil
}
-// Marshal returns Config encoded as a git-config file
+func (c *Config) unmarshalSubmodules() {
+ s := c.raw.Section(submoduleSection)
+ for _, sub := range s.Subsections {
+ m := &Submodule{}
+ m.unmarshal(sub)
+
+ c.Submodules[m.Name] = m
+ }
+}
+
+// Marshal returns Config encoded as a git-config file.
func (c *Config) Marshal() ([]byte, error) {
c.marshalCore()
c.marshalRemotes()
+ c.marshalSubmodules()
buf := bytes.NewBuffer(nil)
if err := format.NewEncoder(buf).Encode(c.raw); err != nil {
@@ -129,6 +151,10 @@ func (c *Config) Marshal() ([]byte, error) {
func (c *Config) marshalCore() {
s := c.raw.Section(coreSection)
s.SetOption(bareKey, fmt.Sprintf("%t", c.Core.IsBare))
+
+ if c.Core.Worktree != "" {
+ s.SetOption(worktreeKey, c.Core.Worktree)
+ }
}
func (c *Config) marshalRemotes() {
@@ -142,7 +168,22 @@ func (c *Config) marshalRemotes() {
}
}
-// RemoteConfig contains the configuration for a given remote repository
+func (c *Config) marshalSubmodules() {
+ s := c.raw.Section(submoduleSection)
+ s.Subsections = make(format.Subsections, len(c.Submodules))
+
+ var i int
+ for _, r := range c.Submodules {
+ section := r.marshal()
+ // the submodule section at config is a subset of the .gitmodule file
+ // we should remove the non-valid options for the config file.
+ section.RemoveOption(pathKey)
+ s.Subsections[i] = section
+ i++
+ }
+}
+
+// RemoteConfig contains the configuration for a given remote repository.
type RemoteConfig struct {
// Name of the remote
Name string
@@ -156,7 +197,7 @@ type RemoteConfig struct {
raw *format.Subsection
}
-// Validate validates the fields and sets the default values
+// Validate validates the fields and sets the default values.
func (c *RemoteConfig) Validate() error {
if c.Name == "" {
return ErrRemoteConfigEmptyName
diff --git a/config/config_test.go b/config/config_test.go
index 2bcefe4..cfab36d 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -9,9 +9,14 @@ var _ = Suite(&ConfigSuite{})
func (s *ConfigSuite) TestUnmarshall(c *C) {
input := []byte(`[core]
bare = true
+ worktree = foo
[remote "origin"]
url = git@github.com:mcuadros/go-git.git
fetch = +refs/heads/*:refs/remotes/origin/*
+[submodule "qux"]
+ path = qux
+ url = https://github.com/foo/qux.git
+ branch = bar
[branch "master"]
remote = origin
merge = refs/heads/master
@@ -22,15 +27,51 @@ func (s *ConfigSuite) TestUnmarshall(c *C) {
c.Assert(err, IsNil)
c.Assert(cfg.Core.IsBare, Equals, true)
+ c.Assert(cfg.Core.Worktree, Equals, "foo")
c.Assert(cfg.Remotes, HasLen, 1)
c.Assert(cfg.Remotes["origin"].Name, Equals, "origin")
c.Assert(cfg.Remotes["origin"].URL, Equals, "git@github.com:mcuadros/go-git.git")
c.Assert(cfg.Remotes["origin"].Fetch, DeepEquals, []RefSpec{"+refs/heads/*:refs/remotes/origin/*"})
+ c.Assert(cfg.Submodules, HasLen, 1)
+ c.Assert(cfg.Submodules["qux"].Name, Equals, "qux")
+ c.Assert(cfg.Submodules["qux"].URL, Equals, "https://github.com/foo/qux.git")
+ c.Assert(cfg.Submodules["qux"].Branch, Equals, "bar")
+
+}
+
+func (s *ConfigSuite) TestMarshall(c *C) {
+ output := []byte(`[core]
+ bare = true
+ worktree = bar
+[remote "origin"]
+ url = git@github.com:mcuadros/go-git.git
+[submodule "qux"]
+ url = https://github.com/foo/qux.git
+`)
+
+ cfg := NewConfig()
+ cfg.Core.IsBare = true
+ cfg.Core.Worktree = "bar"
+ cfg.Remotes["origin"] = &RemoteConfig{
+ Name: "origin",
+ URL: "git@github.com:mcuadros/go-git.git",
+ }
+
+ cfg.Submodules["qux"] = &Submodule{
+ Name: "qux",
+ URL: "https://github.com/foo/qux.git",
+ }
+
+ b, err := cfg.Marshal()
+ c.Assert(err, IsNil)
+
+ c.Assert(string(b), Equals, string(output))
}
func (s *ConfigSuite) TestUnmarshallMarshall(c *C) {
input := []byte(`[core]
bare = true
+ worktree = foo
custom = ignored
[remote "origin"]
url = git@github.com:mcuadros/go-git.git
diff --git a/config/modules.go b/config/modules.go
index 4d98b16..3d01117 100644
--- a/config/modules.go
+++ b/config/modules.go
@@ -15,7 +15,7 @@ var (
// Modules defines the submodules properties, represents a .gitmodules file
// https://www.kernel.org/pub/software/scm/git/docs/gitmodules.html
type Modules struct {
- // Submodules is a map of submodules being the key the name of the submodule
+ // Submodules is a map of submodules being the key the name of the submodule.
Submodules map[string]*Submodule
raw *format.Config
@@ -30,12 +30,11 @@ func NewModules() *Modules {
}
const (
- submoduleSection = "submodule"
- pathKey = "path"
- branchKey = "branch"
+ pathKey = "path"
+ branchKey = "branch"
)
-// Unmarshal parses a git-config file and stores it
+// Unmarshal parses a git-config file and stores it.
func (m *Modules) Unmarshal(b []byte) error {
r := bytes.NewBuffer(b)
d := format.NewDecoder(r)
@@ -56,7 +55,7 @@ func (m *Modules) Unmarshal(b []byte) error {
return nil
}
-// Marshal returns Modules encoded as a git-config file
+// Marshal returns Modules encoded as a git-config file.
func (m *Modules) Marshal() ([]byte, error) {
s := m.raw.Section(submoduleSection)
s.Subsections = make(format.Subsections, len(m.Submodules))
@@ -75,12 +74,12 @@ func (m *Modules) Marshal() ([]byte, error) {
return buf.Bytes(), nil
}
-// Submodule defines a submodule
+// Submodule defines a submodule.
type Submodule struct {
// Name module name
Name string
// Path defines the path, relative to the top-level directory of the Git
- // working tree,
+ // working tree.
Path string
// URL defines a URL from which the submodule repository can be cloned.
URL string
@@ -89,11 +88,11 @@ type Submodule struct {
Branch string
// raw representation of the subsection, filled by marshal or unmarshal are
- // called
+ // called.
raw *format.Subsection
}
-// Validate validates the fields and sets the default values
+// Validate validates the fields and sets the default values.
func (m *Submodule) Validate() error {
if m.Path == "" {
return ErrModuleEmptyPath
diff --git a/config/refspec.go b/config/refspec.go
index dd68edc..9441df8 100644
--- a/config/refspec.go
+++ b/config/refspec.go
@@ -49,7 +49,7 @@ func (s RefSpec) Validate() error {
return ErrRefSpecMalformedWildcard
}
-// IsForceUpdate returns if update is allowed in non fast-forward merges
+// IsForceUpdate returns if update is allowed in non fast-forward merges.
func (s RefSpec) IsForceUpdate() bool {
if s[0] == refSpecForce[0] {
return true
@@ -67,7 +67,7 @@ func (s RefSpec) IsDelete() bool {
return false
}
-// Src return the src side
+// Src return the src side.
func (s RefSpec) Src() string {
spec := string(s)
start := strings.Index(spec, refSpecForce) + 1
@@ -76,7 +76,7 @@ func (s RefSpec) Src() string {
return spec[start:end]
}
-// Match match the given plumbing.ReferenceName against the source
+// Match match the given plumbing.ReferenceName against the source.
func (s RefSpec) Match(n plumbing.ReferenceName) bool {
if !s.IsWildcard() {
return s.matchExact(n)
@@ -85,7 +85,7 @@ func (s RefSpec) Match(n plumbing.ReferenceName) bool {
return s.matchGlob(n)
}
-// IsWildcard returns true if the RefSpec contains a wildcard
+// IsWildcard returns true if the RefSpec contains a wildcard.
func (s RefSpec) IsWildcard() bool {
return strings.Index(string(s), refSpecWildcard) != -1
}
@@ -110,7 +110,7 @@ func (s RefSpec) matchGlob(n plumbing.ReferenceName) bool {
strings.HasSuffix(name, suffix)
}
-// Dst returns the destination for the given remote reference
+// Dst returns the destination for the given remote reference.
func (s RefSpec) Dst(n plumbing.ReferenceName) plumbing.ReferenceName {
spec := string(s)
start := strings.Index(spec, refSpecSeparator) + 1
@@ -133,7 +133,7 @@ func (s RefSpec) String() string {
return string(s)
}
-// MatchAny returns true if any of the RefSpec match with the given ReferenceName
+// MatchAny returns true if any of the RefSpec match with the given ReferenceName.
func MatchAny(l []RefSpec, n plumbing.ReferenceName) bool {
for _, r := range l {
if r.Match(n) {
diff --git a/cshared/README.md b/cshared/README.md
deleted file mode 100644
index ea32b4b..0000000
--- a/cshared/README.md
+++ /dev/null
@@ -1,79 +0,0 @@
-cshared
-=======
-
-Building
---------
-go 1.6+
-```
-go build -o libgogit.so -buildmode=c-shared github.com/src-d/go-git/cshared
-```
-Two files must appear: libgogit.h and libgogit.so. The second must be
-a shared library, not an ar archive (may happen when something goes wrong).
-Check the exported symbols with `nm -g`.
-
-How it works
-------------
-
-Nearly every public Go function is mirrored in the corresponding *_cshared.go
-file. struct fields are also mirrored with getters and setters. The functions
-are marked with `//export ...` "magic" cgo comment so that they appear
-in defined symbols of a shared library built with `-buildmode=c-shared`.
-
-Go pointers may not be passed out of cgo functions, so we maintain the
-two-way registry of all active Go objects mapped to `Handle`-s (`uint64`).
-Every time we need to return a reference to Go object outside, we call
-`RegisterObject(interface{})` which returns a new `Handle` or reuses
-an existing one if the object has already been registered. Then we
-return the obtained `Handle`. When we need to receive a Go object reference
-in cgo function parameters, we accept `uint64` and retrieve the `interface{}`
-with `GetObject(Handle)` which can be casted to the underlying type with a
-type assertion. When the object is no longer needed, we invoke
-`UnregisterObject(Handle)`.
-
-Although `interface{]` is just two `uintptr`-s inside, it is not a hashable
-type and we cannot use it a as key in our backward registry mapping.
-We are using the data `uintptr` as the key there. Since several distinct
-objects may exist with the same data pointer (e.g. struct and first field
-of the struct), the value of that mapping is a slice of `Handle`-s.
-
-All the mentioned service functions are goroutine- and threadsafe.
-
-`std_cshared.go` contains the cgo wrappers for standard library objects.
-
-Debugging
----------
-`c_dump_object()` prints the current state of the two-way object registry
-to stdout. `c_set_trace()` activates echoing of `RegisterObject()` and
-`UnregisterObject()` invocations.
-
-Caveats
--------
-Normally, we pass over a pointer to object as `interface{}` into `RegisterObject()`
-so that it can be mutated later. It requires the corresponding
-pointer-to-type type assertion in cgo functions. If you mess with this,
-the cgo function will, of course, panic.
-
-A cgo function is allowed to take Go's `string` parameters. `string`'s
-data must point to some memory and cgo does not copy the incoming foreign
-memory into Go memory automatically. What's worse, `string`-s are immutable
-and when you copy it, the copy points to the same memory. This means that
-if you pass in a `string` which was constructed using `malloc()`, for example,
-and later `free()` it, all Go strings created from the function parameter
-will point to the invalid memory. Actually, this allowance violates the
-cgo pointer passing rules stated just several blocks of texts
-below the example of string parameters - this is crazy, but we have to live
-with this, as usual in Go world. So, *all incoming `string`-s must be immediately
-safely copied with `CopyString()` once they are used*.
-
-Returning strings and byte slices is also funny: you have to use `C.CString` -> `*C.char`
-and additionally return the length as another result tuple member if needed.
-`C.CString` copies the memory pointed by `string` to a `malloc()`-ed region
-and it is the responsibility of the other side to `free()` it or it will leak
-otherwise.
-
-Another tricky part is in `c_std_map_get_str_str` and similar places
-where you need to return `*C.char` from an unaddressable array accessed under
-a pseudonym type through reflection. The only way I've found working
-is using `reflect.Copy` to byte slice (copy), then `CBytes` (copy) and
-finally another (copy) on the receiving side because the latter must be
-`free()`-d. \ No newline at end of file
diff --git a/cshared/auth_method_cshared.go b/cshared/auth_method_cshared.go
deleted file mode 100644
index 0f0e3a1..0000000
--- a/cshared/auth_method_cshared.go
+++ /dev/null
@@ -1,192 +0,0 @@
-// +build ignore
-package main
-
-import (
- "C"
- "strings"
-
- "golang.org/x/crypto/ssh"
- "srcd.works/go-git.v4/plumbing/transport/http"
- gssh "srcd.works/go-git.v4/plumbing/transport/ssh"
-)
-
-//export c_NewBasicAuth
-func c_NewBasicAuth(username, password string) uint64 {
- auth := http.NewBasicAuth(CopyString(username), CopyString(password))
- return uint64(RegisterObject(auth))
-}
-
-//export c_ParseRawPrivateKey
-func c_ParseRawPrivateKey(pemBytes []byte) (uint64, int, *C.char) {
- pkey, err := ssh.ParseRawPrivateKey(pemBytes)
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- // pointer is received - no need for &
- return uint64(RegisterObject(pkey)), ErrorCodeSuccess, nil
-}
-
-//export c_ParsePrivateKey
-func c_ParsePrivateKey(pemBytes []byte) (uint64, int, *C.char) {
- signer, err := ssh.ParsePrivateKey(pemBytes)
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(&signer)), ErrorCodeSuccess, nil
-}
-
-//export c_NewPublicKey
-func c_NewPublicKey(key uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(key))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- key_obj := obj.(ssh.PublicKey)
- pkey, err := ssh.NewPublicKey(key_obj)
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(&pkey)), ErrorCodeSuccess, nil
-}
-
-//export c_NewSignerFromKey
-func c_NewSignerFromKey(key uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(key))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- signer, err := ssh.NewSignerFromKey(obj)
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(&signer)), ErrorCodeSuccess, nil
-}
-
-//export c_MarshalAuthorizedKey
-func c_MarshalAuthorizedKey(key uint64) (*C.char, int) {
- obj, ok := GetObject(Handle(key))
- if !ok {
- return nil, 0
- }
- obj_key := obj.(ssh.PublicKey)
- mak := ssh.MarshalAuthorizedKey(obj_key)
- return C.CString(string(mak)), len(mak)
-}
-
-//export c_ParsePublicKey
-func c_ParsePublicKey(in []byte) (uint64, int, *C.char) {
- pkey, err := ssh.ParsePublicKey(in)
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(&pkey)), ErrorCodeSuccess, nil
-}
-
-//export c_ParseAuthorizedKey
-func c_ParseAuthorizedKey(in []byte) (uint64, *C.char, *C.char, *C.char, int, int, *C.char) {
- pkey, comment, options, rest, err := ssh.ParseAuthorizedKey(in)
- if err != nil {
- return IH, nil, nil, nil, 0, ErrorCodeInternal,
- C.CString(err.Error())
- }
- pkey_handle := RegisterObject(&pkey)
- mopt := strings.Join(options, "\xff")
- return uint64(pkey_handle), C.CString(comment), C.CString(mopt),
- C.CString(string(rest)), len(rest), ErrorCodeSuccess, nil
-}
-
-//export c_ssh_Password_New
-func c_ssh_Password_New(user, pass string) uint64 {
- obj := gssh.Password{User: CopyString(user), Pass: CopyString(pass)}
- return uint64(RegisterObject(&obj))
-}
-
-//export c_ssh_Password_get_User
-func c_ssh_Password_get_User(p uint64) *C.char {
- obj, ok := GetObject(Handle(p))
- if !ok {
- return nil
- }
- return C.CString(obj.(*gssh.Password).User)
-}
-
-//export c_ssh_Password_set_User
-func c_ssh_Password_set_User(p uint64, v string) {
- obj, ok := GetObject(Handle(p))
- if !ok {
- return
- }
- obj.(*gssh.Password).User = CopyString(v)
-}
-
-//export c_ssh_Password_get_Pass
-func c_ssh_Password_get_Pass(p uint64) *C.char {
- obj, ok := GetObject(Handle(p))
- if !ok {
- return nil
- }
- return C.CString(obj.(*gssh.Password).Pass)
-}
-
-//export c_ssh_Password_set_Pass
-func c_ssh_Password_set_Pass(p uint64, v string) {
- obj, ok := GetObject(Handle(p))
- if !ok {
- return
- }
- obj.(*gssh.Password).Pass = CopyString(v)
-}
-
-//c_ssh_PublicKeys_New
-func c_ssh_PublicKeys_New(user string, signer uint64) uint64 {
- obj, ok := GetObject(Handle(signer))
- if !ok {
- return IH
- }
- pk := gssh.PublicKeys{User: CopyString(user), Signer: obj.(ssh.Signer)}
- return uint64(RegisterObject(&pk))
-}
-
-//export c_ssh_PublicKeys_get_User
-func c_ssh_PublicKeys_get_User(p uint64) *C.char {
- obj, ok := GetObject(Handle(p))
- if !ok {
- return nil
- }
- return C.CString(obj.(*gssh.PublicKeys).User)
-}
-
-//export c_ssh_PublicKeys_set_User
-func c_ssh_PublicKeys_set_User(p uint64, v string) {
- obj, ok := GetObject(Handle(p))
- if !ok {
- return
- }
- obj.(*gssh.PublicKeys).User = CopyString(v)
-}
-
-//export c_ssh_PublicKeys_get_Signer
-func c_ssh_PublicKeys_get_Signer(p uint64) uint64 {
- obj, ok := GetObject(Handle(p))
- if !ok {
- return IH
- }
- handle, ok := GetHandle(&obj.(*gssh.PublicKeys).Signer)
- if !ok {
- return IH
- }
- return uint64(handle)
-}
-
-//export c_ssh_PublicKeys_set_Signer
-func c_ssh_PublicKeys_set_Signer(p uint64, v uint64) {
- obj, ok := GetObject(Handle(p))
- if !ok {
- return
- }
- signer, ok := GetObject(Handle(v))
- if !ok {
- return
- }
- obj.(*gssh.PublicKeys).Signer = *signer.(*ssh.Signer)
-}
diff --git a/cshared/blame_cshared.go b/cshared/blame_cshared.go
deleted file mode 100644
index 8dfee31..0000000
--- a/cshared/blame_cshared.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// +build ignore
-package main
-
-import (
- "C"
-
- "srcd.works/go-git.v4"
-)
-
-//export c_Blame_get_Path
-func c_Blame_get_Path(b uint64) *C.char {
- obj, ok := GetObject(Handle(b))
- if !ok {
- return nil
- }
- blame := obj.(*git.BlameResult)
- return C.CString(blame.Path)
-}
-
-//export c_Blame_get_Rev
-func c_Blame_get_Rev(b uint64) *C.char {
- obj, ok := GetObject(Handle(b))
- if !ok {
- return nil
- }
- blame := obj.(*git.BlameResult)
- return CBytes(blame.Rev[:])
-}
-
-//export c_Blame_get_Lines_len
-func c_Blame_get_Lines_len(b uint64) int {
- obj, ok := GetObject(Handle(b))
- if !ok {
- return 0
- }
- blame := obj.(*git.BlameResult)
- return len(blame.Lines)
-}
-
-//export c_Blame_get_Lines_item
-func c_Blame_get_Lines_item(b uint64, i int) {
- obj, ok := GetObject(Handle(b))
- if !ok {
- return
- }
- blame := obj.(*git.BlameResult)
- line := blame.Lines[i]
- _ = line
-}
diff --git a/cshared/commit_cshared.go b/cshared/commit_cshared.go
deleted file mode 100644
index 78f9e4a..0000000
--- a/cshared/commit_cshared.go
+++ /dev/null
@@ -1,223 +0,0 @@
-// +build ignore
-package main
-
-import (
- "C"
- "io"
- "reflect"
- "unsafe"
-
- "srcd.works/go-git.v4"
- "srcd.works/go-git.v4/plumbing"
- "srcd.works/go-git.v4/plumbing/object"
- "srcd.works/go-git.v4/plumbing/storer"
-)
-
-//export c_Commit_get_Hash
-func c_Commit_get_Hash(c uint64) *C.char {
- obj, ok := GetObject(Handle(c))
- if !ok {
- return nil
- }
- commit := obj.(*object.Commit)
- return CBytes(commit.Hash[:])
-}
-
-//export c_Commit_get_Author
-func c_Commit_get_Author(c uint64) uint64 {
- obj, ok := GetObject(Handle(c))
- if !ok {
- return IH
- }
- commit := obj.(*object.Commit)
- author := &commit.Author
- author_handle := RegisterObject(author)
- return uint64(author_handle)
-}
-
-//export c_Commit_get_Committer
-func c_Commit_get_Committer(c uint64) uint64 {
- obj, ok := GetObject(Handle(c))
- if !ok {
- return IH
- }
- commit := obj.(*object.Commit)
- committer := &commit.Committer
- committer_handle := RegisterObject(committer)
- return uint64(committer_handle)
-}
-
-//export c_Commit_get_Message
-func c_Commit_get_Message(c uint64) *C.char {
- obj, ok := GetObject(Handle(c))
- if !ok {
- return nil
- }
- commit := obj.(*object.Commit)
- return C.CString(commit.Message)
-}
-
-//export c_Commit_Tree
-func c_Commit_Tree(c uint64) uint64 {
- obj, ok := GetObject(Handle(c))
- if !ok {
- return IH
- }
- commit := obj.(*object.Commit)
- tree, err := commit.Tree()
- if err != nil {
- return IH
- }
-
- tree_handle := RegisterObject(tree)
- return uint64(tree_handle)
-}
-
-//export c_Commit_Parents
-func c_Commit_Parents(c uint64) uint64 {
- obj, ok := GetObject(Handle(c))
- if !ok {
- return IH
- }
- commit := obj.(*object.Commit)
- parents := commit.Parents()
- parents_handle := RegisterObject(parents)
- return uint64(parents_handle)
-}
-
-//export c_Commit_NumParents
-func c_Commit_NumParents(c uint64) int {
- obj, ok := GetObject(Handle(c))
- if !ok {
- return -1
- }
- commit := obj.(*object.Commit)
- return commit.NumParents()
-}
-
-//export c_Commit_File
-func c_Commit_File(c uint64, path string) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(c))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- commit := obj.(*object.Commit)
- file, err := commit.File(CopyString(path))
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- file_handle := RegisterObject(file)
- return uint64(file_handle), ErrorCodeSuccess, nil
-}
-
-//export c_Commit_ID
-func c_Commit_ID(c uint64) *C.char {
- return c_Commit_get_Hash(c)
-}
-
-//export c_Commit_Type
-func c_Commit_Type(c uint64) int8 {
- obj, ok := GetObject(Handle(c))
- if !ok {
- return -1
- }
- commit := obj.(*object.Commit)
- return int8(commit.Type())
-}
-
-//export c_Commit_Decode
-func c_Commit_Decode(o uint64) (uint64, int, *C.char) {
- commit := object.Commit{}
- obj, ok := GetObject(Handle(o))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- cobj := obj.(*plumbing.EncodedObject)
- err := commit.Decode(*cobj)
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(&commit)), ErrorCodeSuccess, nil
-}
-
-//export c_Commit_String
-func c_Commit_String(c uint64) *C.char {
- obj, ok := GetObject(Handle(c))
- if !ok {
- return nil
- }
- commit := obj.(*object.Commit)
- return C.CString(commit.String())
-}
-
-//export c_Commit_References
-func c_Commit_References(c uint64, path string) (*C.char, int, int, *C.char) {
- obj, ok := GetObject(Handle(c))
- if !ok {
- return nil, 0, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- commit := obj.(*object.Commit)
- refs, err := git.References(commit, CopyString(path))
- if err != nil {
- return nil, 0, ErrorCodeInternal, C.CString(err.Error())
- }
- handles := make([]uint64, len(refs))
- for i, c := range refs {
- handles[i] = uint64(RegisterObject(c))
- }
- size := 8 * len(handles)
- dest := C.malloc(C.size_t(size))
- header := (*reflect.SliceHeader)(unsafe.Pointer(&handles))
- header.Len *= 8
- copy((*[1 << 30]byte)(dest)[:], *(*[]byte)(unsafe.Pointer(header)))
- return (*C.char)(dest), size / 8, ErrorCodeSuccess, nil
-}
-
-//export c_Commit_Blame
-func c_Commit_Blame(c uint64, path string) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(c))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- commit := obj.(*object.Commit)
- blame, err := git.Blame(commit, CopyString(path))
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(blame)), ErrorCodeSuccess, nil
-}
-
-//export c_NewCommitIter
-func c_NewCommitIter(r uint64, iter uint64) uint64 {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH
- }
- s := obj.(storer.EncodedObjectStorer)
- obj, ok = GetObject(Handle(iter))
- if !ok {
- return IH
- }
- obj_iter := obj.(storer.EncodedObjectIter)
- commit_iter := object.NewCommitIter(s, obj_iter)
- handle := RegisterObject(commit_iter)
- return uint64(handle)
-}
-
-//export c_CommitIter_Next
-func c_CommitIter_Next(iter uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(iter))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- commitIter := obj.(*object.CommitIter)
- commit, err := commitIter.Next()
- if err != nil {
- if err == io.EOF {
- return IH, ErrorCodeSuccess, nil
- }
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- handle := RegisterObject(commit)
- return uint64(handle), ErrorCodeSuccess, nil
-}
diff --git a/cshared/file_cshared.go b/cshared/file_cshared.go
deleted file mode 100644
index bace1f5..0000000
--- a/cshared/file_cshared.go
+++ /dev/null
@@ -1,135 +0,0 @@
-package main
-
-import (
- "C"
- "io"
- "io/ioutil"
-
- "srcd.works/go-git.v4/plumbing"
- "srcd.works/go-git.v4/plumbing/object"
- "srcd.works/go-git.v4/plumbing/storer"
-)
-
-//export c_File_get_Name
-func c_File_get_Name(f uint64) *C.char {
- obj, ok := GetObject(Handle(f))
- if !ok {
- return nil
- }
- file := obj.(*object.File)
- return C.CString(file.Name)
-}
-
-//export c_File_get_Mode
-func c_File_get_Mode(f uint64) uint32 {
- obj, ok := GetObject(Handle(f))
- if !ok {
- return 0
- }
- file := obj.(*object.File)
- return uint32(file.Mode)
-}
-
-//export c_File_get_Hash
-func c_File_get_Hash(b uint64) *C.char {
- obj, ok := GetObject(Handle(b))
- if !ok {
- return nil
- }
- file := obj.(*object.File)
- return CBytes(file.Hash[:])
-}
-
-//export c_File_Size
-func c_File_Size(b uint64) int64 {
- obj, ok := GetObject(Handle(b))
- if !ok {
- return -1
- }
- file := obj.(*object.File)
- return file.Size
-}
-
-//export c_File_Decode
-func c_File_Decode(o uint64) uint64 {
- obj, ok := GetObject(Handle(o))
- if !ok {
- return IH
- }
- cobj := obj.(*plumbing.EncodedObject)
- file := object.File{}
- file.Decode(*cobj)
- return uint64(RegisterObject(&file))
-}
-
-//export c_File_Read
-func c_File_Read(b uint64) (int, *C.char) {
- obj, ok := GetObject(Handle(b))
- if !ok {
- return ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- file := obj.(*object.File)
- reader, err := file.Reader()
- if err != nil {
- return ErrorCodeInternal, C.CString(err.Error())
- }
- data, err := ioutil.ReadAll(reader)
- reader.Close()
- if err != nil {
- return ErrorCodeInternal, C.CString(err.Error())
- }
- return len(data), CBytes(data)
-}
-
-//export c_File_Type
-func c_File_Type(c uint64) int8 {
- obj, ok := GetObject(Handle(c))
- if !ok {
- return -1
- }
- file := obj.(*object.File)
- return int8(file.Type())
-}
-
-//export c_NewFileIter
-func c_NewFileIter(r uint64, t uint64) uint64 {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH
- }
- storer := obj.(storer.EncodedObjectStorer)
- obj, ok = GetObject(Handle(t))
- if !ok {
- return IH
- }
- tree := obj.(*object.Tree)
- iter := object.NewFileIter(storer, tree)
- return uint64(RegisterObject(iter))
-}
-
-//export c_FileIter_Next
-func c_FileIter_Next(i uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(i))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- iter := obj.(*object.FileIter)
- file, err := iter.Next()
- if err != nil {
- if err == io.EOF {
- return IH, ErrorCodeSuccess, nil
- }
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(file)), ErrorCodeSuccess, nil
-}
-
-//export c_FileIter_Close
-func c_FileIter_Close(i uint64) {
- obj, ok := GetObject(Handle(i))
- if !ok {
- return
- }
- iter := obj.(*object.FileIter)
- iter.Close()
-}
diff --git a/cshared/objects.go b/cshared/objects.go
deleted file mode 100644
index d83f224..0000000
--- a/cshared/objects.go
+++ /dev/null
@@ -1,190 +0,0 @@
-// +build ignore
-package main
-
-import (
- "C"
- "fmt"
- "math"
- "reflect"
- "sync"
-)
-
-type Handle uint64
-
-const (
- ErrorCodeSuccess = iota
- ErrorCodeNotFound = -iota
- ErrorCodeInternal = -iota
-)
-
-const MessageNotFound string = "object not found"
-const InvalidHandle Handle = 0
-const IH uint64 = uint64(InvalidHandle)
-
-var counter Handle = InvalidHandle
-var opMutex sync.Mutex
-var registryHandle2Obj map[Handle]interface{} = map[Handle]interface{}{}
-var registryObj2Handle map[uintptr][]Handle = map[uintptr][]Handle{}
-var trace bool = false
-
-func getNewHandle() Handle {
- counter++
- if counter == math.MaxUint64 {
- panic("Handle cache is exhausted")
- }
- return counter
-}
-
-func RegisterObject(obj interface{}) Handle {
- data_ptr := reflect.ValueOf(&obj).Elem().InterfaceData()[1]
- if trace {
- fmt.Printf("RegisterObject 0x%x\t%v\n", data_ptr, obj)
- }
- opMutex.Lock()
- defer opMutex.Unlock()
- handles, ok := registryObj2Handle[data_ptr]
- if ok {
- for _, h := range handles {
- other, ok := registryHandle2Obj[h]
- if !ok {
- panic("Inconsistent internal object mapping state (1)")
- }
- if other == obj {
- if trace {
- fmt.Printf("RegisterObject 0x%x reused %d\n", data_ptr, h)
- }
- return h
- }
- }
- }
- handle := getNewHandle()
- registryHandle2Obj[handle] = obj
- registryObj2Handle[data_ptr] = append(registryObj2Handle[data_ptr], handle)
- if trace {
- c_dump_objects()
- }
- return handle
-}
-
-func UnregisterObject(handle Handle) int {
- if trace {
- fmt.Printf("UnregisterObject %d\n", handle)
- }
- if handle == InvalidHandle {
- return ErrorCodeNotFound
- }
- opMutex.Lock()
- defer opMutex.Unlock()
- obj, ok := registryHandle2Obj[handle]
- if !ok {
- return ErrorCodeNotFound
- }
- delete(registryHandle2Obj, handle)
- data_ptr := reflect.ValueOf(&obj).Elem().InterfaceData()[1]
- other_handles, ok := registryObj2Handle[data_ptr]
- if !ok {
- panic(fmt.Sprintf("Inconsistent internal object mapping state (2): %d",
- handle))
- }
- hi := -1
- for i, h := range other_handles {
- if h == handle {
- hi = i
- break
- }
- }
- if hi < 0 {
- panic(fmt.Sprintf("Inconsistent internal object mapping state (3): %d",
- handle))
- }
- if len(other_handles) == 1 {
- delete(registryObj2Handle, data_ptr)
- } else {
- registryObj2Handle[data_ptr] = append(other_handles[:hi], other_handles[hi+1:]...)
- }
- if trace {
- c_dump_objects()
- }
- return ErrorCodeSuccess
-}
-
-func GetObject(handle Handle) (interface{}, bool) {
- if handle == InvalidHandle {
- return nil, false
- }
- opMutex.Lock()
- defer opMutex.Unlock()
- a, b := registryHandle2Obj[handle]
- return a, b
-}
-
-func GetHandle(obj interface{}) (Handle, bool) {
- data_ptr := reflect.ValueOf(&obj).Elem().InterfaceData()[1]
- opMutex.Lock()
- defer opMutex.Unlock()
- handles, ok := registryObj2Handle[data_ptr]
- if !ok {
- return InvalidHandle, false
- }
- for _, h := range handles {
- candidate := registryHandle2Obj[h]
- if candidate == obj {
- return h, true
- }
- }
- return InvalidHandle, false
-}
-
-func CopyString(str string) string {
- buf := make([]byte, len(str))
- copy(buf, []byte(str))
- return string(buf)
-}
-
-// https://github.com/golang/go/issues/14838
-func CBytes(bytes []byte) *C.char {
- ptr := C.malloc(C.size_t(len(bytes)))
- copy((*[1 << 30]byte)(ptr)[:], bytes)
- return (*C.char)(ptr)
-}
-
-func SafeIsNil(v reflect.Value) bool {
- defer func() { recover() }()
- return v.IsNil()
-}
-
-//export c_dispose
-func c_dispose(handle uint64) {
- UnregisterObject(Handle(handle))
-}
-
-//export c_objects_size
-func c_objects_size() int {
- return len(registryHandle2Obj)
-}
-
-//export c_dump_objects
-func c_dump_objects() {
- fmt.Printf("handles (%d):\n", len(registryHandle2Obj))
- for h, obj := range registryHandle2Obj {
- fmt.Printf("0x%x\t0x%x %v\n", h,
- reflect.ValueOf(&obj).Elem().InterfaceData()[1], obj)
- }
- fmt.Println()
- phs := 0
- for _, h := range registryObj2Handle {
- phs += len(h)
- }
- fmt.Printf("pointers (%d):\n", phs)
- for ptr, h := range registryObj2Handle {
- fmt.Printf("0x%x\t%v\n", ptr, h)
- }
-}
-
-//export c_set_trace
-func c_set_trace(val bool) {
- trace = val
-}
-
-// dummy main() is needed by the linker
-func main() {}
diff --git a/cshared/objects_cshared.go b/cshared/objects_cshared.go
deleted file mode 100644
index 49ddeb7..0000000
--- a/cshared/objects_cshared.go
+++ /dev/null
@@ -1,109 +0,0 @@
-// +build ignore
-package main
-
-import (
- "C"
- "io/ioutil"
- "time"
-
- "srcd.works/go-git.v4/plumbing"
- "srcd.works/go-git.v4/plumbing/object"
-)
-
-//export c_Signature_Name
-func c_Signature_Name(s uint64) *C.char {
- obj, ok := GetObject(Handle(s))
- if !ok {
- return nil
- }
- sign := obj.(*object.Signature)
- return C.CString(sign.Name)
-}
-
-//export c_Signature_Email
-func c_Signature_Email(s uint64) *C.char {
- obj, ok := GetObject(Handle(s))
- if !ok {
- return nil
- }
- sign := obj.(*object.Signature)
- return C.CString(sign.Email)
-}
-
-//export c_Signature_When
-func c_Signature_When(s uint64) *C.char {
- obj, ok := GetObject(Handle(s))
- if !ok {
- return nil
- }
- sign := obj.(*object.Signature)
- return C.CString(sign.When.Format(time.RFC3339))
-}
-
-//export c_Signature_Decode
-func c_Signature_Decode(b []byte) uint64 {
- sign := object.Signature{}
- sign.Decode(b)
- return uint64(RegisterObject(&sign))
-}
-
-//export c_Blob_get_Hash
-func c_Blob_get_Hash(b uint64) *C.char {
- obj, ok := GetObject(Handle(b))
- if !ok {
- return nil
- }
- blob := obj.(*object.Blob)
- return CBytes(blob.Hash[:])
-}
-
-//export c_Blob_Size
-func c_Blob_Size(b uint64) int64 {
- obj, ok := GetObject(Handle(b))
- if !ok {
- return -1
- }
- blob := obj.(*object.Blob)
- return blob.Size
-}
-
-//export c_Blob_Decode
-func c_Blob_Decode(o uint64) uint64 {
- obj, ok := GetObject(Handle(o))
- if !ok {
- return IH
- }
- cobj := obj.(*plumbing.EncodedObject)
- blob := object.Blob{}
- blob.Decode(*cobj)
- return uint64(RegisterObject(&blob))
-}
-
-//export c_Blob_Read
-func c_Blob_Read(b uint64) (int, *C.char) {
- obj, ok := GetObject(Handle(b))
- if !ok {
- return ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- blob := obj.(*object.Blob)
- reader, err := blob.Reader()
- if err != nil {
- return ErrorCodeInternal, C.CString(err.Error())
- }
- data, err := ioutil.ReadAll(reader)
- reader.Close()
- if err != nil {
- return ErrorCodeInternal, C.CString(err.Error())
- }
- return len(data), CBytes(data)
-}
-
-//export c_Blob_Type
-func c_Blob_Type(c uint64) int8 {
- obj, ok := GetObject(Handle(c))
- if !ok {
- return -1
- }
- blob := obj.(*object.Blob)
- return int8(blob.Type())
-}
diff --git a/cshared/remote_cshared.go b/cshared/remote_cshared.go
deleted file mode 100644
index e7da87c..0000000
--- a/cshared/remote_cshared.go
+++ /dev/null
@@ -1,191 +0,0 @@
-// +build ignore
-package main
-
-import "C"
-
-/*
-
-//export c_Remote_get_Endpoint
-func c_Remote_get_Endpoint(r uint64) *C.char {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return nil
- }
- remote := obj.(*git.Remote)
- return C.CString(string(remote.Endpoint))
-}
-
-//export c_Remote_set_Endpoint
-func c_Remote_set_Endpoint(r uint64, value string) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return
- }
- remote := obj.(*git.Remote)
- remote.Endpoint = common.Endpoint(CopyString(value))
-}
-
-//export c_Remote_get_Auth
-func c_Remote_get_Auth(r uint64) uint64 {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH
- }
- remote := obj.(*git.Remote)
- return uint64(RegisterObject(&remote.Auth))
-}
-
-//export c_Remote_set_Auth
-func c_Remote_set_Auth(r uint64, value uint64) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return
- }
- remote := obj.(*git.Remote)
- obj, ok = GetObject(Handle(value))
- if !ok {
- return
- }
- remote.Auth = *obj.(*common.AuthMethod)
-}
-
-//export c_NewRemote
-func c_NewRemote(url string) (uint64, int, *C.char) {
- remote, err := git.NewRemote(CopyString(url))
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(remote)), ErrorCodeSuccess, nil
-}
-
-//export c_NewAuthenticatedRemote
-func c_NewAuthenticatedRemote(url string, auth uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(auth))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- auth_method := *obj.(*common.AuthMethod)
- remote, err := git.NewAuthenticatedRemote(CopyString(url), auth_method)
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(remote)), ErrorCodeSuccess, nil
-}
-
-//export c_Remote_Connect
-func c_Remote_Connect(r uint64) (int, *C.char) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return ErrorCodeNotFound, nil
- }
- remote := obj.(*git.Remote)
- err := remote.Connect()
- if err != nil {
- return ErrorCodeInternal, C.CString(err.Error())
- }
- return ErrorCodeSuccess, nil
-}
-
-//export c_Remote_Info
-func c_Remote_Info(r uint64) uint64 {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH
- }
- remote := obj.(*git.Remote)
- return uint64(RegisterObject(remote.Info()))
-}
-
-//export c_Remote_Capabilities
-func c_Remote_Capabilities(r uint64) uint64 {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH
- }
- remote := obj.(*git.Remote)
- return uint64(RegisterObject(remote.Capabilities()))
-}
-
-//export c_Remote_DefaultBranch
-func c_Remote_DefaultBranch(r uint64) *C.char {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return nil
- }
- remote := obj.(*git.Remote)
- return C.CString(remote.DefaultBranch())
-}
-
-//export c_Remote_Head
-func c_Remote_Head(r uint64) (*C.char, int, *C.char) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return nil, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- remote := obj.(*git.Remote)
- hash, err := remote.Head()
- if err != nil {
- return nil, ErrorCodeInternal, C.CString(err.Error())
- }
- return CBytes(hash[:]), ErrorCodeSuccess, nil
-}
-
-//export c_Remote_Fetch
-func c_Remote_Fetch(r uint64, req uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- remote := obj.(*git.Remote)
- obj, ok = GetObject(Handle(req))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- request := obj.(*common.UploadPackRequest)
- reader, err := remote.Fetch(request)
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(reader)), ErrorCodeSuccess, nil
-}
-
-//export c_Remote_FetchDefaultBranch
-func c_Remote_FetchDefaultBranch(r uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- remote := obj.(*git.Remote)
- reader, err := remote.FetchDefaultBranch()
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(reader)), ErrorCodeSuccess, nil
-}
-
-//export c_Remote_Ref
-func c_Remote_Ref(r uint64, refName string) (*C.char, int, *C.char) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return nil, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- remote := obj.(*git.Remote)
- hash, err := remote.Ref(CopyString(refName))
- if err != nil {
- return nil, ErrorCodeInternal, C.CString(err.Error())
- }
- return CBytes(hash[:]), ErrorCodeSuccess, nil
-}
-
-//export c_Remote_Refs
-func c_Remote_Refs(r uint64) uint64 {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH
- }
- remote := obj.(*git.Remote)
- refs := remote.Refs()
- return uint64(RegisterObject(refs))
-}
-
-*/
diff --git a/cshared/repository_cshared.go b/cshared/repository_cshared.go
deleted file mode 100644
index 76755bf..0000000
--- a/cshared/repository_cshared.go
+++ /dev/null
@@ -1,232 +0,0 @@
-// +build ignore
-package main
-
-import "C"
-
-/*
-
-//export c_Repository
-func c_Repository() uint64 {
- repo := &git.Repository{}
- repo_handle := RegisterObject(repo)
- return uint64(repo_handle)
-}
-
-//export c_NewRepository
-func c_NewRepository(url string, auth uint64) (uint64, int, *C.char) {
- var repo *git.Repository
- var err error
- url = CopyString(url)
- if auth != IH {
- real_auth, ok := GetObject(Handle(auth))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- repo, err = git.NewRepository(url, real_auth.(common.AuthMethod))
- } else {
- repo, err = git.NewRepository(url, nil)
- }
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- repo_handle := RegisterObject(repo)
- return uint64(repo_handle), ErrorCodeSuccess, nil
-}
-
-//export c_NewPlainRepository
-func c_NewPlainRepository() uint64 {
- return uint64(RegisterObject(git.NewPlainRepository()))
-}
-
-//export c_Repository_get_Remotes
-func c_Repository_get_Remotes(r uint64) uint64 {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH
- }
- repo := obj.(*git.Repository)
- return uint64(RegisterObject(&repo.Remotes))
-}
-
-//export c_Repository_set_Remotes
-func c_Repository_set_Remotes(r uint64, val uint64) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return
- }
- repo := obj.(*git.Repository)
- obj, ok = GetObject(Handle(val))
- if !ok {
- return
- }
- repo.Remotes = *obj.(*map[string]*git.Remote)
-}
-
-//export c_Repository_get_Storage
-func c_Repository_get_Storage(r uint64) uint64 {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH
- }
- repo := obj.(*git.Repository)
- return uint64(RegisterObject(&repo.Storage))
-}
-
-//export c_Repository_set_Storage
-func c_Repository_set_Storage(r uint64, val uint64) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return
- }
- repo := obj.(*git.Repository)
- obj, ok = GetObject(Handle(val))
- if !ok {
- return
- }
- repo.Storage = *obj.(*plumbing.ObjectStorage)
-}
-
-//export c_Repository_Pull
-func c_Repository_Pull(r uint64, remoteName, branch string) (int, *C.char) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- repo := obj.(*git.Repository)
- err := repo.Pull(remoteName, CopyString(branch))
- if err == nil {
- return ErrorCodeSuccess, nil
- }
- return ErrorCodeInternal, C.CString(err.Error())
-}
-
-//export c_Repository_PullDefault
-func c_Repository_PullDefault(r uint64) (int, *C.char) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- repo := obj.(*git.Repository)
- err := repo.PullDefault()
- if err == nil {
- return ErrorCodeSuccess, nil
- }
- return ErrorCodeInternal, C.CString(err.Error())
-}
-
-//export c_Repository_Commit
-func c_Repository_Commit(r uint64, h []byte) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- repo := obj.(*git.Repository)
- var hash plumbing.Hash
- copy(hash[:], h)
- commit, err := repo.Commit(hash)
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- commit_handle := RegisterObject(commit)
- return uint64(commit_handle), ErrorCodeSuccess, nil
-}
-
-//export c_Repository_Commits
-func c_Repository_Commits(r uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- repo := obj.(*git.Repository)
- iter, err := repo.Commits()
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- iter_handle := RegisterObject(iter)
- return uint64(iter_handle), ErrorCodeSuccess, nil
-}
-
-//export c_Repository_Tree
-func c_Repository_Tree(r uint64, h []byte) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- repo := obj.(*git.Repository)
- var hash plumbing.Hash
- copy(hash[:], h)
- tree, err := repo.Tree(hash)
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- tree_handle := RegisterObject(tree)
- return uint64(tree_handle), ErrorCodeSuccess, nil
-}
-
-//export c_Repository_Blob
-func c_Repository_Blob(r uint64, h []byte) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- repo := obj.(*git.Repository)
- var hash plumbing.Hash
- copy(hash[:], h)
- blob, err := repo.Blob(hash)
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- blob_handle := RegisterObject(blob)
- return uint64(blob_handle), ErrorCodeSuccess, nil
-}
-
-//export c_Repository_Tag
-func c_Repository_Tag(r uint64, h []byte) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- repo := obj.(*git.Repository)
- var hash plumbing.Hash
- copy(hash[:], h)
- tag, err := repo.Tag(hash)
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- tag_handle := RegisterObject(tag)
- return uint64(tag_handle), ErrorCodeSuccess, nil
-}
-
-//export c_Repository_Tags
-func c_Repository_Tags(r uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- repo := obj.(*git.Repository)
- iter, err := repo.Tags()
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- iter_handle := RegisterObject(iter)
- return uint64(iter_handle), ErrorCodeSuccess, nil
-}
-
-//export c_Repository_Object
-func c_Repository_Object(r uint64, h []byte) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- repo := obj.(*git.Repository)
- var hash plumbing.Hash
- copy(hash[:], h)
- robj, err := repo.Object(hash)
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- robj_handle := RegisterObject(robj)
- return uint64(robj_handle), ErrorCodeSuccess, nil
-}
-
-*/
diff --git a/cshared/std_cshared.go b/cshared/std_cshared.go
deleted file mode 100644
index 90514b8..0000000
--- a/cshared/std_cshared.go
+++ /dev/null
@@ -1,143 +0,0 @@
-// +build ignore
-package main
-
-import (
- "C"
- "reflect"
- "strings"
-)
-
-//export c_std_map_get_str_str
-func c_std_map_get_str_str(m uint64, key string) *C.char {
- obj, ok := GetObject(Handle(m))
- if !ok {
- return nil
- }
- mapval := reflect.ValueOf(obj)
- if mapval.Kind() == reflect.Ptr {
- mapval = mapval.Elem()
- }
- if mapval.Kind() != reflect.Map {
- return nil
- }
- val := mapval.MapIndex(reflect.ValueOf(key))
- if !val.IsValid() || SafeIsNil(val) {
- return nil
- }
- if (val.Kind() == reflect.Slice || val.Kind() == reflect.Array) &&
- val.Type().Elem().Kind() == reflect.Uint8 {
- arr := make([]byte, val.Len(), val.Len())
- reflect.Copy(reflect.ValueOf(arr), val)
- return CBytes(arr)
- }
- return C.CString(val.String())
-}
-
-//export c_std_map_get_str_obj
-func c_std_map_get_str_obj(m uint64, key string) uint64 {
- obj, ok := GetObject(Handle(m))
- if !ok {
- return IH
- }
- mapval := reflect.ValueOf(obj)
- if mapval.Kind() == reflect.Ptr {
- mapval = mapval.Elem()
- }
- if mapval.Kind() != reflect.Map {
- return IH
- }
- val := mapval.MapIndex(reflect.ValueOf(key))
- if !val.IsValid() || SafeIsNil(val) {
- return IH
- }
- val_handle := RegisterObject(val.Interface())
- return uint64(val_handle)
-}
-
-//export c_std_map_get_obj_obj
-func c_std_map_get_obj_obj(m uint64, key uint64) uint64 {
- obj, ok := GetObject(Handle(m))
- if !ok {
- return IH
- }
- mapval := reflect.ValueOf(obj)
- if mapval.Kind() == reflect.Ptr {
- mapval = mapval.Elem()
- }
- if mapval.Kind() != reflect.Map {
- return IH
- }
- obj, ok = GetObject(Handle(key))
- if !ok {
- return IH
- }
- val := mapval.MapIndex(reflect.ValueOf(obj))
- if !val.IsValid() || SafeIsNil(val) {
- return IH
- }
- val_handle := RegisterObject(val.Interface())
- return uint64(val_handle)
-}
-
-//export c_std_map_keys_str
-func c_std_map_keys_str(m uint64) *C.char {
- obj, ok := GetObject(Handle(m))
- if !ok {
- return nil
- }
- mapval := reflect.ValueOf(obj)
- if mapval.Kind() == reflect.Ptr {
- mapval = mapval.Elem()
- }
- if mapval.Kind() != reflect.Map {
- return nil
- }
- keys := mapval.MapKeys()
- keys_str := make([]string, 0, len(keys))
- for _, k := range keys {
- keys_str = append(keys_str, k.String())
- }
- return C.CString(strings.Join(keys_str, "\xff"))
-}
-
-//export c_std_map_len
-func c_std_map_len(m uint64) int {
- obj, ok := GetObject(Handle(m))
- if !ok {
- return -1
- }
- mapval := reflect.ValueOf(obj)
- if mapval.Kind() == reflect.Ptr {
- mapval = mapval.Elem()
- }
- if mapval.Kind() != reflect.Map {
- return -1
- }
- return mapval.Len()
-}
-
-//export c_std_map_set_str
-func c_std_map_set_str(m uint64, key string, val uint64) {
- obj, ok := GetObject(Handle(m))
- if !ok {
- return
- }
- mapval := reflect.ValueOf(obj)
- if mapval.Kind() == reflect.Ptr {
- mapval = mapval.Elem()
- } else {
- return
- }
- if mapval.Kind() != reflect.Map {
- return
- }
- if val == IH {
- mapval.SetMapIndex(reflect.ValueOf(key), reflect.Value{})
- } else {
- obj, ok := GetObject(Handle(val))
- if !ok {
- return
- }
- mapval.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(obj))
- }
-}
diff --git a/cshared/tag_cshared.go b/cshared/tag_cshared.go
deleted file mode 100644
index b13bcf5..0000000
--- a/cshared/tag_cshared.go
+++ /dev/null
@@ -1,188 +0,0 @@
-// +build ignore
-package main
-
-import (
- "C"
- "io"
-
- "srcd.works/go-git.v4/plumbing"
- "srcd.works/go-git.v4/plumbing/object"
- "srcd.works/go-git.v4/plumbing/storer"
-)
-
-func c_Tag_get_Hash(t uint64) *C.char {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return nil
- }
- tag := obj.(*object.Tag)
- return CBytes(tag.Hash[:])
-}
-
-func c_Tag_get_Name(t uint64) *C.char {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return nil
- }
- tag := obj.(*object.Tag)
- return C.CString(tag.Name)
-}
-
-func c_Tag_get_Tagger(t uint64) uint64 {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return IH
- }
- tag := obj.(*object.Tag)
- return uint64(RegisterObject(&tag.Tagger))
-}
-
-func c_Tag_get_Message(t uint64) *C.char {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return nil
- }
- tag := obj.(*object.Tag)
- return C.CString(tag.Message)
-}
-
-func c_Tag_get_TargetType(t uint64) int8 {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return -1
- }
- tag := obj.(*object.Tag)
- return int8(tag.TargetType)
-}
-
-func c_Tag_get_Target(t uint64) *C.char {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return nil
- }
- tag := obj.(*object.Tag)
- return CBytes(tag.Target[:])
-}
-
-//export c_Tag_Type
-func c_Tag_Type(t uint64) int8 {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return -1
- }
- tag := obj.(*object.Tag)
- return int8(tag.Type())
-}
-
-//export c_Tag_Decode
-func c_Tag_Decode(o uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(o))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- cobj := obj.(*plumbing.EncodedObject)
- tag := object.Tag{}
- err := tag.Decode(*cobj)
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(&tag)), ErrorCodeSuccess, nil
-}
-
-//export c_Tag_Commit
-func c_Tag_Commit(t uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- tag := obj.(*object.Tag)
- commit, err := tag.Commit()
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(commit)), ErrorCodeSuccess, nil
-}
-
-//export c_Tag_Tree
-func c_Tag_Tree(t uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- tag := obj.(*object.Tag)
- tree, err := tag.Tree()
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(tree)), ErrorCodeSuccess, nil
-}
-
-//export c_Tag_Blob
-func c_Tag_Blob(t uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- tag := obj.(*object.Tag)
- blob, err := tag.Blob()
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(blob)), ErrorCodeSuccess, nil
-}
-
-//export c_Tag_Object
-func c_Tag_Object(t uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- tag := obj.(*object.Tag)
- object, err := tag.Object()
- if err != nil {
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(&object)), ErrorCodeSuccess, nil
-}
-
-//export c_Tag_String
-func c_Tag_String(t uint64) *C.char {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return nil
- }
- tag := obj.(*object.Tag)
- return C.CString(tag.String())
-}
-
-//export c_NewTagIter
-func c_NewTagIter(r uint64, i uint64) uint64 {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH
- }
- s := obj.(storer.EncodedObjectStorer)
- obj, ok = GetObject(Handle(i))
- if !ok {
- return IH
- }
- iter := obj.(*storer.EncodedObjectIter)
- return uint64(RegisterObject(object.NewTagIter(s, *iter)))
-}
-
-//export c_TagIter_Next
-func c_TagIter_Next(i uint64) (uint64, int, *C.char) {
- obj, ok := GetObject(Handle(i))
- if !ok {
- return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
- }
- tagiter := obj.(*object.TagIter)
- tag, err := tagiter.Next()
- if err != nil {
- if err == io.EOF {
- return IH, ErrorCodeSuccess, nil
- }
- return IH, ErrorCodeInternal, C.CString(err.Error())
- }
- return uint64(RegisterObject(tag)), ErrorCodeSuccess, nil
-}
diff --git a/cshared/tree_cshared.go b/cshared/tree_cshared.go
deleted file mode 100644
index c47ecfb..0000000
--- a/cshared/tree_cshared.go
+++ /dev/null
@@ -1,169 +0,0 @@
-// Created by cgo - DO NOT EDIT
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:2
-package main
-
-/*
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:5
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:4
-import (
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:7
- "srcd.works/go-git.v4"
- "srcd.works/go-git.v4/plumbing"
-)
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:13
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:12
-func c_Tree_get_Entries_len(t uint64) int {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return 0
- }
- tree := obj.(*object.Tree)
- return len(tree.Entries)
-}
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:23
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:22
-func c_Tree_get_Entries_item(t uint64, index int) (*_Ctype_char, uint32, *_Ctype_char) {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return nil, 0, nil
- }
- tree := obj.(*object.Tree)
- item := tree.Entries[index]
- return _Cfunc_CString(item.Name), uint32(item.Mode), CBytes(item.Hash[:])
-}
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:34
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:33
-func c_Tree_get_Hash(t uint64) *_Ctype_char {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return nil
- }
- tree := obj.(*object.Tree)
- return CBytes(tree.Hash[:])
-}
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:44
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:43
-func c_Tree_File(t uint64, path string) (uint64, int, *_Ctype_char) {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return IH, ErrorCodeNotFound, _Cfunc_CString(MessageNotFound)
- }
- tree := obj.(*object.Tree)
- file, err := tree.File(CopyString(path))
- if err != nil {
- return IH, ErrorCodeInternal, _Cfunc_CString(err.Error())
- }
- return uint64(RegisterObject(file)), ErrorCodeSuccess, nil
-}
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:58
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:57
-func c_Tree_Type(t uint64) int8 {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return -1
- }
- tree := obj.(*object.Tree)
- return int8(tree.Type())
-}
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:68
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:67
-func c_Tree_Files(t uint64) uint64 {
- obj, ok := GetObject(Handle(t))
- if !ok {
- return IH
- }
- tree := obj.(*object.Tree)
- iter := tree.Files()
- return uint64(RegisterObject(iter))
-}
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:79
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:78
-func c_Tree_Decode(o uint64) (uint64, int, *_Ctype_char) {
- obj, ok := GetObject(Handle(o))
- if !ok {
- return IH, ErrorCodeNotFound, _Cfunc_CString(MessageNotFound)
- }
- cobj := obj.(*plumbing.EncodedObject)
- tree := object.Tree{}
- err := tree.Decode(*cobj)
- if err != nil {
- return IH, ErrorCodeInternal, _Cfunc_CString(err.Error())
- }
- return uint64(RegisterObject(&tree)), ErrorCodeSuccess, nil
-}
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:94
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:93
-func c_NewTreeWalker(r uint64, t uint64) uint64 {
- obj, ok := GetObject(Handle(r))
- if !ok {
- return IH
- }
- repo := obj.(*git.Repository)
- obj, ok = GetObject(Handle(t))
- if !ok {
- return IH
- }
- tree := obj.(*object.Tree)
- walker := object.NewTreeIter(repo, tree)
- return uint64(RegisterObject(walker))
-}
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:110
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:109
-func c_TreeWalker_Next(tw uint64) (*_Ctype_char, *_Ctype_char, uint32, *_Ctype_char, int, *_Ctype_char) {
- obj, ok := GetObject(Handle(tw))
- if !ok {
- return nil, nil, 0, nil, ErrorCodeNotFound, _Cfunc_CString(MessageNotFound)
- }
- walker := obj.(*object.TreeIter)
- name, entry, err := walker.Next()
- if err != nil {
- return nil, nil, 0, nil, ErrorCodeInternal, _Cfunc_CString(err.Error())
- }
- return _Cfunc_CString(name), _Cfunc_CString(entry.Name), uint32(entry.Mode),
- CBytes(entry.Hash[:]), ErrorCodeSuccess, nil
-}
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:125
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:124
-func c_TreeWalker_Tree(tw uint64) uint64 {
- obj, ok := GetObject(Handle(tw))
- if !ok {
- return IH
- }
- walker := obj.(*object.TreeIter)
- return uint64(RegisterObject(walker.Tree()))
-}
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:135
-
-//line /home/mcuadros/workspace/go/src/srcd.works/go-git.v4/cshared/tree_cshared.go:134
-func c_TreeWalker_Close(tw uint64) {
- obj, ok := GetObject(Handle(tw))
- if !ok {
- return
- }
- walker := obj.(*object.TreeIter)
- walker.Close()
-}
-*/
diff --git a/options.go b/options.go
index 120c472..d018356 100644
--- a/options.go
+++ b/options.go
@@ -9,36 +9,49 @@ import (
"srcd.works/go-git.v4/plumbing/transport"
)
+// SubmoduleRescursivity defines how depth will affect any submodule recursive
+// operation.
+type SubmoduleRescursivity uint
+
const (
- // DefaultRemoteName name of the default Remote, just like git command
+ // DefaultRemoteName name of the default Remote, just like git command.
DefaultRemoteName = "origin"
+
+ // NoRecurseSubmodules disables the recursion for a submodule operation.
+ NoRecurseSubmodules SubmoduleRescursivity = 0
+ // DefaultSubmoduleRecursionDepth allow recursion in a submodule operation.
+ DefaultSubmoduleRecursionDepth SubmoduleRescursivity = 10
)
var (
ErrMissingURL = errors.New("URL field is required")
)
-// CloneOptions describes how a clone should be performed
+// CloneOptions describes how a clone should be performed.
type CloneOptions struct {
- // The (possibly remote) repository URL to clone from
+ // The (possibly remote) repository URL to clone from.
URL string
- // Auth credentials, if required, to use with the remote repository
+ // Auth credentials, if required, to use with the remote repository.
Auth transport.AuthMethod
- // Name of the remote to be added, by default `origin`
+ // Name of the remote to be added, by default `origin`.
RemoteName string
- // Remote branch to clone
+ // Remote branch to clone.
ReferenceName plumbing.ReferenceName
- // Fetch only ReferenceName if true
+ // Fetch only ReferenceName if true.
SingleBranch bool
- // Limit fetching to the specified number of commits
+ // Limit fetching to the specified number of commits.
Depth int
+ // RecurseSubmodules after the clone is created, initialize all submodules
+ // within, using their default settings. This option is ignored if the
+ // cloned repository does not have a worktree.
+ RecurseSubmodules SubmoduleRescursivity
// Progress is where the human readable information sent by the server is
// stored, if nil nothing is stored and the capability (if supported)
- // no-progress, is sent to the server to avoid send this information
+ // no-progress, is sent to the server to avoid send this information.
Progress sideband.Progress
}
-// Validate validates the fields and sets the default values
+// Validate validates the fields and sets the default values.
func (o *CloneOptions) Validate() error {
if o.URL == "" {
return ErrMissingURL
@@ -55,7 +68,7 @@ func (o *CloneOptions) Validate() error {
return nil
}
-// PullOptions describes how a pull should be performed
+// PullOptions describes how a pull should be performed.
type PullOptions struct {
// Name of the remote to be pulled. If empty, uses the default.
RemoteName string
@@ -65,11 +78,14 @@ type PullOptions struct {
SingleBranch bool
// Limit fetching to the specified number of commits.
Depth int
- // Auth credentials, if required, to use with the remote repository
+ // Auth credentials, if required, to use with the remote repository.
Auth transport.AuthMethod
+ // RecurseSubmodules controls if new commits of all populated submodules
+ // should be fetched too.
+ RecurseSubmodules SubmoduleRescursivity
// Progress is where the human readable information sent by the server is
// stored, if nil nothing is stored and the capability (if supported)
- // no-progress, is sent to the server to avoid send this information
+ // no-progress, is sent to the server to avoid send this information.
Progress sideband.Progress
}
@@ -94,15 +110,15 @@ type FetchOptions struct {
// Depth limit fetching to the specified number of commits from the tip of
// each remote branch history.
Depth int
- // Auth credentials, if required, to use with the remote repository
+ // Auth credentials, if required, to use with the remote repository.
Auth transport.AuthMethod
// Progress is where the human readable information sent by the server is
// stored, if nil nothing is stored and the capability (if supported)
- // no-progress, is sent to the server to avoid send this information
+ // no-progress, is sent to the server to avoid send this information.
Progress sideband.Progress
}
-// Validate validates the fields and sets the default values
+// Validate validates the fields and sets the default values.
func (o *FetchOptions) Validate() error {
if o.RemoteName == "" {
o.RemoteName = DefaultRemoteName
@@ -117,18 +133,18 @@ func (o *FetchOptions) Validate() error {
return nil
}
-// PushOptions describes how a push should be performed
+// PushOptions describes how a push should be performed.
type PushOptions struct {
// RemoteName is the name of the remote to be pushed to.
RemoteName string
// RefSpecs specify what destination ref to update with what source
// object. A refspec with empty src can be used to delete a reference.
RefSpecs []config.RefSpec
- // Auth credentials, if required, to use with the remote repository
+ // Auth credentials, if required, to use with the remote repository.
Auth transport.AuthMethod
}
-// Validate validates the fields and sets the default values
+// Validate validates the fields and sets the default values.
func (o *PushOptions) Validate() error {
if o.RemoteName == "" {
o.RemoteName = DefaultRemoteName
@@ -148,3 +164,16 @@ func (o *PushOptions) Validate() error {
return nil
}
+
+// SubmoduleUpdateOptions describes how a submodule update should be performed.
+type SubmoduleUpdateOptions struct {
+ // Init, if true initializes the submodules recorded in the index.
+ Init bool
+ // NoFetch tell to the update command to not fetch new objects from the
+ // remote site.
+ NoFetch bool
+ // RecurseSubmodules the update is performed not only in the submodules of
+ // the current repository but also in any nested submodules inside those
+ // submodules (and so on). Until the SubmoduleRescursivity is reached.
+ RecurseSubmodules SubmoduleRescursivity
+}
diff --git a/plumbing/format/index/encoder.go b/plumbing/format/index/encoder.go
index e5de135..bdb10c1 100644
--- a/plumbing/format/index/encoder.go
+++ b/plumbing/format/index/encoder.go
@@ -6,6 +6,7 @@ import (
"errors"
"hash"
"io"
+ "sort"
"time"
"srcd.works/go-git.v4/utils/binary"
@@ -61,6 +62,8 @@ func (e *Encoder) encodeHeader(idx *Index) error {
}
func (e *Encoder) encodeEntries(idx *Index) error {
+ sort.Sort(byName(idx.Entries))
+
for _, entry := range idx.Entries {
if err := e.encodeEntry(&entry); err != nil {
return err
@@ -139,3 +142,9 @@ func (e *Encoder) padEntry(wrote int) error {
func (e *Encoder) encodeFooter() error {
return binary.Write(e.w, e.hash.Sum(nil))
}
+
+type byName []Entry
+
+func (l byName) Len() int { return len(l) }
+func (l byName) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
+func (l byName) Less(i, j int) bool { return l[i].Name < l[j].Name }
diff --git a/plumbing/format/index/encoder_test.go b/plumbing/format/index/encoder_test.go
index 914ee26..a6a0ea2 100644
--- a/plumbing/format/index/encoder_test.go
+++ b/plumbing/format/index/encoder_test.go
@@ -26,6 +26,11 @@ func (s *IndexSuite) TestEncode(c *C) {
}, {
CreatedAt: time.Now(),
ModifiedAt: time.Now(),
+ Name: "bar",
+ Size: 82,
+ }, {
+ CreatedAt: time.Now(),
+ ModifiedAt: time.Now(),
Name: strings.Repeat(" ", 20),
Size: 82,
}},
@@ -42,6 +47,11 @@ func (s *IndexSuite) TestEncode(c *C) {
c.Assert(err, IsNil)
c.Assert(idx, DeepEquals, output)
+
+ c.Assert(output.Entries[0].Name, Equals, strings.Repeat(" ", 20))
+ c.Assert(output.Entries[1].Name, Equals, "bar")
+ c.Assert(output.Entries[2].Name, Equals, "foo")
+
}
func (s *IndexSuite) TestEncodeUnsuportedVersion(c *C) {
diff --git a/plumbing/format/index/index.go b/plumbing/format/index/index.go
index e5dc178..a95dba2 100644
--- a/plumbing/format/index/index.go
+++ b/plumbing/format/index/index.go
@@ -36,9 +36,14 @@ const (
// in the worktree, having information about the working files. Changes in
// worktree are detected using this Index. The Index is also used during merges
type Index struct {
- Version uint32
- Entries []Entry
- Cache *Tree
+ // Version is index version
+ Version uint32
+ // Entries collection of entries represented by this Index. The order of
+ // this collection is not guaranteed
+ Entries []Entry
+ // Cache represents the 'Cached tree' extension
+ Cache *Tree
+ // ResolveUndo represents the 'Resolve undo' extension
ResolveUndo *ResolveUndo
}
@@ -84,7 +89,7 @@ type TreeEntry struct {
// Path component (relative to its parent directory)
Path string
// Entries is the number of entries in the index that is covered by the tree
- // this entry represents
+ // this entry represents.
Entries int
// Trees is the number that represents the number of subtrees this tree has
Trees int
diff --git a/plumbing/object/file.go b/plumbing/object/file.go
index 35e7f24..4866777 100644
--- a/plumbing/object/file.go
+++ b/plumbing/object/file.go
@@ -81,7 +81,7 @@ func (iter *FileIter) Next() (*File, error) {
return nil, err
}
- if entry.Mode.IsDir() {
+ if entry.Mode.IsDir() || entry.Mode == SubmoduleMode {
continue
}
diff --git a/plumbing/object/file_test.go b/plumbing/object/file_test.go
index 4c8bbb6..ff01c9f 100644
--- a/plumbing/object/file_test.go
+++ b/plumbing/object/file_test.go
@@ -247,3 +247,31 @@ func (s *FileSuite) TestFileIter(c *C) {
c.Assert(count, Equals, 1)
}
+
+func (s *FileSuite) TestFileIterSubmodule(c *C) {
+ dotgit := fixtures.ByURL("https://github.com/git-fixtures/submodule.git").One().DotGit()
+ st, err := filesystem.NewStorage(dotgit)
+
+ c.Assert(err, IsNil)
+
+ hash := plumbing.NewHash("a692ec699bff9117c1ed91752afbb7d9d272ebef")
+ commit, err := GetCommit(st, hash)
+ c.Assert(err, IsNil)
+
+ tree, err := commit.Tree()
+ c.Assert(err, IsNil)
+
+ expected := []string{
+ ".gitmodules",
+ }
+
+ var count int
+ i := tree.Files()
+ i.ForEach(func(f *File) error {
+ c.Assert(f.Name, Equals, expected[count])
+ count++
+ return nil
+ })
+
+ c.Assert(count, Equals, 1)
+}
diff --git a/plumbing/object/tree.go b/plumbing/object/tree.go
index 3bcd80a..27d8578 100644
--- a/plumbing/object/tree.go
+++ b/plumbing/object/tree.go
@@ -375,11 +375,6 @@ func (w *TreeWalker) Next() (name string, entry TreeEntry, err error) {
return
}
- if entry.Mode == SubmoduleMode {
- err = nil
- continue
- }
-
if entry.Mode.IsDir() {
obj, err = GetTree(w.s, entry.Hash)
}
diff --git a/plumbing/object/tree_test.go b/plumbing/object/tree_test.go
index be721b9..8ea31bb 100644
--- a/plumbing/object/tree_test.go
+++ b/plumbing/object/tree_test.go
@@ -4,7 +4,10 @@ import (
"io"
"os"
+ fixtures "github.com/src-d/go-git-fixtures"
+
"srcd.works/go-git.v4/plumbing"
+ "srcd.works/go-git.v4/storage/filesystem"
. "gopkg.in/check.v1"
"srcd.works/go-git.v4/plumbing/storer"
@@ -262,6 +265,44 @@ func (s *TreeSuite) TestTreeWalkerNextNonRecursive(c *C) {
c.Assert(count, Equals, 8)
}
+func (s *TreeSuite) TestTreeWalkerNextSubmodule(c *C) {
+ dotgit := fixtures.ByURL("https://github.com/git-fixtures/submodule.git").One().DotGit()
+ st, err := filesystem.NewStorage(dotgit)
+ c.Assert(err, IsNil)
+
+ hash := plumbing.NewHash("a692ec699bff9117c1ed91752afbb7d9d272ebef")
+ commit, err := GetCommit(st, hash)
+ c.Assert(err, IsNil)
+
+ tree, err := commit.Tree()
+ c.Assert(err, IsNil)
+
+ expected := []string{
+ ".gitmodules",
+ "basic",
+ "itself",
+ }
+
+ var count int
+ walker := NewTreeWalker(tree, true)
+ defer walker.Close()
+
+ for {
+ name, entry, err := walker.Next()
+ if err == io.EOF {
+ break
+ }
+
+ c.Assert(err, IsNil)
+ c.Assert(entry, NotNil)
+ c.Assert(name, Equals, expected[count])
+
+ count++
+ }
+
+ c.Assert(count, Equals, 3)
+}
+
var treeWalkerExpects = []struct {
Path, Mode, Name, Hash, Tree string
}{{
diff --git a/remote.go b/remote.go
index 2d243e9..a51946b 100644
--- a/remote.go
+++ b/remote.go
@@ -16,6 +16,7 @@ import (
"srcd.works/go-git.v4/plumbing/storer"
"srcd.works/go-git.v4/plumbing/transport"
"srcd.works/go-git.v4/plumbing/transport/client"
+ "srcd.works/go-git.v4/storage"
"srcd.works/go-git.v4/storage/memory"
"srcd.works/go-git.v4/utils/ioutil"
)
@@ -25,10 +26,10 @@ var NoErrAlreadyUpToDate = errors.New("already up-to-date")
// Remote represents a connection to a remote repository
type Remote struct {
c *config.RemoteConfig
- s Storer
+ s storage.Storer
}
-func newRemote(s Storer, c *config.RemoteConfig) *Remote {
+func newRemote(s storage.Storer, c *config.RemoteConfig) *Remote {
return &Remote{s: s, c: c}
}
@@ -321,7 +322,9 @@ func getHaves(localRefs storer.ReferenceStorer) ([]plumbing.Hash, error) {
return haves, nil
}
-func getWants(spec []config.RefSpec, localStorer Storer, remoteRefs storer.ReferenceStorer) ([]plumbing.Hash, error) {
+func getWants(
+ spec []config.RefSpec, localStorer storage.Storer, remoteRefs storer.ReferenceStorer,
+) ([]plumbing.Hash, error) {
wantTags := true
for _, s := range spec {
if !s.IsWildcard() {
diff --git a/remote_test.go b/remote_test.go
index 1e34905..e13ef20 100644
--- a/remote_test.go
+++ b/remote_test.go
@@ -11,6 +11,7 @@ import (
"srcd.works/go-git.v4/config"
"srcd.works/go-git.v4/plumbing"
"srcd.works/go-git.v4/plumbing/storer"
+ "srcd.works/go-git.v4/storage"
"srcd.works/go-git.v4/storage/filesystem"
"srcd.works/go-git.v4/storage/memory"
@@ -126,7 +127,7 @@ func (s *RemoteSuite) TestFetchWithProgress(c *C) {
}
type mockPackfileWriter struct {
- Storer
+ storage.Storer
PackfileWriterCalled bool
}
diff --git a/repository.go b/repository.go
index a8dd7ef..c065a26 100644
--- a/repository.go
+++ b/repository.go
@@ -4,12 +4,14 @@ import (
"errors"
"fmt"
"os"
+ "path/filepath"
"srcd.works/go-git.v4/config"
"srcd.works/go-git.v4/internal/revision"
"srcd.works/go-git.v4/plumbing"
"srcd.works/go-git.v4/plumbing/object"
"srcd.works/go-git.v4/plumbing/storer"
+ "srcd.works/go-git.v4/storage"
"srcd.works/go-git.v4/storage/filesystem"
"srcd.works/go-billy.v1"
@@ -29,7 +31,7 @@ var (
// Repository represents a git repository
type Repository struct {
- Storer Storer
+ Storer storage.Storer
r map[string]*Remote
wt billy.Filesystem
@@ -38,7 +40,7 @@ type Repository struct {
// Init creates an empty git repository, based on the given Storer and worktree.
// The worktree Filesystem is optional, if nil a bare repository is created. If
// the given storer is not empty ErrRepositoryAlreadyExists is returned
-func Init(s Storer, worktree billy.Filesystem) (*Repository, error) {
+func Init(s storage.Storer, worktree billy.Filesystem) (*Repository, error) {
r := newRepository(s, worktree)
_, err := r.Reference(plumbing.HEAD, false)
switch err {
@@ -56,9 +58,75 @@ func Init(s Storer, worktree billy.Filesystem) (*Repository, error) {
if worktree == nil {
r.setIsBare(true)
+ return r, nil
}
- return r, nil
+ return r, setWorktreeAndStoragePaths(r, worktree)
+}
+
+func setWorktreeAndStoragePaths(r *Repository, worktree billy.Filesystem) error {
+ type fsBased interface {
+ Filesystem() billy.Filesystem
+ }
+
+ // .git file is only created if the storage is file based and the file
+ // system is osfs.OS
+ fs, isFSBased := r.Storer.(fsBased)
+ if !isFSBased {
+ return nil
+ }
+
+ _, isOS := fs.Filesystem().(*osfs.OS)
+ if !isOS {
+ return nil
+ }
+
+ if err := createDotGitFile(worktree, fs.Filesystem()); err != nil {
+ return err
+ }
+
+ return setConfigWorktree(r, worktree, fs.Filesystem())
+}
+
+func createDotGitFile(worktree, storage billy.Filesystem) error {
+ path, err := filepath.Rel(worktree.Base(), storage.Base())
+ if err != nil {
+ path = storage.Base()
+ }
+
+ if path == ".git" {
+ // not needed, since the folder is the default place
+ return nil
+ }
+
+ f, err := worktree.Create(".git")
+ if err != nil {
+ return err
+ }
+
+ defer f.Close()
+ _, err = fmt.Fprintf(f, "gitdir: %s\n", path)
+ return err
+}
+
+func setConfigWorktree(r *Repository, worktree, storage billy.Filesystem) error {
+ path, err := filepath.Rel(storage.Base(), worktree.Base())
+ if err != nil {
+ path = worktree.Base()
+ }
+
+ if path == ".." {
+ // not needed, since the folder is the default place
+ return nil
+ }
+
+ cfg, err := r.Storer.Config()
+ if err != nil {
+ return err
+ }
+
+ cfg.Core.Worktree = path
+ return r.Storer.SetConfig(cfg)
}
// Open opens a git repository using the given Storer and worktree filesystem,
@@ -66,7 +134,7 @@ func Init(s Storer, worktree billy.Filesystem) (*Repository, error) {
// The worktree can be nil when the repository being opened is bare, if the
// repository is a normal one (not bare) and worktree is nil the err
// ErrWorktreeNotProvided is returned
-func Open(s Storer, worktree billy.Filesystem) (*Repository, error) {
+func Open(s storage.Storer, worktree billy.Filesystem) (*Repository, error) {
_, err := s.Reference(plumbing.HEAD)
if err == plumbing.ErrReferenceNotFound {
return nil, ErrRepositoryNotExists
@@ -91,7 +159,7 @@ func Open(s Storer, worktree billy.Filesystem) (*Repository, error) {
// Clone a repository into the given Storer and worktree Filesystem with the
// given options, if worktree is nil a bare repository is created. If the given
// storer is not empty ErrRepositoryAlreadyExists is returned
-func Clone(s Storer, worktree billy.Filesystem, o *CloneOptions) (*Repository, error) {
+func Clone(s storage.Storer, worktree billy.Filesystem, o *CloneOptions) (*Repository, error) {
r, err := Init(s, worktree)
if err != nil {
return nil, err
@@ -159,7 +227,7 @@ func PlainClone(path string, isBare bool, o *CloneOptions) (*Repository, error)
return r, r.clone(o)
}
-func newRepository(s Storer, worktree billy.Filesystem) *Repository {
+func newRepository(s storage.Storer, worktree billy.Filesystem) *Repository {
return &Repository{
Storer: s,
wt: worktree,
@@ -247,12 +315,6 @@ func (r *Repository) clone(o *CloneOptions) error {
return err
}
- // marks the repository as bare in the config, until we have Worktree, all
- // the repository are bare
- if err := r.setIsBare(true); err != nil {
- return err
- }
-
c := &config.RemoteConfig{
Name: o.RemoteName,
URL: o.URL,
@@ -286,9 +348,32 @@ func (r *Repository) clone(o *CloneOptions) error {
return err
}
+ if o.RecurseSubmodules != NoRecurseSubmodules && r.wt != nil {
+ if err := r.updateSubmodules(o.RecurseSubmodules); err != nil {
+ return err
+ }
+ }
+
return r.updateRemoteConfig(remote, o, c, head)
}
+func (r *Repository) updateSubmodules(recursion SubmoduleRescursivity) error {
+ w, err := r.Worktree()
+ if err != nil {
+ return err
+ }
+
+ s, err := w.Submodules()
+ if err != nil {
+ return err
+ }
+
+ return s.Update(&SubmoduleUpdateOptions{
+ Init: true,
+ RecurseSubmodules: recursion,
+ })
+}
+
func (r *Repository) cloneRefSpec(o *CloneOptions,
c *config.RemoteConfig) []config.RefSpec {
@@ -462,7 +547,17 @@ func (r *Repository) Pull(o *PullOptions) error {
return NoErrAlreadyUpToDate
}
- return r.updateWorktree()
+ if err := r.updateWorktree(); err != nil {
+ return err
+ }
+
+ if o.RecurseSubmodules != NoRecurseSubmodules && r.wt != nil {
+ if err := r.updateSubmodules(o.RecurseSubmodules); err != nil {
+ return err
+ }
+ }
+
+ return nil
}
func (r *Repository) updateWorktree() error {
diff --git a/repository_test.go b/repository_test.go
index 1b5b345..89ea188 100644
--- a/repository_test.go
+++ b/repository_test.go
@@ -18,6 +18,7 @@ import (
. "gopkg.in/check.v1"
"srcd.works/go-billy.v1/memfs"
+ "srcd.works/go-billy.v1/osfs"
)
type RepositorySuite struct {
@@ -36,6 +37,52 @@ func (s *RepositorySuite) TestInit(c *C) {
c.Assert(cfg.Core.IsBare, Equals, false)
}
+func (s *RepositorySuite) TestInitNonStandardDotGit(c *C) {
+ dir, err := ioutil.TempDir("", "init-non-standard")
+ c.Assert(err, IsNil)
+ c.Assert(os.RemoveAll(dir), IsNil)
+
+ fs := osfs.New(dir)
+ storage, err := filesystem.NewStorage(fs.Dir("storage"))
+ c.Assert(err, IsNil)
+
+ r, err := Init(storage, fs.Dir("worktree"))
+ c.Assert(err, IsNil)
+ c.Assert(r, NotNil)
+
+ f, err := fs.Open("worktree/.git")
+ c.Assert(err, IsNil)
+
+ all, err := ioutil.ReadAll(f)
+ c.Assert(err, IsNil)
+ c.Assert(string(all), Equals, "gitdir: ../storage\n")
+
+ cfg, err := r.Config()
+ c.Assert(err, IsNil)
+ c.Assert(cfg.Core.Worktree, Equals, "../worktree")
+}
+
+func (s *RepositorySuite) TestInitStandardDotGit(c *C) {
+ dir, err := ioutil.TempDir("", "init-standard")
+ c.Assert(err, IsNil)
+ c.Assert(os.RemoveAll(dir), IsNil)
+
+ fs := osfs.New(dir)
+ storage, err := filesystem.NewStorage(fs.Dir(".git"))
+ c.Assert(err, IsNil)
+
+ r, err := Init(storage, fs)
+ c.Assert(err, IsNil)
+ c.Assert(r, NotNil)
+
+ l, err := fs.ReadDir(".git")
+ c.Assert(len(l) > 0, Equals, true)
+
+ cfg, err := r.Config()
+ c.Assert(err, IsNil)
+ c.Assert(cfg.Core.Worktree, Equals, "")
+}
+
func (s *RepositorySuite) TestInitBare(c *C) {
r, err := Init(memory.NewStorage(), nil)
c.Assert(err, IsNil)
@@ -246,6 +293,24 @@ func (s *RepositorySuite) TestPlainClone(c *C) {
c.Assert(remotes, HasLen, 1)
}
+func (s *RepositorySuite) TestPlainCloneWithRecurseSubmodules(c *C) {
+ dir, err := ioutil.TempDir("", "plain-clone-submodule")
+ c.Assert(err, IsNil)
+ defer os.RemoveAll(dir)
+
+ path := fixtures.ByTag("submodule").One().Worktree().Base()
+ r, err := PlainClone(dir, false, &CloneOptions{
+ URL: fmt.Sprintf("file://%s", path),
+ RecurseSubmodules: DefaultSubmoduleRecursionDepth,
+ })
+
+ c.Assert(err, IsNil)
+
+ cfg, err := r.Config()
+ c.Assert(cfg.Remotes, HasLen, 1)
+ c.Assert(cfg.Submodules, HasLen, 2)
+}
+
func (s *RepositorySuite) TestFetch(c *C) {
r, _ := Init(memory.NewStorage(), nil)
_, err := r.CreateRemote(&config.RemoteConfig{
@@ -515,27 +580,44 @@ func (s *RepositorySuite) TestPullProgress(c *C) {
c.Assert(buf.Len(), Not(Equals), 0)
}
+func (s *RepositorySuite) TestPullProgressWithRecursion(c *C) {
+ path := fixtures.ByTag("submodule").One().Worktree().Base()
+
+ dir, err := ioutil.TempDir("", "plain-clone-submodule")
+ c.Assert(err, IsNil)
+ defer os.RemoveAll(dir)
+
+ r, _ := PlainInit(dir, false)
+ r.CreateRemote(&config.RemoteConfig{
+ Name: DefaultRemoteName,
+ URL: fmt.Sprintf("file://%s", path),
+ })
+
+ err = r.Pull(&PullOptions{
+ RecurseSubmodules: DefaultSubmoduleRecursionDepth,
+ })
+ c.Assert(err, IsNil)
+
+ cfg, err := r.Config()
+ c.Assert(cfg.Submodules, HasLen, 2)
+}
+
func (s *RepositorySuite) TestPullAdd(c *C) {
- path := fixtures.Basic().One().Worktree().Base()
+ path := fixtures.Basic().ByTag("worktree").One().Worktree().Base()
- r, _ := Init(memory.NewStorage(), nil)
- err := r.clone(&CloneOptions{
+ r, err := Clone(memory.NewStorage(), nil, &CloneOptions{
URL: fmt.Sprintf("file://%s", filepath.Join(path, ".git")),
})
c.Assert(err, IsNil)
storage := r.Storer.(*memory.Storage)
- c.Assert(storage.Objects, HasLen, 31)
+ c.Assert(storage.Objects, HasLen, 28)
branch, err := r.Reference("refs/heads/master", false)
c.Assert(err, IsNil)
c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
- branch, err = r.Reference("refs/remotes/origin/branch", false)
- c.Assert(err, IsNil)
- c.Assert(branch.Hash().String(), Equals, "e8d3ffab552895c19b9fcf7aa264d277cde33881")
-
ExecuteOnPath(c, path,
"touch foo",
"git add foo",
@@ -546,16 +628,11 @@ func (s *RepositorySuite) TestPullAdd(c *C) {
c.Assert(err, IsNil)
// the commit command has introduced a new commit, tree and blob
- c.Assert(storage.Objects, HasLen, 34)
+ c.Assert(storage.Objects, HasLen, 31)
branch, err = r.Reference("refs/heads/master", false)
c.Assert(err, IsNil)
c.Assert(branch.Hash().String(), Not(Equals), "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
-
- // the commit command, was in the local branch, so the remote should be read ok
- branch, err = r.Reference("refs/remotes/origin/branch", false)
- c.Assert(err, IsNil)
- c.Assert(branch.Hash().String(), Equals, "e8d3ffab552895c19b9fcf7aa264d277cde33881")
}
func (s *RepositorySuite) TestPushToEmptyRepository(c *C) {
diff --git a/storage/filesystem/internal/dotgit/dotgit.go b/storage/filesystem/internal/dotgit/dotgit.go
index 6646e18..b46f827 100644
--- a/storage/filesystem/internal/dotgit/dotgit.go
+++ b/storage/filesystem/internal/dotgit/dotgit.go
@@ -21,13 +21,13 @@ const (
configPath = "config"
indexPath = "index"
shallowPath = "shallow"
+ modulePath = "module"
+ objectsPath = "objects"
+ packPath = "pack"
+ refsPath = "refs"
tmpPackedRefsPrefix = "._packed-refs"
- objectsPath = "objects"
- packPath = "pack"
- refsPath = "refs"
-
packExt = ".pack"
idxExt = ".idx"
)
@@ -454,6 +454,11 @@ func (d *DotGit) readReferenceFile(refsPath, refFile string) (ref *plumbing.Refe
return plumbing.NewReferenceFromStrings(refFile, line), nil
}
+// Module return a billy.Filesystem poiting to the module folder
+func (d *DotGit) Module(name string) billy.Filesystem {
+ return d.fs.Dir(d.fs.Join(modulePath, name))
+}
+
func isHex(s string) bool {
for _, b := range []byte(s) {
if isNum(b) {
diff --git a/storage/filesystem/internal/dotgit/dotgit_test.go b/storage/filesystem/internal/dotgit/dotgit_test.go
index 226b299..57dfb53 100644
--- a/storage/filesystem/internal/dotgit/dotgit_test.go
+++ b/storage/filesystem/internal/dotgit/dotgit_test.go
@@ -434,3 +434,11 @@ func (s *SuiteDotGit) TestObjectNotFound(c *C) {
c.Assert(err, NotNil)
c.Assert(file, IsNil)
}
+
+func (s *SuiteDotGit) TestSubmodules(c *C) {
+ fs := fixtures.ByTag("submodule").One().DotGit()
+ dir := New(fs)
+
+ m := dir.Module("basic")
+ c.Assert(strings.HasSuffix(m.Base(), ".git/module/basic"), Equals, true)
+}
diff --git a/storage/filesystem/module.go b/storage/filesystem/module.go
new file mode 100644
index 0000000..e8985d8
--- /dev/null
+++ b/storage/filesystem/module.go
@@ -0,0 +1,14 @@
+package filesystem
+
+import (
+ "srcd.works/go-git.v4/storage"
+ "srcd.works/go-git.v4/storage/filesystem/internal/dotgit"
+)
+
+type ModuleStorage struct {
+ dir *dotgit.DotGit
+}
+
+func (s *ModuleStorage) Module(name string) (storage.Storer, error) {
+ return NewStorage(s.dir.Module(name))
+}
diff --git a/storage/filesystem/storage.go b/storage/filesystem/storage.go
index 7021d3a..9895507 100644
--- a/storage/filesystem/storage.go
+++ b/storage/filesystem/storage.go
@@ -11,11 +11,14 @@ import (
// standard git format (this is, the .git directory). Zero values of this type
// are not safe to use, see the NewStorage function below.
type Storage struct {
+ fs billy.Filesystem
+
ObjectStorage
ReferenceStorage
IndexStorage
ShallowStorage
ConfigStorage
+ ModuleStorage
}
// NewStorage returns a new Storage backed by a given `fs.Filesystem`
@@ -27,10 +30,18 @@ func NewStorage(fs billy.Filesystem) (*Storage, error) {
}
return &Storage{
+ fs: fs,
+
ObjectStorage: o,
ReferenceStorage: ReferenceStorage{dir: dir},
IndexStorage: IndexStorage{dir: dir},
ShallowStorage: ShallowStorage{dir: dir},
ConfigStorage: ConfigStorage{dir: dir},
+ ModuleStorage: ModuleStorage{dir: dir},
}, nil
}
+
+// Filesystem returns the underlying filesystem
+func (s *Storage) Filesystem() billy.Filesystem {
+ return s.fs
+}
diff --git a/storage/filesystem/storage_test.go b/storage/filesystem/storage_test.go
index e398d22..7300de7 100644
--- a/storage/filesystem/storage_test.go
+++ b/storage/filesystem/storage_test.go
@@ -6,6 +6,7 @@ import (
"srcd.works/go-git.v4/storage/test"
. "gopkg.in/check.v1"
+ "srcd.works/go-billy.v1/memfs"
"srcd.works/go-billy.v1/osfs"
)
@@ -23,3 +24,11 @@ func (s *StorageSuite) SetUpTest(c *C) {
s.BaseStorageSuite = test.NewBaseStorageSuite(storage)
}
+
+func (s *StorageSuite) TestFilesystem(c *C) {
+ fs := memfs.New()
+ storage, err := NewStorage(fs)
+ c.Assert(err, IsNil)
+
+ c.Assert(storage.Filesystem(), Equals, fs)
+}
diff --git a/storage/memory/storage.go b/storage/memory/storage.go
index 9b55b1f..92aeec9 100644
--- a/storage/memory/storage.go
+++ b/storage/memory/storage.go
@@ -8,6 +8,7 @@ import (
"srcd.works/go-git.v4/plumbing"
"srcd.works/go-git.v4/plumbing/format/index"
"srcd.works/go-git.v4/plumbing/storer"
+ "srcd.works/go-git.v4/storage"
)
var ErrUnsupportedObjectType = fmt.Errorf("unsupported object type")
@@ -22,6 +23,7 @@ type Storage struct {
ShallowStorage
IndexStorage
ReferenceStorage
+ ModuleStorage
}
// NewStorage returns a new Storage base on memory
@@ -37,6 +39,7 @@ func NewStorage() *Storage {
Blobs: make(map[plumbing.Hash]plumbing.EncodedObject, 0),
Tags: make(map[plumbing.Hash]plumbing.EncodedObject, 0),
},
+ ModuleStorage: make(ModuleStorage, 0),
}
}
@@ -232,3 +235,16 @@ func (s *ShallowStorage) SetShallow(commits []plumbing.Hash) error {
func (s ShallowStorage) Shallow() ([]plumbing.Hash, error) {
return s, nil
}
+
+type ModuleStorage map[string]*Storage
+
+func (s ModuleStorage) Module(name string) (storage.Storer, error) {
+ if m, ok := s[name]; ok {
+ return m, nil
+ }
+
+ m := NewStorage()
+ s[name] = m
+
+ return m, nil
+}
diff --git a/storage/storer.go b/storage/storer.go
new file mode 100644
index 0000000..d217209
--- /dev/null
+++ b/storage/storer.go
@@ -0,0 +1,26 @@
+package storage
+
+import (
+ "srcd.works/go-git.v4/config"
+ "srcd.works/go-git.v4/plumbing/storer"
+)
+
+// Storer is a generic storage of objects, references and any information
+// related to a particular repository. The package srcd.works/go-git.v4/storage
+// contains two implementation a filesystem base implementation (such as `.git`)
+// and a memory implementations being ephemeral
+type Storer interface {
+ storer.EncodedObjectStorer
+ storer.ReferenceStorer
+ storer.ShallowStorer
+ storer.IndexStorer
+ config.ConfigStorer
+ ModuleStorer
+}
+
+// ModuleStorer allows interact with the modules' Storers
+type ModuleStorer interface {
+ // Module returns a Storer reprensting a submodule, if not exists returns a
+ // new empty Storer is returned
+ Module(name string) (Storer, error)
+}
diff --git a/storage/test/storage_suite.go b/storage/test/storage_suite.go
index e09a673..2a10c78 100644
--- a/storage/test/storage_suite.go
+++ b/storage/test/storage_suite.go
@@ -11,6 +11,7 @@ import (
"srcd.works/go-git.v4/plumbing"
"srcd.works/go-git.v4/plumbing/format/index"
"srcd.works/go-git.v4/plumbing/storer"
+ "srcd.works/go-git.v4/storage"
. "gopkg.in/check.v1"
)
@@ -21,6 +22,7 @@ type Storer interface {
storer.ShallowStorer
storer.IndexStorer
config.ConfigStorer
+ storage.ModuleStorer
}
type TestObject struct {
@@ -321,7 +323,9 @@ func (s *BaseStorageSuite) TestSetConfigAndConfig(c *C) {
cfg, err := s.Storer.Config()
c.Assert(err, IsNil)
- c.Assert(cfg, DeepEquals, expected)
+
+ c.Assert(cfg.Core.IsBare, DeepEquals, expected.Core.IsBare)
+ c.Assert(cfg.Remotes, DeepEquals, expected.Remotes)
}
func (s *BaseStorageSuite) TestIndex(c *C) {
@@ -353,6 +357,16 @@ func (s *BaseStorageSuite) TestSetConfigInvalid(c *C) {
c.Assert(err, NotNil)
}
+func (s *BaseStorageSuite) TestModule(c *C) {
+ storer, err := s.Storer.Module("foo")
+ c.Assert(err, IsNil)
+ c.Assert(storer, NotNil)
+
+ storer, err = s.Storer.Module("foo")
+ c.Assert(err, IsNil)
+ c.Assert(storer, NotNil)
+}
+
func objectEquals(a plumbing.EncodedObject, b plumbing.EncodedObject) error {
ha := a.Hash()
hb := b.Hash()
diff --git a/submodule.go b/submodule.go
new file mode 100644
index 0000000..e329fda
--- /dev/null
+++ b/submodule.go
@@ -0,0 +1,174 @@
+package git
+
+import (
+ "errors"
+
+ "srcd.works/go-git.v4/config"
+ "srcd.works/go-git.v4/plumbing"
+)
+
+var (
+ ErrSubmoduleAlreadyInitialized = errors.New("submodule already initialized")
+ ErrSubmoduleNotInitialized = errors.New("submodule not initialized")
+)
+
+// Submodule a submodule allows you to keep another Git repository in a
+// subdirectory of your repository.
+type Submodule struct {
+ initialized bool
+
+ c *config.Submodule
+ w *Worktree
+}
+
+// Config returns the submodule config
+func (s *Submodule) Config() *config.Submodule {
+ return s.c
+}
+
+// Init initialize the submodule reading the recoreded Entry in the index for
+// the given submodule
+func (s *Submodule) Init() error {
+ cfg, err := s.w.r.Storer.Config()
+ if err != nil {
+ return err
+ }
+
+ _, ok := cfg.Submodules[s.c.Name]
+ if ok {
+ return ErrSubmoduleAlreadyInitialized
+ }
+
+ s.initialized = true
+
+ cfg.Submodules[s.c.Name] = s.c
+ return s.w.r.Storer.SetConfig(cfg)
+}
+
+// Repository returns the Repository represented by this submodule
+func (s *Submodule) Repository() (*Repository, error) {
+ storer, err := s.w.r.Storer.Module(s.c.Name)
+ if err != nil {
+ return nil, err
+ }
+
+ _, err = storer.Reference(plumbing.HEAD)
+ if err != nil && err != plumbing.ErrReferenceNotFound {
+ return nil, err
+ }
+
+ worktree := s.w.fs.Dir(s.c.Path)
+ if err == nil {
+ return Open(storer, worktree)
+ }
+
+ r, err := Init(storer, worktree)
+ if err != nil {
+ return nil, err
+ }
+
+ _, err = r.CreateRemote(&config.RemoteConfig{
+ Name: DefaultRemoteName,
+ URL: s.c.URL,
+ })
+
+ return r, err
+}
+
+// Update the registered submodule to match what the superproject expects, the
+// submodule should be initilized first calling the Init method or setting in
+// the options SubmoduleUpdateOptions.Init equals true
+func (s *Submodule) Update(o *SubmoduleUpdateOptions) error {
+ if !s.initialized && !o.Init {
+ return ErrSubmoduleNotInitialized
+ }
+
+ if !s.initialized && o.Init {
+ if err := s.Init(); err != nil {
+ return err
+ }
+ }
+
+ e, err := s.w.readIndexEntry(s.c.Path)
+ if err != nil {
+ return err
+ }
+
+ r, err := s.Repository()
+ if err != nil {
+ return err
+ }
+
+ if err := s.fetchAndCheckout(r, o, e.Hash); err != nil {
+ return err
+ }
+
+ return s.doRecrusiveUpdate(r, o)
+}
+
+func (s *Submodule) doRecrusiveUpdate(r *Repository, o *SubmoduleUpdateOptions) error {
+ if o.RecurseSubmodules == NoRecurseSubmodules {
+ return nil
+ }
+
+ w, err := r.Worktree()
+ if err != nil {
+ return err
+ }
+
+ l, err := w.Submodules()
+ if err != nil {
+ return err
+ }
+
+ new := &SubmoduleUpdateOptions{}
+ *new = *o
+ new.RecurseSubmodules--
+ return l.Update(new)
+}
+
+func (s *Submodule) fetchAndCheckout(r *Repository, o *SubmoduleUpdateOptions, hash plumbing.Hash) error {
+ if !o.NoFetch {
+ err := r.Fetch(&FetchOptions{})
+ if err != nil && err != NoErrAlreadyUpToDate {
+ return err
+ }
+ }
+
+ w, err := r.Worktree()
+ if err != nil {
+ return err
+ }
+
+ if err := w.Checkout(hash); err != nil {
+ return err
+ }
+
+ head := plumbing.NewHashReference(plumbing.HEAD, hash)
+ return r.Storer.SetReference(head)
+}
+
+// Submodules list of several submodules from the same repository
+type Submodules []*Submodule
+
+// Init initializes the submodules in this list
+func (s Submodules) Init() error {
+ for _, sub := range s {
+ if err := sub.Init(); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// Update updates all the submodules in this list
+func (s Submodules) Update(o *SubmoduleUpdateOptions) error {
+ for _, sub := range s {
+ if err := sub.Update(o); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/submodule_test.go b/submodule_test.go
new file mode 100644
index 0000000..a933965
--- /dev/null
+++ b/submodule_test.go
@@ -0,0 +1,164 @@
+package git
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "github.com/src-d/go-git-fixtures"
+
+ . "gopkg.in/check.v1"
+ "srcd.works/go-git.v4/plumbing"
+)
+
+type SubmoduleSuite struct {
+ BaseSuite
+ Worktree *Worktree
+ path string
+}
+
+var _ = Suite(&SubmoduleSuite{})
+
+func (s *SubmoduleSuite) SetUpTest(c *C) {
+ path := fixtures.ByTag("submodule").One().Worktree().Base()
+
+ dir, err := ioutil.TempDir("", "submodule")
+ c.Assert(err, IsNil)
+
+ r, err := PlainClone(dir, false, &CloneOptions{
+ URL: fmt.Sprintf("file://%s", filepath.Join(path)),
+ })
+
+ c.Assert(err, IsNil)
+
+ s.Repository = r
+ s.Worktree, err = r.Worktree()
+ c.Assert(err, IsNil)
+
+ s.path = dir
+}
+
+func (s *SubmoduleSuite) TearDownTest(c *C) {
+ err := os.RemoveAll(s.path)
+ c.Assert(err, IsNil)
+}
+
+func (s *SubmoduleSuite) TestInit(c *C) {
+ sm, err := s.Worktree.Submodule("basic")
+ c.Assert(err, IsNil)
+
+ err = sm.Init()
+ c.Assert(err, IsNil)
+
+ cfg, err := s.Repository.Config()
+ c.Assert(err, IsNil)
+
+ c.Assert(cfg.Submodules, HasLen, 1)
+ c.Assert(cfg.Submodules["basic"], NotNil)
+}
+
+func (s *SubmoduleSuite) TestUpdate(c *C) {
+ sm, err := s.Worktree.Submodule("basic")
+ c.Assert(err, IsNil)
+
+ err = sm.Update(&SubmoduleUpdateOptions{
+ Init: true,
+ })
+
+ c.Assert(err, IsNil)
+
+ r, err := sm.Repository()
+ c.Assert(err, IsNil)
+
+ ref, err := r.Reference(plumbing.HEAD, true)
+ c.Assert(err, IsNil)
+ c.Assert(ref.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
+
+}
+
+func (s *SubmoduleSuite) TestUpdateWithoutInit(c *C) {
+ sm, err := s.Worktree.Submodule("basic")
+ c.Assert(err, IsNil)
+
+ err = sm.Update(&SubmoduleUpdateOptions{})
+ c.Assert(err, Equals, ErrSubmoduleNotInitialized)
+}
+
+func (s *SubmoduleSuite) TestUpdateWithNotFetch(c *C) {
+ sm, err := s.Worktree.Submodule("basic")
+ c.Assert(err, IsNil)
+
+ err = sm.Update(&SubmoduleUpdateOptions{
+ Init: true,
+ NoFetch: true,
+ })
+
+ // Since we are not fetching, the object is not there
+ c.Assert(err, Equals, plumbing.ErrObjectNotFound)
+}
+
+func (s *SubmoduleSuite) TestUpdateWithRecursion(c *C) {
+ sm, err := s.Worktree.Submodule("itself")
+ c.Assert(err, IsNil)
+
+ err = sm.Update(&SubmoduleUpdateOptions{
+ Init: true,
+ RecurseSubmodules: 2,
+ })
+
+ c.Assert(err, IsNil)
+
+ _, err = s.Worktree.fs.Stat("itself/basic/LICENSE")
+ c.Assert(err, IsNil)
+}
+
+func (s *SubmoduleSuite) TestUpdateWithInitAndUpdate(c *C) {
+ sm, err := s.Worktree.Submodule("basic")
+ c.Assert(err, IsNil)
+
+ err = sm.Update(&SubmoduleUpdateOptions{
+ Init: true,
+ })
+ c.Assert(err, IsNil)
+
+ idx, err := s.Repository.Storer.Index()
+ c.Assert(err, IsNil)
+
+ for i, e := range idx.Entries {
+ if e.Name == "basic" {
+ e.Hash = plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d")
+ }
+
+ idx.Entries[i] = e
+ }
+
+ err = s.Repository.Storer.SetIndex(idx)
+ c.Assert(err, IsNil)
+
+ err = sm.Update(&SubmoduleUpdateOptions{})
+ c.Assert(err, IsNil)
+
+ r, err := sm.Repository()
+ c.Assert(err, IsNil)
+
+ ref, err := r.Reference(plumbing.HEAD, true)
+ c.Assert(err, IsNil)
+ c.Assert(ref.Hash().String(), Equals, "b029517f6300c2da0f4b651b8642506cd6aaf45d")
+
+}
+
+func (s *SubmoduleSuite) TestSubmodulesInit(c *C) {
+ sm, err := s.Worktree.Submodules()
+ c.Assert(err, IsNil)
+
+ err = sm.Init()
+ c.Assert(err, IsNil)
+
+ sm, err = s.Worktree.Submodules()
+ c.Assert(err, IsNil)
+
+ for _, m := range sm {
+ c.Assert(m.initialized, Equals, true)
+ }
+}
diff --git a/worktree.go b/worktree.go
index 58e008e..2a4e5d8 100644
--- a/worktree.go
+++ b/worktree.go
@@ -4,8 +4,10 @@ import (
"errors"
"fmt"
"io"
+ "io/ioutil"
"os"
+ "srcd.works/go-git.v4/config"
"srcd.works/go-git.v4/plumbing"
"srcd.works/go-git.v4/plumbing/format/index"
"srcd.works/go-git.v4/plumbing/object"
@@ -14,6 +16,7 @@ import (
)
var ErrWorktreeNotClean = errors.New("worktree is not clean")
+var ErrSubmoduleNotFound = errors.New("submodule not found")
type Worktree struct {
r *Repository
@@ -35,29 +38,57 @@ func (w *Worktree) Checkout(commit plumbing.Hash) error {
return err
}
- files, err := c.Files()
+ t, err := c.Tree()
if err != nil {
return err
}
idx := &index.Index{Version: 2}
- if err := files.ForEach(func(f *object.File) error {
- return w.checkoutFile(f, idx)
- }); err != nil {
- return err
+ walker := object.NewTreeWalker(t, true)
+
+ for {
+ name, entry, err := walker.Next()
+ if err == io.EOF {
+ break
+ }
+
+ if err != nil {
+ return err
+ }
+
+ if err := w.checkoutEntry(name, &entry, idx); err != nil {
+ return err
+ }
}
return w.r.Storer.SetIndex(idx)
}
-func (w *Worktree) checkoutFile(f *object.File, idx *index.Index) error {
- from, err := f.Reader()
+func (w *Worktree) checkoutEntry(name string, e *object.TreeEntry, idx *index.Index) error {
+ if e.Mode == object.SubmoduleMode {
+ return w.addIndexFromTreeEntry(name, e, idx)
+ }
+
+ if e.Mode.IsDir() {
+ return nil
+ }
+
+ return w.checkoutFile(name, e, idx)
+}
+
+func (w *Worktree) checkoutFile(name string, e *object.TreeEntry, idx *index.Index) error {
+ blob, err := object.GetBlob(w.r.Storer, e.Hash)
+ if err != nil {
+ return err
+ }
+
+ from, err := blob.Reader()
if err != nil {
return err
}
defer from.Close()
- to, err := w.fs.OpenFile(f.Name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode.Perm())
+ to, err := w.fs.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, e.Mode.Perm())
if err != nil {
return err
}
@@ -67,20 +98,30 @@ func (w *Worktree) checkoutFile(f *object.File, idx *index.Index) error {
}
defer to.Close()
- return w.indexFile(f, idx)
+ return w.addIndexFromFile(name, e, idx)
}
var fillSystemInfo func(e *index.Entry, sys interface{})
-func (w *Worktree) indexFile(f *object.File, idx *index.Index) error {
- fi, err := w.fs.Stat(f.Name)
+func (w *Worktree) addIndexFromTreeEntry(name string, f *object.TreeEntry, idx *index.Index) error {
+ idx.Entries = append(idx.Entries, index.Entry{
+ Hash: f.Hash,
+ Name: name,
+ Mode: object.SubmoduleMode,
+ })
+
+ return nil
+}
+
+func (w *Worktree) addIndexFromFile(name string, f *object.TreeEntry, idx *index.Index) error {
+ fi, err := w.fs.Stat(name)
if err != nil {
return err
}
e := index.Entry{
Hash: f.Hash,
- Name: f.Name,
+ Name: name,
Mode: w.getMode(fi),
ModifiedAt: fi.ModTime(),
Size: uint32(fi.Size()),
@@ -167,6 +208,90 @@ func (w *Worktree) getMode(fi billy.FileInfo) os.FileMode {
return object.FileMode
}
+const gitmodulesFile = ".gitmodules"
+
+// Submodule returns the submodule with the given name
+func (w *Worktree) Submodule(name string) (*Submodule, error) {
+ l, err := w.Submodules()
+ if err != nil {
+ return nil, err
+ }
+
+ for _, m := range l {
+ if m.Config().Name == name {
+ return m, nil
+ }
+ }
+
+ return nil, ErrSubmoduleNotFound
+}
+
+// Submodules returns all the available submodules
+func (w *Worktree) Submodules() (Submodules, error) {
+ l := make(Submodules, 0)
+ m, err := w.readGitmodulesFile()
+ if err != nil || m == nil {
+ return l, err
+ }
+
+ c, err := w.r.Config()
+ for _, s := range m.Submodules {
+ l = append(l, w.newSubmodule(s, c.Submodules[s.Name]))
+ }
+
+ return l, nil
+}
+
+func (w *Worktree) newSubmodule(fromModules, fromConfig *config.Submodule) *Submodule {
+ m := &Submodule{w: w}
+ m.initialized = fromConfig != nil
+
+ if !m.initialized {
+ m.c = fromModules
+ return m
+ }
+
+ m.c = fromConfig
+ m.c.Path = fromModules.Path
+ return m
+}
+
+func (w *Worktree) readGitmodulesFile() (*config.Modules, error) {
+ f, err := w.fs.Open(gitmodulesFile)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil, nil
+ }
+
+ return nil, err
+ }
+
+ input, err := ioutil.ReadAll(f)
+ if err != nil {
+ return nil, err
+ }
+
+ m := config.NewModules()
+ return m, m.Unmarshal(input)
+}
+
+func (w *Worktree) readIndexEntry(path string) (index.Entry, error) {
+ var e index.Entry
+
+ idx, err := w.r.Storer.Index()
+ if err != nil {
+ return e, err
+ }
+
+ for _, e := range idx.Entries {
+ if e.Name == path {
+ return e, nil
+ }
+ }
+
+ return e, fmt.Errorf("unable to find %q entry in the index", path)
+}
+
// Status current status of a Worktree
type Status map[string]*FileStatus
@@ -281,17 +406,25 @@ func readDirAll(filesystem billy.Filesystem) (map[string]billy.FileInfo, error)
}
func doReadDirAll(fs billy.Filesystem, path string, files map[string]billy.FileInfo) error {
- if path == ".git" {
+ if path == defaultDotGitPath {
return nil
}
l, err := fs.ReadDir(path)
if err != nil {
+ if os.IsNotExist(err) {
+ return nil
+ }
+
return err
}
for _, info := range l {
file := fs.Join(path, info.Name())
+ if file == defaultDotGitPath {
+ continue
+ }
+
if !info.IsDir() {
files[file] = info
continue
diff --git a/worktree_test.go b/worktree_test.go
index 8ca3d4f..81d35b1 100644
--- a/worktree_test.go
+++ b/worktree_test.go
@@ -7,6 +7,7 @@ import (
"srcd.works/go-git.v4/plumbing/format/index"
"srcd.works/go-git.v4/plumbing/object"
+ "github.com/src-d/go-git-fixtures"
. "gopkg.in/check.v1"
"srcd.works/go-billy.v1/memfs"
"srcd.works/go-billy.v1/osfs"
@@ -116,7 +117,6 @@ func (s *WorktreeSuite) TestCheckoutIndexOS(c *C) {
}
func (s *WorktreeSuite) TestStatus(c *C) {
-
h, err := s.Repository.Head()
c.Assert(err, IsNil)
@@ -164,3 +164,31 @@ func (s *WorktreeSuite) TestStatusModified(c *C) {
c.Assert(err, IsNil)
c.Assert(status.IsClean(), Equals, false)
}
+
+func (s *WorktreeSuite) TestSubmodule(c *C) {
+ path := fixtures.ByTag("submodule").One().Worktree().Base()
+ r, err := PlainOpen(path)
+ c.Assert(err, IsNil)
+
+ w, err := r.Worktree()
+ c.Assert(err, IsNil)
+
+ m, err := w.Submodule("basic")
+ c.Assert(err, IsNil)
+
+ c.Assert(m.Config().Name, Equals, "basic")
+}
+
+func (s *WorktreeSuite) TestSubmodules(c *C) {
+ path := fixtures.ByTag("submodule").One().Worktree().Base()
+ r, err := PlainOpen(path)
+ c.Assert(err, IsNil)
+
+ w, err := r.Worktree()
+ c.Assert(err, IsNil)
+
+ l, err := w.Submodules()
+ c.Assert(err, IsNil)
+
+ c.Assert(l, HasLen, 2)
+}