xref: /aosp_15_r20/external/bazelbuild-rules_go/go/tools/builders/flags.go (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
1*9bb1b549SSpandan Das// Copyright 2017 The Bazel Authors. All rights reserved.
2*9bb1b549SSpandan Das//
3*9bb1b549SSpandan Das// Licensed under the Apache License, Version 2.0 (the "License");
4*9bb1b549SSpandan Das// you may not use this file except in compliance with the License.
5*9bb1b549SSpandan Das// You may obtain a copy of the License at
6*9bb1b549SSpandan Das//
7*9bb1b549SSpandan Das//    http://www.apache.org/licenses/LICENSE-2.0
8*9bb1b549SSpandan Das//
9*9bb1b549SSpandan Das// Unless required by applicable law or agreed to in writing, software
10*9bb1b549SSpandan Das// distributed under the License is distributed on an "AS IS" BASIS,
11*9bb1b549SSpandan Das// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9bb1b549SSpandan Das// See the License for the specific language governing permissions and
13*9bb1b549SSpandan Das// limitations under the License.
14*9bb1b549SSpandan Das
15*9bb1b549SSpandan Daspackage main
16*9bb1b549SSpandan Das
17*9bb1b549SSpandan Dasimport (
18*9bb1b549SSpandan Das	"errors"
19*9bb1b549SSpandan Das	"fmt"
20*9bb1b549SSpandan Das	"go/build"
21*9bb1b549SSpandan Das	"strings"
22*9bb1b549SSpandan Das	"unicode"
23*9bb1b549SSpandan Das)
24*9bb1b549SSpandan Das
25*9bb1b549SSpandan Das// multiFlag allows repeated string flags to be collected into a slice
26*9bb1b549SSpandan Dastype multiFlag []string
27*9bb1b549SSpandan Das
28*9bb1b549SSpandan Dasfunc (m *multiFlag) String() string {
29*9bb1b549SSpandan Das	if m == nil || len(*m) == 0 {
30*9bb1b549SSpandan Das		return ""
31*9bb1b549SSpandan Das	}
32*9bb1b549SSpandan Das	return fmt.Sprint(*m)
33*9bb1b549SSpandan Das}
34*9bb1b549SSpandan Das
35*9bb1b549SSpandan Dasfunc (m *multiFlag) Set(v string) error {
36*9bb1b549SSpandan Das	(*m) = append(*m, v)
37*9bb1b549SSpandan Das	return nil
38*9bb1b549SSpandan Das}
39*9bb1b549SSpandan Das
40*9bb1b549SSpandan Das// quoteMultiFlag allows repeated string flags to be collected into a slice.
41*9bb1b549SSpandan Das// Flags are split on spaces. Single quotes are removed, and spaces within
42*9bb1b549SSpandan Das// quotes are removed. Literal quotes may be escaped with a backslash.
43*9bb1b549SSpandan Dastype quoteMultiFlag []string
44*9bb1b549SSpandan Das
45*9bb1b549SSpandan Dasfunc (m *quoteMultiFlag) String() string {
46*9bb1b549SSpandan Das	if m == nil || len(*m) == 0 {
47*9bb1b549SSpandan Das		return ""
48*9bb1b549SSpandan Das	}
49*9bb1b549SSpandan Das	return fmt.Sprint(*m)
50*9bb1b549SSpandan Das}
51*9bb1b549SSpandan Das
52*9bb1b549SSpandan Dasfunc (m *quoteMultiFlag) Set(v string) error {
53*9bb1b549SSpandan Das	fs, err := splitQuoted(v)
54*9bb1b549SSpandan Das	if err != nil {
55*9bb1b549SSpandan Das		return err
56*9bb1b549SSpandan Das	}
57*9bb1b549SSpandan Das	*m = append(*m, fs...)
58*9bb1b549SSpandan Das	return nil
59*9bb1b549SSpandan Das}
60*9bb1b549SSpandan Das
61*9bb1b549SSpandan Das// splitQuoted splits the string s around each instance of one or more consecutive
62*9bb1b549SSpandan Das// white space characters while taking into account quotes and escaping, and
63*9bb1b549SSpandan Das// returns an array of substrings of s or an empty list if s contains only white space.
64*9bb1b549SSpandan Das// Single quotes and double quotes are recognized to prevent splitting within the
65*9bb1b549SSpandan Das// quoted region, and are removed from the resulting substrings. If a quote in s
66*9bb1b549SSpandan Das// isn't closed err will be set and r will have the unclosed argument as the
67*9bb1b549SSpandan Das// last element. The backslash is used for escaping.
68*9bb1b549SSpandan Das//
69*9bb1b549SSpandan Das// For example, the following string:
70*9bb1b549SSpandan Das//
71*9bb1b549SSpandan Das//     a b:"c d" 'e''f'  "g\""
72*9bb1b549SSpandan Das//
73*9bb1b549SSpandan Das// Would be parsed as:
74*9bb1b549SSpandan Das//
75*9bb1b549SSpandan Das//     []string{"a", "b:c d", "ef", `g"`}
76*9bb1b549SSpandan Das//
77*9bb1b549SSpandan Das// Copied from go/build.splitQuoted. Also in Gazelle (where tests are).
78*9bb1b549SSpandan Dasfunc splitQuoted(s string) (r []string, err error) {
79*9bb1b549SSpandan Das	var args []string
80*9bb1b549SSpandan Das	arg := make([]rune, len(s))
81*9bb1b549SSpandan Das	escaped := false
82*9bb1b549SSpandan Das	quoted := false
83*9bb1b549SSpandan Das	quote := '\x00'
84*9bb1b549SSpandan Das	i := 0
85*9bb1b549SSpandan Das	for _, rune := range s {
86*9bb1b549SSpandan Das		switch {
87*9bb1b549SSpandan Das		case escaped:
88*9bb1b549SSpandan Das			escaped = false
89*9bb1b549SSpandan Das		case rune == '\\':
90*9bb1b549SSpandan Das			escaped = true
91*9bb1b549SSpandan Das			continue
92*9bb1b549SSpandan Das		case quote != '\x00':
93*9bb1b549SSpandan Das			if rune == quote {
94*9bb1b549SSpandan Das				quote = '\x00'
95*9bb1b549SSpandan Das				continue
96*9bb1b549SSpandan Das			}
97*9bb1b549SSpandan Das		case rune == '"' || rune == '\'':
98*9bb1b549SSpandan Das			quoted = true
99*9bb1b549SSpandan Das			quote = rune
100*9bb1b549SSpandan Das			continue
101*9bb1b549SSpandan Das		case unicode.IsSpace(rune):
102*9bb1b549SSpandan Das			if quoted || i > 0 {
103*9bb1b549SSpandan Das				quoted = false
104*9bb1b549SSpandan Das				args = append(args, string(arg[:i]))
105*9bb1b549SSpandan Das				i = 0
106*9bb1b549SSpandan Das			}
107*9bb1b549SSpandan Das			continue
108*9bb1b549SSpandan Das		}
109*9bb1b549SSpandan Das		arg[i] = rune
110*9bb1b549SSpandan Das		i++
111*9bb1b549SSpandan Das	}
112*9bb1b549SSpandan Das	if quoted || i > 0 {
113*9bb1b549SSpandan Das		args = append(args, string(arg[:i]))
114*9bb1b549SSpandan Das	}
115*9bb1b549SSpandan Das	if quote != 0 {
116*9bb1b549SSpandan Das		err = errors.New("unclosed quote")
117*9bb1b549SSpandan Das	} else if escaped {
118*9bb1b549SSpandan Das		err = errors.New("unfinished escaping")
119*9bb1b549SSpandan Das	}
120*9bb1b549SSpandan Das	return args, err
121*9bb1b549SSpandan Das}
122*9bb1b549SSpandan Das
123*9bb1b549SSpandan Das// tagFlag adds tags to the build.Default context. Tags are expected to be
124*9bb1b549SSpandan Das// formatted as a comma-separated list.
125*9bb1b549SSpandan Dastype tagFlag struct{}
126*9bb1b549SSpandan Das
127*9bb1b549SSpandan Dasfunc (f *tagFlag) String() string {
128*9bb1b549SSpandan Das	return strings.Join(build.Default.BuildTags, ",")
129*9bb1b549SSpandan Das}
130*9bb1b549SSpandan Das
131*9bb1b549SSpandan Dasfunc (f *tagFlag) Set(opt string) error {
132*9bb1b549SSpandan Das	tags := strings.Split(opt, ",")
133*9bb1b549SSpandan Das	build.Default.BuildTags = append(build.Default.BuildTags, tags...)
134*9bb1b549SSpandan Das	return nil
135*9bb1b549SSpandan Das}
136