Skip to content

Commit

Permalink
moved cache and persistence to internal
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Menet committed Aug 25, 2023
1 parent 7fb3cc3 commit 7c83323
Show file tree
Hide file tree
Showing 5 changed files with 291 additions and 0 deletions.
46 changes: 46 additions & 0 deletions internal/cache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package cache

import (
"time"
)

type Cache struct {
timeout time.Duration
store map[string]cacheElement
}

func New(timeout time.Duration) *Cache {
return &Cache{
timeout: timeout,
store: map[string]cacheElement{},
}
}

func (c *Cache) Add(key string, data []byte) {
c.store[key] = cacheElement{
cachedAt: time.Now(),
data: data,
}
}

func (c *Cache) Get(key string) ([]byte, bool) {
elem, ok := c.store[key]
if !ok {
return nil, false
}
age := time.Since(elem.cachedAt)
if age >= c.timeout {
delete(c.store, key)
return nil, false
}
return elem.data, true
}

func (c *Cache) Purge() {
c.store = make(map[string]cacheElement)
}

type cacheElement struct {
data []byte
cachedAt time.Time
}
93 changes: 93 additions & 0 deletions internal/cache/cache_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package cache

import (
"bytes"
"testing"
"time"
)

func TestCache_Add(t *testing.T) {
// Create a new cache instance
cache := New(time.Minute)

// Add a cache element with a key and data
key := "test"
data := []byte("test data")
cache.Add(key, data)

// Check if the cache element exists in the store
if _, ok := cache.store[key]; !ok {
t.Errorf("Cache element with key '%s' not found", key)
}

// Check if the data of the cache element is correct
if got := cache.store[key].data; !bytes.Equal(got, data) {
t.Errorf("Cache element data mismatch, got %v, want %v", got, data)
}
}

func TestCache_Get(t *testing.T) {
// Create a new cache instance
cache := New(time.Minute)

// Add a cache element with a key and data
key := "test"
data := []byte("test data")
cache.Add(key, data)

// Retrieve the cache element using the Get method
got, ok := cache.Get(key)

// Check if the cache element is found
if !ok {
t.Errorf("Cache element with key '%s' not found", key)
}

// Check if the retrieved data is correct
if string(got) != string(data) {
t.Errorf("Retrieved data mismatch, got %s, want %s", got, data)
}
}

func TestCache_Get_Expired(t *testing.T) {
// Create a new cache instance with a short timeout duration
cache := New(1 * time.Millisecond)

// Add a cache element with a key and data
key := "test"
data := []byte("test data")
cache.Add(key, data)

// Wait for the cache element to expire
time.Sleep(2 * time.Millisecond)

// Retrieve the cache element using the Get method
got, ok := cache.Get(key)

// Check if the cache element is not found
if ok {
t.Errorf("Cache element with key '%s' found, expected not found", key)
}

// Check if the retrieved data is nil
if got != nil {
t.Errorf("Retrieved data mismatch, got %v, want nil", got)
}
}

func TestCache_Purge(t *testing.T) {
// Create a new cache instance
cache := New(time.Minute)

// Add multiple cache elements
cache.Add("key1", []byte("data1"))
cache.Add("key2", []byte("data2"))

// Purge the cache
cache.Purge()

// Check if the store is empty
if len(cache.store) != 0 {
t.Errorf("Cache store is not empty after purging")
}
}
92 changes: 92 additions & 0 deletions internal/persistence/git.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package persistence

import (
"fmt"
"os"

"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"
ssh2 "github.com/go-git/go-git/v5/plumbing/transport/ssh"
"github.com/go-git/go-git/v5/storage/memory"
"golang.org/x/crypto/ssh"
)

type gitrepo struct {
repo *git.Repository
fs billy.Filesystem
}

func NewGitRepo(keypath, pass, url string) (Persistence, error) {
gr := &gitrepo{}
pem, err := os.ReadFile(keypath)
if err != nil {
return gr, err
}
signer, err := ssh.ParsePrivateKeyWithPassphrase(pem, []byte(pass))
if err != nil {
return gr, err
}
auth := &ssh2.PublicKeys{User: "git", Signer: signer}
gr.fs = memfs.New()
gr.repo, err = git.Clone(memory.NewStorage(), gr.fs, &git.CloneOptions{
URL: url,
Auth: auth,
Progress: os.Stdout,
Mirror: true,
})
return gr, err
}

func (gr *gitrepo) Filesystem() billy.Filesystem {
return gr.fs
}

func (gr *gitrepo) Branches() ([]string, error) {
var branches []string
iter, err := gr.repo.Branches()
if err != nil {
return branches, err
}
_ = iter.ForEach(func(this *plumbing.Reference) error {
branches = append(branches, this.Name().String())
return nil
})
return branches, nil
}

func (gr *gitrepo) branch(name string) *plumbing.Reference {
var ref *plumbing.Reference
iter, err := gr.repo.Branches()
if err != nil {
return ref
}
_ = iter.ForEach(func(this *plumbing.Reference) error {
if this.Name().String() == name {
ref = this
}
return nil
})
return ref
}

func (gr *gitrepo) CheckoutBranch(name string) error {
worktree, err := gr.repo.Worktree()
if err != nil {
return err
}
branch := gr.branch(name)
if branch == nil {
return fmt.Errorf("Branch '%s' does not exist", name)
}
err = worktree.Checkout(&git.CheckoutOptions{
Branch: branch.Name(),
Force: true,
})
if err != nil {
return err
}
gr.fs = worktree.Filesystem
return nil
}
29 changes: 29 additions & 0 deletions internal/persistence/local.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package persistence

import (
"github.com/go-git/go-billy/v5"
"github.com/go-git/go-billy/v5/osfs"
)

type local struct {
fs billy.Filesystem
}

func NewLocal(path string) (Persistence, error) {
l := &local{
fs: osfs.New(path),
}
return l, nil
}

func (l *local) Filesystem() billy.Filesystem {
return l.fs
}

func (l *local) Branches() ([]string, error) {
return []string{"local"}, nil
}

func (l *local) CheckoutBranch(name string) error {
return nil
}
31 changes: 31 additions & 0 deletions internal/persistence/persistence.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package persistence

import (
"fmt"

"github.com/go-git/go-billy/v5"
)

type Persistence interface {
Filesystem() billy.Filesystem
Branches() ([]string, error)
CheckoutBranch(string) error
}

type Config struct {
Filepath string
Git struct {
Keyfile string
Pass string
URL string
}
}

func New(c Config) (Persistence, error) {
if c.Git.URL != "" {
return NewGitRepo(c.Git.Keyfile, c.Git.Pass, c.Git.URL)
} else if c.Filepath != "" {
return NewLocal(c.Filepath)
}
return nil, fmt.Errorf("Neither a git url nor a local file path was provided")
}

0 comments on commit 7c83323

Please sign in to comment.