Skip to content
This repository was archived by the owner on Sep 9, 2020. It is now read-only.

Commit e7d68db

Browse files
committed
gps: export content of git submodules
The "git checkout-index" command is unaware of git submodules, therefore their content was missed when exporting files. With "git submodule foreach" the same operation (read-tree + checkout-index) can also be done for all submodules, recursively. The downside is that "foreach" invokes a shell command with certain variables set. To achieve the desired functionality, we have to rely on POSIX shell support. OTOH, the command seems to get embedded by git in a larger shell script because error messages when there are syntax errors show that the command gets invoked via `eval`, so git already depends on a POSIX shell.
1 parent 75ea93f commit e7d68db

File tree

10 files changed

+165
-34
lines changed

10 files changed

+165
-34
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ IMPROVEMENTS:
2727
* Hash digests of vendor contents are now stored in `Gopkg.lock`, and the contents of vendor are only rewritten on change or hash mismatch ([#1912](https://github.com/golang/dep/pull/1912)).
2828
* Don't exclude `Godeps` folder ([#1822](https://github.com/golang/dep/issues/1822)).
2929
* Add project-package relationship graph support in graphviz ([#1588](https://github.com/golang/dep/pull/1588)).
30+
* Export the content of git submodules to the vendor directory ([#1909](https://github.com/golang/dep/pull/1909)).
3031

3132
WIP:
3233
* Enable importing external configuration from dependencies during init (#1277). This is feature flagged and disabled by default.

cmd/dep/integration_test.go

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"strings"
1616
"testing"
1717

18+
"github.com/golang/dep"
1819
"github.com/golang/dep/internal/fs"
1920
"github.com/golang/dep/internal/test"
2021
"github.com/golang/dep/internal/test/integration"
@@ -210,45 +211,60 @@ func testIntegration(name, relPath, wd string, run integration.RunFunc) func(t *
210211
testCase.CompareOutput(testProj.GetStdout())
211212
}
212213

214+
// Determine how the test case specifies the expected
215+
// content: either it lists just some projects, or it
216+
// provides a complete reference directory.
217+
reference := len(testCase.VendorFinal) == 1 && testCase.VendorFinal[0] == "compare"
218+
213219
// Check vendor paths
214220
testProj.CompareImportPaths()
215-
testCase.CompareVendorPaths(testProj.GetVendorPaths())
221+
if !reference {
222+
testCase.CompareVendorPaths(testProj.GetVendorPaths())
223+
}
216224

217-
if *test.UpdateGolden {
218-
// Update all files in the 'final' directory, removing those which
219-
// no longer should exist.
220-
if err := os.RemoveAll(testCase.FinalPath()); err != nil {
221-
t.Fatalf("error removing 'final' directory: %s", err)
222-
}
223-
if err := fs.CopyTree(testCase.FinalPath(), testProj.ProjPath()); err != nil {
224-
t.Fatalf("error copying into 'final' directory: %s", err)
225-
}
226-
} else {
227-
// Compare all files from either of the two trees.
228-
files := make(map[string]bool)
229-
findFiles := func(dir string) error {
230-
return filepath.Walk(dir,
231-
func(path string, info os.FileInfo, err error) error {
232-
if err != nil {
233-
return err
234-
}
235-
if dir == path {
225+
if reference {
226+
// Check all files.
227+
if *test.UpdateGolden {
228+
// Update all files in the 'final' directory, removing those which
229+
// no longer should exist.
230+
if err := os.RemoveAll(testCase.FinalPath()); err != nil {
231+
t.Fatalf("error removing 'final' directory: %s", err)
232+
}
233+
if err := fs.CopyTree(testCase.FinalPath(), testProj.ProjPath()); err != nil {
234+
t.Fatalf("error copying into 'final' directory: %s", err)
235+
}
236+
} else {
237+
// Compare all files from either of the two trees.
238+
files := make(map[string]bool)
239+
findFiles := func(dir string) error {
240+
return filepath.Walk(dir,
241+
func(path string, info os.FileInfo, err error) error {
242+
if err != nil {
243+
return err
244+
}
245+
if dir == path {
246+
return nil
247+
}
248+
if !info.IsDir() {
249+
localpath := path[len(dir)+1:]
250+
files[localpath] = true
251+
}
236252
return nil
237-
}
238-
if !info.IsDir() {
239-
localpath := path[len(dir)+1:]
240-
files[localpath] = true
241-
}
242-
return nil
243-
})
244-
}
245-
findFiles(testCase.FinalPath())
246-
findFiles(testProj.ProjPath())
247-
248-
for localpath, _ := range files {
249-
t.Logf("comparing %s", localpath)
250-
testCase.CompareFile(localpath, testProj.ProjPath(localpath))
253+
})
254+
}
255+
findFiles(testCase.FinalPath())
256+
findFiles(testProj.ProjPath())
257+
258+
t.Logf("checking against %s", testCase.FinalPath())
259+
for localpath, _ := range files {
260+
t.Logf("comparing %s", localpath)
261+
testCase.CompareFile(localpath, testProj.ProjPath(localpath))
262+
}
251263
}
264+
} else {
265+
// Check final manifest and lock
266+
testCase.CompareFile(dep.ManifestName, testProj.ProjPath(dep.ManifestName))
267+
testCase.CompareFile(dep.LockName, testProj.ProjPath(dep.LockName))
252268
}
253269
}
254270
}

cmd/dep/testdata/harness_tests/ensure/submodules/case1/final/Gopkg.lock

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Gopkg.toml example
2+
#
3+
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
4+
# for detailed Gopkg.toml documentation.
5+
#
6+
# required = ["github.com/user/thing/cmd/thing"]
7+
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
8+
#
9+
# [[constraint]]
10+
# name = "github.com/user/project"
11+
# version = "1.0.0"
12+
#
13+
# [[constraint]]
14+
# name = "github.com/user/project2"
15+
# branch = "dev"
16+
# source = "github.com/myfork/project2"
17+
#
18+
# [[override]]
19+
# name = "github.com/x/y"
20+
# version = "2.4.0"
21+
#
22+
# [prune]
23+
# non-go = false
24+
# go-tests = true
25+
# unused-packages = true
26+
27+
28+
[[constraint]]
29+
branch = "master"
30+
name = "github.com/pohly/deptestmodules"
31+
32+
[prune]
33+
go-tests = true
34+
unused-packages = true
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package main
2+
3+
import (
4+
_ "github.com/pohly/deptestmodules/pkg/foo"
5+
)
6+
7+
func main() {
8+
}

cmd/dep/testdata/harness_tests/ensure/submodules/case1/final/vendor/github.com/pohly/deptestmodules/pkg/foo/foo.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package main
2+
3+
import (
4+
_ "github.com/pohly/deptestmodules/pkg/foo"
5+
)
6+
7+
func main() {
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"commands": [
3+
["init"],
4+
["ensure"]
5+
],
6+
"vendor-final": [
7+
"compare"
8+
]
9+
}

gps/vcs_source.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,34 @@ func (s *gitSource) exportRevisionTo(ctx context.Context, rev Revision, to strin
203203
}
204204
}
205205

206+
// Now do the same for any submodule, using a shell command that "git submodule"
207+
// iterates over.
208+
{
209+
cmd := commandContext(ctx, "git", "submodule", "foreach", "--recursive",
210+
// The command gets called in the working tree
211+
// of the git submodule. The .git is a text
212+
// file which contains a relative link to the
213+
// git directory. We need to follow that and
214+
// there do the same "git read-tree + git
215+
// checkout-index" with a temporary index as
216+
// for the main repo.
217+
//
218+
// $toplevel is our initial root directory
219+
// plus any intermediate git repo (i.e. if
220+
// root contains "foo" and "foo" contains
221+
// "bar", then we first get called with
222+
// "<root>" when exporting "foo" and then with
223+
// "<root>/foo" for bar. By stripping our root
224+
// directory we get a relative path that we can
225+
// append to the target directory.
226+
"(cd $(grep gitdir .git | sed -e 's;gitdir: *;;' .git) && mv index origindex && trap 'mv origindex index' EXIT && git read-tree \"$sha1\" && git checkout-index -a --prefix=\""+to+"$(echo \"$toplevel\" | sed -e 's;"+r.LocalPath()+";;')/$path/\")",
227+
)
228+
cmd.SetDir(r.LocalPath())
229+
if out, err := cmd.CombinedOutput(); err != nil {
230+
return errors.Wrap(err, string(out))
231+
}
232+
}
233+
206234
return nil
207235
}
208236

internal/fs/fs.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,9 @@ func volumeName(path string) (v string) {
698698
func CopyTree(dest, src string) error {
699699
return filepath.Walk(src,
700700
func(path string, info os.FileInfo, err error) error {
701+
if err != nil {
702+
return nil
703+
}
701704
var localpath string
702705
if path != src {
703706
localpath = path[len(src)+1:]

0 commit comments

Comments
 (0)