From 63eb070e78d6603752f5d065fa2e0b14af4afc1d Mon Sep 17 00:00:00 2001 From: Christian Zangl Date: Sun, 22 Dec 2024 19:12:22 +0100 Subject: [PATCH] implement db export to json --- README.md | 3 ++ cmd/chkbit/main.go | 11 ++++++ store.go | 86 +++++++++++++++++++++++++++++++++++++++------- 3 files changed, 87 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index ec0066f..ecd29e7 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,9 @@ Commands: init-db [flags] initialize a new index database at the given path for use with --db + export-db [flags] + export a database to a json for archiving + show-ignored-only ... [flags] only show ignored files diff --git a/cmd/chkbit/main.go b/cmd/chkbit/main.go index 259821f..a176238 100644 --- a/cmd/chkbit/main.go +++ b/cmd/chkbit/main.go @@ -67,6 +67,10 @@ type CLI struct { Force bool `help:"force init if a database already exists"` } `cmd:"" help:"initialize a new index database at the given path for use with --db"` + ExportDb struct { + Path string `arg:"" help:"directory for the database"` + } `cmd:"" help:"export a database to a json for archiving"` + ShowIgnoredOnly struct { Paths []string `arg:"" name:"paths" help:"directories to list"` } `cmd:"" help:"only show ignored files"` @@ -377,6 +381,13 @@ func (m *Main) run() int { return 1 } return 0 + case "export-db ": + m.log("chkbit export-db " + cli.ExportDb.Path) + if err := chkbit.ExportIndexDb(cli.ExportDb.Path, cli.IndexName); err != nil { + fmt.Println("error: " + err.Error()) + return 1 + } + return 0 case "tips": fmt.Println(strings.ReplaceAll(helpTips, "", configPath)) return 0 diff --git a/store.go b/store.go index 223e7ff..48054fa 100644 --- a/store.go +++ b/store.go @@ -1,6 +1,7 @@ package chkbit import ( + "encoding/json" "errors" "io" "os" @@ -38,19 +39,8 @@ func (s *store) Open(readOnly bool) error { var err error s.readOnly = readOnly if s.useDb { - optR := &bolt.Options{ - ReadOnly: true, - Timeout: 0, - NoGrowSync: false, - FreelistType: bolt.FreelistArrayType, - } - optW := &bolt.Options{ - Timeout: 0, - NoGrowSync: false, - FreelistType: bolt.FreelistArrayType, - } s.dbFile = getDbFile(s.dbPath, s.indexName, "") - s.connR, err = bolt.Open(s.dbFile, 0600, optR) + s.connR, err = bolt.Open(s.dbFile, 0600, getBoltOptions(true)) if !readOnly { s.newFile = getDbFile(s.dbPath, s.indexName, newDbSuffix) @@ -64,7 +54,7 @@ func (s *store) Open(readOnly bool) error { return err } - s.connW, err = bolt.Open(s.newFile, 0600, optW) + s.connW, err = bolt.Open(s.newFile, 0600, getBoltOptions(false)) if err == nil { err = s.connW.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucketIfNotExists([]byte("data")) @@ -188,6 +178,67 @@ func LocateIndexDb(path, indexName string) (string, error) { } } +func ExportIndexDb(path, indexName string) error { + + dbFile := getDbFile(path, indexName, "") + connR, err := bolt.Open(dbFile, 0600, getBoltOptions(true)) + if err != nil { + return err + } + + file, err := os.Create(getDbFile(path, indexName, ".json")) + if err != nil { + return err + } + defer file.Close() // Ensure the file is closed when the function exits + + _, err = file.WriteString("{") + if err != nil { + return err + } + + err = connR.View(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte("data")) + c := b.Cursor() + var ierr error + first := true + for k, v := c.First(); k != nil; k, v = c.Next() { + + if first { + first = false + } else { + if _, ierr = file.WriteString(","); ierr != nil { + break + } + } + + if idxPath, ierr := json.Marshal(string(k)); ierr == nil { + if _, ierr = file.Write(idxPath); ierr != nil { + break + } + } else { + break + } + + if _, ierr = file.WriteString(":"); ierr != nil { + break + } + + if _, ierr = file.Write(v); ierr != nil { + break + } + } + return ierr + }) + + _, err = file.WriteString("}") + if err != nil { + return err + } + + return err +} + func getDbFile(path, indexFilename, suffix string) string { return filepath.Join(path, indexFilename+dbSuffix+suffix) } @@ -217,3 +268,12 @@ func copyFile(src, dst string) error { _, err = io.Copy(df, sf) return err } + +func getBoltOptions(readOnly bool) *bolt.Options { + return &bolt.Options{ + ReadOnly: readOnly, + Timeout: 0, + NoGrowSync: false, + FreelistType: bolt.FreelistArrayType, + } +}