/
plugin.go
158 lines (127 loc) · 4.12 KB
/
plugin.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Package plugin for caching directories using given backends
package plugin
import (
"crypto/md5" // #nosec
"errors"
"fmt"
"os"
"path/filepath"
"time"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/meltwater/drone-cache/archive"
"github.com/meltwater/drone-cache/cache"
"github.com/meltwater/drone-cache/internal/metadata"
"github.com/meltwater/drone-cache/key"
keygen "github.com/meltwater/drone-cache/key/generator"
"github.com/meltwater/drone-cache/storage"
"github.com/meltwater/drone-cache/storage/backend"
)
// Error recognized error from plugin.
type Error string
// Error is a sentinel plugin error.
func (e Error) Error() string { return string(e) }
// Unwrap unwraps underlying error.
func (e Error) Unwrap() error { return e }
// Plugin stores metadata about current plugin.
type Plugin struct {
logger log.Logger
Metadata metadata.Metadata
Config Config
}
// New creates a new plugin.
func New(logger log.Logger) *Plugin {
return &Plugin{logger: logger}
}
// Exec entry point of Plugin, where the magic happens.
func (p *Plugin) Exec() error { // nolint: funlen,cyclop
cfg := p.Config
// 1. Check parameters
if cfg.Debug {
level.Debug(p.logger).Log("msg", "DEBUG MODE enabled!")
for _, pair := range os.Environ() {
level.Debug(p.logger).Log("var", pair)
}
level.Debug(p.logger).Log("msg", "plugin initialized wth config", "config", fmt.Sprintf("%#v", p.Config))
level.Debug(p.logger).Log("msg", "plugin initialized with metadata", "metadata", fmt.Sprintf("%#v", p.Metadata))
}
// FLUSH
if cfg.Rebuild && cfg.Restore {
return errors.New("rebuild and restore are mutually exclusive, please set only one of them")
}
var localRoot string
if p.Config.LocalRoot != "" {
localRoot = filepath.Clean(p.Config.LocalRoot)
} else {
workspace, err := os.Getwd()
if err != nil {
return fmt.Errorf("get working directory, %w", err)
}
localRoot = workspace
}
var options []cache.Option
if p.Config.RemoteRoot != "" {
options = append(options, cache.WithNamespace(p.Config.RemoteRoot))
} else {
options = append(options, cache.WithNamespace(p.Metadata.Repo.Name))
}
var generator key.Generator
if cfg.CacheKeyTemplate != "" {
generator = keygen.NewMetadata(p.logger, cfg.CacheKeyTemplate, p.Metadata, time.Now)
if err := generator.Check(); err != nil {
return fmt.Errorf("parse failed, falling back to default, %w", err)
}
options = append(options, cache.WithFallbackGenerator(keygen.NewHash(md5.New, p.Metadata.Commit.Branch)))
} else {
generator = keygen.NewHash(md5.New, p.Metadata.Commit.Branch)
options = append(options, cache.WithFallbackGenerator(keygen.NewStatic(p.Metadata.Commit.Branch)))
}
options = append(options, cache.WithOverride(p.Config.Override))
// 2. Initialize storage backend.
b, err := backend.FromConfig(p.logger, cfg.Backend, backend.Config{
Debug: cfg.Debug,
Azure: cfg.Azure,
FileSystem: cfg.FileSystem,
GCS: cfg.GCS,
S3: cfg.S3,
SFTP: cfg.SFTP,
Alioss: cfg.Alioss,
})
if err != nil {
return fmt.Errorf("initialize backend <%s>, %w", cfg.Backend, err)
}
// 3. Initialize cache.
c := cache.New(p.logger,
storage.New(p.logger, b, cfg.StorageOperationTimeout),
archive.FromFormat(p.logger, localRoot, cfg.ArchiveFormat,
archive.WithSkipSymlinks(cfg.SkipSymlinks),
archive.WithCompressionLevel(cfg.CompressionLevel),
),
generator,
options...,
)
// 4. Glob match mounts if doublestar paths exist
cwd, err := os.Getwd()
if err != nil {
return fmt.Errorf("get working directory, %w", err)
}
fsys := os.DirFS(cwd)
if err = p.Config.HandleMount(fsys); err != nil {
return fmt.Errorf("exec handle mount call, %w", err)
}
// 5. Select mode
if cfg.Rebuild {
if err := c.Rebuild(p.Config.Mount); err != nil {
level.Debug(p.logger).Log("err", fmt.Sprintf("%+v\n", err))
return Error(fmt.Sprintf("[IMPORTANT] build cache, %+v\n", err))
}
}
if cfg.Restore {
if err := c.Restore(p.Config.Mount); err != nil {
level.Debug(p.logger).Log("err", fmt.Sprintf("%+v\n", err))
return Error(fmt.Sprintf("[IMPORTANT] restore cache, %+v\n", err))
}
}
// FLUSH
return nil
}