Skip to content

Commit b4c392f

Browse files
author
Jay Conrod
authored
go: use "shell" params file format instead of "multiline" (bazel-contrib#2655)
This lets arguments contain newlines. Fixes bazel-contrib#2635
1 parent 781b247 commit b4c392f

File tree

13 files changed

+91
-28
lines changed

13 files changed

+91
-28
lines changed

go/private/context.bzl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def _new_args(go):
128128
def _builder_args(go, command = None):
129129
args = go.actions.args()
130130
args.use_param_file("-param=%s")
131-
args.set_param_file_format("multiline")
131+
args.set_param_file_format("shell")
132132
if command:
133133
args.add(command)
134134
args.add("-sdk", go.sdk.root_file.dirname)
@@ -139,7 +139,7 @@ def _builder_args(go, command = None):
139139
def _tool_args(go):
140140
args = go.actions.args()
141141
args.use_param_file("-param=%s")
142-
args.set_param_file_format("multiline")
142+
args.set_param_file_format("shell")
143143
return args
144144

145145
def _new_library(go, name = None, importpath = None, resolver = None, importable = True, testfilter = None, is_main = False, **kwargs):

go/tools/builders/asm.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import (
3030
// Go rules as an action.
3131
func asm(args []string) error {
3232
// Parse arguments.
33-
args, err := readParamsFiles(args)
33+
args, err := expandParamsFiles(args)
3434
if err != nil {
3535
return err
3636
}

go/tools/builders/builder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func main() {
2828
log.SetFlags(0)
2929
log.SetPrefix("builder: ")
3030

31-
args, err := readParamsFiles(os.Args[1:])
31+
args, err := expandParamsFiles(os.Args[1:])
3232
if err != nil {
3333
log.Fatal(err)
3434
}

go/tools/builders/compile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import (
2929

3030
func compile(args []string) error {
3131
// Parse arguments.
32-
args, err := readParamsFiles(args)
32+
args, err := expandParamsFiles(args)
3333
if err != nil {
3434
return err
3535
}

go/tools/builders/compilepkg.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import (
3333

3434
func compilePkg(args []string) error {
3535
// Parse arguments.
36-
args, err := readParamsFiles(args)
36+
args, err := expandParamsFiles(args)
3737
if err != nil {
3838
return err
3939
}
@@ -446,13 +446,12 @@ func runNogo(ctx context.Context, workDir string, nogoPath string, srcs []string
446446
args = append(args, "-x", outFactsPath)
447447
args = append(args, srcs...)
448448

449-
paramFile := filepath.Join(workDir, "nogo.param")
450-
params := strings.Join(args[1:], "\n")
451-
if err := ioutil.WriteFile(paramFile, []byte(params), 0666); err != nil {
452-
return fmt.Errorf("error writing nogo paramfile: %v", err)
449+
paramsFile := filepath.Join(workDir, "nogo.param")
450+
if err := writeParamsFile(paramsFile, args[1:]); err != nil {
451+
return fmt.Errorf("error writing nogo params file: %v", err)
453452
}
454453

455-
cmd := exec.CommandContext(ctx, args[0], "-param="+paramFile)
454+
cmd := exec.CommandContext(ctx, args[0], "-param="+paramsFile)
456455
out := &bytes.Buffer{}
457456
cmd.Stdout, cmd.Stderr = out, out
458457
if err := cmd.Run(); err != nil {

go/tools/builders/cover.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828
// cover transforms a source file with "go tool cover". It is invoked by the
2929
// Go rules as an action.
3030
func cover(args []string) error {
31-
args, err := readParamsFiles(args)
31+
args, err := expandParamsFiles(args)
3232
if err != nil {
3333
return err
3434
}

go/tools/builders/env.go

Lines changed: 74 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,10 @@ func runAndLogCommand(cmd *exec.Cmd, verbose bool) error {
169169
return nil
170170
}
171171

172-
// readParamsFile looks for arguments in args of the form
172+
// expandParamsFiles looks for arguments in args of the form
173173
// "-param=filename". When it finds these arguments it reads the file "filename"
174-
// and replaces the argument with its content (each argument must be on a
175-
// separate line; blank lines are ignored).
176-
func readParamsFiles(args []string) ([]string, error) {
174+
// and replaces the argument with its content.
175+
func expandParamsFiles(args []string) ([]string, error) {
177176
var paramsIndices []int
178177
for i, arg := range args {
179178
if strings.HasPrefix(arg, "-param=") {
@@ -190,21 +189,86 @@ func readParamsFiles(args []string) ([]string, error) {
190189
last = pi + 1
191190

192191
fileName := args[pi][len("-param="):]
193-
content, err := ioutil.ReadFile(fileName)
192+
fileArgs, err := readParamsFile(fileName)
194193
if err != nil {
195194
return nil, err
196195
}
197-
fileArgs := strings.Split(string(content), "\n")
198-
if len(fileArgs) >= 0 && fileArgs[len(fileArgs)-1] == "" {
199-
// Ignore final empty line.
200-
fileArgs = fileArgs[:len(fileArgs)-1]
201-
}
202196
expandedArgs = append(expandedArgs, fileArgs...)
203197
}
204198
expandedArgs = append(expandedArgs, args[last:]...)
205199
return expandedArgs, nil
206200
}
207201

202+
// readParamsFiles parses a Bazel params file in "shell" format. The file
203+
// should contain one argument per line. Arguments may be quoted with single
204+
// quotes. All characters within quoted strings are interpreted literally
205+
// including newlines and excepting single quotes. Characters outside quoted
206+
// strings may be escaped with a backslash.
207+
func readParamsFile(name string) ([]string, error) {
208+
data, err := ioutil.ReadFile(name)
209+
if err != nil {
210+
return nil, err
211+
}
212+
213+
var args []string
214+
var arg []byte
215+
quote := false
216+
escape := false
217+
for p := 0; p < len(data); p++ {
218+
b := data[p]
219+
switch {
220+
case escape:
221+
arg = append(arg, b)
222+
escape = false
223+
224+
case b == '\'':
225+
quote = !quote
226+
227+
case !quote && b == '\\':
228+
escape = true
229+
230+
case !quote && b == '\n':
231+
args = append(args, string(arg))
232+
arg = arg[:0]
233+
234+
default:
235+
arg = append(arg, b)
236+
}
237+
}
238+
if quote {
239+
return nil, fmt.Errorf("unterminated quote")
240+
}
241+
if escape {
242+
return nil, fmt.Errorf("unterminated escape")
243+
}
244+
if len(arg) > 0 {
245+
args = append(args, string(arg))
246+
}
247+
return args, nil
248+
}
249+
250+
// writeParamsFile formats a list of arguments in Bazel's "shell" format and writes
251+
// it to a file.
252+
func writeParamsFile(path string, args []string) error {
253+
buf := new(bytes.Buffer)
254+
for _, arg := range args {
255+
if !strings.ContainsAny(arg, "'\n\\") {
256+
fmt.Fprintln(buf, arg)
257+
continue
258+
}
259+
buf.WriteByte('\'')
260+
for _, r := range arg {
261+
if r == '\'' {
262+
buf.WriteString(`'\''`)
263+
} else {
264+
buf.WriteRune(r)
265+
}
266+
}
267+
buf.WriteString("'\n")
268+
}
269+
return ioutil.WriteFile(path, buf.Bytes(), 0666)
270+
}
271+
208272
// splitArgs splits a list of command line arguments into two parts: arguments
209273
// that should be interpreted by the builder (before "--"), and arguments
210274
// that should be passed through to the underlying tool (after "--").

go/tools/builders/generate_test_main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ func main() {
175175

176176
func genTestMain(args []string) error {
177177
// Prepare our flags
178-
args, err := readParamsFiles(args)
178+
args, err := expandParamsFiles(args)
179179
if err != nil {
180180
return err
181181
}

go/tools/builders/info.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
)
2525

2626
func run(args []string) error {
27-
args, err := readParamsFiles(args)
27+
args, err := expandParamsFiles(args)
2828
if err != nil {
2929
return err
3030
}

go/tools/builders/link.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131

3232
func link(args []string) error {
3333
// Parse arguments.
34-
args, err := readParamsFiles(args)
34+
args, err := expandParamsFiles(args)
3535
if err != nil {
3636
return err
3737
}

0 commit comments

Comments
 (0)