diff --git a/distbuild/pkg/api/heartbeat.go b/distbuild/pkg/api/heartbeat.go index 5011e4e..3408af3 100644 --- a/distbuild/pkg/api/heartbeat.go +++ b/distbuild/pkg/api/heartbeat.go @@ -92,5 +92,5 @@ func (h *HeartbeatHandler) Register(mux *http.ServeMux) { } func (h *HeartbeatHandler) heartbeat(w http.ResponseWriter, r *http.Request) { - + panic("implement me") } diff --git a/distbuild/pkg/artifact/cache.go b/distbuild/pkg/artifact/cache.go index 0d321a6..1793510 100644 --- a/distbuild/pkg/artifact/cache.go +++ b/distbuild/pkg/artifact/cache.go @@ -14,9 +14,9 @@ import ( ) var ( - ErrNotFound = errors.New("file not found") - ErrWriteLocked = errors.New("file is locked for write") - ErrReadLocked = errors.New("file is locked for read") + ErrNotFound = errors.New("artifact not found") + ErrWriteLocked = errors.New("artifact is locked for write") + ErrReadLocked = errors.New("artifact is locked for read") ) type Cache struct { diff --git a/distbuild/pkg/filecache/filecache.go b/distbuild/pkg/filecache/filecache.go index 868082f..4ee9b63 100644 --- a/distbuild/pkg/filecache/filecache.go +++ b/distbuild/pkg/filecache/filecache.go @@ -2,11 +2,12 @@ package filecache import ( "errors" - "fmt" "io" "net/http" "os" + "path/filepath" + "gitlab.com/slon/shad-go/distbuild/pkg/artifact" "gitlab.com/slon/shad-go/distbuild/pkg/build" ) @@ -16,33 +17,95 @@ var ( ErrReadLocked = errors.New("file is locked for read") ) +const fileName = "file" + +func convertErr(err error) error { + switch { + case errors.Is(err, artifact.ErrNotFound): + return ErrNotFound + case errors.Is(err, artifact.ErrWriteLocked): + return ErrWriteLocked + case errors.Is(err, artifact.ErrReadLocked): + return ErrReadLocked + default: + return err + } +} + type Cache struct { - rootDir string + cache *artifact.Cache } func New(rootDir string) (*Cache, error) { - if err := os.MkdirAll(rootDir, 0777); err != nil { - return nil, fmt.Errorf("error creating filecache: %w", err) + cache, err := artifact.NewCache(rootDir) + if err != nil { + return nil, err } - c := &Cache{rootDir: rootDir} + c := &Cache{cache: cache} return c, nil } func (c *Cache) Range(fileFn func(file build.ID) error) error { - panic("implement me") + return c.cache.Range(fileFn) } func (c *Cache) Remove(file build.ID) error { - panic("implement me") + return convertErr(c.cache.Remove(file)) } -func (c *Cache) Write(file build.ID) (w io.WriteCloser, abort func(), err error) { - panic("implement me") +type fileWriter struct { + f *os.File + commit func() error +} + +func (f *fileWriter) Write(p []byte) (int, error) { + return f.f.Write(p) +} + +func (f *fileWriter) Close() error { + closeErr := f.f.Close() + commitErr := f.commit() + + if closeErr != nil { + return closeErr + } + + return commitErr +} + +func (c *Cache) Write(file build.ID) (w io.WriteCloser, abort func() error, err error) { + path, commit, abortDir, err := c.cache.Create(file) + if err != nil { + err = convertErr(err) + return + } + + f, err := os.Create(filepath.Join(path, fileName)) + if err != nil { + _ = abort() + return + } + + w = &fileWriter{f: f, commit: commit} + abort = func() error { + closeErr := f.Close() + abortErr := abortDir() + + if closeErr != nil { + return closeErr + } + + return abortErr + } + return } func (c *Cache) Get(file build.ID) (path string, unlock func(), err error) { - panic("implement me") + root, unlock, err := c.cache.Get(file) + path = filepath.Join(root, fileName) + err = convertErr(err) + return } func NewHandler(c *Cache) http.Handler { diff --git a/distbuild/pkg/filecache/filecache_test.go b/distbuild/pkg/filecache/filecache_test.go new file mode 100644 index 0000000..346fc1b --- /dev/null +++ b/distbuild/pkg/filecache/filecache_test.go @@ -0,0 +1,41 @@ +package filecache + +import ( + "errors" + "io/ioutil" + "testing" + + "github.com/stretchr/testify/require" + + "gitlab.com/slon/shad-go/distbuild/pkg/build" +) + +func TestFileCache(t *testing.T) { + tmpDir, err := ioutil.TempDir("", "filecache") + require.NoError(t, err) + + cache, err := New(tmpDir) + require.NoError(t, err) + + _, abort, err := cache.Write(build.ID{01}) + require.NoError(t, err) + require.NoError(t, abort()) + + _, _, err = cache.Get(build.ID{01}) + require.Truef(t, errors.Is(err, ErrNotFound), "real error: %v", err) + + f, _, err := cache.Write(build.ID{02}) + require.NoError(t, err) + + _, err = f.Write([]byte("foo bar")) + require.NoError(t, err) + require.NoError(t, f.Close()) + + path, unlock, err := cache.Get(build.ID{02}) + require.NoError(t, err) + defer unlock() + + content, err := ioutil.ReadFile(path) + require.NoError(t, err) + require.Equal(t, []byte("foo bar"), content) +}