github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/internal/runners/update/update.go (about)

     1  package update
     2  
     3  import (
     4  	"os"
     5  
     6  	"github.com/ActiveState/cli/internal/analytics"
     7  	"github.com/ActiveState/cli/internal/config"
     8  	"github.com/ActiveState/cli/internal/constants"
     9  	"github.com/ActiveState/cli/internal/errs"
    10  	"github.com/ActiveState/cli/internal/installation"
    11  	"github.com/ActiveState/cli/internal/locale"
    12  	"github.com/ActiveState/cli/internal/logging"
    13  	"github.com/ActiveState/cli/internal/multilog"
    14  	"github.com/ActiveState/cli/internal/output"
    15  	"github.com/ActiveState/cli/internal/primer"
    16  	"github.com/ActiveState/cli/internal/prompt"
    17  	"github.com/ActiveState/cli/internal/updater"
    18  	"github.com/ActiveState/cli/pkg/platform/model"
    19  	"github.com/ActiveState/cli/pkg/project"
    20  )
    21  
    22  type Params struct {
    23  	Channel string
    24  }
    25  
    26  type Update struct {
    27  	project *project.Project
    28  	cfg     *config.Instance
    29  	out     output.Outputer
    30  	prompt  prompt.Prompter
    31  	an      analytics.Dispatcher
    32  	svc     *model.SvcModel
    33  }
    34  
    35  type primeable interface {
    36  	primer.Projecter
    37  	primer.Configurer
    38  	primer.Outputer
    39  	primer.Prompter
    40  	primer.Analyticer
    41  	primer.SvcModeler
    42  }
    43  
    44  func New(prime primeable) *Update {
    45  	return &Update{
    46  		prime.Project(),
    47  		prime.Config(),
    48  		prime.Output(),
    49  		prime.Prompt(),
    50  		prime.Analytics(),
    51  		prime.SvcModel(),
    52  	}
    53  }
    54  
    55  func (u *Update) Run(params *Params) error {
    56  	// Check for available update
    57  	channel := fetchChannel(params.Channel, false)
    58  	upd, err := updater.NewDefaultChecker(u.cfg, u.an).CheckFor(channel, "")
    59  	if err != nil {
    60  		return errs.AddTips(locale.WrapError(
    61  			err, "err_update_fetch",
    62  			"Could not retrieve update information.",
    63  		), locale.Tl(
    64  			"err_tip_update_fetch", "Try again, and/or try restarting State Service",
    65  		))
    66  	}
    67  
    68  	update := updater.NewUpdateInstaller(u.an, upd)
    69  	if !update.ShouldInstall() {
    70  		logging.Debug("No update found")
    71  		u.out.Print(output.Prepare(
    72  			locale.Tr("update_none_found", channel),
    73  			&struct{}{},
    74  		))
    75  		return nil
    76  	}
    77  
    78  	u.out.Notice(locale.Tr("updating_version", update.AvailableUpdate.Version))
    79  
    80  	// Handle switching channels
    81  	var installPath string
    82  	if channel != constants.ChannelName {
    83  		installPath, err = installation.InstallPathForChannel(channel)
    84  		if err != nil {
    85  			return locale.WrapError(err, "err_update_install_path", "Could not get installation path for Channel {{.V0}}", channel)
    86  		}
    87  	}
    88  
    89  	err = update.InstallBlocking(installPath)
    90  	if err != nil {
    91  		if os.IsPermission(err) {
    92  			return locale.WrapExternalError(err, "update_permission_err", "", constants.DocumentationURL, errs.JoinMessage(err))
    93  		}
    94  		return locale.WrapError(err, "err_update_generic", "Update could not be installed.")
    95  	}
    96  
    97  	// invalidate the installer version lock if `state update` is requested
    98  	if err := u.cfg.Set(updater.CfgKeyInstallVersion, ""); err != nil {
    99  		multilog.Error("Failed to invalidate installer version lock on `state update` invocation: %v", err)
   100  	}
   101  
   102  	message := ""
   103  	if channel != constants.ChannelName {
   104  		message = locale.Tl("update_switch_channel", "[NOTICE]Please start a new shell for the update to take effect.[/RESET]")
   105  	}
   106  	u.out.Print(output.Prepare(
   107  		message,
   108  		&struct{}{},
   109  	))
   110  
   111  	return nil
   112  }
   113  
   114  func fetchChannel(defaultChannel string, preferDefault bool) string {
   115  	if defaultChannel == "" || !preferDefault {
   116  		if overrideChannel := os.Getenv(constants.UpdateChannelEnvVarName); overrideChannel != "" {
   117  			return overrideChannel
   118  		}
   119  	}
   120  	if defaultChannel != "" {
   121  		return defaultChannel
   122  	}
   123  	return constants.ChannelName
   124  }