Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the issue that tiup may choose yanked version if it's already installed #1191

Merged
merged 4 commits into from
Mar 5, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Simply type tiup help <command>|<component> for full details.`,
func externalHelp(env *environment.Environment, spec string, args ...string) {
profile := env.Profile()
component, version := environment.ParseCompVersion(spec)
selectVer, err := profile.SelectInstalledVersion(component, version)
selectVer, err := env.SelectInstalledVersion(component, version)
if err != nil {
fmt.Println(err)
return
Expand Down
88 changes: 65 additions & 23 deletions pkg/environment/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ const (
tiupName = "tiup"
)

var (
// ErrInstallFirst indicates that a component/version is not installed
ErrInstallFirst = errors.New("component not install")
lucklove marked this conversation as resolved.
Show resolved Hide resolved
)

// Mirror return mirror of tiup.
// If it's not defined, it will use "https://tiup-mirrors.pingcap.com/".
func Mirror() string {
Expand Down Expand Up @@ -179,17 +184,64 @@ func (env *Environment) downloadComponent(component string, version pkgver.Versi

// 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, version pkgver.Version) (pkgver.Version, error) {
return env.profile.SelectInstalledVersion(component, version)
}

// DownloadComponentIfMissing downloads the specific version of a component if it is missing
func (env *Environment) DownloadComponentIfMissing(component string, ver pkgver.Version) (pkgver.Version, error) {
versions, err := env.profile.InstalledVersions(component)
func (env *Environment) SelectInstalledVersion(component string, ver pkgver.Version) (pkgver.Version, error) {
installed, err := env.Profile().InstalledVersions(component)
if err != nil {
return "", err
}

errInstallFirst := errors.Annotatef(ErrInstallFirst, "use `tiup install %s` to install component `%s` first", component, component)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use ErrInstallFirst here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this error will be displayed to the user

if len(installed) < 1 {
return "", errInstallFirst
}

versions := []string{}
for _, v := range installed {
vi, err := env.v1Repo.ComponentVersion(component, v, true)
if err != nil {
return "", err
}
if vi.Yanked {
continue
}
versions = append(versions, v)
}

if !ver.IsEmpty() {
for _, v := range versions {
if pkgver.Version(v) == ver {
return ver, nil
}
}
return "", 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 pkgver.Version(v).IsNightly() {
continue
}
if semver.Prerelease(v) == "" {
ver = pkgver.Version(v)
break
} else if ver.IsEmpty() {
ver = pkgver.Version(v)
}
}

if ver.IsEmpty() {
return "", errInstallFirst
}
return ver, nil
}

// DownloadComponentIfMissing downloads the specific version of a component if it is missing
func (env *Environment) DownloadComponentIfMissing(component string, ver pkgver.Version) (pkgver.Version, error) {
var err error
if ver.String() == version.NightlyVersion {
if ver, _, err = env.v1Repo.LatestNightlyVersion(component); err != nil {
return "", err
Expand All @@ -200,23 +252,13 @@ func (env *Environment) DownloadComponentIfMissing(component string, ver pkgver.
// download the latest version if the specific component doesn't be installed

// Check whether the specific version exist in local
if ver.IsEmpty() && len(versions) > 0 {
sort.Slice(versions, func(i, j int) bool {
return semver.Compare(versions[i], versions[j]) < 0
})
ver = pkgver.Version(versions[len(versions)-1])
}

needDownload := ver.IsEmpty()
if !ver.IsEmpty() {
installed := false
for _, v := range versions {
if pkgver.Version(v) == ver {
installed = true
break
}
needDownload := false
if ver.IsEmpty() {
ver, err = env.SelectInstalledVersion(component, ver)
needDownload = errors.Cause(err) == ErrInstallFirst
if err != nil && errors.Cause(err) != ErrInstallFirst {
lucklove marked this conversation as resolved.
Show resolved Hide resolved
return "", err
}
needDownload = !installed
}

if needDownload {
Expand Down
32 changes: 0 additions & 32 deletions pkg/localdata/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,38 +224,6 @@ func (p *Profile) VersionIsInstalled(component, version string) (bool, error) {
return false, nil
}

// SelectInstalledVersion selects the installed versions and the latest release version
// will be chosen if there is an empty version
func (p *Profile) SelectInstalledVersion(component string, version pkgver.Version) (pkgver.Version, error) {
installed, err := p.InstalledVersions(component)
if err != nil {
return "", err
}

errInstallFirst := fmt.Errorf("use `tiup install %[1]s` to install `%[1]s` first", component)
if len(installed) < 1 {
return "", errInstallFirst
}

if version.IsEmpty() {
sort.Slice(installed, func(i, j int) bool {
return semver.Compare(installed[i], installed[j]) < 0
})
version = pkgver.Version(installed[len(installed)-1])
}
found := false
for _, v := range installed {
if pkgver.Version(v) == version {
found = true
break
}
}
if !found {
return "", errInstallFirst
}
return version, nil
}

// ResetMirror reset root.json and cleanup manifests directory
func (p *Profile) ResetMirror(addr, root string) error {
// Calculating root.json path
Expand Down