diff --git a/cmd/get.go b/cmd/get.go index 425b8c5..4431c59 100644 --- a/cmd/get.go +++ b/cmd/get.go @@ -17,14 +17,17 @@ func runGetCmd(cmd *cobra.Command, args []string) error { // Get git dir gitDir, err := git.GetNearestRepoDir(".") if err != nil { - return err + log.Print(log.IconFailure, "Failed to find a git repository", log.ColorRed(err)) + log.PrintNotInitialized() + log.DumpAndExit(1) } // Load the conf conf, err := config.Read(gitDir) if err != nil { + println("Failed to read config file", err.Error()) log.PrintNotInitialized() - log.DumpAndExit(0) + log.DumpAndExit(1) } // Get flags diff --git a/cmd/migrate.go b/cmd/migrate.go index 70cf858..9f13c89 100644 --- a/cmd/migrate.go +++ b/cmd/migrate.go @@ -8,40 +8,51 @@ import ( "github.com/spf13/cobra" ) -func runMigrateModule(msg string, migrateFunc func() ([]string, error)) { +func runMigrateModule(msg string, migrateFunc func(bool) ([]string, error), dry bool) { log.Print(msg) - filesModified, err := migrateFunc() + files, err := migrateFunc(dry) log.OverwritePreviousLine() if err != nil { log.Print(msg, log.IconFailure) log.Print(" ", log.ColorRed(err)) - } else if len(filesModified) == 0 { + } else if len(files) == 0 { log.Print(msg, log.IconSuccess, log.ColorGreen("already up to date")) } else { - log.Print(msg, log.IconSuccess, log.ColorGreen("migrated ", fmt.Sprint(len(filesModified)), " files")) - for _, file := range filesModified { + log.Print(msg, log.IconSuccess, log.ColorGreen("migrated ", fmt.Sprint(len(files)), " files")) + for _, file := range files { log.Print(" ", log.ColorFile(file)) } } } func runMigrateCmd(cmd *cobra.Command, args []string) { - runMigrateModule("Migrating local metadata...", migrate.MigrateMetaFiles) - runMigrateModule("Migrating files in storage...", migrate.MigrateStorageFiles) + dry, err := cmd.Flags().GetBool("dry") + if err != nil { + return + } + + runMigrateModule("Migrating local metadata...", migrate.MigrateMetaFiles, dry) + runMigrateModule("Migrating files in storage...", migrate.MigrateStorageFiles, dry) log.Print("\nMigration complete!") + + log.DumpAndExit(0) } func getMigrateCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "migrate", - Short: "Migrates data to the latest format", - Long: "Migrates data to the latest format. This includes the meta files and the storage.", + Use: "migrate", + Short: "Migrates data to the latest format", + Long: "Migrates data to the latest format. This includes the meta files and the storage.", + PersistentPreRun: func(cmd *cobra.Command, args []string) {}, PreRun: func(cmd *cobra.Command, args []string) { log.PrintLogo() }, Run: runMigrateCmd, } + // Add --dry flag + cmd.Flags().BoolP("dry", "d", false, "dry run") + return cmd } diff --git a/cmd/root.go b/cmd/root.go index 2fe38ab..1171fee 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,6 +1,7 @@ package cmd import ( + "dvs/internal" "dvs/internal/log" "os" @@ -19,6 +20,16 @@ func getRootCmd() *cobra.Command { if json { log.JsonLogging = true } + + valid, msg := internal.ValidateEnvironment() + if !valid { + log.Print(msg) + log.JsonLogger.Issues = append(log.JsonLogger.Issues, log.JsonIssue{ + Severity: "error", + Message: msg, + }) + log.DumpAndExit(1) + } }, } diff --git a/cmd/status.go b/cmd/status.go index 3089f36..079a6c3 100644 --- a/cmd/status.go +++ b/cmd/status.go @@ -13,7 +13,7 @@ import ( "github.com/spf13/cobra" ) -func runStatusCmd(cmd *cobra.Command, args []string) error { +func runStatusCmd(cmd *cobra.Command, args []string) { type jsonFileResult struct { Path string `json:"path"` Status string `json:"status"` @@ -37,12 +37,14 @@ func runStatusCmd(cmd *cobra.Command, args []string) error { // Get git dir gitDir, err := git.GetNearestRepoDir(".") if err != nil { - return err + log.Print(log.IconFailure, "Failed to find a git repository", log.ColorRed(err)) + os.Exit(1) } metaPaths, err = meta.GetAllMetaFiles(gitDir) if err != nil { - return err + log.Print(log.IconFailure, "Failed to get meta files", log.ColorRed(err)) + os.Exit(1) } } else { // Get meta files from globs @@ -158,8 +160,6 @@ func runStatusCmd(cmd *cobra.Command, args []string) error { } log.Dump(jsonLogger) - - return nil } func getStatusCmd() *cobra.Command { @@ -170,7 +170,7 @@ func getStatusCmd() *cobra.Command { PreRun: func(cmd *cobra.Command, args []string) { log.PrintLogo() }, - RunE: runStatusCmd, + Run: runStatusCmd, } return cmd diff --git a/internal/migrate/main.go b/internal/migrate/main.go index 9aef0d9..2330332 100644 --- a/internal/migrate/main.go +++ b/internal/migrate/main.go @@ -1,6 +1,21 @@ package migrate -func MigrateToLatest() { - MigrateMetaFiles() - MigrateStorageFiles() +func MigrateToLatest(dry bool) (match bool, err error) { + files, err := MigrateMetaFiles(dry) + if err != nil { + return false, err + } + if len(files) > 0 { + return true, err + } + + files, err = MigrateStorageFiles(dry) + if err != nil { + return false, err + } + if len(files) > 0 { + return true, err + } + + return false, nil } diff --git a/internal/migrate/meta.go b/internal/migrate/meta.go index b261047..d1aa76d 100644 --- a/internal/migrate/meta.go +++ b/internal/migrate/meta.go @@ -12,7 +12,7 @@ import ( ) // Attempts to migrate a metafile format from version 1 to the latest, returns true if anything was migrated -func migrateMetaFormatV1(path string) (actionTaken bool, err error) { +func migrateMetaFormatV1(path string) (match bool, err error) { type LegacyMetadata struct { FileHash string `json:"blake3_checksum"` FileSize uint64 `json:"file_size_bytes"` @@ -48,10 +48,14 @@ func migrateMetaFormatV1(path string) (actionTaken bool, err error) { } // Migrate a single meta file to the latest format, returns true if anything was migrated -func migrateMetaFile(path string) (actionTaken bool, errs error) { +func migrateMetaFile(path string, dry bool) (match bool, errs error) { // Ensure the file has the correct extension ext := filepath.Ext(path) if ext != meta.FileExtension { + if dry { + return true, nil + } + newPath := strings.TrimSuffix(path, ext) + meta.FileExtension err := os.Rename(path, newPath) if err != nil { @@ -59,26 +63,30 @@ func migrateMetaFile(path string) (actionTaken bool, errs error) { } path = newPath - actionTaken = true + match = true } // Ensure the file has the correct content structure pathNoExt := strings.TrimSuffix(path, meta.FileExtension) _, err := meta.Load(pathNoExt) if err != nil { + if dry { + return true, nil + } + _, err = migrateMetaFormatV1(path) if err != nil { return false, err } - actionTaken = true + match = true } - return actionTaken, err + return match, err } // Migrates local meta files to the latest format, returning a list of files that were modified -func MigrateMetaFiles() (filesModified []string, err error) { +func MigrateMetaFiles(dry bool) (files []string, err error) { // Iterate over all files in the git repository repoDir, _ := git.GetNearestRepoDir(".") filepath.WalkDir(repoDir, func(path string, d fs.DirEntry, _ error) error { @@ -86,17 +94,17 @@ func MigrateMetaFiles() (filesModified []string, err error) { // Check if the file is a meta file of some format if filepath.Ext(path) == ".dvsmeta" || filepath.Ext(path) == ".dvs" { - fileWasMigrated, err := migrateMetaFile(path) + wasOtherFormat, err := migrateMetaFile(path, dry) if err != nil { return err } - if fileWasMigrated { - filesModified = append(filesModified, path) + if wasOtherFormat { + files = append(files, path) } } return nil }) - return filesModified, nil + return files, nil } diff --git a/internal/migrate/storage.go b/internal/migrate/storage.go index 5df85dc..0da1540 100644 --- a/internal/migrate/storage.go +++ b/internal/migrate/storage.go @@ -10,10 +10,14 @@ import ( "strings" ) -func migrateStorageFile(storageDir string, path string) (modified bool, err error) { +func migrateStorageFile(storageDir string, path string, dry bool) (match bool, err error) { // Ensure the file has the correct extension ext := filepath.Ext(path) if ext != "" { + if dry { + return true, nil + } + newPath := strings.TrimSuffix(path, ext) err := os.Rename(path, newPath) if err != nil { @@ -21,11 +25,15 @@ func migrateStorageFile(storageDir string, path string) (modified bool, err erro } path = newPath - modified = true + match = true } // Ensure the file is not at the root level if filepath.Dir(path) == storageDir { + if dry { + return true, nil + } + // Create new directory newDir := storage.GetStoragePath(storageDir, filepath.Base(path)) err := os.MkdirAll(newDir, storage.StorageDirPermissions) @@ -37,24 +45,24 @@ func migrateStorageFile(storageDir string, path string) (modified bool, err erro newPath := storage.GetStoragePath(storageDir, filepath.Base(path)) err = os.Rename(path, newPath) - modified = true + match = true if os.IsExist(err) { // File already exists, delete the old one err = os.Remove(path) if err != nil { - return modified, err + return match, err } } else if err != nil { - return modified, err + return match, err } } - return modified, nil + return match, nil } // Migrates storage files to the latest format, returning a list of files that were modified -func MigrateStorageFiles() (modifiedFiles []string, err error) { +func MigrateStorageFiles(dry bool) (files []string, err error) { repoDir, _ := git.GetNearestRepoDir(".") config, err := config.Read(repoDir) if err != nil { @@ -69,13 +77,13 @@ func MigrateStorageFiles() (modifiedFiles []string, err error) { } // TODO respect gitignore? - modified, err := migrateStorageFile(config.StorageDir, path) + modified, err := migrateStorageFile(config.StorageDir, path, dry) if err != nil { return err } if modified { - modifiedFiles = append(modifiedFiles, path) + files = append(files, path) } return nil @@ -84,5 +92,5 @@ func MigrateStorageFiles() (modifiedFiles []string, err error) { return nil, err } - return modifiedFiles, nil + return files, nil } diff --git a/internal/validate.go b/internal/validate.go new file mode 100644 index 0000000..e002576 --- /dev/null +++ b/internal/validate.go @@ -0,0 +1,27 @@ +package internal + +import ( + "dvs/internal/git" + "dvs/internal/log" + "dvs/internal/migrate" +) + +func ValidateEnvironment() (bool, string) { + // Ensure we can find a git repository + _, err := git.GetNearestRepoDir(".") + if err != nil { + return false, log.IconFailure + "Failed to find a git repository here -- are you sure you're in one?" + } + + // Ensure data is migrated + match, err := migrate.MigrateToLatest(true) + if err != nil { + log.Print() + return false, log.IconFailure + " Error validating environment " + log.ColorRed(err) + } + if match { + return false, log.IconWarning + " Data is not migrated - run " + log.ColorFaint("dvs migrate") + " to migrate your data to the current version" + } + + return true, "" +} diff --git a/testing/1G.dvs b/testing/1G.dvs index 47a6ec8..206194c 100644 --- a/testing/1G.dvs +++ b/testing/1G.dvs @@ -1,7 +1,7 @@ { "blake3_checksum": "94b4ec39d8d42ebda685fbb5429e8ab0086e65245e750142c1eea36a26abc24d", "file_size_bytes": 1073741824, - "timestamp": "2023-10-11T11:47:21.736802714-04:00", + "timestamp": "2023-11-13T12:52:44.564590289-05:00", "message": "", - "saved_by": "andriygm" + "saved_by": "andriy" } \ No newline at end of file diff --git a/testing/571-536x354.jpg.dvs b/testing/571-536x354.jpg.dvs index cf7179e..e66bcda 100644 --- a/testing/571-536x354.jpg.dvs +++ b/testing/571-536x354.jpg.dvs @@ -1,7 +1,7 @@ { "blake3_checksum": "800fe626b5b4a066de815d9486893fe549e2af1742558ed4110c6ea424425c42", "file_size_bytes": 23091, - "timestamp": "2023-10-11T11:47:21.737655146-04:00", + "timestamp": "2023-11-13T12:56:25.947082624-05:00", "message": "", - "saved_by": "andriygm" + "saved_by": "andriy" } \ No newline at end of file