Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -1168,7 +1168,7 @@ func (a *agent) handleManifest(manifestOK *checkpoint) func(ctx context.Context,
// return existing devcontainers but actual container detection
// and creation will be deferred.
a.containerAPI.Init(
agentcontainers.WithManifestInfo(manifest.OwnerName, manifest.WorkspaceName, manifest.AgentName),
agentcontainers.WithManifestInfo(manifest.OwnerName, manifest.WorkspaceName, manifest.AgentName, manifest.Directory),
agentcontainers.WithDevcontainers(manifest.Devcontainers, manifest.Scripts),
agentcontainers.WithSubAgentClient(agentcontainers.NewSubAgentClientFromAPI(a.logger, aAPI)),
)
Expand Down
111 changes: 107 additions & 4 deletions agent/agentcontainers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"encoding/json"
"errors"
"fmt"
"io/fs"
"maps"
"net/http"
"os"
Expand All @@ -21,6 +22,7 @@
"github.com/fsnotify/fsnotify"
"github.com/go-chi/chi/v5"
"github.com/google/uuid"
"github.com/spf13/afero"
"golang.org/x/xerrors"

"cdr.dev/slog"
Expand Down Expand Up @@ -60,6 +62,7 @@
updateInterval time.Duration // Interval for periodic container updates.
logger slog.Logger
watcher watcher.Watcher
fs afero.Fs
execer agentexec.Execer
commandEnv CommandEnv
ccli ContainerCLI
Expand All @@ -71,9 +74,10 @@
subAgentURL string
subAgentEnv []string

ownerName string
workspaceName string
parentAgent string
ownerName string
workspaceName string
parentAgent string
agentDirectory string

mu sync.RWMutex // Protects the following fields.
initDone chan struct{} // Closed by Init.
Expand Down Expand Up @@ -192,11 +196,12 @@

// WithManifestInfo sets the owner name, and workspace name
// for the sub-agent.
func WithManifestInfo(owner, workspace, parentAgent string) Option {
func WithManifestInfo(owner, workspace, parentAgent, agentDirectory string) Option {
return func(api *API) {
api.ownerName = owner
api.workspaceName = workspace
api.parentAgent = parentAgent
api.agentDirectory = agentDirectory
}
}

Expand Down Expand Up @@ -261,6 +266,13 @@
}
}

// WithFileSystem sets the file system used for discovering projects.
func WithFileSystem(fs afero.Fs) Option {

Check failure on line 270 in agent/agentcontainers/api.go

View workflow job for this annotation

GitHub Actions / lint

import-shadowing: The name 'fs' shadows an import name (revive)
return func(api *API) {
api.fs = fs
}
}

// ScriptLogger is an interface for sending devcontainer logs to the
// controlplane.
type ScriptLogger interface {
Expand Down Expand Up @@ -331,6 +343,9 @@
api.watcher = watcher.NewNoop()
}
}
if api.fs == nil {
api.fs = afero.NewOsFs()
}
if api.subAgentClient.Load() == nil {
var c SubAgentClient = noopSubAgentClient{}
api.subAgentClient.Store(&c)
Expand Down Expand Up @@ -375,10 +390,98 @@
api.watcherDone = make(chan struct{})
api.updaterDone = make(chan struct{})

go func() {
if err := api.discoverDevcontainerProjects(); err != nil {
api.logger.Error(api.ctx, "discovering dev container projects", slog.Error(err))
}
}()

go api.watcherLoop()
go api.updaterLoop()
}

func (api *API) discoverDevcontainerProjects() error {
isGitProject, err := afero.DirExists(api.fs, filepath.Join(api.agentDirectory, "/.git"))
if err != nil {
return xerrors.Errorf(".git dir exists: %w", err)
}

// If the agent directory is a git project, we'll search
// the project for any `.devcontainer/devcontainer.json`
// files.
if isGitProject {
return api.discoverDevcontainersInProject(api.agentDirectory)
}

// The agent directory is _not_ a git project, so we'll
// search the top level of the agent directory for any
// git projects, and search those.
entries, err := afero.ReadDir(api.fs, api.agentDirectory)
if err != nil {
return xerrors.Errorf("read agent directory: %w", err)
}

for _, entry := range entries {
if !entry.IsDir() {
continue
}

isGitProject, err = afero.DirExists(api.fs, filepath.Join(api.agentDirectory, entry.Name(), ".git"))
if err != nil {
return xerrors.Errorf(".git dir exists: %w", err)
}

// If this directory is a git project, we'll search
// it for any `.devcontainer/devcontainer.json` files.
if isGitProject {
if err := api.discoverDevcontainersInProject(filepath.Join(api.agentDirectory, entry.Name())); err != nil {
return err
}
}
}

return nil
}

func (api *API) discoverDevcontainersInProject(projectPath string) error {
devcontainerConfigPaths := []string{
"/.devcontainer/devcontainer.json",
"/.devcontainer.json",
}

return afero.Walk(api.fs, projectPath, func(path string, info fs.FileInfo, err error) error {

Check failure on line 452 in agent/agentcontainers/api.go

View workflow job for this annotation

GitHub Actions / lint

unused-parameter: parameter 'info' seems to be unused, consider removing or renaming it as _ (revive)
for _, relativeConfigPath := range devcontainerConfigPaths {
if !strings.HasSuffix(path, relativeConfigPath) {
continue
}

workspaceFolder := strings.TrimSuffix(path, relativeConfigPath)

api.logger.Debug(api.ctx, "discovered dev container project", slog.F("workspace_folder", workspaceFolder))

api.mu.Lock()
if _, found := api.knownDevcontainers[workspaceFolder]; !found {
api.logger.Debug(api.ctx, "adding dev container project", slog.F("workspace_folder", workspaceFolder))

dc := codersdk.WorkspaceAgentDevcontainer{
ID: uuid.New(),
Name: "", // Updated later based on container state.
WorkspaceFolder: workspaceFolder,
ConfigPath: path,
Status: "", // Updated later based on container state.
Dirty: false, // Updated later based on config file changes.
Container: nil,
}

api.knownDevcontainers[workspaceFolder] = dc
}
api.mu.Unlock()
}

return nil
})
}

func (api *API) watcherLoop() {
defer close(api.watcherDone)
defer api.logger.Debug(api.ctx, "watcher loop stopped")
Expand Down
Loading
Loading