Skip to content

Commit

Permalink
Better handling of terminals that do not respond to queries
Browse files Browse the repository at this point in the history
  • Loading branch information
Nuru committed Dec 29, 2024
1 parent a39ac0e commit 5cf74bb
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 11 deletions.
42 changes: 34 additions & 8 deletions docs/ReleaseNotes-v4.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,70 @@

#### Better Shell Management

##### Equal Treatment for Multiple Shells in a Single Container

A much requested feature, Geodesic no longer exits the container when the first shell exits.
Instead, the container runs until all shells have exited. This means you can now run multiple shells
inside the container, and exit them in any order; you no longer have to keep track of which
shell was the first one launched. Unfortunately, this also means that you can no longer
detach and reattach to a shell.

A side benefit of this is that previously, if did something like `trap handler EXIT` in your
top-level shell, there was a good chance the handler would not run because the shell will
be killed (SIGKILL, `kill -9`) rather than shut down cleanly. Now, there is a much greater
likelihood that the shells will shut down in an orderly manner and run their exit hooks.

##### New Capability for Multiple Shells with One Container per Shell

However, Geodesic now supports another much requested feature: launching a new container
each time you run Geodesic. This is done by setting the `ONE_SHELL` environment variable to "true"
or passing `--one-shell` on the command line. This allows you to run multiple versions of Geodesic,
and also allows you to detach from a shell and reattach to it later.

##### External Command to Stop Geodesic

Not a new feature, but one that many people were not aware of: you can kill the running
Geodesic container with the command `geodesic stop`. This will stop the container, and it
will be automatically removed (assuming you started it with `geodesic`). Now, however,
there is the possibility you will have several running containers. If this is the case
`geodesic stop` will list the running containers by name. You can then pass the
name as an argument to `geodesic stop` and it will stop that one.

##### Cleanup Commands on Shell Exit and Container Exit

Another old feature few people knew about: you can have Geodesic automatically
run a command when a shell exits. This was done by creating an executable command named
`geodesic_on_exit` and putting it in your `$PATH`. This feature has been enhanced
in 2 ways:

1. Now, you can set the name of the command to run when the shell exits via `ON_SHELL_EXIT`
(defaults to `geodesic_on_exit`). Also new: the `ON_SHELL_EXIT` command will have available to it the short ID of the container in which it was running, via the
environment variable `GEODESIC_CONTAINER_EXITING`.
1. Now you can set the name of the command to run when the shell exits via `ON_SHELL_EXIT`
(defaults to `geodesic_on_exit`). Also new: the `ON_SHELL_EXIT` command will have available
to it the short ID and name of the container in which it was running, via the
environment variables `GEODESIC_EXITING_CONTAINER_ID` and `GEODESIC_EXITING_CONTAINER_NAME`,
respectively.
2. You can use the new environment variable `ON_CONTAINER_EXIT` to configure a different
command to run only when the container exits.
command to run only when the container exits. It will also have the container ID and name
available to it via the same environment variables.

Be aware that the commands are called on a best-effort basis when the Geodesic
launch wrapper exits. If you detach from a shell, the wrapper will run then and
call `ON_SHELL_EXIT`. If you reattach to the shell, the wrapper is not involved,
so quitting the shell or container will not run the cleanup command.

Alternately, if you quit 2 shells at nearly the same time, the `ON_CONTAINER_EXIT`
command may be called twice. This is because the wrapper does not know which shell
is the last one to exit; it calls the command when the container has stopped
before shell exit processing has finished.
Alternately, if you quit 2 shells at nearly the same time, for example by
running `geodesic stop`, the `ON_CONTAINER_EXIT` command may be called twice.
This is because the wrapper calls the command when the container has stopped
before shell exit processing has finished, and both shells fit the criterion.

Now that shells normally exit cleanly (pretty much as long as you do not
run `docker kill geodesic`), you may find that you get more reliable behavior
out of

```bash
trap exit_handler EXIT
```

to run on each shell completion.

#### Better Configuration Management

Expand Down
38 changes: 38 additions & 0 deletions rootfs/etc/profile.d/_07-term-mode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,49 @@
#
# At some point we may introduce other methods to determine the terminal's color scheme.

# First, at startup, let's try an OSC query. If we get no response, we will assume light mode
# and disable further queries.

function _verify_terminal_queries_are_supported() {
if tty -s && [[ -n "$(tput setaf 1 2>/dev/null)" ]]; then
local saved_state=$(stty -g)
[[ $GEODESIC_TRACE =~ "terminal" ]] && echo "$(tput setaf 1)* TERMINAL TRACE: Checking if terminal responds to color queries...$(tput sgr0)" >&2
stty -echo
echo -ne '\e]10;?\a\e]11;?\a' >/dev/tty
# If 2 seconds is not enough at startup, then the terminal is either non-responsive or too slow.
IFS=: read -s -t 2 -d $'\a' x fg_rgb
exit_code=$?
[[ $exit_code -gt 128 ]] || exit_code=0
IFS=: read -s -t 0.5 -d $'\a' x bg_rgb
((exit_code += $?))
stty "$saved_state"
if [[ $exit_code -gt 128 ]] || [[ -z $fg_rgb ]] || [[ -z $bg_rgb ]]; then
if [[ $GEODESIC_TRACE =~ "terminal" ]]; then
echo "$(tput setaf 1)* TERMINAL TRACE: Terminal did not respond to OSC 10 and 11 queries. Disabling color mode detection.$(tput sgr0)" >&2
fi
export GEODESIC_TERM_COLOR_AUTO=unsupported
fi
fi
}

_verify_terminal_queries_are_supported

# Normally this function produces no output, but with -b, it outputs "true" or "false",
# with -bb it outputs "true", "false", or "unknown". (Otherwise, unknown assume light mode.)
# With -m it outputs "dark" or "light", with -mm it outputs "dark", "light", or "unknown".
# and always returns true. With -l it outputs integer luminance values for foreground
# and background colors. With -ll it outputs labels on the luminance values as well.
function _is_term_dark_mode() {
[[ ${GEODESIC_TERM_COLOR_AUTO} == "unsupported" ]] && case "$1" in
-b) echo "false" ;;
-bb) echo "unknown" ;;
-m) echo "light" ;;
-mm) echo "unknown" ;;
-l) echo "0 1000000000" ;;
-ll) echo "Foreground luminance: 0, Background luminance: 1000000000" ;;
*) return 1 ;;
esac && return 0

local x fg_rgb bg_rgb fg_lum bg_lum exit_code

# Do not try to auto-detect if we are not in a terminal
Expand All @@ -35,6 +72,7 @@ function _is_term_dark_mode() {
# Timeout of 2 was not enough when waking for sleep.
# The second read should be part of the first response, should not need much time at all regardless.
IFS=: read -s -t 1 -d $'\a' x fg_rgb
exit_code=$?
if [[ $exit_code -gt 128 ]] || [[ -z $fg_rgb ]] && [[ ${GEODESIC_TERM_COLOR_SIGNAL} == "true" ]]; then
IFS=: read -s -t 30 -d $'\a' x fg_rgb
exit_code=$?
Expand Down
9 changes: 7 additions & 2 deletions rootfs/etc/profile.d/_10-colors.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ function update-terminal-color-mode() {
[[ "$quiet" == "true" ]] || echo "No terminal detected." >&2
elif [[ -z "$(tput op 2>/dev/null)" ]]; then
[[ "$quiet" == "true" ]] || echo "Terminal does not appear to support color." >&2
elif [[ ${GEODESIC_TERM_COLOR_AUTO} == "unsupported" ]]; then
[[ "$quiet" == "true" ]] || echo "Terminal does not support color mode detection." >&2
else
[[ "$quiet" == "true" ]] || echo "Terminal did not respond to color queries." >&2
fi
# "light" is historical default for unknown terminals.
new_mode="light"
fi

Expand Down Expand Up @@ -312,8 +317,8 @@ function _update-terminal-color-mode-sigwinch() {
unset GEODESIC_TERM_COLOR_SIGNAL
}

if _is_color_term; then
# We install the trap handler whether GEODESIC_TERM_COLOR_AUTO is set or not,
if [[ ${GEODESIC_TERM_COLOR_AUTO} != "unsupported" ]] && _is_color_term; then
# We install the trap handler whether GEODESIC_TERM_COLOR_AUTO is set to "disabled" or "false",
# because we will not be able to detect the change in that variable if
# it started out disabled and then someone enables it.

Expand Down
3 changes: 2 additions & 1 deletion rootfs/templates/wrapper-body.sh
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ function _on_shell_exit() {
}

function _on_container_exit() {
export GEODESIC_CONTAINER_EXITING="${CONTAINER_ID:0:12}"
export GEODESIC_EXITING_CONTAINER_ID="${CONTAINER_ID:0:12}"
export GEODESIC_EXITING_CONTAINER_NAME="${DOCKER_NAME}"
_on_shell_exit
[ -n "${ON_CONTAINER_EXIT}" ] && command -v "${ON_CONTAINER_EXIT}" >/dev/null && "${ON_CONTAINER_EXIT}"
}
Expand Down

0 comments on commit 5cf74bb

Please sign in to comment.