cmd, pkg/podman: Introduce Image Interface and Unit Tests#1724
cmd, pkg/podman: Introduce Image Interface and Unit Tests#1724DaliborKr wants to merge 1 commit intocontainers:mainfrom
Conversation
|
Build succeeded. ✔️ unit-test SUCCESS in 2m 06s |
debarshiray
left a comment
There was a problem hiding this comment.
Thanks for working on this, @DaliborKr ! My apologies for the delay.
I am still reading through the changes, but one thing popped out at me.
src/pkg/podman/image.go
Outdated
| } | ||
|
|
||
| func (images Images) Len() int { | ||
| return len(images.data) |
There was a problem hiding this comment.
It might be better to change these pre-existing methods from ImageSlice that earlier had value receivers to pointer receivers.
I am not an expert on value versus pointer receivers, and I get confused all the time. It seems that the general advice is to not mix pointer and value receivers for a given type.
In the case of the Images type, the Reset() method must have a pointer receiver because it modifies a field of the type.
In case you wonder how the Swap() method was working, just like I did, it's because in Go slices are references to an underlying array and changing an element of a slice modifies the array and other slices see the same change. The value receiver copies the slice and the underlying array stays the same.
This is a step towards eliminating or reducing the code in getImages() by doing everything or more in podman.GetImages(). If nothing else, this removes the need to export Image.FlattenNames() from the podman package. The getImages() function originated as listContainers(), when it invoked 'podman images --filter label=...' through podman.GetImages() separately for each label used to identify Toolbx images, and then joined and sorted the results. This changed in commit 2369da5 when getImages() started invoking 'podman images' only once through podman.GetImages() to get all available images, and then filtered them itself based on the labels. Before this change in commit 2369da5, it probably made some sense to keep podman.GetImages() only as a thin wrapper to invoke 'podman images' with different options, and to do everything else in getImages(). However, since then more is being done inside the podman package (eg., unmarshalling the 'podman images' JSON in commit 5f324d5 and flattening the images in commit 6aab0a6), and getImages() is the only caller of podman.GetImages(). Therefore, it looks awkward to have the code to get all Toolbx images split across two functions in different packages. containers#1724
This is a step towards eliminating or reducing the code in getImages() by doing everything or more in podman.GetImages(). If nothing else, this removes the need to export Image.FlattenNames() from the podman package. The getImages() function originated as listContainers(), when it invoked 'podman images --filter label=...' through podman.GetImages() separately for each label used to identify Toolbx images, and then joined and sorted the results. This changed in commit 2369da5 when getImages() started invoking 'podman images' only once through podman.GetImages() to get all available images, and then filtered them itself based on the labels. Before this change in commit 2369da5, it probably made some sense to keep podman.GetImages() only as a thin wrapper to invoke 'podman images' with different options, and to do everything else in getImages(). However, since then more is being done inside the podman package (eg., unmarshalling the 'podman images' JSON in commit 5f324d5 and flattening the images in commit 6aab0a6), and getImages() is the only caller of podman.GetImages(). Therefore, it looks awkward to have the code to get all Toolbx images split across two functions in different packages. containers#1724 containers#1772
This is a step towards eliminating or reducing the code in getImages() by doing everything or more in podman.GetImages(). If nothing else, this removes the need to export Image.FlattenNames() from the podman package. The getImages() function originated as listContainers(), when it invoked 'podman images --filter label=...' through podman.GetImages() separately for each label used to identify Toolbx images, and then joined and sorted the results. This changed in commit 2369da5 when getImages() started invoking 'podman images' only once through podman.GetImages() to get all available images, and then filtered them itself based on the labels. Before this change in commit 2369da5, it probably made some sense to keep podman.GetImages() only as a thin wrapper to invoke 'podman images' with different options, and to do everything else in getImages(). However, since then more is being done inside the podman package (eg., unmarshalling the 'podman images' JSON in commit 5f324d5 and flattening the images in commit 6aab0a6), and getImages() is the only caller of podman.GetImages(). Therefore, it looks awkward to have the code to get all Toolbx images split across two functions in different packages. containers#1724 containers#1772
Subsequent commits will use isToolbx() for image labels. So, it can't be in a file that's specific to containers. containers#1724 containers#1772
This is a step towards eliminating or reducing the code in getImages() by doing everything or more in podman.GetImages(). If nothing else, this removes the need to keep a copy of the labels used to identify Toolbx images for getImages(). The getImages() function originated as listContainers(), when it invoked 'podman images --filter label=...' through podman.GetImages() separately for each label used to identify Toolbx images, and then joined and sorted the results. This changed in commit 2369da5 when getImages() started invoking 'podman images' only once through podman.GetImages() to get all available images, and then filtered them itself based on the labels. Before this change in commit 2369da5, it probably made some sense to keep podman.GetImages() only as a thin wrapper to invoke 'podman images' with different options, and to do everything else in getImages(). However, since then more is being done inside the podman package (eg., unmarshalling the 'podman images' JSON in commit 5f324d5 and flattening the images in commit 6aab0a6), and getImages() is the only caller of podman.GetImages(). Therefore, it looks awkward to have the code to get all Toolbx images split across two functions in different packages. containers#1724 containers#1772
This is a step towards eliminating the code in getImages() by doing everything in podman.GetImages(). This removes the need to export the podman.ImageSlice type from the podman package. The getImages() function originated as listContainers(), when it invoked 'podman images --filter label=...' through podman.GetImages() separately for each label used to identify Toolbx images, and then joined and sorted the results. This changed in commit 2369da5 when getImages() started invoking 'podman images' only once through podman.GetImages() to get all available images, and then filtered them itself based on the labels. Before this change in commit 2369da5, it probably made some sense to keep podman.GetImages() only as a thin wrapper to invoke 'podman images' with different options, and to do everything else in getImages(). However, since then more is being done inside the podman package (eg., unmarshalling the 'podman images' JSON in commit 5f324d5 and flattening the images in commit 6aab0a6), and getImages() is the only caller of podman.GetImages(). Therefore, it looks awkward to have the code to get all Toolbx images split across two functions in different packages. containers#1724 containers#1772
5a6721a to
12863ee
Compare
|
Merge Failed. This change or one of its cross-repo dependencies was unable to be automatically merged with the current state of its repository. Please rebase the change and upload a new patchset. |
debarshiray
left a comment
There was a problem hiding this comment.
I noticed a few more relatively minor things while trying to rebase this against main.
In reaction to the conversation in PR containers#1707, I made suggested changes to the implementation in terms of how Image information, received from Podman, is represented and treated in the Toolbx code. I used the same procedure as in the case of representing Containers: - Commit e611969 - Commit ec7eb59 In short, the JSON from 'podman inspect --type image' and 'podman images' are different, so logically, there should be different implementations of the JSON.Unmarshaler interface [1] for them as well. The new Image interface provides access to the values parsed from the JSONs and two different concrete types, which are implemented separately to handle the differences in the JSONs. GetImages() now returns an Images iterator-like structure that handles image flattening and sorting internally. InspectImage() returns an Image interface instead of map[string]interface{}, and the IsToolboxImage() function was replaced with the IsToolbx() method on the Image interface. Tested were results of Podman starting on version 1.1.2, which should be sufficient since the minimum required Podman version is 1.6.4 (see commit 8e80dd5). Covered are structures representing podman commands 'podman inspect --type image' and 'podman images'. [1] https://pkg.go.dev/encoding/json#Unmarshaler containers#1724 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
12863ee to
aa553fc
Compare
In reaction to the conversation in PR containers#1707, I made suggested changes to the implementation in terms of how Image information, received from Podman, is represented and treated in the Toolbx code. I used the same procedure as in the case of representing Containers: - Commit e611969 - Commit ec7eb59 In short, the JSON from 'podman inspect --type image' and 'podman images' are different, so logically, there should be different implementations of the JSON.Unmarshaler interface [1] for them as well. The new Image interface provides access to the values parsed from the JSONs and two different concrete types, which are implemented separately to handle the differences in the JSONs. GetImages() now returns an Images iterator-like structure that handles image flattening and sorting internally. InspectImage() returns an Image interface instead of map[string]interface{}, and the IsToolboxImage() function was replaced with the IsToolbx() method on the Image interface. Tested were results of Podman starting on version 1.1.2, which should be sufficient since the minimum required Podman version is 1.6.4 (see commit 8e80dd5). Covered are structures representing podman commands 'podman inspect --type image' and 'podman images'. [1] https://pkg.go.dev/encoding/json#Unmarshaler containers#1724 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
aa553fc to
904a92e
Compare
|
I rebased this branch on top of |
In reaction to the conversation in PR containers#1707, I made suggested changes to the implementation in terms of how Image information, received from Podman, is represented and treated in the Toolbx code. I used the same procedure as in the case of representing Containers: - Commit e611969 - Commit ec7eb59 In short, the JSON from 'podman inspect --type image' and 'podman images' are different, so logically, there should be different implementations of the JSON.Unmarshaler interface [1] for them as well. The new Image interface provides access to the values parsed from the JSONs and two different concrete types, which are implemented separately to handle the differences in the JSONs. GetImages() now returns an Images iterator-like structure that handles image flattening and sorting internally. InspectImage() returns an Image interface instead of map[string]interface{}, and the IsToolboxImage() function was replaced with the IsToolbx() method on the Image interface. Tested were results of Podman starting on version 1.1.2, which should be sufficient since the minimum required Podman version is 1.6.4 (see commit 8e80dd5). Covered are structures representing podman commands 'podman inspect --type image' and 'podman images'. [1] https://pkg.go.dev/encoding/json#Unmarshaler containers#1724 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
| return image.names | ||
| } | ||
|
|
||
| func (image *imageImages) setNames(names []string) { |
There was a problem hiding this comment.
Do we really need this private setter method? We don't have them for the other fields, and it might be overkill because these values can't be set from outside the podman package.
There was a problem hiding this comment.
Yes, you are right. This setter function is really unnecessary here. In other functions in image.go (e.g., UnmarshalJSON()), fields are set directly so that we can do the same here.
| ID() string | ||
| IsToolbx() bool | ||
| Labels() map[string]string | ||
| Names() []string |
There was a problem hiding this comment.
I am wondering if we can have a Name() variant (ie., singular) of the Names() method. In practical terms, it would simplify the rest of the code because we almost always want Names()[0], except in imageImages.flattenNames.
In philosophical terms, I am a bit worried about returning a slice because in Go slices are references to a underlying arrays. Changing the elements of a slice modifies the corresponding elements of its underlying array. Other slices that share the same underlying array will see those changes. So, it's theoretically possible that after copying and slicing a slice several times, a piece of code can unexpectedly change the elements to the surprise of a different piece of code.
One way to avoid that is to return a copy of the internal slice using copy.
I had originally added the Names() method to the podman.Containers type (in commit e611969) purely for the sake of completeness. So, maybe it's simpler to remove the method? What do you think?
One inconvenient detail is that we have assertions that check the number of elements in Names() to ensure that the images were flattened. Even if we retain the Names() method by returning a copy of the slice, it would be good to avoid the copies just for assertions.
I wonder if we can move the assertions to the Name() variant (ie., singular). Now that getImages() is removed and everything happens in podman.GetImages(), it seems that all images should be already flattened before any code outside this function sees them, and podman.GetImages() doesn't use the names. What do you think?
There was a problem hiding this comment.
This is a very good idea! We can have a method Name() like the example below, which also encapsulates the assertion, and use the Names() method only to flatten the names within the podman package, ensuring that only flattened images are returned from its functions.
func (image *imageImages) Name() string {
if len(image.names) != 1 {
panic("cannot use Name() on unflattened Image")
}
return image.names[0]
}
Did you mean something like this?
|
Build succeeded. ✔️ unit-test SUCCESS in 2m 09s |
904a92e to
40496b2
Compare
|
Build succeeded. ✔️ unit-test SUCCESS in 2m 11s |
Introduces an Image interface based on the conversation in PR #1707.
Similar to how container information is handled (introduced in commits e611969 and ec7eb59), this PR abstracts the representation of an image. This is necessary because
podman inspect --type imageandpodman imagesreturn different JSON structures. The Image interface provides a unified way to access image data, with two distinct implementations to handle the different JSON formats.Updates related functions:
Adds unit tests: This PR includes unit tests for the new Image interface implementation, covering the output of both
podman inspect --type imageandpodman images.