pkg/backup/backup.go (116 lines of code) (raw):
package backup
import (
"fmt"
"os"
"path/filepath"
"strings"
filesystem "github.com/Azure/mapotf/pkg/fs"
"github.com/spf13/afero"
)
const BackupExtension = ".mptfbackup"
const NewFileExtension = ".mptfnew"
func BackupFolder(dir string) error {
terraformFile, err := afero.Glob(filesystem.Fs, filepath.Join(dir, "*.tf"))
if err != nil {
return fmt.Errorf("cannot list terraform files in %s:%+v", dir, err)
}
for _, file := range terraformFile {
backupFile := file + BackupExtension
exist, err := afero.Exists(filesystem.Fs, backupFile)
if err != nil {
return fmt.Errorf("cannot check backup file %s:%+v", backupFile, err)
}
if exist {
continue
}
// create the backup file, then copy the content of the terraform file to the backup file, with the same permission
content, err := afero.ReadFile(filesystem.Fs, file)
if err != nil {
return fmt.Errorf("cannot read terraform file %s:%+v", file, err)
}
// get permission of the terraform file
info, err := filesystem.Fs.Stat(file)
if err != nil {
return fmt.Errorf("cannot get permission of terraform file %s:%+v", file, err)
}
// write the content to the backup file
if err = afero.WriteFile(filesystem.Fs, backupFile, content, info.Mode()); err != nil {
return fmt.Errorf("cannot write backup file %s:%+v", backupFile, err)
}
}
return nil
}
func Reset(dir string) error {
err := restoreBackup(dir)
if err != nil {
return err
}
return removeNewFiles(dir)
}
func removeNewFiles(dir string) error {
newFileIndicators, err := afero.Glob(filesystem.Fs, filepath.Join(dir, "*"+NewFileExtension))
if err != nil {
return fmt.Errorf("cannot list new file indicators in %s:%+v", dir, err)
}
for _, newFileIndicator := range newFileIndicators {
newFile, _ := strings.CutSuffix(newFileIndicator, NewFileExtension)
if err = filesystem.Fs.Remove(newFile); err != nil {
return fmt.Errorf("cannot delete new file %s:%+v", newFile, err)
}
if err = filesystem.Fs.Remove(newFileIndicator); err != nil {
return fmt.Errorf("cannot delete new file indicator in %s:%+v", newFileIndicator, err)
}
}
return nil
}
func restoreBackup(dir string) error {
backupFiles, err := afero.Glob(filesystem.Fs, filepath.Join(dir, "*"+BackupExtension))
if err != nil {
return fmt.Errorf("cannot list backup files in %s:%+v", dir, err)
}
for _, backupFile := range backupFiles {
// read the content of the backup file
content, err := afero.ReadFile(filesystem.Fs, backupFile)
if err != nil {
return fmt.Errorf("cannot read backup file %s:%+v", backupFile, err)
}
// write the content to the original file
originalFile := backupFile[:len(backupFile)-len(BackupExtension)] // remove the extension to get the original file name
info, err := getFilePerm(originalFile, backupFile, err)
if err != nil {
return err
}
if err = afero.WriteFile(filesystem.Fs, originalFile, content, info.Mode()); err != nil {
return fmt.Errorf("cannot write original file %s:%+v", originalFile, err)
}
// delete the backup file
if err = filesystem.Fs.Remove(backupFile); err != nil {
return fmt.Errorf("cannot delete backup file %s:%+v", backupFile, err)
}
}
return nil
}
func ClearBackup(dir string) error {
backupFiles, err := afero.Glob(filesystem.Fs, filepath.Join(dir, "*"+BackupExtension))
if err != nil {
return fmt.Errorf("cannot list backup files in %s:%+v", dir, err)
}
newFileIndicators, err := afero.Glob(filesystem.Fs, filepath.Join(dir, "*"+NewFileExtension))
if err != nil {
return fmt.Errorf("cannot list new file indicators in %s:%+v", dir, err)
}
files := append(backupFiles, newFileIndicators...)
for _, backupFile := range files {
// delete the backup file
if err = filesystem.Fs.Remove(backupFile); err != nil {
return fmt.Errorf("cannot delete backup file %s:%+v", backupFile, err)
}
}
return nil
}
func getFilePerm(originalFile string, backupFile string, err error) (os.FileInfo, error) {
var info os.FileInfo
for _, path := range []string{originalFile, backupFile} {
info, err = filesystem.Fs.Stat(path)
if err == nil {
break
}
}
if err != nil {
return nil, fmt.Errorf("cannot get permission of backup file %s:%+v", backupFile, err)
}
return info, nil
}