返回 DeepSeek-Reasonix
rebuild.go
根目录 / internal / taskcatalog / rebuild.go
1 package taskcatalog
2
3 import (
4 "context"
5 "database/sql"
6 "path/filepath"
7 "strings"
8 "time"
9
10 "reasonix/internal/projectiondb"
11 "reasonix/internal/taskmonitor"
12 )
13
14 // Rebuild replaces only the disposable task projection after replaying the
15 // authoritative snapshots for the supplied projects into a validated sibling
16 // database. Event logs remain lazily indexed when a task is expanded.
17 func Rebuild(ctx context.Context, path string, projects []Project) (Status, error) {
18 if path == "" {
19 path = DefaultPath()
20 }
21 if strings.TrimSpace(path) == "" {
22 catalog, err := Open(ctx, "")
23 if err != nil {
24 return Status{}, err
25 }
26 catalog.reconcileMu.Lock()
27 catalog.reconcileDone = true
28 catalog.reconcileMu.Unlock()
29 if err := reconcileProjects(ctx, catalog, projects); err != nil {
30 closeRebuildCatalog(catalog)
31 return catalog.Status(), err
32 }
33 status := catalog.Status()
34 closeRebuildCatalog(catalog)
35 return status, nil
36 }
37 err := projectiondb.Rebuild(ctx, projectiondb.OpenOptions{
38 Path: path, MemoryName: "task-catalog-rebuild", Migrations: migrations(),
39 }, func(ctx context.Context, db *sql.DB) error {
40 catalog := &Catalog{
41 db: db, store: taskmonitor.NewFileStore(filepath.Join(".reasonix", "tasks")),
42 status: Status{State: "ready", Mode: projectiondb.ModeDisk, Path: path},
43 reconciling: map[string]bool{}, registered: map[string]bool{}, reconcileDone: true,
44 }
45 return reconcileProjects(ctx, catalog, projects)
46 })
47 if err != nil {
48 return Status{}, err
49 }
50 published, err := Open(ctx, path)
51 if err != nil {
52 return Status{}, err
53 }
54 status := published.Status()
55 closeRebuildCatalog(published)
56 return status, nil
57 }
58
59 func reconcileProjects(ctx context.Context, catalog *Catalog, projects []Project) error {
60 for _, input := range projects {
61 project, err := catalog.RegisterProject(ctx, input.Root, input.Label)
62 if err != nil {
63 return err
64 }
65 if err := catalog.ReconcileProject(ctx, project); err != nil {
66 return err
67 }
68 }
69 return nil
70 }
71
72 func normalizeProject(project Project) Project {
73 project.Root = filepath.Clean(strings.TrimSpace(project.Root))
74 if abs, err := filepath.Abs(project.Root); err == nil {
75 project.Root = abs
76 }
77 project.Key = ProjectKey(project.Root)
78 project.Label = strings.TrimSpace(project.Label)
79 return project
80 }
81
82 func closeRebuildCatalog(catalog *Catalog) {
83 closeCtx, cancel := context.WithTimeout(context.Background(), time.Second)
84 defer cancel()
85 _ = catalog.Close(closeCtx)
86 }
87
87 lines GO