# component.exec

The `exec` method of a component handle runs a program in the component's own directory, with the component's
environment applied. Use it instead of guessing a path from a component name.

## Usage

The method is available on the handle returned by [`components.get`](/functions/automation/components.get) and on
[`ctx.component`](/functions/automation/ctx.component):

```python
component.exec(argv, working_directory = ..., env = ..., output = "stream", check = True, timeout = "", retry = None)
```

## Arguments

The method takes the same arguments as [`exec.run`](/functions/automation/exec.run#arguments), with different
defaults for the directory and environment.

- **`argv`**
  Required. A non-empty list or tuple of strings: the program and its arguments, run without a shell.
- **`working_directory`**

  (Optional) Defaults to the component's directory, which is the handle's `path`. A relative path resolves
  against the component directory.
- **`env`**

  (Optional) Extra environment variables for this call. They are applied last, so they override everything
  else.
- **`output`**
  (Optional) 
  `"stream"`
   (the default) or 
  `"capture"`
  .
- **`check`**
  (Optional) Defaults to 
  `True`
  : a nonzero exit code raises an error.

## Environment layering

The program inherits the invocation's execution environment, and Atmos then layers, in this order:

1. The component's `env` section.
2. For a hook, the hook's environment overrides.
3. The command or step overrides in effect for the script.
4. The script's [`env`](/functions/automation/env) inputs.
5. The `env` argument of the call.

Each layer replaces variables of the same name from the layers before it.

The `timeout` and `retry` options apply to this individual process call:

- **`timeout`**
  A positive duration such as 
  `"30s"`
   or 
  `"5m"`
  . It bounds the entire call,
  including all attempts and retry delays. Omit it for no additional deadline;
  an enclosing task or script can still cancel the call.
- **`retry`**
  A dictionary using the same policy fields as

  [`steps.task`](/functions/automation/steps.task#retry-policy)
  , including

  `max_attempts`
  , 
  `initial_delay`
  , and 
  `backoff_strategy`
  . Optional 
  `conditions`

  are regular expressions matched against the failed attempt's stdout and stderr.
  At least one must match when supplied. Omit the policy to run once.

Only ordinary nonzero exits are retried. Cancellation, timeout, failure to start,
signals, and I/O errors stop the call. With `check=False`, an ordinary nonzero exit
is returned immediately and does not trigger retries. Captured output contains
only the final attempt; streaming displays each attempt as it runs. Retrying
repeats the command's effects, so use it only for operations safe to repeat.
Set `max_attempts` or `timeout` to bound a retry policy.

## Returns

A result with `stdout`, `stderr`, and `exit_code`. See [`exec.run`](/functions/automation/exec.run#returns) for the
shared behavior of streaming, capturing, and failure handling.

## Examples

### Run a script that ships with the component

```python
api = components.get("api", "dev", "container")
api.exec(["./smoke-test", "--strict"])
```

### Capture output from the component directory

```python
station = components.get("station", "dev", "terraform")
files = station.exec(["ls", "-1"], output = "capture").stdout.splitlines()
print(files)
```

### Use the component in a hook

```python
def post_apply():
    if ctx.operation.status != "success":
        return
    ctx.component.exec(ctx.component.settings.get("smoke_command", ["./smoke-test"]))
    ui.success("Smoke tests passed for " + ctx.component.name)

post_apply()
```

### Run in every stack

```python
def smoke(stack):
    return components.get("api", stack, "container").exec(["./smoke-test"], output = "capture").exit_code

output = steps.parallel(
    tasks = [steps.task(name = s, function = smoke, args = [s]) for s in ["dev", "prod"]],
)
```

## Related

- [`components.get`](/functions/automation/components.get) returns the handle.
- [`ctx.component`](/functions/automation/ctx.component) is the handle already in scope in commands and hooks.
- [`exec.run`](/functions/automation/exec.run) runs a program from the script's own working directory.
- [Atmos Automation Language](/automation/language) and the [script step](/steps/type/script#custom-components)
