2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 10:17:17 +08:00

feat: 优化部分命令处理方式

This commit is contained in:
耗子
2023-11-20 21:26:02 +08:00
parent 5e7859f063
commit 4ab4f273e7
9 changed files with 405 additions and 146 deletions

View File

@@ -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"
}

View File

@@ -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())
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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)