mirror of https://github.com/markbates/pkger.git
beyond belief
This commit is contained in:
parent
b2d6806f3f
commit
a40fcc3eeb
2
Makefile
2
Makefile
|
@ -2,7 +2,7 @@ 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:
|
||||||
|
|
|
@ -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 => ../../
|
|
@ -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=
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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))
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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
2
go.mod
|
@ -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
|
||||||
|
|
|
@ -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=
|
|
@ -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{}
|
|
@ -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{},
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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)))
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
module github.com/markbates/pkger/pkger/cmd/pkger
|
|
||||||
|
|
||||||
go 1.12
|
|
|
@ -1,7 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
fmt.Println("vim-go")
|
|
||||||
}
|
|
|
@ -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))
|
||||||
|
}
|
Loading…
Reference in New Issue