func buildContainerListOptions(opts *psOptions) (*types.ContainerListOptions, error) { options := &types.ContainerListOptions{ All: opts.all, Limit: opts.last, Size: opts.size, Filters: opts.filter.Value(), } if opts.nLatest && opts.last == -1 { options.Limit = 1 } // Currently only used with Size, so we can determine if the user // put {{.Size}} in their format. pre := &preProcessor{opts: options} tmpl, err := templates.Parse(opts.format) if err != nil { return nil, err } // This shouldn't error out but swallowing the error makes it harder // to track down if preProcessor issues come up. Ref #24696 if err := tmpl.Execute(ioutil.Discard, pre); err != nil { return nil, err } return options, nil }
func buildContainerListOptions(opts *psOptions) (*types.ContainerListOptions, error) { options := &types.ContainerListOptions{ All: opts.all, Limit: opts.last, Size: opts.size, Filters: opts.filter.Value(), } if opts.nLatest && opts.last == -1 { options.Limit = 1 } tmpl, err := templates.Parse(opts.format) if err != nil { return nil, err } optionsProcessor := listOptionsProcessor{} // This shouldn't error out but swallowing the error makes it harder // to track down if preProcessor issues come up. Ref #24696 if err := tmpl.Execute(ioutil.Discard, optionsProcessor); err != nil { return nil, err } // At the moment all we need is to capture .Size for preprocessor options.Size = opts.size || optionsProcessor["size"] return options, nil }
func (c *Context) parseFormat() (*template.Template, error) { tmpl, err := templates.Parse(c.finalFormat) if err != nil { return tmpl, fmt.Errorf("Template parsing error: %v\n", err) } return tmpl, err }
func (c *Context) parseFormat() (*template.Template, error) { tmpl, err := templates.Parse(c.finalFormat) if err != nil { c.buffer.WriteString(fmt.Sprintf("Template parsing error: %v\n", err)) c.buffer.WriteTo(c.Output) } return tmpl, err }
func formatInfo(dockerCli *client.DockerCli, info types.Info, format string) error { tmpl, err := templates.Parse(format) if err != nil { return cli.StatusError{StatusCode: 64, Status: "Template parsing error: " + err.Error()} } err = tmpl.Execute(dockerCli.Out(), info) dockerCli.Out().Write([]byte{'\n'}) return err }
func runVersion(dockerCli *command.DockerCli, opts *versionOptions) error { ctx := context.Background() templateFormat := versionTemplate if opts.format != "" { templateFormat = opts.format } tmpl, err := templates.Parse(templateFormat) if err != nil { return cli.StatusError{StatusCode: 64, Status: "Template parsing error: " + err.Error()} } APIVersion := dockerCli.Client().ClientVersion() if defaultAPIVersion := dockerCli.DefaultVersion(); APIVersion != defaultAPIVersion { APIVersion = fmt.Sprintf("%s (downgraded from %s)", APIVersion, defaultAPIVersion) } vd := types.VersionResponse{ Client: &types.Version{ Version: dockerversion.Version, APIVersion: APIVersion, GoVersion: runtime.Version(), GitCommit: dockerversion.GitCommit, BuildTime: dockerversion.BuildTime, Os: runtime.GOOS, Arch: runtime.GOARCH, }, } serverVersion, err := dockerCli.Client().ServerVersion(ctx) if err == nil { vd.Server = &serverVersion } // first we need to make BuildTime more human friendly t, errTime := time.Parse(time.RFC3339Nano, vd.Client.BuildTime) if errTime == nil { vd.Client.BuildTime = t.Format(time.ANSIC) } if vd.ServerOK() { t, errTime = time.Parse(time.RFC3339Nano, vd.Server.BuildTime) if errTime == nil { vd.Server.BuildTime = t.Format(time.ANSIC) } } if err2 := tmpl.Execute(dockerCli.Out(), vd); err2 != nil && err == nil { err = err2 } dockerCli.Out().Write([]byte{'\n'}) return err }
// CmdVersion shows Docker version information. // // Available version information is shown for: client Docker version, client API version, client Go version, client Git commit, client OS/Arch, server Docker version, server API version, server Go version, server Git commit, and server OS/Arch. // // Usage: docker version func (cli *DockerCli) CmdVersion(args ...string) (err error) { cmd := Cli.Subcmd("version", nil, Cli.DockerCommands["version"].Description, true) tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template") cmd.Require(flag.Exact, 0) cmd.ParseFlags(args, true) templateFormat := versionTemplate if *tmplStr != "" { templateFormat = *tmplStr } var tmpl *template.Template if tmpl, err = templates.Parse(templateFormat); err != nil { return Cli.StatusError{StatusCode: 64, Status: "Template parsing error: " + err.Error()} } vd := types.VersionResponse{ Client: &types.Version{ Version: dockerversion.Version, APIVersion: cli.client.ClientVersion(), GoVersion: runtime.Version(), GitCommit: dockerversion.GitCommit, BuildTime: dockerversion.BuildTime, Os: runtime.GOOS, Arch: runtime.GOARCH, Experimental: utils.ExperimentalBuild(), }, } serverVersion, err := cli.client.ServerVersion() if err == nil { vd.Server = &serverVersion } // first we need to make BuildTime more human friendly t, errTime := time.Parse(time.RFC3339Nano, vd.Client.BuildTime) if errTime == nil { vd.Client.BuildTime = t.Format(time.ANSIC) } if vd.ServerOK() { t, errTime = time.Parse(time.RFC3339Nano, vd.Server.BuildTime) if errTime == nil { vd.Server.BuildTime = t.Format(time.ANSIC) } } if err2 := tmpl.Execute(cli.out, vd); err2 != nil && err == nil { err = err2 } cli.out.Write([]byte{'\n'}) return err }
// NewTemplateInspectorFromString creates a new TemplateInspector from a string // which is compiled into a template. func NewTemplateInspectorFromString(out io.Writer, tmplStr string) (Inspector, error) { if tmplStr == "" { return NewIndentedInspector(out), nil } tmpl, err := templates.Parse(tmplStr) if err != nil { return nil, fmt.Errorf("Template parsing error: %s", err) } return NewTemplateInspector(out, tmpl), nil }
func (cli *DockerCli) newInspectorWithTemplate(tmplStr string) (inspect.Inspector, error) { elementInspector := inspect.NewIndentedInspector(cli.out) if tmplStr != "" { tmpl, err := templates.Parse(tmplStr) if err != nil { return nil, fmt.Errorf("Template parsing error: %s", err) } elementInspector = inspect.NewTemplateInspector(cli.out, tmpl) } return elementInspector, nil }
func makeTemplate(format string) (*template.Template, error) { if format == "" { return nil, nil } tmpl, err := templates.Parse(format) if err != nil { return tmpl, err } // we execute the template for an empty message, so as to validate // a bad template like "{{.badFieldString}}" return tmpl, tmpl.Execute(ioutil.Discard, &eventtypes.Message{}) }
func TestTemplateInspectorEmpty(t *testing.T) { b := new(bytes.Buffer) tmpl, err := templates.Parse("{{.DNS}}") if err != nil { t.Fatal(err) } i := NewTemplateInspector(b, tmpl) if err := i.Flush(); err != nil { t.Fatal(err) } if b.String() != "\n" { t.Fatalf("Expected `\\n`, got `%s`", b.String()) } }
func TestTemplateInspectorRawFallbackError(t *testing.T) { b := new(bytes.Buffer) tmpl, err := templates.Parse("{{.Dns}}") if err != nil { t.Fatal(err) } i := NewTemplateInspector(b, tmpl) err = i.Inspect(testElement{"0.0.0.0"}, []byte(`{"Foo": "0.0.0.0"}`)) if err == nil { t.Fatal("Expected error got nil") } if !strings.HasPrefix(err.Error(), "Template parsing error") { t.Fatalf("Expected template error, got %v", err) } }
func TestTemplateInspectorRawFallback(t *testing.T) { b := new(bytes.Buffer) tmpl, err := templates.Parse("{{.Dns}}") if err != nil { t.Fatal(err) } i := NewTemplateInspector(b, tmpl) if err := i.Inspect(testElement{"0.0.0.0"}, []byte(`{"Dns": "0.0.0.0"}`)); err != nil { t.Fatal(err) } if err := i.Flush(); err != nil { t.Fatal(err) } if b.String() != "0.0.0.0\n" { t.Fatalf("Expected `0.0.0.0\\n`, got `%s`", b.String()) } }
func TestTemplateInspectorDefault(t *testing.T) { b := new(bytes.Buffer) tmpl, err := templates.Parse("{{.DNS}}") if err != nil { t.Fatal(err) } i := NewTemplateInspector(b, tmpl) if err := i.Inspect(testElement{"0.0.0.0"}, nil); err != nil { t.Fatal(err) } if err := i.Flush(); err != nil { t.Fatal(err) } if b.String() != "0.0.0.0\n" { t.Fatalf("Expected `0.0.0.0\\n`, got `%s`", b.String()) } }
func runPs(dockerCli *client.DockerCli, opts *psOptions) error { ctx := context.Background() if opts.nLatest && opts.last == -1 { opts.last = 1 } containerFilterArgs := filters.NewArgs() for _, f := range opts.filter { var err error containerFilterArgs, err = filters.ParseFlag(f, containerFilterArgs) if err != nil { return err } } options := types.ContainerListOptions{ All: opts.all, Limit: opts.last, Size: opts.size, Filter: containerFilterArgs, } pre := &preProcessor{opts: &options} tmpl, err := templates.Parse(opts.format) if err != nil { return err } _ = tmpl.Execute(ioutil.Discard, pre) containers, err := dockerCli.Client().ContainerList(ctx, options) if err != nil { return err } f := opts.format if len(f) == 0 { if len(dockerCli.PsFormat()) > 0 && !opts.quiet { f = dockerCli.PsFormat() } else { f = "table" } } psCtx := formatter.ContainerContext{ Context: formatter.Context{ Output: dockerCli.Out(), Format: f, Quiet: opts.quiet, Trunc: !opts.noTrunc, }, Size: opts.size, Containers: containers, } psCtx.Write() return nil }
// CmdPs outputs a list of Docker containers. // // Usage: docker ps [OPTIONS] func (cli *DockerCli) CmdPs(args ...string) error { var ( err error psFilterArgs = filters.NewArgs() cmd = Cli.Subcmd("ps", nil, Cli.DockerCommands["ps"].Description, true) quiet = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs") size = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes") all = cmd.Bool([]string{"a", "-all"}, false, "Show all containers (default shows just running)") noTrunc = cmd.Bool([]string{"-no-trunc"}, false, "Don't truncate output") nLatest = cmd.Bool([]string{"l", "-latest"}, false, "Show the latest created container (includes all states)") last = cmd.Int([]string{"n"}, -1, "Show n last created containers (includes all states)") format = cmd.String([]string{"-format"}, "", "Pretty-print containers using a Go template") flFilter = opts.NewListOpts(nil) ) cmd.Require(flag.Exact, 0) cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided") cmd.ParseFlags(args, true) if *last == -1 && *nLatest { *last = 1 } // Consolidate all filter flags, and sanity check them. // They'll get processed in the daemon/server. for _, f := range flFilter.GetAll() { if psFilterArgs, err = filters.ParseFlag(f, psFilterArgs); err != nil { return err } } options := types.ContainerListOptions{ All: *all, Limit: *last, Size: *size, Filter: psFilterArgs, } pre := &preProcessor{opts: &options} tmpl, err := templates.Parse(*format) if err != nil { return err } _ = tmpl.Execute(ioutil.Discard, pre) containers, err := cli.client.ContainerList(context.Background(), options) if err != nil { return err } f := *format if len(f) == 0 { if len(cli.PsFormat()) > 0 && !*quiet { f = cli.PsFormat() } else { f = "table" } } psCtx := formatter.ContainerContext{ Context: formatter.Context{ Output: cli.out, Format: f, Quiet: *quiet, Trunc: !*noTrunc, }, Size: *size, Containers: containers, } psCtx.Write() return nil }