Skip to content

Commit

Permalink
refactor: extract functions into modules
Browse files Browse the repository at this point in the history
  • Loading branch information
shivjm committed Nov 8, 2021
1 parent 315ab64 commit e11796a
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 73 deletions.
76 changes: 7 additions & 69 deletions main.go
Expand Up @@ -4,17 +4,14 @@ import (
"encoding/json"
"fmt"
"log"
"os"
"strings"

"github.com/asottile/dockerfile"
"github.com/spf13/cobra"

"github.com/shivjm/dockerfile-image-tags/pkg/images"
"github.com/shivjm/dockerfile-image-tags/pkg/input"
)

type Image struct {
Name string `json:"name"`
Tag string `json:"tag"`
}

func main() {
var unknownMarker string
Expand All @@ -26,7 +23,7 @@ func main() {
Short: "List or query images & tags used in a Dockerfile.",
Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
file, err := getInput(args)
file, err := input.GetInput(args)

if err != nil {
log.Fatalf("Could not read Dockerfile: %s", err)
Expand All @@ -38,9 +35,9 @@ func main() {
log.Fatalf("Could not parse Dockerfile: %s\n", err)
}

images := getImages(parsed, unknownMarker)
allImages := images.GetImages(parsed, unknownMarker)

val, err := json.Marshal(images)
val, err := json.Marshal(allImages)

if err != nil {
log.Fatalf("Could not serialize images as JSON: %s\n", err)
Expand All @@ -49,7 +46,7 @@ func main() {
if query == "" {
fmt.Println(string(val))
} else {
tag, err := getSingleTag(images, query, occurrence)
tag, err := images.GetSingleTag(allImages, query, occurrence)

if err != nil {
log.Fatalf("Could not find image in Dockerfile: %s", query)
Expand All @@ -67,62 +64,3 @@ func main() {
log.Fatal(err)
}
}

// getInput opens the file named in `args` if present, `os.Stdin` if not.
func getInput(args []string) (*os.File, error) {
if len(args) == 1 {
name := args[0]
f, err := os.Open(name)

if err != nil {
return nil, fmt.Errorf("could not open %s: %s", name, err)
}

return f, nil
}

return os.Stdin, nil
}

// getImages returns the `Image`s used in the given list of Dockerfile commands.
func getImages(commands []dockerfile.Command, unknownMarker string) []Image {
images := []Image{}

for _, cmd := range commands {
if cmd.Cmd == "FROM" {
full := cmd.Value
rawImage := full[0]
imageParts := strings.Split(rawImage, ":")
image := imageParts[0]
var version string

if len(imageParts) > 1 {
version = imageParts[1]
} else {
version = unknownMarker
}

images = append(images, Image{Name: image, Tag: version})
}
}

return images
}

// getSingleTag returns the tag for the nth `occurrence` of `query` in
// the given list of `Image`s.
func getSingleTag(images []Image, query string, occurrence int) (string, error) {
found := 0

for _, i := range images {
if i.Name == query {
found += 1

if found >= occurrence {
return i.Tag, nil
}
}
}

return "", fmt.Errorf("could not find image %s in list", query)
}
10 changes: 6 additions & 4 deletions main_test.go
Expand Up @@ -5,10 +5,12 @@ import (

"github.com/asottile/dockerfile"
"github.com/stretchr/testify/assert"

"github.com/shivjm/dockerfile-image-tags/pkg/images"
)

func TestParsing(t *testing.T) {
expected := []Image{
expected := []images.Image{
{Name: "golang", Tag: "1.17.0-alpine"},
{Name: "common", Tag: " * "},
{Name: "common", Tag: "fixme"},
Expand All @@ -23,7 +25,7 @@ func TestParsing(t *testing.T) {
t.Errorf("Could not open Dockerfile.1: %s", err)
}

tags := getImages(commands, " * ")
tags := images.GetImages(commands, " * ")

assert.Equal(t, expected, tags)
}
Expand Down Expand Up @@ -53,10 +55,10 @@ func TestQuery(t *testing.T) {
t.Errorf("Could not open Dockerfile.1: %s", err)
}

tags := getImages(commands, "?")
tags := images.GetImages(commands, "?")

for _, c := range cases {
result, err := getSingleTag(tags, c.query, c.occurrence)
result, err := images.GetSingleTag(tags, c.query, c.occurrence)

if c.match {
assert.NoError(t, err, "must match %v", c.query)
Expand Down
56 changes: 56 additions & 0 deletions pkg/images/images.go
@@ -0,0 +1,56 @@
package images

import (
"fmt"
"strings"

"github.com/asottile/dockerfile"
)

type Image struct {
Name string `json:"name"`
Tag string `json:"tag"`
}

// GetImages returns the `Image`s used in the given list of Dockerfile commands.
func GetImages(commands []dockerfile.Command, unknownMarker string) []Image {
images := []Image{}

for _, cmd := range commands {
if cmd.Cmd == "FROM" {
full := cmd.Value
rawImage := full[0]
imageParts := strings.Split(rawImage, ":")
image := imageParts[0]
var version string

if len(imageParts) > 1 {
version = imageParts[1]
} else {
version = unknownMarker
}

images = append(images, Image{Name: image, Tag: version})
}
}

return images
}

// GetSingleTag returns the tag for the nth `occurrence` of `query` in
// the given list of `Image`s.
func GetSingleTag(images []Image, query string, occurrence int) (string, error) {
found := 0

for _, i := range images {
if i.Name == query {
found += 1

if found >= occurrence {
return i.Tag, nil
}
}
}

return "", fmt.Errorf("could not find image %s in list", query)
}
22 changes: 22 additions & 0 deletions pkg/input/input.go
@@ -0,0 +1,22 @@
package input

import (
"fmt"
"os"
)

// GetInput opens the file named in `args` if present, `os.Stdin` if not.
func GetInput(args []string) (*os.File, error) {
if len(args) == 1 {
name := args[0]
f, err := os.Open(name)

if err != nil {
return nil, fmt.Errorf("could not open %s: %s", name, err)
}

return f, nil
}

return os.Stdin, nil
}

0 comments on commit e11796a

Please sign in to comment.