mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-05-23 22:50:41 +02:00
Restrucure project in a way where it is more modular
This commit is contained in:
parent
98c22a36fd
commit
dcd461d29f
31
main.go
31
main.go
@ -14,6 +14,8 @@ import (
|
|||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/app"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
git "gopkg.in/src-d/go-git.v4"
|
git "gopkg.in/src-d/go-git.v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,8 +26,8 @@ var (
|
|||||||
|
|
||||||
commit string
|
commit string
|
||||||
version = "unversioned"
|
version = "unversioned"
|
||||||
|
date string
|
||||||
|
|
||||||
date string
|
|
||||||
debuggingFlag = flag.Bool("debug", false, "a boolean")
|
debuggingFlag = flag.Bool("debug", false, "a boolean")
|
||||||
versionFlag = flag.Bool("v", false, "Print the current version")
|
versionFlag = flag.Bool("v", false, "Print the current version")
|
||||||
|
|
||||||
@ -77,15 +79,6 @@ func localLog(path string, objects ...interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func navigateToRepoRootDirectory() {
|
|
||||||
_, err := os.Stat(".git")
|
|
||||||
for os.IsNotExist(err) {
|
|
||||||
devLog("going up a directory to find the root")
|
|
||||||
os.Chdir("..")
|
|
||||||
_, err = os.Stat(".git")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// when building the binary, `version` is set as a compile-time variable, along
|
// when building the binary, `version` is set as a compile-time variable, along
|
||||||
// with `date` and `commit`. If this program has been opened directly via go,
|
// with `date` and `commit`. If this program has been opened directly via go,
|
||||||
// we will populate the `version` with VERSION in the lazygit root directory
|
// we will populate the `version` with VERSION in the lazygit root directory
|
||||||
@ -112,7 +105,6 @@ func setupWorktree() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
devLog("\n\n\n\n\n\n\n\n\n\n")
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if version == "unversioned" {
|
if version == "unversioned" {
|
||||||
version = fallbackVersion()
|
version = fallbackVersion()
|
||||||
@ -121,9 +113,22 @@ func main() {
|
|||||||
fmt.Printf("commit=%s, build date=%s, version=%s", commit, date, version)
|
fmt.Printf("commit=%s, build date=%s, version=%s", commit, date, version)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
verifyInGitRepo()
|
appConfig := &config.AppConfig{
|
||||||
navigateToRepoRootDirectory()
|
Name: "lazygit",
|
||||||
|
Version: version,
|
||||||
|
Commit: commit,
|
||||||
|
BuildDate: date,
|
||||||
|
Debug: *debuggingFlag,
|
||||||
|
}
|
||||||
|
app, err := app.NewApp(appConfig)
|
||||||
|
app.Log.Info(err)
|
||||||
|
|
||||||
|
app.GitCommand.SetupGit()
|
||||||
|
// TODO remove this once r, w not used
|
||||||
setupWorktree()
|
setupWorktree()
|
||||||
|
|
||||||
|
app.Gui.Run()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if err := run(); err != nil {
|
if err := run(); err != nil {
|
||||||
if err == gocui.ErrQuit {
|
if err == gocui.ErrQuit {
|
||||||
|
49
pkg/app/app.go
Normal file
49
pkg/app/app.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/commands"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// App struct
|
||||||
|
type App struct {
|
||||||
|
closers []io.Closer
|
||||||
|
|
||||||
|
Config config.AppConfigurer
|
||||||
|
Log *logrus.Logger
|
||||||
|
OSCommand *commands.OSCommand
|
||||||
|
GitCommand *commands.GitCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewApp retruns a new applications
|
||||||
|
func NewApp(config config.AppConfigurer) (*App, error) {
|
||||||
|
app := &App{
|
||||||
|
closers: []io.Closer{},
|
||||||
|
Config: config,
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
app.Log = logrus.New()
|
||||||
|
app.OSCommand, err = commands.NewOSCommand(app.Log)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
app.GitCommand, err = commands.NewGitCommand(app.Log, app.OSCommand)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return app, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes any resources
|
||||||
|
func (app *App) Close() error {
|
||||||
|
for _, closer := range app.closers {
|
||||||
|
err := closer.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
71
pkg/commands/git.go
Normal file
71
pkg/commands/git.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
git "gopkg.in/src-d/go-git.v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GitCommand is our main git interface
|
||||||
|
type GitCommand struct {
|
||||||
|
Log *logrus.Logger
|
||||||
|
OSCommand *OSCommand
|
||||||
|
Worktree *git.Worktree
|
||||||
|
Repo *git.Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGitCommand it runs git commands
|
||||||
|
func NewGitCommand(log *logrus.Logger, osCommand *OSCommand) (*GitCommand, error) {
|
||||||
|
gitCommand := &GitCommand{
|
||||||
|
Log: log,
|
||||||
|
OSCommand: osCommand,
|
||||||
|
}
|
||||||
|
return gitCommand, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupGit sets git repo up
|
||||||
|
func (c *GitCommand) SetupGit() {
|
||||||
|
c.verifyInGitRepo()
|
||||||
|
c.navigateToRepoRootDirectory()
|
||||||
|
c.setupWorktree()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GitCommand) GitIgnore(filename string) {
|
||||||
|
if _, err := c.OSCommand.RunDirectCommand("echo '" + filename + "' >> .gitignore"); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GitCommand) verifyInGitRepo() {
|
||||||
|
if output, err := c.OSCommand.RunCommand("git status"); err != nil {
|
||||||
|
fmt.Println(output)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GitCommand) navigateToRepoRootDirectory() {
|
||||||
|
_, err := os.Stat(".git")
|
||||||
|
for os.IsNotExist(err) {
|
||||||
|
c.Log.Debug("going up a directory to find the root")
|
||||||
|
os.Chdir("..")
|
||||||
|
_, err = os.Stat(".git")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GitCommand) setupWorktree() {
|
||||||
|
var err error
|
||||||
|
r, err := git.PlainOpen(".")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
c.Repo = r
|
||||||
|
|
||||||
|
w, err := r.Worktree()
|
||||||
|
c.Worktree = w
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
c.Worktree = w
|
||||||
|
}
|
@ -21,33 +21,6 @@ var (
|
|||||||
ErrNoOpenCommand = errors.New("Unsure what command to use to open this file")
|
ErrNoOpenCommand = errors.New("Unsure what command to use to open this file")
|
||||||
)
|
)
|
||||||
|
|
||||||
// GitFile : A staged/unstaged file
|
|
||||||
// TODO: decide whether to give all of these the Git prefix
|
|
||||||
type GitFile struct {
|
|
||||||
Name string
|
|
||||||
HasStagedChanges bool
|
|
||||||
HasUnstagedChanges bool
|
|
||||||
Tracked bool
|
|
||||||
Deleted bool
|
|
||||||
HasMergeConflicts bool
|
|
||||||
DisplayString string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commit : A git commit
|
|
||||||
type Commit struct {
|
|
||||||
Sha string
|
|
||||||
Name string
|
|
||||||
Pushed bool
|
|
||||||
DisplayString string
|
|
||||||
}
|
|
||||||
|
|
||||||
// StashEntry : A git stash entry
|
|
||||||
type StashEntry struct {
|
|
||||||
Index int
|
|
||||||
Name string
|
|
||||||
DisplayString string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map (from https://gobyexample.com/collection-functions)
|
// Map (from https://gobyexample.com/collection-functions)
|
||||||
func Map(vs []string, f func(string) string) []string {
|
func Map(vs []string, f func(string) string) []string {
|
||||||
vsm := make([]string, len(vs))
|
vsm := make([]string, len(vs))
|
77
pkg/commands/os.go
Normal file
77
pkg/commands/os.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Platform stores the os state
|
||||||
|
type platform struct {
|
||||||
|
os string
|
||||||
|
shell string
|
||||||
|
shellArg string
|
||||||
|
escapedQuote string
|
||||||
|
}
|
||||||
|
|
||||||
|
// OSCommand holds all the os commands
|
||||||
|
type OSCommand struct {
|
||||||
|
Log *logrus.Logger
|
||||||
|
Platform platform
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOSCommand os command runner
|
||||||
|
func NewOSCommand(log *logrus.Logger) (*OSCommand, error) {
|
||||||
|
osCommand := &OSCommand{
|
||||||
|
Log: log,
|
||||||
|
Platform: getPlatform(),
|
||||||
|
}
|
||||||
|
return osCommand, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunCommand wrapper around commands
|
||||||
|
func (c *OSCommand) RunCommand(command string) (string, error) {
|
||||||
|
c.Log.WithField("command", command).Info("RunCommand")
|
||||||
|
splitCmd := strings.Split(command, " ")
|
||||||
|
cmdOut, err := exec.Command(splitCmd[0], splitCmd[1:]...).CombinedOutput()
|
||||||
|
return sanitisedCommandOutput(cmdOut, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunDirectCommand wrapper around direct commands
|
||||||
|
func (c *OSCommand) RunDirectCommand(command string) (string, error) {
|
||||||
|
c.Log.WithField("command", command).Info("RunDirectCommand")
|
||||||
|
|
||||||
|
cmdOut, err := exec.
|
||||||
|
Command(c.Platform.shell, c.Platform.shellArg, command).
|
||||||
|
CombinedOutput()
|
||||||
|
return sanitisedCommandOutput(cmdOut, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sanitisedCommandOutput(output []byte, err error) (string, error) {
|
||||||
|
outputString := string(output)
|
||||||
|
if outputString == "" && err != nil {
|
||||||
|
return err.Error(), err
|
||||||
|
}
|
||||||
|
return outputString, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPlatform() platform {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
return platform{
|
||||||
|
os: "windows",
|
||||||
|
shell: "cmd",
|
||||||
|
shellArg: "/c",
|
||||||
|
escapedQuote: "\\\"",
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return platform{
|
||||||
|
os: runtime.GOOS,
|
||||||
|
shell: "bash",
|
||||||
|
shellArg: "-c",
|
||||||
|
escapedQuote: "\"",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
pkg/config/app_config.go
Normal file
45
pkg/config/app_config.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
// AppConfig contains the base configuration fields required for lazygit.
|
||||||
|
type AppConfig struct {
|
||||||
|
Debug bool `long:"debug" env:"DEBUG" default:"false"`
|
||||||
|
Version string `long:"version" env:"VERSION" default:"unversioned"`
|
||||||
|
Commit string `long:"commit" env:"COMMIT"`
|
||||||
|
BuildDate string `long:"build-date" env:"BUILD_DATE"`
|
||||||
|
Name string `long:"name" env:"NAME" default:"lazygit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppConfigurer interface allows individual app config structs to inherit Fields
|
||||||
|
// from AppConfig and still be used by lazygit.
|
||||||
|
type AppConfigurer interface {
|
||||||
|
GetDebug() bool
|
||||||
|
GetVersion() string
|
||||||
|
GetCommit() string
|
||||||
|
GetBuildDate() string
|
||||||
|
GetName() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDebug returns debug flag
|
||||||
|
func (c *AppConfig) GetDebug() bool {
|
||||||
|
return c.Debug
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVersion returns debug flag
|
||||||
|
func (c *AppConfig) GetVersion() string {
|
||||||
|
return c.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCommit returns debug flag
|
||||||
|
func (c *AppConfig) GetCommit() string {
|
||||||
|
return c.Commit
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBuildDate returns debug flag
|
||||||
|
func (c *AppConfig) GetBuildDate() string {
|
||||||
|
return c.BuildDate
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetName returns debug flag
|
||||||
|
func (c *AppConfig) GetName() string {
|
||||||
|
return c.Name
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
@ -12,11 +12,13 @@ type Branch struct {
|
|||||||
Recency string
|
Recency string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Branch) getDisplayString() string {
|
// GetDisplayString returns the dispaly string of branch
|
||||||
return withPadding(b.Recency, 4) + coloredString(b.Name, b.getColor())
|
// func (b *Branch) GetDisplayString() string {
|
||||||
}
|
// return gui.withPadding(b.Recency, 4) + gui.coloredString(b.Name, b.getColor())
|
||||||
|
// }
|
||||||
|
|
||||||
func (b *Branch) getColor() color.Attribute {
|
// GetColor branch color
|
||||||
|
func (b *Branch) GetColor() color.Attribute {
|
||||||
switch b.getType() {
|
switch b.getType() {
|
||||||
case "feature":
|
case "feature":
|
||||||
return color.FgGreen
|
return color.FgGreen
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
28
pkg/git/git_structs.go
Normal file
28
pkg/git/git_structs.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package git
|
||||||
|
|
||||||
|
// File : A staged/unstaged file
|
||||||
|
// TODO: decide whether to give all of these the Git prefix
|
||||||
|
type File struct {
|
||||||
|
Name string
|
||||||
|
HasStagedChanges bool
|
||||||
|
HasUnstagedChanges bool
|
||||||
|
Tracked bool
|
||||||
|
Deleted bool
|
||||||
|
HasMergeConflicts bool
|
||||||
|
DisplayString string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit : A git commit
|
||||||
|
type Commit struct {
|
||||||
|
Sha string
|
||||||
|
Name string
|
||||||
|
Pushed bool
|
||||||
|
DisplayString string
|
||||||
|
}
|
||||||
|
|
||||||
|
// StashEntry : A git stash entry
|
||||||
|
type StashEntry struct {
|
||||||
|
Index int
|
||||||
|
Name string
|
||||||
|
DisplayString string
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package gui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
||||||
@ -13,16 +13,17 @@ import (
|
|||||||
|
|
||||||
"github.com/golang-collections/collections/stack"
|
"github.com/golang-collections/collections/stack"
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/git"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OverlappingEdges determines if panel edges overlap
|
// OverlappingEdges determines if panel edges overlap
|
||||||
var OverlappingEdges = false
|
var OverlappingEdges = false
|
||||||
|
|
||||||
type stateType struct {
|
type stateType struct {
|
||||||
GitFiles []GitFile
|
GitFiles []git.File
|
||||||
Branches []Branch
|
Branches []git.Branch
|
||||||
Commits []Commit
|
Commits []git.Commit
|
||||||
StashEntries []StashEntry
|
StashEntries []git.StashEntry
|
||||||
PreviousView string
|
PreviousView string
|
||||||
HasMergeConflicts bool
|
HasMergeConflicts bool
|
||||||
ConflictIndex int
|
ConflictIndex int
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package gui
|
||||||
|
|
||||||
import "github.com/jesseduffield/gocui"
|
import "github.com/jesseduffield/gocui"
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package gui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -233,3 +233,7 @@ func getCommitMessageView(g *gocui.Gui) *gocui.View {
|
|||||||
v, _ := g.View("commitMessage")
|
v, _ := g.View("commitMessage")
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func trimmedContent(v *gocui.View) string {
|
||||||
|
return strings.TrimSpace(v.Buffer())
|
||||||
|
}
|
49
pkg/utils/utils.go
Normal file
49
pkg/utils/utils.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
func splitLines(multilineString string) []string {
|
||||||
|
multilineString = strings.Replace(multilineString, "\r", "", -1)
|
||||||
|
if multilineString == "" || multilineString == "\n" {
|
||||||
|
return make([]string, 0)
|
||||||
|
}
|
||||||
|
lines := strings.Split(multilineString, "\n")
|
||||||
|
if lines[len(lines)-1] == "" {
|
||||||
|
return lines[:len(lines)-1]
|
||||||
|
}
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func withPadding(str string, padding int) string {
|
||||||
|
if padding-len(str) < 0 {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
return str + strings.Repeat(" ", padding-len(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
func coloredString(str string, colorAttribute color.Attribute) string {
|
||||||
|
colour := color.New(colorAttribute)
|
||||||
|
return coloredStringDirect(str, colour)
|
||||||
|
}
|
||||||
|
|
||||||
|
// used for aggregating a few color attributes rather than just sending a single one
|
||||||
|
func coloredStringDirect(str string, colour *color.Color) string {
|
||||||
|
return colour.SprintFunc()(fmt.Sprint(str))
|
||||||
|
}
|
||||||
|
|
||||||
|
// used to get the project name
|
||||||
|
func getCurrentProject() string {
|
||||||
|
pwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err.Error())
|
||||||
|
}
|
||||||
|
return filepath.Base(pwd)
|
||||||
|
}
|
5
utils.go
5
utils.go
@ -8,7 +8,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/jesseduffield/gocui"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func splitLines(multilineString string) []string {
|
func splitLines(multilineString string) []string {
|
||||||
@ -23,10 +22,6 @@ func splitLines(multilineString string) []string {
|
|||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
func trimmedContent(v *gocui.View) string {
|
|
||||||
return strings.TrimSpace(v.Buffer())
|
|
||||||
}
|
|
||||||
|
|
||||||
func withPadding(str string, padding int) string {
|
func withPadding(str string, padding int) string {
|
||||||
if padding-len(str) < 0 {
|
if padding-len(str) < 0 {
|
||||||
return str
|
return str
|
||||||
|
Loading…
x
Reference in New Issue
Block a user