Skip to content

Commit 9861e8b

Browse files
committed
cmd/{cover,go}: avoid use of os.PathListSeparator in cmd/cover flag
Rework the mechanism for passing a list of output files from cmd/go to cmd/cover when running new-style package-scope coverage instrumentation (-pkgcfg mode). The old scheme passed a single string with all output files joined together with os.PathListSeparator, but this scheme is not viable on plan9, where strings containing the separator character are not permitted when running exec.Command(). Instead, switch cmd/cover to use an arguments file (a file containing a list of names) to specify names of instrumented output files. This fixes the cmd/cover test failures on the plan9 builders. Updates #51430. Change-Id: I919f5e0a79500e28648fb9177225a9b938e4fdee Reviewed-on: https://go-review.googlesource.com/c/go/+/436675 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Bryan Mills <[email protected]> Run-TryBot: Than McIntosh <[email protected]>
1 parent e22af33 commit 9861e8b

File tree

3 files changed

+65
-26
lines changed

3 files changed

+65
-26
lines changed

src/cmd/cover/cfg_test.go

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,29 @@ func writePkgConfig(t *testing.T, outdir, tag, ppath, pname string, gran string)
3939
return incfg
4040
}
4141

42+
func writeOutFileList(t *testing.T, infiles []string, outdir, tag string) ([]string, string) {
43+
outfilelist := filepath.Join(outdir, tag+"outfilelist.txt")
44+
var sb strings.Builder
45+
outfs := []string{}
46+
for _, inf := range infiles {
47+
base := filepath.Base(inf)
48+
of := filepath.Join(outdir, tag+".cov."+base)
49+
outfs = append(outfs, of)
50+
fmt.Fprintf(&sb, "%s\n", of)
51+
}
52+
if err := os.WriteFile(outfilelist, []byte(sb.String()), 0666); err != nil {
53+
t.Fatalf("writing %s: %v", outfilelist, err)
54+
}
55+
return outfs, outfilelist
56+
}
57+
4258
func runPkgCover(t *testing.T, outdir string, tag string, incfg string, mode string, infiles []string, errExpected bool) ([]string, string, string) {
4359
// Write the pkgcfg file.
4460
outcfg := filepath.Join(outdir, "outcfg.txt")
4561

4662
// Form up the arguments and run the tool.
47-
outfiles := []string{}
48-
for _, inf := range infiles {
49-
base := filepath.Base(inf)
50-
outfiles = append(outfiles, filepath.Join(outdir, "cov."+base))
51-
}
52-
ofs := strings.Join(outfiles, string(os.PathListSeparator))
53-
args := []string{"-pkgcfg", incfg, "-mode=" + mode, "-var=var" + tag, "-o", ofs}
63+
outfiles, outfilelist := writeOutFileList(t, infiles, outdir, tag)
64+
args := []string{"-pkgcfg", incfg, "-mode=" + mode, "-var=var" + tag, "-outfilelist", outfilelist}
5465
args = append(args, infiles...)
5566
cmd := exec.Command(testcover, args...)
5667
if errExpected {

src/cmd/cover/cover.go

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,12 @@ Display coverage percentages to stdout for each function:
4444
Finally, to generate modified source code with coverage annotations
4545
for a package (what go test -cover does):
4646
go tool cover -mode=set -var=CoverageVariableName \
47-
-pkgcfg=<config> -o=<outputfiles> file1.go ... fileN.go
47+
-pkgcfg=<config> -outfilelist=<file> file1.go ... fileN.go
4848
4949
where -pkgcfg points to a file containing the package path,
50-
package name, module path, and related info from "go build".
50+
package name, module path, and related info from "go build",
51+
and -outfilelist points to a file containing the filenames
52+
of the instrumented output files (one per input file).
5153
See https://pkg.go.dev/internal/coverage#CoverPkgConfig for
5254
more on the package config.
5355
`
@@ -61,16 +63,19 @@ func usage() {
6163
}
6264

6365
var (
64-
mode = flag.String("mode", "", "coverage mode: set, count, atomic")
65-
varVar = flag.String("var", "GoCover", "name of coverage variable to generate")
66-
output = flag.String("o", "", fmt.Sprintf("file(s) for output (if multiple inputs, this is a %q-separated list); defaults to stdout if omitted.", string(os.PathListSeparator)))
67-
htmlOut = flag.String("html", "", "generate HTML representation of coverage profile")
68-
funcOut = flag.String("func", "", "output coverage profile information for each function")
69-
pkgcfg = flag.String("pkgcfg", "", "enable full-package instrumentation mode using params from specified config file")
66+
mode = flag.String("mode", "", "coverage mode: set, count, atomic")
67+
varVar = flag.String("var", "GoCover", "name of coverage variable to generate")
68+
output = flag.String("o", "", "file for output")
69+
outfilelist = flag.String("outfilelist", "", "file containing list of output files (one per line) if -pkgcfg is in use")
70+
htmlOut = flag.String("html", "", "generate HTML representation of coverage profile")
71+
funcOut = flag.String("func", "", "output coverage profile information for each function")
72+
pkgcfg = flag.String("pkgcfg", "", "enable full-package instrumentation mode using params from specified config file")
7073
)
7174

7275
var pkgconfig coverage.CoverPkgConfig
7376

77+
var outputfiles []string // set whe -pkgcfg is in use
78+
7479
var profile string // The profile to read; the value of -html or -func
7580

7681
var counterStmt func(*File, string) string
@@ -153,18 +158,26 @@ func parseFlags() error {
153158
return fmt.Errorf("missing source file(s)")
154159
} else {
155160
if *pkgcfg != "" {
156-
if *output == "" {
157-
return fmt.Errorf("supply output file(s) with -o")
161+
if *output != "" {
162+
return fmt.Errorf("please use '-outfilelist' flag instead of '-o'")
163+
}
164+
var err error
165+
if outputfiles, err = readOutFileList(*outfilelist); err != nil {
166+
return err
158167
}
159168
numInputs := len(flag.Args())
160-
numOutputs := len(strings.Split(*output, string(os.PathListSeparator)))
169+
numOutputs := len(outputfiles)
161170
if numOutputs != numInputs {
162171
return fmt.Errorf("number of output files (%d) not equal to number of input files (%d)", numOutputs, numInputs)
163172
}
164173
if err := readPackageConfig(*pkgcfg); err != nil {
165174
return err
166175
}
167176
return nil
177+
} else {
178+
if *outfilelist != "" {
179+
return fmt.Errorf("'-outfilelist' flag applicable only when -pkgcfg used")
180+
}
168181
}
169182
if flag.NArg() == 1 {
170183
return nil
@@ -176,6 +189,14 @@ func parseFlags() error {
176189
return fmt.Errorf("too many arguments")
177190
}
178191

192+
func readOutFileList(path string) ([]string, error) {
193+
data, err := ioutil.ReadFile(path)
194+
if err != nil {
195+
return nil, fmt.Errorf("error reading -outfilelist file %q: %v", path, err)
196+
}
197+
return strings.Split(strings.TrimSpace(string(data)), "\n"), nil
198+
}
199+
179200
func readPackageConfig(path string) error {
180201
data, err := ioutil.ReadFile(path)
181202
if err != nil {
@@ -495,7 +516,6 @@ func annotate(names []string) {
495516
}
496517
}
497518
// TODO: process files in parallel here if it matters.
498-
outfiles := strings.Split(*output, string(os.PathListSeparator))
499519
for k, name := range names {
500520
last := false
501521
if k == len(names)-1 {
@@ -506,7 +526,7 @@ func annotate(names []string) {
506526
isStdout := true
507527
if *pkgcfg != "" {
508528
var err error
509-
fd, err = os.Create(outfiles[k])
529+
fd, err = os.Create(outputfiles[k])
510530
if err != nil {
511531
log.Fatalf("cover: %s", err)
512532
}

src/cmd/go/internal/work/exec.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,8 @@ OverlayLoop:
691691
panic("covermode should be set at this point")
692692
}
693693
pkgcfg := a.Objdir + "pkgcfg.txt"
694-
if err := b.cover2(a, pkgcfg, infiles, outfiles, coverVar, mode); err != nil {
694+
covoutfiles := a.Objdir + "coveroutfiles.txt"
695+
if err := b.cover2(a, pkgcfg, covoutfiles, infiles, outfiles, coverVar, mode); err != nil {
695696
return err
696697
}
697698
} else {
@@ -1943,22 +1944,22 @@ func (b *Builder) cover(a *Action, dst, src string, varName string) error {
19431944
// cover2 runs, in effect,
19441945
//
19451946
// go tool cover -pkgcfg=<config file> -mode=b.coverMode -var="varName" -o <outfiles> <infiles>
1946-
func (b *Builder) cover2(a *Action, pkgcfg string, infiles, outfiles []string, varName string, mode string) error {
1947-
if err := b.writeCoverPkgCfg(a, pkgcfg); err != nil {
1947+
func (b *Builder) cover2(a *Action, pkgcfg, covoutputs string, infiles, outfiles []string, varName string, mode string) error {
1948+
if err := b.writeCoverPkgInputs(a, pkgcfg, covoutputs, outfiles); err != nil {
19481949
return err
19491950
}
19501951
args := []string{base.Tool("cover"),
19511952
"-pkgcfg", pkgcfg,
19521953
"-mode", mode,
19531954
"-var", varName,
1954-
"-o", strings.Join(outfiles, string(os.PathListSeparator)),
1955+
"-outfilelist", covoutputs,
19551956
}
19561957
args = append(args, infiles...)
19571958
return b.run(a, a.Objdir, "cover "+a.Package.ImportPath, nil,
19581959
cfg.BuildToolexec, args)
19591960
}
19601961

1961-
func (b *Builder) writeCoverPkgCfg(a *Action, file string) error {
1962+
func (b *Builder) writeCoverPkgInputs(a *Action, pconfigfile string, covoutputsfile string, outfiles []string) error {
19621963
p := a.Package
19631964
p.Internal.CoverageCfg = a.Objdir + "coveragecfg"
19641965
pcfg := coverage.CoverPkgConfig{
@@ -1978,7 +1979,14 @@ func (b *Builder) writeCoverPkgCfg(a *Action, file string) error {
19781979
if err != nil {
19791980
return err
19801981
}
1981-
return b.writeFile(file, data)
1982+
if err := b.writeFile(pconfigfile, data); err != nil {
1983+
return err
1984+
}
1985+
var sb strings.Builder
1986+
for i := range outfiles {
1987+
fmt.Fprintf(&sb, "%s\n", outfiles[i])
1988+
}
1989+
return b.writeFile(covoutputsfile, []byte(sb.String()))
19821990
}
19831991

19841992
var objectMagic = [][]byte{

0 commit comments

Comments
 (0)