Backups: Improve command-line backup and restore commands #4243

Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
Michael Mayer
2024-05-15 15:25:30 +02:00
parent 6a1c92a8af
commit ca78305eac
5 changed files with 23 additions and 20 deletions

View File

@@ -91,7 +91,7 @@ func backupAction(ctx *cli.Context) error {
if fileName == "" { if fileName == "" {
if !fs.PathWritable(databasePath) { if !fs.PathWritable(databasePath) {
if databasePath != "" { if databasePath != "" {
log.Warnf("backup: specified database backup path not writable, using default backup path") log.Warnf("backup: specified database backup path is not writable, using default directory instead")
} }
databasePath = conf.BackupDatabasePath() databasePath = conf.BackupDatabasePath()
@@ -109,7 +109,7 @@ func backupAction(ctx *cli.Context) error {
if backupAlbums { if backupAlbums {
if !fs.PathWritable(albumsPath) { if !fs.PathWritable(albumsPath) {
if albumsPath != "" { if albumsPath != "" {
log.Warnf("backup: specified album backup path not writable, using default backup path") log.Warnf("backup: specified albums backup path is not writable, using default directory instead")
} }
albumsPath = conf.BackupAlbumsPath() albumsPath = conf.BackupAlbumsPath()

View File

@@ -98,12 +98,12 @@ func restoreAction(ctx *cli.Context) error {
} }
if !fs.PathExists(albumsPath) { if !fs.PathExists(albumsPath) {
log.Warnf("restore: album files path %s not found", clean.Log(albumsPath)) log.Warnf("restore: failed to open %s, album backups cannot be restored", clean.Log(albumsPath))
} else { } else {
log.Infof("restore: restoring albums from %s", clean.Log(albumsPath)) log.Infof("restore: restoring album backups from %s", clean.Log(albumsPath))
if count, err := photoprism.RestoreAlbums(albumsPath, true); err != nil { if count, restoreErr := photoprism.RestoreAlbums(albumsPath, true); restoreErr != nil {
return err return restoreErr
} else { } else {
log.Infof("restore: restored %s from YAML files", english.Plural(count, "album", "albums")) log.Infof("restore: restored %s from YAML files", english.Plural(count, "album", "albums"))
} }

View File

@@ -9,6 +9,7 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/dustin/go-humanize/english"
"github.com/sevlyar/go-daemon" "github.com/sevlyar/go-daemon"
"github.com/urfave/cli" "github.com/urfave/cli"
@@ -126,9 +127,9 @@ func startAction(ctx *cli.Context) error {
// Restore albums from YAML files. // Restore albums from YAML files.
if count, restoreErr := photoprism.RestoreAlbums(conf.BackupAlbumsPath(), false); restoreErr != nil { if count, restoreErr := photoprism.RestoreAlbums(conf.BackupAlbumsPath(), false); restoreErr != nil {
log.Errorf("restore: %s", restoreErr) log.Errorf("restore: %s (albums)", restoreErr)
} else if count > 0 { } else if count > 0 {
log.Infof("%d albums restored", count) log.Infof("restore: %s restored", english.Plural(count, "album backup", "album backups"))
} }
// Start worker that periodically deletes expired sessions. // Start worker that periodically deletes expired sessions.

View File

@@ -19,7 +19,7 @@ func RestoreAlbums(backupPath string, force bool) (count int, result error) {
c := Config() c := Config()
if !c.BackupAlbums() && !force { if !c.BackupAlbums() && !force {
log.Debugf("restore: album metadata backups are disabled") log.Debugf("albums: metadata backup files are disabled")
return count, nil return count, nil
} }
@@ -30,7 +30,7 @@ func RestoreAlbums(backupPath string, force bool) (count int, result error) {
} }
if len(existing) > 0 && !force { if len(existing) > 0 && !force {
log.Debugf("restore: found existing albums, backup not restored") log.Debugf("albums: skipped restoring backups because albums already exist")
return count, nil return count, nil
} }
@@ -57,14 +57,14 @@ func RestoreAlbums(backupPath string, force bool) (count int, result error) {
a := entity.Album{} a := entity.Album{}
if err = a.LoadFromYaml(fileName); err != nil { if err = a.LoadFromYaml(fileName); err != nil {
log.Errorf("restore: %s in %s", err, clean.Log(filepath.Base(fileName))) log.Errorf("albums: %s in %s (restore)", err, clean.Log(filepath.Base(fileName)))
result = err result = err
} else if a.AlbumType == "" || len(a.Photos) == 0 && a.AlbumFilter == "" { } else if a.AlbumType == "" || len(a.Photos) == 0 && a.AlbumFilter == "" {
log.Debugf("restore: skipping %s", clean.Log(filepath.Base(fileName))) log.Debugf("albums: skipped %s (restore)", clean.Log(filepath.Base(fileName)))
} else if found := a.Find(); found != nil { } else if found := a.Find(); found != nil {
log.Infof("%s: %s already exists", found.AlbumType, clean.Log(found.AlbumTitle)) log.Infof("%s: %s already exists (restore)", found.AlbumType, clean.Log(found.AlbumTitle))
} else if err = a.Create(); err != nil { } else if err = a.Create(); err != nil {
log.Errorf("%s: %s in %s", a.AlbumType, err, clean.Log(filepath.Base(fileName))) log.Errorf("%s: %s in %s (restore)", a.AlbumType, err, clean.Log(filepath.Base(fileName)))
} else { } else {
count++ count++
} }

View File

@@ -42,7 +42,7 @@ func RestoreDatabase(backupPath, fileName string, fromStdIn, force bool) (err er
} }
if len(files) == 0 { if len(files) == 0 {
return fmt.Errorf("found no database backup files in %s", backupPath) return fmt.Errorf("failed to find a backup in %s, index cannot be restored", backupPath)
} }
sort.Strings(files) sort.Strings(files)
@@ -50,22 +50,22 @@ func RestoreDatabase(backupPath, fileName string, fromStdIn, force bool) (err er
fileName = files[len(files)-1] fileName = files[len(files)-1]
if !fs.FileExistsNotEmpty(fileName) { if !fs.FileExistsNotEmpty(fileName) {
return fmt.Errorf("no database backup found in %s", filepath.Base(fileName)) return fmt.Errorf("failed to open %s, index cannot be restored", filepath.Base(fileName))
} }
} else if backupPath == "" { } else if backupPath == "" {
if absName, absErr := filepath.Abs(fileName); absErr == nil && fs.FileExists(absName) { if absName, absErr := filepath.Abs(fileName); absErr == nil && fs.FileExists(absName) {
fileName = absName fileName = absName
} else if dir := filepath.Dir(fileName); dir != "" && dir != "." { } else if dir := filepath.Dir(fileName); dir != "" && dir != "." {
return fmt.Errorf("file %s not found", clean.Log(fileName)) return fmt.Errorf("failed to find %s, index cannot be restored", clean.Log(fileName))
} else if absName = filepath.Join(c.BackupDatabasePath(), fileName); !fs.FileExists(absName) { } else if absName = filepath.Join(c.BackupDatabasePath(), fileName); !fs.FileExists(absName) {
return fmt.Errorf("file %s not found in %s backup path", clean.Log(fileName), clean.Log(filepath.Base(c.BackupDatabasePath()))) return fmt.Errorf("failed to find %s in the %s backup path, index cannot be restored", clean.Log(fileName), clean.Log(filepath.Base(c.BackupDatabasePath())))
} else { } else {
fileName = absName fileName = absName
} }
} else if absName, absErr := filepath.Abs(filepath.Join(backupPath, fileName)); absErr == nil && fs.FileExists(absName) { } else if absName, absErr := filepath.Abs(filepath.Join(backupPath, fileName)); absErr == nil && fs.FileExists(absName) {
fileName = absName fileName = absName
} else { } else {
return fmt.Errorf("file %s not found in %s", clean.Log(filepath.Base(fileName)), clean.Log(backupPath)) return fmt.Errorf("failed to find %s in %s, index cannot be restored", clean.Log(filepath.Base(fileName)), clean.Log(backupPath))
} }
} }
@@ -144,13 +144,15 @@ func RestoreDatabase(backupPath, fileName string, fromStdIn, force bool) (err er
// Run restore command. // Run restore command.
if cmdErr := cmd.Run(); cmdErr != nil { if cmdErr := cmd.Run(); cmdErr != nil {
log.Errorf("restore: failed to restore database backup") log.Errorf("restore: failed to restore index database")
if errStr := strings.TrimSpace(stderr.String()); errStr != "" { if errStr := strings.TrimSpace(stderr.String()); errStr != "" {
return errors.New(errStr) return errors.New(errStr)
} }
return cmdErr return cmdErr
} else {
log.Infof("restore: index database successfully restored")
} }
return nil return nil