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  */