almost blue

This commit is contained in:
Mark Bates 2019-08-09 15:43:58 -04:00
parent ba21368aeb
commit 8f38beeddf
14 changed files with 253 additions and 319 deletions

36
create.go Normal file
View File

@ -0,0 +1,36 @@
package pkger
import (
"path/filepath"
"time"
)
func Create(name string) (*File, error) {
pt, err := Parse(name)
if err != nil {
return nil, err
}
her, err := Info(pt.Pkg)
if err != nil {
return nil, err
}
f := &File{
path: pt,
her: her,
info: &FileInfo{
name: pt.Name,
mode: 0666,
modTime: time.Now(),
virtual: true,
},
}
filesCache.Store(pt, f)
dir := filepath.Dir(pt.Name)
if err := MkdirAll(dir, 0644); err != nil {
return nil, err
}
return f, nil
}

55
create_test.go Normal file
View File

@ -0,0 +1,55 @@
package pkger
import (
"io"
"os"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func Testg_Create(t *testing.T) {
r := require.New(t)
f, err := 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())
her := f.her
r.NotZero(her)
r.Equal("github.com/markbates/pkger", her.ImportPath)
}
func Testg_Create_Write(t *testing.T) {
r := require.New(t)
f, err := 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())
}

View File

@ -1 +0,0 @@
package pkger

126
index.go
View File

@ -1,126 +0,0 @@
package pkger
import (
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"time"
"github.com/markbates/pkger/here"
"github.com/markbates/pkger/internal/debug"
)
var filesCache = &filesMap{}
var infosCache = &infosMap{}
var pathsCache = &pathsMap{}
var curOnce = &sync.Once{}
var currentInfo here.Info
func dubeg(key, format string, args ...interface{}) {
s := fmt.Sprintf(format, args...)
debug.Debug("[%s|%s] %s", key, s)
}
func Parse(p string) (Path, error) {
dubeg("Parse", p)
pt, ok := pathsCache.Load(p)
if ok {
return pt, nil
}
if len(p) == 0 {
return build(p, "", "")
}
res := pathrx.FindAllStringSubmatch(p, -1)
if len(res) == 0 {
return pt, fmt.Errorf("could not parse %q", p)
}
matches := res[0]
if len(matches) != 4 {
return pt, fmt.Errorf("could not parse %q", p)
}
return build(p, matches[1], matches[3])
}
func Info(p string) (here.Info, error) {
info, ok := infosCache.Load(p)
if ok {
return info, nil
}
info, err := here.Package(p)
if err != nil {
return info, err
}
infosCache.Store(p, info)
return info, nil
}
func Stat() (here.Info, error) {
var err error
curOnce.Do(func() {
if currentInfo.IsZero() {
currentInfo, err = here.Current()
}
})
return currentInfo, err
}
func Create(name string) (*File, error) {
pt, err := Parse(name)
if err != nil {
return nil, err
}
her, err := Info(pt.Pkg)
if err != nil {
return nil, err
}
f := &File{
path: pt,
her: her,
info: &FileInfo{
name: pt.Name,
mode: 0666,
modTime: time.Now(),
virtual: true,
},
}
filesCache.Store(pt, f)
dir := filepath.Dir(pt.Name)
if err := MkdirAll(dir, 0644); err != nil {
return nil, err
}
return f, nil
}
func openDisk(pt Path) (*File, error) {
dubeg("openDisk", pt.String())
info, err := Info(pt.Pkg)
if err != nil {
return nil, err
}
fp := info.Dir
if len(pt.Name) > 0 {
fp = filepath.Join(fp, pt.Name)
}
fi, err := os.Stat(fp)
if err != nil {
return nil, err
}
f := &File{
info: WithName(strings.TrimPrefix(pt.Name, "/"), NewFileInfo(fi)),
her: info,
path: pt,
}
return f, nil
}

View File

@ -1,117 +0,0 @@
package pkger
import (
"io"
"os"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func Test_index_Create(t *testing.T) {
r := require.New(t)
f, err := 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())
her := f.her
r.NotZero(her)
r.Equal("github.com/markbates/pkger", her.ImportPath)
}
func Test_index_Create_Write(t *testing.T) {
r := require.New(t)
f, err := 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())
}
// TODO
// func Test_index_JSON(t *testing.T) {
// r := require.New(t)
//
// f, err := Create("/radio.radio")
// r.NoError(err)
// r.NotNil(f)
// fmt.Fprint(f, radio)
// r.NoError(f.Close())
//
// c, err := Stat()
// r.NoError(err)
// r.Equal(curPkg, c.ImportPath)
//
// _, err = Info("github.com/markbates/hepa")
// r.NoError(err)
//
// r.Equal(1, len(filesCache.Keys()))
// r.Equal(1, len(infosCache.Keys()))
// r.NotZero(cur)
//
// jason, err := json.Marshal(i)
// r.NoError(err)
// r.NotZero(jason)
//
// i2 := &index{}
//
// r.NoError(json.Unmarshal(jason, i2))
//
// r.NotNil(i2.infosCache)
// r.NotNil(i2.filesCache)
// r.NotZero(i2.cur)
// r.Equal(1, len(i2.filesCache.Keys()))
// r.Equal(1, len(i2.infosCache.Keys()))
//
// f2, err := i2.Open(Path{Name: "/radio.radio"})
// r.NoError(err)
// r.Equal(f.data, f2.data)
// }
func Test_index_Parse(t *testing.T) {
table := []struct {
in string
out string
}{
{in: "", out: curPkg + ":/"},
{in: curPkg, out: curPkg + ":/"},
// {in: curPkg + "/foo.go", out: curPkg + ":/foo.go"},
// {in: "/foo.go", out: curPkg + ":/foo.go"},
{in: "github.com/markbates/pkger/internal/examples/app", out: "github.com/markbates/pkger/internal/examples/app:/"},
}
for _, tt := range table {
t.Run(tt.in, func(st *testing.T) {
r := require.New(st)
pt, err := Parse(tt.in)
r.NoError(err)
r.Equal(tt.out, pt.String())
})
}
}

17
info.go Normal file
View File

@ -0,0 +1,17 @@
package pkger
import "github.com/markbates/pkger/here"
func Info(p string) (here.Info, error) {
info, ok := infosCache.Load(p)
if ok {
return info, nil
}
info, err := here.Package(p)
if err != nil {
return info, err
}
infosCache.Store(p, info)
return info, nil
}

View File

@ -2,7 +2,10 @@ package pkger
import (
"net/http"
"os"
"path"
"path/filepath"
"strings"
)
func (f *File) Open(name string) (http.File, error) {
@ -52,3 +55,26 @@ func Open(name string) (*File, error) {
return nf, nil
}
func openDisk(pt Path) (*File, error) {
dubeg("openDisk", pt.String())
info, err := Info(pt.Pkg)
if err != nil {
return nil, err
}
fp := info.Dir
if len(pt.Name) > 0 {
fp = filepath.Join(fp, pt.Name)
}
fi, err := os.Stat(fp)
if err != nil {
return nil, err
}
f := &File{
info: WithName(strings.TrimPrefix(pt.Name, "/"), NewFileInfo(fi)),
her: info,
path: pt,
}
return f, nil
}

View File

@ -9,7 +9,7 @@ import (
"github.com/stretchr/testify/require"
)
func Test_HTTP_File(t *testing.T) {
func Test_Open_File(t *testing.T) {
r := require.New(t)
f, err := Open(".")
@ -29,7 +29,7 @@ func Test_HTTP_File(t *testing.T) {
r.NoError(f.Close())
}
func Test_HTTP_Dir(t *testing.T) {
func Test_Open_Dir(t *testing.T) {
r := require.New(t)
f, err := Open("/")
@ -49,7 +49,7 @@ func Test_HTTP_Dir(t *testing.T) {
r.NoError(f.Close())
}
func Test_HTTP_File_Memory(t *testing.T) {
func Test_Open_File_Memory(t *testing.T) {
r := require.New(t)
f, err := Create("/suit/case.txt")
@ -77,7 +77,7 @@ func Test_HTTP_File_Memory(t *testing.T) {
}
func Test_HTTP_Dir_Memory(t *testing.T) {
func Test_Open_Dir_Memory(t *testing.T) {
r := require.New(t)
f, err := Create("/public/radio.radio")

View File

@ -1,40 +0,0 @@
package pkger
import (
"regexp"
"strings"
)
var pathrx = regexp.MustCompile("([^:]+)(:(/.+))?")
func build(p, pkg, name string) (Path, error) {
pt := Path{
Pkg: pkg,
Name: name,
}
current, err := Stat()
if err != nil {
return pt, err
}
if strings.HasPrefix(pt.Pkg, "/") || len(pt.Pkg) == 0 {
pt.Name = pt.Pkg
pt.Pkg = current.ImportPath
}
if len(pt.Name) == 0 {
pt.Name = "/"
}
if pt.Pkg == pt.Name {
pt.Pkg = current.ImportPath
pt.Name = "/"
}
if !strings.HasPrefix(pt.Name, "/") {
pt.Name = "/" + pt.Name
}
pathsCache.Store(p, pt)
return pt, nil
}

View File

@ -1,31 +0,0 @@
package pkger
import (
"testing"
"github.com/stretchr/testify/require"
)
func Test_Parse_Happy(t *testing.T) {
table := []struct {
in string
out Path
}{
{in: curPkg, out: Path{Pkg: curPkg, Name: "/"}},
{in: curPkg + ":/foo.go", out: Path{Pkg: curPkg, Name: "/foo.go"}},
{in: "/paths/parse_test.go", out: Path{Pkg: curPkg, Name: "/paths/parse_test.go"}},
{in: "", out: Path{Pkg: curPkg, Name: "/"}},
}
for _, tt := range table {
t.Run(tt.in, func(st *testing.T) {
r := require.New(st)
pt, err := Parse(tt.in)
r.NoError(err)
r.Equal(tt.out.Pkg, pt.Pkg)
r.Equal(tt.out.Name, pt.Name)
})
}
}

61
path.go
View File

@ -4,6 +4,8 @@ import (
"encoding/json"
"fmt"
"os"
"regexp"
"strings"
)
type Path struct {
@ -11,6 +13,31 @@ type Path struct {
Name string `json:"name"`
}
func Parse(p string) (Path, error) {
dubeg("Parse", p)
p = strings.Replace(p, "\\", "/", -1)
pt, ok := pathsCache.Load(p)
if ok {
return pt, nil
}
if len(p) == 0 {
return build(p, "", "")
}
res := pathrx.FindAllStringSubmatch(p, -1)
if len(res) == 0 {
return pt, fmt.Errorf("could not parse %q", p)
}
matches := res[0]
if len(matches) != 4 {
return pt, fmt.Errorf("could not parse %q", p)
}
return build(p, matches[1], matches[3])
}
func (p Path) String() string {
if p.Name == "" {
p.Name = "/"
@ -37,3 +64,37 @@ func (p Path) Format(st fmt.State, verb rune) {
fmt.Fprint(st, p.String())
}
}
var pathrx = regexp.MustCompile("([^:]+)(:(/.+))?")
func build(p, pkg, name string) (Path, error) {
pt := Path{
Pkg: pkg,
Name: name,
}
current, err := Stat()
if err != nil {
return pt, err
}
if strings.HasPrefix(pt.Pkg, "/") || len(pt.Pkg) == 0 {
pt.Name = pt.Pkg
pt.Pkg = current.ImportPath
}
if len(pt.Name) == 0 {
pt.Name = "/"
}
if pt.Pkg == pt.Name {
pt.Pkg = current.ImportPath
pt.Name = "/"
}
if !strings.HasPrefix(pt.Name, "/") {
pt.Name = "/" + pt.Name
}
pathsCache.Store(p, pt)
return pt, nil
}

View File

@ -25,3 +25,28 @@ func Test_Path_String(t *testing.T) {
})
}
}
func Test_Parse(t *testing.T) {
table := []struct {
in string
out Path
}{
{in: curPkg, out: Path{Pkg: curPkg, Name: "/"}},
{in: curPkg + ":/foo.go", out: Path{Pkg: curPkg, Name: "/foo.go"}},
{in: "/paths/parse_test.go", out: Path{Pkg: curPkg, Name: "/paths/parse_test.go"}},
{in: `\windows\path.go`, out: Path{Pkg: curPkg, Name: "/windows/path.go"}},
{in: "", out: Path{Pkg: curPkg, Name: "/"}},
{in: "github.com/markbates/pkger/internal/examples/app", out: Path{Pkg: "github.com/markbates/pkger/internal/examples/app", Name: "/"}},
}
for _, tt := range table {
t.Run(tt.in, func(st *testing.T) {
r := require.New(st)
pt, err := Parse(tt.in)
r.NoError(err)
r.Equal(tt.out.Pkg, pt.Pkg)
r.Equal(tt.out.Name, pt.Name)
})
}
}

View File

@ -8,8 +8,23 @@ import (
"fmt"
"io"
"log"
"sync"
"github.com/markbates/pkger/here"
"github.com/markbates/pkger/internal/debug"
)
var filesCache = &filesMap{}
var infosCache = &infosMap{}
var pathsCache = &pathsMap{}
var curOnce = &sync.Once{}
var currentInfo here.Info
func dubeg(key, format string, args ...interface{}) {
s := fmt.Sprintf(format, args...)
debug.Debug("[%s|%s] %s", key, s)
}
func Unpack(ind string) error {
b, err := hex.DecodeString(ind)
if err != nil {

14
stat.go Normal file
View File

@ -0,0 +1,14 @@
package pkger
import "github.com/markbates/pkger/here"
func Stat() (here.Info, error) {
var err error
curOnce.Do(func() {
if currentInfo.IsZero() {
currentInfo, err = here.Current()
}
})
return currentInfo, err
}