1
// Copyright 2012, 2013 Canonical Ltd.
2
// Licensed under the LGPLv3, see LICENCE file for details.
15
"github.com/juju/testing/filetesting"
16
gc "gopkg.in/check.v1"
18
"gopkg.in/juju/charm.v5"
21
// Charm holds a charm for testing. It does not
22
// have a representation on disk by default, but
23
// can be written to disk using Archive and its ExpandTo
24
// method. It implements the charm.Charm interface.
26
// All methods on Charm may be called concurrently.
30
actions *charm.Actions
31
metrics *charm.Metrics
34
files filetesting.Entries
36
makeArchiveOnce sync.Once
38
archive *charm.CharmArchive
41
// CharmSpec holds the specification for a charm. The fields
42
// hold data in YAML format.
43
type CharmSpec struct {
44
// Meta holds the contents of metadata.yaml.
47
// Config holds the contents of config.yaml.
50
// Actions holds the contents of actions.yaml.
53
// Metrics holds the contents of metrics.yaml.
56
// Files holds any additional files that should be
57
// added to the charm. If this is nil, a minimal set
58
// of files will be added to ensure the charm is readable.
59
Files []filetesting.Entry
61
// Revision specifies the revision of the charm.
65
// NewCharm returns a new charm
66
func NewCharm(c *gc.C, spec CharmSpec) *Charm {
68
revision: spec.Revision,
71
ch.meta, err = charm.ReadMeta(strings.NewReader(spec.Meta))
72
c.Assert(err, gc.IsNil)
73
ch.files = append(ch.files, filetesting.File{
74
Path: "metadata.yaml",
79
if spec.Config != "" {
80
ch.config, err = charm.ReadConfig(strings.NewReader(spec.Config))
81
c.Assert(err, gc.IsNil)
82
ch.files = append(ch.files, filetesting.File{
88
if spec.Actions != "" {
89
ch.actions, err = charm.ReadActionsYaml(strings.NewReader(spec.Actions))
90
c.Assert(err, gc.IsNil)
91
ch.files = append(ch.files, filetesting.File{
97
if spec.Metrics != "" {
98
ch.metrics, err = charm.ReadMetrics(strings.NewReader(spec.Metrics))
99
c.Assert(err, gc.IsNil)
100
ch.files = append(ch.files, filetesting.File{
101
Path: "metrics.yaml",
106
if spec.Files == nil {
107
ch.files = append(ch.files, filetesting.File{
108
Path: "hooks/install",
117
ch.files = append(ch.files, spec.Files...)
118
// Check for duplicates.
119
names := make(map[string]bool)
120
for _, f := range ch.files {
121
name := path.Clean(f.GetPath())
123
panic(fmt.Errorf("duplicate file entry %q", f.GetPath()))
131
// Meta implements charm.Charm.Meta.
132
func (ch *Charm) Meta() *charm.Meta {
136
// Config implements charm.Charm.Config.
137
func (ch *Charm) Config() *charm.Config {
138
if ch.config == nil {
139
return &charm.Config{
140
Options: map[string]charm.Option{},
146
// Metrics implements charm.Charm.Metrics.
147
func (ch *Charm) Metrics() *charm.Metrics {
151
// Actions implements charm.Charm.Actions.
152
func (ch *Charm) Actions() *charm.Actions {
153
if ch.actions == nil {
154
return &charm.Actions{}
159
// Revision implements charm.Charm.Revision.
160
func (ch *Charm) Revision() int {
164
// Archive returns a charm archive holding the charm.
165
func (ch *Charm) Archive() *charm.CharmArchive {
166
ch.makeArchiveOnce.Do(ch.makeArchive)
170
// ArchiveBytes returns the contents of the charm archive
171
// holding the charm.
172
func (ch *Charm) ArchiveBytes() []byte {
173
ch.makeArchiveOnce.Do(ch.makeArchive)
174
return ch.archiveBytes
177
func (ch *Charm) makeArchive() {
179
zw := zip.NewWriter(&buf)
181
for _, f := range ch.files {
184
if err := zw.Close(); err != nil {
187
// ReadCharmArchiveFromReader requires a ReaderAt, so make one.
188
r := bytes.NewReader(buf.Bytes())
190
// Actually make the charm archive.
191
archive, err := charm.ReadCharmArchiveFromReader(r, int64(buf.Len()))
195
ch.archiveBytes = buf.Bytes()
197
ch.archive.SetRevision(ch.revision)
200
func addZipEntry(zw *zip.Writer, f filetesting.Entry) {
201
h := &zip.FileHeader{
203
// Don't bother compressing - the contents are so small that
204
// it will just slow things down for no particular benefit.
208
switch f := f.(type) {
209
case filetesting.Dir:
210
h.SetMode(os.ModeDir | 0755)
211
case filetesting.File:
214
case filetesting.Symlink:
215
h.SetMode(os.ModeSymlink | 0777)
218
w, err := zw.CreateHeader(h)
223
if _, err := w.Write([]byte(contents)); err != nil {