@@ -13,6 +13,7 @@ import (
1313 "golang.org/x/xerrors"
1414 "gopkg.in/yaml.v3"
1515
16+ "github.com/aquasecurity/go-version/pkg/semver"
1617 "github.com/aquasecurity/trivy/pkg/downloader"
1718 ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
1819 "github.com/aquasecurity/trivy/pkg/log"
@@ -30,14 +31,20 @@ var (
3031type ManagerOption func (indexer * Manager )
3132
3233func 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
3542 }
3643}
3744
3845func WithIndexURL (indexURL string ) ManagerOption {
39- return func (indexer * Manager ) {
40- indexer .indexURL = indexURL
46+ return func (manager * Manager ) {
47+ manager .indexURL = indexURL
4148 }
4249}
4350
@@ -88,17 +95,18 @@ func Update(ctx context.Context) error { return defaultManager(
8895func Search (ctx context.Context , keyword string ) error { return defaultManager ().Search (ctx , keyword ) }
8996
9097// 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 )
93101
94102 // 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 {
96104 m .logger .InfoContext (ctx , "The plugin is already installed" , log .String ("name" , p .Name ))
97105 return p , nil
98106 }
99107
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 )
102110}
103111
104112func (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
129137 return Plugin {}, xerrors .Errorf ("yaml encode error: %w" , err )
130138 }
131139
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 ))
133142
134143 return plugin , nil
135144}
@@ -340,16 +349,45 @@ func (m *Manager) loadMetadata(dir string) (Plugin, error) {
340349 return plugin , nil
341350}
342351
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 ) {
344353 installedPlugins , err := m .LoadAll (ctx )
345354 if err != nil {
346355 return Plugin {}, false
347356 }
348357
349358 for _ , plugin := range installedPlugins {
350- if plugin .Repository == url {
359+ if plugin .Repository == url && ( version == "" || plugin . Version == version ) {
351360 return plugin , true
352361 }
353362 }
354363 return Plugin {}, false
355364}
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