Skip to content

Commit

Permalink
analysis/build: Add assistant plugin
Browse files Browse the repository at this point in the history
The user can specify an assistant directory with some python code in which is
called in a container with the app directory mounted.

This assistant script can generate or modify code in the app directory
before it is further analysed and ran.
  • Loading branch information
richiejp committed Aug 21, 2024
1 parent 408ca47 commit 10be97e
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 0 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
21 changes: 21 additions & 0 deletions examples/assistants/test/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import os

file_path = '/app/__main__.py'
file_content = """from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.run(debug=True, host="0.0.0.0")
"""

os.makedirs(os.path.dirname(file_path), exist_ok=True)

with open(file_path, 'w') as file:
file.write(file_content)

print(f"File written to {file_path}")
Empty file.
77 changes: 77 additions & 0 deletions go/srv/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,77 @@ func (s *Srv) useDockerfile(ctx context.Context, stream pb.Srv_AnalysisServer) (
return true, nil
}

func (s *Srv) assistantLlb(ctx context.Context) (*llb.Definition, error) {
assLocal := llb.Local("assistant")
appLocal := llb.Local("app")
st := pythonSlimLlb().
File(llb.Mkdir("/assistant", 0755)).
Dir("/assistant")

st = st.File(llb.Copy(assLocal, "requirements.txt", "."))

appMnt := llb.AddMount(
"/app",
appLocal,
)
st = pythonSlimPip(st, "install -r requirements.txt").
File(llb.Copy(assLocal, ".", ".")).
Run(llb.Shlex("python __main__.py"), appMnt).Root()

dt, err := st.Marshal(ctx, llb.LinuxAmd64)
if err != nil {
return nil, terror.Errorf(ctx, "marshal: %w", err)
}

return dt, nil
}

func (s *Srv) callAssistant(ctx context.Context, stream pb.Srv_AnalysisServer, c *client.Client) error {
ctx, span := trace.Span(ctx, "assistant")
defer span.End()

internalError := mkInternalError(ctx, stream)

b := func(ctx context.Context, c gateway.Client) (*gateway.Result, error) {
def, err := s.assistantLlb(ctx)
if err != nil {
return nil, internalError("mkllb: %w", err)
}

r, err := c.Solve(ctx, gateway.SolveRequest{
Definition: def.ToPB(),
})
if err != nil {
return nil, internalError("client solve: %w", err)
}

return r, nil
}

statusChan := buildkitStatusSender(ctx, stream)
assistantFS, err := fsutil.NewFS(s.AssistantDir)
if err != nil {
return internalError("fsutil newfs: %w", err)
}
appFS, err := fsutil.NewFS(s.SrcDir)
if err != nil {
return internalError("fsutil newfs: %w", err)
}

_, err = c.Build(ctx, client.SolveOpt{
LocalMounts: map[string]fsutil.FS{
"assistant": assistantFS,
"app": appFS,
},
}, "ayup", b, statusChan)

if err != nil {
return internalError("client build: %w", err)
}

return nil
}

func (s *Srv) Analysis(stream pb.Srv_AnalysisServer) error {
ctx := stream.Context()
span := tr.SpanFromContext(ctx)
Expand Down Expand Up @@ -101,6 +172,12 @@ func (s *Srv) Analysis(stream pb.Srv_AnalysisServer) error {
return sendError("premature choice")
}

if s.AssistantDir != "" {
if err := s.callAssistant(ctx, stream, c); err != nil {
return err
}
}

requirements_path := filepath.Join(s.SrcDir, "requirements.txt")

if ok, err := s.useDockerfile(ctx, stream); ok || err != nil {
Expand Down

0 comments on commit 10be97e

Please sign in to comment.