@@ -11,6 +11,7 @@ import (
1111 "os"
1212 "os/exec"
1313 "path/filepath"
14+ "runtime"
1415 "strings"
1516
1617 "github.com/Masterminds/semver"
@@ -56,7 +57,26 @@ const (
5657 errorNoActiveContexForGivenContextType = "there is no active context for the given context type `%v`"
5758)
5859
60+ var totalPluginsToInstall = 0
61+ var pluginsInstalledCount = 0
5962var execCommand = exec .Command
63+ var spinner component.OutputWriterSpinner
64+
65+ func init () {
66+ // Initialize global spinner
67+ spinner = component .NewOutputWriterSpinner (component .WithOutputStream (os .Stderr ))
68+ runtime .SetFinalizer (spinner , func (s component.OutputWriterSpinner ) {
69+ if s != nil {
70+ s .StopSpinner ()
71+ }
72+ })
73+ }
74+
75+ func StopSpinner () {
76+ if spinner != nil {
77+ spinner .StopSpinner ()
78+ }
79+ }
6080
6181type DeletePluginOptions struct {
6282 Target configtypes.Target
@@ -475,6 +495,21 @@ func InstallStandalonePlugin(pluginName, version string, target configtypes.Targ
475495 return installPlugin (pluginName , version , target , "" )
476496}
477497
498+ // SetTotalPluginsToInstall sets the total number of plugins to install
499+ func SetTotalPluginsToInstall (total int ) {
500+ totalPluginsToInstall = total
501+ }
502+
503+ // SetPluginsInstalledCount sets the number of plugins installed already
504+ func SetPluginsInstalledCount (count int ) {
505+ pluginsInstalledCount = count
506+ }
507+
508+ // IncrementPluginsInstalledCount increments the number of plugins installed
509+ func IncrementPluginsInstalledCount (count int ) {
510+ pluginsInstalledCount += count
511+ }
512+
478513// installs a plugin by name, version and target.
479514// If the contextName is not empty, it implies the plugin is a context-scope plugin, otherwise
480515// we are installing a standalone plugin.
@@ -560,7 +595,7 @@ func installPlugin(pluginName, version string, target configtypes.Target, contex
560595 if len (matchedPlugins ) == 1 {
561596 return installOrUpgradePlugin (& matchedPlugins [0 ], matchedPlugins [0 ].RecommendedVersion , false )
562597 }
563-
598+ // there can be only one plugin with the same name and target, so we can safely return the first one
564599 for i := range matchedPlugins {
565600 if matchedPlugins [i ].Target == target {
566601 return installOrUpgradePlugin (& matchedPlugins [i ], matchedPlugins [i ].RecommendedVersion , false )
@@ -592,31 +627,37 @@ func InstallPluginsFromGroup(pluginName, groupIDAndVersion string, options ...Pl
592627 // from the database
593628 groupIDAndVersion = fmt .Sprintf ("%s-%s/%s:%s" , pg .Vendor , pg .Publisher , pg .Name , pg .RecommendedVersion )
594629 log .Infof ("Installing plugins from plugin group '%s'" , groupIDAndVersion )
595-
596630 return InstallPluginsFromGivenPluginGroup (pluginName , groupIDAndVersion , pg )
597631}
598632
599633// InstallPluginsFromGivenPluginGroup installs either the specified plugin or all plugins from given plugin group plugins.
600634func InstallPluginsFromGivenPluginGroup (pluginName , groupIDAndVersion string , pg * plugininventory.PluginGroup ) (string , error ) {
601635 numErrors := 0
602- numInstalled := 0
603636 mandatoryPluginsExist := false
604637 pluginExist := false
638+ pluginsInstalledCount = 0
639+
640+ pluginsToInstall := make ([]* plugininventory.PluginGroupPluginEntry , 0 )
605641 for _ , plugin := range pg .Versions [pg .RecommendedVersion ] {
606642 if pluginName == cli .AllPlugins || pluginName == plugin .Name {
607643 pluginExist = true
608644 if plugin .Mandatory {
609645 mandatoryPluginsExist = true
610- err := InstallStandalonePlugin (plugin .Name , plugin .Version , plugin .Target )
611- if err != nil {
612- numErrors ++
613- log .Warningf ("unable to install plugin '%s': %v" , plugin .Name , err .Error ())
614- } else {
615- numInstalled ++
616- }
646+ pluginsToInstall = append (pluginsToInstall , plugin ) // Add mandatory plugin to the slice
617647 }
618648 }
619649 }
650+ SetTotalPluginsToInstall (len (pluginsToInstall ))
651+ SetPluginsInstalledCount (0 )
652+ for _ , plugin := range pluginsToInstall {
653+ err := InstallStandalonePlugin (plugin .Name , plugin .Version , plugin .Target )
654+ if err != nil {
655+ numErrors ++
656+ log .Warningf ("unable to install plugin '%s': %v" , plugin .Name , err .Error ())
657+ } else {
658+ IncrementPluginsInstalledCount (1 )
659+ }
660+ }
620661
621662 if ! pluginExist {
622663 return groupIDAndVersion , fmt .Errorf ("plugin '%s' is not part of the group '%s'" , pluginName , groupIDAndVersion )
@@ -633,9 +674,12 @@ func InstallPluginsFromGivenPluginGroup(pluginName, groupIDAndVersion string, pg
633674 return groupIDAndVersion , fmt .Errorf ("could not install %d plugin(s) from group '%s'" , numErrors , groupIDAndVersion )
634675 }
635676
636- if numInstalled == 0 {
677+ if pluginsInstalledCount == 0 {
637678 return groupIDAndVersion , fmt .Errorf ("plugin '%s' is not part of the group '%s'" , pluginName , groupIDAndVersion )
638679 }
680+ SetTotalPluginsToInstall (0 )
681+ SetPluginsInstalledCount (0 )
682+ defer StopSpinner ()
639683
640684 return groupIDAndVersion , nil
641685}
@@ -704,7 +748,7 @@ func getPluginInstallationMessage(p *discovery.Discovered, version string, isPlu
704748 installingMsg = fmt .Sprintf ("Installing plugin '%v:%v' %v(from cache)" , p .Name , version , withTarget )
705749 installedMsg = fmt .Sprintf ("Installed plugin '%v:%v' %v(from cache)" , p .Name , version , withTarget )
706750 } else {
707- installingMsg = fmt .Sprintf ("Plugin '%v:%v' %vis already installed. Reinitializing... " , p .Name , version , withTarget )
751+ installingMsg = fmt .Sprintf ("Already installed : Plugin '%v:%v' %v " , p .Name , version , withTarget )
708752 installedMsg = fmt .Sprintf ("Reinitialized plugin '%v:%v' %v" , p .Name , version , withTarget )
709753 }
710754 } else {
@@ -734,25 +778,27 @@ func installOrUpgradePlugin(p *discovery.Discovered, version string, installTest
734778 }
735779
736780 // Log message based on different installation conditions
737- installingMsg , installedMsg , errMsg := getPluginInstallationMessage (p , version , plugin != nil , isPluginAlreadyInstalled )
781+ installingMsg , _ , errMsg := getPluginInstallationMessage (p , version , plugin != nil , isPluginAlreadyInstalled )
738782
739- var spinner component.OutputWriterSpinner
783+ installingMsg = fmt .Sprintf ("[%v/%v] %v" , pluginsInstalledCount , totalPluginsToInstall , installingMsg )
784+ errMsg = fmt .Sprintf ("[%v/%v] %v" , pluginsInstalledCount , totalPluginsToInstall , errMsg )
785+ numPluginsInstalled := fmt .Sprintf ("%d plugins installed out of %d" , pluginsInstalledCount , totalPluginsToInstall )
786+ numPluginsInstalledWithLog := fmt .Sprintf ("%s%s" , log .GetLogTypeIndicator (log .LogTypeERROR ), numPluginsInstalled )
787+ errMsg = fmt .Sprintf ("%s\n %s" , errMsg , numPluginsInstalledWithLog )
740788
741789 // Initialize the spinner if the spinner is allowed
742- if component .IsTTYEnabled () {
743- // Initialize the spinner
744- spinner = component .NewOutputWriterSpinner (component .WithOutputStream (os .Stderr ),
745- component .WithSpinnerText (installingMsg ),
746- component .WithSpinnerStarted ())
790+ if component .IsTTYEnabled () && spinner != nil {
791+ spinner .SetText (installingMsg )
747792 spinner .SetFinalText (errMsg , log .LogTypeERROR )
748- defer spinner .StopSpinner ()
793+ spinner .StartSpinner ()
749794 } else {
750795 log .Info (installingMsg )
751796 }
752797
753798 pluginErr := verifyInstallAndInitializePlugin (plugin , p , version , installTestPlugin )
754799 if pluginErr == nil && spinner != nil {
755- spinner .SetFinalText (installedMsg , log .LogTypeINFO )
800+ // unset the final text to avoid the spinner from showing the final text
801+ spinner .SetFinalText ("" , "" )
756802 }
757803 return pluginErr
758804}
@@ -1104,7 +1150,6 @@ func InstallPluginsFromLocalSource(pluginName, version string, target configtype
11041150 if err != nil {
11051151 return errors .Wrap (err , "unable to discover plugins" )
11061152 }
1107-
11081153 var errList []error
11091154
11101155 var matchedPlugins []discovery.Discovered
@@ -1132,16 +1177,24 @@ func InstallPluginsFromLocalSource(pluginName, version string, target configtype
11321177 return installOrUpgradePlugin (& matchedPlugins [0 ], version , installTestPlugin )
11331178 }
11341179
1180+ var pluginsToInstall []* discovery.Discovered
11351181 for i := range matchedPlugins {
11361182 // Install all plugins otherwise include all matching plugins
11371183 if pluginName == cli .AllPlugins || matchedPlugins [i ].Target == target {
1138- err = installOrUpgradePlugin (& matchedPlugins [i ], version , installTestPlugin )
1139- if err != nil {
1140- errList = append (errList , err )
1141- }
1184+ plugin := matchedPlugins [i ]
1185+ pluginsToInstall = append (pluginsToInstall , & plugin )
11421186 }
11431187 }
1144-
1188+ SetTotalPluginsToInstall (len (pluginsToInstall ))
1189+ SetPluginsInstalledCount (0 )
1190+ for _ , plugin := range pluginsToInstall {
1191+ err = installOrUpgradePlugin (plugin , version , installTestPlugin )
1192+ if err != nil {
1193+ errList = append (errList , err )
1194+ }
1195+ }
1196+ SetTotalPluginsToInstall (0 )
1197+ SetPluginsInstalledCount (0 )
11451198 err = kerrors .NewAggregate (errList )
11461199 if err != nil {
11471200 return err
0 commit comments