go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/grpc/cmd/prpc/show.go (about)

     1  // Copyright 2016 The LUCI 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 main
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"os"
    21  	"strings"
    22  
    23  	"github.com/maruel/subcommands"
    24  	"google.golang.org/protobuf/types/descriptorpb"
    25  
    26  	"go.chromium.org/luci/auth"
    27  	"go.chromium.org/luci/common/cli"
    28  	"go.chromium.org/luci/common/proto/google/descutil"
    29  	"go.chromium.org/luci/common/proto/google/descutil/printer"
    30  	"go.chromium.org/luci/grpc/prpc"
    31  )
    32  
    33  const (
    34  	cmdShowUsage = `show [flags] <server> [name]
    35  
    36    server: host ("example.com") or port for localhost (":8080").
    37    name: a full name of service, method or type. If not specified prints names
    38      of all available services.
    39  `
    40  
    41  	cmdShowDesc = "lists services and prints a definition of a referenced object."
    42  )
    43  
    44  func cmdShow(defaultAuthOpts auth.Options) *subcommands.Command {
    45  	return &subcommands.Command{
    46  		UsageLine: cmdShowUsage,
    47  		ShortDesc: cmdShowDesc,
    48  		LongDesc:  "Lists services and prints a definition of a referenced object.",
    49  		CommandRun: func() subcommands.CommandRun {
    50  			c := &showRun{}
    51  			c.registerBaseFlags(defaultAuthOpts)
    52  			return c
    53  		},
    54  	}
    55  }
    56  
    57  type showRun struct {
    58  	cmdRun
    59  }
    60  
    61  func (r *showRun) Run(a subcommands.Application, args []string, env subcommands.Env) int {
    62  	var host, name string
    63  	switch len(args) {
    64  	case 2:
    65  		name = args[1]
    66  		fallthrough
    67  	case 1:
    68  		host = args[0]
    69  
    70  	default:
    71  		return r.argErr(cmdShowDesc, cmdShowUsage, "")
    72  	}
    73  
    74  	ctx := cli.GetContext(a, r, env)
    75  	client, err := r.authenticatedClient(ctx, host)
    76  	if err != nil {
    77  		return ecAuthenticatedClientError
    78  	}
    79  	return r.done(show(ctx, client, name))
    80  }
    81  
    82  // show prints a definition of an object referenced by name in proto3 style.
    83  func show(ctx context.Context, client *prpc.Client, name string) error {
    84  	desc, err := loadDescription(ctx, client)
    85  	if err != nil {
    86  		return fmt.Errorf("could not load server description: %s", err)
    87  	}
    88  
    89  	if name == "" {
    90  		for _, s := range desc.Services {
    91  			fmt.Println(s)
    92  		}
    93  		return nil
    94  	}
    95  
    96  	file, obj, path := descutil.Resolve(desc.Description, name)
    97  	if obj == nil {
    98  		return fmt.Errorf("name %q could not resolved", name)
    99  	}
   100  
   101  	printer := printer.NewPrinter(os.Stdout)
   102  	if err := printer.SetFile(file); err != nil {
   103  		return err
   104  	}
   105  
   106  	switch obj := obj.(type) {
   107  
   108  	case *descriptorpb.ServiceDescriptorProto:
   109  		printer.Service(obj, -1)
   110  
   111  	case *descriptorpb.MethodDescriptorProto:
   112  		serviceIndex, methodIndex := path[1], path[3]
   113  		printer.Service(file.Service[serviceIndex], methodIndex)
   114  
   115  		printMsg := func(name string) error {
   116  			name = strings.TrimPrefix(name, ".")
   117  			file, msg, _ := descutil.Resolve(desc.Description, name)
   118  			if msg == nil {
   119  				printer.Printf("// Message %q is not found\n", name)
   120  				return nil
   121  			}
   122  			if err := printer.SetFile(file); err != nil {
   123  				return err
   124  			}
   125  			printer.Message(msg.(*descriptorpb.DescriptorProto))
   126  			return nil
   127  		}
   128  
   129  		printer.Printf("\n")
   130  		if err := printMsg(obj.GetInputType()); err != nil {
   131  			return err
   132  		}
   133  		printer.Printf("\n")
   134  		if err := printMsg(obj.GetOutputType()); err != nil {
   135  			return err
   136  		}
   137  
   138  	case *descriptorpb.DescriptorProto:
   139  		printer.Message(obj)
   140  
   141  	case *descriptorpb.FieldDescriptorProto:
   142  		printer.Field(obj)
   143  
   144  	case *descriptorpb.EnumDescriptorProto:
   145  		printer.Enum(obj)
   146  
   147  	case *descriptorpb.EnumValueDescriptorProto:
   148  		printer.EnumValue(obj)
   149  
   150  	default:
   151  		return fmt.Errorf("object of type %T is not supported", obj)
   152  	}
   153  
   154  	return printer.Err
   155  }