1
0
mirror of https://github.com/astaxie/beego.git synced 2024-06-30 16:54:14 +00:00

Merge remote-tracking branch 'remotes/upstream/develop' into err_ctrler

This commit is contained in:
JessonChan 2016-03-02 13:34:00 +08:00
commit b30ce768f8
7 changed files with 151 additions and 97 deletions

View File

@ -2,9 +2,9 @@ language: go
go: go:
- tip - tip
- 1.6.0
- 1.5.3 - 1.5.3
- 1.4.3 - 1.4.3
- 1.3.3
services: services:
- redis-server - redis-server
- mysql - mysql
@ -21,9 +21,9 @@ install:
- go get github.com/bradfitz/gomemcache/memcache - go get github.com/bradfitz/gomemcache/memcache
- go get github.com/garyburd/redigo/redis - go get github.com/garyburd/redigo/redis
- go get github.com/beego/x2j - go get github.com/beego/x2j
- go get github.com/couchbase/go-couchbase
- go get github.com/beego/goyaml2 - go get github.com/beego/goyaml2
- go get github.com/belogik/goes - go get github.com/belogik/goes
- go get github.com/couchbase/go-couchbase
- go get github.com/siddontang/ledisdb/config - go get github.com/siddontang/ledisdb/config
- go get github.com/siddontang/ledisdb/ledis - go get github.com/siddontang/ledisdb/ledis
- go get golang.org/x/tools/cmd/vet - go get golang.org/x/tools/cmd/vet

View File

@ -15,11 +15,11 @@
package beego package beego
import ( import (
"fmt"
"html/template" "html/template"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"fmt"
"github.com/astaxie/beego/config" "github.com/astaxie/beego/config"
"github.com/astaxie/beego/session" "github.com/astaxie/beego/session"
@ -111,7 +111,6 @@ var (
// GlobalSessions is the instance for the session manager // GlobalSessions is the instance for the session manager
GlobalSessions *session.Manager GlobalSessions *session.Manager
workPath string
// appConfigPath is the path to the config files // appConfigPath is the path to the config files
appConfigPath string appConfigPath string
// appConfigProvider is the provider for the config, default is ini // appConfigProvider is the provider for the config, default is ini
@ -120,12 +119,8 @@ var (
func init() { func init() {
AppPath, _ = filepath.Abs(filepath.Dir(os.Args[0])) AppPath, _ = filepath.Abs(filepath.Dir(os.Args[0]))
workPath, _ = os.Getwd()
workPath, _ = filepath.Abs(workPath)
if workPath != AppPath { os.Chdir(AppPath)
os.Chdir(AppPath)
}
BConfig = &Config{ BConfig = &Config{
AppName: "beego", AppName: "beego",
@ -175,7 +170,7 @@ func init() {
SessionName: "beegosessionID", SessionName: "beegosessionID",
SessionGCMaxLifetime: 3600, SessionGCMaxLifetime: 3600,
SessionProviderConfig: "", SessionProviderConfig: "",
SessionCookieLifeTime: 0, //set cookie default is the brower life SessionCookieLifeTime: 0, //set cookie default is the browser life
SessionAutoSetCookie: true, SessionAutoSetCookie: true,
SessionDomain: "", SessionDomain: "",
}, },
@ -189,7 +184,7 @@ func init() {
appConfigPath = filepath.Join(AppPath, "conf", "app.conf") appConfigPath = filepath.Join(AppPath, "conf", "app.conf")
if !utils.FileExists(appConfigPath) { if !utils.FileExists(appConfigPath) {
AppConfig = &beegoAppConfig{config.NewFakeConfig()} AppConfig = &beegoAppConfig{innerConfig: config.NewFakeConfig()}
return return
} }
@ -202,11 +197,11 @@ func parseConfig(appConfigPath string) (err error) {
if err != nil { if err != nil {
return err return err
} }
// set the runmode first // set the run mode first
if envRunMode := os.Getenv("BEEGO_RUNMODE"); envRunMode != "" { if envRunMode := os.Getenv("BEEGO_RUNMODE"); envRunMode != "" {
BConfig.RunMode = envRunMode BConfig.RunMode = envRunMode
} else if runmode := AppConfig.String("RunMode"); runmode != "" { } else if runMode := AppConfig.String("RunMode"); runMode != "" {
BConfig.RunMode = runmode BConfig.RunMode = runMode
} }
BConfig.AppName = AppConfig.DefaultString("AppName", BConfig.AppName) BConfig.AppName = AppConfig.DefaultString("AppName", BConfig.AppName)
@ -299,7 +294,7 @@ func parseConfig(appConfigPath string) (err error) {
} }
//init log //init log
BeeLogger.Close() BeeLogger.Reset()
for adaptor, config := range BConfig.Log.Outputs { for adaptor, config := range BConfig.Log.Outputs {
err = BeeLogger.SetLogger(adaptor, config) err = BeeLogger.SetLogger(adaptor, config)
if err != nil { if err != nil {
@ -393,46 +388,46 @@ func (b *beegoAppConfig) Float(key string) (float64, error) {
return b.innerConfig.Float(key) return b.innerConfig.Float(key)
} }
func (b *beegoAppConfig) DefaultString(key string, defaultval string) string { func (b *beegoAppConfig) DefaultString(key string, defaultVal string) string {
if v := b.String(key); v != "" { if v := b.String(key); v != "" {
return v return v
} }
return defaultval return defaultVal
} }
func (b *beegoAppConfig) DefaultStrings(key string, defaultval []string) []string { func (b *beegoAppConfig) DefaultStrings(key string, defaultVal []string) []string {
if v := b.Strings(key); len(v) != 0 { if v := b.Strings(key); len(v) != 0 {
return v return v
} }
return defaultval return defaultVal
} }
func (b *beegoAppConfig) DefaultInt(key string, defaultval int) int { func (b *beegoAppConfig) DefaultInt(key string, defaultVal int) int {
if v, err := b.Int(key); err == nil { if v, err := b.Int(key); err == nil {
return v return v
} }
return defaultval return defaultVal
} }
func (b *beegoAppConfig) DefaultInt64(key string, defaultval int64) int64 { func (b *beegoAppConfig) DefaultInt64(key string, defaultVal int64) int64 {
if v, err := b.Int64(key); err == nil { if v, err := b.Int64(key); err == nil {
return v return v
} }
return defaultval return defaultVal
} }
func (b *beegoAppConfig) DefaultBool(key string, defaultval bool) bool { func (b *beegoAppConfig) DefaultBool(key string, defaultVal bool) bool {
if v, err := b.Bool(key); err == nil { if v, err := b.Bool(key); err == nil {
return v return v
} }
return defaultval return defaultVal
} }
func (b *beegoAppConfig) DefaultFloat(key string, defaultval float64) float64 { func (b *beegoAppConfig) DefaultFloat(key string, defaultVal float64) float64 {
if v, err := b.Float(key); err == nil { if v, err := b.Float(key); err == nil {
return v return v
} }
return defaultval return defaultVal
} }
func (b *beegoAppConfig) DIY(key string) (interface{}, error) { func (b *beegoAppConfig) DIY(key string) (interface{}, error) {

View File

@ -47,17 +47,17 @@ var colors = []brush{
// consoleWriter implements LoggerInterface and writes messages to terminal. // consoleWriter implements LoggerInterface and writes messages to terminal.
type consoleWriter struct { type consoleWriter struct {
lg *log.Logger lg *log.Logger
Level int `json:"level"` Level int `json:"level"`
Color bool `json:"color"` Colorful bool `json:"color"` //this filed is useful only when system's terminal supports color
} }
// NewConsole create ConsoleWriter returning as LoggerInterface. // NewConsole create ConsoleWriter returning as LoggerInterface.
func NewConsole() Logger { func NewConsole() Logger {
cw := &consoleWriter{ cw := &consoleWriter{
lg: log.New(os.Stdout, "", 0), lg: log.New(os.Stdout, "", 0),
Level: LevelDebug, Level: LevelDebug,
Color: true, Colorful: true,
} }
return cw return cw
} }
@ -68,7 +68,11 @@ func (c *consoleWriter) Init(jsonConfig string) error {
if len(jsonConfig) == 0 { if len(jsonConfig) == 0 {
return nil return nil
} }
return json.Unmarshal([]byte(jsonConfig), c) err := json.Unmarshal([]byte(jsonConfig), c)
if runtime.GOOS == "windows" {
c.Colorful = false
}
return err
} }
// WriteMsg write message in console. // WriteMsg write message in console.
@ -77,12 +81,11 @@ func (c *consoleWriter) WriteMsg(when time.Time, msg string, level int) error {
return nil return nil
} }
msg = formatLogTime(when) + msg msg = formatLogTime(when) + msg
if runtime.GOOS == "windows" || !c.Color { if c.Colorful {
c.lg.Println(colors[level](msg))
} else {
c.lg.Println(msg) c.lg.Println(msg)
return nil
} }
c.lg.Println(colors[level](msg))
return nil return nil
} }

View File

@ -98,6 +98,8 @@ type BeeLogger struct {
loggerFuncCallDepth int loggerFuncCallDepth int
asynchronous bool asynchronous bool
msgChan chan *logMsg msgChan chan *logMsg
signalChan chan string
wg sync.WaitGroup
outputs []*nameLogger outputs []*nameLogger
} }
@ -109,7 +111,7 @@ type nameLogger struct {
type logMsg struct { type logMsg struct {
level int level int
msg string msg string
when time.Time when time.Time
} }
var logMsgPool *sync.Pool var logMsgPool *sync.Pool
@ -122,6 +124,7 @@ func NewLogger(channelLen int64) *BeeLogger {
bl.level = LevelDebug bl.level = LevelDebug
bl.loggerFuncCallDepth = 2 bl.loggerFuncCallDepth = 2
bl.msgChan = make(chan *logMsg, channelLen) bl.msgChan = make(chan *logMsg, channelLen)
bl.signalChan = make(chan string, 1)
return bl return bl
} }
@ -133,6 +136,7 @@ func (bl *BeeLogger) Async() *BeeLogger {
return &logMsg{} return &logMsg{}
}, },
} }
bl.wg.Add(1)
go bl.startLogger() go bl.startLogger()
return bl return bl
} }
@ -232,11 +236,26 @@ func (bl *BeeLogger) EnableFuncCallDepth(b bool) {
// start logger chan reading. // start logger chan reading.
// when chan is not empty, write logs. // when chan is not empty, write logs.
func (bl *BeeLogger) startLogger() { func (bl *BeeLogger) startLogger() {
gameOver := false
for { for {
select { select {
case bm := <-bl.msgChan: case bm := <-bl.msgChan:
bl.writeToLoggers(bm.when, bm.msg, bm.level) bl.writeToLoggers(bm.when, bm.msg, bm.level)
logMsgPool.Put(bm) logMsgPool.Put(bm)
case sg := <-bl.signalChan:
// Now should only send "flush" or "close" to bl.signalChan
bl.flush()
if sg == "close" {
for _, l := range bl.outputs {
l.Destroy()
}
bl.outputs = nil
gameOver = true
}
bl.wg.Done()
}
if gameOver {
break
} }
} }
} }
@ -345,13 +364,41 @@ func (bl *BeeLogger) Trace(format string, v ...interface{}) {
// Flush flush all chan data. // Flush flush all chan data.
func (bl *BeeLogger) Flush() { func (bl *BeeLogger) Flush() {
for _, l := range bl.outputs { if bl.asynchronous {
l.Flush() bl.signalChan <- "flush"
bl.wg.Wait()
bl.wg.Add(1)
return
} }
bl.flush()
} }
// Close close logger, flush all chan data and destroy all adapters in BeeLogger. // Close close logger, flush all chan data and destroy all adapters in BeeLogger.
func (bl *BeeLogger) Close() { func (bl *BeeLogger) Close() {
if bl.asynchronous {
bl.signalChan <- "close"
bl.wg.Wait()
} else {
bl.flush()
for _, l := range bl.outputs {
l.Destroy()
}
bl.outputs = nil
}
close(bl.msgChan)
close(bl.signalChan)
}
// Reset close all outputs, and set bl.outputs to nil
func (bl *BeeLogger) Reset() {
bl.Flush()
for _, l := range bl.outputs {
l.Destroy()
}
bl.outputs = nil
}
func (bl *BeeLogger) flush() {
for { for {
if len(bl.msgChan) > 0 { if len(bl.msgChan) > 0 {
bm := <-bl.msgChan bm := <-bl.msgChan
@ -363,9 +410,7 @@ func (bl *BeeLogger) Close() {
} }
for _, l := range bl.outputs { for _, l := range bl.outputs {
l.Flush() l.Flush()
l.Destroy()
} }
bl.outputs = nil
} }
func formatLogTime(when time.Time) string { func formatLogTime(when time.Time) string {

View File

@ -23,6 +23,7 @@ import (
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
"sync"
"github.com/astaxie/beego/utils" "github.com/astaxie/beego/utils"
) )
@ -30,7 +31,8 @@ import (
var ( var (
beegoTplFuncMap = make(template.FuncMap) beegoTplFuncMap = make(template.FuncMap)
// BeeTemplates caching map and supported template file extensions. // BeeTemplates caching map and supported template file extensions.
BeeTemplates = make(map[string]*template.Template) BeeTemplates = make(map[string]*template.Template)
templatesLock sync.Mutex
// BeeTemplateExt stores the template extension which will build // BeeTemplateExt stores the template extension which will build
BeeTemplateExt = []string{"tpl", "html"} BeeTemplateExt = []string{"tpl", "html"}
) )
@ -66,17 +68,21 @@ func init() {
} }
// AddFuncMap let user to register a func in the template. // AddFuncMap let user to register a func in the template.
func AddFuncMap(key string, funname interface{}) error { func AddFuncMap(key string, fn interface{}) error {
beegoTplFuncMap[key] = funname beegoTplFuncMap[key] = fn
return nil return nil
} }
type templatefile struct { type templateFile struct {
root string root string
files map[string][]string files map[string][]string
} }
func (tf *templatefile) visit(paths string, f os.FileInfo, err error) error { // visit will make the paths into two part,the first is subDir (without tf.root),the second is full path(without tf.root).
// if tf.root="views" and
// paths is "views/errors/404.html",the subDir will be "errors",the file will be "errors/404.html"
// paths is "views/admin/errors/404.html",the subDir will be "admin/errors",the file will be "admin/errors/404.html"
func (tf *templateFile) visit(paths string, f os.FileInfo, err error) error {
if f == nil { if f == nil {
return err return err
} }
@ -88,18 +94,10 @@ func (tf *templatefile) visit(paths string, f os.FileInfo, err error) error {
} }
replace := strings.NewReplacer("\\", "/") replace := strings.NewReplacer("\\", "/")
a := []byte(paths) file := strings.TrimLeft(replace.Replace(paths[len(tf.root):]), "/")
a = a[len([]byte(tf.root)):] subDir := filepath.Dir(file)
file := strings.TrimLeft(replace.Replace(string(a)), "/")
subdir := filepath.Dir(file)
if _, ok := tf.files[subdir]; ok {
tf.files[subdir] = append(tf.files[subdir], file)
} else {
m := make([]string, 1)
m[0] = file
tf.files[subdir] = m
}
tf.files[subDir] = append(tf.files[subDir], file)
return nil return nil
} }
@ -132,7 +130,7 @@ func BuildTemplate(dir string, files ...string) error {
} }
return errors.New("dir open err") return errors.New("dir open err")
} }
self := &templatefile{ self := &templateFile{
root: dir, root: dir,
files: make(map[string][]string), files: make(map[string][]string),
} }
@ -146,12 +144,14 @@ func BuildTemplate(dir string, files ...string) error {
for _, v := range self.files { for _, v := range self.files {
for _, file := range v { for _, file := range v {
if len(files) == 0 || utils.InSlice(file, files) { if len(files) == 0 || utils.InSlice(file, files) {
templatesLock.Lock()
t, err := getTemplate(self.root, file, v...) t, err := getTemplate(self.root, file, v...)
if err != nil { if err != nil {
Trace("parse template err:", file, err) Trace("parse template err:", file, err)
} else { } else {
BeeTemplates[file] = t BeeTemplates[file] = t
} }
templatesLock.Unlock()
} }
} }
} }
@ -159,16 +159,16 @@ func BuildTemplate(dir string, files ...string) error {
} }
func getTplDeep(root, file, parent string, t *template.Template) (*template.Template, [][]string, error) { func getTplDeep(root, file, parent string, t *template.Template) (*template.Template, [][]string, error) {
var fileabspath string var fileAbsPath string
if filepath.HasPrefix(file, "../") { if filepath.HasPrefix(file, "../") {
fileabspath = filepath.Join(root, filepath.Dir(parent), file) fileAbsPath = filepath.Join(root, filepath.Dir(parent), file)
} else { } else {
fileabspath = filepath.Join(root, file) fileAbsPath = filepath.Join(root, file)
} }
if e := utils.FileExists(fileabspath); !e { if e := utils.FileExists(fileAbsPath); !e {
panic("can't find template file:" + file) panic("can't find template file:" + file)
} }
data, err := ioutil.ReadFile(fileabspath) data, err := ioutil.ReadFile(fileAbsPath)
if err != nil { if err != nil {
return nil, [][]string{}, err return nil, [][]string{}, err
} }
@ -177,11 +177,11 @@ func getTplDeep(root, file, parent string, t *template.Template) (*template.Temp
return nil, [][]string{}, err return nil, [][]string{}, err
} }
reg := regexp.MustCompile(BConfig.WebConfig.TemplateLeft + "[ ]*template[ ]+\"([^\"]+)\"") reg := regexp.MustCompile(BConfig.WebConfig.TemplateLeft + "[ ]*template[ ]+\"([^\"]+)\"")
allsub := reg.FindAllStringSubmatch(string(data), -1) allSub := reg.FindAllStringSubmatch(string(data), -1)
for _, m := range allsub { for _, m := range allSub {
if len(m) == 2 { if len(m) == 2 {
tlook := t.Lookup(m[1]) tl := t.Lookup(m[1])
if tlook != nil { if tl != nil {
continue continue
} }
if !HasTemplateExt(m[1]) { if !HasTemplateExt(m[1]) {
@ -193,17 +193,17 @@ func getTplDeep(root, file, parent string, t *template.Template) (*template.Temp
} }
} }
} }
return t, allsub, nil return t, allSub, nil
} }
func getTemplate(root, file string, others ...string) (t *template.Template, err error) { func getTemplate(root, file string, others ...string) (t *template.Template, err error) {
t = template.New(file).Delims(BConfig.WebConfig.TemplateLeft, BConfig.WebConfig.TemplateRight).Funcs(beegoTplFuncMap) t = template.New(file).Delims(BConfig.WebConfig.TemplateLeft, BConfig.WebConfig.TemplateRight).Funcs(beegoTplFuncMap)
var submods [][]string var subMods [][]string
t, submods, err = getTplDeep(root, file, "", t) t, subMods, err = getTplDeep(root, file, "", t)
if err != nil { if err != nil {
return nil, err return nil, err
} }
t, err = _getTemplate(t, root, submods, others...) t, err = _getTemplate(t, root, subMods, others...)
if err != nil { if err != nil {
return nil, err return nil, err
@ -211,44 +211,44 @@ func getTemplate(root, file string, others ...string) (t *template.Template, err
return return
} }
func _getTemplate(t0 *template.Template, root string, submods [][]string, others ...string) (t *template.Template, err error) { func _getTemplate(t0 *template.Template, root string, subMods [][]string, others ...string) (t *template.Template, err error) {
t = t0 t = t0
for _, m := range submods { for _, m := range subMods {
if len(m) == 2 { if len(m) == 2 {
templ := t.Lookup(m[1]) tpl := t.Lookup(m[1])
if templ != nil { if tpl != nil {
continue continue
} }
//first check filename //first check filename
for _, otherfile := range others { for _, otherFile := range others {
if otherfile == m[1] { if otherFile == m[1] {
var submods1 [][]string var subMods1 [][]string
t, submods1, err = getTplDeep(root, otherfile, "", t) t, subMods1, err = getTplDeep(root, otherFile, "", t)
if err != nil { if err != nil {
Trace("template parse file err:", err) Trace("template parse file err:", err)
} else if submods1 != nil && len(submods1) > 0 { } else if subMods1 != nil && len(subMods1) > 0 {
t, err = _getTemplate(t, root, submods1, others...) t, err = _getTemplate(t, root, subMods1, others...)
} }
break break
} }
} }
//second check define //second check define
for _, otherfile := range others { for _, otherFile := range others {
fileabspath := filepath.Join(root, otherfile) fileAbsPath := filepath.Join(root, otherFile)
data, err := ioutil.ReadFile(fileabspath) data, err := ioutil.ReadFile(fileAbsPath)
if err != nil { if err != nil {
continue continue
} }
reg := regexp.MustCompile(BConfig.WebConfig.TemplateLeft + "[ ]*define[ ]+\"([^\"]+)\"") reg := regexp.MustCompile(BConfig.WebConfig.TemplateLeft + "[ ]*define[ ]+\"([^\"]+)\"")
allsub := reg.FindAllStringSubmatch(string(data), -1) allSub := reg.FindAllStringSubmatch(string(data), -1)
for _, sub := range allsub { for _, sub := range allSub {
if len(sub) == 2 && sub[1] == m[1] { if len(sub) == 2 && sub[1] == m[1] {
var submods1 [][]string var subMods1 [][]string
t, submods1, err = getTplDeep(root, otherfile, "", t) t, subMods1, err = getTplDeep(root, otherFile, "", t)
if err != nil { if err != nil {
Trace("template parse file err:", err) Trace("template parse file err:", err)
} else if submods1 != nil && len(submods1) > 0 { } else if subMods1 != nil && len(subMods1) > 0 {
t, err = _getTemplate(t, root, submods1, others...) t, err = _getTemplate(t, root, subMods1, others...)
} }
break break
} }

View File

@ -265,15 +265,14 @@ func (t *Tree) addseg(segments []string, route interface{}, wildcards []string,
} }
t.wildcard.addseg(segments[1:], route, append(wildcards, params...), reg+regexpStr) t.wildcard.addseg(segments[1:], route, append(wildcards, params...), reg+regexpStr)
} else { } else {
var ok bool
var subTree *Tree var subTree *Tree
for _, subTree = range t.fixrouters { for _, sub := range t.fixrouters {
if t.prefix == seg { if sub.prefix == seg {
ok = true subTree = sub
break break
} }
} }
if !ok { if subTree == nil {
subTree = NewTree() subTree = NewTree()
subTree.prefix = seg subTree.prefix = seg
t.fixrouters = append(t.fixrouters, subTree) t.fixrouters = append(t.fixrouters, subTree)

View File

@ -221,6 +221,18 @@ func TestAddTree4(t *testing.T) {
} }
} }
// Test for issue #1595
func TestAddTree5(t *testing.T) {
tr := NewTree()
tr.AddRouter("/v1/shop/:id", "shopdetail")
tr.AddRouter("/v1/shop/", "shophome")
ctx := context.NewContext()
obj := tr.Match("/v1/shop/", ctx)
if obj == nil || obj.(string) != "shophome" {
t.Fatal("url /v1/shop/ need match router /v1/shop/ ")
}
}
func TestSplitPath(t *testing.T) { func TestSplitPath(t *testing.T) {
a := splitPath("") a := splitPath("")
if len(a) != 0 { if len(a) != 0 {