Skip to content

Commit

Permalink
v1.1 (gin-gonic#751)
Browse files Browse the repository at this point in the history
* Implement QueryArray and PostArray methods

* Refactor GetQuery and GetPostForm

* Removed additional Iota

I think assigning iota to each constant is not required

* Add 1.7 test.

* Add codecov.io

* corrected a typo in README

* remove coveralls services.

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>

* Update TravisCI to Gitter webhook

* Add codecov.yml Gitter webhook

* Changed imports to gopkg instead of github in README (gin-gonic#733)

* Add contribution guide

* Update go get for stable version

In the future, github default branch will be develop so running `go get github.com/gin-gonic/gin` will pull latest code from develop.

* Changed imports to gopkg instead of github in README

* Update README.md

* Logger: skip ANSI color commands if output is not a tty
  • Loading branch information
javierprovecho authored Dec 3, 2016
1 parent bb159f9 commit 32cab50
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 27 deletions.
6 changes: 2 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@ go:
- tip

script:
- go get golang.org/x/tools/cmd/cover
- go get github.com/mattn/goveralls
- go test -v -covermode=count -coverprofile=coverage.out

after_success:
- goveralls -coverprofile=coverage.out -service=travis-ci -repotoken yFj7FrCeddvBzUaaCyG33jCLfWXeb93eA
- bash <(curl -s https://codecov.io/bash)

notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/acc2c57482e94b44f557
- https://webhooks.gitter.im/e/7f95bf605c4d356372f4
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: false # default: false
26 changes: 12 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@

#Gin Web Framework

<img align="right" src="https://raw.githubusercontent.com/gin-gonic/gin/master/logo.jpg">
[![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin)
[![Coverage Status](https://coveralls.io/repos/gin-gonic/gin/badge.svg?branch=master)](https://coveralls.io/r/gin-gonic/gin?branch=master)
[![codecov](https://codecov.io/gh/gin-gonic/gin/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-gonic/gin)
[![Go Report Card](https://goreportcard.com/badge/github.com/gin-gonic/gin)](https://goreportcard.com/report/github.com/gin-gonic/gin)
[![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.svg)](https://godoc.org/github.com/gin-gonic/gin)
[![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

Gin is a web framework written in Go (Golang). It features a martini-like API with much better performance, up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin.



![Gin console logger](https://gin-gonic.github.io/gin/other/console.png)

```sh
Expand All @@ -19,7 +18,7 @@ $ cat test.go
```go
package main

import "github.com/gin-gonic/gin"
import "gopkg.in/gin-gonic/gin.v1"

func main() {
r := gin.Default()
Expand All @@ -28,7 +27,7 @@ func main() {
"message": "pong",
})
})
r.Run() // listen and server on 0.0.0.0:8080
r.Run() // listen and serve on 0.0.0.0:8080
}
```

Expand Down Expand Up @@ -317,7 +316,7 @@ func main() {
testing.GET("/analytics", analyticsEndpoint)
}
// Listen and server on 0.0.0.0:8080
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
```
Expand Down Expand Up @@ -367,7 +366,7 @@ func main() {
}
})
// Listen and server on 0.0.0.0:8080
// Listen and serve on 0.0.0.0:8080
router.Run(":8080")
}
```
Expand All @@ -378,8 +377,7 @@ func main() {
package main
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"gopkg.in/gin-gonic/gin.v1"
)
type LoginForm struct {
Expand Down Expand Up @@ -447,7 +445,7 @@ func main() {
c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
})
// Listen and server on 0.0.0.0:8080
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
```
Expand All @@ -461,7 +459,7 @@ func main() {
router.StaticFS("/more_static", http.Dir("my_file_system"))
router.StaticFile("/favicon.ico", "./resources/favicon.ico")
// Listen and server on 0.0.0.0:8080
// Listen and serve on 0.0.0.0:8080
router.Run(":8080")
}
```
Expand Down Expand Up @@ -593,7 +591,7 @@ func main() {
log.Println(example)
})
// Listen and server on 0.0.0.0:8080
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
```
Expand Down Expand Up @@ -631,7 +629,7 @@ func main() {
}
})
// Listen and server on 0.0.0.0:8080
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
```
Expand Down Expand Up @@ -664,7 +662,7 @@ func main() {
log.Println("Done! in path " + c.Request.URL.Path)
})
// Listen and server on 0.0.0.0:8080
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
```
Expand Down
5 changes: 5 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
coverage:
notify:
gitter:
default:
url: https://webhooks.gitter.im/e/d90dcdeeab2f1e357165
43 changes: 38 additions & 5 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,27 @@ func (c *Context) DefaultQuery(key, defaultValue string) string {
// ("", false) == c.GetQuery("id")
// ("", true) == c.GetQuery("lastname")
func (c *Context) GetQuery(key string) (string, bool) {
if values, ok := c.GetQueryArray(key); ok {
return values[0], ok
}
return "", false
}

// QueryArray returns a slice of strings for a given query key.
// The length of the slice depends on the number of params with the given key.
func (c *Context) QueryArray(key string) []string {
values, _ := c.GetQueryArray(key)
return values
}

// GetQueryArray returns a slice of strings for a given query key, plus
// a boolean value whether at least one value exists for the given key.
func (c *Context) GetQueryArray(key string) ([]string, bool) {
req := c.Request
if values, ok := req.URL.Query()[key]; ok && len(values) > 0 {
return values[0], true
return values, true
}
return "", false
return []string{}, false
}

// PostForm returns the specified key from a POST urlencoded form or multipart form
Expand Down Expand Up @@ -262,17 +278,34 @@ func (c *Context) DefaultPostForm(key, defaultValue string) string {
// email= --> ("", true) := GetPostForm("email") // set email to ""
// --> ("", false) := GetPostForm("email") // do nothing with email
func (c *Context) GetPostForm(key string) (string, bool) {
if values, ok := c.GetPostFormArray(key); ok {
return values[0], ok
}
return "", false
}

// PostFormArray returns a slice of strings for a given form key.
// The length of the slice depends on the number of params with the given key.
func (c *Context) PostFormArray(key string) []string {
values, _ := c.GetPostFormArray(key)
return values
}

// GetPostFormArray returns a slice of strings for a given form key, plus
// a boolean value whether at least one value exists for the given key.
func (c *Context) GetPostFormArray(key string) ([]string, bool) {
req := c.Request
req.ParseForm()
req.ParseMultipartForm(32 << 20) // 32 MB
if values := req.PostForm[key]; len(values) > 0 {
return values[0], true
return values, true
}
if req.MultipartForm != nil && req.MultipartForm.File != nil {
if values := req.MultipartForm.Value[key]; len(values) > 0 {
return values[0], true
return values, true
}
}
return "", false
return []string{}, false
}

// Bind checks the Content-Type to select a binding engine automatically,
Expand Down
32 changes: 32 additions & 0 deletions context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,22 @@ func TestContextQueryAndPostForm(t *testing.T) {
assert.Equal(t, obj.Page, 11)
assert.Equal(t, obj.Both, "")
assert.Equal(t, obj.Array, []string{"first", "second"})

values, ok := c.GetQueryArray("array[]")
assert.True(t, ok)
assert.Equal(t, "first", values[0])
assert.Equal(t, "second", values[1])

values = c.QueryArray("array[]")
assert.Equal(t, "first", values[0])
assert.Equal(t, "second", values[1])

values = c.QueryArray("nokey")
assert.Equal(t, 0, len(values))

values = c.QueryArray("both")
assert.Equal(t, 1, len(values))
assert.Equal(t, "GET", values[0])
}

func TestContextPostFormMultipart(t *testing.T) {
Expand Down Expand Up @@ -299,6 +315,22 @@ func TestContextPostFormMultipart(t *testing.T) {
assert.False(t, ok)
assert.Empty(t, value)
assert.Equal(t, c.DefaultPostForm("nokey", "nothing"), "nothing")

values, ok := c.GetPostFormArray("array")
assert.True(t, ok)
assert.Equal(t, "first", values[0])
assert.Equal(t, "second", values[1])

values = c.PostFormArray("array")
assert.Equal(t, "first", values[0])
assert.Equal(t, "second", values[1])

values = c.PostFormArray("nokey")
assert.Equal(t, 0, len(values))

values = c.PostFormArray("foo")
assert.Equal(t, 1, len(values))
assert.Equal(t, "bar", values[0])
}

func TestContextSetCookie(t *testing.T) {
Expand Down
15 changes: 13 additions & 2 deletions logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ package gin
import (
"fmt"
"io"
"os"
"time"

"golang.org/x/crypto/ssh/terminal"
)

var (
Expand Down Expand Up @@ -44,6 +47,11 @@ func Logger() HandlerFunc {
// LoggerWithWriter instance a Logger middleware with the specified writter buffer.
// Example: os.Stdout, a file opened in write mode, a socket...
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
isTerm := true
if outFile, ok := out.(*os.File); ok {
isTerm = terminal.IsTerminal(int(outFile.Fd()))
}

var skip map[string]struct{}

if length := len(notlogged); length > 0 {
Expand Down Expand Up @@ -71,8 +79,11 @@ func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc {
clientIP := c.ClientIP()
method := c.Request.Method
statusCode := c.Writer.Status()
statusColor := colorForStatus(statusCode)
methodColor := colorForMethod(method)
var statusColor, methodColor string
if isTerm {
statusColor = colorForStatus(statusCode)
methodColor = colorForMethod(method)
}
comment := c.Errors.ByType(ErrorTypePrivate).String()

fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %s |%s %s %-7s %s\n%s",
Expand Down
4 changes: 2 additions & 2 deletions mode.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ const (
)
const (
debugCode = iota
releaseCode = iota
testCode = iota
releaseCode
testCode
)

// DefaultWriter is the default io.Writer used the Gin for debug output and
Expand Down

0 comments on commit 32cab50

Please sign in to comment.