Browse Source

add interface: query public datasets

tags/v1.21.12.1
yuyuanshifu 5 years ago
parent
commit
c80c882d08
38 changed files with 4219 additions and 138 deletions
  1. +3
    -0
      custom/conf/app.ini.sample
  2. +2
    -0
      go.mod
  3. +6
    -0
      go.sum
  4. +9
    -0
      models/attachment.go
  5. +29
    -0
      modules/context/auth.go
  6. +8
    -0
      modules/setting/setting.go
  7. +43
    -1
      routers/repo/attachment.go
  8. +5
    -0
      routers/routes/routes.go
  9. +20
    -0
      vendor/github.com/go-macaron/auth/LICENSE
  10. +68
    -0
      vendor/github.com/go-macaron/auth/README.md
  11. +59
    -0
      vendor/github.com/go-macaron/auth/basic.go
  12. +44
    -0
      vendor/github.com/go-macaron/auth/bearer.go
  13. +14
    -0
      vendor/github.com/go-macaron/auth/util.go
  14. +1
    -0
      vendor/github.com/go-macaron/auth/wercker.yml
  15. +14
    -0
      vendor/github.com/go-macaron/inject/.travis.yml
  16. +191
    -0
      vendor/github.com/go-macaron/inject/LICENSE
  17. +11
    -0
      vendor/github.com/go-macaron/inject/README.md
  18. +262
    -0
      vendor/github.com/go-macaron/inject/inject.go
  19. +3
    -0
      vendor/gopkg.in/macaron.v1/.gitignore
  20. +191
    -0
      vendor/gopkg.in/macaron.v1/LICENSE
  21. +96
    -0
      vendor/gopkg.in/macaron.v1/README.md
  22. +9
    -0
      vendor/gopkg.in/macaron.v1/codecov.yml
  23. +537
    -0
      vendor/gopkg.in/macaron.v1/context.go
  24. +13
    -0
      vendor/gopkg.in/macaron.v1/go.mod
  25. +32
    -0
      vendor/gopkg.in/macaron.v1/go.sum
  26. +73
    -0
      vendor/gopkg.in/macaron.v1/logger.go
  27. +334
    -0
      vendor/gopkg.in/macaron.v1/macaron.go
  28. BIN
      vendor/gopkg.in/macaron.v1/macaronlogo.png
  29. +163
    -0
      vendor/gopkg.in/macaron.v1/recovery.go
  30. +724
    -0
      vendor/gopkg.in/macaron.v1/render.go
  31. +124
    -0
      vendor/gopkg.in/macaron.v1/response_writer.go
  32. +76
    -0
      vendor/gopkg.in/macaron.v1/return_handler.go
  33. +380
    -0
      vendor/gopkg.in/macaron.v1/router.go
  34. +230
    -0
      vendor/gopkg.in/macaron.v1/static.go
  35. +390
    -0
      vendor/gopkg.in/macaron.v1/tree.go
  36. +25
    -0
      vendor/gopkg.in/macaron.v1/util_go17.go
  37. +24
    -0
      vendor/gopkg.in/macaron.v1/util_go18.go
  38. +6
    -137
      vendor/modules.txt

+ 3
- 0
custom/conf/app.ini.sample View File

@@ -1049,6 +1049,9 @@ RESULT_BACKEND = redis://localhost:6379
HOST = http://192.168.204.24
USERNAME =
PASSWORD =
; cloudbrain visit opendata
USER = cW4cMtH24eoWPE7X
PWD = 4BPmgvK2hb2Eywwyp4YZRY4B7yQf4DAC

[decompress]
HOST = http://192.168.207.34:39987


+ 2
- 0
go.mod View File

@@ -42,6 +42,7 @@ require (
github.com/go-git/go-billy/v5 v5.0.0
github.com/go-git/go-git/v5 v5.0.0
github.com/go-ini/ini v1.56.0 // indirect
github.com/go-macaron/auth v0.0.0-20161228062157-884c0e6c9b92
github.com/go-openapi/jsonreference v0.19.3 // indirect
github.com/go-redis/redis v6.15.2+incompatible
github.com/go-resty/resty/v2 v2.3.0
@@ -121,6 +122,7 @@ require (
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/ini.v1 v1.52.0
gopkg.in/ldap.v3 v3.0.2
gopkg.in/macaron.v1 v1.3.9 // indirect
gopkg.in/testfixtures.v2 v2.5.0
gopkg.in/yaml.v2 v2.2.8
mvdan.cc/xurls/v2 v2.1.0


+ 6
- 0
go.sum View File

@@ -234,6 +234,10 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-macaron/auth v0.0.0-20161228062157-884c0e6c9b92 h1:71YL0o1ch/APk7bmW9jWKBY7ibd9U8NQX2bQ25EJMHI=
github.com/go-macaron/auth v0.0.0-20161228062157-884c0e6c9b92/go.mod h1:saPJfEeea+kiiZJF4GG7TSOao0T/Yrm5rpsqYglss6k=
github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI=
github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw=
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
@@ -1032,6 +1036,8 @@ gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4=
gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ldap.v3 v3.0.2 h1:R6RBtabK6e1GO0eQKtkyOFbAHO73QesLzI2w2DZ6b9w=
gopkg.in/ldap.v3 v3.0.2/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw=
gopkg.in/macaron.v1 v1.3.9 h1:Dw+DDRYdXgQyEsPlfAfKz+UA5qVUrH3KPD7JhmZ9MFc=
gopkg.in/macaron.v1 v1.3.9/go.mod h1:uMZCFccv9yr5TipIalVOyAyZQuOH3OkmXvgcWwhJuP4=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/testfixtures.v2 v2.5.0 h1:N08B7l2GzFQenyYbzqthDnKAA+cmb17iAZhhFxr7JHw=


+ 9
- 0
models/attachment.go View File

@@ -346,3 +346,12 @@ func getUnDecompressAttachments(e Engine) ([]*Attachment, error) {
attachments := make([]*Attachment, 0, 10)
return attachments, e.Where("decompress_state = ? and dataset_id != 0 and name like '%.zip'", DecompressStateInit).Find(&attachments)
}

func GetAllPublicAttachments() ([]*Attachment, error) {
return getAllPublicAttachments(x)
}

func getAllPublicAttachments(e Engine) ([]*Attachment, error) {
attachments := make([]*Attachment, 0, 10)
return attachments, e.Where("is_private = true ").Find(&attachments)
}

+ 29
- 0
modules/context/auth.go View File

@@ -10,9 +10,13 @@ import (
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"encoding/base64"
"net/http"

"gitea.com/macaron/csrf"
"gitea.com/macaron/macaron"

marc_auth "github.com/go-macaron/auth"
)

// ToggleOptions contains required or check options
@@ -21,6 +25,7 @@ type ToggleOptions struct {
SignOutRequired bool
AdminRequired bool
DisableCSRF bool
BasicAuthRequired bool
}

// Toggle returns toggle options as middleware
@@ -130,5 +135,29 @@ func Toggle(options *ToggleOptions) macaron.Handler {
}
ctx.Data["PageIsAdmin"] = true
}

if options.BasicAuthRequired {
if !basicAuth(ctx) {
basicUnauthorized(ctx.Resp)
return
}
}
}
}

func basicAuth(ctx *Context) bool {
var siteAuth = base64.StdEncoding.EncodeToString([]byte(setting.CBAuthUser + ":" + setting.CBAuthPassword))
auth := ctx.Req.Header.Get("Authorization")

if !marc_auth.SecureCompare(auth, "Basic " + siteAuth) {
return false
}

return true

}

func basicUnauthorized(res http.ResponseWriter) {
res.Header().Set("WWW-Authenticate", "Basic realm=\"" + marc_auth.BasicRealm + "\"")
http.Error(res, "Not Authorized", http.StatusUnauthorized)
}

+ 8
- 0
modules/setting/setting.go View File

@@ -430,6 +430,10 @@ var (
DecompressAddress string
AuthUser string
AuthPassword string

//cloudbrain config
CBAuthUser string
CBAuthPassword string
)

// DateLang transforms standard language locale name to corresponding value in datetime plugin.
@@ -1097,6 +1101,10 @@ func NewContext() {
DecompressAddress = sec.Key("HOST").MustString("http://192.168.207.34:39987")
AuthUser = sec.Key("USER").MustString("cW4cMtH24eoWPE7X")
AuthPassword = sec.Key("PASSWORD").MustString("4BPmgvK2hb2Eywwyp4YZRY4B7yQf4DAC")

sec = Cfg.Section("cloudbrain")
CBAuthUser = sec.Key("USER").MustString("cW4cMtH24eoWPE7X")
CBAuthPassword = sec.Key("PWD").MustString("4BPmgvK2hb2Eywwyp4YZRY4B7yQf4DAC")
}

func loadInternalToken(sec *ini.Section) string {


+ 43
- 1
routers/repo/attachment.go View File

@@ -6,6 +6,7 @@ package repo

import (
contexExt "context"
"encoding/json"
"fmt"
"net/http"
"strconv"
@@ -29,6 +30,11 @@ const (
DecompressFailed = "1"
)

type PublicDataset struct {
Name string `json:"name"`
Path string `json:"path"`
}

func RenderAttachmentSettings(ctx *context.Context) {
renderAttachmentSettings(ctx)
}
@@ -374,7 +380,7 @@ func GetSuccessChunks(ctx *context.Context) {

chunks, err = storage.GetPartInfos(fileChunk.UUID, fileChunk.UploadID)
if err != nil {
ctx.ServerError("json.Marshal failed", err)
ctx.ServerError("GetPartInfos failed", err)
return
}
}
@@ -601,3 +607,39 @@ func HandleUnDecompressAttachment() {

return
}

func QueryAllPublicDataset(ctx *context.Context){
log.Info("QueryAllPublicDataset")

attachs, err := models.GetAllPublicAttachments()
if err != nil {
ctx.JSON(200, map[string]string{
"result_code": "-1",
"data": "",
})
return
}

var publicDatasets []PublicDataset
for _, attch := range attachs {
publicDatasets = append(publicDatasets, PublicDataset{attch.Name,
models.AttachmentRelativePath(attch.UUID)})
}

data,err := json.Marshal(publicDatasets)
if err != nil {
log.Error("json.Marshal failed:", err.Error())
ctx.JSON(200, map[string]string{
"result_code": "-1",
"data": "",
})
return
}

log.Info(string(data))

ctx.JSON(200, map[string]string{
"result_code": "0",
"data": string(data),
})
}

+ 5
- 0
routers/routes/routes.go View File

@@ -245,6 +245,7 @@ func RegisterRoutes(m *macaron.Macaron) {
ignSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: setting.Service.RequireSignInView})
ignSignInAndCsrf := context.Toggle(&context.ToggleOptions{DisableCSRF: true})
reqSignOut := context.Toggle(&context.ToggleOptions{SignOutRequired: true})
reqBasicAuth := context.Toggle(&context.ToggleOptions{BasicAuthRequired:true})

bindIgnErr := binding.BindIgnErr
validation.AddBindingRules()
@@ -533,6 +534,10 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/decompress_done_notify", repo.UpdateAttachmentDecompressState)
})

m.Group("/attachments/public", func() {
m.Get("/query", repo.QueryAllPublicDataset)
}, reqBasicAuth)

m.Group("/:username", func() {
m.Post("/action/:action", user.Action)
}, reqSignIn)


+ 20
- 0
vendor/github.com/go-macaron/auth/LICENSE View File

@@ -0,0 +1,20 @@
The MIT License (MIT)

Copyright (c) 2013 Jeremy Saenz

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.

+ 68
- 0
vendor/github.com/go-macaron/auth/README.md View File

@@ -0,0 +1,68 @@
# auth
Macaron middleware/handler for http basic authentication. Modified from <https://github.com/martini-contrib/auth>

[API Reference](http://godoc.org/github.com/go-macaron/auth)

## Simple Usage

Use `auth.Basic` to authenticate against a pre-defined username and password:

~~~ go
import (
"gopkg.in/macaron.v1"
"github.com/go-macaron/auth"
)

func main() {
m := macaron.Classic()
// authenticate every request
m.Use(auth.Basic("username", "secretpassword"))
m.Run()
}
~~~

## Advanced Usage

Using `auth.BasicFunc` lets you authenticate on a per-user level, by checking
the username and password in the callback function:

~~~ go
import (
"gopkg.in/macaron.v1"
"github.com/go-macaron/auth"
)

func main() {
m := macaron.Classic()
// authenticate every request
m.Use(auth.BasicFunc(func(username, password string) bool {
return username == "admin" && password == "guessme"
}))
m.Run()
}
~~~

Note that checking usernames and passwords with string comparison might be
susceptible to timing attacks. To avoid that, use `auth.SecureCompare` instead:

~~~ go
m.Use(auth.BasicFunc(func(username, password string) bool {
return auth.SecureCompare(username, "admin") && auth.SecureCompare(password, "guessme")
}))
}
~~~

Upon successful authentication, the username is available to all subsequent
handlers via the `auth.User` type:

~~~ go
m.Get("/", func(user auth.User) string {
return "Welcome, " + string(user)
})
}
~~~

## Authors
* [Jeremy Saenz](https://github.com/codegangsta)
* [Brendon Murphy](https://github.com/bemurphy)
* [codeskyblue](https://github.com/codeskyblue)

+ 59
- 0
vendor/github.com/go-macaron/auth/basic.go View File

@@ -0,0 +1,59 @@
package auth

import (
"encoding/base64"
"net/http"
"strings"

"gopkg.in/macaron.v1"
)

// User is the authenticated username that was extracted from the request.
type User string

// BasicRealm is used when setting the WWW-Authenticate response header.
var BasicRealm = "Authorization Required"
var basicPrefix = "Basic "

// Basic returns a Handler that authenticates via Basic Auth. Writes a http.StatusUnauthorized
// if authentication fails.
func Basic(username string, password string) macaron.Handler {
var siteAuth = base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) {
auth := req.Header.Get("Authorization")
if !SecureCompare(auth, basicPrefix+siteAuth) {
basicUnauthorized(res)
return
}
c.Map(User(username))
}
}

// BasicFunc returns a Handler that authenticates via Basic Auth using the provided function.
// The function should return true for a valid username/password combination.
func BasicFunc(authfn func(string, string) bool) macaron.Handler {
return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) {
auth := req.Header.Get("Authorization")
n := len(basicPrefix)
if len(auth) < n || auth[:n] != basicPrefix {
basicUnauthorized(res)
return
}
b, err := base64.StdEncoding.DecodeString(auth[n:])
if err != nil {
basicUnauthorized(res)
return
}
tokens := strings.SplitN(string(b), ":", 2)
if len(tokens) != 2 || !authfn(tokens[0], tokens[1]) {
basicUnauthorized(res)
return
}
c.Map(User(tokens[0]))
}
}

func basicUnauthorized(res http.ResponseWriter) {
res.Header().Set("WWW-Authenticate", "Basic realm=\""+BasicRealm+"\"")
http.Error(res, "Not Authorized", http.StatusUnauthorized)
}

+ 44
- 0
vendor/github.com/go-macaron/auth/bearer.go View File

@@ -0,0 +1,44 @@
package auth

import (
"net/http"

"gopkg.in/macaron.v1"
)

var bearerPrefix = "Bearer "

// Bearer returns a Handler that authenticates via Bearer Auth. Writes a http.StatusUnauthorized
// if authentication fails.
func Bearer(token string) macaron.Handler {
return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) {
auth := req.Header.Get("Authorization")
if !SecureCompare(auth, bearerPrefix+token) {
bearerUnauthorized(res)
return
}
c.Map(User(""))
}
}

// BearerFunc returns a Handler that authenticates via Bearer Auth using the provided function.
// The function should return true for a valid bearer token.
func BearerFunc(authfn func(string) bool) macaron.Handler {
return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) {
auth := req.Header.Get("Authorization")
n := len(bearerPrefix)
if len(auth) < n || auth[:n] != bearerPrefix {
bearerUnauthorized(res)
return
}
if !authfn(auth[n:]) {
bearerUnauthorized(res)
return
}
c.Map(User(""))
}
}

func bearerUnauthorized(res http.ResponseWriter) {
http.Error(res, "Not Authorized", http.StatusUnauthorized)
}

+ 14
- 0
vendor/github.com/go-macaron/auth/util.go View File

@@ -0,0 +1,14 @@
package auth

import (
"crypto/sha512"
"crypto/subtle"
)

// SecureCompare performs a constant time compare of two strings to limit timing attacks.
func SecureCompare(given string, actual string) bool {
givenSha := sha512.Sum512([]byte(given))
actualSha := sha512.Sum512([]byte(actual))

return subtle.ConstantTimeCompare(givenSha[:], actualSha[:]) == 1
}

+ 1
- 0
vendor/github.com/go-macaron/auth/wercker.yml View File

@@ -0,0 +1 @@
box: wercker/golang@1.1.1

+ 14
- 0
vendor/github.com/go-macaron/inject/.travis.yml View File

@@ -0,0 +1,14 @@
sudo: false
language: go

go:
- 1.3
- 1.4
- 1.5
- tip

script: go test -v -cover -race

notifications:
email:
- u@gogs.io

+ 191
- 0
vendor/github.com/go-macaron/inject/LICENSE View File

@@ -0,0 +1,191 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.

"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.

"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.

"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.

"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.

"Object" form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.

"Work" shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).

"Derivative Works" shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.

"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."

"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.

2. Grant of Copyright License.

Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.

3. Grant of Patent License.

Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.

4. Redistribution.

You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:

You must give any other recipients of the Work or Derivative Works a copy of
this License; and
You must cause any modified files to carry prominent notices stating that You
changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.

5. Submission of Contributions.

Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.

6. Trademarks.

This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.

7. Disclaimer of Warranty.

Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.

8. Limitation of Liability.

In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability.

While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work

To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "[]" replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within
third-party archives.

Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

+ 11
- 0
vendor/github.com/go-macaron/inject/README.md View File

@@ -0,0 +1,11 @@
# inject [![Build Status](https://travis-ci.org/go-macaron/inject.svg?branch=master)](https://travis-ci.org/go-macaron/inject) [![](http://gocover.io/_badge/github.com/go-macaron/inject)](http://gocover.io/github.com/go-macaron/inject)

Package inject provides utilities for mapping and injecting dependencies in various ways.

**This a modified version of [codegangsta/inject](https://github.com/codegangsta/inject) for special purpose of Macaron**

**Please use the original version if you need dependency injection feature**

## License

This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text.

+ 262
- 0
vendor/github.com/go-macaron/inject/inject.go View File

@@ -0,0 +1,262 @@
// Copyright 2013 Jeremy Saenz
// Copyright 2015 The Macaron Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

// Package inject provides utilities for mapping and injecting dependencies in various ways.
package inject

import (
"fmt"
"reflect"
)

// Injector represents an interface for mapping and injecting dependencies into structs
// and function arguments.
type Injector interface {
Applicator
Invoker
TypeMapper
// SetParent sets the parent of the injector. If the injector cannot find a
// dependency in its Type map it will check its parent before returning an
// error.
SetParent(Injector)
}

// Applicator represents an interface for mapping dependencies to a struct.
type Applicator interface {
// Maps dependencies in the Type map to each field in the struct
// that is tagged with 'inject'. Returns an error if the injection
// fails.
Apply(interface{}) error
}

// Invoker represents an interface for calling functions via reflection.
type Invoker interface {
// Invoke attempts to call the interface{} provided as a function,
// providing dependencies for function arguments based on Type. Returns
// a slice of reflect.Value representing the returned values of the function.
// Returns an error if the injection fails.
Invoke(interface{}) ([]reflect.Value, error)
}

// FastInvoker represents an interface in order to avoid the calling function via reflection.
//
// example:
// type handlerFuncHandler func(http.ResponseWriter, *http.Request) error
// func (f handlerFuncHandler)Invoke([]interface{}) ([]reflect.Value, error){
// ret := f(p[0].(http.ResponseWriter), p[1].(*http.Request))
// return []reflect.Value{reflect.ValueOf(ret)}, nil
// }
//
// type funcHandler func(int, string)
// func (f funcHandler)Invoke([]interface{}) ([]reflect.Value, error){
// f(p[0].(int), p[1].(string))
// return nil, nil
// }
type FastInvoker interface {
// Invoke attempts to call the ordinary functions. If f is a function
// with the appropriate signature, f.Invoke([]interface{}) is a Call that calls f.
// Returns a slice of reflect.Value representing the returned values of the function.
// Returns an error if the injection fails.
Invoke([]interface{}) ([]reflect.Value, error)
}

// IsFastInvoker check interface is FastInvoker
func IsFastInvoker(h interface{}) bool {
_, ok := h.(FastInvoker)
return ok
}

// TypeMapper represents an interface for mapping interface{} values based on type.
type TypeMapper interface {
// Maps the interface{} value based on its immediate type from reflect.TypeOf.
Map(interface{}) TypeMapper
// Maps the interface{} value based on the pointer of an Interface provided.
// This is really only useful for mapping a value as an interface, as interfaces
// cannot at this time be referenced directly without a pointer.
MapTo(interface{}, interface{}) TypeMapper
// Provides a possibility to directly insert a mapping based on type and value.
// This makes it possible to directly map type arguments not possible to instantiate
// with reflect like unidirectional channels.
Set(reflect.Type, reflect.Value) TypeMapper
// Returns the Value that is mapped to the current type. Returns a zeroed Value if
// the Type has not been mapped.
GetVal(reflect.Type) reflect.Value
}

type injector struct {
values map[reflect.Type]reflect.Value
parent Injector
}

// InterfaceOf dereferences a pointer to an Interface type.
// It panics if value is not an pointer to an interface.
func InterfaceOf(value interface{}) reflect.Type {
t := reflect.TypeOf(value)

for t.Kind() == reflect.Ptr {
t = t.Elem()
}

if t.Kind() != reflect.Interface {
panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)")
}

return t
}

// New returns a new Injector.
func New() Injector {
return &injector{
values: make(map[reflect.Type]reflect.Value),
}
}

// Invoke attempts to call the interface{} provided as a function,
// providing dependencies for function arguments based on Type.
// Returns a slice of reflect.Value representing the returned values of the function.
// Returns an error if the injection fails.
// It panics if f is not a function
func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) {
t := reflect.TypeOf(f)
switch v := f.(type) {
case FastInvoker:
return inj.fastInvoke(v, t, t.NumIn())
default:
return inj.callInvoke(f, t, t.NumIn())
}
}

func (inj *injector) fastInvoke(f FastInvoker, t reflect.Type, numIn int) ([]reflect.Value, error) {
var in []interface{}
if numIn > 0 {
in = make([]interface{}, numIn) // Panic if t is not kind of Func
var argType reflect.Type
var val reflect.Value
for i := 0; i < numIn; i++ {
argType = t.In(i)
val = inj.GetVal(argType)
if !val.IsValid() {
return nil, fmt.Errorf("Value not found for type %v", argType)
}

in[i] = val.Interface()
}
}
return f.Invoke(in)
}

// callInvoke reflect.Value.Call
func (inj *injector) callInvoke(f interface{}, t reflect.Type, numIn int) ([]reflect.Value, error) {
var in []reflect.Value
if numIn > 0 {
in = make([]reflect.Value, numIn)
var argType reflect.Type
var val reflect.Value
for i := 0; i < numIn; i++ {
argType = t.In(i)
val = inj.GetVal(argType)
if !val.IsValid() {
return nil, fmt.Errorf("Value not found for type %v", argType)
}

in[i] = val
}
}
return reflect.ValueOf(f).Call(in), nil
}

// Maps dependencies in the Type map to each field in the struct
// that is tagged with 'inject'.
// Returns an error if the injection fails.
func (inj *injector) Apply(val interface{}) error {
v := reflect.ValueOf(val)

for v.Kind() == reflect.Ptr {
v = v.Elem()
}

if v.Kind() != reflect.Struct {
return nil // Should not panic here ?
}

t := v.Type()

for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
structField := t.Field(i)
if f.CanSet() && (structField.Tag == "inject" || structField.Tag.Get("inject") != "") {
ft := f.Type()
v := inj.GetVal(ft)
if !v.IsValid() {
return fmt.Errorf("Value not found for type %v", ft)
}

f.Set(v)
}

}

return nil
}

// Maps the concrete value of val to its dynamic type using reflect.TypeOf,
// It returns the TypeMapper registered in.
func (i *injector) Map(val interface{}) TypeMapper {
i.values[reflect.TypeOf(val)] = reflect.ValueOf(val)
return i
}

func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper {
i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val)
return i
}

// Maps the given reflect.Type to the given reflect.Value and returns
// the Typemapper the mapping has been registered in.
func (i *injector) Set(typ reflect.Type, val reflect.Value) TypeMapper {
i.values[typ] = val
return i
}

func (i *injector) GetVal(t reflect.Type) reflect.Value {
val := i.values[t]

if val.IsValid() {
return val
}

// no concrete types found, try to find implementors
// if t is an interface
if t.Kind() == reflect.Interface {
for k, v := range i.values {
if k.Implements(t) {
val = v
break
}
}
}

// Still no type found, try to look it up on the parent
if !val.IsValid() && i.parent != nil {
val = i.parent.GetVal(t)
}

return val

}

func (i *injector) SetParent(parent Injector) {
i.parent = parent
}

+ 3
- 0
vendor/gopkg.in/macaron.v1/.gitignore View File

@@ -0,0 +1,3 @@
macaron.sublime-project
macaron.sublime-workspace
.idea

+ 191
- 0
vendor/gopkg.in/macaron.v1/LICENSE View File

@@ -0,0 +1,191 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.

"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.

"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.

"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.

"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.

"Object" form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.

"Work" shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).

"Derivative Works" shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.

"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."

"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.

2. Grant of Copyright License.

Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.

3. Grant of Patent License.

Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.

4. Redistribution.

You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:

You must give any other recipients of the Work or Derivative Works a copy of
this License; and
You must cause any modified files to carry prominent notices stating that You
changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.

5. Submission of Contributions.

Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.

6. Trademarks.

This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.

7. Disclaimer of Warranty.

Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.

8. Limitation of Liability.

In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability.

While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work

To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "[]" replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within
third-party archives.

Copyright 2014 The Macaron Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

+ 96
- 0
vendor/gopkg.in/macaron.v1/README.md View File

@@ -0,0 +1,96 @@
# Macaron

[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/go-macaron/macaron/Go?logo=github&style=for-the-badge)](https://github.com/go-macaron/macaron/actions?query=workflow%3AGo)
[![codecov](https://img.shields.io/codecov/c/github/go-macaron/macaron/master?logo=codecov&style=for-the-badge)](https://codecov.io/gh/go-macaron/macaron)
[![GoDoc](https://img.shields.io/badge/GoDoc-Reference-blue?style=for-the-badge&logo=go)](https://pkg.go.dev/gopkg.in/macaron.v1?tab=doc)
[![Sourcegraph](https://img.shields.io/badge/view%20on-Sourcegraph-brightgreen.svg?style=for-the-badge&logo=sourcegraph)](https://sourcegraph.com/github.com/go-macaron/macaron)

![Macaron Logo](https://raw.githubusercontent.com/go-macaron/macaron/v1/macaronlogo.png)

Package macaron is a high productive and modular web framework in Go.

## Getting Started

The minimum requirement of Go is **1.6**.

To install Macaron:

go get gopkg.in/macaron.v1

The very basic usage of Macaron:

```go
package main

import "gopkg.in/macaron.v1"

func main() {
m := macaron.Classic()
m.Get("/", func() string {
return "Hello world!"
})
m.Run()
}
```

## Features

- Powerful routing with suburl.
- Flexible routes combinations.
- Unlimited nested group routers.
- Directly integrate with existing services.
- Dynamically change template files at runtime.
- Allow to use in-memory template and static files.
- Easy to plugin/unplugin features with modular design.
- Handy dependency injection powered by [inject](https://github.com/codegangsta/inject).
- Better router layer and less reflection make faster speed.

## Middlewares

Middlewares allow you easily plugin/unplugin features for your Macaron applications.

There are already many [middlewares](https://github.com/go-macaron) to simplify your work:

- render - Go template engine
- static - Serves static files
- [gzip](https://github.com/go-macaron/gzip) - Gzip compression to all responses
- [binding](https://github.com/go-macaron/binding) - Request data binding and validation
- [i18n](https://github.com/go-macaron/i18n) - Internationalization and Localization
- [cache](https://github.com/go-macaron/cache) - Cache manager
- [session](https://github.com/go-macaron/session) - Session manager
- [csrf](https://github.com/go-macaron/csrf) - Generates and validates csrf tokens
- [captcha](https://github.com/go-macaron/captcha) - Captcha service
- [pongo2](https://github.com/go-macaron/pongo2) - Pongo2 template engine support
- [sockets](https://github.com/go-macaron/sockets) - WebSockets channels binding
- [bindata](https://github.com/go-macaron/bindata) - Embed binary data as static and template files
- [toolbox](https://github.com/go-macaron/toolbox) - Health check, pprof, profile and statistic services
- [oauth2](https://github.com/go-macaron/oauth2) - OAuth 2.0 backend
- [authz](https://github.com/go-macaron/authz) - ACL/RBAC/ABAC authorization based on Casbin
- [switcher](https://github.com/go-macaron/switcher) - Multiple-site support
- [method](https://github.com/go-macaron/method) - HTTP method override
- [permissions2](https://github.com/xyproto/permissions2) - Cookies, users and permissions
- [renders](https://github.com/go-macaron/renders) - Beego-like render engine(Macaron has built-in template engine, this is another option)
- [piwik](https://github.com/veecue/piwik-middleware) - Server-side piwik analytics

## Use Cases

- [Gogs](https://gogs.io): A painless self-hosted Git Service
- [Grafana](http://grafana.org/): The open platform for beautiful analytics and monitoring
- [Peach](https://peachdocs.org): A modern web documentation server
- [Go Walker](https://gowalker.org): Go online API documentation
- [Critical Stack Intel](https://intel.criticalstack.com/): A 100% free intel marketplace from Critical Stack, Inc.

## Getting Help

- [API Reference](https://gowalker.org/gopkg.in/macaron.v1)
- [Documentation](https://go-macaron.com)
- [FAQs](https://go-macaron.com/docs/faqs)

## Credits

- Basic design of [Martini](https://github.com/go-martini/martini).
- Logo is modified by [@insionng](https://github.com/insionng) based on [Tribal Dragon](http://xtremeyamazaki.deviantart.com/art/Tribal-Dragon-27005087).

## License

This project is under the Apache License, Version 2.0. See the [LICENSE](LICENSE) file for the full license text.

+ 9
- 0
vendor/gopkg.in/macaron.v1/codecov.yml View File

@@ -0,0 +1,9 @@
coverage:
range: "60...95"
status:
project:
default:
threshold: 1%

comment:
layout: 'diff, files'

+ 537
- 0
vendor/gopkg.in/macaron.v1/context.go View File

@@ -0,0 +1,537 @@
// Copyright 2014 The Macaron Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package macaron

import (
"crypto/sha256"
"encoding/hex"
"html/template"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"reflect"
"strconv"
"strings"
"time"

"github.com/go-macaron/inject"
"github.com/unknwon/com"
"golang.org/x/crypto/pbkdf2"
)

// Locale reprents a localization interface.
type Locale interface {
Language() string
Tr(string, ...interface{}) string
}

// RequestBody represents a request body.
type RequestBody struct {
reader io.ReadCloser
}

// Bytes reads and returns content of request body in bytes.
func (rb *RequestBody) Bytes() ([]byte, error) {
return ioutil.ReadAll(rb.reader)
}

// String reads and returns content of request body in string.
func (rb *RequestBody) String() (string, error) {
data, err := rb.Bytes()
return string(data), err
}

// ReadCloser returns a ReadCloser for request body.
func (rb *RequestBody) ReadCloser() io.ReadCloser {
return rb.reader
}

// Request represents an HTTP request received by a server or to be sent by a client.
type Request struct {
*http.Request
}

func (r *Request) Body() *RequestBody {
return &RequestBody{r.Request.Body}
}

// ContextInvoker is an inject.FastInvoker wrapper of func(ctx *Context).
type ContextInvoker func(ctx *Context)

func (invoke ContextInvoker) Invoke(params []interface{}) ([]reflect.Value, error) {
invoke(params[0].(*Context))
return nil, nil
}

// Context represents the runtime context of current request of Macaron instance.
// It is the integration of most frequently used middlewares and helper methods.
type Context struct {
inject.Injector
handlers []Handler
action Handler
index int

*Router
Req Request
Resp ResponseWriter
params Params
Render
Locale
Data map[string]interface{}
}

func (c *Context) handler() Handler {
if c.index < len(c.handlers) {
return c.handlers[c.index]
}
if c.index == len(c.handlers) {
return c.action
}
panic("invalid index for context handler")
}

func (c *Context) Next() {
c.index += 1
c.run()
}

func (c *Context) Written() bool {
return c.Resp.Written()
}

func (c *Context) run() {
for c.index <= len(c.handlers) {
vals, err := c.Invoke(c.handler())
if err != nil {
panic(err)
}
c.index += 1

// if the handler returned something, write it to the http response
if len(vals) > 0 {
ev := c.GetVal(reflect.TypeOf(ReturnHandler(nil)))
handleReturn := ev.Interface().(ReturnHandler)
handleReturn(c, vals)
}

if c.Written() {
return
}
}
}

// RemoteAddr returns more real IP address.
func (ctx *Context) RemoteAddr() string {
addr := ctx.Req.Header.Get("X-Real-IP")
if len(addr) == 0 {
addr = ctx.Req.Header.Get("X-Forwarded-For")
if addr == "" {
addr = ctx.Req.RemoteAddr
if i := strings.LastIndex(addr, ":"); i > -1 {
addr = addr[:i]
}
}
}
return addr
}

func (ctx *Context) renderHTML(status int, setName, tplName string, data ...interface{}) {
if len(data) <= 0 {
ctx.Render.HTMLSet(status, setName, tplName, ctx.Data)
} else if len(data) == 1 {
ctx.Render.HTMLSet(status, setName, tplName, data[0])
} else {
ctx.Render.HTMLSet(status, setName, tplName, data[0], data[1].(HTMLOptions))
}
}

// HTML renders the HTML with default template set.
func (ctx *Context) HTML(status int, name string, data ...interface{}) {
ctx.renderHTML(status, DEFAULT_TPL_SET_NAME, name, data...)
}

// HTMLSet renders the HTML with given template set name.
func (ctx *Context) HTMLSet(status int, setName, tplName string, data ...interface{}) {
ctx.renderHTML(status, setName, tplName, data...)
}

func (ctx *Context) Redirect(location string, status ...int) {
code := http.StatusFound
if len(status) == 1 {
code = status[0]
}

http.Redirect(ctx.Resp, ctx.Req.Request, location, code)
}

// Maximum amount of memory to use when parsing a multipart form.
// Set this to whatever value you prefer; default is 10 MB.
var MaxMemory = int64(1024 * 1024 * 10)

func (ctx *Context) parseForm() {
if ctx.Req.Form != nil {
return
}

contentType := ctx.Req.Header.Get(_CONTENT_TYPE)
if (ctx.Req.Method == "POST" || ctx.Req.Method == "PUT") &&
len(contentType) > 0 && strings.Contains(contentType, "multipart/form-data") {
_ = ctx.Req.ParseMultipartForm(MaxMemory)
} else {
_ = ctx.Req.ParseForm()
}
}

// Query querys form parameter.
func (ctx *Context) Query(name string) string {
ctx.parseForm()
return ctx.Req.Form.Get(name)
}

// QueryTrim querys and trims spaces form parameter.
func (ctx *Context) QueryTrim(name string) string {
return strings.TrimSpace(ctx.Query(name))
}

// QueryStrings returns a list of results by given query name.
func (ctx *Context) QueryStrings(name string) []string {
ctx.parseForm()

vals, ok := ctx.Req.Form[name]
if !ok {
return []string{}
}
return vals
}

// QueryEscape returns escapred query result.
func (ctx *Context) QueryEscape(name string) string {
return template.HTMLEscapeString(ctx.Query(name))
}

// QueryBool returns query result in bool type.
func (ctx *Context) QueryBool(name string) bool {
v, _ := strconv.ParseBool(ctx.Query(name))
return v
}

// QueryInt returns query result in int type.
func (ctx *Context) QueryInt(name string) int {
return com.StrTo(ctx.Query(name)).MustInt()
}

// QueryInt64 returns query result in int64 type.
func (ctx *Context) QueryInt64(name string) int64 {
return com.StrTo(ctx.Query(name)).MustInt64()
}

// QueryFloat64 returns query result in float64 type.
func (ctx *Context) QueryFloat64(name string) float64 {
v, _ := strconv.ParseFloat(ctx.Query(name), 64)
return v
}

// Params returns value of given param name.
// e.g. ctx.Params(":uid") or ctx.Params("uid")
func (ctx *Context) Params(name string) string {
if len(name) == 0 {
return ""
}
if len(name) > 1 && name[0] != ':' {
name = ":" + name
}
return ctx.params[name]
}

// AllParams returns all params.
func (ctx *Context) AllParams() Params {
return ctx.params
}

// SetParams sets value of param with given name.
func (ctx *Context) SetParams(name, val string) {
if name != "*" && !strings.HasPrefix(name, ":") {
name = ":" + name
}
ctx.params[name] = val
}

// ReplaceAllParams replace all current params with given params
func (ctx *Context) ReplaceAllParams(params Params) {
ctx.params = params
}

// ParamsEscape returns escapred params result.
// e.g. ctx.ParamsEscape(":uname")
func (ctx *Context) ParamsEscape(name string) string {
return template.HTMLEscapeString(ctx.Params(name))
}

// ParamsInt returns params result in int type.
// e.g. ctx.ParamsInt(":uid")
func (ctx *Context) ParamsInt(name string) int {
return com.StrTo(ctx.Params(name)).MustInt()
}

// ParamsInt64 returns params result in int64 type.
// e.g. ctx.ParamsInt64(":uid")
func (ctx *Context) ParamsInt64(name string) int64 {
return com.StrTo(ctx.Params(name)).MustInt64()
}

// ParamsFloat64 returns params result in int64 type.
// e.g. ctx.ParamsFloat64(":uid")
func (ctx *Context) ParamsFloat64(name string) float64 {
v, _ := strconv.ParseFloat(ctx.Params(name), 64)
return v
}

// GetFile returns information about user upload file by given form field name.
func (ctx *Context) GetFile(name string) (multipart.File, *multipart.FileHeader, error) {
return ctx.Req.FormFile(name)
}

// SaveToFile reads a file from request by field name and saves to given path.
func (ctx *Context) SaveToFile(name, savePath string) error {
fr, _, err := ctx.GetFile(name)
if err != nil {
return err
}
defer fr.Close()

fw, err := os.OpenFile(savePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer fw.Close()

_, err = io.Copy(fw, fr)
return err
}

// SetCookie sets given cookie value to response header.
// FIXME: IE support? http://golanghome.com/post/620#reply2
func (ctx *Context) SetCookie(name string, value string, others ...interface{}) {
cookie := http.Cookie{}
cookie.Name = name
cookie.Value = url.QueryEscape(value)

if len(others) > 0 {
switch v := others[0].(type) {
case int:
cookie.MaxAge = v
case int64:
cookie.MaxAge = int(v)
case int32:
cookie.MaxAge = int(v)
}
}

cookie.Path = "/"
if len(others) > 1 {
if v, ok := others[1].(string); ok && len(v) > 0 {
cookie.Path = v
}
}

if len(others) > 2 {
if v, ok := others[2].(string); ok && len(v) > 0 {
cookie.Domain = v
}
}

if len(others) > 3 {
switch v := others[3].(type) {
case bool:
cookie.Secure = v
default:
if others[3] != nil {
cookie.Secure = true
}
}
}

if len(others) > 4 {
if v, ok := others[4].(bool); ok && v {
cookie.HttpOnly = true
}
}

if len(others) > 5 {
if v, ok := others[5].(time.Time); ok {
cookie.Expires = v
cookie.RawExpires = v.Format(time.UnixDate)
}
}

ctx.Resp.Header().Add("Set-Cookie", cookie.String())
}

// GetCookie returns given cookie value from request header.
func (ctx *Context) GetCookie(name string) string {
cookie, err := ctx.Req.Cookie(name)
if err != nil {
return ""
}
val, _ := url.QueryUnescape(cookie.Value)
return val
}

// GetCookieInt returns cookie result in int type.
func (ctx *Context) GetCookieInt(name string) int {
return com.StrTo(ctx.GetCookie(name)).MustInt()
}

// GetCookieInt64 returns cookie result in int64 type.
func (ctx *Context) GetCookieInt64(name string) int64 {
return com.StrTo(ctx.GetCookie(name)).MustInt64()
}

// GetCookieFloat64 returns cookie result in float64 type.
func (ctx *Context) GetCookieFloat64(name string) float64 {
v, _ := strconv.ParseFloat(ctx.GetCookie(name), 64)
return v
}

var defaultCookieSecret string

// SetDefaultCookieSecret sets global default secure cookie secret.
func (m *Macaron) SetDefaultCookieSecret(secret string) {
defaultCookieSecret = secret
}

// SetSecureCookie sets given cookie value to response header with default secret string.
func (ctx *Context) SetSecureCookie(name, value string, others ...interface{}) {
ctx.SetSuperSecureCookie(defaultCookieSecret, name, value, others...)
}

// GetSecureCookie returns given cookie value from request header with default secret string.
func (ctx *Context) GetSecureCookie(key string) (string, bool) {
return ctx.GetSuperSecureCookie(defaultCookieSecret, key)
}

// SetSuperSecureCookie sets given cookie value to response header with secret string.
func (ctx *Context) SetSuperSecureCookie(secret, name, value string, others ...interface{}) {
key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New)
text, err := com.AESGCMEncrypt(key, []byte(value))
if err != nil {
panic("error encrypting cookie: " + err.Error())
}

ctx.SetCookie(name, hex.EncodeToString(text), others...)
}

// GetSuperSecureCookie returns given cookie value from request header with secret string.
func (ctx *Context) GetSuperSecureCookie(secret, name string) (string, bool) {
val := ctx.GetCookie(name)
if val == "" {
return "", false
}

text, err := hex.DecodeString(val)
if err != nil {
return "", false
}

key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New)
text, err = com.AESGCMDecrypt(key, text)
return string(text), err == nil
}

func (ctx *Context) setRawContentHeader() {
ctx.Resp.Header().Set("Content-Description", "Raw content")
ctx.Resp.Header().Set("Content-Type", "text/plain")
ctx.Resp.Header().Set("Expires", "0")
ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
ctx.Resp.Header().Set("Pragma", "public")
}

// ServeContent serves given content to response.
func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) {
modtime := time.Now()
for _, p := range params {
switch v := p.(type) {
case time.Time:
modtime = v
}
}

ctx.setRawContentHeader()
http.ServeContent(ctx.Resp, ctx.Req.Request, name, modtime, r)
}

// ServeFileContent serves given file as content to response.
func (ctx *Context) ServeFileContent(file string, names ...string) {
var name string
if len(names) > 0 {
name = names[0]
} else {
name = path.Base(file)
}

f, err := os.Open(file)
if err != nil {
if Env == PROD {
http.Error(ctx.Resp, "Internal Server Error", 500)
} else {
http.Error(ctx.Resp, err.Error(), 500)
}
return
}
defer f.Close()

ctx.setRawContentHeader()
http.ServeContent(ctx.Resp, ctx.Req.Request, name, time.Now(), f)
}

// ServeFile serves given file to response.
func (ctx *Context) ServeFile(file string, names ...string) {
var name string
if len(names) > 0 {
name = names[0]
} else {
name = path.Base(file)
}
ctx.Resp.Header().Set("Content-Description", "File Transfer")
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+name)
ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary")
ctx.Resp.Header().Set("Expires", "0")
ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
ctx.Resp.Header().Set("Pragma", "public")
http.ServeFile(ctx.Resp, ctx.Req.Request, file)
}

// ChangeStaticPath changes static path from old to new one.
func (ctx *Context) ChangeStaticPath(oldPath, newPath string) {
if !filepath.IsAbs(oldPath) {
oldPath = filepath.Join(Root, oldPath)
}
dir := statics.Get(oldPath)
if dir != nil {
statics.Delete(oldPath)

if !filepath.IsAbs(newPath) {
newPath = filepath.Join(Root, newPath)
}
*dir = http.Dir(newPath)
statics.Set(dir)
}
}

+ 13
- 0
vendor/gopkg.in/macaron.v1/go.mod View File

@@ -0,0 +1,13 @@
module gopkg.in/macaron.v1

go 1.12

require (
github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c // indirect
github.com/smartystreets/assertions v1.0.1 // indirect
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
gopkg.in/ini.v1 v1.46.0
)

+ 32
- 0
vendor/gopkg.in/macaron.v1/go.sum View File

@@ -0,0 +1,32 @@
github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI=
github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY=
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w=
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8=
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM=
github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
gopkg.in/ini.v1 v1.46.0 h1:VeDZbLYGaupuvIrsYCEOe/L/2Pcs5n7hdO1ZTjporag=
gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=

+ 73
- 0
vendor/gopkg.in/macaron.v1/logger.go View File

@@ -0,0 +1,73 @@
// Copyright 2013 Martini Authors
// Copyright 2014 The Macaron Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package macaron

import (
"fmt"
"log"
"net/http"
"reflect"
"runtime"
"time"
)

var (
ColorLog = true
LogTimeFormat = "2006-01-02 15:04:05"
)

func init() {
ColorLog = runtime.GOOS != "windows"
}

// LoggerInvoker is an inject.FastInvoker wrapper of func(ctx *Context, log *log.Logger).
type LoggerInvoker func(ctx *Context, log *log.Logger)

func (invoke LoggerInvoker) Invoke(params []interface{}) ([]reflect.Value, error) {
invoke(params[0].(*Context), params[1].(*log.Logger))
return nil, nil
}

// Logger returns a middleware handler that logs the request as it goes in and the response as it goes out.
func Logger() Handler {
return func(ctx *Context, log *log.Logger) {
start := time.Now()

log.Printf("%s: Started %s %s for %s", time.Now().Format(LogTimeFormat), ctx.Req.Method, ctx.Req.RequestURI, ctx.RemoteAddr())

rw := ctx.Resp.(ResponseWriter)
ctx.Next()

content := fmt.Sprintf("%s: Completed %s %s %v %s in %v", time.Now().Format(LogTimeFormat), ctx.Req.Method, ctx.Req.RequestURI, rw.Status(), http.StatusText(rw.Status()), time.Since(start))
if ColorLog {
switch rw.Status() {
case 200, 201, 202:
content = fmt.Sprintf("\033[1;32m%s\033[0m", content)
case 301, 302:
content = fmt.Sprintf("\033[1;37m%s\033[0m", content)
case 304:
content = fmt.Sprintf("\033[1;33m%s\033[0m", content)
case 401, 403:
content = fmt.Sprintf("\033[4;31m%s\033[0m", content)
case 404:
content = fmt.Sprintf("\033[1;31m%s\033[0m", content)
case 500:
content = fmt.Sprintf("\033[1;36m%s\033[0m", content)
}
}
log.Println(content)
}
}

+ 334
- 0
vendor/gopkg.in/macaron.v1/macaron.go View File

@@ -0,0 +1,334 @@
// +build go1.3

// Copyright 2014 The Macaron Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

// Package macaron is a high productive and modular web framework in Go.
package macaron // import "gopkg.in/macaron.v1"

import (
"io"
"log"
"net/http"
"os"
"reflect"
"strings"
"sync"

"github.com/unknwon/com"
"gopkg.in/ini.v1"

"github.com/go-macaron/inject"
)

const _VERSION = "1.3.4.0805"

func Version() string {
return _VERSION
}

// Handler can be any callable function.
// Macaron attempts to inject services into the handler's argument list,
// and panics if an argument could not be fullfilled via dependency injection.
type Handler interface{}

// handlerFuncInvoker is an inject.FastInvoker wrapper of func(http.ResponseWriter, *http.Request).
type handlerFuncInvoker func(http.ResponseWriter, *http.Request)

func (invoke handlerFuncInvoker) Invoke(params []interface{}) ([]reflect.Value, error) {
invoke(params[0].(http.ResponseWriter), params[1].(*http.Request))
return nil, nil
}

// internalServerErrorInvoker is an inject.FastInvoker wrapper of func(rw http.ResponseWriter, err error).
type internalServerErrorInvoker func(rw http.ResponseWriter, err error)

func (invoke internalServerErrorInvoker) Invoke(params []interface{}) ([]reflect.Value, error) {
invoke(params[0].(http.ResponseWriter), params[1].(error))
return nil, nil
}

// validateAndWrapHandler makes sure a handler is a callable function, it panics if not.
// When the handler is also potential to be any built-in inject.FastInvoker,
// it wraps the handler automatically to have some performance gain.
func validateAndWrapHandler(h Handler) Handler {
if reflect.TypeOf(h).Kind() != reflect.Func {
panic("Macaron handler must be a callable function")
}

if !inject.IsFastInvoker(h) {
switch v := h.(type) {
case func(*Context):
return ContextInvoker(v)
case func(*Context, *log.Logger):
return LoggerInvoker(v)
case func(http.ResponseWriter, *http.Request):
return handlerFuncInvoker(v)
case func(http.ResponseWriter, error):
return internalServerErrorInvoker(v)
}
}
return h
}

// validateAndWrapHandlers preforms validation and wrapping for each input handler.
// It accepts an optional wrapper function to perform custom wrapping on handlers.
func validateAndWrapHandlers(handlers []Handler, wrappers ...func(Handler) Handler) []Handler {
var wrapper func(Handler) Handler
if len(wrappers) > 0 {
wrapper = wrappers[0]
}

wrappedHandlers := make([]Handler, len(handlers))
for i, h := range handlers {
h = validateAndWrapHandler(h)
if wrapper != nil && !inject.IsFastInvoker(h) {
h = wrapper(h)
}
wrappedHandlers[i] = h
}

return wrappedHandlers
}

// Macaron represents the top level web application.
// inject.Injector methods can be invoked to map services on a global level.
type Macaron struct {
inject.Injector
befores []BeforeHandler
handlers []Handler
action Handler

hasURLPrefix bool
urlPrefix string // For suburl support.
*Router

logger *log.Logger
}

// NewWithLogger creates a bare bones Macaron instance.
// Use this method if you want to have full control over the middleware that is used.
// You can specify logger output writer with this function.
func NewWithLogger(out io.Writer) *Macaron {
m := &Macaron{
Injector: inject.New(),
action: func() {},
Router: NewRouter(),
logger: log.New(out, "[Macaron] ", 0),
}
m.Router.m = m
m.Map(m.logger)
m.Map(defaultReturnHandler())
m.NotFound(http.NotFound)
m.InternalServerError(func(rw http.ResponseWriter, err error) {
http.Error(rw, err.Error(), 500)
})
return m
}

// New creates a bare bones Macaron instance.
// Use this method if you want to have full control over the middleware that is used.
func New() *Macaron {
return NewWithLogger(os.Stdout)
}

// Classic creates a classic Macaron with some basic default middleware:
// macaron.Logger, macaron.Recovery and macaron.Static.
func Classic() *Macaron {
m := New()
m.Use(Logger())
m.Use(Recovery())
m.Use(Static("public"))
return m
}

// Handlers sets the entire middleware stack with the given Handlers.
// This will clear any current middleware handlers,
// and panics if any of the handlers is not a callable function
func (m *Macaron) Handlers(handlers ...Handler) {
m.handlers = make([]Handler, 0)
for _, handler := range handlers {
m.Use(handler)
}
}

// Action sets the handler that will be called after all the middleware has been invoked.
// This is set to macaron.Router in a macaron.Classic().
func (m *Macaron) Action(handler Handler) {
handler = validateAndWrapHandler(handler)
m.action = handler
}

// BeforeHandler represents a handler executes at beginning of every request.
// Macaron stops future process when it returns true.
type BeforeHandler func(rw http.ResponseWriter, req *http.Request) bool

func (m *Macaron) Before(handler BeforeHandler) {
m.befores = append(m.befores, handler)
}

// Use adds a middleware Handler to the stack,
// and panics if the handler is not a callable func.
// Middleware Handlers are invoked in the order that they are added.
func (m *Macaron) Use(handler Handler) {
handler = validateAndWrapHandler(handler)
m.handlers = append(m.handlers, handler)
}

func (m *Macaron) createContext(rw http.ResponseWriter, req *http.Request) *Context {
c := &Context{
Injector: inject.New(),
handlers: m.handlers,
action: m.action,
index: 0,
Router: m.Router,
Req: Request{req},
Resp: NewResponseWriter(req.Method, rw),
Render: &DummyRender{rw},
Data: make(map[string]interface{}),
}
c.SetParent(m)
c.Map(c)
c.MapTo(c.Resp, (*http.ResponseWriter)(nil))
c.Map(req)
return c
}

// ServeHTTP is the HTTP Entry point for a Macaron instance.
// Useful if you want to control your own HTTP server.
// Be aware that none of middleware will run without registering any router.
func (m *Macaron) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if m.hasURLPrefix {
req.URL.Path = strings.TrimPrefix(req.URL.Path, m.urlPrefix)
}
for _, h := range m.befores {
if h(rw, req) {
return
}
}
m.Router.ServeHTTP(rw, req)
}

func GetDefaultListenInfo() (string, int) {
host := os.Getenv("HOST")
if len(host) == 0 {
host = "0.0.0.0"
}
port := com.StrTo(os.Getenv("PORT")).MustInt()
if port == 0 {
port = 4000
}
return host, port
}

// Run the http server. Listening on os.GetEnv("PORT") or 4000 by default.
func (m *Macaron) Run(args ...interface{}) {
host, port := GetDefaultListenInfo()
if len(args) == 1 {
switch arg := args[0].(type) {
case string:
host = arg
case int:
port = arg
}
} else if len(args) >= 2 {
if arg, ok := args[0].(string); ok {
host = arg
}
if arg, ok := args[1].(int); ok {
port = arg
}
}

addr := host + ":" + com.ToStr(port)
logger := m.GetVal(reflect.TypeOf(m.logger)).Interface().(*log.Logger)
logger.Printf("listening on %s (%s)\n", addr, safeEnv())
logger.Fatalln(http.ListenAndServe(addr, m))
}

// SetURLPrefix sets URL prefix of router layer, so that it support suburl.
func (m *Macaron) SetURLPrefix(prefix string) {
m.urlPrefix = prefix
m.hasURLPrefix = len(m.urlPrefix) > 0
}

// ____ ____ .__ ___. .__
// \ \ / /____ _______|__|____ \_ |__ | | ____ ______
// \ Y /\__ \\_ __ \ \__ \ | __ \| | _/ __ \ / ___/
// \ / / __ \| | \/ |/ __ \| \_\ \ |_\ ___/ \___ \
// \___/ (____ /__| |__(____ /___ /____/\___ >____ >
// \/ \/ \/ \/ \/

const (
DEV = "development"
PROD = "production"
TEST = "test"
)

var (
// Env is the environment that Macaron is executing in.
// The MACARON_ENV is read on initialization to set this variable.
Env = DEV
envLock sync.Mutex

// Path of work directory.
Root string

// Flash applies to current request.
FlashNow bool

// Configuration convention object.
cfg *ini.File
)

func setENV(e string) {
envLock.Lock()
defer envLock.Unlock()

if len(e) > 0 {
Env = e
}
}

func safeEnv() string {
envLock.Lock()
defer envLock.Unlock()

return Env
}

func init() {
setENV(os.Getenv("MACARON_ENV"))

var err error
Root, err = os.Getwd()
if err != nil {
panic("error getting work directory: " + err.Error())
}
}

// SetConfig sets data sources for configuration.
func SetConfig(source interface{}, others ...interface{}) (_ *ini.File, err error) {
cfg, err = ini.Load(source, others...)
return Config(), err
}

// Config returns configuration convention object.
// It returns an empty object if there is no one available.
func Config() *ini.File {
if cfg == nil {
return ini.Empty()
}
return cfg
}

BIN
vendor/gopkg.in/macaron.v1/macaronlogo.png View File

Before After
Width: 300  |  Height: 300  |  Size: 89 kB

+ 163
- 0
vendor/gopkg.in/macaron.v1/recovery.go View File

@@ -0,0 +1,163 @@
// Copyright 2013 Martini Authors
// Copyright 2014 The Macaron Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package macaron

import (
"bytes"
"fmt"
"io/ioutil"
"log"
"net/http"
"runtime"

"github.com/go-macaron/inject"
)

const (
panicHtml = `<html>
<head><title>PANIC: %s</title>
<meta charset="utf-8" />
<style type="text/css">
html, body {
font-family: "Roboto", sans-serif;
color: #333333;
background-color: #ea5343;
margin: 0px;
}
h1 {
color: #d04526;
background-color: #ffffff;
padding: 20px;
border-bottom: 1px dashed #2b3848;
}
pre {
margin: 20px;
padding: 20px;
border: 2px solid #2b3848;
background-color: #ffffff;
white-space: pre-wrap; /* css-3 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
</style>
</head><body>
<h1>PANIC</h1>
<pre style="font-weight: bold;">%s</pre>
<pre>%s</pre>
</body>
</html>`
)

var (
dunno = []byte("???")
centerDot = []byte("·")
dot = []byte(".")
slash = []byte("/")
)

// stack returns a nicely formated stack frame, skipping skip frames
func stack(skip int) []byte {
buf := new(bytes.Buffer) // the returned data
// As we loop, we open files and read them. These variables record the currently
// loaded file.
var lines [][]byte
var lastFile string
for i := skip; ; i++ { // Skip the expected number of frames
pc, file, line, ok := runtime.Caller(i)
if !ok {
break
}
// Print this much at least. If we can't find the source, it won't show.
fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc)
if file != lastFile {
data, err := ioutil.ReadFile(file)
if err != nil {
continue
}
lines = bytes.Split(data, []byte{'\n'})
lastFile = file
}
fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line))
}
return buf.Bytes()
}

// source returns a space-trimmed slice of the n'th line.
func source(lines [][]byte, n int) []byte {
n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
if n < 0 || n >= len(lines) {
return dunno
}
return bytes.TrimSpace(lines[n])
}

// function returns, if possible, the name of the function containing the PC.
func function(pc uintptr) []byte {
fn := runtime.FuncForPC(pc)
if fn == nil {
return dunno
}
name := []byte(fn.Name())
// The name includes the path name to the package, which is unnecessary
// since the file name is already included. Plus, it has center dots.
// That is, we see
// runtime/debug.*T·ptrmethod
// and want
// *T.ptrmethod
// Also the package path might contains dot (e.g. code.google.com/...),
// so first eliminate the path prefix
if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
name = name[lastslash+1:]
}
if period := bytes.Index(name, dot); period >= 0 {
name = name[period+1:]
}
name = bytes.Replace(name, centerDot, dot, -1)
return name
}

// Recovery returns a middleware that recovers from any panics and writes a 500 if there was one.
// While Martini is in development mode, Recovery will also output the panic as HTML.
func Recovery() Handler {
return func(c *Context, log *log.Logger) {
defer func() {
if err := recover(); err != nil {
stack := stack(3)
log.Printf("PANIC: %s\n%s", err, stack)

// Lookup the current responsewriter
val := c.GetVal(inject.InterfaceOf((*http.ResponseWriter)(nil)))
res := val.Interface().(http.ResponseWriter)

// respond with panic message while in development mode
var body []byte
if Env == DEV {
res.Header().Set("Content-Type", "text/html")
body = []byte(fmt.Sprintf(panicHtml, err, err, stack))
}

res.WriteHeader(http.StatusInternalServerError)
if nil != body {
_, _ = res.Write(body)
}
}
}()

c.Next()
}
}

+ 724
- 0
vendor/gopkg.in/macaron.v1/render.go View File

@@ -0,0 +1,724 @@
// Copyright 2013 Martini Authors
// Copyright 2014 The Macaron Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package macaron

import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"html/template"
"io"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"sync"
"time"

"github.com/unknwon/com"
)

const (
_CONTENT_TYPE = "Content-Type"
_CONTENT_BINARY = "application/octet-stream"
_CONTENT_JSON = "application/json"
_CONTENT_HTML = "text/html"
_CONTENT_PLAIN = "text/plain"
_CONTENT_XHTML = "application/xhtml+xml"
_CONTENT_XML = "text/xml"
_DEFAULT_CHARSET = "UTF-8"
)

var (
// Provides a temporary buffer to execute templates into and catch errors.
bufpool = sync.Pool{
New: func() interface{} { return new(bytes.Buffer) },
}

// Included helper functions for use when rendering html
helperFuncs = template.FuncMap{
"yield": func() (string, error) {
return "", fmt.Errorf("yield called with no layout defined")
},
"current": func() (string, error) {
return "", nil
},
}
)

type (
// TemplateFile represents a interface of template file that has name and can be read.
TemplateFile interface {
Name() string
Data() []byte
Ext() string
}
// TemplateFileSystem represents a interface of template file system that able to list all files.
TemplateFileSystem interface {
ListFiles() []TemplateFile
Get(string) (io.Reader, error)
}

// Delims represents a set of Left and Right delimiters for HTML template rendering
Delims struct {
// Left delimiter, defaults to {{
Left string
// Right delimiter, defaults to }}
Right string
}

// RenderOptions represents a struct for specifying configuration options for the Render middleware.
RenderOptions struct {
// Directory to load templates. Default is "templates".
Directory string
// Addtional directories to overwite templates.
AppendDirectories []string
// Layout template name. Will not render a layout if "". Default is to "".
Layout string
// Extensions to parse template files from. Defaults are [".tmpl", ".html"].
Extensions []string
// Funcs is a slice of FuncMaps to apply to the template upon compilation. This is useful for helper functions. Default is [].
Funcs []template.FuncMap
// Delims sets the action delimiters to the specified strings in the Delims struct.
Delims Delims
// Appends the given charset to the Content-Type header. Default is "UTF-8".
Charset string
// Outputs human readable JSON.
IndentJSON bool
// Outputs human readable XML.
IndentXML bool
// Prefixes the JSON output with the given bytes.
PrefixJSON []byte
// Prefixes the XML output with the given bytes.
PrefixXML []byte
// Allows changing of output to XHTML instead of HTML. Default is "text/html"
HTMLContentType string
// TemplateFileSystem is the interface for supporting any implmentation of template file system.
TemplateFileSystem
}

// HTMLOptions is a struct for overriding some rendering Options for specific HTML call
HTMLOptions struct {
// Layout template name. Overrides Options.Layout.
Layout string
}

Render interface {
http.ResponseWriter
SetResponseWriter(http.ResponseWriter)

JSON(int, interface{})
JSONString(interface{}) (string, error)
RawData(int, []byte) // Serve content as binary
PlainText(int, []byte) // Serve content as plain text
HTML(int, string, interface{}, ...HTMLOptions)
HTMLSet(int, string, string, interface{}, ...HTMLOptions)
HTMLSetString(string, string, interface{}, ...HTMLOptions) (string, error)
HTMLString(string, interface{}, ...HTMLOptions) (string, error)
HTMLSetBytes(string, string, interface{}, ...HTMLOptions) ([]byte, error)
HTMLBytes(string, interface{}, ...HTMLOptions) ([]byte, error)
XML(int, interface{})
Error(int, ...string)
Status(int)
SetTemplatePath(string, string)
HasTemplateSet(string) bool
}
)

// TplFile implements TemplateFile interface.
type TplFile struct {
name string
data []byte
ext string
}

// NewTplFile cerates new template file with given name and data.
func NewTplFile(name string, data []byte, ext string) *TplFile {
return &TplFile{name, data, ext}
}

func (f *TplFile) Name() string {
return f.name
}

func (f *TplFile) Data() []byte {
return f.data
}

func (f *TplFile) Ext() string {
return f.ext
}

// TplFileSystem implements TemplateFileSystem interface.
type TplFileSystem struct {
files []TemplateFile
}

// NewTemplateFileSystem creates new template file system with given options.
func NewTemplateFileSystem(opt RenderOptions, omitData bool) TplFileSystem {
fs := TplFileSystem{}
fs.files = make([]TemplateFile, 0, 10)

// Directories are composed in reverse order because later one overwrites previous ones,
// so once found, we can directly jump out of the loop.
dirs := make([]string, 0, len(opt.AppendDirectories)+1)
for i := len(opt.AppendDirectories) - 1; i >= 0; i-- {
dirs = append(dirs, opt.AppendDirectories[i])
}
dirs = append(dirs, opt.Directory)

var err error
for i := range dirs {
// Skip ones that does not exists for symlink test,
// but allow non-symlink ones added after start.
if !com.IsExist(dirs[i]) {
continue
}

dirs[i], err = filepath.EvalSymlinks(dirs[i])
if err != nil {
panic("EvalSymlinks(" + dirs[i] + "): " + err.Error())
}
}
lastDir := dirs[len(dirs)-1]

// We still walk the last (original) directory because it's non-sense we load templates not exist in original directory.
if err = filepath.Walk(lastDir, func(path string, info os.FileInfo, _ error) error {
r, err := filepath.Rel(lastDir, path)
if err != nil {
return err
}

ext := GetExt(r)

for _, extension := range opt.Extensions {
if ext != extension {
continue
}

var data []byte
if !omitData {
// Loop over candidates of directory, break out once found.
// The file always exists because it's inside the walk function,
// and read original file is the worst case.
for i := range dirs {
path = filepath.Join(dirs[i], r)
if !com.IsFile(path) {
continue
}

data, err = ioutil.ReadFile(path)
if err != nil {
return err
}
break
}
}

name := filepath.ToSlash((r[0 : len(r)-len(ext)]))
fs.files = append(fs.files, NewTplFile(name, data, ext))
}

return nil
}); err != nil {
panic("NewTemplateFileSystem: " + err.Error())
}

return fs
}

func (fs TplFileSystem) ListFiles() []TemplateFile {
return fs.files
}

func (fs TplFileSystem) Get(name string) (io.Reader, error) {
for i := range fs.files {
if fs.files[i].Name()+fs.files[i].Ext() == name {
return bytes.NewReader(fs.files[i].Data()), nil
}
}
return nil, fmt.Errorf("file '%s' not found", name)
}

func PrepareCharset(charset string) string {
if len(charset) != 0 {
return "; charset=" + charset
}

return "; charset=" + _DEFAULT_CHARSET
}

func GetExt(s string) string {
index := strings.Index(s, ".")
if index == -1 {
return ""
}
return s[index:]
}

func compile(opt RenderOptions) *template.Template {
t := template.New(opt.Directory)
t.Delims(opt.Delims.Left, opt.Delims.Right)
// Parse an initial template in case we don't have any.
template.Must(t.Parse("Macaron"))

if opt.TemplateFileSystem == nil {
opt.TemplateFileSystem = NewTemplateFileSystem(opt, false)
}

for _, f := range opt.TemplateFileSystem.ListFiles() {
tmpl := t.New(f.Name())
for _, funcs := range opt.Funcs {
tmpl.Funcs(funcs)
}
// Bomb out if parse fails. We don't want any silent server starts.
template.Must(tmpl.Funcs(helperFuncs).Parse(string(f.Data())))
}

return t
}

const (
DEFAULT_TPL_SET_NAME = "DEFAULT"
)

// TemplateSet represents a template set of type *template.Template.
type TemplateSet struct {
lock sync.RWMutex
sets map[string]*template.Template
dirs map[string]string
}

// NewTemplateSet initializes a new empty template set.
func NewTemplateSet() *TemplateSet {
return &TemplateSet{
sets: make(map[string]*template.Template),
dirs: make(map[string]string),
}
}

func (ts *TemplateSet) Set(name string, opt *RenderOptions) *template.Template {
t := compile(*opt)

ts.lock.Lock()
defer ts.lock.Unlock()

ts.sets[name] = t
ts.dirs[name] = opt.Directory
return t
}

func (ts *TemplateSet) Get(name string) *template.Template {
ts.lock.RLock()
defer ts.lock.RUnlock()

return ts.sets[name]
}

func (ts *TemplateSet) GetDir(name string) string {
ts.lock.RLock()
defer ts.lock.RUnlock()

return ts.dirs[name]
}

func prepareRenderOptions(options []RenderOptions) RenderOptions {
var opt RenderOptions
if len(options) > 0 {
opt = options[0]
}

// Defaults.
if len(opt.Directory) == 0 {
opt.Directory = "templates"
}
if len(opt.Extensions) == 0 {
opt.Extensions = []string{".tmpl", ".html"}
}
if len(opt.HTMLContentType) == 0 {
opt.HTMLContentType = _CONTENT_HTML
}

return opt
}

func ParseTplSet(tplSet string) (tplName string, tplDir string) {
tplSet = strings.TrimSpace(tplSet)
if len(tplSet) == 0 {
panic("empty template set argument")
}
infos := strings.Split(tplSet, ":")
if len(infos) == 1 {
tplDir = infos[0]
tplName = path.Base(tplDir)
} else {
tplName = infos[0]
tplDir = infos[1]
}

if !com.IsDir(tplDir) {
panic("template set path does not exist or is not a directory")
}
return tplName, tplDir
}

func renderHandler(opt RenderOptions, tplSets []string) Handler {
cs := PrepareCharset(opt.Charset)
ts := NewTemplateSet()
ts.Set(DEFAULT_TPL_SET_NAME, &opt)

var tmpOpt RenderOptions
for _, tplSet := range tplSets {
tplName, tplDir := ParseTplSet(tplSet)
tmpOpt = opt
tmpOpt.Directory = tplDir
ts.Set(tplName, &tmpOpt)
}

return func(ctx *Context) {
r := &TplRender{
ResponseWriter: ctx.Resp,
TemplateSet: ts,
Opt: &opt,
CompiledCharset: cs,
}
ctx.Data["TmplLoadTimes"] = func() string {
if r.startTime.IsZero() {
return ""
}
return fmt.Sprint(time.Since(r.startTime).Nanoseconds()/1e6) + "ms"
}

ctx.Render = r
ctx.MapTo(r, (*Render)(nil))
}
}

// Renderer is a Middleware that maps a macaron.Render service into the Macaron handler chain.
// An single variadic macaron.RenderOptions struct can be optionally provided to configure
// HTML rendering. The default directory for templates is "templates" and the default
// file extension is ".tmpl" and ".html".
//
// If MACARON_ENV is set to "" or "development" then templates will be recompiled on every request. For more performance, set the
// MACARON_ENV environment variable to "production".
func Renderer(options ...RenderOptions) Handler {
return renderHandler(prepareRenderOptions(options), []string{})
}

func Renderers(options RenderOptions, tplSets ...string) Handler {
return renderHandler(prepareRenderOptions([]RenderOptions{options}), tplSets)
}

type TplRender struct {
http.ResponseWriter
*TemplateSet
Opt *RenderOptions
CompiledCharset string

startTime time.Time
}

func (r *TplRender) SetResponseWriter(rw http.ResponseWriter) {
r.ResponseWriter = rw
}

func (r *TplRender) JSON(status int, v interface{}) {
var (
result []byte
err error
)
if r.Opt.IndentJSON {
result, err = json.MarshalIndent(v, "", " ")
} else {
result, err = json.Marshal(v)
}
if err != nil {
http.Error(r, err.Error(), 500)
return
}

// json rendered fine, write out the result
r.Header().Set(_CONTENT_TYPE, _CONTENT_JSON+r.CompiledCharset)
r.WriteHeader(status)
if len(r.Opt.PrefixJSON) > 0 {
_, _ = r.Write(r.Opt.PrefixJSON)
}
_, _ = r.Write(result)
}

func (r *TplRender) JSONString(v interface{}) (string, error) {
var result []byte
var err error
if r.Opt.IndentJSON {
result, err = json.MarshalIndent(v, "", " ")
} else {
result, err = json.Marshal(v)
}
if err != nil {
return "", err
}
return string(result), nil
}

func (r *TplRender) XML(status int, v interface{}) {
var result []byte
var err error
if r.Opt.IndentXML {
result, err = xml.MarshalIndent(v, "", " ")
} else {
result, err = xml.Marshal(v)
}
if err != nil {
http.Error(r, err.Error(), 500)
return
}

// XML rendered fine, write out the result
r.Header().Set(_CONTENT_TYPE, _CONTENT_XML+r.CompiledCharset)
r.WriteHeader(status)
if len(r.Opt.PrefixXML) > 0 {
_, _ = r.Write(r.Opt.PrefixXML)
}
_, _ = r.Write(result)
}

func (r *TplRender) data(status int, contentType string, v []byte) {
if r.Header().Get(_CONTENT_TYPE) == "" {
r.Header().Set(_CONTENT_TYPE, contentType)
}
r.WriteHeader(status)
_, _ = r.Write(v)
}

func (r *TplRender) RawData(status int, v []byte) {
r.data(status, _CONTENT_BINARY, v)
}

func (r *TplRender) PlainText(status int, v []byte) {
r.data(status, _CONTENT_PLAIN, v)
}

func (r *TplRender) execute(t *template.Template, name string, data interface{}) (*bytes.Buffer, error) {
buf := bufpool.Get().(*bytes.Buffer)
return buf, t.ExecuteTemplate(buf, name, data)
}

func (r *TplRender) addYield(t *template.Template, tplName string, data interface{}) {
funcs := template.FuncMap{
"yield": func() (template.HTML, error) {
buf, err := r.execute(t, tplName, data)
// return safe html here since we are rendering our own template
return template.HTML(buf.String()), err
},
"current": func() (string, error) {
return tplName, nil
},
}
t.Funcs(funcs)
}

func (r *TplRender) renderBytes(setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) (*bytes.Buffer, error) {
t := r.TemplateSet.Get(setName)
if Env == DEV {
opt := *r.Opt
opt.Directory = r.TemplateSet.GetDir(setName)
t = r.TemplateSet.Set(setName, &opt)
}
if t == nil {
return nil, fmt.Errorf("html/template: template \"%s\" is undefined", tplName)
}

opt := r.prepareHTMLOptions(htmlOpt)

if len(opt.Layout) > 0 {
r.addYield(t, tplName, data)
tplName = opt.Layout
}

out, err := r.execute(t, tplName, data)
if err != nil {
return nil, err
}

return out, nil
}

func (r *TplRender) renderHTML(status int, setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) {
r.startTime = time.Now()

out, err := r.renderBytes(setName, tplName, data, htmlOpt...)
if err != nil {
http.Error(r, err.Error(), http.StatusInternalServerError)
return
}

r.Header().Set(_CONTENT_TYPE, r.Opt.HTMLContentType+r.CompiledCharset)
r.WriteHeader(status)

if _, err := out.WriteTo(r); err != nil {
out.Reset()
}
bufpool.Put(out)
}

func (r *TplRender) HTML(status int, name string, data interface{}, htmlOpt ...HTMLOptions) {
r.renderHTML(status, DEFAULT_TPL_SET_NAME, name, data, htmlOpt...)
}

func (r *TplRender) HTMLSet(status int, setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) {
r.renderHTML(status, setName, tplName, data, htmlOpt...)
}

func (r *TplRender) HTMLSetBytes(setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) ([]byte, error) {
out, err := r.renderBytes(setName, tplName, data, htmlOpt...)
if err != nil {
return []byte(""), err
}
return out.Bytes(), nil
}

func (r *TplRender) HTMLBytes(name string, data interface{}, htmlOpt ...HTMLOptions) ([]byte, error) {
return r.HTMLSetBytes(DEFAULT_TPL_SET_NAME, name, data, htmlOpt...)
}

func (r *TplRender) HTMLSetString(setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) (string, error) {
p, err := r.HTMLSetBytes(setName, tplName, data, htmlOpt...)
return string(p), err
}

func (r *TplRender) HTMLString(name string, data interface{}, htmlOpt ...HTMLOptions) (string, error) {
p, err := r.HTMLBytes(name, data, htmlOpt...)
return string(p), err
}

// Error writes the given HTTP status to the current ResponseWriter
func (r *TplRender) Error(status int, message ...string) {
r.WriteHeader(status)
if len(message) > 0 {
_, _ = r.Write([]byte(message[0]))
}
}

func (r *TplRender) Status(status int) {
r.WriteHeader(status)
}

func (r *TplRender) prepareHTMLOptions(htmlOpt []HTMLOptions) HTMLOptions {
if len(htmlOpt) > 0 {
return htmlOpt[0]
}

return HTMLOptions{
Layout: r.Opt.Layout,
}
}

func (r *TplRender) SetTemplatePath(setName, dir string) {
if len(setName) == 0 {
setName = DEFAULT_TPL_SET_NAME
}
opt := *r.Opt
opt.Directory = dir
r.TemplateSet.Set(setName, &opt)
}

func (r *TplRender) HasTemplateSet(name string) bool {
return r.TemplateSet.Get(name) != nil
}

// DummyRender is used when user does not choose any real render to use.
// This way, we can print out friendly message which asks them to register one,
// instead of ugly and confusing 'nil pointer' panic.
type DummyRender struct {
http.ResponseWriter
}

func renderNotRegistered() {
panic("middleware render hasn't been registered")
}

func (r *DummyRender) SetResponseWriter(http.ResponseWriter) {
renderNotRegistered()
}

func (r *DummyRender) JSON(int, interface{}) {
renderNotRegistered()
}

func (r *DummyRender) JSONString(interface{}) (string, error) {
renderNotRegistered()
return "", nil
}

func (r *DummyRender) RawData(int, []byte) {
renderNotRegistered()
}

func (r *DummyRender) PlainText(int, []byte) {
renderNotRegistered()
}

func (r *DummyRender) HTML(int, string, interface{}, ...HTMLOptions) {
renderNotRegistered()
}

func (r *DummyRender) HTMLSet(int, string, string, interface{}, ...HTMLOptions) {
renderNotRegistered()
}

func (r *DummyRender) HTMLSetString(string, string, interface{}, ...HTMLOptions) (string, error) {
renderNotRegistered()
return "", nil
}

func (r *DummyRender) HTMLString(string, interface{}, ...HTMLOptions) (string, error) {
renderNotRegistered()
return "", nil
}

func (r *DummyRender) HTMLSetBytes(string, string, interface{}, ...HTMLOptions) ([]byte, error) {
renderNotRegistered()
return nil, nil
}

func (r *DummyRender) HTMLBytes(string, interface{}, ...HTMLOptions) ([]byte, error) {
renderNotRegistered()
return nil, nil
}

func (r *DummyRender) XML(int, interface{}) {
renderNotRegistered()
}

func (r *DummyRender) Error(int, ...string) {
renderNotRegistered()
}

func (r *DummyRender) Status(int) {
renderNotRegistered()
}

func (r *DummyRender) SetTemplatePath(string, string) {
renderNotRegistered()
}

func (r *DummyRender) HasTemplateSet(string) bool {
renderNotRegistered()
return false
}

+ 124
- 0
vendor/gopkg.in/macaron.v1/response_writer.go View File

@@ -0,0 +1,124 @@
// Copyright 2013 Martini Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package macaron

import (
"bufio"
"errors"
"net"
"net/http"
)

// ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about
// the response. It is recommended that middleware handlers use this construct to wrap a responsewriter
// if the functionality calls for it.
type ResponseWriter interface {
http.ResponseWriter
http.Flusher
http.Pusher
// Status returns the status code of the response or 0 if the response has not been written.
Status() int
// Written returns whether or not the ResponseWriter has been written.
Written() bool
// Size returns the size of the response body.
Size() int
// Before allows for a function to be called before the ResponseWriter has been written to. This is
// useful for setting headers or any other operations that must happen before a response has been written.
Before(BeforeFunc)
}

// BeforeFunc is a function that is called before the ResponseWriter has been written to.
type BeforeFunc func(ResponseWriter)

// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter
func NewResponseWriter(method string, rw http.ResponseWriter) ResponseWriter {
return &responseWriter{method, rw, 0, 0, nil}
}

type responseWriter struct {
method string
http.ResponseWriter
status int
size int
beforeFuncs []BeforeFunc
}

func (rw *responseWriter) WriteHeader(s int) {
rw.callBefore()
rw.ResponseWriter.WriteHeader(s)
rw.status = s
}

func (rw *responseWriter) Write(b []byte) (size int, err error) {
if !rw.Written() {
// The status will be StatusOK if WriteHeader has not been called yet
rw.WriteHeader(http.StatusOK)
}
if rw.method != "HEAD" {
size, err = rw.ResponseWriter.Write(b)
rw.size += size
}
return size, err
}

func (rw *responseWriter) Status() int {
return rw.status
}

func (rw *responseWriter) Size() int {
return rw.size
}

func (rw *responseWriter) Written() bool {
return rw.status != 0
}

func (rw *responseWriter) Before(before BeforeFunc) {
rw.beforeFuncs = append(rw.beforeFuncs, before)
}

func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hijacker, ok := rw.ResponseWriter.(http.Hijacker)
if !ok {
return nil, nil, errors.New("the ResponseWriter doesn't support the Hijacker interface")
}
return hijacker.Hijack()
}

//nolint
func (rw *responseWriter) CloseNotify() <-chan bool {
return rw.ResponseWriter.(http.CloseNotifier).CloseNotify()
}

func (rw *responseWriter) callBefore() {
for i := len(rw.beforeFuncs) - 1; i >= 0; i-- {
rw.beforeFuncs[i](rw)
}
}

func (rw *responseWriter) Flush() {
flusher, ok := rw.ResponseWriter.(http.Flusher)
if ok {
flusher.Flush()
}
}

func (rw *responseWriter) Push(target string, opts *http.PushOptions) error {
pusher, ok := rw.ResponseWriter.(http.Pusher)
if !ok {
return errors.New("the ResponseWriter doesn't support the Pusher interface")
}
return pusher.Push(target, opts)
}

+ 76
- 0
vendor/gopkg.in/macaron.v1/return_handler.go View File

@@ -0,0 +1,76 @@
// Copyright 2013 Martini Authors
// Copyright 2014 The Macaron Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package macaron

import (
"net/http"
"reflect"

"github.com/go-macaron/inject"
)

// ReturnHandler is a service that Martini provides that is called
// when a route handler returns something. The ReturnHandler is
// responsible for writing to the ResponseWriter based on the values
// that are passed into this function.
type ReturnHandler func(*Context, []reflect.Value)

func canDeref(val reflect.Value) bool {
return val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr
}

func isError(val reflect.Value) bool {
_, ok := val.Interface().(error)
return ok
}

func isByteSlice(val reflect.Value) bool {
return val.Kind() == reflect.Slice && val.Type().Elem().Kind() == reflect.Uint8
}

func defaultReturnHandler() ReturnHandler {
return func(ctx *Context, vals []reflect.Value) {
rv := ctx.GetVal(inject.InterfaceOf((*http.ResponseWriter)(nil)))
resp := rv.Interface().(http.ResponseWriter)
var respVal reflect.Value
if len(vals) > 1 && vals[0].Kind() == reflect.Int {
resp.WriteHeader(int(vals[0].Int()))
respVal = vals[1]
} else if len(vals) > 0 {
respVal = vals[0]

if isError(respVal) {
err := respVal.Interface().(error)
if err != nil {
ctx.internalServerError(ctx, err)
}
return
} else if canDeref(respVal) {
if respVal.IsNil() {
return // Ignore nil error
}
}
}
if canDeref(respVal) {
respVal = respVal.Elem()
}
if isByteSlice(respVal) {
_, _ = resp.Write(respVal.Bytes())
} else {
_, _ = resp.Write([]byte(respVal.String()))
}
}
}

+ 380
- 0
vendor/gopkg.in/macaron.v1/router.go View File

@@ -0,0 +1,380 @@
// Copyright 2014 The Macaron Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package macaron

import (
"net/http"
"strings"
"sync"
)

var (
// Known HTTP methods.
_HTTP_METHODS = map[string]bool{
"GET": true,
"POST": true,
"PUT": true,
"DELETE": true,
"PATCH": true,
"OPTIONS": true,
"HEAD": true,
}
)

// routeMap represents a thread-safe map for route tree.
type routeMap struct {
lock sync.RWMutex
routes map[string]map[string]*Leaf
}

// NewRouteMap initializes and returns a new routeMap.
func NewRouteMap() *routeMap {
rm := &routeMap{
routes: make(map[string]map[string]*Leaf),
}
for m := range _HTTP_METHODS {
rm.routes[m] = make(map[string]*Leaf)
}
return rm
}

// getLeaf returns Leaf object if a route has been registered.
func (rm *routeMap) getLeaf(method, pattern string) *Leaf {
rm.lock.RLock()
defer rm.lock.RUnlock()

return rm.routes[method][pattern]
}

// add adds new route to route tree map.
func (rm *routeMap) add(method, pattern string, leaf *Leaf) {
rm.lock.Lock()
defer rm.lock.Unlock()

rm.routes[method][pattern] = leaf
}

type group struct {
pattern string
handlers []Handler
}

// Router represents a Macaron router layer.
type Router struct {
m *Macaron
autoHead bool
routers map[string]*Tree
*routeMap
namedRoutes map[string]*Leaf

groups []group
notFound http.HandlerFunc
internalServerError func(*Context, error)

// handlerWrapper is used to wrap arbitrary function from Handler to inject.FastInvoker.
handlerWrapper func(Handler) Handler
}

func NewRouter() *Router {
return &Router{
routers: make(map[string]*Tree),
routeMap: NewRouteMap(),
namedRoutes: make(map[string]*Leaf),
}
}

// SetAutoHead sets the value who determines whether add HEAD method automatically
// when GET method is added.
func (r *Router) SetAutoHead(v bool) {
r.autoHead = v
}

type Params map[string]string

// Handle is a function that can be registered to a route to handle HTTP requests.
// Like http.HandlerFunc, but has a third parameter for the values of wildcards (variables).
type Handle func(http.ResponseWriter, *http.Request, Params)

// Route represents a wrapper of leaf route and upper level router.
type Route struct {
router *Router
leaf *Leaf
}

// Name sets name of route.
func (r *Route) Name(name string) {
if len(name) == 0 {
panic("route name cannot be empty")
} else if r.router.namedRoutes[name] != nil {
panic("route with given name already exists: " + name)
}
r.router.namedRoutes[name] = r.leaf
}

// handle adds new route to the router tree.
func (r *Router) handle(method, pattern string, handle Handle) *Route {
method = strings.ToUpper(method)

var leaf *Leaf
// Prevent duplicate routes.
if leaf = r.getLeaf(method, pattern); leaf != nil {
return &Route{r, leaf}
}

// Validate HTTP methods.
if !_HTTP_METHODS[method] && method != "*" {
panic("unknown HTTP method: " + method)
}

// Generate methods need register.
methods := make(map[string]bool)
if method == "*" {
for m := range _HTTP_METHODS {
methods[m] = true
}
} else {
methods[method] = true
}

// Add to router tree.
for m := range methods {
if t, ok := r.routers[m]; ok {
leaf = t.Add(pattern, handle)
} else {
t := NewTree()
leaf = t.Add(pattern, handle)
r.routers[m] = t
}
r.add(m, pattern, leaf)
}
return &Route{r, leaf}
}

// Handle registers a new request handle with the given pattern, method and handlers.
func (r *Router) Handle(method string, pattern string, handlers []Handler) *Route {
if len(r.groups) > 0 {
groupPattern := ""
h := make([]Handler, 0)
for _, g := range r.groups {
groupPattern += g.pattern
h = append(h, g.handlers...)
}

pattern = groupPattern + pattern
h = append(h, handlers...)
handlers = h
}
handlers = validateAndWrapHandlers(handlers, r.handlerWrapper)

return r.handle(method, pattern, func(resp http.ResponseWriter, req *http.Request, params Params) {
c := r.m.createContext(resp, req)
c.params = params
c.handlers = make([]Handler, 0, len(r.m.handlers)+len(handlers))
c.handlers = append(c.handlers, r.m.handlers...)
c.handlers = append(c.handlers, handlers...)
c.run()
})
}

func (r *Router) Group(pattern string, fn func(), h ...Handler) {
r.groups = append(r.groups, group{pattern, h})
fn()
r.groups = r.groups[:len(r.groups)-1]
}

// Get is a shortcut for r.Handle("GET", pattern, handlers)
func (r *Router) Get(pattern string, h ...Handler) (leaf *Route) {
leaf = r.Handle("GET", pattern, h)
if r.autoHead {
r.Head(pattern, h...)
}
return leaf
}

// Patch is a shortcut for r.Handle("PATCH", pattern, handlers)
func (r *Router) Patch(pattern string, h ...Handler) *Route {
return r.Handle("PATCH", pattern, h)
}

// Post is a shortcut for r.Handle("POST", pattern, handlers)
func (r *Router) Post(pattern string, h ...Handler) *Route {
return r.Handle("POST", pattern, h)
}

// Put is a shortcut for r.Handle("PUT", pattern, handlers)
func (r *Router) Put(pattern string, h ...Handler) *Route {
return r.Handle("PUT", pattern, h)
}

// Delete is a shortcut for r.Handle("DELETE", pattern, handlers)
func (r *Router) Delete(pattern string, h ...Handler) *Route {
return r.Handle("DELETE", pattern, h)
}

// Options is a shortcut for r.Handle("OPTIONS", pattern, handlers)
func (r *Router) Options(pattern string, h ...Handler) *Route {
return r.Handle("OPTIONS", pattern, h)
}

// Head is a shortcut for r.Handle("HEAD", pattern, handlers)
func (r *Router) Head(pattern string, h ...Handler) *Route {
return r.Handle("HEAD", pattern, h)
}

// Any is a shortcut for r.Handle("*", pattern, handlers)
func (r *Router) Any(pattern string, h ...Handler) *Route {
return r.Handle("*", pattern, h)
}

// Route is a shortcut for same handlers but different HTTP methods.
//
// Example:
// m.Route("/", "GET,POST", h)
func (r *Router) Route(pattern, methods string, h ...Handler) (route *Route) {
for _, m := range strings.Split(methods, ",") {
route = r.Handle(strings.TrimSpace(m), pattern, h)
}
return route
}

// Combo returns a combo router.
func (r *Router) Combo(pattern string, h ...Handler) *ComboRouter {
return &ComboRouter{r, pattern, h, map[string]bool{}, nil}
}

// NotFound configurates http.HandlerFunc which is called when no matching route is
// found. If it is not set, http.NotFound is used.
// Be sure to set 404 response code in your handler.
func (r *Router) NotFound(handlers ...Handler) {
handlers = validateAndWrapHandlers(handlers)
r.notFound = func(rw http.ResponseWriter, req *http.Request) {
c := r.m.createContext(rw, req)
c.handlers = make([]Handler, 0, len(r.m.handlers)+len(handlers))
c.handlers = append(c.handlers, r.m.handlers...)
c.handlers = append(c.handlers, handlers...)
c.run()
}
}

// InternalServerError configurates handler which is called when route handler returns
// error. If it is not set, default handler is used.
// Be sure to set 500 response code in your handler.
func (r *Router) InternalServerError(handlers ...Handler) {
handlers = validateAndWrapHandlers(handlers)
r.internalServerError = func(c *Context, err error) {
c.index = 0
c.handlers = handlers
c.Map(err)
c.run()
}
}

// SetHandlerWrapper sets handlerWrapper for the router.
func (r *Router) SetHandlerWrapper(f func(Handler) Handler) {
r.handlerWrapper = f
}

func (r *Router) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if t, ok := r.routers[req.Method]; ok {
// Fast match for static routes
leaf := r.getLeaf(req.Method, req.URL.Path)
if leaf != nil {
leaf.handle(rw, req, nil)
return
}

h, p, ok := t.Match(req.URL.EscapedPath())
if ok {
if splat, ok := p["*0"]; ok {
p["*"] = splat // Easy name.
}
h(rw, req, p)
return
}
}

r.notFound(rw, req)
}

// URLFor builds path part of URL by given pair values.
func (r *Router) URLFor(name string, pairs ...string) string {
leaf, ok := r.namedRoutes[name]
if !ok {
panic("route with given name does not exists: " + name)
}
return leaf.URLPath(pairs...)
}

// ComboRouter represents a combo router.
type ComboRouter struct {
router *Router
pattern string
handlers []Handler
methods map[string]bool // Registered methods.

lastRoute *Route
}

func (cr *ComboRouter) checkMethod(name string) {
if cr.methods[name] {
panic("method '" + name + "' has already been registered")
}
cr.methods[name] = true
}

func (cr *ComboRouter) route(fn func(string, ...Handler) *Route, method string, h ...Handler) *ComboRouter {
cr.checkMethod(method)
cr.lastRoute = fn(cr.pattern, append(cr.handlers, h...)...)
return cr
}

func (cr *ComboRouter) Get(h ...Handler) *ComboRouter {
if cr.router.autoHead {
cr.Head(h...)
}
return cr.route(cr.router.Get, "GET", h...)
}

func (cr *ComboRouter) Patch(h ...Handler) *ComboRouter {
return cr.route(cr.router.Patch, "PATCH", h...)
}

func (cr *ComboRouter) Post(h ...Handler) *ComboRouter {
return cr.route(cr.router.Post, "POST", h...)
}

func (cr *ComboRouter) Put(h ...Handler) *ComboRouter {
return cr.route(cr.router.Put, "PUT", h...)
}

func (cr *ComboRouter) Delete(h ...Handler) *ComboRouter {
return cr.route(cr.router.Delete, "DELETE", h...)
}

func (cr *ComboRouter) Options(h ...Handler) *ComboRouter {
return cr.route(cr.router.Options, "OPTIONS", h...)
}

func (cr *ComboRouter) Head(h ...Handler) *ComboRouter {
return cr.route(cr.router.Head, "HEAD", h...)
}

// Name sets name of ComboRouter route.
func (cr *ComboRouter) Name(name string) {
if cr.lastRoute == nil {
panic("no corresponding route to be named")
}
cr.lastRoute.Name(name)
}

+ 230
- 0
vendor/gopkg.in/macaron.v1/static.go View File

@@ -0,0 +1,230 @@
// Copyright 2013 Martini Authors
// Copyright 2014 The Macaron Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package macaron

import (
"encoding/base64"
"log"
"net/http"
"path"
"path/filepath"
"strings"
"sync"
)

// StaticOptions is a struct for specifying configuration options for the macaron.Static middleware.
type StaticOptions struct {
// Prefix is the optional prefix used to serve the static directory content
Prefix string
// SkipLogging will disable [Static] log messages when a static file is served.
SkipLogging bool
// IndexFile defines which file to serve as index if it exists.
IndexFile string
// Expires defines which user-defined function to use for producing a HTTP Expires Header
// https://developers.google.com/speed/docs/insights/LeverageBrowserCaching
Expires func() string
// ETag defines if we should add an ETag header
// https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#validating-cached-responses-with-etags
ETag bool
// FileSystem is the interface for supporting any implmentation of file system.
FileSystem http.FileSystem
}

// FIXME: to be deleted.
type staticMap struct {
lock sync.RWMutex
data map[string]*http.Dir
}

func (sm *staticMap) Set(dir *http.Dir) {
sm.lock.Lock()
defer sm.lock.Unlock()

sm.data[string(*dir)] = dir
}

func (sm *staticMap) Get(name string) *http.Dir {
sm.lock.RLock()
defer sm.lock.RUnlock()

return sm.data[name]
}

func (sm *staticMap) Delete(name string) {
sm.lock.Lock()
defer sm.lock.Unlock()

delete(sm.data, name)
}

var statics = staticMap{sync.RWMutex{}, map[string]*http.Dir{}}

// staticFileSystem implements http.FileSystem interface.
type staticFileSystem struct {
dir *http.Dir
}

func newStaticFileSystem(directory string) staticFileSystem {
if !filepath.IsAbs(directory) {
directory = filepath.Join(Root, directory)
}
dir := http.Dir(directory)
statics.Set(&dir)
return staticFileSystem{&dir}
}

func (fs staticFileSystem) Open(name string) (http.File, error) {
return fs.dir.Open(name)
}

func prepareStaticOption(dir string, opt StaticOptions) StaticOptions {
// Defaults
if len(opt.IndexFile) == 0 {
opt.IndexFile = "index.html"
}
// Normalize the prefix if provided
if opt.Prefix != "" {
// Ensure we have a leading '/'
if opt.Prefix[0] != '/' {
opt.Prefix = "/" + opt.Prefix
}
// Remove any trailing '/'
opt.Prefix = strings.TrimRight(opt.Prefix, "/")
}
if opt.FileSystem == nil {
opt.FileSystem = newStaticFileSystem(dir)
}
return opt
}

func prepareStaticOptions(dir string, options []StaticOptions) StaticOptions {
var opt StaticOptions
if len(options) > 0 {
opt = options[0]
}
return prepareStaticOption(dir, opt)
}

func staticHandler(ctx *Context, log *log.Logger, opt StaticOptions) bool {
if ctx.Req.Method != "GET" && ctx.Req.Method != "HEAD" {
return false
}

file := ctx.Req.URL.Path
// if we have a prefix, filter requests by stripping the prefix
if opt.Prefix != "" {
if !strings.HasPrefix(file, opt.Prefix) {
return false
}
file = file[len(opt.Prefix):]
if file != "" && file[0] != '/' {
return false
}
}

f, err := opt.FileSystem.Open(file)
if err != nil {
return false
}
defer f.Close()

fi, err := f.Stat()
if err != nil {
return true // File exists but fail to open.
}

// Try to serve index file
if fi.IsDir() {
redirPath := path.Clean(ctx.Req.URL.Path)
// path.Clean removes the trailing slash, so we need to add it back when
// the original path has it.
if strings.HasSuffix(ctx.Req.URL.Path, "/") {
redirPath = redirPath + "/"
}
// Redirect if missing trailing slash.
if !strings.HasSuffix(redirPath, "/") {
http.Redirect(ctx.Resp, ctx.Req.Request, redirPath+"/", http.StatusFound)
return true
}

file = path.Join(file, opt.IndexFile)
f, err = opt.FileSystem.Open(file)
if err != nil {
return false // Discard error.
}
defer f.Close()

fi, err = f.Stat()
if err != nil || fi.IsDir() {
return true
}
}

if !opt.SkipLogging {
log.Println("[Static] Serving " + file)
}

// Add an Expires header to the static content
if opt.Expires != nil {
ctx.Resp.Header().Set("Expires", opt.Expires())
}

if opt.ETag {
tag := `"` + GenerateETag(string(fi.Size()), fi.Name(), fi.ModTime().UTC().Format(http.TimeFormat)) + `"`
ctx.Resp.Header().Set("ETag", tag)
if ctx.Req.Header.Get("If-None-Match") == tag {
ctx.Resp.WriteHeader(http.StatusNotModified)
return true
}
}

http.ServeContent(ctx.Resp, ctx.Req.Request, file, fi.ModTime(), f)
return true
}

// GenerateETag generates an ETag based on size, filename and file modification time
func GenerateETag(fileSize, fileName, modTime string) string {
etag := fileSize + fileName + modTime
return base64.StdEncoding.EncodeToString([]byte(etag))
}

// Static returns a middleware handler that serves static files in the given directory.
func Static(directory string, staticOpt ...StaticOptions) Handler {
opt := prepareStaticOptions(directory, staticOpt)

return func(ctx *Context, log *log.Logger) {
staticHandler(ctx, log, opt)
}
}

// Statics registers multiple static middleware handlers all at once.
func Statics(opt StaticOptions, dirs ...string) Handler {
if len(dirs) == 0 {
panic("no static directory is given")
}
opts := make([]StaticOptions, len(dirs))
for i := range dirs {
opts[i] = prepareStaticOption(dirs[i], opt)
}

return func(ctx *Context, log *log.Logger) {
for i := range opts {
if staticHandler(ctx, log, opts[i]) {
return
}
}
}
}

+ 390
- 0
vendor/gopkg.in/macaron.v1/tree.go View File

@@ -0,0 +1,390 @@
// Copyright 2015 The Macaron Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package macaron

import (
"regexp"
"strings"

"github.com/unknwon/com"
)

type patternType int8

const (
_PATTERN_STATIC patternType = iota // /home
_PATTERN_REGEXP // /:id([0-9]+)
_PATTERN_PATH_EXT // /*.*
_PATTERN_HOLDER // /:user
_PATTERN_MATCH_ALL // /*
)

// Leaf represents a leaf route information.
type Leaf struct {
parent *Tree

typ patternType
pattern string
rawPattern string // Contains wildcard instead of regexp
wildcards []string
reg *regexp.Regexp
optional bool

handle Handle
}

var wildcardPattern = regexp.MustCompile(`:[a-zA-Z0-9]+`)

func isSpecialRegexp(pattern, regStr string, pos []int) bool {
return len(pattern) >= pos[1]+len(regStr) && pattern[pos[1]:pos[1]+len(regStr)] == regStr
}

// getNextWildcard tries to find next wildcard and update pattern with corresponding regexp.
func getNextWildcard(pattern string) (wildcard, _ string) {
pos := wildcardPattern.FindStringIndex(pattern)
if pos == nil {
return "", pattern
}
wildcard = pattern[pos[0]:pos[1]]

// Reach last character or no regexp is given.
if len(pattern) == pos[1] {
return wildcard, strings.Replace(pattern, wildcard, `(.+)`, 1)
} else if pattern[pos[1]] != '(' {
switch {
case isSpecialRegexp(pattern, ":int", pos):
pattern = strings.Replace(pattern, ":int", "([0-9]+)", 1)
case isSpecialRegexp(pattern, ":string", pos):
pattern = strings.Replace(pattern, ":string", "([\\w]+)", 1)
default:
return wildcard, strings.Replace(pattern, wildcard, `(.+)`, 1)
}
}

// Cut out placeholder directly.
return wildcard, pattern[:pos[0]] + pattern[pos[1]:]
}

func getWildcards(pattern string) (string, []string) {
wildcards := make([]string, 0, 2)

// Keep getting next wildcard until nothing is left.
var wildcard string
for {
wildcard, pattern = getNextWildcard(pattern)
if len(wildcard) > 0 {
wildcards = append(wildcards, wildcard)
} else {
break
}
}

return pattern, wildcards
}

// getRawPattern removes all regexp but keeps wildcards for building URL path.
func getRawPattern(rawPattern string) string {
rawPattern = strings.Replace(rawPattern, ":int", "", -1)
rawPattern = strings.Replace(rawPattern, ":string", "", -1)

for {
startIdx := strings.Index(rawPattern, "(")
if startIdx == -1 {
break
}

closeIdx := strings.Index(rawPattern, ")")
if closeIdx > -1 {
rawPattern = rawPattern[:startIdx] + rawPattern[closeIdx+1:]
}
}
return rawPattern
}

func checkPattern(pattern string) (typ patternType, rawPattern string, wildcards []string, reg *regexp.Regexp) {
pattern = strings.TrimLeft(pattern, "?")
rawPattern = getRawPattern(pattern)

if pattern == "*" {
typ = _PATTERN_MATCH_ALL
} else if pattern == "*.*" {
typ = _PATTERN_PATH_EXT
} else if strings.Contains(pattern, ":") {
typ = _PATTERN_REGEXP
pattern, wildcards = getWildcards(pattern)
if pattern == "(.+)" {
typ = _PATTERN_HOLDER
} else {
reg = regexp.MustCompile(pattern)
}
}
return typ, rawPattern, wildcards, reg
}

func NewLeaf(parent *Tree, pattern string, handle Handle) *Leaf {
typ, rawPattern, wildcards, reg := checkPattern(pattern)
optional := false
if len(pattern) > 0 && pattern[0] == '?' {
optional = true
}
return &Leaf{parent, typ, pattern, rawPattern, wildcards, reg, optional, handle}
}

// URLPath build path part of URL by given pair values.
func (l *Leaf) URLPath(pairs ...string) string {
if len(pairs)%2 != 0 {
panic("number of pairs does not match")
}

urlPath := l.rawPattern
parent := l.parent
for parent != nil {
urlPath = parent.rawPattern + "/" + urlPath
parent = parent.parent
}
for i := 0; i < len(pairs); i += 2 {
if len(pairs[i]) == 0 {
panic("pair value cannot be empty: " + com.ToStr(i))
} else if pairs[i][0] != ':' && pairs[i] != "*" && pairs[i] != "*.*" {
pairs[i] = ":" + pairs[i]
}
urlPath = strings.Replace(urlPath, pairs[i], pairs[i+1], 1)
}
return urlPath
}

// Tree represents a router tree in Macaron.
type Tree struct {
parent *Tree

typ patternType
pattern string
rawPattern string
wildcards []string
reg *regexp.Regexp

subtrees []*Tree
leaves []*Leaf
}

func NewSubtree(parent *Tree, pattern string) *Tree {
typ, rawPattern, wildcards, reg := checkPattern(pattern)
return &Tree{parent, typ, pattern, rawPattern, wildcards, reg, make([]*Tree, 0, 5), make([]*Leaf, 0, 5)}
}

func NewTree() *Tree {
return NewSubtree(nil, "")
}

func (t *Tree) addLeaf(pattern string, handle Handle) *Leaf {
for i := 0; i < len(t.leaves); i++ {
if t.leaves[i].pattern == pattern {
return t.leaves[i]
}
}

leaf := NewLeaf(t, pattern, handle)

// Add exact same leaf to grandparent/parent level without optional.
if leaf.optional {
parent := leaf.parent
if parent.parent != nil {
parent.parent.addLeaf(parent.pattern, handle)
} else {
parent.addLeaf("", handle) // Root tree can add as empty pattern.
}
}

i := 0
for ; i < len(t.leaves); i++ {
if leaf.typ < t.leaves[i].typ {
break
}
}

if i == len(t.leaves) {
t.leaves = append(t.leaves, leaf)
} else {
t.leaves = append(t.leaves[:i], append([]*Leaf{leaf}, t.leaves[i:]...)...)
}
return leaf
}

func (t *Tree) addSubtree(segment, pattern string, handle Handle) *Leaf {
for i := 0; i < len(t.subtrees); i++ {
if t.subtrees[i].pattern == segment {
return t.subtrees[i].addNextSegment(pattern, handle)
}
}

subtree := NewSubtree(t, segment)
i := 0
for ; i < len(t.subtrees); i++ {
if subtree.typ < t.subtrees[i].typ {
break
}
}

if i == len(t.subtrees) {
t.subtrees = append(t.subtrees, subtree)
} else {
t.subtrees = append(t.subtrees[:i], append([]*Tree{subtree}, t.subtrees[i:]...)...)
}
return subtree.addNextSegment(pattern, handle)
}

func (t *Tree) addNextSegment(pattern string, handle Handle) *Leaf {
pattern = strings.TrimPrefix(pattern, "/")

i := strings.Index(pattern, "/")
if i == -1 {
return t.addLeaf(pattern, handle)
}
return t.addSubtree(pattern[:i], pattern[i+1:], handle)
}

func (t *Tree) Add(pattern string, handle Handle) *Leaf {
pattern = strings.TrimSuffix(pattern, "/")
return t.addNextSegment(pattern, handle)
}

func (t *Tree) matchLeaf(globLevel int, url string, params Params) (Handle, bool) {
url, err := PathUnescape(url)
if err != nil {
return nil, false
}
for i := 0; i < len(t.leaves); i++ {
switch t.leaves[i].typ {
case _PATTERN_STATIC:
if t.leaves[i].pattern == url {
return t.leaves[i].handle, true
}
case _PATTERN_REGEXP:
results := t.leaves[i].reg.FindStringSubmatch(url)
// Number of results and wildcasrd should be exact same.
if len(results)-1 != len(t.leaves[i].wildcards) {
break
}

for j := 0; j < len(t.leaves[i].wildcards); j++ {
params[t.leaves[i].wildcards[j]] = results[j+1]
}
return t.leaves[i].handle, true
case _PATTERN_PATH_EXT:
j := strings.LastIndex(url, ".")
if j > -1 {
params[":path"] = url[:j]
params[":ext"] = url[j+1:]
} else {
params[":path"] = url
}
return t.leaves[i].handle, true
case _PATTERN_HOLDER:
params[t.leaves[i].wildcards[0]] = url
return t.leaves[i].handle, true
case _PATTERN_MATCH_ALL:
params["*"] = url
params["*"+com.ToStr(globLevel)] = url
return t.leaves[i].handle, true
}
}
return nil, false
}

func (t *Tree) matchSubtree(globLevel int, segment, url string, params Params) (Handle, bool) {
unescapedSegment, err := PathUnescape(segment)
if err != nil {
return nil, false
}
for i := 0; i < len(t.subtrees); i++ {
switch t.subtrees[i].typ {
case _PATTERN_STATIC:
if t.subtrees[i].pattern == unescapedSegment {
if handle, ok := t.subtrees[i].matchNextSegment(globLevel, url, params); ok {
return handle, true
}
}
case _PATTERN_REGEXP:
results := t.subtrees[i].reg.FindStringSubmatch(unescapedSegment)
if len(results)-1 != len(t.subtrees[i].wildcards) {
break
}

for j := 0; j < len(t.subtrees[i].wildcards); j++ {
params[t.subtrees[i].wildcards[j]] = results[j+1]
}
if handle, ok := t.subtrees[i].matchNextSegment(globLevel, url, params); ok {
return handle, true
}
case _PATTERN_HOLDER:
if handle, ok := t.subtrees[i].matchNextSegment(globLevel+1, url, params); ok {
params[t.subtrees[i].wildcards[0]] = unescapedSegment
return handle, true
}
case _PATTERN_MATCH_ALL:
if handle, ok := t.subtrees[i].matchNextSegment(globLevel+1, url, params); ok {
params["*"+com.ToStr(globLevel)] = unescapedSegment
return handle, true
}
}
}

if len(t.leaves) > 0 {
leaf := t.leaves[len(t.leaves)-1]
unescapedURL, err := PathUnescape(segment + "/" + url)
if err != nil {
return nil, false
}
if leaf.typ == _PATTERN_PATH_EXT {
j := strings.LastIndex(unescapedURL, ".")
if j > -1 {
params[":path"] = unescapedURL[:j]
params[":ext"] = unescapedURL[j+1:]
} else {
params[":path"] = unescapedURL
}
return leaf.handle, true
} else if leaf.typ == _PATTERN_MATCH_ALL {
params["*"] = unescapedURL
params["*"+com.ToStr(globLevel)] = unescapedURL
return leaf.handle, true
}
}
return nil, false
}

func (t *Tree) matchNextSegment(globLevel int, url string, params Params) (Handle, bool) {
i := strings.Index(url, "/")
if i == -1 {
return t.matchLeaf(globLevel, url, params)
}
return t.matchSubtree(globLevel, url[:i], url[i+1:], params)
}

func (t *Tree) Match(url string) (Handle, Params, bool) {
url = strings.TrimPrefix(url, "/")
url = strings.TrimSuffix(url, "/")
params := make(Params)
handle, ok := t.matchNextSegment(0, url, params)
return handle, params, ok
}

// MatchTest returns true if given URL is matched by given pattern.
func MatchTest(pattern, url string) bool {
t := NewTree()
t.Add(pattern, nil)
_, _, ok := t.Match(url)
return ok
}

+ 25
- 0
vendor/gopkg.in/macaron.v1/util_go17.go View File

@@ -0,0 +1,25 @@
// +build !go1.8

// Copyright 2017 The Macaron Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package macaron

import "net/url"

// PathUnescape unescapes a path. Ideally, this function would use
// url.PathUnescape(..), but the function was not introduced until go1.8.
func PathUnescape(s string) (string, error) {
return url.QueryUnescape(s)
}

+ 24
- 0
vendor/gopkg.in/macaron.v1/util_go18.go View File

@@ -0,0 +1,24 @@
// +build go1.8

// Copyright 2017 The Macaron Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package macaron

import "net/url"

// PathUnescape unescapes a path.
func PathUnescape(s string) (string, error) {
return url.PathUnescape(s)
}

+ 6
- 137
vendor/modules.txt View File

@@ -1,5 +1,4 @@
# cloud.google.com/go v0.45.0
## explicit
cloud.google.com/go/compute/metadata
cloud.google.com/go/iam
cloud.google.com/go/internal/optional
@@ -8,43 +7,31 @@ cloud.google.com/go/pubsub
cloud.google.com/go/pubsub/apiv1
cloud.google.com/go/pubsub/internal/distribution
# gitea.com/jolheiser/gitea-vet v0.1.0
## explicit
gitea.com/jolheiser/gitea-vet
gitea.com/jolheiser/gitea-vet/checks
# gitea.com/lunny/levelqueue v0.3.0
## explicit
gitea.com/lunny/levelqueue
# gitea.com/macaron/binding v0.0.0-20190822013154-a5f53841ed2b
## explicit
gitea.com/macaron/binding
# gitea.com/macaron/cache v0.0.0-20190822004001-a6e7fee4ee76
## explicit
gitea.com/macaron/cache
gitea.com/macaron/cache/memcache
gitea.com/macaron/cache/redis
# gitea.com/macaron/captcha v0.0.0-20190822015246-daa973478bae
## explicit
gitea.com/macaron/captcha
# gitea.com/macaron/cors v0.0.0-20190826180238-95aec09ea8b4
## explicit
gitea.com/macaron/cors
# gitea.com/macaron/csrf v0.0.0-20190822024205-3dc5a4474439
## explicit
gitea.com/macaron/csrf
# gitea.com/macaron/gzip v0.0.0-20191118041502-506895b47aae
## explicit
gitea.com/macaron/gzip
# gitea.com/macaron/i18n v0.0.0-20190822004228-474e714e2223
## explicit
gitea.com/macaron/i18n
# gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a
## explicit
gitea.com/macaron/inject
# gitea.com/macaron/macaron v1.4.0
## explicit
gitea.com/macaron/macaron
# gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d
## explicit
gitea.com/macaron/session
gitea.com/macaron/session/couchbase
gitea.com/macaron/session/memcache
@@ -53,13 +40,10 @@ gitea.com/macaron/session/nodb
gitea.com/macaron/session/postgres
gitea.com/macaron/session/redis
# gitea.com/macaron/toolbox v0.0.0-20190822013122-05ff0fc766b7
## explicit
gitea.com/macaron/toolbox
# github.com/BurntSushi/toml v0.3.1
## explicit
github.com/BurntSushi/toml
# github.com/PuerkitoBio/goquery v1.5.0
## explicit
github.com/PuerkitoBio/goquery
# github.com/PuerkitoBio/purell v1.1.1
github.com/PuerkitoBio/purell
@@ -68,7 +52,6 @@ github.com/PuerkitoBio/urlesc
# github.com/RichardKnop/logging v0.0.0-20181101035820-b1d5d44c82d6
github.com/RichardKnop/logging
# github.com/RichardKnop/machinery v1.6.9
## explicit
github.com/RichardKnop/machinery/v1
github.com/RichardKnop/machinery/v1/backends/amqp
github.com/RichardKnop/machinery/v1/backends/dynamodb
@@ -95,7 +78,6 @@ github.com/RichardKnop/machinery/v1/tracing
# github.com/RichardKnop/redsync v1.2.0
github.com/RichardKnop/redsync
# github.com/RoaringBitmap/roaring v0.4.23
## explicit
github.com/RoaringBitmap/roaring
# github.com/andybalholm/cascadia v1.0.0
github.com/andybalholm/cascadia
@@ -147,10 +129,7 @@ github.com/aws/aws-sdk-go/service/sts/stsiface
github.com/aymerick/douceur/css
# github.com/beorn7/perks v1.0.1
github.com/beorn7/perks/quantile
# github.com/bgentry/speakeasy v0.1.0
## explicit
# github.com/blevesearch/bleve v1.0.7
## explicit
github.com/blevesearch/bleve
github.com/blevesearch/bleve/analysis
github.com/blevesearch/bleve/analysis/analyzer/custom
@@ -212,7 +191,6 @@ github.com/bradfitz/gomemcache/memcache
# github.com/chris-ramon/douceur v0.2.0
github.com/chris-ramon/douceur/parser
# github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2
## explicit
github.com/couchbase/gomemcached
github.com/couchbase/gomemcached/client
# github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85
@@ -227,31 +205,20 @@ github.com/couchbase/vellum/utf8
github.com/couchbaselabs/go-couchbase
# github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d
github.com/cpuguy83/go-md2man/v2/md2man
# github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d
## explicit
# github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548
## explicit
# github.com/cznic/strutil v0.0.0-20181122101858-275e90344537
## explicit
# github.com/davecgh/go-spew v1.1.1
github.com/davecgh/go-spew/spew
# github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc
## explicit
github.com/denisenkom/go-mssqldb
github.com/denisenkom/go-mssqldb/internal/cp
github.com/denisenkom/go-mssqldb/internal/decimal
github.com/denisenkom/go-mssqldb/internal/querytext
# github.com/dgrijalva/jwt-go v3.2.0+incompatible
## explicit
github.com/dgrijalva/jwt-go
# github.com/dustin/go-humanize v1.0.0
## explicit
github.com/dustin/go-humanize
# github.com/editorconfig/editorconfig-core-go/v2 v2.1.1
## explicit
github.com/editorconfig/editorconfig-core-go/v2
# github.com/emirpasic/gods v1.12.0
## explicit
github.com/emirpasic/gods/containers
github.com/emirpasic/gods/lists
github.com/emirpasic/gods/lists/arraylist
@@ -259,14 +226,7 @@ github.com/emirpasic/gods/trees
github.com/emirpasic/gods/trees/binaryheap
github.com/emirpasic/gods/utils
# github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a
## explicit
github.com/ethantkoenig/rupture
# github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51
## explicit
# github.com/facebookgo/stack v0.0.0-20160209184415-751773369052
## explicit
# github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870
## explicit
# github.com/fatih/color v1.9.0
github.com/fatih/color
# github.com/fatih/structtag v1.2.0
@@ -274,13 +234,10 @@ github.com/fatih/structtag
# github.com/fsnotify/fsnotify v1.4.7
github.com/fsnotify/fsnotify
# github.com/gliderlabs/ssh v0.2.2
## explicit
github.com/gliderlabs/ssh
# github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a
## explicit
github.com/glycerine/go-unsnap-stream
# github.com/go-enry/go-enry/v2 v2.3.0
## explicit
github.com/go-enry/go-enry/v2
github.com/go-enry/go-enry/v2/data
github.com/go-enry/go-enry/v2/data/rule
@@ -295,14 +252,12 @@ github.com/go-git/gcfg/scanner
github.com/go-git/gcfg/token
github.com/go-git/gcfg/types
# github.com/go-git/go-billy/v5 v5.0.0
## explicit
github.com/go-git/go-billy/v5
github.com/go-git/go-billy/v5/helper/chroot
github.com/go-git/go-billy/v5/helper/polyfill
github.com/go-git/go-billy/v5/osfs
github.com/go-git/go-billy/v5/util
# github.com/go-git/go-git/v5 v5.0.0
## explicit
github.com/go-git/go-git/v5
github.com/go-git/go-git/v5/config
github.com/go-git/go-git/v5/internal/revision
@@ -347,8 +302,11 @@ github.com/go-git/go-git/v5/utils/merkletrie/index
github.com/go-git/go-git/v5/utils/merkletrie/internal/frame
github.com/go-git/go-git/v5/utils/merkletrie/noder
# github.com/go-ini/ini v1.56.0
## explicit
github.com/go-ini/ini
# github.com/go-macaron/auth v0.0.0-20161228062157-884c0e6c9b92
github.com/go-macaron/auth
# github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191
github.com/go-macaron/inject
# github.com/go-openapi/analysis v0.19.5
github.com/go-openapi/analysis
github.com/go-openapi/analysis/internal
@@ -359,7 +317,6 @@ github.com/go-openapi/inflect
# github.com/go-openapi/jsonpointer v0.19.3
github.com/go-openapi/jsonpointer
# github.com/go-openapi/jsonreference v0.19.3
## explicit
github.com/go-openapi/jsonreference
# github.com/go-openapi/loads v0.19.3
github.com/go-openapi/loads
@@ -381,7 +338,6 @@ github.com/go-openapi/swag
# github.com/go-openapi/validate v0.19.3
github.com/go-openapi/validate
# github.com/go-redis/redis v6.15.2+incompatible
## explicit
github.com/go-redis/redis
github.com/go-redis/redis/internal
github.com/go-redis/redis/internal/consistenthash
@@ -390,15 +346,12 @@ github.com/go-redis/redis/internal/pool
github.com/go-redis/redis/internal/proto
github.com/go-redis/redis/internal/util
# github.com/go-resty/resty/v2 v2.3.0
## explicit
github.com/go-resty/resty/v2
# github.com/go-sql-driver/mysql v1.4.1
## explicit
github.com/go-sql-driver/mysql
# github.com/go-stack/stack v1.8.0
github.com/go-stack/stack
# github.com/go-swagger/go-swagger v0.21.0
## explicit
github.com/go-swagger/go-swagger/cmd/swagger
github.com/go-swagger/go-swagger/cmd/swagger/commands
github.com/go-swagger/go-swagger/cmd/swagger/commands/diff
@@ -408,7 +361,6 @@ github.com/go-swagger/go-swagger/codescan
github.com/go-swagger/go-swagger/generator
github.com/go-swagger/go-swagger/scan
# github.com/gobwas/glob v0.2.3
## explicit
github.com/gobwas/glob
github.com/gobwas/glob/compiler
github.com/gobwas/glob/match
@@ -418,17 +370,14 @@ github.com/gobwas/glob/syntax/lexer
github.com/gobwas/glob/util/runes
github.com/gobwas/glob/util/strings
# github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28
## explicit
github.com/gogs/chardet
# github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
## explicit
github.com/gogs/cron
# github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe
github.com/golang-sql/civil
# github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6
github.com/golang/groupcache/lru
# github.com/golang/protobuf v1.4.1
## explicit
github.com/golang/protobuf/proto
github.com/golang/protobuf/protoc-gen-go/descriptor
github.com/golang/protobuf/ptypes
@@ -442,7 +391,6 @@ github.com/golang/snappy
github.com/gomodule/redigo/internal
github.com/gomodule/redigo/redis
# github.com/google/go-github/v24 v24.0.1
## explicit
github.com/google/go-github/v24/github
# github.com/google/go-querystring v1.0.0
github.com/google/go-querystring/query
@@ -451,7 +399,6 @@ github.com/google/uuid
# github.com/googleapis/gax-go/v2 v2.0.5
github.com/googleapis/gax-go/v2
# github.com/gorilla/context v1.1.1
## explicit
github.com/gorilla/context
# github.com/gorilla/css v1.0.0
github.com/gorilla/css/scanner
@@ -466,7 +413,6 @@ github.com/gorilla/sessions
# github.com/hashicorp/go-cleanhttp v0.5.1
github.com/hashicorp/go-cleanhttp
# github.com/hashicorp/go-retryablehttp v0.6.6
## explicit
github.com/hashicorp/go-retryablehttp
# github.com/hashicorp/hcl v1.0.0
github.com/hashicorp/hcl
@@ -480,15 +426,10 @@ github.com/hashicorp/hcl/json/parser
github.com/hashicorp/hcl/json/scanner
github.com/hashicorp/hcl/json/token
# github.com/huandu/xstrings v1.3.0
## explicit
github.com/huandu/xstrings
# github.com/issue9/assert v1.3.2
## explicit
# github.com/issue9/identicon v1.0.1
## explicit
github.com/issue9/identicon
# github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d
## explicit
github.com/jaytaylor/html2text
# github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99
github.com/jbenet/go-context/io
@@ -496,21 +437,15 @@ github.com/jbenet/go-context/io
github.com/jessevdk/go-flags
# github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af
github.com/jmespath/go-jmespath
# github.com/jmhodges/levigo v1.0.0
## explicit
# github.com/joho/godotenv v1.3.0
## explicit
# github.com/json-iterator/go v1.1.9
github.com/json-iterator/go
# github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657
## explicit
github.com/kballard/go-shellquote
# github.com/kelseyhightower/envconfig v1.3.0
github.com/kelseyhightower/envconfig
# github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd
github.com/kevinburke/ssh_config
# github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4
## explicit
github.com/keybase/go-crypto/brainpool
github.com/keybase/go-crypto/cast5
github.com/keybase/go-crypto/curve25519
@@ -525,7 +460,6 @@ github.com/keybase/go-crypto/openpgp/packet
github.com/keybase/go-crypto/openpgp/s2k
github.com/keybase/go-crypto/rsa
# github.com/klauspost/compress v1.10.2
## explicit
github.com/klauspost/compress/flate
github.com/klauspost/compress/gzip
# github.com/klauspost/cpuid v1.2.3
@@ -535,16 +469,13 @@ github.com/kr/pretty
# github.com/kr/text v0.2.0
github.com/kr/text
# github.com/lafriks/xormstore v1.3.2
## explicit
github.com/lafriks/xormstore
github.com/lafriks/xormstore/util
# github.com/lib/pq v1.2.0
## explicit
github.com/lib/pq
github.com/lib/pq/oid
github.com/lib/pq/scram
# github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96
## explicit
github.com/lunny/dingtalk_webhook
# github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de
github.com/lunny/log
@@ -557,13 +488,11 @@ github.com/lunny/nodb/store/goleveldb
# github.com/magiconair/properties v1.8.1
github.com/magiconair/properties
# github.com/mailru/easyjson v0.7.0
## explicit
github.com/mailru/easyjson
github.com/mailru/easyjson/buffer
github.com/mailru/easyjson/jlexer
github.com/mailru/easyjson/jwriter
# github.com/markbates/goth v1.61.2
## explicit
github.com/markbates/goth
github.com/markbates/goth/gothic
github.com/markbates/goth/providers/bitbucket
@@ -581,35 +510,26 @@ github.com/markbates/goth/providers/yandex
# github.com/mattn/go-colorable v0.1.4
github.com/mattn/go-colorable
# github.com/mattn/go-isatty v0.0.11
## explicit
github.com/mattn/go-isatty
# github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d
## explicit
# github.com/mattn/go-runewidth v0.0.7
github.com/mattn/go-runewidth
# github.com/mattn/go-sqlite3 v1.11.0
## explicit
github.com/mattn/go-sqlite3
# github.com/matttproud/golang_protobuf_extensions v1.0.1
github.com/matttproud/golang_protobuf_extensions/pbutil
# github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75
## explicit
github.com/mcuadros/go-version
# github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81
## explicit
github.com/mgechev/dots
# github.com/mgechev/revive v1.0.2
## explicit
github.com/mgechev/revive/formatter
github.com/mgechev/revive/lint
github.com/mgechev/revive/rule
# github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912
## explicit
github.com/microcosm-cc/bluemonday
# github.com/minio/md5-simd v1.1.0
github.com/minio/md5-simd
# github.com/minio/minio-go v6.0.14+incompatible
## explicit
github.com/minio/minio-go
github.com/minio/minio-go/pkg/credentials
github.com/minio/minio-go/pkg/encrypt
@@ -617,7 +537,6 @@ github.com/minio/minio-go/pkg/s3signer
github.com/minio/minio-go/pkg/s3utils
github.com/minio/minio-go/pkg/set
# github.com/minio/minio-go/v6 v6.0.57
## explicit
github.com/minio/minio-go/v6
github.com/minio/minio-go/v6/pkg/credentials
github.com/minio/minio-go/v6/pkg/encrypt
@@ -628,7 +547,6 @@ github.com/minio/minio-go/v6/pkg/tags
# github.com/minio/sha256-simd v0.1.1
github.com/minio/sha256-simd
# github.com/mitchellh/go-homedir v1.1.0
## explicit
github.com/mitchellh/go-homedir
# github.com/mitchellh/mapstructure v1.1.2
github.com/mitchellh/mapstructure
@@ -641,21 +559,16 @@ github.com/mrjones/oauth
# github.com/mschoch/smat v0.2.0
github.com/mschoch/smat
# github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc
## explicit
github.com/msteinert/pam
# github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5
## explicit
github.com/nfnt/resize
# github.com/niklasfasching/go-org v0.1.9
## explicit
github.com/niklasfasching/go-org/org
# github.com/olekukonko/tablewriter v0.0.4
github.com/olekukonko/tablewriter
# github.com/oliamb/cutter v0.2.2
## explicit
github.com/oliamb/cutter
# github.com/olivere/elastic/v7 v7.0.9
## explicit
github.com/olivere/elastic/v7
github.com/olivere/elastic/v7/config
github.com/olivere/elastic/v7/uritemplates
@@ -668,53 +581,41 @@ github.com/pelletier/go-toml
# github.com/philhofer/fwd v1.0.0
github.com/philhofer/fwd
# github.com/pkg/errors v0.9.1
## explicit
github.com/pkg/errors
# github.com/pmezard/go-difflib v1.0.0
github.com/pmezard/go-difflib/difflib
# github.com/pquerna/otp v1.2.0
## explicit
github.com/pquerna/otp
github.com/pquerna/otp/hotp
github.com/pquerna/otp/totp
# github.com/prometheus/client_golang v1.1.0
## explicit
github.com/prometheus/client_golang/prometheus
github.com/prometheus/client_golang/prometheus/internal
github.com/prometheus/client_golang/prometheus/promhttp
# github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4
## explicit
github.com/prometheus/client_model/go
# github.com/prometheus/common v0.6.0
github.com/prometheus/common/expfmt
github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg
github.com/prometheus/common/model
# github.com/prometheus/procfs v0.0.4
## explicit
github.com/prometheus/procfs
github.com/prometheus/procfs/internal/fs
github.com/prometheus/procfs/internal/util
# github.com/quasoft/websspi v1.0.0
## explicit
github.com/quasoft/websspi
github.com/quasoft/websspi/secctx
# github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001
## explicit
# github.com/russross/blackfriday/v2 v2.0.1
github.com/russross/blackfriday/v2
# github.com/satori/go.uuid v1.2.0
## explicit
github.com/satori/go.uuid
# github.com/sergi/go-diff v1.1.0
## explicit
github.com/sergi/go-diff/diffmatchpatch
# github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b
## explicit
github.com/shurcooL/httpfs/vfsutil
# github.com/shurcooL/sanitized_anchor_name v1.0.0
github.com/shurcooL/sanitized_anchor_name
# github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd
## explicit
github.com/shurcooL/vfsgen
# github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d
github.com/siddontang/go-snappy/snappy
@@ -734,7 +635,6 @@ github.com/steveyen/gtreap
# github.com/streadway/amqp v0.0.0-20190214183023-884228600bc9
github.com/streadway/amqp
# github.com/stretchr/testify v1.4.0
## explicit
github.com/stretchr/testify/assert
github.com/stretchr/testify/require
# github.com/syndtr/goleveldb v1.0.0
@@ -750,38 +650,28 @@ github.com/syndtr/goleveldb/leveldb/opt
github.com/syndtr/goleveldb/leveldb/storage
github.com/syndtr/goleveldb/leveldb/table
github.com/syndtr/goleveldb/leveldb/util
# github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481
## explicit
# github.com/tinylib/msgp v1.1.2
## explicit
github.com/tinylib/msgp/msgp
# github.com/toqueteos/trie v1.0.0
github.com/toqueteos/trie
# github.com/toqueteos/webbrowser v1.2.0
github.com/toqueteos/webbrowser
# github.com/tstranex/u2f v1.0.0
## explicit
github.com/tstranex/u2f
# github.com/unknwon/cae v1.0.0
## explicit
github.com/unknwon/cae
github.com/unknwon/cae/zip
# github.com/unknwon/com v1.0.1
## explicit
github.com/unknwon/com
# github.com/unknwon/i18n v0.0.0-20190805065654-5c6446a380b6
## explicit
github.com/unknwon/i18n
# github.com/unknwon/paginater v0.0.0-20151104151617-7748a72e0141
## explicit
github.com/unknwon/paginater
# github.com/urfave/cli v1.22.1
## explicit
github.com/urfave/cli
# github.com/willf/bitset v1.1.10
github.com/willf/bitset
# github.com/xanzy/go-gitlab v0.31.0
## explicit
github.com/xanzy/go-gitlab
# github.com/xanzy/ssh-agent v0.2.1
github.com/xanzy/ssh-agent
@@ -790,10 +680,8 @@ github.com/xdg/scram
# github.com/xdg/stringprep v1.0.0
github.com/xdg/stringprep
# github.com/yohcop/openid-go v1.0.0
## explicit
github.com/yohcop/openid-go
# github.com/yuin/goldmark v1.1.27
## explicit
github.com/yuin/goldmark
github.com/yuin/goldmark/ast
github.com/yuin/goldmark/extension
@@ -804,7 +692,6 @@ github.com/yuin/goldmark/renderer/html
github.com/yuin/goldmark/text
github.com/yuin/goldmark/util
# github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60
## explicit
github.com/yuin/goldmark-meta
# go.etcd.io/bbolt v1.3.4
go.etcd.io/bbolt
@@ -856,7 +743,6 @@ go.opencensus.io/trace/internal
go.opencensus.io/trace/propagation
go.opencensus.io/trace/tracestate
# golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79
## explicit
golang.org/x/crypto/acme
golang.org/x/crypto/acme/autocert
golang.org/x/crypto/argon2
@@ -884,11 +770,9 @@ golang.org/x/crypto/ssh/agent
golang.org/x/crypto/ssh/internal/bcrypt_pbkdf
golang.org/x/crypto/ssh/knownhosts
# golang.org/x/mod v0.3.0
## explicit
golang.org/x/mod/module
golang.org/x/mod/semver
# golang.org/x/net v0.0.0-20200513185701-a91f0712d120
## explicit
golang.org/x/net/context
golang.org/x/net/context/ctxhttp
golang.org/x/net/html
@@ -904,7 +788,6 @@ golang.org/x/net/proxy
golang.org/x/net/publicsuffix
golang.org/x/net/trace
# golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
## explicit
golang.org/x/oauth2
golang.org/x/oauth2/google
golang.org/x/oauth2/internal
@@ -914,7 +797,6 @@ golang.org/x/oauth2/jwt
golang.org/x/sync/errgroup
golang.org/x/sync/semaphore
# golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f
## explicit
golang.org/x/sys/cpu
golang.org/x/sys/internal/unsafeheader
golang.org/x/sys/unix
@@ -922,7 +804,6 @@ golang.org/x/sys/windows
golang.org/x/sys/windows/svc
golang.org/x/sys/windows/svc/debug
# golang.org/x/text v0.3.2
## explicit
golang.org/x/text/encoding
golang.org/x/text/encoding/charmap
golang.org/x/text/encoding/htmlindex
@@ -945,10 +826,8 @@ golang.org/x/text/unicode/bidi
golang.org/x/text/unicode/norm
golang.org/x/text/width
# golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1
## explicit
golang.org/x/time/rate
# golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53
## explicit
golang.org/x/tools/cover
golang.org/x/tools/go/analysis
golang.org/x/tools/go/analysis/internal/analysisflags
@@ -988,7 +867,6 @@ google.golang.org/api/transport/grpc
google.golang.org/api/transport/http
google.golang.org/api/transport/http/internal/propagation
# google.golang.org/appengine v1.6.5
## explicit
google.golang.org/appengine
google.golang.org/appengine/cloudsql
google.golang.org/appengine/internal
@@ -1087,41 +965,32 @@ google.golang.org/protobuf/types/known/durationpb
google.golang.org/protobuf/types/known/emptypb
google.golang.org/protobuf/types/known/timestamppb
# gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc
## explicit
gopkg.in/alexcesaro/quotedprintable.v3
# gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175
## explicit
gopkg.in/asn1-ber.v1
# gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
## explicit
gopkg.in/gomail.v2
# gopkg.in/ini.v1 v1.52.0
## explicit
gopkg.in/ini.v1
# gopkg.in/ldap.v3 v3.0.2
## explicit
gopkg.in/ldap.v3
# gopkg.in/macaron.v1 v1.3.9
gopkg.in/macaron.v1
# gopkg.in/testfixtures.v2 v2.5.0
## explicit
gopkg.in/testfixtures.v2
# gopkg.in/toqueteos/substring.v1 v1.0.2
gopkg.in/toqueteos/substring.v1
# gopkg.in/warnings.v0 v0.1.2
gopkg.in/warnings.v0
# gopkg.in/yaml.v2 v2.2.8
## explicit
gopkg.in/yaml.v2
# mvdan.cc/xurls/v2 v2.1.0
## explicit
mvdan.cc/xurls/v2
# strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
## explicit
strk.kbt.io/projects/go/libravatar
# xorm.io/builder v0.3.7
## explicit
xorm.io/builder
# xorm.io/xorm v1.0.1
## explicit
xorm.io/xorm
xorm.io/xorm/caches
xorm.io/xorm/contexts


Loading…
Cancel
Save