1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-07-17 01:42:45 +02:00

Clean up utils package (#4538)

- **PR Description**

The utils package is a bit of a heterogeneous bag of miscellaneous
things at different abstraction levels right now; ideally it should only
contain low-level utilities similar to the helpers in utils/slice.go.
Further cleanup is possible here, e.g. something like rebase_todo.go
shouldn't be in this utils package. This PR doesn't address that,
however.

The goal of this PR is just to make it possible to import utils from any
other package. Previously it wasn't possible to import it from config,
because some of the stuff in utils depended on the config package. So
here we move only those things to better places. See the individual
commit messages for details.
This commit is contained in:
Stefan Haller
2025-05-06 13:07:30 +02:00
committed by GitHub
18 changed files with 77 additions and 68 deletions

View File

@ -8,6 +8,7 @@ import (
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo" "github.com/samber/lo"
@ -296,7 +297,7 @@ func TestGetCommits(t *testing.T) {
for _, scenario := range scenarios { for _, scenario := range scenarios {
t.Run(scenario.testName, func(t *testing.T) { t.Run(scenario.testName, func(t *testing.T) {
common := utils.NewDummyCommon() common := common.NewDummyCommon()
common.AppState = &config.AppState{} common.AppState = &config.AppState{}
common.AppState.GitLogOrder = scenario.logOrder common.AppState.GitLogOrder = scenario.logOrder
cmd := oscommands.NewDummyCmdObjBuilder(scenario.runner) cmd := oscommands.NewDummyCmdObjBuilder(scenario.runner)
@ -516,7 +517,7 @@ func TestCommitLoader_getConflictedCommitImpl(t *testing.T) {
} }
for _, scenario := range scenarios { for _, scenario := range scenarios {
t.Run(scenario.testName, func(t *testing.T) { t.Run(scenario.testName, func(t *testing.T) {
common := utils.NewDummyCommon() common := common.NewDummyCommon()
builder := &CommitLoader{ builder := &CommitLoader{
Common: common, Common: common,

View File

@ -9,7 +9,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/spf13/afero" "github.com/spf13/afero"
) )
@ -32,7 +31,7 @@ func buildGitCommon(deps commonDeps) *GitCommon {
gitCommon.Common = deps.common gitCommon.Common = deps.common
if gitCommon.Common == nil { if gitCommon.Common == nil {
gitCommon.Common = utils.NewDummyCommonWithUserConfigAndAppState(deps.userConfig, deps.appState) gitCommon.Common = common.NewDummyCommonWithUserConfigAndAppState(deps.userConfig, deps.appState)
} }
if deps.fs != nil { if deps.fs != nil {

View File

@ -7,6 +7,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/sanity-io/litter" "github.com/sanity-io/litter"
@ -181,7 +182,7 @@ func TestGetReflogCommits(t *testing.T) {
for _, scenario := range scenarios { for _, scenario := range scenarios {
t.Run(scenario.testName, func(t *testing.T) { t.Run(scenario.testName, func(t *testing.T) {
builder := &ReflogCommitLoader{ builder := &ReflogCommitLoader{
Common: utils.NewDummyCommon(), Common: common.NewDummyCommon(),
cmd: oscommands.NewDummyCmdObjBuilder(scenario.runner), cmd: oscommands.NewDummyCmdObjBuilder(scenario.runner),
} }

View File

@ -5,7 +5,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -50,7 +50,7 @@ func TestGetStashEntries(t *testing.T) {
t.Run(s.testName, func(t *testing.T) { t.Run(s.testName, func(t *testing.T) {
cmd := oscommands.NewDummyCmdObjBuilder(s.runner) cmd := oscommands.NewDummyCmdObjBuilder(s.runner)
loader := NewStashLoader(utils.NewDummyCommon(), cmd) loader := NewStashLoader(common.NewDummyCommon(), cmd)
assert.EqualValues(t, s.expectedStashEntries, loader.GetStashEntries(s.filterPath)) assert.EqualValues(t, s.expectedStashEntries, loader.GetStashEntries(s.filterPath))
}) })

View File

@ -5,7 +5,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -46,7 +46,7 @@ func TestGetTags(t *testing.T) {
for _, scenario := range scenarios { for _, scenario := range scenarios {
t.Run(scenario.testName, func(t *testing.T) { t.Run(scenario.testName, func(t *testing.T) {
loader := &TagLoader{ loader := &TagLoader{
Common: utils.NewDummyCommon(), Common: common.NewDummyCommon(),
cmd: oscommands.NewDummyCmdObjBuilder(scenario.runner), cmd: oscommands.NewDummyCmdObjBuilder(scenario.runner),
} }

View File

@ -8,7 +8,7 @@ import (
// NewDummyOSCommand creates a new dummy OSCommand for testing // NewDummyOSCommand creates a new dummy OSCommand for testing
func NewDummyOSCommand() *OSCommand { func NewDummyOSCommand() *OSCommand {
osCmd := NewOSCommand(utils.NewDummyCommon(), config.NewDummyAppConfig(), dummyPlatform, NewNullGuiIO(utils.NewDummyLog())) osCmd := NewOSCommand(common.NewDummyCommon(), config.NewDummyAppConfig(), dummyPlatform, NewNullGuiIO(utils.NewDummyLog()))
return osCmd return osCmd
} }
@ -23,9 +23,9 @@ type OSCommandDeps struct {
} }
func NewDummyOSCommandWithDeps(deps OSCommandDeps) *OSCommand { func NewDummyOSCommandWithDeps(deps OSCommandDeps) *OSCommand {
common := deps.Common cmn := deps.Common
if common == nil { if cmn == nil {
common = utils.NewDummyCommon() cmn = common.NewDummyCommon()
} }
platform := deps.Platform platform := deps.Platform
@ -34,7 +34,7 @@ func NewDummyOSCommandWithDeps(deps OSCommandDeps) *OSCommand {
} }
return &OSCommand{ return &OSCommand{
Common: common, Common: cmn,
Platform: platform, Platform: platform,
getenvFn: deps.GetenvFn, getenvFn: deps.GetenvFn,
removeFileFn: deps.RemoveFileFn, removeFileFn: deps.RemoveFileFn,
@ -59,7 +59,7 @@ var dummyPlatform = &Platform{
} }
func NewDummyOSCommandWithRunner(runner *FakeCmdObjRunner) *OSCommand { func NewDummyOSCommandWithRunner(runner *FakeCmdObjRunner) *OSCommand {
osCommand := NewOSCommand(utils.NewDummyCommon(), config.NewDummyAppConfig(), dummyPlatform, NewNullGuiIO(utils.NewDummyLog())) osCommand := NewOSCommand(common.NewDummyCommon(), config.NewDummyAppConfig(), dummyPlatform, NewNullGuiIO(utils.NewDummyLog()))
osCommand.Cmd = NewDummyCmdObjBuilder(runner) osCommand.Cmd = NewDummyCmdObjBuilder(runner)
return osCommand return osCommand

33
pkg/common/dummies.go Normal file
View File

@ -0,0 +1,33 @@
package common
import (
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/i18n"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/spf13/afero"
)
func NewDummyCommon() *Common {
tr := i18n.EnglishTranslationSet()
cmn := &Common{
Log: utils.NewDummyLog(),
Tr: tr,
Fs: afero.NewOsFs(),
}
cmn.SetUserConfig(config.GetDefaultConfig())
return cmn
}
func NewDummyCommonWithUserConfigAndAppState(userConfig *config.UserConfig, appState *config.AppState) *Common {
tr := i18n.EnglishTranslationSet()
cmn := &Common{
Log: utils.NewDummyLog(),
Tr: tr,
AppState: appState,
// TODO: remove dependency on actual filesystem in tests and switch to using
// in-memory for everything
Fs: afero.NewOsFs(),
}
cmn.SetUserConfig(userConfig)
return cmn
}

View File

@ -3,20 +3,20 @@ package gui
import ( import (
"github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/updates" "github.com/jesseduffield/lazygit/pkg/updates"
"github.com/jesseduffield/lazygit/pkg/utils"
) )
func NewDummyUpdater() *updates.Updater { func NewDummyUpdater() *updates.Updater {
newAppConfig := config.NewDummyAppConfig() newAppConfig := config.NewDummyAppConfig()
dummyUpdater, _ := updates.NewUpdater(utils.NewDummyCommon(), newAppConfig, oscommands.NewDummyOSCommand()) dummyUpdater, _ := updates.NewUpdater(common.NewDummyCommon(), newAppConfig, oscommands.NewDummyOSCommand())
return dummyUpdater return dummyUpdater
} }
// NewDummyGui creates a new dummy GUI for testing // NewDummyGui creates a new dummy GUI for testing
func NewDummyGui() *Gui { func NewDummyGui() *Gui {
newAppConfig := config.NewDummyAppConfig() newAppConfig := config.NewDummyAppConfig()
dummyGui, _ := NewGui(utils.NewDummyCommon(), newAppConfig, &git_commands.GitVersion{Major: 2, Minor: 0, Patch: 0}, NewDummyUpdater(), false, "", nil) dummyGui, _ := NewGui(common.NewDummyCommon(), newAppConfig, &git_commands.GitVersion{Major: 2, Minor: 0, Patch: 0}, NewDummyUpdater(), false, "", nil)
return dummyGui return dummyGui
} }

View File

@ -165,7 +165,7 @@ func BranchStatus(
) string { ) string {
itemOperationStr := ItemOperationToString(itemOperation, tr) itemOperationStr := ItemOperationToString(itemOperation, tr)
if itemOperationStr != "" { if itemOperationStr != "" {
return style.FgCyan.Sprintf("%s %s", itemOperationStr, utils.Loader(now, userConfig.Gui.Spinner)) return style.FgCyan.Sprintf("%s %s", itemOperationStr, Loader(now, userConfig.Gui.Spinner))
} }
result := "" result := ""

View File

@ -8,9 +8,9 @@ import (
"github.com/gookit/color" "github.com/gookit/color"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/gui/presentation/icons" "github.com/jesseduffield/lazygit/pkg/gui/presentation/icons"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/xo/terminfo" "github.com/xo/terminfo"
@ -320,7 +320,7 @@ func Test_getBranchDisplayStrings(t *testing.T) {
oldColorLevel := color.ForceSetColorLevel(terminfo.ColorLevelNone) oldColorLevel := color.ForceSetColorLevel(terminfo.ColorLevelNone)
defer color.ForceSetColorLevel(oldColorLevel) defer color.ForceSetColorLevel(oldColorLevel)
c := utils.NewDummyCommon() c := common.NewDummyCommon()
SetCustomBranches(c.UserConfig().Gui.BranchColorPatterns, true) SetCustomBranches(c.UserConfig().Gui.BranchColorPatterns, true)
for i, s := range scenarios { for i, s := range scenarios {

View File

@ -10,6 +10,7 @@ import (
"github.com/jesseduffield/generics/set" "github.com/jesseduffield/generics/set"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands" "github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/stefanhaller/git-todo-parser/todo" "github.com/stefanhaller/git-todo-parser/todo"
@ -539,7 +540,7 @@ func TestGetCommitListDisplayStrings(t *testing.T) {
} }
} }
common := utils.NewDummyCommon() common := common.NewDummyCommon()
for _, s := range scenarios { for _, s := range scenarios {
if !focusing || s.focus { if !focusing || s.focus {

View File

@ -0,0 +1,14 @@
package presentation
import (
"time"
"github.com/jesseduffield/lazygit/pkg/config"
)
// Loader dumps a string to be displayed as a loader
func Loader(now time.Time, config config.SpinnerConfig) string {
milliseconds := now.UnixMilli()
index := milliseconds / int64(config.Rate) % int64(len(config.Frames))
return config.Frames[index]
}

View File

@ -10,7 +10,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/i18n" "github.com/jesseduffield/lazygit/pkg/i18n"
"github.com/jesseduffield/lazygit/pkg/theme" "github.com/jesseduffield/lazygit/pkg/theme"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo" "github.com/samber/lo"
) )
@ -49,7 +48,7 @@ func getRemoteDisplayStrings(
descriptionStr := style.FgBlue.Sprintf("%d branches", branchCount) descriptionStr := style.FgBlue.Sprintf("%d branches", branchCount)
itemOperationStr := ItemOperationToString(itemOperation, tr) itemOperationStr := ItemOperationToString(itemOperation, tr)
if itemOperationStr != "" { if itemOperationStr != "" {
descriptionStr += " " + style.FgCyan.Sprint(itemOperationStr+" "+utils.Loader(time.Now(), userConfig.Gui.Spinner)) descriptionStr += " " + style.FgCyan.Sprint(itemOperationStr+" "+Loader(time.Now(), userConfig.Gui.Spinner))
} }
res = append(res, textStyle.Sprint(r.Name), descriptionStr) res = append(res, textStyle.Sprint(r.Name), descriptionStr)
return res return res

View File

@ -10,7 +10,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/i18n" "github.com/jesseduffield/lazygit/pkg/i18n"
"github.com/jesseduffield/lazygit/pkg/theme" "github.com/jesseduffield/lazygit/pkg/theme"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo" "github.com/samber/lo"
) )
@ -47,7 +46,7 @@ func getTagDisplayStrings(
descriptionStr := descriptionColor.Sprint(t.Description()) descriptionStr := descriptionColor.Sprint(t.Description())
itemOperationStr := ItemOperationToString(itemOperation, tr) itemOperationStr := ItemOperationToString(itemOperation, tr)
if itemOperationStr != "" { if itemOperationStr != "" {
descriptionStr = style.FgCyan.Sprint(itemOperationStr+" "+utils.Loader(time.Now(), userConfig.Gui.Spinner)) + " " + descriptionStr descriptionStr = style.FgCyan.Sprint(itemOperationStr+" "+Loader(time.Now(), userConfig.Gui.Spinner)) + " " + descriptionStr
} }
res = append(res, textStyle.Sprint(t.Name), descriptionStr) res = append(res, textStyle.Sprint(t.Name), descriptionStr)
return res return res

View File

@ -3,7 +3,7 @@ package custom_commands
import ( import (
"testing" "testing"
"github.com/jesseduffield/lazygit/pkg/utils" "github.com/jesseduffield/lazygit/pkg/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -82,7 +82,7 @@ func TestMenuGenerator(t *testing.T) {
for _, s := range scenarios { for _, s := range scenarios {
t.Run(s.testName, func(t *testing.T) { t.Run(s.testName, func(t *testing.T) {
s.test(NewMenuGenerator(utils.NewDummyCommon()).call(s.cmdOut, s.filter, s.valueFormat, s.labelFormat)) s.test(NewMenuGenerator(common.NewDummyCommon()).call(s.cmdOut, s.filter, s.valueFormat, s.labelFormat))
}) })
} }
} }

View File

@ -5,8 +5,8 @@ import (
"github.com/jesseduffield/gocui" "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
"github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo" "github.com/samber/lo"
"github.com/sasha-s/go-deadlock" "github.com/sasha-s/go-deadlock"
) )
@ -75,7 +75,7 @@ func (self *StatusManager) GetStatusString(userConfig *config.UserConfig) (strin
} }
topStatus := self.statuses[0] topStatus := self.statuses[0]
if topStatus.statusType == "waiting" { if topStatus.statusType == "waiting" {
return topStatus.message + " " + utils.Loader(time.Now(), userConfig.Gui.Spinner), topStatus.color return topStatus.message + " " + presentation.Loader(time.Now(), userConfig.Gui.Spinner), topStatus.color
} }
return topStatus.message, topStatus.color return topStatus.message, topStatus.color
} }

View File

@ -3,11 +3,7 @@ package utils
import ( import (
"io" "io"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/i18n"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/spf13/afero"
) )
// NewDummyLog creates a new dummy Log for testing // NewDummyLog creates a new dummy Log for testing
@ -16,28 +12,3 @@ func NewDummyLog() *logrus.Entry {
log.Out = io.Discard log.Out = io.Discard
return log.WithField("test", "test") return log.WithField("test", "test")
} }
func NewDummyCommon() *common.Common {
tr := i18n.EnglishTranslationSet()
cmn := &common.Common{
Log: NewDummyLog(),
Tr: tr,
Fs: afero.NewOsFs(),
}
cmn.SetUserConfig(config.GetDefaultConfig())
return cmn
}
func NewDummyCommonWithUserConfigAndAppState(userConfig *config.UserConfig, appState *config.AppState) *common.Common {
tr := i18n.EnglishTranslationSet()
cmn := &common.Common{
Log: NewDummyLog(),
Tr: tr,
AppState: appState,
// TODO: remove dependency on actual filesystem in tests and switch to using
// in-memory for everything
Fs: afero.NewOsFs(),
}
cmn.SetUserConfig(userConfig)
return cmn
}

View File

@ -8,10 +8,8 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/jesseduffield/gocui" "github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/config"
) )
// GetProjectRoot returns the path to the root of the project. Only to be used // GetProjectRoot returns the path to the root of the project. Only to be used
@ -25,13 +23,6 @@ func GetProjectRoot() string {
return strings.Split(dir, "lazygit")[0] + "lazygit" return strings.Split(dir, "lazygit")[0] + "lazygit"
} }
// Loader dumps a string to be displayed as a loader
func Loader(now time.Time, config config.SpinnerConfig) string {
milliseconds := now.UnixMilli()
index := milliseconds / int64(config.Rate) % int64(len(config.Frames))
return config.Frames[index]
}
func SortRange(x int, y int) (int, int) { func SortRange(x int, y int) (int, int) {
if x < y { if x < y {
return x, y return x, y