From 0e23b5321958bba7a3049efcbebaa89a98ad6e28 Mon Sep 17 00:00:00 2001 From: bupd Date: Wed, 3 Jul 2024 04:44:01 +0530 Subject: [PATCH] Refactor store and modularize code Signed-off-by: bupd --- internal/store/in-memory-store.go | 216 +++++++++++++++++------------- 1 file changed, 123 insertions(+), 93 deletions(-) diff --git a/internal/store/in-memory-store.go b/internal/store/in-memory-store.go index 7b04cb6..a997ba4 100644 --- a/internal/store/in-memory-store.go +++ b/internal/store/in-memory-store.go @@ -9,28 +9,33 @@ import ( "github.com/google/go-containerregistry/pkg/crane" ) +// Image represents a container image with its digest and name. type Image struct { Digest string Name string } +// inMemoryStore stores images in memory and uses an ImageFetcher to manage images. type inMemoryStore struct { images map[string]string fetcher ImageFetcher } +// Storer is the interface for image storage operations. type Storer interface { List(ctx context.Context) ([]Image, error) - Add(ctx context.Context, digest string, image string) error - Remove(ctx context.Context, digest string, image string) error + Add(ctx context.Context, digest, image string) error + Remove(ctx context.Context, digest, image string) error } +// ImageFetcher is the interface for fetching images. type ImageFetcher interface { List(ctx context.Context) ([]Image, error) GetDigest(ctx context.Context, tag string) (string, error) SourceType() string } +// NewInMemoryStore creates a new in-memory store with the given ImageFetcher. func NewInMemoryStore(fetcher ImageFetcher) Storer { return &inMemoryStore{ images: make(map[string]string), @@ -38,123 +43,148 @@ func NewInMemoryStore(fetcher ImageFetcher) Storer { } } +// List retrieves and synchronizes the list of images from the fetcher. func (s *inMemoryStore) List(ctx context.Context) ([]Image, error) { - var imageList []Image - var change bool - - // Fetch images from the file/remote source + // fetch List of images imageList, err := s.fetcher.List(ctx) if err != nil { return nil, err } - // Handle File and Remote fetcher types differently + var changeDetected bool + switch s.fetcher.SourceType() { case "File": - for _, img := range imageList { - // Check if the image already exists in the store - if _, exists := s.images[img.Name]; !exists { - // Add the image to the store - s.AddImage(ctx, img.Name) - change = true - } else { - fmt.Printf("Image %s already exists in the store\n", img.Name) - } + changeDetected, err = s.handleFileSource(ctx, imageList) + case "Remote": + changeDetected, err = s.handleRemoteSource(ctx, imageList) + default: + return nil, fmt.Errorf("unknown source type") + } + + if changeDetected { + fmt.Println("Changes detected in the store") + return s.getImageList(), nil + } else { + fmt.Println("No changes detected in the store") + return nil, nil + } +} + +// handleFileSource handles image from a file +func (s *inMemoryStore) handleFileSource(ctx context.Context, imageList []Image) (bool, error) { + var change bool + for _, img := range imageList { + // Check if the image already exists in the store + if _, exists := s.images[img.Name]; !exists { + // Add the image to the store + s.AddImage(ctx, img.Name) + change = true + } else { + fmt.Printf("Image %s already exists in the store\n", img.Name) } + } - // Iterate over s.images and remove any image that is not found in imageList - for image := range s.images { - found := false - for _, img := range imageList { - if img.Name == image { - found = true - break - } - } - if !found { - s.RemoveImage(ctx, image) - change = true + // Iterate over s.images and remove any image that is not found in imageList + for image := range s.images { + found := false + for _, img := range imageList { + if img.Name == image { + found = true + break } } - - // Empty and refill imageList with the contents from s.images - imageList = imageList[:0] - for name, digest := range s.images { - imageList = append(imageList, Image{Name: name, Digest: digest}) + if !found { + s.RemoveImage(ctx, image) + change = true } + } - // Print out the entire store for debugging purposes - fmt.Println("Current store:") - for image := range s.images { - fmt.Printf("Image: %s\n", image) - } + // Empty and refill imageList with the contents from s.images + imageList = imageList[:0] + for name, digest := range s.images { + imageList = append(imageList, Image{Name: name, Digest: digest}) + } - case "Remote": - // Trim the imageList elements to remove the project name from the image reference - for i, img := range imageList { - parts := strings.Split(img.Name, "/") - if len(parts) > 1 { - // Take the second part as the new Reference - imageList[i].Name = parts[1] - } - } - // iterate over imageList and call GetDigest for each tag - for _, img := range imageList { - // Split the image reference to get the tag - tagParts := strings.Split(img.Name, ":") - // Check if there is a tag part, min length is 1 char - if len(tagParts) < 2 { - fmt.Println("No tag part found in the image reference") - } - // Use the last part as the tag - tag := tagParts[len(tagParts)-1] - // Get the digest for the tag - digest, err := s.fetcher.GetDigest(ctx, tag) - if err != nil { - return nil, err - } + // Print out the entire store for debugging purposes + fmt.Println("Current store:") + for image := range s.images { + fmt.Printf("Image: %s\n", image) + } - // Check if the image exists and matches the digest - if !(s.checkImageAndDigest(digest, img.Name)) { - change = true - } + return change, nil +} +// handleRemoteSource handles images fetched from a remote source. +func (s *inMemoryStore) handleRemoteSource(ctx context.Context, imageList []Image) (bool, error) { + var change bool + // Trim the imageList elements to remove the project name from the image reference + for i, img := range imageList { + parts := strings.Split(img.Name, "/") + if len(parts) > 1 { + // Take the second part as the new Reference + imageList[i].Name = parts[1] } - - // Create imageMap filled with all images from remote imageList - imageMap := make(map[string]bool) - for _, img := range imageList { - imageMap[img.Name] = true + } + // iterate over imageList and call GetDigest for each tag + for _, img := range imageList { + // Split the image reference to get the tag + tagParts := strings.Split(img.Name, ":") + // Check if there is a tag part, min length is 1 char + if len(tagParts) < 2 { + fmt.Println("No tag part found in the image reference") } - - // Iterate over in memory store and remove any image that is not found in imageMap - for digest, image := range s.images { - if _, exists := imageMap[image]; !exists { - s.Remove(ctx, digest, image) - change = true - } + // Use the last part as the tag + tag := tagParts[len(tagParts)-1] + // Get the digest for the tag + digest, err := s.fetcher.GetDigest(ctx, tag) + if err != nil { + return false, err } - // Print out the entire store for debugging purposes - fmt.Println("Current store:") - for digest, imageRef := range s.images { - fmt.Printf("Digest: %s, Image: %s\n", digest, imageRef) + + // Check if the image exists and matches the digest + if !(s.checkImageAndDigest(digest, img.Name)) { + change = true } - // Empty and refill imageList with the contents from s.images - imageList = imageList[:0] - for _, name := range s.images { - imageList = append(imageList, Image{Digest: "", Name: name}) + } + + // Create imageMap filled with all images from remote imageList + imageMap := make(map[string]bool) + for _, img := range imageList { + imageMap[img.Name] = true + } + + // Iterate over in memory store and remove any image that is not found in imageMap + for digest, image := range s.images { + if _, exists := imageMap[image]; !exists { + s.Remove(ctx, digest, image) + change = true } + } + // Print out the entire store for debugging purposes + fmt.Println("Current store:") + for digest, imageRef := range s.images { + fmt.Printf("Digest: %s, Image: %s\n", digest, imageRef) + } + // Empty and refill imageList with the contents from s.images + imageList = imageList[:0] + for _, name := range s.images { + imageList = append(imageList, Image{Digest: "", Name: name}) } - if change { - fmt.Println("Changes detected in the store") - change = false - return imageList, nil - } else { - fmt.Println("No changes detected in the store") - return nil, nil + + return change, nil +} + +// getImageList converts the in-memory store to a list of Image structs. +func (s *inMemoryStore) getImageList() []Image { + var imageList []Image + // Empty and refill imageList with the contents from s.images + for _, name := range s.images { + imageList = append(imageList, Image{Digest: "", Name: name}) } + return imageList } func (s *inMemoryStore) Add(ctx context.Context, digest string, image string) error {