github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/libnetwork/client/client.go (about) 1 package client 2 3 import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 "net/http" 8 "reflect" 9 "strings" 10 11 flag "github.com/docker/libnetwork/client/mflag" 12 ) 13 14 // CallFunc provides environment specific call utility to invoke backend functions from UI 15 type CallFunc func(string, string, interface{}, map[string][]string) (io.ReadCloser, http.Header, int, error) 16 17 // NetworkCli is the UI object for network subcmds 18 type NetworkCli struct { 19 out io.Writer 20 err io.Writer 21 call CallFunc 22 } 23 24 // NewNetworkCli is a convenient function to create a NetworkCli object 25 func NewNetworkCli(out, err io.Writer, call CallFunc) *NetworkCli { 26 return &NetworkCli{ 27 out: out, 28 err: err, 29 call: call, 30 } 31 } 32 33 // getMethod is Borrowed from Docker UI which uses reflection to identify the UI Handler 34 func (cli *NetworkCli) getMethod(args ...string) (func(string, ...string) error, bool) { 35 camelArgs := make([]string, len(args)) 36 for i, s := range args { 37 if len(s) == 0 { 38 return nil, false 39 } 40 camelArgs[i] = strings.ToUpper(s[:1]) + strings.ToLower(s[1:]) 41 } 42 methodName := "Cmd" + strings.Join(camelArgs, "") 43 method := reflect.ValueOf(cli).MethodByName(methodName) 44 if !method.IsValid() { 45 return nil, false 46 } 47 return method.Interface().(func(string, ...string) error), true 48 } 49 50 // Cmd is borrowed from Docker UI and acts as the entry point for network UI commands. 51 // network UI commands are designed to be invoked from multiple parent chains 52 func (cli *NetworkCli) Cmd(chain string, args ...string) error { 53 if len(args) > 2 { 54 method, exists := cli.getMethod(args[:3]...) 55 if exists { 56 return method(chain+" "+args[0]+" "+args[1], args[3:]...) 57 } 58 } 59 if len(args) > 1 { 60 method, exists := cli.getMethod(args[:2]...) 61 if exists { 62 return method(chain+" "+args[0], args[2:]...) 63 } 64 } 65 if len(args) > 0 { 66 method, exists := cli.getMethod(args[0]) 67 if !exists { 68 return fmt.Errorf("%s: '%s' is not a %s command. See '%s --help'", chain, args[0], chain, chain) 69 } 70 return method(chain, args[1:]...) 71 } 72 flag.Usage() 73 return nil 74 } 75 76 // Subcmd is borrowed from Docker UI and performs the same function of configuring the subCmds 77 func (cli *NetworkCli) Subcmd(chain, name, signature, description string, exitOnError bool) *flag.FlagSet { 78 var errorHandling flag.ErrorHandling 79 if exitOnError { 80 errorHandling = flag.ExitOnError 81 } else { 82 errorHandling = flag.ContinueOnError 83 } 84 flags := flag.NewFlagSet(name, errorHandling) 85 flags.Usage = func() { 86 flags.ShortUsage() 87 flags.PrintDefaults() 88 } 89 flags.ShortUsage = func() { 90 options := "" 91 if signature != "" { 92 signature = " " + signature 93 } 94 if flags.FlagCountUndeprecated() > 0 { 95 options = " [OPTIONS]" 96 } 97 fmt.Fprintf(cli.out, "\nUsage: %s %s%s%s\n\n%s\n\n", chain, name, options, signature, description) 98 flags.SetOutput(cli.out) 99 } 100 return flags 101 } 102 103 func readBody(stream io.ReadCloser, hdr http.Header, statusCode int, err error) ([]byte, int, error) { 104 if stream != nil { 105 defer stream.Close() 106 } 107 if err != nil { 108 return nil, statusCode, err 109 } 110 body, err := ioutil.ReadAll(stream) 111 if err != nil { 112 return nil, -1, err 113 } 114 return body, statusCode, nil 115 }