Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Changed

- `tt pack` now skips all `.git` files in packed environment, not only in main directory.
### Added

- `tt install tarantool-dev`: ability to install tarantool from the local build directory.

## [1.1.2] - 2023-06-16

Expand All @@ -25,6 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Fixed

- Panic in tarantool 1.10.15 static build by `tt`.
- Removed `--use-docker` flag from `tt uninstall tarantool` since it was added by mistake.

## [1.1.1] - 2023-06-08

Expand Down
26 changes: 26 additions & 0 deletions cli/cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,31 @@ func newInstallTarantoolEeCmd() *cobra.Command {
return tntCmd
}

// newInstallTarantoolDevCmd creates a command to install tarantool
// from the local build directory.
func newInstallTarantoolDevCmd() *cobra.Command {
tntCmd := &cobra.Command{
Use: "tarantool-dev <DIRECTORY>",
Short: "Install tarantool from the local build directory",
Example: "Assume, tarantool build directory is ~/src/tarantool/build\n" +
" Consider the following use case:\n\n" +
" make -j16 -C ~/src/tarantool/build\n" +
" tt install tarantool-dev ~/src/tarantool/build\n" +
" tt run # runs the binary compiled above",
Run: func(cmd *cobra.Command, args []string) {
cmdCtx.CommandName = cmd.Name()
installCtx.ProgramName = cmd.Name()
err := modules.RunCmd(&cmdCtx, cmd.CommandPath(), &modulesInfo,
internalInstallModule, args)
handleCmdErr(cmd, err)
},
}

tntCmd.Flags().StringVar(&installCtx.IncDir, "include-dir", "",
"tarantool headers directory")
return tntCmd
}

// NewInstallCmd creates install command.
func NewInstallCmd() *cobra.Command {
var installCmd = &cobra.Command{
Expand All @@ -91,6 +116,7 @@ func NewInstallCmd() *cobra.Command {
newInstallTtCmd(),
newInstallTarantoolCmd(),
newInstallTarantoolEeCmd(),
newInstallTarantoolDevCmd(),
)

return installCmd
Expand Down
21 changes: 18 additions & 3 deletions cli/cmd/uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ func newUninstallTarantoolCmd() *cobra.Command {
},
}

tntCmd.Flags().BoolVarP(&installCtx.BuildInDocker, "use-docker", "", false,
"build tarantool in Ubuntu 18.04 docker container")

return tntCmd
}

Expand All @@ -67,6 +64,23 @@ func newUninstallTarantoolEeCmd() *cobra.Command {
return tntCmd
}

// newUninstallTarantoolDevCmd creates a command to uninstall tarantool-dev.
func newUninstallTarantoolDevCmd() *cobra.Command {
tntCmd := &cobra.Command{
Use: "tarantool-dev",
Short: "Uninstall tarantool-dev",
Run: func(cmd *cobra.Command, args []string) {
cmdCtx.CommandName = cmd.Name()
programName = cmd.Name()
err := modules.RunCmd(&cmdCtx, cmd.CommandPath(), &modulesInfo,
InternalUninstallModule, args)
handleCmdErr(cmd, err)
},
}

return tntCmd
}

// NewUninstallCmd creates uninstall command.
func NewUninstallCmd() *cobra.Command {
var uninstallCmd = &cobra.Command{
Expand All @@ -82,6 +96,7 @@ func NewUninstallCmd() *cobra.Command {
newUninstallTtCmd(),
newUninstallTarantoolCmd(),
newUninstallTarantoolEeCmd(),
newUninstallTarantoolDevCmd(),
)

return uninstallCmd
Expand Down
111 changes: 111 additions & 0 deletions cli/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ type InstallCtx struct {
version string
// Dynamic flag enables dynamic linking.
Dynamic bool
// buildDir is the directory, where the tarantool executable is searched,
// in case of installation from the local build directory.
buildDir string
// IncDir is the directory, where the tarantool headers are located.
IncDir string
}

// Package is a struct containing sys and install name of the package.
Expand Down Expand Up @@ -124,6 +129,18 @@ var (
VersionIDRe = regexp.MustCompile(`^VERSION_ID=(.*)$`)
)

// IsTarantoolDev returns true if tarantoolBinarySymlink is `tarantool-dev` version.
func IsTarantoolDev(tarantoolBinarySymlink, binDir string) (string, bool, error) {
bin, err := os.Readlink(tarantoolBinarySymlink)
if err != nil {
return "", false, err
}
if !filepath.IsAbs(bin) {
bin = filepath.Join(binDir, bin)
}
return bin, filepath.Dir(bin) != binDir, nil
}

// getDistroInfo collects info about linux distro.
func getDistroInfo() (DistroInfo, error) {
var distroInfo DistroInfo
Expand Down Expand Up @@ -1114,6 +1131,89 @@ func dirIsWritable(dir string) bool {
return unix.Access(dir, unix.W_OK) == nil
}

// installTarantoolDev installs tarantool from the local build directory.
func installTarantoolDev(ttBinDir string, ttIncludeDir, buildDir,
includeDir string) error {
var err error

// Validate build directory.
if buildDir, err = filepath.Abs(buildDir); err != nil {
return fmt.Errorf("failed to get absolute path: %v", err)
}
if !util.IsDir(buildDir) {
return fmt.Errorf("directory %v doesn't exist, or isn't directory", buildDir)
}

defaultIncPath := filepath.Join(buildDir, "tarantool-prefix", "include", "tarantool")
if includeDir != "" {
// Validate headers directory.
if includeDir, err = filepath.Abs(includeDir); err != nil {
return fmt.Errorf("failed to get absolute path: %v", err)
}
if !util.IsDir(includeDir) {
return fmt.Errorf("directory %v doesn't exist, "+
"or isn't directory", includeDir)
}
} else {
// Check for default.
if util.IsDir(defaultIncPath) {
log.Infof("tarantool headers directory set as %v", defaultIncPath)
includeDir = defaultIncPath
}
}

if includeDir == "" {
log.Warn("Tarantool headers location was not specified and" +
fmt.Sprintf(" was not found in %v\n", defaultIncPath) +
"`tt build`, `tt rocks` may not work properly.\n" +
" To specify include files location use --include-dir option.")
}

// Check that tt directories exist.
if err = util.CreateDirectory(ttBinDir, defaultDirPermissions); err != nil {
return err
}
if err = util.CreateDirectory(ttIncludeDir, defaultDirPermissions); err != nil {
return err
}

checkedBinaryPaths := make([]string, 0)

// Searching for tarantool binary.
for _, binaryRelPath := range [...]string{"src/tarantool", "tarantool/src/tarantool"} {
binaryPath := filepath.Join(buildDir, binaryRelPath)

var isExecOwner bool
isExecOwner, err = util.IsExecOwner(binaryPath)
if err == nil && isExecOwner && !util.IsDir(binaryPath) {
log.Infof("Changing symlinks...")
err = util.CreateSymlink(binaryPath, filepath.Join(ttBinDir, "tarantool"), true)
if err != nil {
return err
}
tarantoolIncludeSymlink := filepath.Join(ttIncludeDir, "tarantool")
// Remove the old symlink to the tarantool headers.
// RemoveAll is used to perform deletion even if the file is not a symlink.
err = os.RemoveAll(tarantoolIncludeSymlink)
if err != nil {
return err
}
if includeDir != "" {
err = util.CreateSymlink(includeDir, tarantoolIncludeSymlink, true)
if err != nil {
return err
}
}
log.Infof("Done.")
return nil
}
checkedBinaryPaths = append(checkedBinaryPaths, binaryPath)
}

return fmt.Errorf("tarantool binary was not found in the paths:\n%s",
strings.Join(checkedBinaryPaths, "\n"))
}

// subDirIsWritable checks if the passed dir doesn't exist but can be created.
func subDirIsWritable(dir string) bool {
var err error
Expand Down Expand Up @@ -1153,6 +1253,9 @@ func Install(binDir string, includeDir string, installCtx InstallCtx,
err = installTarantool(binDir, includeDir, installCtx, local)
case search.ProgramEe:
err = installTarantoolEE(binDir, includeDir, installCtx, local, cliOpts)
case search.ProgramDev:
err = installTarantoolDev(binDir, includeDir, installCtx.buildDir,
installCtx.IncDir)
default:
return fmt.Errorf("unknown application: %s", installCtx.ProgramName)
}
Expand All @@ -1163,6 +1266,14 @@ func Install(binDir string, includeDir string, installCtx InstallCtx,
func FillCtx(cmdCtx *cmdcontext.CmdCtx, installCtx *InstallCtx, args []string) error {
installCtx.verbose = cmdCtx.Cli.Verbose

if cmdCtx.CommandName == search.ProgramDev {
if len(args) != 1 {
return fmt.Errorf("exactly one build directory must be specified")
}
installCtx.buildDir = args[0]
return nil
}

if len(args) == 1 {
installCtx.version = args[0]
} else if len(args) > 1 {
Expand Down
130 changes: 130 additions & 0 deletions cli/install/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,133 @@ func Test_getLatestRelease(t *testing.T) {
latestRelease = getLatestRelease(versions[1:6])
require.Equal(t, "", latestRelease)
}

func Test_installTarantoolDev(t *testing.T) {
ttBinDir := "binDir"
ttIncDir := "incDir"

setupEnv := func() string {
// ├── ttBinDir
// ├── build_ce
// │ └── src
// │ └── tarantool
// ├── build_invalid
// │ └── tarantool
// │ └── src
// │ └── tarantool
// └── ttIncDir

tempDir := os.TempDir()
tempsDir, _ := os.MkdirTemp(tempDir, "install_tarantool_dev_test")

ttBinDir := filepath.Join(tempsDir, ttBinDir)
os.Mkdir(ttBinDir, os.ModePerm)

ttIncDir := filepath.Join(tempsDir, ttIncDir)
os.Mkdir(ttIncDir, os.ModePerm)

buildDir1 := filepath.Join(tempsDir, "build_ce")
os.MkdirAll(filepath.Join(buildDir1, "src"), os.ModePerm)
binaryPath1 := filepath.Join(buildDir1, "src/tarantool")
os.Create(binaryPath1)
os.Chmod(binaryPath1, 0700)

buildDir2 := filepath.Join(tempsDir, "build_invalid")
os.MkdirAll(filepath.Join(buildDir2, "tarantool/src"), os.ModePerm)
binaryPath2 := filepath.Join(buildDir2, "tarantool/src/tarantool")
os.Create(binaryPath2)
os.Chmod(binaryPath2, 0700)

return tempsDir
}

t.Run("no include-dir", func(t *testing.T) {
tempDirectory := setupEnv()
defer os.RemoveAll(tempDirectory)

ttBinPath := filepath.Join(tempDirectory, ttBinDir)
ttIncPath := filepath.Join(tempDirectory, ttIncDir)

cases := []struct {
buildDir string
relExecPath string
}{
{filepath.Join(tempDirectory, "build_ce"), "/src/tarantool"},
{filepath.Join(tempDirectory, "build_invalid"), "/tarantool/src/tarantool"},
}

for _, tc := range cases {
err := installTarantoolDev(ttBinPath, ttIncPath, tc.buildDir, "")
assert.NoError(t, err)
link, err := os.Readlink(filepath.Join(ttBinPath, "tarantool"))
assert.NoError(t, err)
assert.Equal(t, filepath.Join(tc.buildDir, tc.relExecPath), link)

// Check that old includeDir was removed.
_, err = os.Readlink(filepath.Join(ttIncPath, "tarantool"))
assert.Error(t, err)
}
})

t.Run("with include-dir", func(t *testing.T) {
tempDirectory := setupEnv()
defer os.RemoveAll(tempDirectory)

ttBinPath := filepath.Join(tempDirectory, ttBinDir)
ttIncPath := filepath.Join(tempDirectory, ttIncDir)

// Default include-dir.
os.MkdirAll(filepath.Join(tempDirectory, "build_ce", "tarantool-prefix", "include",
"tarantool"), os.ModePerm,
)

// Custom include-dir.
customIncDirectoryPath := filepath.Join(tempDirectory, "build_invalid", "custom_inc")
os.MkdirAll(customIncDirectoryPath, os.ModePerm)
cases := []struct {
buildDir string
incDir string
relExecPath string
expectedIncLink string
}{
{
filepath.Join(tempDirectory, "build_ce"),
"",
"/src/tarantool",
filepath.Join(tempDirectory, "build_ce", "tarantool-prefix", "include",
"tarantool"),
},
{
filepath.Join(tempDirectory, "build_invalid"),
customIncDirectoryPath,
"/tarantool/src/tarantool",
filepath.Join(tempDirectory, "build_invalid", "custom_inc"),
},
}

for _, tc := range cases {
err := installTarantoolDev(ttBinPath, ttIncPath, tc.buildDir, tc.incDir)
assert.NoError(t, err)
execLink, err := os.Readlink(filepath.Join(ttBinPath, "tarantool"))
assert.NoError(t, err)
assert.Equal(t, execLink, filepath.Join(tc.buildDir, tc.relExecPath))

incLink, err := os.Readlink(filepath.Join(ttIncPath, "tarantool"))
assert.NoError(t, err)
assert.Equal(t, tc.expectedIncLink, incLink)
}
})

t.Run("no executable", func(t *testing.T) {
tempDirectory := setupEnv()
defer os.RemoveAll(tempDirectory)

ttBinPath := filepath.Join(tempDirectory, ttBinDir)
ttIncPath := filepath.Join(tempDirectory, ttIncDir)

buildDir := filepath.Join(tempDirectory, "build_ee")
os.MkdirAll(buildDir, os.ModePerm)
err := installTarantoolDev(ttBinPath, ttIncPath, buildDir, "")
assert.Error(t, err)
})
}
Loading