160 lines
3.8 KiB
Go
160 lines
3.8 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/spf13/cobra"
|
|
"github.com/yeho/doks/internal/registry"
|
|
"github.com/yeho/doks/internal/storage"
|
|
)
|
|
|
|
var (
|
|
addKey string
|
|
addPreserve bool
|
|
addTags string
|
|
addDescription string
|
|
)
|
|
|
|
var addCmd = &cobra.Command{
|
|
Use: "add <path>",
|
|
Short: "Add a document to doks",
|
|
Long: `Add a document to doks by copying it to the storage directory.
|
|
Use -p to create a symlink at the original location pointing to the stored file.`,
|
|
Args: cobra.ExactArgs(1),
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
filePath := args[0]
|
|
|
|
if addKey == "" {
|
|
fmt.Fprintln(os.Stderr, "Error: -k (key) flag is required")
|
|
os.Exit(1)
|
|
}
|
|
|
|
absPath, err := storage.GetAbsolutePath(filePath)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error resolving path: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Check if file exists
|
|
if _, err := os.Stat(absPath); os.IsNotExist(err) {
|
|
fmt.Fprintf(os.Stderr, "Error: file not found: %s\n", absPath)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Load registry
|
|
reg, err := registry.Load(cfg.RegistryPath())
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error loading registry: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Check if key already exists
|
|
if reg.Exists(addKey) {
|
|
fmt.Fprintf(os.Stderr, "Error: key '%s' already exists\n", addKey)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Generate unique filename
|
|
filename := storage.GenerateFilename(absPath)
|
|
|
|
// Create storage and copy file
|
|
store := storage.New(cfg.FilesDir())
|
|
if err := store.CopyFile(absPath, filename); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error copying file: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Remove original and create symlink if preserve flag is set
|
|
if addPreserve {
|
|
if err := os.Remove(absPath); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error removing original file: %v\n", err)
|
|
// Clean up copied file
|
|
store.RemoveFile(filename)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err := store.CreateSymlink(absPath, filename); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error creating symlink: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
// Parse tags
|
|
var tags []string
|
|
if addTags != "" {
|
|
tags = splitTags(addTags)
|
|
}
|
|
|
|
// Create registry entry
|
|
entry := ®istry.Entry{
|
|
Key: addKey,
|
|
Filename: filename,
|
|
OriginalPath: absPath,
|
|
HasSymlink: addPreserve,
|
|
Tags: tags,
|
|
Description: addDescription,
|
|
}
|
|
|
|
if err := reg.Add(entry); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error adding to registry: %v\n", err)
|
|
// Clean up
|
|
store.RemoveFile(filename)
|
|
if addPreserve {
|
|
store.RemoveSymlink(absPath)
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Printf("Added '%s' with key '%s'\n", filePath, addKey)
|
|
},
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(addCmd)
|
|
addCmd.Flags().StringVarP(&addKey, "key", "k", "", "Unique key for the document (required)")
|
|
addCmd.Flags().BoolVarP(&addPreserve, "preserve", "p", false, "Create symlink at original location")
|
|
addCmd.Flags().StringVarP(&addTags, "tags", "t", "", "Comma-separated tags")
|
|
addCmd.Flags().StringVarP(&addDescription, "description", "d", "", "Description of the document")
|
|
addCmd.MarkFlagRequired("key")
|
|
}
|
|
|
|
func splitTags(tags string) []string {
|
|
if tags == "" {
|
|
return nil
|
|
}
|
|
result := []string{}
|
|
for _, tag := range splitString(tags, ",") {
|
|
tag = trimSpace(tag)
|
|
if tag != "" {
|
|
result = append(result, tag)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func splitString(s, sep string) []string {
|
|
var result []string
|
|
start := 0
|
|
for i := 0; i < len(s); i++ {
|
|
if i+len(sep) <= len(s) && s[i:i+len(sep)] == sep {
|
|
result = append(result, s[start:i])
|
|
start = i + len(sep)
|
|
}
|
|
}
|
|
result = append(result, s[start:])
|
|
return result
|
|
}
|
|
|
|
func trimSpace(s string) string {
|
|
start := 0
|
|
end := len(s)
|
|
for start < end && (s[start] == ' ' || s[start] == '\t') {
|
|
start++
|
|
}
|
|
for end > start && (s[end-1] == ' ' || s[end-1] == '\t') {
|
|
end--
|
|
}
|
|
return s[start:end]
|
|
}
|