mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-04 18:59:08 +01:00
* logging and add a flag to debug returnstate file * fix for issue #368. clean up more zsh options. force global_rcs to be off.
This commit is contained in:
parent
7bf1a259a2
commit
a1ab25936e
@ -37,7 +37,8 @@ const LogFileName = "mshell.log"
|
|||||||
const ForceDebugLog = false
|
const ForceDebugLog = false
|
||||||
|
|
||||||
const DebugFlag_LogRcFile = "logrc"
|
const DebugFlag_LogRcFile = "logrc"
|
||||||
const LogRcFileName = "debug.rcfile"
|
const DebugRcFileName = "debug.rcfile"
|
||||||
|
const DebugReturnStateFileName = "debug.returnstate"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ProcessType_Unknown = "unknown"
|
ProcessType_Unknown = "unknown"
|
||||||
@ -175,7 +176,12 @@ func HasDebugFlag(envMap map[string]string, flagName string) bool {
|
|||||||
|
|
||||||
func GetDebugRcFileName() string {
|
func GetDebugRcFileName() string {
|
||||||
msHome := GetMShellHomeDir()
|
msHome := GetMShellHomeDir()
|
||||||
return path.Join(msHome, LogRcFileName)
|
return path.Join(msHome, DebugRcFileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDebugReturnStateFileName() string {
|
||||||
|
msHome := GetMShellHomeDir()
|
||||||
|
return path.Join(msHome, DebugReturnStateFileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetHomeDir() string {
|
func GetHomeDir() string {
|
||||||
|
@ -6,6 +6,7 @@ package shellapi
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -20,6 +21,7 @@ import (
|
|||||||
"github.com/wavetermdev/waveterm/waveshell/pkg/shellenv"
|
"github.com/wavetermdev/waveterm/waveshell/pkg/shellenv"
|
||||||
"github.com/wavetermdev/waveterm/waveshell/pkg/statediff"
|
"github.com/wavetermdev/waveterm/waveshell/pkg/statediff"
|
||||||
"github.com/wavetermdev/waveterm/waveshell/pkg/utilfn"
|
"github.com/wavetermdev/waveterm/waveshell/pkg/utilfn"
|
||||||
|
"github.com/wavetermdev/waveterm/waveshell/pkg/wlog"
|
||||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbase"
|
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbase"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -56,7 +58,7 @@ var ZshIgnoreVars = map[string]bool{
|
|||||||
"langinfo": true,
|
"langinfo": true,
|
||||||
"keymaps": true,
|
"keymaps": true,
|
||||||
"widgets": true,
|
"widgets": true,
|
||||||
|
"options": true,
|
||||||
"aliases": true,
|
"aliases": true,
|
||||||
"dis_aliases": true,
|
"dis_aliases": true,
|
||||||
"saliases": true,
|
"saliases": true,
|
||||||
@ -86,6 +88,34 @@ var ZshIgnoreVars = map[string]bool{
|
|||||||
"_postpatcomps": true,
|
"_postpatcomps": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only options we restore (other than ZshForceOptions)
|
||||||
|
var ZshIgnoreOptions = map[string]bool{
|
||||||
|
"globalrcs": true, // must stay off (otherwise /etc/zprofile runs)
|
||||||
|
"ksharrays": true,
|
||||||
|
"kshtypeset": true,
|
||||||
|
"kshautoload": true,
|
||||||
|
"kshzerosubscript": true,
|
||||||
|
"interactive": true,
|
||||||
|
"login": true,
|
||||||
|
"zle": true,
|
||||||
|
"shinstdin": true,
|
||||||
|
"privileged": true,
|
||||||
|
"restricted": true,
|
||||||
|
"singlecommand": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// force these options on/off at beginning of rcfile
|
||||||
|
var ZshForceOptions = map[string]bool{
|
||||||
|
"globalrcs": false,
|
||||||
|
"ksharrays": false,
|
||||||
|
"kshtypeset": false,
|
||||||
|
"kshautoload": false,
|
||||||
|
"kshzerosubscript": false,
|
||||||
|
"xtrace": false, // not in ZshIgnoreOptions
|
||||||
|
"verbose": false, // not in ZshIgnoreOptions
|
||||||
|
"debugbeforecmd": false, // not in ZshIgnoreOptions
|
||||||
|
}
|
||||||
|
|
||||||
var ZshUniqueArrayVars = map[string]bool{
|
var ZshUniqueArrayVars = map[string]bool{
|
||||||
"path": true,
|
"path": true,
|
||||||
"fpath": true,
|
"fpath": true,
|
||||||
@ -101,6 +131,11 @@ var ZshUnsetVars = []string{
|
|||||||
"ZSH_EXECUTION_STRING",
|
"ZSH_EXECUTION_STRING",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ZshLoadMods = []string{
|
||||||
|
"zsh/parameter",
|
||||||
|
"zsh/langinfo",
|
||||||
|
}
|
||||||
|
|
||||||
// do not use these directly, call GetLocalMajorVersion()
|
// do not use these directly, call GetLocalMajorVersion()
|
||||||
var localZshMajorVersionOnce = &sync.Once{}
|
var localZshMajorVersionOnce = &sync.Once{}
|
||||||
var localZshMajorVersion = ""
|
var localZshMajorVersion = ""
|
||||||
@ -223,10 +258,19 @@ func isZshSafeNameStr(name string) bool {
|
|||||||
func (z zshShellApi) MakeRcFileStr(pk *packet.RunPacketType) string {
|
func (z zshShellApi) MakeRcFileStr(pk *packet.RunPacketType) string {
|
||||||
var rcBuf bytes.Buffer
|
var rcBuf bytes.Buffer
|
||||||
rcBuf.WriteString(z.GetBaseShellOpts() + "\n")
|
rcBuf.WriteString(z.GetBaseShellOpts() + "\n")
|
||||||
rcBuf.WriteString("unsetopt GLOBAL_RCS\n")
|
// rcBuf.WriteString("echo 'running generated rcfile' $0 $ZSH_ARGZERO '|' $ZDOTDIR\n")
|
||||||
rcBuf.WriteString("unset KSH_ARRAYS\n")
|
|
||||||
rcBuf.WriteString("zmodload zsh/parameter\n")
|
|
||||||
varDecls := shellenv.VarDeclsFromState(pk.State)
|
varDecls := shellenv.VarDeclsFromState(pk.State)
|
||||||
|
// force options come at the beginning of the file (other options come at the end)
|
||||||
|
for optName, optVal := range ZshForceOptions {
|
||||||
|
if optVal {
|
||||||
|
rcBuf.WriteString(fmt.Sprintf("setopt %s\n", optName))
|
||||||
|
} else {
|
||||||
|
rcBuf.WriteString(fmt.Sprintf("unsetopt %s\n", optName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, modName := range ZshLoadMods {
|
||||||
|
rcBuf.WriteString(fmt.Sprintf("zmodload %s\n", modName))
|
||||||
|
}
|
||||||
var postDecls []*shellenv.DeclareDeclType
|
var postDecls []*shellenv.DeclareDeclType
|
||||||
for _, varDecl := range varDecls {
|
for _, varDecl := range varDecls {
|
||||||
if ZshIgnoreVars[varDecl.Name] {
|
if ZshIgnoreVars[varDecl.Name] {
|
||||||
@ -294,16 +338,37 @@ func (z zshShellApi) MakeRcFileStr(pk *packet.RunPacketType) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// write postdecls
|
// write postdecls
|
||||||
for _, varDecl := range postDecls {
|
for _, varDecl := range postDecls {
|
||||||
rcBuf.WriteString(makeZshTypesetStmt(varDecl))
|
rcBuf.WriteString(makeZshTypesetStmt(varDecl))
|
||||||
rcBuf.WriteString("\n")
|
rcBuf.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
writeZshOptions(&rcBuf, varDecls)
|
||||||
return rcBuf.String()
|
return rcBuf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writeZshOptions(rcBuf *bytes.Buffer, declArr []*shellenv.DeclareDeclType) {
|
||||||
|
optionDecl := getDeclByName(declArr, "options")
|
||||||
|
var optionsMap map[string]string
|
||||||
|
if optionDecl != nil {
|
||||||
|
var err error
|
||||||
|
optionsMap, err = parseSimpleZshOptions(optionDecl.Value)
|
||||||
|
if err != nil {
|
||||||
|
wlog.Logf("error decoding zsh options: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for optName := range optionsMap {
|
||||||
|
if ZshIgnoreOptions[optName] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if optionsMap[optName] == "on" {
|
||||||
|
rcBuf.WriteString(fmt.Sprintf("setopt %s\n", optName))
|
||||||
|
} else {
|
||||||
|
rcBuf.WriteString(fmt.Sprintf("unsetopt %s\n", optName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func writeZshId(buf *bytes.Buffer, idStr string) {
|
func writeZshId(buf *bytes.Buffer, idStr string) {
|
||||||
buf.WriteString(shellescape.Quote(idStr))
|
buf.WriteString(shellescape.Quote(idStr))
|
||||||
}
|
}
|
||||||
@ -334,6 +399,7 @@ func GetZshShellStateCmd(fdNum int) string {
|
|||||||
exec > [%OUTPUTFD%]
|
exec > [%OUTPUTFD%]
|
||||||
unsetopt SH_WORD_SPLIT;
|
unsetopt SH_WORD_SPLIT;
|
||||||
zmodload zsh/parameter;
|
zmodload zsh/parameter;
|
||||||
|
zmodload zsh/langinfo;
|
||||||
[%ZSHVERSION%];
|
[%ZSHVERSION%];
|
||||||
printf "\x00[%SECTIONSEP%]";
|
printf "\x00[%SECTIONSEP%]";
|
||||||
pwd;
|
pwd;
|
||||||
@ -853,3 +919,42 @@ func (zshShellApi) ApplyShellStateDiff(oldState *packet.ShellState, diff *packet
|
|||||||
}
|
}
|
||||||
return rtnState, nil
|
return rtnState, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this will *not* parse general zsh assoc arrays, used to parse zsh options (no spaces)
|
||||||
|
// ( [posixargzero]=off [autolist]=on )
|
||||||
|
func parseSimpleZshOptions(decl string) (map[string]string, error) {
|
||||||
|
decl = strings.TrimSpace(decl)
|
||||||
|
if !strings.HasPrefix(decl, "(") || !strings.HasSuffix(decl, ")") {
|
||||||
|
return nil, errors.New("invalid assoc array decl, must start and end with parens")
|
||||||
|
}
|
||||||
|
decl = decl[1 : len(decl)-1]
|
||||||
|
parts := strings.Split(decl, " ")
|
||||||
|
rtn := make(map[string]string)
|
||||||
|
for _, part := range parts {
|
||||||
|
part = strings.TrimSpace(part)
|
||||||
|
if part == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
eqIdx := strings.Index(part, "=")
|
||||||
|
if eqIdx == -1 {
|
||||||
|
return nil, fmt.Errorf("invalid assoc array decl part: %q", part)
|
||||||
|
}
|
||||||
|
bracketedKey := part[0:eqIdx]
|
||||||
|
val := part[eqIdx+1:]
|
||||||
|
if !strings.HasPrefix(bracketedKey, "[") || !strings.HasSuffix(bracketedKey, "]") {
|
||||||
|
return nil, fmt.Errorf("invalid assoc array decl part: %q", part)
|
||||||
|
}
|
||||||
|
key := bracketedKey[1 : len(bracketedKey)-1]
|
||||||
|
rtn[key] = val
|
||||||
|
}
|
||||||
|
return rtn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDeclByName(decls []*shellenv.DeclareDeclType, name string) *shellenv.DeclareDeclType {
|
||||||
|
for _, decl := range decls {
|
||||||
|
if decl.Name == name {
|
||||||
|
return decl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
"github.com/wavetermdev/waveterm/waveshell/pkg/shellapi"
|
"github.com/wavetermdev/waveterm/waveshell/pkg/shellapi"
|
||||||
"github.com/wavetermdev/waveterm/waveshell/pkg/shellenv"
|
"github.com/wavetermdev/waveterm/waveshell/pkg/shellenv"
|
||||||
"github.com/wavetermdev/waveterm/waveshell/pkg/shellutil"
|
"github.com/wavetermdev/waveterm/waveshell/pkg/shellutil"
|
||||||
|
"github.com/wavetermdev/waveterm/waveshell/pkg/wlog"
|
||||||
"golang.org/x/mod/semver"
|
"golang.org/x/mod/semver"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
@ -51,6 +52,7 @@ const SigKillWaitTime = 2 * time.Second
|
|||||||
const RtnStateFdNum = 20
|
const RtnStateFdNum = 20
|
||||||
const ReturnStateReadWaitTime = 2 * time.Second
|
const ReturnStateReadWaitTime = 2 * time.Second
|
||||||
const ForceDebugRcFile = false
|
const ForceDebugRcFile = false
|
||||||
|
const ForceDebugReturnState = false
|
||||||
|
|
||||||
const ClientCommandFmt = `
|
const ClientCommandFmt = `
|
||||||
PATH=$PATH:~/.mshell;
|
PATH=$PATH:~/.mshell;
|
||||||
@ -833,6 +835,7 @@ func RunCommandSimple(pk *packet.RunPacketType, sender *packet.PacketSender, fro
|
|||||||
}
|
}
|
||||||
shellVarMap := shellenv.ShellVarMapFromState(state)
|
shellVarMap := shellenv.ShellVarMapFromState(state)
|
||||||
if base.HasDebugFlag(shellVarMap, base.DebugFlag_LogRcFile) || ForceDebugRcFile {
|
if base.HasDebugFlag(shellVarMap, base.DebugFlag_LogRcFile) || ForceDebugRcFile {
|
||||||
|
wlog.Logf("debugrc file %q\n", base.GetDebugRcFileName())
|
||||||
debugRcFileName := base.GetDebugRcFileName()
|
debugRcFileName := base.GetDebugRcFileName()
|
||||||
err := os.WriteFile(debugRcFileName, []byte(rcFileStr), 0600)
|
err := os.WriteFile(debugRcFileName, []byte(rcFileStr), 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1196,6 +1199,10 @@ func (c *ShExecType) WaitForCommand() *packet.CmdDonePacketType {
|
|||||||
c.ReturnState.Reader.Close()
|
c.ReturnState.Reader.Close()
|
||||||
}()
|
}()
|
||||||
<-c.ReturnState.DoneCh
|
<-c.ReturnState.DoneCh
|
||||||
|
if ForceDebugReturnState {
|
||||||
|
wlog.Logf("debug returnstate file %q\n", base.GetDebugReturnStateFileName())
|
||||||
|
os.WriteFile(base.GetDebugReturnStateFileName(), c.ReturnState.Buf, 0666)
|
||||||
|
}
|
||||||
state, _ := c.SAPI.ParseShellStateOutput(c.ReturnState.Buf) // TODO what to do with error?
|
state, _ := c.SAPI.ParseShellStateOutput(c.ReturnState.Buf) // TODO what to do with error?
|
||||||
donePacket.FinalState = state
|
donePacket.FinalState = state
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user