Skip to content
This repository was archived by the owner on Jun 27, 2023. It is now read-only.

Commit 44f7022

Browse files
authored
Merge pull request #169 from golang/iss29
Support internal directories
2 parents c5c5a8f + 9f324bb commit 44f7022

File tree

7 files changed

+328
-59
lines changed

7 files changed

+328
-59
lines changed

mockgen/reflect.go

+89-58
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
"bytes"
2121
"encoding/gob"
2222
"flag"
23-
"io"
23+
"go/build"
2424
"io/ioutil"
2525
"os"
2626
"os/exec"
@@ -32,69 +32,27 @@ import (
3232
)
3333

3434
var (
35-
progOnly = flag.Bool("prog_only", false, "(reflect mode) Only generate the reflection program; write it to stdout.")
35+
progOnly = flag.Bool("prog_only", false, "(reflect mode) Only generate the reflection program; write it to stdout and exit.")
3636
execOnly = flag.String("exec_only", "", "(reflect mode) If set, execute this reflection program.")
3737
buildFlags = flag.String("build_flags", "", "(reflect mode) Additional flags for go build.")
3838
)
3939

40-
func Reflect(importPath string, symbols []string) (*model.Package, error) {
41-
// TODO: sanity check arguments
42-
43-
progPath := *execOnly
44-
if *execOnly == "" {
45-
pwd, _ := os.Getwd()
46-
// We use TempDir instead of TempFile so we can control the filename.
47-
// Try to place the TempDir under pwd, so that if there is some package in
48-
// vendor directory, 'go build' can also load/mock it.
49-
tmpDir, err := ioutil.TempDir(pwd, "gomock_reflect_")
50-
if err != nil {
51-
return nil, err
52-
}
53-
defer func() { os.RemoveAll(tmpDir) }()
54-
const progSource = "prog.go"
55-
var progBinary = "prog.bin"
56-
if runtime.GOOS == "windows" {
57-
// Windows won't execute a program unless it has a ".exe" suffix.
58-
progBinary += ".exe"
59-
}
60-
61-
// Generate program.
62-
var program bytes.Buffer
63-
data := reflectData{
64-
ImportPath: importPath,
65-
Symbols: symbols,
66-
}
67-
if err := reflectProgram.Execute(&program, &data); err != nil {
68-
return nil, err
69-
}
70-
if *progOnly {
71-
io.Copy(os.Stdout, &program)
72-
os.Exit(0)
73-
}
74-
if err := ioutil.WriteFile(filepath.Join(tmpDir, progSource), program.Bytes(), 0600); err != nil {
75-
return nil, err
76-
}
77-
78-
cmdArgs := []string{}
79-
cmdArgs = append(cmdArgs, "build")
80-
if *buildFlags != "" {
81-
cmdArgs = append(cmdArgs, *buildFlags)
82-
}
83-
cmdArgs = append(cmdArgs, "-o", progBinary, progSource)
84-
85-
// Build the program.
86-
cmd := exec.Command("go", cmdArgs...)
87-
cmd.Dir = tmpDir
88-
cmd.Stdout = os.Stdout
89-
cmd.Stderr = os.Stderr
90-
if err := cmd.Run(); err != nil {
91-
return nil, err
92-
}
93-
progPath = filepath.Join(tmpDir, progBinary)
40+
func writeProgram(importPath string, symbols []string) ([]byte, error) {
41+
var program bytes.Buffer
42+
data := reflectData{
43+
ImportPath: importPath,
44+
Symbols: symbols,
45+
}
46+
if err := reflectProgram.Execute(&program, &data); err != nil {
47+
return nil, err
9448
}
49+
return program.Bytes(), nil
50+
}
9551

96-
// Run it.
97-
cmd := exec.Command(progPath)
52+
// run the given command and parse the output as a model.Package.
53+
func run(command string) (*model.Package, error) {
54+
// Run the program.
55+
cmd := exec.Command(command)
9856
var stdout bytes.Buffer
9957
cmd.Stdout = &stdout
10058
cmd.Stderr = os.Stderr
@@ -110,6 +68,79 @@ func Reflect(importPath string, symbols []string) (*model.Package, error) {
11068
return &pkg, nil
11169
}
11270

71+
// runInDir writes the given program into the given dir, runs it there, and
72+
// parses the output as a model.Package.
73+
func runInDir(program []byte, dir string) (*model.Package, error) {
74+
// We use TempDir instead of TempFile so we can control the filename.
75+
tmpDir, err := ioutil.TempDir(dir, "gomock_reflect_")
76+
if err != nil {
77+
return nil, err
78+
}
79+
defer func() { os.RemoveAll(tmpDir) }()
80+
const progSource = "prog.go"
81+
var progBinary = "prog.bin"
82+
if runtime.GOOS == "windows" {
83+
// Windows won't execute a program unless it has a ".exe" suffix.
84+
progBinary += ".exe"
85+
}
86+
87+
if err := ioutil.WriteFile(filepath.Join(tmpDir, progSource), program, 0600); err != nil {
88+
return nil, err
89+
}
90+
91+
cmdArgs := []string{}
92+
cmdArgs = append(cmdArgs, "build")
93+
if *buildFlags != "" {
94+
cmdArgs = append(cmdArgs, *buildFlags)
95+
}
96+
cmdArgs = append(cmdArgs, "-o", progBinary, progSource)
97+
98+
// Build the program.
99+
cmd := exec.Command("go", cmdArgs...)
100+
cmd.Dir = tmpDir
101+
cmd.Stdout = os.Stdout
102+
cmd.Stderr = os.Stderr
103+
if err := cmd.Run(); err != nil {
104+
return nil, err
105+
}
106+
return run(filepath.Join(tmpDir, progBinary))
107+
}
108+
109+
func Reflect(importPath string, symbols []string) (*model.Package, error) {
110+
// TODO: sanity check arguments
111+
112+
if *execOnly != "" {
113+
return run(*execOnly)
114+
}
115+
116+
program, err := writeProgram(importPath, symbols)
117+
if err != nil {
118+
return nil, err
119+
}
120+
121+
if *progOnly {
122+
os.Stdout.Write(program)
123+
os.Exit(0)
124+
}
125+
126+
wd, _ := os.Getwd()
127+
128+
// Try to run the program in the same directory as the input package.
129+
if p, err := build.Import(importPath, wd, build.FindOnly); err == nil {
130+
dir := p.Dir
131+
if p, err := runInDir(program, dir); err == nil {
132+
return p, nil
133+
}
134+
}
135+
136+
// Since that didn't work, try to run it in the current working directory.
137+
if p, err := runInDir(program, wd); err == nil {
138+
return p, nil
139+
}
140+
// Since that didn't work, try to run it in a standard temp directory.
141+
return runInDir(program, "")
142+
}
143+
113144
type reflectData struct {
114145
ImportPath string
115146
Symbols []string
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
//go:generate mockgen -destination subdir/internal/pkg/reflect_output/mock.go github.com/golang/mock/mockgen/tests/internal_pkg/subdir/internal/pkg Intf
2+
//go:generate mockgen -source subdir/internal/pkg/input.go -destination subdir/internal/pkg/source_output/mock.go
3+
package test
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package pkg
2+
3+
type Arg interface {
4+
Foo() int
5+
}
6+
7+
type Intf interface {
8+
F() Arg
9+
}

mockgen/tests/internal_pkg/subdir/internal/pkg/reflect_output/mock.go

+46
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mockgen/tests/internal_pkg/subdir/internal/pkg/source_output/mock.go

+81
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mockgen/tests/vendor_pkg/doc.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
package vendor_pkg
22

3-
//go:generate mockgen a Ifc
3+
//go:generate mockgen -destination mock.go -package vendor_pkg a Ifc

0 commit comments

Comments
 (0)