forked from juju/juju
-
Notifications
You must be signed in to change notification settings - Fork 0
/
charm.go
130 lines (109 loc) · 3.25 KB
/
charm.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
// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
// Package testcharms holds a corpus of charms
// for testing.
package testcharms
import (
"archive/zip"
"bytes"
"io"
"io/ioutil"
"os"
"time"
jc "github.com/juju/testing/checkers"
gc "gopkg.in/check.v1"
"github.com/juju/charm/v9"
"github.com/juju/charmrepo/v7/testing"
jtesting "github.com/juju/juju/testing"
)
const (
defaultSeries = "quantal"
localCharmRepo = "charm-repo"
localCharmHub = "charm-hub"
)
// Repo provides access to the test charm repository.
var Repo = testing.NewRepo(localCharmRepo, defaultSeries)
// Hub provides access to the test charmhub repository.
var Hub = testing.NewRepo(localCharmHub, defaultSeries)
// RepoForSeries returns a new charm repository for the specified series.
// Note: this is a bit weird, as it ignores the series if it's NOT kubernetes
// and falls back to the default series, which makes this pretty pointless.
func RepoForSeries(series string) *testing.Repo {
return testing.NewRepo(localCharmRepo, series)
}
// RepoWithSeries returns a new charm repository for the specified series.
func RepoWithSeries(series string) *testing.Repo {
return testing.NewRepo(localCharmRepo, series)
}
// CheckCharmReady ensures that a desired charm archive exists and
// has some content.
func CheckCharmReady(c *gc.C, charmArchive *charm.CharmArchive) {
fileSize := func() int64 {
f, err := os.Open(charmArchive.Path)
c.Assert(err, jc.ErrorIsNil)
defer f.Close()
fi, err := f.Stat()
c.Assert(err, jc.ErrorIsNil)
return fi.Size()
}
var oldSize, currentSize int64
var charmReady bool
runs := 1
timeout := time.After(jtesting.LongWait)
for !charmReady {
select {
case <-time.After(jtesting.ShortWait):
currentSize = fileSize()
// Since we do not know when the charm is ready, for as long as the size changes
// we'll assume that we'd need to wait.
charmReady = oldSize != 0 && currentSize == oldSize
c.Logf("%d: new file size %v (old size %v)", runs, currentSize, oldSize)
oldSize = currentSize
runs++
case <-timeout:
c.Fatalf("timed out waiting for charm @%v to be ready", charmArchive.Path)
}
}
}
// InjectFilesToCharmArchive overwrites the contents of pathToArchive with a
// new archive containing the original files plus the ones provided in the
// fileContents map (key: file name, value: file contents).
func InjectFilesToCharmArchive(pathToArchive string, fileContents map[string]string) error {
zr, err := zip.OpenReader(pathToArchive)
if err != nil {
return err
}
defer func() { _ = zr.Close() }()
var buf bytes.Buffer
zw := zip.NewWriter(&buf)
defer func() { _ = zw.Close() }()
// Copy existing files
for _, f := range zr.File {
w, err := zw.CreateHeader(&f.FileHeader)
if err != nil {
return err
}
r, err := f.Open()
if err != nil {
return err
}
_, err = io.Copy(w, r)
_ = r.Close()
if err != nil {
return err
}
}
// Add new files
for name, contents := range fileContents {
w, err := zw.Create(name)
if err != nil {
return err
}
if _, err = w.Write([]byte(contents)); err != nil {
return err
}
}
// Overwrite original archive with the patched version
_, _ = zr.Close(), zw.Close()
return ioutil.WriteFile(pathToArchive, buf.Bytes(), 0644)
}