diff --git a/cmd/pkger/list.go b/cmd/pkger/list.go index 911da05..0deffbb 100644 --- a/cmd/pkger/list.go +++ b/cmd/pkger/list.go @@ -8,7 +8,7 @@ import ( ) func list(args []string) error { - info, err := pkger.Current() + info, err := pkger.Stat() if err != nil { return err } diff --git a/cmd/pkger/pack.go b/cmd/pkger/pack.go index c283783..4a552b5 100644 --- a/cmd/pkger/pack.go +++ b/cmd/pkger/pack.go @@ -12,7 +12,7 @@ import ( const outName = "pkged.go" func pack(args []string) error { - info, err := pkger.Current() + info, err := pkger.Stat() if err != nil { return err } @@ -41,7 +41,7 @@ func Package(out string, paths []pkger.Path) error { return err } - c, err := pkger.Current() + c, err := pkger.Stat() if err != nil { return err } diff --git a/current.go b/current.go index c0ec910..205f2b8 100644 --- a/current.go +++ b/current.go @@ -8,6 +8,6 @@ func Info(p string) (here.Info, error) { return rootIndex.Info(p) } -func Current() (here.Info, error) { - return rootIndex.Current() +func Stat() (here.Info, error) { + return rootIndex.Stat() } diff --git a/debug.go b/debug.go new file mode 100644 index 0000000..91cc5ce --- /dev/null +++ b/debug.go @@ -0,0 +1,7 @@ +// +build debug + +package pkger + +func Debug(format string, a ...interface{}) { + fmt.Println("[PKGER] ", fmt.Sprintf(format, a...) +} diff --git a/debug_shim.go b/debug_shim.go new file mode 100644 index 0000000..8647406 --- /dev/null +++ b/debug_shim.go @@ -0,0 +1,5 @@ +// +build !debug + +package pkger + +func Debug(format string, a ...interface{}) {} diff --git a/file.go b/file.go index 944a13b..ece2c9e 100644 --- a/file.go +++ b/file.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "net/http" "os" + "path" "time" "github.com/gobuffalo/here" @@ -62,12 +63,8 @@ func (f *File) Close() error { } func (f *File) Read(p []byte) (int, error) { - if len(f.data) > 0 && len(f.data) <= len(p) { - return copy(p, f.data), io.EOF - } - - if len(f.data) > 0 { - f.reader = ioutil.NopCloser(bytes.NewReader(f.data)) + if len(f.data) > 0 && f.reader == nil { + f.reader = bytes.NewReader(f.data) } if f.reader != nil { @@ -168,6 +165,7 @@ func (f *File) Open(name string) (http.File, error) { return f, nil } + pt.Name = path.Join(f.Path().Name, pt.Name) return rootIndex.Open(pt) } diff --git a/files_map.go b/files_map.go index 056e141..de4adde 100644 --- a/files_map.go +++ b/files_map.go @@ -13,12 +13,18 @@ import ( // value: *File type filesMap struct { data *sync.Map + once *sync.Once } func (m *filesMap) Data() *sync.Map { - if m.data == nil { - m.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 } diff --git a/index.go b/index.go index 569f903..49a4785 100644 --- a/index.go +++ b/index.go @@ -1,7 +1,6 @@ package pkger import ( - "encoding/json" "fmt" "os" "path/filepath" @@ -10,17 +9,40 @@ import ( "time" "github.com/gobuffalo/here" - "github.com/markbates/hepa" - "github.com/markbates/hepa/filters" ) type index struct { - Files *filesMap - Infos *infosMap - current here.Info + Files *filesMap `json:"files"` + Infos *infosMap `json:"infos"` + Paths *pathsMap `json:"paths"` + Current here.Info `json:"current"` once sync.Once } +func (i *index) Parse(p string) (Path, error) { + pt, ok := i.Paths.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]) + return rootIndex.Parse(p) +} + func (i *index) Info(p string) (here.Info, error) { info, ok := i.Infos.Load(p) if ok { @@ -35,14 +57,14 @@ func (i *index) Info(p string) (here.Info, error) { return info, nil } -func (i *index) Current() (here.Info, error) { +func (i *index) Stat() (here.Info, error) { i.once.Do(func() { - i.current, _ = here.Cache("", func(string) (here.Info, error) { + i.Current, _ = here.Cache("", func(string) (here.Info, error) { return here.Current() }) }) - return i.current, nil + return i.Current, nil } func (i *index) Create(pt Path) (*File, error) { @@ -60,63 +82,67 @@ func (i *index) Create(pt Path) (*File, error) { }, } + if i.Files == nil { + i.Files = &filesMap{} + } + i.Files.Store(pt, f) return f, nil } -func (i *index) MarshalJSON() ([]byte, error) { - m := map[string]interface{}{} +// func (i *index) MarshalJSON() ([]byte, error) { +// m := map[string]interface{}{} +// +// m["files"] = i.Files +// m["infos"] = i.Infos +// m["current"] = i.Current +// +// b, err := json.Marshal(m) +// if err != nil { +// return nil, err +// } +// +// hep := hepa.New() +// hep = hepa.With(hep, filters.Golang()) +// hep = hepa.With(hep, filters.Secrets()) +// return hep.Filter(b) +// } - m["files"] = i.Files - m["infos"] = i.Infos - m["current"] = i.current - - b, err := json.Marshal(m) - if err != nil { - return nil, err - } - - hep := hepa.New() - hep = hepa.With(hep, filters.Golang()) - hep = hepa.With(hep, filters.Secrets()) - return hep.Filter(b) -} - -func (i *index) UnmarshalJSON(b []byte) error { - m := map[string]json.RawMessage{} - - if err := json.Unmarshal(b, &m); err != nil { - return err - } - - infos, ok := m["infos"] - if !ok { - return fmt.Errorf("missing infos") - } - i.Infos = &infosMap{} - if err := json.Unmarshal(infos, i.Infos); err != nil { - return err - } - - files, ok := m["files"] - if !ok { - return fmt.Errorf("missing files") - } - - i.Files = &filesMap{} - if err := json.Unmarshal(files, i.Files); err != nil { - return err - } - - current, ok := m["current"] - if !ok { - return fmt.Errorf("missing current") - } - if err := json.Unmarshal(current, &i.current); err != nil { - return err - } - return nil -} +// func (i *index) UnmarshalJSON(b []byte) error { +// m := map[string]json.RawMessage{} +// +// if err := json.Unmarshal(b, &m); err != nil { +// return err +// } +// +// infos, ok := m["infos"] +// if !ok { +// return fmt.Errorf("missing infos") +// } +// i.Infos = &infosMap{} +// if err := json.Unmarshal(infos, i.Infos); err != nil { +// return err +// } +// +// files, ok := m["files"] +// if !ok { +// return fmt.Errorf("missing files") +// } +// +// i.Files = &filesMap{} +// if err := json.Unmarshal(files, i.Files); err != nil { +// return err +// } +// +// current, ok := m["current"] +// if !ok { +// return fmt.Errorf("missing current") +// } +// if err := json.Unmarshal(current, &i.Current); err != nil { +// return err +// } +// return nil +// } func (i index) Walk(pt Path, wf WalkFunc) error { var err error @@ -136,7 +162,7 @@ func (i index) Walk(pt Path, wf WalkFunc) error { var info here.Info if pt.Pkg == "." { - info, err = Current() + info, err = Stat() if err != nil { return err } @@ -207,6 +233,7 @@ func newIndex() *index { return &index{ Files: &filesMap{}, Infos: &infosMap{}, + Paths: &pathsMap{}, } } diff --git a/index_test.go b/index_test.go index 67eb68d..a158d07 100644 --- a/index_test.go +++ b/index_test.go @@ -77,7 +77,7 @@ func Test_index_JSON(t *testing.T) { fmt.Fprint(f, radio) r.NoError(f.Close()) - c, err := i.Current() + c, err := i.Stat() r.NoError(err) r.Equal(curPkg, c.ImportPath) @@ -86,7 +86,7 @@ func Test_index_JSON(t *testing.T) { r.Equal(1, len(i.Files.Keys())) r.Equal(1, len(i.Infos.Keys())) - r.NotZero(i.current) + r.NotZero(i.Current) jason, err := json.Marshal(i) r.NoError(err) @@ -98,7 +98,7 @@ func Test_index_JSON(t *testing.T) { r.NotNil(i2.Infos) r.NotNil(i2.Files) - r.NotZero(i2.current) + r.NotZero(i2.Current) r.Equal(1, len(i2.Files.Keys())) r.Equal(1, len(i2.Infos.Keys())) diff --git a/infos_map.go b/infos_map.go index 3af414f..d10b131 100644 --- a/infos_map.go +++ b/infos_map.go @@ -16,11 +16,14 @@ import ( // value: here.Info type infosMap struct { data *sync.Map - init sync.Once + once *sync.Once } func (m *infosMap) Data() *sync.Map { - m.init.Do(func() { + if m.once == nil { + m.once = &sync.Once{} + } + m.once.Do(func() { if m.data == nil { m.data = &sync.Map{} } diff --git a/internal/examples/app/.gitignore b/internal/examples/app/.gitignore new file mode 100644 index 0000000..294b4e0 --- /dev/null +++ b/internal/examples/app/.gitignore @@ -0,0 +1,2 @@ +example +app diff --git a/internal/examples/app/Dockerfile b/internal/examples/app/Dockerfile new file mode 100644 index 0000000..1360374 --- /dev/null +++ b/internal/examples/app/Dockerfile @@ -0,0 +1,7 @@ +FROM alpine + +EXPOSE 3000 +COPY example /bin/ +RUN ls -la + +CMD /bin/example diff --git a/internal/examples/app/Makefile b/internal/examples/app/Makefile new file mode 100644 index 0000000..15e77ba --- /dev/null +++ b/internal/examples/app/Makefile @@ -0,0 +1,6 @@ +default: + cd ../../../cmd/pkger && go install -v . + pkger + GOOS=linux go build -v -o example + docker build -t pkger:example . + docker run -p 3000:3000 pkger:example diff --git a/internal/examples/app/go.sum b/internal/examples/app/go.sum index 61d952f..ee68fca 100644 --- a/internal/examples/app/go.sum +++ b/internal/examples/app/go.sum @@ -4,6 +4,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/gobuffalo/here v0.2.2 h1:AXEK2ApOb4F5cKZ46Ofi8inGWa0qy5ChmJXAK5/IDmo= github.com/gobuffalo/here v0.2.2/go.mod h1:2a6G14FaAKOGJMK/5UNa4Og/+iyFS5cq3MnlvFR7YDk= github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= +github.com/markbates/hepa v0.0.0-20190718154049-1d900199db5b h1:ns0oO2sMEoFJMmrbiWzGQO5AR3GgqfYRAos0gz8C0Cw= +github.com/markbates/hepa v0.0.0-20190718154049-1d900199db5b/go.mod h1:jHlCX3RNqF+epcY1FxjLyDGzr3l9+mNCh3YDDw6BFvY= 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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/internal/examples/app/main.go b/internal/examples/app/main.go index 7d152d4..d95bddf 100644 --- a/internal/examples/app/main.go +++ b/internal/examples/app/main.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "io" "log" "net/http" @@ -15,10 +16,34 @@ func main() { if err != nil { log.Fatal(err) } + defer pub.Close() + + fi, err := pub.Stat() + if err != nil { + log.Fatal(err) + } + fmt.Println(fi) + mux.Handle("/t", http.StripPrefix("/t", tmplHandler())) mux.Handle("/logo", http.StripPrefix("/logo", logoHandler())) mux.Handle("/", http.FileServer(pub)) + f, err := pkger.Open("/public/images/mark.png") + if err != nil { + log.Fatal(err) + } + defer f.Close() + + // lcl, err := os.Create("me.png") + // if err != nil { + // log.Fatal(err) + // } + // + // if _, err := io.Copy(lcl, f); err != nil { + // log.Fatal(err) + // } + // lcl.Close() + log.Fatal(http.ListenAndServe(":3000", mux)) } diff --git a/parse.go b/parse.go index 451c0b7..6f1eb98 100644 --- a/parse.go +++ b/parse.go @@ -1,39 +1,14 @@ package pkger import ( - "fmt" "regexp" "strings" - "sync" ) -var cache = pathsMap{ - data: &sync.Map{}, -} - var pathrx = regexp.MustCompile("([^:]+)(:(/.+))?") func Parse(p string) (Path, error) { - pt, ok := cache.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]) + return rootIndex.Parse(p) } func build(p, pkg, name string) (Path, error) { @@ -42,7 +17,7 @@ func build(p, pkg, name string) (Path, error) { Name: name, } - info, err := Current() + info, err := Stat() if err != nil { return pt, err } @@ -59,6 +34,6 @@ func build(p, pkg, name string) (Path, error) { if !strings.HasPrefix(pt.Name, "/") { pt.Name = "/" + pt.Name } - cache.Store(p, pt) + rootIndex.Paths.Store(p, pt) return pt, nil } diff --git a/parser/parser.go b/parser/parser.go index 7e13e22..d4ed99b 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -13,7 +13,7 @@ var DefaultIgnoredFolders = []string{".", "_", "vendor", "node_modules", "_fixtu func Parse(name string) (Results, error) { var r Results - c, err := pkger.Current() + c, err := pkger.Stat() if err != nil { return r, err } @@ -149,7 +149,7 @@ func sourceFiles(pt pkger.Path) ([]pkger.Path, error) { return res, nil } - c, err := pkger.Current() + c, err := pkger.Stat() if err != nil { return res, err } diff --git a/paths_map.go b/paths_map.go index d82f02b..e0fcb0f 100644 --- a/paths_map.go +++ b/paths_map.go @@ -3,6 +3,8 @@ package pkger import ( + "encoding/json" + "fmt" "sort" "sync" ) @@ -12,11 +14,45 @@ import ( // 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) + m.Data().Delete(key) } // Load the key from the map. @@ -24,7 +60,7 @@ func (m *pathsMap) Delete(key string) { // 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) + i, ok := m.Data().Load(key) if !ok { return Path{}, false } @@ -35,7 +71,7 @@ func (m *pathsMap) Load(key string) (Path, bool) { // 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) + i, _ := m.Data().LoadOrStore(key, value) s, ok := i.(Path) return s, ok } @@ -57,7 +93,7 @@ func (m *pathsMap) LoadOr(key string, fn func(*pathsMap) (Path, bool)) (Path, bo // 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 { + m.Data().Range(func(k, v interface{}) bool { key, ok := k.(string) if !ok { return false @@ -72,7 +108,7 @@ func (m *pathsMap) Range(f func(key string, value Path) bool) { // Store a Path in the map func (m *pathsMap) Store(key string, value Path) { - m.data.Store(key, value) + m.Data().Store(key, value) } // Keys returns a list of keys in the map diff --git a/pkger.go b/pkger.go index 99eeec2..6cacc9e 100644 --- a/pkger.go +++ b/pkger.go @@ -47,8 +47,6 @@ func Unpack(ind string) error { return err } - fmt.Println(rootIndex.Files.Keys()) - return nil } @@ -62,13 +60,6 @@ func Pack(out io.Writer, paths []Path) error { if err != nil { return err } - fi, err := f.Stat() - if err != nil { - return err - } - if fi.IsDir() { - continue - } rootIndex.Files.Store(p, f) f.Close() }