mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 10:17:17 +08:00
feat: 优化部分命令处理方式
This commit is contained in:
@@ -21,3 +21,13 @@ func IsRHEL() bool {
|
||||
func IsArm() bool {
|
||||
return runtime.GOARCH == "arm" || runtime.GOARCH == "arm64"
|
||||
}
|
||||
|
||||
// IsLinux 判断是否是 Linux 系统
|
||||
func IsLinux() bool {
|
||||
return runtime.GOOS == "linux"
|
||||
}
|
||||
|
||||
// IsWindows 判断是否是 Windows 系统
|
||||
func IsWindows() bool {
|
||||
return runtime.GOOS == "windows"
|
||||
}
|
||||
|
||||
@@ -15,10 +15,16 @@ func TestOSHelperTestSuite(t *testing.T) {
|
||||
}
|
||||
|
||||
func (s *OSHelperTestSuite) TestIsDebian() {
|
||||
if IsWindows() {
|
||||
return
|
||||
}
|
||||
s.True(IsDebian())
|
||||
}
|
||||
|
||||
func (s *OSHelperTestSuite) TestIsRHEL() {
|
||||
if IsWindows() {
|
||||
return
|
||||
}
|
||||
s.False(IsRHEL())
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,17 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/goravel/framework/support"
|
||||
"github.com/mholt/archiver/v3"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
// Write 写入文件
|
||||
@@ -39,7 +44,12 @@ func Remove(path string) error {
|
||||
|
||||
// Exec 执行 shell 命令
|
||||
func Exec(shell string) (string, error) {
|
||||
cmd := exec.Command("bash", "-c", "LC_ALL=C "+shell)
|
||||
var cmd *exec.Cmd
|
||||
if IsLinux() {
|
||||
cmd = exec.Command("bash", "-c", "LC_ALL=C "+shell)
|
||||
} else {
|
||||
cmd = exec.Command("cmd", "/C", "chcp 65001 >nul && "+shell)
|
||||
}
|
||||
|
||||
var stdoutBuf, stderrBuf bytes.Buffer
|
||||
cmd.Stdout = &stdoutBuf
|
||||
@@ -55,7 +65,13 @@ func Exec(shell string) (string, error) {
|
||||
|
||||
// ExecAsync 异步执行 shell 命令
|
||||
func ExecAsync(shell string) error {
|
||||
cmd := exec.Command("bash", "-c", shell)
|
||||
var cmd *exec.Cmd
|
||||
if IsLinux() {
|
||||
cmd = exec.Command("bash", "-c", "LC_ALL=C "+shell)
|
||||
} else {
|
||||
cmd = exec.Command("cmd", "/C", "chcp 65001 >nul && "+shell)
|
||||
}
|
||||
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -84,10 +100,53 @@ func Chmod(path string, permission os.FileMode) error {
|
||||
return os.Chmod(path, permission)
|
||||
}
|
||||
|
||||
// Chown 修改文件/目录所有者
|
||||
func Chown(path, user, group string) error {
|
||||
cmd := exec.Command("chown", "-R", user+":"+group, path)
|
||||
return cmd.Run()
|
||||
// Chown 修改文件或目录所有者
|
||||
func Chown(path, userName, groupName string) error {
|
||||
if IsWindows() {
|
||||
return errors.New("chown is not supported on Windows")
|
||||
}
|
||||
|
||||
usr, err := user.Lookup(userName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
grp, err := user.LookupGroup(groupName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return chownR(path, cast.ToInt(usr.Uid), cast.ToInt(grp.Gid))
|
||||
}
|
||||
|
||||
// chownR 递归修改文件或目录的所有者
|
||||
func chownR(path string, uid, gid int) error {
|
||||
err := os.Chown(path, uid, gid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fileInfo, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fileInfo.IsDir() {
|
||||
entries, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
subPath := path + "/" + entry.Name()
|
||||
err = chownR(subPath, uid, gid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Exists 判断路径是否存在
|
||||
@@ -106,18 +165,85 @@ func Empty(path string) bool {
|
||||
return len(files) == 0
|
||||
}
|
||||
|
||||
// Mv 移动文件/目录
|
||||
func Mv(src, dst string) error {
|
||||
cmd := exec.Command("mv", src, dst)
|
||||
|
||||
return cmd.Run()
|
||||
err := os.Rename(src, dst)
|
||||
if err != nil {
|
||||
// 如果在不同的文件系统中移动文件,os.Rename 可能会失败
|
||||
// 在这种情况下,可以先复制然后删除原文件
|
||||
if os.IsExist(err) {
|
||||
err := Cp(src, dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.RemoveAll(src)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Cp 复制文件/目录
|
||||
// Cp 复制文件或目录
|
||||
func Cp(src, dst string) error {
|
||||
cmd := exec.Command("cp", "-r", src, dst)
|
||||
srcInfo, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cmd.Run()
|
||||
if srcInfo.IsDir() {
|
||||
return copyDir(src, dst)
|
||||
}
|
||||
return copyFile(src, dst)
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) error {
|
||||
srcFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
dstFile, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstFile.Close()
|
||||
|
||||
_, err = io.Copy(dstFile, srcFile)
|
||||
return err
|
||||
}
|
||||
|
||||
func copyDir(src, dst string) error {
|
||||
srcInfo, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.MkdirAll(dst, srcInfo.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entries, err := ioutil.ReadDir(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
srcPath := filepath.Join(src, entry.Name())
|
||||
dstPath := filepath.Join(dst, entry.Name())
|
||||
|
||||
if entry.IsDir() {
|
||||
err = copyDir(srcPath, dstPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = copyFile(srcPath, dstPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Size 获取路径大小
|
||||
@@ -139,3 +265,23 @@ func Size(path string) (int64, error) {
|
||||
func FileInfo(path string) (os.FileInfo, error) {
|
||||
return os.Stat(path)
|
||||
}
|
||||
|
||||
// UnArchive 智能解压文件
|
||||
func UnArchive(file string, dst string) error {
|
||||
return archiver.Unarchive(file, dst)
|
||||
}
|
||||
|
||||
// Archive 智能压缩文件
|
||||
func Archive(src []string, dst string) error {
|
||||
return archiver.Archive(src, dst)
|
||||
}
|
||||
|
||||
// TempDir 创建临时目录
|
||||
func TempDir(prefix string) (string, error) {
|
||||
return os.MkdirTemp("", prefix)
|
||||
}
|
||||
|
||||
// TempFile 创建临时文件
|
||||
func TempFile(prefix string) (*os.File, error) {
|
||||
return os.CreateTemp("", prefix)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -18,78 +18,88 @@ func TestSystemHelperTestSuite(t *testing.T) {
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestWrite() {
|
||||
filePath := "/tmp/testfile"
|
||||
defer os.Remove(filePath)
|
||||
filePath, _ := TempFile("testfile")
|
||||
defer Remove(filePath.Name())
|
||||
|
||||
s.Nil(Write(filePath, "test data", 0644))
|
||||
s.FileExists(filePath)
|
||||
s.Nil(Write(filePath.Name(), "test data", 0644))
|
||||
s.FileExists(filePath.Name())
|
||||
|
||||
content, _ := os.ReadFile(filePath)
|
||||
s.Equal("test data", string(content))
|
||||
content, _ := Read(filePath.Name())
|
||||
s.Equal("test data", content)
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestRead() {
|
||||
filePath := "/tmp/testfile"
|
||||
defer os.Remove(filePath)
|
||||
filePath, _ := TempFile("testfile")
|
||||
defer Remove(filePath.Name())
|
||||
|
||||
err := os.WriteFile(filePath, []byte("test data"), 0644)
|
||||
err := Write(filePath.Name(), "test data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
data, err := Read(filePath)
|
||||
data, err := Read(filePath.Name())
|
||||
s.Nil(err)
|
||||
s.Equal("test data", data)
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestRemove() {
|
||||
filePath := "/tmp/testfile"
|
||||
file, _ := TempFile("testfile")
|
||||
file.Close()
|
||||
|
||||
err := os.WriteFile(filePath, []byte("test data"), 0644)
|
||||
err := Write(file.Name(), "test data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
s.Nil(Remove(filePath))
|
||||
s.Nil(Remove(file.Name()))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestExec() {
|
||||
output, err := Exec("echo 'test'")
|
||||
output, err := Exec("echo test")
|
||||
s.Equal("test", output)
|
||||
s.Nil(err)
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestExecAsync() {
|
||||
command := "echo 'test' > /tmp/testfile"
|
||||
defer os.Remove("/tmp/testfile")
|
||||
command := "echo test > test.txt"
|
||||
if IsWindows() {
|
||||
command = "echo test> test.txt"
|
||||
}
|
||||
|
||||
err := ExecAsync(command)
|
||||
s.Nil(err)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
content, _ := os.ReadFile("/tmp/testfile")
|
||||
s.Equal("test\n", string(content))
|
||||
content, err := Read("test.txt")
|
||||
s.Nil(err)
|
||||
|
||||
condition := "test\n"
|
||||
if IsWindows() {
|
||||
condition = "test\r\n"
|
||||
}
|
||||
s.Equal(condition, content)
|
||||
s.Nil(Remove("test.txt"))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestMkdir() {
|
||||
dirPath := "/tmp/testdir"
|
||||
defer os.RemoveAll(dirPath)
|
||||
dirPath, _ := TempDir("testdir")
|
||||
defer Remove(dirPath)
|
||||
|
||||
s.Nil(Mkdir(dirPath, 0755))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestChmod() {
|
||||
filePath := "/tmp/testfile"
|
||||
defer os.Remove(filePath)
|
||||
filePath, _ := TempFile("testfile")
|
||||
defer Remove(filePath.Name())
|
||||
|
||||
err := os.WriteFile(filePath, []byte("test data"), 0644)
|
||||
err := Write(filePath.Name(), "test data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
s.Nil(Chmod(filePath, 0755))
|
||||
s.Nil(Chmod(filePath.Name(), 0755))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestChown() {
|
||||
filePath := "/tmp/testfile"
|
||||
defer os.Remove(filePath)
|
||||
filePath, _ := TempFile("testfile")
|
||||
defer Remove(filePath.Name())
|
||||
|
||||
err := os.WriteFile(filePath, []byte("test data"), 0644)
|
||||
err := Write(filePath.Name(), "test data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
currentUser, err := user.Current()
|
||||
@@ -97,48 +107,132 @@ func (s *SystemHelperTestSuite) TestChown() {
|
||||
groups, err := currentUser.GroupIds()
|
||||
s.Nil(err)
|
||||
|
||||
s.Nil(Chown(filePath, currentUser.Username, groups[0]))
|
||||
err = Chown(filePath.Name(), currentUser.Username, groups[0])
|
||||
if IsWindows() {
|
||||
s.NotNil(err)
|
||||
} else {
|
||||
s.Nil(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestExists() {
|
||||
s.True(Exists("/tmp"))
|
||||
filePath, _ := TempFile("testfile")
|
||||
defer Remove(filePath.Name())
|
||||
|
||||
s.True(Exists(filePath.Name()))
|
||||
s.False(Exists("/tmp/123"))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestEmpty() {
|
||||
s.True(Empty("/tmp/123"))
|
||||
s.False(Empty("/tmp"))
|
||||
filePath, _ := TempFile("testfile")
|
||||
defer Remove(filePath.Name())
|
||||
|
||||
s.True(Empty(filePath.Name()))
|
||||
if IsWindows() {
|
||||
s.True(Empty("C:\\Windows\\System32\\drivers\\etc\\hosts"))
|
||||
} else {
|
||||
s.True(Empty("/etc/hosts"))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestMv() {
|
||||
filePath := "/tmp/testfile"
|
||||
defer os.Remove(filePath)
|
||||
filePath, _ := TempFile("testfile")
|
||||
defer Remove(filePath.Name())
|
||||
|
||||
err := os.WriteFile(filePath, []byte("test data"), 0644)
|
||||
err := Write(filePath.Name(), "test data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
s.Nil(Mv(filePath, "/tmp/testfile2"))
|
||||
s.False(Exists(filePath))
|
||||
newFilePath, _ := TempFile("testfile2")
|
||||
defer Remove(newFilePath.Name())
|
||||
|
||||
filePath.Close()
|
||||
newFilePath.Close()
|
||||
|
||||
s.Nil(Mv(filePath.Name(), newFilePath.Name()))
|
||||
s.False(Exists(filePath.Name()))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestCp() {
|
||||
filePath := "/tmp/testfile"
|
||||
defer os.Remove(filePath)
|
||||
tempDir, _ := TempDir("testdir")
|
||||
defer Remove(tempDir)
|
||||
|
||||
err := os.WriteFile(filePath, []byte("test data"), 0644)
|
||||
err := Write(filepath.Join(tempDir, "testfile"), "test data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
s.Nil(Cp(filePath, "/tmp/testfile2"))
|
||||
s.True(Exists(filePath))
|
||||
s.Nil(Cp(filepath.Join(tempDir, "testfile"), filepath.Join(tempDir, "testfile2")))
|
||||
s.True(Exists(filepath.Join(tempDir, "testfile2")))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestSize() {
|
||||
size, err := Size("/tmp/123")
|
||||
s.Equal(int64(0), size)
|
||||
s.Error(err)
|
||||
filePath, _ := TempFile("testfile")
|
||||
defer Remove(filePath.Name())
|
||||
|
||||
err := Write(filePath.Name(), "test data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
size, err := Size(filePath.Name())
|
||||
s.Nil(err)
|
||||
s.Equal(int64(len("test data")), size)
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestFileInfo() {
|
||||
_, err := FileInfo("/tmp/123")
|
||||
s.Error(err)
|
||||
filePath, _ := TempFile("testfile")
|
||||
defer Remove(filePath.Name())
|
||||
|
||||
err := Write(filePath.Name(), "test data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
info, err := FileInfo(filePath.Name())
|
||||
s.Nil(err)
|
||||
s.Equal(filepath.Base(filePath.Name()), info.Name())
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestUnArchiveSuccessfullyUnarchivesFile() {
|
||||
file, _ := TempFile("test")
|
||||
defer Remove(file.Name())
|
||||
dstDir, _ := TempDir("archive")
|
||||
defer Remove(dstDir)
|
||||
|
||||
err := Write(file.Name(), "test data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
err = Archive([]string{file.Name()}, filepath.Join(dstDir, "test.zip"))
|
||||
s.Nil(err)
|
||||
s.FileExists(filepath.Join(dstDir, "test.zip"))
|
||||
|
||||
err = UnArchive(filepath.Join(dstDir, "test.zip"), dstDir)
|
||||
s.Nil(err)
|
||||
s.FileExists(filepath.Join(dstDir, filepath.Base(file.Name())))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestUnArchiveFailsForNonExistentFile() {
|
||||
srcFile := "nonexistent.zip"
|
||||
dstDir, _ := TempDir("unarchived")
|
||||
defer Remove(dstDir)
|
||||
|
||||
err := UnArchive(srcFile, dstDir)
|
||||
s.NotNil(err)
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestArchiveSuccessfullyArchivesFiles() {
|
||||
srcFile, _ := TempFile("test")
|
||||
defer Remove(srcFile.Name())
|
||||
dstDir, _ := TempDir("archive")
|
||||
defer Remove(dstDir)
|
||||
|
||||
err := Write(srcFile.Name(), "test data", 0644)
|
||||
s.Nil(err)
|
||||
|
||||
err = Archive([]string{srcFile.Name()}, filepath.Join(dstDir, "test.zip"))
|
||||
s.Nil(err)
|
||||
s.FileExists(filepath.Join(dstDir, "test.zip"))
|
||||
}
|
||||
|
||||
func (s *SystemHelperTestSuite) TestArchiveFailsForNonExistentFiles() {
|
||||
srcFile := "nonexistent"
|
||||
dstDir, _ := TempDir("archive")
|
||||
defer Remove(dstDir)
|
||||
|
||||
err := Archive([]string{srcFile}, filepath.Join(dstDir, "test.zip"))
|
||||
s.NotNil(err)
|
||||
}
|
||||
|
||||
@@ -84,12 +84,18 @@ func (s *HelperTestSuite) TestGenerateVersions() {
|
||||
}
|
||||
|
||||
func (s *HelperTestSuite) TestGetLatestPanelVersion() {
|
||||
if IsWindows() {
|
||||
return
|
||||
}
|
||||
version, err := GetLatestPanelVersion()
|
||||
s.NotEmpty(version)
|
||||
s.Nil(err)
|
||||
}
|
||||
|
||||
func (s *HelperTestSuite) TestGetPanelVersion() {
|
||||
if IsWindows() {
|
||||
return
|
||||
}
|
||||
version, err := GetPanelVersion("v2.0.58")
|
||||
s.NotEmpty(version)
|
||||
s.Nil(err)
|
||||
|
||||
Reference in New Issue
Block a user