/
main.go
126 lines (98 loc) · 2.66 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"strings"
"github.com/asottile/dockerfile"
"github.com/spf13/cobra"
)
type Image struct {
Name string `json:"name"`
Tag string `json:"tag"`
}
func main() {
var unknownMarker string
var query string
var occurrence int
var rootCmd = &cobra.Command{
Use: "dockerfile-image-tags",
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)
if err != nil {
log.Fatalf("Could not read Dockerfile: %s", err)
}
parsed, err := dockerfile.ParseReader(file)
if err != nil {
log.Fatalf("Could not parse Dockerfile: %s\n", err)
}
images := getImages(parsed, unknownMarker)
val, err := json.Marshal(images)
if err != nil {
log.Fatalf("Could not serialize images as JSON: %s\n", err)
}
if query == "" {
fmt.Println(string(val))
} else {
tag, err := getSingleTag(images, query, occurrence)
if err != nil {
log.Fatalf("Could not find image in Dockerfile: %s", query)
}
fmt.Println(tag)
}
},
}
rootCmd.Flags().StringVarP(&unknownMarker, "unknown-marker", "m", "?", "string to use to indicate unknown tags")
rootCmd.Flags().StringVarP(&query, "query", "q", "", "single image to return tag for (see `occurrence`)")
rootCmd.Flags().IntVarP(&occurrence, "occurrence", "n", 1, "which occurrence of image to return tag for")
if err := rootCmd.Execute(); err != nil {
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 sets 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
}
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)
}