Treat config as a bare git repository to keep consistency

Ayman Bagabas created

Change summary

go.mod                    |  3 ++-
internal/config/config.go | 21 +++++++++++++--------
internal/git/git.go       | 19 +++++++++++++++++--
3 files changed, 32 insertions(+), 11 deletions(-)

Detailed changes

go.mod 🔗

@@ -20,6 +20,8 @@ require (
 	gopkg.in/yaml.v2 v2.3.0
 )
 
+require github.com/go-git/go-billy/v5 v5.3.1
+
 require (
 	github.com/Microsoft/go-winio v0.4.16 // indirect
 	github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
@@ -33,7 +35,6 @@ require (
 	github.com/dlclark/regexp2 v1.2.0 // indirect
 	github.com/emirpasic/gods v1.12.0 // indirect
 	github.com/go-git/gcfg v1.5.0 // indirect
-	github.com/go-git/go-billy/v5 v5.3.1 // indirect
 	github.com/gorilla/css v1.0.0 // indirect
 	github.com/imdario/mergo v0.3.12 // indirect
 	github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect

internal/config/config.go 🔗

@@ -7,7 +7,6 @@ import (
 
 	"fmt"
 	"os"
-	"path/filepath"
 
 	"github.com/charmbracelet/soft/config"
 	"github.com/charmbracelet/soft/internal/git"
@@ -125,22 +124,27 @@ func (cfg *Config) createDefaultConfigRepo(yaml string) error {
 	}
 	_, err = rs.GetRepo(cn)
 	if err == git.ErrMissingRepo {
-		cr, err := rs.InitRepo(cn, false)
+		cr, err := rs.InitRepo(cn, true)
 		if err != nil {
 			return err
 		}
-
-		rp := filepath.Join(rs.Path, cn, "README.md")
-		err = createFile(rp, defaultReadme)
+		wt, err := cr.Repository.Worktree()
 		if err != nil {
 			return err
 		}
-		cp := filepath.Join(rs.Path, cn, "config.yaml")
-		err = createFile(cp, yaml)
+		rm, err := wt.Filesystem.Create("README.md")
 		if err != nil {
 			return err
 		}
-		wt, err := cr.Repository.Worktree()
+		_, err = rm.Write([]byte(defaultReadme))
+		if err != nil {
+			return err
+		}
+		cf, err := wt.Filesystem.Create("config.yaml")
+		if err != nil {
+			return err
+		}
+		_, err = cf.Write([]byte(yaml))
 		if err != nil {
 			return err
 		}
@@ -162,6 +166,7 @@ func (cfg *Config) createDefaultConfigRepo(yaml string) error {
 		if err != nil {
 			return err
 		}
+		err = cr.Repository.Push(&gg.PushOptions{})
 		if err != nil {
 			return err
 		}

internal/git/git.go 🔗

@@ -4,12 +4,16 @@ import (
 	"errors"
 	"log"
 	"os"
+	"path/filepath"
 	"sort"
 	"sync"
 	"time"
 
+	"github.com/go-git/go-billy/v5/memfs"
 	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing/object"
+	"github.com/go-git/go-git/v5/plumbing/transport"
+	"github.com/go-git/go-git/v5/storage/memory"
 )
 
 var ErrMissingRepo = errors.New("missing repo")
@@ -70,10 +74,21 @@ func (rs *RepoSource) GetRepo(name string) (*Repo, error) {
 func (rs *RepoSource) InitRepo(name string, bare bool) (*Repo, error) {
 	rs.mtx.Lock()
 	defer rs.mtx.Unlock()
-	rg, err := git.PlainInit(rs.Path+string(os.PathSeparator)+name, bare)
+	rp := filepath.Join(rs.Path, name)
+	rg, err := git.PlainInit(rp, bare)
 	if err != nil {
 		return nil, err
 	}
+	if bare {
+		// Clone repo into memory storage
+		ar, err := git.Clone(memory.NewStorage(), memfs.New(), &git.CloneOptions{
+			URL: rp,
+		})
+		if err != nil && err != transport.ErrEmptyRemoteRepository {
+			return nil, err
+		}
+		rg = ar
+	}
 	r := &Repo{
 		Name:       name,
 		Repository: rg,
@@ -102,7 +117,7 @@ func (rs *RepoSource) LoadRepos() error {
 	rs.commits = make([]RepoCommit, 0)
 	for _, de := range rd {
 		rn := de.Name()
-		rg, err := git.PlainOpen(rs.Path + string(os.PathSeparator) + rn)
+		rg, err := git.PlainOpen(filepath.Join(rs.Path, rn))
 		if err != nil {
 			return err
 		}