mirror of
https://github.com/Dvorinka/Devour.git
synced 2026-06-03 20:13:03 +00:00
115 lines
2.8 KiB
Go
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"
|
|
}
|