Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions root/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fi

# a non-interactive shell (tool runners sourcing rc files, scripts) has no
# prompt to complete, and exec'ing here would seize the tty from the real iris
if [[ -o interactive ]] && [ -t 0 ] && [ -z "$IRIS_PID" ] && [ -z "$IRIS_RESCUE" ]; then
if [[ -o interactive ]] && [ -t 0 ] && [ -z "$IRIS_PID" ] && [ -z "$IRIS_RESCUE" ] && [ -z "$ZSH_EXECUTION_STRING" ]; then
export IRIS_ACTIVE_SHELL="zsh"
if [ -n "$FNM_MULTISHELL_PATH" ]; then
path=(${path:#*fnm_multishells*})
Expand Down Expand Up @@ -84,7 +84,7 @@ fi

# a non-interactive shell (tool runners sourcing rc files, scripts) has no
# prompt to complete, and exec'ing here would seize the tty from the real iris
if [[ $- == *i* ]] && [ -t 0 ] && [ -z "$IRIS_PID" ] && [ -z "$IRIS_RESCUE" ]; then
if [[ $- == *i* ]] && [ -t 0 ] && [ -z "$IRIS_PID" ] && [ -z "$IRIS_RESCUE" ] && [ -z "$BASH_EXECUTION_STRING" ]; then
export IRIS_ACTIVE_SHELL="bash"
if [ -n "$FNM_MULTISHELL_PATH" ]; then
PATH=":$PATH:"
Expand Down Expand Up @@ -134,7 +134,7 @@ if set -q IRIS_PID
end
end

if status is-interactive; and not set -q IRIS_PID; and not set -q IRIS_RESCUE
if status is-interactive; and test -t 0; and not set -q IRIS_PID; and not set -q IRIS_RESCUE
set -gx IRIS_ACTIVE_SHELL "fish"
if set -q FNM_MULTISHELL_PATH
set -gx PATH (string match -v "*fnm_multishells*" $PATH)
Expand Down
29 changes: 29 additions & 0 deletions root/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,32 @@ func TestFishAutosuggestionsFollowGhostTextMode(t *testing.T) {
}
}
}

func TestInitAutostartSkipsExecutionString(t *testing.T) {
guards := map[string]string{
"zsh": `[ -z "$ZSH_EXECUTION_STRING" ]`,
"bash": `[ -z "$BASH_EXECUTION_STRING" ]`,
"fish": "test -t 0",
}

for shell, guard := range guards {
t.Run(shell, func(t *testing.T) {
script := captureInitScript(t, shell)

head, _, found := strings.Cut(script, "exec iris")
if !found {
t.Fatalf("%s init script has no autostart", shell)
}

cond := strings.LastIndex(head, "\nif ")
if cond < 0 {
t.Fatalf("%s autostart is not inside an if", shell)
}

if !strings.Contains(head[cond:], guard) {
t.Fatalf("%s autostart is not guarded by %q:\n%s", shell, guard, head[cond:])
}
})
}
}

90 changes: 90 additions & 0 deletions tests/tui/autostart_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package tui

import (
"bytes"
"context"
"io"
"os/exec"
"testing"
"time"

"github.com/creack/pty"
)

func TestAutostartDoesNotSwallowCommand(t *testing.T) {
bin := binary(t)

t.Run("bash", func(t *testing.T) {
if _, err := exec.LookPath("bash"); err != nil {
t.Skip("bash not installed")
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

initScript, err := exec.CommandContext(ctx, bin, "init", "bash").Output()
if err != nil {
t.Fatalf("iris init bash: %v", err)
}
cmd := exec.CommandContext(ctx, "bash", "--norc", "-i", "-c", string(initScript)+"\necho RAN_BASH_42")
ptmx, err := pty.Start(cmd)
if err != nil {
t.Fatalf("starting bash in pty: %v", err)
}
defer func() { _ = ptmx.Close() }()

var out bytes.Buffer
done := make(chan error, 1)
go func() {
_, errCopy := io.Copy(&out, ptmx)
done <- errCopy
}()

select {
case <-ctx.Done():
_ = cmd.Process.Kill()
t.Fatalf("timed out waiting for bash command, output:\n%s", out.String())
case <-done:
}

if !bytes.Contains(out.Bytes(), []byte("RAN_BASH_42")) {
t.Fatalf("expected output to contain RAN_BASH_42, got:\n%s", out.String())
}
})

t.Run("zsh", func(t *testing.T) {
if _, err := exec.LookPath("zsh"); err != nil {
t.Skip("zsh not installed")
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

initScript, err := exec.CommandContext(ctx, bin, "init", "zsh").Output()
if err != nil {
t.Fatalf("iris init zsh: %v", err)
}
cmd := exec.CommandContext(ctx, "zsh", "-f", "-i", "-c", string(initScript)+"\necho RAN_ZSH_42")
ptmx, err := pty.Start(cmd)
if err != nil {
t.Fatalf("starting zsh in pty: %v", err)
}
defer func() { _ = ptmx.Close() }()

var out bytes.Buffer
done := make(chan error, 1)
go func() {
_, errCopy := io.Copy(&out, ptmx)
done <- errCopy
}()

select {
case <-ctx.Done():
_ = cmd.Process.Kill()
t.Fatalf("timed out waiting for zsh command, output:\n%s", out.String())
case <-done:
}

if !bytes.Contains(out.Bytes(), []byte("RAN_ZSH_42")) {
t.Fatalf("expected output to contain RAN_ZSH_42, got:\n%s", out.String())
}
})
}
Loading