github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/cli/command/cli.go (about) 1 package command 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 "net/http" 8 "os" 9 "path/filepath" 10 "runtime" 11 12 //"github.com/Sirupsen/logrus" 13 //"github.com/docker/docker/cli" 14 // "github.com/docker/docker/api/types/versions" 15 //"github.com/docker/docker/cli/command/commands" 16 // cliflags "github.com/docker/docker/cli/flags" 17 //"github.com/docker/docker/cliconfig" 18 //"github.com/docker/docker/dockerversion" 19 // "github.com/docker/docker/pkg/term" 20 //"github.com/docker/docker/utils" 21 //"github.com/spf13/pflag" 22 23 24 "github.com/docker/docker/api" 25 "github.com/docker/docker/api/types" 26 "github.com/docker/docker/api/types/versions" 27 cliflags "github.com/docker/docker/cli/flags" 28 "github.com/docker/docker/cliconfig" 29 "github.com/docker/docker/cliconfig/configfile" 30 "github.com/docker/docker/cliconfig/credentials" 31 "github.com/docker/docker/client" 32 "github.com/docker/docker/dockerversion" 33 dopts "github.com/docker/docker/opts" 34 "github.com/docker/go-connections/sockets" 35 "github.com/docker/go-connections/tlsconfig" 36 "github.com/spf13/cobra" 37 "golang.org/x/net/context" 38 ) 39 40 // Streams is an interface which exposes the standard input and output streams 41 type Streams interface { 42 In() *InStream 43 Out() *OutStream 44 Err() io.Writer 45 } 46 47 // DockerCli represents the docker command line client. 48 // Instances of the client can be returned from NewDockerCli. 49 type DockerCli struct { 50 configFile *configfile.ConfigFile 51 in *InStream 52 out *OutStream 53 err io.Writer 54 keyFile string 55 client client.APIClient 56 hasExperimental bool 57 defaultVersion string 58 //added characters 59 container string 60 execConfig *types.ExecConfig 61 } 62 63 func (cli *DockerCli) SetCliclient(c client.APIClient) error { 64 cli.client = c 65 return nil 66 } 67 68 func (cli *DockerCli) GetClicontainer() string { 69 return cli.container 70 } 71 72 func (cli *DockerCli) GetCliexecconfig() *types.ExecConfig { 73 return cli.execConfig 74 } 75 76 func NewFirstDockerCli(in io.ReadCloser, out, err io.Writer, c string, ec *types.ExecConfig) *DockerCli { 77 fmt.Println("cli/command/cli.go NewFirstDockerCli()") 78 return &DockerCli{in: NewInStream(in), out: NewOutStream(out), err: err, container: c, execConfig: ec,} 79 } 80 81 82 // HasExperimental returns true if experimental features are accessible. 83 func (cli *DockerCli) HasExperimental() bool { 84 return cli.hasExperimental 85 } 86 87 // DefaultVersion returns api.defaultVersion of DOCKER_API_VERSION if specified. 88 func (cli *DockerCli) DefaultVersion() string { 89 return cli.defaultVersion 90 } 91 92 // Client returns the APIClient 93 func (cli *DockerCli) Client() client.APIClient { 94 return cli.client 95 } 96 97 // Out returns the writer used for stdout 98 func (cli *DockerCli) Out() *OutStream { 99 return cli.out 100 } 101 102 // Err returns the writer used for stderr 103 func (cli *DockerCli) Err() io.Writer { 104 return cli.err 105 } 106 107 // In returns the reader used for stdin 108 func (cli *DockerCli) In() *InStream { 109 return cli.in 110 } 111 112 // ShowHelp shows the command help. 113 func (cli *DockerCli) ShowHelp(cmd *cobra.Command, args []string) error { 114 cmd.SetOutput(cli.err) 115 cmd.HelpFunc()(cmd, args) 116 return nil 117 } 118 119 // ConfigFile returns the ConfigFile 120 func (cli *DockerCli) ConfigFile() *configfile.ConfigFile { 121 return cli.configFile 122 } 123 124 // GetAllCredentials returns all of the credentials stored in all of the 125 // configured credential stores. 126 func (cli *DockerCli) GetAllCredentials() (map[string]types.AuthConfig, error) { 127 auths := make(map[string]types.AuthConfig) 128 for registry := range cli.configFile.CredentialHelpers { 129 helper := cli.CredentialsStore(registry) 130 newAuths, err := helper.GetAll() 131 if err != nil { 132 return nil, err 133 } 134 addAll(auths, newAuths) 135 } 136 defaultStore := cli.CredentialsStore("") 137 newAuths, err := defaultStore.GetAll() 138 if err != nil { 139 return nil, err 140 } 141 addAll(auths, newAuths) 142 return auths, nil 143 } 144 145 func addAll(to, from map[string]types.AuthConfig) { 146 for reg, ac := range from { 147 to[reg] = ac 148 } 149 } 150 151 // CredentialsStore returns a new credentials store based 152 // on the settings provided in the configuration file. Empty string returns 153 // the default credential store. 154 func (cli *DockerCli) CredentialsStore(serverAddress string) credentials.Store { 155 if helper := getConfiguredCredentialStore(cli.configFile, serverAddress); helper != "" { 156 return credentials.NewNativeStore(cli.configFile, helper) 157 } 158 return credentials.NewFileStore(cli.configFile) 159 } 160 161 // getConfiguredCredentialStore returns the credential helper configured for the 162 // given registry, the default credsStore, or the empty string if neither are 163 // configured. 164 func getConfiguredCredentialStore(c *configfile.ConfigFile, serverAddress string) string { 165 if c.CredentialHelpers != nil && serverAddress != "" { 166 if helper, exists := c.CredentialHelpers[serverAddress]; exists { 167 return helper 168 } 169 } 170 return c.CredentialsStore 171 } 172 173 // Initialize the dockerCli runs initialization that must happen after command 174 // line flags are parsed. 175 func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions) error { 176 cli.configFile = LoadDefaultConfigFile(cli.err) 177 178 var err error 179 cli.client, err = NewAPIClientFromFlags(opts.Common, cli.configFile) 180 if err != nil { 181 return err 182 } 183 184 cli.defaultVersion = cli.client.ClientVersion() 185 186 if opts.Common.TrustKey == "" { 187 cli.keyFile = filepath.Join(cliconfig.ConfigDir(), cliflags.DefaultTrustKeyFile) 188 } else { 189 cli.keyFile = opts.Common.TrustKey 190 } 191 192 if ping, err := cli.client.Ping(context.Background()); err == nil { 193 cli.hasExperimental = ping.Experimental 194 195 // since the new header was added in 1.25, assume server is 1.24 if header is not present. 196 if ping.APIVersion == "" { 197 ping.APIVersion = "1.24" 198 } 199 200 // if server version is lower than the current cli, downgrade 201 if versions.LessThan(ping.APIVersion, cli.client.ClientVersion()) { 202 cli.client.UpdateClientVersion(ping.APIVersion) 203 } 204 } 205 return nil 206 } 207 208 // NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err. 209 func NewDockerCli(in io.ReadCloser, out, err io.Writer) *DockerCli { 210 fmt.Println("cli/command/cli.go NewDockerCli()") 211 return &DockerCli{in: NewInStream(in), out: NewOutStream(out), err: err} 212 } 213 214 // LoadDefaultConfigFile attempts to load the default config file and returns 215 // an initialized ConfigFile struct if none is found. 216 func LoadDefaultConfigFile(err io.Writer) *configfile.ConfigFile { 217 configFile, e := cliconfig.Load(cliconfig.ConfigDir()) 218 if e != nil { 219 fmt.Fprintf(err, "WARNING: Error loading config file:%v\n", e) 220 } 221 if !configFile.ContainsAuth() { 222 credentials.DetectDefaultStore(configFile) 223 } 224 return configFile 225 } 226 227 // NewAPIClientFromFlags creates a new APIClient from command line flags 228 func NewAPIClientFromFlags(opts *cliflags.CommonOptions, configFile *configfile.ConfigFile) (client.APIClient, error) { 229 host, err := getServerHost(opts.Hosts, opts.TLSOptions) 230 if err != nil { 231 return &client.Client{}, err 232 } 233 234 customHeaders := configFile.HTTPHeaders 235 if customHeaders == nil { 236 customHeaders = map[string]string{} 237 } 238 customHeaders["User-Agent"] = UserAgent() 239 240 verStr := api.DefaultVersion 241 if tmpStr := os.Getenv("DOCKER_API_VERSION"); tmpStr != "" { 242 verStr = tmpStr 243 } 244 245 httpClient, err := newHTTPClient(host, opts.TLSOptions) 246 if err != nil { 247 return &client.Client{}, err 248 } 249 250 return client.NewClient(host, verStr, httpClient, customHeaders) 251 } 252 253 func getServerHost(hosts []string, tlsOptions *tlsconfig.Options) (host string, err error) { 254 switch len(hosts) { 255 case 0: 256 host = os.Getenv("DOCKER_HOST") 257 case 1: 258 host = hosts[0] 259 default: 260 return "", errors.New("Please specify only one -H") 261 } 262 263 host, err = dopts.ParseHost(tlsOptions != nil, host) 264 return 265 } 266 267 func newHTTPClient(host string, tlsOptions *tlsconfig.Options) (*http.Client, error) { 268 if tlsOptions == nil { 269 // let the api client configure the default transport. 270 return nil, nil 271 } 272 273 config, err := tlsconfig.Client(*tlsOptions) 274 if err != nil { 275 return nil, err 276 } 277 tr := &http.Transport{ 278 TLSClientConfig: config, 279 } 280 proto, addr, _, err := client.ParseHost(host) 281 if err != nil { 282 return nil, err 283 } 284 285 sockets.ConfigureTransport(tr, proto, addr) 286 287 return &http.Client{ 288 Transport: tr, 289 }, nil 290 } 291 292 // UserAgent returns the user agent string used for making API requests 293 func UserAgent() string { 294 return "Docker-Client/" + dockerversion.Version + " (" + runtime.GOOS + ")" 295 } 296 297 298 299 300 301 302 303 /* 304 //func newFirstDockerCommand(dockerCli *command.DockerCli) *cobra.Command { 305 fmt.Println("cli/command/container/exec.go newFirstDockerCommand()") 306 opts := cliflags.NewClientOptions() 307 var flags *pflag.FlagSet 308 309 cmd := &cobra.Command{ 310 Use: "docker [OPTIONS] COMMAND [ARG...]", 311 Short: "A self-sufficient runtime for containers", 312 SilenceUsage: true, 313 SilenceErrors: true, 314 TraverseChildren: true, 315 Args: noArgs, 316 RunE: func(cmd *cobra.Command, args []string) error { 317 if opts.Version { 318 showVersion() 319 return nil 320 } 321 return dockerCli.ShowHelp(cmd, args) 322 }, 323 PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 324 // daemon command is special, we redirect directly to another binary 325 if cmd.Name() == "daemon" { 326 return nil 327 } 328 // flags must be the top-level command flags, not cmd.Flags() 329 opts.Common.SetDefaultOptions(flags) 330 dockerPreRun(opts) 331 if err := dockerCli.Initialize(opts); err != nil { 332 return err 333 } 334 return isSupported(cmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental()) 335 }, 336 } 337 cli.SetupRootCommand(cmd) 338 339 cmd.SetHelpFunc(func(ccmd *cobra.Command, args []string) { 340 if dockerCli.Client() == nil { // when using --help, PersistenPreRun is not called, so initialization is needed. 341 // flags must be the top-level command flags, not cmd.Flags() 342 opts.Common.SetDefaultOptions(flags) 343 dockerPreRun(opts) 344 dockerCli.Initialize(opts) 345 } 346 347 if err := isSupported(ccmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental()); err != nil { 348 ccmd.Println(err) 349 return 350 } 351 352 hideUnsupportedFeatures(ccmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental()) 353 354 if err := ccmd.Help(); err != nil { 355 ccmd.Println(err) 356 } 357 }) 358 359 flags = cmd.Flags() 360 flags.BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit") 361 flags.StringVar(&opts.ConfigDir, "config", cliconfig.ConfigDir(), "Location of client config files") 362 opts.Common.InstallFlags(flags) 363 364 cmd.SetOutput(dockerCli.Out()) 365 cmd.AddCommand(newDaemonCommand()) 366 commands.AddCommands(cmd, dockerCli) 367 368 fmt.Println("cli/command/container/exec.go newFirstDockerCommand() end ") 369 370 return cmd 371 } 372 373 func noArgs(cmd *cobra.Command, args []string) error { 374 if len(args) == 0 { 375 return nil 376 } 377 fmt.Println("cli/command/cli.go noArgs() err : is not a docker cmmand") 378 return fmt.Errorf( 379 "docker: '%s' is not a docker command.\nSee 'docker --help'", args[0]) 380 } 381 382 383 func showVersion() { 384 fmt.Printf("Docker version %s, build %s\n", dockerversion.Version, dockerversion.GitCommit) 385 } 386 387 func dockerPreRun(opts *cliflags.ClientOptions) { 388 cliflags.SetLogLevel(opts.Common.LogLevel) 389 390 if opts.ConfigDir != "" { 391 cliconfig.SetConfigDir(opts.ConfigDir) 392 } 393 394 if opts.Common.Debug { 395 utils.EnableDebug() 396 } 397 } 398 399 func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion string, hasExperimental bool) { 400 cmd.Flags().VisitAll(func(f *pflag.Flag) { 401 // hide experimental flags 402 if !hasExperimental { 403 if _, ok := f.Annotations["experimental"]; ok { 404 f.Hidden = true 405 } 406 } 407 408 // hide flags not supported by the server 409 if flagVersion, ok := f.Annotations["version"]; ok && len(flagVersion) == 1 && versions.LessThan(clientVersion, flagVersion[0]) { 410 f.Hidden = true 411 } 412 413 }) 414 415 for _, subcmd := range cmd.Commands() { 416 // hide experimental subcommands 417 if !hasExperimental { 418 if _, ok := subcmd.Tags["experimental"]; ok { 419 subcmd.Hidden = true 420 } 421 } 422 423 // hide subcommands not supported by the server 424 if subcmdVersion, ok := subcmd.Tags["version"]; ok && versions.LessThan(clientVersion, subcmdVersion) { 425 subcmd.Hidden = true 426 } 427 } 428 } 429 430 func isSupported(cmd *cobra.Command, clientVersion string, hasExperimental bool) error { 431 if !hasExperimental { 432 if _, ok := cmd.Tags["experimental"]; ok { 433 return errors.New("only supported with experimental daemon") 434 } 435 } 436 437 if cmdVersion, ok := cmd.Tags["version"]; ok && versions.LessThan(clientVersion, cmdVersion) { 438 return fmt.Errorf("only supported with daemon version >= %s", cmdVersion) 439 } 440 441 return nil 442 } 443 */