/
marshal.go
134 lines (122 loc) · 4.59 KB
/
marshal.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
// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
// The tools package supports locating, parsing, and filtering Ubuntu tools metadata in simplestreams format.
// See http://launchpad.net/simplestreams and in particular the doc/README file in that project for more information
// about the file formats.
package tools
import (
"encoding/json"
"fmt"
"time"
"github.com/juju/utils/set"
"github.com/juju/juju/environs/simplestreams"
"github.com/juju/juju/version"
)
// ToolsContentId returns the tools content id for the given stream.
func ToolsContentId(stream string) string {
return fmt.Sprintf("com.ubuntu.juju:%s:tools", stream)
}
// ProductMetadataPath returns the tools product metadata path for the given stream.
func ProductMetadataPath(stream string) string {
return fmt.Sprintf("streams/v1/com.ubuntu.juju-%s-tools.json", stream)
}
// MarshalToolsMetadataJSON marshals tools metadata to index and products JSON.
// updated is the time at which the JSON file was updated.
func MarshalToolsMetadataJSON(metadata map[string][]*ToolsMetadata, updated time.Time) (index, legacyIndex []byte, products map[string][]byte, err error) {
if index, legacyIndex, err = marshalToolsMetadataIndexJSON(metadata, updated); err != nil {
return nil, nil, nil, err
}
if products, err = MarshalToolsMetadataProductsJSON(metadata, updated); err != nil {
return nil, nil, nil, err
}
return index, legacyIndex, products, err
}
// marshalToolsMetadataIndexJSON marshals tools metadata to index JSON.
// updated is the time at which the JSON file was updated.
func marshalToolsMetadataIndexJSON(streamMetadata map[string][]*ToolsMetadata, updated time.Time) (out, outlegacy []byte, err error) {
var indices simplestreams.Indices
indices.Updated = updated.Format(time.RFC1123Z)
indices.Format = simplestreams.IndexFormat
indices.Indexes = make(map[string]*simplestreams.IndexMetadata, len(streamMetadata))
var indicesLegacy simplestreams.Indices
indicesLegacy.Updated = updated.Format(time.RFC1123Z)
indicesLegacy.Format = simplestreams.IndexFormat
for stream, metadata := range streamMetadata {
var productIds []string
for _, t := range metadata {
id, err := t.productId()
if err != nil {
if version.IsUnknownSeriesVersionError(err) {
logger.Infof("ignoring tools metadata with unknown series %q", t.Release)
continue
}
return nil, nil, err
}
productIds = append(productIds, id)
}
indexMetadata := &simplestreams.IndexMetadata{
Updated: indices.Updated,
Format: simplestreams.ProductFormat,
DataType: ContentDownload,
ProductsFilePath: ProductMetadataPath(stream),
ProductIds: set.NewStrings(productIds...).SortedValues(),
}
indices.Indexes[ToolsContentId(stream)] = indexMetadata
if stream == ReleasedStream {
indicesLegacy.Indexes = make(map[string]*simplestreams.IndexMetadata, 1)
indicesLegacy.Indexes[ToolsContentId(stream)] = indexMetadata
}
}
out, err = json.MarshalIndent(&indices, "", " ")
if len(indicesLegacy.Indexes) == 0 {
return out, nil, err
}
outlegacy, err = json.MarshalIndent(&indicesLegacy, "", " ")
if err != nil {
return nil, nil, err
}
return out, outlegacy, nil
}
// MarshalToolsMetadataProductsJSON marshals tools metadata to products JSON.
// updated is the time at which the JSON file was updated.
func MarshalToolsMetadataProductsJSON(
streamMetadata map[string][]*ToolsMetadata, updated time.Time,
) (out map[string][]byte, err error) {
out = make(map[string][]byte, len(streamMetadata))
for stream, metadata := range streamMetadata {
var cloud simplestreams.CloudMetadata
cloud.Updated = updated.Format(time.RFC1123Z)
cloud.Format = simplestreams.ProductFormat
cloud.ContentId = ToolsContentId(stream)
cloud.Products = make(map[string]simplestreams.MetadataCatalog)
itemsversion := updated.Format("20060102") // YYYYMMDD
for _, t := range metadata {
id, err := t.productId()
if err != nil {
if version.IsUnknownSeriesVersionError(err) {
continue
}
return nil, err
}
itemid := fmt.Sprintf("%s-%s-%s", t.Version, t.Release, t.Arch)
if catalog, ok := cloud.Products[id]; ok {
catalog.Items[itemsversion].Items[itemid] = t
} else {
catalog = simplestreams.MetadataCatalog{
Arch: t.Arch,
Version: t.Version,
Items: map[string]*simplestreams.ItemCollection{
itemsversion: {
Items: map[string]interface{}{itemid: t},
},
},
}
cloud.Products[id] = catalog
}
}
if out[stream], err = json.MarshalIndent(&cloud, "", " "); err != nil {
return nil, err
}
}
return out, nil
}