1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-02-03 13:21:56 +02:00

refactor credential handling

This commit is contained in:
Jesse Duffield 2022-02-23 19:44:48 +11:00
parent d0805616e4
commit 46e9946854
16 changed files with 118 additions and 112 deletions

View File

@ -87,7 +87,6 @@ func localisedTitle(mApp *app.App, str string) string {
"commitMessage": tr.CommitMessageTitle,
"commits": tr.CommitsTitle,
"confirmation": tr.ConfirmationTitle,
"credentials": tr.CredentialsTitle,
"information": tr.InformationTitle,
"main": tr.MainTitle,
"patchBuilding": tr.PatchBuildingTitle,

View File

@ -120,6 +120,7 @@ func (gui *Gui) prepareConfirmationPanel(
hasLoader bool,
findSuggestionsFunc func(string) []*types.Suggestion,
editable bool,
mask bool,
) error {
x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(true, prompt)
// calling SetView on an existing view returns the same view, so I'm not bothering
@ -136,6 +137,7 @@ func (gui *Gui) prepareConfirmationPanel(
// for now we do not support wrapping in our editor
gui.Views.Confirmation.Wrap = !editable
gui.Views.Confirmation.FgColor = theme.GocuiDefaultTextColor
gui.Views.Confirmation.Mask = runeForMask(mask)
gui.findSuggestions = findSuggestionsFunc
if findSuggestionsFunc != nil {
@ -154,7 +156,25 @@ func (gui *Gui) prepareConfirmationPanel(
return nil
}
func runeForMask(mask bool) rune {
if mask {
return '*'
}
return 0
}
func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error {
// if a popup panel already appears we must ignore this current one. This is
// not great but it prevents lost state. The proper solution is to have a stack of
// popups. We could have a queue of types.CreatePopupPanelOpts so that if you
// close a popup and there's another one in the queue we show that.
// One important popup we don't want to interrupt is the credentials popup
// or a process might get stuck waiting on user input.
if gui.currentContext().GetKey() == context.CONFIRMATION_CONTEXT_KEY {
gui.Log.Error("ignoring create popup panel because a popup panel is already open")
return nil
}
// remove any previous keybindings
gui.clearConfirmationViewKeyBindings()
@ -164,6 +184,7 @@ func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error {
opts.HasLoader,
opts.FindSuggestionsFunc,
opts.Editable,
opts.Mask,
)
if err != nil {
return err

View File

@ -24,7 +24,6 @@ const (
MAIN_PATCH_BUILDING_CONTEXT_KEY types.ContextKey = "patchBuilding"
MAIN_STAGING_CONTEXT_KEY types.ContextKey = "staging"
MENU_CONTEXT_KEY types.ContextKey = "menu"
CREDENTIALS_CONTEXT_KEY types.ContextKey = "credentials"
CONFIRMATION_CONTEXT_KEY types.ContextKey = "confirmation"
SEARCH_CONTEXT_KEY types.ContextKey = "search"
COMMIT_MESSAGE_CONTEXT_KEY types.ContextKey = "commitMessage"
@ -51,7 +50,6 @@ var AllContextKeys = []types.ContextKey{
MAIN_PATCH_BUILDING_CONTEXT_KEY,
MAIN_STAGING_CONTEXT_KEY, // not focusable for secondary view
MENU_CONTEXT_KEY,
CREDENTIALS_CONTEXT_KEY,
CONFIRMATION_CONTEXT_KEY,
SEARCH_CONTEXT_KEY,
COMMIT_MESSAGE_CONTEXT_KEY,
@ -80,7 +78,6 @@ type ContextTree struct {
Staging types.Context
PatchBuilding types.Context
Merging types.Context
Credentials types.Context
Confirmation types.Context
CommitMessage types.Context
Search types.Context
@ -103,7 +100,6 @@ func (self *ContextTree) Flatten() []types.Context {
self.Stash,
self.Menu,
self.Confirmation,
self.Credentials,
self.CommitMessage,
self.Normal,
self.Staging,

View File

@ -114,18 +114,6 @@ func (gui *Gui) contextTree() *context.ContextTree {
OnFocus: OnFocusWrapper(func() error { return gui.renderConflictsWithLock(true) }),
},
),
Credentials: context.NewSimpleContext(
context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.PERSISTENT_POPUP,
ViewName: "credentials",
WindowName: "credentials",
Key: context.CREDENTIALS_CONTEXT_KEY,
Focusable: true,
}),
context.ContextCallbackOpts{
OnFocus: OnFocusWrapper(gui.handleAskFocused),
},
),
Confirmation: context.NewSimpleContext(
context.NewBaseContext(context.NewBaseContextOpts{
Kind: types.TEMPORARY_POPUP,

View File

@ -0,0 +1,68 @@
package helpers
import (
"sync"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type CredentialsHelper struct {
c *types.HelperCommon
}
func NewCredentialsHelper(
c *types.HelperCommon,
) *CredentialsHelper {
return &CredentialsHelper{
c: c,
}
}
// promptUserForCredential wait for a username, password or passphrase input from the credentials popup
func (self *CredentialsHelper) PromptUserForCredential(passOrUname oscommands.CredentialType) string {
waitGroup := sync.WaitGroup{}
waitGroup.Add(1)
userInput := ""
self.c.OnUIThread(func() error {
title, mask := self.getTitleAndMask(passOrUname)
return self.c.Prompt(types.PromptOpts{
Title: title,
Mask: mask,
HandleConfirm: func(input string) error {
userInput = input
waitGroup.Done()
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
},
HandleClose: func() error {
waitGroup.Done()
return nil
},
})
})
// wait for username/passwords/passphrase input
waitGroup.Wait()
return userInput + "\n"
}
func (self *CredentialsHelper) getTitleAndMask(passOrUname oscommands.CredentialType) (string, bool) {
switch passOrUname {
case oscommands.Username:
return self.c.Tr.CredentialsUsername, false
case oscommands.Password:
return self.c.Tr.CredentialsPassword, true
case oscommands.Passphrase:
return self.c.Tr.CredentialsPassphrase, true
}
// should never land here
panic("unexpected credential request")
}

View File

@ -1,57 +0,0 @@
package gui
import (
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type credentials chan string
// promptUserForCredential wait for a username, password or passphrase input from the credentials popup
func (gui *Gui) promptUserForCredential(passOrUname oscommands.CredentialType) string {
gui.credentials = make(chan string)
gui.OnUIThread(func() error {
credentialsView := gui.Views.Credentials
switch passOrUname {
case oscommands.Username:
credentialsView.Title = gui.c.Tr.CredentialsUsername
credentialsView.Mask = 0
case oscommands.Password:
credentialsView.Title = gui.c.Tr.CredentialsPassword
credentialsView.Mask = '*'
case oscommands.Passphrase:
credentialsView.Title = gui.c.Tr.CredentialsPassphrase
credentialsView.Mask = '*'
}
if err := gui.c.PushContext(gui.State.Contexts.Credentials); err != nil {
return err
}
return nil
})
// wait for username/passwords/passphrase input
userInput := <-gui.credentials
return userInput + "\n"
}
func (gui *Gui) handleSubmitCredential() error {
credentialsView := gui.Views.Credentials
message := strings.TrimSpace(credentialsView.TextArea.GetContent())
gui.credentials <- message
credentialsView.ClearTextArea()
if err := gui.c.PopContext(); err != nil {
return err
}
return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
}
func (gui *Gui) handleCloseCredentialsView() error {
gui.Views.Credentials.ClearTextArea()
gui.credentials <- ""
return gui.c.PopContext()
}

View File

@ -86,7 +86,6 @@ type Gui struct {
Config config.AppConfigurer
Updater *updates.Updater
statusManager *statusManager
credentials credentials
waitForIntro sync.WaitGroup
fileWatcher *fileWatcher
viewBufferManagerMap map[string]*tasks.ViewBufferManager
@ -247,7 +246,6 @@ type Views struct {
Options *gocui.View
Confirmation *gocui.View
Menu *gocui.View
Credentials *gocui.View
CommitMessage *gocui.View
CommitFiles *gocui.View
Information *gocui.View
@ -403,7 +401,6 @@ func initialViewContextMapping(contextTree *context.ContextTree) map[string]type
"stash": contextTree.Stash,
"menu": contextTree.Menu,
"confirmation": contextTree.Confirmation,
"credentials": contextTree.Credentials,
"commitMessage": contextTree.CommitMessage,
"main": contextTree.Normal,
"secondary": contextTree.Normal,
@ -448,17 +445,6 @@ func NewGui(
InitialDir: initialDir,
}
guiIO := oscommands.NewGuiIO(
cmn.Log,
gui.LogCommand,
gui.getCmdWriter,
gui.promptUserForCredential,
)
osCommand := oscommands.NewOSCommand(cmn, oscommands.GetPlatform(), guiIO)
gui.os = osCommand
gui.watchFilesForChanges()
gui.PopupHandler = popup.NewPopupHandler(
@ -475,6 +461,19 @@ func NewGui(
guiCommon := &guiCommon{gui: gui, IPopupHandler: gui.PopupHandler}
helperCommon := &types.HelperCommon{IGuiCommon: guiCommon, Common: cmn}
credentialsHelper := helpers.NewCredentialsHelper(helperCommon)
guiIO := oscommands.NewGuiIO(
cmn.Log,
gui.LogCommand,
gui.getCmdWriter,
credentialsHelper.PromptUserForCredential,
)
osCommand := oscommands.NewOSCommand(cmn, oscommands.GetPlatform(), guiIO)
gui.os = osCommand
// storing this stuff on the gui for now to ease refactoring
// TODO: reset these controllers upon changing repos due to state changing
gui.c = helperCommon
@ -751,7 +750,6 @@ func (gui *Gui) createAllViews() error {
{viewPtr: &gui.Views.Search, name: "search"},
{viewPtr: &gui.Views.SearchPrefix, name: "searchPrefix"},
{viewPtr: &gui.Views.CommitMessage, name: "commitMessage"},
{viewPtr: &gui.Views.Credentials, name: "credentials"},
{viewPtr: &gui.Views.Menu, name: "menu"},
{viewPtr: &gui.Views.Suggestions, name: "suggestions"},
{viewPtr: &gui.Views.Confirmation, name: "confirmation"},
@ -825,11 +823,6 @@ func (gui *Gui) createAllViews() error {
gui.Views.Confirmation.Visible = false
gui.Views.Credentials.Visible = false
gui.Views.Credentials.Title = gui.c.Tr.CredentialsUsername
gui.Views.Credentials.FgColor = theme.GocuiDefaultTextColor
gui.Views.Credentials.Editable = true
gui.Views.Suggestions.Visible = false
gui.Views.Menu.Visible = false

View File

@ -65,3 +65,7 @@ func (self *guiCommon) Render() {
func (self *guiCommon) OpenSearch() {
_ = self.gui.handleOpenSearch(self.gui.currentViewName())
}
func (self *guiCommon) OnUIThread(f func() error) {
self.gui.OnUIThread(f)
}

View File

@ -430,18 +430,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi
Handler: self.handleCopySelectedSideContextItemToClipboard,
Description: self.c.Tr.LcCopyCommitShaToClipboard,
},
{
ViewName: "credentials",
Key: opts.GetKey(opts.Config.Universal.Confirm),
Modifier: gocui.ModNone,
Handler: self.handleSubmitCredential,
},
{
ViewName: "credentials",
Key: opts.GetKey(opts.Config.Universal.Return),
Modifier: gocui.ModNone,
Handler: self.handleCloseCredentialsView,
},
{
ViewName: "menu",
Key: opts.GetKey(opts.Config.Universal.Return),

View File

@ -224,7 +224,6 @@ func (gui *Gui) onInitialViewsCreation() error {
gui.Views.Menu,
gui.Views.Suggestions,
gui.Views.Confirmation,
gui.Views.Credentials,
// this guy will cover everything else when it appears
gui.Views.Limit,

View File

@ -109,7 +109,9 @@ func (self *RealPopupHandler) Prompt(opts types.PromptOpts) error {
Prompt: opts.InitialContent,
Editable: true,
HandleConfirmPrompt: opts.HandleConfirm,
HandleClose: opts.HandleClose,
FindSuggestionsFunc: opts.FindSuggestionsFunc,
Mask: opts.Mask,
})
}

View File

@ -40,6 +40,11 @@ type IGuiCommon interface {
GetAppState() *config.AppState
SaveAppState() error
// Runs the given function on the UI thread (this is for things like showing a popup asking a user for input).
// Only necessary to call if you're not already on the UI thread i.e. you're inside a goroutine.
// All controller handlers are executed on the UI thread.
OnUIThread(f func() error)
}
type IPopupHandler interface {
@ -73,6 +78,7 @@ type CreatePopupPanelOpts struct {
HandlersManageFocus bool
FindSuggestionsFunc func(string) []*Suggestion
Mask bool
}
type AskOpts struct {
@ -88,6 +94,9 @@ type PromptOpts struct {
InitialContent string
FindSuggestionsFunc func(string) []*Suggestion
HandleConfirm func(string) error
// CAPTURE THIS
HandleClose func() error
Mask bool
}
type MenuItem struct {

View File

@ -80,7 +80,7 @@ func (gui *Gui) globalOptionsMap() map[string]string {
}
func (gui *Gui) isPopupPanel(viewName string) bool {
return viewName == "commitMessage" || viewName == "credentials" || viewName == "confirmation" || viewName == "menu"
return viewName == "commitMessage" || viewName == "confirmation" || viewName == "menu"
}
func (gui *Gui) popupPanelFocused() bool {

View File

@ -191,7 +191,6 @@ func chineseTranslationSet() TranslationSet {
TagsTitle: "标签页面",
MenuTitle: "菜单",
RemotesTitle: "远程页面",
CredentialsTitle: "证书",
RemoteBranchesTitle: "远程分支(在远程页面中)",
PatchBuildingTitle: "构建补丁中",
InformationTitle: "信息",

View File

@ -161,7 +161,6 @@ func dutchTranslationSet() TranslationSet {
TagsTitle: "Tags Tabblad",
MenuTitle: "Menu",
RemotesTitle: "Remotes Tabblad",
CredentialsTitle: "Credentials",
RemoteBranchesTitle: "Remote Branches (in Remotes tabblad)",
PatchBuildingTitle: "Patch Bouwen",
InformationTitle: "Informatie",

View File

@ -177,7 +177,6 @@ type TranslationSet struct {
TagsTitle string
MenuTitle string
RemotesTitle string
CredentialsTitle string
RemoteBranchesTitle string
PatchBuildingTitle string
InformationTitle string
@ -748,7 +747,6 @@ func EnglishTranslationSet() TranslationSet {
TagsTitle: "Tags Tab",
MenuTitle: "Menu",
RemotesTitle: "Remotes Tab",
CredentialsTitle: "Credentials",
RemoteBranchesTitle: "Remote Branches (in Remotes tab)",
PatchBuildingTitle: "Patch Building",
InformationTitle: "Information",