(ctx context.Context, envOpts devopt.EnvOptions, cmdName string, cmdArgs []string)
| 261 | } |
| 262 | |
| 263 | func (d *Devbox) RunScript(ctx context.Context, envOpts devopt.EnvOptions, cmdName string, cmdArgs []string) error { |
| 264 | ctx, task := trace.NewTask(ctx, "devboxRun") |
| 265 | defer task.End() |
| 266 | |
| 267 | if err := shellgen.WriteScriptsToFiles(d); err != nil { |
| 268 | return err |
| 269 | } |
| 270 | |
| 271 | lock.SetIgnoreShellMismatch(true) |
| 272 | |
| 273 | var env map[string]string |
| 274 | if d.IsEnvEnabled() { |
| 275 | // Skip ensureStateIsUpToDate if we are already in a shell of this devbox-project |
| 276 | env = envir.PairsToMap(os.Environ()) |
| 277 | |
| 278 | // We set this to ensure that init-hooks do NOT re-run. They would have |
| 279 | // run when initializing the Devbox Environment in the current shell. |
| 280 | env[d.SkipInitHookEnvName()] = "true" |
| 281 | } else { |
| 282 | var err error |
| 283 | env, err = d.ensureStateIsUpToDateAndComputeEnv(ctx, envOpts) |
| 284 | if err != nil { |
| 285 | return err |
| 286 | } |
| 287 | } |
| 288 | |
| 289 | // Used to determine whether we're inside a shell (e.g. to prevent shell inception) |
| 290 | // This is temporary because StartServices() needs it but should be replaced with |
| 291 | // better alternative since devbox run and devbox shell are not the same. |
| 292 | env["DEVBOX_SHELL_ENABLED"] = "1" |
| 293 | |
| 294 | // wrap the arg in double-quotes, and escape any double-quotes inside it. |
| 295 | // |
| 296 | // TODO(gcurtis): this breaks quote-removal in parameter expansion, |
| 297 | // command substitution, and arithmetic expansion: |
| 298 | // |
| 299 | // $ unset x |
| 300 | // $ echo ${x:-"my file"} |
| 301 | // my file |
| 302 | // $ devbox run -- echo '${x:-"my file"}' |
| 303 | // "my file" |
| 304 | for idx, arg := range cmdArgs { |
| 305 | cmdArgs[idx] = strconv.Quote(arg) |
| 306 | } |
| 307 | |
| 308 | var cmdWithArgs []string |
| 309 | if _, ok := d.cfg.Scripts()[cmdName]; ok { |
| 310 | // it's a script, so replace the command with the script file's path. |
| 311 | script := shellgen.ScriptPath(d.ProjectDir(), cmdName) |
| 312 | cmdWithArgs = append([]string{strconv.Quote(script)}, cmdArgs...) |
| 313 | } else { |
| 314 | // Arbitrary commands should also run the hooks, so we write them to a file as well. However, if the |
| 315 | // command args include env variable evaluations, then they'll be evaluated _before_ the hooks run, |
| 316 | // which we don't want. So, one solution is to write the entire command and its arguments into the |
| 317 | // file itself, but that may not be great if the variables contain sensitive information. Instead, |
| 318 | // we save the entire command (with args) into the DEVBOX_RUN_CMD var, and then the script evals it. |
| 319 | // |
| 320 | // If cmdName is an alias defined in devbox.json, expand it to its command |
no test coverage detected