get resh to compile and run

pull/179/head
Simon Let 3 years ago
parent 9dfcb25d95
commit 0c6ce3c8e9
No known key found for this signature in database
GPG Key ID: D650C65DD46D431D
  1. 9
      .goreleaser.yml
  2. 2
      Makefile
  3. 10
      cmd/cli/main.go
  4. 166
      cmd/collect/main.go
  5. 2
      cmd/daemon/dump.go
  6. 8
      cmd/daemon/main.go
  7. 16
      cmd/daemon/record.go
  8. 12
      cmd/daemon/run-server.go
  9. 14
      cmd/daemon/session-init.go
  10. 4
      cmd/install-utils/main.go
  11. 111
      cmd/postcollect/main.go
  12. 143
      cmd/session-init/main.go
  13. 1
      go.mod
  14. 2
      go.sum
  15. 1
      internal/cfg/cfg.go
  16. 33
      internal/collect/collect.go
  17. 11
      internal/histcli/histcli.go
  18. 125
      internal/histfile/histfile.go
  19. 4
      internal/msg/msg.go
  20. 20
      internal/output/output.go
  21. 28
      internal/recconv/recconv.go
  22. 2
      internal/recio/read.go
  23. 34
      internal/recio/write.go
  24. 8
      internal/record/v1.go
  25. 13
      internal/recordint/collect.go
  26. 51
      internal/recordint/enriched.go
  27. 51
      internal/recordint/searchapp.go
  28. 256
      internal/records/records.go
  29. 85
      internal/records/records_test.go
  30. 27
      internal/records/testdata/resh_history.json
  31. 109
      internal/recutil/recutil.go
  32. 22
      internal/searchapp/item.go
  33. 12
      internal/searchapp/test.go
  34. 26
      internal/sesswatch/sesswatch.go
  35. 75
      scripts/hooks.sh
  36. 5
      scripts/install.sh
  37. 4
      scripts/reshctl.sh
  38. 3
      scripts/shellrc.sh
  39. 40
      scripts/util.sh
  40. 6
      scripts/widgets.sh

@ -102,6 +102,15 @@ builds:
- amd64
- arm
- arm64
-
id: "install-utils"
main: ./cmd/install-utils
binary: bin/resh-install-utils
goarch:
- 386
- amd64
- arm
- arm64
# signs:
# - artifacts: checksum

@ -7,7 +7,7 @@ GOFLAGS=-ldflags "-X main.version=${VERSION} -X main.commit=${COMMIT} -X main.de
build: submodules bin/resh-session-init bin/resh-collect bin/resh-postcollect\
bin/resh-daemon bin/resh-control bin/resh-config bin/resh-cli\
bin/installutil
bin/resh-install-utils
install: build
scripts/install.sh

@ -19,7 +19,7 @@ import (
"github.com/curusarn/resh/internal/logger"
"github.com/curusarn/resh/internal/msg"
"github.com/curusarn/resh/internal/output"
"github.com/curusarn/resh/internal/records"
"github.com/curusarn/resh/internal/recordint"
"github.com/curusarn/resh/internal/searchapp"
"go.uber.org/zap"
@ -96,7 +96,7 @@ func runReshCli(out *output.Output, config cfg.Config) (string, int) {
st := state{
// lock sync.Mutex
cliRecords: resp.CliRecords,
cliRecords: resp.Records,
initialQuery: *query,
}
@ -106,7 +106,7 @@ func runReshCli(out *output.Output, config cfg.Config) (string, int) {
sessionID: *sessionID,
host: *host,
pwd: *pwd,
gitOriginRemote: records.NormalizeGitRemote(*gitOriginRemote),
gitOriginRemote: *gitOriginRemote,
s: &st,
}
g.SetManager(layout)
@ -159,7 +159,7 @@ func runReshCli(out *output.Output, config cfg.Config) (string, int) {
type state struct {
lock sync.Mutex
cliRecords []records.CliRecord
cliRecords []recordint.SearchApp
data []searchapp.Item
rawData []searchapp.RawItem
highlightedItem int
@ -600,7 +600,7 @@ func SendCliMsg(out *output.Output, m msg.CliMsg, port string) msg.CliResponse {
out.Fatal("Failed decode response", err)
}
sugar.Debugw("Recieved records from daemon",
"recordCount", len(response.CliRecords),
"recordCount", len(response.Records),
)
return response
}

@ -9,7 +9,8 @@ import (
"github.com/curusarn/resh/internal/collect"
"github.com/curusarn/resh/internal/logger"
"github.com/curusarn/resh/internal/output"
"github.com/curusarn/resh/internal/records"
"github.com/curusarn/resh/internal/record"
"github.com/curusarn/resh/internal/recordint"
"go.uber.org/zap"
// "os/exec"
@ -32,14 +33,6 @@ func main() {
}
out := output.New(logger, "resh-collect ERROR")
homeDir, err := os.UserHomeDir()
if err != nil {
out.Fatal("Could not get user home dir", err)
}
reshUUIDPath := filepath.Join(homeDir, "/.resh/resh-uuid")
machineIDPath := "/etc/machine-id"
// version
showVersion := flag.Bool("version", false, "Show version and exit")
showRevision := flag.Bool("revision", false, "Show git revision and exit")
@ -49,55 +42,27 @@ func main() {
// core
cmdLine := flag.String("cmdLine", "", "command line")
exitCode := flag.Int("exitCode", -1, "exit code")
shell := flag.String("shell", "", "actual shell")
uname := flag.String("uname", "", "uname")
sessionID := flag.String("sessionId", "", "resh generated session id")
recordID := flag.String("recordId", "", "resh generated record id")
// posix variables
cols := flag.String("cols", "-1", "$COLUMNS")
lines := flag.String("lines", "-1", "$LINES")
home := flag.String("home", "", "$HOME")
lang := flag.String("lang", "", "$LANG")
lcAll := flag.String("lcAll", "", "$LC_ALL")
login := flag.String("login", "", "$LOGIN")
// path := flag.String("path", "", "$PATH")
pwd := flag.String("pwd", "", "$PWD - present working directory")
shellEnv := flag.String("shellEnv", "", "$SHELL")
term := flag.String("term", "", "$TERM")
// FIXME: get device ID
deviceID := flag.String("deviceID", "", "RESH device ID")
sessionID := flag.String("sessionID", "", "resh generated session ID")
recordID := flag.String("recordID", "", "resh generated record ID")
sessionPID := flag.Int("sessionPID", -1, "PID at the start of the terminal session")
shell := flag.String("shell", "", "current shell")
logname := flag.String("logname", "", "$LOGNAME")
hostname := flag.String("hostname", "", "$HOSTNAME")
// non-posix
pid := flag.Int("pid", -1, "$$")
sessionPid := flag.Int("sessionPid", -1, "$$ at session start")
shlvl := flag.Int("shlvl", -1, "$SHLVL")
host := flag.String("host", "", "$HOSTNAME")
hosttype := flag.String("hosttype", "", "$HOSTTYPE")
ostype := flag.String("ostype", "", "$OSTYPE")
machtype := flag.String("machtype", "", "$MACHTYPE")
gitCdup := flag.String("gitCdup", "", "git rev-parse --show-cdup")
gitRemote := flag.String("gitRemote", "", "git remote get-url origin")
gitCdupExitCode := flag.Int("gitCdupExitCode", -1, "... $?")
gitRemoteExitCode := flag.Int("gitRemoteExitCode", -1, "... $?")
// before after
timezoneBefore := flag.String("timezoneBefore", "", "")
osReleaseID := flag.String("osReleaseId", "", "/etc/os-release ID")
osReleaseVersionID := flag.String("osReleaseVersionId", "",
"/etc/os-release ID")
osReleaseIDLike := flag.String("osReleaseIdLike", "", "/etc/os-release ID")
osReleaseName := flag.String("osReleaseName", "", "/etc/os-release ID")
osReleasePrettyName := flag.String("osReleasePrettyName", "",
"/etc/os-release ID")
rtb := flag.String("realtimeBefore", "-1", "before $EPOCHREALTIME")
rtsess := flag.String("realtimeSession", "-1",
"on session start $EPOCHREALTIME")
rtsessboot := flag.String("realtimeSessSinceBoot", "-1",
"on session start $EPOCHREALTIME")
time_ := flag.String("time", "-1", "$EPOCHREALTIME")
flag.Parse()
if *showVersion == true {
@ -109,37 +74,17 @@ func main() {
os.Exit(0)
}
if *requireVersion != "" && *requireVersion != version {
fmt.Println("Please restart/reload this terminal session " +
"(resh version: " + version +
"; resh version of this terminal session: " + *requireVersion +
")")
os.Exit(3)
out.FatalVersionMismatch(version, *requireVersion)
}
if *requireRevision != "" && *requireRevision != commit {
fmt.Println("Please restart/reload this terminal session " +
"(resh revision: " + commit +
"; resh revision of this terminal session: " + *requireRevision +
")")
os.Exit(3)
// this is only relevant for dev versions so we can reuse FatalVersionMismatch()
out.FatalVersionMismatch("revision "+commit, "revision "+*requireVersion)
}
realtimeBefore, err := strconv.ParseFloat(*rtb, 64)
if err != nil {
out.Fatal("Error while parsing flag --realtimeBefore", err)
}
realtimeSessionStart, err := strconv.ParseFloat(*rtsess, 64)
time, err := strconv.ParseFloat(*time_, 64)
if err != nil {
out.Fatal("Error while parsing flag --realtimeSession", err)
out.Fatal("Error while parsing flag --time", err)
}
realtimeSessSinceBoot, err := strconv.ParseFloat(*rtsessboot, 64)
if err != nil {
out.Fatal("Error while parsing flag --realtimeSessSinceBoot", err)
}
realtimeSinceSessionStart := realtimeBefore - realtimeSessionStart
realtimeSinceBoot := realtimeSessSinceBoot + realtimeSinceSessionStart
timezoneBeforeOffset := collect.GetTimezoneOffsetInSeconds(logger, *timezoneBefore)
realtimeBeforeLocal := realtimeBefore + timezoneBeforeOffset
realPwd, err := filepath.EvalSymlinks(*pwd)
if err != nil {
@ -147,79 +92,34 @@ func main() {
realPwd = ""
}
gitDir, gitRealDir := collect.GetGitDirs(logger, *gitCdup, *gitCdupExitCode, *pwd)
if *gitRemoteExitCode != 0 {
*gitRemote = ""
}
rec := recordint.Collect{
SessionID: *sessionID,
Shlvl: *shlvl,
SessionPID: *sessionPID,
// if *osReleaseID == "" {
// *osReleaseID = "linux"
// }
// if *osReleaseName == "" {
// *osReleaseName = "Linux"
// }
// if *osReleasePrettyName == "" {
// *osReleasePrettyName = "Linux"
// }
rec := records.Record{
// posix
Cols: *cols,
Lines: *lines,
// core
BaseRecord: records.BaseRecord{
CmdLine: *cmdLine,
ExitCode: *exitCode,
Shell: *shell,
Uname: *uname,
Rec: record.V1{
DeviceID: *deviceID,
SessionID: *sessionID,
RecordID: *recordID,
CmdLine: *cmdLine,
// posix
Home: *home,
Lang: *lang,
LcAll: *lcAll,
Login: *login,
// Path: *path,
Pwd: *pwd,
ShellEnv: *shellEnv,
Term: *term,
// non-posix
RealPwd: realPwd,
Pid: *pid,
SessionPID: *sessionPid,
Host: *host,
Hosttype: *hosttype,
Ostype: *ostype,
Machtype: *machtype,
Shlvl: *shlvl,
// before after
TimezoneBefore: *timezoneBefore,
Logname: *logname,
Hostname: *hostname,
RealtimeBefore: realtimeBefore,
RealtimeBeforeLocal: realtimeBeforeLocal,
RealtimeSinceSessionStart: realtimeSinceSessionStart,
RealtimeSinceBoot: realtimeSinceBoot,
GitDir: gitDir,
GitRealDir: gitRealDir,
GitOriginRemote: *gitRemote,
MachineID: collect.ReadFileContent(out.Logger, machineIDPath),
OsReleaseID: *osReleaseID,
OsReleaseVersionID: *osReleaseVersionID,
OsReleaseIDLike: *osReleaseIDLike,
OsReleaseName: *osReleaseName,
OsReleasePrettyName: *osReleasePrettyName,
Time: time,
PartOne: true,
ReshUUID: collect.ReadFileContent(out.Logger, reshUUIDPath),
ReshVersion: version,
ReshRevision: commit,
PartsNotMerged: true,
},
}
collect.SendRecord(out, rec, strconv.Itoa(config.Port), "/record")

@ -40,7 +40,7 @@ func (h *dumpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
sugar.Errorw("Error when getting records", "error", err)
}
resp := msg.CliResponse{CliRecords: fullRecords.List}
resp := msg.CliResponse{Records: fullRecords.List}
jsn, err = json.Marshal(&resp)
if err != nil {
sugar.Errorw("Error when marshaling", "error", err)

@ -22,7 +22,10 @@ var developement bool
func main() {
config, errCfg := cfg.New()
logger, _ := logger.New("daemon", config.LogLevel, developement)
logger, err := logger.New("daemon", config.LogLevel, developement)
if err != nil {
fmt.Printf("Error while creating logger: %v", err)
}
defer logger.Sync() // flushes buffer, if any
if errCfg != nil {
logger.Error("Error while getting configuration", zap.Error(errCfg))
@ -34,9 +37,6 @@ func main() {
"commit", commit,
)
// xdgCacheHome := d.getEnvOrPanic("__RESH_XDG_CACHE_HOME")
// xdgDataHome := d.getEnvOrPanic("__RESH_XDG_DATA_HOME")
// TODO: rethink PID file and logs location
homeDir, err := os.UserHomeDir()
if err != nil {

@ -5,11 +5,11 @@ import (
"io/ioutil"
"net/http"
"github.com/curusarn/resh/internal/records"
"github.com/curusarn/resh/internal/recordint"
"go.uber.org/zap"
)
func NewRecordHandler(sugar *zap.SugaredLogger, subscribers []chan records.Record) recordHandler {
func NewRecordHandler(sugar *zap.SugaredLogger, subscribers []chan recordint.Collect) recordHandler {
return recordHandler{
sugar: sugar.With(zap.String("endpoint", "/record")),
subscribers: subscribers,
@ -18,7 +18,7 @@ func NewRecordHandler(sugar *zap.SugaredLogger, subscribers []chan records.Recor
type recordHandler struct {
sugar *zap.SugaredLogger
subscribers []chan records.Record
subscribers []chan recordint.Collect
}
func (h *recordHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@ -34,8 +34,8 @@ func (h *recordHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
sugar.Debugw("Unmarshaling record ...")
record := records.Record{}
err = json.Unmarshal(jsn, &record)
rec := recordint.Collect{}
err = json.Unmarshal(jsn, &rec)
if err != nil {
sugar.Errorw("Error during unmarshaling",
"error", err,
@ -44,16 +44,16 @@ func (h *recordHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
part := "2"
if record.PartOne {
if rec.Rec.PartOne {
part = "1"
}
sugar := sugar.With(
"cmdLine", record.CmdLine,
"cmdLine", rec.Rec.CmdLine,
"part", part,
)
sugar.Debugw("Got record, sending to subscribers ...")
for _, sub := range h.subscribers {
sub <- record
sub <- rec
}
sugar.Debugw("Record sent to subscribers")
}()

@ -8,7 +8,7 @@ import (
"github.com/curusarn/resh/internal/cfg"
"github.com/curusarn/resh/internal/histfile"
"github.com/curusarn/resh/internal/records"
"github.com/curusarn/resh/internal/recordint"
"github.com/curusarn/resh/internal/sesswatch"
"github.com/curusarn/resh/internal/signalhandler"
"go.uber.org/zap"
@ -26,15 +26,15 @@ type Server struct {
}
func (s *Server) Run() {
var recordSubscribers []chan records.Record
var sessionInitSubscribers []chan records.Record
var recordSubscribers []chan recordint.Collect
var sessionInitSubscribers []chan recordint.SessionInit
var sessionDropSubscribers []chan string
var signalSubscribers []chan os.Signal
shutdown := make(chan string)
// histfile
histfileRecords := make(chan records.Record)
histfileRecords := make(chan recordint.Collect)
recordSubscribers = append(recordSubscribers, histfileRecords)
histfileSessionsToDrop := make(chan string)
sessionDropSubscribers = append(sessionDropSubscribers, histfileSessionsToDrop)
@ -48,9 +48,9 @@ func (s *Server) Run() {
histfileSignals, shutdown)
// sesswatch
sesswatchRecords := make(chan records.Record)
sesswatchRecords := make(chan recordint.Collect)
recordSubscribers = append(recordSubscribers, sesswatchRecords)
sesswatchSessionsToWatch := make(chan records.Record)
sesswatchSessionsToWatch := make(chan recordint.SessionInit)
sessionInitSubscribers = append(sessionInitSubscribers, sesswatchSessionsToWatch)
sesswatch.Go(
s.sugar,

@ -5,13 +5,13 @@ import (
"io/ioutil"
"net/http"
"github.com/curusarn/resh/internal/records"
"github.com/curusarn/resh/internal/recordint"
"go.uber.org/zap"
)
type sessionInitHandler struct {
sugar *zap.SugaredLogger
subscribers []chan records.Record
subscribers []chan recordint.SessionInit
}
func (h *sessionInitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@ -28,8 +28,8 @@ func (h *sessionInitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
sugar.Debugw("Unmarshaling record ...")
record := records.Record{}
err = json.Unmarshal(jsn, &record)
rec := recordint.SessionInit{}
err = json.Unmarshal(jsn, &rec)
if err != nil {
sugar.Errorw("Error during unmarshaling",
"error", err,
@ -38,12 +38,12 @@ func (h *sessionInitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
sugar := sugar.With(
"sessionID", record.SessionID,
"sessionPID", record.SessionPID,
"sessionID", rec.SessionID,
"sessionPID", rec.SessionPID,
)
sugar.Infow("Got session, sending to subscribers ...")
for _, sub := range h.subscribers {
sub <- record
sub <- rec
}
sugar.Debugw("Session sent to subscribers")
}()

@ -20,7 +20,9 @@ func main() {
case "backup":
backup()
case "rollback":
rollback()
// FIXME
panic("Rollback not implemented yet!")
// rollback()
case "migrate-config":
migrateConfig()
case "migrate-history":

@ -9,12 +9,12 @@ import (
"github.com/curusarn/resh/internal/collect"
"github.com/curusarn/resh/internal/logger"
"github.com/curusarn/resh/internal/output"
"github.com/curusarn/resh/internal/records"
"github.com/curusarn/resh/internal/record"
"github.com/curusarn/resh/internal/recordint"
"go.uber.org/zap"
// "os/exec"
"path/filepath"
"strconv"
)
@ -32,44 +32,20 @@ func main() {
}
out := output.New(logger, "resh-postcollect ERROR")
homeDir, err := os.UserHomeDir()
if err != nil {
out.Fatal("Could not get user home dir", err)
}
reshUUIDPath := filepath.Join(homeDir, "/.resh/resh-uuid")
machineIDPath := "/etc/machine-id"
showVersion := flag.Bool("version", false, "Show version and exit")
showRevision := flag.Bool("revision", false, "Show git revision and exit")
requireVersion := flag.String("requireVersion", "", "abort if version doesn't match")
requireRevision := flag.String("requireRevision", "", "abort if revision doesn't match")
cmdLine := flag.String("cmdLine", "", "command line")
exitCode := flag.Int("exitCode", -1, "exit code")
sessionID := flag.String("sessionId", "", "resh generated session id")
recordID := flag.String("recordId", "", "resh generated record id")
sessionID := flag.String("sessionID", "", "resh generated session id")
recordID := flag.String("recordID", "", "resh generated record id")
shlvl := flag.Int("shlvl", -1, "$SHLVL")
shell := flag.String("shell", "", "actual shell")
// posix variables
pwdAfter := flag.String("pwdAfter", "", "$PWD after command")
// non-posix
// sessionPid := flag.Int("sessionPid", -1, "$$ at session start")
gitCdupAfter := flag.String("gitCdupAfter", "", "git rev-parse --show-cdup")
gitRemoteAfter := flag.String("gitRemoteAfter", "", "git remote get-url origin")
gitCdupExitCodeAfter := flag.Int("gitCdupExitCodeAfter", -1, "... $?")
gitRemoteExitCodeAfter := flag.Int("gitRemoteExitCodeAfter", -1, "... $?")
// before after
timezoneAfter := flag.String("timezoneAfter", "", "")
rtb := flag.String("realtimeBefore", "-1", "before $EPOCHREALTIME")
rta := flag.String("realtimeAfter", "-1", "after $EPOCHREALTIME")
rtb := flag.String("timeBefore", "-1", "before $EPOCHREALTIME")
rta := flag.String("timeAfter", "-1", "after $EPOCHREALTIME")
flag.Parse()
if *showVersion == true {
@ -81,77 +57,36 @@ func main() {
os.Exit(0)
}
if *requireVersion != "" && *requireVersion != version {
fmt.Println("Please restart/reload this terminal session " +
"(resh version: " + version +
"; resh version of this terminal session: " + *requireVersion +
")")
os.Exit(3)
out.FatalVersionMismatch(version, *requireVersion)
}
if *requireRevision != "" && *requireRevision != commit {
fmt.Println("Please restart/reload this terminal session " +
"(resh revision: " + commit +
"; resh revision of this terminal session: " + *requireRevision +
")")
os.Exit(3)
}
realtimeAfter, err := strconv.ParseFloat(*rta, 64)
if err != nil {
out.Fatal("Error while parsing flag --realtimeAfter", err)
// this is only relevant for dev versions so we can reuse FatalVersionMismatch()
out.FatalVersionMismatch("revision "+commit, "revision "+*requireVersion)
}
realtimeBefore, err := strconv.ParseFloat(*rtb, 64)
if err != nil {
out.Fatal("Error while parsing flag --realtimeBefore", err)
}
realtimeDuration := realtimeAfter - realtimeBefore
timezoneAfterOffset := collect.GetTimezoneOffsetInSeconds(logger, *timezoneAfter)
realtimeAfterLocal := realtimeAfter + timezoneAfterOffset
realPwdAfter, err := filepath.EvalSymlinks(*pwdAfter)
timeAfter, err := strconv.ParseFloat(*rta, 64)
if err != nil {
logger.Error("Error while handling pwdAfter realpath", zap.Error(err))
realPwdAfter = ""
out.Fatal("Error while parsing flag --timeAfter", err)
}
gitDirAfter, gitRealDirAfter := collect.GetGitDirs(logger, *gitCdupAfter, *gitCdupExitCodeAfter, *pwdAfter)
if *gitRemoteExitCodeAfter != 0 {
*gitRemoteAfter = ""
timeBefore, err := strconv.ParseFloat(*rtb, 64)
if err != nil {
out.Fatal("Error while parsing flag --timeBefore", err)
}
duration := timeAfter - timeBefore
rec := records.Record{
// core
BaseRecord: records.BaseRecord{
CmdLine: *cmdLine,
ExitCode: *exitCode,
// FIXME: use recordint.Postollect
rec := recordint.Collect{
SessionID: *sessionID,
RecordID: *recordID,
Shlvl: *shlvl,
Shell: *shell,
PwdAfter: *pwdAfter,
// non-posix
RealPwdAfter: realPwdAfter,
// before after
TimezoneAfter: *timezoneAfter,
RealtimeBefore: realtimeBefore,
RealtimeAfter: realtimeAfter,
RealtimeAfterLocal: realtimeAfterLocal,
RealtimeDuration: realtimeDuration,
GitDirAfter: gitDirAfter,
GitRealDirAfter: gitRealDirAfter,
GitOriginRemoteAfter: *gitRemoteAfter,
MachineID: collect.ReadFileContent(out.Logger, machineIDPath),
Rec: record.V1{
RecordID: *recordID,
SessionID: *sessionID,
PartOne: false,
ExitCode: *exitCode,
Duration: duration,
ReshUUID: collect.ReadFileContent(out.Logger, reshUUIDPath),
ReshVersion: version,
ReshRevision: commit,
PartsNotMerged: true,
},
}
collect.SendRecord(out, rec, strconv.Itoa(config.Port), "/record")

@ -9,10 +9,9 @@ import (
"github.com/curusarn/resh/internal/collect"
"github.com/curusarn/resh/internal/logger"
"github.com/curusarn/resh/internal/output"
"github.com/curusarn/resh/internal/records"
"github.com/curusarn/resh/internal/recordint"
"go.uber.org/zap"
"path/filepath"
"strconv"
)
@ -30,61 +29,15 @@ func main() {
}
out := output.New(logger, "resh-collect ERROR")
homeDir, err := os.UserHomeDir()
if err != nil {
out.Fatal("Could not get user home dir", err)
}
reshUUIDPath := filepath.Join(homeDir, "/.resh/resh-uuid")
machineIDPath := "/etc/machine-id"
showVersion := flag.Bool("version", false, "Show version and exit")
showRevision := flag.Bool("revision", false, "Show git revision and exit")
requireVersion := flag.String("requireVersion", "", "abort if version doesn't match")
requireRevision := flag.String("requireRevision", "", "abort if revision doesn't match")
shell := flag.String("shell", "", "actual shell")
uname := flag.String("uname", "", "uname")
sessionID := flag.String("sessionId", "", "resh generated session id")
// posix variables
cols := flag.String("cols", "-1", "$COLUMNS")
lines := flag.String("lines", "-1", "$LINES")
home := flag.String("home", "", "$HOME")
lang := flag.String("lang", "", "$LANG")
lcAll := flag.String("lcAll", "", "$LC_ALL")
login := flag.String("login", "", "$LOGIN")
shellEnv := flag.String("shellEnv", "", "$SHELL")
term := flag.String("term", "", "$TERM")
// non-posix
pid := flag.Int("pid", -1, "$$")
sessionPid := flag.Int("sessionPid", -1, "$$ at session start")
shlvl := flag.Int("shlvl", -1, "$SHLVL")
host := flag.String("host", "", "$HOSTNAME")
hosttype := flag.String("hosttype", "", "$HOSTTYPE")
ostype := flag.String("ostype", "", "$OSTYPE")
machtype := flag.String("machtype", "", "$MACHTYPE")
// before after
timezoneBefore := flag.String("timezoneBefore", "", "")
osReleaseID := flag.String("osReleaseId", "", "/etc/os-release ID")
osReleaseVersionID := flag.String("osReleaseVersionId", "",
"/etc/os-release ID")
osReleaseIDLike := flag.String("osReleaseIdLike", "", "/etc/os-release ID")
osReleaseName := flag.String("osReleaseName", "", "/etc/os-release ID")
osReleasePrettyName := flag.String("osReleasePrettyName", "",
"/etc/os-release ID")
rtb := flag.String("realtimeBefore", "-1", "before $EPOCHREALTIME")
rtsess := flag.String("realtimeSession", "-1",
"on session start $EPOCHREALTIME")
rtsessboot := flag.String("realtimeSessSinceBoot", "-1",
"on session start $EPOCHREALTIME")
sessionPID := flag.Int("sessionPid", -1, "$$ at session start")
flag.Parse()
if *showVersion == true {
@ -96,96 +49,16 @@ func main() {
os.Exit(0)
}
if *requireVersion != "" && *requireVersion != version {
fmt.Println("Please restart/reload this terminal session " +
"(resh version: " + version +
"; resh version of this terminal session: " + *requireVersion +
")")
os.Exit(3)
out.FatalVersionMismatch(version, *requireVersion)
}
if *requireRevision != "" && *requireRevision != commit {
fmt.Println("Please restart/reload this terminal session " +
"(resh revision: " + commit +
"; resh revision of this terminal session: " + *requireRevision +
")")
os.Exit(3)
}
realtimeBefore, err := strconv.ParseFloat(*rtb, 64)
if err != nil {
out.Fatal("Error while parsing flag --realtimeBefore", err)
// this is only relevant for dev versions so we can reuse FatalVersionMismatch()
out.FatalVersionMismatch("revision "+commit, "revision "+*requireVersion)
}
realtimeSessionStart, err := strconv.ParseFloat(*rtsess, 64)
if err != nil {
out.Fatal("Error while parsing flag --realtimeSession", err)
}
realtimeSessSinceBoot, err := strconv.ParseFloat(*rtsessboot, 64)
if err != nil {
out.Fatal("Error while parsing flag --realtimeSessSinceBoot", err)
}
realtimeSinceSessionStart := realtimeBefore - realtimeSessionStart
realtimeSinceBoot := realtimeSessSinceBoot + realtimeSinceSessionStart
timezoneBeforeOffset := collect.GetTimezoneOffsetInSeconds(logger, *timezoneBefore)
realtimeBeforeLocal := realtimeBefore + timezoneBeforeOffset
if *osReleaseID == "" {
*osReleaseID = "linux"
}
if *osReleaseName == "" {
*osReleaseName = "Linux"
}
if *osReleasePrettyName == "" {
*osReleasePrettyName = "Linux"
}
rec := records.Record{
// posix
Cols: *cols,
Lines: *lines,
// core
BaseRecord: records.BaseRecord{
Shell: *shell,
Uname: *uname,
rec := recordint.SessionInit{
SessionID: *sessionID,
// posix
Home: *home,
Lang: *lang,
LcAll: *lcAll,
Login: *login,
// Path: *path,
ShellEnv: *shellEnv,
Term: *term,
// non-posix
Pid: *pid,
SessionPID: *sessionPid,
Host: *host,
Hosttype: *hosttype,
Ostype: *ostype,
Machtype: *machtype,
Shlvl: *shlvl,
// before after
TimezoneBefore: *timezoneBefore,
RealtimeBefore: realtimeBefore,
RealtimeBeforeLocal: realtimeBeforeLocal,
RealtimeSinceSessionStart: realtimeSinceSessionStart,
RealtimeSinceBoot: realtimeSinceBoot,
MachineID: collect.ReadFileContent(out.Logger, machineIDPath),
OsReleaseID: *osReleaseID,
OsReleaseVersionID: *osReleaseVersionID,
OsReleaseIDLike: *osReleaseIDLike,
OsReleaseName: *osReleaseName,
OsReleasePrettyName: *osReleasePrettyName,
ReshUUID: collect.ReadFileContent(out.Logger, reshUUIDPath),
ReshVersion: version,
ReshRevision: commit,
},
SessionPID: *sessionPID,
}
collect.SendRecord(out, rec, strconv.Itoa(config.Port), "/session_init")
collect.SendSessionInit(out, rec, strconv.Itoa(config.Port))
}

@ -5,7 +5,6 @@ go 1.18
require (
github.com/BurntSushi/toml v0.4.1
github.com/awesome-gocui/gocui v1.0.0
github.com/mattn/go-shellwords v1.0.12
github.com/mitchellh/go-ps v1.0.0
github.com/spf13/cobra v1.2.1
github.com/whilp/git-urls v1.0.0

@ -193,8 +193,6 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=

@ -92,6 +92,7 @@ func getConfig() (*configFile, error) {
return readConfig(path)
}
// returned config is always usable, returned errors are informative
func processAndFillDefaults(configF *configFile) (Config, error) {
config := defaults

@ -11,14 +11,14 @@ import (
"time"
"github.com/curusarn/resh/internal/output"
"github.com/curusarn/resh/internal/records"
"github.com/curusarn/resh/internal/recordint"
"go.uber.org/zap"
)
// SendRecord to daemon
func SendRecord(out *output.Output, r records.Record, port, path string) {
func SendRecord(out *output.Output, r recordint.Collect, port, path string) {
out.Logger.Debug("Sending record ...",
zap.String("cmdLine", r.CmdLine),
zap.String("cmdLine", r.Rec.CmdLine),
zap.String("sessionID", r.SessionID),
)
recJSON, err := json.Marshal(r)
@ -42,6 +42,33 @@ func SendRecord(out *output.Output, r records.Record, port, path string) {
}
}
// SendSessionInit to daemon
func SendSessionInit(out *output.Output, r recordint.SessionInit, port string) {
out.Logger.Debug("Sending session init ...",
zap.String("sessionID", r.SessionID),
zap.Int("sessionPID", r.SessionPID),
)
recJSON, err := json.Marshal(r)
if err != nil {
out.Fatal("Error while encoding record", err)
}
req, err := http.NewRequest("POST", "http://localhost:"+port+"/session_init",
bytes.NewBuffer(recJSON))
if err != nil {
out.Fatal("Error while sending record", err)
}
req.Header.Set("Content-Type", "application/json")
client := http.Client{
Timeout: 1 * time.Second,
}
_, err = client.Do(req)
if err != nil {
out.FatalDaemonNotRunning(err)
}
}
// ReadFileContent and return it as a string
func ReadFileContent(logger *zap.Logger, path string) string {
dat, err := ioutil.ReadFile(path)

@ -1,13 +1,13 @@
package histcli
import (
"github.com/curusarn/resh/internal/records"
"github.com/curusarn/resh/internal/recordint"
)
// Histcli is a dump of history preprocessed for resh cli purposes
type Histcli struct {
// list of records
List []records.CliRecord
List []recordint.SearchApp
}
// New Histcli
@ -16,16 +16,15 @@ func New() Histcli {
}
// AddRecord to the histcli
func (h *Histcli) AddRecord(record records.Record) {
enriched := records.Enriched(record)
cli := records.NewCliRecord(enriched)
func (h *Histcli) AddRecord(rec *recordint.Indexed) {
cli := recordint.NewSearchApp(rec)
h.List = append(h.List, cli)
}
// AddCmdLine to the histcli
func (h *Histcli) AddCmdLine(cmdline string) {
cli := records.NewCliRecordFromCmdLine(cmdline)
cli := recordint.NewSearchAppFromCmdLine(cmdline)
h.List = append(h.List, cli)
}

@ -1,7 +1,6 @@
package histfile
import (
"encoding/json"
"math"
"os"
"strconv"
@ -9,42 +8,48 @@ import (
"github.com/curusarn/resh/internal/histcli"
"github.com/curusarn/resh/internal/histlist"
"github.com/curusarn/resh/internal/recio"
"github.com/curusarn/resh/internal/record"
"github.com/curusarn/resh/internal/recordint"
"github.com/curusarn/resh/internal/records"
"github.com/curusarn/resh/internal/recutil"
"go.uber.org/zap"
)
// TODO: get rid of histfile - use histio instead
// Histfile writes records to histfile
type Histfile struct {
sugar *zap.SugaredLogger
sessionsMutex sync.Mutex
sessions map[string]records.Record
sessions map[string]recordint.Collect
historyPath string
recentMutex sync.Mutex
recentRecords []records.Record
// NOTE: we have separate histories which only differ if there was not enough resh_history
// resh_history itself is common for both bash and zsh
bashCmdLines histlist.Histlist
zshCmdLines histlist.Histlist
cliRecords histcli.Histcli
rio *recio.RecIO
}
// New creates new histfile and runs its gorutines
func New(sugar *zap.SugaredLogger, input chan records.Record, sessionsToDrop chan string,
func New(sugar *zap.SugaredLogger, input chan recordint.Collect, sessionsToDrop chan string,
reshHistoryPath string, bashHistoryPath string, zshHistoryPath string,
maxInitHistSize int, minInitHistSizeKB int,
signals chan os.Signal, shutdownDone chan string) *Histfile {
rio := recio.New(sugar.With("module", "histfile"))
hf := Histfile{
sugar: sugar.With("module", "histfile"),
sessions: map[string]records.Record{},
sessions: map[string]recordint.Collect{},
historyPath: reshHistoryPath,
bashCmdLines: histlist.New(sugar),
zshCmdLines: histlist.New(sugar),
cliRecords: histcli.New(),
rio: &rio,
}
go hf.loadHistory(bashHistoryPath, zshHistoryPath, maxInitHistSize, minInitHistSizeKB)
go hf.writer(input, signals, shutdownDone)
@ -53,7 +58,7 @@ func New(sugar *zap.SugaredLogger, input chan records.Record, sessionsToDrop cha
}
// load records from resh history, reverse, enrich and save
func (h *Histfile) loadCliRecords(recs []records.Record) {
func (h *Histfile) loadCliRecords(recs []recordint.Indexed) {
for _, cmdline := range h.bashCmdLines.List {
h.cliRecords.AddCmdLine(cmdline)
}
@ -62,7 +67,7 @@ func (h *Histfile) loadCliRecords(recs []records.Record) {
}
for i := len(recs) - 1; i >= 0; i-- {
rec := recs[i]
h.cliRecords.AddRecord(rec)
h.cliRecords.AddRecord(&rec)
}
h.sugar.Infow("Resh history loaded",
"historyRecordsCount", len(h.cliRecords.List),
@ -71,8 +76,6 @@ func (h *Histfile) loadCliRecords(recs []records.Record) {
// loadsHistory from resh_history and if there is not enough of it also load native shell histories
func (h *Histfile) loadHistory(bashHistoryPath, zshHistoryPath string, maxInitHistSize, minInitHistSizeKB int) {
h.recentMutex.Lock()
defer h.recentMutex.Unlock()
h.sugar.Infow("Checking if resh_history is large enough ...")
fi, err := os.Stat(h.historyPath)
var size int
@ -95,7 +98,10 @@ func (h *Histfile) loadHistory(bashHistoryPath, zshHistoryPath string, maxInitHi
h.sugar.Debugw("Loading resh history from file ...",
"historyFile", h.historyPath,
)
history := records.LoadFromFile(h.sugar, h.historyPath)
history, err := h.rio.ReadAndFixFile(h.historyPath, 3)
if err != nil {
h.sugar.Panicf("Failed to read file: %w", err)
}
h.sugar.Infow("Resh history loaded from file",
"historyFile", h.historyPath,
"recordCount", len(history),
@ -130,7 +136,7 @@ func (h *Histfile) sessionGC(sessionsToDrop chan string) {
if part1, found := h.sessions[session]; found == true {
sugar.Infow("Dropping session")
delete(h.sessions, session)
go writeRecord(sugar, part1, h.historyPath)
go h.rio.AppendToFile(h.historyPath, []record.V1{part1.Rec})
} else {
sugar.Infow("No hanging parts for session - nothing to drop")
}
@ -139,43 +145,43 @@ func (h *Histfile) sessionGC(sessionsToDrop chan string) {
}
// writer reads records from channel, merges them and writes them to file
func (h *Histfile) writer(input chan records.Record, signals chan os.Signal, shutdownDone chan string) {
func (h *Histfile) writer(collect chan recordint.Collect, signals chan os.Signal, shutdownDone chan string) {
for {
func() {
select {
case record := <-input:
case rec := <-collect:
part := "2"
if record.PartOne {
if rec.Rec.PartOne {
part = "1"
}
sugar := h.sugar.With(
"recordCmdLine", record.CmdLine,
"recordCmdLine", rec.Rec.CmdLine,
"recordPart", part,
"recordShell", record.Shell,
"recordShell", rec.Shell,
)
sugar.Debugw("Got record")
h.sessionsMutex.Lock()
defer h.sessionsMutex.Unlock()
// allows nested sessions to merge records properly
mergeID := record.SessionID + "_" + strconv.Itoa(record.Shlvl)
mergeID := rec.SessionID + "_" + strconv.Itoa(rec.Shlvl)
sugar = sugar.With("mergeID", mergeID)
if record.PartOne {
if rec.Rec.PartOne {
if _, found := h.sessions[mergeID]; found {
msg := "Got another first part of the records before merging the previous one - overwriting!"
if record.Shell == "zsh" {
if rec.Shell == "zsh" {
sugar.Warnw(msg)
} else {
sugar.Infow(msg + " Unfortunately this is normal in bash, it can't be prevented.")
}
}
h.sessions[mergeID] = record
h.sessions[mergeID] = rec
} else {
if part1, found := h.sessions[mergeID]; found == false {
sugar.Warnw("Got second part of record and nothing to merge it with - ignoring!")
} else {
delete(h.sessions, mergeID)
go h.mergeAndWriteRecord(sugar, part1, record)
go h.mergeAndWriteRecord(sugar, part1, rec)
}
}
case sig := <-signals:
@ -187,11 +193,11 @@ func (h *Histfile) writer(input chan records.Record, signals chan os.Signal, shu
defer h.sessionsMutex.Unlock()
sugar.Debugw("Unlocked mutex")
for sessID, record := range h.sessions {
for sessID, rec := range h.sessions {
sugar.Warnw("Writing incomplete record for session",
"sessionID", sessID,
)
h.writeRecord(sugar, record)
h.writeRecord(sugar, rec.Rec)
}
sugar.Debugw("Shutdown successful")
shutdownDone <- "histfile"
@ -201,52 +207,53 @@ func (h *Histfile) writer(input chan records.Record, signals chan os.Signal, shu
}
}
func (h *Histfile) writeRecord(sugar *zap.SugaredLogger, part1 records.Record) {
writeRecord(sugar, part1, h.historyPath)
func (h *Histfile) writeRecord(sugar *zap.SugaredLogger, rec record.V1) {
h.rio.AppendToFile(h.historyPath, []record.V1{rec})
}
func (h *Histfile) mergeAndWriteRecord(sugar *zap.SugaredLogger, part1, part2 records.Record) {
err := part1.Merge(part2)
func (h *Histfile) mergeAndWriteRecord(sugar *zap.SugaredLogger, part1 recordint.Collect, part2 recordint.Collect) {
rec, err := recutil.Merge(&part1, &part2)
if err != nil {
sugar.Errorw("Error while merging records", "error", err)
return
}
func() {
h.recentMutex.Lock()
defer h.recentMutex.Unlock()
h.recentRecords = append(h.recentRecords, part1)
cmdLine := part1.CmdLine
cmdLine := rec.CmdLine
h.bashCmdLines.AddCmdLine(cmdLine)
h.zshCmdLines.AddCmdLine(cmdLine)
h.cliRecords.AddRecord(part1)
h.cliRecords.AddRecord(&recordint.Indexed{
// TODO: is this what we want?
Rec: rec,
})
}()
writeRecord(sugar, part1, h.historyPath)
h.rio.AppendToFile(h.historyPath, []record.V1{rec})
}
func writeRecord(sugar *zap.SugaredLogger, rec records.Record, outputPath string) {
recJSON, err := json.Marshal(rec)
if err != nil {
sugar.Errorw("Marshalling error", "error", err)
return
}
f, err := os.OpenFile(outputPath,
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
sugar.Errorw("Could not open file", "error", err)
return
}
defer f.Close()
_, err = f.Write(append(recJSON, []byte("\n")...))
if err != nil {
sugar.Errorw("Error while writing record",
"recordRaw", rec,
"error", err,
)
return
}
}
// TODO: use errors in RecIO
// func writeRecord(sugar *zap.SugaredLogger, rec record.V1, outputPath string) {
// recJSON, err := json.Marshal(rec)
// if err != nil {
// sugar.Errorw("Marshalling error", "error", err)
// return
// }
// f, err := os.OpenFile(outputPath,
// os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
// if err != nil {
// sugar.Errorw("Could not open file", "error", err)
// return
// }
// defer f.Close()
// _, err = f.Write(append(recJSON, []byte("\n")...))
// if err != nil {
// sugar.Errorw("Error while writing record",
// "recordRaw", rec,
// "error", err,
// )
// return
// }
// }
// DumpCliRecords returns enriched records
func (h *Histfile) DumpCliRecords() histcli.Histcli {
@ -254,13 +261,13 @@ func (h *Histfile) DumpCliRecords() histcli.Histcli {
return h.cliRecords
}
func loadCmdLines(sugar *zap.SugaredLogger, recs []records.Record) histlist.Histlist {
func loadCmdLines(sugar *zap.SugaredLogger, recs []recordint.Indexed) histlist.Histlist {
hl := histlist.New(sugar)
// go from bottom and deduplicate
var cmdLines []string
cmdLinesSet := map[string]bool{}
for i := len(recs) - 1; i >= 0; i-- {
cmdLine := recs[i].CmdLine
cmdLine := recs[i].Rec.CmdLine
if cmdLinesSet[cmdLine] {
continue
}

@ -1,5 +1,7 @@
package msg
import "github.com/curusarn/resh/internal/recordint"
// CliMsg struct
type CliMsg struct {
SessionID string
@ -8,7 +10,7 @@ type CliMsg struct {
// CliResponse struct
type CliResponse struct {
Records []record.SearchApp
Records []recordint.SearchApp
}
// StatusResponse struct

@ -39,7 +39,7 @@ func (f *Output) Fatal(msg string, err error) {
var msgDeamonNotRunning = `Resh-daemon didn't respond - it's probably not running.
-> Try restarting this terminal window to bring resh-daemon back up
-> If the problem persists you can check resh-daemon logs: ~/.resh/log.json
-> If the problem persists you can check resh-daemon logs: ~/.local/share/resh/log.json (or ~/$XDG_DATA_HOME/resh/log.json)
-> You can create an issue at: https://github.com/curusarn/resh/issues
`
var msgVersionMismatch = `This terminal session was started with different resh version than is installed now.
@ -58,12 +58,18 @@ func (f *Output) FatalDaemonNotRunning(err error) {
f.Logger.Fatal("Daemon is not running", zap.Error(err))
}
func (f *Output) ErrorVersionMismatch(err error) {
fmt.Fprintf(os.Stderr, "%s: %s", f.ErrPrefix, msgVersionMismatch)
f.Logger.Fatal("Version mismatch", zap.Error(err))
func (f *Output) ErrorVersionMismatch(installedVer, terminalVer string) {
fmt.Fprintf(os.Stderr, "%s: %s\n\n(installed version: %s, this terminal version: %s)",
f.ErrPrefix, msgVersionMismatch, installedVer, terminalVer)
f.Logger.Fatal("Version mismatch",
zap.String("installed", installedVer),
zap.String("terminal", terminalVer))
}
func (f *Output) FatalVersionMismatch(err error) {
fmt.Fprintf(os.Stderr, "%s: %s", f.ErrPrefix, msgVersionMismatch)
f.Logger.Fatal("Version mismatch", zap.Error(err))
func (f *Output) FatalVersionMismatch(installedVer, terminalVer string) {
fmt.Fprintf(os.Stderr, "%s: %s\n\n(installed version: %s, this terminal version: %s)",
f.ErrPrefix, msgVersionMismatch, installedVer, terminalVer)
f.Logger.Fatal("Version mismatch",
zap.String("installed", installedVer),
zap.String("terminal", terminalVer))
}

@ -1,9 +1,35 @@
package recconv
import "github.com/curusarn/resh/internal/record"
import (
"github.com/curusarn/resh/internal/record"
)
func LegacyToV1(r *record.Legacy) *record.V1 {
return &record.V1{
// FIXME: fill in all the fields
// Flags: 0,
DeviceID: r.MachineID,
SessionID: r.SessionID,
RecordID: r.RecordID,
CmdLine: r.CmdLine,
ExitCode: r.ExitCode,
Home: r.Home,
Pwd: r.Pwd,
RealPwd: r.RealPwd,
Logname: r.Login,
Hostname: r.Host,
GitOriginRemote: r.GitOriginRemote,
Time: r.RealtimeBefore,
Duration: r.RealtimeDuration,
PartOne: r.PartOne,
PartsNotMerged: !r.PartsMerged,
}
}

@ -48,7 +48,7 @@ func (r *RecIO) ReadAndFixFile(fpath string, maxErrors int) ([]recordint.Indexed
for _, rec := range recs {
recsV1 = append(recsV1, rec.Rec)
}
err = r.WriteFile(fpath, recsV1)
err = r.OverwriteFile(fpath, recsV1)
if err != nil {
r.sugar.Errorw("Failed write fixed history file - aborting fixing history file",
"filename", fpath,

@ -10,37 +10,53 @@ import (
)
// TODO: better errors
func (r *RecIO) WriteFile(fpath string, data []record.V1) error {
func (r *RecIO) OverwriteFile(fpath string, recs []record.V1) error {
file, err := os.Create(fpath)
if err != nil {
return err
}
defer file.Close()
for _, rec := range data {
jsn, err := encodeV1Record(rec)
if err != nil {
return err
return writeRecords(file, recs)
}
_, err = file.Write(jsn)
// TODO: better errors
func (r *RecIO) AppendToFile(fpath string, recs []record.V1) error {
file, err := os.OpenFile(fpath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
}
return nil
defer file.Close()
return writeRecords(file, recs)
}
// TODO: better errors
func (r *RecIO) EditRecordFlagsInFile(fpath string, idx int, rec recordint.Flag) error {
// FIXME: implement
// open file "not as append"
// scan to the correct line
r.sugar.Error("not implemented yet (FIXME)")
return nil
}
func writeRecords(file *os.File, recs []record.V1) error {
for _, rec := range recs {
jsn, err := encodeV1Record(rec)
if err != nil {
return err
}
_, err = file.Write(jsn)
if err != nil {
return err
}
}
return nil
}
func encodeV1Record(rec record.V1) ([]byte, error) {
version := []byte("v1")
jsn, err := json.Marshal(rec)
if err != nil {
return nil, fmt.Errorf("failed to encode json: %w", err)
}
return append(jsn, []byte("\n")...), nil
return append(append(version, jsn...), []byte("\n")...), nil
}

@ -16,6 +16,7 @@ type V1 struct {
ExitCode int `json:"exitCode"`
// paths
// TODO: Do we need both pwd and real pwd?
Home string `json:"home"`
Pwd string `json:"pwd"`
RealPwd string `json:"realPwd"`
@ -27,8 +28,9 @@ type V1 struct {
// git info
// origin is the most important
GitOriginRemote string `json:"gitOriginRemote"`
// TODO: add GitBranch (v2 ?)
// maybe branch could be useful - e.g. in monorepo ??
GitBranch string `json:"gitBranch"`
// GitBranch string `json:"gitBranch"`
// what is this for ??
// session watching needs this
@ -36,11 +38,11 @@ type V1 struct {
// records belong to sessions
// PID int `json:"pid"`
// needed for tracking of sessions but I think it shouldn't be part of V1
SessionPID int `json:"sessionPID"`
// SessionPID int `json:"sessionPID"`
// needed to because records are merged with parts with same "SessionID + Shlvl"
// I don't think we need to save it
Shlvl int `json:"shlvl"`
// Shlvl int `json:"shlvl"`
// time (before), duration of command
Time float64 `json:"time"`

@ -8,6 +8,7 @@ type Collect struct {
Shlvl int
// session watching
SessionPID int
Shell string
Rec record.V1
}
@ -18,4 +19,16 @@ type Postcollect struct {
Shlvl int
// session watching
SessionPID int
RecordID string
ExitCode int
Duration float64
}
type SessionInit struct {
// record merging
SessionID string
Shlvl int
// session watching
SessionPID int
}

@ -1,51 +0,0 @@
package recordint
import (
"github.com/curusarn/resh/internal/record"
"github.com/curusarn/resh/internal/recutil"
)
// TODO: This all seems excessive
// TODO: V1 should be converted directly to SearchApp record
// EnrichedRecord - record enriched with additional data
type Enriched struct {
// TODO: think about if it really makes sense to have this based on V1
record.V1
// TODO: drop some/all of this
// enriching fields - added "later"
Command string `json:"command"`
FirstWord string `json:"firstWord"`
Invalid bool `json:"invalid"`
SeqSessionID uint64 `json:"seqSessionId"`
LastRecordOfSession bool `json:"lastRecordOfSession"`
DebugThisRecord bool `json:"debugThisRecord"`
Errors []string `json:"errors"`
// SeqSessionID uint64 `json:"seqSessionId,omitempty"`
}
// Enriched - returns enriched record
func NewEnrichedFromV1(r *record.V1) Enriched {
rec := Enriched{Record: r}
// normlize git remote
rec.GitOriginRemote = NormalizeGitRemote(rec.GitOriginRemote)
rec.GitOriginRemoteAfter = NormalizeGitRemote(rec.GitOriginRemoteAfter)
// Get command/first word from commandline
var err error
err = recutil.Validate(r)
if err != nil {
rec.Errors = append(rec.Errors, "Validate error:"+err.Error())
// rec, _ := record.ToString()
// sugar.Println("Invalid command:", rec)
rec.Invalid = true
}
rec.Command, rec.FirstWord, err = GetCommandAndFirstWord(r.CmdLine)
if err != nil {
rec.Errors = append(rec.Errors, "GetCommandAndFirstWord error:"+err.Error())
// rec, _ := record.ToString()
// sugar.Println("Invalid command:", rec)
rec.Invalid = true // should this be really invalid ?
}
return rec
}

@ -1,5 +1,12 @@
package recordint
import (
"net/url"
"strings"
giturls "github.com/whilp/git-urls"
)
// SearchApp record used for sending records to RESH-CLI
type SearchApp struct {
IsRaw bool
@ -14,6 +21,9 @@ type SearchApp struct {
ExitCode int
Time float64
// file index
Idx int
}
// NewCliRecordFromCmdLine
@ -25,16 +35,39 @@ func NewSearchAppFromCmdLine(cmdLine string) SearchApp {
}
// NewCliRecord from EnrichedRecord
func NewSearchApp(r *Enriched) SearchApp {
func NewSearchApp(r *Indexed) SearchApp {
// TODO: we used to validate records with recutil.Validate()
return SearchApp{
IsRaw: false,
SessionID: r.SessionID,
CmdLine: r.CmdLine,
Host: r.Hostname,
Pwd: r.Pwd,
Home: r.Home,
GitOriginRemote: r.GitOriginRemote,
ExitCode: r.ExitCode,
Time: r.Time,
SessionID: r.Rec.SessionID,
CmdLine: r.Rec.CmdLine,
Host: r.Rec.Hostname,
Pwd: r.Rec.Pwd,
Home: r.Rec.Home,
// TODO: is this the right place to normalize the git remote
GitOriginRemote: normalizeGitRemote(r.Rec.GitOriginRemote),
ExitCode: r.Rec.ExitCode,
Time: r.Rec.Time,
Idx: r.Idx,
}
}
// TODO: maybe move this to a more appropriate place
// normalizeGitRemote helper
func normalizeGitRemote(gitRemote string) string {
if strings.HasSuffix(gitRemote, ".git") {
gitRemote = gitRemote[:len(gitRemote)-4]
}
parsedURL, err := giturls.Parse(gitRemote)
if err != nil {
// TODO: log this error
return gitRemote
}
if parsedURL.User == nil || parsedURL.User.Username() == "" {
parsedURL.User = url.User("git")
}
// TODO: figure out what scheme we want
parsedURL.Scheme = "git+ssh"
return parsedURL.String()
}

@ -2,269 +2,13 @@ package records
import (
"bufio"
"encoding/json"
"fmt"
"io"
"os"
"strconv"
"strings"
"github.com/curusarn/resh/internal/histlist"
"go.uber.org/zap"
)
// BaseRecord - common base for Record and FallbackRecord
type BaseRecord struct {
// core
CmdLine string `json:"cmdLine"`
ExitCode int `json:"exitCode"`
Shell string `json:"shell"`
Uname string `json:"uname"`
SessionID string `json:"sessionId"`
RecordID string `json:"recordId"`
// posix
Home string `json:"home"`
Lang string `json:"lang"`
LcAll string `json:"lcAll"`
Login string `json:"login"`
//Path string `json:"path"`
Pwd string `json:"pwd"`
PwdAfter string `json:"pwdAfter"`
ShellEnv string `json:"shellEnv"`
Term string `json:"term"`
// non-posix"`
RealPwd string `json:"realPwd"`
RealPwdAfter string `json:"realPwdAfter"`
Pid int `json:"pid"`
SessionPID int `json:"sessionPid"`
Host string `json:"host"`
Hosttype string `json:"hosttype"`
Ostype string `json:"ostype"`
Machtype string `json:"machtype"`
Shlvl int `json:"shlvl"`
// before after
TimezoneBefore string `json:"timezoneBefore"`
TimezoneAfter string `json:"timezoneAfter"`
RealtimeBefore float64 `json:"realtimeBefore"`
RealtimeAfter float64 `json:"realtimeAfter"`
RealtimeBeforeLocal float64 `json:"realtimeBeforeLocal"`
RealtimeAfterLocal float64 `json:"realtimeAfterLocal"`
RealtimeDuration float64 `json:"realtimeDuration"`
RealtimeSinceSessionStart float64 `json:"realtimeSinceSessionStart"`
RealtimeSinceBoot float64 `json:"realtimeSinceBoot"`
//Logs []string `json: "logs"`
GitDir string `json:"gitDir"`
GitRealDir string `json:"gitRealDir"`
GitOriginRemote string `json:"gitOriginRemote"`
GitDirAfter string `json:"gitDirAfter"`
GitRealDirAfter string `json:"gitRealDirAfter"`
GitOriginRemoteAfter string `json:"gitOriginRemoteAfter"`
MachineID string `json:"machineId"`
OsReleaseID string `json:"osReleaseId"`
OsReleaseVersionID string `json:"osReleaseVersionId"`
OsReleaseIDLike string `json:"osReleaseIdLike"`
OsReleaseName string `json:"osReleaseName"`
OsReleasePrettyName string `json:"osReleasePrettyName"`
ReshUUID string `json:"reshUuid"`
ReshVersion string `json:"reshVersion"`
ReshRevision string `json:"reshRevision"`
// records come in two parts (collect and postcollect)
PartOne bool `json:"partOne,omitempty"` // false => part two
PartsMerged bool `json:"partsMerged"`
// special flag -> not an actual record but an session end
SessionExit bool `json:"sessionExit,omitempty"`
// recall metadata
Recalled bool `json:"recalled"`
RecallHistno int `json:"recallHistno,omitempty"`
RecallStrategy string `json:"recallStrategy,omitempty"`
RecallActionsRaw string `json:"recallActionsRaw,omitempty"`
RecallActions []string `json:"recallActions,omitempty"`
RecallLastCmdLine string `json:"recallLastCmdLine"`
// recall command
RecallPrefix string `json:"recallPrefix,omitempty"`
// added by sanitizatizer
Sanitized bool `json:"sanitized,omitempty"`
CmdLength int `json:"cmdLength,omitempty"`
}
// Record representing single executed command with its metadata
type Record struct {
BaseRecord
Cols string `json:"cols"`
Lines string `json:"lines"`
}
// EnrichedRecord - record enriched with additional data
type EnrichedRecord struct {
Record
// enriching fields - added "later"
Command string `json:"command"`
FirstWord string `json:"firstWord"`
Invalid bool `json:"invalid"`
SeqSessionID uint64 `json:"seqSessionId"`
LastRecordOfSession bool `json:"lastRecordOfSession"`
DebugThisRecord bool `json:"debugThisRecord"`
Errors []string `json:"errors"`
// SeqSessionID uint64 `json:"seqSessionId,omitempty"`
}
// FallbackRecord when record is too old and can't be parsed into regular Record
type FallbackRecord struct {
BaseRecord
// older version of the record where cols and lines are int
Cols int `json:"cols"` // notice the int type
Lines int `json:"lines"` // notice the int type
}
// Convert from FallbackRecord to Record
func Convert(r *FallbackRecord) Record {
return Record{
BaseRecord: r.BaseRecord,
// these two lines are the only reason we are doing this
Cols: strconv.Itoa(r.Cols),
Lines: strconv.Itoa(r.Lines),
}
}
// ToString - returns record the json
func (r EnrichedRecord) ToString() (string, error) {
jsonRec, err := json.Marshal(r)
if err != nil {
return "marshalling error", err
}
return string(jsonRec), nil
}
// LoadFromFile loads records from 'fname' file
func LoadFromFile(sugar *zap.SugaredLogger, fname string) []Record {
const allowedErrors = 3
var encounteredErrors int
var recs []Record
file, err := os.Open(fname)
if err != nil {
sugar.Error("Failed to open resh history file - skipping reading resh history", zap.Error(err))
return recs
}
defer file.Close()
reader := bufio.NewReader(file)
var i int
for {
var line string
line, err = reader.ReadString('\n')
if err != nil {
break
}
i++
record := Record{}
fallbackRecord := FallbackRecord{}
err = json.Unmarshal([]byte(line), &record)
if err != nil {
err = json.Unmarshal([]byte(line), &fallbackRecord)
if err != nil {
encounteredErrors++
sugar.Error("Could not decode line in resh history file",
"lineContents", line,
"lineNumber", i,
zap.Error(err),
)
if encounteredErrors > allowedErrors {
sugar.Fatal("Encountered too many errors during decoding - exiting",
"allowedErrors", allowedErrors,
)
}
}
record = Convert(&fallbackRecord)
}
recs = append(recs, record)
}
if err != io.EOF {
sugar.Error("Error while loading file", zap.Error(err))
}
sugar.Infow("Loaded resh history records",
"recordCount", len(recs),
)
if encounteredErrors > 0 {
// fix errors in the history file
sugar.Warnw("Some history records could not be decoded - fixing resh history file by dropping them",
"corruptedRecords", encounteredErrors,
)
fnameBak := fname + ".bak"
sugar.Infow("Backing up current corrupted history file",
"backupFilename", fnameBak,
)
err := copyFile(fname, fnameBak)
if err != nil {
sugar.Errorw("Failed to create a backup history file - aborting fixing history file",
"backupFilename", fnameBak,
zap.Error(err),
)
return recs
}
sugar.Info("Writing resh history file without errors ...")
err = writeHistory(fname, recs)
if err != nil {
sugar.Errorw("Failed write fixed history file - aborting fixing history file",
"filename", fname,
zap.Error(err),
)
}
}
return recs
}
func copyFile(source, dest string) error {
from, err := os.Open(source)
if err != nil {
return err
}
defer from.Close()
// to, err := os.OpenFile(dest, os.O_RDWR|os.O_CREATE, 0666)
to, err := os.Create(dest)
if err != nil {
return err
}
defer to.Close()
_, err = io.Copy(to, from)
if err != nil {
return err
}
return nil
}
func writeHistory(fname string, history []Record) error {
file, err := os.Create(fname)
if err != nil {
return err
}
defer file.Close()
for _, rec := range history {
jsn, err := json.Marshal(rec)
if err != nil {
return fmt.Errorf("failed to encode record: %w", err)
}
file.Write(append(jsn, []byte("\n")...))
}
return nil
}
// LoadCmdLinesFromZshFile loads cmdlines from zsh history file
func LoadCmdLinesFromZshFile(sugar *zap.SugaredLogger, fname string) histlist.Histlist {
hl := histlist.New(sugar)

@ -1,85 +0,0 @@
package records
import (
"bufio"
"encoding/json"
"log"
"os"
"testing"
)
func GetTestRecords() []Record {
file, err := os.Open("testdata/resh_history.json")
if err != nil {
log.Fatalf("Failed to open resh history file: %v", err)
}
defer file.Close()
var recs []Record
scanner := bufio.NewScanner(file)
for scanner.Scan() {
record := Record{}
line := scanner.Text()
err = json.Unmarshal([]byte(line), &record)
if err != nil {
log.Fatalf("Error decoding record: '%s'; err: %v", line, err)
}
recs = append(recs, record)
}
return recs
}
func GetTestEnrichedRecords() []EnrichedRecord {
var recs []EnrichedRecord
for _, rec := range GetTestRecords() {
recs = append(recs, Enriched(rec))
}
return recs
}
func TestToString(t *testing.T) {
for _, rec := range GetTestEnrichedRecords() {
_, err := rec.ToString()
if err != nil {
t.Error("ToString() failed")
}
}
}
func TestEnriched(t *testing.T) {
record := Record{BaseRecord: BaseRecord{CmdLine: "cmd arg1 arg2"}}
enriched := Enriched(record)
if enriched.FirstWord != "cmd" || enriched.Command != "cmd" {
t.Error("Enriched() returned reocord w/ wrong Command OR FirstWord")
}
}
func TestValidate(t *testing.T) {
record := EnrichedRecord{}
if record.Validate() == nil {
t.Error("Validate() didn't return an error for invalid record")
}
record.CmdLine = "cmd arg"
record.FirstWord = "cmd"
record.Command = "cmd"
time := 1234.5678
record.RealtimeBefore = time
record.RealtimeAfter = time
record.RealtimeBeforeLocal = time
record.RealtimeAfterLocal = time
pwd := "/pwd"
record.Pwd = pwd
record.PwdAfter = pwd
record.RealPwd = pwd
record.RealPwdAfter = pwd
if record.Validate() != nil {
t.Error("Validate() returned an error for a valid record")
}
}
func TestGetCommandAndFirstWord(t *testing.T) {
cmd, stWord, err := GetCommandAndFirstWord("cmd arg1 arg2")
if err != nil || cmd != "cmd" || stWord != "cmd" {
t.Error("GetCommandAndFirstWord() returned wrong Command OR FirstWord")
}
}

@ -1,27 +0,0 @@
{"cmdLine":"ls","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"d5c0fe70-c80b-4715-87cb-f8d8d5b4c673","cols":"80","lines":"24","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon","pwdAfter":"/home/simon","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon","realPwdAfter":"/home/simon","pid":14560,"sessionPid":14560,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1566762905.173595,"realtimeAfter":1566762905.1894295,"realtimeBeforeLocal":1566770105.173595,"realtimeAfterLocal":1566770105.1894295,"realtimeDuration":0.015834569931030273,"realtimeSinceSessionStart":1.7122540473937988,"realtimeSinceBoot":20766.542254047396,"gitDir":"","gitRealDir":"","gitOriginRemote":"","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"752acb916f2a"}
{"cmdLine":"find . -name applications","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"c5251955-3a64-4353-952e-08d62a898694","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon","pwdAfter":"/home/simon","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon","realPwdAfter":"/home/simon","pid":3109,"sessionPid":3109,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1567420001.2531302,"realtimeAfter":1567420002.4311218,"realtimeBeforeLocal":1567427201.2531302,"realtimeAfterLocal":1567427202.4311218,"realtimeDuration":1.1779916286468506,"realtimeSinceSessionStart":957.4848053455353,"realtimeSinceBoot":2336.594805345535,"gitDir":"","gitRealDir":"","gitOriginRemote":"","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"752acb916f2a"}
{"cmdLine":"desktop-file-validate curusarn.sync-clipboards.desktop ","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"c5251955-3a64-4353-952e-08d62a898694","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/.local/share/applications","pwdAfter":"/home/simon/.local/share/applications","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/.local/share/applications","realPwdAfter":"/home/simon/.local/share/applications","pid":3109,"sessionPid":3109,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1567421748.2965438,"realtimeAfter":1567421748.3068867,"realtimeBeforeLocal":1567428948.2965438,"realtimeAfterLocal":1567428948.3068867,"realtimeDuration":0.010342836380004883,"realtimeSinceSessionStart":2704.528218984604,"realtimeSinceBoot":4083.6382189846036,"gitDir":"","gitRealDir":"","gitOriginRemote":"","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"752acb916f2a"}
{"cmdLine":"cat /tmp/extensions | grep '.'","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"f044cdbf-fd51-4c37-8528-dcd98fc7b6d9","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon","pwdAfter":"/home/simon","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon","realPwdAfter":"/home/simon","pid":6887,"sessionPid":6887,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1567461416.6871984,"realtimeAfter":1567461416.7336714,"realtimeBeforeLocal":1567468616.6871984,"realtimeAfterLocal":1567468616.7336714,"realtimeDuration":0.046473026275634766,"realtimeSinceSessionStart":21.45597553253174,"realtimeSinceBoot":43752.03597553253,"gitDir":"","gitRealDir":"","gitOriginRemote":"","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"752acb916f2a"}
{"cmdLine":"cd git/resh/","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"f044cdbf-fd51-4c37-8528-dcd98fc7b6d9","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon","realPwdAfter":"/home/simon/git/resh","pid":6887,"sessionPid":6887,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1567461667.8806899,"realtimeAfter":1567461667.8949044,"realtimeBeforeLocal":1567468867.8806899,"realtimeAfterLocal":1567468867.8949044,"realtimeDuration":0.014214515686035156,"realtimeSinceSessionStart":272.64946699142456,"realtimeSinceBoot":44003.229466991426,"gitDir":"","gitRealDir":"","gitOriginRemote":"","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"752acb916f2a"}
{"cmdLine":"git s","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"f044cdbf-fd51-4c37-8528-dcd98fc7b6d9","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":6887,"sessionPid":6887,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1567461707.6467602,"realtimeAfter":1567461707.7177293,"realtimeBeforeLocal":1567468907.6467602,"realtimeAfterLocal":1567468907.7177293,"realtimeDuration":0.0709691047668457,"realtimeSinceSessionStart":312.4155373573303,"realtimeSinceBoot":44042.99553735733,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"752acb916f2a"}
{"cmdLine":"cat /tmp/extensions | grep '^\\.' | cut -f1 |tr '[:upper:]' '[:lower:]' ","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"f044cdbf-fd51-4c37-8528-dcd98fc7b6d9","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":6887,"sessionPid":6887,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1567461722.813049,"realtimeAfter":1567461722.8280325,"realtimeBeforeLocal":1567468922.813049,"realtimeAfterLocal":1567468922.8280325,"realtimeDuration":0.014983415603637695,"realtimeSinceSessionStart":327.581826210022,"realtimeSinceBoot":44058.161826210024,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"752acb916f2a"}
{"cmdLine":"tig","exitCode":127,"shell":"bash","uname":"Linux","sessionId":"f044cdbf-fd51-4c37-8528-dcd98fc7b6d9","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":6887,"sessionPid":6887,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1567461906.3896828,"realtimeAfter":1567461906.4084594,"realtimeBeforeLocal":1567469106.3896828,"realtimeAfterLocal":1567469106.4084594,"realtimeDuration":0.018776655197143555,"realtimeSinceSessionStart":511.1584599018097,"realtimeSinceBoot":44241.73845990181,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"752acb916f2a"}
{"cmdLine":"resh-sanitize-history | jq","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"a3318c80-3521-4b22-aa64-ea0f6c641410","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon","pwdAfter":"/home/simon","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon","realPwdAfter":"/home/simon","pid":14601,"sessionPid":14601,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1567547116.2430356,"realtimeAfter":1567547116.7547352,"realtimeBeforeLocal":1567554316.2430356,"realtimeAfterLocal":1567554316.7547352,"realtimeDuration":0.5116996765136719,"realtimeSinceSessionStart":15.841878414154053,"realtimeSinceBoot":30527.201878414155,"gitDir":"","gitRealDir":"","gitOriginRemote":"","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"737bc0a4df38","cmdLength":0}
{"cmdLine":"sudo pacman -S ansible","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"64154f2d-a4bc-4463-a690-520080b61ead","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/kristin","pwdAfter":"/home/simon/git/kristin","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/kristin","realPwdAfter":"/home/simon/git/kristin","pid":5663,"sessionPid":5663,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1567609042.0166302,"realtimeAfter":1567609076.9726007,"realtimeBeforeLocal":1567616242.0166302,"realtimeAfterLocal":1567616276.9726007,"realtimeDuration":34.95597052574158,"realtimeSinceSessionStart":1617.0794131755829,"realtimeSinceBoot":6120.029413175583,"gitDir":"/home/simon/git/kristin","gitRealDir":"/home/simon/git/kristin","gitOriginRemote":"git@gitlab.com:sucvut/kristin.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"737bc0a4df38","cmdLength":0}
{"cmdLine":"vagrant up","exitCode":1,"shell":"bash","uname":"Linux","sessionId":"64154f2d-a4bc-4463-a690-520080b61ead","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/kristin","pwdAfter":"/home/simon/git/kristin","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/kristin","realPwdAfter":"/home/simon/git/kristin","pid":5663,"sessionPid":5663,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1567609090.7359188,"realtimeAfter":1567609098.3125577,"realtimeBeforeLocal":1567616290.7359188,"realtimeAfterLocal":1567616298.3125577,"realtimeDuration":7.57663893699646,"realtimeSinceSessionStart":1665.798701763153,"realtimeSinceBoot":6168.748701763153,"gitDir":"/home/simon/git/kristin","gitRealDir":"/home/simon/git/kristin","gitOriginRemote":"git@gitlab.com:sucvut/kristin.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"737bc0a4df38","cmdLength":0}
{"cmdLine":"sudo modprobe vboxnetflt","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"64154f2d-a4bc-4463-a690-520080b61ead","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/kristin","pwdAfter":"/home/simon/git/kristin","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/kristin","realPwdAfter":"/home/simon/git/kristin","pid":5663,"sessionPid":5663,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1567609143.2847652,"realtimeAfter":1567609143.3116078,"realtimeBeforeLocal":1567616343.2847652,"realtimeAfterLocal":1567616343.3116078,"realtimeDuration":0.026842594146728516,"realtimeSinceSessionStart":1718.3475482463837,"realtimeSinceBoot":6221.2975482463835,"gitDir":"/home/simon/git/kristin","gitRealDir":"/home/simon/git/kristin","gitOriginRemote":"git@gitlab.com:sucvut/kristin.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"737bc0a4df38","cmdLength":0}
{"cmdLine":"echo $RANDOM","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"8ddacadc-6e73-483c-b347-4e18df204466","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon","pwdAfter":"/home/simon","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon","realPwdAfter":"/home/simon","pid":31387,"sessionPid":31387,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1567727039.6540458,"realtimeAfter":1567727039.6629689,"realtimeBeforeLocal":1567734239.6540458,"realtimeAfterLocal":1567734239.6629689,"realtimeDuration":0.008923053741455078,"realtimeSinceSessionStart":1470.7667458057404,"realtimeSinceBoot":18495.01674580574,"gitDir":"","gitRealDir":"","gitOriginRemote":"","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"737bc0a4df38","cmdLength":0}
{"cmdLine":"make resh-evaluate ","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"93998b68-ec48-4e48-9e4a-b37b39f5439e","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":9463,"sessionPid":9463,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1567977478.9672194,"realtimeAfter":1567977479.5449634,"realtimeBeforeLocal":1567984678.9672194,"realtimeAfterLocal":1567984679.5449634,"realtimeDuration":0.5777440071105957,"realtimeSinceSessionStart":5738.577540636063,"realtimeSinceBoot":20980.42754063606,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"737bc0a4df38","cmdLength":0}
{"cmdLine":"cat ~/.resh_history.json | grep \"./resh-eval\" | jq","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"93998b68-ec48-4e48-9e4a-b37b39f5439e","cols":"105","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":9463,"sessionPid":9463,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1567986105.3988302,"realtimeAfter":1567986105.4809113,"realtimeBeforeLocal":1567993305.3988302,"realtimeAfterLocal":1567993305.4809113,"realtimeDuration":0.08208107948303223,"realtimeSinceSessionStart":14365.00915145874,"realtimeSinceBoot":29606.85915145874,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"737bc0a4df38","cmdLength":0}
{"cmdLine":"git c \"add sanitized flag to record, add Enrich() to record\"","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"93998b68-ec48-4e48-9e4a-b37b39f5439e","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":9463,"sessionPid":9463,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1568063976.9103937,"realtimeAfter":1568063976.9326868,"realtimeBeforeLocal":1568071176.9103937,"realtimeAfterLocal":1568071176.9326868,"realtimeDuration":0.0222930908203125,"realtimeSinceSessionStart":92236.52071499825,"realtimeSinceBoot":107478.37071499825,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"737bc0a4df38","cmdLength":0}
{"cmdLine":"git s","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"93998b68-ec48-4e48-9e4a-b37b39f5439e","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":9463,"sessionPid":9463,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1568063978.2340608,"realtimeAfter":1568063978.252463,"realtimeBeforeLocal":1568071178.2340608,"realtimeAfterLocal":1568071178.252463,"realtimeDuration":0.0184023380279541,"realtimeSinceSessionStart":92237.84438204765,"realtimeSinceBoot":107479.69438204766,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"737bc0a4df38","cmdLength":0}
{"cmdLine":"git a evaluate/results.go ","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"93998b68-ec48-4e48-9e4a-b37b39f5439e","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":9463,"sessionPid":9463,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1568063989.0446353,"realtimeAfter":1568063989.2452207,"realtimeBeforeLocal":1568071189.0446353,"realtimeAfterLocal":1568071189.2452207,"realtimeDuration":0.20058536529541016,"realtimeSinceSessionStart":92248.65495657921,"realtimeSinceBoot":107490.50495657921,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"737bc0a4df38","cmdLength":0}
{"cmdLine":"sudo pacman -S python-pip","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"93998b68-ec48-4e48-9e4a-b37b39f5439e","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":9463,"sessionPid":9463,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1568072068.3557143,"realtimeAfter":1568072070.7509863,"realtimeBeforeLocal":1568079268.3557143,"realtimeAfterLocal":1568079270.7509863,"realtimeDuration":2.3952720165252686,"realtimeSinceSessionStart":100327.96603560448,"realtimeSinceBoot":115569.81603560448,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"737bc0a4df38","cmdLength":0}
{"cmdLine":"pip3 install matplotlib","exitCode":1,"shell":"bash","uname":"Linux","sessionId":"93998b68-ec48-4e48-9e4a-b37b39f5439e","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":9463,"sessionPid":9463,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1568072088.5575967,"realtimeAfter":1568072094.372314,"realtimeBeforeLocal":1568079288.5575967,"realtimeAfterLocal":1568079294.372314,"realtimeDuration":5.8147172927856445,"realtimeSinceSessionStart":100348.16791796684,"realtimeSinceBoot":115590.01791796685,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"737bc0a4df38","cmdLength":0}
{"cmdLine":"sudo pip3 install matplotlib","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"93998b68-ec48-4e48-9e4a-b37b39f5439e","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":9463,"sessionPid":9463,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1568072106.138616,"realtimeAfter":1568072115.1124601,"realtimeBeforeLocal":1568079306.138616,"realtimeAfterLocal":1568079315.1124601,"realtimeDuration":8.973844051361084,"realtimeSinceSessionStart":100365.7489373684,"realtimeSinceBoot":115607.5989373684,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"737bc0a4df38","cmdLength":0}
{"cmdLine":"./resh-evaluate --plotting-script evaluate/resh-evaluate-plot.py --input ~/git/resh_private/history_data/simon/dell/resh_history.json ","exitCode":130,"shell":"bash","uname":"Linux","sessionId":"93998b68-ec48-4e48-9e4a-b37b39f5439e","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":9463,"sessionPid":9463,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1568076266.9364285,"realtimeAfter":1568076288.1131275,"realtimeBeforeLocal":1568083466.9364285,"realtimeAfterLocal":1568083488.1131275,"realtimeDuration":21.176698923110962,"realtimeSinceSessionStart":104526.54674983025,"realtimeSinceBoot":119768.39674983025,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.1","reshRevision":"737bc0a4df38","cmdLength":0}
{"cmdLine":"git c \"Add a bunch of useless comments to make linter happy\"","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"04050353-a97d-4435-9248-f47dd08b2f2a","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":14702,"sessionPid":14702,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1569456045.8763022,"realtimeAfter":1569456045.9030173,"realtimeBeforeLocal":1569463245.8763022,"realtimeAfterLocal":1569463245.9030173,"realtimeDuration":0.02671504020690918,"realtimeSinceSessionStart":2289.789242744446,"realtimeSinceBoot":143217.91924274445,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.3","reshRevision":"188d8b420493","sanitized":false}
{"cmdLine":"fuck","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"a4aadf03-610d-4731-ba94-5b7ce21e7bb9","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":3413,"sessionPid":3413,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1569687682.4250975,"realtimeAfter":1569687682.5877323,"realtimeBeforeLocal":1569694882.4250975,"realtimeAfterLocal":1569694882.5877323,"realtimeDuration":0.16263484954833984,"realtimeSinceSessionStart":264603.49496507645,"realtimeSinceBoot":374854.48496507644,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.3","reshRevision":"188d8b420493","sanitized":false}
{"cmdLine":"code .","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"87c7ab14-ae51-408d-adbc-fc4f9d28de6e","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":31947,"sessionPid":31947,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1569709366.523767,"realtimeAfter":1569709367.516908,"realtimeBeforeLocal":1569716566.523767,"realtimeAfterLocal":1569716567.516908,"realtimeDuration":0.9931409358978271,"realtimeSinceSessionStart":23846.908839941025,"realtimeSinceBoot":396539.888839941,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.3","reshRevision":"188d8b420493","sanitized":false}
{"cmdLine":"make test","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"87c7ab14-ae51-408d-adbc-fc4f9d28de6e","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon/git/resh","pwdAfter":"/home/simon/git/resh","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon/git/resh","realPwdAfter":"/home/simon/git/resh","pid":31947,"sessionPid":31947,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1569709371.89966,"realtimeAfter":1569709377.430194,"realtimeBeforeLocal":1569716571.89966,"realtimeAfterLocal":1569716577.430194,"realtimeDuration":5.530533790588379,"realtimeSinceSessionStart":23852.284733057022,"realtimeSinceBoot":396545.264733057,"gitDir":"/home/simon/git/resh","gitRealDir":"/home/simon/git/resh","gitOriginRemote":"git@github.com:curusarn/resh.git","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.3","reshRevision":"188d8b420493","sanitized":false}
{"cmdLine":"mkdir ~/git/resh/testdata","exitCode":0,"shell":"bash","uname":"Linux","sessionId":"71529b60-2e7b-4d5b-8dc1-6d0740b58e9e","cols":"211","lines":"56","home":"/home/simon","lang":"en_US.UTF-8","lcAll":"","login":"simon","pwd":"/home/simon","pwdAfter":"/home/simon","shellEnv":"/bin/bash","term":"xterm-256color","realPwd":"/home/simon","realPwdAfter":"/home/simon","pid":21224,"sessionPid":21224,"host":"simon-pc","hosttype":"x86_64","ostype":"linux-gnu","machtype":"x86_64-pc-linux-gnu","shlvl":1,"timezoneBefore":"+0200","timezoneAfter":"+0200","realtimeBefore":1569709838.4642656,"realtimeAfter":1569709838.4718792,"realtimeBeforeLocal":1569717038.4642656,"realtimeAfterLocal":1569717038.4718792,"realtimeDuration":0.007613658905029297,"realtimeSinceSessionStart":9.437154054641724,"realtimeSinceBoot":397011.02715405467,"gitDir":"","gitRealDir":"","gitOriginRemote":"","machineId":"c70365240bc647f09e2490722cc8186b","osReleaseId":"manjaro","osReleaseVersionId":"","osReleaseIdLike":"arch","osReleaseName":"Manjaro Linux","osReleasePrettyName":"Manjaro Linux","reshUuid":"","reshVersion":"1.1.3","reshRevision":"188d8b420493","sanitized":false}

@ -2,93 +2,50 @@ package recutil
import (
"errors"
"net/url"
"strings"
"github.com/curusarn/resh/internal/record"
"github.com/mattn/go-shellwords"
giturls "github.com/whilp/git-urls"
"github.com/curusarn/resh/internal/recordint"
)
// NormalizeGitRemote helper
func NormalizeGitRemote(gitRemote string) string {
if strings.HasSuffix(gitRemote, ".git") {
gitRemote = gitRemote[:len(gitRemote)-4]
}
parsedURL, err := giturls.Parse(gitRemote)
if err != nil {
// TODO: log this error
return gitRemote
}
if parsedURL.User == nil || parsedURL.User.Username() == "" {
parsedURL.User = url.User("git")
}
// TODO: figure out what scheme we want
parsedURL.Scheme = "git+ssh"
return parsedURL.String()
}
// TODO: reintroduce validation
// Validate returns error if the record is invalid
func Validate(r *record.V1) error {
if r.CmdLine == "" {
return errors.New("There is no CmdLine")
}
if r.RealtimeBefore == 0 || r.RealtimeAfter == 0 {
return errors.New("There is no Time")
}
if r.RealtimeBeforeLocal == 0 || r.RealtimeAfterLocal == 0 {
return errors.New("There is no Local Time")
}
if r.RealPwd == "" || r.RealPwdAfter == "" {
return errors.New("There is no Real Pwd")
}
if r.Pwd == "" || r.PwdAfter == "" {
return errors.New("There is no Pwd")
}
return nil
}
// func Validate(r *record.V1) error {
// if r.CmdLine == "" {
// return errors.New("There is no CmdLine")
// }
// if r.Time == 0 {
// return errors.New("There is no Time")
// }
// if r.RealPwd == "" {
// return errors.New("There is no Real Pwd")
// }
// if r.Pwd == "" {
// return errors.New("There is no Pwd")
// }
// return nil
// }
// TODO: maybe more to a more appropriate place
// TODO: cleanup the interface - stop modifying the part1 and returning a ew record at the same time
// Merge two records (part1 - collect + part2 - postcollect)
func Merge(r1 *record.V1, r2 *record.V1) error {
if r1.PartOne == false || r2.PartOne {
return errors.New("Expected part1 and part2 of the same record - usage: Merge(part1, part2)")
}
func Merge(r1 *recordint.Collect, r2 *recordint.Collect) (record.V1, error) {
if r1.SessionID != r2.SessionID {
return errors.New("Records to merge are not from the same sesion - r1:" + r1.SessionID + " r2:" + r2.SessionID)
}
if r1.CmdLine != r2.CmdLine {
return errors.New("Records to merge are not parts of the same records - r1:" + r1.CmdLine + " r2:" + r2.CmdLine)
return record.V1{}, errors.New("Records to merge are not from the same sesion - r1:" + r1.SessionID + " r2:" + r2.SessionID)
}
if r1.RecordID != r2.RecordID {
return errors.New("Records to merge do not have the same ID - r1:" + r1.RecordID + " r2:" + r2.RecordID)
if r1.Rec.RecordID != r2.Rec.RecordID {
return record.V1{}, errors.New("Records to merge do not have the same ID - r1:" + r1.Rec.RecordID + " r2:" + r2.Rec.RecordID)
}
r1.ExitCode = r2.ExitCode
r1.Duration = r2.Duration
r1.PartsMerged = true
r1.PartOne = false
return nil
}
r := recordint.Collect{
SessionID: r1.SessionID,
Shlvl: r1.Shlvl,
SessionPID: r1.SessionPID,
// GetCommandAndFirstWord func
func GetCommandAndFirstWord(cmdLine string) (string, string, error) {
args, err := shellwords.Parse(cmdLine)
if err != nil {
// Println("shellwords Error:", err, " (cmdLine: <", cmdLine, "> )")
return "", "", err
}
if len(args) == 0 {
return "", "", nil
}
i := 0
for true {
// commands in shell sometimes look like this `variable=something command argument otherArgument --option`
// to get the command we skip over tokens that contain '='
if strings.ContainsRune(args[i], '=') && len(args) > i+1 {
i++
continue
}
return args[i], args[0], nil
Rec: r1.Rec,
}
return "ERROR", "ERROR", errors.New("failed to retrieve first word of command")
r.Rec.ExitCode = r2.Rec.ExitCode
r.Rec.Duration = r2.Rec.Duration
r.Rec.PartOne = false
r.Rec.PartsNotMerged = false
return r.Rec, nil
}

@ -7,7 +7,7 @@ import (
"strings"
"time"
"github.com/curusarn/resh/internal/records"
"github.com/curusarn/resh/internal/recordint"
"golang.org/x/exp/utf8string"
)
@ -18,7 +18,7 @@ const dots = "…"
type Item struct {
isRaw bool
realtimeBefore float64
time float64
// [host:]pwd
differentHost bool
@ -105,8 +105,8 @@ func (i Item) DrawStatusLine(compactRendering bool, printedLineLength, realLineL
if i.isRaw {
return splitStatusLineToLines(i.CmdLine, printedLineLength, realLineLength)
}
secs := int64(i.realtimeBefore)
nsecs := int64((i.realtimeBefore - float64(secs)) * 1e9)
secs := int64(i.time)
nsecs := int64((i.time - float64(secs)) * 1e9)
tm := time.Unix(secs, nsecs)
const timeFormat = "2006-01-02 15:04:05"
timeString := tm.Format(timeFormat)
@ -142,8 +142,8 @@ func (i Item) DrawItemColumns(compactRendering bool, debug bool) ItemColumns {
// DISPLAY
// DISPLAY > date
secs := int64(i.realtimeBefore)
nsecs := int64((i.realtimeBefore - float64(secs)) * 1e9)
secs := int64(i.time)
nsecs := int64((i.time - float64(secs)) * 1e9)
tm := time.Unix(secs, nsecs)
var date string
@ -314,7 +314,7 @@ func properMatch(str, term, padChar string) bool {
// NewItemFromRecordForQuery creates new item from record based on given query
// returns error if the query doesn't match the record
func NewItemFromRecordForQuery(record records.CliRecord, query Query, debug bool) (Item, error) {
func NewItemFromRecordForQuery(record recordint.SearchApp, query Query, debug bool) (Item, error) {
// Use numbers that won't add up to same score for any number of query words
// query score weigth 1.51
const hitScore = 1.517 // 1 * 1.51
@ -411,10 +411,10 @@ func NewItemFromRecordForQuery(record records.CliRecord, query Query, debug bool
// if score <= 0 && !anyHit {
// return Item{}, errors.New("no match for given record and query")
// }
score += record.RealtimeBefore * timeScoreCoef
score += record.Time * timeScoreCoef
it := Item{
realtimeBefore: record.RealtimeBefore,
time: record.Time,
differentHost: differentHost,
host: record.Host,
@ -470,7 +470,7 @@ type RawItem struct {
// NewRawItemFromRecordForQuery creates new item from record based on given query
// returns error if the query doesn't match the record
func NewRawItemFromRecordForQuery(record records.CliRecord, terms []string, debug bool) (RawItem, error) {
func NewRawItemFromRecordForQuery(record recordint.SearchApp, terms []string, debug bool) (RawItem, error) {
const hitScore = 1.0
const hitScoreConsecutive = 0.01
const properMatchScore = 0.3
@ -489,7 +489,7 @@ func NewRawItemFromRecordForQuery(record records.CliRecord, terms []string, debu
cmd = strings.ReplaceAll(cmd, term, highlightMatch(term))
}
}
score += record.RealtimeBefore * timeScoreCoef
score += record.Time * timeScoreCoef
// KEY for deduplication
key := record.CmdLine

@ -3,20 +3,24 @@ package searchapp
import (
"github.com/curusarn/resh/internal/histcli"
"github.com/curusarn/resh/internal/msg"
"github.com/curusarn/resh/internal/records"
"github.com/curusarn/resh/internal/recio"
"go.uber.org/zap"
)
// LoadHistoryFromFile ...
func LoadHistoryFromFile(sugar *zap.SugaredLogger, historyPath string, numLines int) msg.CliResponse {
recs := records.LoadFromFile(sugar, historyPath)
rio := recio.New(sugar)
recs, _, err := rio.ReadFile(historyPath)
if err != nil {
sugar.Panicf("failed to read hisotry file: %w", err)
}
if numLines != 0 && numLines < len(recs) {
recs = recs[:numLines]
}
cliRecords := histcli.New()
for i := len(recs) - 1; i >= 0; i-- {
rec := recs[i]
cliRecords.AddRecord(rec)
cliRecords.AddRecord(&rec)
}
return msg.CliResponse{CliRecords: cliRecords.List}
return msg.CliResponse{Records: cliRecords.List}
}

@ -4,7 +4,7 @@ import (
"sync"
"time"
"github.com/curusarn/resh/internal/records"
"github.com/curusarn/resh/internal/recordint"
"github.com/mitchellh/go-ps"
"go.uber.org/zap"
)
@ -21,7 +21,7 @@ type sesswatch struct {
// Go runs the session watcher - watches sessions and sends
func Go(sugar *zap.SugaredLogger,
sessionsToWatch chan records.Record, sessionsToWatchRecords chan records.Record,
sessionsToWatch chan recordint.SessionInit, sessionsToWatchRecords chan recordint.Collect,
sessionsToDrop []chan string, sleepSeconds uint) {
sw := sesswatch{
@ -33,17 +33,17 @@ func Go(sugar *zap.SugaredLogger,
go sw.waiter(sessionsToWatch, sessionsToWatchRecords)
}
func (s *sesswatch) waiter(sessionsToWatch chan records.Record, sessionsToWatchRecords chan records.Record) {
func (s *sesswatch) waiter(sessionsToWatch chan recordint.SessionInit, sessionsToWatchRecords chan recordint.Collect) {
for {
func() {
select {
case record := <-sessionsToWatch:
case rec := <-sessionsToWatch:
// normal way to start watching a session
id := record.SessionID
pid := record.SessionPID
id := rec.SessionID
pid := rec.SessionPID
sugar := s.sugar.With(
"sessionID", record.SessionID,
"sessionPID", record.SessionPID,
"sessionID", rec.SessionID,
"sessionPID", rec.SessionPID,
)
s.mutex.Lock()
defer s.mutex.Unlock()
@ -52,13 +52,13 @@ func (s *sesswatch) waiter(sessionsToWatch chan records.Record, sessionsToWatchR
s.watchedSessions[id] = true
go s.watcher(sugar, id, pid)
}
case record := <-sessionsToWatchRecords:
case rec := <-sessionsToWatchRecords:
// additional safety - watch sessions that were never properly initialized
id := record.SessionID
pid := record.SessionPID
id := rec.SessionID
pid := rec.SessionPID
sugar := s.sugar.With(
"sessionID", record.SessionID,
"sessionPID", record.SessionPID,
"sessionID", rec.SessionID,
"sessionPID", rec.SessionPID,
)
s.mutex.Lock()
defer s.mutex.Unlock()

@ -8,30 +8,21 @@ __resh_preexec() {
# core
__RESH_COLLECT=1
__RESH_CMDLINE="$1" # not local to preserve it for postcollect (useful as sanity check)
local fpath_last_run="$__RESH_XDG_CACHE_HOME/collect_last_run_out.txt"
__resh_collect --cmdLine "$__RESH_CMDLINE" \
>| "$fpath_last_run" 2>&1 || echo "resh-collect ERROR: $(head -n 1 $fpath_last_run)"
__resh_collect --cmdLine "$__RESH_CMDLINE"
}
# used for collect and collect --recall
__resh_collect() {
# posix
local __RESH_COLS="$COLUMNS"
local __RESH_LANG="$LANG"
local __RESH_LC_ALL="$LC_ALL"
local __RESH_LINES="$LINES"
local __RESH_PWD="$PWD"
# non-posix
local __RESH_SHLVL="$SHLVL"
local __RESH_GIT_CDUP; __RESH_GIT_CDUP="$(git rev-parse --show-cdup 2>/dev/null)"
local __RESH_GIT_CDUP_EXIT_CODE=$?
local __RESH_GIT_REMOTE; __RESH_GIT_REMOTE="$(git remote get-url origin 2>/dev/null)"
local __RESH_GIT_REMOTE_EXIT_CODE=$?
local __RESH_PID="$$" # current pid
# time
local __RESH_TZ_BEFORE; __RESH_TZ_BEFORE=$(date +%z)
# __RESH_RT_BEFORE="$EPOCHREALTIME"
__RESH_RT_BEFORE=$(__resh_get_epochrealtime)
@ -54,38 +45,16 @@ __resh_collect() {
resh-collect -requireVersion "$__RESH_VERSION" \
-requireRevision "$__RESH_REVISION" \
-shell "$__RESH_SHELL" \
-uname "$__RESH_UNAME" \
-sessionId "$__RESH_SESSION_ID" \
-recordId "$__RESH_RECORD_ID" \
-cols "$__RESH_COLS" \
-sessionID "$__RESH_SESSION_ID" \
-recordID "$__RESH_RECORD_ID" \
-home "$__RESH_HOME" \
-lang "$__RESH_LANG" \
-lcAll "$__RESH_LC_ALL" \
-lines "$__RESH_LINES" \
-login "$__RESH_LOGIN" \
-logname "$__RESH_LOGIN" \
-pwd "$__RESH_PWD" \
-shellEnv "$__RESH_SHELL_ENV" \
-term "$__RESH_TERM" \
-pid "$__RESH_PID" \
-sessionPid "$__RESH_SESSION_PID" \
-host "$__RESH_HOST" \
-hosttype "$__RESH_HOSTTYPE" \
-ostype "$__RESH_OSTYPE" \
-machtype "$__RESH_MACHTYPE" \
-sessionPID "$__RESH_SESSION_PID" \
-hostname "$__RESH_HOST" \
-shlvl "$__RESH_SHLVL" \
-gitCdup "$__RESH_GIT_CDUP" \
-gitCdupExitCode "$__RESH_GIT_CDUP_EXIT_CODE" \
-gitRemote "$__RESH_GIT_REMOTE" \
-gitRemoteExitCode "$__RESH_GIT_REMOTE_EXIT_CODE" \
-realtimeBefore "$__RESH_RT_BEFORE" \
-realtimeSession "$__RESH_RT_SESSION" \
-realtimeSessSinceBoot "$__RESH_RT_SESS_SINCE_BOOT" \
-timezoneBefore "$__RESH_TZ_BEFORE" \
-osReleaseId "$__RESH_OS_RELEASE_ID" \
-osReleaseVersionId "$__RESH_OS_RELEASE_VERSION_ID" \
-osReleaseIdLike "$__RESH_OS_RELEASE_ID_LIKE" \
-osReleaseName "$__RESH_OS_RELEASE_NAME" \
-osReleasePrettyName "$__RESH_OS_RELEASE_PRETTY_NAME" \
-time "$__RESH_RT_BEFORE" \
"$@"
return $?
fi
@ -95,20 +64,8 @@ __resh_collect() {
__resh_precmd() {
local __RESH_EXIT_CODE=$?
local __RESH_RT_AFTER
local __RESH_TZ_AFTER
local __RESH_PWD_AFTER
local __RESH_GIT_CDUP_AFTER
local __RESH_GIT_CDUP_EXIT_CODE_AFTER
local __RESH_GIT_REMOTE_AFTER
local __RESH_GIT_REMOTE_EXIT_CODE_AFTER
local __RESH_SHLVL="$SHLVL"
__RESH_RT_AFTER=$(__resh_get_epochrealtime)
__RESH_TZ_AFTER=$(date +%z)
__RESH_PWD_AFTER="$PWD"
__RESH_GIT_CDUP_AFTER="$(git rev-parse --show-cdup 2>/dev/null)"
__RESH_GIT_CDUP_EXIT_CODE_AFTER=$?
__RESH_GIT_REMOTE_AFTER="$(git remote get-url origin 2>/dev/null)"
__RESH_GIT_REMOTE_EXIT_CODE_AFTER=$?
if [ -n "${__RESH_COLLECT}" ]; then
if [ "$__RESH_VERSION" != "$(resh-postcollect -version)" ]; then
# shellcheck source=shellrc.sh
@ -126,24 +83,14 @@ __resh_precmd() {
fi
fi
if [ "$__RESH_VERSION" = "$(resh-postcollect -version)" ] && [ "$__RESH_REVISION" = "$(resh-postcollect -revision)" ]; then
local fpath_last_run="$__RESH_XDG_CACHE_HOME/postcollect_last_run_out.txt"
resh-postcollect -requireVersion "$__RESH_VERSION" \
-requireRevision "$__RESH_REVISION" \
-cmdLine "$__RESH_CMDLINE" \
-realtimeBefore "$__RESH_RT_BEFORE" \
-timeBefore "$__RESH_RT_BEFORE" \
-exitCode "$__RESH_EXIT_CODE" \
-sessionId "$__RESH_SESSION_ID" \
-recordId "$__RESH_RECORD_ID" \
-shell "$__RESH_SHELL" \
-sessionID "$__RESH_SESSION_ID" \
-recordID "$__RESH_RECORD_ID" \
-shlvl "$__RESH_SHLVL" \
-pwdAfter "$__RESH_PWD_AFTER" \
-gitCdupAfter "$__RESH_GIT_CDUP_AFTER" \
-gitCdupExitCodeAfter "$__RESH_GIT_CDUP_EXIT_CODE_AFTER" \
-gitRemoteAfter "$__RESH_GIT_REMOTE_AFTER" \
-gitRemoteExitCodeAfter "$__RESH_GIT_REMOTE_EXIT_CODE_AFTER" \
-realtimeAfter "$__RESH_RT_AFTER" \
-timezoneAfter "$__RESH_TZ_AFTER" \
>| "$fpath_last_run" 2>&1 || echo "resh-postcollect ERROR: $(head -n 1 $fpath_last_run)"
-timeAfter "$__RESH_RT_AFTER"
fi
__resh_reset_variables
fi

@ -135,7 +135,7 @@ bin/resh-control completion zsh > ~/.resh/zsh_completion.d/_reshctl
echo "Copying more files ..."
cp -f scripts/uuid.sh ~/.resh/bin/resh-uuid
cp -f bin/resh-{daemon,control,collect,postcollect,session-init,config} ~/.resh/bin/
cp -f bin/resh-{daemon,cli,control,collect,postcollect,session-init,config} ~/.resh/bin/
echo "Creating/updating config file ..."
./bin/resh-config-setup
@ -179,7 +179,8 @@ else
pkill -SIGTERM "resh-daemon" || true
fi
# daemon uses xdg path variables
__resh_set_xdg_home_paths
# FIXME: this does not exist anymore
#__resh_set_xdg_home_paths
__resh_run_daemon

@ -74,8 +74,6 @@ resh() {
elif [ $status_code = 130 ]; then
true
else
local fpath_last_run="$__RESH_XDG_CACHE_HOME/cli_last_run_out.txt"
echo "$buffer" >| "$fpath_last_run"
echo "resh-cli failed - check '$fpath_last_run' and '~/.resh/cli.log'"
printf "%s" "$buffer" >&2
fi
}

@ -55,7 +55,8 @@ export __RESH_VERSION=$(resh-collect -version)
# shellcheck disable=2155
export __RESH_REVISION=$(resh-collect -revision)
__resh_set_xdg_home_paths
# FIXME: this does not exist anymore
# __resh_set_xdg_home_paths
__resh_run_daemon

@ -47,19 +47,21 @@ __resh_get_epochrealtime() {
fi
}
# FIXME: figure out if stdout/stderr should be discarded
__resh_run_daemon() {
if [ -n "${ZSH_VERSION-}" ]; then
setopt LOCAL_OPTIONS NO_NOTIFY NO_MONITOR
fi
local fpath_last_run="$__RESH_XDG_CACHE_HOME/daemon_last_run_out.txt"
if [ "$(uname)" = Darwin ]; then
# hotfix
gnohup resh-daemon >| "$fpath_last_run" 2>&1 & disown
# gnohup resh-daemon 2>&1 & disown
gnohup resh-daemon & disown
else
# TODO: switch to nohup for consistency once you confirm that daemon is
# not getting killed anymore on macOS
# nohup resh-daemon >| "$fpath_last_run" 2>&1 & disown
setsid resh-daemon >| "$fpath_last_run" 2>&1 & disown
nohup resh-daemon & disown
#nohup resh-daemon 2>&1 & disown
#setsid resh-daemon 2>&1 & disown
fi
}
@ -71,7 +73,7 @@ __resh_bash_completion_init() {
. ~/.resh/bash_completion.d/_reshctl
}
// TODO: redo this
# TODO: redo this
__resh_zsh_completion_init() {
# NOTE: this is hacky - each completion needs to be added individually
# TODO: fix later
@ -131,32 +133,8 @@ __resh_session_init() {
if [ "$__RESH_VERSION" = "$(resh-session-init -version)" ] && [ "$__RESH_REVISION" = "$(resh-session-init -revision)" ]; then
resh-session-init -requireVersion "$__RESH_VERSION" \
-requireRevision "$__RESH_REVISION" \
-shell "$__RESH_SHELL" \
-uname "$__RESH_UNAME" \
-sessionId "$__RESH_SESSION_ID" \
-cols "$__RESH_COLS" \
-home "$__RESH_HOME" \
-lang "$__RESH_LANG" \
-lcAll "$__RESH_LC_ALL" \
-lines "$__RESH_LINES" \
-login "$__RESH_LOGIN" \
-shellEnv "$__RESH_SHELL_ENV" \
-term "$__RESH_TERM" \
-pid "$__RESH_PID" \
-sessionPid "$__RESH_SESSION_PID" \
-host "$__RESH_HOST" \
-hosttype "$__RESH_HOSTTYPE" \
-ostype "$__RESH_OSTYPE" \
-machtype "$__RESH_MACHTYPE" \
-shlvl "$__RESH_SHLVL" \
-realtimeBefore "$__RESH_RT_BEFORE" \
-realtimeSession "$__RESH_RT_SESSION" \
-realtimeSessSinceBoot "$__RESH_RT_SESS_SINCE_BOOT" \
-timezoneBefore "$__RESH_TZ_BEFORE" \
-osReleaseId "$__RESH_OS_RELEASE_ID" \
-osReleaseVersionId "$__RESH_OS_RELEASE_VERSION_ID" \
-osReleaseIdLike "$__RESH_OS_RELEASE_ID_LIKE" \
-osReleaseName "$__RESH_OS_RELEASE_NAME" \
-osReleasePrettyName "$__RESH_OS_RELEASE_PRETTY_NAME"
-sessionPid "$__RESH_SESSION_PID"
fi
}

@ -16,8 +16,6 @@ __resh_widget_control_R() {
local git_remote; git_remote="$(git remote get-url origin 2>/dev/null)"
BUFFER=$(resh-cli --sessionID "$__RESH_SESSION_ID" --host "$__RESH_HOST" --pwd "$PWD" --gitOriginRemote "$git_remote" --query "$BUFFER")
status_code=$?
local fpath_last_run="$__RESH_XDG_CACHE_HOME/cli_last_run_out.txt"
touch "$fpath_last_run"
if [ $status_code = 111 ]; then
# execute
if [ -n "${ZSH_VERSION-}" ]; then
@ -35,8 +33,8 @@ __resh_widget_control_R() {
bind -x '"\u[32~": __resh_nop'
fi
else
echo "$BUFFER" >| "$fpath_last_run"
echo "# RESH SEARCH APP failed - sorry for the inconvinience - check '$fpath_last_run' and '~/.resh/cli.log'"
echo "RESH SEARCH APP failed"
printf "%s" "$buffer" >&2
BUFFER="$PREVBUFFER"
fi
CURSOR=${#BUFFER}

Loading…
Cancel
Save