Skip to content

Commit

Permalink
--tmux: Export bash functions
Browse files Browse the repository at this point in the history
Fix #4001
  • Loading branch information
junegunn committed Sep 29, 2024
1 parent 53bcdc4 commit 4161403
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 23 deletions.
22 changes: 17 additions & 5 deletions src/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os/exec"
"os/signal"
"path/filepath"
"regexp"
"strings"
"time"

Expand All @@ -32,7 +33,7 @@ func fifo(name string) (string, error) {
return output, nil
}

func runProxy(commandPrefix string, cmdBuilder func(temp string) *exec.Cmd, opts *Options, withExports bool) (int, error) {
func runProxy(commandPrefix string, cmdBuilder func(temp string, needBash bool) (*exec.Cmd, error), opts *Options, withExports bool) (int, error) {
output, err := fifo("proxy-output")
if err != nil {
return ExitError, err
Expand Down Expand Up @@ -92,17 +93,28 @@ func runProxy(commandPrefix string, cmdBuilder func(temp string) *exec.Cmd, opts
// To ensure that the options are processed by a POSIX-compliant shell,
// we need to write the command to a temporary file and execute it with sh.
var exports []string
needBash := false
if withExports {
exports = os.Environ()
for idx, pairStr := range exports {
validIdentifier := regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
for _, pairStr := range os.Environ() {
pair := strings.SplitN(pairStr, "=", 2)
exports[idx] = fmt.Sprintf("export %s=%s", pair[0], escapeSingleQuote(pair[1]))
if validIdentifier.MatchString(pair[0]) {
exports = append(exports, fmt.Sprintf("export %s=%s", pair[0], escapeSingleQuote(pair[1])))
} else if strings.HasPrefix(pair[0], "BASH_FUNC_") && strings.HasSuffix(pair[0], "%%") {
name := pair[0][10 : len(pair[0])-2]
exports = append(exports, name+pair[1])
exports = append(exports, "export -f "+name)
needBash = true
}
}
}
temp := WriteTemporaryFile(append(exports, command), "\n")
defer os.Remove(temp)

cmd := cmdBuilder(temp)
cmd, err := cmdBuilder(temp, needBash)
if err != nil {
return ExitError, err
}
cmd.Stderr = os.Stderr
intChan := make(chan os.Signal, 1)
defer close(intChan)
Expand Down
5 changes: 4 additions & 1 deletion src/proxy_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import (
"golang.org/x/sys/unix"
)

func sh() (string, error) {
func sh(bash bool) (string, error) {
if bash {
return "bash", nil
}
return "sh", nil
}

Expand Down
14 changes: 9 additions & 5 deletions src/proxy_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@ import (

var shPath atomic.Value

func sh() (string, error) {
func sh(bash bool) (string, error) {
if cached := shPath.Load(); cached != nil {
return cached.(string), nil
}

cmd := exec.Command("cygpath", "-w", "/usr/bin/sh")
name := "sh"
if bash {
name = "bash"
}
cmd := exec.Command("cygpath", "-w", "/usr/bin/"+name)
bytes, err := cmd.Output()
if err != nil {
return "", err
Expand All @@ -31,7 +35,7 @@ func sh() (string, error) {

func mkfifo(path string, mode uint32) (string, error) {
m := strconv.FormatUint(uint64(mode), 8)
sh, err := sh()
sh, err := sh(false)
if err != nil {
return path, err
}
Expand All @@ -43,7 +47,7 @@ func mkfifo(path string, mode uint32) (string, error) {
}

func withOutputPipe(output string, task func(io.ReadCloser)) error {
sh, err := sh()
sh, err := sh(false)
if err != nil {
return err
}
Expand All @@ -62,7 +66,7 @@ func withOutputPipe(output string, task func(io.ReadCloser)) error {
}

func withInputPipe(input string, task func(io.WriteCloser)) error {
sh, err := sh()
sh, err := sh(false)
if err != nil {
return err
}
Expand Down
9 changes: 6 additions & 3 deletions src/tmux.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,12 @@ func runTmux(args []string, opts *Options) (int, error) {
tmuxArgs = append(tmuxArgs, "-w"+opts.Tmux.width.String())
tmuxArgs = append(tmuxArgs, "-h"+opts.Tmux.height.String())

return runProxy(argStr, func(temp string) *exec.Cmd {
sh, _ := sh()
return runProxy(argStr, func(temp string, needBash bool) (*exec.Cmd, error) {
sh, err := sh(needBash)
if err != nil {
return nil, err
}
tmuxArgs = append(tmuxArgs, sh, temp)
return exec.Command("tmux", tmuxArgs...)
return exec.Command("tmux", tmuxArgs...), nil
}, opts, true)
}
23 changes: 14 additions & 9 deletions src/winpty_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,32 +44,37 @@ func needWinpty(opts *Options) bool {
}

func runWinpty(args []string, opts *Options) (int, error) {
sh, err := sh()
if err != nil {
return ExitError, err
}

argStr := escapeSingleQuote(args[0])
for _, arg := range args[1:] {
argStr += " " + escapeSingleQuote(arg)
}
argStr += ` --no-winpty`

if isMintty345() {
return runProxy(argStr, func(temp string) *exec.Cmd {
return runProxy(argStr, func(temp string, needBash bool) (*exec.Cmd, error) {
sh, err := sh(needBash)
if err != nil {
return nil, err
}

cmd := exec.Command(sh, temp)
cmd.Env = append(os.Environ(), "MSYS=enable_pcon")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd
return cmd, nil
}, opts, false)
}

return runProxy(argStr, func(temp string) *exec.Cmd {
return runProxy(argStr, func(temp string, needBash bool) (*exec.Cmd, error) {
sh, err := sh(needBash)
if err != nil {
return nil, err
}

cmd := exec.Command(sh, "-c", fmt.Sprintf(`winpty < /dev/tty > /dev/tty -- sh %q`, temp))
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd
return cmd, nil
}, opts, false)
}

0 comments on commit 4161403

Please sign in to comment.