feat(opencode): рабочий serve для dev стартует из папки репозитория; пул покрывает внешним сервером подкаталоги
Some checks failed
CI / test (push) Failing after 1m59s
CI / build-and-package (amd64, linux) (push) Failing after 1m2s
CI / build-and-package (amd64, windows) (push) Successful in 26s

This commit is contained in:
ki.sagidullin
2026-08-24 19:36:38 +05:00
parent 6c0b903794
commit 2005421739
4 changed files with 84 additions and 18 deletions

View File

@@ -34,6 +34,12 @@ type Pool struct {
segs map[string]*Server // dir → сервер (root тоже здесь)
used map[int]bool // занятые порты
next int // следующий кандидат порта
// externs — внешние (уже запущенные) серверы, зарегистрированные как
// префикс каталога: Ensure(dir) отдаёт такой сервер и для подкаталогов
// зарегистрированного каталога (используется тестами для эмуляции serve,
// покрывающего всё дерево worktree).
externs map[string]*Server // dir → внешний сервер
}
// NewPool создаёт пул. rootDir помечен как служебный (не снимается ReleaseTask).
@@ -92,11 +98,18 @@ func (p *Pool) EnsureRoot(ctx context.Context) error {
// Возвращает сервер; root-сервер для rootDir возвращается как есть.
func (p *Pool) Ensure(ctx context.Context, dir string) (*Server, error) {
p.mu.Lock()
if s, ok := p.segs[dir]; ok {
abs := filepath.Clean(dir)
if s, ok := p.segs[abs]; ok {
p.mu.Unlock()
return s, nil
}
// Внешний сервер-префикс покрывает дерево каталога (тестовая эмуляция):
// подкаталог обслуживается тем же сервером, spawn не нужен.
if s := p.externalFor(abs); s != nil {
p.segs[abs] = s
p.mu.Unlock()
return s, nil
}
abs := filepath.Clean(dir)
s := &Server{
Bin: p.Bin,
DBPath: p.DBPath,
@@ -129,9 +142,31 @@ func (p *Pool) RegisterExternal(dir, url string) {
p.mu.Lock()
defer p.mu.Unlock()
abs := filepath.Clean(dir)
p.segs[abs] = &Server{URL: url, Host: p.Host, PollInterval: 0}
s := &Server{URL: url, Host: p.Host, PollInterval: 0}
p.segs[abs] = s
if p.externs == nil {
p.externs = map[string]*Server{}
}
p.externs[abs] = s
if p.rootDir != "" && abs == p.rootDir {
p.root = p.segs[abs]
p.root = s
}
}
// externalFor возвращает внешний сервер-префикс для dir: самого каталога или
// его родителя (подкаталоги зарегистрированного каталога обслуживаются тем же
// внешним сервером). Вызывается под блокировкой p.mu.
func (p *Pool) externalFor(dir string) *Server {
cur := dir
for {
if s, ok := p.externs[cur]; ok {
return s
}
parent := filepath.Dir(cur)
if parent == cur {
return nil
}
cur = parent
}
}