From 2d089b98fbda7e09ce30a29b8e5a860e3b17083a Mon Sep 17 00:00:00 2001 From: sawka Date: Thu, 6 Oct 2022 23:58:38 -0700 Subject: [PATCH] tweaks to genericresolver (and bug fix) --- pkg/cmdrunner/cmdrunner.go | 2 +- pkg/cmdrunner/resolver.go | 131 ++++++++++++++++++++++++------------- pkg/sstore/dbops.go | 15 ++++- pkg/sstore/sstore.go | 6 ++ 4 files changed, 108 insertions(+), 46 deletions(-) diff --git a/pkg/cmdrunner/cmdrunner.go b/pkg/cmdrunner/cmdrunner.go index 43a589868..1e7ce512d 100644 --- a/pkg/cmdrunner/cmdrunner.go +++ b/pkg/cmdrunner/cmdrunner.go @@ -1372,7 +1372,7 @@ func SessionCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ssto return nil, err } ritems := sessionsToResolveItems(bareSessions) - ritem, err := genericResolve(firstArg, ids.SessionId, ritems, "session") + ritem, err := genericResolve(firstArg, ids.SessionId, ritems, false, "session") if err != nil { return nil, err } diff --git a/pkg/cmdrunner/resolver.go b/pkg/cmdrunner/resolver.go index 4fb1cf2c8..984a9e4ea 100644 --- a/pkg/cmdrunner/resolver.go +++ b/pkg/cmdrunner/resolver.go @@ -37,10 +37,7 @@ type ResolvedRemote struct { RemoteCopy *sstore.RemoteType } -type ResolveItem struct { - Name string - Id string -} +type ResolveItem = sstore.ResolveItem func itemNames(items []ResolveItem) []string { if len(items) == 0 { @@ -75,48 +72,74 @@ func screensToResolveItems(screens []*sstore.ScreenType) []ResolveItem { return rtn } -func resolveByPosition(items []ResolveItem, curId string, posStr string) *ResolveItem { - if len(items) == 0 { - return nil +// 1-indexed +func boundInt(ival int, maxVal int, wrap bool) int { + if maxVal == 0 { + return 0 } + if ival < 1 { + if wrap { + return maxVal + } else { + return 1 + } + } + if ival > maxVal { + if wrap { + return 1 + } else { + return maxVal + } + } + return ival +} + +type posArgType struct { + Pos int + IsWrap bool + IsRelative bool +} + +func parsePosArg(posStr string) *posArgType { if !positionRe.MatchString(posStr) { return nil } - curIdx := 1 // if no match, curIdx will be first item - for idx, item := range items { - if item.Id == curId { - curIdx = idx + 1 - break - } - } - isRelative := strings.HasPrefix(posStr, "+") || strings.HasPrefix(posStr, "-") - isWrap := posStr == "+" || posStr == "-" - var pos int - if isWrap && posStr == "+" { - pos = 1 - } else if isWrap && posStr == "-" { - pos = -1 + rtn := &posArgType{} + rtn.IsRelative = strings.HasPrefix(posStr, "+") || strings.HasPrefix(posStr, "-") + rtn.IsWrap = posStr == "+" || posStr == "-" + if rtn.IsWrap && posStr == "+" { + rtn.Pos = 1 + } else if rtn.IsWrap && posStr == "-" { + rtn.Pos = -1 } else { - pos, _ = strconv.Atoi(posStr) + rtn.Pos, _ = strconv.Atoi(posStr) // don't need to check error because of positionRe.Match } - if isRelative { - pos = curIdx + pos + return rtn +} + +func resolveByPosition(isNumeric bool, items []ResolveItem, curId string, posStr string) *ResolveItem { + if len(items) == 0 { + return nil } - if pos < 1 { - if isWrap { - pos = len(items) - } else { - pos = 1 + posArg := parsePosArg(posStr) + if posArg == nil { + return nil + } + var finalPos int + if posArg.IsRelative { + curIdx := 1 // if no match, curIdx will be first item + for idx, item := range items { + if item.Id == curId { + curIdx = idx + 1 + break + } } + finalPos = curIdx + posArg.Pos + } else { + finalPos = posArg.Pos } - if pos > len(items) { - if isWrap { - pos = 1 - } else { - pos = len(items) - } - } - return &items[pos-1] + finalPos = boundInt(finalPos, len(items), posArg.IsWrap) + return &items[finalPos-1] } func resolveRemoteArg(remoteArg string) (*sstore.RemotePtrType, error) { @@ -223,7 +246,7 @@ func resolveSessionScreen(ctx context.Context, sessionId string, screenArg strin return nil, fmt.Errorf("could not retreive screens for session=%s", sessionId) } ritems := screensToResolveItems(screens) - return genericResolve(screenArg, curScreenArg, ritems, "screen") + return genericResolve(screenArg, curScreenArg, ritems, false, "screen") } func getSessionIds(sarr []*sstore.SessionType) []string { @@ -240,26 +263,46 @@ func isPartialUUID(s string) bool { return partialUUIDRe.MatchString(s) } -func genericResolve(arg string, curArg string, items []ResolveItem, typeStr string) (*ResolveItem, error) { +func getResolveItemById(id string, items []ResolveItem) *ResolveItem { + if id == "" { + return nil + } + for _, item := range items { + if item.Id == id { + return &item + } + } + return nil +} + +func genericResolve(arg string, curArg string, items []ResolveItem, isNumeric bool, typeStr string) (*ResolveItem, error) { + if len(items) == 0 || arg == "" { + return nil, nil + } var curId string if curArg != "" { - curItem, _ := genericResolve(curArg, "", items, typeStr) + curItem, _ := genericResolve(curArg, "", items, isNumeric, typeStr) if curItem != nil { curId = curItem.Id } } - rtnItem := resolveByPosition(items, curId, arg) + rtnItem := resolveByPosition(isNumeric, items, curId, arg) if rtnItem != nil { return rtnItem, nil } tryPuid := isPartialUUID(arg) var prefixMatches []ResolveItem for _, item := range items { - if item.Id == arg || item.Name == arg || (tryPuid && strings.HasPrefix(item.Id, arg)) { + if item.Id == arg || (tryPuid && strings.HasPrefix(item.Id, arg)) { return &item, nil } - if strings.HasPrefix(item.Name, arg) { - prefixMatches = append(prefixMatches, item) + if item.Name != "" { + if item.Name == arg { + return &item, nil + } + if strings.HasPrefix(item.Name, arg) { + prefixMatches = append(prefixMatches, item) + } } } if len(prefixMatches) == 1 { diff --git a/pkg/sstore/dbops.go b/pkg/sstore/dbops.go index 350eb2ea2..709c08fd9 100644 --- a/pkg/sstore/dbops.go +++ b/pkg/sstore/dbops.go @@ -335,7 +335,7 @@ func GetWindowById(ctx context.Context, sessionId string, windowId string) (*Win return nil } rtnWindow = WindowFromMap(m) - query = `SELECT * FROM line WHERE sessionid = ? AND windowid = ?` + query = `SELECT * FROM line WHERE sessionid = ? AND windowid = ? ORDER BY linenum` tx.SelectWrap(&rtnWindow.Lines, query, sessionId, windowId) query = `SELECT * FROM cmd WHERE cmdid IN (SELECT cmdid FROM line WHERE sessionid = ? AND windowid = ?)` cmdMaps := tx.SelectMaps(query, sessionId, windowId) @@ -1132,3 +1132,16 @@ func UpdateScreenWindow(ctx context.Context, sessionId string, screenId string, } return rtn, nil } + +func GetLineResolveItems(ctx context.Context, sessionId string, windowId string) ([]ResolveItem, error) { + var rtn []ResolveItem + txErr := WithTx(ctx, func(tx *TxWrap) error { + query := `SELECT lineid as id, linenum as num FROM line WHERE sessionid = ? AND windowid = ? ORDER BY linenum` + tx.SelectWrap(&rtn, query, sessionId, windowId) + return nil + }) + if txErr != nil { + return nil, txErr + } + return rtn, nil +} diff --git a/pkg/sstore/sstore.go b/pkg/sstore/sstore.go index f18658bd0..fbf80c0b1 100644 --- a/pkg/sstore/sstore.go +++ b/pkg/sstore/sstore.go @@ -471,6 +471,12 @@ type LineType struct { Remove bool `json:"remove,omitempty"` } +type ResolveItem struct { + Name string + Num int + Id string +} + type SSHOpts struct { Local bool `json:"local,omitempty"` SSHHost string `json:"sshhost"`