From d02937cada3965263e3e2e3a50cc2f771e5f05b0 Mon Sep 17 00:00:00 2001 From: better0fdead Date: Thu, 16 Feb 2023 11:43:35 +0300 Subject: [PATCH 1/3] tt: add binaries command Added binaries command. It prints installed binaries. Closes #196 --- CHANGELOG.md | 1 + README.rst | 1 + cli/cmd/binaries.go | 30 ++++ cli/cmd/root.go | 1 + cli/list/list.go | 134 ++++++++++++++++++ cli/list/list_test.go | 53 +++++++ .../integration/binaries/bin/tarantool_2.10.3 | 0 test/integration/binaries/bin/tarantool_2.8.1 | 0 test/integration/binaries/bin/tt_v0.1.0 | 0 test/integration/binaries/test_binaries.py | 80 +++++++++++ 10 files changed, 300 insertions(+) create mode 100644 cli/cmd/binaries.go create mode 100644 cli/list/list_test.go create mode 100644 test/integration/binaries/bin/tarantool_2.10.3 create mode 100644 test/integration/binaries/bin/tarantool_2.8.1 create mode 100644 test/integration/binaries/bin/tt_v0.1.0 create mode 100644 test/integration/binaries/test_binaries.py diff --git a/CHANGELOG.md b/CHANGELOG.md index f0e3aefa7..3192281bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - ``tt instances`` command to print a list of enabled applications. - SSL options for ``tt connect`` command. - An ability to pass arguments to a connect command. +- ``tt binaries`` command. It shows a list of installed binaries and their versions. ### Changed diff --git a/README.rst b/README.rst index 9db7df415..d9e8989a0 100644 --- a/README.rst +++ b/README.rst @@ -462,3 +462,4 @@ Common description. For a detailed description, use ``tt help command`` . * ``cfg dump`` - print tt environment configuration. * ``pack`` - pack an environment into a tarball/RPM/Deb. * ``instances`` - show enabled applications. +* ``binaries`` - show a list of installed binaries and their versions. diff --git a/cli/cmd/binaries.go b/cli/cmd/binaries.go new file mode 100644 index 000000000..3e70fcf99 --- /dev/null +++ b/cli/cmd/binaries.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "github.com/spf13/cobra" + "github.com/tarantool/tt/cli/cmdcontext" + "github.com/tarantool/tt/cli/list" + "github.com/tarantool/tt/cli/modules" +) + +// NewBinariesCmd creates binaries command. +func NewBinariesCmd() *cobra.Command { + var binariesCmd = &cobra.Command{ + Use: "binaries", + Short: "Show a list of installed binaries and their versions.", + Run: func(cmd *cobra.Command, args []string) { + err := modules.RunCmd(&cmdCtx, cmd.CommandPath(), &modulesInfo, + internalBinariesModule, args) + handleCmdErr(cmd, err) + }, + } + + return binariesCmd +} + +// internalBinariesModule is a default binaries module. +func internalBinariesModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { + err := list.ListBinaries(cmdCtx, cliOpts) + + return err +} diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 79a0e6bac..b73097a6e 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -149,6 +149,7 @@ func NewCmdRoot() *cobra.Command { NewDaemonCmd(), NewCfgCmd(), NewInstancesCmd(), + NewBinariesCmd(), ) if err := injectCmds(rootCmd); err != nil { panic(err.Error()) diff --git a/cli/list/list.go b/cli/list/list.go index e756450a2..46d7fc4b1 100644 --- a/cli/list/list.go +++ b/cli/list/list.go @@ -2,7 +2,10 @@ package list import ( "fmt" + "io/fs" "os" + "path/filepath" + "strconv" "strings" "github.com/apex/log" @@ -11,6 +14,7 @@ import ( "github.com/tarantool/tt/cli/config" "github.com/tarantool/tt/cli/running" "github.com/tarantool/tt/cli/util" + "github.com/tarantool/tt/cli/version" ) // ListInstances shows enabled applications. @@ -54,3 +58,133 @@ func ListInstances(cmdCtx *cmdcontext.CmdCtx, cliOpts *config.CliOpts) error { return nil } + +// printBinaries outputs installed versions of the program. +func printBinaries(program string, binList []string) { + if len(binList) > 0 { + log.Infof(program + ":") + for _, bin := range binList { + if strings.HasSuffix(bin, "[active]") { + fmt.Printf(" %s\n", util.Bold(color.GreenString(bin))) + } else { + fmt.Printf(" %s\n", color.YellowString(bin)) + } + } + } +} + +// sortBinaryVersions sorts versions of binary. +func sortBinaryVersions(binList []string) ([]string, error) { + var versions []version.Version + var sortedVersions []string + var err error + + // Convert string to version (struct). + for _, ver := range binList { + if strings.HasPrefix(ver, "master") { + sortedVersions = append(sortedVersions, ver) + } + var versionInt [3]int + var version version.Version + verString := strings.Split(ver, ".") + if len(verString) != 3 { + continue + } + verPatch := strings.Split(verString[2], "") + verString[2] = verPatch[0] + for i, ch := range verString { + versionInt[i], err = strconv.Atoi(ch) + if err != nil { + return nil, err + } + } + version.Major = uint64(versionInt[0]) + version.Minor = uint64(versionInt[1]) + version.Patch = uint64(versionInt[2]) + version.Str = ver + + versions = append(versions, version) + } + + // Sort versions. + version.SortVersions(versions) + for i, j := 0, len(versions)-1; i < j; i, j = i+1, j-1 { + versions[i], versions[j] = versions[j], versions[i] + } + + for _, version := range versions { + sortedVersions = append(sortedVersions, version.Str) + } + return sortedVersions, err +} + +// parseBinaries seeks through fileList returning array of found versions of program. +func parseBinaries(fileList []fs.DirEntry, programName string, + binDir string) ([]string, error) { + var err error + var binaryVersion []string + binActive := "" + + // Files w/o version in name are symlinks to the active binaries. + if util.ContainsFile(fileList, programName) { + binActive, err = util.ResolveSymlink(filepath.Join(binDir, programName)) + if err != nil { + return nil, err + } + binActive = strings.TrimPrefix(filepath.Base(binActive), programName+"_") + } + + for _, f := range fileList { + if f.IsDir() { + continue + } + if strings.HasPrefix(f.Name(), programName) && f.Name() != programName { + binVersion := strings.TrimPrefix(f.Name(), programName+"_") + binVersion = strings.TrimPrefix(binVersion, "v") + if binVersion == binActive { + binaryVersion = append(binaryVersion, binVersion+" [active]") + } else { + binaryVersion = append(binaryVersion, binVersion) + } + } + } + + return binaryVersion, err +} + +// ListBinaries outputs installed versions of programs from bin_dir. +func ListBinaries(cmdCtx *cmdcontext.CmdCtx, cliOpts *config.CliOpts) error { + var err error + + binDir := cliOpts.App.BinDir + binDirFilesList, err := os.ReadDir(cliOpts.App.BinDir) + if err != nil { + return fmt.Errorf("there was some problem reading bin_dir: %s", err) + } + + if len(binDirFilesList) == 0 { + return fmt.Errorf("there are no installed binaries") + } + + programs := [...]string{"tt", "tarantool"} + fmt.Println("List of installed binaries:") + for _, prog := range programs { + binaryVersion, err := parseBinaries(binDirFilesList, prog, binDir) + if err != nil { + return err + } + + if len(binaryVersion) > 0 { + // Sort version array. + sorted, err := sortBinaryVersions(binaryVersion) + if err != nil { + return err + } + // Print the output. + printBinaries(prog, sorted) + } + + } + + return err +} diff --git a/cli/list/list_test.go b/cli/list/list_test.go new file mode 100644 index 000000000..6dd824b1d --- /dev/null +++ b/cli/list/list_test.go @@ -0,0 +1,53 @@ +package list + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSortValid(t *testing.T) { + type argsData struct { + input, expected []string + } + + testArgsData := []argsData{ + {[]string{"0.3.0", "1.3.0-nightly", "0.1.0"}, + []string{"1.3.0-nightly", "0.3.0", "0.1.0"}}, + {[]string{"1.3.0", "1.4.0", "1.2.0"}, + []string{"1.4.0", "1.3.0", "1.2.0"}}, + {[]string{"1.3.0", "2.3.0", "3.3.0"}, + []string{"3.3.0", "2.3.0", "1.3.0"}}, + {[]string{"3.3.1", "3.3.3", "3.3.0"}, + []string{"3.3.3", "3.3.1", "3.3.0"}}, + {[]string{"master", "3.3.3", "3.3.0"}, + []string{"master", "3.3.3", "3.3.0"}}, + } + + for _, testData := range testArgsData { + returned, err := sortBinaryVersions(testData.input) + require.Nil(t, err) + require.Equal(t, returned, testData.expected) + } +} + +func TestSortNonValid(t *testing.T) { + type argsData struct { + input, expected []string + } + + testArgsData := []argsData{ + {[]string{"123123", "1.3.0-nightly", "0.1.0"}, + []string{"1.3.0-nightly", "0.1.0"}}, + {[]string{"1.3.0.2.2.2.2", "1.4.0", "1.2.0"}, + []string{"1.4.0", "1.2.0"}}, + {[]string{"3.3.1", "foo", "3.3.0"}, + []string{"3.3.1", "3.3.0"}}, + } + + for _, testData := range testArgsData { + returned, err := sortBinaryVersions(testData.input) + require.Nil(t, err) + require.Equal(t, returned, testData.expected) + } +} diff --git a/test/integration/binaries/bin/tarantool_2.10.3 b/test/integration/binaries/bin/tarantool_2.10.3 new file mode 100644 index 000000000..e69de29bb diff --git a/test/integration/binaries/bin/tarantool_2.8.1 b/test/integration/binaries/bin/tarantool_2.8.1 new file mode 100644 index 000000000..e69de29bb diff --git a/test/integration/binaries/bin/tt_v0.1.0 b/test/integration/binaries/bin/tt_v0.1.0 new file mode 100644 index 000000000..e69de29bb diff --git a/test/integration/binaries/test_binaries.py b/test/integration/binaries/test_binaries.py new file mode 100644 index 000000000..41b423dee --- /dev/null +++ b/test/integration/binaries/test_binaries.py @@ -0,0 +1,80 @@ +import os +import shutil +import subprocess + +from utils import config_name + + +def test_binaries(tt_cmd, tmpdir): + # Copy the test bin_dir to the "run" directory. + test_app_path = os.path.join(os.path.dirname(__file__), "bin") + shutil.copytree(test_app_path, tmpdir + "/bin") + + configPath = os.path.join(tmpdir, config_name) + # Create test config + with open(configPath, 'w') as f: + f.write('tt:\n app:\n bin_dir: "./bin"\n inc_dir:\n') + + # Print binaries + binaries_cmd = [tt_cmd, "--cfg", configPath, "binaries"] + binaries_process = subprocess.Popen( + binaries_cmd, + cwd=tmpdir, + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + text=True + ) + + binaries_process.wait() + output = binaries_process.stdout.read() + + assert "tt" in output + assert "0.1.0" in output + assert "tarantool" in output + assert "2.10.3" in output + assert "2.8.1" in output + + +def test_binaries_no_directory(tt_cmd, tmpdir): + configPath = os.path.join(tmpdir, config_name) + # Create test config + with open(configPath, 'w') as f: + f.write('tt:\n app:\n bin_dir: "./bin"\n inc_dir:\n') + + # Print binaries + binaries_cmd = [tt_cmd, "--cfg", configPath, "binaries"] + binaries_process = subprocess.Popen( + binaries_cmd, + cwd=tmpdir, + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + text=True + ) + + binaries_process.wait() + output = binaries_process.stdout.read() + + assert "there was some problem reading bin_dir" in output + + +def test_binaries_empty_directory(tt_cmd, tmpdir): + configPath = os.path.join(tmpdir, config_name) + os.mkdir(tmpdir+"/bin") + # Create test config + with open(configPath, 'w') as f: + f.write('tt:\n app:\n bin_dir: "./bin"\n inc_dir:\n') + + # Print binaries + binaries_cmd = [tt_cmd, "--cfg", configPath, "binaries"] + binaries_process = subprocess.Popen( + binaries_cmd, + cwd=tmpdir, + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + text=True + ) + + binaries_process.wait() + output = binaries_process.stdout.read() + + assert "there are no installed binaries" in output From deb73a91f05e3b2a5faf6aac50363ff3db72a8a6 Mon Sep 17 00:00:00 2001 From: better0fdead Date: Wed, 15 Mar 2023 12:30:45 +0300 Subject: [PATCH 2/3] version: refactor code Moved variables to version package. Refactored code. Co-authored-by: psergee Part of #196 --- cli/cmd/install.go | 4 +- cli/cmd/uninstall.go | 6 +-- cli/install/install.go | 69 ++++++++++++++++--------------- cli/list/list.go | 3 +- cli/pack/deb.go | 2 +- cli/pack/rpm_header.go | 2 +- cli/search/bundle.go | 32 +++++++++++++- cli/search/search.go | 32 ++++++-------- cli/uninstall/uninstall.go | 10 ++--- cli/uninstall/uninstall_test.go | 14 +++---- cli/version/version_tools.go | 37 +++++++++++------ cli/version/version_tools_test.go | 6 +-- 12 files changed, 127 insertions(+), 90 deletions(-) diff --git a/cli/cmd/install.go b/cli/cmd/install.go index 39bdaa7da..4b44a21d2 100644 --- a/cli/cmd/install.go +++ b/cli/cmd/install.go @@ -7,7 +7,7 @@ import ( "github.com/tarantool/tt/cli/cmdcontext" "github.com/tarantool/tt/cli/install" "github.com/tarantool/tt/cli/modules" - "github.com/tarantool/tt/cli/search" + "github.com/tarantool/tt/cli/version" ) var ( @@ -40,7 +40,7 @@ func NewInstallCmd() *cobra.Command { # Install Tarantool 2.10.5 with limit number of simultaneous jobs for make. - $ MAKEFLAGS="-j2" tt install tarantool` + search.VersionCliSeparator + "2.10.5", + $ MAKEFLAGS="-j2" tt install tarantool` + version.CliSeparator + "2.10.5", ValidArgs: []string{"tt", "tarantool", "tarantool-ee"}, } installCmd.Flags().BoolVarP(&force, "force", "f", false, diff --git a/cli/cmd/uninstall.go b/cli/cmd/uninstall.go index e81cf0ae9..cd8c13264 100644 --- a/cli/cmd/uninstall.go +++ b/cli/cmd/uninstall.go @@ -7,8 +7,8 @@ import ( "github.com/spf13/cobra" "github.com/tarantool/tt/cli/cmdcontext" "github.com/tarantool/tt/cli/modules" - "github.com/tarantool/tt/cli/search" "github.com/tarantool/tt/cli/uninstall" + "github.com/tarantool/tt/cli/version" ) // NewUninstallCmd creates uninstall command. @@ -44,8 +44,8 @@ func NewUninstallCmd() *cobra.Command { // InternalUninstallModule is a default uninstall module. func InternalUninstallModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { - if !strings.Contains(args[0], search.VersionCliSeparator) { - return fmt.Errorf("incorrect usage.\n e.g program%sversion", search.VersionCliSeparator) + if !strings.Contains(args[0], version.CliSeparator) { + return fmt.Errorf("incorrect usage.\n e.g program%sversion", version.CliSeparator) } err := uninstall.UninstallProgram(args[0], cliOpts.App.BinDir, cliOpts.App.IncludeDir+"/include", cmdCtx) diff --git a/cli/install/install.go b/cli/install/install.go index 8475dffe4..78d59b6c7 100644 --- a/cli/install/install.go +++ b/cli/install/install.go @@ -380,14 +380,14 @@ func copyBuildedTT(binDir, path, version string, installCtx InstallCtx, } // installTt installs selected version of tt. -func installTt(version string, binDir string, installCtx InstallCtx, distfiles string) error { +func installTt(versionStr string, binDir string, installCtx InstallCtx, distfiles string) error { versions, err := getTTVersions(installCtx.Local, distfiles) if err != nil { return err } // Get latest version if it was not specified. - _, ttVersion, _ := strings.Cut(version, search.VersionCliSeparator) + _, ttVersion, _ := strings.Cut(versionStr, version.CliSeparator) if ttVersion == "" { log.Infof("Getting latest tt version..") if len(versions) == 0 { @@ -435,12 +435,12 @@ func installTt(version string, binDir string, installCtx InstallCtx, distfiles s } } - version = "tt" + search.VersionFsSeparator + ttVersion + versionStr = "tt" + version.FsSeparator + ttVersion // Check if that version is already installed. log.Infof("Checking existing...") - if checkExisting(version, binDir) && !installCtx.Reinstall { - log.Infof("%s version of tt already exists, updating symlink...", version) - err := util.CreateSymlink(version, filepath.Join(binDir, "tt"), true) + if checkExisting(versionStr, binDir) && !installCtx.Reinstall { + log.Infof("%s version of tt already exists, updating symlink...", versionStr) + err := util.CreateSymlink(versionStr, filepath.Join(binDir, "tt"), true) log.Infof("Done") return err } @@ -488,14 +488,14 @@ func installTt(version string, binDir string, installCtx InstallCtx, distfiles s // Copy binary. log.Infof("Copying executable...") - err = copyBuildedTT(binDir, path, version, installCtx, logFile) + err = copyBuildedTT(binDir, path, versionStr, installCtx, logFile) if err != nil { printLog(logFile.Name()) return err } // Set symlink. - err = util.CreateSymlink(version, filepath.Join(binDir, "tt"), true) + err = util.CreateSymlink(versionStr, filepath.Join(binDir, "tt"), true) if err != nil { printLog(logFile.Name()) return err @@ -531,7 +531,7 @@ func patchTarantool(srcPath string, tarVersion string, return nil } - ver, err := version.GetVersionDetails(tarVersion) + ver, err := version.Parse(tarVersion) if err != nil { return err } @@ -581,7 +581,7 @@ func buildTarantool(srcPath string, tarVersion string, // This feature is not supported by a backported static build. btFlag := "ON" if tarVersion != "master" { - version, err := version.GetVersionDetails(tarVersion) + version, err := version.Parse(tarVersion) if err != nil { return err } @@ -713,7 +713,7 @@ func installTarantoolInDocker(tntVersion, binDir, incDir string, installCtx Inst tntInstallCommandLine = append(tntInstallCommandLine, "-V") } tntInstallCommandLine = append(tntInstallCommandLine, "install", - "tarantool"+search.VersionCliSeparator+tntVersion, "-f") + "tarantool"+version.CliSeparator+tntVersion, "-f") if installCtx.Reinstall { tntInstallCommandLine = append(tntInstallCommandLine, "--reinstall") } @@ -742,7 +742,7 @@ func installTarantoolInDocker(tntVersion, binDir, incDir string, installCtx Inst } // installTarantool installs selected version of tarantool. -func installTarantool(version string, binDir string, incDir string, +func installTarantool(versionStr string, binDir string, incDir string, installCtx InstallCtx, distfiles string) error { // Check bin and header dirs. if binDir == "" { @@ -758,7 +758,7 @@ func installTarantool(version string, binDir string, incDir string, } // Get latest version if it was not specified. - _, tarVersion, _ := strings.Cut(version, search.VersionCliSeparator) + _, tarVersion, _ := strings.Cut(versionStr, version.CliSeparator) if tarVersion == "" { log.Infof("Getting latest tarantool version..") if len(versions) == 0 { @@ -783,11 +783,11 @@ func installTarantool(version string, binDir string, incDir string, } } - version = "tarantool" + search.VersionFsSeparator + tarVersion + versionStr = "tarantool" + version.FsSeparator + tarVersion // Check if program is already installed. if !installCtx.Reinstall { log.Infof("Checking existing...") - versionExists, err := checkExistingTarantool(version, + versionExists, err := checkExistingTarantool(versionStr, binDir, incDir, installCtx) if err != nil || versionExists { return err @@ -854,15 +854,15 @@ func installTarantool(version string, binDir string, incDir string, } // Copy binary and headers. if installCtx.Reinstall { - if checkExisting(version, binDir) { + if checkExisting(versionStr, binDir) { log.Infof("%s version of tarantool already exists, removing files...", - version) - err = os.RemoveAll(filepath.Join(binDir, version)) + versionStr) + err = os.RemoveAll(filepath.Join(binDir, versionStr)) if err != nil { printLog(logFile.Name()) return err } - err = os.RemoveAll(filepath.Join(incDir, version)) + err = os.RemoveAll(filepath.Join(incDir, versionStr)) } } if err != nil { @@ -872,7 +872,7 @@ func installTarantool(version string, binDir string, incDir string, buildPath := filepath.Join(path, "/static-build/build") binPath := filepath.Join(buildPath, "/tarantool-prefix/bin/tarantool") incPath := filepath.Join(buildPath, "/tarantool-prefix/include/tarantool") + "/" - err = copyBuildedTarantool(binPath, incPath, binDir, incDir, version, installCtx, + err = copyBuildedTarantool(binPath, incPath, binDir, incDir, versionStr, installCtx, logFile) if err != nil { printLog(logFile.Name()) @@ -880,12 +880,12 @@ func installTarantool(version string, binDir string, incDir string, } // Set symlinks. log.Infof("Changing symlinks...") - err = util.CreateSymlink(version, filepath.Join(binDir, "tarantool"), true) + err = util.CreateSymlink(versionStr, filepath.Join(binDir, "tarantool"), true) if err != nil { printLog(logFile.Name()) return err } - err = util.CreateSymlink(version, filepath.Join(incDir, "tarantool"), true) + err = util.CreateSymlink(versionStr, filepath.Join(incDir, "tarantool"), true) if err != nil { printLog(logFile.Name()) return err @@ -898,7 +898,7 @@ func installTarantool(version string, binDir string, incDir string, } // installTarantoolEE installs selected version of tarantool-ee. -func installTarantoolEE(version string, binDir string, includeDir string, installCtx InstallCtx, +func installTarantoolEE(versionStr string, binDir string, includeDir string, installCtx InstallCtx, distfiles string, cliOpts *config.CliOpts) error { var err error @@ -916,7 +916,8 @@ func installTarantoolEE(version string, binDir string, includeDir string, instal } } - _, tarVersion, _ := strings.Cut(version, search.VersionCliSeparator) + // Get latest version if it was not specified. + _, tarVersion, _ := strings.Cut(versionStr, version.CliSeparator) if tarVersion == "" { log.Infof("Getting latest tarantool-ee version..") } @@ -955,10 +956,10 @@ func installTarantoolEE(version string, binDir string, includeDir string, instal bundleName := ver.Version.Tarball bundleSource := ver.Prefix - version = "tarantool-ee" + search.VersionFsSeparator + tarVersion + versionStr = "tarantool-ee" + version.FsSeparator + tarVersion if !installCtx.Reinstall { log.Infof("Checking existing...") - versionExists, err := checkExistingTarantool(version, + versionExists, err := checkExistingTarantool(versionStr, binDir, includeDir, installCtx) if err != nil || versionExists { return err @@ -1010,15 +1011,15 @@ func installTarantoolEE(version string, binDir string, includeDir string, instal // Copy binary and headers. if installCtx.Reinstall { - if checkExisting(version, binDir) { + if checkExisting(versionStr, binDir) { log.Infof("%s version of tarantool-ee already exists, removing files...", - version) - err = os.RemoveAll(filepath.Join(binDir, version)) + versionStr) + err = os.RemoveAll(filepath.Join(binDir, versionStr)) if err != nil { printLog(logFile.Name()) return err } - err = os.RemoveAll(filepath.Join(includeDir, version)) + err = os.RemoveAll(filepath.Join(includeDir, versionStr)) } } if err != nil { @@ -1027,7 +1028,7 @@ func installTarantoolEE(version string, binDir string, includeDir string, instal } binPath := filepath.Join(path, "/tarantool-enterprise/tarantool") incPath := filepath.Join(path, "/tarantool-enterprise/include/tarantool") + "/" - err = copyBuildedTarantool(binPath, incPath, binDir, includeDir, version, installCtx, + err = copyBuildedTarantool(binPath, incPath, binDir, includeDir, versionStr, installCtx, logFile) if err != nil { printLog(logFile.Name()) @@ -1036,11 +1037,11 @@ func installTarantoolEE(version string, binDir string, includeDir string, instal // Set symlinks. log.Infof("Changing symlinks...") - err = util.CreateSymlink(version, filepath.Join(binDir, "tarantool"), true) + err = util.CreateSymlink(versionStr, filepath.Join(binDir, "tarantool"), true) if err != nil { return err } - err = util.CreateSymlink(version, filepath.Join(includeDir, "tarantool"), true) + err = util.CreateSymlink(versionStr, filepath.Join(includeDir, "tarantool"), true) if err != nil { printLog(logFile.Name()) return err @@ -1080,7 +1081,7 @@ func FillCtx(cmdCtx *cmdcontext.CmdCtx, installCtx *InstallCtx, args []string) e } re := regexp.MustCompile( - "^(?Ptt|tarantool|tarantool-ee)(?:" + search.VersionCliSeparator + ".*)?$", + "^(?Ptt|tarantool|tarantool-ee)(?:" + version.CliSeparator + ".*)?$", ) matches := util.FindNamedMatches(re, args[0]) if len(matches) == 0 { diff --git a/cli/list/list.go b/cli/list/list.go index 46d7fc4b1..65372f806 100644 --- a/cli/list/list.go +++ b/cli/list/list.go @@ -5,6 +5,7 @@ import ( "io/fs" "os" "path/filepath" + "sort" "strconv" "strings" @@ -107,7 +108,7 @@ func sortBinaryVersions(binList []string) ([]string, error) { } // Sort versions. - version.SortVersions(versions) + sort.Stable(version.VersionSlice(versions)) for i, j := 0, len(versions)-1; i < j; i, j = i+1, j-1 { versions[i], versions[j] = versions[j], versions[i] } diff --git a/cli/pack/deb.go b/cli/pack/deb.go index 180e17c5f..62790f80c 100644 --- a/cli/pack/deb.go +++ b/cli/pack/deb.go @@ -192,7 +192,7 @@ func getTntTTAsDeps(cmdCtx *cmdcontext.CmdCtx) (PackDependencies, error) { if err != nil { return nil, err } - tntVerParsed, err := version.GetVersionDetails(tntVerRaw) + tntVerParsed, err := version.Parse(tntVerRaw) if err != nil { return nil, err } diff --git a/cli/pack/rpm_header.go b/cli/pack/rpm_header.go index f76d7a2c1..28e39c73c 100644 --- a/cli/pack/rpm_header.go +++ b/cli/pack/rpm_header.go @@ -124,7 +124,7 @@ func genRpmHeader(relPaths []string, cpioPath, compresedCpioPath, packageFilesDi versionString := getVersion(packCtx, opts, defaultVersion) - ver, err := version.GetVersionDetails(versionString) + ver, err := version.Parse(versionString) if err != nil { return nil, err } diff --git a/cli/search/bundle.go b/cli/search/bundle.go index 6c420d899..b41ab2327 100644 --- a/cli/search/bundle.go +++ b/cli/search/bundle.go @@ -1,6 +1,7 @@ package search import ( + "github.com/tarantool/tt/cli/util" "github.com/tarantool/tt/cli/version" ) @@ -30,5 +31,34 @@ func (bundles BundleInfoSlice) Len() int { func (bundles BundleInfoSlice) Less(i, j int) bool { verLeft := bundles[i].Version verRight := bundles[j].Version - return version.Less(verLeft, verRight) + return Less(verLeft, verRight) +} + +// Less is a common function-comparator using for the Version type. +func Less(verLeft, verRight version.Version) bool { + left := []uint64{verLeft.Major, verLeft.Minor, + verLeft.Patch, uint64(verLeft.Release.Type), + verLeft.Release.Num, verLeft.Additional, verLeft.Revision} + right := []uint64{verRight.Major, verRight.Minor, + verRight.Patch, uint64(verRight.Release.Type), + verRight.Release.Num, verRight.Additional, verRight.Revision} + + largestLen := util.Max(len(left), len(right)) + + for i := 0; i < largestLen; i++ { + var valLeft, valRight uint64 = 0, 0 + if i < len(left) { + valLeft = left[i] + } + + if i < len(right) { + valRight = right[i] + } + + if valLeft != valRight { + return valLeft < valRight + } + } + + return false } diff --git a/cli/search/search.go b/cli/search/search.go index 490ef3aa3..a30252d9f 100644 --- a/cli/search/search.go +++ b/cli/search/search.go @@ -31,13 +31,6 @@ const ( GitRepoTT = "https://github.com/tarantool/tt.git" ) -const ( - // VersionCliSeparator is used in commands to specify version. E.g: program=version. - VersionCliSeparator = "=" - // VersionFsSeparator is used in file names to specify version. E.g: program_version. - VersionFsSeparator = "_" -) - // isMasked function checks that the given version of tarantool is masked. func isMasked(version version.Version) bool { // Mask all versions below 1.10: deprecated. @@ -96,7 +89,7 @@ func GetVersionsFromGitRemote(repo string) ([]version.Version, error) { slashIdx += 1 } ver := line[slashIdx:] - version, err := version.GetVersionDetails(ver) + version, err := version.Parse(ver) if err != nil { continue } @@ -106,7 +99,7 @@ func GetVersionsFromGitRemote(repo string) ([]version.Version, error) { versions = append(versions, version) } - version.SortVersions(versions) + sort.Stable(version.VersionSlice(versions)) return versions, nil } @@ -132,7 +125,7 @@ func GetVersionsFromGitLocal(repo string) ([]version.Version, error) { } for _, line := range lines { - version, err := version.GetVersionDetails(line) + version, err := version.Parse(line) if err != nil { continue } @@ -142,7 +135,7 @@ func GetVersionsFromGitLocal(repo string) ([]version.Version, error) { versions = append(versions, version) } - version.SortVersions(versions) + sort.Stable(version.VersionSlice(versions)) return versions, nil } @@ -150,8 +143,9 @@ func GetVersionsFromGitLocal(repo string) ([]version.Version, error) { // printVersion prints the version and labels: // * if the package is installed: [installed] // * if the package is installed and in use: [active] -func printVersion(bindir string, program string, version string) { - if _, err := os.Stat(filepath.Join(bindir, program+VersionFsSeparator+version)); err == nil { +func printVersion(bindir string, program string, versionStr string) { + if _, err := os.Stat(filepath.Join(bindir, + program+version.FsSeparator+versionStr)); err == nil { target := "" if program == "tarantool-ee" { target, _ = util.ResolveSymlink(filepath.Join(bindir, "tarantool")) @@ -159,13 +153,13 @@ func printVersion(bindir string, program string, version string) { target, _ = util.ResolveSymlink(filepath.Join(bindir, program)) } - if path.Base(target) == program+VersionFsSeparator+version { - fmt.Printf("%s [active]\n", version) + if path.Base(target) == program+version.FsSeparator+versionStr { + fmt.Printf("%s [active]\n", versionStr) } else { - fmt.Printf("%s [installed]\n", version) + fmt.Printf("%s [installed]\n", versionStr) } } else { - fmt.Println(version) + fmt.Println(versionStr) } } @@ -383,7 +377,7 @@ func getBundles(rawBundleInfoList []string) (BundleInfoSlice, error) { } for _, bundleInfo := range parsedBundleInfo { - ver, err := version.GetVersionDetails(bundleInfo["version"]) + ver, err := version.Parse(bundleInfo["version"]) if err != nil { return nil, err } @@ -415,7 +409,7 @@ func FetchBundlesInfoLocal(files []string) ([]BundleInfo, error) { continue } - version, err := version.GetVersionDetails(parsedData[4]) + version, err := version.Parse(parsedData[4]) if err != nil { return nil, err } diff --git a/cli/uninstall/uninstall.go b/cli/uninstall/uninstall.go index 9a11eb2a4..dff3e5077 100644 --- a/cli/uninstall/uninstall.go +++ b/cli/uninstall/uninstall.go @@ -10,8 +10,8 @@ import ( "github.com/apex/log" "github.com/tarantool/tt/cli/cmdcontext" "github.com/tarantool/tt/cli/config" - "github.com/tarantool/tt/cli/search" "github.com/tarantool/tt/cli/util" + "github.com/tarantool/tt/cli/version" ) // remove removes binary/directory and symlinks from directory. @@ -20,7 +20,7 @@ func remove(program string, directory string, cmdCtx *cmdcontext.CmdCtx) error { var err error re := regexp.MustCompile( - "^(?Ptt|tarantool|tarantool-ee)(?:" + search.VersionCliSeparator + "(?P.*))?$", + "^(?Ptt|tarantool|tarantool-ee)(?:" + version.CliSeparator + "(?P.*))?$", ) matches := util.FindNamedMatches(re, program) @@ -40,7 +40,7 @@ func remove(program string, directory string, cmdCtx *cmdcontext.CmdCtx) error { return fmt.Errorf("there was some problem with %s directory", directory) } - fileName := matches["prog"] + search.VersionFsSeparator + matches["ver"] + fileName := matches["prog"] + version.FsSeparator + matches["ver"] path := filepath.Join(directory, fileName) if _, err := os.Stat(path); os.IsNotExist(err) { @@ -89,7 +89,7 @@ func GetList(cliOpts *config.CliOpts) []string { list := []string{} re := regexp.MustCompile( "^(?P(?:tarantool)|(?:tarantool-ee)|(?:tt))" + - search.VersionFsSeparator + + version.FsSeparator + "(?P.*)$", ) @@ -105,7 +105,7 @@ func GetList(cliOpts *config.CliOpts) []string { for _, file := range installedPrograms { matches := util.FindNamedMatches(re, file.Name()) if len(matches) != 0 { - list = append(list, matches["prog"]+search.VersionCliSeparator+matches["ver"]) + list = append(list, matches["prog"]+version.CliSeparator+matches["ver"]) } } diff --git a/cli/uninstall/uninstall_test.go b/cli/uninstall/uninstall_test.go index d4eff4869..79b35f26a 100644 --- a/cli/uninstall/uninstall_test.go +++ b/cli/uninstall/uninstall_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tarantool/tt/cli/configure" - "github.com/tarantool/tt/cli/search" + "github.com/tarantool/tt/cli/version" ) const testDirName = "uninstall-test-dir" @@ -31,9 +31,9 @@ func TestGetList(t *testing.T) { require.NoError(t, err) files := []string{ - "tt" + search.VersionFsSeparator + "1.2.3", - "tarantool" + search.VersionFsSeparator + "1.2.10", - "tarantool-ee" + search.VersionFsSeparator + "master", + "tt" + version.FsSeparator + "1.2.3", + "tarantool" + version.FsSeparator + "1.2.10", + "tarantool-ee" + version.FsSeparator + "master", } for _, file := range files { f, err := os.Create(filepath.Join(binDir, file)) @@ -42,9 +42,9 @@ func TestGetList(t *testing.T) { } expected := []string{ - "tt" + search.VersionCliSeparator + "1.2.3", - "tarantool" + search.VersionCliSeparator + "1.2.10", - "tarantool-ee" + search.VersionCliSeparator + "master", + "tt" + version.CliSeparator + "1.2.3", + "tarantool" + version.CliSeparator + "1.2.10", + "tarantool-ee" + version.CliSeparator + "master", } cliOpts, _, err := configure.GetCliOpts(cfgPath) diff --git a/cli/version/version_tools.go b/cli/version/version_tools.go index 0f63db586..5645bd4f6 100644 --- a/cli/version/version_tools.go +++ b/cli/version/version_tools.go @@ -3,7 +3,6 @@ package version import ( "fmt" "regexp" - "sort" "github.com/tarantool/tt/cli/util" ) @@ -16,6 +15,11 @@ const ( TypeBeta TypeRC TypeRelease + + // CliSeparator is used in commands to specify version. E.g: program=version. + CliSeparator = "=" + // FsSeparator is used in file names to specify version. E.g: program_version. + FsSeparator = "_" ) type Release struct { @@ -36,8 +40,8 @@ type Version struct { GCSuffix string // GC suffix. } -// GetVersionDetails collects information about all version details. -func GetVersionDetails(verStr string) (Version, error) { +// Parse parses a version string and return the version value it represents. +func Parse(verStr string) (Version, error) { version := Version{} var err error @@ -55,7 +59,7 @@ func GetVersionDetails(verStr string) (Version, error) { matches := util.FindNamedMatches(re, verStr) if len(matches) == 0 { - return version, fmt.Errorf("failed to parse version: format is not valid") + return version, fmt.Errorf("failed to parse version %q: format is not valid", verStr) } if matches["gc"] != "" { @@ -114,17 +118,19 @@ func GetVersionDetails(verStr string) (Version, error) { return version, nil } -// SortVersions sorts versions from oldest to newest. -func SortVersions(versions []Version) { - sort.SliceStable(versions, func(i, j int) bool { - verLeft := versions[i] - verRight := versions[j] - return Less(verLeft, verRight) - }) +// VersionSlice attaches the methods of sort.Interface to []Version, sorting from oldest to newest. +type VersionSlice []Version + +// sort.Interface Len implementation +func (v VersionSlice) Len() int { + return len(v) } -// Less is a common function-comparator using for the Version type. -func Less(verLeft, verRight Version) bool { +// sort.Interface Less implementation, sorts from oldest to newest +func (v VersionSlice) Less(i, j int) bool { + verLeft := v[i] + verRight := v[j] + left := []uint64{verLeft.Major, verLeft.Minor, verLeft.Patch, uint64(verLeft.Release.Type), verLeft.Release.Num, verLeft.Additional, verLeft.Revision} @@ -151,3 +157,8 @@ func Less(verLeft, verRight Version) bool { return false } + +// sort.Interface Swap implementation +func (v VersionSlice) Swap(i, j int) { + v[i], v[j] = v[j], v[i] +} diff --git a/cli/version/version_tools_test.go b/cli/version/version_tools_test.go index dc8e009e4..6b93d8d74 100644 --- a/cli/version/version_tools_test.go +++ b/cli/version/version_tools_test.go @@ -116,16 +116,16 @@ func TestParseVersion(t *testing.T) { testCases["2.8"] = returnValueParseVersion{ Version{}, - fmt.Errorf("failed to parse version: format is not valid"), + fmt.Errorf("failed to parse version \"2.8\": format is not valid"), } testCases["42"] = returnValueParseVersion{ Version{}, - fmt.Errorf("failed to parse version: format is not valid"), + fmt.Errorf("failed to parse version \"42\": format is not valid"), } for input, output := range testCases { - version, err := GetVersionDetails(input) + version, err := Parse(input) if output.err == nil { assert.Nil(err) From 59c1341035453a4a53b2e6b607e12f67b34c77f7 Mon Sep 17 00:00:00 2001 From: better0fdead Date: Wed, 15 Mar 2023 12:31:53 +0300 Subject: [PATCH 3/3] binaries: refactor code Refactored code of binaries package. Refactored tests. Co-authored-by: psergee Part of #196 --- cli/cmd/binaries.go | 4 +- cli/list/list.go | 131 ++++++------------ cli/list/list_test.go | 57 ++------ cli/list/testdata/bin/tarantool | 1 + cli/list/testdata/bin/tarantool_1.10.0 | 0 cli/list/testdata/bin/tarantool_2.10.5 | 0 cli/list/testdata/bin/tarantool_master | 0 cli/list/testdata/bin/tarantool_v2.8.6 | 0 test/integration/binaries/bin/tarantool | 1 + .../integration/binaries/bin/tarantool_2.10.3 | 0 test/integration/binaries/bin/tarantool_2.8.1 | 0 test/integration/binaries/bin/tt_v0.1.0 | 0 test/integration/binaries/test_binaries.py | 6 +- 13 files changed, 59 insertions(+), 141 deletions(-) create mode 120000 cli/list/testdata/bin/tarantool create mode 100644 cli/list/testdata/bin/tarantool_1.10.0 create mode 100644 cli/list/testdata/bin/tarantool_2.10.5 create mode 100644 cli/list/testdata/bin/tarantool_master create mode 100644 cli/list/testdata/bin/tarantool_v2.8.6 create mode 120000 test/integration/binaries/bin/tarantool mode change 100644 => 100755 test/integration/binaries/bin/tarantool_2.10.3 mode change 100644 => 100755 test/integration/binaries/bin/tarantool_2.8.1 mode change 100644 => 100755 test/integration/binaries/bin/tt_v0.1.0 diff --git a/cli/cmd/binaries.go b/cli/cmd/binaries.go index 3e70fcf99..cd4b23297 100644 --- a/cli/cmd/binaries.go +++ b/cli/cmd/binaries.go @@ -24,7 +24,5 @@ func NewBinariesCmd() *cobra.Command { // internalBinariesModule is a default binaries module. func internalBinariesModule(cmdCtx *cmdcontext.CmdCtx, args []string) error { - err := list.ListBinaries(cmdCtx, cliOpts) - - return err + return list.ListBinaries(cmdCtx, cliOpts) } diff --git a/cli/list/list.go b/cli/list/list.go index 65372f806..da41dc4e6 100644 --- a/cli/list/list.go +++ b/cli/list/list.go @@ -3,10 +3,10 @@ package list import ( "fmt" "io/fs" + "math" "os" "path/filepath" "sort" - "strconv" "strings" "github.com/apex/log" @@ -61,106 +61,55 @@ func ListInstances(cmdCtx *cmdcontext.CmdCtx, cliOpts *config.CliOpts) error { } // printBinaries outputs installed versions of the program. -func printBinaries(program string, binList []string) { - if len(binList) > 0 { - log.Infof(program + ":") - for _, bin := range binList { - if strings.HasSuffix(bin, "[active]") { - fmt.Printf(" %s\n", util.Bold(color.GreenString(bin))) - } else { - fmt.Printf(" %s\n", color.YellowString(bin)) - } - } - } -} - -// sortBinaryVersions sorts versions of binary. -func sortBinaryVersions(binList []string) ([]string, error) { - var versions []version.Version - var sortedVersions []string - var err error - - // Convert string to version (struct). - for _, ver := range binList { - if strings.HasPrefix(ver, "master") { - sortedVersions = append(sortedVersions, ver) - } - var versionInt [3]int - var version version.Version - verString := strings.Split(ver, ".") - if len(verString) != 3 { - continue - } - verPatch := strings.Split(verString[2], "") - verString[2] = verPatch[0] - for i, ch := range verString { - versionInt[i], err = strconv.Atoi(ch) - if err != nil { - return nil, err - } - } - version.Major = uint64(versionInt[0]) - version.Minor = uint64(versionInt[1]) - version.Patch = uint64(versionInt[2]) - version.Str = ver - - versions = append(versions, version) - } - - // Sort versions. - sort.Stable(version.VersionSlice(versions)) - for i, j := 0, len(versions)-1; i < j; i, j = i+1, j-1 { - versions[i], versions[j] = versions[j], versions[i] - } - - for _, version := range versions { - sortedVersions = append(sortedVersions, version.Str) +func printVersion(versionString string) { + if strings.HasSuffix(versionString, "[active]") { + fmt.Printf(" %s\n", util.Bold(color.GreenString(versionString))) + } else { + fmt.Printf(" %s\n", color.YellowString(versionString)) } - return sortedVersions, err } // parseBinaries seeks through fileList returning array of found versions of program. func parseBinaries(fileList []fs.DirEntry, programName string, - binDir string) ([]string, error) { - var err error - var binaryVersion []string - binActive := "" - - // Files w/o version in name are symlinks to the active binaries. - if util.ContainsFile(fileList, programName) { - binActive, err = util.ResolveSymlink(filepath.Join(binDir, programName)) - if err != nil { - return nil, err - } - binActive = strings.TrimPrefix(filepath.Base(binActive), programName+"_") + binDir string) ([]version.Version, error) { + var binaryVersions []version.Version + binActive, err := util.ResolveSymlink(filepath.Join(binDir, programName)) + if err != nil && !os.IsNotExist(err) { + return binaryVersions, err } + binActive = filepath.Base(binActive) + versionPrefix := programName + version.FsSeparator for _, f := range fileList { - if f.IsDir() { - continue - } - if strings.HasPrefix(f.Name(), programName) && f.Name() != programName { - binVersion := strings.TrimPrefix(f.Name(), programName+"_") - binVersion = strings.TrimPrefix(binVersion, "v") - if binVersion == binActive { - binaryVersion = append(binaryVersion, binVersion+" [active]") + if strings.HasPrefix(f.Name(), versionPrefix) { + versionStr := strings.TrimPrefix(strings.TrimPrefix(f.Name(), versionPrefix), "v") + if versionStr == "master" { + binaryVersions = append(binaryVersions, version.Version{ + Major: math.MaxUint, // Small hack to make master the newest version. + Str: "master", + }) } else { - binaryVersion = append(binaryVersion, binVersion) + ver, err := version.Parse(versionStr) + if err != nil { + return binaryVersions, err + } + if binActive == f.Name() { + ver.Str += " [active]" + } + binaryVersions = append(binaryVersions, ver) } } } - return binaryVersion, err + return binaryVersions, nil } // ListBinaries outputs installed versions of programs from bin_dir. -func ListBinaries(cmdCtx *cmdcontext.CmdCtx, cliOpts *config.CliOpts) error { - var err error - +func ListBinaries(cmdCtx *cmdcontext.CmdCtx, cliOpts *config.CliOpts) (err error) { binDir := cliOpts.App.BinDir - binDirFilesList, err := os.ReadDir(cliOpts.App.BinDir) + binDirFilesList, err := os.ReadDir(binDir) if err != nil { - return fmt.Errorf("there was some problem reading bin_dir: %s", err) + return fmt.Errorf("error reading directory %q: %s", binDir, err) } if len(binDirFilesList) == 0 { @@ -169,20 +118,18 @@ func ListBinaries(cmdCtx *cmdcontext.CmdCtx, cliOpts *config.CliOpts) error { programs := [...]string{"tt", "tarantool"} fmt.Println("List of installed binaries:") - for _, prog := range programs { - binaryVersion, err := parseBinaries(binDirFilesList, prog, binDir) + for _, programName := range programs { + binaryVersions, err := parseBinaries(binDirFilesList, programName, binDir) if err != nil { return err } - if len(binaryVersion) > 0 { - // Sort version array. - sorted, err := sortBinaryVersions(binaryVersion) - if err != nil { - return err + if len(binaryVersions) > 0 { + sort.Stable(sort.Reverse(version.VersionSlice(binaryVersions))) + log.Infof(programName + ":") + for _, binVersion := range binaryVersions { + printVersion(binVersion.Str) } - // Print the output. - printBinaries(prog, sorted) } } diff --git a/cli/list/list_test.go b/cli/list/list_test.go index 6dd824b1d..bed787b21 100644 --- a/cli/list/list_test.go +++ b/cli/list/list_test.go @@ -1,53 +1,24 @@ package list import ( + "os" + "sort" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tarantool/tt/cli/version" ) -func TestSortValid(t *testing.T) { - type argsData struct { - input, expected []string - } - - testArgsData := []argsData{ - {[]string{"0.3.0", "1.3.0-nightly", "0.1.0"}, - []string{"1.3.0-nightly", "0.3.0", "0.1.0"}}, - {[]string{"1.3.0", "1.4.0", "1.2.0"}, - []string{"1.4.0", "1.3.0", "1.2.0"}}, - {[]string{"1.3.0", "2.3.0", "3.3.0"}, - []string{"3.3.0", "2.3.0", "1.3.0"}}, - {[]string{"3.3.1", "3.3.3", "3.3.0"}, - []string{"3.3.3", "3.3.1", "3.3.0"}}, - {[]string{"master", "3.3.3", "3.3.0"}, - []string{"master", "3.3.3", "3.3.0"}}, - } - - for _, testData := range testArgsData { - returned, err := sortBinaryVersions(testData.input) - require.Nil(t, err) - require.Equal(t, returned, testData.expected) - } -} - -func TestSortNonValid(t *testing.T) { - type argsData struct { - input, expected []string - } - - testArgsData := []argsData{ - {[]string{"123123", "1.3.0-nightly", "0.1.0"}, - []string{"1.3.0-nightly", "0.1.0"}}, - {[]string{"1.3.0.2.2.2.2", "1.4.0", "1.2.0"}, - []string{"1.4.0", "1.2.0"}}, - {[]string{"3.3.1", "foo", "3.3.0"}, - []string{"3.3.1", "3.3.0"}}, - } - - for _, testData := range testArgsData { - returned, err := sortBinaryVersions(testData.input) - require.Nil(t, err) - require.Equal(t, returned, testData.expected) +func TestParseBinaries(t *testing.T) { + fileList, err := os.ReadDir("./testdata/bin") + require.NoError(t, err) + versions, err := parseBinaries(fileList, "tarantool", "./testdata/bin") + require.NoError(t, err) + sort.Stable(sort.Reverse(version.VersionSlice(versions))) + expectedSortedVersions := []string{"master", "2.10.5", "2.8.6 [active]", "1.10.0"} + require.Equal(t, len(expectedSortedVersions), len(versions)) + for i := 0; i < len(expectedSortedVersions); i++ { + assert.Equal(t, expectedSortedVersions[i], versions[i].Str) } } diff --git a/cli/list/testdata/bin/tarantool b/cli/list/testdata/bin/tarantool new file mode 120000 index 000000000..d1a032223 --- /dev/null +++ b/cli/list/testdata/bin/tarantool @@ -0,0 +1 @@ +tarantool_v2.8.6 \ No newline at end of file diff --git a/cli/list/testdata/bin/tarantool_1.10.0 b/cli/list/testdata/bin/tarantool_1.10.0 new file mode 100644 index 000000000..e69de29bb diff --git a/cli/list/testdata/bin/tarantool_2.10.5 b/cli/list/testdata/bin/tarantool_2.10.5 new file mode 100644 index 000000000..e69de29bb diff --git a/cli/list/testdata/bin/tarantool_master b/cli/list/testdata/bin/tarantool_master new file mode 100644 index 000000000..e69de29bb diff --git a/cli/list/testdata/bin/tarantool_v2.8.6 b/cli/list/testdata/bin/tarantool_v2.8.6 new file mode 100644 index 000000000..e69de29bb diff --git a/test/integration/binaries/bin/tarantool b/test/integration/binaries/bin/tarantool new file mode 120000 index 000000000..9b336d7e3 --- /dev/null +++ b/test/integration/binaries/bin/tarantool @@ -0,0 +1 @@ +tarantool_2.8.1 \ No newline at end of file diff --git a/test/integration/binaries/bin/tarantool_2.10.3 b/test/integration/binaries/bin/tarantool_2.10.3 old mode 100644 new mode 100755 diff --git a/test/integration/binaries/bin/tarantool_2.8.1 b/test/integration/binaries/bin/tarantool_2.8.1 old mode 100644 new mode 100755 diff --git a/test/integration/binaries/bin/tt_v0.1.0 b/test/integration/binaries/bin/tt_v0.1.0 old mode 100644 new mode 100755 diff --git a/test/integration/binaries/test_binaries.py b/test/integration/binaries/test_binaries.py index 41b423dee..5ee3dc021 100644 --- a/test/integration/binaries/test_binaries.py +++ b/test/integration/binaries/test_binaries.py @@ -8,7 +8,7 @@ def test_binaries(tt_cmd, tmpdir): # Copy the test bin_dir to the "run" directory. test_app_path = os.path.join(os.path.dirname(__file__), "bin") - shutil.copytree(test_app_path, tmpdir + "/bin") + shutil.copytree(test_app_path, tmpdir + "/bin", True) configPath = os.path.join(tmpdir, config_name) # Create test config @@ -32,7 +32,7 @@ def test_binaries(tt_cmd, tmpdir): assert "0.1.0" in output assert "tarantool" in output assert "2.10.3" in output - assert "2.8.1" in output + assert "2.8.1 [active]" in output def test_binaries_no_directory(tt_cmd, tmpdir): @@ -54,7 +54,7 @@ def test_binaries_no_directory(tt_cmd, tmpdir): binaries_process.wait() output = binaries_process.stdout.read() - assert "there was some problem reading bin_dir" in output + assert "error reading directory" in output def test_binaries_empty_directory(tt_cmd, tmpdir):