aboutsummaryrefslogtreecommitdiffstats
path: root/submodule.go
diff options
context:
space:
mode:
authorMáximo Cuadros <mcuadros@gmail.com>2017-02-14 19:26:32 +0100
committerMáximo Cuadros <mcuadros@gmail.com>2017-02-15 09:30:05 +0100
commitd6a6decd1be0515faf36256ce06c58c7d662bbd0 (patch)
treeb91c4f618470c7cf1ef9547b9146d08e30df6204 /submodule.go
parent09110d8e6d1ddb6f6a22867dcedeebd8f2262780 (diff)
downloadgo-git-d6a6decd1be0515faf36256ce06c58c7d662bbd0.tar.gz
submodule update implementation
Diffstat (limited to 'submodule.go')
-rw-r--r--submodule.go128
1 files changed, 110 insertions, 18 deletions
diff --git a/submodule.go b/submodule.go
index 83c28b7..b6cc045 100644
--- a/submodule.go
+++ b/submodule.go
@@ -1,60 +1,141 @@
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 {
- m *config.Submodule
+ initialized bool
+
+ c *config.Submodule
w *Worktree
- // r is the submodule repository
- r *Repository
}
// Config returns the submodule config
func (s *Submodule) Config() *config.Submodule {
- return s.m
+ return s.c
}
// Init initialize the submodule reading the recoreded Entry in the index for
// the given submodule
func (s *Submodule) Init() error {
- e, err := s.w.readIndexEntry(s.m.Path)
+ cfg, err := s.w.r.Storer.Config()
if err != nil {
return err
}
- _, err = s.r.CreateRemote(&config.RemoteConfig{
+ _, 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.m.URL,
+ 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
}
- return s.fetchAndCheckout(e.Hash)
+ 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)
}
-// Update the registered submodule to match what the superproject expects
-func (s *Submodule) Update() error {
- e, err := s.w.readIndexEntry(s.m.Path)
+func (s *Submodule) doRecrusiveUpdate(r *Repository, o *SubmoduleUpdateOptions) error {
+ if o.RecurseSubmodules == NoRecursivity {
+ return nil
+ }
+
+ w, err := r.Worktree()
if err != nil {
return err
}
- return s.fetchAndCheckout(e.Hash)
+ l, err := w.Submodules()
+ if err != nil {
+ return err
+ }
+
+ new := &SubmoduleUpdateOptions{}
+ *new = *o
+ new.RecurseSubmodules--
+ return l.Update(new)
}
-func (s *Submodule) fetchAndCheckout(hash plumbing.Hash) error {
- if err := s.r.Fetch(&FetchOptions{}); err != nil && err != NoErrAlreadyUpToDate {
- return err
+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 := s.r.Worktree()
+ w, err := r.Worktree()
if err != nil {
return err
}
@@ -64,13 +145,13 @@ func (s *Submodule) fetchAndCheckout(hash plumbing.Hash) error {
}
head := plumbing.NewHashReference(plumbing.HEAD, hash)
- return s.r.Storer.SetReference(head)
+ return r.Storer.SetReference(head)
}
// Submodules list of several submodules from the same repository
type Submodules []*Submodule
-// Init initialize the submodule recorded in the index
+// Init initializes the submodules in this list
func (s Submodules) Init() error {
for _, sub := range s {
if err := sub.Init(); err != nil {
@@ -80,3 +161,14 @@ func (s Submodules) Init() error {
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
+}