Makefile: Set GO111MODULE=on for consistency, adjust tests accordingly
This commit is contained in:
parent
b51d53e11e
commit
9ce337296b
@ -4,9 +4,6 @@ go:
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
|
||||
before_script:
|
||||
- go get github.com/valyala/quicktemplate
|
||||
|
||||
script: make check_generated test
|
||||
|
||||
after_success:
|
||||
|
8
Makefile
8
Makefile
@ -1,3 +1,5 @@
|
||||
export GO111MODULE = on
|
||||
|
||||
test: build
|
||||
GL_TEST_RUN=1 ./golangci-lint run -v
|
||||
GL_TEST_RUN=1 ./golangci-lint run --fast --no-config -v --skip-dirs 'test/testdata_etc,pkg/golinters/goanalysis/(checker|passes)'
|
||||
@ -32,9 +34,9 @@ release:
|
||||
curl -sL https://git.io/goreleaser | bash
|
||||
|
||||
update_deps:
|
||||
GO111MODULE=on go mod verify
|
||||
GO111MODULE=on go mod tidy
|
||||
go mod verify
|
||||
go mod tidy
|
||||
rm -rf vendor
|
||||
GO111MODULE=on go mod vendor
|
||||
go mod vendor
|
||||
|
||||
.PHONY: test
|
||||
|
1
go.mod
1
go.mod
@ -49,6 +49,7 @@ require (
|
||||
github.com/spf13/pflag v1.0.1
|
||||
github.com/spf13/viper v1.0.2
|
||||
github.com/stretchr/testify v1.2.2
|
||||
github.com/valyala/quicktemplate v1.1.1
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a // indirect
|
||||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977 // indirect
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313 // indirect
|
||||
|
11
go.sum
11
go.sum
@ -86,6 +86,10 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
|
||||
github.com/kisielk/gotool v0.0.0-20161130080628-0de1eaf82fa3/go.mod h1:jxZFDH7ILpTPQTk+E2s+z4CUas9lVNjIuKR4c5/zKgM=
|
||||
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
@ -150,12 +154,19 @@ github.com/spf13/viper v1.0.2 h1:Ncr3ZIuJn322w2k1qmzXDnkLAdQMlJqBa9kfAH+irso=
|
||||
github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
|
||||
github.com/valyala/quicktemplate v1.1.1 h1:C58y/wN0FMTi2PR0n3onltemfFabany53j7M6SDDB8k=
|
||||
github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a h1:YX8ljsm6wXlHZO+aRz9Exqr0evNhKRNe5K/gi+zKh4U=
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977 h1:actzWV6iWn3GLqN8dZjzsB+CLt+gaV2+wsxroxiQI8I=
|
||||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
|
@ -53,18 +53,18 @@ func buildTemplateContext() (map[string]interface{}, error) {
|
||||
return nil, fmt.Errorf("can't read .golangci.example.yml: %s", err)
|
||||
}
|
||||
|
||||
if err = exec.Command("go", "install", "./cmd/...").Run(); err != nil {
|
||||
if err = exec.Command("make", "build").Run(); err != nil {
|
||||
return nil, fmt.Errorf("can't run go install: %s", err)
|
||||
}
|
||||
|
||||
lintersOut, err := exec.Command("golangci-lint", "help", "linters").Output()
|
||||
lintersOut, err := exec.Command("./golangci-lint", "help", "linters").Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't run linters cmd: %s", err)
|
||||
}
|
||||
|
||||
lintersOutParts := bytes.Split(lintersOut, []byte("\n\n"))
|
||||
|
||||
helpCmd := exec.Command("golangci-lint", "run", "-h")
|
||||
helpCmd := exec.Command("./golangci-lint", "run", "-h")
|
||||
helpCmd.Env = append(helpCmd.Env, os.Environ()...)
|
||||
helpCmd.Env = append(helpCmd.Env, "HELP_RUN=1") // make default concurrency stable: don't depend on machine CPU number
|
||||
help, err := helpCmd.Output()
|
||||
|
@ -3,7 +3,7 @@ package test
|
||||
import "path/filepath"
|
||||
|
||||
const testdataDir = "testdata"
|
||||
const binName = "golangci-lint"
|
||||
const binName = "../golangci-lint"
|
||||
|
||||
func getProjectRoot() string {
|
||||
return filepath.Join("..", "...")
|
||||
|
@ -10,6 +10,8 @@ import (
|
||||
"github.com/golangci/golangci-lint/test/testshared"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/exitcodes"
|
||||
|
||||
_ "github.com/valyala/quicktemplate"
|
||||
)
|
||||
|
||||
func getCommonRunArgs() []string {
|
||||
@ -25,13 +27,13 @@ func TestAutogeneratedNoIssues(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEmptyDirRun(t *testing.T) {
|
||||
testshared.NewLintRunner(t).Run(getTestDataDir("nogofiles")).
|
||||
testshared.NewLintRunner(t, "GO111MODULE=off").Run(getTestDataDir("nogofiles")).
|
||||
ExpectExitCode(exitcodes.NoGoFiles).
|
||||
ExpectOutputContains(": no go files to analyze")
|
||||
}
|
||||
|
||||
func TestNotExistingDirRun(t *testing.T) {
|
||||
testshared.NewLintRunner(t).Run(getTestDataDir("no_such_dir")).
|
||||
testshared.NewLintRunner(t, "GO111MODULE=off").Run(getTestDataDir("no_such_dir")).
|
||||
ExpectExitCode(exitcodes.Failure).
|
||||
ExpectOutputContains(`cannot find package \"./testdata/no_such_dir\"`)
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
@ -17,27 +16,26 @@ import (
|
||||
type LintRunner struct {
|
||||
t assert.TestingT
|
||||
log logutils.Log
|
||||
|
||||
installed bool
|
||||
env []string
|
||||
}
|
||||
|
||||
func NewLintRunner(t assert.TestingT) *LintRunner {
|
||||
func NewLintRunner(t assert.TestingT, environ ...string) *LintRunner {
|
||||
log := logutils.NewStderrLog("test")
|
||||
log.SetLevel(logutils.LogLevelInfo)
|
||||
return &LintRunner{
|
||||
t: t,
|
||||
log: log,
|
||||
env: environ,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *LintRunner) Install() {
|
||||
if r.installed {
|
||||
if _, err := os.Stat("../golangci-lint"); err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
cmd := exec.Command("go", "install", filepath.Join("..", "cmd", "golangci-lint"))
|
||||
cmd := exec.Command("make", "-C", "..", "build")
|
||||
assert.NoError(r.t, cmd.Run(), "Can't go install golangci-lint")
|
||||
r.installed = true
|
||||
}
|
||||
|
||||
type RunResult struct {
|
||||
@ -82,7 +80,8 @@ func (r *LintRunner) Run(args ...string) *RunResult {
|
||||
|
||||
runArgs := append([]string{"run"}, args...)
|
||||
r.log.Infof("golangci-lint %s", strings.Join(runArgs, " "))
|
||||
cmd := exec.Command("golangci-lint", runArgs...)
|
||||
cmd := exec.Command("../golangci-lint", runArgs...)
|
||||
cmd.Env = append(os.Environ(), r.env...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
if exitError, ok := err.(*exec.ExitError); ok {
|
||||
|
15
vendor/github.com/valyala/bytebufferpool/.travis.yml
generated
vendored
Normal file
15
vendor/github.com/valyala/bytebufferpool/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.6
|
||||
|
||||
script:
|
||||
# build test for supported platforms
|
||||
- GOOS=linux go build
|
||||
- GOOS=darwin go build
|
||||
- GOOS=freebsd go build
|
||||
- GOOS=windows go build
|
||||
- GOARCH=386 go build
|
||||
|
||||
# run tests on a standard platform
|
||||
- go test -v ./...
|
22
vendor/github.com/valyala/bytebufferpool/LICENSE
generated
vendored
Normal file
22
vendor/github.com/valyala/bytebufferpool/LICENSE
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Aliaksandr Valialkin, VertaMedia
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
21
vendor/github.com/valyala/bytebufferpool/README.md
generated
vendored
Normal file
21
vendor/github.com/valyala/bytebufferpool/README.md
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
[](https://travis-ci.org/valyala/bytebufferpool)
|
||||
[](http://godoc.org/github.com/valyala/bytebufferpool)
|
||||
[](http://goreportcard.com/report/valyala/bytebufferpool)
|
||||
|
||||
# bytebufferpool
|
||||
|
||||
An implementation of a pool of byte buffers with anti-memory-waste protection.
|
||||
|
||||
The pool may waste limited amount of memory due to fragmentation.
|
||||
This amount equals to the maximum total size of the byte buffers
|
||||
in concurrent use.
|
||||
|
||||
# Benchmark results
|
||||
Currently bytebufferpool is fastest and most effective buffer pool written in Go.
|
||||
|
||||
You can find results [here](https://omgnull.github.io/go-benchmark/buffer/).
|
||||
|
||||
# bytebufferpool users
|
||||
|
||||
* [fasthttp](https://github.com/valyala/fasthttp)
|
||||
* [quicktemplate](https://github.com/valyala/quicktemplate)
|
111
vendor/github.com/valyala/bytebufferpool/bytebuffer.go
generated
vendored
Normal file
111
vendor/github.com/valyala/bytebufferpool/bytebuffer.go
generated
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
package bytebufferpool
|
||||
|
||||
import "io"
|
||||
|
||||
// ByteBuffer provides byte buffer, which can be used for minimizing
|
||||
// memory allocations.
|
||||
//
|
||||
// ByteBuffer may be used with functions appending data to the given []byte
|
||||
// slice. See example code for details.
|
||||
//
|
||||
// Use Get for obtaining an empty byte buffer.
|
||||
type ByteBuffer struct {
|
||||
|
||||
// B is a byte buffer to use in append-like workloads.
|
||||
// See example code for details.
|
||||
B []byte
|
||||
}
|
||||
|
||||
// Len returns the size of the byte buffer.
|
||||
func (b *ByteBuffer) Len() int {
|
||||
return len(b.B)
|
||||
}
|
||||
|
||||
// ReadFrom implements io.ReaderFrom.
|
||||
//
|
||||
// The function appends all the data read from r to b.
|
||||
func (b *ByteBuffer) ReadFrom(r io.Reader) (int64, error) {
|
||||
p := b.B
|
||||
nStart := int64(len(p))
|
||||
nMax := int64(cap(p))
|
||||
n := nStart
|
||||
if nMax == 0 {
|
||||
nMax = 64
|
||||
p = make([]byte, nMax)
|
||||
} else {
|
||||
p = p[:nMax]
|
||||
}
|
||||
for {
|
||||
if n == nMax {
|
||||
nMax *= 2
|
||||
bNew := make([]byte, nMax)
|
||||
copy(bNew, p)
|
||||
p = bNew
|
||||
}
|
||||
nn, err := r.Read(p[n:])
|
||||
n += int64(nn)
|
||||
if err != nil {
|
||||
b.B = p[:n]
|
||||
n -= nStart
|
||||
if err == io.EOF {
|
||||
return n, nil
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WriteTo implements io.WriterTo.
|
||||
func (b *ByteBuffer) WriteTo(w io.Writer) (int64, error) {
|
||||
n, err := w.Write(b.B)
|
||||
return int64(n), err
|
||||
}
|
||||
|
||||
// Bytes returns b.B, i.e. all the bytes accumulated in the buffer.
|
||||
//
|
||||
// The purpose of this function is bytes.Buffer compatibility.
|
||||
func (b *ByteBuffer) Bytes() []byte {
|
||||
return b.B
|
||||
}
|
||||
|
||||
// Write implements io.Writer - it appends p to ByteBuffer.B
|
||||
func (b *ByteBuffer) Write(p []byte) (int, error) {
|
||||
b.B = append(b.B, p...)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// WriteByte appends the byte c to the buffer.
|
||||
//
|
||||
// The purpose of this function is bytes.Buffer compatibility.
|
||||
//
|
||||
// The function always returns nil.
|
||||
func (b *ByteBuffer) WriteByte(c byte) error {
|
||||
b.B = append(b.B, c)
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteString appends s to ByteBuffer.B.
|
||||
func (b *ByteBuffer) WriteString(s string) (int, error) {
|
||||
b.B = append(b.B, s...)
|
||||
return len(s), nil
|
||||
}
|
||||
|
||||
// Set sets ByteBuffer.B to p.
|
||||
func (b *ByteBuffer) Set(p []byte) {
|
||||
b.B = append(b.B[:0], p...)
|
||||
}
|
||||
|
||||
// SetString sets ByteBuffer.B to s.
|
||||
func (b *ByteBuffer) SetString(s string) {
|
||||
b.B = append(b.B[:0], s...)
|
||||
}
|
||||
|
||||
// String returns string representation of ByteBuffer.B.
|
||||
func (b *ByteBuffer) String() string {
|
||||
return string(b.B)
|
||||
}
|
||||
|
||||
// Reset makes ByteBuffer.B empty.
|
||||
func (b *ByteBuffer) Reset() {
|
||||
b.B = b.B[:0]
|
||||
}
|
7
vendor/github.com/valyala/bytebufferpool/doc.go
generated
vendored
Normal file
7
vendor/github.com/valyala/bytebufferpool/doc.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// Package bytebufferpool implements a pool of byte buffers
|
||||
// with anti-fragmentation protection.
|
||||
//
|
||||
// The pool may waste limited amount of memory due to fragmentation.
|
||||
// This amount equals to the maximum total size of the byte buffers
|
||||
// in concurrent use.
|
||||
package bytebufferpool
|
151
vendor/github.com/valyala/bytebufferpool/pool.go
generated
vendored
Normal file
151
vendor/github.com/valyala/bytebufferpool/pool.go
generated
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
package bytebufferpool
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
const (
|
||||
minBitSize = 6 // 2**6=64 is a CPU cache line size
|
||||
steps = 20
|
||||
|
||||
minSize = 1 << minBitSize
|
||||
maxSize = 1 << (minBitSize + steps - 1)
|
||||
|
||||
calibrateCallsThreshold = 42000
|
||||
maxPercentile = 0.95
|
||||
)
|
||||
|
||||
// Pool represents byte buffer pool.
|
||||
//
|
||||
// Distinct pools may be used for distinct types of byte buffers.
|
||||
// Properly determined byte buffer types with their own pools may help reducing
|
||||
// memory waste.
|
||||
type Pool struct {
|
||||
calls [steps]uint64
|
||||
calibrating uint64
|
||||
|
||||
defaultSize uint64
|
||||
maxSize uint64
|
||||
|
||||
pool sync.Pool
|
||||
}
|
||||
|
||||
var defaultPool Pool
|
||||
|
||||
// Get returns an empty byte buffer from the pool.
|
||||
//
|
||||
// Got byte buffer may be returned to the pool via Put call.
|
||||
// This reduces the number of memory allocations required for byte buffer
|
||||
// management.
|
||||
func Get() *ByteBuffer { return defaultPool.Get() }
|
||||
|
||||
// Get returns new byte buffer with zero length.
|
||||
//
|
||||
// The byte buffer may be returned to the pool via Put after the use
|
||||
// in order to minimize GC overhead.
|
||||
func (p *Pool) Get() *ByteBuffer {
|
||||
v := p.pool.Get()
|
||||
if v != nil {
|
||||
return v.(*ByteBuffer)
|
||||
}
|
||||
return &ByteBuffer{
|
||||
B: make([]byte, 0, atomic.LoadUint64(&p.defaultSize)),
|
||||
}
|
||||
}
|
||||
|
||||
// Put returns byte buffer to the pool.
|
||||
//
|
||||
// ByteBuffer.B mustn't be touched after returning it to the pool.
|
||||
// Otherwise data races will occur.
|
||||
func Put(b *ByteBuffer) { defaultPool.Put(b) }
|
||||
|
||||
// Put releases byte buffer obtained via Get to the pool.
|
||||
//
|
||||
// The buffer mustn't be accessed after returning to the pool.
|
||||
func (p *Pool) Put(b *ByteBuffer) {
|
||||
idx := index(len(b.B))
|
||||
|
||||
if atomic.AddUint64(&p.calls[idx], 1) > calibrateCallsThreshold {
|
||||
p.calibrate()
|
||||
}
|
||||
|
||||
maxSize := int(atomic.LoadUint64(&p.maxSize))
|
||||
if maxSize == 0 || cap(b.B) <= maxSize {
|
||||
b.Reset()
|
||||
p.pool.Put(b)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pool) calibrate() {
|
||||
if !atomic.CompareAndSwapUint64(&p.calibrating, 0, 1) {
|
||||
return
|
||||
}
|
||||
|
||||
a := make(callSizes, 0, steps)
|
||||
var callsSum uint64
|
||||
for i := uint64(0); i < steps; i++ {
|
||||
calls := atomic.SwapUint64(&p.calls[i], 0)
|
||||
callsSum += calls
|
||||
a = append(a, callSize{
|
||||
calls: calls,
|
||||
size: minSize << i,
|
||||
})
|
||||
}
|
||||
sort.Sort(a)
|
||||
|
||||
defaultSize := a[0].size
|
||||
maxSize := defaultSize
|
||||
|
||||
maxSum := uint64(float64(callsSum) * maxPercentile)
|
||||
callsSum = 0
|
||||
for i := 0; i < steps; i++ {
|
||||
if callsSum > maxSum {
|
||||
break
|
||||
}
|
||||
callsSum += a[i].calls
|
||||
size := a[i].size
|
||||
if size > maxSize {
|
||||
maxSize = size
|
||||
}
|
||||
}
|
||||
|
||||
atomic.StoreUint64(&p.defaultSize, defaultSize)
|
||||
atomic.StoreUint64(&p.maxSize, maxSize)
|
||||
|
||||
atomic.StoreUint64(&p.calibrating, 0)
|
||||
}
|
||||
|
||||
type callSize struct {
|
||||
calls uint64
|
||||
size uint64
|
||||
}
|
||||
|
||||
type callSizes []callSize
|
||||
|
||||
func (ci callSizes) Len() int {
|
||||
return len(ci)
|
||||
}
|
||||
|
||||
func (ci callSizes) Less(i, j int) bool {
|
||||
return ci[i].calls > ci[j].calls
|
||||
}
|
||||
|
||||
func (ci callSizes) Swap(i, j int) {
|
||||
ci[i], ci[j] = ci[j], ci[i]
|
||||
}
|
||||
|
||||
func index(n int) int {
|
||||
n--
|
||||
n >>= minBitSize
|
||||
idx := 0
|
||||
for n > 0 {
|
||||
n >>= 1
|
||||
idx++
|
||||
}
|
||||
if idx >= steps {
|
||||
idx = steps - 1
|
||||
}
|
||||
return idx
|
||||
}
|
1
vendor/github.com/valyala/quicktemplate/.gitignore
generated
vendored
Normal file
1
vendor/github.com/valyala/quicktemplate/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
tags
|
19
vendor/github.com/valyala/quicktemplate/.travis.yml
generated
vendored
Normal file
19
vendor/github.com/valyala/quicktemplate/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- tip
|
||||
|
||||
before_install:
|
||||
- go get -u github.com/valyala/quicktemplate/qtc
|
||||
- go generate
|
||||
|
||||
script:
|
||||
# build test for supported platforms
|
||||
- GOOS=linux go build
|
||||
- GOOS=darwin go build
|
||||
- GOOS=freebsd go build
|
||||
|
||||
# run tests on a standard platform
|
||||
- go test -v ./...
|
22
vendor/github.com/valyala/quicktemplate/LICENSE
generated
vendored
Normal file
22
vendor/github.com/valyala/quicktemplate/LICENSE
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Aliaksandr Valialkin, VertaMedia
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
16
vendor/github.com/valyala/quicktemplate/QuickTemplate.xml
generated
vendored
Normal file
16
vendor/github.com/valyala/quicktemplate/QuickTemplate.xml
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<filetype binary="false" description="QuickTemplate" name="QuickTemplate">
|
||||
<highlighting>
|
||||
<options>
|
||||
<option name="LINE_COMMENT" value="//" />
|
||||
<option name="COMMENT_START" value="" />
|
||||
<option name="COMMENT_END" value="" />
|
||||
<option name="HEX_PREFIX" value="" />
|
||||
<option name="NUM_POSTFIXES" value="" />
|
||||
</options>
|
||||
<keywords keywords="case;cat;code;collapsespace;comment;default;else;elseif;endcollapsespace;endcomment;endfor;endfunc;endif;endplain;endstripspace;endswitch;for;func;if;import;interface;package;plain;space;stripspace;struct;switch;type" ignore_case="false" />
|
||||
<keywords3 keywords="{%=;{%=h;{%=j;{%=jh;{%=q;{%=qh;{%=u;{%=uh;{%d;{%d=;{%f;{%f.;{%f.=;{%f=;{%j;{%j=;{%q;{%q=;{%s=;{%u;{%u=;{%uz;{%uz=;{%v;{%v=;{%z;{%z=" />
|
||||
</highlighting>
|
||||
<extensionMap>
|
||||
<mapping ext="qtpl" />
|
||||
</extensionMap>
|
||||
</filetype>
|
621
vendor/github.com/valyala/quicktemplate/README.md
generated
vendored
Normal file
621
vendor/github.com/valyala/quicktemplate/README.md
generated
vendored
Normal file
@ -0,0 +1,621 @@
|
||||
[](https://travis-ci.org/valyala/quicktemplate)
|
||||
[](http://godoc.org/github.com/valyala/quicktemplate)
|
||||
[](https://goreportcard.com/report/github.com/valyala/quicktemplate)
|
||||
|
||||
# quicktemplate
|
||||
|
||||
A fast, powerful, yet easy to use template engine for Go.
|
||||
Inspired by the [Mako templates](http://www.makotemplates.org/) philosophy.
|
||||
|
||||
# Features
|
||||
|
||||
* [Extremely fast](#performance-comparison-with-htmltemplate).
|
||||
Templates are converted into Go code and then compiled.
|
||||
* Quicktemplate syntax is very close to Go - there is no need to learn
|
||||
yet another template language before starting to use quicktemplate.
|
||||
* Almost all bugs are caught during template compilation, so production
|
||||
suffers less from template-related bugs.
|
||||
* Easy to use. See [quickstart](#quick-start) and [examples](https://github.com/valyala/quicktemplate/tree/master/examples)
|
||||
for details.
|
||||
* Powerful. Arbitrary Go code may be embedded into and mixed with templates.
|
||||
Be careful with this power - do not query the database and/or external resources from
|
||||
templates unless you miss the PHP way in Go :) This power is mostly for
|
||||
arbitrary data transformations.
|
||||
* Easy to use template inheritance powered by [Go interfaces](https://golang.org/doc/effective_go.html#interfaces).
|
||||
See [this example](https://github.com/valyala/quicktemplate/tree/master/examples/basicserver) for details.
|
||||
* Templates are compiled into a single binary, so there is no need to copy
|
||||
template files to the server.
|
||||
|
||||
# Drawbacks
|
||||
|
||||
* Templates cannot be updated on the fly on the server, since they
|
||||
are compiled into a single binary.
|
||||
Take a look at [fasttemplate](https://github.com/valyala/fasttemplate)
|
||||
if you need a fast template engine for simple dynamically updated templates.
|
||||
|
||||
# Performance comparison with html/template
|
||||
|
||||
Quicktemplate is more than 20x faster than [html/template](https://golang.org/pkg/html/template/).
|
||||
The following simple template is used in the benchmark:
|
||||
|
||||
* [html/template version](https://github.com/valyala/quicktemplate/blob/master/testdata/templates/bench.tpl)
|
||||
* [quicktemplate version](https://github.com/valyala/quicktemplate/blob/master/testdata/templates/bench.qtpl)
|
||||
|
||||
Benchmark results:
|
||||
|
||||
```
|
||||
$ go test -bench='Benchmark(Quick|HTML)Template' -benchmem github.com/valyala/quicktemplate/tests
|
||||
BenchmarkQuickTemplate1-4 10000000 120 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkQuickTemplate10-4 3000000 441 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkQuickTemplate100-4 300000 3945 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkHTMLTemplate1-4 500000 2501 ns/op 752 B/op 23 allocs/op
|
||||
BenchmarkHTMLTemplate10-4 100000 12442 ns/op 3521 B/op 117 allocs/op
|
||||
BenchmarkHTMLTemplate100-4 10000 123392 ns/op 34498 B/op 1152 allocs/op
|
||||
```
|
||||
|
||||
[goTemplateBenchmark](https://github.com/SlinSo/goTemplateBenchmark) compares QuickTemplate with numerous Go templating packages. QuickTemplate performs favorably.
|
||||
|
||||
# Security
|
||||
|
||||
* All template placeholders are HTML-escaped by default.
|
||||
* Template placeholders for JSON strings prevent from `</script>`-based
|
||||
XSS attacks:
|
||||
|
||||
```qtpl
|
||||
{% func FailedXSS() %}
|
||||
<script>
|
||||
var s = {%q= "</script><script>alert('you pwned!')" %};
|
||||
</script>
|
||||
{% endfunc %}
|
||||
```
|
||||
|
||||
# Examples
|
||||
|
||||
See [examples](https://github.com/valyala/quicktemplate/tree/master/examples).
|
||||
|
||||
# Quick start
|
||||
|
||||
First of all, install the `quicktemplate` package
|
||||
and [quicktemplate compiler](https://github.com/valyala/quicktemplate/tree/master/qtc) (`qtc`):
|
||||
|
||||
```
|
||||
go get -u github.com/valyala/quicktemplate
|
||||
go get -u github.com/valyala/quicktemplate/qtc
|
||||
```
|
||||
|
||||
Let's start with a minimal template example:
|
||||
|
||||
```qtpl
|
||||
All text outside function templates is treated as comments,
|
||||
i.e. it is just ignored by quicktemplate compiler (`qtc`). It is for humans.
|
||||
|
||||
Hello is a simple template function.
|
||||
{% func Hello(name string) %}
|
||||
Hello, {%s name %}!
|
||||
{% endfunc %}
|
||||
```
|
||||
|
||||
Save this file into a `templates` folder under the name `hello.qtpl`
|
||||
and run `qtc` inside this folder.
|
||||
|
||||
If everything went OK, `hello.qtpl.go` file should appear in the `templates` folder.
|
||||
This file contains Go code for `hello.qtpl`. Let's use it!
|
||||
|
||||
Create a file main.go outside `templates` folder and put the following
|
||||
code there:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"./templates"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("%s\n", templates.Hello("Foo"))
|
||||
fmt.Printf("%s\n", templates.Hello("Bar"))
|
||||
}
|
||||
```
|
||||
|
||||
Then issue `go run`. If everything went OK, you'll see something like this:
|
||||
|
||||
```
|
||||
|
||||
Hello, Foo!
|
||||
|
||||
|
||||
Hello, Bar!
|
||||
|
||||
```
|
||||
|
||||
Let's create more a complex template which calls other template functions,
|
||||
contains loops, conditions, breaks, continues and returns.
|
||||
Put the following template into `templates/greetings.qtpl`:
|
||||
|
||||
```qtpl
|
||||
|
||||
Greetings greets up to 42 names.
|
||||
It also greets John differently comparing to others.
|
||||
{% func Greetings(names []string) %}
|
||||
{% if len(names) == 0 %}
|
||||
Nobody to greet :(
|
||||
{% return %}
|
||||
{% endif %}
|
||||
|
||||
{% for i, name := range names %}
|
||||
{% if i == 42 %}
|
||||
I'm tired to greet so many people...
|
||||
{% break %}
|
||||
{% elseif name == "John" %}
|
||||
{%= sayHi("Mr. " + name) %}
|
||||
{% continue %}
|
||||
{% else %}
|
||||
{%= Hello(name) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfunc %}
|
||||
|
||||
sayHi is unexported, since it starts with lowercase letter.
|
||||
{% func sayHi(name string) %}
|
||||
Hi, {%s name %}
|
||||
{% endfunc %}
|
||||
|
||||
Note that every template file may contain an arbitrary number
|
||||
of template functions. For instance, this file contains Greetings and sayHi
|
||||
functions.
|
||||
```
|
||||
|
||||
Run `qtc` inside `templates` folder. Now the folder should contain
|
||||
two files with Go code: `hello.qtpl.go` and `greetings.qtpl.go`. These files
|
||||
form a single `templates` Go package. Template functions and other template
|
||||
stuff is shared between template files located in the same folder.
|
||||
So `Hello` template function may be used inside `greetings.qtpl` while
|
||||
it is defined in `hello.qtpl`.
|
||||
Moreover, the folder may contain ordinary Go files, so its contents may
|
||||
be used inside templates and vice versa.
|
||||
The package name inside template files may be overriden
|
||||
with `{% package packageName %}`.
|
||||
|
||||
Now put the following code into `main.go`:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"./templates"
|
||||
)
|
||||
|
||||
func main() {
|
||||
names := []string{"Kate", "Go", "John", "Brad"}
|
||||
|
||||
// qtc creates Write* function for each template function.
|
||||
// Such functions accept io.Writer as first parameter:
|
||||
var buf bytes.Buffer
|
||||
templates.WriteGreetings(&buf, names)
|
||||
|
||||
fmt.Printf("buf=\n%s", buf.Bytes())
|
||||
}
|
||||
```
|
||||
|
||||
Careful readers may notice different output tags were used in these
|
||||
templates: `{%s name %}` and `{%= Hello(name) %}`. What's the difference?
|
||||
The `{%s x %}` is used for printing HTML-safe strings, while `{%= F() %}`
|
||||
is used for embedding template function calls. Quicktemplate supports also
|
||||
other output tags:
|
||||
|
||||
* `{%d num %}` for integers.
|
||||
* `{%f float %}` for float64.
|
||||
Floating point precision may be set via `{%f.precision float %}`.
|
||||
For example, `{%f.2 1.2345 %}` outputs `1.23`.
|
||||
* `{%z bytes %}` for byte slices.
|
||||
* `{%q str %}` and `{%qz bytes %}` for JSON-compatible quoted strings.
|
||||
* `{%j str %}` and `{%jz bytes %}` for embedding str into a JSON string. Unlike `{%q str %}`,
|
||||
it doesn't quote the string.
|
||||
* `{%u str %}` and `{%uz bytes %}` for [URL encoding](https://en.wikipedia.org/wiki/Percent-encoding)
|
||||
the given str.
|
||||
* `{%v anything %}` is equivalent to `%v` in [printf-like functions](https://golang.org/pkg/fmt/).
|
||||
|
||||
All the output tags except `{%= F() %}` produce HTML-safe output, i.e. they
|
||||
escape `<` to `<`, `>` to `>`, etc. If you don't want HTML-safe output,
|
||||
then just put `=` after the tag. For example: `{%s= "<h1>This h1 won't be escaped</h1>" %}`.
|
||||
|
||||
As you may notice `{%= F() %}` and `{%s= F() %}` produce the same output for `{% func F() %}`.
|
||||
But the first one is optimized for speed - it avoids memory allocations and copies.
|
||||
It is therefore recommended to stick to it when embedding template function calls.
|
||||
|
||||
Additionally, the following extensions are supported for `{%= F() %}`:
|
||||
|
||||
* `{%=h F() %}` produces html-escaped output.
|
||||
* `{%=u F() %}` produces [URL-encoded](https://en.wikipedia.org/wiki/Percent-encoding) output.
|
||||
* `{%=q F() %}` produces quoted json string.
|
||||
* `{%=j F() %}` produces json string without quotes.
|
||||
* `{%=uh F() %}` produces html-safe URL-encoded output.
|
||||
* `{%=qh F() %}` produces html-safe quoted json string.
|
||||
* `{%=jh F() %}` produces html-safe json string without quotes.
|
||||
|
||||
All output tags except `{%= F() %}` family may contain arbitrary valid
|
||||
Go expressions instead of just an identifier. For example:
|
||||
|
||||
```qtpl
|
||||
Import fmt for fmt.Sprintf()
|
||||
{% import "fmt" %}
|
||||
|
||||
FmtFunc uses fmt.Sprintf() inside output tag
|
||||
{% func FmtFunc(s string) %}
|
||||
{%s fmt.Sprintf("FmtFunc accepted %q string", s) %}
|
||||
{% endfunc %}
|
||||
```
|
||||
|
||||
There are other useful tags supported by quicktemplate:
|
||||
|
||||
* `{% comment %}`
|
||||
|
||||
```qtpl
|
||||
{% comment %}
|
||||
This is a comment. It won't trap into the output.
|
||||
It may contain {% arbitrary tags %}. They are just ignored.
|
||||
{% endcomment %}
|
||||
```
|
||||
|
||||
* `{% plain %}`
|
||||
|
||||
```qtpl
|
||||
{% plain %}
|
||||
Tags will {% trap into %} the output {% unmodified %}.
|
||||
Plain block may contain invalid and {% incomplete tags.
|
||||
{% endplain %}
|
||||
```
|
||||
|
||||
* `{% collapsespace %}`
|
||||
|
||||
```qtpl
|
||||
{% collapsespace %}
|
||||
<div>
|
||||
<div>space between lines</div>
|
||||
and {%s "tags" %}
|
||||
<div>is collapsed into a single space
|
||||
unless{% newline %}or{% space %}is used</div>
|
||||
</div>
|
||||
{% endcollapsespace %}
|
||||
```
|
||||
|
||||
Is converted into:
|
||||
|
||||
```
|
||||
<div> <div>space between lines</div> and tags <div>is collapsed into a single space unless
|
||||
or is used</div> </div>
|
||||
```
|
||||
|
||||
* `{% stripspace %}`
|
||||
|
||||
```qtpl
|
||||
{% stripspace %}
|
||||
<div>
|
||||
<div>space between lines</div>
|
||||
and {%s " tags" %}
|
||||
<div>is removed unless{% newline %}or{% space %}is used</div>
|
||||
</div>
|
||||
{% endstripspace %}
|
||||
```
|
||||
|
||||
Is converted into:
|
||||
|
||||
```
|
||||
<div><div>space between lines</div>and tags<div>is removed unless
|
||||
or is used</div></div>
|
||||
```
|
||||
|
||||
* `{% switch %}`, `{% case %}` and `{% default %}`:
|
||||
|
||||
|
||||
```qtpl
|
||||
1 + 1 =
|
||||
{% switch 1+1 %}
|
||||
{% case 2 %}
|
||||
2?
|
||||
{% case 42 %}
|
||||
42!
|
||||
{% default %}
|
||||
I don't know :(
|
||||
{% endswitch %}
|
||||
```
|
||||
|
||||
* `{% code %}`:
|
||||
|
||||
```qtpl
|
||||
{% code
|
||||
// arbitrary Go code may be embedded here!
|
||||
type FooArg struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
%}
|
||||
```
|
||||
|
||||
* `{% package %}`:
|
||||
|
||||
```qtpl
|
||||
Override default package name with the custom name
|
||||
{% package customPackageName %}
|
||||
```
|
||||
|
||||
* `{% import %}`:
|
||||
|
||||
```qtpl
|
||||
Import external packages.
|
||||
{% import "foo/bar" %}
|
||||
{% import (
|
||||
"foo"
|
||||
bar "baz/baa"
|
||||
) %}
|
||||
```
|
||||
|
||||
* `{% cat "/path/to/file" %}`:
|
||||
|
||||
```qtpl
|
||||
Cat emits the given file contents as a plaintext:
|
||||
{% func passwords() %}
|
||||
/etc/passwd contents:
|
||||
{% cat "/etc/passwd" %}
|
||||
{% endfunc %}
|
||||
```
|
||||
|
||||
* `{% interface %}`:
|
||||
|
||||
```qtpl
|
||||
Interfaces allow powerful templates' inheritance
|
||||
{%
|
||||
interface Page {
|
||||
Title()
|
||||
Body(s string, n int)
|
||||
Footer()
|
||||
}
|
||||
%}
|
||||
|
||||
PrintPage prints Page
|
||||
{% func PrintPage(p Page) %}
|
||||
<html>
|
||||
<head><title>{%= p.Title() %}</title></head>
|
||||
<body>
|
||||
<div>{%= p.Body("foo", 42) %}</div>
|
||||
<div>{%= p.Footer() %}</div>
|
||||
</body>
|
||||
</html>
|
||||
{% endfunc %}
|
||||
|
||||
Base page implementation
|
||||
{% code
|
||||
type BasePage struct {
|
||||
TitleStr string
|
||||
FooterStr string
|
||||
}
|
||||
%}
|
||||
{% func (bp *BasePage) Title() %}{%s bp.TitleStr %}{% endfunc %}
|
||||
{% func (bp *BasePage) Body(s string, n int) %}
|
||||
<b>s={%q s %}, n={%d n %}</b>
|
||||
{% endfunc %}
|
||||
{% func (bp *BasePage) Footer() %}{%s bp.FooterStr %}{% endfunc %}
|
||||
|
||||
Main page implementation
|
||||
{% code
|
||||
type MainPage struct {
|
||||
// inherit from BasePage
|
||||
BasePage
|
||||
|
||||
// real body for main page
|
||||
BodyStr string
|
||||
}
|
||||
%}
|
||||
|
||||
Override only Body
|
||||
Title and Footer are used from BasePage.
|
||||
{% func (mp *MainPage) Body(s string, n int) %}
|
||||
<div>
|
||||
main body: {%s mp.BodyStr %}
|
||||
</div>
|
||||
<div>
|
||||
base body: {%= mp.BasePage.Body(s, n) %}
|
||||
</div>
|
||||
{% endfunc %}
|
||||
```
|
||||
|
||||
See [basicserver example](https://github.com/valyala/quicktemplate/tree/master/examples/basicserver)
|
||||
for more details.
|
||||
|
||||
# Performance optimization tips
|
||||
|
||||
* Prefer calling `WriteFoo` instead of `Foo` when generating template output
|
||||
for `{% func Foo() %}`. This avoids unnesessary memory allocation and a copy
|
||||
for a `string` returned from `Foo()`.
|
||||
|
||||
* Prefer `{%= Foo() %}` instead of `{%s= Foo() %}` when embedding
|
||||
a function template `{% func Foo() %}`. Though both approaches generate
|
||||
identical output, the first approach is optimized for speed.
|
||||
|
||||
* Prefer using existing output tags instead of passing `fmt.Sprintf`
|
||||
to `{%s %}`. For instance, use `{%d num %}` instead
|
||||
of `{%s fmt.Sprintf("%d", num) %}`, because the first approach is optimized
|
||||
for speed.
|
||||
|
||||
* Prefer using specific output tags instead of generic output tag
|
||||
`{%v %}`. For example, use `{%s str %}` instead of `{%v str %}`, since
|
||||
specific output tags are optimized for speed.
|
||||
|
||||
* Prefer creating custom function templates instead of composing complex
|
||||
strings by hands before passing them to `{%s %}`.
|
||||
For instance, the first approach is slower than the second one:
|
||||
|
||||
```qtpl
|
||||
{% func Foo(n int) %}
|
||||
{% code
|
||||
// construct complex string
|
||||
complexStr := ""
|
||||
for i := 0; i < n; i++ {
|
||||
complexStr += fmt.Sprintf("num %d,", i)
|
||||
}
|
||||
%}
|
||||
complex string = {%s= complexStr %}
|
||||
{% endfunc %}
|
||||
```
|
||||
|
||||
```qtpl
|
||||
{% func Foo(n int) %}
|
||||
complex string = {%= complexStr(n) %}
|
||||
{% endfunc %}
|
||||
|
||||
// Wrap complexStr func into stripspace for stripping unnesessary space
|
||||
// between tags and lines.
|
||||
{% stripspace %}
|
||||
{% func complexStr(n int) %}
|
||||
{% for i := 0; i < n; i++ %}
|
||||
num{% space %}{%d i %}{% newline %}
|
||||
{% endfor %}
|
||||
{% endfunc %}
|
||||
{% endstripspace %}
|
||||
```
|
||||
|
||||
* Make sure that the `io.Writer` passed to `Write*` functions
|
||||
is [buffered](https://golang.org/pkg/bufio/#Writer).
|
||||
This will minimize the number of `write`
|
||||
[syscalls](https://en.wikipedia.org/wiki/System_call),
|
||||
which may be quite expensive.
|
||||
|
||||
Note: There is no need to wrap [fasthttp.RequestCtx](https://godoc.org/github.com/valyala/fasthttp#RequestCtx)
|
||||
into [bufio.Writer](https://golang.org/pkg/bufio/#Writer), since it is already buffered.
|
||||
|
||||
* [Profile](http://blog.golang.org/profiling-go-programs) your programs
|
||||
for memory allocations and fix the most demanding functions based on
|
||||
the output of `go tool pprof --alloc_objects`.
|
||||
|
||||
# Use cases
|
||||
|
||||
While the main quicktemplate purpose is generating HTML, it may be used
|
||||
for generating other data too. For example, JSON and XML marshalling may
|
||||
be easily implemented with quicktemplate:
|
||||
|
||||
```qtpl
|
||||
{% code
|
||||
type MarshalRow struct {
|
||||
Msg string
|
||||
N int
|
||||
}
|
||||
|
||||
type MarshalData struct {
|
||||
Foo int
|
||||
Bar string
|
||||
Rows []MarshalRow
|
||||
}
|
||||
%}
|
||||
|
||||
// JSON marshaling
|
||||
{% stripspace %}
|
||||
{% func (d *MarshalData) JSON() %}
|
||||
{
|
||||
"Foo": {%d d.Foo %},
|
||||
"Bar": {%q= d.Bar %},
|
||||
"Rows":[
|
||||
{% for i, r := range d.Rows %}
|
||||
{
|
||||
"Msg": {%q= r.Msg %},
|
||||
"N": {%d r.N %}
|
||||
}
|
||||
{% if i + 1 < len(d.Rows) %},{% endif %}
|
||||
{% endfor %}
|
||||
]
|
||||
}
|
||||
{% endfunc %}
|
||||
{% endstripspace %}
|
||||
|
||||
// XML marshalling
|
||||
{% stripspace %}
|
||||
{% func (d *MarshalData) XML() %}
|
||||
<MarshalData>
|
||||
<Foo>{%d d.Foo %}</Foo>
|
||||
<Bar>{%s d.Bar %}</Bar>
|
||||
<Rows>
|
||||
{% for _, r := range d.Rows %}
|
||||
<Row>
|
||||
<Msg>{%s r.Msg %}</Msg>
|
||||
<N>{%d r.N %}</N>
|
||||
</Row>
|
||||
{% endfor %}
|
||||
</Rows>
|
||||
</MarshalData>
|
||||
{% endfunc %}
|
||||
{% endstripspace %}
|
||||
```
|
||||
|
||||
Usually, marshalling built with quicktemplate works faster than the marshalling
|
||||
implemented via standard [encoding/json](https://golang.org/pkg/encoding/json/)
|
||||
and [encoding/xml](https://golang.org/pkg/encoding/xml/).
|
||||
See the corresponding benchmark results:
|
||||
|
||||
```
|
||||
go test -bench=Marshal -benchmem github.com/valyala/quicktemplate/tests
|
||||
BenchmarkMarshalJSONStd1-4 3000000 480 ns/op 8 B/op 1 allocs/op
|
||||
BenchmarkMarshalJSONStd10-4 1000000 1842 ns/op 8 B/op 1 allocs/op
|
||||
BenchmarkMarshalJSONStd100-4 100000 15820 ns/op 8 B/op 1 allocs/op
|
||||
BenchmarkMarshalJSONStd1000-4 10000 159327 ns/op 59 B/op 1 allocs/op
|
||||
BenchmarkMarshalJSONQuickTemplate1-4 10000000 162 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMarshalJSONQuickTemplate10-4 2000000 748 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMarshalJSONQuickTemplate100-4 200000 6572 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMarshalJSONQuickTemplate1000-4 20000 66784 ns/op 29 B/op 0 allocs/op
|
||||
BenchmarkMarshalXMLStd1-4 1000000 1652 ns/op 2 B/op 2 allocs/op
|
||||
BenchmarkMarshalXMLStd10-4 200000 7533 ns/op 11 B/op 11 allocs/op
|
||||
BenchmarkMarshalXMLStd100-4 20000 65763 ns/op 195 B/op 101 allocs/op
|
||||
BenchmarkMarshalXMLStd1000-4 2000 663373 ns/op 3522 B/op 1002 allocs/op
|
||||
BenchmarkMarshalXMLQuickTemplate1-4 10000000 145 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMarshalXMLQuickTemplate10-4 3000000 597 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMarshalXMLQuickTemplate100-4 300000 5833 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMarshalXMLQuickTemplate1000-4 30000 53000 ns/op 32 B/op 0 allocs/op
|
||||
```
|
||||
|
||||
# FAQ
|
||||
|
||||
* *Why is the quicktemplate syntax incompatible with [html/template](https://golang.org/pkg/html/template/)?*
|
||||
|
||||
Because `html/template` syntax isn't expressive enough for `quicktemplate`.
|
||||
|
||||
* *What's the difference between quicktemplate and [ego](https://github.com/benbjohnson/ego)?*
|
||||
|
||||
`Ego` is similar to `quicktemplate` in the sense it converts templates into Go code.
|
||||
But it misses the following stuff, which makes `quicktemplate` so powerful
|
||||
and easy to use:
|
||||
|
||||
* Defining multiple function templates in a single template file.
|
||||
* Embedding function templates inside other function templates.
|
||||
* Template interfaces, inheritance and overriding.
|
||||
See [this example](https://github.com/valyala/quicktemplate/tree/master/examples/basicserver)
|
||||
for details.
|
||||
* Top-level comments outside function templates.
|
||||
* Template packages.
|
||||
* Combining arbitrary Go files with template files in template packages.
|
||||
* Performance optimizations.
|
||||
|
||||
* *What's the difference between quicktemplate and [gorazor](https://github.com/sipin/gorazor)?*
|
||||
|
||||
`Gorazor` is similar to `quicktemplate` in the sense it converts templates into Go code.
|
||||
But it misses the following useful features:
|
||||
|
||||
* Clear syntax insead of hard-to-understand magic stuff related
|
||||
to template arguments, template inheritance and embedding function
|
||||
templates into other templates.
|
||||
* Performance optimizations.
|
||||
|
||||
* *Is there a syntax highlighting for qtpl files?*
|
||||
|
||||
Yes - see [this issue](https://github.com/valyala/quicktemplate/issues/19) for details.
|
||||
If you are using JetBrains products (syntax highlighting and autocomplete):
|
||||
* cd [JetBrains settings directory](https://intellij-support.jetbrains.com/hc/en-us/articles/206544519-Directories-used-by-the-IDE-to-store-settings-caches-plugins-and-logs)
|
||||
* mkdir -p filetypes && cd filetypes
|
||||
* curl https://raw.githubusercontent.com/valyala/quicktemplate/master/QuickTemplate.xml >> QuickTemplate.xml
|
||||
* Restart your IDE
|
||||
|
||||
* *I didn't find an answer for my question here.*
|
||||
|
||||
Try exploring [these questions](https://github.com/valyala/quicktemplate/issues?q=label%3Aquestion).
|
45
vendor/github.com/valyala/quicktemplate/bytebuffer.go
generated
vendored
Normal file
45
vendor/github.com/valyala/quicktemplate/bytebuffer.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
package quicktemplate
|
||||
|
||||
import (
|
||||
"github.com/valyala/bytebufferpool"
|
||||
)
|
||||
|
||||
// ByteBuffer implements io.Writer on top of byte slice.
|
||||
//
|
||||
// Recycle byte buffers via AcquireByteBuffer and ReleaseByteBuffer
|
||||
// in order to reduce memory allocations.
|
||||
//
|
||||
// Deprecated: use github.com/valyala/bytebufferpool instead.
|
||||
type ByteBuffer bytebufferpool.ByteBuffer
|
||||
|
||||
// Write implements io.Writer.
|
||||
func (b *ByteBuffer) Write(p []byte) (int, error) {
|
||||
return bb(b).Write(p)
|
||||
}
|
||||
|
||||
// Reset resets the byte buffer.
|
||||
func (b *ByteBuffer) Reset() {
|
||||
bb(b).Reset()
|
||||
}
|
||||
|
||||
// AcquireByteBuffer returns new ByteBuffer from the pool.
|
||||
//
|
||||
// Return unneeded buffers to the pool by calling ReleaseByteBuffer
|
||||
// in order to reduce memory allocations.
|
||||
func AcquireByteBuffer() *ByteBuffer {
|
||||
return (*ByteBuffer)(byteBufferPool.Get())
|
||||
}
|
||||
|
||||
// ReleaseByteBuffer retruns byte buffer to the pool.
|
||||
//
|
||||
// Do not access byte buffer after returning it to the pool,
|
||||
// otherwise data races may occur.
|
||||
func ReleaseByteBuffer(b *ByteBuffer) {
|
||||
byteBufferPool.Put(bb(b))
|
||||
}
|
||||
|
||||
func bb(b *ByteBuffer) *bytebufferpool.ByteBuffer {
|
||||
return (*bytebufferpool.ByteBuffer)(b)
|
||||
}
|
||||
|
||||
var byteBufferPool bytebufferpool.Pool
|
6
vendor/github.com/valyala/quicktemplate/doc.go
generated
vendored
Normal file
6
vendor/github.com/valyala/quicktemplate/doc.go
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/*
|
||||
Package quicktemplate provides fast and powerful template engine.
|
||||
|
||||
See https://github.com/valyala/quicktemplate for details.
|
||||
*/
|
||||
package quicktemplate
|
8
vendor/github.com/valyala/quicktemplate/go.mod
generated
vendored
Normal file
8
vendor/github.com/valyala/quicktemplate/go.mod
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
module github.com/valyala/quicktemplate
|
||||
|
||||
require (
|
||||
github.com/klauspost/compress v1.4.1 // indirect
|
||||
github.com/klauspost/cpuid v1.2.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0
|
||||
github.com/valyala/fasthttp v1.2.0
|
||||
)
|
12
vendor/github.com/valyala/quicktemplate/go.sum
generated
vendored
Normal file
12
vendor/github.com/valyala/quicktemplate/go.sum
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.4.1 h1:8VMb5+0wMgdBykOV96DwNwKFQ+WTI4pzYURP99CcB9E=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.2.0 h1:dzZJf2IuMiclVjdw0kkT+f9u4YdrapbNyGAN47E/qnk=
|
||||
github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
62
vendor/github.com/valyala/quicktemplate/htmlescapewriter.go
generated
vendored
Normal file
62
vendor/github.com/valyala/quicktemplate/htmlescapewriter.go
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
package quicktemplate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
type htmlEscapeWriter struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func (w *htmlEscapeWriter) Write(b []byte) (int, error) {
|
||||
if bytes.IndexByte(b, '<') < 0 &&
|
||||
bytes.IndexByte(b, '>') < 0 &&
|
||||
bytes.IndexByte(b, '"') < 0 &&
|
||||
bytes.IndexByte(b, '\'') < 0 &&
|
||||
bytes.IndexByte(b, '&') < 0 {
|
||||
|
||||
// fast path - nothing to escape
|
||||
return w.w.Write(b)
|
||||
}
|
||||
|
||||
// slow path
|
||||
write := w.w.Write
|
||||
j := 0
|
||||
for i, c := range b {
|
||||
switch c {
|
||||
case '<':
|
||||
write(b[j:i])
|
||||
write(strLT)
|
||||
j = i + 1
|
||||
case '>':
|
||||
write(b[j:i])
|
||||
write(strGT)
|
||||
j = i + 1
|
||||
case '"':
|
||||
write(b[j:i])
|
||||
write(strQuot)
|
||||
j = i + 1
|
||||
case '\'':
|
||||
write(b[j:i])
|
||||
write(strApos)
|
||||
j = i + 1
|
||||
case '&':
|
||||
write(b[j:i])
|
||||
write(strAmp)
|
||||
j = i + 1
|
||||
}
|
||||
}
|
||||
if n, err := write(b[j:]); err != nil {
|
||||
return j + n, err
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
var (
|
||||
strLT = []byte("<")
|
||||
strGT = []byte(">")
|
||||
strQuot = []byte(""")
|
||||
strApos = []byte("'")
|
||||
strAmp = []byte("&")
|
||||
)
|
93
vendor/github.com/valyala/quicktemplate/jsonstring.go
generated
vendored
Normal file
93
vendor/github.com/valyala/quicktemplate/jsonstring.go
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
package quicktemplate
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func writeJSONString(w io.Writer, s string) {
|
||||
if len(s) > 24 &&
|
||||
strings.IndexByte(s, '"') < 0 &&
|
||||
strings.IndexByte(s, '\\') < 0 &&
|
||||
strings.IndexByte(s, '\n') < 0 &&
|
||||
strings.IndexByte(s, '\r') < 0 &&
|
||||
strings.IndexByte(s, '\t') < 0 &&
|
||||
strings.IndexByte(s, '\f') < 0 &&
|
||||
strings.IndexByte(s, '\b') < 0 &&
|
||||
strings.IndexByte(s, '<') < 0 &&
|
||||
strings.IndexByte(s, '\'') < 0 &&
|
||||
strings.IndexByte(s, 0) < 0 {
|
||||
|
||||
// fast path - nothing to escape
|
||||
w.Write(unsafeStrToBytes(s))
|
||||
return
|
||||
}
|
||||
|
||||
// slow path
|
||||
write := w.Write
|
||||
b := unsafeStrToBytes(s)
|
||||
j := 0
|
||||
n := len(b)
|
||||
if n > 0 {
|
||||
// Hint the compiler to remove bounds checks in the loop below.
|
||||
_ = b[n-1]
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
switch b[i] {
|
||||
case '"':
|
||||
write(b[j:i])
|
||||
write(strBackslashQuote)
|
||||
j = i + 1
|
||||
case '\\':
|
||||
write(b[j:i])
|
||||
write(strBackslashBackslash)
|
||||
j = i + 1
|
||||
case '\n':
|
||||
write(b[j:i])
|
||||
write(strBackslashN)
|
||||
j = i + 1
|
||||
case '\r':
|
||||
write(b[j:i])
|
||||
write(strBackslashR)
|
||||
j = i + 1
|
||||
case '\t':
|
||||
write(b[j:i])
|
||||
write(strBackslashT)
|
||||
j = i + 1
|
||||
case '\f':
|
||||
write(b[j:i])
|
||||
write(strBackslashF)
|
||||
j = i + 1
|
||||
case '\b':
|
||||
write(b[j:i])
|
||||
write(strBackslashB)
|
||||
j = i + 1
|
||||
case '<':
|
||||
write(b[j:i])
|
||||
write(strBackslashLT)
|
||||
j = i + 1
|
||||
case '\'':
|
||||
write(b[j:i])
|
||||
write(strBackslashQ)
|
||||
j = i + 1
|
||||
case 0:
|
||||
write(b[j:i])
|
||||
write(strBackslashZero)
|
||||
j = i + 1
|
||||
}
|
||||
}
|
||||
write(b[j:])
|
||||
}
|
||||
|
||||
var (
|
||||
strBackslashQuote = []byte(`\"`)
|
||||
strBackslashBackslash = []byte(`\\`)
|
||||
strBackslashN = []byte(`\n`)
|
||||
strBackslashR = []byte(`\r`)
|
||||
strBackslashT = []byte(`\t`)
|
||||
strBackslashF = []byte(`\u000c`)
|
||||
strBackslashB = []byte(`\u0008`)
|
||||
strBackslashLT = []byte(`\u003c`)
|
||||
strBackslashQ = []byte(`\u0027`)
|
||||
strBackslashZero = []byte(`\u0000`)
|
||||
)
|
32
vendor/github.com/valyala/quicktemplate/urlencode.go
generated
vendored
Normal file
32
vendor/github.com/valyala/quicktemplate/urlencode.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
package quicktemplate
|
||||
|
||||
func appendURLEncode(dst []byte, src string) []byte {
|
||||
n := len(src)
|
||||
if n > 0 {
|
||||
// Hint the compiler to remove bounds checks in the loop below.
|
||||
_ = src[n-1]
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
c := src[i]
|
||||
|
||||
// See http://www.w3.org/TR/html5/forms.html#form-submission-algorithm
|
||||
if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' ||
|
||||
c == '-' || c == '.' || c == '_' {
|
||||
dst = append(dst, c)
|
||||
} else {
|
||||
if c == ' ' {
|
||||
dst = append(dst, '+')
|
||||
} else {
|
||||
dst = append(dst, '%', hexCharUpper(c>>4), hexCharUpper(c&15))
|
||||
}
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func hexCharUpper(c byte) byte {
|
||||
if c < 10 {
|
||||
return '0' + c
|
||||
}
|
||||
return c - 10 + 'A'
|
||||
}
|
3
vendor/github.com/valyala/quicktemplate/util.go
generated
vendored
Normal file
3
vendor/github.com/valyala/quicktemplate/util.go
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package quicktemplate
|
||||
|
||||
//go:generate qtc -dir=testdata/templates
|
11
vendor/github.com/valyala/quicktemplate/util_appengine.go
generated
vendored
Normal file
11
vendor/github.com/valyala/quicktemplate/util_appengine.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
// +build appengine appenginevm
|
||||
|
||||
package quicktemplate
|
||||
|
||||
func unsafeStrToBytes(s string) []byte {
|
||||
return []byte(s)
|
||||
}
|
||||
|
||||
func unsafeBytesToStr(z []byte) string {
|
||||
return string(z)
|
||||
}
|
22
vendor/github.com/valyala/quicktemplate/util_noappengine.go
generated
vendored
Normal file
22
vendor/github.com/valyala/quicktemplate/util_noappengine.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// +build !appengine,!appenginevm
|
||||
|
||||
package quicktemplate
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func unsafeStrToBytes(s string) []byte {
|
||||
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||||
bh := reflect.SliceHeader{
|
||||
Data: sh.Data,
|
||||
Len: sh.Len,
|
||||
Cap: sh.Len,
|
||||
}
|
||||
return *(*[]byte)(unsafe.Pointer(&bh))
|
||||
}
|
||||
|
||||
func unsafeBytesToStr(z []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&z))
|
||||
}
|
188
vendor/github.com/valyala/quicktemplate/writer.go
generated
vendored
Normal file
188
vendor/github.com/valyala/quicktemplate/writer.go
generated
vendored
Normal file
@ -0,0 +1,188 @@
|
||||
package quicktemplate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Writer implements auxiliary writer used by quicktemplate functions.
|
||||
//
|
||||
// Use AcquireWriter for creating new writers.
|
||||
type Writer struct {
|
||||
e QWriter
|
||||
n QWriter
|
||||
}
|
||||
|
||||
// W returns the underlying writer passed to AcquireWriter.
|
||||
func (qw *Writer) W() io.Writer {
|
||||
return qw.n.w
|
||||
}
|
||||
|
||||
// E returns QWriter with enabled html escaping.
|
||||
func (qw *Writer) E() *QWriter {
|
||||
return &qw.e
|
||||
}
|
||||
|
||||
// N returns QWriter without html escaping.
|
||||
func (qw *Writer) N() *QWriter {
|
||||
return &qw.n
|
||||
}
|
||||
|
||||
// AcquireWriter returns new writer from the pool.
|
||||
//
|
||||
// Return unneeded writer to the pool by calling ReleaseWriter
|
||||
// in order to reduce memory allocations.
|
||||
func AcquireWriter(w io.Writer) *Writer {
|
||||
v := writerPool.Get()
|
||||
if v == nil {
|
||||
qw := &Writer{}
|
||||
qw.e.w = &htmlEscapeWriter{}
|
||||
v = qw
|
||||
}
|
||||
qw := v.(*Writer)
|
||||
qw.e.w.(*htmlEscapeWriter).w = w
|
||||
qw.n.w = w
|
||||
return qw
|
||||
}
|
||||
|
||||
// ReleaseWriter returns the writer to the pool.
|
||||
//
|
||||
// Do not access released writer, otherwise data races may occur.
|
||||
func ReleaseWriter(qw *Writer) {
|
||||
hw := qw.e.w.(*htmlEscapeWriter)
|
||||
hw.w = nil
|
||||
qw.e.Reset()
|
||||
qw.e.w = hw
|
||||
|
||||
qw.n.Reset()
|
||||
|
||||
writerPool.Put(qw)
|
||||
}
|
||||
|
||||
var writerPool sync.Pool
|
||||
|
||||
// QWriter is auxiliary writer used by Writer.
|
||||
type QWriter struct {
|
||||
w io.Writer
|
||||
err error
|
||||
b []byte
|
||||
}
|
||||
|
||||
// Write implements io.Writer.
|
||||
func (w *QWriter) Write(p []byte) (int, error) {
|
||||
if w.err != nil {
|
||||
return 0, w.err
|
||||
}
|
||||
n, err := w.w.Write(p)
|
||||
if err != nil {
|
||||
w.err = err
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Reset resets QWriter to the original state.
|
||||
func (w *QWriter) Reset() {
|
||||
w.w = nil
|
||||
w.err = nil
|
||||
}
|
||||
|
||||
// S writes s to w.
|
||||
func (w *QWriter) S(s string) {
|
||||
w.Write(unsafeStrToBytes(s))
|
||||
}
|
||||
|
||||
// Z writes z to w.
|
||||
func (w *QWriter) Z(z []byte) {
|
||||
w.Write(z)
|
||||
}
|
||||
|
||||
// SZ is a synonym to Z.
|
||||
func (w *QWriter) SZ(z []byte) {
|
||||
w.Write(z)
|
||||
}
|
||||
|
||||
// D writes n to w.
|
||||
func (w *QWriter) D(n int) {
|
||||
bb, ok := w.w.(*ByteBuffer)
|
||||
if ok {
|
||||
bb.B = strconv.AppendInt(bb.B, int64(n), 10)
|
||||
} else {
|
||||
w.b = strconv.AppendInt(w.b[:0], int64(n), 10)
|
||||
w.Write(w.b)
|
||||
}
|
||||
}
|
||||
|
||||
// F writes f to w.
|
||||
func (w *QWriter) F(f float64) {
|
||||
n := int(f)
|
||||
if float64(n) == f {
|
||||
// Fast path - just int.
|
||||
w.D(n)
|
||||
return
|
||||
}
|
||||
|
||||
// Slow path.
|
||||
w.FPrec(f, -1)
|
||||
}
|
||||
|
||||
// FPrec writes f to w using the given floating point precision.
|
||||
func (w *QWriter) FPrec(f float64, prec int) {
|
||||
bb, ok := w.w.(*ByteBuffer)
|
||||
if ok {
|
||||
bb.B = strconv.AppendFloat(bb.B, f, 'f', prec, 64)
|
||||
} else {
|
||||
w.b = strconv.AppendFloat(w.b[:0], f, 'f', prec, 64)
|
||||
w.Write(w.b)
|
||||
}
|
||||
}
|
||||
|
||||
// Q writes quoted json-safe s to w.
|
||||
func (w *QWriter) Q(s string) {
|
||||
w.Write(strQuote)
|
||||
writeJSONString(w, s)
|
||||
w.Write(strQuote)
|
||||
}
|
||||
|
||||
var strQuote = []byte(`"`)
|
||||
|
||||
// QZ writes quoted json-safe z to w.
|
||||
func (w *QWriter) QZ(z []byte) {
|
||||
w.Q(unsafeBytesToStr(z))
|
||||
}
|
||||
|
||||
// J writes json-safe s to w.
|
||||
//
|
||||
// Unlike Q it doesn't qoute resulting s.
|
||||
func (w *QWriter) J(s string) {
|
||||
writeJSONString(w, s)
|
||||
}
|
||||
|
||||
// JZ writes json-safe z to w.
|
||||
//
|
||||
// Unlike Q it doesn't qoute resulting z.
|
||||
func (w *QWriter) JZ(z []byte) {
|
||||
w.J(unsafeBytesToStr(z))
|
||||
}
|
||||
|
||||
// V writes v to w.
|
||||
func (w *QWriter) V(v interface{}) {
|
||||
fmt.Fprintf(w, "%v", v)
|
||||
}
|
||||
|
||||
// U writes url-encoded s to w.
|
||||
func (w *QWriter) U(s string) {
|
||||
bb, ok := w.w.(*ByteBuffer)
|
||||
if ok {
|
||||
bb.B = appendURLEncode(bb.B, s)
|
||||
} else {
|
||||
w.b = appendURLEncode(w.b[:0], s)
|
||||
w.Write(w.b)
|
||||
}
|
||||
}
|
||||
|
||||
// UZ writes url-encoded z to w.
|
||||
func (w *QWriter) UZ(z []byte) {
|
||||
w.U(unsafeBytesToStr(z))
|
||||
}
|
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@ -179,6 +179,10 @@ github.com/spf13/viper
|
||||
# github.com/stretchr/testify v1.2.2
|
||||
github.com/stretchr/testify/assert
|
||||
github.com/stretchr/testify/require
|
||||
# github.com/valyala/bytebufferpool v1.0.0
|
||||
github.com/valyala/bytebufferpool
|
||||
# github.com/valyala/quicktemplate v1.1.1
|
||||
github.com/valyala/quicktemplate
|
||||
# golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a
|
||||
golang.org/x/crypto/ssh/terminal
|
||||
# golang.org/x/net v0.0.0-20190313220215-9f648a60d977
|
||||
|
Loading…
x
Reference in New Issue
Block a user