From c4d4107bb682f2e5e76c410a90e0b40b78aded4e Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Mon, 2 Sep 2024 20:02:47 -0400 Subject: [PATCH] dev: forward correct environment variables so that vscode breakpoints work --- pkg/runtime/node.go | 151 ++++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 97 deletions(-) diff --git a/pkg/runtime/node.go b/pkg/runtime/node.go index b37ea0525..2c585d88d 100644 --- a/pkg/runtime/node.go +++ b/pkg/runtime/node.go @@ -10,6 +10,7 @@ import ( "os/exec" "path/filepath" "strings" + "sync" "github.com/evanw/esbuild/pkg/api" esbuild "github.com/evanw/esbuild/pkg/api" @@ -20,41 +21,46 @@ import ( type NodeRuntime struct { contexts map[string]esbuild.BuildContext results map[string]esbuild.BuildResult - workers map[string]*NodeWorker - loop *NodeLoop -} - -type NodeLoop struct { - stdout io.ReadCloser - stderr io.ReadCloser - stdin io.WriteCloser - cmd *exec.Cmd } func newNodeRuntime() *NodeRuntime { return &NodeRuntime{ contexts: map[string]esbuild.BuildContext{}, results: map[string]esbuild.BuildResult{}, - workers: map[string]*NodeWorker{}, } } type NodeWorker struct { - workerID string - out io.ReadCloser - in io.WriteCloser - loop *NodeLoop + stdout io.ReadCloser + stderr io.ReadCloser + cmd *exec.Cmd } func (w *NodeWorker) Stop() { - json.NewEncoder(w.loop.stdin).Encode(map[string]interface{}{ - "type": "worker.stop", - "workerID": w.workerID, - }) + // Terminate the whole process group + util.TerminateProcess(w.cmd.Process.Pid) } func (w *NodeWorker) Logs() io.ReadCloser { - return w.out + reader, writer := io.Pipe() + + var wg sync.WaitGroup + wg.Add(2) + go func() { + defer wg.Done() + _, _ = io.Copy(writer, w.stdout) + }() + go func() { + defer wg.Done() + _, _ = io.Copy(writer, w.stderr) + }() + + go func() { + wg.Wait() + defer writer.Close() + }() + + return reader } type NodeProperties struct { @@ -195,85 +201,36 @@ func (r *NodeRuntime) Build(ctx context.Context, input *BuildInput) (*BuildOutpu } func (r *NodeRuntime) Run(ctx context.Context, input *RunInput) (Worker, error) { - if r.loop == nil { - cmd := exec.CommandContext( - ctx, - "node", - "--inspect", - "--enable-source-maps", - filepath.Join( - input.Project.PathPlatformDir(), - "/dist/nodejs-runtime/loop.js", - ), - ) - util.SetProcessGroupID(cmd) - cmd.Cancel = func() error { - return util.TerminateProcess(cmd.Process.Pid) - } - stdin, _ := cmd.StdinPipe() - stdout, _ := cmd.StdoutPipe() - stderr, _ := cmd.StderrPipe() - r.loop = &NodeLoop{ - stdout: stdout, - stderr: stderr, - stdin: stdin, - cmd: cmd, - } - err := cmd.Start() - if err != nil { - return nil, err - } - go func() { - decoder := json.NewDecoder(r.loop.stdout) - for { - var msg map[string]interface{} - err := decoder.Decode(&msg) - if err != nil { - if err == io.EOF { - return - } - slog.Error("node loop error", "err", err) - continue - } - - switch msg["type"] { - case "worker.out": - w := r.workers[msg["workerID"].(string)] - if w != nil { - w.in.Write([]byte(msg["data"].(string))) - } - case "worker.exit": - w := r.workers[msg["workerID"].(string)] - if w != nil { - w.in.Close() - } - } - } - }() - } - env := map[string]string{} - for _, value := range input.Env { - pair := strings.SplitN(value, "=", 2) - if len(pair) == 2 { - env[pair[0]] = pair[1] - } - } - env["AWS_LAMBDA_RUNTIME_API"] = input.Server - json.NewEncoder(r.loop.stdin).Encode(map[string]interface{}{ - "type": "worker.start", - "workerID": input.WorkerID, - "env": env, - "args": []string{filepath.Join(input.Build.Out, input.Build.Handler), input.WorkerID}, - }) - out, in := io.Pipe() - w := &NodeWorker{ - loop: r.loop, - workerID: input.WorkerID, - out: out, - in: in, + cmd := exec.CommandContext( + ctx, + "node", + "--enable-source-maps", + filepath.Join( + input.Project.PathPlatformDir(), + "/dist/nodejs-runtime/index.js", + ), + filepath.Join(input.Build.Out, input.Build.Handler), + input.WorkerID, + ) + util.SetProcessGroupID(cmd) + cmd.Cancel = func() error { + return util.TerminateProcess(cmd.Process.Pid) } - r.workers[input.WorkerID] = w - return w, nil + + cmd.Env = input.Env + cmd.Env = append(cmd.Env, "NODE_OPTIONS="+os.Getenv("NODE_OPTIONS")) + cmd.Env = append(cmd.Env, "VSCODE_INSPECTOR_OPTIONS="+os.Getenv("VSCODE_INSPECTOR_OPTIONS")) + cmd.Env = append(cmd.Env, "AWS_LAMBDA_RUNTIME_API="+input.Server) + slog.Info("starting worker", "env", cmd.Env, "args", cmd.Args) + cmd.Dir = input.Build.Out + stdout, _ := cmd.StdoutPipe() + stderr, _ := cmd.StderrPipe() + cmd.Start() + return &NodeWorker{ + stdout, + stderr, + cmd, + }, nil } func (r *NodeRuntime) Match(runtime string) bool {