-
Notifications
You must be signed in to change notification settings - Fork 1
/
client.go
225 lines (193 loc) · 4.53 KB
/
client.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
package main
import (
"net/http"
"io/ioutil"
// "fmt"
// "os"
"github.com/BurntSushi/toml"
"strings"
"encoding/json"
"log"
"html"
)
type WebClient interface {
Get(string) []byte
}
type Client struct {
config *Config
dockerfiles map[string]string
Images []DockerImage
Results []DockerImage
Http WebClient
Verbose bool
}
type Docker struct {
terms []string
}
func (c *Client) Load( files map[string]string ) {
c.dockerfiles = files
}
type Config struct {
Host string
Endpoint string
UpdateCheck bool
}
func (c* Client) log( msg ...string ) {
logit( c.Verbose, msg... )
}
func (c* Client) LoadConfig( path string ) bool {
rv := true
var conf Config
if _, err := toml.DecodeFile( path, &conf ); err != nil {
// handle error
log.Fatal( err )
rv = false
} else {
c.config = &conf
}
return rv
}
type Tuple struct {
Name string
Dockerfile string
}
type RealWebClient struct {
}
func (r* RealWebClient) Get( url string ) []byte {
var body []byte
// Raw link: https://registry.hub.docker.com/u/bfirsh/ffmpeg/dockerfile/raw
client := &http.Client{}
req, _ := http.NewRequest( "GET", url, nil )
if resp, err := client.Do(req); nil != err {
log.Fatal( err )
} else {
defer resp.Body.Close()
body, _ = ioutil.ReadAll(resp.Body)
}
return body
}
func (c* Client) grabDockerfile( name string ) []byte {
url := "https://registry.hub.docker.com/u/" + name + "/dockerfile/raw"
body := c.Http.Get( url )
return body
}
func (c* Client) sendBackDockerfile( ci chan<- Tuple, name string ) {
body := c.grabDockerfile( name )
ci <- Tuple{name,string(body)}
}
func (c* Client) processDockerfile( ci <-chan Tuple ) {
tuple := <- ci
// Apply it to the correct result
for i,image := range c.Images {
if tuple.Name == image.Name {
c.log( "Got dockerfile for: " + tuple.Name )
c.Images[i].Dockerfile = strings.TrimSpace( html.UnescapeString( tuple.Dockerfile ) )
}
}
}
func (c* Client) Annotate() {
// Grab a bunch of Dockerfiles, and then process them
count := 0
ci := make(chan Tuple, 4 )
for _, image := range c.Images {
c.log( "Annotating image " + image.Name + " with Dockerfile" )
go c.sendBackDockerfile( ci, image.Name )
count++
}
for count > 0 {
c.processDockerfile( ci )
count--
}
c.log( "Finished annotation of dockerfiles" )
}
func (c* Client) Filter( filters []string ) {
// Set them to the results
c.Results = []DockerImage{}
filterCount := len( filters )
counts := make( map[string]int )
if 0 < filterCount {
c.log( "Filtering dockerfiles" )
for _, filter := range filters {
td := ProcessFilter( filter )
for _, image := range c.Images {
if -1 != strings.Index( image.Dockerfile, td.Target ) {
c.log( "Found match for filter " + td.Target + " of Dockerfile for image: " + image.Name )
counts[image.Name] += 1
}
}
}
for k, v := range counts {
if v == filterCount { // Every filter matches
// Find the image and add it
for _, e := range c.Images {
if e.Name == k {
c.Results = append( c.Results, e ) // Add it to the results
}
}
}
}
} else {
// No filters, give back all results
c.Results = c.Images
}
}
type TargetDescription struct {
Src bool
Version string
Target string
}
func ProcessFilter( needle string ) *TargetDescription {
td := new(TargetDescription)
td.Src = false
td.Version = ""
usingColon := strings.Index( needle, ":" )
usingComma := strings.Index( needle, "," )
if -1 !=usingColon || -1 != usingComma {
// Split it up, using the correct delimiter
delimiter := ":"
if -1 != usingComma {
delimiter = ","
}
pieces := strings.Split( needle, delimiter )
needle = pieces[0]
for _,e := range pieces[1:] {
if "src" == e {
td.Src = true
} else {
// assume it is the version
td.Version = e
}
}
}
td.Target = needle
return td
}
type DockerResults struct {
Results []DockerImage `json:"results"`
Query string `json:"query"`
}
type DockerImage struct {
Description string
IsOfficial bool `json:"is_official"`
IsTrusted bool `json:"is_trusted"`
Name string
StarCount int `json:"star_count"`
Dockerfile string `json:"dockerfile"`
}
func (c* Client) Query( term string ) bool {
rv := true
// GET /v1/search?q=search_term HTTP/1.1
// Host: example.com
// Accept: application/json
url := c.config.Host + c.config.Endpoint + "?q=" + term
body := c.Http.Get( url )
var res DockerResults
err := json.Unmarshal(body, &res)
if nil == err {
c.Images = res.Results
c.Results = res.Results
} else {
log.Fatal( err )
}
return rv
}