2021-10-10 10:48:53 +08:00
|
|
|
|
// Copyright (c) 2020 tickstep.
|
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
2023-10-07 16:42:43 +08:00
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2021-10-10 10:48:53 +08:00
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
2024-03-02 00:55:46 +08:00
|
|
|
|
"github.com/tickstep/aliyunpan/internal/global"
|
2022-01-12 15:55:09 +08:00
|
|
|
|
"io/ioutil"
|
2021-10-10 10:48:53 +08:00
|
|
|
|
"os"
|
2023-04-01 20:20:32 +08:00
|
|
|
|
"os/exec"
|
2021-10-10 10:48:53 +08:00
|
|
|
|
"path"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"runtime"
|
|
|
|
|
"sort"
|
2022-01-12 15:55:09 +08:00
|
|
|
|
"strconv"
|
2021-10-10 10:48:53 +08:00
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
"unicode"
|
|
|
|
|
|
2023-12-10 21:44:48 +08:00
|
|
|
|
"github.com/olekukonko/tablewriter"
|
2021-10-10 10:48:53 +08:00
|
|
|
|
"github.com/peterh/liner"
|
2023-12-10 21:44:48 +08:00
|
|
|
|
"github.com/tickstep/aliyunpan/cmder"
|
2021-10-10 10:48:53 +08:00
|
|
|
|
"github.com/tickstep/aliyunpan/cmder/cmdliner"
|
|
|
|
|
"github.com/tickstep/aliyunpan/cmder/cmdliner/args"
|
2023-12-10 21:44:48 +08:00
|
|
|
|
"github.com/tickstep/aliyunpan/cmder/cmdtable"
|
2021-10-10 10:48:53 +08:00
|
|
|
|
"github.com/tickstep/aliyunpan/cmder/cmdutil"
|
|
|
|
|
"github.com/tickstep/aliyunpan/cmder/cmdutil/escaper"
|
|
|
|
|
"github.com/tickstep/aliyunpan/internal/command"
|
|
|
|
|
"github.com/tickstep/aliyunpan/internal/config"
|
|
|
|
|
"github.com/tickstep/aliyunpan/internal/panupdate"
|
|
|
|
|
"github.com/tickstep/aliyunpan/internal/utils"
|
|
|
|
|
"github.com/tickstep/library-go/converter"
|
|
|
|
|
"github.com/tickstep/library-go/logger"
|
|
|
|
|
"github.com/urfave/cli"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// NameShortDisplayNum 文件名缩略显示长度
|
|
|
|
|
NameShortDisplayNum = 16
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
// Version 版本号
|
2024-08-11 16:57:13 +08:00
|
|
|
|
Version = "v0.3.3"
|
2021-10-10 10:48:53 +08:00
|
|
|
|
|
2022-01-30 10:39:26 +08:00
|
|
|
|
// 命令历史文件
|
2021-10-10 10:48:53 +08:00
|
|
|
|
historyFilePath = filepath.Join(config.GetConfigDir(), "aliyunpan_command_history.txt")
|
|
|
|
|
|
2022-01-30 10:39:26 +08:00
|
|
|
|
// 是否是交互命令行形态
|
2021-10-10 10:48:53 +08:00
|
|
|
|
isCli bool
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func init() {
|
2024-04-27 22:18:38 +08:00
|
|
|
|
b, ok := os.LookupEnv("ALIYUNPAN_NONE_OPENAPI")
|
|
|
|
|
if ok && b == "1" {
|
|
|
|
|
global.IsSupportNoneOpenApiCommands = true
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-02 00:55:46 +08:00
|
|
|
|
global.AppVersion = Version
|
2021-10-10 10:48:53 +08:00
|
|
|
|
cmdutil.ChWorkDir()
|
|
|
|
|
|
|
|
|
|
err := config.Config.Init()
|
|
|
|
|
switch err {
|
|
|
|
|
case nil:
|
|
|
|
|
case config.ErrConfigFileNoPermission, config.ErrConfigContentsParseError:
|
|
|
|
|
fmt.Fprintf(os.Stderr, "FATAL ERROR: config file error: %s\n", err)
|
2023-04-02 22:23:55 +08:00
|
|
|
|
//os.Exit(1)
|
2021-10-10 10:48:53 +08:00
|
|
|
|
default:
|
|
|
|
|
fmt.Printf("WARNING: config init error: %s\n", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func checkLoginExpiredAndRelogin() {
|
2022-12-10 14:07:28 +08:00
|
|
|
|
command.ReloadConfigFunc(nil)
|
2021-10-10 10:48:53 +08:00
|
|
|
|
activeUser := config.Config.ActiveUser()
|
|
|
|
|
if activeUser == nil || activeUser.UserId == "" {
|
|
|
|
|
// maybe expired, try to login
|
2022-12-10 14:07:28 +08:00
|
|
|
|
command.TryLogin()
|
2021-10-10 10:48:53 +08:00
|
|
|
|
} else {
|
2022-09-24 15:09:31 +08:00
|
|
|
|
// 刷新过期Token并保存到配置文件
|
2024-03-02 21:26:37 +08:00
|
|
|
|
command.RefreshWebTokenInNeed(activeUser, config.Config.DeviceName)
|
2024-03-03 09:11:58 +08:00
|
|
|
|
command.RefreshOpenTokenInNeed(activeUser)
|
2021-10-10 10:48:53 +08:00
|
|
|
|
}
|
2022-12-10 14:07:28 +08:00
|
|
|
|
command.SaveConfigFunc(nil)
|
2021-10-10 10:48:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
defer config.Config.Close()
|
|
|
|
|
|
|
|
|
|
// check & relogin
|
|
|
|
|
checkLoginExpiredAndRelogin()
|
|
|
|
|
|
|
|
|
|
// check token expired task
|
|
|
|
|
go func() {
|
|
|
|
|
for {
|
2022-09-24 15:09:31 +08:00
|
|
|
|
// Token刷新进程,不管是CLI命令行模式,还是直接命令模式,本刷新任务都会执行
|
2022-12-06 13:46:19 +08:00
|
|
|
|
time.Sleep(time.Duration(1) * time.Minute)
|
2021-10-10 10:48:53 +08:00
|
|
|
|
//time.Sleep(time.Duration(5) * time.Second)
|
2024-03-03 23:20:27 +08:00
|
|
|
|
for _, u := range config.Config.UserList {
|
|
|
|
|
if u.UserId == config.Config.ActiveUID {
|
|
|
|
|
if u.PanClient() != nil {
|
|
|
|
|
checkLoginExpiredAndRelogin()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-10 10:48:53 +08:00
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
app := cli.NewApp()
|
|
|
|
|
cmder.SetApp(app)
|
|
|
|
|
|
|
|
|
|
app.Name = "aliyunpan"
|
|
|
|
|
app.Version = Version
|
|
|
|
|
app.Author = "tickstep/aliyunpan: https://github.com/tickstep/aliyunpan"
|
2024-01-30 14:13:23 +08:00
|
|
|
|
app.Copyright = "(c) 2021-2024 tickstep."
|
2021-10-10 10:48:53 +08:00
|
|
|
|
app.Usage = "阿里云盘客户端 for " + runtime.GOOS + "/" + runtime.GOARCH
|
2022-08-19 11:52:37 +08:00
|
|
|
|
app.Description = `aliyunpan 是一款阿里云盘命令行客户端工具, 为操作阿里云盘, 提供实用功能。
|
2024-08-11 14:21:51 +08:00
|
|
|
|
支持同步备份功能,支持备份本地文件到云盘,备份云盘文件到本地。
|
2022-07-07 11:01:52 +08:00
|
|
|
|
具体功能, 参见 COMMANDS 列表。
|
|
|
|
|
|
|
|
|
|
支持设置环境变量 ALIYUNPAN_CONFIG_DIR 更改配置文件存储路径:
|
|
|
|
|
export ALIYUNPAN_CONFIG_DIR=/etc/aliyunpan/config
|
2024-08-11 14:21:51 +08:00
|
|
|
|
|
|
|
|
|
支持XDG目录规范:
|
|
|
|
|
默认XDG配置目录:$XDG_CONFIG_HOME/aliyunpan
|
|
|
|
|
默认XDG下载目录:$XDG_DOWNLOAD_DIR
|
|
|
|
|
|
2021-10-10 10:48:53 +08:00
|
|
|
|
------------------------------------------------------------------------------
|
|
|
|
|
前往 https://github.com/tickstep/aliyunpan 以获取更多帮助信息!
|
|
|
|
|
前往 https://github.com/tickstep/aliyunpan/releases 以获取程序更新信息!
|
|
|
|
|
------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
交流反馈:
|
|
|
|
|
提交Issue: https://github.com/tickstep/aliyunpan/issues
|
|
|
|
|
联系邮箱: tickstep@outlook.com`
|
|
|
|
|
|
|
|
|
|
// 全局options
|
|
|
|
|
app.Flags = []cli.Flag{
|
|
|
|
|
cli.BoolFlag{
|
|
|
|
|
Name: "verbose",
|
|
|
|
|
Usage: "启用调试",
|
|
|
|
|
EnvVar: config.EnvVerbose,
|
|
|
|
|
Destination: &logger.IsVerbose,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 进入交互CLI命令行界面
|
|
|
|
|
app.Action = func(c *cli.Context) {
|
|
|
|
|
if c.NArg() != 0 {
|
|
|
|
|
fmt.Printf("未找到命令: %s\n运行命令 %s help 获取帮助\n", c.Args().Get(0), app.Name)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
os.Setenv(config.EnvVerbose, c.String("verbose"))
|
|
|
|
|
isCli = true
|
2024-03-02 00:55:46 +08:00
|
|
|
|
global.IsAppInCliMode = true
|
2021-10-10 10:48:53 +08:00
|
|
|
|
logger.Verbosef("提示: 你已经开启VERBOSE调试日志\n\n")
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
line = cmdliner.NewLiner()
|
|
|
|
|
err error
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
line.History, err = cmdliner.NewLineHistory(historyFilePath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("警告: 读取历史命令文件错误, %s\n", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
line.ReadHistory()
|
|
|
|
|
defer func() {
|
|
|
|
|
line.DoWriteHistory()
|
|
|
|
|
line.Close()
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
// tab 自动补全命令
|
|
|
|
|
line.State.SetCompleter(func(line string) (s []string) {
|
|
|
|
|
var (
|
|
|
|
|
lineArgs = args.Parse(line)
|
|
|
|
|
numArgs = len(lineArgs)
|
|
|
|
|
acceptCompleteFileCommands = []string{
|
2023-12-10 21:44:48 +08:00
|
|
|
|
"cd", "cp", "xcp", "download", "ls", "mkdir", "mv", "pwd", "rename", "rm", "share", "save", "upload", "login", "loglist", "logout",
|
2021-10-10 10:48:53 +08:00
|
|
|
|
"clear", "quit", "exit", "quota", "who", "sign", "update", "who", "su", "config",
|
2022-08-19 17:27:54 +08:00
|
|
|
|
"drive", "export", "import", "sync", "tree",
|
2021-10-10 10:48:53 +08:00
|
|
|
|
}
|
|
|
|
|
closed = strings.LastIndex(line, " ") == len(line)-1
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
for _, cmd := range app.Commands {
|
|
|
|
|
for _, name := range cmd.Names() {
|
|
|
|
|
if !strings.HasPrefix(name, line) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s = append(s, name+" ")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch numArgs {
|
|
|
|
|
case 0:
|
|
|
|
|
return
|
|
|
|
|
case 1:
|
|
|
|
|
if !closed {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
thisCmd := app.Command(lineArgs[0])
|
|
|
|
|
if thisCmd == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !cmdutil.ContainsString(acceptCompleteFileCommands, thisCmd.FullName()) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
2022-01-24 22:17:33 +08:00
|
|
|
|
activeUser = config.Config.ActiveUser()
|
|
|
|
|
runeFunc = unicode.IsSpace
|
2021-10-30 22:53:08 +08:00
|
|
|
|
cmdRuneFunc = func(r rune) bool {
|
|
|
|
|
switch r {
|
|
|
|
|
case '\'', '"':
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return unicode.IsSpace(r)
|
|
|
|
|
}
|
2021-10-10 10:48:53 +08:00
|
|
|
|
targetPath string
|
|
|
|
|
)
|
|
|
|
|
|
2022-12-27 17:19:22 +08:00
|
|
|
|
if activeUser == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-10 10:48:53 +08:00
|
|
|
|
if !closed {
|
|
|
|
|
targetPath = lineArgs[numArgs-1]
|
|
|
|
|
escaper.EscapeStringsByRuneFunc(lineArgs[:numArgs-1], runeFunc) // 转义
|
|
|
|
|
} else {
|
|
|
|
|
escaper.EscapeStringsByRuneFunc(lineArgs, runeFunc)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch {
|
|
|
|
|
case targetPath == "." || strings.HasSuffix(targetPath, "/."):
|
|
|
|
|
s = append(s, line+"/")
|
|
|
|
|
return
|
|
|
|
|
case targetPath == ".." || strings.HasSuffix(targetPath, "/.."):
|
|
|
|
|
s = append(s, line+"/")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
targetDir string
|
|
|
|
|
isAbs = path.IsAbs(targetPath)
|
|
|
|
|
isDir = strings.LastIndex(targetPath, "/") == len(targetPath)-1
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if isAbs {
|
|
|
|
|
targetDir = path.Dir(targetPath)
|
|
|
|
|
} else {
|
2021-10-30 22:53:08 +08:00
|
|
|
|
wd := "/"
|
|
|
|
|
if activeUser.IsFileDriveActive() {
|
|
|
|
|
wd = activeUser.Workdir
|
2023-10-07 16:42:43 +08:00
|
|
|
|
} else if activeUser.IsResourceDriveActive() {
|
|
|
|
|
wd = activeUser.ResourceWorkdir
|
2021-10-30 22:53:08 +08:00
|
|
|
|
} else if activeUser.IsAlbumDriveActive() {
|
|
|
|
|
wd = activeUser.AlbumWorkdir
|
|
|
|
|
}
|
|
|
|
|
targetDir = path.Join(wd, targetPath)
|
2021-10-10 10:48:53 +08:00
|
|
|
|
if !isDir {
|
|
|
|
|
targetDir = path.Dir(targetDir)
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-02 17:38:21 +08:00
|
|
|
|
|
|
|
|
|
// tab键补全路径
|
2021-10-30 22:53:08 +08:00
|
|
|
|
files, err := activeUser.CacheFilesDirectoriesList(targetDir)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
for _, file := range files {
|
|
|
|
|
if file == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
appendLine string
|
|
|
|
|
)
|
2021-10-10 10:48:53 +08:00
|
|
|
|
|
2021-10-30 22:53:08 +08:00
|
|
|
|
// 已经有的情况
|
|
|
|
|
if !closed {
|
|
|
|
|
if !strings.HasPrefix(file.Path, path.Clean(path.Join(targetDir, path.Base(targetPath)))) {
|
|
|
|
|
if path.Base(targetDir) == path.Base(targetPath) {
|
|
|
|
|
appendLine = strings.Join(append(lineArgs[:numArgs-1], escaper.EscapeByRuneFunc(path.Join(targetPath, file.FileName), cmdRuneFunc)), " ")
|
|
|
|
|
goto handle
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
appendLine = strings.Join(append(lineArgs[:numArgs-1], escaper.EscapeByRuneFunc(path.Clean(path.Join(path.Dir(targetPath), file.FileName)), cmdRuneFunc)), " ")
|
|
|
|
|
goto handle
|
|
|
|
|
}
|
|
|
|
|
// 没有的情况
|
|
|
|
|
appendLine = strings.Join(append(lineArgs, escaper.EscapeByRuneFunc(file.FileName, cmdRuneFunc)), " ")
|
|
|
|
|
goto handle
|
|
|
|
|
|
|
|
|
|
handle:
|
|
|
|
|
if file.IsFolder() {
|
|
|
|
|
s = append(s, appendLine+"/")
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
s = append(s, appendLine+" ")
|
|
|
|
|
continue
|
|
|
|
|
}
|
2021-10-10 10:48:53 +08:00
|
|
|
|
return
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
fmt.Printf("提示: 方向键上下可切换历史命令.\n")
|
|
|
|
|
fmt.Printf("提示: Ctrl + A / E 跳转命令 首 / 尾.\n")
|
|
|
|
|
fmt.Printf("提示: 输入 help 获取帮助.\n")
|
|
|
|
|
|
|
|
|
|
// check update
|
2022-12-10 14:07:28 +08:00
|
|
|
|
command.ReloadConfigFunc(c)
|
2021-10-10 10:48:53 +08:00
|
|
|
|
if config.Config.UpdateCheckInfo.LatestVer != "" {
|
2024-03-02 00:55:46 +08:00
|
|
|
|
if utils.ParseVersionNum(config.Config.UpdateCheckInfo.LatestVer) > utils.ParseVersionNum(global.AppVersion) {
|
2021-10-10 10:48:53 +08:00
|
|
|
|
fmt.Printf("\n当前的软件版本为:%s, 现在有新版本 %s 可供更新,强烈推荐进行更新!(可以输入 update 命令进行更新)\n\n",
|
2024-03-02 00:55:46 +08:00
|
|
|
|
global.AppVersion, config.Config.UpdateCheckInfo.LatestVer)
|
2021-10-10 10:48:53 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
go func() {
|
|
|
|
|
latestCheckTime := config.Config.UpdateCheckInfo.CheckTime
|
|
|
|
|
nowTime := time.Now().Unix()
|
|
|
|
|
secsOf12Hour := int64(43200)
|
|
|
|
|
if (nowTime - latestCheckTime) > secsOf12Hour {
|
|
|
|
|
releaseInfo := panupdate.GetLatestReleaseInfo(false)
|
|
|
|
|
if releaseInfo == nil {
|
|
|
|
|
logger.Verboseln("获取版本信息失败!")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
config.Config.UpdateCheckInfo.LatestVer = releaseInfo.TagName
|
|
|
|
|
config.Config.UpdateCheckInfo.CheckTime = nowTime
|
|
|
|
|
|
|
|
|
|
// save
|
2022-12-10 14:07:28 +08:00
|
|
|
|
command.SaveConfigFunc(c)
|
2021-10-10 10:48:53 +08:00
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
var (
|
|
|
|
|
prompt string
|
|
|
|
|
activeUser = config.Config.ActiveUser()
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if activeUser == nil {
|
2022-12-10 14:07:28 +08:00
|
|
|
|
activeUser = command.TryLogin()
|
2021-10-10 10:48:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if activeUser != nil && activeUser.Nickname != "" {
|
|
|
|
|
// 格式: aliyunpan:<工作目录> <UserName>$
|
|
|
|
|
// 工作目录太长时, 会自动缩略
|
|
|
|
|
wd := "/"
|
|
|
|
|
if activeUser.IsFileDriveActive() {
|
|
|
|
|
wd = activeUser.Workdir
|
2023-10-07 16:42:43 +08:00
|
|
|
|
prompt = app.Name + ":" + converter.ShortDisplay(path.Base(wd), NameShortDisplayNum) + " " + activeUser.Nickname + "(备份盘)$ "
|
|
|
|
|
} else if activeUser.IsResourceDriveActive() {
|
|
|
|
|
wd = activeUser.ResourceWorkdir
|
|
|
|
|
prompt = app.Name + ":" + converter.ShortDisplay(path.Base(wd), NameShortDisplayNum) + " " + activeUser.Nickname + "(资源库)$ "
|
2021-10-10 10:48:53 +08:00
|
|
|
|
} else if activeUser.IsAlbumDriveActive() {
|
|
|
|
|
wd = activeUser.AlbumWorkdir
|
|
|
|
|
prompt = app.Name + ":" + converter.ShortDisplay(path.Base(wd), NameShortDisplayNum) + " " + activeUser.Nickname + "(相册)$ "
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// aliyunpan >
|
|
|
|
|
prompt = app.Name + " > "
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
commandLine, err := line.State.Prompt(prompt)
|
|
|
|
|
switch err {
|
|
|
|
|
case liner.ErrPromptAborted:
|
|
|
|
|
return
|
|
|
|
|
case nil:
|
|
|
|
|
// continue
|
|
|
|
|
default:
|
|
|
|
|
fmt.Println(err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
line.State.AppendHistory(commandLine)
|
|
|
|
|
|
|
|
|
|
cmdArgs := args.Parse(commandLine)
|
|
|
|
|
if len(cmdArgs) == 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s := []string{os.Args[0]}
|
|
|
|
|
s = append(s, cmdArgs...)
|
|
|
|
|
|
|
|
|
|
// 恢复原始终端状态
|
|
|
|
|
// 防止运行命令时程序被结束, 终端出现异常
|
|
|
|
|
line.Pause()
|
|
|
|
|
c.App.Run(s)
|
|
|
|
|
line.Resume()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 命令配置和对应的处理func
|
|
|
|
|
app.Commands = []cli.Command{
|
|
|
|
|
// 登录账号 login
|
|
|
|
|
command.CmdLogin(),
|
|
|
|
|
|
|
|
|
|
// 退出登录帐号 logout
|
|
|
|
|
command.CmdLogout(),
|
|
|
|
|
|
|
|
|
|
// 列出帐号列表 loglist
|
|
|
|
|
command.CmdLoglist(),
|
|
|
|
|
|
|
|
|
|
// 切换网盘 drive
|
|
|
|
|
command.CmdDrive(),
|
|
|
|
|
|
|
|
|
|
// 切换阿里账号 su
|
|
|
|
|
command.CmdSu(),
|
|
|
|
|
|
|
|
|
|
// 获取当前帐号 who
|
|
|
|
|
command.CmdWho(),
|
|
|
|
|
|
|
|
|
|
// 获取当前帐号空间配额 quota
|
|
|
|
|
command.CmdQuota(),
|
|
|
|
|
|
|
|
|
|
// 切换工作目录 cd
|
|
|
|
|
command.CmdCd(),
|
|
|
|
|
|
|
|
|
|
// 输出工作目录 pwd
|
|
|
|
|
command.CmdPwd(),
|
|
|
|
|
|
|
|
|
|
// 列出目录 ls
|
|
|
|
|
command.CmdLs(),
|
|
|
|
|
|
2022-08-19 17:27:54 +08:00
|
|
|
|
// 显示树形目录 tree
|
|
|
|
|
command.CmdTree(),
|
|
|
|
|
|
2021-10-10 10:48:53 +08:00
|
|
|
|
// 创建目录 mkdir
|
|
|
|
|
command.CmdMkdir(),
|
|
|
|
|
|
|
|
|
|
// 删除文件/目录 rm
|
|
|
|
|
command.CmdRm(),
|
|
|
|
|
|
2024-03-06 22:53:30 +08:00
|
|
|
|
// 复制文件/目录 cp
|
|
|
|
|
command.CmdCp(),
|
|
|
|
|
|
2021-10-10 10:48:53 +08:00
|
|
|
|
// 移动文件/目录 mv
|
|
|
|
|
command.CmdMv(),
|
|
|
|
|
|
|
|
|
|
// 重命名文件 rename
|
|
|
|
|
command.CmdRename(),
|
|
|
|
|
|
2022-06-09 19:58:16 +08:00
|
|
|
|
// 同步备份 sync
|
|
|
|
|
command.CmdSync(),
|
|
|
|
|
|
2021-10-10 10:48:53 +08:00
|
|
|
|
// 上传文件/目录 upload
|
|
|
|
|
command.CmdUpload(),
|
|
|
|
|
|
|
|
|
|
// 下载文件/目录 download
|
|
|
|
|
command.CmdDownload(),
|
|
|
|
|
|
|
|
|
|
// 显示和修改程序配置项 config
|
|
|
|
|
command.CmdConfig(),
|
|
|
|
|
|
|
|
|
|
// 工具箱 tool
|
|
|
|
|
command.CmdTool(),
|
|
|
|
|
|
2022-01-12 15:55:09 +08:00
|
|
|
|
// 显示命令历史
|
|
|
|
|
{
|
2022-01-24 22:17:33 +08:00
|
|
|
|
Name: "history",
|
|
|
|
|
Aliases: []string{},
|
|
|
|
|
Usage: "显示命令历史",
|
|
|
|
|
UsageText: app.Name + " history",
|
2022-01-12 15:55:09 +08:00
|
|
|
|
Description: `显示命令历史
|
|
|
|
|
|
|
|
|
|
示例:
|
|
|
|
|
1. 显示最近命令历史
|
|
|
|
|
aliyunpan history
|
|
|
|
|
|
|
|
|
|
2. 显示最近10条命令历史
|
|
|
|
|
aliyunpan history -n 10
|
|
|
|
|
|
|
|
|
|
3. 显示全部命令历史
|
|
|
|
|
aliyunpan history -n 0
|
|
|
|
|
`,
|
2022-01-24 22:17:33 +08:00
|
|
|
|
Category: "其他",
|
2022-01-12 15:55:09 +08:00
|
|
|
|
Action: func(c *cli.Context) error {
|
|
|
|
|
lineCount := 20
|
|
|
|
|
if c.IsSet("n") {
|
2022-01-24 22:17:33 +08:00
|
|
|
|
lineCount = c.Int("n")
|
2022-01-12 15:55:09 +08:00
|
|
|
|
}
|
|
|
|
|
printTable := func(lines []string) {
|
|
|
|
|
tb := cmdtable.NewTable(os.Stdout)
|
|
|
|
|
tb.SetHeader([]string{"序号", "命令"})
|
|
|
|
|
tb.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
|
|
|
|
tb.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT})
|
|
|
|
|
idx := 1
|
2022-01-24 22:17:33 +08:00
|
|
|
|
for _, line := range lines {
|
2022-01-12 15:55:09 +08:00
|
|
|
|
if line == "" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2022-08-20 16:37:28 +08:00
|
|
|
|
tb.Append([]string{strconv.Itoa(idx + 1), line})
|
2022-01-12 15:55:09 +08:00
|
|
|
|
idx++
|
|
|
|
|
}
|
|
|
|
|
tb.Render()
|
|
|
|
|
}
|
2022-01-24 22:17:33 +08:00
|
|
|
|
if contents, err := ioutil.ReadFile(historyFilePath); err == nil {
|
2022-01-12 15:55:09 +08:00
|
|
|
|
result := strings.Split(string(contents), "\n")
|
|
|
|
|
if lineCount == 0 {
|
|
|
|
|
printTable(result)
|
|
|
|
|
} else {
|
|
|
|
|
outputLine := make([]string, 0)
|
2022-01-24 22:17:33 +08:00
|
|
|
|
for idx := len(result) - 1; idx >= 0; idx-- {
|
2022-01-12 15:55:09 +08:00
|
|
|
|
line := result[idx]
|
|
|
|
|
if line != "" {
|
|
|
|
|
outputLine = append(outputLine, line)
|
|
|
|
|
}
|
|
|
|
|
if len(outputLine) >= lineCount {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lines := make([]string, 0)
|
2022-01-24 22:17:33 +08:00
|
|
|
|
for idx := len(outputLine) - 1; idx >= 0; idx-- {
|
2022-01-12 15:55:09 +08:00
|
|
|
|
lines = append(lines, outputLine[idx])
|
|
|
|
|
}
|
|
|
|
|
printTable(lines)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
|
cli.IntFlag{
|
|
|
|
|
Name: "n",
|
|
|
|
|
Usage: "显示最近历史的行数。0-代表全部,默认为20",
|
|
|
|
|
Value: 20,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
2021-10-10 10:48:53 +08:00
|
|
|
|
// 清空控制台 clear
|
|
|
|
|
{
|
|
|
|
|
Name: "clear",
|
|
|
|
|
Aliases: []string{"cls"},
|
|
|
|
|
Usage: "清空控制台",
|
|
|
|
|
UsageText: app.Name + " clear",
|
|
|
|
|
Description: "清空控制台屏幕",
|
|
|
|
|
Category: "其他",
|
|
|
|
|
Action: func(c *cli.Context) error {
|
|
|
|
|
cmdliner.ClearScreen()
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 检测程序更新 update
|
|
|
|
|
{
|
|
|
|
|
Name: "update",
|
|
|
|
|
Usage: "检测程序更新",
|
|
|
|
|
Category: "其他",
|
|
|
|
|
Action: func(c *cli.Context) error {
|
|
|
|
|
if c.IsSet("y") {
|
|
|
|
|
if !c.Bool("y") {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
panupdate.CheckUpdate(app.Version, c.Bool("y"))
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
|
cli.BoolFlag{
|
|
|
|
|
Name: "y",
|
|
|
|
|
Usage: "确认更新",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// 退出程序 quit
|
|
|
|
|
{
|
|
|
|
|
Name: "quit",
|
|
|
|
|
Aliases: []string{"exit"},
|
|
|
|
|
Usage: "退出程序",
|
|
|
|
|
Description: "退出程序",
|
|
|
|
|
Category: "其他",
|
|
|
|
|
Action: func(c *cli.Context) error {
|
|
|
|
|
return cli.NewExitError("", 0)
|
|
|
|
|
},
|
|
|
|
|
Hidden: true,
|
|
|
|
|
HideHelp: true,
|
|
|
|
|
},
|
|
|
|
|
|
2023-04-01 20:20:32 +08:00
|
|
|
|
// 执行系统命令
|
|
|
|
|
{
|
|
|
|
|
Name: "run",
|
|
|
|
|
Usage: "执行系统命令",
|
|
|
|
|
Category: "其他",
|
|
|
|
|
Action: func(c *cli.Context) error {
|
|
|
|
|
if c.NArg() == 0 {
|
|
|
|
|
cli.ShowCommandHelp(c, c.Command.Name)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd := exec.Command(c.Args().First(), c.Args().Tail()...)
|
|
|
|
|
cmd.Stdout = os.Stdout
|
|
|
|
|
cmd.Stdin = os.Stdin
|
|
|
|
|
cmd.Stderr = os.Stderr
|
|
|
|
|
err := cmd.Run()
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println(err)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
2024-08-18 17:03:10 +08:00
|
|
|
|
// 显示程序环境变量
|
|
|
|
|
{
|
|
|
|
|
Name: "env",
|
|
|
|
|
Usage: "显示程序环境变量",
|
|
|
|
|
Description: ` ALIYUNPAN_CONFIG_DIR: 配置文件路径
|
|
|
|
|
ALIYUNPAN_DOWNLOAD_DIR: 配置下载路径
|
|
|
|
|
ALIYUNPAN_VERBOSE: 是否启用调试
|
|
|
|
|
XDG_CONFIG_HOME: XDG配置主目录
|
|
|
|
|
XDG_DOWNLOAD_DIR: XDG配置下载目录
|
|
|
|
|
`,
|
|
|
|
|
Category: "其他",
|
|
|
|
|
Action: func(c *cli.Context) error {
|
|
|
|
|
envStr := "%s=%s\n"
|
|
|
|
|
envVar, ok := os.LookupEnv(config.EnvVerbose)
|
|
|
|
|
if ok {
|
|
|
|
|
if envVar == "1" {
|
|
|
|
|
fmt.Printf(envStr, config.EnvVerbose, "1")
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Printf(envStr, config.EnvVerbose, "0")
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Printf(envStr, config.EnvVerbose, "0")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
envVar, ok = os.LookupEnv(config.EnvConfigDir)
|
|
|
|
|
if ok {
|
|
|
|
|
fmt.Printf(envStr, config.EnvConfigDir, envVar)
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Printf(envStr, config.EnvConfigDir, config.GetConfigDir())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
envVar, ok = os.LookupEnv(config.EnvDownloadDir)
|
|
|
|
|
if ok {
|
|
|
|
|
fmt.Printf(envStr, config.EnvDownloadDir, envVar)
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Printf(envStr, config.EnvDownloadDir, config.GetDefaultDownloadDir())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
envVar, ok = os.LookupEnv("XDG_CONFIG_HOME")
|
|
|
|
|
if ok {
|
|
|
|
|
fmt.Printf(envStr, "XDG_CONFIG_HOME", envVar)
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Printf(envStr, "XDG_CONFIG_HOME", "")
|
|
|
|
|
}
|
|
|
|
|
envVar, ok = os.LookupEnv("XDG_DOWNLOAD_DIR")
|
|
|
|
|
if ok {
|
|
|
|
|
fmt.Printf(envStr, "XDG_DOWNLOAD_DIR", envVar)
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Printf(envStr, "XDG_DOWNLOAD_DIR", "")
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
2021-10-10 10:48:53 +08:00
|
|
|
|
// 调试用 debug
|
2022-06-20 17:28:25 +08:00
|
|
|
|
//{
|
|
|
|
|
// Name: "debug",
|
|
|
|
|
// Aliases: []string{"dg"},
|
|
|
|
|
// Usage: "开发调试用",
|
|
|
|
|
// Description: "",
|
|
|
|
|
// Category: "debug",
|
|
|
|
|
// Before: cmder.ReloadConfigFunc,
|
|
|
|
|
// Action: func(c *cli.Context) error {
|
|
|
|
|
// os.Setenv(config.EnvVerbose, "1")
|
|
|
|
|
// logger.IsVerbose = true
|
|
|
|
|
// fmt.Println("显示调试日志", logger.IsVerbose)
|
|
|
|
|
// return nil
|
|
|
|
|
// },
|
|
|
|
|
// Flags: []cli.Flag{
|
|
|
|
|
// cli.StringFlag{
|
|
|
|
|
// Name: "param",
|
|
|
|
|
// Usage: "参数",
|
|
|
|
|
// },
|
|
|
|
|
// cli.BoolFlag{
|
|
|
|
|
// Name: "verbose",
|
|
|
|
|
// Destination: &logger.IsVerbose,
|
|
|
|
|
// EnvVar: config.EnvVerbose,
|
|
|
|
|
// Usage: "显示调试信息",
|
|
|
|
|
// },
|
|
|
|
|
// },
|
|
|
|
|
//},
|
2021-10-10 10:48:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-04-27 19:13:59 +08:00
|
|
|
|
// 隐藏不支持的命令
|
|
|
|
|
if global.IsSupportNoneOpenApiCommands {
|
|
|
|
|
hiddenCommands := []cli.Command{
|
|
|
|
|
// 备份盘和资源库之间拷贝文件 xcp
|
|
|
|
|
command.CmdXcp(),
|
|
|
|
|
|
|
|
|
|
// 分享文件/目录 share
|
|
|
|
|
command.CmdShare(),
|
|
|
|
|
|
|
|
|
|
// 保存分享文件/目录 save
|
|
|
|
|
command.CmdSave(),
|
|
|
|
|
|
|
|
|
|
// 回收站
|
|
|
|
|
command.CmdRecycle(),
|
|
|
|
|
|
|
|
|
|
// 相簿
|
|
|
|
|
//command.CmdAlbum(),
|
|
|
|
|
}
|
|
|
|
|
app.Commands = append(app.Commands, hiddenCommands...)
|
|
|
|
|
}
|
2021-10-10 10:48:53 +08:00
|
|
|
|
sort.Sort(cli.FlagsByName(app.Flags))
|
|
|
|
|
sort.Sort(cli.CommandsByName(app.Commands))
|
|
|
|
|
app.Run(os.Args)
|
|
|
|
|
}
|