forked from mirror/pkger
job jargon
This commit is contained in:
parent
68f3a2a457
commit
b42e0b7d71
|
@ -28,3 +28,4 @@ bin/*
|
|||
gin-bin
|
||||
.idea/
|
||||
pkged.go
|
||||
cover.out
|
||||
|
|
6
Makefile
6
Makefile
|
@ -16,6 +16,11 @@ test: tidy
|
|||
$(GO_BIN) test -cover -tags ${TAGS} -timeout 5s ./...
|
||||
make tidy
|
||||
|
||||
cov:
|
||||
$(GO_BIN) test -coverprofile cover.out -tags ${TAGS} ./...
|
||||
go tool cover -html cover.out
|
||||
make tidy
|
||||
|
||||
ci-test:
|
||||
$(GO_BIN) test -tags ${TAGS} -race ./...
|
||||
|
||||
|
@ -43,4 +48,3 @@ release:
|
|||
make tidy
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Testg_Create(t *testing.T) {
|
||||
func Test_Create(t *testing.T) {
|
||||
r := require.New(t)
|
||||
|
||||
f, err := Create("/hello.txt")
|
||||
|
@ -28,7 +28,7 @@ func Testg_Create(t *testing.T) {
|
|||
r.Equal("github.com/markbates/pkger", her.ImportPath)
|
||||
}
|
||||
|
||||
func Testg_Create_Write(t *testing.T) {
|
||||
func Test_Create_Write(t *testing.T) {
|
||||
r := require.New(t)
|
||||
|
||||
f, err := Create("/hello.txt")
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package fs
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/markbates/pkger/here"
|
||||
)
|
||||
|
||||
type File interface {
|
||||
Close() error
|
||||
FilePath() string
|
||||
Info() here.Info
|
||||
Name() string
|
||||
Open(name string) (http.File, error)
|
||||
Path() Path
|
||||
Read(p []byte) (int, error)
|
||||
Readdir(count int) ([]os.FileInfo, error)
|
||||
Seek(offset int64, whence int) (int64, error)
|
||||
Stat() (os.FileInfo, error)
|
||||
Write(b []byte) (int, error)
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package fs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/markbates/pkger/here"
|
||||
)
|
||||
|
||||
type FileSystem interface {
|
||||
Create(name string) (File, error)
|
||||
Current() (here.Info, error)
|
||||
Info(p string) (here.Info, error)
|
||||
MkdirAll(p string, perm os.FileMode) error
|
||||
Open(name string) (File, error)
|
||||
Parse(p string) (Path, error)
|
||||
ReadFile(s string) ([]byte, error)
|
||||
Stat(name string) (os.FileInfo, error)
|
||||
Walk(p string, wf filepath.WalkFunc) error
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package fstest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
"github.com/markbates/pkger/fs"
|
||||
)
|
||||
|
||||
type TestFile struct {
|
||||
Name string
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func (t TestFile) Create(fx fs.FileSystem) error {
|
||||
f, err := fx.Create(t.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(f, bytes.NewReader(t.Data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.Close()
|
||||
}
|
||||
|
||||
type TestFiles map[string]TestFile
|
||||
|
||||
func (t TestFiles) Create(fx fs.FileSystem) error {
|
||||
for k, f := range t {
|
||||
f.Name = k
|
||||
if err := f.Create(fx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package hdfs
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/markbates/pkger/fs"
|
||||
"github.com/markbates/pkger/here"
|
||||
)
|
||||
|
||||
var _ fs.File = &File{}
|
||||
|
||||
type File struct {
|
||||
*os.File
|
||||
filePath string
|
||||
info *fs.FileInfo
|
||||
her here.Info
|
||||
path fs.Path
|
||||
fs fs.FileSystem
|
||||
}
|
||||
|
||||
func NewFile(fx fs.FileSystem, osf *os.File) (*File, error) {
|
||||
info, err := osf.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pt, err := fx.Parse(info.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
f := &File{
|
||||
File: osf,
|
||||
filePath: info.Name(),
|
||||
path: pt,
|
||||
fs: fx,
|
||||
}
|
||||
f.info = fs.WithName(pt.Name, info)
|
||||
|
||||
her, err := here.Package(pt.Pkg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.her = her
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (f *File) Close() error {
|
||||
return f.File.Close()
|
||||
}
|
||||
|
||||
func (f *File) FilePath() string {
|
||||
return f.filePath
|
||||
}
|
||||
|
||||
func (f *File) Info() here.Info {
|
||||
return f.her
|
||||
}
|
||||
|
||||
func (f *File) Name() string {
|
||||
return f.info.Name()
|
||||
}
|
||||
|
||||
func (f *File) Open(name string) (http.File, error) {
|
||||
return f.File, nil
|
||||
}
|
||||
|
||||
func (f *File) Path() fs.Path {
|
||||
return f.path
|
||||
}
|
||||
|
||||
func (f *File) Stat() (os.FileInfo, error) {
|
||||
if f.info == nil {
|
||||
info, err := os.Stat(f.filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.info = fs.NewFileInfo(info)
|
||||
}
|
||||
return f.info, nil
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
package hdfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/markbates/pkger/fs"
|
||||
"github.com/markbates/pkger/here"
|
||||
"github.com/markbates/pkger/internal/maps"
|
||||
)
|
||||
|
||||
var _ fs.FileSystem = &FS{}
|
||||
|
||||
type FS struct {
|
||||
infos *maps.Infos
|
||||
paths *maps.Paths
|
||||
current here.Info
|
||||
}
|
||||
|
||||
func New() (*FS, error) {
|
||||
f := &FS{
|
||||
infos: &maps.Infos{},
|
||||
paths: &maps.Paths{},
|
||||
}
|
||||
|
||||
var err error
|
||||
f.current, err = here.Current()
|
||||
return f, err
|
||||
}
|
||||
|
||||
func (fx *FS) Create(name string) (fs.File, error) {
|
||||
name, err := fx.locate(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := os.Create(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewFile(fx, f)
|
||||
}
|
||||
|
||||
func (f *FS) Current() (here.Info, error) {
|
||||
return f.current, nil
|
||||
}
|
||||
|
||||
func (f *FS) Info(p string) (here.Info, error) {
|
||||
info, ok := f.infos.Load(p)
|
||||
if ok {
|
||||
return info, nil
|
||||
}
|
||||
|
||||
info, err := here.Package(p)
|
||||
if err != nil {
|
||||
return info, err
|
||||
}
|
||||
f.infos.Store(p, info)
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (f *FS) MkdirAll(p string, perm os.FileMode) error {
|
||||
p, err := f.locate(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.MkdirAll(p, perm)
|
||||
}
|
||||
|
||||
func (fx *FS) Open(name string) (fs.File, error) {
|
||||
name, err := fx.locate(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewFile(fx, f)
|
||||
}
|
||||
|
||||
func (f *FS) Parse(p string) (fs.Path, error) {
|
||||
return f.paths.Parse(p)
|
||||
}
|
||||
|
||||
func (f *FS) ReadFile(s string) ([]byte, error) {
|
||||
s, err := f.locate(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ioutil.ReadFile(s)
|
||||
}
|
||||
|
||||
func (f *FS) Stat(name string) (os.FileInfo, error) {
|
||||
name, err := f.locate(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return os.Stat(name)
|
||||
}
|
||||
|
||||
func (f *FS) Walk(p string, wf filepath.WalkFunc) error {
|
||||
fp, err := f.locate(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pt, err := f.Parse(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = filepath.Walk(fp, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
path = strings.TrimPrefix(path, fp)
|
||||
pt, err := f.Parse(fmt.Sprintf("%s:%s", pt.Pkg, path))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return wf(pt.String(), fs.WithName(path, fs.NewFileInfo(fi)), nil)
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *FS) locate(p string) (string, error) {
|
||||
pt, err := f.Parse(p)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var info here.Info
|
||||
if pt.Pkg == "." {
|
||||
info, err = f.Current()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
pt.Pkg = info.ImportPath
|
||||
}
|
||||
|
||||
if info.IsZero() {
|
||||
info, err = f.Info(pt.Pkg)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%s: %s", pt, err)
|
||||
}
|
||||
}
|
||||
fp := filepath.Join(info.Dir, pt.Name)
|
||||
return fp, nil
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package fs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const timeFmt = time.RFC3339Nano
|
||||
|
||||
type ModTime time.Time
|
||||
|
||||
func (m ModTime) MarshalJSON() ([]byte, error) {
|
||||
t := time.Time(m)
|
||||
return json.Marshal(t.Format(timeFmt))
|
||||
}
|
||||
|
||||
func (m *ModTime) UnmarshalJSON(b []byte) error {
|
||||
t := time.Time{}
|
||||
if err := json.Unmarshal(b, &t); err != nil {
|
||||
return err
|
||||
}
|
||||
(*m) = ModTime(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
type Details struct {
|
||||
Name string `json:"name"`
|
||||
Size int64 `json:"size"`
|
||||
Mode os.FileMode `json:"mode"`
|
||||
ModTime ModTime `json:"mod_time"`
|
||||
IsDir bool `json:"is_dir"`
|
||||
Sys interface{} `json:"sys"`
|
||||
}
|
||||
type FileInfo struct {
|
||||
Details `json:"details"`
|
||||
}
|
||||
|
||||
func (f *FileInfo) String() string {
|
||||
b, _ := json.MarshalIndent(f, "", " ")
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (f *FileInfo) Name() string {
|
||||
return f.Details.Name
|
||||
}
|
||||
|
||||
func (f *FileInfo) Size() int64 {
|
||||
return f.Details.Size
|
||||
}
|
||||
|
||||
func (f *FileInfo) Mode() os.FileMode {
|
||||
return f.Details.Mode
|
||||
}
|
||||
|
||||
func (f *FileInfo) ModTime() time.Time {
|
||||
return time.Time(f.Details.ModTime)
|
||||
}
|
||||
|
||||
func (f *FileInfo) IsDir() bool {
|
||||
return f.Details.IsDir
|
||||
}
|
||||
|
||||
func (f *FileInfo) Sys() interface{} {
|
||||
return f.Details.Sys
|
||||
}
|
||||
|
||||
var _ os.FileInfo = &FileInfo{}
|
||||
|
||||
func NewFileInfo(info os.FileInfo) *FileInfo {
|
||||
fi := &FileInfo{
|
||||
Details: Details{
|
||||
Name: cleanName(info.Name()),
|
||||
Size: info.Size(),
|
||||
Mode: info.Mode(),
|
||||
ModTime: ModTime(info.ModTime()),
|
||||
IsDir: info.IsDir(),
|
||||
Sys: info.Sys(),
|
||||
},
|
||||
}
|
||||
return fi
|
||||
}
|
||||
|
||||
func WithName(name string, info os.FileInfo) *FileInfo {
|
||||
if ft, ok := info.(*FileInfo); ok {
|
||||
ft.Details.Name = cleanName(name)
|
||||
return ft
|
||||
}
|
||||
|
||||
fo := NewFileInfo(info)
|
||||
fo.Details.Name = cleanName(name)
|
||||
return fo
|
||||
}
|
||||
|
||||
func cleanName(s string) string {
|
||||
if strings.Contains(s, "\\") {
|
||||
s = strings.Replace(s, "\\", "/", -1)
|
||||
}
|
||||
if !strings.HasPrefix(s, "/") {
|
||||
s = "/" + s
|
||||
}
|
||||
return s
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/markbates/pkger/fs"
|
||||
)
|
||||
|
||||
func (fx *FS) Create(name string) (fs.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
|
||||
}
|
||||
f := &File{
|
||||
path: pt,
|
||||
her: her,
|
||||
info: &fs.FileInfo{
|
||||
Details: fs.Details{
|
||||
Name: pt.Name,
|
||||
Mode: 0666,
|
||||
ModTime: fs.ModTime(time.Now()),
|
||||
},
|
||||
},
|
||||
fs: fx,
|
||||
}
|
||||
|
||||
fx.files.Store(pt, f)
|
||||
|
||||
dir := filepath.Dir(pt.Name)
|
||||
if err := fx.MkdirAll(dir, 0644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/markbates/pkger/here"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
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`
|
|
@ -0,0 +1,203 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/markbates/pkger/fs"
|
||||
"github.com/markbates/pkger/here"
|
||||
)
|
||||
|
||||
const timeFmt = time.RFC3339Nano
|
||||
|
||||
var _ fs.File = &File{}
|
||||
|
||||
type File struct {
|
||||
info *fs.FileInfo
|
||||
her here.Info
|
||||
path fs.Path
|
||||
data []byte
|
||||
parent fs.Path
|
||||
writer *bytes.Buffer
|
||||
reader io.Reader
|
||||
fs fs.FileSystem
|
||||
}
|
||||
|
||||
func (f *File) Seek(offset int64, whence int) (int64, error) {
|
||||
if sk, ok := f.reader.(io.Seeker); ok {
|
||||
return sk.Seek(offset, whence)
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (f *File) Close() error {
|
||||
defer func() {
|
||||
f.reader = nil
|
||||
f.writer = nil
|
||||
}()
|
||||
if f.reader != nil {
|
||||
if c, ok := f.reader.(io.Closer); ok {
|
||||
if err := c.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if f.writer == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
f.data = f.writer.Bytes()
|
||||
|
||||
fi := f.info
|
||||
fi.Details.Size = int64(len(f.data))
|
||||
fi.Details.ModTime = fs.ModTime(time.Now())
|
||||
f.info = fi
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) Read(p []byte) (int, error) {
|
||||
if len(f.data) > 0 && f.reader == nil {
|
||||
f.reader = bytes.NewReader(f.data)
|
||||
}
|
||||
|
||||
if f.reader != nil {
|
||||
return f.reader.Read(p)
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("unable to read %s", f.Name())
|
||||
}
|
||||
|
||||
func (f *File) Write(b []byte) (int, error) {
|
||||
if f.writer == nil {
|
||||
f.writer = &bytes.Buffer{}
|
||||
}
|
||||
i, err := f.writer.Write(b)
|
||||
return i, err
|
||||
}
|
||||
|
||||
func (f File) Info() here.Info {
|
||||
return f.her
|
||||
}
|
||||
|
||||
func (f File) Stat() (os.FileInfo, error) {
|
||||
if f.info == nil {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
return f.info, nil
|
||||
}
|
||||
|
||||
func (f File) Name() string {
|
||||
return f.info.Name()
|
||||
}
|
||||
|
||||
func (f File) FilePath() string {
|
||||
return f.her.FilePath(f.Name())
|
||||
}
|
||||
|
||||
func (f File) Path() fs.Path {
|
||||
return f.path
|
||||
}
|
||||
|
||||
func (f File) String() string {
|
||||
return f.Path().String()
|
||||
}
|
||||
|
||||
func (f File) Format(st fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if st.Flag('+') {
|
||||
b, err := json.MarshalIndent(f, "", " ")
|
||||
if err != nil {
|
||||
fmt.Fprint(os.Stderr, err)
|
||||
return
|
||||
}
|
||||
fmt.Fprint(st, string(b))
|
||||
return
|
||||
}
|
||||
fmt.Fprint(st, f.String())
|
||||
case 'q':
|
||||
fmt.Fprintf(st, "%q", f.String())
|
||||
default:
|
||||
fmt.Fprint(st, f.String())
|
||||
}
|
||||
}
|
||||
|
||||
func (f *File) Readdir(count int) ([]os.FileInfo, error) {
|
||||
var infos []os.FileInfo
|
||||
root := f.Path().String()
|
||||
err := f.fs.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if count > 0 && len(infos) == count {
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
pt, err := f.fs.Parse(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pt.Name == f.parent.Name {
|
||||
return nil
|
||||
}
|
||||
// if f.parent.Name != "/" {
|
||||
info = fs.WithName(strings.TrimPrefix(info.Name(), f.parent.Name), info)
|
||||
// }
|
||||
infos = append(infos, info)
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if _, ok := err.(*os.PathError); ok {
|
||||
return infos, nil
|
||||
}
|
||||
if err != io.EOF {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return infos, nil
|
||||
|
||||
}
|
||||
|
||||
func (f *File) Open(name string) (http.File, error) {
|
||||
pt, err := f.fs.Parse(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pt == f.path {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
pt.Name = path.Join(f.Path().Name, pt.Name)
|
||||
|
||||
di, err := f.fs.Open(pt.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fi, err := di.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if fi.IsDir() {
|
||||
d2 := &File{
|
||||
info: fs.NewFileInfo(fi),
|
||||
her: di.Info(),
|
||||
path: pt,
|
||||
parent: f.path,
|
||||
fs: f.fs,
|
||||
}
|
||||
di = d2
|
||||
}
|
||||
return di, nil
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/markbates/pkger/here"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
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())
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
package memfs
|
|
@ -0,0 +1,84 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_HTTP_Dir(t *testing.T) {
|
||||
r := require.New(t)
|
||||
|
||||
fs := NewFS()
|
||||
|
||||
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 := NewFS()
|
||||
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 := NewFS()
|
||||
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`)
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/markbates/pkger/fs"
|
||||
)
|
||||
|
||||
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 = &fs.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
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/markbates/pkger/here"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
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))
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/markbates/pkger/fs"
|
||||
"github.com/markbates/pkger/here"
|
||||
"github.com/markbates/pkger/internal/maps"
|
||||
)
|
||||
|
||||
var _ fs.FileSystem = &FS{}
|
||||
|
||||
func New(info here.Info) (*FS, error) {
|
||||
f := &FS{
|
||||
infos: &maps.Infos{},
|
||||
paths: &maps.Paths{},
|
||||
files: &maps.Files{},
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
type FS struct {
|
||||
infos *maps.Infos
|
||||
paths *maps.Paths
|
||||
files *maps.Files
|
||||
current here.Info
|
||||
}
|
||||
|
||||
func (f *FS) Current() (here.Info, error) {
|
||||
return f.current, nil
|
||||
}
|
||||
|
||||
func (f *FS) Info(p string) (here.Info, error) {
|
||||
info, ok := f.infos.Load(p)
|
||||
if ok {
|
||||
return info, nil
|
||||
}
|
||||
|
||||
info, err := here.Package(p)
|
||||
if err != nil {
|
||||
return info, err
|
||||
}
|
||||
f.infos.Store(p, info)
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (f *FS) Parse(p string) (fs.Path, error) {
|
||||
return f.paths.Parse(p)
|
||||
}
|
||||
|
||||
func (fx *FS) ReadFile(s string) ([]byte, error) {
|
||||
f, err := fx.Open(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
return ioutil.ReadAll(f)
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/markbates/pkger/fs/fstest"
|
||||
"github.com/markbates/pkger/here"
|
||||
)
|
||||
|
||||
func NewFS() *FS {
|
||||
fs, err := New(here.Info{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
var Folder = fstest.TestFiles{
|
||||
"/main.go": {Data: []byte("!/main.go")},
|
||||
"/go.mod": {Data: []byte("!/go.mod")},
|
||||
"/go.sum": {Data: []byte("!/go.sum")},
|
||||
"/public/index.html": {Data: []byte("!/public/index.html")},
|
||||
"/public/images/mark.png": {Data: []byte("!/public/images/mark.png")},
|
||||
"/templates/a.txt": {Data: []byte("!/templates/a.txt")},
|
||||
"/templates/b/b.txt": {Data: []byte("!/templates/b/b.txt")},
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/markbates/pkger/fs"
|
||||
)
|
||||
|
||||
func (fx *FS) 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 := fs.Path{
|
||||
Pkg: path.Pkg,
|
||||
Name: root,
|
||||
}
|
||||
if _, ok := fx.files.Load(pt); ok {
|
||||
root = filepath.Dir(root)
|
||||
if root == "/" || root == "\\" {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
f := &File{
|
||||
fs: fx,
|
||||
path: pt,
|
||||
her: cur,
|
||||
info: &fs.FileInfo{
|
||||
Details: fs.Details{
|
||||
Name: pt.Name,
|
||||
Mode: perm,
|
||||
ModTime: fs.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
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package memfs
|
||||
|
||||
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())
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/markbates/pkger/fs"
|
||||
)
|
||||
|
||||
func (fx *FS) Open(name string) (fs.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{
|
||||
fs: fx,
|
||||
info: fs.WithName(f.info.Name(), f.info),
|
||||
path: f.path,
|
||||
data: f.data,
|
||||
her: f.her,
|
||||
}
|
||||
|
||||
return nf, nil
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/markbates/pkger/here"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func (fx *FS) 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", name)
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/markbates/pkger/here"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
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())
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/markbates/pkger/fs"
|
||||
)
|
||||
|
||||
func (f *FS) Walk(p string, wf filepath.WalkFunc) error {
|
||||
keys := f.files.Keys()
|
||||
|
||||
pt, err := f.Parse(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, k := range keys {
|
||||
if !strings.HasPrefix(k.Name, pt.Name) {
|
||||
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 = fs.WithName(strings.TrimPrefix(k.Name, pt.Name), fi)
|
||||
err = wf(k.String(), fi, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package memfs
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/markbates/pkger/here"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package fs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Path struct {
|
||||
Pkg string `json:"pkg"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (p Path) String() string {
|
||||
if p.Name == "" {
|
||||
p.Name = "/"
|
||||
}
|
||||
return fmt.Sprintf("%s:%s", p.Pkg, p.Name)
|
||||
}
|
||||
|
||||
func (p Path) Format(st fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if st.Flag('+') {
|
||||
b, err := json.MarshalIndent(p, "", " ")
|
||||
if err != nil {
|
||||
fmt.Fprint(os.Stderr, err)
|
||||
return
|
||||
}
|
||||
fmt.Fprint(st, string(b))
|
||||
return
|
||||
}
|
||||
fmt.Fprint(st, p.String())
|
||||
case 'q':
|
||||
fmt.Fprintf(st, "%q", p.String())
|
||||
default:
|
||||
fmt.Fprint(st, p.String())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
// Code generated by github.com/gobuffalo/mapgen. DO NOT EDIT.
|
||||
|
||||
package maps
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/markbates/pkger/fs"
|
||||
)
|
||||
|
||||
// Files wraps sync.Map and uses the following types:
|
||||
// key: fs.Path
|
||||
// value: fs.File
|
||||
type Files struct {
|
||||
data *sync.Map
|
||||
once *sync.Once
|
||||
}
|
||||
|
||||
func (m *Files) Data() *sync.Map {
|
||||
if m.once == nil {
|
||||
m.once = &sync.Once{}
|
||||
}
|
||||
m.once.Do(func() {
|
||||
if m.data == nil {
|
||||
m.data = &sync.Map{}
|
||||
}
|
||||
})
|
||||
return m.data
|
||||
}
|
||||
|
||||
func (m *Files) MarshalJSON() ([]byte, error) {
|
||||
var err error
|
||||
mm := map[string]interface{}{}
|
||||
m.Data().Range(func(key, value interface{}) bool {
|
||||
var b []byte
|
||||
b, err = json.Marshal(key)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
mm[string(b)] = value
|
||||
return true
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(mm)
|
||||
}
|
||||
|
||||
func (m *Files) UnmarshalJSON(b []byte) error {
|
||||
mm := map[string]fs.File{}
|
||||
|
||||
if err := json.Unmarshal(b, &mm); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range mm {
|
||||
var pt fs.Path
|
||||
if err := json.Unmarshal([]byte(k), &pt); err != nil {
|
||||
return err
|
||||
}
|
||||
m.Store(pt, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete the key from the map
|
||||
func (m *Files) Delete(key fs.Path) {
|
||||
m.Data().Delete(key)
|
||||
}
|
||||
|
||||
// Load the key from the map.
|
||||
// Returns fs.File or bool.
|
||||
// A false return indicates either the key was not found
|
||||
// or the value is not of type fs.File
|
||||
func (m *Files) Load(key fs.Path) (fs.File, bool) {
|
||||
i, ok := m.Data().Load(key)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
s, ok := i.(fs.File)
|
||||
return s, ok
|
||||
}
|
||||
|
||||
// LoadOrStore will return an existing key or
|
||||
// store the value if not already in the map
|
||||
func (m *Files) LoadOrStore(key fs.Path, value fs.File) (fs.File, bool) {
|
||||
i, _ := m.Data().LoadOrStore(key, value)
|
||||
s, ok := i.(fs.File)
|
||||
return s, ok
|
||||
}
|
||||
|
||||
// LoadOr will return an existing key or
|
||||
// run the function and store the results
|
||||
func (m *Files) LoadOr(key fs.Path, fn func(*Files) (fs.File, bool)) (fs.File, bool) {
|
||||
i, ok := m.Load(key)
|
||||
if ok {
|
||||
return i, ok
|
||||
}
|
||||
i, ok = fn(m)
|
||||
if ok {
|
||||
m.Store(key, i)
|
||||
return i, ok
|
||||
}
|
||||
return i, false
|
||||
}
|
||||
|
||||
// Range over the fs.File values in the map
|
||||
func (m *Files) Range(f func(key fs.Path, value fs.File) bool) {
|
||||
m.Data().Range(func(k, v interface{}) bool {
|
||||
key, ok := k.(fs.Path)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
value, ok := v.(fs.File)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return f(key, value)
|
||||
})
|
||||
}
|
||||
|
||||
// Store a fs.File in the map
|
||||
func (m *Files) Store(key fs.Path, value fs.File) {
|
||||
m.Data().Store(key, value)
|
||||
}
|
||||
|
||||
// Keys returns a list of keys in the map
|
||||
func (m *Files) Keys() []fs.Path {
|
||||
var keys []fs.Path
|
||||
m.Range(func(key fs.Path, value fs.File) bool {
|
||||
keys = append(keys, key)
|
||||
return true
|
||||
})
|
||||
sort.Slice(keys, func(a, b int) bool {
|
||||
return keys[a].String() <= keys[b].String()
|
||||
})
|
||||
return keys
|
||||
}
|
||||
|
||||
func (m *Files) String() string {
|
||||
return fmt.Sprintf("%v", m.Keys())
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
// Code generated by github.com/markbates/pkger/mapgen. DO NOT EDIT.
|
||||
|
||||
package maps
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/markbates/pkger/here"
|
||||
)
|
||||
|
||||
// Infos wraps sync.Map and uses the following types:
|
||||
// key: string
|
||||
// value: here.Info
|
||||
type Infos struct {
|
||||
data *sync.Map
|
||||
once *sync.Once
|
||||
}
|
||||
|
||||
func (m *Infos) Data() *sync.Map {
|
||||
if m.once == nil {
|
||||
m.once = &sync.Once{}
|
||||
}
|
||||
m.once.Do(func() {
|
||||
if m.data == nil {
|
||||
m.data = &sync.Map{}
|
||||
}
|
||||
})
|
||||
return m.data
|
||||
}
|
||||
|
||||
func (m *Infos) MarshalJSON() ([]byte, error) {
|
||||
mm := map[string]interface{}{}
|
||||
m.data.Range(func(key, value interface{}) bool {
|
||||
mm[fmt.Sprintf("%s", key)] = value
|
||||
return true
|
||||
})
|
||||
return json.Marshal(mm)
|
||||
}
|
||||
|
||||
func (m *Infos) UnmarshalJSON(b []byte) error {
|
||||
mm := map[string]here.Info{}
|
||||
|
||||
if err := json.Unmarshal(b, &mm); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range mm {
|
||||
m.Store(k, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete the key from the map
|
||||
func (m *Infos) Delete(key string) {
|
||||
m.Data().Delete(key)
|
||||
}
|
||||
|
||||
// Load the key from the map.
|
||||
// Returns here.Info or bool.
|
||||
// A false return indicates either the key was not found
|
||||
// or the value is not of type here.Info
|
||||
func (m *Infos) Load(key string) (here.Info, bool) {
|
||||
m.Data()
|
||||
i, ok := m.data.Load(key)
|
||||
if !ok {
|
||||
return here.Info{}, false
|
||||
}
|
||||
s, ok := i.(here.Info)
|
||||
return s, ok
|
||||
}
|
||||
|
||||
// LoadOrStore will return an existing key or
|
||||
// store the value if not already in the map
|
||||
func (m *Infos) LoadOrStore(key string, value here.Info) (here.Info, bool) {
|
||||
i, _ := m.Data().LoadOrStore(key, value)
|
||||
s, ok := i.(here.Info)
|
||||
return s, ok
|
||||
}
|
||||
|
||||
// LoadOr will return an existing key or
|
||||
// run the function and store the results
|
||||
func (m *Infos) LoadOr(key string, fn func(*Infos) (here.Info, bool)) (here.Info, bool) {
|
||||
i, ok := m.Load(key)
|
||||
if ok {
|
||||
return i, ok
|
||||
}
|
||||
i, ok = fn(m)
|
||||
if ok {
|
||||
m.Store(key, i)
|
||||
return i, ok
|
||||
}
|
||||
return i, false
|
||||
}
|
||||
|
||||
// Range over the here.Info values in the map
|
||||
func (m *Infos) Range(f func(key string, value here.Info) bool) {
|
||||
m.Data().Range(func(k, v interface{}) bool {
|
||||
key, ok := k.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
value, ok := v.(here.Info)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return f(key, value)
|
||||
})
|
||||
}
|
||||
|
||||
// Store a here.Info in the map
|
||||
func (m *Infos) Store(key string, value here.Info) {
|
||||
m.Data().Store(key, value)
|
||||
}
|
||||
|
||||
// Keys returns a list of keys in the map
|
||||
func (m *Infos) Keys() []string {
|
||||
var keys []string
|
||||
m.Range(func(key string, value here.Info) bool {
|
||||
keys = append(keys, key)
|
||||
return true
|
||||
})
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
// Code generated by github.com/gobuffalo/mapgen. DO NOT EDIT.
|
||||
|
||||
package maps
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/markbates/pkger/fs"
|
||||
"github.com/markbates/pkger/here"
|
||||
)
|
||||
|
||||
// Paths wraps sync.Map and uses the following types:
|
||||
// key: string
|
||||
// value: Path
|
||||
type Paths struct {
|
||||
Current here.Info
|
||||
data *sync.Map
|
||||
once *sync.Once
|
||||
}
|
||||
|
||||
func (m *Paths) Data() *sync.Map {
|
||||
if m.once == nil {
|
||||
m.once = &sync.Once{}
|
||||
}
|
||||
m.once.Do(func() {
|
||||
if m.data == nil {
|
||||
m.data = &sync.Map{}
|
||||
}
|
||||
})
|
||||
return m.data
|
||||
}
|
||||
|
||||
func (m *Paths) MarshalJSON() ([]byte, error) {
|
||||
mm := map[string]interface{}{}
|
||||
m.Data().Range(func(key, value interface{}) bool {
|
||||
mm[fmt.Sprintf("%s", key)] = value
|
||||
return true
|
||||
})
|
||||
return json.Marshal(mm)
|
||||
}
|
||||
|
||||
func (m *Paths) UnmarshalJSON(b []byte) error {
|
||||
mm := map[string]fs.Path{}
|
||||
|
||||
if err := json.Unmarshal(b, &mm); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range mm {
|
||||
m.Store(k, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete the key from the map
|
||||
func (m *Paths) Delete(key string) {
|
||||
m.Data().Delete(key)
|
||||
}
|
||||
|
||||
// Load the key from the map.
|
||||
// Returns Path or bool.
|
||||
// A false return indicates either the key was not found
|
||||
// or the value is not of type Path
|
||||
func (m *Paths) Load(key string) (fs.Path, bool) {
|
||||
i, ok := m.Data().Load(key)
|
||||
if !ok {
|
||||
return fs.Path{}, false
|
||||
}
|
||||
s, ok := i.(fs.Path)
|
||||
return s, ok
|
||||
}
|
||||
|
||||
// LoadOrStore will return an existing key or
|
||||
// store the value if not already in the map
|
||||
func (m *Paths) LoadOrStore(key string, value fs.Path) (fs.Path, bool) {
|
||||
i, _ := m.Data().LoadOrStore(key, value)
|
||||
s, ok := i.(fs.Path)
|
||||
return s, ok
|
||||
}
|
||||
|
||||
// LoadOr will return an existing key or
|
||||
// run the function and store the results
|
||||
func (m *Paths) LoadOr(key string, fn func(*Paths) (fs.Path, bool)) (fs.Path, bool) {
|
||||
i, ok := m.Load(key)
|
||||
if ok {
|
||||
return i, ok
|
||||
}
|
||||
i, ok = fn(m)
|
||||
if ok {
|
||||
m.Store(key, i)
|
||||
return i, ok
|
||||
}
|
||||
return i, false
|
||||
}
|
||||
|
||||
// Range over the Path values in the map
|
||||
func (m *Paths) Range(f func(key string, value fs.Path) bool) {
|
||||
m.Data().Range(func(k, v interface{}) bool {
|
||||
key, ok := k.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
value, ok := v.(fs.Path)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return f(key, value)
|
||||
})
|
||||
}
|
||||
|
||||
// Store a Path in the map
|
||||
func (m *Paths) Store(key string, value fs.Path) {
|
||||
m.Data().Store(key, value)
|
||||
}
|
||||
|
||||
// Keys returns a list of keys in the map
|
||||
func (m *Paths) Keys() []string {
|
||||
var keys []string
|
||||
m.Range(func(key string, value fs.Path) bool {
|
||||
keys = append(keys, key)
|
||||
return true
|
||||
})
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
func (m *Paths) Parse(p string) (fs.Path, error) {
|
||||
p = strings.Replace(p, "\\", "/", -1)
|
||||
pt, ok := m.Load(p)
|
||||
if ok {
|
||||
return pt, nil
|
||||
}
|
||||
if len(p) == 0 {
|
||||
return m.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 m.build(p, matches[1], matches[3])
|
||||
}
|
||||
|
||||
var pathrx = regexp.MustCompile("([^:]+)(:(/.+))?")
|
||||
|
||||
func (m *Paths) build(p, pkg, name string) (fs.Path, error) {
|
||||
pt := fs.Path{
|
||||
Pkg: pkg,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
if strings.HasPrefix(pt.Pkg, "/") || len(pt.Pkg) == 0 {
|
||||
pt.Name = pt.Pkg
|
||||
pt.Pkg = m.Current.ImportPath
|
||||
}
|
||||
|
||||
if len(pt.Name) == 0 {
|
||||
pt.Name = "/"
|
||||
}
|
||||
|
||||
if pt.Pkg == pt.Name {
|
||||
pt.Pkg = m.Current.ImportPath
|
||||
pt.Name = "/"
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(pt.Name, "/") {
|
||||
pt.Name = "/" + pt.Name
|
||||
}
|
||||
m.Store(p, pt)
|
||||
return pt, nil
|
||||
}
|
Loading…
Reference in New Issue