Add GO templating capabilities to images and list commands
What I did
Implemented GO templates for images and list commands. I tried to align the changes with already existing commits, such as 1054792b4778b9fa9f8e0d24594882733aa4ed28, 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
Hello @leoperegrino for legal reasons all contributors must sign-off commits so we can accept them in this repository please amend your PR thanks
LGTM regarding the code approach
- for legal reasons, you have to sign-off your commits so we can accept contributions
- 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.
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.
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
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":"..."}]
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)
I've made the ImageContext and StackContext aware of the cliformatter.Context by adding a new cliFormat field to their structs:
https://github.com/docker/compose/blob/5a0ca602e99c269b9bb05c299ba911ee865960e6/cmd/compose/images.go#L128-L133
https://github.com/docker/compose/blob/5a0ca602e99c269b9bb05c299ba911ee865960e6/cmd/compose/list.go#L129-L133
Now, it's possible to access the --format passed in the cli in the *Context methods and have different logic paths if cliFormat.isJSON():
https://github.com/docker/compose/blob/5a0ca602e99c269b9bb05c299ba911ee865960e6/cmd/compose/images.go#L181-L186
https://github.com/docker/compose/blob/5a0ca602e99c269b9bb05c299ba911ee865960e6/cmd/compose/images.go#L154-L159
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.
for JSON support, sounds way simpler to just bypass all the formater logic and rely on json.Marshall, or did I missed something ?
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?
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
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: https://github.com/docker/compose/blob/4f491ffa9869869579b7b5f5a3b3d94bc8395377/cmd/compose/ps.go#L154-L160
To me this makes more sense than to have another logical path in the run command just for JSON