1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-04-07 07:19:57 +02:00

Restrucure project in a way where it is more modular

This commit is contained in:
Andrei Miulescu 2018-08-12 19:31:27 +10:00
parent 98c22a36fd
commit dcd461d29f
No known key found for this signature in database
GPG Key ID: 7C452D659F3A0FCB
22 changed files with 357 additions and 58 deletions

31
main.go
View File

@ -14,6 +14,8 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/app"
"github.com/jesseduffield/lazygit/pkg/config"
git "gopkg.in/src-d/go-git.v4"
)
@ -24,8 +26,8 @@ var (
commit string
version = "unversioned"
date string
date string
debuggingFlag = flag.Bool("debug", false, "a boolean")
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
// 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
@ -112,7 +105,6 @@ func setupWorktree() {
}
func main() {
devLog("\n\n\n\n\n\n\n\n\n\n")
flag.Parse()
if version == "unversioned" {
version = fallbackVersion()
@ -121,9 +113,22 @@ func main() {
fmt.Printf("commit=%s, build date=%s, version=%s", commit, date, version)
os.Exit(0)
}
verifyInGitRepo()
navigateToRepoRootDirectory()
appConfig := &config.AppConfig{
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()
app.Gui.Run()
for {
if err := run(); err != nil {
if err == gocui.ErrQuit {

49
pkg/app/app.go Normal file
View 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
View 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
}

View File

@ -21,33 +21,6 @@ var (
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)
func Map(vs []string, f func(string) string) []string {
vsm := make([]string, len(vs))

77
pkg/commands/os.go Normal file
View 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
View 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
}

View File

@ -1,4 +1,4 @@
package main
package git
import (
"strings"
@ -12,11 +12,13 @@ type Branch struct {
Recency string
}
func (b *Branch) getDisplayString() string {
return withPadding(b.Recency, 4) + coloredString(b.Name, b.getColor())
}
// GetDisplayString returns the dispaly string of branch
// 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() {
case "feature":
return color.FgGreen

View File

@ -1,4 +1,4 @@
package main
package git
import (
"regexp"

28
pkg/git/git_structs.go Normal file
View 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
}

View File

@ -1,4 +1,4 @@
package main
package gui
import (
@ -13,16 +13,17 @@ import (
"github.com/golang-collections/collections/stack"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/git"
)
// OverlappingEdges determines if panel edges overlap
var OverlappingEdges = false
type stateType struct {
GitFiles []GitFile
Branches []Branch
Commits []Commit
StashEntries []StashEntry
GitFiles []git.File
Branches []git.Branch
Commits []git.Commit
StashEntries []git.StashEntry
PreviousView string
HasMergeConflicts bool
ConflictIndex int

View File

@ -1,4 +1,4 @@
package main
package gui
import "github.com/jesseduffield/gocui"

View File

@ -1,4 +1,4 @@
package main
package gui
import (
"fmt"
@ -233,3 +233,7 @@ func getCommitMessageView(g *gocui.Gui) *gocui.View {
v, _ := g.View("commitMessage")
return v
}
func trimmedContent(v *gocui.View) string {
return strings.TrimSpace(v.Buffer())
}

49
pkg/utils/utils.go Normal file
View 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)
}

View File

@ -8,7 +8,6 @@ import (
"strings"
"github.com/fatih/color"
"github.com/jesseduffield/gocui"
)
func splitLines(multilineString string) []string {
@ -23,10 +22,6 @@ func splitLines(multilineString string) []string {
return lines
}
func trimmedContent(v *gocui.View) string {
return strings.TrimSpace(v.Buffer())
}
func withPadding(str string, padding int) string {
if padding-len(str) < 0 {
return str