Skip to content

Commit

Permalink
local
Browse files Browse the repository at this point in the history
  • Loading branch information
vcraescu committed Jul 26, 2020
1 parent 813ab8a commit 22345b0
Show file tree
Hide file tree
Showing 7 changed files with 973 additions and 13 deletions.
10 changes: 0 additions & 10 deletions bucketly.go
Expand Up @@ -34,16 +34,6 @@ type (

CopyFn func(ctx context.Context, from Item, to string) error

Item interface {
fmt.Stringer
os.FileInfo

Bucket() Bucket
Open(context.Context) (io.ReadCloser, error)
ETag() (string, error)
Metadata() (Metadata, error)
}

Walkable interface {
Walk(ctx context.Context, dir string, walkFunc WalkFunc) error
}
Expand Down
15 changes: 15 additions & 0 deletions item.go
Expand Up @@ -2,13 +2,24 @@ package bucketly

import (
"context"
"fmt"
"io"
"os"
"sync"
"time"
)

type (
Item interface {
fmt.Stringer
os.FileInfo

Bucket() Bucket
Open(context.Context) (io.ReadCloser, error)
ETag() (string, error)
Metadata() (Metadata, error)
}

BucketItem struct {
bucket Bucket
name string
Expand Down Expand Up @@ -113,6 +124,10 @@ func (i *BucketItem) Sys() interface{} {
return i.sys
}

func (i *BucketItem) SetSys(sys interface{}) {
i.sys = sys
}

func (i *BucketItem) Open(ctx context.Context) (io.ReadCloser, error) {
return i.bucket.NewReader(ctx, i.name)
}
Expand Down
244 changes: 244 additions & 0 deletions local/bucket.go
@@ -0,0 +1,244 @@
package local

import (
"context"
"github.com/vcraescu/bucketly"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
)

const (
defaultDirMode os.FileMode = 0744
defaultFileMode os.FileMode = 0666
)

type (
Bucket struct {
name string
}

listIterator struct {
name string
bucket *Bucket
queue []os.FileInfo
}
)

func NewBucket(name string) *Bucket {
return &Bucket{name: name}
}

func (b *Bucket) PathSeparator() rune {
return os.PathSeparator
}

func (b *Bucket) Name() string {
return b.name
}

func (b *Bucket) Read(ctx context.Context, name string) ([]byte, error) {
r, err := b.NewReader(ctx, name)
if err != nil {
return nil, err
}
defer r.Close()

return ioutil.ReadAll(r)
}

func (b *Bucket) NewReader(_ context.Context, name string) (io.ReadCloser, error) {
return os.Open(b.realPath(name))
}

func (b *Bucket) Write(ctx context.Context, name string, data []byte, opts ...bucketly.WriteOption) (int, error) {
dir := filepath.Dir(name)
if err := b.MkdirAll(ctx, dir); err != nil {
return 0, err
}

w, err := b.NewWriter(ctx, name, opts...)
if err != nil {
return 0, err
}
defer w.Close()

return w.Write(data)
}

func (b *Bucket) NewWriter(_ context.Context, name string, opts ...bucketly.WriteOption) (io.WriteCloser, error) {
wo := &bucketly.WriteOptions{
Mode: defaultFileMode,
}
for _, opt := range opts {
opt(wo)
}

return os.OpenFile(b.realPath(name), os.O_CREATE|os.O_WRONLY, wo.Mode)
}

func (b *Bucket) Exists(ctx context.Context, name string) (bool, error) {
_, err := b.Stat(ctx, name)
if err != nil {
if os.IsNotExist(err) {
return false, nil
}

return false, err
}

return true, nil
}

func (b *Bucket) Remove(_ context.Context, name string) error {
return os.Remove(b.realPath(name))
}

func (b *Bucket) Stat(_ context.Context, name string) (bucketly.Item, error) {
fi, err := os.Stat(b.realPath(name))
if err != nil {
return nil, err
}

return b.fileInfoToItem(name, fi), nil
}

func (b *Bucket) Mkdir(_ context.Context, name string, opts ...bucketly.WriteOption) error {
wo := &bucketly.WriteOptions{
Mode: defaultDirMode,
}
for _, opt := range opts {
opt(wo)
}

return os.Mkdir(b.realPath(name), wo.Mode)
}

func (b *Bucket) MkdirAll(_ context.Context, name string, opts ...bucketly.WriteOption) error {
wo := &bucketly.WriteOptions{
Mode: defaultDirMode,
}
for _, opt := range opts {
opt(wo)
}

return os.MkdirAll(b.realPath(name), wo.Mode)
}

func (b *Bucket) Chmod(_ context.Context, name string, mode os.FileMode) error {
return os.Chmod(b.realPath(name), mode)
}

func (b *Bucket) RemoveAll(_ context.Context, name string) error {
return os.RemoveAll(b.realPath(name))
}

func (b *Bucket) Rename(_ context.Context, from string, to string, opts ...bucketly.CopyOption) error {
return os.Rename(b.realPath(from), b.realPath(to))
}

func (b *Bucket) Copy(ctx context.Context, from bucketly.Item, to string, opts ...bucketly.CopyOption) error {
panic("implement me")
}

func (b *Bucket) CopyAll(ctx context.Context, from bucketly.Item, to string, opts ...bucketly.CopyOption) error {
panic("implement me")
}

func (b *Bucket) Copy2(ctx context.Context, from string, to string, opts ...bucketly.CopyOption) error {
panic("implement me")
}

func (b *Bucket) CopyAll2(ctx context.Context, from string, to string, opts ...bucketly.CopyOption) error {
panic("implement me")
}

func (b *Bucket) Walk(_ context.Context, dir string, walkFunc bucketly.WalkFunc) error {
dir = bucketly.Clean(b, dir)
return filepath.Walk(b.realPath(dir), func(path string, info os.FileInfo, err error) error {
name, err := filepath.Rel(b.name, path)
if name == dir {
return nil
}

if err != nil {
return err
}

item := b.fileInfoToItem(name, info)

if err := walkFunc(item, err); err != nil {
if err == bucketly.SkipWalkDir {
return filepath.SkipDir
}

return err
}

return nil
})
}

func (b *Bucket) Items(name string) (bucketly.ListIterator, error) {
iter := &listIterator{
name: name,
bucket: b,
}

return iter, nil
}

func (b *Bucket) realPath(name string) string {
return bucketly.Join(b, b.name, name)
}

func (b *Bucket) fileInfoToItem(name string, info os.FileInfo) bucketly.Item {
item := bucketly.NewItem(b, name)
item.SetMode(info.Mode())
item.SetModeTime(info.ModTime())
item.SetDir(info.IsDir())
item.SetSize(info.Size())
item.SetSys(info.Sys())

return item
}

func (i *listIterator) Next(ctx context.Context) (bucketly.Item, error) {
if i.queue == nil {
item, err := i.bucket.Stat(ctx, i.name)
if err != nil {
return nil, err
}

if !item.IsDir() {
i.queue = make([]os.FileInfo, 0)

return item, nil
}

infos, err := ioutil.ReadDir(i.bucket.realPath(item.Name()))
if err != nil {
return nil, err
}

i.queue = infos
}

if len(i.queue) == 0 {
return nil, io.EOF
}

info := i.queue[0]
i.queue = i.queue[1:]
name := strings.TrimLeft(bucketly.Join(i.bucket, i.name, info.Name()), string(i.bucket.PathSeparator()))

return i.bucket.fileInfoToItem(name, info), nil
}

func (i *listIterator) Close() error {
i.queue = nil

return nil
}

0 comments on commit 22345b0

Please sign in to comment.