1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-04-13 11:50:28 +02:00

Merge pull request from jesseduffield/remove-old-integration-test-stuff

This commit is contained in:
Jesse Duffield 2023-03-24 18:55:06 +11:00 committed by GitHub
commit 3bfbc9d255
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 16 additions and 253 deletions
go.modgo.sum
pkg
gui
integration/clients
scripts
vendor
github.com/jesseduffield/gocui
modules.txt

2
go.mod

@ -18,7 +18,7 @@ require (
github.com/integrii/flaggy v1.4.0
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
github.com/jesseduffield/gocui v0.3.1-0.20230319043340-e793609bfbf5
github.com/jesseduffield/gocui v0.3.1-0.20230324073941-36f2e87458fa
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e

4
go.sum

@ -72,8 +72,8 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE=
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
github.com/jesseduffield/gocui v0.3.1-0.20230319043340-e793609bfbf5 h1:8k7VTfj/RSKwYQ7Cn+iy876CjixBrTyyn+npxT/Wn/Q=
github.com/jesseduffield/gocui v0.3.1-0.20230319043340-e793609bfbf5/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU=
github.com/jesseduffield/gocui v0.3.1-0.20230324073941-36f2e87458fa h1:E9G1mj94rMal1YLaABwdxLUUgKq+xGbElFjHRNaDJUg=
github.com/jesseduffield/gocui v0.3.1-0.20230324073941-36f2e87458fa/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=

@ -3,7 +3,6 @@ package gui
import (
"fmt"
"io"
"log"
"os"
"strings"
"sync"
@ -436,17 +435,9 @@ var RuneReplacements = map[rune]string{
}
func (gui *Gui) initGocui(headless bool, test integrationTypes.IntegrationTest) (*gocui.Gui, error) {
recordEvents := RecordingEvents()
playMode := gocui.NORMAL
if recordEvents {
playMode = gocui.RECORDING
} else if Replaying() {
playMode = gocui.REPLAYING
} else if test != nil && os.Getenv(components.SANDBOX_ENV_VAR) != "true" {
playMode = gocui.REPLAYING_NEW
}
playRecording := test != nil && os.Getenv(components.SANDBOX_ENV_VAR) != "true"
g, err := gocui.NewGui(gocui.OutputTrue, OverlappingEdges, playMode, headless, RuneReplacements)
g, err := gocui.NewGui(gocui.OutputTrue, OverlappingEdges, playRecording, headless, RuneReplacements)
if err != nil {
return nil, err
}
@ -577,10 +568,6 @@ func (gui *Gui) RunAndHandleError(startArgs appTypes.StartArgs) error {
}
}
if err := SaveRecording(gui.g.Recording); err != nil {
return err
}
return nil
default:
@ -611,14 +598,6 @@ func (gui *Gui) runSubprocessWithSuspense(subprocess oscommands.ICmdObj) (bool,
gui.Mutexes.SubprocessMutex.Lock()
defer gui.Mutexes.SubprocessMutex.Unlock()
if Replaying() {
// we do not yet support running subprocesses within integration tests. So if
// we're replaying an integration test and we're inside this method, something
// has gone wrong, so we should fail
log.Fatal("opening subprocesses not yet supported in integration tests. Chances are that this test is running too fast and a subprocess is accidentally opened")
}
if err := gui.g.Suspend(); err != nil {
return false, gui.c.Error(err)
}

@ -1,10 +1,8 @@
package gui
import (
"encoding/json"
"log"
"os"
"strconv"
"time"
"github.com/jesseduffield/gocui"
@ -42,87 +40,8 @@ func (gui *Gui) handleTestMode(test integrationTypes.IntegrationTest) {
log.Fatal("40 seconds is up, lazygit recording took too long to complete")
})
}
if Replaying() {
gui.g.RecordingConfig = gocui.RecordingConfig{
Speed: GetRecordingSpeed(),
Leeway: 1000,
}
var err error
gui.g.Recording, err = LoadRecording()
if err != nil {
panic(err)
}
go utils.Safe(func() {
time.Sleep(time.Second * 40)
log.Fatal("40 seconds is up, lazygit recording took too long to complete")
})
}
}
func Headless() bool {
return os.Getenv("HEADLESS") != ""
}
// OLD integration test format stuff
func Replaying() bool {
return os.Getenv("REPLAY_EVENTS_FROM") != ""
}
func RecordingEvents() bool {
return recordEventsTo() != ""
}
func recordEventsTo() string {
return os.Getenv("RECORD_EVENTS_TO")
}
func GetRecordingSpeed() float64 {
// humans are slow so this speeds things up.
speed := 1.0
envReplaySpeed := os.Getenv("SPEED")
if envReplaySpeed != "" {
var err error
speed, err = strconv.ParseFloat(envReplaySpeed, 64)
if err != nil {
log.Fatal(err)
}
}
return speed
}
func LoadRecording() (*gocui.Recording, error) {
path := os.Getenv("REPLAY_EVENTS_FROM")
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
recording := &gocui.Recording{}
err = json.Unmarshal(data, &recording)
if err != nil {
return nil, err
}
return recording, nil
}
func SaveRecording(recording *gocui.Recording) error {
if !RecordingEvents() {
return nil
}
jsonEvents, err := json.Marshal(recording)
if err != nil {
return err
}
path := recordEventsTo()
return os.WriteFile(path, jsonEvents, 0o600)
}

@ -28,7 +28,7 @@ func RunTUI() {
app := newApp(testDir)
app.loadTests()
g, err := gocui.NewGui(gocui.OutputTrue, false, gocui.NORMAL, false, gui.RuneReplacements)
g, err := gocui.NewGui(gocui.OutputTrue, false, false, false, gui.RuneReplacements)
if err != nil {
log.Panicln(err)
}

@ -1,5 +1,7 @@
#!/bin/sh
# Go's proxy servers are not very up-to-date so that's why we use `GOPROXY=direct`
# We specify the `awesome` branch to avoid the default behaviour of looking for a semver tag.
GOPROXY=direct go get -u github.com/jesseduffield/gocui@awesome && go mod vendor && go mod tidy
# We specify the `master` branch to avoid the default behaviour of looking for a semver tag.
GOPROXY=direct go get -u github.com/jesseduffield/gocui@master && go mod vendor && go mod tidy
# Note to self if you ever want to fork a repo be sure to use this same approach: it's important to use the branch name (e.g. master)

@ -7,7 +7,6 @@ package gocui
import (
"context"
standardErrors "errors"
"log"
"runtime"
"strings"
"sync"
@ -103,21 +102,6 @@ type GuiMutexes struct {
ViewsMutex sync.Mutex
}
type PlayMode int
const (
NORMAL PlayMode = iota
RECORDING
REPLAYING
// for the new form of integration tests
REPLAYING_NEW
)
type Recording struct {
KeyEvents []*TcellKeyEventWrapper
ResizeEvents []*TcellResizeEventWrapper
}
type replayedEvents struct {
Keys chan *TcellKeyEventWrapper
Resizes chan *TcellResizeEventWrapper
@ -132,11 +116,9 @@ type RecordingConfig struct {
// and keybindings.
type Gui struct {
RecordingConfig
Recording *Recording
// ReplayedEvents is for passing pre-recorded input events, for the purposes of testing
ReplayedEvents replayedEvents
PlayMode PlayMode
StartTime time.Time
playRecording bool
tabClickBindings []*tabClickBinding
viewMouseBindings []*ViewMouseBinding
@ -194,7 +176,7 @@ type Gui struct {
}
// NewGui returns a new Gui object with a given output mode.
func NewGui(mode OutputMode, supportOverlaps bool, playMode PlayMode, headless bool, runeReplacements map[rune]string) (*Gui, error) {
func NewGui(mode OutputMode, supportOverlaps bool, playRecording bool, headless bool, runeReplacements map[rune]string) (*Gui, error) {
g := &Gui{}
var err error
@ -224,12 +206,7 @@ func NewGui(mode OutputMode, supportOverlaps bool, playMode PlayMode, headless b
g.gEvents = make(chan GocuiEvent, 20)
g.userEvents = make(chan userEvent, 20)
if playMode == RECORDING {
g.Recording = &Recording{
KeyEvents: []*TcellKeyEventWrapper{},
ResizeEvents: []*TcellResizeEventWrapper{},
}
} else if playMode == REPLAYING || playMode == REPLAYING_NEW {
if playRecording {
g.ReplayedEvents = replayedEvents{
Keys: make(chan *TcellKeyEventWrapper),
Resizes: make(chan *TcellResizeEventWrapper),
@ -248,7 +225,7 @@ func NewGui(mode OutputMode, supportOverlaps bool, playMode PlayMode, headless b
g.NextSearchMatchKey = 'n'
g.PrevSearchMatchKey = 'N'
g.PlayMode = playMode
g.playRecording = playRecording
return g, nil
}
@ -673,11 +650,6 @@ func (g *Gui) SetManagerFunc(manager func(*Gui) error) {
// MainLoop runs the main loop until an error is returned. A successful
// finish should return ErrQuit.
func (g *Gui) MainLoop() error {
g.StartTime = time.Now()
if g.PlayMode == REPLAYING {
go g.replayRecording()
}
go func() {
for {
select {
@ -1417,97 +1389,6 @@ func IsQuit(err error) bool {
return err != nil && err.Error() == ErrQuit.Error()
}
func (g *Gui) replayRecording() {
waitGroup := sync.WaitGroup{}
waitGroup.Add(2)
// lots of duplication here due to lack of generics. Also we don't support mouse
// events because it would be awkward to replicate but it would be trivial to add
// support
go func() {
ticker := time.NewTicker(time.Millisecond)
defer ticker.Stop()
// The playback could be paused at any time because integration tests run concurrently.
// Therefore we can't just check for a given event whether we've passed its timestamp,
// or else we'll have an explosion of keypresses after the test is resumed.
// We need to check if we've waited long enough since the last event was replayed.
for i, event := range g.Recording.KeyEvents {
var prevEventTimestamp int64 = 0
if i > 0 {
prevEventTimestamp = g.Recording.KeyEvents[i-1].Timestamp
}
timeToWait := float64(event.Timestamp-prevEventTimestamp) / g.RecordingConfig.Speed
if i == 0 {
timeToWait += float64(g.RecordingConfig.Leeway)
}
var timeWaited float64 = 0
middle:
for {
select {
case <-ticker.C:
timeWaited += 1
if timeWaited >= timeToWait {
g.ReplayedEvents.Keys <- event
break middle
}
case <-g.stop:
return
}
}
}
waitGroup.Done()
}()
go func() {
ticker := time.NewTicker(time.Millisecond)
defer ticker.Stop()
// duplicating until Go gets generics
for i, event := range g.Recording.ResizeEvents {
var prevEventTimestamp int64 = 0
if i > 0 {
prevEventTimestamp = g.Recording.ResizeEvents[i-1].Timestamp
}
timeToWait := float64(event.Timestamp-prevEventTimestamp) / g.RecordingConfig.Speed
if i == 0 {
timeToWait += float64(g.RecordingConfig.Leeway)
}
var timeWaited float64 = 0
middle2:
for {
select {
case <-ticker.C:
timeWaited += 1
if timeWaited >= timeToWait {
g.ReplayedEvents.Resizes <- event
break middle2
}
case <-g.stop:
return
}
}
}
waitGroup.Done()
}()
waitGroup.Wait()
// leaving some time for any handlers to execute before quitting
time.Sleep(time.Second * 1)
g.Update(func(*Gui) error {
return ErrQuit
})
time.Sleep(time.Second * 1)
log.Fatal("gocui should have already exited")
}
func (g *Gui) Suspend() error {
g.suspendedMutex.Lock()
defer g.suspendedMutex.Unlock()

@ -5,8 +5,6 @@
package gocui
import (
"time"
"github.com/gdamore/tcell/v2"
"github.com/mattn/go-runewidth"
)
@ -236,14 +234,10 @@ func (wrapper TcellResizeEventWrapper) toTcellEvent() tcell.Event {
return tcell.NewEventResize(wrapper.Width, wrapper.Height)
}
func (g *Gui) timeSinceStart() int64 {
return time.Since(g.StartTime).Nanoseconds() / 1e6
}
// pollEvent get tcell.Event and transform it into gocuiEvent
func (g *Gui) pollEvent() GocuiEvent {
var tev tcell.Event
if g.PlayMode == REPLAYING || g.PlayMode == REPLAYING_NEW {
if g.playRecording {
select {
case ev := <-g.ReplayedEvents.Keys:
tev = (ev).toTcellEvent()
@ -258,21 +252,9 @@ func (g *Gui) pollEvent() GocuiEvent {
case *tcell.EventInterrupt:
return GocuiEvent{Type: eventInterrupt}
case *tcell.EventResize:
if g.PlayMode == RECORDING {
g.Recording.ResizeEvents = append(
g.Recording.ResizeEvents, NewTcellResizeEventWrapper(tev, g.timeSinceStart()),
)
}
w, h := tev.Size()
return GocuiEvent{Type: eventResize, Width: w, Height: h}
case *tcell.EventKey:
if g.PlayMode == RECORDING {
g.Recording.KeyEvents = append(
g.Recording.KeyEvents, NewTcellKeyEventWrapper(tev, g.timeSinceStart()),
)
}
k := tev.Key()
ch := rune(0)
if k == tcell.KeyRune {

2
vendor/modules.txt vendored

@ -172,7 +172,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem
github.com/jesseduffield/go-git/v5/utils/merkletrie/index
github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
# github.com/jesseduffield/gocui v0.3.1-0.20230319043340-e793609bfbf5
# github.com/jesseduffield/gocui v0.3.1-0.20230324073941-36f2e87458fa
## explicit; go 1.12
github.com/jesseduffield/gocui
# github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10