forked from mirror/pkger
almost blue
This commit is contained in:
parent
ba21368aeb
commit
8f38beeddf
|
@ -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
|
||||
}
|
|
@ -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())
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
package pkger
|
126
index.go
126
index.go
|
@ -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
|
||||
}
|
117
index_test.go
117
index_test.go
|
@ -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())
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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")
|
40
parse.go
40
parse.go
|
@ -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
|
||||
}
|
|
@ -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
61
path.go
|
@ -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
|
||||
}
|
||||
|
|
25
path_test.go
25
path_test.go
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
15
pkger.go
15
pkger.go
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue