MCPcopy
hub / github.com/dagger/dagger / Exec

Method Exec

cmd/dagger/shell_exec.go:152–284  ·  view source on GitHub ↗

Exec is the main handler for executing simple commands. It is called for all [syntax.CallExpr] nodes where the first argument is neither a declared shell function nor a builtin. This handler is responsible to interpreting functions and module references as commands that can be executed, and wraps

(next interp.ExecHandlerFunc)

Source from the content-addressed store, hash-verified

150// This handler is responsible to interpreting functions and module references
151// as commands that can be executed, and wraps any returned errors.
152func (h *shellCallHandler) Exec(next interp.ExecHandlerFunc) interp.ExecHandlerFunc {
153 return func(ctx context.Context, args []string) (rerr error) {
154 // This avoids interpreter builtins running first, which would make it
155 // impossible to have a function named "echo", for example. We can
156 // remove `__dag` from this point onward.
157 if args[0] == shellInternalCmd {
158 args = args[1:]
159 }
160
161 // If argument is a state value, just pass it on to stdout directly.
162 // Example: `$FOO` or `$FOO | bar`
163 if GetStateKey(args[0]) != "" {
164 hctx := interp.HandlerCtx(ctx)
165 fmt.Fprint(hctx.Stdout, args[0])
166 return nil
167 }
168
169 // It's a cascading error if the state from the previous handler in a
170 // pipeline failed.
171 var cascadingErr bool
172
173 // Read stdin. If not nil this will block until the previous handler
174 // has finished. If state is nil here it means it's the first command
175 // in a pipeline (foo | bar).
176 st, err := h.loadInput(ctx, args)
177 if st != nil {
178 cascadingErr = st.IsHandlerError()
179 }
180
181 // Having a span for each handler makes it much easier to debug what
182 // the shell is doing.
183 opts := make([]trace.SpanStartOption, 0, 2)
184 opts = append(opts, trace.WithAttributes(attribute.StringSlice("dagger.io/shell.handler.args", args)))
185 // Don't show span by default unless there's an error or we're debugging
186 // (with `.debug`).
187 if !h.Debug() {
188 opts = append(opts, telemetry.Passthrough())
189 }
190 ctx, span := Tracer().Start(ctx, args[0], opts...)
191 defer telemetry.EndWithCause(span, &rerr)
192
193 defer func() {
194 if cascadingErr {
195 // Early exit if an error is passed through stdin.
196 span.SetAttributes(
197 attribute.Bool(telemetry.CanceledAttr, true),
198 )
199 } else if rerr != nil {
200 // TODO: it's helpful to show the span on error when it's a usage
201 // issue, but if it's from resolving a query it shows the error
202 // twice. Could still be useful though, to pinpoint exactly which
203 // part of the script triggered it.
204 attrs := []attribute.KeyValue{
205 attribute.Bool(telemetry.UIPassthroughAttr, false),
206 }
207 var he *HandlerError
208 if errors.As(rerr, &he) {
209 attrs = append(attrs, attribute.Int("dagger.io/shell.handler.exit", he.ExitCode))

Callers

nothing calls this directly

Calls 15

loadInputMethod · 0.95
DebugMethod · 0.95
cmdMethod · 0.95
SaveMethod · 0.95
SpanLoggerFunction · 0.92
DebugFunction · 0.92
ErrorFunction · 0.92
GetStateKeyFunction · 0.85
NewHandlerErrorFunction · 0.85
IsHandlerErrorMethod · 0.80
SetAttributesMethod · 0.80
TracerFunction · 0.70

Tested by

no test coverage detected