This commit is contained in:
Mark Bates 2019-09-03 15:18:31 -04:00
parent c129ccbfe0
commit d453473dc0
20 changed files with 291 additions and 678 deletions

View File

@ -1,42 +0,0 @@
package mem
import (
"path/filepath"
"time"
"github.com/markbates/pkger/pkging"
)
// no such file or directory
func (fx *Pkger) Create(name string) (pkging.File, error) {
pt, err := fx.Parse(name)
if err != nil {
return nil, err
}
her, err := fx.Info(pt.Pkg)
if err != nil {
return nil, err
}
if _, err := fx.Stat(filepath.Dir(pt.Name)); err != nil {
return nil, err
}
f := &File{
path: pt,
her: her,
info: &pkging.FileInfo{
Details: pkging.Details{
Name: pt.Name,
Mode: 0644,
ModTime: pkging.ModTime(time.Now()),
},
},
pkging: fx,
}
fx.files.Store(pt, f)
return f, nil
}

View File

@ -1,80 +0,0 @@
package mem
// func Test_Create(t *testing.T) {
// r := require.New(t)
//
// fs, err := New(here.Info{})
// f, err := fs.Create("/hello.txt")
// r.NoError(err)
// r.NotNil(f)
//
// fi, err := f.Stat()
// r.NoError(err)
//
// r.Equal("/hello.txt", fi.Name())
// r.Equal(os.FileMode(0666), fi.Mode())
// r.NotZero(fi.ModTime())
// }
//
// func Test_Create_Write(t *testing.T) {
// r := require.New(t)
//
// fs, err := New(here.Info{})
// f, err := fs.Create("/hello.txt")
// r.NoError(err)
// r.NotNil(f)
//
// fi, err := f.Stat()
// r.NoError(err)
// r.Zero(fi.Size())
//
// r.Equal("/hello.txt", fi.Name())
//
// mt := fi.ModTime()
// r.NotZero(mt)
//
// sz, err := io.Copy(f, strings.NewReader(radio))
// r.NoError(err)
// r.Equal(int64(1381), sz)
//
// r.NoError(f.Close())
// r.Equal(int64(1381), fi.Size())
// r.NotZero(fi.ModTime())
// r.NotEqual(mt, fi.ModTime())
// }
//
// const radio = `I was tuning in the shine on the late night dial
// Doing anything my radio advised
// With every one of those late night stations
// Playing songs bringing tears to my eyes
// I was seriously thinking about hiding the receiver
// When the switch broke 'cause it's old
// They're saying things that I can hardly believe
// They really think we're getting out of control
// Radio is a sound salvation
// Radio is cleaning up the nation
// They say you better listen to the voice of reason
// But they don't give you any choice 'cause they think that it's treason
// So you had better do as you are told
// You better listen to the radio
// I wanna bite the hand that feeds me
// I wanna bite that hand so badly
// I want to make them wish they'd never seen me
// Some of my friends sit around every evening
// And they worry about the times ahead
// But everybody else is overwhelmed by indifference
// And the promise of an early bed
// You either shut up or get cut up; they don't wanna hear about it
// It's only inches on the reel-to-reel
// And the radio is in the hands of such a lot of fools
// Tryin' to anesthetize the way that you feel
// Radio is a sound salvation
// Radio is cleaning up the nation
// They say you better listen to the voice of reason
// But they don't give you any choice 'cause they think that it's treason
// So you had better do as you are told
// You better listen to the radio
// Wonderful radio
// Marvelous radio
// Wonderful radio
// Radio, radio`

View File

@ -152,6 +152,10 @@ func (f *File) Readdir(count int) ([]os.FileInfo, error) {
}
info = pkging.WithName(strings.TrimPrefix(info.Name(), f.parent.Name), info)
if minf, ok := info.(*pkging.FileInfo); ok {
minf.Details.Name = strings.TrimPrefix(info.Name(), "/")
info = minf
}
infos = append(infos, info)
if info.IsDir() && path != root {
return filepath.SkipDir
@ -205,3 +209,61 @@ func (f *File) Open(name string) (http.File, error) {
}
return di, nil
}
func (f File) MarshalJSON() ([]byte, error) {
m := map[string]interface{}{
"info": f.info,
"her": f.her,
"path": f.path,
"data": f.data,
"parent": f.parent,
}
return json.Marshal(m)
}
func (f *File) UnmarshalJSON(b []byte) error {
m := map[string]json.RawMessage{}
if err := json.Unmarshal(b, &m); err != nil {
return err
}
info, ok := m["info"]
if !ok {
return fmt.Errorf("missing info")
}
f.info = &pkging.FileInfo{}
if err := json.Unmarshal(info, f.info); err != nil {
return err
}
her, ok := m["her"]
if !ok {
return fmt.Errorf("missing her")
}
if err := json.Unmarshal(her, &f.her); err != nil {
return err
}
path, ok := m["path"]
if !ok {
return fmt.Errorf("missing path")
}
if err := json.Unmarshal(path, &f.path); err != nil {
return err
}
parent, ok := m["parent"]
if !ok {
return fmt.Errorf("missing parent")
}
if err := json.Unmarshal(parent, &f.parent); err != nil {
return err
}
if err := json.Unmarshal(m["data"], &f.data); err != nil {
return err
}
return nil
}

View File

@ -1,58 +0,0 @@
package mem
// func Test_File_Read_Memory(t *testing.T) {
// r := require.New(t)
//
// fs, err := New(here.Info{})
// r.NoError(err)
//
// f, err := fs.Create("/file_test.go")
// r.NoError(err)
// _, err = io.Copy(f, bytes.NewReader([]byte("hi!")))
// r.NoError(err)
// r.NoError(f.Close())
//
// f, err = fs.Open("/file_test.go")
// r.NoError(err)
// fi, err := f.Stat()
// r.NoError(err)
// r.Equal("/file_test.go", fi.Name())
//
// b, err := ioutil.ReadAll(f)
// r.NoError(err)
// r.Equal(string(b), "hi!")
// }
//
// func Test_File_Write(t *testing.T) {
// r := require.New(t)
//
// fs, err := New(here.Info{})
// r.NoError(err)
//
// f, err := fs.Create("/hello.txt")
// r.NoError(err)
// r.NotNil(f)
//
// fi, err := f.Stat()
// r.NoError(err)
// r.Zero(fi.Size())
//
// r.Equal("/hello.txt", fi.Name())
//
// mt := fi.ModTime()
// r.NotZero(mt)
//
// sz, err := io.Copy(f, strings.NewReader(radio))
// r.NoError(err)
// r.Equal(int64(1381), sz)
//
// // because windows can't handle the time precisely
// // enough, we have to *force* just a smidge of time
// // to ensure the two ModTime's are different.
// // i know, i hate it too.
// time.Sleep(time.Millisecond)
// r.NoError(f.Close())
// r.Equal(int64(1381), fi.Size())
// r.NotZero(fi.ModTime())
// r.NotEqual(mt, fi.ModTime())
// }

View File

@ -1 +0,0 @@
package mem

View File

@ -1,75 +0,0 @@
package mem
// func Test_HTTP_Dir(t *testing.T) {
// r := require.New(t)
//
// fs := NewPkger()
//
// r.NoError(Folder.Create(fs))
//
// dir, err := fs.Open("/")
// r.NoError(err)
// ts := httptest.NewServer(http.FileServer(dir))
// defer ts.Close()
//
// res, err := http.Get(ts.URL + "/")
// r.NoError(err)
// r.Equal(200, res.StatusCode)
//
// b, err := ioutil.ReadAll(res.Body)
// r.NoError(err)
// r.Contains(string(b), `<a href="/public/images/mark.png">/public/images/mark.png</a>`)
// }
//
// func Test_HTTP_File_Memory(t *testing.T) {
// r := require.New(t)
//
// fs := NewPkger()
// r.NoError(Folder.Create(fs))
//
// dir, err := fs.Open("/")
// r.NoError(err)
// ts := httptest.NewServer(http.FileServer(dir))
// defer ts.Close()
//
// res, err := http.Get(ts.URL + "/public/images/mark.png")
// r.NoError(err)
// r.Equal(200, res.StatusCode)
//
// b, err := ioutil.ReadAll(res.Body)
// r.NoError(err)
// r.Contains(string(b), `!/public/images/mark.png`)
// }
//
// func Test_HTTP_Dir_Memory_StripPrefix(t *testing.T) {
// r := require.New(t)
//
// fs := NewPkger()
// r.NoError(Folder.Create(fs))
//
// dir, err := fs.Open("/public")
// r.NoError(err)
// defer dir.Close()
//
// ts := httptest.NewServer(http.StripPrefix("/assets/", http.FileServer(dir)))
// defer ts.Close()
//
// res, err := http.Get(ts.URL + "/assets/images/mark.png")
// r.NoError(err)
// r.Equal(200, res.StatusCode)
//
// b, _ := ioutil.ReadAll(res.Body)
// // r.NoError(err)
// r.Contains(string(b), "!/public/images/mark.png")
//
// res, err = http.Get(ts.URL + "/assets/images/")
// r.NoError(err)
// r.Equal(200, res.StatusCode)
//
// b, _ = ioutil.ReadAll(res.Body)
// // r.NoError(err)
// r.Contains(string(b), `<a href="/mark.png">/mark.png</a>`)
// r.NotContains(string(b), `/public`)
// r.NotContains(string(b), `/images`)
// r.NotContains(string(b), `/go.mod`)
// }

View File

@ -1,66 +0,0 @@
package mem
import (
"encoding/json"
"fmt"
"github.com/markbates/pkger/pkging"
)
func (f File) MarshalJSON() ([]byte, error) {
m := map[string]interface{}{
"info": f.info,
"her": f.her,
"path": f.path,
"data": f.data,
"parent": f.parent,
}
return json.Marshal(m)
}
func (f *File) UnmarshalJSON(b []byte) error {
m := map[string]json.RawMessage{}
if err := json.Unmarshal(b, &m); err != nil {
return err
}
info, ok := m["info"]
if !ok {
return fmt.Errorf("missing info")
}
f.info = &pkging.FileInfo{}
if err := json.Unmarshal(info, f.info); err != nil {
return err
}
her, ok := m["her"]
if !ok {
return fmt.Errorf("missing her")
}
if err := json.Unmarshal(her, &f.her); err != nil {
return err
}
path, ok := m["path"]
if !ok {
return fmt.Errorf("missing path")
}
if err := json.Unmarshal(path, &f.path); err != nil {
return err
}
parent, ok := m["parent"]
if !ok {
return fmt.Errorf("missing parent")
}
if err := json.Unmarshal(parent, &f.parent); err != nil {
return err
}
if err := json.Unmarshal(m["data"], &f.data); err != nil {
return err
}
return nil
}

View File

@ -1,33 +0,0 @@
package mem
// func Test_File_JSON(t *testing.T) {
// r := require.New(t)
//
// fs, err := New(here.Info{})
// r.NoError(err)
//
// f, err := fs.Create("/radio.radio")
// r.NoError(err)
// _, err = io.Copy(f, strings.NewReader(radio))
// r.NoError(err)
// r.NoError(f.Close())
//
// f, err = fs.Open("/radio.radio")
// r.NoError(err)
// bi, err := f.Stat()
// r.NoError(err)
//
// mj, err := json.Marshal(f)
// r.NoError(err)
//
// f2 := &File{}
//
// r.NoError(json.Unmarshal(mj, f2))
//
// ai, err := f2.Stat()
// r.NoError(err)
//
// r.Equal(bi.Size(), ai.Size())
//
// r.Equal(radio, string(f2.data))
// }

View File

@ -3,7 +3,9 @@ package mem
import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/markbates/pkger/here"
"github.com/markbates/pkger/internal/maps"
@ -95,3 +97,166 @@ func (fx *Pkger) RemoveAll(name string) error {
return nil
}
func (fx *Pkger) Create(name string) (pkging.File, error) {
pt, err := fx.Parse(name)
if err != nil {
return nil, err
}
her, err := fx.Info(pt.Pkg)
if err != nil {
return nil, err
}
if _, err := fx.Stat(filepath.Dir(pt.Name)); err != nil {
return nil, err
}
f := &File{
path: pt,
her: her,
info: &pkging.FileInfo{
Details: pkging.Details{
Name: pt.Name,
Mode: 0644,
ModTime: pkging.ModTime(time.Now()),
},
},
pkging: fx,
}
fx.files.Store(pt, f)
return f, nil
}
func (fx *Pkger) MkdirAll(p string, perm os.FileMode) error {
path, err := fx.Parse(p)
if err != nil {
return err
}
root := path.Name
cur, err := fx.Current()
if err != nil {
return err
}
for root != "" {
pt := pkging.Path{
Pkg: path.Pkg,
Name: root,
}
if _, ok := fx.files.Load(pt); ok {
root = filepath.Dir(root)
if root == "/" || root == "\\" {
break
}
continue
}
f := &File{
pkging: fx,
path: pt,
her: cur,
info: &pkging.FileInfo{
Details: pkging.Details{
Name: pt.Name,
Mode: perm,
ModTime: pkging.ModTime(time.Now()),
},
},
}
if err != nil {
return err
}
f.info.Details.IsDir = true
f.info.Details.Mode = perm
if err := f.Close(); err != nil {
return err
}
fx.files.Store(pt, f)
root = filepath.Dir(root)
}
return nil
}
func (fx *Pkger) Open(name string) (pkging.File, error) {
pt, err := fx.Parse(name)
if err != nil {
return nil, err
}
fl, ok := fx.files.Load(pt)
if !ok {
return nil, fmt.Errorf("could not open %s", name)
}
f, ok := fl.(*File)
if !ok {
return nil, fmt.Errorf("could not open %s", name)
}
nf := &File{
pkging: fx,
info: pkging.WithName(f.info.Name(), f.info),
path: f.path,
data: f.data,
her: f.her,
}
return nf, nil
}
func (fx *Pkger) Stat(name string) (os.FileInfo, error) {
pt, err := fx.Parse(name)
if err != nil {
return nil, err
}
f, ok := fx.files.Load(pt)
if ok {
return f.Stat()
}
return nil, fmt.Errorf("could not stat %s", pt)
}
func (f *Pkger) Walk(p string, wf filepath.WalkFunc) error {
keys := f.files.Keys()
pt, err := f.Parse(p)
if err != nil {
return err
}
skip := "!"
for _, k := range keys {
if !strings.HasPrefix(k.Name, pt.Name) {
continue
}
if strings.HasPrefix(k.Name, skip) {
continue
}
fl, ok := f.files.Load(k)
if !ok {
return fmt.Errorf("could not find %s", k)
}
fi, err := fl.Stat()
if err != nil {
return err
}
fi = pkging.WithName(strings.TrimPrefix(k.Name, pt.Name), fi)
err = wf(k.String(), fi, nil)
if err == filepath.SkipDir {
skip = k.Name
continue
}
if err != nil {
return err
}
}
return nil
}

View File

@ -1,61 +0,0 @@
package mem
import (
"os"
"path/filepath"
"time"
"github.com/markbates/pkger/pkging"
)
func (fx *Pkger) MkdirAll(p string, perm os.FileMode) error {
path, err := fx.Parse(p)
if err != nil {
return err
}
root := path.Name
cur, err := fx.Current()
if err != nil {
return err
}
for root != "" {
pt := pkging.Path{
Pkg: path.Pkg,
Name: root,
}
if _, ok := fx.files.Load(pt); ok {
root = filepath.Dir(root)
if root == "/" || root == "\\" {
break
}
continue
}
f := &File{
pkging: fx,
path: pt,
her: cur,
info: &pkging.FileInfo{
Details: pkging.Details{
Name: pt.Name,
Mode: perm,
ModTime: pkging.ModTime(time.Now()),
},
},
}
if err != nil {
return err
}
f.info.Details.IsDir = true
f.info.Details.Mode = perm
if err := f.Close(); err != nil {
return err
}
fx.files.Store(pt, f)
root = filepath.Dir(root)
}
return nil
}

View File

@ -1,25 +0,0 @@
package mem
import (
"os"
"testing"
"github.com/markbates/pkger/here"
"github.com/stretchr/testify/require"
)
func Test_MkdirAll(t *testing.T) {
r := require.New(t)
fs, _ := New(here.Info{})
err := fs.MkdirAll("/foo/bar/baz", 0755)
r.NoError(err)
fi, err := fs.Stat("/foo/bar/baz")
r.NoError(err)
r.Equal("/foo/bar/baz", fi.Name())
r.Equal(os.FileMode(0755), fi.Mode())
r.True(fi.IsDir())
}

View File

@ -1,32 +0,0 @@
package mem
import (
"fmt"
"github.com/markbates/pkger/pkging"
)
func (fx *Pkger) Open(name string) (pkging.File, error) {
pt, err := fx.Parse(name)
if err != nil {
return nil, err
}
fl, ok := fx.files.Load(pt)
if !ok {
return nil, fmt.Errorf("could not open %s", name)
}
f, ok := fl.(*File)
if !ok {
return nil, fmt.Errorf("could not open %s", name)
}
nf := &File{
pkging: fx,
info: pkging.WithName(f.info.Name(), f.info),
path: f.path,
data: f.data,
her: f.her,
}
return nf, nil
}

View File

@ -1,24 +0,0 @@
package mem
// func Test_Open(t *testing.T) {
// r := require.New(t)
//
// fs, err := New(here.Info{})
// r.NoError(err)
//
// _, err = fs.Open("/i.dont.exist")
// r.Error(err)
//
// f, err := fs.Create("/i.exist")
// r.NoError(err)
// _, err = io.Copy(f, strings.NewReader(radio))
// r.NoError(err)
// r.NoError(f.Close())
//
// f, err = fs.Open("/i.exist")
// r.NoError(err)
// b, err := ioutil.ReadAll(f)
// r.NoError(err)
// r.NoError(f.Close())
// r.Equal([]byte(radio), b)
// }

View File

@ -1,18 +0,0 @@
package mem
import (
"fmt"
"os"
)
func (fx *Pkger) Stat(name string) (os.FileInfo, error) {
pt, err := fx.Parse(name)
if err != nil {
return nil, err
}
f, ok := fx.files.Load(pt)
if ok {
return f.Stat()
}
return nil, fmt.Errorf("could not stat %s", pt)
}

View File

@ -1,18 +0,0 @@
package mem
// func Test_Stat(t *testing.T) {
// r := require.New(t)
//
// fs, err := New(here.Info{})
// r.NoError(err)
// _, err = fs.Stat("/i.dont.exist")
// r.Error(err)
//
// f, err := fs.Create("/i.exist")
// r.NoError(err)
// r.NoError(f.Close())
//
// fi, err := fs.Stat("/i.exist")
// r.NoError(err)
// r.Equal("/i.exist", fi.Name())
// }

View File

@ -1,50 +0,0 @@
package mem
import (
"fmt"
"path/filepath"
"strings"
"github.com/markbates/pkger/pkging"
)
func (f *Pkger) Walk(p string, wf filepath.WalkFunc) error {
keys := f.files.Keys()
pt, err := f.Parse(p)
if err != nil {
return err
}
skip := "!"
for _, k := range keys {
if !strings.HasPrefix(k.Name, pt.Name) {
continue
}
if strings.HasPrefix(k.Name, skip) {
continue
}
fl, ok := f.files.Load(k)
if !ok {
return fmt.Errorf("could not find %s", k)
}
fi, err := fl.Stat()
if err != nil {
return err
}
fi = pkging.WithName(strings.TrimPrefix(k.Name, pt.Name), fi)
err = wf(k.String(), fi, nil)
if err == filepath.SkipDir {
skip = k.Name
continue
}
if err != nil {
return err
}
}
return nil
}

View File

@ -1,58 +0,0 @@
package mem
// func Test_Walk(t *testing.T) {
// r := require.New(t)
//
// files := []struct {
// name string
// body string
// }{
// {name: "/a/a.txt", body: "A"},
// {name: "/a/a.md", body: "Amd"},
// {name: "/b/c/d.txt", body: "B"},
// {name: "/f.txt", body: "F"},
// }
//
// sort.Slice(files, func(a, b int) bool {
// return files[a].name < files[b].name
// })
//
// fs, err := New(here.Info{})
// r.NoError(err)
//
// for _, file := range files {
// f, err := fs.Create(file.name)
// r.NoError(err)
// _, err = io.Copy(f, strings.NewReader(file.body))
// r.NoError(err)
// r.NoError(f.Close())
// }
//
// var found []string
// err = fs.Walk("/", func(path string, info os.FileInfo, err error) error {
// if err != nil {
// return err
// }
//
// found = append(found, path)
// return nil
// })
// r.NoError(err)
//
// expected := []string{":/", ":/a", ":/a/a.md", ":/a/a.txt", ":/b", ":/b/c", ":/b/c/d.txt", ":/f.txt"}
// r.Equal(expected, found)
//
// found = []string{}
// err = fs.Walk("/a/", func(path string, info os.FileInfo, err error) error {
// if err != nil {
// return err
// }
//
// found = append(found, path)
// return nil
// })
// r.NoError(err)
//
// expected = []string{":/a/a.md", ":/a/a.txt"}
// r.Equal(expected, found)
// }

View File

@ -40,22 +40,22 @@ func (s Suite) Test_File_Info(t *testing.T) {
}
}
func (s Suite) Test_File_Read(t *testing.T) {
panic("not implemented")
}
func (s Suite) Test_File_Readdir(t *testing.T) {
panic("not implemented")
}
func (s Suite) Test_File_Seek(t *testing.T) {
panic("not implemented")
}
func (s Suite) Test_File_Stat(t *testing.T) {
panic("not implemented")
}
func (s Suite) Test_File_Write(t *testing.T) {
panic("not implemented")
}
// func (s Suite) Test_File_Read(t *testing.T) {
// panic("not implemented")
// }
//
// func (s Suite) Test_File_Readdir(t *testing.T) {
// panic("not implemented")
// }
//
// func (s Suite) Test_File_Seek(t *testing.T) {
// panic("not implemented")
// }
//
// func (s Suite) Test_File_Stat(t *testing.T) {
// panic("not implemented")
// }
//
// func (s Suite) Test_File_Write(t *testing.T) {
// panic("not implemented")
// }

View File

@ -5,6 +5,7 @@ import (
"net/http"
"net/http/httptest"
"path/filepath"
"strings"
"testing"
"github.com/markbates/pkger/pkging/pkgutil"
@ -86,6 +87,49 @@ func (s Suite) Test_HTTP_Dir(t *testing.T) {
}
}
func (s Suite) Test_HTTP_Dir_IndexHTML(t *testing.T) {
r := require.New(t)
cur, err := s.Current()
r.NoError(err)
ip := cur.ImportPath
r.NoError(s.LoadFolder())
table := []struct {
in string
req string
}{
{in: "/public", req: "/"},
{in: ":" + "/public", req: "/"},
{in: ip + ":" + "/public", req: "/"},
}
exp := "!/public/index.html"
for _, tt := range table {
t.Run(tt.in+exp, func(st *testing.T) {
r := require.New(st)
dir, err := s.Open(tt.in)
r.NoError(err)
ts := httptest.NewServer(http.FileServer(dir))
defer ts.Close()
res, err := http.Get(ts.URL + tt.req)
r.NoError(err)
r.Equal(200, res.StatusCode)
b, err := ioutil.ReadAll(res.Body)
r.NoError(err)
body := strings.TrimSpace(string(b))
r.Equal(exp, body)
r.NotContains(body, "mark.png")
})
}
}
// func (s Suite) Test_HTTP_File_Memory(t *testing.T) {
// r := require.New(t)
//

View File

@ -18,24 +18,7 @@ type File struct {
pkging pkging.Pkger
}
type HTTPFile struct {
http.File
}
func (f *HTTPFile) Readdir(n int) ([]os.FileInfo, error) {
infos, err := f.File.Readdir(n)
if err != nil {
return nil, err
}
for i, info := range infos {
infos[i] = pkging.NewFileInfo(info)
}
return infos, nil
}
func NewFile(fx pkging.Pkger, osf *os.File) (*File, error) {
pt, err := fx.Parse(osf.Name())
if err != nil {
return nil, err
@ -78,7 +61,7 @@ func (f *File) Name() string {
}
func (f *File) Open(name string) (http.File, error) {
return &HTTPFile{f.File}, nil
return f.File, nil
}
func (f *File) Path() pkging.Path {