mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-22 16:48:23 +01:00
Powershell Wsh Integration (#320)
Add wsh to the path in powershell. Should work locally and in remote connections. Should work on both windows and unix systems.
This commit is contained in:
parent
4e60880b8f
commit
b3a7c466e5
@ -212,7 +212,16 @@ func (conn *SSHConn) StartConnServer() error {
|
|||||||
pipeRead, pipeWrite := io.Pipe()
|
pipeRead, pipeWrite := io.Pipe()
|
||||||
sshSession.Stdout = pipeWrite
|
sshSession.Stdout = pipeWrite
|
||||||
sshSession.Stderr = pipeWrite
|
sshSession.Stderr = pipeWrite
|
||||||
cmdStr := fmt.Sprintf("%s=\"%s\" %s connserver", wshutil.WaveJwtTokenVarName, jwtToken, wshPath)
|
shellPath, err := remote.DetectShell(client)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var cmdStr string
|
||||||
|
if remote.IsPowershell(shellPath) {
|
||||||
|
cmdStr = fmt.Sprintf("$env:%s=\"%s\"; %s connserver", wshutil.WaveJwtTokenVarName, jwtToken, wshPath)
|
||||||
|
} else {
|
||||||
|
cmdStr = fmt.Sprintf("%s=\"%s\" %s connserver", wshutil.WaveJwtTokenVarName, jwtToken, wshPath)
|
||||||
|
}
|
||||||
log.Printf("starting conn controller: %s\n", cmdStr)
|
log.Printf("starting conn controller: %s\n", cmdStr)
|
||||||
err = sshSession.Start(cmdStr)
|
err = sshSession.Start(cmdStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -311,10 +311,25 @@ func GetHomeDir(client *ssh.Client) string {
|
|||||||
return "~"
|
return "~"
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := session.Output("pwd")
|
out, err := session.Output(`echo "$HOME"`)
|
||||||
|
if err == nil {
|
||||||
|
return strings.TrimSpace(string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
session, err = client.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "~"
|
return "~"
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(string(out))
|
out, err = session.Output(`echo %userprofile%`)
|
||||||
|
if err == nil {
|
||||||
|
return strings.TrimSpace(string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
return "~"
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsPowershell(shellPath string) bool {
|
||||||
|
// get the base path, and then check contains
|
||||||
|
shellBase := filepath.Base(shellPath)
|
||||||
|
return strings.Contains(shellBase, "powershell") || strings.Contains(shellBase, "pwsh")
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -91,18 +89,6 @@ func ExitCodeFromWaitErr(err error) int {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setBoolConditionally(rval reflect.Value, field string, value bool) {
|
|
||||||
if rval.Elem().FieldByName(field).IsValid() {
|
|
||||||
rval.Elem().FieldByName(field).SetBool(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setSysProcAttrs(cmd *exec.Cmd) {
|
|
||||||
rval := reflect.ValueOf(cmd.SysProcAttr)
|
|
||||||
setBoolConditionally(rval, "Setsid", true)
|
|
||||||
setBoolConditionally(rval, "Setctty", true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkCwd(cwd string) error {
|
func checkCwd(cwd string) error {
|
||||||
if cwd == "" {
|
if cwd == "" {
|
||||||
return fmt.Errorf("cwd is empty")
|
return fmt.Errorf("cwd is empty")
|
||||||
@ -113,8 +99,6 @@ func checkCwd(cwd string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var userHostRe = regexp.MustCompile(`^([a-zA-Z0-9][a-zA-Z0-9._@\\-]*@)?([a-z0-9][a-z0-9.-]*)(?::([0-9]+))?$`)
|
|
||||||
|
|
||||||
type PipePty struct {
|
type PipePty struct {
|
||||||
remoteStdinWrite *os.File
|
remoteStdinWrite *os.File
|
||||||
remoteStdoutRead *os.File
|
remoteStdoutRead *os.File
|
||||||
@ -174,6 +158,10 @@ func StartRemoteShellProc(termSize waveobj.TermSize, cmdStr string, cmdOpts Comm
|
|||||||
// add --rcfile
|
// add --rcfile
|
||||||
// cant set -l or -i with --rcfile
|
// cant set -l or -i with --rcfile
|
||||||
shellOpts = append(shellOpts, "--rcfile", fmt.Sprintf(`"%s"/.waveterm/bash-integration/.bashrc`, homeDir))
|
shellOpts = append(shellOpts, "--rcfile", fmt.Sprintf(`"%s"/.waveterm/bash-integration/.bashrc`, homeDir))
|
||||||
|
} else if remote.IsPowershell(shellPath) {
|
||||||
|
// powershell is weird about quoted path executables and requires an ampersand first
|
||||||
|
shellPath = "& " + shellPath
|
||||||
|
shellOpts = append(shellOpts, "-NoExit", "-File", homeDir+"/.waveterm/pwsh-integration/wavepwsh.ps1")
|
||||||
} else {
|
} else {
|
||||||
if cmdOpts.Login {
|
if cmdOpts.Login {
|
||||||
shellOpts = append(shellOpts, "-l")
|
shellOpts = append(shellOpts, "-l")
|
||||||
@ -241,7 +229,12 @@ func StartRemoteShellProc(termSize waveobj.TermSize, cmdStr string, cmdOpts Comm
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("no jwt token provided to connection")
|
return nil, fmt.Errorf("no jwt token provided to connection")
|
||||||
}
|
}
|
||||||
cmdCombined = fmt.Sprintf(`%s=%s %s`, wshutil.WaveJwtTokenVarName, jwtToken, cmdCombined)
|
|
||||||
|
if remote.IsPowershell(shellPath) {
|
||||||
|
cmdCombined = fmt.Sprintf(`$env:%s="%s"; %s`, wshutil.WaveJwtTokenVarName, jwtToken, cmdCombined)
|
||||||
|
} else {
|
||||||
|
cmdCombined = fmt.Sprintf(`%s=%s %s`, wshutil.WaveJwtTokenVarName, jwtToken, cmdCombined)
|
||||||
|
}
|
||||||
|
|
||||||
session.RequestPty("xterm-256color", termSize.Rows, termSize.Cols, nil)
|
session.RequestPty("xterm-256color", termSize.Rows, termSize.Cols, nil)
|
||||||
|
|
||||||
@ -277,7 +270,9 @@ func StartShellProc(termSize waveobj.TermSize, cmdStr string, cmdOpts CommandOpt
|
|||||||
// add --rcfile
|
// add --rcfile
|
||||||
// cant set -l or -i with --rcfile
|
// cant set -l or -i with --rcfile
|
||||||
shellOpts = append(shellOpts, "--rcfile", shellutil.GetBashRcFileOverride())
|
shellOpts = append(shellOpts, "--rcfile", shellutil.GetBashRcFileOverride())
|
||||||
} else if runtime.GOOS != "windows" {
|
} else if remote.IsPowershell(shellPath) {
|
||||||
|
shellOpts = append(shellOpts, "-NoExit", "-File", shellutil.GetWavePowershellEnv())
|
||||||
|
} else {
|
||||||
if cmdOpts.Login {
|
if cmdOpts.Login {
|
||||||
shellOpts = append(shellOpts, "-l")
|
shellOpts = append(shellOpts, "-l")
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ const AppPathBinDir = "bin"
|
|||||||
const (
|
const (
|
||||||
ZshIntegrationDir = "zsh-integration"
|
ZshIntegrationDir = "zsh-integration"
|
||||||
BashIntegrationDir = "bash-integration"
|
BashIntegrationDir = "bash-integration"
|
||||||
|
PwshIntegrationDir = "pwsh-integration"
|
||||||
WaveHomeBinDir = "bin"
|
WaveHomeBinDir = "bin"
|
||||||
|
|
||||||
ZshStartup_Zprofile = `
|
ZshStartup_Zprofile = `
|
||||||
@ -77,6 +78,12 @@ elif [ -f ~/.profile ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
export PATH={{.WSHBINDIR}}:$PATH
|
export PATH={{.WSHBINDIR}}:$PATH
|
||||||
|
`
|
||||||
|
PwshStartup_wavepwsh = `
|
||||||
|
# no need to source regular profiles since we cannot
|
||||||
|
# overwrite those with powershell. Instead we will source
|
||||||
|
# this file with -NoExit
|
||||||
|
$env:PATH = "{{.WSHBINDIR}}" + "{{.PATHSEP}}" + $env:PATH
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -194,6 +201,10 @@ func GetBashRcFileOverride() string {
|
|||||||
return filepath.Join(wavebase.GetWaveHomeDir(), BashIntegrationDir, ".bashrc")
|
return filepath.Join(wavebase.GetWaveHomeDir(), BashIntegrationDir, ".bashrc")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetWavePowershellEnv() string {
|
||||||
|
return filepath.Join(wavebase.GetWaveHomeDir(), PwshIntegrationDir, "wavepwsh.ps1")
|
||||||
|
}
|
||||||
|
|
||||||
func GetZshZDotDir() string {
|
func GetZshZDotDir() string {
|
||||||
return filepath.Join(wavebase.GetWaveHomeDir(), ZshIntegrationDir)
|
return filepath.Join(wavebase.GetWaveHomeDir(), ZshIntegrationDir)
|
||||||
}
|
}
|
||||||
@ -218,6 +229,11 @@ func InitRcFiles(waveHome string, wshBinDir string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
pwshDir := filepath.Join(waveHome, PwshIntegrationDir)
|
||||||
|
err = wavebase.CacheEnsureDir(pwshDir, PwshIntegrationDir, 0755, PwshIntegrationDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// write files to directory
|
// write files to directory
|
||||||
zprofilePath := filepath.Join(zshDir, ".zprofile")
|
zprofilePath := filepath.Join(zshDir, ".zprofile")
|
||||||
@ -243,6 +259,16 @@ func InitRcFiles(waveHome string, wshBinDir string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error writing bash-integration .bashrc: %v", err)
|
return fmt.Errorf("error writing bash-integration .bashrc: %v", err)
|
||||||
}
|
}
|
||||||
|
var pathSep string
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
pathSep = ";"
|
||||||
|
} else {
|
||||||
|
pathSep = ":"
|
||||||
|
}
|
||||||
|
err = utilfn.WriteTemplateToFile(filepath.Join(pwshDir, "wavepwsh.ps1"), PwshStartup_wavepwsh, map[string]string{"WSHBINDIR": toPwshEnvVarRef(wshBinDir), "PATHSEP": pathSep})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error writing pwsh-integration wavepwsh.ps1: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -282,3 +308,7 @@ func initCustomShellStartupFilesInternal() error {
|
|||||||
func computeWshBaseName() string {
|
func computeWshBaseName() string {
|
||||||
return fmt.Sprintf("wsh-%s-%s.%s", wavebase.WaveVersion, runtime.GOOS, runtime.GOARCH)
|
return fmt.Sprintf("wsh-%s-%s.%s", wavebase.WaveVersion, runtime.GOOS, runtime.GOARCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toPwshEnvVarRef(input string) string {
|
||||||
|
return strings.Replace(input, "$", "$env:", -1)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user