kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/platform/tools/kzip/createcmd/flag.go (about)

     1  /*
     2   * Copyright 2019 The Kythe Authors. All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *   http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package createcmd
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  	"fmt"
    23  	"io/ioutil"
    24  	"sort"
    25  	"strings"
    26  
    27  	"kythe.io/kythe/go/util/kytheuri"
    28  	"kythe.io/kythe/go/util/vnameutil"
    29  
    30  	"google.golang.org/protobuf/encoding/protojson"
    31  
    32  	anypb "github.com/golang/protobuf/ptypes/any"
    33  	apb "kythe.io/kythe/proto/analysis_go_proto"
    34  )
    35  
    36  type repeatedString []string
    37  
    38  // Set implements part of the flag.Getter interface and will append a new value to the flag.
    39  func (f *repeatedString) Set(s string) error {
    40  	*f = append(*f, s)
    41  	return nil
    42  }
    43  
    44  // String implements part of the flag.Getter interface and returns a string-ish value for the flag.
    45  func (f *repeatedString) String() string {
    46  	if f == nil {
    47  		return ""
    48  	}
    49  	return strings.Join(*f, ",")
    50  }
    51  
    52  // Get implements flag.Getter and returns a slice of string values.
    53  func (f *repeatedString) Get() any {
    54  	if f == nil {
    55  		return []string(nil)
    56  	}
    57  	return *f
    58  }
    59  
    60  type repeatedEnv map[string]string
    61  
    62  // Set implements part of the flag.Getter interface and will append a new value to the flag.
    63  func (f *repeatedEnv) Set(s string) error {
    64  	parts := strings.SplitN(s, "=", 2)
    65  	if len(parts) != 2 {
    66  		return fmt.Errorf("invalid environment entry: %v", s)
    67  	}
    68  	if *f == nil {
    69  		*f = make(map[string]string)
    70  	}
    71  	(*f)[parts[0]] = parts[1]
    72  	return nil
    73  }
    74  
    75  // String implements part of the flag.Getter interface and returns a string-ish value for the flag.
    76  func (f *repeatedEnv) String() string {
    77  	if f == nil || *f == nil {
    78  		return ""
    79  	}
    80  	var values []string
    81  	for key, value := range *f {
    82  		values = append(values, key+"="+value)
    83  	}
    84  	return strings.Join(values, "\n")
    85  }
    86  
    87  // Get implements flag.Getter and returns a slice of string values.
    88  func (f *repeatedEnv) Get() any {
    89  	if f == nil {
    90  		return map[string]string(nil)
    91  	}
    92  	return *f
    93  }
    94  
    95  // ToProto returns a []*apb.CompilationUnit_Env for the mapped environment.
    96  func (f *repeatedEnv) ToProto() []*apb.CompilationUnit_Env {
    97  	if f == nil || *f == nil {
    98  		return nil
    99  	}
   100  	var result []*apb.CompilationUnit_Env
   101  	for key, value := range *f {
   102  		result = append(result, &apb.CompilationUnit_Env{
   103  			Name:  key,
   104  			Value: value,
   105  		})
   106  	}
   107  	sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name })
   108  	return result
   109  }
   110  
   111  type kytheURI kytheuri.URI
   112  
   113  // Set implements part of the flag.Value interface and will append a new value to the flag.
   114  func (f *kytheURI) Set(s string) error {
   115  	uri, err := kytheuri.Parse(s)
   116  	switch {
   117  	case err != nil:
   118  		return err
   119  	case uri.Corpus == "":
   120  		return errors.New("missing required URI field: corpus")
   121  	case uri.Language == "":
   122  		return errors.New("missing required URI field: language")
   123  
   124  	}
   125  	*f = *(*kytheURI)(uri)
   126  	return err
   127  }
   128  
   129  // String implements part of the flag.Value interface and returns a string-ish value for the flag.
   130  func (f *kytheURI) String() string {
   131  	return (*kytheuri.URI)(f).String()
   132  }
   133  
   134  // Get implements part of the flag.Getter interface.
   135  func (f *kytheURI) Get() any {
   136  	return f
   137  }
   138  
   139  // repeatedAny is a repeated flag of JSON-encoded Any messages.
   140  type repeatedAny []*anypb.Any
   141  
   142  // Set implements part of the flag.Getter interface and will append a new value to the flag.
   143  func (f *repeatedAny) Set(s string) error {
   144  	dec := json.NewDecoder(strings.NewReader(s))
   145  	for dec.More() {
   146  		var raw json.RawMessage
   147  		if err := dec.Decode(&raw); err != nil {
   148  			return err
   149  		}
   150  		var detail anypb.Any
   151  		if err := protojson.Unmarshal(raw, &detail); err != nil {
   152  			return err
   153  		}
   154  		*f = append(*f, &detail)
   155  	}
   156  	return nil
   157  }
   158  
   159  var toJSON = &protojson.MarshalOptions{UseProtoNames: true}
   160  
   161  // String implements part of the flag.Getter interface and returns a string-ish value for the flag.
   162  func (f *repeatedAny) String() string {
   163  	if f == nil {
   164  		return ""
   165  	}
   166  	var result []string
   167  	for _, val := range *f {
   168  		rec, err := toJSON.Marshal(val)
   169  		if err != nil {
   170  			panic(err)
   171  		}
   172  		result = append(result, string(rec))
   173  	}
   174  	return strings.Join(result, " ")
   175  }
   176  
   177  // Get implements flag.Getter and returns a slice of string values.
   178  func (f *repeatedAny) Get() any {
   179  	if f == nil {
   180  		return []*anypb.Any(nil)
   181  	}
   182  	return *f
   183  }
   184  
   185  // vnameRules is a path-valued flag used for loading VName mapping rules from a vnames.json file.
   186  type vnameRules struct {
   187  	filename string
   188  	vnameutil.Rules
   189  }
   190  
   191  // Set implements part of the flag.Value interface and will append a new value to the flag.
   192  func (f *vnameRules) Set(s string) error {
   193  	f.filename = s
   194  	data, err := ioutil.ReadFile(f.filename)
   195  	if err != nil {
   196  		return fmt.Errorf("reading vname rules: %v", err)
   197  	}
   198  	f.Rules, err = vnameutil.ParseRules(data)
   199  	if err != nil {
   200  		return fmt.Errorf("reading vname rules: %v", err)
   201  	}
   202  	return nil
   203  }
   204  
   205  // String implements part of the flag.Value interface and returns a string-ish value for the flag.
   206  func (f *vnameRules) String() string {
   207  	return f.filename
   208  }
   209  
   210  // Get implements part of the flag.Getter interface.
   211  func (f *vnameRules) Get() any {
   212  	return f
   213  }