Skip to content

Add GO templating capabilities to images and list commands #12949

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

leoperegrino
Copy link
Contributor

@leoperegrino leoperegrino commented Jun 16, 2025

What I did
Implemented GO templates for images and list commands. I tried to align the changes with already existing commits, such as 1054792, even though a new formatter file in cmd/formatter/<command>.go was not created.

This PR changes the output of the json format. This is the default behavior for the commands that have template support.

# behavior for other commands with templating
docker images --format json
# {"Containers":"N/A","CreatedAt":"2014-07-19 04:02:32 -0300 -03","CreatedSince":"10 years ago","Digest":"\u003cnone\u003e","ID":"350b164e7ae1","Repository":"gcr.io/google-containers/pause","SharedSize":"N/A","Size":"240kB","Tag":"latest","UniqueSize":"N/A","VirtualSize":"239.8kB"}
# {"Containers":"N/A","CreatedAt":"1979-12-31 21:00:00 -0300 -03","CreatedSince":"45 years ago","Digest":"\u003cnone\u003e","ID":"f576b2d0af25","Repository":"test","SharedSize":"N/A","Size":"2.06GB","Tag":"latest","UniqueSize":"N/A","VirtualSize":"2.056GB"}

# images before this PR
docker compose images --format json
# [{"ID":"sha256:350b164e7ae1dcddeffadd65c76226c9b6dc5553f5179153fb0e36b78f2a5e06","ContainerName":"test_1-compose_test-1","Repository":"gcr.io/google-containers/pause","Tag":"latest","Size":239840,"LastTagTime":"0001-01-01T00:00:00Z"},{"ID":"sha256:350b164e7ae1dcddeffadd65c76226c9b6dc5553f5179153fb0e36b78f2a5e06","ContainerName":"test_1-compose_test_2-1","Repository":"gcr.io/google-containers/pause","Tag":"latest","Size":239840,"LastTagTime":"0001-01-01T00:00:00Z"}]

# images after this PR
docker compose images --format json
# {"ContainerName":"test_1-compose_test-1","Created":"292 years ago","ID":"350b164e7ae1","LastTagTime":"0001-01-01 00:00:00 +0000 UTC","Platform":"linux/amd64","Repository":"gcr.io/google-containers/pause","Size":"240kB","Tag":"latest"}
# {"ContainerName":"test_1-compose_test_2-1","Created":"292 years ago","ID":"350b164e7ae1","LastTagTime":"0001-01-01 00:00:00 +0000 UTC","Platform":"linux/amd64","Repository":"gcr.io/google-containers/pause","Size":"240kB","Tag":"latest"}

For the images command, a new --no-trunc flag was added to control the truncate behavior of the image ID.

Related issue

This closes #12948.

(not mandatory) A picture of a cute animal, if possible in relation to what you did

@leoperegrino leoperegrino requested a review from a team as a code owner June 16, 2025 14:04
@leoperegrino leoperegrino requested review from ndeloof and glours June 16, 2025 14:04
@glours
Copy link
Contributor

glours commented Jun 16, 2025

Hello @leoperegrino
for legal reasons all contributors must sign-off commits so we can accept them in this repository
please amend your PR
thanks

@ndeloof
Copy link
Contributor

ndeloof commented Jun 16, 2025

LGTM regarding the code approach

  1. for legal reasons, you have to sign-off your commits so we can accept contributions
  2. regarding compatibility break, cli/formatter applies slice formatting per entry, not as an array. I wonder we need to find a workaround; As your example illustrate, attribute formatting also changed, typically using a "human friendly" format which IMHO doesn't make any sense for json output.

Assuming the final goal is to align with docker/cli, format should offer the same data as https://github.com/docker/cli/blob/master/cli/command/formatter/image.go#L198-L208 and reuse existing public types

I'm not convince alignment with docker/cli is the best option here, and go templating format support is even desirable (with json output, you can pipe to a dedicated formatting engine, typically jq)
but won't block this PR is others see value.

@leoperegrino
Copy link
Contributor Author

leoperegrino commented Jun 16, 2025

Sorry about the signoff, I thought it was done automatically but already push forced amended commits.

The use case for this feature was expanded a bit more in the issue #12948. It consists in avoiding the use of a external tool such as jq to process a machine readable format, as most distributions don't come with jq pre installed and you may not have the permission to install it.

I don't think it needs to be a 1-1 mapping to docker/cli, I just tried to not deviate from the current codebase. But if a specific data structure format is required, I could change it when agreed upon.

Besides the slice/array difference, I think the only change in the attributes it's the ID. Now it's going to be truncated unless the --no-trunc flag is passed, as it is with docker compose ps.

@ndeloof
Copy link
Contributor

ndeloof commented Jun 16, 2025

feel free to change "api" so that it returns image.Summary and you can use more of the existing public types from https://github.com/docker/cli/blob/master/cli/command/image/list.go

@leoperegrino
Copy link
Contributor Author

The api.Stack struct holds attributes (ID and Reason) which doesn't seem to be used, maybe left from the ecs integration.

When formatting as json should they appear? Because right now, they don't.

docker compose ls --format json
# [{"Name":"test_1","Status":"running(2)","ConfigFiles":"..."},{"Name":"test_2","Status":"running(1)","ConfigFiles":"..."}]

@ndeloof
Copy link
Contributor

ndeloof commented Jun 16, 2025

maybe left from the ecs integration
indeed 🥹 - lot's of legacy here, feel free to remove those (can do in a separate PR if you prefer to keep this one focussed)

This is inspired by docker/cli and 1054792

Signed-off-by: Leonardo Peregrino <[email protected]>
This is inspired by docker/cli and 1054792

Signed-off-by: Leonardo Peregrino <[email protected]>
@leoperegrino
Copy link
Contributor Author

leoperegrino commented Jun 16, 2025

I've made the ImageContext and StackContext aware of the cliformatter.Context by adding a new cliFormat field to their structs:

type ImageContext struct {
cliformatter.HeaderContext
i api.ImageSummary
container string
cliFormat cliformatter.Format
}

compose/cmd/compose/list.go

Lines 129 to 133 in 5a0ca60

type StackContext struct {
cliformatter.HeaderContext
s api.Stack
cliFormat cliformatter.Format
}

Now, it's possible to access the --format passed in the cli in the *Context methods and have different logic paths if cliFormat.isJSON():

func (i *ImageContext) Size() string {
if i.cliFormat.IsJSON() {
return strconv.FormatInt(i.i.Size, 10)
}
return units.HumanSizeWithPrecision(float64(i.i.Size), 3)
}

func (i *ImageContext) ID() string {
if i.cliFormat.IsJSON() {
return i.i.ID
}
return stringid.TruncateID(i.i.ID)
}

docker compose images --format json

# {"ContainerName":"test_1-compose_test-1","Created":"292 years ago","ID":"sha256:350b164e7ae1dcddeffadd65c76226c9b6dc5553f5179153fb0e36b78f2a5e06","LastTagTime":"0001-01-01 00:00:00 +0000 UTC","Platform":"linux/amd64","Repository":"gcr.io/google-containers/pause","Size":"239840","Tag":"latest"}
# {"ContainerName":"test_1-compose_test_2-1","Created":"292 years ago","ID":"sha256:350b164e7ae1dcddeffadd65c76226c9b6dc5553f5179153fb0e36b78f2a5e06","LastTagTime":"0001-01-01 00:00:00 +0000 UTC","Platform":"linux/amd64","Repository":"gcr.io/google-containers/pause","Size":"239840","Tag":"latest"}

docker compose images --format table

# CONTAINER                 REPOSITORY                       TAG       PLATFORM      IMAGE ID       SIZE      CREATED
# test_1-compose_test_2-1   gcr.io/google-containers/pause   latest    linux/amd64   350b164e7ae1   240kB     292 years ago
# test_1-compose_test-1     gcr.io/google-containers/pause   latest    linux/amd64   350b164e7ae1   240kB     292 years ago

docker-compose ls --format json

# {"ConfigFiles":"...","Name":"test_1","Status":"running(2)"}
# {"ConfigFiles":"...","Name":"test_2","Status":"running(1)"}

docker compose ls --format table

# NAME      STATUS       CONFIG FILES
# test_1    running(2)   ...
# test_2    running(1)   ...

I believe this should be enough but tell me what do you think.

@ndeloof
Copy link
Contributor

ndeloof commented Jun 16, 2025

for JSON support, sounds way simpler to just bypass all the formater logic and rely on json.Marshall, or did I missed something ?

@leoperegrino
Copy link
Contributor Author

for JSON support, sounds way simpler to just bypass all the formater logic and rely on json.Marshall, or did I missed something ?

Could definitely be, I tried to mimic already inplace behavior and that's why I used the Context approach.
So, do you think I should drop the Contexts and use Marshal directly in their run functions?

@ndeloof
Copy link
Contributor

ndeloof commented Jun 16, 2025

yes, adopt docker/cli approach with the minimal amount of code (feel free to make a few changes so you can directly use the same structs/functions) + include a dedicated if block to manage JSON output for backward compatibility

@leoperegrino
Copy link
Contributor Author

Ok but to maintain the templating capability we would also need all the Context code, right? So if that code is already going to be there, why not reuse for the JSON marshal? This is how it's done by the ps command where it simply calls the ContainerWrite regardless if it was passed a JSON format or not:

compose/cmd/compose/ps.go

Lines 154 to 160 in 4f491ff

containerCtx := cliformatter.Context{
Output: dockerCli.Out(),
Format: formatter.NewContainerFormat(opts.Format, opts.Quiet, false),
Trunc: !opts.noTrunc,
}
return formatter.ContainerWrite(containerCtx, containers)
}

To me this makes more sense than to have another logical path in the run command just for JSON

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[FEATURE REQUEST] Add GO templating capabilities to images and/or list commands
3 participants