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
3 changes: 3 additions & 0 deletions main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/aliyun/aliyun-cli/v3/openapi"
"github.com/aliyun/aliyun-cli/v3/oss/lib"
"github.com/aliyun/aliyun-cli/v3/ossutil"
"github.com/aliyun/aliyun-cli/v3/otsutil"
)

func Main(args []string) {
Expand Down Expand Up @@ -79,6 +80,8 @@ func Main(args []string) {
rootCmd.AddSubCommand(go_migrate.NewGoMigrateCommand())
// new oss command
rootCmd.AddSubCommand(ossutil.NewOssutilCommand())
// tablestore command
rootCmd.AddSubCommand(otsutil.NewOtsutilCommand())
if os.Getenv("GENERATE_METADATA") == "YES" {
generateMetadata(rootCmd)
} else {
Expand Down
5 changes: 3 additions & 2 deletions ossutil/ossutil2.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/alibabacloud-go/tea/tea"
"github.com/aliyun/aliyun-cli/v3/cli"
"github.com/aliyun/aliyun-cli/v3/config"
"github.com/aliyun/aliyun-cli/v3/util"
)

type Context struct {
Expand Down Expand Up @@ -327,9 +328,9 @@ func DownloadAndUnzip(url string, destFile string, exeFilePath string, extractCe
return fmt.Errorf("failed to remove existing file %s: %v", exeFilePath, err)
}
}
err = os.Rename(sourceFile, exeFilePath)
err = util.CopyFileAndRemoveSource(sourceFile, exeFilePath)
if err != nil {
return fmt.Errorf("failed to move file from %s to %s: %v", sourceFile, exeFilePath, err)
return err
}
// set exec permission
if runtime.GOOS != "windows" {
Expand Down
42 changes: 42 additions & 0 deletions otsutil/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package otsutil

import (
"github.com/aliyun/aliyun-cli/v3/cli"
"github.com/aliyun/aliyun-cli/v3/i18n"
)

func NewOtsutilCommand() *cli.Command {
return &cli.Command{
Name: "otsutil",
Short: i18n.T("Alibaba Cloud Tablestore Utility", "阿里云表格存储工具"),
Usage: "aliyun otsutil <command> [args...]",
Hidden: false,
Run: func(ctx *cli.Context, args []string) error {
if ctx.IsHelp() {
hasHelp := false
for i, arg := range args {
if arg == "help" {
hasHelp = true
break
} else if arg == "--help" {
// 将 --help 替换为 help
args[i] = "help"
hasHelp = true
break
}
}
// 如果没有找到 help 相关参数,说明是被过滤掉的 "help" 参数
if !hasHelp {
args = append(args, "help")
}
}
// fmt.Println("otsutil args", args)
options := NewContext(ctx)
return options.Run(args)
},
// allow unknown args
EnableUnknownFlag: true,
KeepArgs: true,
SkipDefaultHelp: true, // DO NOT use default help and version
}
}
106 changes: 106 additions & 0 deletions otsutil/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package otsutil

import (
"bytes"
"os"
"path/filepath"
"testing"

"github.com/aliyun/aliyun-cli/v3/cli"
)

func TestNewOtsCommand(t *testing.T) {
cmd := NewOtsutilCommand()
if cmd == nil {
t.Fatalf("NewOtsutilCommand returned nil")
}
if cmd.Name != "otsutil" {
t.Errorf("Name expected 'otsutil', got %s", cmd.Name)
}
if cmd.Short == nil {
t.Fatalf("Short i18n text nil")
}
if en := cmd.Short.Get("en"); en != "Alibaba Cloud Tablestore Utility" {
t.Errorf("Short en expected 'Alibaba Cloud Tablestore Utility', got %s", en)
}
if zh := cmd.Short.Get("zh"); zh != "阿里云表格存储工具" {
t.Errorf("Short zh expected '阿里云表格存储工具', got %s", zh)
}
if cmd.Usage != "aliyun otsutil <command> [args...]" {
t.Errorf("Usage expected 'aliyun otsutil <command> [args...]', got %s", cmd.Usage)
}
if cmd.Hidden {
t.Errorf("Hidden expected false")
}
if !cmd.EnableUnknownFlag {
t.Errorf("EnableUnknownFlag expected true")
}
if !cmd.KeepArgs {
t.Errorf("KeepArgs expected true")
}
if !cmd.SkipDefaultHelp {
t.Errorf("SkipDefaultHelp expected true")
}
if cmd.Run == nil {
t.Errorf("Run function should not be nil")
}
}

func TestNewOtsCommandMetadata(t *testing.T) {
cmd := NewOtsutilCommand()
metaMap := map[string]*cli.Metadata{}
cmd.GetMetadata(metaMap)
m, ok := metaMap[cmd.Name]
if !ok {
t.Fatalf("metadata for %s not found", cmd.Name)
}
if m.Name != "otsutil" {
t.Errorf("metadata name expected otsutil, got %s", m.Name)
}
if m.Usage != cmd.Usage {
t.Errorf("metadata usage mismatch")
}
if m.Hidden != cmd.Hidden {
t.Errorf("metadata hidden mismatch")
}
if se := m.Short["en"]; se != "Alibaba Cloud Tablestore Utility" {
t.Errorf("metadata short en mismatch: %s", se)
}
if sz := m.Short["zh"]; sz != "阿里云表格存储工具" {
t.Errorf("metadata short zh mismatch: %s", sz)
}
}

func TestOtsCommandRunInstalledSkipNetwork(t *testing.T) {
// 准备临时目录作为配置路径
tmpDir := t.TempDir()
oldGet := getConfigurePathFunc
getConfigurePathFunc = func() string { return tmpDir }
defer func() { getConfigurePathFunc = oldGet }()

// 创建假可执行文件(ts)
execPath := filepath.Join(tmpDir, "ts")
if err := os.WriteFile(execPath, []byte("#!/bin/sh\necho dummy\n"), 0755); err != nil {
t.Fatalf("write fake exec: %v", err)
}

// 设置忽略profile,避免真实配置依赖
os.Setenv("ALIBABA_CLOUD_IGNORE_PROFILE", "TRUE")
defer os.Unsetenv("ALIBABA_CLOUD_IGNORE_PROFILE")

cmd := NewOtsutilCommand()
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
ctx := cli.NewCommandContext(stdout, stderr)

// 直接调用Run函数(不经过Command.Execute解析)
err := cmd.Run(ctx, []string{})
if err == nil {
t.Fatalf("expected error, got nil")
}
errStr := err.Error()
if !bytes.Contains([]byte(errStr), []byte("profile default is not configure yet")) &&
!bytes.Contains([]byte(errStr), []byte("can't get credential")) {
t.Errorf("unexpected error: %v", err)
}
}
Loading
Loading