@@ -13,6 +13,7 @@ import (
13
13
"golang.org/x/xerrors"
14
14
"gopkg.in/yaml.v3"
15
15
16
+ "github.com/aquasecurity/go-version/pkg/semver"
16
17
"github.com/aquasecurity/trivy/pkg/downloader"
17
18
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
18
19
"github.com/aquasecurity/trivy/pkg/log"
@@ -30,14 +31,20 @@ var (
30
31
type ManagerOption func (indexer * Manager )
31
32
32
33
func WithWriter (w io.Writer ) ManagerOption {
33
- return func (indexer * Manager ) {
34
- indexer .w = w
34
+ return func (manager * Manager ) {
35
+ manager .w = w
36
+ }
37
+ }
38
+
39
+ func WithLogger (logger * log.Logger ) ManagerOption {
40
+ return func (manager * Manager ) {
41
+ manager .logger = logger
35
42
}
36
43
}
37
44
38
45
func WithIndexURL (indexURL string ) ManagerOption {
39
- return func (indexer * Manager ) {
40
- indexer .indexURL = indexURL
46
+ return func (manager * Manager ) {
47
+ manager .indexURL = indexURL
41
48
}
42
49
}
43
50
@@ -88,17 +95,18 @@ func Update(ctx context.Context) error { return defaultManager(
88
95
func Search (ctx context.Context , keyword string ) error { return defaultManager ().Search (ctx , keyword ) }
89
96
90
97
// Install installs a plugin
91
- func (m * Manager ) Install (ctx context.Context , name string , opts Options ) (Plugin , error ) {
92
- src := m .tryIndex (ctx , name )
98
+ func (m * Manager ) Install (ctx context.Context , arg string , opts Options ) (Plugin , error ) {
99
+ input := m .parseArg (ctx , arg )
100
+ input .name = m .tryIndex (ctx , input .name )
93
101
94
102
// If the plugin is already installed, it skips installing the plugin.
95
- if p , installed := m .isInstalled (ctx , src ); installed {
103
+ if p , installed := m .isInstalled (ctx , input . name , input . version ); installed {
96
104
m .logger .InfoContext (ctx , "The plugin is already installed" , log .String ("name" , p .Name ))
97
105
return p , nil
98
106
}
99
107
100
- m .logger .InfoContext (ctx , "Installing the plugin..." , log .String ("src" , src ))
101
- return m .install (ctx , src , opts )
108
+ m .logger .InfoContext (ctx , "Installing the plugin..." , log .String ("src" , input . name ))
109
+ return m .install (ctx , input . String () , opts )
102
110
}
103
111
104
112
func (m * Manager ) install (ctx context.Context , src string , opts Options ) (Plugin , error ) {
@@ -129,7 +137,8 @@ func (m *Manager) install(ctx context.Context, src string, opts Options) (Plugin
129
137
return Plugin {}, xerrors .Errorf ("yaml encode error: %w" , err )
130
138
}
131
139
132
- m .logger .InfoContext (ctx , "Plugin successfully installed" , log .String ("name" , plugin .Name ))
140
+ m .logger .InfoContext (ctx , "Plugin successfully installed" ,
141
+ log .String ("name" , plugin .Name ), log .String ("version" , plugin .Version ))
133
142
134
143
return plugin , nil
135
144
}
@@ -340,16 +349,45 @@ func (m *Manager) loadMetadata(dir string) (Plugin, error) {
340
349
return plugin , nil
341
350
}
342
351
343
- func (m * Manager ) isInstalled (ctx context.Context , url string ) (Plugin , bool ) {
352
+ func (m * Manager ) isInstalled (ctx context.Context , url , version string ) (Plugin , bool ) {
344
353
installedPlugins , err := m .LoadAll (ctx )
345
354
if err != nil {
346
355
return Plugin {}, false
347
356
}
348
357
349
358
for _ , plugin := range installedPlugins {
350
- if plugin .Repository == url {
359
+ if plugin .Repository == url && ( version == "" || plugin . Version == version ) {
351
360
return plugin , true
352
361
}
353
362
}
354
363
return Plugin {}, false
355
364
}
365
+
366
+ // Input represents the user-specified Input.
367
+ type Input struct {
368
+ name string
369
+ version string
370
+ }
371
+
372
+ func (i * Input ) String () string {
373
+ if i .version != "" {
374
+ // cf. https://github.com/hashicorp/go-getter/blob/268c11cae8cf0d9374783e06572679796abe9ce9/README.md#git-git
375
+ return i .name + "?ref=v" + i .version
376
+ }
377
+ return i .name
378
+ }
379
+
380
+ func (m * Manager ) parseArg (ctx context.Context , arg string ) Input {
381
+ before , after , found := strings .Cut (arg , "@v" )
382
+ if ! found {
383
+ return Input {name : arg }
384
+ } else if _ , err := semver .Parse (after ); err != nil {
385
+ m .logger .DebugContext (ctx , "Unable to identify the plugin version" , log .String ("name" , arg ), log .Err (err ))
386
+ return Input {name : arg }
387
+ }
388
+ // cf. https://github.com/hashicorp/go-getter/blob/268c11cae8cf0d9374783e06572679796abe9ce9/README.md#git-git
389
+ return Input {
390
+ name : before ,
391
+ version : after ,
392
+ }
393
+ }
0 commit comments