fix: centralize cache file registry (#1370)

Mohamed Mahmoud created

## What?

Replaces the hardcoded file list inside `MigrateCacheFiles()` with two
package-level registries: `cacheFiles` for JSON cache files and
`cacheDirectories` for cache subdirectories.

## Why?

Previously, adding a new cache file to the project required finding and
updating the hardcoded list inside `MigrateCacheFiles()`. This was easy
to forget and caused files to be silently left behind in the old
`~/.config/matcha/` location after migration. Now there is a single
obvious place to register new cache paths.

Closes #564

Change summary

config/config.go     | 53 ++++++++++++++++++++++++++++-----------------
config/encryption.go | 25 ++++++--------------
2 files changed, 41 insertions(+), 37 deletions(-)

Detailed changes

config/config.go 🔗

@@ -38,6 +38,18 @@ const (
 	DateFormatEU  = "DD/MM/YYYY HH:MM"
 )
 
+var cacheFiles = []string{
+	"email_cache.json",
+	"contacts.json",
+	"drafts.json",
+	"folder_cache.json",
+}
+
+var cacheDirectories = []string{
+	"folder_emails",
+	"email_bodies",
+}
+
 type SessionCache struct {
 	once  sync.Once
 	cache tls.ClientSessionCache
@@ -342,6 +354,21 @@ func cacheDir() (string, error) {
 	return filepath.Join(home, ".cache", "matcha"), nil
 }
 
+func migrate(src, dst string) error {
+	if _, err := os.Stat(src); err != nil {
+		if os.IsNotExist(err) {
+			return nil
+		}
+		return err
+	}
+	if _, err := os.Stat(dst); err == nil {
+		return nil
+	} else if !os.IsNotExist(err) {
+		return err
+	}
+	return os.Rename(src, dst)
+}
+
 // MigrateCacheFiles moves cache files from ~/.config/matcha/ to ~/.cache/matcha/ if needed.
 // This is a one-time migration for existing installations.
 func MigrateCacheFiles() error {
@@ -357,29 +384,15 @@ func MigrateCacheFiles() error {
 		return err
 	}
 
-	// Files to migrate
-	files := []string{"email_cache.json", "contacts.json", "drafts.json", "folder_cache.json"}
-	for _, f := range files {
-		oldPath := filepath.Join(src, f)
-		newPath := filepath.Join(dst, f)
-		if _, err := os.Stat(oldPath); err == nil {
-			// Only migrate if destination doesn't already exist
-			if _, err := os.Stat(newPath); err != nil {
-				if err := os.Rename(oldPath, newPath); err != nil {
-					return err
-				}
-			}
+	for _, f := range cacheFiles {
+		if err := migrate(filepath.Join(src, f), filepath.Join(dst, f)); err != nil {
+			return err
 		}
 	}
 
-	// Migrate folder_emails directory
-	oldDir := filepath.Join(src, "folder_emails")
-	newDir := filepath.Join(dst, "folder_emails")
-	if info, err := os.Stat(oldDir); err == nil && info.IsDir() {
-		if _, err := os.Stat(newDir); err != nil {
-			if err := os.Rename(oldDir, newDir); err != nil {
-				return err
-			}
+	for _, f := range cacheDirectories {
+		if err := migrate(filepath.Join(src, f), filepath.Join(dst, f)); err != nil {
+			return err
 		}
 	}
 

config/encryption.go 🔗

@@ -375,27 +375,18 @@ func collectDataFiles() ([]string, error) {
 	if err != nil {
 		return nil, err
 	}
-	cacheFiles := []string{"email_cache.json", "contacts.json", "drafts.json", "folder_cache.json"}
+
 	for _, f := range cacheFiles {
 		files = append(files, filepath.Join(cDir, f))
 	}
 
-	// Folder email cache files
-	folderDir := filepath.Join(cDir, "folder_emails")
-	if entries, err := os.ReadDir(folderDir); err == nil {
-		for _, entry := range entries {
-			if !entry.IsDir() {
-				files = append(files, filepath.Join(folderDir, entry.Name()))
-			}
-		}
-	}
-
-	// Email body cache files
-	bodyDir := filepath.Join(cDir, "email_bodies")
-	if entries, err := os.ReadDir(bodyDir); err == nil {
-		for _, entry := range entries {
-			if !entry.IsDir() {
-				files = append(files, filepath.Join(bodyDir, entry.Name()))
+	for _, f := range cacheDirectories {
+		dir := filepath.Join(cDir, f)
+		if entries, err := os.ReadDir(dir); err == nil {
+			for _, entry := range entries {
+				if !entry.IsDir() {
+					files = append(files, filepath.Join(dir, entry.Name()))
+				}
 			}
 		}
 	}