Files
Devour/cmd/push.go
T
2026-02-24 12:10:13 +01:00

115 lines
2.8 KiB
Go

package cmd
import (
"context"
"fmt"
"net/url"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/yourorg/devour/internal/scraper"
"github.com/yourorg/devour/internal/search"
"github.com/yourorg/devour/internal/storage"
)
var pushCmd = &cobra.Command{
Use: "push <path>",
Short: "Import local documents into Devour storage/index",
Long: `Push local documents into your Devour local workspace.
Current stable behavior:
- local ingest into docs storage
- local reindex for query/ask/status
Remote push is experimental and not enabled by default.
Examples:
devour push ./docs
devour push ./docs --project my-project`,
Args: cobra.ExactArgs(1),
RunE: runPush,
}
var (
pushServer string
pushProject string
)
func init() {
pushCmd.Flags().StringVar(&pushServer, "server", "", "remote Devour server URL (experimental)")
pushCmd.Flags().StringVarP(&pushProject, "project", "p", "", "project name label")
}
func runPush(cmd *cobra.Command, args []string) error {
path := args[0]
if _, err := os.Stat(path); err != nil {
return fmt.Errorf("path does not exist: %s", path)
}
cfg, err := loadAppConfig()
if err != nil {
return fmt.Errorf("load app config for push command: %w", err)
}
server := strings.TrimSpace(pushServer)
if server != "" && !isLocalServer(server) {
return fmt.Errorf("remote push is experimental and not enabled in this build; use local push without --server")
}
projectName := strings.TrimSpace(pushProject)
if projectName == "" {
projectName = "local-push"
}
fmt.Printf("📤 Ingesting local docs from: %s\n", path)
fmt.Printf(" Project: %s\n", projectName)
fmt.Printf(" Target docs dir: %s\n", cfg.Storage.DocsDir)
s := scraper.NewScraper(scraper.SourceTypeLocal, toScraperConfig(cfg, 0))
if s == nil {
return fmt.Errorf("local scraper not available")
}
docs, err := s.Scrape(context.Background(), &scraper.Source{
Name: projectName,
Type: scraper.SourceTypeLocal,
Path: path,
Include: []string{`.*`},
})
if err != nil {
return fmt.Errorf("local ingest failed: %w", err)
}
saved, err := storage.SaveDocuments(docs, storage.SaveOptions{
Format: "json",
OutputDir: cfg.Storage.DocsDir,
AllowEmpty: false,
PrintWriter: nil,
})
if err != nil {
return fmt.Errorf("save docs failed: %w", err)
}
engine := search.NewEngine(cfg)
stats, err := engine.Rebuild(context.Background())
if err != nil {
return fmt.Errorf("reindex failed: %w", err)
}
fmt.Println("\n✓ Push complete")
fmt.Printf(" Documents imported: %d\n", saved.Count)
fmt.Printf(" Index docs: %d\n", stats.Documents)
fmt.Printf(" Index path: %s\n", stats.IndexPath)
return nil
}
func isLocalServer(raw string) bool {
u, err := url.Parse(raw)
if err != nil {
return false
}
host := strings.ToLower(u.Hostname())
return host == "" || host == "localhost" || host == "127.0.0.1"
}