Skip to content

Commit 7ff6918

Browse files
authored
Merge pull request #1490 from imnitishng/cache-flag/build-volume-cache
Add 'volume' cache format support for --cache flag
2 parents 30de289 + 1eb52c0 commit 7ff6918

9 files changed

Lines changed: 298 additions & 153 deletions

File tree

acceptance/acceptance_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -780,8 +780,8 @@ func testAcceptance(
780780
ref, err := name.ParseReference(repoName, name.WeakValidation)
781781
assert.Nil(err)
782782
cacheImage := cache.NewImageCache(ref, dockerCli)
783-
buildCacheVolume := cache.NewVolumeCache(ref, "build", dockerCli)
784-
launchCacheVolume := cache.NewVolumeCache(ref, "launch", dockerCli)
783+
buildCacheVolume := cache.NewVolumeCache(ref, cache.CacheInfo{}, "build", dockerCli)
784+
launchCacheVolume := cache.NewVolumeCache(ref, cache.CacheInfo{}, "launch", dockerCli)
785785
cacheImage.Clear(context.TODO())
786786
buildCacheVolume.Clear(context.TODO())
787787
launchCacheVolume.Clear(context.TODO())
@@ -2423,8 +2423,8 @@ include = [ "*.jar", "media/mountain.jpg", "/media/person.png", ]
24232423
imageManager.CleanupImages(origID, repoName, runBefore)
24242424
ref, err := name.ParseReference(repoName, name.WeakValidation)
24252425
assert.Nil(err)
2426-
buildCacheVolume := cache.NewVolumeCache(ref, "build", dockerCli)
2427-
launchCacheVolume := cache.NewVolumeCache(ref, "launch", dockerCli)
2426+
buildCacheVolume := cache.NewVolumeCache(ref, cache.CacheInfo{}, "build", dockerCli)
2427+
launchCacheVolume := cache.NewVolumeCache(ref, cache.CacheInfo{}, "launch", dockerCli)
24282428
assert.Succeeds(buildCacheVolume.Clear(context.TODO()))
24292429
assert.Succeeds(launchCacheVolume.Clear(context.TODO()))
24302430
})

internal/build/lifecycle_execution.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,18 @@ func (l *LifecycleExecution) PrevImageName() string {
124124
func (l *LifecycleExecution) Run(ctx context.Context, phaseFactoryCreator PhaseFactoryCreator) error {
125125
phaseFactory := phaseFactoryCreator(l)
126126
var buildCache Cache
127-
if l.opts.CacheImage != "" || (l.opts.Cache.CacheType == cache.Build && l.opts.Cache.Format == cache.CacheImage) {
127+
if l.opts.CacheImage != "" || (l.opts.Cache.Build.Format == cache.CacheImage) {
128128
cacheImageName := l.opts.CacheImage
129129
if cacheImageName == "" {
130-
cacheImageName = l.opts.Cache.Source
130+
cacheImageName = l.opts.Cache.Build.Source
131131
}
132132
cacheImage, err := name.ParseReference(cacheImageName, name.WeakValidation)
133133
if err != nil {
134134
return fmt.Errorf("invalid cache image name: %s", err)
135135
}
136136
buildCache = cache.NewImageCache(cacheImage, l.docker)
137137
} else {
138-
buildCache = cache.NewVolumeCache(l.opts.Image, "build", l.docker)
138+
buildCache = cache.NewVolumeCache(l.opts.Image, l.opts.Cache.Build, "build", l.docker)
139139
}
140140

141141
l.logger.Debugf("Using build cache volume %s", style.Symbol(buildCache.Name()))
@@ -146,7 +146,7 @@ func (l *LifecycleExecution) Run(ctx context.Context, phaseFactoryCreator PhaseF
146146
l.logger.Debugf("Build cache %s cleared", style.Symbol(buildCache.Name()))
147147
}
148148

149-
launchCache := cache.NewVolumeCache(l.opts.Image, "launch", l.docker)
149+
launchCache := cache.NewVolumeCache(l.opts.Image, l.opts.Cache.Launch, "launch", l.docker)
150150

151151
if !l.opts.UseCreator {
152152
if l.platformAPI.LessThan("0.7") {

internal/build/lifecycle_execution_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,9 +365,10 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) {
365365
TrustBuilder: false,
366366
UseCreator: false,
367367
Cache: cache.CacheOpts{
368-
CacheType: cache.Build,
369-
Format: cache.CacheImage,
370-
Source: "%%%",
368+
Build: cache.CacheInfo{
369+
Format: cache.CacheImage,
370+
Source: "%%%",
371+
},
371372
},
372373
Termui: fakeTermui,
373374
}

internal/cache/cache_opts.go

Lines changed: 42 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,21 @@ import (
88
"github.com/pkg/errors"
99
)
1010

11-
type Cache int
1211
type Format int
12+
type CacheInfo struct {
13+
Format Format
14+
Source string
15+
}
1316
type CacheOpts struct {
14-
CacheType Cache
15-
Format Format
16-
Source string
17+
Build CacheInfo
18+
Launch CacheInfo
1719
}
1820

19-
const (
20-
Build Cache = iota
21-
Launch
22-
)
2321
const (
2422
CacheVolume Format = iota
2523
CacheImage
2624
)
2725

28-
func (c Cache) String() string {
29-
switch c {
30-
case Build:
31-
return "build"
32-
case Launch:
33-
return "launch"
34-
}
35-
return ""
36-
}
37-
3826
func (f Format) String() string {
3927
switch f {
4028
case CacheImage:
@@ -53,36 +41,46 @@ func (c *CacheOpts) Set(value string) error {
5341
return err
5442
}
5543

44+
cache := &c.Build
5645
for _, field := range fields {
5746
parts := strings.SplitN(field, "=", 2)
58-
5947
if len(parts) != 2 {
6048
return errors.Errorf("invalid field '%s' must be a key=value pair", field)
6149
}
50+
key := strings.ToLower(parts[0])
51+
value := strings.ToLower(parts[1])
52+
if key == "type" {
53+
switch value {
54+
case "build":
55+
cache = &c.Build
56+
case "launch":
57+
cache = &c.Launch
58+
default:
59+
return errors.Errorf("invalid cache type '%s'", value)
60+
}
61+
break
62+
}
63+
}
6264

63-
if len(parts) == 2 {
64-
key := strings.ToLower(parts[0])
65-
value := strings.ToLower(parts[1])
66-
switch key {
67-
case "type":
68-
switch value {
69-
case "build":
70-
c.CacheType = Build
71-
case "launch":
72-
c.CacheType = Launch
73-
default:
74-
return errors.Errorf("invalid cache type '%s'", value)
75-
}
76-
case "format":
77-
switch value {
78-
case "image":
79-
c.Format = CacheImage
80-
default:
81-
return errors.Errorf("invalid cache format '%s'", value)
82-
}
83-
case "name":
84-
c.Source = value
65+
for _, field := range fields {
66+
parts := strings.SplitN(field, "=", 2)
67+
if len(parts) != 2 {
68+
return errors.Errorf("invalid field '%s' must be a key=value pair", field)
69+
}
70+
key := strings.ToLower(parts[0])
71+
value := strings.ToLower(parts[1])
72+
switch key {
73+
case "format":
74+
switch value {
75+
case "image":
76+
cache.Format = CacheImage
77+
case "volume":
78+
cache.Format = CacheVolume
79+
default:
80+
return errors.Errorf("invalid cache format '%s'", value)
8581
}
82+
case "name":
83+
cache.Source = value
8684
}
8785
}
8886

@@ -95,15 +93,8 @@ func (c *CacheOpts) Set(value string) error {
9593

9694
func (c *CacheOpts) String() string {
9795
var cacheFlag string
98-
if c.CacheType.String() != "" {
99-
cacheFlag += fmt.Sprintf("type=%s;", c.CacheType)
100-
}
101-
if c.Format.String() != "" {
102-
cacheFlag += fmt.Sprintf("format=%s;", c.Format)
103-
}
104-
if c.Source != "" {
105-
cacheFlag += fmt.Sprintf("name=%s", c.Source)
106-
}
96+
cacheFlag = fmt.Sprintf("type=build;format=%s;name=%s;", c.Build.Format.String(), c.Build.Source)
97+
cacheFlag += fmt.Sprintf("type=launch;format=%s;name=%s;", c.Launch.Format.String(), c.Launch.Source)
10798
return cacheFlag
10899
}
109100

@@ -112,7 +103,7 @@ func (c *CacheOpts) Type() string {
112103
}
113104

114105
func populateMissing(c *CacheOpts) error {
115-
if c.Source == "" {
106+
if (c.Build.Source == "" && c.Build.Format == CacheImage) || (c.Launch.Source == "" && c.Launch.Format == CacheImage) {
116107
return errors.Errorf("cache 'name' is required")
117108
}
118109
return nil

internal/cache/cache_opts_test.go

Lines changed: 83 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,18 @@ func TestMetadata(t *testing.T) {
2424
}
2525

2626
func testCacheOpts(t *testing.T, when spec.G, it spec.S) {
27-
when("cache options are passed", func() {
28-
it("image cache format with complete options", func() {
27+
when("image cache format options are passed", func() {
28+
it("with complete options", func() {
2929
testcases := []CacheOptTestCase{
3030
{
3131
name: "Build cache as Image",
3232
input: "type=build;format=image;name=io.test.io/myorg/my-cache:build",
33-
output: "type=build;format=image;name=io.test.io/myorg/my-cache:build",
33+
output: "type=build;format=image;name=io.test.io/myorg/my-cache:build;type=launch;format=volume;name=;",
3434
},
3535
{
3636
name: "Launch cache as Image",
3737
input: "type=launch;format=image;name=io.test.io/myorg/my-cache:build",
38-
output: "type=launch;format=image;name=io.test.io/myorg/my-cache:build",
38+
output: "type=build;format=volume;name=;type=launch;format=image;name=io.test.io/myorg/my-cache:build;",
3939
},
4040
}
4141

@@ -48,22 +48,17 @@ func testCacheOpts(t *testing.T, when spec.G, it spec.S) {
4848
}
4949
})
5050

51-
it("image cache format with missing options", func() {
51+
it("with missing options", func() {
5252
successTestCases := []CacheOptTestCase{
5353
{
5454
name: "Build cache as Image missing: type",
5555
input: "format=image;name=io.test.io/myorg/my-cache:build",
56-
output: "type=build;format=image;name=io.test.io/myorg/my-cache:build",
56+
output: "type=build;format=image;name=io.test.io/myorg/my-cache:build;type=launch;format=volume;name=;",
5757
},
5858
{
5959
name: "Build cache as Image missing: format",
6060
input: "type=build;name=io.test.io/myorg/my-cache:build",
61-
output: "type=build;format=volume;name=io.test.io/myorg/my-cache:build",
62-
},
63-
{
64-
name: "Build cache as Image missing: type, format",
65-
input: "name=io.test.io/myorg/my-cache:build",
66-
output: "type=build;format=volume;name=io.test.io/myorg/my-cache:build",
61+
output: "type=build;format=volume;name=io.test.io/myorg/my-cache:build;type=launch;format=volume;name=;",
6762
},
6863
{
6964
name: "Build cache as Image missing: name",
@@ -72,10 +67,14 @@ func testCacheOpts(t *testing.T, when spec.G, it spec.S) {
7267
shouldFail: true,
7368
},
7469
{
75-
name: "Build cache as Image missing: format, name",
76-
input: "type=build",
77-
output: "cache 'name' is required",
78-
shouldFail: true,
70+
name: "Build cache as Image missing: type, format",
71+
input: "name=io.test.io/myorg/my-cache:build",
72+
output: "type=build;format=volume;name=io.test.io/myorg/my-cache:build;type=launch;format=volume;name=;",
73+
},
74+
{
75+
name: "Build cache as Image missing: format, name",
76+
input: "type=build",
77+
output: "type=build;format=volume;name=;type=launch;format=volume;name=;",
7978
},
8079
{
8180
name: "Build cache as Image missing: type, name",
@@ -94,6 +93,9 @@ func testCacheOpts(t *testing.T, when spec.G, it spec.S) {
9493
for _, testcase := range successTestCases {
9594
var cacheFlags CacheOpts
9695
t.Logf("Testing cache type: %s", testcase.name)
96+
if testcase.name == "Everything missing" {
97+
print("i am here")
98+
}
9799
err := cacheFlags.Set(testcase.input)
98100

99101
if testcase.shouldFail {
@@ -106,7 +108,7 @@ func testCacheOpts(t *testing.T, when spec.G, it spec.S) {
106108
}
107109
})
108110

109-
it("image cache format with invalid options", func() {
111+
it("with invalid options", func() {
110112
testcases := []CacheOptTestCase{
111113
{
112114
name: "Invalid cache type",
@@ -142,4 +144,68 @@ func testCacheOpts(t *testing.T, when spec.G, it spec.S) {
142144
}
143145
})
144146
})
147+
148+
when("volume cache format options are passed", func() {
149+
it("with complete options", func() {
150+
testcases := []CacheOptTestCase{
151+
{
152+
name: "Build cache as Volume",
153+
input: "type=build;format=volume;name=test-build-volume-cache",
154+
output: "type=build;format=volume;name=test-build-volume-cache;type=launch;format=volume;name=;",
155+
},
156+
{
157+
name: "Launch cache as Volume",
158+
input: "type=launch;format=volume;name=test-launch-volume-cache",
159+
output: "type=build;format=volume;name=;type=launch;format=volume;name=test-launch-volume-cache;",
160+
},
161+
}
162+
163+
for _, testcase := range testcases {
164+
var cacheFlags CacheOpts
165+
t.Logf("Testing cache type: %s", testcase.name)
166+
err := cacheFlags.Set(testcase.input)
167+
h.AssertNil(t, err)
168+
h.AssertEq(t, testcase.output, cacheFlags.String())
169+
}
170+
})
171+
172+
it("with missing options", func() {
173+
successTestCases := []CacheOptTestCase{
174+
{
175+
name: "Launch cache as Volume missing: format",
176+
input: "type=launch;name=test-launch-volume",
177+
output: "type=build;format=volume;name=;type=launch;format=volume;name=test-launch-volume;",
178+
},
179+
{
180+
name: "Launch cache as Volume missing: name",
181+
input: "type=launch;format=volume",
182+
output: "type=build;format=volume;name=;type=launch;format=volume;name=;",
183+
},
184+
{
185+
name: "Launch cache as Volume missing: format, name",
186+
input: "type=launch",
187+
output: "type=build;format=volume;name=;type=launch;format=volume;name=;",
188+
},
189+
{
190+
name: "Launch cache as Volume missing: type, name",
191+
input: "format=volume",
192+
output: "type=build;format=volume;name=;type=launch;format=volume;name=;",
193+
},
194+
}
195+
196+
for _, testcase := range successTestCases {
197+
var cacheFlags CacheOpts
198+
t.Logf("Testing cache type: %s", testcase.name)
199+
err := cacheFlags.Set(testcase.input)
200+
201+
if testcase.shouldFail {
202+
h.AssertError(t, err, testcase.output)
203+
} else {
204+
h.AssertNil(t, err)
205+
output := cacheFlags.String()
206+
h.AssertEq(t, testcase.output, output)
207+
}
208+
}
209+
})
210+
})
145211
}

internal/cache/volume_cache.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,18 @@ type VolumeCache struct {
1717
volume string
1818
}
1919

20-
func NewVolumeCache(imageRef name.Reference, suffix string, dockerClient client.CommonAPIClient) *VolumeCache {
21-
sum := sha256.Sum256([]byte(imageRef.Name()))
20+
func NewVolumeCache(imageRef name.Reference, cacheType CacheInfo, suffix string, dockerClient client.CommonAPIClient) *VolumeCache {
21+
var volumeName string
22+
if cacheType.Source == "" {
23+
sum := sha256.Sum256([]byte(imageRef.Name()))
24+
vol := paths.FilterReservedNames(fmt.Sprintf("%s-%x", sanitizedRef(imageRef), sum[:6]))
25+
volumeName = fmt.Sprintf("pack-cache-%s.%s", vol, suffix)
26+
} else {
27+
volumeName = paths.FilterReservedNames(cacheType.Source)
28+
}
2229

23-
vol := paths.FilterReservedNames(fmt.Sprintf("%s-%x", sanitizedRef(imageRef), sum[:6]))
2430
return &VolumeCache{
25-
volume: fmt.Sprintf("pack-cache-%s.%s", vol, suffix),
31+
volume: volumeName,
2632
docker: dockerClient,
2733
}
2834
}

0 commit comments

Comments
 (0)