diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 90552ef45..37a212520 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,7 +21,7 @@ Please take moment and read this fantastic post on how to easily work with Go re ## Documentation Welcome -Hands down the most important, and the most welcome, pull requests are for documentation. We LOVE documentation PRs, and so don't all those that come after you. +Hands down the most important, and the most welcome, pull requests are for documentation. We LOVE documentation PRs, and so do all those that come after you. Whether it's GoDoc or prose on [http://gobuffalo.io](http://gobuffalo.io) all documentation is welcome. diff --git a/Dockerfile b/Dockerfile index 6e609e6f7..2e5f9910a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,7 +26,7 @@ ADD . . RUN go get -v -t ./... RUN make install -RUN go test -tags sqlite -race ./... +RUN go test -tags sqlite -race ./... RUN go test -tags sqlite -coverprofile cover.out -covermode count ./... RUN if [ -z "$CODECOV_TOKEN" ] ; then \ @@ -39,6 +39,22 @@ RUN gometalinter --install RUN gometalinter --vendor --deadline=5m ./... --skip=internal WORKDIR $GOPATH/src/ + +# START: tests bins are built with tags properly +RUN mkdir -p $GOPATH/src/github.com/markbates +WORKDIR $GOPATH/src/github.com/markbates +RUN buffalo new --skip-webpack coke --db-type=sqlite3 +WORKDIR $GOPATH/src/github.com/markbates/coke +RUN buffalo db create -a -d +RUN buffalo g resource widget name +RUN buffalo b -d +# works fine: +RUN ./bin/coke migrate +RUN rm -rfv $GOPATH/src/github.com/markbates/coke +# :END + +WORKDIR $GOPATH/src/ + RUN buffalo new --db-type=sqlite3 hello_world --ci-provider=travis WORKDIR ./hello_world diff --git a/Dockerfile.build b/Dockerfile.build index d85ef86ab..ab9720687 100644 --- a/Dockerfile.build +++ b/Dockerfile.build @@ -1,58 +1,50 @@ FROM golang:latest - -RUN go version -RUN go get -v -u github.com/markbates/deplist/deplist - -RUN apt-get update -RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -RUN apt-get install -y build-essential nodejs -RUN apt-get install -y sqlite3 libsqlite3-dev -RUN sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" >> /etc/apt/sources.list.d/pgdg.list' -RUN wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O - | apt-key add - -RUN apt-get install -y postgresql postgresql-contrib libpq-dev -RUN apt-get install -y -q mysql-client -RUN apt-get install -y vim - -RUN go get -u github.com/golang/dep/cmd/dep -RUN go get -v -u github.com/gobuffalo/makr -RUN go get -v -u github.com/gobuffalo/packr -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/gobuffalo/x/... -RUN go get -v -u github.com/mattn/go-sqlite3 -RUN go get -v -u github.com/markbates/filetest -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 -RUN go get -v -u github.com/gorilla/sessions -RUN go get -v -u golang.org/x/vgo -RUN go get -u github.com/alecthomas/gometalinter -RUN gometalinter --install - -RUN npm install -g --no-progress yarn -RUN yarn config set yarn-offline-mirror /npm-packages-offline-cache -RUN yarn config set yarn-offline-mirror-pruning true - +EXPOSE 3000 ENV BP=$GOPATH/src/github.com/gobuffalo/buffalo - -RUN rm -rfv $BP -RUN mkdir -p $BP +RUN go version && go get -v -u github.com/markbates/deplist/deplist + +RUN curl -sL https://deb.nodesource.com/setup_8.x | bash \ +&& sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" >> /etc/apt/sources.list.d/pgdg.list' \ +&& wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O - | apt-key add - \ +&& apt-get update \ +&& apt-get install -y -q build-essential nodejs sqlite3 libsqlite3-dev postgresql postgresql-contrib libpq-dev mysql-client vim \ +&& rm -rf /var/lib/apt/lists/* + + +RUN go get -u github.com/golang/dep/cmd/dep \ +&& go get -v -u github.com/gobuffalo/makr \ +&& go get -v -u github.com/gobuffalo/packr \ +&& go get -v -u github.com/gobuffalo/tags \ +&& go get -v -u github.com/gobuffalo/pop \ +&& go get -v -u github.com/gobuffalo/x/... \ +&& go get -v -u github.com/mattn/go-sqlite3 \ +&& go get -v -u github.com/markbates/filetest \ +&& go get -v -u github.com/markbates/grift \ +&& go get -v -u github.com/markbates/inflect \ +&& go get -v -u github.com/markbates/refresh \ +&& go get -v -u github.com/markbates/willie \ +&& go get -v -u github.com/gorilla/sessions \ +&& go get -v -u golang.org/x/vgo \ +&& go get -u github.com/alecthomas/gometalinter \ +&& gometalinter --install + +RUN npm install -g --no-progress yarn \ +&& yarn config set yarn-offline-mirror /npm-packages-offline-cache \ +&& yarn config set yarn-offline-mirror-pruning true + + +RUN rm -rfv $BP && mkdir -p $BP WORKDIR $BP ADD . . -RUN go get -tags "sqlite" -v -t github.com/gobuffalo/buffalo/... -RUN make install - +RUN go get -tags "sqlite" -v -t github.com/gobuffalo/buffalo/... && make install # cache yarn packages to an offline mirror so they're faster to load. hopefully. -RUN grep -v '{{' ./generators/assets/webpack/templates/package.json.tmpl > package.json -RUN yarn install --no-progress +RUN grep -v '{{' ./generators/assets/webpack/templates/package.json.tmpl > package.json \ +&& yarn install --no-progress RUN buffalo version WORKDIR $GOPATH/src RUN ls -la /npm-packages-offline-cache - -EXPOSE 3000 diff --git a/Dockerfile.slim.build b/Dockerfile.slim.build new file mode 100644 index 000000000..9db682a34 --- /dev/null +++ b/Dockerfile.slim.build @@ -0,0 +1,46 @@ +FROM golang:alpine +EXPOSE 3000 +ENV BP=$GOPATH/src/github.com/gobuffalo/buffalo +RUN apk add --no-cache --upgrade apk-tools \ +&& apk add --no-cache bash curl openssl git build-base yarn nodejs postgresql libpq postgresql-contrib sqlite sqlite-dev mysql-client vim + +RUN go version && go get -v -u github.com/markbates/deplist/deplist + + +RUN go get -u github.com/golang/dep/cmd/dep \ +&& go get -v -u github.com/gobuffalo/makr \ +&& go get -v -u github.com/gobuffalo/packr \ +&& go get -v -u github.com/gobuffalo/tags \ +&& go get -v -u github.com/gobuffalo/pop \ +&& go get -v -u github.com/gobuffalo/x/... \ +&& go get -v -u github.com/mattn/go-sqlite3 \ +&& go get -v -u github.com/markbates/filetest \ +&& go get -v -u github.com/markbates/grift \ +&& go get -v -u github.com/markbates/inflect \ +&& go get -v -u github.com/markbates/refresh \ +&& go get -v -u github.com/markbates/willie \ +&& go get -v -u github.com/gorilla/sessions \ +&& go get -v -u golang.org/x/vgo \ +&& go get -u github.com/alecthomas/gometalinter \ +&& gometalinter --install + +RUN npm install -g --no-progress yarn \ +&& yarn config set yarn-offline-mirror /npm-packages-offline-cache \ +&& yarn config set yarn-offline-mirror-pruning true + + +RUN rm -rfv $BP && mkdir -p $BP +WORKDIR $BP + +ADD . . +RUN go get -tags "sqlite" -v -t github.com/gobuffalo/buffalo/... && make install + +# cache yarn packages to an offline mirror so they're faster to load. hopefully. +RUN grep -v '{{' ./generators/assets/webpack/templates/package.json.tmpl > package.json \ +&& yarn install --no-progress + +RUN buffalo version + +WORKDIR $GOPATH/src + +RUN ls -la /npm-packages-offline-cache diff --git a/README.md b/README.md index fccdca51b..509c8c450 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -
+diff --git a/SHOULDERS.md b/SHOULDERS.md index 8efd9dcb8..f0742deef 100644 --- a/SHOULDERS.md +++ b/SHOULDERS.md @@ -166,7 +166,5 @@ Thank you to the following **GIANTS**: * [github.com/spf13/pflag](https://godoc.org/github.com/spf13/pflag) -* [github.com/unrolled/secure](https://godoc.org/github.com/unrolled/secure) - * [golang.org/x/tools/cmd/goimports](https://godoc.org/golang.org/x/tools/cmd/goimports) diff --git a/buffalo/cmd/new.go b/buffalo/cmd/new.go index faa32401e..4a7e28ed7 100644 --- a/buffalo/cmd/new.go +++ b/buffalo/cmd/new.go @@ -152,7 +152,7 @@ func init() { newCmd.Flags().String("docker", "multi", "specify the type of Docker file to generate [none, multi, standard]") newCmd.Flags().String("ci-provider", "none", "specify the type of ci file you would like buffalo to generate [none, travis, gitlab-ci]") newCmd.Flags().String("vcs", "git", "specify the Version control system you would like to use [none, git, bzr]") - newCmd.Flags().Int("bootstrap", 3, "specify version for Bootstrap [3, 4]") + newCmd.Flags().Int("bootstrap", 4, "specify version for Bootstrap [3, 4]") viper.BindPFlags(newCmd.Flags()) cfgFile := newCmd.PersistentFlags().String("config", "", "config file (default is $HOME/.buffalo.yaml)") skipConfig := newCmd.Flags().Bool("skip-config", false, "skips using the config file") diff --git a/buffalo/cmd/new_test.go b/buffalo/cmd/new_test.go new file mode 100644 index 000000000..1896acc0d --- /dev/null +++ b/buffalo/cmd/new_test.go @@ -0,0 +1,14 @@ +package cmd + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_Bootstrap4_Default(t *testing.T) { + r := require.New(t) + f, err := newCmd.Flags().GetInt("bootstrap") + r.NoError(err) + r.Equal(4, f) +} diff --git a/handler.go b/handler.go index 4ff9c5099..190a03b34 100644 --- a/handler.go +++ b/handler.go @@ -75,11 +75,10 @@ func (info RouteInfo) ServeHTTP(res http.ResponseWriter, req *http.Request) { c := a.newContext(info, res, req) - defer c.Flash().persist(c.Session()) - err := a.Middleware.handler(info)(c) if err != nil { + c.Flash().persist(c.Session()) status := 500 // unpack root cause and check for HTTPError cause := errors.Cause(err) diff --git a/meta/tags.go b/meta/tags.go index 19dcf4c62..b7e2524ee 100644 --- a/meta/tags.go +++ b/meta/tags.go @@ -12,7 +12,7 @@ type BuildTags []string // String returns the tags in the form of: // "foo bar baz" (with the quotes!) func (t BuildTags) String() string { - return `"` + strings.Join(t, " ") + `"` + return strings.Join(t, " ") } // BuildTags combines the passed in env, and any additional tags, diff --git a/meta/tags_test.go b/meta/tags_test.go index 87f5042d6..efdcbdead 100644 --- a/meta/tags_test.go +++ b/meta/tags_test.go @@ -15,7 +15,7 @@ func Test_BuildTags(t *testing.T) { tags := app.BuildTags("dev") r.Len(tags, 1) r.Equal("dev", tags[0]) - r.Equal(`"dev"`, tags.String()) + r.Equal(`dev`, tags.String()) }) t.Run("with database.yml", func(st *testing.T) { t.Run("with sqlite", func(st *testing.T) { @@ -29,7 +29,7 @@ func Test_BuildTags(t *testing.T) { r.Len(tags, 2) r.Equal("dev", tags[0]) r.Equal("sqlite", tags[1]) - r.Equal(`"dev sqlite"`, tags.String()) + r.Equal(`dev sqlite`, tags.String()) }) t.Run("without sqlite", func(st *testing.T) { r := require.New(st) @@ -41,7 +41,7 @@ func Test_BuildTags(t *testing.T) { tags := app.BuildTags("dev") r.Len(tags, 1) r.Equal("dev", tags[0]) - r.Equal(`"dev"`, tags.String()) + r.Equal(`dev`, tags.String()) }) }) } diff --git a/plugins/plugins.go b/plugins/plugins.go index 47aa5918a..eeb4cdc8c 100644 --- a/plugins/plugins.go +++ b/plugins/plugins.go @@ -31,6 +31,12 @@ type List map[string]Commands // plugins.Commands{} // // Limit full path scan with direct plugin path +// +// If a file/command doesn't respond to being invoked with `available` +// within one second, buffalo will assume that it is unable to load. This +// can be changed by setting the $BUFFALO_PLUGIN_TIMEOUT environment +// variable. It must be set to a duration that `time.ParseDuration` can +// process. func Available() (List, error) { list := List{} paths := []string{"plugins"} @@ -44,6 +50,19 @@ func Available() (List, error) { from = filepath.Join(from, "bin") } + const timeoutEnv = "BUFFALO_PLUGIN_TIMEOUT" + timeout := time.Second + rawTimeout, err := envy.MustGet(timeoutEnv) + if err == nil { + if parsed, err := time.ParseDuration(rawTimeout); err == nil { + timeout = parsed + } else { + logrus.Errorf("%q value is malformed assuming default %q: %v", timeoutEnv, timeout, err) + } + } else { + logrus.Debugf("%q not set, assuming default of %v", timeoutEnv, timeout) + } + if runtime.GOOS == "windows" { paths = append(paths, strings.Split(from, ";")...) } else { @@ -67,7 +86,9 @@ func Available() (List, error) { } base := filepath.Base(path) if strings.HasPrefix(base, "buffalo-") { - commands := askBin(path) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + commands := askBin(ctx, path) + cancel() for _, c := range commands { bc := c.BuffaloCommand if _, ok := list[bc]; !ok { @@ -86,10 +107,9 @@ func Available() (List, error) { return list, nil } -func askBin(path string) Commands { +func askBin(ctx context.Context, path string) Commands { commands := Commands{} - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() + cmd := exec.CommandContext(ctx, path, "available") bb := &bytes.Buffer{} cmd.Stdout = bb diff --git a/plugins/plugins_test.go b/plugins/plugins_test.go new file mode 100644 index 000000000..9f81497b2 --- /dev/null +++ b/plugins/plugins_test.go @@ -0,0 +1,57 @@ +package plugins + +import ( + "context" + "io/ioutil" + "strings" + "testing" + "time" + + "github.com/gobuffalo/envy" + "github.com/stretchr/testify/require" +) + +func TestAskBin_respectsTimeout(t *testing.T) { + r := require.New(t) + + from, err := envy.MustGet("BUFFALO_PLUGIN_PATH") + if err != nil { + t.Skipf("BUFFALO_PLUGIN_PATH not set.") + return + } + + if fileEntries, err := ioutil.ReadDir(from); err == nil { + found := false + for _, e := range fileEntries { + if strings.HasPrefix(e.Name(), "buffalo-") { + from = e.Name() + found = true + break + } + } + if !found { + t.Skipf("no plugins found") + return + } + } else { + r.Error(err, "plugin path not able to be read") + return + } + + const tooShort = time.Millisecond + impossible, cancel := context.WithTimeout(context.Background(), tooShort) + defer cancel() + + done := make(chan struct{}) + go func() { + askBin(impossible, from) + close(done) + }() + + select { + case <-time.After(tooShort + 80*time.Millisecond): + r.Fail("did not time-out quickly enough") + case <-done: + t.Log("timed-out successfully") + } +} diff --git a/render/helpers.go b/render/helpers.go index 95f6c2648..276a804ff 100644 --- a/render/helpers.go +++ b/render/helpers.go @@ -5,13 +5,12 @@ import ( "net/http" "github.com/gobuffalo/plush" - "github.com/gobuffalo/pop" "github.com/gobuffalo/tags" "github.com/pkg/errors" ) func init() { - plush.Helpers.Add("paginator", func(pagination *pop.Paginator, opts map[string]interface{}, help plush.HelperContext) (template.HTML, error) { + plush.Helpers.Add("paginator", func(pagination interface{}, opts map[string]interface{}, help plush.HelperContext) (template.HTML, error) { if opts["path"] == nil { if req, ok := help.Value("request").(*http.Request); ok { opts["path"] = req.URL.String() diff --git a/render/template_helpers.go b/render/template_helpers.go index 4346e0d0b..d41957b8a 100644 --- a/render/template_helpers.go +++ b/render/template_helpers.go @@ -10,7 +10,7 @@ import ( "github.com/pkg/errors" ) -var assetsMutex = &sync.Mutex{} +var assetsMutex = &sync.RWMutex{} var assetMap map[string]string func loadManifest(manifest string) error { @@ -22,10 +22,9 @@ func loadManifest(manifest string) error { } func assetPathFor(file string) string { - assetsMutex.Lock() - defer assetsMutex.Unlock() - + assetsMutex.RLock() filePath := assetMap[file] + assetsMutex.RUnlock() if filePath == "" { filePath = file } diff --git a/runtime/version.go b/runtime/version.go index e68e7b739..4e38a9e07 100644 --- a/runtime/version.go +++ b/runtime/version.go @@ -1,5 +1,7 @@ package runtime // Version is the current version of the buffalo binary -// const Version = "v0.12.2" +// const Version = "v0.12.3" + +// Version is the current version of the buffalo binary const Version = "development"