From bad099075abf2e33eb8adce0c8453f7260bb19e2 Mon Sep 17 00:00:00 2001 From: Mark Bates Date: Thu, 19 Apr 2018 07:31:15 -0400 Subject: [PATCH] Allow the buffalo binary to use the version vendored with dep (#1023) * wip * Vendor the Buffalo Binary inside Applications fixes #986 * added some docs for code climate * log packing if in debug mode * fixed weird import * Update vbuffalo.go * fixed issue with gometalinter * adding some filetests to check the buffalo-version output (#1028) * adding some filetests to check the buffalo-version output * making it version independent * removing unneeded newline from broken filetest --- Dockerfile | 25 ++++++- buffalo/cmd/build/assets.go | 2 + buffalo/cmd/build/builder.go | 6 ++ buffalo/cmd/build/templates/main.go.tmpl | 3 +- buffalo/cmd/filetests/version-dep.json | 6 ++ buffalo/cmd/filetests/version-no-dep.json | 9 +++ buffalo/cmd/info.go | 7 ++ buffalo/cmd/new.go | 5 +- buffalo/main.go | 15 +++- generators/newapp/new.go | 25 ++++++- internal/vbuffalo/build.go | 40 ++++++++++ internal/vbuffalo/dep.go | 60 +++++++++++++++ internal/vbuffalo/vbuffalo.go | 90 +++++++++++++++++++++++ meta/app.go | 10 ++- 14 files changed, 292 insertions(+), 11 deletions(-) create mode 100644 buffalo/cmd/filetests/version-dep.json create mode 100644 buffalo/cmd/filetests/version-no-dep.json create mode 100644 internal/vbuffalo/build.go create mode 100644 internal/vbuffalo/dep.go create mode 100644 internal/vbuffalo/vbuffalo.go diff --git a/Dockerfile b/Dockerfile index 332098b96..dcc7531b4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,15 +4,19 @@ RUN buffalo version RUN go get -u github.com/alecthomas/gometalinter RUN gometalinter --install + RUN go get -v -u github.com/markbates/filetest + RUN go get -v -u github.com/gobuffalo/makr -RUN go get -v -u github.com/markbates/grift -RUN go get -v -u github.com/markbates/inflect -RUN go get -v -u github.com/markbates/refresh RUN go get -v -u github.com/gobuffalo/tags RUN go get -v -u github.com/gobuffalo/pop RUN go get -v -u github.com/mattn/go-sqlite3 +RUN go get -v -u github.com/markbates/grift +RUN go get -v -u github.com/markbates/inflect +RUN go get -v -u github.com/markbates/refresh +RUN go get -v -u github.com/markbates/willie + ENV BP=$GOPATH/src/github.com/gobuffalo/buffalo RUN rm $(which buffalo) @@ -22,7 +26,6 @@ WORKDIR $BP ADD . . RUN go get -v -t ./... - RUN go install -v -tags sqlite ./buffalo RUN go test -tags sqlite -race ./... @@ -123,3 +126,17 @@ RUN filetest -c $GOPATH/src/github.com/gobuffalo/buffalo/buffalo/cmd/filetests/g RUN rm -rf bin RUN buffalo build -k -e RUN filetest -c $GOPATH/src/github.com/gobuffalo/buffalo/buffalo/cmd/filetests/no_assets_build.json + +# Vendored buffalo version. +WORKDIR $GOPATH/src +RUN buffalo new app -f --api --with-dep +WORKDIR $GOPATH/src/app +RUN buffalo version > output.txt 2>&1 +RUN filetest -c $GOPATH/src/github.com/gobuffalo/buffalo/buffalo/cmd/filetests/version-dep.json + +# Non-Vendored buffalo version. +WORKDIR $GOPATH/src +RUN buffalo new app -f --api +WORKDIR $GOPATH/src/app +RUN buffalo version > output.txt 2>&1 +RUN filetest -c $GOPATH/src/github.com/gobuffalo/buffalo/buffalo/cmd/filetests/version-no-dep.json diff --git a/buffalo/cmd/build/assets.go b/buffalo/cmd/build/assets.go index 9984a88c4..b719fdcae 100644 --- a/buffalo/cmd/build/assets.go +++ b/buffalo/cmd/build/assets.go @@ -23,6 +23,8 @@ func (b *Builder) buildAssets() error { if !b.Options.WithAssets { p.IgnoredBoxes = append(p.IgnoredBoxes, "../public/assets") + } else { + p.IgnoredFolders = p.IgnoredFolders[1:] } if b.ExtractAssets && b.Options.WithAssets { diff --git a/buffalo/cmd/build/builder.go b/buffalo/cmd/build/builder.go index 2341bc995..29e26b565 100644 --- a/buffalo/cmd/build/builder.go +++ b/buffalo/cmd/build/builder.go @@ -47,6 +47,12 @@ func (b *Builder) Run() error { defer b.Cleanup() logrus.Debug(b.Options) + if b.Debug { + builder.DebugLog = func(m string, a ...interface{}) { + logrus.Debugf(m, a...) + } + } + for _, s := range b.steps { err := s() if err != nil { diff --git a/buffalo/cmd/build/templates/main.go.tmpl b/buffalo/cmd/build/templates/main.go.tmpl index 56af3c807..8964d1f0f 100644 --- a/buffalo/cmd/build/templates/main.go.tmpl +++ b/buffalo/cmd/build/templates/main.go.tmpl @@ -6,6 +6,7 @@ import ( "os" "github.com/markbates/grift/grift" + "github.com/gobuffalo/buffalo/buffalo/cmd" _ "<%= opts.PackagePkg %>/a" _ "<%= opts.ActionsPkg %>" <%= if (opts.WithPop) { %> @@ -47,7 +48,7 @@ func main() { log.Fatal(err) } default: - originalMain() + cmd.Execute() } } diff --git a/buffalo/cmd/filetests/version-dep.json b/buffalo/cmd/filetests/version-dep.json new file mode 100644 index 000000000..eb35d0e6c --- /dev/null +++ b/buffalo/cmd/filetests/version-dep.json @@ -0,0 +1,6 @@ +[{ + "path": "output.txt", + "contains": [ + "msg=\"Buffalo version is: v" + ] +}] \ No newline at end of file diff --git a/buffalo/cmd/filetests/version-no-dep.json b/buffalo/cmd/filetests/version-no-dep.json new file mode 100644 index 000000000..ce9698c44 --- /dev/null +++ b/buffalo/cmd/filetests/version-no-dep.json @@ -0,0 +1,9 @@ +[{ + "path": "output.txt", + "contains": [ + "msg=\"Buffalo version is: development" + ], + "!contains": [ + "msg=\"Buffalo version is: v" + ] +}] \ No newline at end of file diff --git a/buffalo/cmd/info.go b/buffalo/cmd/info.go index 9c4c52baf..27d06fbc5 100644 --- a/buffalo/cmd/info.go +++ b/buffalo/cmd/info.go @@ -71,6 +71,13 @@ func execIfExists(infoCmd infoCommand) error { bb := os.Stdout bb.WriteString(infoCmd.InfoLabel) + if infoCmd.Name == "dep" { + if _, err := os.Stat("Gopkg.toml"); err != nil { + bb.WriteString("could not find a Gopkg.toml file\n") + return nil + } + } + if _, err := exec.LookPath(infoCmd.PathName); err != nil { bb.WriteString(fmt.Sprintf("%s Not Found\n", infoCmd.Name)) return nil diff --git a/buffalo/cmd/new.go b/buffalo/cmd/new.go index 074ead63d..b1b1c0fb3 100644 --- a/buffalo/cmd/new.go +++ b/buffalo/cmd/new.go @@ -68,7 +68,10 @@ var newCmd = &cobra.Command{ app.WithWebpack = false } - if err := app.Run(app.Root, makr.Data{}); err != nil { + data := makr.Data{ + "version": Version, + } + if err := app.Run(app.Root, data); err != nil { return errors.WithStack(err) } diff --git a/buffalo/main.go b/buffalo/main.go index e011ef1fd..7b89cbf97 100644 --- a/buffalo/main.go +++ b/buffalo/main.go @@ -1,7 +1,18 @@ package main -import "github.com/gobuffalo/buffalo/buffalo/cmd" +import ( + "log" + + "github.com/gobuffalo/buffalo/buffalo/cmd" + "github.com/gobuffalo/buffalo/internal/vbuffalo" +) func main() { - cmd.Execute() + err := vbuffalo.Execute(func() error { + cmd.Execute() + return nil + }) + if err != nil { + log.Fatal(err) + } } diff --git a/generators/newapp/new.go b/generators/newapp/new.go index b21974549..f0d6307a8 100644 --- a/generators/newapp/new.go +++ b/generators/newapp/new.go @@ -37,6 +37,8 @@ func (a Generator) Run(root string, data makr.Data) error { } if a.WithDep { + data["addPrune"] = true + g.Add(makr.NewFile("Gopkg.toml", GopkgTomlTmpl)) if _, err := exec.LookPath("dep"); err != nil { g.Add(makr.NewCommand(makr.GoGet("github.com/golang/dep/cmd/dep", "-u"))) } @@ -199,7 +201,7 @@ func (a Generator) goGet() *exec.Cmd { os.Chdir(a.Root) if a.WithDep { if _, err := exec.LookPath("dep"); err == nil { - return exec.Command("dep", "init") + return exec.Command("dep", "ensure", "-v") } } appArgs := []string{"get", "-t"} @@ -361,3 +363,24 @@ public/assets/ .grifter/ .env ` + +// GopkgTomlTmpl is the default dep Gopkg.toml +const GopkgTomlTmpl = ` +{{ if .addPrune }} +[prune] + go-tests = true + unused-packages = true +{{ end }} + + # DO NOT DELETE + [[prune.project]] # buffalo + name = "github.com/gobuffalo/buffalo" + unused-packages = false + +{{ if .opts.WithPop }} + # DO NOT DELETE + [[prune.project]] # pop + name = "github.com/gobuffalo/pop" + unused-packages = false +{{ end }} +` diff --git a/internal/vbuffalo/build.go b/internal/vbuffalo/build.go new file mode 100644 index 000000000..e479e45cd --- /dev/null +++ b/internal/vbuffalo/build.go @@ -0,0 +1,40 @@ +package vbuffalo + +import ( + "os" + + "github.com/gobuffalo/buffalo/buffalo/cmd" + "github.com/gobuffalo/plush" + "github.com/pkg/errors" +) + +func writeMain() error { + f, err := os.Create(mainPath) + if err != nil { + return errors.WithStack(err) + } + defer f.Close() + s, err := plush.Render(mainTemplate, plush.NewContextWith(map[string]interface{}{ + "app": app, + "cmdPkg": cmdPkg, + "version": cmd.Version, + })) + if err != nil { + return errors.WithStack(err) + } + _, err = f.WriteString(s) + return err +} + +const mainTemplate = `package main + +import ( + "fmt" + "<%= cmdPkg %>" +) + +func main() { + fmt.Printf("%s [<%= version %>]\n\n", cmd.Version) + cmd.Execute() +} +` diff --git a/internal/vbuffalo/dep.go b/internal/vbuffalo/dep.go new file mode 100644 index 000000000..c9ff79e5e --- /dev/null +++ b/internal/vbuffalo/dep.go @@ -0,0 +1,60 @@ +package vbuffalo + +import ( + "bytes" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + + "html/template" + + "github.com/gobuffalo/buffalo/generators/newapp" + "github.com/pkg/errors" +) + +func depEnsure() error { + toml := filepath.Join(pwd, "Gopkg.toml") + b, err := ioutil.ReadFile(toml) + if err != nil { + return errors.WithStack(err) + } + + addPrune := !bytes.Contains(b, []byte("[prune]")) + + make := func() error { + f, err := os.Create(toml) + if err != nil { + return errors.WithStack(err) + } + defer f.Close() + f.Write(b) + + t, err := template.New("toml template").Parse(newapp.GopkgTomlTmpl) + if err != nil { + return errors.WithStack(err) + } + + err = t.Execute(f, map[string]interface{}{ + "opts": app, + "addPrune": addPrune, + }) + if err != nil { + return errors.WithStack(err) + } + + return run(exec.Command("dep", "ensure", "-v")) + } + + if addPrune { + if err := make(); err != nil { + return errors.WithStack(err) + } + } + if !bytes.Contains(b, []byte("[[prune.project]] # buffalo")) { + if err := make(); err != nil { + return errors.WithStack(err) + } + } + return nil +} diff --git a/internal/vbuffalo/vbuffalo.go b/internal/vbuffalo/vbuffalo.go new file mode 100644 index 000000000..90187a7a6 --- /dev/null +++ b/internal/vbuffalo/vbuffalo.go @@ -0,0 +1,90 @@ +package vbuffalo + +import ( + "os" + "os/exec" + "path/filepath" + "runtime" + + "github.com/gobuffalo/buffalo/meta" + "github.com/pkg/errors" +) + +const cmdPkg = "github.com/gobuffalo/buffalo/buffalo/cmd" + +var pwd, _ = os.Getwd() +var mainPath = filepath.Join(pwd, ".grifter", "main.go") +var binPath = filepath.Join(pwd, "bin", "vbuffalo") +var app meta.App + +func init() { + if runtime.GOOS == "windows" { + binPath += ".exe" + } +} + +// Execute using vbuffalo. If this doesn't meet the vbuffalo +// requirements then it should use the passed in function instead. +func Execute(ex func() error) error { + if !exists(".buffalo.dev.yml") { + return ex() + } + app = meta.New(".") + // not using dep or there isn't a vendor folder + if !app.WithDep || !exists("vendor") { + return ex() + } + return execute() +} + +func execute() error { + dir := filepath.Dir(mainPath) + err := os.MkdirAll(dir, 0755) + if err != nil { + return errors.WithStack(err) + } + defer os.RemoveAll(dir) + + if err := depEnsure(); err != nil { + return errors.WithStack(err) + } + + if err = writeMain(); err != nil { + return errors.WithStack(err) + } + + err = cd(filepath.Dir(mainPath), func() error { + args := []string{"build", "-v"} + if app.WithSQLite { + args = append(args, "--tags", "sqlite") + } + args = append(args, "-o", binPath) + cmd := exec.Command("go", args...) + return run(cmd) + }) + if err != nil { + return errors.WithStack(err) + } + + cmd := exec.Command(binPath, os.Args[1:]...) + return run(cmd) +} + +func cd(dir string, fn func() error) error { + defer os.Chdir(pwd) + os.Chdir(dir) + return fn() +} + +func run(cmd *exec.Cmd) error { + // fmt.Println(strings.Join(cmd.Args, " ")) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} + +func exists(f string) bool { + _, err := os.Stat(f) + return err == nil +} diff --git a/meta/app.go b/meta/app.go index d68893037..9b9d1f93b 100644 --- a/meta/app.go +++ b/meta/app.go @@ -1,7 +1,9 @@ package meta import ( + "bytes" "encoding/json" + "io/ioutil" "os" "path" "path/filepath" @@ -24,6 +26,7 @@ type App struct { GriftsPkg string `json:"grifts_path"` VCS string `json:"vcs"` WithPop bool `json:"with_pop"` + WithSQLite bool `json:"with_sqlite"` WithDep bool `json:"with_dep"` WithWebpack bool `json:"with_webpack"` WithYarn bool `json:"with_yarn"` @@ -78,9 +81,12 @@ func New(root string) App { if runtime.GOOS == "windows" { app.Bin += ".exe" } - - if _, err := os.Stat(filepath.Join(root, "database.yml")); err == nil { + db := filepath.Join(root, "database.yml") + if _, err := os.Stat(db); err == nil { app.WithPop = true + if b, err := ioutil.ReadFile(db); err == nil { + app.WithSQLite = bytes.Contains(bytes.ToLower(b), []byte("sqlite")) + } } if _, err := os.Stat(filepath.Join(root, "Gopkg.toml")); err == nil { app.WithDep = true