Skip to content

Commit 6a21040

Browse files
committed
Automatically fetch missing commits from submodules.
1 parent 7ce52a4 commit 6a21040

File tree

1 file changed

+80
-8
lines changed

1 file changed

+80
-8
lines changed

subtrac.go

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import (
44
"fmt"
55
"github.com/pborman/getopt/v2"
66
"gopkg.in/src-d/go-git.v4"
7+
"gopkg.in/src-d/go-git.v4/config"
78
"gopkg.in/src-d/go-git.v4/plumbing"
89
"gopkg.in/src-d/go-git.v4/plumbing/filemode"
910
"gopkg.in/src-d/go-git.v4/plumbing/object"
1011
"log"
1112
"os"
13+
"path/filepath"
1214
"sort"
1315
"strconv"
1416
"strings"
@@ -45,14 +47,16 @@ func (t Trac) String() string {
4547
}
4648

4749
type Cache struct {
48-
repo *git.Repository
49-
tracs map[plumbing.Hash]*Trac
50+
repoDir string
51+
repo *git.Repository
52+
tracs map[plumbing.Hash]*Trac
5053
}
5154

52-
func NewCache(r *git.Repository) *Cache {
55+
func NewCache(rdir string, r *git.Repository) *Cache {
5356
c := Cache{
54-
repo: r,
55-
tracs: make(map[plumbing.Hash]*Trac),
57+
repoDir: rdir,
58+
repo: r,
59+
tracs: make(map[plumbing.Hash]*Trac),
5660
}
5761
return &c
5862
}
@@ -138,17 +142,85 @@ func commitPath(path string, sub int) string {
138142
return fmt.Sprintf("%s~%d", path[:ix], v+1)
139143
}
140144

145+
func (c *Cache) tryFetchFromSubmodules(path string, hash plumbing.Hash) error {
146+
debugf("Searching submodules for: %.10v %v\n", hash, path)
147+
wt, err := c.repo.Worktree()
148+
if err != nil {
149+
return fmt.Errorf("git worktree: %v", err)
150+
}
151+
subs, err := wt.Submodules()
152+
if err != nil {
153+
return fmt.Errorf("git submodules: %v", subs)
154+
}
155+
for _, sub := range subs {
156+
subpath := sub.Config().Path
157+
subr, err := sub.Repository()
158+
if err != nil {
159+
return fmt.Errorf("submodule %v: %v", subpath, err)
160+
}
161+
_, err = subr.CommitObject(hash)
162+
if err != nil {
163+
debugf(" ...not in %v\n", subpath)
164+
continue
165+
}
166+
brname := fmt.Sprintf("subtrac-tmp-%v", hash)
167+
brrefname := plumbing.NewBranchReferenceName(brname)
168+
ref := plumbing.NewHashReference(brrefname, hash)
169+
err = subr.Storer.SetReference(ref)
170+
defer subr.Storer.RemoveReference(brrefname)
171+
if err != nil {
172+
return fmt.Errorf("submodule %v: create %v: %v", subpath, ref, err)
173+
}
174+
remotename := fmt.Sprintf("%v/.git/modules/%v",
175+
c.repoDir, sub.Config().Name)
176+
absremotename, err := filepath.Abs(remotename)
177+
if err != nil {
178+
return fmt.Errorf("AbsPath(%v): %v", remotename, err)
179+
}
180+
remote, err := c.repo.CreateRemoteAnonymous(&config.RemoteConfig{
181+
Name: "anonymous",
182+
URLs: []string{absremotename},
183+
})
184+
if err != nil {
185+
return fmt.Errorf("submodule %v: CreateRemote: %v", absremotename, err)
186+
}
187+
err = remote.Fetch(&git.FetchOptions{
188+
RemoteName: "anonymous",
189+
RefSpecs: []config.RefSpec{
190+
config.RefSpec(brrefname + ":TRAC_FETCH_HEAD"),
191+
},
192+
})
193+
if err != nil {
194+
return fmt.Errorf("submodule %v: fetch: %v", absremotename, err)
195+
}
196+
// Fetch worked!
197+
err = subr.Storer.RemoveReference(brrefname)
198+
if err != nil {
199+
return fmt.Errorf("submodule %v: remove %v: %v", subpath, ref, err)
200+
}
201+
return nil
202+
}
203+
return fmt.Errorf("%v: %.10v not found.", path, hash)
204+
}
205+
141206
func (c *Cache) tracTree(path string, tree *object.Tree) (*Trac, error) {
142207
trac := c.tracs[tree.Hash]
143208
if trac != nil {
144209
return trac, nil
145210
}
146211
for _, e := range tree.Entries {
147212
if e.Mode == filemode.Submodule {
148-
sc, err := c.repo.CommitObject(e.Hash)
149213
subpath := fmt.Sprintf("%s%s@%.10v", path, e.Name, e.Hash)
214+
sc, err := c.repo.CommitObject(e.Hash)
215+
if err != nil {
216+
err = c.tryFetchFromSubmodules(subpath, e.Hash)
217+
if err != nil {
218+
return nil, fmt.Errorf("%v (maybe fetch it manually?)", err)
219+
}
220+
}
221+
sc, err = c.repo.CommitObject(e.Hash)
150222
if err != nil {
151-
return nil, fmt.Errorf("%v: %v (maybe fetch it?)",
223+
return nil, fmt.Errorf("%v: %v",
152224
subpath, err)
153225
}
154226
_, err = c.tracCommit(subpath, sc)
@@ -214,7 +286,7 @@ func main() {
214286
if len(args) != 2 {
215287
usagef("command cid takes exactly 1 argument")
216288
}
217-
c := NewCache(r)
289+
c := NewCache(*repodir, r)
218290
refname := args[1]
219291
_, err = c.tracByRef(refname)
220292
if err != nil {

0 commit comments

Comments
 (0)