Skip to content

Commit ee5eb84

Browse files
Merge pull request #58 from bitrise-io/config-cache-command
feat: ACI-2928 Gradle save/restore config cache commands
2 parents b9c3a88 + f6edab9 commit ee5eb84

20 files changed

+788
-313
lines changed

cmd/analytics.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import (
88
"github.com/google/uuid"
99

1010
xa "github.com/bitrise-io/bitrise-build-cache-cli/internal/analytics"
11+
"github.com/bitrise-io/bitrise-build-cache-cli/internal/build_cache/kv"
1112
"github.com/bitrise-io/bitrise-build-cache-cli/internal/config/common"
1213
"github.com/bitrise-io/bitrise-build-cache-cli/internal/consts"
13-
"github.com/bitrise-io/bitrise-build-cache-cli/internal/xcode"
1414
"github.com/bitrise-io/go-utils/v2/log"
1515
)
1616

@@ -76,7 +76,7 @@ func newCacheOperation(startT time.Time, operationType string, envProvider func(
7676
return op
7777
}
7878

79-
func fillCacheOperationWithUploadStats(op *xa.CacheOperation, stats xcode.UploadFilesStats) {
79+
func fillCacheOperationWithUploadStats(op *xa.CacheOperation, stats kv.UploadFilesStats) {
8080
op.TransferSize = stats.UploadSize
8181
op.FileStats = xa.FileStats{
8282
FilesToTransfer: stats.FilesToUpload,
@@ -87,7 +87,7 @@ func fillCacheOperationWithUploadStats(op *xa.CacheOperation, stats xcode.Upload
8787
}
8888
}
8989

90-
func fillCacheOperationWithDownloadStats(op *xa.CacheOperation, stats xcode.DownloadFilesStats) {
90+
func fillCacheOperationWithDownloadStats(op *xa.CacheOperation, stats kv.DownloadFilesStats) {
9191
op.TransferSize = stats.DownloadSize
9292
op.FileStats = xa.FileStats{
9393
FilesToTransfer: stats.FilesToBeDownloaded,

cmd/client.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import (
1111
"github.com/bitrise-io/go-utils/v2/log"
1212
)
1313

14-
func createKVClient(ctx context.Context, cacheOperationID string, authConfig common.CacheAuthConfig, envProvider common.EnvProviderFunc, logger log.Logger) (*kv.Client, error) {
14+
func createKVClient(ctx context.Context,
15+
cacheOperationID string,
16+
authConfig common.CacheAuthConfig,
17+
envProvider common.EnvProviderFunc,
18+
logger log.Logger) (*kv.Client, error) {
1519
endpointURL := common.SelectEndpointURL("", envProvider)
1620
logger.Infof("(i) Build Cache Endpoint URL: %s", endpointURL)
1721

cmd/deleteXcodeDerivedData.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212

1313
"github.com/bitrise-io/bitrise-build-cache-cli/internal/build_cache/kv"
1414
"github.com/bitrise-io/bitrise-build-cache-cli/internal/config/common"
15+
"github.com/bitrise-io/bitrise-build-cache-cli/internal/filegroup"
16+
"github.com/bitrise-io/bitrise-build-cache-cli/internal/hash"
1517
"github.com/bitrise-io/bitrise-build-cache-cli/internal/xcode"
1618
"github.com/bitrise-io/go-utils/v2/log"
1719
"google.golang.org/grpc/codes"
@@ -83,11 +85,11 @@ func deleteXcodeDerivedDataCmdFn(ctx context.Context, providedCacheKey string, u
8385
}
8486

8587
func uploadEmptyMetadata(ctx context.Context, providedCacheKey, cacheKey string, envProvider common.EnvProviderFunc, client *kv.Client, logger log.Logger) error {
86-
logger.TInfof("Saving empty metadata file %s", CacheMetadataPath)
88+
logger.TInfof("Saving empty metadata file %s", XCodeCacheMetadataPath)
8789
_, err := xcode.SaveMetadata(&xcode.Metadata{
88-
ProjectFiles: xcode.FileGroupInfo{},
89-
DerivedData: xcode.FileGroupInfo{},
90-
XcodeCacheDir: xcode.FileGroupInfo{},
90+
ProjectFiles: filegroup.Info{},
91+
DerivedData: filegroup.Info{},
92+
XcodeCacheDir: filegroup.Info{},
9193
CacheKey: cacheKey,
9294
CreatedAt: time.Now(),
9395
AppID: envProvider("BITRISE_APP_SLUG"),
@@ -96,24 +98,24 @@ func uploadEmptyMetadata(ctx context.Context, providedCacheKey, cacheKey string,
9698
GitBranch: envProvider("BITRISE_GIT_BRANCH"),
9799
BuildCacheCLIVersion: envProvider("BITRISE_BUILD_CACHE_CLI_VERSION"),
98100
MetadataVersion: 1,
99-
}, CacheMetadataPath, logger)
101+
}, XCodeCacheMetadataPath, logger)
100102
if err != nil {
101103
return fmt.Errorf("save metadata: %w", err)
102104
}
103105

104-
mdChecksum, err := xcode.ChecksumOfFile(CacheMetadataPath)
106+
mdChecksum, err := hash.ChecksumOfFile(XCodeCacheMetadataPath)
105107
mdChecksumReader := strings.NewReader(mdChecksum)
106108
if err != nil {
107109
return fmt.Errorf("checksum of metadata file: %w", err)
108110
}
109111

110-
logger.TInfof("Uploading metadata checksum of %s (%s) for key %s", CacheMetadataPath, mdChecksum, cacheKey)
111-
if err := xcode.UploadStreamToBuildCache(ctx, mdChecksumReader, cacheKey, mdChecksumReader.Size(), client, logger); err != nil {
112+
logger.TInfof("Uploading metadata checksum of %s (%s) for key %s", XCodeCacheMetadataPath, mdChecksum, cacheKey)
113+
if err := client.UploadStreamToBuildCache(ctx, mdChecksumReader, cacheKey, mdChecksumReader.Size()); err != nil {
112114
return fmt.Errorf("upload metadata checksum to build cache: %w", err)
113115
}
114116

115-
logger.TInfof("Uploading metadata content of %s for key %s", CacheMetadataPath, mdChecksum)
116-
if err := xcode.UploadFileToBuildCache(ctx, CacheMetadataPath, mdChecksum, client, logger); err != nil {
117+
logger.TInfof("Uploading metadata content of %s for key %s", XCodeCacheMetadataPath, mdChecksum)
118+
if err := client.UploadFileToBuildCache(ctx, XCodeCacheMetadataPath, mdChecksum); err != nil {
117119
return fmt.Errorf("upload metadata content to build cache: %w", err)
118120
}
119121

@@ -124,8 +126,8 @@ func uploadEmptyMetadata(ctx context.Context, providedCacheKey, cacheKey string,
124126
} else if fallbackCacheKey != "" && cacheKey != fallbackCacheKey {
125127
cacheKey = fallbackCacheKey
126128
mdChecksumReader = strings.NewReader(mdChecksum) // reset reader
127-
logger.TInfof("Uploading metadata checksum of %s (%s) for fallback key %s", CacheMetadataPath, mdChecksum, cacheKey)
128-
if err := xcode.UploadStreamToBuildCache(ctx, mdChecksumReader, cacheKey, mdChecksumReader.Size(), client, logger); err != nil {
129+
logger.TInfof("Uploading metadata checksum of %s (%s) for fallback key %s", XCodeCacheMetadataPath, mdChecksum, cacheKey)
130+
if err := client.UploadStreamToBuildCache(ctx, mdChecksumReader, cacheKey, mdChecksumReader.Size()); err != nil {
129131
return fmt.Errorf("upload metadata checksum to build cache: %w", err)
130132
}
131133
}
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"os"
8+
"strings"
9+
10+
"github.com/bitrise-io/bitrise-build-cache-cli/internal/build_cache/kv"
11+
"github.com/bitrise-io/bitrise-build-cache-cli/internal/config/common"
12+
"github.com/bitrise-io/bitrise-build-cache-cli/internal/filegroup"
13+
"github.com/bitrise-io/bitrise-build-cache-cli/internal/gradle"
14+
"github.com/bitrise-io/go-utils/v2/log"
15+
"github.com/google/uuid"
16+
"github.com/spf13/cobra"
17+
)
18+
19+
// nolint: gochecknoglobals
20+
var restoreGradleConfigCacheCmd = &cobra.Command{
21+
Use: "restore-gradle-configuration-cache",
22+
Short: "Restore the Gradle configuration cache directory from Bitrise Build Cache",
23+
Long: `Restore the contents of the Gradle configuration cache folder (used by Gradle to store task graph produced by the configuration phase) from Bitrise Build Cache.`,
24+
SilenceUsage: true,
25+
RunE: func(cmd *cobra.Command, _ []string) error {
26+
logger := log.NewLogger()
27+
logger.EnableDebugLog(isDebugLogMode)
28+
logCurrentUserInfo(logger)
29+
30+
logger.TInfof("Restore the Gradle configuration cache directory from Bitrise Build Cache")
31+
32+
logger.Infof("(i) Debug mode and verbose logs: %t", isDebugLogMode)
33+
34+
logger.Infof("(i) Checking parameters")
35+
cacheKey, _ := cmd.Flags().GetString("key")
36+
37+
logger.Infof("(i) Check Auth Config")
38+
authConfig, err := common.ReadAuthConfigFromEnvironments(os.Getenv)
39+
if err != nil {
40+
return fmt.Errorf("read auth config from environments: %w", err)
41+
}
42+
43+
err = restoreGradleConfigCacheCmdFn(cmd.Context(),
44+
authConfig,
45+
cacheKey,
46+
logger,
47+
os.Getenv)
48+
if err != nil {
49+
return fmt.Errorf("restore Gradle config cache from Bitrise Build Cache: %w", err)
50+
}
51+
52+
logger.TInfof("✅ Configufation cache restored from Bitrise Build Cache ")
53+
54+
return nil
55+
},
56+
}
57+
58+
func init() {
59+
rootCmd.AddCommand(restoreGradleConfigCacheCmd)
60+
61+
restoreGradleConfigCacheCmd.Flags().String("key", "", "The cache key used for the saved cache item (set to the Bitrise app's slug and current git branch by default)")
62+
}
63+
64+
func restoreGradleConfigCacheCmdFn(ctx context.Context,
65+
authConfig common.CacheAuthConfig,
66+
providedCacheKey string,
67+
logger log.Logger,
68+
envProvider func(string) string) error {
69+
kvClient, err := createKVClient(ctx, uuid.NewString(), authConfig, envProvider, logger)
70+
if err != nil {
71+
return fmt.Errorf("create kv client: %w", err)
72+
}
73+
74+
g := gradle.NewCache(logger, envProvider, kvClient)
75+
76+
logger.TInfof("(i) Restoring Gradle configuration cache")
77+
78+
_, _, err = downloadGradleConfigCacheMetadata(ctx, GradleConfigCacheMetadataPath, providedCacheKey, g, kvClient, logger)
79+
if err != nil {
80+
return fmt.Errorf("download cache metadata: %w", err)
81+
}
82+
83+
logger.TInfof("Loading metadata from %s", GradleConfigCacheMetadataPath)
84+
var metadata *gradle.Metadata
85+
if metadata, _, err = g.LoadMetadata(GradleConfigCacheMetadataPath); err != nil {
86+
return fmt.Errorf("load metadata: %w", err)
87+
}
88+
89+
metadata.Print(logger)
90+
91+
logger.TInfof("Downloading configuration cache files")
92+
_, err = kvClient.DownloadFileGroupFromBuildCache(ctx, metadata.ConfigCacheFiles, isDebugLogMode, true, false, 100)
93+
if err != nil {
94+
logger.Infof("Failed to download DerivedData files, clearing")
95+
// To prevent the build from failing
96+
for _, file := range metadata.ConfigCacheFiles.Files {
97+
if err := os.Remove(file.Path); err != nil {
98+
logger.Infof("Failed to remove file %s: %s", file.Path, err)
99+
}
100+
}
101+
102+
return fmt.Errorf("download config cache files: %w", err)
103+
}
104+
105+
updated := 0
106+
107+
logger.Infof("(i) %d files' info loaded from cache metadata", len(metadata.ConfigCacheFiles.Files))
108+
109+
for _, fi := range metadata.ConfigCacheFiles.Files {
110+
if filegroup.RestoreFileInfo(*fi, "", logger) {
111+
updated++
112+
}
113+
}
114+
115+
logger.Infof("(i) %d files' modification time restored", updated)
116+
117+
return nil
118+
}
119+
120+
func downloadGradleConfigCacheMetadata(ctx context.Context, cacheMetadataPath, providedCacheKey string,
121+
gradleCache *gradle.Cache,
122+
kvClient *kv.Client,
123+
logger log.Logger) (CacheKeyType, string, error) {
124+
var cacheKeyType CacheKeyType = CacheKeyTypeDefault
125+
var cacheKey string
126+
var err error
127+
if providedCacheKey == "" {
128+
if cacheKey, err = gradleCache.GetCacheKey(gradle.CacheKeyParams{}); err != nil {
129+
return "", "", fmt.Errorf("get cache key: %w", err)
130+
}
131+
logger.TInfof("Downloading cache metadata checksum for key %s", cacheKey)
132+
} else {
133+
cacheKeyType = CacheKeyTypeProvided
134+
cacheKey = providedCacheKey
135+
logger.TInfof("Downloading cache metadata checksum for provided key %s", cacheKey)
136+
}
137+
138+
var mdChecksum strings.Builder
139+
err = kvClient.DownloadStreamFromBuildCache(ctx, &mdChecksum, cacheKey)
140+
if err != nil && !errors.Is(err, kv.ErrCacheNotFound) {
141+
return cacheKeyType, cacheKey, fmt.Errorf("download cache metadata checksum: %w", err)
142+
}
143+
144+
if errors.Is(err, kv.ErrCacheNotFound) {
145+
cacheKeyType = CacheKeyTypeFallback
146+
fallbackCacheKey, fallbackErr := gradleCache.GetCacheKey(gradle.CacheKeyParams{IsFallback: true})
147+
if fallbackErr != nil {
148+
return cacheKeyType, fallbackCacheKey, errors.New("cache metadata not found in cache")
149+
}
150+
151+
cacheKey = fallbackCacheKey
152+
logger.Infof("Cache metadata not found for original key, trying fallback key %s", cacheKey)
153+
154+
err = kvClient.DownloadStreamFromBuildCache(ctx, &mdChecksum, cacheKey)
155+
if errors.Is(err, kv.ErrCacheNotFound) {
156+
return cacheKeyType, cacheKey, errors.New("cache metadata not found in cache")
157+
}
158+
if err != nil {
159+
return cacheKeyType, cacheKey, fmt.Errorf("download cache metadata checksum: %w", err)
160+
}
161+
logger.Infof("Cache metadata found for fallback key %s", cacheKey)
162+
}
163+
164+
logger.TInfof("Downloading cache metadata content to %s for key %s", cacheMetadataPath, mdChecksum.String())
165+
if err := kvClient.DownloadFileFromBuildCache(ctx, cacheMetadataPath, mdChecksum.String()); err != nil {
166+
return cacheKeyType, cacheKey, fmt.Errorf("download cache archive: %w", err)
167+
}
168+
169+
return cacheKeyType, cacheKey, nil
170+
}

0 commit comments

Comments
 (0)