diff options
Diffstat (limited to 'cmd/import.go')
-rw-r--r-- | cmd/import.go | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/cmd/import.go b/cmd/import.go new file mode 100644 index 0000000..2bcb1d1 --- /dev/null +++ b/cmd/import.go @@ -0,0 +1,203 @@ +/* +Copyright © 2025 NAME HERE <EMAIL ADDRESS> +*/ +package cmd + +import ( + "encoding/json" + "fmt" + "io" + "os" + "sync" + + "github.com/scrotadamus/ghligh/document" + "github.com/spf13/cobra" + + "crypto/sha256" +) + +var inputFiles []string + +type importedAnnots struct { + // FIXME just internatl map[string]struct where + // struct contains map[string]bool and document.AnnotsMap + internal map[string]document.AnnotsMap + annotsHashes map[string]map[string]bool + mutex sync.Mutex +} + +func (ia *importedAnnots) get(hash string) document.AnnotsMap { + return ia.internal[hash] +} + +func (ia *importedAnnots) init(hash string) { + ia.mutex.Lock() + defer ia.mutex.Unlock() + if ia.internal[hash] == nil { + ia.internal[hash] = make(document.AnnotsMap) + } + if ia.annotsHashes[hash] == nil { + ia.annotsHashes[hash] = make(map[string]bool) + } +} + +func (ia *importedAnnots) check(docHash string, annotsHash string) bool { + ia.mutex.Lock() + defer ia.mutex.Unlock() + ok := ia.annotsHashes[docHash][annotsHash] + return ok +} + +func (ia *importedAnnots) insert(hash string, am document.AnnotsMap) error { + amHash, err := hashAnnotsMap(am) + if err != nil { + return err + } + + present := ia.check(hash, amHash) + if !present { + ia.mutex.Lock() + for key, value := range am { + ia.internal[hash][key] = append(ia.internal[hash][key], value...) + ia.annotsHashes[hash][amHash] = true + } + ia.mutex.Unlock() + } + return nil +} + +func hashAnnotsMap(am document.AnnotsMap) (string, error) { + jsonBytes, err := json.Marshal(am) + if err != nil { + return "", err + } + + h := sha256.Sum256(jsonBytes) + return fmt.Sprintf("%x", h), nil +} + +func loadImportedAnnots(ia *importedAnnots, reader io.Reader) { + data, err := io.ReadAll(reader) + if err != nil { + fmt.Fprintf(os.Stderr, "could not read data: %v\n", err) + return + } + + var importedDocs []document.GhlighDoc + + err = json.Unmarshal(data, &importedDocs) + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + return + } + + for _, importedDoc := range importedDocs { + hash := importedDoc.HashBuffer + ia.init(hash) + ia.insert(hash, importedDoc.AnnotsBuffer) + } +} + +// importCmd represents the import command +var importCmd = &cobra.Command{ + Use: "import", + Short: "import highlights from json file", + Long: ` + ghligh import foo.pdf bar.pdf ... [--from fnord.json] [--from kadio.json] [-0] [--save=false] + + will import into foo.pdf bar.pdf etc... the highlights from file specified + with the --from flag + + if -0 is set ghligh will read json from stdin + + --save=false will run without saving documents, it will just tells you how + many annotations from the json files specified will be imported +`, + + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 0 { + cmd.Help() + return + } + + stdin, err := cmd.Flags().GetBool("stdin") + if err != nil { + cmd.Help() + return + } + + save, err := cmd.Flags().GetBool("save") + if err != nil { + cmd.Help() + return + } + + if stdin == false && len(inputFiles) == 0 { + fmt.Fprintf(os.Stderr, "nowhere to put output I am not doing anything\n") + return + } + + // Load Annot Maps + ia := importedAnnots{ + internal: make(map[string]document.AnnotsMap), + annotsHashes: make(map[string]map[string]bool), + } + + var wg sync.WaitGroup + + wg.Add(len(inputFiles)) + for _, file := range inputFiles { + //wg.Add(1) + go func(path string) { + defer wg.Done() + + f, err := os.Open(path) + if err != nil { + fmt.Fprintf(os.Stderr, "could not open file %s: %v\n", path, err) + return + } + defer f.Close() + + loadImportedAnnots(&ia, f) + }(file) + } + + wg.Wait() + + if stdin { + loadImportedAnnots(&ia, os.Stdin) + } + + // load from inputFiles + for _, file := range args { + doc, err := document.Open(file) + if err != nil { + fmt.Fprintf(os.Stderr, "error loading %s: %v", file, err) + continue + } + + hash := doc.HashDoc() + + num, err := doc.Import(ia.get(hash)) + if err != nil { + fmt.Fprintf(os.Stderr, "could not import highlights into %s: %v\n", file, err) + } else { + fmt.Fprintf(os.Stderr, "imported %d annots into %s\n", num, file) + if save { + doc.Save() + } + } + doc.Close() + + } + + }, +} + +func init() { + rootCmd.AddCommand(importCmd) + + importCmd.Flags().BoolP("stdin", "0", false, "read json from stdin") + importCmd.Flags().BoolP("save", "", true, "save the file with new annotation importer") + importCmd.Flags().StringArrayVarP(&inputFiles, "from", "f", []string{}, "files to import annots from") +} |