mirror of https://github.com/curusarn/resh
add session history dispatch extend reshctl add recall - both command and handler for the daemon add session_initpull/18/head
parent
ce7768949a
commit
e12e366dda
@ -0,0 +1,48 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"io/ioutil" |
||||
"log" |
||||
"net/http" |
||||
|
||||
"github.com/curusarn/resh/pkg/collect" |
||||
"github.com/curusarn/resh/pkg/records" |
||||
"github.com/curusarn/resh/pkg/sesshist" |
||||
) |
||||
|
||||
type recallHandler struct { |
||||
sesshistDispatch *sesshist.Dispatch |
||||
} |
||||
|
||||
func (h *recallHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { |
||||
jsn, err := ioutil.ReadAll(r.Body) |
||||
if err != nil { |
||||
log.Println("Error reading the body", err) |
||||
return |
||||
} |
||||
|
||||
rec := records.Record{} |
||||
err = json.Unmarshal(jsn, &rec) |
||||
if err != nil { |
||||
log.Println("Decoding error:", err) |
||||
log.Println("Payload:", jsn) |
||||
return |
||||
} |
||||
cmd, err := h.sesshistDispatch.Recall(rec.SessionID, rec.RecallHistno) |
||||
if err != nil { |
||||
log.Println("/recall - sess id:", rec.SessionID, " - histno:", rec.RecallHistno, " -> ERROR") |
||||
log.Println("Recall error:", err) |
||||
return |
||||
} |
||||
resp := collect.SingleResponse{cmd} |
||||
jsn, err = json.Marshal(&resp) |
||||
if err != nil { |
||||
log.Println("Encoding error:", err) |
||||
log.Println("Response:", resp) |
||||
return |
||||
} |
||||
log.Println(string(jsn)) |
||||
w.Write(jsn) |
||||
log.Println("/recall - sess id:", rec.SessionID, " - histno:", rec.RecallHistno, " -> ", cmd) |
||||
} |
||||
@ -0,0 +1,47 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"io/ioutil" |
||||
"log" |
||||
"net/http" |
||||
|
||||
"github.com/curusarn/resh/pkg/records" |
||||
) |
||||
|
||||
type recordHandler struct { |
||||
subscribers []chan records.Record |
||||
} |
||||
|
||||
func (h *recordHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { |
||||
w.Write([]byte("OK\n")) |
||||
jsn, err := ioutil.ReadAll(r.Body) |
||||
// run rest of the handler as goroutine to prevent any hangups
|
||||
go func() { |
||||
if err != nil { |
||||
log.Println("Error reading the body", err) |
||||
return |
||||
} |
||||
|
||||
record := records.Record{} |
||||
err = json.Unmarshal(jsn, &record) |
||||
if err != nil { |
||||
log.Println("Decoding error: ", err) |
||||
log.Println("Payload: ", jsn) |
||||
return |
||||
} |
||||
for _, sub := range h.subscribers { |
||||
sub <- record |
||||
} |
||||
part := "2" |
||||
if record.PartOne { |
||||
part = "1" |
||||
} |
||||
log.Println("/record - ", record.CmdLine, " - part", part) |
||||
}() |
||||
|
||||
// fmt.Println("cmd:", r.CmdLine)
|
||||
// fmt.Println("pwd:", r.Pwd)
|
||||
// fmt.Println("git:", r.GitWorkTree)
|
||||
// fmt.Println("exit_code:", r.ExitCode)
|
||||
} |
||||
@ -0,0 +1,46 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"net/http" |
||||
"strconv" |
||||
|
||||
"github.com/curusarn/resh/pkg/cfg" |
||||
"github.com/curusarn/resh/pkg/histfile" |
||||
"github.com/curusarn/resh/pkg/records" |
||||
"github.com/curusarn/resh/pkg/sesshist" |
||||
"github.com/curusarn/resh/pkg/sesswatch" |
||||
) |
||||
|
||||
func runServer(config cfg.Config, outputPath string) { |
||||
var recordSubscribers []chan records.Record |
||||
var sessionInitSubscribers []chan records.Record |
||||
var sessionDropSubscribers []chan string |
||||
|
||||
// sessshist
|
||||
sesshistSessionsToInit := make(chan records.Record) |
||||
sessionInitSubscribers = append(sessionInitSubscribers, sesshistSessionsToInit) |
||||
sesshistSessionsToDrop := make(chan string) |
||||
sessionDropSubscribers = append(sessionDropSubscribers, sesshistSessionsToDrop) |
||||
sesshistRecords := make(chan records.Record) |
||||
recordSubscribers = append(recordSubscribers, sesshistRecords) |
||||
sesshistDispatch := sesshist.NewDispatch(sesshistSessionsToInit, sesshistSessionsToDrop, sesshistRecords) |
||||
|
||||
// histfile
|
||||
histfileRecords := make(chan records.Record) |
||||
recordSubscribers = append(recordSubscribers, histfileRecords) |
||||
histfileSessionsToDrop := make(chan string) |
||||
sessionDropSubscribers = append(sessionDropSubscribers, histfileSessionsToDrop) |
||||
histfile.Go(histfileRecords, outputPath, histfileSessionsToDrop) |
||||
|
||||
// sesswatch
|
||||
sesswatchSessionsToWatch := make(chan records.Record) |
||||
sessionInitSubscribers = append(sessionInitSubscribers, sesswatchSessionsToWatch) |
||||
sesswatch.Go(sesswatchSessionsToWatch, sessionDropSubscribers, config.SesswatchPeriodSeconds) |
||||
|
||||
// handlers
|
||||
http.HandleFunc("/status", statusHandler) |
||||
http.Handle("/record", &recordHandler{subscribers: recordSubscribers}) |
||||
http.Handle("/session_init", &sessionInitHandler{subscribers: sessionInitSubscribers}) |
||||
http.Handle("/recall", &recallHandler{sesshistDispatch: sesshistDispatch}) |
||||
http.ListenAndServe(":"+strconv.Itoa(config.Port), nil) |
||||
} |
||||
@ -0,0 +1,38 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"io/ioutil" |
||||
"log" |
||||
"net/http" |
||||
|
||||
"github.com/curusarn/resh/pkg/records" |
||||
) |
||||
|
||||
type sessionInitHandler struct { |
||||
subscribers []chan records.Record |
||||
} |
||||
|
||||
func (h *sessionInitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { |
||||
w.Write([]byte("OK\n")) |
||||
jsn, err := ioutil.ReadAll(r.Body) |
||||
// run rest of the handler as goroutine to prevent any hangups
|
||||
go func() { |
||||
if err != nil { |
||||
log.Println("Error reading the body", err) |
||||
return |
||||
} |
||||
|
||||
record := records.Record{} |
||||
err = json.Unmarshal(jsn, &record) |
||||
if err != nil { |
||||
log.Println("Decoding error: ", err) |
||||
log.Println("Payload: ", jsn) |
||||
return |
||||
} |
||||
for _, sub := range h.subscribers { |
||||
sub <- record |
||||
} |
||||
log.Println("/session_init - id:", record.SessionID, " - pid:", record.SessionPID) |
||||
}() |
||||
} |
||||
@ -0,0 +1,186 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"flag" |
||||
"fmt" |
||||
"log" |
||||
"os" |
||||
|
||||
"github.com/BurntSushi/toml" |
||||
"github.com/curusarn/resh/pkg/cfg" |
||||
"github.com/curusarn/resh/pkg/collect" |
||||
"github.com/curusarn/resh/pkg/records" |
||||
|
||||
"os/user" |
||||
"path/filepath" |
||||
"strconv" |
||||
) |
||||
|
||||
// Version from git set during build
|
||||
var Version string |
||||
|
||||
// Revision from git set during build
|
||||
var Revision string |
||||
|
||||
func main() { |
||||
usr, _ := user.Current() |
||||
dir := usr.HomeDir |
||||
configPath := filepath.Join(dir, "/.config/resh.toml") |
||||
reshUUIDPath := filepath.Join(dir, "/.resh/resh-uuid") |
||||
|
||||
machineIDPath := "/etc/machine-id" |
||||
|
||||
var config cfg.Config |
||||
if _, err := toml.DecodeFile(configPath, &config); err != nil { |
||||
log.Fatal("Error reading config:", err) |
||||
} |
||||
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") |
||||
flag.Parse() |
||||
|
||||
if *showVersion == true { |
||||
fmt.Println(Version) |
||||
os.Exit(0) |
||||
} |
||||
if *showRevision == true { |
||||
fmt.Println(Revision) |
||||
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) |
||||
} |
||||
if *requireRevision != "" && *requireRevision != Revision { |
||||
fmt.Println("Please restart/reload this terminal session " + |
||||
"(resh revision: " + Revision + |
||||
"; resh revision of this terminal session: " + *requireRevision + |
||||
")") |
||||
os.Exit(3) |
||||
} |
||||
realtimeBefore, err := strconv.ParseFloat(*rtb, 64) |
||||
if err != nil { |
||||
log.Fatal("Flag Parsing error (rtb):", err) |
||||
} |
||||
realtimeSessionStart, err := strconv.ParseFloat(*rtsess, 64) |
||||
if err != nil { |
||||
log.Fatal("Flag Parsing error (rt sess):", err) |
||||
} |
||||
realtimeSessSinceBoot, err := strconv.ParseFloat(*rtsessboot, 64) |
||||
if err != nil { |
||||
log.Fatal("Flag Parsing error (rt sess boot):", err) |
||||
} |
||||
realtimeSinceSessionStart := realtimeBefore - realtimeSessionStart |
||||
realtimeSinceBoot := realtimeSessSinceBoot + realtimeSinceSessionStart |
||||
|
||||
timezoneBeforeOffset := collect.GetTimezoneOffsetInSeconds(*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, |
||||
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(machineIDPath), |
||||
|
||||
OsReleaseID: *osReleaseID, |
||||
OsReleaseVersionID: *osReleaseVersionID, |
||||
OsReleaseIDLike: *osReleaseIDLike, |
||||
OsReleaseName: *osReleaseName, |
||||
OsReleasePrettyName: *osReleasePrettyName, |
||||
|
||||
ReshUUID: collect.ReadFileContent(reshUUIDPath), |
||||
ReshVersion: Version, |
||||
ReshRevision: Revision, |
||||
}, |
||||
} |
||||
collect.SendRecord(rec, strconv.Itoa(config.Port), "/session_init") |
||||
} |
||||
@ -0,0 +1,7 @@ |
||||
package sess |
||||
|
||||
// Session represents a session, used for sennding through channels when more than just ID is needed
|
||||
type Session struct { |
||||
ID string |
||||
PID int |
||||
} |
||||
@ -0,0 +1,135 @@ |
||||
package sesshist |
||||
|
||||
import ( |
||||
"errors" |
||||
"log" |
||||
"strconv" |
||||
"sync" |
||||
|
||||
"github.com/curusarn/resh/pkg/records" |
||||
) |
||||
|
||||
// Dispatch Recall() calls to an apropriate session history (sesshist)
|
||||
type Dispatch struct { |
||||
sessions map[string]*sesshist |
||||
mutex sync.RWMutex |
||||
} |
||||
|
||||
// NewDispatch creates a new sesshist.Dispatch and starts necessary gorutines
|
||||
func NewDispatch(sessionsToInit chan records.Record, sessionsToDrop chan string, recordsToAdd chan records.Record) *Dispatch { |
||||
s := Dispatch{sessions: map[string]*sesshist{}} |
||||
go s.sessionInitializer(sessionsToInit) |
||||
go s.sessionDropper(sessionsToDrop) |
||||
go s.recordAdder(recordsToAdd) |
||||
return &s |
||||
} |
||||
|
||||
func (s *Dispatch) sessionInitializer(sessionsToInit chan records.Record) { |
||||
for { |
||||
record := <-sessionsToInit |
||||
log.Println("sesshist: got session to init - " + record.SessionID) |
||||
s.initSession(record.SessionID) |
||||
} |
||||
} |
||||
|
||||
func (s *Dispatch) sessionDropper(sessionsToDrop chan string) { |
||||
for { |
||||
sessionID := <-sessionsToDrop |
||||
log.Println("sesshist: got session to drop - " + sessionID) |
||||
s.dropSession(sessionID) |
||||
} |
||||
} |
||||
|
||||
func (s *Dispatch) recordAdder(recordsToAdd chan records.Record) { |
||||
for { |
||||
record := <-recordsToAdd |
||||
if record.PartOne { |
||||
log.Println("sesshist: got record to add - " + record.CmdLine) |
||||
s.addRecentRecord(record.SessionID, record) |
||||
} |
||||
// TODO: we will need to handle part2 as well eventually
|
||||
} |
||||
} |
||||
|
||||
// InitSession struct
|
||||
func (s *Dispatch) initSession(sessionID string) error { |
||||
s.mutex.RLock() |
||||
_, found := s.sessions[sessionID] |
||||
s.mutex.RUnlock() |
||||
|
||||
if found == true { |
||||
return errors.New("sesshist ERROR: Can't INIT already existing session " + sessionID) |
||||
} |
||||
|
||||
s.mutex.Lock() |
||||
defer s.mutex.Unlock() |
||||
s.sessions[sessionID] = &sesshist{} |
||||
return nil |
||||
} |
||||
|
||||
// DropSession struct
|
||||
func (s *Dispatch) dropSession(sessionID string) error { |
||||
s.mutex.RLock() |
||||
_, found := s.sessions[sessionID] |
||||
s.mutex.RUnlock() |
||||
|
||||
if found == false { |
||||
return errors.New("sesshist ERROR: Can't DROP not existing session " + sessionID) |
||||
} |
||||
|
||||
s.mutex.Lock() |
||||
defer s.mutex.Unlock() |
||||
delete(s.sessions, sessionID) |
||||
return nil |
||||
} |
||||
|
||||
// AddRecent record to session
|
||||
func (s *Dispatch) addRecentRecord(sessionID string, record records.Record) error { |
||||
s.mutex.RLock() |
||||
session, found := s.sessions[sessionID] |
||||
s.mutex.RUnlock() |
||||
|
||||
if found == false { |
||||
return errors.New("sesshist ERROR: No session history for SessionID " + sessionID + " (should we create one?)") |
||||
} |
||||
session.mutex.Lock() |
||||
defer session.mutex.Unlock() |
||||
session.recent = append(session.recent, record) |
||||
log.Println("sesshist: record:", record.CmdLine, "; added to session:", sessionID, "; session len:", len(session.recent)) |
||||
return nil |
||||
} |
||||
|
||||
// Recall command from recent session history
|
||||
func (s *Dispatch) Recall(sessionID string, histno int) (string, error) { |
||||
s.mutex.RLock() |
||||
session, found := s.sessions[sessionID] |
||||
s.mutex.RUnlock() |
||||
|
||||
if found == false { |
||||
return "", errors.New("sesshist ERROR: No session history for SessionID " + sessionID) |
||||
} |
||||
session.mutex.Lock() |
||||
defer session.mutex.Unlock() |
||||
return session.getRecordByHistno(histno) |
||||
} |
||||
|
||||
type sesshist struct { |
||||
recent []records.Record |
||||
mutex sync.Mutex |
||||
} |
||||
|
||||
func (s *sesshist) getRecordByHistno(histno int) (string, error) { |
||||
// records get appended to the end of the slice
|
||||
// -> this func handles the indexing
|
||||
if histno == 0 { |
||||
return "", errors.New("sesshist ERROR: 'histno == 0' is not a record from history") |
||||
} |
||||
if histno < 0 { |
||||
return "", errors.New("sesshist ERROR: 'histno < 0' is a command from future (not supperted yet)") |
||||
} |
||||
index := len(s.recent) - histno |
||||
if index < 0 { |
||||
return "", errors.New("sesshist ERROR: 'histno > number of commands in the session' (" + strconv.Itoa(len(s.recent)) + ")") |
||||
} |
||||
return s.recent[index].CmdLine, nil |
||||
} |
||||
@ -1,37 +0,0 @@ |
||||
|
||||
|
||||
# shellcheck source=../submodules/bash-zsh-compat-widgets/bindfunc.sh |
||||
. ~/.resh/bindfunc.sh |
||||
# shellcheck source=widgets.sh |
||||
. ~/.resh/widgets.sh |
||||
|
||||
__resh_bind_arrows() { |
||||
echo "bindfunc __resh_widget_arrow_up" |
||||
echo "bindfunc __resh_widget_arrow_down" |
||||
return 0 |
||||
} |
||||
|
||||
__resh_bind_control_R() { |
||||
echo "bindfunc __resh_widget_control_R" |
||||
return 0 |
||||
} |
||||
__resh_unbind_arrows() { |
||||
echo "\ bindfunc __resh_widget_arrow_up" |
||||
echo "\ bindfunc __resh_widget_arrow_down" |
||||
return 0 |
||||
} |
||||
|
||||
__resh_unbind_control_R() { |
||||
echo "\ bindfunc __resh_widget_control_R" |
||||
return 0 |
||||
} |
||||
|
||||
__resh_bind_all() { |
||||
__resh_bind_arrows |
||||
__resh_bind_control_R |
||||
} |
||||
|
||||
__resh_unbind_all() { |
||||
__resh_unbind_arrows |
||||
__resh_unbind_control_R |
||||
} |
||||
@ -0,0 +1,147 @@ |
||||
|
||||
__resh_preexec() { |
||||
__RESH_HISTNO=0 |
||||
# core |
||||
__RESH_COLLECT=1 |
||||
__RESH_CMDLINE="$1" # not local to preserve it for postcollect (useful as sanity check) |
||||
__resh_collect --cmdLine "$__RESH_CMDLINE" \ |
||||
&>~/.resh/collect_last_run_out.txt || echo "resh-collect ERROR: $(head -n 1 ~/.resh/collect_last_run_out.txt)" |
||||
} |
||||
|
||||
# used for collect and collect --recall |
||||
__resh_collect() { |
||||
# posix |
||||
local __RESH_COLS="$COLUMNS" |
||||
local __RESH_LANG="$LANG" |
||||
local __RESH_LC_ALL="$LC_ALL" |
||||
# other LC ? |
||||
local __RESH_LINES="$LINES" |
||||
# __RESH_PATH="$PATH" |
||||
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=$? |
||||
#__RESH_GIT_TOPLEVEL="$(git rev-parse --show-toplevel)" |
||||
#__RESH_GIT_TOPLEVEL_EXIT_CODE=$? |
||||
|
||||
if [ -n "$ZSH_VERSION" ]; then |
||||
# assume Zsh |
||||
local __RESH_PID="$$" # current pid |
||||
elif [ -n "$BASH_VERSION" ]; then |
||||
# assume Bash |
||||
local __RESH_PID="$BASHPID" # current pid |
||||
fi |
||||
# time |
||||
local __RESH_TZ_BEFORE; __RESH_TZ_BEFORE=$(date +%z) |
||||
# __RESH_RT_BEFORE="$EPOCHREALTIME" |
||||
__RESH_RT_BEFORE=$(__resh_get_epochrealtime) |
||||
|
||||
if [ "$__RESH_VERSION" != "$(resh-collect -version)" ]; then |
||||
# shellcheck source=shellrc.sh |
||||
source ~/.resh/shellrc |
||||
if [ "$__RESH_VERSION" != "$(resh-collect -version)" ]; then |
||||
echo "RESH WARNING: You probably just updated RESH - PLEASE RESTART OR RELOAD THIS TERMINAL SESSION (resh version: $(resh-collect -version); resh version of this terminal session: ${__RESH_VERSION})" |
||||
else |
||||
echo "RESH INFO: New RESH shellrc script was loaded - if you encounter any issues please restart this terminal session." |
||||
fi |
||||
elif [ "$__RESH_REVISION" != "$(resh-collect -revision)" ]; then |
||||
# shellcheck source=shellrc.sh |
||||
source ~/.resh/shellrc |
||||
if [ "$__RESH_REVISION" != "$(resh-collect -revision)" ]; then |
||||
echo "RESH WARNING: You probably just updated RESH - PLEASE RESTART OR RELOAD THIS TERMINAL SESSION (resh revision: $(resh-collect -revision); resh revision of this terminal session: ${__RESH_REVISION})" |
||||
fi |
||||
fi |
||||
if [ "$__RESH_VERSION" = "$(resh-collect -version)" ] && [ "$__RESH_REVISION" = "$(resh-collect -revision)" ]; then |
||||
resh-collect -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" \ |
||||
-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" \ |
||||
-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" \ |
||||
"$@" |
||||
fi |
||||
} |
||||
|
||||
__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 |
||||
__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 |
||||
source ~/.resh/shellrc |
||||
if [ "$__RESH_VERSION" != "$(resh-postcollect -version)" ]; then |
||||
echo "RESH WARNING: You probably just updated RESH - PLEASE RESTART OR RELOAD THIS TERMINAL SESSION (resh version: $(resh-collect -version); resh version of this terminal session: ${__RESH_VERSION})" |
||||
else |
||||
echo "RESH INFO: New RESH shellrc script was loaded - if you encounter any issues please restart this terminal session." |
||||
fi |
||||
elif [ "$__RESH_REVISION" != "$(resh-postcollect -revision)" ]; then |
||||
# shellcheck source=shellrc.sh |
||||
source ~/.resh/shellrc |
||||
if [ "$__RESH_REVISION" != "$(resh-postcollect -revision)" ]; then |
||||
echo "RESH WARNING: You probably just updated RESH - PLEASE RESTART OR RELOAD THIS TERMINAL SESSION (resh revision: $(resh-collect -revision); resh revision of this terminal session: ${__RESH_REVISION})" |
||||
fi |
||||
fi |
||||
if [ "$__RESH_VERSION" = "$(resh-postcollect -version)" ] && [ "$__RESH_REVISION" = "$(resh-postcollect -revision)" ]; then |
||||
resh-postcollect -requireVersion "$__RESH_VERSION" \ |
||||
-requireRevision "$__RESH_REVISION" \ |
||||
-cmdLine "$__RESH_CMDLINE" \ |
||||
-realtimeBefore "$__RESH_RT_BEFORE" \ |
||||
-exitCode "$__RESH_EXIT_CODE" \ |
||||
-sessionId "$__RESH_SESSION_ID" \ |
||||
-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" \ |
||||
&>~/.resh/postcollect_last_run_out.txt || echo "resh-postcollect ERROR: $(head -n 1 ~/.resh/postcollect_last_run_out.txt)" |
||||
fi |
||||
fi |
||||
unset __RESH_COLLECT |
||||
} |
||||
@ -0,0 +1,136 @@ |
||||
# util.sh - resh utility functions |
||||
__resh_get_uuid() { |
||||
cat /proc/sys/kernel/random/uuid 2>/dev/null || resh-uuid |
||||
} |
||||
|
||||
__resh_get_pid() { |
||||
if [ -n "$ZSH_VERSION" ]; then |
||||
# assume Zsh |
||||
local __RESH_PID="$$" # current pid |
||||
elif [ -n "$BASH_VERSION" ]; then |
||||
# assume Bash |
||||
local __RESH_PID="$BASHPID" # current pid |
||||
fi |
||||
echo "$__RESH_PID" |
||||
} |
||||
|
||||
__resh_get_epochrealtime() { |
||||
if date +%s.%N | grep -vq 'N'; then |
||||
# GNU date |
||||
date +%s.%N |
||||
elif gdate --version >/dev/null && gdate +%s.%N | grep -vq 'N'; then |
||||
# GNU date take 2 |
||||
gdate +%s.%N |
||||
elif [ -n "$ZSH_VERSION" ]; then |
||||
# zsh fallback using $EPOCHREALTIME |
||||
if [ -z "${__RESH_ZSH_LOADED_DATETIME+x}" ]; then |
||||
zmodload zsh/datetime |
||||
__RESH_ZSH_LOADED_DATETIME=1 |
||||
fi |
||||
echo "$EPOCHREALTIME" |
||||
else |
||||
# dumb date |
||||
# XXX: we lost precison beyond seconds |
||||
date +%s |
||||
if [ -z "${__RESH_DATE_WARN+x}" ]; then |
||||
echo "resh WARN: can't get precise time - consider installing GNU date!" |
||||
__RESH_DATE_WARN=1 |
||||
fi |
||||
fi |
||||
} |
||||
|
||||
__resh_run_daemon() { |
||||
if [ -n "$ZSH_VERSION" ]; then |
||||
setopt LOCAL_OPTIONS NO_NOTIFY NO_MONITOR |
||||
fi |
||||
nohup resh-daemon &>~/.resh/daemon_last_run_out.txt & disown |
||||
} |
||||
|
||||
__resh_bash_completion_init() { |
||||
local bash_completion_dir=~/.resh/bash_completion.d |
||||
# source user completion directory definitions |
||||
# taken from /usr/share/bash-completion/bash_completion |
||||
if [[ -d $bash_completion_dir && -r $bash_completion_dir && \ |
||||
-x $bash_completion_dir ]]; then |
||||
for i in $(LC_ALL=C command ls "$bash_completion_dir"); do |
||||
i=$bash_completion_dir/$i |
||||
# shellcheck disable=SC2154 |
||||
# shellcheck source=/dev/null |
||||
[[ ${i##*/} != @($_backup_glob|Makefile*|$_blacklist_glob) \ |
||||
&& -f $i && -r $i ]] && . "$i" |
||||
done |
||||
fi |
||||
} |
||||
|
||||
__resh_zsh_completion_init() { |
||||
# shellcheck disable=SC2206 |
||||
fpath=(~/.resh/zsh_completion.d $fpath) |
||||
} |
||||
|
||||
__resh_session_init() { |
||||
# posix |
||||
local __RESH_COLS="$COLUMNS" |
||||
local __RESH_LANG="$LANG" |
||||
local __RESH_LC_ALL="$LC_ALL" |
||||
# other LC ? |
||||
local __RESH_LINES="$LINES" |
||||
local __RESH_PWD="$PWD" |
||||
|
||||
# non-posix |
||||
local __RESH_SHLVL="$SHLVL" |
||||
|
||||
# pid |
||||
local __RESH_PID; __RESH_PID=$(__resh_get_pid) |
||||
|
||||
# time |
||||
local __RESH_TZ_BEFORE; __RESH_TZ_BEFORE=$(date +%z) |
||||
local __RESH_RT_BEFORE; __RESH_RT_BEFORE=$(__resh_get_epochrealtime) |
||||
|
||||
if [ "$__RESH_VERSION" != "$(resh-session-init -version)" ]; then |
||||
# shellcheck source=shellrc.sh |
||||
source ~/.resh/shellrc |
||||
if [ "$__RESH_VERSION" != "$(resh-session-init -version)" ]; then |
||||
echo "RESH WARNING: You probably just updated RESH - PLEASE RESTART OR RELOAD THIS TERMINAL SESSION (resh version: $(resh-session-init -version); resh version of this terminal session: ${__RESH_VERSION})" |
||||
else |
||||
echo "RESH INFO: New RESH shellrc script was loaded - if you encounter any issues please restart this terminal session." |
||||
fi |
||||
elif [ "$__RESH_REVISION" != "$(resh-session-init -revision)" ]; then |
||||
# shellcheck source=shellrc.sh |
||||
source ~/.resh/shellrc |
||||
if [ "$__RESH_REVISION" != "$(resh-session-init -revision)" ]; then |
||||
echo "RESH WARNING: You probably just updated RESH - PLEASE RESTART OR RELOAD THIS TERMINAL SESSION (resh revision: $(resh-session-init -revision); resh revision of this terminal session: ${__RESH_REVISION})" |
||||
fi |
||||
fi |
||||
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" \ |
||||
&>~/.resh/session_init_last_run_out.txt || echo "resh-session-init ERROR: $(head -n 1 ~/.resh/session_init_last_run_out.txt)" |
||||
fi |
||||
} |
||||
@ -1,10 +1,28 @@ |
||||
|
||||
# shellcheck source=hooks.sh |
||||
. ~/.resh/hooks.sh |
||||
|
||||
__resh_widget_arrow_up() { |
||||
return 0 |
||||
(( __RESH_HISTNO++ )) |
||||
BUFFER="$(__resh_collect --recall --histno "$__RESH_HISTNO" 2> ~/.resh/arrow_up_last_run_out.txt)" |
||||
} |
||||
__resh_widget_arrow_down() { |
||||
return 0 |
||||
(( __RESH_HISTNO-- )) |
||||
BUFFER="$(__resh_collect --recall --histno "$__RESH_HISTNO" 2> ~/.resh/arrow_down_last_run_out.txt)" |
||||
} |
||||
__resh_widget_control_R() { |
||||
return 0 |
||||
} |
||||
# resh-collect --hstr |
||||
hstr |
||||
} |
||||
|
||||
__resh_widget_arrow_up_compat() { |
||||
__bindfunc_compat_wrapper __resh_widget_arrow_up |
||||
} |
||||
|
||||
__resh_widget_arrow_down_compat() { |
||||
__bindfunc_compat_wrapper __resh_widget_arrow_down |
||||
} |
||||
|
||||
__resh_widget_control_R_compat() { |
||||
__bindfunc_compat_wrapper __resh_widget_control_R |
||||
} |
||||
|
||||
Loading…
Reference in new issue