Skip to content

Commit

Permalink
add ability to write and commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mput committed Feb 19, 2024
1 parent cb98654 commit 6fb62ad
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 29 deletions.
4 changes: 2 additions & 2 deletions app/bot/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func NewLedger(rs repo.Service, mainFile string, strict bool) *Ledger {
const ledgerBinary = "ledger"

func resolveIncludesReader(rs repo.Service, file string) (io.ReadCloser, error) {
ledgerFile, err := rs.OpenReader(file)
ledgerFile, err := rs.Open(file)
if err != nil {
return nil, err
}
Expand All @@ -53,7 +53,7 @@ func resolveIncludesReader(rs repo.Service, file string) (io.ReadCloser, error)
if strings.HasPrefix(linetr, "include") {
path := strings.TrimPrefix(linetr, "include")
path = strings.TrimSpace(path)
ir, rerr := rs.OpenReader(path)
ir, rerr := rs.Open(path)
if rerr == nil {
f(ir, false)
continue
Expand Down
13 changes: 11 additions & 2 deletions app/repo/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package repo
import (
"fmt"
"io"
"os"
"strings"
)

Expand All @@ -11,13 +12,21 @@ type Mock struct {
Files map[string]string
}

func (r *Mock) OpenReader(file string) (io.ReadCloser, error) {
func (r *Mock) Open(file string) (io.ReadCloser, error) {
if content, ok := r.Files[file]; ok {
return io.NopCloser(strings.NewReader(content)), nil
}
return nil, fmt.Errorf("file not found")
}

func (r *Mock) OpenWriter(_ string) (io.WriteCloser, error) {
func (r *Mock) OpenFile(_ string, _ int, _ os.FileMode) (io.ReadWriteCloser, error) {
return nil, fmt.Errorf("not implemented")
}

func (r *Mock) OpenForAppend(_ string) (io.WriteCloser, error) {
return nil, fmt.Errorf("not implemented")
}

func (r *Mock) CommitPush(_, _, _ string) error {
return nil
}
131 changes: 121 additions & 10 deletions app/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,31 @@ import (
"fmt"
"io"
"log/slog"
"os"
"time"

"github.com/go-git/go-billy/v5"
"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"
"github.com/go-git/go-git/v5/plumbing/transport/http"
"github.com/go-git/go-git/v5/storage/memory"
)


type Service interface {
OpenReader(file string) (io.ReadCloser, error)
OpenWriter(file string) (io.WriteCloser, error)
// Commit(msg string) error

Open(file string) (io.ReadCloser, error)
OpenForAppend(file string) (io.WriteCloser, error)
OpenFile(file string, flag int, perm os.FileMode) (io.ReadWriteCloser, error)
CommitPush(msg, name, email string) error
}

type InMemoryRepo struct {
url string
token string
fs *billy.Filesystem
repo *git.Repository
dirtyFiles map[string]bool
}

func NewInMemoryRepo(url, token string) (*InMemoryRepo, error) {
Expand Down Expand Up @@ -52,15 +56,122 @@ func NewInMemoryRepo(url, token string) (*InMemoryRepo, error) {
return &InMemoryRepo{
url: url,
token: token,
fs: &fs,
repo: r,
dirtyFiles: make(map[string]bool),
}, nil
}

func (r *InMemoryRepo) OpenReader(file string) (io.ReadCloser, error) {
return (*r.fs).Open(file)
func (r *InMemoryRepo) Open(file string) (io.ReadCloser, error) {
wtr, err := r.repo.Worktree()
if err != nil {
return nil, fmt.Errorf("worktree receiving error: %v", err)
}
return wtr.Filesystem.Open(file)
}

type WriteCloser struct {
f *billy.File
r *InMemoryRepo
path string
}

func (w *WriteCloser) Write(p []byte) (n int, err error) {
return (*w.f).Write(p)
}

func (w *WriteCloser) Read(p []byte) (n int, err error) {
return (*w.f).Read(p)
}

func (w *WriteCloser) Close() error {
w.r.dirtyFiles[w.path] = true
return (*w.f).Close()
}

func (r *InMemoryRepo) OpenFile(file string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) {
wtr, err := r.repo.Worktree()
f, err := wtr.Filesystem.OpenFile(file, flag, perm)
wc := WriteCloser{
r: r,
path: file,
f: &f,
}
return &wc, err
}


func (r *InMemoryRepo) OpenForAppend(file string) (io.WriteCloser, error) {
return r.OpenFile(file, os.O_APPEND|os.O_WRONLY, 0o666)
}

func (r *InMemoryRepo) OpenWriter(file string) (io.WriteCloser, error) {
return (*r.fs).Create(file)

func (r *InMemoryRepo) CommitPush(msg, name, email string) error {
wtr, err := r.repo.Worktree()

if err != nil {
return fmt.Errorf("worktree receiving error: %v", err)
}

for file, dirty := range r.dirtyFiles {
if dirty {
_, err = wtr.Add(file)
if err != nil {
return fmt.Errorf("error while adding to worktree: %v", err)
}
}
}
_, err = wtr.Commit(msg, &git.CommitOptions{
Author: &object.Signature{
Name: name,
Email: email,
When: time.Now(),
},
})

if err != nil {
return fmt.Errorf("error while committing: %v", err)
}
err = r.repo.Push(&git.PushOptions{
Auth: &http.BasicAuth{
Username: "username",
Password: r.token,
},
})

if err != nil {
return fmt.Errorf("error while pushing: %v", err)
}

return nil
}

func (r *InMemoryRepo) resetPush(hash plumbing.Hash) error {
wtr, err := r.repo.Worktree()

if err != nil {
return fmt.Errorf("worktree receiving error: %v", err)
}

err = wtr.Reset(&git.ResetOptions{
Commit: hash,
Mode: git.HardReset,
})

if err != nil {
return fmt.Errorf("error while resetting: %v", err)
}

err = r.repo.Push(&git.PushOptions{
ForceWithLease: &git.ForceWithLease{},
Auth: &http.BasicAuth{
Username: "username",
Password: r.token,
},
})

if err != nil {
return fmt.Errorf("error while pushing reset: %v", err)
}

return nil
}
82 changes: 67 additions & 15 deletions app/repo/repo_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
package repo

import (
"fmt"
"io"
"os"
"strings"
"testing"
"time"

"github.com/joho/godotenv"
"github.com/stretchr/testify/require"
)

func checkReadString (t *testing.T, repo Service, fp string) string {
r, err := repo.Open(fp)
if err != nil {
t.Errorf("Unexpected error on file open: %v", err)
}
d, err := io.ReadAll(r)
if err != nil {
t.Fatalf("Unexpected error on file read: %v", err)
}
return string(d)
}

func TestNewInMemoryRepo(t *testing.T) {
_ = godotenv.Load("../../.env.dev")
Expand All @@ -29,36 +44,73 @@ func TestNewInMemoryRepo(t *testing.T) {
}

t.Run("OpenReader", func(t *testing.T) {
r, err := repo.OpenReader("main.ledger")
if checkReadString(t, repo, "main.ledger") == "" {
t.Fatal("Unexpected empty file.")
}

if err != nil {
t.Errorf("Unexpected error on file open: %v", err)
return
r, _ := repo.Open("./main.ledger")
d, _ := io.ReadAll(r)

if len(d) == 0 {
t.Fatal("Unexpected empty file for relative link.")
}

d, err := io.ReadAll(r)

_, err = repo.Open("./nonexisting.ledger")

if err == nil {
t.Fatal("Error expected on nonexisting file open.")
}
})

t.Run("Write And Commit File", func(t *testing.T) {
w, err := repo.OpenForAppend("main.ledger")

if err != nil {
t.Fatalf("Unexpected error on file read: %v", err)
t.Fatal(err)
}

if len(d) == 0 {
t.Fatal("Unexpected empty file.")
ref, err := repo.repo.Head()
if err != nil {
t.Fatal(err)
}

r, _ = repo.OpenReader("./main.ledger")
d, _ = io.ReadAll(r)
hash := ref.Hash()

if len(d) == 0 {
t.Fatal("Unexpected empty file for relative link.")
if err != nil {
t.Fatal(err)
}

line := fmt.Sprintf(";; %s: line added by the Write File test", time.Now())
fmt.Fprintf(w, "\n%s", line)

_, err = repo.OpenReader("./nonexisting.ledger")
require.False(t, repo.dirtyFiles["main.ledger"])
w.Close()
require.True(t, repo.dirtyFiles["main.ledger"])

if err == nil {
t.Fatal("Error expected on nonexisting file open.")
if !strings.HasSuffix(checkReadString(t, repo, "main.ledger"), line) {
t.Fatal("Reader doesn't contains written string")
}

err = repo.CommitPush("test commit", "teledger", "teledger@github.io")
if err != nil {
t.Fatal(err)
}

t.Cleanup(func() {
err = repo.resetPush(hash)
if err != nil {
t.Fatal(err)
}
})

newRepo, err := NewInMemoryRepo(gitURL, gitToken)

if !strings.HasSuffix(checkReadString(t, newRepo, "main.ledger"), line) {
t.Fatal("Reader doesn't contains committed string")
}


})

}
7 changes: 7 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ require (
github.com/joho/godotenv v1.5.1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

require (
dario.cat/mergo v1.0.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
Expand All @@ -25,6 +31,7 @@ require (
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/skeema/knownhosts v1.2.1 // indirect
github.com/stretchr/testify v1.8.4
github.com/xanzy/ssh-agent v0.3.3 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/mod v0.12.0 // indirect
Expand Down

0 comments on commit 6fb62ad

Please sign in to comment.