110 lines
2.2 KiB
Go
110 lines
2.2 KiB
Go
|
|
package runtimews
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"io"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
)
|
||
|
|
|
||
|
|
const envWorkspaceDir = "AGENT_WORKSPACE_DIR"
|
||
|
|
|
||
|
|
func PrepareFromEnv() (string, error) {
|
||
|
|
workspaceDir := strings.TrimSpace(os.Getenv(envWorkspaceDir))
|
||
|
|
if workspaceDir == "" {
|
||
|
|
workspaceDir = filepath.Join(".", "workspace", "agent_runtime")
|
||
|
|
}
|
||
|
|
absWorkspace, err := filepath.Abs(workspaceDir)
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
if err := os.MkdirAll(absWorkspace, 0o755); err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := seedRuntimeWorkspace(absWorkspace); err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := os.Setenv(envWorkspaceDir, absWorkspace); err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
_ = os.Setenv("CONFIG_ENV_FILE", filepath.Join(absWorkspace, "configs", "env"))
|
||
|
|
return absWorkspace, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func seedRuntimeWorkspace(workspaceRoot string) error {
|
||
|
|
seedDirs := []string{"configs", "data", "bot_context", "skills"}
|
||
|
|
for _, name := range seedDirs {
|
||
|
|
src := filepath.Join(".", name)
|
||
|
|
dst := filepath.Join(workspaceRoot, name)
|
||
|
|
if err := copyDirIfMissing(src, dst); err != nil {
|
||
|
|
return fmt.Errorf("seed %s failed: %w", name, err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if err := os.MkdirAll(filepath.Join(workspaceRoot, "workspace"), 0o755); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func copyDirIfMissing(src, dst string) error {
|
||
|
|
info, err := os.Stat(src)
|
||
|
|
if err != nil {
|
||
|
|
if os.IsNotExist(err) {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
if !info.IsDir() {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
if err := os.MkdirAll(dst, 0o755); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
return filepath.WalkDir(src, func(path string, d os.DirEntry, walkErr error) error {
|
||
|
|
if walkErr != nil {
|
||
|
|
return walkErr
|
||
|
|
}
|
||
|
|
rel, err := filepath.Rel(src, path)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
target := filepath.Join(dst, rel)
|
||
|
|
if d.IsDir() {
|
||
|
|
return os.MkdirAll(target, 0o755)
|
||
|
|
}
|
||
|
|
if _, err := os.Stat(target); err == nil {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
if err := copyFile(path, target); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func copyFile(src, dst string) error {
|
||
|
|
in, err := os.Open(src)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
defer in.Close()
|
||
|
|
|
||
|
|
if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
out, err := os.Create(dst)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
defer out.Close()
|
||
|
|
|
||
|
|
if _, err := io.Copy(out, in); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return out.Sync()
|
||
|
|
}
|