mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 04:14:39 +03:00
Developer option: extra blob paths (#4566)
* Allow additional read-only blob paths * Add developer option to add more blob sources * Add makefile targets to start and remove build container * Documentation
This commit is contained in:
@@ -19,65 +19,34 @@ const (
|
||||
blobsDirLength int = 2 // thumbDirDepth * thumbDirLength must be smaller than the length of checksum
|
||||
)
|
||||
|
||||
type FS interface {
|
||||
type FSReader interface {
|
||||
Open(name string) (fs.ReadDirFile, error)
|
||||
}
|
||||
|
||||
type FSWriter interface {
|
||||
Create(name string) (*os.File, error)
|
||||
MkdirAll(path string, perm fs.FileMode) error
|
||||
Open(name string) (fs.ReadDirFile, error)
|
||||
|
||||
Remove(name string) error
|
||||
|
||||
file.RenamerRemover
|
||||
}
|
||||
|
||||
type FilesystemStore struct {
|
||||
deleter *file.Deleter
|
||||
path string
|
||||
fs FS
|
||||
type FS interface {
|
||||
FSReader
|
||||
FSWriter
|
||||
}
|
||||
|
||||
func NewFilesystemStore(path string, fs FS) *FilesystemStore {
|
||||
deleter := &file.Deleter{
|
||||
RenamerRemover: fs,
|
||||
}
|
||||
|
||||
return &FilesystemStore{
|
||||
deleter: deleter,
|
||||
path: path,
|
||||
fs: fs,
|
||||
}
|
||||
type FilesystemReader struct {
|
||||
path string
|
||||
fs FSReader
|
||||
}
|
||||
|
||||
func (s *FilesystemStore) checksumToPath(checksum string) string {
|
||||
func (s *FilesystemReader) checksumToPath(checksum string) string {
|
||||
return filepath.Join(s.path, fsutil.GetIntraDir(checksum, blobsDirDepth, blobsDirLength), checksum)
|
||||
}
|
||||
|
||||
func (s *FilesystemStore) Write(ctx context.Context, checksum string, data []byte) error {
|
||||
if s.path == "" {
|
||||
return fmt.Errorf("no path set")
|
||||
}
|
||||
|
||||
fn := s.checksumToPath(checksum)
|
||||
|
||||
// create the directory if it doesn't exist
|
||||
if err := s.fs.MkdirAll(filepath.Dir(fn), 0755); err != nil {
|
||||
return fmt.Errorf("creating directory %q: %w", filepath.Dir(fn), err)
|
||||
}
|
||||
|
||||
logger.Debugf("Writing blob file %s", fn)
|
||||
out, err := s.fs.Create(fn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating file %q: %w", fn, err)
|
||||
}
|
||||
|
||||
r := bytes.NewReader(data)
|
||||
|
||||
if _, err = io.Copy(out, r); err != nil {
|
||||
return fmt.Errorf("writing file %q: %w", fn, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *FilesystemStore) Read(ctx context.Context, checksum string) ([]byte, error) {
|
||||
func (s *FilesystemReader) Read(ctx context.Context, checksum string) ([]byte, error) {
|
||||
if s.path == "" {
|
||||
return nil, fmt.Errorf("no path set")
|
||||
}
|
||||
@@ -93,6 +62,61 @@ func (s *FilesystemStore) Read(ctx context.Context, checksum string) ([]byte, er
|
||||
return io.ReadAll(f)
|
||||
}
|
||||
|
||||
type FilesystemStore struct {
|
||||
FilesystemReader
|
||||
deleter *file.Deleter
|
||||
}
|
||||
|
||||
func NewFilesystemStore(path string, fs FS) *FilesystemStore {
|
||||
deleter := &file.Deleter{
|
||||
RenamerRemover: fs,
|
||||
}
|
||||
|
||||
return &FilesystemStore{
|
||||
FilesystemReader: *NewReadonlyFilesystemStore(path, fs),
|
||||
deleter: deleter,
|
||||
}
|
||||
}
|
||||
|
||||
func NewReadonlyFilesystemStore(path string, fs FSReader) *FilesystemReader {
|
||||
return &FilesystemReader{
|
||||
path: path,
|
||||
fs: fs,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *FilesystemStore) Write(ctx context.Context, checksum string, data []byte) error {
|
||||
fs, ok := s.fs.(FS)
|
||||
if !ok {
|
||||
return fmt.Errorf("internal error: fs is not an FS")
|
||||
}
|
||||
|
||||
if s.path == "" {
|
||||
return fmt.Errorf("no path set")
|
||||
}
|
||||
|
||||
fn := s.checksumToPath(checksum)
|
||||
|
||||
// create the directory if it doesn't exist
|
||||
if err := fs.MkdirAll(filepath.Dir(fn), 0755); err != nil {
|
||||
return fmt.Errorf("creating directory %q: %w", filepath.Dir(fn), err)
|
||||
}
|
||||
|
||||
logger.Debugf("Writing blob file %s", fn)
|
||||
out, err := fs.Create(fn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating file %q: %w", fn, err)
|
||||
}
|
||||
|
||||
r := bytes.NewReader(data)
|
||||
|
||||
if _, err = io.Copy(out, r); err != nil {
|
||||
return fmt.Errorf("writing file %q: %w", fn, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *FilesystemStore) Delete(ctx context.Context, checksum string) error {
|
||||
if s.path == "" {
|
||||
return fmt.Errorf("no path set")
|
||||
|
||||
Reference in New Issue
Block a user