save+util: Provide a meaningful error message for safe (over-)write fails

This commit is contained in:
Jöran Karl 2024-11-05 21:35:41 +01:00
parent 79ce93fb7d
commit 49aebe8aca
4 changed files with 72 additions and 5 deletions

View File

@ -3,6 +3,7 @@ package main
import (
"bufio"
"encoding/gob"
"errors"
"fmt"
"os"
"path/filepath"
@ -11,6 +12,7 @@ import (
"github.com/zyedidia/micro/v2/internal/buffer"
"github.com/zyedidia/micro/v2/internal/config"
"github.com/zyedidia/micro/v2/internal/util"
)
func shouldContinue() bool {
@ -42,7 +44,11 @@ func CleanConfig() {
settingsFile := filepath.Join(config.ConfigDir, "settings.json")
err := config.WriteSettings(settingsFile)
if err != nil {
fmt.Println("Error writing settings.json file: " + err.Error())
if errors.Is(err, util.ErrOverwrite) {
fmt.Println(err.Error())
} else {
fmt.Println("Error writing settings.json file: " + err.Error())
}
}
// detect unused options
@ -80,7 +86,11 @@ func CleanConfig() {
err := config.OverwriteSettings(settingsFile)
if err != nil {
fmt.Println("Error overwriting settings.json file: " + err.Error())
if errors.Is(err, util.ErrOverwrite) {
fmt.Println(err.Error())
} else {
fmt.Println("Error overwriting settings.json file: " + err.Error())
}
}
fmt.Println("Removed unused options")

View File

@ -658,7 +658,16 @@ func SetGlobalOptionNative(option string, nativeValue interface{}) error {
delete(b.LocalSettings, option)
}
return config.WriteSettings(filepath.Join(config.ConfigDir, "settings.json"))
err := config.WriteSettings(filepath.Join(config.ConfigDir, "settings.json"))
if err != nil {
if errors.Is(err, util.ErrOverwrite) {
screen.TermMessage(err)
err = errors.Unwrap(err)
}
return err
}
return nil
}
func SetGlobalOption(option, value string) error {
@ -783,7 +792,11 @@ func (h *BufPane) BindCmd(args []string) {
_, err := TryBindKey(parseKeyArg(args[0]), args[1], true)
if err != nil {
InfoBar.Error(err)
if errors.Is(err, util.ErrOverwrite) {
screen.TermMessage(err)
} else {
InfoBar.Error(err)
}
}
}
@ -796,7 +809,11 @@ func (h *BufPane) UnbindCmd(args []string) {
err := UnbindKey(parseKeyArg(args[0]))
if err != nil {
InfoBar.Error(err)
if errors.Is(err, util.ErrOverwrite) {
screen.TermMessage(err)
} else {
InfoBar.Error(err)
}
}
}

View File

@ -316,6 +316,10 @@ func (b *Buffer) saveToFile(filename string, withSudo bool, autoSave bool) error
result := <-saveResponseChan
err = result.err
if err != nil {
if errors.Is(err, util.ErrOverwrite) {
screen.TermMessage(err)
err = errors.Unwrap(err)
}
return err
}
@ -371,6 +375,7 @@ func (b *Buffer) safeWrite(path string, withSudo bool, newFile bool) (int, error
b.forceKeepBackup = true
size, err := file.Write(b)
if err != nil {
err = util.OverwriteError{err, backupName}
return size, err
}
b.forceKeepBackup = false

View File

@ -45,11 +45,44 @@ var (
Stdout *bytes.Buffer
// Sigterm is a channel where micro exits when written
Sigterm chan os.Signal
// To be used for fails on (over-)write with safe writes
ErrOverwrite = OverwriteError{}
)
// To be used for file writes before umask is applied
const FileMode os.FileMode = 0666
const OverwriteFailMsg = `An error occurred while writing to the file:
%s
The file may be corrupted now. The good news is that it has been
successfully backed up. Next time you open this file with Micro,
Micro will ask if you want to recover it from the backup.
The backup path is:
%s`
// OverwriteError is a custom error to add additional information
type OverwriteError struct {
What error
BackupName string
}
func (e OverwriteError) Error() string {
return fmt.Sprintf(OverwriteFailMsg, e.What, e.BackupName)
}
func (e OverwriteError) Is(target error) bool {
return target == ErrOverwrite
}
func (e OverwriteError) Unwrap() error {
return e.What
}
func init() {
var err error
SemVersion, err = semver.Make(Version)
@ -685,6 +718,8 @@ func SafeWrite(path string, bytes []byte, rename bool) error {
if err != nil {
if rename {
os.Remove(tmp)
} else {
err = OverwriteError{err, tmp}
}
return err
}