my science fiction twin

This commit is contained in:
Mark Bates 2019-08-04 17:13:27 -04:00
parent a4a55a52dc
commit 76afe6eed9
29 changed files with 407 additions and 196 deletions

View File

@ -1,32 +1,21 @@
TAGS ?= ""
GO_BIN ?= "go"
install:
tidy:
$(GO_BIN) mod tidy
install: tidy
cd ./cmd/pkger && $(GO_BIN) install -tags ${TAGS} -v .
make tidy
tidy:
ifeq ($(GO111MODULE),on)
$(GO_BIN) mod tidy
else
echo skipping go mod tidy
endif
deps:
$(GO_BIN) get -tags ${TAGS} -t ./...
make tidy
build:
build: tidy
$(GO_BIN) build -v .
make tidy
test:
test: tidy
$(GO_BIN) test -cover -tags ${TAGS} -timeout 5s ./...
make tidy
ci-deps:
$(GO_BIN) get -tags ${TAGS} -t ./...
ci-test:
$(GO_BIN) test -tags ${TAGS} -race ./...
@ -36,13 +25,9 @@ lint:
make tidy
update:
ifeq ($(GO111MODULE),on)
rm go.*
$(GO_BIN) mod init
$(GO_BIN) mod tidy
else
$(GO_BIN) get -u -tags ${TAGS}
endif
make test
make install
make tidy

View File

@ -1,26 +0,0 @@
package main
import (
"fmt"
"github.com/markbates/pkger"
"github.com/markbates/pkger/parser"
)
func list(args []string) error {
info, err := pkger.Stat()
if err != nil {
return err
}
res, err := parser.Parse(info.Dir)
if err != nil {
return err
}
fmt.Println(res.Path)
for _, p := range res.Paths {
fmt.Printf(" > %s\n", p)
}
return nil
}

View File

@ -1,19 +1,11 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"os/exec"
)
var globalFlags = struct {
*flag.FlagSet
}{
FlagSet: flag.NewFlagSet("", flag.ContinueOnError),
}
func main() {
defer func() {
@ -28,7 +20,6 @@ func main() {
"read": read,
"info": info,
"serve": serve,
"list": list,
"pack": pack,
}
args := os.Args[1:]
@ -38,15 +29,11 @@ func main() {
if len(args) > 0 {
var ok bool
fn, ok = cmds[args[0]]
if !ok {
fmt.Fprintf(os.Stderr, "couldn't understand args %q\n\n", args)
fmt.Fprintf(os.Stderr, "the following is a list of available commands:\n\n")
for k := range cmds {
fmt.Fprintf(os.Stderr, "\t%s\n", k)
}
os.Exit(1)
if ok {
args = args[1:]
} else {
fn = pack
}
args = args[1:]
}
if err := fn(args); err != nil {
log.Fatal(err)

View File

@ -1,9 +1,9 @@
package main
import (
"bytes"
"flag"
"fmt"
"os"
"text/template"
"github.com/markbates/pkger"
"github.com/markbates/pkger/parser"
@ -11,20 +11,47 @@ import (
const outName = "pkged.go"
type packOptions struct {
*flag.FlagSet
List bool
}
var packFlags = func() *packOptions {
rd := &packOptions{}
fs := flag.NewFlagSet("", flag.ExitOnError)
fs.BoolVar(&rd.List, "list", false, "prints a list of files/dirs to be packaged")
rd.FlagSet = fs
return rd
}()
func pack(args []string) error {
if err := packFlags.Parse(args); err != nil {
return err
}
args = packFlags.Args()
info, err := pkger.Stat()
if err != nil {
return err
}
fp := info.FilePath(outName)
os.RemoveAll(fp)
res, err := parser.Parse(info.Dir)
if err != nil {
return err
}
if packFlags.List {
fmt.Println(res.Path)
for _, p := range res.Paths {
fmt.Printf(" > %s\n", p)
}
return nil
}
fp := info.FilePath(outName)
os.RemoveAll(fp)
if err := Package(fp, res.Paths); err != nil {
return err
}
@ -35,9 +62,8 @@ func pack(args []string) error {
func Package(out string, paths []pkger.Path) error {
os.RemoveAll(out)
bb := &bytes.Buffer{}
if err := pkger.Pack(bb, paths); err != nil {
f, err := os.Create(out)
if err != nil {
return err
}
@ -45,28 +71,15 @@ func Package(out string, paths []pkger.Path) error {
if err != nil {
return err
}
d := struct {
Pkg string
Data string
}{
Pkg: c.Name,
Data: bb.String(),
fmt.Fprintf(f, "package %s\n\n", c.Name)
fmt.Fprintf(f, "import \"github.com/markbates/pkger\"\n\n")
fmt.Fprintf(f, "var _ = pkger.Unpack(`")
if err := pkger.Pack(f, paths); err != nil {
return err
}
f, err := os.Create(out)
if err != nil {
return err
}
defer f.Close()
fmt.Fprintf(f, "`)\n")
t, err := template.New(outName).Parse(outTmpl)
if err != nil {
return err
}
if err := t.Execute(f, d); err != nil {
return err
}
return nil
}
const outTmpl = "package {{.Pkg}}\nimport \"github.com/markbates/pkger\"\nvar _ = pkger.Unpack(`{{.Data}}`) "

View File

@ -1,7 +1,7 @@
package pkger
import (
"github.com/gobuffalo/here"
"github.com/markbates/pkger/here"
)
func Info(p string) (here.Info, error) {

View File

@ -1,7 +0,0 @@
// +build debug
package pkger
func Debug(format string, a ...interface{}) {
fmt.Println("[PKGER] ", fmt.Sprintf(format, a...)
}

14
file.go
View File

@ -11,9 +11,7 @@ import (
"path"
"time"
"github.com/gobuffalo/here"
"github.com/markbates/hepa"
"github.com/markbates/hepa/filters"
"github.com/markbates/pkger/here"
)
const timeFmt = time.RFC3339Nano
@ -105,15 +103,7 @@ func (f File) MarshalJSON() ([]byte, error) {
m["data"] = b
}
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)
return json.Marshal(m)
}
func (f *File) UnmarshalJSON(b []byte) error {

View File

@ -4,6 +4,7 @@ package pkger
import (
"encoding/json"
"fmt"
"sort"
"sync"
)
@ -137,3 +138,7 @@ func (m *filesMap) Keys() []Path {
})
return keys
}
func (m *filesMap) String() string {
return fmt.Sprintf("%v", m.Keys())
}

3
go.mod
View File

@ -3,9 +3,6 @@ module github.com/markbates/pkger
go 1.12
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gobuffalo/here v0.2.2
github.com/markbates/errx v1.1.0
github.com/markbates/hepa v0.0.0-20190718154049-1d900199db5b
github.com/stretchr/testify v1.3.0
)

6
go.sum
View File

@ -1,13 +1,7 @@
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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI=
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=

32
here/current.go Normal file
View File

@ -0,0 +1,32 @@
package here
import (
"path/filepath"
"sync"
"github.com/markbates/pkger/internal/debug"
)
var curOnce sync.Once
var curErr error
var current Info
func Current() (Info, error) {
(&curOnce).Do(func() {
debug.Debug("[HERE] Current")
b, err := run("go", "env", "GOMOD")
if err != nil {
curErr = err
return
}
root := filepath.Dir(string(b))
i, err := Dir(root)
if err != nil {
curErr = err
return
}
current = i
})
return current, curErr
}

41
here/dir.go Normal file
View File

@ -0,0 +1,41 @@
package here
import (
"encoding/json"
"os"
"path/filepath"
)
// Dir attempts to gather info for the requested directory.
func Dir(p string) (Info, error) {
var i Info
fi, err := os.Stat(p)
if err != nil {
return i, err
}
if !fi.IsDir() {
p = filepath.Dir(p)
}
pwd, err := os.Getwd()
if err != nil {
return i, err
}
defer os.Chdir(pwd)
os.Chdir(p)
b, err := run("go", "list", "-json")
if err != nil {
return i, err
}
if err := json.Unmarshal(b, &i); err != nil {
return i, err
}
return i, nil
}

25
here/here.go Normal file
View File

@ -0,0 +1,25 @@
package here
import (
"bytes"
"os"
"os/exec"
"github.com/markbates/pkger/internal/debug"
)
func run(n string, args ...string) ([]byte, error) {
c := exec.Command(n, args...)
debug.Debug("[HERE] %s", c.Args)
bb := &bytes.Buffer{}
c.Stdout = bb
c.Stderr = os.Stderr
err := c.Run()
if err != nil {
return nil, err
}
return bb.Bytes(), nil
}

76
here/info.go Normal file
View File

@ -0,0 +1,76 @@
package here
import (
"encoding/json"
"os"
"path/filepath"
"runtime"
"strings"
)
// Info represents details about the directory/package
type Info struct {
Dir string
ImportPath string
Name string
Doc string
Target string
Root string
Match []string
Stale bool
StaleReason string
GoFiles []string
Imports []string
Deps []string
TestGoFiles []string
TestImports []string
Module Module
}
func (i Info) FilePath(paths ...string) string {
res := []string{i.Dir}
for _, p := range paths {
p = strings.TrimPrefix(p, i.Dir)
p = strings.TrimPrefix(p, "/")
if runtime.GOOS == "windows" {
p = strings.Replace(p, "/", "\\", -1)
}
res = append(res, p)
}
return filepath.Join(res...)
}
func (i Info) Open(p string) (*os.File, error) {
return os.Open(i.FilePath(p))
}
// ModuleName returns the name of the current
// module, or if not using modules, the current
// package. These *might* not match.
func (i Info) ModuleName() string {
if i.Mods() {
return i.Module.Path
}
return i.ImportPath
}
// IsZero checks if the type has been filled
// with rich chocolately data goodness
func (i Info) IsZero() bool {
return i.String() == Info{}.String()
}
// Mods returns whether Go modules are used
// in this directory/package.
func (i Info) Mods() bool {
return !i.Module.IsZero()
}
func (i Info) String() string {
b, err := json.MarshalIndent(i, "", " ")
if err != nil {
return err.Error()
}
s := string(b)
return s
}

23
here/module.go Normal file
View File

@ -0,0 +1,23 @@
package here
import "encoding/json"
type Module struct {
Path string `json:"Path"`
Main bool `json:"Main"`
Dir string `json:"Dir"`
GoMod string `json:"GoMod"`
GoVersion string `json:"GoVersion"`
}
func (i Module) String() string {
b, err := json.MarshalIndent(i, "", " ")
if err != nil {
return err.Error()
}
return string(b)
}
func (i Module) IsZero() bool {
return i.String() == Module{}.String()
}

25
here/pkg.go Normal file
View File

@ -0,0 +1,25 @@
package here
import "encoding/json"
// Package attempts to gather info for the requested package.
//
// From the `go help list` docs:
// The -find flag causes list to identify the named packages but not
// resolve their dependencies: the Imports and Deps lists will be empty.
//
// A workaround for this issue is to use the `Dir` field in the
// returned `Info` value and pass it to the `Dir(string) (Info, error)`
// function to return the complete data.
func Package(p string) (Info, error) {
var i Info
b, err := run("go", "list", "-json", "-find", p)
if err != nil {
return i, err
}
if err := json.Unmarshal(b, &i); err != nil {
return i, err
}
return i, nil
}

115
index.go
View File

@ -1,6 +1,7 @@
package pkger
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
@ -8,7 +9,8 @@ import (
"sync"
"time"
"github.com/gobuffalo/here"
"github.com/markbates/pkger/here"
"github.com/markbates/pkger/internal/debug"
)
type index struct {
@ -16,10 +18,16 @@ type index struct {
Infos *infosMap `json:"infos"`
Paths *pathsMap `json:"paths"`
Current here.Info `json:"current"`
once sync.Once
once *sync.Once
}
func (i *index) debug(key, format string, args ...interface{}) {
s := fmt.Sprintf(format, args...)
debug.Debug("[*index|%s|%s] %s", i.Current.ImportPath, key, s)
}
func (i *index) Parse(p string) (Path, error) {
i.debug("Parse", p)
pt, ok := i.Paths.Load(p)
if ok {
return pt, nil
@ -40,7 +48,6 @@ func (i *index) Parse(p string) (Path, error) {
}
return build(p, matches[1], matches[3])
return rootIndex.Parse(p)
}
func (i *index) Info(p string) (here.Info, error) {
@ -49,7 +56,7 @@ func (i *index) Info(p string) (here.Info, error) {
return info, nil
}
info, err := here.Cache(p, here.Package)
info, err := here.Package(p)
if err != nil {
return info, err
}
@ -58,13 +65,14 @@ func (i *index) Info(p string) (here.Info, error) {
}
func (i *index) Stat() (here.Info, error) {
var err error
i.once.Do(func() {
i.Current, _ = here.Cache("", func(string) (here.Info, error) {
return here.Current()
})
if i.Current.IsZero() {
i.Current, err = here.Current()
}
})
return i.Current, nil
return i.Current, err
}
func (i *index) Create(pt Path) (*File, error) {
@ -90,59 +98,43 @@ func (i *index) Create(pt Path) (*File, error) {
return f, nil
}
// 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)
// }
func (i *index) UnmarshalJSON(b []byte) error {
i.once = &sync.Once{}
m := map[string]json.RawMessage{}
// 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
// }
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
}
i.debug("UnmarshalJSON", "%v", i)
return nil
}
func (i index) Walk(pt Path, wf WalkFunc) error {
var err error
@ -193,6 +185,7 @@ func (i index) Walk(pt Path, wf WalkFunc) error {
}
func (i *index) Open(pt Path) (*File, error) {
i.debug("Open", pt.String())
f, ok := i.Files.Load(pt)
if !ok {
return i.openDisk(pt)
@ -208,6 +201,7 @@ func (i *index) Open(pt Path) (*File, error) {
}
func (i index) openDisk(pt Path) (*File, error) {
i.debug("openDisk", pt.String())
info, err := Info(pt.Pkg)
if err != nil {
return nil, err
@ -234,6 +228,7 @@ func newIndex() *index {
Files: &filesMap{},
Infos: &infosMap{},
Paths: &pathsMap{},
once: &sync.Once{},
}
}

View File

@ -106,3 +106,25 @@ func Test_index_JSON(t *testing.T) {
r.NoError(err)
r.Equal(f.data, f2.data)
}
func Test_index_Parse(t *testing.T) {
table := []struct {
in string
out string
}{
{in: "", out: curPkg + ":/"},
{in: curPkg, out: curPkg + ":/"},
// {in: curPkg + "/foo.go", out: curPkg + ":/foo.go"},
// {in: "/foo.go", out: curPkg + ":/foo.go"},
{in: "github.com/markbates/pkger/internal/examples/app", out: "github.com/markbates/pkger/internal/examples/app:/"},
}
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, pt.String())
})
}
}

View File

@ -1,4 +1,4 @@
// Code generated by github.com/gobuffalo/mapgen. DO NOT EDIT.
// Code generated by github.com/markbates/pkger/mapgen. DO NOT EDIT.
package pkger
@ -8,7 +8,7 @@ import (
"sort"
"sync"
"github.com/gobuffalo/here"
"github.com/markbates/pkger/here"
)
// infosMap wraps sync.Map and uses the following types:

9
internal/debug/debug.go Normal file
View File

@ -0,0 +1,9 @@
// +build debug
package debug
import "fmt"
func Debug(format string, a ...interface{}) {
fmt.Println("[PKGER]", fmt.Sprintf(format, a...))
}

View File

@ -1,5 +1,5 @@
// +build !debug
package pkger
package debug
func Debug(format string, a ...interface{}) {}

View File

@ -1,6 +1,6 @@
default:
cd ../../../cmd/pkger && go install -v .
cd ../../../cmd/pkger && go install -v -tags debug .
pkger
GOOS=linux go build -v -o example
GOOS=linux go build -v -tags debug -o example
docker build -t pkger:example .
docker run -p 3000:3000 pkger:example

View File

@ -2,6 +2,4 @@ module github.com/markbates/pkger/internal/examples/app
go 1.12
require github.com/markbates/pkger v0.0.0
replace github.com/markbates/pkger => ../../../
require github.com/markbates/pkger v0.0.0-20190803203656-a4a55a52dc5d

View File

@ -6,6 +6,8 @@ github.com/gobuffalo/here v0.2.2/go.mod h1:2a6G14FaAKOGJMK/5UNa4Og/+iyFS5cq3Mnlv
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/markbates/pkger v0.0.0-20190803203656-a4a55a52dc5d h1:uu7nHVFsVBjS7Uzv5Q9U7hA5cpsL3tmwOJ8KDDt9IMI=
github.com/markbates/pkger v0.0.0-20190803203656-a4a55a52dc5d/go.mod h1:2JPlcJvXSHDXTwhR0Fp7IvfGpSCRQ3WQpn4mn899KPw=
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=

View File

@ -17,18 +17,23 @@ func build(p, pkg, name string) (Path, error) {
Name: name,
}
info, err := Stat()
current, err := Stat()
if err != nil {
return pt, err
}
if strings.HasPrefix(pt.Pkg, "/") || len(pt.Pkg) == 0 {
pt.Name = pt.Pkg
pt.Pkg = info.ImportPath
pt.Pkg = current.ImportPath
}
if pt.Pkg == pt.Name || len(pt.Name) == 0 {
pt.Pkg = info.ImportPath
if len(pt.Name) == 0 {
pt.Name = "/"
}
if pt.Pkg == pt.Name {
pt.Pkg = current.ImportPath
pt.Name = "/"
}
if !strings.HasPrefix(pt.Name, "/") {

View File

@ -78,6 +78,12 @@ func Parse(name string) (Results, error) {
}
if info.IsDir() {
n := strings.TrimPrefix(name, her.Dir)
pt, err := pkger.Parse(n)
if err != nil {
return err
}
m[pt] = true
return nil
}

View File

@ -10,7 +10,7 @@ import (
func Test_Parser(t *testing.T) {
r := require.New(t)
res, err := Parse("/internal/app")
res, err := Parse("github.com/markbates/pkger/internal/examples/app")
r.NoError(err)

View File

@ -15,6 +15,7 @@ func Test_Path_String(t *testing.T) {
{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 {

View File

@ -60,8 +60,21 @@ 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() {
rootIndex.Files.Store(p, f)
f.Close()
continue
}
rootIndex.debug("Pack", "%s", p)
rootIndex.Files.Store(p, f)
f.Close()
}
if err := json.NewEncoder(gz).Encode(rootIndex); err != nil {
@ -71,6 +84,6 @@ func Pack(out io.Writer, paths []Path) error {
return err
}
s := hex.EncodeToString(bb.Bytes())
fmt.Fprint(out, s)
return nil
_, err := fmt.Fprint(out, s)
return err
}