summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIbrahim Serdar Acikgoz <serdaracikgoz86@gmail.com>2018-12-09 03:28:31 +0300
committerIbrahim Serdar Acikgoz <serdaracikgoz86@gmail.com>2018-12-09 03:28:31 +0300
commitad96d97d0262df1e1ab3b054b8d2600c8d821d42 (patch)
treef79da661cf2d7cdad2fdec1ad8e68e1e518ecab1
parentadded sync to remote branches with git fetch prune (diff)
downloadgitbatch-ad96d97d0262df1e1ab3b054b8d2600c8d821d42.tar.gz
added config file option and some minor bugfixes
-rw-r--r--README.md8
-rw-r--r--main.go5
-rw-r--r--pkg/app/app.go25
-rw-r--r--pkg/app/config.go96
-rw-r--r--pkg/app/files.go2
-rw-r--r--pkg/git/status.go2
-rw-r--r--pkg/gui/stagedview.go1
-rw-r--r--pkg/gui/stashview.go1
-rw-r--r--pkg/gui/unstagedview.go1
9 files changed, 127 insertions, 14 deletions
diff --git a/README.md b/README.md
index ed3396a..fb88f9f 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,6 @@ Aim of this tool to make your local repositories synchronized with remotes easil
- [BitBucket Set up an SSH key](https://confluence.atlassian.com/bitbucket/set-up-ssh-for-git-728138079.html)
- Feedbacks are welcome. For now, known issues are:
- At very low probability app fails to load repositories, try again it will load next time (multithreading problem).
- - Sometimes when you scroll too fast while pulling/fetching/merging, some multithreading problem occurs and app crashes (will fix soon).
- Colors vary to your terminal theme colors, so if the contrast is not enough on some color decisions; discussions are welcome.
Here is the screencast of the app:
@@ -46,13 +45,14 @@ For more information;
- shift keys, i.e. **s** for iterate **alt + s** for reverse iteration ✔
- recursive repository search from the filesystem
- full src-d/go-git integration (*having some performance issues*)
-- implement config file to pre-define repo locations or some settings
+- implement config file to pre-define repo locations or some settings ✔
- resolve authentication issues
## Credits
-- [go-git](https://github.com/src-d/go-git) for git interface
+- [go-git](https://github.com/src-d/go-git) for git interface (partially)
- [gocui](https://github.com/jroimartin/gocui) for user interface
- [logrus](https://github.com/sirupsen/logrus) for logging
-- [lazygit](https://github.com/jesseduffield/lazygit) as app template
+- [viper](https://github.com/spf13/viper) for configuration management
- [color](https://github.com/fatih/color) for colored text
+- [lazygit](https://github.com/jesseduffield/lazygit) as app template and reference
- [kingpin](https://github.com/alecthomas/kingpin) for command-line flag&options
diff --git a/main.go b/main.go
index 011f952..5491b97 100644
--- a/main.go
+++ b/main.go
@@ -11,7 +11,8 @@ import (
var (
// take this as default directory if user does not start app with -d flag
currentDir, err = os.Getwd()
- dir = kingpin.Flag("directory", "Directory to roam for git repositories.").Default(currentDir).Short('d').String()
+ dir = kingpin.Flag("directory", "Directory to roam for git repositories").Default(currentDir).Short('d').String()
+ ignoreConfig = kingpin.Flag("ignore-config", "Ignore config file").Short('i').Bool()
repoPattern = kingpin.Flag("pattern", "Pattern to filter repositories").Short('p').String()
logLevel = kingpin.Flag("log-level", "Logging level; trace,debug,info,warn,error").Default("error").Short('l').String()
)
@@ -22,7 +23,7 @@ func main() {
kingpin.Parse()
// set the app
- app, err := app.Setup(*dir, *repoPattern, *logLevel)
+ app, err := app.Setup(*dir, *repoPattern, *logLevel, *ignoreConfig)
if err != nil {
log.Fatal(err)
}
diff --git a/pkg/app/app.go b/pkg/app/app.go
index 624b048..e281abc 100644
--- a/pkg/app/app.go
+++ b/pkg/app/app.go
@@ -1,6 +1,8 @@
package app
import (
+ "os"
+
"github.com/isacikgoz/gitbatch/pkg/gui"
log "github.com/sirupsen/logrus"
)
@@ -14,13 +16,30 @@ type App struct {
// Setup will handle pre-required operations. It is designed to be a wrapper for
// main method right now.
-func Setup(directory, repoPattern, logLevel string) (*App, error) {
+func Setup(directory, repoPattern, logLevel string, ignoreConfig bool) (*App, error) {
// initiate the app and give it initial values
app := &App{}
- app.Config, _ = LoadConfiguration()
setLogLevel(logLevel)
var err error
- directories := generateDirectories(directory, repoPattern)
+ app.Config, err = LoadConfiguration()
+ if err != nil {
+ // the error types and handling is not considered yer
+ log.Error(err)
+ return app, err
+ }
+ workingDirectory, _ := os.Getwd()
+
+ directories := make([]string, 0)
+ if len(app.Config.Directories) <= 0 || ignoreConfig ||
+ (workingDirectory != directory && len(app.Config.Directories) > 0 ){
+ directories = generateDirectories(directory, repoPattern)
+ } else {
+ for _, dir := range app.Config.Directories {
+ for _, d := range generateDirectories(dir, repoPattern) {
+ directories = append(directories, d)
+ }
+ }
+ }
// create a gui.Gui struct and set it as App's gui
app.Gui, err = gui.NewGui(app.Config.Mode, directories)
diff --git a/pkg/app/config.go b/pkg/app/config.go
index d34e647..815b5b0 100644
--- a/pkg/app/config.go
+++ b/pkg/app/config.go
@@ -1,16 +1,112 @@
package app
import (
+ "os"
+ "path/filepath"
+ "runtime"
+ "github.com/spf13/viper"
+ log "github.com/sirupsen/logrus"
)
+// Config type is the configuration entity of the application
type Config struct {
Mode string
Directories []string
}
+// config file stuff
+var (
+ configFileName = "config"
+ configFileExt = ".yml"
+ configType = "yaml"
+ appName = "gitbatch"
+
+ configurationDirectory = filepath.Join(osConfigDirectory(), appName)
+ configFileAbsPath = filepath.Join(configurationDirectory, configFileName)
+)
+
+// configuration items
+var (
+ modeKey = "mode"
+ modeKeyDefault = "fetch"
+ pathsKey = "paths"
+ pathsKeyDefault = []string{"."}
+)
+
+// LoadConfiguration returns a Config struct is filled
func LoadConfiguration() (*Config, error) {
+ if err := initializeConfigurationManager(); err != nil {
+ return nil, err
+ }
+ if err := setDefaults(); err != nil {
+ return nil, err
+ }
+ if err := readConfiguration(); err != nil {
+ return nil, err
+ }
config := &Config{
+ Mode: viper.GetString(modeKey),
+ Directories: viper.GetStringSlice(pathsKey),
}
return config, nil
+}
+
+// set default configuration parameters
+func setDefaults() error {
+ viper.SetDefault(modeKey, modeKeyDefault)
+ // viper.SetDefault(pathsKey, pathsKeyDefault)
+ return nil
+}
+
+// read configuration from file
+func readConfiguration() error{
+ err := viper.ReadInConfig() // Find and read the config file
+ if err != nil { // Handle errors reading the config file
+ // if file does not exist, simply create one
+ if _, err := os.Stat(configFileAbsPath+configFileExt); os.IsNotExist(err) {
+ os.MkdirAll(configurationDirectory, 0755)
+ os.Create(configFileAbsPath+configFileExt)
+ } else {
+ return err
+ }
+ // let's write defaults
+ if err := viper.WriteConfig(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// write configuration to a file
+func writeConfiguration() error{
+ if err := viper.WriteConfig(); err != nil {
+ return err
+ }
+ return nil
+}
+
+// initialize the configuration manager
+func initializeConfigurationManager() error {
+ // config viper
+ viper.AddConfigPath(configurationDirectory)
+ viper.SetConfigName(configFileName)
+ viper.SetConfigType(configType)
+
+ return nil
+}
+
+// returns OS dependent config directory
+func osConfigDirectory() (osConfigDirectory string) {
+ switch osname := runtime.GOOS; osname {
+ case "windows":
+ osConfigDirectory = os.Getenv("APPDATA")
+ case "darwin":
+ osConfigDirectory = os.Getenv("HOME") + "/Library/Application Support"
+ case "linux":
+ osConfigDirectory = os.Getenv("HOME") + "/.config"
+ default:
+ log.Warn("Operating system couldn't be recognized")
+ }
+ return osConfigDirectory
} \ No newline at end of file
diff --git a/pkg/app/files.go b/pkg/app/files.go
index f6ae947..b210c66 100644
--- a/pkg/app/files.go
+++ b/pkg/app/files.go
@@ -52,7 +52,7 @@ func filterDirectories(files []os.FileInfo, repoPattern string) []os.FileInfo {
var filteredRepos []os.FileInfo
for _, f := range files {
// it is just a simple filter
- if strings.Contains(f.Name(), repoPattern) {
+ if strings.Contains(f.Name(), repoPattern) && f.Name() != ".git" {
filteredRepos = append(filteredRepos, f)
} else {
continue
diff --git a/pkg/git/status.go b/pkg/git/status.go
index 51a622b..5644a09 100644
--- a/pkg/git/status.go
+++ b/pkg/git/status.go
@@ -54,7 +54,7 @@ func (entity *RepoEntity) LoadFiles() ([]*File, error) {
for _, file := range fileslist {
x := rune(file[0])
y := rune(file[1])
- relativePathRegex := regexp.MustCompile(`[(\w|/|.)]+`)
+ relativePathRegex := regexp.MustCompile(`[(\w|/|.|\-)]+`)
path := relativePathRegex.FindString(file[2:])
files = append(files, &File{
diff --git a/pkg/gui/stagedview.go b/pkg/gui/stagedview.go
index bae80bd..91b0df3 100644
--- a/pkg/gui/stagedview.go
+++ b/pkg/gui/stagedview.go
@@ -17,7 +17,6 @@ func (gui *Gui) openStageView(g *gocui.Gui) error {
return err
}
v.Title = stageViewFeature.Title
- v.Wrap = true
}
entity := gui.getSelectedRepository()
if err := refreshStagedView(g, entity); err != nil {
diff --git a/pkg/gui/stashview.go b/pkg/gui/stashview.go
index 7322328..c9c246e 100644
--- a/pkg/gui/stashview.go
+++ b/pkg/gui/stashview.go
@@ -17,7 +17,6 @@ func (gui *Gui) openStashView(g *gocui.Gui) error {
return err
}
v.Title = stashViewFeature.Title
- v.Wrap = true
}
entity := gui.getSelectedRepository()
if err := refreshStashView(g, entity); err != nil {
diff --git a/pkg/gui/unstagedview.go b/pkg/gui/unstagedview.go
index ede4844..cf74ce4 100644
--- a/pkg/gui/unstagedview.go
+++ b/pkg/gui/unstagedview.go
@@ -17,7 +17,6 @@ func (gui *Gui) openUnStagedView(g *gocui.Gui) error {
return err
}
v.Title = unstageViewFeature.Title
- v.Wrap = true
}
entity := gui.getSelectedRepository()
if err := refreshUnstagedView(g, entity); err != nil {