66 "io"
77 "runtime"
88 "sort"
9+ "strconv"
910 "text/template"
1011 "time"
1112
@@ -63,7 +64,7 @@ type versionOptions struct {
6364// versionInfo contains version information of both the Client, and Server
6465type versionInfo struct {
6566 Client clientVersion
66- Server * client. ServerVersionResult
67+ Server * serverVersion
6768}
6869
6970type platformInfo struct {
@@ -83,6 +84,26 @@ type clientVersion struct {
8384 Context string `json:"Context"`
8485}
8586
87+ // serverVersion contains information about the Docker server host.
88+ // it's the client-side presentation of [client.ServerVersionResult].
89+ type serverVersion struct {
90+ Platform client.PlatformInfo `json:",omitempty"` // Platform is the platform (product name) the server is running on.
91+ Version string `json:"Version"` // Version is the version of the daemon.
92+ APIVersion string `json:"ApiVersion"` // APIVersion is the highest API version supported by the server.
93+ MinAPIVersion string `json:"MinAPIVersion,omitempty"` // MinAPIVersion is the minimum API version the server supports.
94+ Os string `json:"Os"` // Os is the operating system the server runs on.
95+ Arch string `json:"Arch"` // Arch is the hardware architecture the server runs on.
96+ Components []system.ComponentVersion `json:"Components,omitempty"` // Components contains version information for the components making up the server.
97+
98+ // The following fields are deprecated, they relate to the Engine component and are kept for backwards compatibility
99+
100+ GitCommit string `json:"GitCommit,omitempty"`
101+ GoVersion string `json:"GoVersion,omitempty"`
102+ KernelVersion string `json:"KernelVersion,omitempty"`
103+ Experimental bool `json:"Experimental,omitempty"`
104+ BuildTime string `json:"BuildTime,omitempty"`
105+ }
106+
86107// newClientVersion constructs a new clientVersion. If a dockerCLI is
87108// passed as argument, additional information is included (API version),
88109// which may invoke an API connection. Pass nil to omit the additional
@@ -107,6 +128,47 @@ func newClientVersion(contextName string, dockerCli command.Cli) clientVersion {
107128 return v
108129}
109130
131+ func newServerVersion (sv client.ServerVersionResult ) * serverVersion {
132+ out := & serverVersion {
133+ Platform : sv .Platform ,
134+ Version : sv .Version ,
135+ APIVersion : sv .APIVersion ,
136+ MinAPIVersion : sv .MinAPIVersion ,
137+ Os : sv .Os ,
138+ Arch : sv .Arch ,
139+ Experimental : sv .Experimental , //nolint:staticcheck // ignore deprecated field.
140+ }
141+ foundEngine := false
142+ for _ , component := range sv .Components {
143+ if component .Name == "Engine" {
144+ foundEngine = true
145+ buildTime , ok := component .Details ["BuildTime" ]
146+ if ok {
147+ component .Details ["BuildTime" ] = reformatDate (buildTime )
148+ }
149+ out .GitCommit = component .Details ["GitCommit" ]
150+ out .GoVersion = component .Details ["GoVersion" ]
151+ out .KernelVersion = component .Details ["KernelVersion" ]
152+ out .Experimental = func () bool { b , _ := strconv .ParseBool (component .Details ["Experimental" ]); return b }()
153+ out .BuildTime = reformatDate (component .Details ["BuildTime" ])
154+ }
155+ }
156+
157+ if ! foundEngine {
158+ out .Components = append (out .Components , system.ComponentVersion {
159+ Name : "Engine" ,
160+ Version : sv .Version ,
161+ Details : map [string ]string {
162+ "ApiVersion" : sv .APIVersion ,
163+ "MinAPIVersion" : sv .MinAPIVersion ,
164+ "Os" : sv .Os ,
165+ "Arch" : sv .Arch ,
166+ },
167+ })
168+ }
169+ return out
170+ }
171+
110172// newVersionCommand creates a new cobra.Command for `docker version`
111173func newVersionCommand (dockerCLI command.Cli ) * cobra.Command {
112174 var opts versionOptions
@@ -138,51 +200,28 @@ func reformatDate(buildTime string) string {
138200}
139201
140202func arch () string {
141- arch := runtime .GOARCH
203+ out := runtime .GOARCH
142204 if rosetta .Enabled () {
143- arch += " (rosetta)"
205+ out += " (rosetta)"
144206 }
145- return arch
207+ return out
146208}
147209
148- func runVersion (ctx context.Context , dockerCli command.Cli , opts * versionOptions ) error {
210+ func runVersion (ctx context.Context , dockerCLI command.Cli , opts * versionOptions ) error {
149211 var err error
150212 tmpl , err := newVersionTemplate (opts .format )
151213 if err != nil {
152214 return cli.StatusError {StatusCode : 64 , Status : err .Error ()}
153215 }
154216
155217 vd := versionInfo {
156- Client : newClientVersion (dockerCli .CurrentContext (), dockerCli ),
218+ Client : newClientVersion (dockerCLI .CurrentContext (), dockerCLI ),
157219 }
158- sv , err := dockerCli .Client ().ServerVersion (ctx , client.ServerVersionOptions {})
220+ sv , err := dockerCLI .Client ().ServerVersion (ctx , client.ServerVersionOptions {})
159221 if err == nil {
160- vd .Server = & sv
161- foundEngine := false
162- for _ , component := range sv .Components {
163- if component .Name == "Engine" {
164- foundEngine = true
165- buildTime , ok := component .Details ["BuildTime" ]
166- if ok {
167- component .Details ["BuildTime" ] = reformatDate (buildTime )
168- }
169- }
170- }
171-
172- if ! foundEngine {
173- vd .Server .Components = append (vd .Server .Components , system.ComponentVersion {
174- Name : "Engine" ,
175- Version : sv .Version ,
176- Details : map [string ]string {
177- "ApiVersion" : sv .APIVersion ,
178- "MinAPIVersion" : sv .MinAPIVersion ,
179- "Os" : sv .Os ,
180- "Arch" : sv .Arch ,
181- },
182- })
183- }
222+ vd .Server = newServerVersion (sv )
184223 }
185- if err2 := prettyPrintVersion (dockerCli .Out (), vd , tmpl ); err2 != nil && err == nil {
224+ if err2 := prettyPrintVersion (dockerCLI .Out (), vd , tmpl ); err2 != nil && err == nil {
186225 err = err2
187226 }
188227 return err
0 commit comments