Skip to content

Commit

Permalink
save+util: Provide a meaningful error message for safe (over-)write f…
Browse files Browse the repository at this point in the history
…ails
  • Loading branch information
JoeKar committed Nov 6, 2024
1 parent 6ec4771 commit 8053648
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 5 deletions.
14 changes: 12 additions & 2 deletions cmd/micro/clean.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"bufio"
"encoding/gob"
"errors"
"fmt"
"os"
"path/filepath"
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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")
Expand Down
23 changes: 20 additions & 3 deletions internal/action/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,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 {
Expand Down Expand Up @@ -782,7 +791,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)
}
}
}

Expand All @@ -795,7 +808,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)
}
}
}

Expand Down
8 changes: 8 additions & 0 deletions internal/buffer/save.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,13 @@ func (b *Buffer) saveToFile(filename string, withSudo bool, autoSave bool) error
result := <-saveResponseChan
err = result.err
if err != nil {
if errors.Is(err, fs.ErrPermission) {
return errors.Unwrap(err)
}
if errors.Is(err, util.ErrOverwrite) {
screen.TermMessage(err)
err = errors.Unwrap(err)
}
return err
}

Expand Down Expand Up @@ -325,6 +332,7 @@ func (b *Buffer) safeWrite(path string, withSudo bool) (int, error) {

size, err := b.overwriteFile(path, withSudo)
if err != nil {
err = util.OverwriteError{err, backupName}
return size, err
}
b.forceKeepBackup = false
Expand Down
35 changes: 35 additions & 0 deletions internal/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,41 @@ var (

// To be used for file writes before umask is applied
FileMode os.FileMode = 0666

// To be used for fails on (over-)write with safe writes
ErrOverwrite = OverwriteError{}
)

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)
Expand Down Expand Up @@ -670,6 +703,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
}
Expand Down

0 comments on commit 8053648

Please sign in to comment.