2020-03-10 12:08:59 +00:00
|
|
|
package filecache
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"io"
|
2023-04-26 12:06:56 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2020-03-10 12:08:59 +00:00
|
|
|
|
2023-10-03 17:25:41 +00:00
|
|
|
"gitlab.com/manytask/itmo-go/public/distbuild/pkg/artifact"
|
|
|
|
"gitlab.com/manytask/itmo-go/public/distbuild/pkg/build"
|
2020-03-10 12:08:59 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
ErrNotFound = errors.New("file not found")
|
2020-04-04 18:45:29 +00:00
|
|
|
ErrExists = errors.New("file exists")
|
2020-03-10 12:08:59 +00:00
|
|
|
ErrWriteLocked = errors.New("file is locked for write")
|
|
|
|
ErrReadLocked = errors.New("file is locked for read")
|
|
|
|
)
|
|
|
|
|
2023-04-26 12:06:56 +00:00
|
|
|
const fileName = "file"
|
|
|
|
|
|
|
|
func convertErr(err error) error {
|
|
|
|
switch {
|
|
|
|
case errors.Is(err, artifact.ErrNotFound):
|
|
|
|
return ErrNotFound
|
|
|
|
case errors.Is(err, artifact.ErrExists):
|
|
|
|
return ErrExists
|
|
|
|
case errors.Is(err, artifact.ErrWriteLocked):
|
|
|
|
return ErrWriteLocked
|
|
|
|
case errors.Is(err, artifact.ErrReadLocked):
|
|
|
|
return ErrReadLocked
|
|
|
|
default:
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-10 12:08:59 +00:00
|
|
|
type Cache struct {
|
2023-04-26 12:06:56 +00:00
|
|
|
cache *artifact.Cache
|
2020-03-10 12:08:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func New(rootDir string) (*Cache, error) {
|
2023-04-26 12:06:56 +00:00
|
|
|
cache, err := artifact.NewCache(rootDir)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
c := &Cache{cache: cache}
|
|
|
|
return c, nil
|
2020-03-10 12:08:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Cache) Range(fileFn func(file build.ID) error) error {
|
2023-04-26 12:06:56 +00:00
|
|
|
return c.cache.Range(fileFn)
|
2020-03-10 12:08:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Cache) Remove(file build.ID) error {
|
2023-04-26 12:06:56 +00:00
|
|
|
return convertErr(c.cache.Remove(file))
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2020-03-29 20:35:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Cache) Write(file build.ID) (w io.WriteCloser, abort func() error, err error) {
|
2023-04-26 12:06:56 +00:00
|
|
|
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
|
2020-03-10 12:08:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Cache) Get(file build.ID) (path string, unlock func(), err error) {
|
2023-04-26 12:06:56 +00:00
|
|
|
root, unlock, err := c.cache.Get(file)
|
|
|
|
path = filepath.Join(root, fileName)
|
|
|
|
err = convertErr(err)
|
|
|
|
return
|
2020-03-10 12:08:59 +00:00
|
|
|
}
|