mirror of https://github.com/curusarn/resh
Realpaths for before fields are actually evaluated before. Hard prerequisite for any recall functionalitypull/18/head
parent
7b437b6870
commit
b8c00b6c73
@ -0,0 +1,57 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"log" |
||||
"os" |
||||
|
||||
"github.com/curusarn/resh/pkg/records" |
||||
) |
||||
|
||||
// HistfileWriter - reads records from channel, merges them and wrotes them to file
|
||||
func HistfileWriter(input chan records.Record, outputPath string) { |
||||
sessions := map[string]records.Record{} |
||||
|
||||
for { |
||||
record := <-input |
||||
if record.PartOne { |
||||
if _, found := sessions[record.SessionID]; found { |
||||
log.Println("ERROR: Got another first part of the records before merging the previous one - overwriting!") |
||||
} |
||||
sessions[record.SessionID] = record |
||||
} else { |
||||
part1, found := sessions[record.SessionID] |
||||
if found == false { |
||||
log.Println("ERROR: Got second part of records and nothing to merge it with - ignoring!") |
||||
continue |
||||
} |
||||
delete(sessions, record.SessionID) |
||||
go mergeAndWriteRecord(part1, record, outputPath) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func mergeAndWriteRecord(part1, part2 records.Record, outputPath string) { |
||||
err := part1.Merge(part2) |
||||
if err != nil { |
||||
log.Println("Error while merging", err) |
||||
return |
||||
} |
||||
recJSON, err := json.Marshal(part1) |
||||
if err != nil { |
||||
log.Println("Marshalling error", err) |
||||
return |
||||
} |
||||
f, err := os.OpenFile(outputPath, |
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) |
||||
if err != nil { |
||||
log.Println("Could not open file", err) |
||||
return |
||||
} |
||||
defer f.Close() |
||||
_, err = f.Write(append(recJSON, []byte("\n")...)) |
||||
if err != nil { |
||||
log.Printf("Error while writing: %v, %s\n", part1, err) |
||||
return |
||||
} |
||||
} |
||||
@ -0,0 +1,7 @@ |
||||
package main |
||||
|
||||
import "fmt" |
||||
|
||||
func main() { |
||||
fmt.Println("Hell world") |
||||
} |
||||
@ -0,0 +1,147 @@ |
||||
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/exec"
|
||||
"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") |
||||
|
||||
cmdLine := flag.String("cmdLine", "", "command line") |
||||
exitCode := flag.Int("exitCode", -1, "exit code") |
||||
sessionID := flag.String("sessionId", "", "resh generated session id") |
||||
|
||||
// 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") |
||||
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) |
||||
} |
||||
realtimeAfter, err := strconv.ParseFloat(*rta, 64) |
||||
if err != nil { |
||||
log.Fatal("Flag Parsing error (rta):", err) |
||||
} |
||||
realtimeBefore, err := strconv.ParseFloat(*rtb, 64) |
||||
if err != nil { |
||||
log.Fatal("Flag Parsing error (rtb):", err) |
||||
} |
||||
realtimeDuration := realtimeAfter - realtimeBefore |
||||
|
||||
timezoneAfterOffset := collect.GetTimezoneOffsetInSeconds(*timezoneAfter) |
||||
realtimeAfterLocal := realtimeAfter + timezoneAfterOffset |
||||
|
||||
realPwdAfter, err := filepath.EvalSymlinks(*pwdAfter) |
||||
if err != nil { |
||||
log.Println("err while handling pwdAfter realpath:", err) |
||||
realPwdAfter = "" |
||||
} |
||||
|
||||
gitDirAfter, gitRealDirAfter := collect.GetGitDirs(*gitCdupAfter, *gitCdupExitCodeAfter, *pwdAfter) |
||||
if *gitRemoteExitCodeAfter != 0 { |
||||
*gitRemoteAfter = "" |
||||
} |
||||
|
||||
rec := records.Record{ |
||||
// core
|
||||
BaseRecord: records.BaseRecord{ |
||||
CmdLine: *cmdLine, |
||||
ExitCode: *exitCode, |
||||
SessionID: *sessionID, |
||||
|
||||
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(machineIDPath), |
||||
|
||||
PartOne: false, |
||||
|
||||
ReshUUID: collect.ReadFileContent(reshUUIDPath), |
||||
ReshVersion: Version, |
||||
ReshRevision: Revision, |
||||
}, |
||||
} |
||||
collect.SendRecord(rec, strconv.Itoa(config.Port)) |
||||
} |
||||
@ -0,0 +1,78 @@ |
||||
package collect |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"io/ioutil" |
||||
"log" |
||||
"net/http" |
||||
"path/filepath" |
||||
"strconv" |
||||
"strings" |
||||
|
||||
"github.com/curusarn/resh/pkg/records" |
||||
) |
||||
|
||||
// SendRecord to daemon
|
||||
func SendRecord(r records.Record, port string) { |
||||
recJSON, err := json.Marshal(r) |
||||
if err != nil { |
||||
log.Fatal("send err 1", err) |
||||
} |
||||
|
||||
req, err := http.NewRequest("POST", "http://localhost:"+port+"/record", |
||||
bytes.NewBuffer(recJSON)) |
||||
if err != nil { |
||||
log.Fatal("send err 2", err) |
||||
} |
||||
req.Header.Set("Content-Type", "application/json") |
||||
|
||||
client := &http.Client{} |
||||
_, err = client.Do(req) |
||||
if err != nil { |
||||
log.Fatal("resh-daemon is not running :(") |
||||
} |
||||
} |
||||
|
||||
// ReadFileContent and return it as a string
|
||||
func ReadFileContent(path string) string { |
||||
dat, err := ioutil.ReadFile(path) |
||||
if err != nil { |
||||
return "" |
||||
//log.Fatal("failed to open " + path)
|
||||
} |
||||
return strings.TrimSuffix(string(dat), "\n") |
||||
} |
||||
|
||||
// GetGitDirs based on result of git "cdup" command
|
||||
func GetGitDirs(cdup string, exitCode int, pwd string) (string, string) { |
||||
if exitCode != 0 { |
||||
return "", "" |
||||
} |
||||
abspath := filepath.Clean(filepath.Join(pwd, cdup)) |
||||
realpath, err := filepath.EvalSymlinks(abspath) |
||||
if err != nil { |
||||
log.Println("err while handling git dir paths:", err) |
||||
return "", "" |
||||
} |
||||
return abspath, realpath |
||||
} |
||||
|
||||
// GetTimezoneOffsetInSeconds based on zone returned by date command
|
||||
func GetTimezoneOffsetInSeconds(zone string) float64 { |
||||
// date +%z -> "+0200"
|
||||
hoursStr := zone[:3] |
||||
minsStr := zone[3:] |
||||
hours, err := strconv.Atoi(hoursStr) |
||||
if err != nil { |
||||
log.Println("err while parsing hours in timezone offset:", err) |
||||
return -1 |
||||
} |
||||
mins, err := strconv.Atoi(minsStr) |
||||
if err != nil { |
||||
log.Println("err while parsing mins in timezone offset:", err) |
||||
return -1 |
||||
} |
||||
secs := ((hours * 60) + mins) * 60 |
||||
return float64(secs) |
||||
} |
||||
Loading…
Reference in new issue