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 }