@background_app.command(
context_settings={
# Allow extra arguments for user provided command
"allow_extra_args": True,
"ignore_unknown_options": True,
}
)
def run(
ctx: typer.Context,
*,
pid_file: Path = typer.Option( # noqa: B008
Path("./.aws-annoying.pid"),
help="The path to the PID file to store the process ID of the background command.",
),
terminate_running_process: bool = typer.Option(
False, # noqa: FBT003
help="Terminate the process in the PID file if it already exists.",
),
log_file: Path = typer.Option( # noqa: B008
Path("./.aws-annoying.log"),
help="The path to the log file to store the output of the background command.",
),
) -> None:
r"""Run a command in the background detached from the current terminal.
Examples:
- Run a port-forwarding command in the background and store its PID in a file:
```bash
$ aws-annoying background run \
--pid-file ./session.pid \
--terminate-running-process \
-- session-manager port-forward \
...
```
"""
command = ctx.args
if not command:
logger.error("No command specified to run in the background.")
raise typer.Exit(1)
# NOTE: This(background run) is a wrapper around the main CLI command
command = [sys.executable, "-m", "aws_annoying._cli.main", *command]
if terminate_running_process and pid_file.exists():
terminate_process_by_pid_file(pid_file, remove=True)
_claim_pid_file(pid_file)
try:
with log_file.open(mode="at+", buffering=1) as stdout:
logger.info("Starting background process: %s", " ".join(command))
pid = _spawn_process(command, stdout=stdout)
logger.info("Process started with PID %d. Outputs will be logged to %s.", pid, log_file.absolute())
# Write the PID to the PID file after the process has started successfully
pid_file.write_text(str(pid))
logger.info("PID file written to %s.", pid_file.absolute())
except Exception:
pid_file.unlink(missing_ok=True)
raise