gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/tools/nogo/flags/flags.go (about)

     1  // Copyright 2019 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package flags contains globally-visible flags.
    16  package flags
    17  
    18  import (
    19  	"bytes"
    20  	"encoding/json"
    21  	"fmt"
    22  	"os"
    23  	"os/exec"
    24  	"runtime"
    25  	"strings"
    26  	"sync"
    27  
    28  	"gvisor.dev/gvisor/runsc/flag"
    29  )
    30  
    31  var (
    32  	// Go location.
    33  	Go string
    34  
    35  	// GOOS defines the GOOS for analysis.
    36  	GOOS string
    37  
    38  	// GOARCH defines the GOARCH for analysis.
    39  	GOARCH string
    40  
    41  	// BuildTags defines the set of build tags for analysis. Note that
    42  	// while this may also be a StringList, it is kept as an explicit
    43  	// comma-separated list in order to build the standard flag.
    44  	BuildTags string
    45  
    46  	// ImportMap defines all binary input files.
    47  	ImportMap = StringMap{}
    48  
    49  	// ArchiveMap defines all binary archive files.
    50  	ArchiveMap = StringMap{}
    51  
    52  	// FactMap defines all fact input files.
    53  	FactMap = StringMap{}
    54  
    55  	// Bundles define fact bundles. This is typically used to contain the
    56  	// inputs for the standard library.
    57  	Bundles StringList
    58  )
    59  
    60  func init() {
    61  	flag.StringVar(&Go, "go", "go", "command used to invoke 'go tool'")
    62  	flag.StringVar(&GOOS, "GOOS", runtime.GOOS, "GOOS for analysis")
    63  	flag.StringVar(&GOARCH, "GOARCH", runtime.GOARCH, "GOARCH for analysis")
    64  	flag.StringVar(&BuildTags, "tags", "", "comma-separated build tags")
    65  	flag.Var(&ImportMap, "import", "map of import paths to binaries")
    66  	flag.Var(&ArchiveMap, "archive", "map of import paths to archives")
    67  	flag.Var(&FactMap, "facts", "map of import paths to facts")
    68  	flag.Var(&Bundles, "bundle", "list of fact bundles")
    69  }
    70  
    71  // StringList is a list of strings.
    72  type StringList []string
    73  
    74  // String implements fmt.Stringer.String.
    75  func (s *StringList) String() string {
    76  	return strings.Join((*s), ",")
    77  }
    78  
    79  // Set implements flag.Value.Set.
    80  func (s *StringList) Set(value string) error {
    81  	(*s) = append((*s), value)
    82  	return nil
    83  }
    84  
    85  // Get implements flag.Value.Get.
    86  func (s *StringList) Get() any {
    87  	return *s
    88  }
    89  
    90  // StringMap is a string to string map.
    91  type StringMap map[string]string
    92  
    93  // String implements fmt.Stringer.String.
    94  func (s *StringMap) String() string {
    95  	parts := make([]string, 0, len(*s))
    96  	for k, v := range *s {
    97  		parts = append(parts, fmt.Sprintf("%s=%s", k, v))
    98  	}
    99  	return strings.Join(parts, ",")
   100  }
   101  
   102  // Get implements flag.Value.Get.
   103  func (s *StringMap) Get() any {
   104  	return *s
   105  }
   106  
   107  // Set implements flag.Value.Set.
   108  func (s *StringMap) Set(value string) error {
   109  	if (*s) == nil {
   110  		(*s) = make(map[string]string)
   111  	}
   112  	parts := strings.SplitN(value, "=", 2)
   113  	if len(parts) != 2 {
   114  		// We specify the flag as -x=y=z. This string missed the second '='.
   115  		return fmt.Errorf("invalid format: expected at least one '=' in flag value, got %q", value)
   116  	}
   117  	(*s)[parts[0]] = parts[1]
   118  	return nil
   119  }
   120  
   121  var (
   122  	envOnce sync.Once
   123  	envErr  error
   124  	envMap  = map[string]string{}
   125  )
   126  
   127  // Env gets a Go environment value.
   128  func Env(value string) (string, error) {
   129  	if v := os.Getenv(value); v != "" {
   130  		return v, nil
   131  	}
   132  	envOnce.Do(func() {
   133  		// Pull the go environment.
   134  		cmd := exec.Command(Go, "env", "-json")
   135  		output, err := cmd.Output()
   136  		if err != nil {
   137  			envErr = fmt.Errorf("error executing 'go env -json': %w", err)
   138  			return
   139  		}
   140  		dec := json.NewDecoder(bytes.NewBuffer(output))
   141  		if err := dec.Decode(&envMap); err != nil {
   142  			envErr = fmt.Errorf("error decoding 'go env -json': %w", err)
   143  			return
   144  		}
   145  	})
   146  	return envMap[value], envErr // From above.
   147  }