mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 19:37:18 +08:00
feat: 适配面板备份
This commit is contained in:
@@ -332,14 +332,28 @@ func (r *backupRepo) createPanel(to string) error {
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
if err := io.Compress(filepath.Dir(filepath.Join(app.Root, "panel")), []string{
|
||||
".",
|
||||
"/usr/local/sbin/panel-cli",
|
||||
"/usr/local/etc/panel/config.yml",
|
||||
}, backup); err != nil {
|
||||
|
||||
temp, err := io.TempDir("panel-backup")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := io.Chmod(backup, 0600); err != nil {
|
||||
defer io.Remove(temp)
|
||||
|
||||
if err = io.Cp(filepath.Join(app.Root, "panel"), temp); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = io.Cp("/usr/local/sbin/panel-cli", temp); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = io.Cp("/usr/local/etc/panel/config.yml", temp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_ = io.Chmod(temp, 0600)
|
||||
if err = io.Compress(temp, nil, backup); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = io.Chmod(backup, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -327,7 +327,7 @@ func (r *settingRepo) UpdatePanel(version, url, checksum string) error {
|
||||
if app.IsCli {
|
||||
fmt.Println("|-恢复面板数据...")
|
||||
}
|
||||
if err := io.UnCompress("/tmp/panel-storage.zip", filepath.Join(app.Root, "panel")); err != nil {
|
||||
if err := io.UnCompress("/tmp/panel-storage.zip", filepath.Join(app.Root, "panel", "storage")); err != nil {
|
||||
return fmt.Errorf("恢复面板数据失败:%w", err)
|
||||
}
|
||||
if !io.Exists(filepath.Join(app.Root, "panel/storage/app.db")) {
|
||||
@@ -455,7 +455,7 @@ func (r *settingRepo) FixPanel() error {
|
||||
}
|
||||
}
|
||||
|
||||
// tmp目录下如果有storage备份,则解压回去
|
||||
// tmp 目录下如果有 storage 备份,则解压回去
|
||||
if app.IsCli {
|
||||
fmt.Println("|-恢复面板数据...")
|
||||
}
|
||||
|
||||
@@ -464,7 +464,7 @@ func (s *CliService) BackupWebsite(ctx context.Context, cmd *cli.Command) error
|
||||
fmt.Println("|-备份类型:网站")
|
||||
fmt.Printf("|-备份目标:%s\n", cmd.String("name"))
|
||||
if err := s.backupRepo.Create(biz.BackupTypeWebsite, cmd.String("name"), cmd.String("path")); err != nil {
|
||||
return fmt.Errorf("|-备份失败:%v", err)
|
||||
return fmt.Errorf("备份失败:%v", err)
|
||||
}
|
||||
fmt.Println(s.hr)
|
||||
fmt.Printf("☆ 备份成功 [%s]\n", time.Now().Format(time.DateTime))
|
||||
@@ -480,7 +480,7 @@ func (s *CliService) BackupDatabase(ctx context.Context, cmd *cli.Command) error
|
||||
fmt.Printf("|-数据库:%s\n", cmd.String("type"))
|
||||
fmt.Printf("|-备份目标:%s\n", cmd.String("name"))
|
||||
if err := s.backupRepo.Create(biz.BackupType(cmd.String("type")), cmd.String("name"), cmd.String("path")); err != nil {
|
||||
return fmt.Errorf("|-备份失败:%v", err)
|
||||
return fmt.Errorf("备份失败:%v", err)
|
||||
}
|
||||
fmt.Println(s.hr)
|
||||
fmt.Printf("☆ 备份成功 [%s]\n", time.Now().Format(time.DateTime))
|
||||
@@ -494,7 +494,7 @@ func (s *CliService) BackupPanel(ctx context.Context, cmd *cli.Command) error {
|
||||
fmt.Println(s.hr)
|
||||
fmt.Println("|-备份类型:面板")
|
||||
if err := s.backupRepo.Create(biz.BackupTypePanel, "", cmd.String("path")); err != nil {
|
||||
return fmt.Errorf("|-备份失败:%v", err)
|
||||
return fmt.Errorf("备份失败:%v", err)
|
||||
}
|
||||
fmt.Println(s.hr)
|
||||
fmt.Printf("☆ 备份成功 [%s]\n", time.Now().Format(time.DateTime))
|
||||
@@ -518,7 +518,7 @@ func (s *CliService) BackupClear(ctx context.Context, cmd *cli.Command) error {
|
||||
fmt.Printf("|-清理目标:%s\n", cmd.String("file"))
|
||||
fmt.Printf("|-保留份数:%d\n", cmd.Int("save"))
|
||||
if err = s.backupRepo.ClearExpired(path, cmd.String("file"), int(cmd.Int("save"))); err != nil {
|
||||
return fmt.Errorf("|-清理失败:%v", err)
|
||||
return fmt.Errorf("清理失败:%v", err)
|
||||
}
|
||||
fmt.Println(s.hr)
|
||||
fmt.Printf("☆ 清理成功 [%s]\n", time.Now().Format(time.DateTime))
|
||||
|
||||
@@ -30,21 +30,18 @@ func Compress(dir string, src []string, dst string) error {
|
||||
for i, s := range src {
|
||||
if strings.HasPrefix(s, dir) {
|
||||
s = strings.TrimPrefix(s, dir)
|
||||
src[i] = strings.TrimPrefix(s, "/")
|
||||
}
|
||||
if src[i] == "" {
|
||||
src[i] = "."
|
||||
if s != "" && s[0] == '/' {
|
||||
src[i] = strings.TrimPrefix(s, "/")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmd := new(exec.Cmd)
|
||||
cmd.Dir = dir
|
||||
|
||||
format, err := formatArchiveByPath(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := new(exec.Cmd)
|
||||
switch format {
|
||||
case Zip:
|
||||
cmd = exec.Command("zip", append([]string{"-qr", "-o", dst}, src...)...)
|
||||
@@ -62,6 +59,7 @@ func Compress(dir string, src []string, dst string) error {
|
||||
return errors.New("unsupported format")
|
||||
}
|
||||
|
||||
cmd.Dir = dir
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package io
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -52,81 +51,16 @@ func Empty(path string) bool {
|
||||
}
|
||||
|
||||
func Mv(src, dst string) error {
|
||||
if err := os.Rename(src, dst); err != nil {
|
||||
// 在不同的文件系统中无法使用 os.Rename
|
||||
if _, err = shell.Execf(`mv -f '%s' '%s'`, src, dst); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
_, err := shell.Execf(`mv -f '%s' '%s'`, src, dst)
|
||||
return err
|
||||
}
|
||||
|
||||
// Cp 复制文件或目录
|
||||
func Cp(src, dst string) error {
|
||||
srcInfo, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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)
|
||||
_, err := shell.Execf(`cp -rf '%s' '%s'`, src, dst)
|
||||
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 := os.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 获取路径大小
|
||||
func Size(path string) (int64, error) {
|
||||
var size int64
|
||||
|
||||
Reference in New Issue
Block a user