120 lines
2.6 KiB
Go
120 lines
2.6 KiB
Go
package platform
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
|
|
"github.com/Eriyc/rules_wails/pkg/wails3kit/updates"
|
|
)
|
|
|
|
type restorePoint struct {
|
|
path string
|
|
backup string
|
|
hadPrior bool
|
|
}
|
|
|
|
func applyBundle(request helperRequest) error {
|
|
backupDir, err := os.MkdirTemp("", "wails3kit-backup-*")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
restores := make([]restorePoint, 0, len(request.Bundle.Files))
|
|
for _, file := range request.Bundle.Files {
|
|
source := filepath.Join(request.StagedPath, filepath.FromSlash(file.Path))
|
|
target := filepath.Join(request.InstallRoot, filepath.FromSlash(file.Path))
|
|
modeValue, err := strconv.ParseUint(file.Mode, 8, 32)
|
|
if err != nil {
|
|
rollback(restores)
|
|
return err
|
|
}
|
|
mode := os.FileMode(modeValue)
|
|
|
|
restore, err := backupTarget(backupDir, target)
|
|
if err != nil {
|
|
rollback(restores)
|
|
return err
|
|
}
|
|
restores = append(restores, restore)
|
|
|
|
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
|
|
rollback(restores)
|
|
return err
|
|
}
|
|
if err := os.RemoveAll(target); err != nil {
|
|
rollback(restores)
|
|
return err
|
|
}
|
|
if err := copyFile(source, target, mode); err != nil {
|
|
rollback(restores)
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func backupTarget(backupDir string, target string) (restorePoint, error) {
|
|
point := restorePoint{path: target}
|
|
info, err := os.Stat(target)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return point, nil
|
|
}
|
|
return point, err
|
|
}
|
|
if info.IsDir() {
|
|
return point, fmt.Errorf("%w: target %s is a directory", updates.ErrInvalidArtifact, target)
|
|
}
|
|
|
|
backupPath := filepath.Join(backupDir, filepath.Base(target))
|
|
if err := copyFile(target, backupPath, info.Mode()); err != nil {
|
|
return point, err
|
|
}
|
|
point.hadPrior = true
|
|
point.backup = backupPath
|
|
return point, nil
|
|
}
|
|
|
|
func rollback(restores []restorePoint) {
|
|
for index := len(restores) - 1; index >= 0; index-- {
|
|
restore := restores[index]
|
|
if restore.hadPrior {
|
|
info, err := os.Stat(restore.backup)
|
|
if err == nil {
|
|
_ = os.RemoveAll(restore.path)
|
|
_ = os.MkdirAll(filepath.Dir(restore.path), 0o755)
|
|
_ = copyFile(restore.backup, restore.path, info.Mode())
|
|
}
|
|
continue
|
|
}
|
|
_ = os.RemoveAll(restore.path)
|
|
}
|
|
}
|
|
|
|
func copyFile(sourcePath string, destinationPath string, mode os.FileMode) error {
|
|
source, err := os.Open(sourcePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer source.Close()
|
|
|
|
return writeFile(destinationPath, source, mode)
|
|
}
|
|
|
|
func writeFile(path string, source io.Reader, mode os.FileMode) error {
|
|
file, err := os.Create(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
if _, err := io.Copy(file, source); err != nil {
|
|
return err
|
|
}
|
|
return file.Chmod(mode)
|
|
}
|