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