AddRoot adds a directory root to the engine.
(ctx context.Context, root string)
| 108 | |
| 109 | // AddRoot adds a directory root to the engine. |
| 110 | func (e *Engine) AddRoot(ctx context.Context, root string) error { |
| 111 | absRoot, err := filepath.Abs(root) |
| 112 | if err != nil { |
| 113 | return xerrors.Errorf("resolve root: %w", err) |
| 114 | } |
| 115 | e.mu.Lock() |
| 116 | if e.closed.Load() { |
| 117 | e.mu.Unlock() |
| 118 | return ErrClosed |
| 119 | } |
| 120 | if _, exists := e.roots[absRoot]; exists { |
| 121 | e.mu.Unlock() |
| 122 | return nil |
| 123 | } |
| 124 | e.mu.Unlock() |
| 125 | |
| 126 | // Walk and create the watcher outside the lock to avoid |
| 127 | // blocking the event pipeline on filesystem I/O. |
| 128 | idx, walkErr := walkRoot(absRoot) |
| 129 | if walkErr != nil { |
| 130 | return xerrors.Errorf("walk root: %w", walkErr) |
| 131 | } |
| 132 | wCtx, wCancel := context.WithCancel(context.Background()) |
| 133 | w, wErr := newFSWatcher(absRoot, e.logger) |
| 134 | if wErr != nil { |
| 135 | wCancel() |
| 136 | return xerrors.Errorf("create watcher: %w", wErr) |
| 137 | } |
| 138 | |
| 139 | e.mu.Lock() |
| 140 | // Re-check after re-acquiring the lock: another goroutine |
| 141 | // may have added this root or closed the engine while we |
| 142 | // were walking. |
| 143 | if e.closed.Load() { |
| 144 | e.mu.Unlock() |
| 145 | wCancel() |
| 146 | _ = w.Close() |
| 147 | return ErrClosed |
| 148 | } |
| 149 | if _, exists := e.roots[absRoot]; exists { |
| 150 | e.mu.Unlock() |
| 151 | wCancel() |
| 152 | _ = w.Close() |
| 153 | return nil |
| 154 | } |
| 155 | rs := &rootState{root: absRoot, index: idx, watcher: w, cancel: wCancel} |
| 156 | e.roots[absRoot] = rs |
| 157 | w.Start(wCtx) |
| 158 | e.wg.Add(1) |
| 159 | go e.forwardEvents(wCtx, absRoot, w) |
| 160 | e.publishSnapshot() |
| 161 | fileCount := idx.Len() |
| 162 | e.mu.Unlock() |
| 163 | e.logger.Info(ctx, "added root to engine", |
| 164 | slog.F("root", absRoot), |
| 165 | slog.F("files", fileCount), |
| 166 | ) |
| 167 | return nil |