mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +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 DebugFlag_LogRcFile = "logrc"
|
||||
const LogRcFileName = "debug.rcfile"
|
||||
const DebugRcFileName = "debug.rcfile"
|
||||
const DebugReturnStateFileName = "debug.returnstate"
|
||||
|
||||
const (
|
||||
ProcessType_Unknown = "unknown"
|
||||
@ -175,7 +176,12 @@ func HasDebugFlag(envMap map[string]string, flagName string) bool {
|
||||
|
||||
func GetDebugRcFileName() string {
|
||||
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 {
|
||||
|
@ -6,6 +6,7 @@ package shellapi
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os/exec"
|
||||
@ -20,6 +21,7 @@ import (
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/shellenv"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/statediff"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/utilfn"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/wlog"
|
||||
"github.com/wavetermdev/waveterm/wavesrv/pkg/scbase"
|
||||
)
|
||||
|
||||
@ -56,7 +58,7 @@ var ZshIgnoreVars = map[string]bool{
|
||||
"langinfo": true,
|
||||
"keymaps": true,
|
||||
"widgets": true,
|
||||
|
||||
"options": true,
|
||||
"aliases": true,
|
||||
"dis_aliases": true,
|
||||
"saliases": true,
|
||||
@ -86,6 +88,34 @@ var ZshIgnoreVars = map[string]bool{
|
||||
"_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{
|
||||
"path": true,
|
||||
"fpath": true,
|
||||
@ -101,6 +131,11 @@ var ZshUnsetVars = []string{
|
||||
"ZSH_EXECUTION_STRING",
|
||||
}
|
||||
|
||||
var ZshLoadMods = []string{
|
||||
"zsh/parameter",
|
||||
"zsh/langinfo",
|
||||
}
|
||||
|
||||
// do not use these directly, call GetLocalMajorVersion()
|
||||
var localZshMajorVersionOnce = &sync.Once{}
|
||||
var localZshMajorVersion = ""
|
||||
@ -223,10 +258,19 @@ func isZshSafeNameStr(name string) bool {
|
||||
func (z zshShellApi) MakeRcFileStr(pk *packet.RunPacketType) string {
|
||||
var rcBuf bytes.Buffer
|
||||
rcBuf.WriteString(z.GetBaseShellOpts() + "\n")
|
||||
rcBuf.WriteString("unsetopt GLOBAL_RCS\n")
|
||||
rcBuf.WriteString("unset KSH_ARRAYS\n")
|
||||
rcBuf.WriteString("zmodload zsh/parameter\n")
|
||||
// rcBuf.WriteString("echo 'running generated rcfile' $0 $ZSH_ARGZERO '|' $ZDOTDIR\n")
|
||||
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
|
||||
for _, varDecl := range varDecls {
|
||||
if ZshIgnoreVars[varDecl.Name] {
|
||||
@ -294,16 +338,37 @@ func (z zshShellApi) MakeRcFileStr(pk *packet.RunPacketType) string {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write postdecls
|
||||
for _, varDecl := range postDecls {
|
||||
rcBuf.WriteString(makeZshTypesetStmt(varDecl))
|
||||
rcBuf.WriteString("\n")
|
||||
}
|
||||
|
||||
writeZshOptions(&rcBuf, varDecls)
|
||||
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) {
|
||||
buf.WriteString(shellescape.Quote(idStr))
|
||||
}
|
||||
@ -334,6 +399,7 @@ func GetZshShellStateCmd(fdNum int) string {
|
||||
exec > [%OUTPUTFD%]
|
||||
unsetopt SH_WORD_SPLIT;
|
||||
zmodload zsh/parameter;
|
||||
zmodload zsh/langinfo;
|
||||
[%ZSHVERSION%];
|
||||
printf "\x00[%SECTIONSEP%]";
|
||||
pwd;
|
||||
@ -853,3 +919,42 @@ func (zshShellApi) ApplyShellStateDiff(oldState *packet.ShellState, diff *packet
|
||||
}
|
||||
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/shellenv"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/shellutil"
|
||||
"github.com/wavetermdev/waveterm/waveshell/pkg/wlog"
|
||||
"golang.org/x/mod/semver"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
@ -51,6 +52,7 @@ const SigKillWaitTime = 2 * time.Second
|
||||
const RtnStateFdNum = 20
|
||||
const ReturnStateReadWaitTime = 2 * time.Second
|
||||
const ForceDebugRcFile = false
|
||||
const ForceDebugReturnState = false
|
||||
|
||||
const ClientCommandFmt = `
|
||||
PATH=$PATH:~/.mshell;
|
||||
@ -833,6 +835,7 @@ func RunCommandSimple(pk *packet.RunPacketType, sender *packet.PacketSender, fro
|
||||
}
|
||||
shellVarMap := shellenv.ShellVarMapFromState(state)
|
||||
if base.HasDebugFlag(shellVarMap, base.DebugFlag_LogRcFile) || ForceDebugRcFile {
|
||||
wlog.Logf("debugrc file %q\n", base.GetDebugRcFileName())
|
||||
debugRcFileName := base.GetDebugRcFileName()
|
||||
err := os.WriteFile(debugRcFileName, []byte(rcFileStr), 0600)
|
||||
if err != nil {
|
||||
@ -1196,6 +1199,10 @@ func (c *ShExecType) WaitForCommand() *packet.CmdDonePacketType {
|
||||
c.ReturnState.Reader.Close()
|
||||
}()
|
||||
<-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?
|
||||
donePacket.FinalState = state
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user