beyond belief

This commit is contained in:
Mark Bates 2019-07-30 17:21:26 -04:00
parent b2d6806f3f
commit a40fcc3eeb
23 changed files with 817 additions and 17 deletions

View File

@ -1,8 +1,8 @@
TAGS ?= "" TAGS ?= ""
GO_BIN ?= "go" GO_BIN ?= "go"
install: install:
$(GO_BIN) install -tags ${TAGS} -v ./pkger/cmd/pkger cd ./cmd/pkger && $(GO_BIN) install -tags ${TAGS} -v .
make tidy make tidy
tidy: tidy:
@ -16,18 +16,18 @@ deps:
$(GO_BIN) get -tags ${TAGS} -t ./... $(GO_BIN) get -tags ${TAGS} -t ./...
make tidy make tidy
build: build:
$(GO_BIN) build -v . $(GO_BIN) build -v .
make tidy make tidy
test: test:
$(GO_BIN) test -cover -tags ${TAGS} ./... $(GO_BIN) test -cover -tags ${TAGS} ./...
make tidy make tidy
ci-deps: ci-deps:
$(GO_BIN) get -tags ${TAGS} -t ./... $(GO_BIN) get -tags ${TAGS} -t ./...
ci-test: ci-test:
$(GO_BIN) test -tags ${TAGS} -race ./... $(GO_BIN) test -tags ${TAGS} -race ./...
lint: lint:
@ -47,7 +47,7 @@ endif
make install make install
make tidy make tidy
release-test: release-test:
$(GO_BIN) test -tags ${TAGS} -race ./... $(GO_BIN) test -tags ${TAGS} -race ./...
make tidy make tidy

7
cmd/pkger/go.mod Normal file
View File

@ -0,0 +1,7 @@
module github.com/markbates/pkger/cmd/pkger
go 1.12
require github.com/markbates/pkger v0.0.0
replace github.com/markbates/pkger => ../../

2
cmd/pkger/go.sum Normal file
View File

@ -0,0 +1,2 @@
github.com/gobuffalo/here v0.2.0 h1:tbOsO8QVUL5MT4swc0JnqZ7IlUm09e6vXYxNSMhOYMw=
github.com/gobuffalo/here v0.2.0/go.mod h1:2a6G14FaAKOGJMK/5UNa4Og/+iyFS5cq3MnlvFR7YDk=

40
cmd/pkger/info.go Normal file
View File

@ -0,0 +1,40 @@
package main
import (
"fmt"
"github.com/markbates/pkger"
)
func info(args []string) error {
if len(args) == 0 {
args = []string{"."}
}
for _, a := range args {
f, err := pkger.Open(a)
if err != nil {
return err
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
return err
}
if fi.IsDir() {
files, err := f.Readdir(-1)
if err != nil {
return err
}
for _, ff := range files {
fmt.Println(pkger.NewFileInfo(ff))
}
continue
}
fmt.Println(pkger.NewFileInfo(fi))
}
return nil
}

34
cmd/pkger/main.go Normal file
View File

@ -0,0 +1,34 @@
package main
import (
"log"
"os"
)
func main() {
type ex func([]string) error
args := os.Args[1:]
if len(args) == 0 {
log.Fatal("does not compute")
}
var fn ex
switch args[0] {
case "walk":
fn = walk
case "read":
fn = read
case "info":
fn = info
case "serve":
fn = serve
}
if fn == nil {
log.Fatal(args)
}
if err := fn(args[1:]); err != nil {
log.Fatal(err)
}
}

41
cmd/pkger/read.go Normal file
View File

@ -0,0 +1,41 @@
package main
import (
"fmt"
"io"
"os"
"github.com/markbates/pkger"
)
func read(args []string) error {
if len(args) == 0 {
args = []string{"."}
}
for _, a := range args {
fmt.Printf("### cmd/pkger/read.go:16 a (%T) -> %q %+v\n", a, a, a)
f, err := pkger.Open(a)
if err != nil {
return err
}
defer f.Close()
fmt.Println(f.Path())
fi, err := f.Stat()
if err != nil {
return err
}
if fi.IsDir() {
return fmt.Errorf("can not read a dir %s", a)
}
_, err = io.Copy(os.Stdout, f)
if err != nil {
return err
}
}
return nil
}

24
cmd/pkger/serve.go Normal file
View File

@ -0,0 +1,24 @@
package main
import (
"fmt"
"log"
"net/http"
"github.com/markbates/pkger"
)
func serve(args []string) error {
if len(args) == 0 {
args = []string{"."}
}
f, err := pkger.Open(args[0])
if err != nil {
log.Fatal("1", err)
}
defer f.Close()
fmt.Println(f.Path())
return http.ListenAndServe(":3000", http.FileServer(f))
}

19
cmd/pkger/walk.go Normal file
View File

@ -0,0 +1,19 @@
package main
import (
"fmt"
"os"
"github.com/markbates/pkger"
)
func walk(args []string) error {
err := pkger.Walk(".", func(path pkger.Path, info os.FileInfo, err error) error {
if err != nil {
return err
}
fmt.Println(path)
return nil
})
return err
}

142
file.go Normal file
View File

@ -0,0 +1,142 @@
package pkger
import (
"bytes"
"encoding/json"
"io"
"net/http"
"os"
"path/filepath"
"time"
"github.com/gobuffalo/here"
)
const timeFmt = time.RFC3339Nano
type File struct {
info *FileInfo
her here.Info
path Path
data []byte
index *index
Source io.ReadCloser
}
func (f *File) Open(name string) (http.File, error) {
if f.index == nil {
f.index = &index{
Files: map[Path]*File{},
}
}
pt, err := Parse(name)
if err != nil {
return nil, err
}
if len(pt.Pkg) == 0 {
pt.Pkg = f.path.Pkg
}
h := httpFile{}
if pt == f.path {
h.File = f
} else {
of, err := f.index.Open(pt)
if err != nil {
return nil, err
}
defer of.Close()
h.File = of
}
if len(f.data) > 0 {
h.crs = &byteCRS{bytes.NewReader(f.data)}
return h, nil
}
bf, err := os.Open(h.File.Path())
if err != nil {
return h, err
}
fi, err := bf.Stat()
if err != nil {
return h, err
}
if fi.IsDir() {
return h, nil
}
if err != nil {
return nil, err
}
h.crs = bf
return h, nil
}
func (f File) Stat() (os.FileInfo, error) {
if f.info == nil {
return nil, os.ErrNotExist
}
return f.info, nil
}
func (f *File) Close() error {
if f.Source == nil {
return nil
}
if c, ok := f.Source.(io.Closer); ok {
return c.Close()
}
return nil
}
func (f File) Name() string {
return f.info.Name()
}
func (f File) Path() string {
dir := f.her.Dir
if filepath.Base(dir) == f.Name() {
return dir
}
fp := filepath.Join(dir, f.Name())
return fp
}
func (f File) String() string {
if f.info == nil {
return ""
}
b, _ := json.MarshalIndent(f.info, "", " ")
return string(b)
}
func (f *File) Read(p []byte) (int, error) {
if f.Source != nil {
return f.Source.Read(p)
}
of, err := os.Open(f.Path())
if err != nil {
return 0, err
}
f.Source = of
return f.Source.Read(p)
}
// Readdir reads the contents of the directory associated with file and returns a slice of up to n FileInfo values, as would be returned by Lstat, in directory order. Subsequent calls on the same file will yield further FileInfos.
//
// If n > 0, Readdir returns at most n FileInfo structures. In this case, if Readdir returns an empty slice, it will return a non-nil error explaining why. At the end of a directory, the error is io.EOF.
//
// If n <= 0, Readdir returns all the FileInfo from the directory in a single slice. In this case, if Readdir succeeds (reads all the way to the end of the directory), it returns the slice and a nil error. If it encounters an error before the end of the directory, Readdir returns the FileInfo read until that point and a non-nil error.
func (f *File) Readdir(count int) ([]os.FileInfo, error) {
of, err := os.Open(f.Path())
if err != nil {
return nil, err
}
defer of.Close()
return of.Readdir(count)
}

124
file_info.go Normal file
View File

@ -0,0 +1,124 @@
package pkger
import (
"encoding/json"
"os"
"time"
)
type FileInfo struct {
name string
size int64
mode os.FileMode
modTime time.Time
isDir 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,
"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"]
// 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: 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 = name
return ft
}
fo := NewFileInfo(info)
fo.name = name
return fo
}

2
go.mod
View File

@ -1,3 +1,5 @@
module github.com/markbates/pkger module github.com/markbates/pkger
go 1.12 go 1.12
require github.com/gobuffalo/here v0.2.0

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
github.com/gobuffalo/here v0.2.0 h1:tbOsO8QVUL5MT4swc0JnqZ7IlUm09e6vXYxNSMhOYMw=
github.com/gobuffalo/here v0.2.0/go.mod h1:2a6G14FaAKOGJMK/5UNa4Og/+iyFS5cq3MnlvFR7YDk=

45
http.go Normal file
View File

@ -0,0 +1,45 @@
package pkger
import (
"bytes"
"io"
"net/http"
"os"
)
type crs interface {
io.Closer
io.Reader
io.Seeker
}
type byteCRS struct {
*bytes.Reader
}
func (byteCRS) Close() error {
return nil
}
var _ crs = &byteCRS{}
type httpFile struct {
File *File
crs
}
func (h httpFile) Readdir(n int) ([]os.FileInfo, error) {
if h.File == nil {
return nil, os.ErrNotExist
}
return h.File.Readdir(n)
}
func (h httpFile) Stat() (os.FileInfo, error) {
if h.File == nil {
return nil, os.ErrNotExist
}
return h.File.Stat()
}
var _ http.File = &httpFile{}

116
index.go Normal file
View File

@ -0,0 +1,116 @@
package pkger
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/gobuffalo/here"
"github.com/markbates/pkger/pkgs"
)
type index struct {
Pkg string
Files map[Path]*File
}
func (i index) Walk(pt Path, wf WalkFunc) error {
if len(pt.Pkg) == 0 {
pt.Pkg = i.Pkg
}
if len(i.Files) > 0 {
for k, v := range i.Files {
if k.Pkg != pt.Pkg {
continue
}
if err := wf(k, v.info, nil); err != nil {
return err
}
}
}
var info here.Info
var err error
if pt.Pkg == "." {
info, err = pkgs.Current()
if err != nil {
return err
}
pt.Pkg = info.ImportPath
}
if info.IsZero() {
info, err = pkgs.Pkg(pt.Pkg)
if err != nil {
return fmt.Errorf("%s: %s", pt, err)
}
}
err = filepath.Walk(info.Dir, 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, NewFileInfo(fi), err)
})
return err
}
func (i index) Open(pt Path) (*File, error) {
if len(pt.Pkg) == 0 {
pt.Pkg = i.Pkg
}
f, ok := i.Files[pt]
if !ok {
return i.openDisk(pt)
}
return &File{
info: f.info,
path: f.path,
data: f.data,
her: f.her,
index: &index{
Files: map[Path]*File{},
},
}, nil
}
func (i index) openDisk(pt Path) (*File, error) {
if len(pt.Pkg) == 0 {
pt.Pkg = i.Pkg
}
info, err := pkgs.Pkg(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(pt.Name, NewFileInfo(fi)),
her: info,
path: pt,
index: &index{
Files: map[Path]*File{},
},
}
return f, nil
}
var rootIndex = &index{
Files: map[Path]*File{},
}

View File

@ -0,0 +1,28 @@
package main
import (
"fmt"
"io"
"log"
"os"
"github.com/markbates/pkger"
)
func main() {
f, err := pkger.Open("github.com/gobuffalo/buffalo:/server.go")
if err != nil {
log.Fatal("1", err)
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
log.Fatal("2", err)
}
fmt.Println(fi)
io.Copy(os.Stdout, f)
}

View File

@ -0,0 +1,43 @@
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
"time"
"github.com/markbates/pkger"
)
func main() {
f, err := pkger.Open("github.com/gobuffalo/buffalo")
if err != nil {
log.Fatal("1", err)
}
defer f.Close()
fmt.Println(f.Path())
go func() {
time.Sleep(1 * time.Second)
res, err := http.Get("http://127.0.0.1:3000/app.go")
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
_, err = io.Copy(os.Stdout, res.Body)
if err != nil {
log.Fatal(err)
}
if res.StatusCode >= 300 {
log.Fatal("code: ", res.StatusCode)
}
}()
log.Fatal(http.ListenAndServe(":3000", http.FileServer(f)))
}

View File

@ -0,0 +1,22 @@
package main
import (
"fmt"
"log"
"os"
"github.com/markbates/pkger"
)
func main() {
err := pkger.Walk("github.com/gobuffalo/buffalo", func(path pkger.Path, info os.FileInfo, err error) error {
if err != nil {
return err
}
fmt.Println(path)
return nil
})
if err != nil {
log.Fatal(err)
}
}

43
path.go Normal file
View File

@ -0,0 +1,43 @@
package pkger
import (
"fmt"
"strings"
)
type Path struct {
Pkg string
Name string
}
func (p Path) String() string {
if len(p.Pkg) == 0 {
return p.Name
}
if len(p.Name) == 0 {
return p.Pkg
}
return fmt.Sprintf("%s:/%s", p.Pkg, p.Name)
}
func Parse(p string) (Path, error) {
var pt Path
res := strings.Split(p, ":")
if len(res) < 1 {
return pt, fmt.Errorf("could not parse %q (%d)", res, len(res))
}
if len(res) == 1 {
if strings.HasPrefix(res[0], "/") {
pt.Name = res[0]
} else {
pt.Pkg = res[0]
}
} else {
pt.Pkg = res[0]
pt.Name = res[1]
}
pt.Name = strings.TrimPrefix(pt.Name, "/")
pt.Pkg = strings.TrimPrefix(pt.Pkg, "/")
return pt, nil
}

35
pkger.go Normal file
View File

@ -0,0 +1,35 @@
package pkger
import (
"bytes"
"fmt"
"os/exec"
"path/filepath"
)
func modRoot() (string, error) {
c := exec.Command("go", "env", "GOMOD")
b, err := c.CombinedOutput()
if err != nil {
return "", err
}
b = bytes.TrimSpace(b)
if len(b) == 0 {
return "", fmt.Errorf("the `go env GOMOD` was empty/modules are required")
}
return filepath.Dir(string(b)), nil
}
func Getwd() (string, error) {
return modRoot()
}
func Open(p string) (*File, error) {
pt, err := Parse(p)
if err != nil {
return nil, err
}
return rootIndex.Open(pt)
}

View File

@ -1,3 +0,0 @@
module github.com/markbates/pkger/pkger/cmd/pkger
go 1.12

View File

@ -1,7 +0,0 @@
package main
import "fmt"
func main() {
fmt.Println("vim-go")
}

28
pkgs/current.go Normal file
View File

@ -0,0 +1,28 @@
package pkgs
import (
"os"
"path/filepath"
"github.com/gobuffalo/here"
)
func Pkg(p string) (here.Info, error) {
return here.Cache(p, here.Package)
}
func Dir(p string) (here.Info, error) {
return here.Cache(p, here.Dir)
}
func Current() (here.Info, error) {
return Dir(".")
}
func Open(info here.Info, p string) (*os.File, error) {
return os.Open(filepath.Join(info.Dir, p))
}
func Stat(info here.Info, p string) (os.FileInfo, error) {
return os.Stat(filepath.Join(info.Dir, p))
}

13
walk.go Normal file
View File

@ -0,0 +1,13 @@
package pkger
import "os"
type WalkFunc func(Path, os.FileInfo, error) error
func Walk(p string, wf WalkFunc) error {
pt, err := Parse(p)
if err != nil {
return err
}
return rootIndex.Walk(pt, wf)
}