Files
Agent-System-Backend/cmd/agent-system/env.go
T
weichenandCursor 28544cfe5d
ci / vet-and-test (pull_request) Successful in 1m3s
Execute the managed interpreter through its real path
Why: the sandbox hides /home and only remounts the resolved Python prefix, so executing python/current/bin/python3 failed before the base layer could be imported.
Evidence: go test ./internal/tools/ -run TestResolveInterpreterFollowsManagedSymlink passed, and env doctor against the built base layer printed doctor ok (SELF).
Impact: run_python and env doctor follow the symlink into the mounted prefix or /usr/bin/python3. The layer and the prefix mount stay the same.
Refs: Agent-System-Backend PR 207
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-15 14:43:13 +00:00

151 lines
3.5 KiB
Go

package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"os"
"path/filepath"
"time"
"agent-system-backend/internal/execenv"
)
func runEnv(args []string) int {
if len(args) == 0 {
fmt.Fprintln(os.Stderr, "用法:agent-system env <ensure|lock|gc|doctor|rebase|python> --root <dir>")
return 2
}
sub := args[0]
fs := flag.NewFlagSet("env "+sub, flag.ExitOnError)
rootPath := fs.String("root", "", "环境根目录")
ttl := fs.Duration("ttl", 7*24*time.Hour, "gc 保留窗口")
bin := fs.String("bin", "", "python link 要指向的解释器")
_ = fs.Parse(args[1:])
if *rootPath == "" {
fmt.Fprintln(os.Stderr, "env: --root 必填")
return 2
}
root, err := execenv.Open(*rootPath)
if err != nil {
fmt.Fprintln(os.Stderr, "env:", err)
return 1
}
ctx := context.Background()
switch sub {
case "ensure":
py, err := root.EnsurePython(ctx)
if err != nil {
fmt.Fprintln(os.Stderr, "env ensure:", err)
return 1
}
id, err := execenv.NewBroker(root, nil, execenv.Pip{Python: py}).EnsureBase(ctx)
if err != nil {
fmt.Fprintln(os.Stderr, "env ensure:", err)
return 1
}
fmt.Println(id)
return runDoctor(ctx, root, py, true)
case "lock":
id, err := root.CurrentBase()
if err != nil || id == "" {
fmt.Fprintln(os.Stderr, "env lock: 没有 current 基础层")
return 1
}
lock, err := root.ReadLock(id)
if err != nil {
fmt.Fprintln(os.Stderr, "env lock:", err)
return 1
}
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
if err := enc.Encode(lock); err != nil {
fmt.Fprintln(os.Stderr, "env lock:", err)
return 1
}
return 0
case "gc":
removed, err := execenv.NewBroker(root, nil, execenv.Pip{}).GC(*ttl)
if err != nil {
fmt.Fprintln(os.Stderr, "env gc:", err)
return 1
}
for _, id := range removed {
fmt.Println(id)
}
return 0
case "doctor":
py, ok := root.PythonBin()
if !ok {
py = "/usr/bin/python3"
}
return runDoctor(ctx, root, py, true)
case "rebase":
py, err := root.EnsurePython(ctx)
if err != nil {
fmt.Fprintln(os.Stderr, "env rebase:", err)
return 1
}
id, err := execenv.NewBroker(root, nil, execenv.Pip{Python: py}).Rebase(ctx)
if err != nil {
fmt.Fprintln(os.Stderr, "env rebase:", err)
return 1
}
fmt.Println(id)
return 0
case "python":
action := "install"
if fs.NArg() > 0 {
action = fs.Arg(0)
}
switch action {
case "install":
py, err := root.EnsurePython(ctx)
if err != nil {
fmt.Fprintln(os.Stderr, "env python:", err)
return 1
}
fmt.Println(py)
return 0
case "link":
if *bin == "" {
fmt.Fprintln(os.Stderr, "env python link: --bin 必填")
return 2
}
if err := root.LinkPython(*bin); err != nil {
fmt.Fprintln(os.Stderr, "env python link:", err)
return 1
}
fmt.Println(*bin)
return 0
default:
fmt.Fprintln(os.Stderr, "env python: install | link")
return 2
}
default:
fmt.Fprintf(os.Stderr, "env: 未知动作 %s\n", sub)
return 2
}
}
func runDoctor(ctx context.Context, root *execenv.Root, py string, sandbox bool) int {
var pyPath []string
if id, err := root.CurrentBase(); err == nil && id != "" {
pyPath = append(pyPath, root.LayerDir(id))
}
mounts := append([]string{}, pyPath...)
if prefix := root.PythonPrefix(); prefix != "" {
mounts = append(mounts, prefix)
}
if resolved, err := filepath.EvalSymlinks(py); err == nil {
py = resolved
}
if err := execenv.Doctor(ctx, py, pyPath, nil, sandbox, mounts); err != nil {
fmt.Fprintln(os.Stderr, "env doctor:", err)
return 1
}
fmt.Println("doctor ok")
return 0
}