mirror of https://github.com/markbates/pkger.git
camera's flash
This commit is contained in:
parent
830ed679a8
commit
fa998dbcb3
|
@ -1,4 +1,5 @@
|
||||||
variables:
|
variables:
|
||||||
|
GOPROXY: "https://proxy.golang.org"
|
||||||
GOBIN: "$(GOPATH)/bin" # Go binaries path
|
GOBIN: "$(GOPATH)/bin" # Go binaries path
|
||||||
GOPATH: "$(system.defaultWorkingDirectory)/gopath" # Go workspace path
|
GOPATH: "$(system.defaultWorkingDirectory)/gopath" # Go workspace path
|
||||||
modulePath: "$(GOPATH)/src/github.com/$(build.repository.name)" # Path to the module"s code
|
modulePath: "$(GOPATH)/src/github.com/$(build.repository.name)" # Path to the module"s code
|
||||||
|
@ -9,12 +10,12 @@ jobs:
|
||||||
vmImage: "vs2017-win2016"
|
vmImage: "vs2017-win2016"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go 1.11 (on):
|
|
||||||
go_version: "1.11.13"
|
|
||||||
GO111MODULE: "on"
|
|
||||||
go 1.12 (on):
|
go 1.12 (on):
|
||||||
go_version: "1.12.9"
|
go_version: "1.12.9"
|
||||||
GO111MODULE: "on"
|
GO111MODULE: "on"
|
||||||
|
go 1.13 (on):
|
||||||
|
go_version: "1.13"
|
||||||
|
GO111MODULE: "on"
|
||||||
steps:
|
steps:
|
||||||
- template: azure-tests.yml
|
- template: azure-tests.yml
|
||||||
|
|
||||||
|
@ -23,12 +24,12 @@ jobs:
|
||||||
vmImage: "macOS-10.13"
|
vmImage: "macOS-10.13"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go 1.11 (on):
|
|
||||||
go_version: "1.11.13"
|
|
||||||
GO111MODULE: "on"
|
|
||||||
go 1.12 (on):
|
go 1.12 (on):
|
||||||
go_version: "1.12.9"
|
go_version: "1.12.9"
|
||||||
GO111MODULE: "on"
|
GO111MODULE: "on"
|
||||||
|
go 1.13 (on):
|
||||||
|
go_version: "1.13"
|
||||||
|
GO111MODULE: "on"
|
||||||
steps:
|
steps:
|
||||||
- template: azure-tests.yml
|
- template: azure-tests.yml
|
||||||
|
|
||||||
|
@ -37,11 +38,11 @@ jobs:
|
||||||
vmImage: "ubuntu-16.04"
|
vmImage: "ubuntu-16.04"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go 1.11 (on):
|
|
||||||
go_version: "1.11.13"
|
|
||||||
GO111MODULE: "on"
|
|
||||||
go 1.12 (on):
|
go 1.12 (on):
|
||||||
go_version: "1.12.9"
|
go_version: "1.12.9"
|
||||||
GO111MODULE: "on"
|
GO111MODULE: "on"
|
||||||
|
go 1.13 (on):
|
||||||
|
go_version: "1.13"
|
||||||
|
GO111MODULE: "on"
|
||||||
steps:
|
steps:
|
||||||
- template: azure-tests.yml
|
- template: azure-tests.yml
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/markbates/pkger"
|
"github.com/markbates/pkger"
|
||||||
|
"github.com/markbates/pkger/pkging"
|
||||||
)
|
)
|
||||||
|
|
||||||
type infoCmd struct {
|
type infoCmd struct {
|
||||||
|
@ -44,12 +45,12 @@ func (f *infoCmd) Exec(args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, ff := range files {
|
for _, ff := range files {
|
||||||
fmt.Println(pkger.NewFileInfo(ff))
|
fmt.Println(pkging.NewFileInfo(ff))
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(pkger.NewFileInfo(fi))
|
fmt.Println(pkging.NewFileInfo(fi))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/markbates/pkger"
|
"github.com/markbates/pkger"
|
||||||
"github.com/markbates/pkger/parser"
|
"github.com/markbates/pkger/parser"
|
||||||
|
"github.com/markbates/pkger/pkging"
|
||||||
)
|
)
|
||||||
|
|
||||||
const outName = "pkged.go"
|
const outName = "pkged.go"
|
||||||
|
@ -24,12 +25,12 @@ func (e *packCmd) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *packCmd) Exec(args []string) error {
|
func (e *packCmd) Exec(args []string) error {
|
||||||
info, err := pkger.Stat()
|
info, err := pkger.Current()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := parser.Parse(info.Dir)
|
res, err := parser.Parse(info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -116,7 +117,7 @@ func (e *packCmd) Flags() *flag.FlagSet {
|
||||||
return e.FlagSet
|
return e.FlagSet
|
||||||
}
|
}
|
||||||
|
|
||||||
func Package(out string, paths []pkger.Path) error {
|
func Package(out string, paths []pkging.Path) error {
|
||||||
os.RemoveAll(out)
|
os.RemoveAll(out)
|
||||||
|
|
||||||
f, err := os.Create(out)
|
f, err := os.Create(out)
|
||||||
|
@ -124,7 +125,7 @@ func Package(out string, paths []pkger.Path) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := pkger.Stat()
|
c, err := pkger.Current()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -132,9 +133,10 @@ func Package(out string, paths []pkger.Path) error {
|
||||||
fmt.Fprintf(f, "import \"github.com/markbates/pkger\"\n\n")
|
fmt.Fprintf(f, "import \"github.com/markbates/pkger\"\n\n")
|
||||||
fmt.Fprintf(f, "var _ = pkger.Unpack(`")
|
fmt.Fprintf(f, "var _ = pkger.Unpack(`")
|
||||||
|
|
||||||
if err := pkger.Pack(f, paths); err != nil {
|
// TODO
|
||||||
return err
|
// if err := pkger.Pack(f, paths); err != nil {
|
||||||
}
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
fmt.Fprintf(f, "`)\n")
|
fmt.Fprintf(f, "`)\n")
|
||||||
|
|
||||||
|
|
|
@ -48,10 +48,11 @@ func (s *serveCmd) Exec(args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ex := append(defaultExcludes, s.excludes...)
|
// TODO
|
||||||
if err := pkger.Exclude(f, ex...); err != nil {
|
// ex := append(defaultExcludes, s.excludes...)
|
||||||
return err
|
// if err := pkger.Exclude(f, ex...); err != nil {
|
||||||
}
|
// return err
|
||||||
|
// }
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
fmt.Println(f.Path())
|
fmt.Println(f.Path())
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func walk(args []string) error {
|
func walk(args []string) error {
|
||||||
err := pkger.Walk(".", func(path pkger.Path, info os.FileInfo) error {
|
err := pkger.Walk(".", func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
fmt.Println(path)
|
fmt.Println(path)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
36
create.go
36
create.go
|
@ -1,36 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
package pkger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_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_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())
|
|
||||||
}
|
|
55
dir.go
55
dir.go
|
@ -1,55 +0,0 @@
|
||||||
package pkger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MkdirAll(p string, perm os.FileMode) error {
|
|
||||||
path, err := Parse(p)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
root := path.Name
|
|
||||||
|
|
||||||
cur, err := Stat()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for root != "" && root != "/" && root != "\\" {
|
|
||||||
pt := Path{
|
|
||||||
Pkg: path.Pkg,
|
|
||||||
Name: root,
|
|
||||||
}
|
|
||||||
if _, ok := filesCache.Load(pt); ok {
|
|
||||||
root = filepath.Dir(root)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
f := &File{
|
|
||||||
path: pt,
|
|
||||||
her: cur,
|
|
||||||
info: &FileInfo{
|
|
||||||
name: pt.Name,
|
|
||||||
mode: 0666,
|
|
||||||
modTime: time.Now(),
|
|
||||||
virtual: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
f.info.isDir = true
|
|
||||||
f.info.mode = perm
|
|
||||||
f.info.virtual = true
|
|
||||||
if err := f.Close(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
filesCache.Store(pt, f)
|
|
||||||
root = filepath.Dir(root)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,5 +1,12 @@
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
|
github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
@ -8,5 +15,7 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|
179
file.go
179
file.go
|
@ -1,179 +0,0 @@
|
||||||
package pkger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/markbates/pkger/here"
|
|
||||||
)
|
|
||||||
|
|
||||||
const timeFmt = time.RFC3339Nano
|
|
||||||
|
|
||||||
var _ http.File = &File{}
|
|
||||||
|
|
||||||
type File struct {
|
|
||||||
info *FileInfo
|
|
||||||
her here.Info
|
|
||||||
path Path
|
|
||||||
data []byte
|
|
||||||
parent Path
|
|
||||||
writer *bytes.Buffer
|
|
||||||
reader io.Reader
|
|
||||||
excludes []string
|
|
||||||
}
|
|
||||||
|
|
||||||
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.size = int64(len(f.data))
|
|
||||||
fi.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)
|
|
||||||
}
|
|
||||||
|
|
||||||
of, err := f.her.Open(f.FilePath())
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
f.reader = of
|
|
||||||
return f.reader.Read(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
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() 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
|
|
||||||
err := Walk(f.Name(), func(pt Path, info os.FileInfo) error {
|
|
||||||
if count > 0 && len(infos) == count {
|
|
||||||
return io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, x := range f.excludes {
|
|
||||||
rx, err := regexp.Compile(x)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if rx.MatchString(pt.Name) {
|
|
||||||
if info.IsDir() {
|
|
||||||
return filepath.SkipDir
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if pt.Name == f.parent.Name {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if f.parent.Name != "/" {
|
|
||||||
info = 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
|
|
||||||
|
|
||||||
}
|
|
139
file_info.go
139
file_info.go
|
@ -1,139 +0,0 @@
|
||||||
package pkger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FileInfo struct {
|
|
||||||
name string
|
|
||||||
size int64
|
|
||||||
mode os.FileMode
|
|
||||||
modTime time.Time
|
|
||||||
isDir bool
|
|
||||||
virtual bool
|
|
||||||
sys interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FileInfo) String() string {
|
|
||||||
b, _ := json.MarshalIndent(f, "", " ")
|
|
||||||
return string(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FileInfo) MarshalJSON() ([]byte, error) {
|
|
||||||
return json.Marshal(map[string]interface{}{
|
|
||||||
"name": f.name,
|
|
||||||
"size": f.size,
|
|
||||||
"mode": f.mode,
|
|
||||||
"modTime": f.modTime.Format(timeFmt),
|
|
||||||
"isDir": f.isDir,
|
|
||||||
"virtual": true,
|
|
||||||
"sys": f.sys,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FileInfo) UnmarshalJSON(b []byte) error {
|
|
||||||
m := map[string]interface{}{}
|
|
||||||
if err := json.Unmarshal(b, &m); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var ok bool
|
|
||||||
|
|
||||||
f.name, ok = m["name"].(string)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("could not determine name %q", m["name"])
|
|
||||||
}
|
|
||||||
|
|
||||||
size, ok := m["size"].(float64)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("could not determine size %q", m["size"])
|
|
||||||
}
|
|
||||||
f.size = int64(size)
|
|
||||||
|
|
||||||
mode, ok := m["mode"].(float64)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("could not determine mode %q", m["mode"])
|
|
||||||
}
|
|
||||||
f.mode = os.FileMode(mode)
|
|
||||||
|
|
||||||
modTime, ok := m["modTime"].(string)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("could not determine modTime %q", m["modTime"])
|
|
||||||
}
|
|
||||||
t, err := time.Parse(timeFmt, modTime)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
f.modTime = t
|
|
||||||
|
|
||||||
f.isDir, ok = m["isDir"].(bool)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("could not determine isDir %q", m["isDir"])
|
|
||||||
}
|
|
||||||
f.sys = m["sys"]
|
|
||||||
f.virtual = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FileInfo) Name() string {
|
|
||||||
return f.name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FileInfo) Size() int64 {
|
|
||||||
return f.size
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FileInfo) Mode() os.FileMode {
|
|
||||||
return f.mode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FileInfo) ModTime() time.Time {
|
|
||||||
return f.modTime
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FileInfo) IsDir() bool {
|
|
||||||
return f.isDir
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FileInfo) Sys() interface{} {
|
|
||||||
return f.sys
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ os.FileInfo = &FileInfo{}
|
|
||||||
|
|
||||||
func NewFileInfo(info os.FileInfo) *FileInfo {
|
|
||||||
fi := &FileInfo{
|
|
||||||
name: cleanName(info.Name()),
|
|
||||||
size: info.Size(),
|
|
||||||
mode: info.Mode(),
|
|
||||||
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.name = cleanName(name)
|
|
||||||
return ft
|
|
||||||
}
|
|
||||||
|
|
||||||
fo := NewFileInfo(info)
|
|
||||||
fo.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
|
|
||||||
}
|
|
108
file_test.go
108
file_test.go
|
@ -1,108 +0,0 @@
|
||||||
package pkger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_File_Open(t *testing.T) {
|
|
||||||
r := require.New(t)
|
|
||||||
|
|
||||||
f, err := Open("/file_test.go")
|
|
||||||
r.NoError(err)
|
|
||||||
|
|
||||||
r.Equal("/file_test.go", f.Name())
|
|
||||||
|
|
||||||
b, err := ioutil.ReadAll(f)
|
|
||||||
r.NoError(err)
|
|
||||||
r.Contains(string(b), "Test_File_Open")
|
|
||||||
r.NoError(f.Close())
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_File_Open_Dir(t *testing.T) {
|
|
||||||
r := require.New(t)
|
|
||||||
|
|
||||||
f, err := Open("/cmd")
|
|
||||||
r.NoError(err)
|
|
||||||
|
|
||||||
r.Equal("/cmd", f.Name())
|
|
||||||
|
|
||||||
r.NoError(f.Close())
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_File_Read_Memory(t *testing.T) {
|
|
||||||
r := require.New(t)
|
|
||||||
|
|
||||||
f, err := Open("/file_test.go")
|
|
||||||
r.NoError(err)
|
|
||||||
f.data = []byte("hi!")
|
|
||||||
|
|
||||||
r.Equal("/file_test.go", f.Name())
|
|
||||||
|
|
||||||
b, err := ioutil.ReadAll(f)
|
|
||||||
r.NoError(err)
|
|
||||||
r.Equal(string(b), "hi!")
|
|
||||||
r.NoError(f.Close())
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_File_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)
|
|
||||||
|
|
||||||
// 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())
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_File_JSON(t *testing.T) {
|
|
||||||
r := require.New(t)
|
|
||||||
|
|
||||||
f, err := createFile("/radio.radio")
|
|
||||||
r.NoError(err)
|
|
||||||
r.NotNil(f)
|
|
||||||
|
|
||||||
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(string(f.data), string(f2.data))
|
|
||||||
}
|
|
144
files_map.go
144
files_map.go
|
@ -1,144 +0,0 @@
|
||||||
// Code generated by github.com/gobuffalo/mapgen. DO NOT EDIT.
|
|
||||||
|
|
||||||
package pkger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// filesMap wraps sync.Map and uses the following types:
|
|
||||||
// key: Path
|
|
||||||
// value: *File
|
|
||||||
type filesMap struct {
|
|
||||||
data *sync.Map
|
|
||||||
once *sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *filesMap) 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 *filesMap) 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 *filesMap) UnmarshalJSON(b []byte) error {
|
|
||||||
mm := map[string]*File{}
|
|
||||||
|
|
||||||
if err := json.Unmarshal(b, &mm); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for k, v := range mm {
|
|
||||||
var pt 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 *filesMap) Delete(key Path) {
|
|
||||||
m.Data().Delete(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the key from the map.
|
|
||||||
// Returns *File or bool.
|
|
||||||
// A false return indicates either the key was not found
|
|
||||||
// or the value is not of type *File
|
|
||||||
func (m *filesMap) Load(key Path) (*File, bool) {
|
|
||||||
i, ok := m.Data().Load(key)
|
|
||||||
if !ok {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
s, ok := i.(*File)
|
|
||||||
return s, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadOrStore will return an existing key or
|
|
||||||
// store the value if not already in the map
|
|
||||||
func (m *filesMap) LoadOrStore(key Path, value *File) (*File, bool) {
|
|
||||||
i, _ := m.Data().LoadOrStore(key, value)
|
|
||||||
s, ok := i.(*File)
|
|
||||||
return s, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadOr will return an existing key or
|
|
||||||
// run the function and store the results
|
|
||||||
func (m *filesMap) LoadOr(key Path, fn func(*filesMap) (*File, bool)) (*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 *File values in the map
|
|
||||||
func (m *filesMap) Range(f func(key Path, value *File) bool) {
|
|
||||||
m.Data().Range(func(k, v interface{}) bool {
|
|
||||||
key, ok := k.(Path)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
value, ok := v.(*File)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return f(key, value)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store a *File in the map
|
|
||||||
func (m *filesMap) Store(key Path, value *File) {
|
|
||||||
m.Data().Store(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keys returns a list of keys in the map
|
|
||||||
func (m *filesMap) Keys() []Path {
|
|
||||||
var keys []Path
|
|
||||||
m.Range(func(key Path, value *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 *filesMap) String() string {
|
|
||||||
return fmt.Sprintf("%v", m.Keys())
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
package pkger
|
|
||||||
|
|
||||||
func Exclude(fl *File, excludes ...string) error {
|
|
||||||
fl.excludes = append(fl.excludes, excludes...)
|
|
||||||
return nil
|
|
||||||
}
|
|
3
go.mod
3
go.mod
|
@ -3,6 +3,9 @@ module github.com/markbates/pkger
|
||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/kr/pretty v0.1.0 // indirect
|
||||||
github.com/markbates/errx v1.1.0
|
github.com/markbates/errx v1.1.0
|
||||||
github.com/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.4.0
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||||
)
|
)
|
||||||
|
|
9
go.sum
9
go.sum
|
@ -1,5 +1,12 @@
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI=
|
github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI=
|
||||||
github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
|
github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
@ -9,5 +16,7 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|
17
info.go
17
info.go
|
@ -1,17 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
126
infos_map.go
126
infos_map.go
|
@ -1,126 +0,0 @@
|
||||||
// Code generated by github.com/markbates/pkger/mapgen. DO NOT EDIT.
|
|
||||||
|
|
||||||
package pkger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/markbates/pkger/here"
|
|
||||||
)
|
|
||||||
|
|
||||||
// infosMap wraps sync.Map and uses the following types:
|
|
||||||
// key: string
|
|
||||||
// value: here.Info
|
|
||||||
type infosMap struct {
|
|
||||||
data *sync.Map
|
|
||||||
once *sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *infosMap) 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 *infosMap) 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 *infosMap) 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 *infosMap) 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 *infosMap) 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 *infosMap) 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 *infosMap) LoadOr(key string, fn func(*infosMap) (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 *infosMap) 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 *infosMap) Store(key string, value here.Info) {
|
|
||||||
m.Data().Store(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keys returns a list of keys in the map
|
|
||||||
func (m *infosMap) 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
|
|
||||||
}
|
|
83
json.go
83
json.go
|
@ -1,83 +0,0 @@
|
||||||
package pkger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
"github.com/markbates/pkger/here"
|
|
||||||
)
|
|
||||||
|
|
||||||
type jason struct {
|
|
||||||
Files *filesMap `json:"files"`
|
|
||||||
Infos *infosMap `json:"infos"`
|
|
||||||
Paths *pathsMap `json:"paths"`
|
|
||||||
CurrentInfo here.Info `json:"current_info"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f File) MarshalJSON() ([]byte, error) {
|
|
||||||
m := map[string]interface{}{}
|
|
||||||
m["info"] = f.info
|
|
||||||
m["her"] = f.her
|
|
||||||
m["path"] = f.path
|
|
||||||
m["data"] = f.data
|
|
||||||
m["parent"] = f.parent
|
|
||||||
if !f.info.virtual {
|
|
||||||
if len(f.data) == 0 && !f.info.IsDir() {
|
|
||||||
b, err := ioutil.ReadAll(&f)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
m["data"] = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = &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
|
|
||||||
}
|
|
79
open.go
79
open.go
|
@ -1,79 +0,0 @@
|
||||||
package pkger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (f *File) Open(name string) (http.File, error) {
|
|
||||||
pt, err := 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 := Open(pt.String())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
fi, err := di.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if fi.IsDir() {
|
|
||||||
di.parent = f.path
|
|
||||||
di.excludes = f.excludes
|
|
||||||
}
|
|
||||||
return di, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Open(name string) (*File, error) {
|
|
||||||
pt, err := Parse(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
f, ok := filesCache.Load(pt)
|
|
||||||
if !ok {
|
|
||||||
return openDisk(pt)
|
|
||||||
}
|
|
||||||
nf := &File{
|
|
||||||
info: WithName(f.info.Name(), f.info),
|
|
||||||
path: f.path,
|
|
||||||
data: f.data,
|
|
||||||
her: f.her,
|
|
||||||
}
|
|
||||||
|
|
||||||
return nf, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func openDisk(pt Path) (*File, error) {
|
|
||||||
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
|
|
||||||
}
|
|
124
open_test.go
124
open_test.go
|
@ -1,124 +0,0 @@
|
||||||
package pkger
|
|
||||||
|
|
||||||
// func Test_Open_File(t *testing.T) {
|
|
||||||
// r := require.New(t)
|
|
||||||
//
|
|
||||||
// f, err := Open(".")
|
|
||||||
// r.NoError(err)
|
|
||||||
//
|
|
||||||
// ts := httptest.NewServer(http.FileServer(f))
|
|
||||||
// defer ts.Close()
|
|
||||||
//
|
|
||||||
// res, err := http.Get(ts.URL + "/cmd/pkger/main.go")
|
|
||||||
// r.NoError(err)
|
|
||||||
// r.Equal(200, res.StatusCode)
|
|
||||||
//
|
|
||||||
// b, err := ioutil.ReadAll(res.Body)
|
|
||||||
// r.NoError(err)
|
|
||||||
// r.Contains(string(b), "does not compute")
|
|
||||||
//
|
|
||||||
// r.NoError(f.Close())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func Test_Open_Dir(t *testing.T) {
|
|
||||||
// r := require.New(t)
|
|
||||||
//
|
|
||||||
// f, err := Open("/")
|
|
||||||
// r.NoError(err)
|
|
||||||
//
|
|
||||||
// ts := httptest.NewServer(http.FileServer(f))
|
|
||||||
// defer ts.Close()
|
|
||||||
//
|
|
||||||
// res, err := http.Get(ts.URL + "/cmd/pkger")
|
|
||||||
// r.NoError(err)
|
|
||||||
// r.Equal(200, res.StatusCode)
|
|
||||||
//
|
|
||||||
// b, err := ioutil.ReadAll(res.Body)
|
|
||||||
// r.NoError(err)
|
|
||||||
// r.Contains(string(b), `<a href="/cmd/pkger/main.go">/cmd/pkger/main.go</a>`)
|
|
||||||
//
|
|
||||||
// r.NoError(f.Close())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func Test_Open_File_Memory(t *testing.T) {
|
|
||||||
// r := require.New(t)
|
|
||||||
//
|
|
||||||
// f, err := Create("/suit/case.txt")
|
|
||||||
// r.NoError(err)
|
|
||||||
// f.Write([]byte(radio))
|
|
||||||
// r.NoError(f.Close())
|
|
||||||
//
|
|
||||||
// r.Equal([]byte(radio), f.data)
|
|
||||||
// r.Contains(string(f.data), "I wanna bite the hand that feeds me")
|
|
||||||
//
|
|
||||||
// dir, err := Open("/")
|
|
||||||
// r.NoError(err)
|
|
||||||
// defer dir.Close()
|
|
||||||
//
|
|
||||||
// ts := httptest.NewServer(http.FileServer(dir))
|
|
||||||
// defer ts.Close()
|
|
||||||
//
|
|
||||||
// res, err := http.Get(ts.URL + "/suit/case.txt")
|
|
||||||
// r.NoError(err)
|
|
||||||
// r.Equal(200, res.StatusCode)
|
|
||||||
//
|
|
||||||
// b, _ := ioutil.ReadAll(res.Body)
|
|
||||||
// // r.NoError(err)
|
|
||||||
// r.Contains(string(b), "I wanna bite the hand that feeds me")
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func Test_Open_Dir_StripPrefix(t *testing.T) {
|
|
||||||
// r := require.New(t)
|
|
||||||
//
|
|
||||||
// ts := httptest.NewServer(http.StripPrefix("/assets/", http.FileServer(http.Dir("./testdata/public"))))
|
|
||||||
// defer ts.Close()
|
|
||||||
//
|
|
||||||
// res, err := http.Get(ts.URL + "/assets/radio.radio")
|
|
||||||
// r.NoError(err)
|
|
||||||
// r.Equal(200, res.StatusCode)
|
|
||||||
//
|
|
||||||
// b, _ := ioutil.ReadAll(res.Body)
|
|
||||||
// // r.NoError(err)
|
|
||||||
// r.Contains(string(b), "I wanna bite the hand that feeds me")
|
|
||||||
//
|
|
||||||
// res, err = http.Get(ts.URL + "/assets/")
|
|
||||||
// r.NoError(err)
|
|
||||||
// r.Equal(200, res.StatusCode)
|
|
||||||
//
|
|
||||||
// b, _ = ioutil.ReadAll(res.Body)
|
|
||||||
// // r.NoError(err)
|
|
||||||
// r.Contains(string(b), `<a href="radio.radio">radio.radio</a>`)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func Test_Open_Dir_Memory_StripPrefix(t *testing.T) {
|
|
||||||
// r := require.New(t)
|
|
||||||
//
|
|
||||||
// err := MkdirAll("/testdata/public", 0755)
|
|
||||||
// r.NoError(err)
|
|
||||||
//
|
|
||||||
// dir, err := Open("/testdata/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/radio.radio")
|
|
||||||
// r.NoError(err)
|
|
||||||
// r.Equal(200, res.StatusCode)
|
|
||||||
//
|
|
||||||
// b, _ := ioutil.ReadAll(res.Body)
|
|
||||||
// // r.NoError(err)
|
|
||||||
// r.Contains(string(b), "I wanna bite the hand that feeds me")
|
|
||||||
//
|
|
||||||
// res, err = http.Get(ts.URL + "/assets/")
|
|
||||||
// r.NoError(err)
|
|
||||||
// r.Equal(200, res.StatusCode)
|
|
||||||
//
|
|
||||||
// b, _ = ioutil.ReadAll(res.Body)
|
|
||||||
// // r.NoError(err)
|
|
||||||
// r.Contains(string(b), `<a href="/radio.radio">/radio.radio</a>`)
|
|
||||||
// r.NotContains(string(b), `/public`)
|
|
||||||
// r.NotContains(string(b), `//`)
|
|
||||||
// }
|
|
|
@ -9,20 +9,15 @@ import (
|
||||||
|
|
||||||
"github.com/markbates/pkger"
|
"github.com/markbates/pkger"
|
||||||
"github.com/markbates/pkger/here"
|
"github.com/markbates/pkger/here"
|
||||||
|
"github.com/markbates/pkger/pkging"
|
||||||
)
|
)
|
||||||
|
|
||||||
var DefaultIgnoredFolders = []string{".", "_", "vendor", "node_modules", "_fixtures", "testdata"}
|
var DefaultIgnoredFolders = []string{".", "_", "vendor", "node_modules", "_fixtures", "testdata"}
|
||||||
|
|
||||||
func Parse(name string) (Results, error) {
|
func Parse(cur here.Info) (Results, error) {
|
||||||
var r Results
|
var r Results
|
||||||
c, err := pkger.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return r, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if name == "" {
|
name := cur.ImportPath
|
||||||
name = c.ImportPath
|
|
||||||
}
|
|
||||||
|
|
||||||
pt, err := pkger.Parse(name)
|
pt, err := pkger.Parse(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -36,7 +31,7 @@ func Parse(name string) (Results, error) {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
m := map[pkger.Path]bool{}
|
m := map[pkging.Path]bool{}
|
||||||
|
|
||||||
root := r.Path.Name
|
root := r.Path.Name
|
||||||
if !strings.HasPrefix(root, string(filepath.Separator)) {
|
if !strings.HasPrefix(root, string(filepath.Separator)) {
|
||||||
|
@ -117,7 +112,7 @@ func Parse(name string) (Results, error) {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
var found []pkger.Path
|
var found []pkging.Path
|
||||||
|
|
||||||
for k := range m {
|
for k := range m {
|
||||||
if len(k.String()) == 0 {
|
if len(k.String()) == 0 {
|
||||||
|
@ -133,8 +128,8 @@ func Parse(name string) (Results, error) {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func sourceFiles(pt pkger.Path) ([]pkger.Path, error) {
|
func sourceFiles(pt pkging.Path) ([]pkging.Path, error) {
|
||||||
var res []pkger.Path
|
var res []pkging.Path
|
||||||
|
|
||||||
her, err := pkger.Info(pt.Pkg)
|
her, err := pkger.Info(pt.Pkg)
|
||||||
|
|
||||||
|
@ -177,7 +172,7 @@ func sourceFiles(pt pkger.Path) ([]pkger.Path, error) {
|
||||||
|
|
||||||
n := strings.TrimPrefix(p, her.Dir)
|
n := strings.TrimPrefix(p, her.Dir)
|
||||||
n = strings.Replace(n, "\\", "/", -1)
|
n = strings.Replace(n, "\\", "/", -1)
|
||||||
pt := pkger.Path{
|
pt := pkging.Path{
|
||||||
Name: n,
|
Name: n,
|
||||||
}
|
}
|
||||||
res = append(res, pt)
|
res = append(res, pt)
|
||||||
|
@ -188,6 +183,6 @@ func sourceFiles(pt pkger.Path) ([]pkger.Path, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Results struct {
|
type Results struct {
|
||||||
Paths []pkger.Path
|
Paths []pkging.Path
|
||||||
Path pkger.Path
|
Path pkging.Path
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
package parser
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/markbates/pkger/here"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Parser(t *testing.T) {
|
func Test_Parser(t *testing.T) {
|
||||||
r := require.New(t)
|
r := require.New(t)
|
||||||
pwd, err := os.Getwd()
|
|
||||||
r.NoError(err)
|
|
||||||
r.NoError(os.Chdir(filepath.Join("..", "examples", "app")))
|
|
||||||
defer os.Chdir(pwd)
|
|
||||||
|
|
||||||
res, err := Parse("")
|
ch := filepath.Join("..", "examples", "app")
|
||||||
|
info := here.Info{
|
||||||
|
Dir: ch,
|
||||||
|
ImportPath: "github.com/markbates/pkger/examples/app",
|
||||||
|
}
|
||||||
|
res, err := Parse(info)
|
||||||
|
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,12 @@ import (
|
||||||
|
|
||||||
"github.com/markbates/pkger"
|
"github.com/markbates/pkger"
|
||||||
"github.com/markbates/pkger/here"
|
"github.com/markbates/pkger/here"
|
||||||
|
"github.com/markbates/pkger/pkging"
|
||||||
)
|
)
|
||||||
|
|
||||||
type visitor struct {
|
type visitor struct {
|
||||||
File string
|
File string
|
||||||
Found map[pkger.Path]bool
|
Found map[pkging.Path]bool
|
||||||
info here.Info
|
info here.Info
|
||||||
errors []error
|
errors []error
|
||||||
}
|
}
|
||||||
|
@ -20,12 +21,12 @@ type visitor struct {
|
||||||
func newVisitor(p string, info here.Info) (*visitor, error) {
|
func newVisitor(p string, info here.Info) (*visitor, error) {
|
||||||
return &visitor{
|
return &visitor{
|
||||||
File: p,
|
File: p,
|
||||||
Found: map[pkger.Path]bool{},
|
Found: map[pkging.Path]bool{},
|
||||||
info: info,
|
info: info,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *visitor) Run() ([]pkger.Path, error) {
|
func (v *visitor) Run() ([]pkging.Path, error) {
|
||||||
pf, err := parseFile(v.File)
|
pf, err := parseFile(v.File)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%s: %v", v.File, err)
|
return nil, fmt.Errorf("%s: %v", v.File, err)
|
||||||
|
@ -33,7 +34,7 @@ func (v *visitor) Run() ([]pkger.Path, error) {
|
||||||
|
|
||||||
ast.Walk(v, pf.Ast)
|
ast.Walk(v, pf.Ast)
|
||||||
|
|
||||||
var found []pkger.Path
|
var found []pkging.Path
|
||||||
|
|
||||||
for k := range v.Found {
|
for k := range v.Found {
|
||||||
found = append(found, k)
|
found = append(found, k)
|
||||||
|
|
99
path.go
99
path.go
|
@ -1,99 +0,0 @@
|
||||||
package pkger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Path struct {
|
|
||||||
Pkg string `json:"pkg"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func Parse(p string) (Path, error) {
|
|
||||||
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 = "/"
|
|
||||||
}
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
52
path_test.go
52
path_test.go
|
@ -1,52 +0,0 @@
|
||||||
package pkger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_Path_String(t *testing.T) {
|
|
||||||
table := []struct {
|
|
||||||
in Path
|
|
||||||
out string
|
|
||||||
}{
|
|
||||||
{in: Path{}, out: ":/"},
|
|
||||||
{in: Path{Pkg: curPkg}, out: curPkg + ":/"},
|
|
||||||
{in: Path{Pkg: curPkg, Name: "/foo.go"}, out: curPkg + ":/foo.go"},
|
|
||||||
{in: Path{Name: "/foo.go"}, out: ":/foo.go"},
|
|
||||||
{in: Path{Pkg: "github.com/markbates/pkger/internal/examples/app"}, out: "github.com/markbates/pkger/internal/examples/app:/"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range table {
|
|
||||||
t.Run(tt.in.String(), func(st *testing.T) {
|
|
||||||
r := require.New(st)
|
|
||||||
r.Equal(tt.out, tt.in.String())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
123
paths_map.go
123
paths_map.go
|
@ -1,123 +0,0 @@
|
||||||
// Code generated by github.com/gobuffalo/mapgen. DO NOT EDIT.
|
|
||||||
|
|
||||||
package pkger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// pathsMap wraps sync.Map and uses the following types:
|
|
||||||
// key: string
|
|
||||||
// value: Path
|
|
||||||
type pathsMap struct {
|
|
||||||
data *sync.Map
|
|
||||||
once *sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *pathsMap) 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 *pathsMap) 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 *pathsMap) UnmarshalJSON(b []byte) error {
|
|
||||||
mm := map[string]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 *pathsMap) 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 *pathsMap) Load(key string) (Path, bool) {
|
|
||||||
i, ok := m.Data().Load(key)
|
|
||||||
if !ok {
|
|
||||||
return Path{}, false
|
|
||||||
}
|
|
||||||
s, ok := i.(Path)
|
|
||||||
return s, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadOrStore will return an existing key or
|
|
||||||
// store the value if not already in the map
|
|
||||||
func (m *pathsMap) LoadOrStore(key string, value Path) (Path, bool) {
|
|
||||||
i, _ := m.Data().LoadOrStore(key, value)
|
|
||||||
s, ok := i.(Path)
|
|
||||||
return s, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadOr will return an existing key or
|
|
||||||
// run the function and store the results
|
|
||||||
func (m *pathsMap) LoadOr(key string, fn func(*pathsMap) (Path, bool)) (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 *pathsMap) Range(f func(key string, value Path) bool) {
|
|
||||||
m.Data().Range(func(k, v interface{}) bool {
|
|
||||||
key, ok := k.(string)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
value, ok := v.(Path)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return f(key, value)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store a Path in the map
|
|
||||||
func (m *pathsMap) Store(key string, value Path) {
|
|
||||||
m.Data().Store(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keys returns a list of keys in the map
|
|
||||||
func (m *pathsMap) Keys() []string {
|
|
||||||
var keys []string
|
|
||||||
m.Range(func(key string, value Path) bool {
|
|
||||||
keys = append(keys, key)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
sort.Strings(keys)
|
|
||||||
return keys
|
|
||||||
}
|
|
126
pkger.go
126
pkger.go
|
@ -1,117 +1,29 @@
|
||||||
package pkger
|
package pkger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"compress/gzip"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/markbates/pkger/here"
|
"github.com/markbates/pkger/pkging"
|
||||||
|
"github.com/markbates/pkger/pkging/stdos"
|
||||||
)
|
)
|
||||||
|
|
||||||
var filesCache = &filesMap{}
|
var current = func() pkging.Pkger {
|
||||||
var infosCache = &infosMap{}
|
n, err := stdos.New()
|
||||||
var pathsCache = &pathsMap{}
|
|
||||||
var curOnce = &sync.Once{}
|
|
||||||
var currentInfo here.Info
|
|
||||||
|
|
||||||
var packed bool
|
|
||||||
|
|
||||||
var packMU = &sync.RWMutex{}
|
|
||||||
|
|
||||||
func ReadFile(s string) ([]byte, error) {
|
|
||||||
f, err := Open(s)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
log.Fatal(err)
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
return ioutil.ReadAll(f)
|
|
||||||
}
|
}
|
||||||
|
return n
|
||||||
|
}()
|
||||||
|
|
||||||
func Unpack(ind string) error {
|
var Abs = current.Abs
|
||||||
packed = true
|
var AbsPath = current.AbsPath
|
||||||
packMU.Lock()
|
var Create = current.Create
|
||||||
defer packMU.Unlock()
|
var Current = current.Current
|
||||||
b, err := hex.DecodeString(ind)
|
var Info = current.Info
|
||||||
if err != nil {
|
var MkdirAll = current.MkdirAll
|
||||||
log.Fatal("hex.DecodeString", err)
|
var Open = current.Open
|
||||||
return err
|
var Parse = current.Parse
|
||||||
}
|
var Remove = current.Remove
|
||||||
|
var RemoveAll = current.RemoveAll
|
||||||
gz, err := gzip.NewReader(bytes.NewReader(b))
|
var Stat = current.Stat
|
||||||
if err != nil {
|
var Walk = current.Walk
|
||||||
log.Fatal("gzip.NewReader", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer gz.Close()
|
|
||||||
|
|
||||||
var jay jason
|
|
||||||
if err := json.NewDecoder(gz).Decode(&jay); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
jay.Files.Range(func(key Path, value *File) bool {
|
|
||||||
filesCache.Store(key, value)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
jay.Infos.Range(func(key string, value here.Info) bool {
|
|
||||||
infosCache.Store(key, value)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
jay.Paths.Range(func(key string, value Path) bool {
|
|
||||||
pathsCache.Store(key, value)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
currentInfo = jay.CurrentInfo
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Pack(out io.Writer, paths []Path) error {
|
|
||||||
packMU.RLock()
|
|
||||||
defer packMU.RUnlock()
|
|
||||||
bb := &bytes.Buffer{}
|
|
||||||
gz := gzip.NewWriter(bb)
|
|
||||||
defer gz.Close()
|
|
||||||
|
|
||||||
for _, p := range paths {
|
|
||||||
f, err := Open(p.String())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fi, err := f.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if fi.IsDir() {
|
|
||||||
filesCache.Store(p, f)
|
|
||||||
f.Close()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
filesCache.Store(p, f)
|
|
||||||
f.Close()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
jay := jason{
|
|
||||||
Files: filesCache,
|
|
||||||
Infos: infosCache,
|
|
||||||
Paths: pathsCache,
|
|
||||||
CurrentInfo: currentInfo,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.NewEncoder(gz).Encode(jay); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := gz.Close(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s := hex.EncodeToString(bb.Bytes())
|
|
||||||
_, err := fmt.Fprint(out, s)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
package pkger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
const curPkg = "github.com/markbates/pkger"
|
|
||||||
|
|
||||||
func Test_ReadFile(t *testing.T) {
|
|
||||||
r := require.New(t)
|
|
||||||
b, err := ReadFile("/LICENSE")
|
|
||||||
r.NoError(err)
|
|
||||||
r.Contains(string(b), "MIT")
|
|
||||||
}
|
|
||||||
|
|
||||||
func createFile(p string, body ...string) (*File, error) {
|
|
||||||
if len(body) == 0 {
|
|
||||||
body = append(body, radio)
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := Create(p)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = io.Copy(f, strings.NewReader(strings.Join(body, "\n\n")))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := f.Close(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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`
|
|
14
stat.go
14
stat.go
|
@ -1,14 +0,0 @@
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
package pkger
|
|
||||||
|
|
||||||
// Version of pkger
|
|
||||||
const Version = "v0.0.1"
|
|
70
walk.go
70
walk.go
|
@ -1,70 +0,0 @@
|
||||||
package pkger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/markbates/pkger/here"
|
|
||||||
)
|
|
||||||
|
|
||||||
type WalkFunc func(Path, os.FileInfo) error
|
|
||||||
|
|
||||||
func Walk(p string, wf WalkFunc) error {
|
|
||||||
pt, err := Parse(p)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
filesCache.Range(func(k Path, v *File) bool {
|
|
||||||
if k.Pkg != pt.Pkg {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if !strings.HasPrefix(k.Name, pt.Name) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if err = wf(k, v.info); err != nil {
|
|
||||||
if err == filepath.SkipDir {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
if packed {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var info here.Info
|
|
||||||
if pt.Pkg == "." {
|
|
||||||
info, err = Stat()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
pt.Pkg = info.ImportPath
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.IsZero() {
|
|
||||||
info, err = Info(pt.Pkg)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%s: %s", pt, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fp := filepath.Join(info.Dir, pt.Name)
|
|
||||||
err = filepath.Walk(fp, func(path string, fi os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
path = strings.TrimPrefix(path, info.Dir)
|
|
||||||
pt, err := Parse(fmt.Sprintf("%s:%s", pt.Pkg, path))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return wf(pt, WithName(path, NewFileInfo(fi)))
|
|
||||||
})
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
Loading…
Reference in New Issue