* use config for dotfile path, add some makefile scripts

* update README

* add unit test for link command

* fixing ci
pull/16/head
Marcus Kok 2 years ago committed by GitHub
parent 2060833611
commit 9ef61b2626
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -15,4 +15,4 @@ jobs:
- name: Install dependencies
run: go get .
- name: Test with Go CLI
run: TESTING=true go test -v ./test
run: make unit-test

@ -0,0 +1,10 @@
clean:
rm -rf test/bender_test 2> /dev/null
rm -rf tmp 2> /dev/null
sandbox:
mkdir -p ./tmp/ 2> /dev/null
cp -r ~/.config/ ./tmp/config 2> /dev/null
unit-test:
TESTING=true go test -v ./test

@ -1,15 +1,36 @@
# Bender
![](assets/bender.png)
A general purpose CLI tool.
A cli tool to manage your dotfiles
## About
Bender is a tool to help you easily manage your dotfiles and sync them across separate machines using
git. It aims to abstract away the manual effort of symlinking your dotfiles to config directories and
updating them with git.
## Installation
- TBD
## Usage
use pretty command to get whitespace for special characters like `\n` and `\t`
e.g.
```bash
bender pretty example.txt
# init sets up the config file and directory to hold all dotfiles
bender init --dotfile-path=/path/to/dotfile/repo
# add a config directory for bender to track
bender add /.config/nvim
# create symlinks
bender link
```
## Development
It's preferable to create a temporary directory and copy your system's config
directory over to avoid making undesirable changes to your system.
A couple of useful makefile scripts exist to set up and tear down this.
It will create a testing directory in `./tmp/config` and copy your system configs
over.
```bash
make sandbox # creates the directory and copies over from ~/.config
make clean # removes directory
```

@ -34,16 +34,21 @@ func runAddCommand(cmd *cobra.Command, args []string) {
dirs := strings.Split(configSrc, "/")
name := dirs[len(dirs) - 1]
viper.Set(name, configSrc)
viper.WriteConfig()
err := viper.WriteConfig()
if err != nil {
fmt.Printf("Problem updating bender config %s", err)
}
dotfilePath := viper.Get("dotfile-path").(string)
dotfileDest := filepath.Join(DotfilePath, name)
dotfileDest := filepath.Join(dotfilePath, name)
if DryRun {
fmt.Printf("Will copy %s -> %s \n", configSrc, dotfileDest)
return
}
err := tools.CopyDir(fs, configSrc, dotfileDest)
err = tools.CopyDir(fs, configSrc, dotfileDest)
if err != nil {
log.Fatal(err)
}

@ -53,6 +53,9 @@ var initCommand = &cobra.Command {
func runInitCommand(cmd *cobra.Command, args []string) {
fs := FileSystem
// if user has passed a dotfile path flag need to add it to
// viper's search path for a config file
viper.AddConfigPath(filepath.Join(DotfilePath, "bender"))
if(viper.Get("testing") == true && fs.Name() != "MemMapFS") {
log.Fatalf("wrong filesystem, got %s", fs.Name())
@ -68,7 +71,10 @@ func runInitCommand(cmd *cobra.Command, args []string) {
panic(fmt.Errorf("Unable to create config file %w", err))
}
viper.WriteConfig()
err = viper.WriteConfig()
if err != nil && viper.Get("testing") != true {
log.Fatalf("Unable to write config on init: %s\n", err)
}
if (viper.Get("testing") != "true"){
_, err = git.PlainInit(DotfilePath, false)
@ -77,5 +83,5 @@ func runInitCommand(cmd *cobra.Command, args []string) {
}
}
fmt.Fprintf(cmd.OutOrStdout(), "Successfully created dotfiles repository\n")
fmt.Fprintf(cmd.OutOrStdout(), "Successfully created dotfiles repository at %s\n", DotfilePath)
}

@ -7,6 +7,7 @@ import (
"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var linkCommand = &cobra.Command {
@ -19,18 +20,25 @@ func init() {
}
func runLinkCommand(cmd *cobra.Command, args []string) {
fs := UseFilesystem()
fs := FileSystem
fmt.Println("Symlinking dotfiles...")
entries, err := afero.ReadDir(fs, DotfilePath)
dotfileRoot := viper.Get("dotfile-path").(string)
entries, err := afero.ReadDir(fs, dotfileRoot)
if err != nil {
log.Fatal(err)
log.Fatalf("Could not read dotfiles directory: %s\n",err)
}
for _, entry := range(entries) {
if entry.Name() == ".git" {
configName := entry.Name()
if configName == ".git" || configName == "bender" {
continue
}
dotPath := filepath.Join(DotfilePath, entry.Name())
configPath := filepath.Join(ConfigPath, entry.Name())
dotPath := filepath.Join(dotfileRoot, entry.Name())
configPath := viper.GetString(configName)
if configPath == ""{
fmt.Fprintf(cmd.OutOrStdout(), "Warning: could not find config for %s\n", entry.Name())
}
// destination needs to be removed before symlink
if(DryRun) {
@ -40,11 +48,17 @@ func runLinkCommand(cmd *cobra.Command, args []string) {
fs.RemoveAll(configPath)
}
testing := viper.Get("testing")
if(DryRun) {
log.Printf("Will link %s -> %s\n", dotPath, configPath)
log.Printf("Will link %s -> %s\n", configPath, dotPath)
} else {
if(testing == true) {
fmt.Fprintf(cmd.OutOrStdout(), "%s,%s", configPath, dotPath)
} else {
err = afero.OsFs.SymlinkIfPossible(afero.OsFs{}, dotPath, configPath)
}
}
if err != nil {
log.Fatalf("Cannot symlink %s: %s", entry.Name(), err.Error())
}

@ -66,10 +66,11 @@ func init() {
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(filepath.Join(defaultDotPath, "bender"))
viper.AddConfigPath("./bender")
viper.AddConfigPath("./tmp/dotfiles/bender")
viper.AddConfigPath(filepath.Join(DotfilePath, "bender"))
err := viper.ReadInConfig()
if err != nil {
fmt.Println("No config detected. You can generate one by using 'bender init'")
}
@ -88,29 +89,4 @@ func UseFilesystem() afero.Fs {
}
// TODO: this can probably be removed
func SetUpForTesting() afero.Fs {
viper.Set("testing", true)
fs := UseFilesystem()
homedir := "bender_test/"
fs.MkdirAll(filepath.Join(homedir, ".config/"), 0755)
fs.MkdirAll(filepath.Join(homedir, ".dotfiles/"), 0755)
fs.Mkdir("bin/", 0755)
fs.Create("bin/alacritty")
fs.Create("bin/nvim")
fs.Create("bin/tmux")
fs.Mkdir(filepath.Join(homedir, ".config/alacritty"), 0755)
fs.Mkdir(filepath.Join(homedir, ".config/nvim"), 0755)
fs.Mkdir(filepath.Join(homedir, ".config/tmux"), 0755)
fs.Create(filepath.Join(homedir, ".config/alacritty/alacritty.conf"))
fs.Create(filepath.Join(homedir, ".config/nvim/nvim.conf"))
fs.Create(filepath.Join(homedir, ".config/tmux/tmux.conf"))
FileSystem = fs
return fs
}

@ -20,13 +20,13 @@ func TestInitCommand(t *testing.T) {
bender.SetOut(actual)
bender.SetErr(actual)
bender.SetArgs([]string{"init", "--dotfile-path=bender_test/.dotfiles"})
bender.SetArgs([]string{"init", "--dotfile-path=bender_test/dotfiles"})
bender.Execute()
homedir := "bender_test/"
_, err := afero.ReadFile(fs, filepath.Join(homedir, ".dotfiles/bender/config"))
_, err := afero.ReadFile(fs, filepath.Join(homedir, "dotfiles/bender/config"))
if err != nil {
t.Error(err.Error())
}

@ -0,0 +1,54 @@
package test
import (
"bytes"
"fmt"
"os"
"path/filepath"
"testing"
"github.com/Marcusk19/bender/cmd"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
)
func TestLinkCommand(t *testing.T) {
setUpTesting()
bender := cmd.RootCmd
actual := new(bytes.Buffer)
bender.SetOut(actual)
bender.SetErr(actual)
bender.SetArgs([]string{"link"})
bender.Execute()
homedir := os.Getenv("HOME")
someconfig := filepath.Join(homedir, ".config/someconfig/")
somedot := filepath.Join(homedir, ".dotfiles/someconfig/")
expected := fmt.Sprintf("%s,%s", someconfig, somedot)
assert.Equal(t, expected, actual.String(), "actual differs from expected")
tearDownTesting()
}
func setUpTesting() {
fs := cmd.FileSystem
homedir := os.Getenv("HOME")
fs.MkdirAll(filepath.Join(homedir, ".dotfiles/bender"), 0755)
fs.Create(filepath.Join(homedir, ".dotfiles/bender/config"))
fs.MkdirAll(filepath.Join(homedir, ".dotfiles/someconfig/"), 0755)
viper.Set("dotfile-path", filepath.Join(homedir, ".dotfiles"))
viper.Set("someconfig", filepath.Join(homedir, ".config/someconfig/"))
viper.Set("testing", true)
}
func tearDownTesting() {
fs := cmd.FileSystem
fs.RemoveAll("bender_test/")
}
Loading…
Cancel
Save