Skip to content

Commit

Permalink
Stop combining annotations and labels
Browse files Browse the repository at this point in the history
Representing labels as annotations starting with label: was more confusing than
any code/efficiency gain. Split labels and annotations fully apart.
  • Loading branch information
owtaylor committed Oct 7, 2017
1 parent f34fa71 commit 21f4f44
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 23 deletions.
20 changes: 20 additions & 0 deletions database.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ type Query struct {
os []QueryTerm
architecture []QueryTerm
annotations map[string][]QueryTerm
labels map[string][]QueryTerm
}

func NewQuery() *Query {
return &Query{
annotations: make(map[string][]QueryTerm),
labels: make(map[string][]QueryTerm),
}
}

Expand Down Expand Up @@ -76,6 +78,24 @@ func (q *Query) AnnotationMatches(annotation string, pattern string) *Query {
return q
}

func (q *Query) LabelExists(label string) *Query {
q.labels[label] = append(q.labels[label],
QueryTerm{QueryExists, ""})
return q
}

func (q *Query) LabelIs(label string, value string) *Query {
q.labels[label] = append(q.labels[label],
QueryTerm{QueryIs, value})
return q
}

func (q *Query) LabelMatches(label string, pattern string) *Query {
q.labels[label] = append(q.labels[label],
QueryTerm{QueryMatches, pattern})
return q
}

type Tx interface {
Commit() error
Rollback() error
Expand Down
9 changes: 6 additions & 3 deletions docs/protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,11 @@ The basic structure of the JSON returned from a request is:
"OS": "<os>",
"Architecture": "<architecture>",
"Annotations": {
"org.example.annotations.x": "<value>",
"label:com.redhat.component": "<value>",
"org.example.annotations.x": "<value>"
}
"Labels": {
"com.redhat.component": "<value>"
}
}
```

Expand All @@ -84,7 +86,8 @@ The basic structure of the JSON returned from a request is:
* **`MediaType`**: `application/vnd.oci.image.manifest.v1+json` or `application/vnd.docker.distribution.manifest.v2+json`
* **`OS`**: The operating system that this image is for. Values are as for [`GOOS`](https://golang.org/doc/install/source#environment).
* **`Architecture`**: The architecture this image is for. Values are as for [`GOARCH`](https://golang.org/doc/install/source#environment).
* **`Annotations`**: Annotations applied to the image. An annotations that starts with label: (which would not be a valid annotation valid according to the OCI specification) represents a label applied to the image.
* **`Annotations`**: Annotations applied to the image.
* **`Labels`**: Labels applied to the image

**Image List**

Expand Down
3 changes: 2 additions & 1 deletion fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ func (f *Fetcher) fetchImage(op *fetchOperation, dgst digest.Digest, image *Imag

image.Digest = dgst
image.Annotations = make(map[string]string)
image.Labels = make(map[string]string)

var labelMap *map[string]interface{}

Expand Down Expand Up @@ -278,7 +279,7 @@ func (f *Fetcher) fetchImage(op *fetchOperation, dgst digest.Digest, image *Imag
for label, value := range *labelMap {
valueString, ok := value.(string)
if ok {
image.Annotations["label:"+label] = valueString
image.Labels[label] = valueString
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,10 +355,11 @@ func (ptx postgresTransaction) SetImageListTags(repository string, dgst digest.D
func (ptx postgresTransaction) storeImage(repository string, image *Image) error {
log.Printf("Storing image %s/%s", repository, image.Digest)
annotationsJson, _ := json.Marshal(image.Annotations)
labelsJson, _ := json.Marshal(image.Labels)
_, err := ptx.exec(
`INSERT INTO image (Digest, MediaType, Architecture, OS, Annotations) `+
`VALUES ($1, $2, $3, $4, $5) ON CONFLICT (digest) DO NOTHING `,
image.Digest, image.MediaType, image.Architecture, image.OS, annotationsJson)
`INSERT INTO image (Digest, MediaType, Architecture, OS, Annotations, Labels) `+
`VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (digest) DO NOTHING `,
image.Digest, image.MediaType, image.Architecture, image.OS, annotationsJson, labelsJson)
return err
}

Expand Down
3 changes: 2 additions & 1 deletion schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ CREATE TABLE image (
MediaType text,
Architecture text,
OS text,
Annotations jsonb
Annotations jsonb,
Labels jsonb
);
CREATE INDEX imageAnnotations ON image USING gin(Annotations);

Expand Down
10 changes: 9 additions & 1 deletion templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,17 @@ description: {{.}}
{{- end }}
architecture: {{.Architecture}}
os: {{.OS}}
{{- with .Annotations}}
annotations:
{{- range $k, $v := .Annotations}}
{{- range $k, $v := .}}
{{$k}}: {{$v}}
{{- end}}
{{- end -}}
{{- with .Labels}}
labels:
{{- range $k, $v := .}}
{{$k}}: {{$v}}
{{- end}}
{{- end -}}
{{- end}}
<ul>
Expand Down
17 changes: 9 additions & 8 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type Image struct {
OS string
Architecture string
Annotations map[string]string
Labels map[string]string
}

type TaggedImage struct {
Expand Down Expand Up @@ -38,13 +39,13 @@ type Repository struct {
func (im *Image) Title() string {
if v := im.Annotations["org.opencontainers.image.title"]; v != "" {
return v
} else if v := im.Annotations["label:org.label-schema.name"]; v != "" {
} else if v := im.Labels["org.label-schema.name"]; v != "" {
return v
} else if v := im.Annotations["label:io.k8s.display-name"]; v != "" {
} else if v := im.Labels["io.k8s.display-name"]; v != "" {
return v
} else if v := im.Annotations["label:name"]; v != "" {
} else if v := im.Labels["name"]; v != "" {
return v
} else if v := im.Annotations["label:Name"]; v != "" {
} else if v := im.Labels["Name"]; v != "" {
return v
} else {
return ""
Expand All @@ -53,13 +54,13 @@ func (im *Image) Title() string {
func (im *Image) Description() string {
if v := im.Annotations["org.opencontainers.image.description"]; v != "" {
return v
} else if v := im.Annotations["label:org.label-schema.description"]; v != "" {
} else if v := im.Labels["org.label-schema.description"]; v != "" {
return v
} else if v := im.Annotations["label:io.k8s.description"]; v != "" {
} else if v := im.Labels["io.k8s.description"]; v != "" {
return v
} else if v := im.Annotations["label:description"]; v != "" {
} else if v := im.Labels["description"]; v != "" {
return v
} else if v := im.Annotations["label:Description"]; v != "" {
} else if v := im.Labels["Description"]; v != "" {
return v
} else {
return ""
Expand Down
16 changes: 10 additions & 6 deletions wherebuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,19 @@ func (wb *whereBuilder) makeWhereSubclause(subject string, terms []QueryTerm) {
wb.addPiece("")
}

func (wb *whereBuilder) makeAnnotationSubclause(annotation string, terms []QueryTerm) {
func (wb *whereBuilder) makeMapSubclause(name string, key string, terms []QueryTerm) {
for _, term := range terms {
switch term.queryType {
case QueryIs:
wb.addPiece(`i.Annotations ? ` + wb.addArg(annotation))
wb.addPiece(`i.` + name + ` ? ` + wb.addArg(key))
case QueryMatches:
wb.addPiece(`jsonb_object_field_text(i.Annotations, ` + wb.addArg(annotation) + `) ` +
wb.addPiece(`jsonb_object_field_text(i.` + name + `, ` + wb.addArg(key) + `) ` +
`like ` + wb.addArg(likePattern(term.argument)))
case QueryExists:
argJson, _ := json.Marshal(map[string]string{
annotation: term.argument,
key: term.argument,
})
wb.addPiece(`i.Annotations @> ` + wb.addArg(string(argJson)))
wb.addPiece(`i.` + name + ` @> ` + wb.addArg(string(argJson)))
}
}
wb.addPiece("")
Expand Down Expand Up @@ -134,7 +134,11 @@ func makeWhereClause(query *Query) (clause string, args []interface{}) {
}

for annotation, terms := range query.annotations {
wb.makeAnnotationSubclause(annotation, terms)
wb.makeMapSubclause("Annotations", annotation, terms)
}

for label, terms := range query.labels {
wb.makeMapSubclause("Labels", label, terms)
}

args = wb.args
Expand Down
9 changes: 9 additions & 0 deletions wherebuilder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ func TestMakeWhereClause(t *testing.T) {
expectWhereClause(t, NewQuery().AnnotationMatches("org.fishsoup.nonsense", "foo-*"),
" WHERE jsonb_object_field_text(i.Annotations, $1) like $2",
"org.fishsoup.nonsense", "foo-%")
expectWhereClause(t, NewQuery().LabelIs("org.fishsoup.nonsense", "foo"),
" WHERE i.Labels ? $1",
"org.fishsoup.nonsense")
expectWhereClause(t, NewQuery().LabelExists("org.fishsoup.nonsense"),
" WHERE i.Labels @> $1",
`{"org.fishsoup.nonsense":""}`)
expectWhereClause(t, NewQuery().LabelMatches("org.fishsoup.nonsense", "foo-*"),
" WHERE jsonb_object_field_text(i.Labels, $1) like $2",
"org.fishsoup.nonsense", "foo-%")

expectWhereClause(t, NewQuery(), "")
expectWhereClause(t, NewQuery().Repository("foo").Repository("bar"),
Expand Down

0 comments on commit 21f4f44

Please sign in to comment.