diff --git a/pkg/environment/env.go b/pkg/environment/env.go index 88b21f7f32..b01abb7e54 100644 --- a/pkg/environment/env.go +++ b/pkg/environment/env.go @@ -187,13 +187,6 @@ func (env *Environment) downloadComponent(component string, version utils.Versio // SelectInstalledVersion selects the installed versions and the latest release version // will be chosen if there is an empty version func (env *Environment) SelectInstalledVersion(component string, ver utils.Version) (utils.Version, error) { - if ver == utils.NightlyVersionAlias { - var err error - if ver, _, err = env.v1Repo.LatestNightlyVersion(component); err != nil { - return ver, err - } - } - installed, err := env.Profile().InstalledVersions(component) if err != nil { return ver, err @@ -201,7 +194,7 @@ func (env *Environment) SelectInstalledVersion(component string, ver utils.Versi versions := []string{} for _, v := range installed { - vi, err := env.v1Repo.ComponentVersion(component, v, true) + vi, err := env.v1Repo.LocalComponentVersion(component, v, true) if errors.Cause(err) == repository.ErrUnknownVersion { continue } @@ -211,44 +204,40 @@ func (env *Environment) SelectInstalledVersion(component string, ver utils.Versi if vi.Yanked { continue } + if (string(ver) == utils.NightlyVersionAlias) != utils.Version(v).IsNightly() { + continue + } versions = append(versions, v) } + // Reverse sort: v5.0.0-rc,v5.0.0-nightly-20210305,v4.0.11 + sort.Slice(versions, func(i, j int) bool { + return semver.Compare(versions[i], versions[j]) > 0 + }) errInstallFirst := errors.Annotatef(ErrInstallFirst, "use `tiup install %s` to install component `%s` first", component, component) - if len(installed) == 0 { - return ver, errInstallFirst - } - if !ver.IsEmpty() { + if ver.IsEmpty() || string(ver) == utils.NightlyVersionAlias { + var selected utils.Version for _, v := range versions { - if utils.Version(v) == ver { - return ver, nil + if semver.Prerelease(v) == "" { + return utils.Version(v), nil + } + // select prerelease version when there is only prelease version on local + if selected.IsEmpty() { + selected = utils.Version(v) } } - return ver, errInstallFirst - } - - sort.Slice(versions, func(i, j int) bool { - // Reverse sort: v5.0.0-rc,v5.0.0-nightly-20210305,v4.0.11 - return semver.Compare(versions[i], versions[j]) > 0 - }) - - for _, v := range versions { - if utils.Version(v).IsNightly() { - continue + if !selected.IsEmpty() { + return selected, nil } - if semver.Prerelease(v) == "" { - ver = utils.Version(v) - break - } else if ver.IsEmpty() { - ver = utils.Version(v) + } else { + for _, v := range versions { + if utils.Version(v) == ver { + return ver, nil + } } } - - if ver.IsEmpty() { - return ver, errInstallFirst - } - return ver, nil + return ver, errInstallFirst } // DownloadComponentIfMissing downloads the specific version of a component if it is missing diff --git a/pkg/exec/run.go b/pkg/exec/run.go index 0c497550e7..773caffcef 100644 --- a/pkg/exec/run.go +++ b/pkg/exec/run.go @@ -67,6 +67,7 @@ func RunComponent(env *environment.Environment, tag, spec, binPath string, args var sig syscall.Signal sc := make(chan os.Signal, 1) signal.Notify(sc, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + updateC := make(chan string) defer func() { for err := range ch { @@ -87,6 +88,35 @@ func RunComponent(env *environment.Environment, tag, spec, binPath string, args ch <- p.Cmd.Wait() }() + // timeout for check update + go func() { + time.Sleep(2 * time.Second) + updateC <- "" + }() + + go func() { + var updateInfo string + if version.IsEmpty() { + latestV, _, err := env.V1Repository().LatestStableVersion(p.Component, false) + if err != nil { + return + } + selectVer, _ := env.SelectInstalledVersion(component, version) + + if semver.Compare(selectVer.String(), latestV.String()) < 0 { + updateInfo = fmt.Sprint(color.YellowString(` +Found %[1]s newer version: + The latest version: %[2]s + Local installed version: %[3]s + Update current component: tiup update %[1]s + Update all components: tiup update --all +`, + p.Component, latestV.String(), selectVer.String())) + } + } + updateC <- updateInfo + }() + select { case s := <-sc: sig = s.(syscall.Signal) @@ -100,6 +130,7 @@ func RunComponent(env *environment.Environment, tag, spec, binPath string, args return nil case err := <-ch: + defer fmt.Print(<-updateC) return errors.Annotatef(err, "run `%s` (wd:%s) failed", p.Exec, p.Dir) } } @@ -151,23 +182,6 @@ func PrepareCommand(p *PrepareCommandParams) (*exec.Cmd, error) { return nil, err } - if p.Version.IsEmpty() && p.CheckUpdate { - latestV, _, err := env.V1Repository().LatestStableVersion(p.Component, false) - if err != nil { - return nil, err - } - if semver.Compare(selectVer.String(), latestV.String()) < 0 { - fmt.Fprintln(os.Stderr, color.YellowString(`Found %[1]s newer version: - - The latest version: %[2]s - Local installed version: %[3]s - Update current component: tiup update %[1]s - Update all components: tiup update --all -`, - p.Component, latestV.String(), selectVer.String())) - } - } - // playground && cluster version must greater than v1.0.0 if (p.Component == "playground" || p.Component == "cluster") && semver.Compare(selectVer.String(), "v1.0.0") < 0 { return nil, errors.Errorf("incompatible component version, please use `tiup update %s` to upgrade to the latest version", p.Component) diff --git a/pkg/repository/v1_repository.go b/pkg/repository/v1_repository.go index e0f9f60107..656493b4de 100644 --- a/pkg/repository/v1_repository.go +++ b/pkg/repository/v1_repository.go @@ -756,6 +756,54 @@ func (r *V1Repository) ComponentVersion(id, ver string, includeYanked bool) (*v1 return vi, nil } +// LocalComponentVersion returns version item of a component from local manifest file +func (r *V1Repository) LocalComponentVersion(id, ver string, includeYanked bool) (*v1manifest.VersionItem, error) { + index := v1manifest.Index{} + _, exists, err := r.Local().LoadManifest(&index) + if err != nil { + return nil, err + } + if !exists { + err = r.ensureManifests() + if err != nil { + return nil, err + } + _, _, err := r.Local().LoadManifest(&index) + + if err != nil { + return nil, err + } + } + + components := index.ComponentList() + comp := components[id] + filename := v1manifest.ComponentManifestFilename(id) + manifest, err := r.Local().LoadComponentManifest(&comp, filename) + if err != nil { + return nil, err + } + + if ver == utils.NightlyVersionAlias { + if !manifest.HasNightly(r.PlatformString()) { + return nil, errors.Annotatef(ErrUnknownVersion, "component %s does not have nightly on %s", id, r.PlatformString()) + } + + ver = manifest.Nightly + } + if ver == "" { + v, _, err := r.LatestStableVersion(id, includeYanked) + if err != nil { + return nil, err + } + ver = v.String() + } + vi := manifest.VersionItem(r.PlatformString(), ver, includeYanked) + if vi == nil { + return nil, errors.Annotatef(ErrUnknownVersion, "version %s on %s for component %s not found", ver, r.PlatformString(), id) + } + return vi, nil +} + // ResolveComponentVersionWithPlatform resolves the latest version of a component that satisfies the constraint func (r *V1Repository) ResolveComponentVersionWithPlatform(id, constraint, platform string) (utils.Version, error) { manifest, err := r.FetchComponentManifest(id, false) @@ -873,23 +921,8 @@ func (r *V1Repository) LatestStableVersion(id string, withYanked bool) (utils.Ve // Support you have install the component, need to get entry from local manifest. // Load the manifest locally only to get then Entry, do not force do something need access mirror. func (r *V1Repository) BinaryPath(installPath string, componentID string, ver string) (string, error) { - component, err := r.updateComponentManifest(componentID, false) - if err != nil { - return "", err - } - - // Always use the newest nightly entry. - // Because the one the user installed may be scraped. - if utils.Version(ver).IsNightly() { - if !component.HasNightly(r.PlatformString()) { - return "", errors.Errorf("the component `%s` on platform %s does not have a nightly version", componentID, r.PlatformString()) - } - - ver = component.Nightly - } - // We need yanked version because we may have installed that version before it was yanked - versionItem, err := r.ComponentVersion(componentID, ver, true) + versionItem, err := r.LocalComponentVersion(componentID, ver, true) if err != nil { return "", err }