github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/cmd/go/internal/load/flag.go (about)

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package load
     6  
     7  import (
     8  	"cmd/go/internal/base"
     9  	"cmd/go/internal/str"
    10  	"fmt"
    11  	"strings"
    12  )
    13  
    14  var (
    15  	BuildAsmflags   PerPackageFlag // -asmflags
    16  	BuildGcflags    PerPackageFlag // -gcflags
    17  	BuildLdflags    PerPackageFlag // -ldflags
    18  	BuildGccgoflags PerPackageFlag // -gccgoflags
    19  )
    20  
    21  // A PerPackageFlag is a command-line flag implementation (a flag.Value)
    22  // that allows specifying different effective flags for different packages.
    23  // See 'go help build' for more details about per-package flags.
    24  type PerPackageFlag struct {
    25  	present bool
    26  	values  []ppfValue
    27  }
    28  
    29  // A ppfValue is a single <pattern>=<flags> per-package flag value.
    30  type ppfValue struct {
    31  	match func(*Package) bool // compiled pattern
    32  	flags []string
    33  }
    34  
    35  // Set is called each time the flag is encountered on the command line.
    36  func (f *PerPackageFlag) Set(v string) error {
    37  	return f.set(v, base.Cwd)
    38  }
    39  
    40  // set is the implementation of Set, taking a cwd (current working directory) for easier testing.
    41  func (f *PerPackageFlag) set(v, cwd string) error {
    42  	f.present = true
    43  	match := func(p *Package) bool { return p.Internal.CmdlinePkg || p.Internal.CmdlineFiles } // default predicate with no pattern
    44  	if v == "" {
    45  		// Special case: -gcflags="" means no flags for command-line arguments
    46  		// (overrides previous -gcflags="-whatever").
    47  		f.values = append(f.values, ppfValue{match, []string{}})
    48  		return nil
    49  	}
    50  	if !strings.HasPrefix(v, "-") {
    51  		i := strings.Index(v, "=")
    52  		if i < 0 {
    53  			return fmt.Errorf("missing =<value> in <pattern>=<value>")
    54  		}
    55  		if i == 0 {
    56  			return fmt.Errorf("missing <pattern> in <pattern>=<value>")
    57  		}
    58  		pattern := v[:i]
    59  		match = MatchPackage(pattern, cwd)
    60  		v = v[i+1:]
    61  	}
    62  	flags, err := str.SplitQuotedFields(v)
    63  	if err != nil {
    64  		return err
    65  	}
    66  	if flags == nil {
    67  		flags = []string{}
    68  	}
    69  	f.values = append(f.values, ppfValue{match, flags})
    70  	return nil
    71  }
    72  
    73  // String is required to implement flag.Value.
    74  // It is not used, because cmd/go never calls flag.PrintDefaults.
    75  func (f *PerPackageFlag) String() string { return "<PerPackageFlag>" }
    76  
    77  // Present reports whether the flag appeared on the command line.
    78  func (f *PerPackageFlag) Present() bool {
    79  	return f.present
    80  }
    81  
    82  // For returns the flags to use for the given package.
    83  func (f *PerPackageFlag) For(p *Package) []string {
    84  	flags := []string{}
    85  	for _, v := range f.values {
    86  		if v.match(p) {
    87  			flags = v.flags
    88  		}
    89  	}
    90  	return flags
    91  }
    92  
    93  var cmdlineMatchers []func(*Package) bool
    94  
    95  // SetCmdlinePatterns records the set of patterns given on the command line,
    96  // for use by the PerPackageFlags.
    97  func SetCmdlinePatterns(args []string) {
    98  	setCmdlinePatterns(args, base.Cwd)
    99  }
   100  
   101  func setCmdlinePatterns(args []string, cwd string) {
   102  	if len(args) == 0 {
   103  		args = []string{"."}
   104  	}
   105  	cmdlineMatchers = nil // allow reset for testing
   106  	for _, arg := range args {
   107  		cmdlineMatchers = append(cmdlineMatchers, MatchPackage(arg, cwd))
   108  	}
   109  }
   110  
   111  // isCmdlinePkg reports whether p is a package listed on the command line.
   112  func isCmdlinePkg(p *Package) bool {
   113  	for _, m := range cmdlineMatchers {
   114  		if m(p) {
   115  			return true
   116  		}
   117  	}
   118  	return false
   119  }