github.com/containerd/nerdctl@v1.7.7/cmd/nerdctl/version.go (about)

     1  /*
     2     Copyright The containerd Authors.
     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 main
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"os"
    24  	"text/template"
    25  
    26  	"github.com/containerd/log"
    27  	"github.com/containerd/nerdctl/pkg/clientutil"
    28  	"github.com/containerd/nerdctl/pkg/formatter"
    29  	"github.com/containerd/nerdctl/pkg/infoutil"
    30  	"github.com/containerd/nerdctl/pkg/inspecttypes/dockercompat"
    31  	"github.com/containerd/nerdctl/pkg/rootlessutil"
    32  	"github.com/spf13/cobra"
    33  )
    34  
    35  func newVersionCommand() *cobra.Command {
    36  	var versionCommand = &cobra.Command{
    37  		Use:           "version",
    38  		Args:          cobra.NoArgs,
    39  		Short:         "Show the nerdctl version information",
    40  		RunE:          versionAction,
    41  		SilenceUsage:  true,
    42  		SilenceErrors: true,
    43  	}
    44  	versionCommand.Flags().StringP("format", "f", "", "Format the output using the given Go template, e.g, '{{json .}}'")
    45  	versionCommand.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
    46  		return []string{"json"}, cobra.ShellCompDirectiveNoFileComp
    47  	})
    48  	return versionCommand
    49  }
    50  
    51  func versionAction(cmd *cobra.Command, args []string) error {
    52  	var w io.Writer = os.Stdout
    53  	var tmpl *template.Template
    54  	globalOptions, err := processRootCmdFlags(cmd)
    55  	if err != nil {
    56  		return err
    57  	}
    58  	format, err := cmd.Flags().GetString("format")
    59  	if err != nil {
    60  		return err
    61  	}
    62  	if format != "" {
    63  		var err error
    64  		tmpl, err = formatter.ParseTemplate(format)
    65  		if err != nil {
    66  			return err
    67  		}
    68  	}
    69  
    70  	address := globalOptions.Address
    71  	// rootless `nerdctl version` runs in the host namespaces, so the address is different
    72  	if rootlessutil.IsRootless() {
    73  		address, err = rootlessutil.RootlessContainredSockAddress()
    74  		if err != nil {
    75  			log.L.WithError(err).Warning("failed to inspect the rootless containerd socket address")
    76  			address = ""
    77  		}
    78  	}
    79  
    80  	v, vErr := versionInfo(cmd, globalOptions.Namespace, address)
    81  	if tmpl != nil {
    82  		var b bytes.Buffer
    83  		if err := tmpl.Execute(&b, v); err != nil {
    84  			return err
    85  		}
    86  		if _, err := fmt.Fprintln(w, b.String()); err != nil {
    87  			return err
    88  		}
    89  	} else {
    90  		fmt.Fprintln(w, "Client:")
    91  		fmt.Fprintf(w, " Version:\t%s\n", v.Client.Version)
    92  		fmt.Fprintf(w, " OS/Arch:\t%s/%s\n", v.Client.Os, v.Client.Arch)
    93  		fmt.Fprintf(w, " Git commit:\t%s\n", v.Client.GitCommit)
    94  		for _, compo := range v.Client.Components {
    95  			fmt.Fprintf(w, " %s:\n", compo.Name)
    96  			fmt.Fprintf(w, "  Version:\t%s\n", compo.Version)
    97  			for detailK, detailV := range compo.Details {
    98  				fmt.Fprintf(w, "  %s:\t%s\n", detailK, detailV)
    99  			}
   100  		}
   101  		if v.Server != nil {
   102  			fmt.Fprintln(w)
   103  			fmt.Fprintln(w, "Server:")
   104  			for _, compo := range v.Server.Components {
   105  				fmt.Fprintf(w, " %s:\n", compo.Name)
   106  				fmt.Fprintf(w, "  Version:\t%s\n", compo.Version)
   107  				for detailK, detailV := range compo.Details {
   108  					fmt.Fprintf(w, "  %s:\t%s\n", detailK, detailV)
   109  				}
   110  			}
   111  		}
   112  	}
   113  	return vErr
   114  }
   115  
   116  // versionInfo may return partial VersionInfo on error.
   117  // Address can be empty to skip inspecting the server.
   118  func versionInfo(cmd *cobra.Command, ns, address string) (dockercompat.VersionInfo, error) {
   119  	v := dockercompat.VersionInfo{
   120  		Client: infoutil.ClientVersion(),
   121  	}
   122  	if address == "" {
   123  		return v, nil
   124  	}
   125  	client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), ns, address)
   126  	if err != nil {
   127  		return v, err
   128  	}
   129  	defer cancel()
   130  	v.Server, err = infoutil.ServerVersion(ctx, client)
   131  	return v, err
   132  }