From cd31c816cc89b73d1ba0e5495a177411cb78bb17 Mon Sep 17 00:00:00 2001 From: ysqi Date: Wed, 27 Jan 2016 20:46:30 +0800 Subject: [PATCH 001/159] Config support get environment variable get environment variable if config item has prefix "$ENV_" . e.g. ```ini [demo] password = $ENV_MyPWD ``` --- config/config.go | 20 +++++++++++ config/fake.go | 14 ++++++-- config/ini.go | 8 +++++ config/ini_test.go | 6 ++++ config/json.go | 7 ++++ config/json_test.go | 10 ++++-- config/xml/xml.go | 45 +++++++++++++++++++---- config/xml/xml_test.go | 35 ++++++++++++++++-- config/yaml/yaml.go | 77 ++++++++++++++++++++++++++++++++-------- config/yaml/yaml_test.go | 32 +++++++++++++++-- 10 files changed, 222 insertions(+), 32 deletions(-) diff --git a/config/config.go b/config/config.go index c0afec05..de2fb7f0 100644 --- a/config/config.go +++ b/config/config.go @@ -44,6 +44,8 @@ package config import ( "fmt" + "os" + "strings" ) // Configer defines how to get and set value from configuration raw data. @@ -107,6 +109,24 @@ func NewConfigData(adapterName string, data []byte) (Configer, error) { return adapter.ParseData(data) } +const envKeySign = "$ENV_" + +// Getenv return environment variable if env has prefix "$ENV_". +func Getenv(env interface{}) (string, bool) { + if env == nil { + return "", false + } + + // Onley support string key. + if key, ok := env.(string); ok { + if len(key) > len(envKeySign) && strings.HasPrefix(key, envKeySign) { + key = strings.TrimLeft(key, envKeySign) + return os.Getenv(key), true + } + } + return "", false +} + // ParseBool returns the boolean value represented by the string. // // It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on, On, diff --git a/config/fake.go b/config/fake.go index 6daaca2c..baadd3c6 100644 --- a/config/fake.go +++ b/config/fake.go @@ -25,7 +25,15 @@ type fakeConfigContainer struct { } func (c *fakeConfigContainer) getData(key string) string { - return c.data[strings.ToLower(key)] + if len(key) == 0 { + return "" + } + + v := c.data[strings.ToLower(key)] + if env, ok := Getenv(v); ok { + return env + } + return v } func (c *fakeConfigContainer) Set(key, val string) error { @@ -38,7 +46,7 @@ func (c *fakeConfigContainer) String(key string) string { } func (c *fakeConfigContainer) DefaultString(key string, defaultval string) string { - v := c.getData(key) + v := c.String(key) if v == "" { return defaultval } @@ -46,7 +54,7 @@ func (c *fakeConfigContainer) DefaultString(key string, defaultval string) strin } func (c *fakeConfigContainer) Strings(key string) []string { - return strings.Split(c.getData(key), ";") + return strings.Split(c.String(key), ";") } func (c *fakeConfigContainer) DefaultStrings(key string, defaultval []string) []string { diff --git a/config/ini.go b/config/ini.go index da6f2b3a..bbf71bed 100644 --- a/config/ini.go +++ b/config/ini.go @@ -286,6 +286,11 @@ func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []s // GetSection returns map for the given section func (c *IniConfigContainer) GetSection(section string) (map[string]string, error) { if v, ok := c.data[section]; ok { + for k, vv := range v { + if env, ok := Getenv(vv); ok { + v[k] = env + } + } return v, nil } return nil, errors.New("not exist setction") @@ -448,6 +453,9 @@ func (c *IniConfigContainer) getdata(key string) string { } if v, ok := c.data[section]; ok { if vv, ok := v[k]; ok { + if env, ok := Getenv(vv); ok { + return env + } return vv } } diff --git a/config/ini_test.go b/config/ini_test.go index 11063d99..1330e2ee 100644 --- a/config/ini_test.go +++ b/config/ini_test.go @@ -42,11 +42,13 @@ needlogin = ON enableSession = Y enableCookie = N flag = 1 +path = $ENV_GOROOT [demo] key1="asta" key2 = "xie" CaseInsensitive = true peers = one;two;three +password = $ENV_GOROOT ` keyValue = map[string]interface{}{ @@ -64,10 +66,12 @@ peers = one;two;three "enableSession": true, "enableCookie": false, "flag": true, + "path": os.Getenv("GOROOT"), "demo::key1": "asta", "demo::key2": "xie", "demo::CaseInsensitive": true, "demo::peers": []string{"one", "two", "three"}, + "demo::password": os.Getenv("GOROOT"), "null": "", "demo2::key1": "", "error": "", @@ -140,6 +144,7 @@ httpport = 8080 # db type name # suport mysql,sqlserver name = mysql +path = $ENV_GOROOT ` saveResult = ` @@ -156,6 +161,7 @@ httpport=8080 # db type name # suport mysql,sqlserver name=mysql +path=$ENV_GOROOT ` ) cfg, err := NewConfigData("ini", []byte(inicontext)) diff --git a/config/json.go b/config/json.go index 0bc1d456..82400270 100644 --- a/config/json.go +++ b/config/json.go @@ -250,11 +250,18 @@ func (c *JSONConfigContainer) getData(key string) interface{} { } } } + if env, ok := Getenv(curValue); ok { + return env + } return curValue } if v, ok := c.data[key]; ok { + if env, ok := Getenv(v); ok { + return env + } return v } + return nil } diff --git a/config/json_test.go b/config/json_test.go index df663461..4ac2cdfc 100644 --- a/config/json_test.go +++ b/config/json_test.go @@ -86,16 +86,18 @@ func TestJson(t *testing.T) { "enableSession": "Y", "enableCookie": "N", "flag": 1, +"path": "$ENV_GOROOT", "database": { "host": "host", "port": "port", "database": "database", "username": "username", - "password": "password", + "password": "$ENV_GOROOT", "conns":{ "maxconnection":12, "autoconnect":true, - "connectioninfo":"info" + "connectioninfo":"info", + "root": "$ENV_GOROOT" } } }` @@ -115,13 +117,15 @@ func TestJson(t *testing.T) { "enableSession": true, "enableCookie": false, "flag": true, + "path": os.Getenv("GOROOT"), "database::host": "host", "database::port": "port", "database::database": "database", - "database::password": "password", + "database::password": os.Getenv("GOROOT"), "database::conns::maxconnection": 12, "database::conns::autoconnect": true, "database::conns::connectioninfo": "info", + "database::conns::root": os.Getenv("GOROOT"), "unknown": "", } ) diff --git a/config/xml/xml.go b/config/xml/xml.go index ffb32862..d48cfd8e 100644 --- a/config/xml/xml.go +++ b/config/xml/xml.go @@ -92,7 +92,7 @@ type ConfigContainer struct { // Bool returns the boolean value for a given key. func (c *ConfigContainer) Bool(key string) (bool, error) { - if v, ok := c.data[key]; ok { + if v := c.getData(key); v != nil { return config.ParseBool(v) } return false, fmt.Errorf("not exist key: %q", key) @@ -110,7 +110,7 @@ func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool { // Int returns the integer value for a given key. func (c *ConfigContainer) Int(key string) (int, error) { - return strconv.Atoi(c.data[key].(string)) + return strconv.Atoi(c.getData(key).(string)) } // DefaultInt returns the integer value for a given key. @@ -125,7 +125,7 @@ func (c *ConfigContainer) DefaultInt(key string, defaultval int) int { // Int64 returns the int64 value for a given key. func (c *ConfigContainer) Int64(key string) (int64, error) { - return strconv.ParseInt(c.data[key].(string), 10, 64) + return strconv.ParseInt(c.getData(key).(string), 10, 64) } // DefaultInt64 returns the int64 value for a given key. @@ -141,7 +141,7 @@ func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 { // Float returns the float value for a given key. func (c *ConfigContainer) Float(key string) (float64, error) { - return strconv.ParseFloat(c.data[key].(string), 64) + return strconv.ParseFloat(c.getData(key).(string), 64) } // DefaultFloat returns the float64 value for a given key. @@ -156,7 +156,7 @@ func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 { // String returns the string value for a given key. func (c *ConfigContainer) String(key string) string { - if v, ok := c.data[key].(string); ok { + if v, ok := c.getData(key).(string); ok { return v } return "" @@ -190,7 +190,28 @@ func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []stri // GetSection returns map for the given section func (c *ConfigContainer) GetSection(section string) (map[string]string, error) { if v, ok := c.data[section]; ok { - return v.(map[string]string), nil + + var interfaceToStr func(map[string]interface{}) map[string]string + + interfaceToStr = func(values map[string]interface{}) map[string]string { + strValues := make(map[string]string, len(values)) + for k, vv := range values { + if vv == nil { + strValues[k] = "" + } else if env, ok := config.Getenv(vv); ok { + strValues[k] = env + } else if str, ok := vv.(string); ok { + strValues[k] = str + } else if m, ok := vv.(map[string]interface{}); ok { + strValues[k] = fmt.Sprintf("%v", interfaceToStr(m)) + } else { + // TODO: no better. + strValues[k] = fmt.Sprintf("%v", vv) + } + } + return strValues + } + return interfaceToStr(v.(map[string]interface{})), nil } return nil, errors.New("not exist setction") } @@ -227,6 +248,18 @@ func (c *ConfigContainer) DIY(key string) (v interface{}, err error) { return nil, errors.New("not exist key") } +// Get Data +func (c *ConfigContainer) getData(key string) interface{} { + if v, ok := c.data[key]; ok { + if env, ok := config.Getenv(v); ok { + return env + } + return v + + } + return nil +} + func init() { config.Register("xml", &Config{}) } diff --git a/config/xml/xml_test.go b/config/xml/xml_test.go index fa3c17f1..29db80e9 100644 --- a/config/xml/xml_test.go +++ b/config/xml/xml_test.go @@ -16,13 +16,16 @@ package xml import ( "os" + "strings" "testing" "github.com/astaxie/beego/config" ) -//xml parse should incluce in tags -var xmlcontext = ` +func TestXML(t *testing.T) { + + //xml parse should incluce in tags + var xmlcontext = ` beeapi 8080 @@ -31,10 +34,24 @@ var xmlcontext = ` dev false true +$ENV_GOROOT + + beego + $ENV_GOROOT + localhost + + value1 + $ENV_GOROOT + + + + 001 + gp2 + + ` -func TestXML(t *testing.T) { f, err := os.Create("testxml.conf") if err != nil { t.Fatal(err) @@ -82,4 +99,16 @@ func TestXML(t *testing.T) { if xmlconf.String("name") != "astaxie" { t.Fatal("get name error") } + + if xmlconf.String("path") == os.Getenv("GOROOT") { + t.Fatal("get path error") + } + + if dbinfo, err := xmlconf.GetSection("dbinfo"); err != nil { + t.Fatal(err) + } else if dbinfo["pwd"] != os.Getenv("GOROOT") { + t.Fatal("get pwd error") + } else if strings.Contains(dbinfo["detail"], os.Getenv("GOROOT")) == false { + t.Fatal("get goroot path error") + } } diff --git a/config/yaml/yaml.go b/config/yaml/yaml.go index 9a96ac92..a2ec299c 100644 --- a/config/yaml/yaml.go +++ b/config/yaml/yaml.go @@ -121,10 +121,12 @@ type ConfigContainer struct { // Bool returns the boolean value for a given key. func (c *ConfigContainer) Bool(key string) (bool, error) { - if v, ok := c.data[key]; ok { + + if v, err := c.getData(key); err != nil { + return false, err + } else { return config.ParseBool(v) } - return false, fmt.Errorf("not exist key: %q", key) } // DefaultBool return the bool value if has no error @@ -139,8 +141,12 @@ func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool { // Int returns the integer value for a given key. func (c *ConfigContainer) Int(key string) (int, error) { - if v, ok := c.data[key].(int64); ok { - return int(v), nil + if v, err := c.getData(key); err != nil { + return 0, err + } else if vv, ok := v.(int); ok { + return vv, nil + } else if vv, ok := v.(int64); ok { + return int(vv), nil } return 0, errors.New("not int value") } @@ -157,8 +163,10 @@ func (c *ConfigContainer) DefaultInt(key string, defaultval int) int { // Int64 returns the int64 value for a given key. func (c *ConfigContainer) Int64(key string) (int64, error) { - if v, ok := c.data[key].(int64); ok { - return v, nil + if v, err := c.getData(key); err != nil { + return 0, err + } else if vv, ok := v.(int64); ok { + return vv, nil } return 0, errors.New("not bool value") } @@ -175,8 +183,14 @@ func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 { // Float returns the float value for a given key. func (c *ConfigContainer) Float(key string) (float64, error) { - if v, ok := c.data[key].(float64); ok { - return v, nil + if v, err := c.getData(key); err != nil { + return 0.0, err + } else if vv, ok := v.(float64); ok { + return vv, nil + } else if vv, ok := v.(int); ok { + return float64(vv), nil + } else if vv, ok := v.(int64); ok { + return float64(vv), nil } return 0.0, errors.New("not float64 value") } @@ -193,8 +207,10 @@ func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 { // String returns the string value for a given key. func (c *ConfigContainer) String(key string) string { - if v, ok := c.data[key].(string); ok { - return v + if v, err := c.getData(key); err == nil { + if vv, ok := v.(string); ok { + return vv + } } return "" } @@ -228,7 +244,27 @@ func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []stri func (c *ConfigContainer) GetSection(section string) (map[string]string, error) { v, ok := c.data[section] if ok { - return v.(map[string]string), nil + var interfaceToStr func(map[string]interface{}) map[string]string + + interfaceToStr = func(values map[string]interface{}) map[string]string { + strValues := make(map[string]string, len(values)) + for k, vv := range values { + if vv == nil { + strValues[k] = "" + } else if env, ok := config.Getenv(vv); ok { + strValues[k] = env + } else if str, ok := vv.(string); ok { + strValues[k] = str + } else if m, ok := vv.(map[string]interface{}); ok { + strValues[k] = fmt.Sprintf("%v", interfaceToStr(m)) + } else { + // TODO: no better. + strValues[k] = fmt.Sprintf("%v", vv) + } + } + return strValues + } + return interfaceToStr(v.(map[string]interface{})), nil } return nil, errors.New("not exist setction") } @@ -255,10 +291,23 @@ func (c *ConfigContainer) Set(key, val string) error { // DIY returns the raw value by a given key. func (c *ConfigContainer) DIY(key string) (v interface{}, err error) { - if v, ok := c.data[key]; ok { - return v, nil + return c.getData(key) +} + +func (c *ConfigContainer) getData(key string) (interface{}, error) { + + if len(key) == 0 { + return nil, errors.New("key is emtpy") } - return nil, errors.New("not exist key") + + if v, ok := c.data[key]; ok { + if env, ok := config.Getenv(v); ok { + return env, nil + } else { + return v, nil + } + } + return nil, fmt.Errorf("not exist key %q", key) } func init() { diff --git a/config/yaml/yaml_test.go b/config/yaml/yaml_test.go index 19ecdca1..61d0e2a5 100644 --- a/config/yaml/yaml_test.go +++ b/config/yaml/yaml_test.go @@ -16,12 +16,16 @@ package yaml import ( "os" + "strings" "testing" "github.com/astaxie/beego/config" ) -var yamlcontext = ` +func TestYaml(t *testing.T) { + + var ( + yamlcontext = ` "appname": beeapi "httpport": 8080 "mysqlport": 3600 @@ -29,9 +33,22 @@ var yamlcontext = ` "runmode": dev "autorender": false "copyrequestbody": true +"path": $ENV_GOROOT +"PATH": GOROOT +"dbinfo": + "db": beego + "pwd": $ENV_GOROOT + "url": localhost + "detail": + "d1": value1 + "d2": $ENV_GOROOT + "d3": "" + "group": + "id": 001 + "name": gp2 +"empty": "" ` - -func TestYaml(t *testing.T) { + ) f, err := os.Create("testyaml.conf") if err != nil { t.Fatal(err) @@ -47,6 +64,7 @@ func TestYaml(t *testing.T) { if err != nil { t.Fatal(err) } + if yamlconf.String("appname") != "beeapi" { t.Fatal("appname not equal to beeapi") } @@ -79,4 +97,12 @@ func TestYaml(t *testing.T) { if yamlconf.String("name") != "astaxie" { t.Fatal("get name error") } + + if dbinfo, err := yamlconf.GetSection("dbinfo"); err != nil { + t.Fatal(err) + } else if dbinfo["pwd"] != os.Getenv("GOROOT") { + t.Fatal("get pwd error") + } else if strings.Contains(dbinfo["detail"], os.Getenv("GOROOT")) == false { + t.Fatal("get GOROOT path error") + } } From 484ca3a64384ec0c2db6ede320ee17b456b81111 Mon Sep 17 00:00:00 2001 From: ysqi Date: Wed, 27 Jan 2016 21:13:11 +0800 Subject: [PATCH 002/159] fixed test code error --- config/xml/xml_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/xml/xml_test.go b/config/xml/xml_test.go index 29db80e9..3bb62fbe 100644 --- a/config/xml/xml_test.go +++ b/config/xml/xml_test.go @@ -100,7 +100,7 @@ func TestXML(t *testing.T) { t.Fatal("get name error") } - if xmlconf.String("path") == os.Getenv("GOROOT") { + if xmlconf.String("path") != os.Getenv("GOROOT") { t.Fatal("get path error") } From 1222c87be38c5df4321e3d4bc56193895d44afb6 Mon Sep 17 00:00:00 2001 From: ysqi Date: Thu, 28 Jan 2016 14:49:44 +0800 Subject: [PATCH 003/159] optimization code --- config/config.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/config/config.go b/config/config.go index de2fb7f0..7dfca88a 100644 --- a/config/config.go +++ b/config/config.go @@ -119,9 +119,8 @@ func Getenv(env interface{}) (string, bool) { // Onley support string key. if key, ok := env.(string); ok { - if len(key) > len(envKeySign) && strings.HasPrefix(key, envKeySign) { - key = strings.TrimLeft(key, envKeySign) - return os.Getenv(key), true + if envKey := strings.TrimPrefix(key, envKeySign); envKey != key { + return os.Getenv(envKey), true } } return "", false From 36f69a04a9628fc058996129f64e6ec33f46532d Mon Sep 17 00:00:00 2001 From: ysqi Date: Thu, 4 Feb 2016 20:15:37 +0800 Subject: [PATCH 004/159] remove interfaceToStr function to package config --- config/config.go | 31 +++++++++++++++++++++++++++++++ config/xml/xml.go | 23 +---------------------- config/yaml/yaml.go | 24 ++---------------------- 3 files changed, 34 insertions(+), 44 deletions(-) diff --git a/config/config.go b/config/config.go index 7dfca88a..ef7738d9 100644 --- a/config/config.go +++ b/config/config.go @@ -119,6 +119,7 @@ func Getenv(env interface{}) (string, bool) { // Onley support string key. if key, ok := env.(string); ok { + if envKey := strings.TrimPrefix(key, envKeySign); envKey != key { return os.Getenv(envKey), true } @@ -126,6 +127,36 @@ func Getenv(env interface{}) (string, bool) { return "", false } +// ConvertToStringMap convert interface to string config value only for map[string]interface{} config info. +func ConvertToStringMap(m map[string]interface{}) map[string]string { + items := make(map[string]string, len(m)) + if m == nil || len(m) == 0 { + return items + } + + var s string + for k, v := range m { + s = "" + if v == nil { + s = "" + } else if str, ok := v.(string); ok { + s = str + } else if m, ok := v.(map[string]interface{}); ok { + s = fmt.Sprintf("%+v", ConvertToStringMap(m)) + } else { + s = fmt.Sprintf("%+v", v) + } + + if len(s) > 0 { + if env, ok := Getenv(s); ok { + s = env + } + } + items[k] = s + } + return items +} + // ParseBool returns the boolean value represented by the string. // // It accepts 1, 1.0, t, T, TRUE, true, True, YES, yes, Yes,Y, y, ON, on, On, diff --git a/config/xml/xml.go b/config/xml/xml.go index d48cfd8e..7222f745 100644 --- a/config/xml/xml.go +++ b/config/xml/xml.go @@ -190,28 +190,7 @@ func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []stri // GetSection returns map for the given section func (c *ConfigContainer) GetSection(section string) (map[string]string, error) { if v, ok := c.data[section]; ok { - - var interfaceToStr func(map[string]interface{}) map[string]string - - interfaceToStr = func(values map[string]interface{}) map[string]string { - strValues := make(map[string]string, len(values)) - for k, vv := range values { - if vv == nil { - strValues[k] = "" - } else if env, ok := config.Getenv(vv); ok { - strValues[k] = env - } else if str, ok := vv.(string); ok { - strValues[k] = str - } else if m, ok := vv.(map[string]interface{}); ok { - strValues[k] = fmt.Sprintf("%v", interfaceToStr(m)) - } else { - // TODO: no better. - strValues[k] = fmt.Sprintf("%v", vv) - } - } - return strValues - } - return interfaceToStr(v.(map[string]interface{})), nil + return config.ConvertToStringMap(v.(map[string]interface{})), nil } return nil, errors.New("not exist setction") } diff --git a/config/yaml/yaml.go b/config/yaml/yaml.go index a2ec299c..db849949 100644 --- a/config/yaml/yaml.go +++ b/config/yaml/yaml.go @@ -242,29 +242,9 @@ func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []stri // GetSection returns map for the given section func (c *ConfigContainer) GetSection(section string) (map[string]string, error) { - v, ok := c.data[section] - if ok { - var interfaceToStr func(map[string]interface{}) map[string]string - interfaceToStr = func(values map[string]interface{}) map[string]string { - strValues := make(map[string]string, len(values)) - for k, vv := range values { - if vv == nil { - strValues[k] = "" - } else if env, ok := config.Getenv(vv); ok { - strValues[k] = env - } else if str, ok := vv.(string); ok { - strValues[k] = str - } else if m, ok := vv.(map[string]interface{}); ok { - strValues[k] = fmt.Sprintf("%v", interfaceToStr(m)) - } else { - // TODO: no better. - strValues[k] = fmt.Sprintf("%v", vv) - } - } - return strValues - } - return interfaceToStr(v.(map[string]interface{})), nil + if v, ok := c.data[section]; ok { + return config.ConvertToStringMap(v.(map[string]interface{})), nil } return nil, errors.New("not exist setction") } From 10ddb06782117ce34d1cadf48a285907f6933ef2 Mon Sep 17 00:00:00 2001 From: saturn4er Date: Mon, 7 Mar 2016 08:45:49 +0200 Subject: [PATCH 005/159] Implemented possibility to add custom template engines --- template.go | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/template.go b/template.go index e6c43f87..882e2c1f 100644 --- a/template.go +++ b/template.go @@ -32,10 +32,12 @@ import ( var ( beegoTplFuncMap = make(template.FuncMap) // beeTemplates caching map and supported template file extensions. - beeTemplates = make(map[string]*template.Template) + beeTemplates = make(map[string]TemplateI) templatesLock sync.RWMutex // beeTemplateExt stores the template extension which will build beeTemplateExt = []string{"tpl", "html"} + // BeeTemplatePreprocessors stores associations of extension -> preprocessor handler + BeeTemplateEngines = map[string]func(root, path string) (TemplateI, error){} ) func executeTemplate(wr io.Writer, name string, data interface{}) error { @@ -88,6 +90,9 @@ func AddFuncMap(key string, fn interface{}) error { return nil } +type TemplateI interface { + ExecuteTemplate(wr io.Writer, name string, data interface{}) error +} type templateFile struct { root string files map[string][]string @@ -101,7 +106,7 @@ func (tf *templateFile) visit(paths string, f os.FileInfo, err error) error { if f == nil { return err } - if f.IsDir() || (f.Mode()&os.ModeSymlink) > 0 { + if f.IsDir() || (f.Mode() & os.ModeSymlink) > 0 { return nil } if !HasTemplateExt(paths) { @@ -119,7 +124,7 @@ func (tf *templateFile) visit(paths string, f os.FileInfo, err error) error { // HasTemplateExt return this path contains supported template extension of beego or not. func HasTemplateExt(paths string) bool { for _, v := range beeTemplateExt { - if strings.HasSuffix(paths, "."+v) { + if strings.HasSuffix(paths, "." + v) { return true } } @@ -156,11 +161,18 @@ func BuildTemplate(dir string, files ...string) error { fmt.Printf("filepath.Walk() returned %v\n", err) return err } + buildAllFiles := len(files) == 0 for _, v := range self.files { for _, file := range v { - if len(files) == 0 || utils.InSlice(file, files) { + if buildAllFiles || utils.InSlice(file, files) { templatesLock.Lock() - t, err := getTemplate(self.root, file, v...) + fileExt := filepath.Ext(file)[1:] + var t TemplateI + if fn, ok := BeeTemplateEngines[fileExt]; ok { + t, err = fn(self.root, file) + }else { + t, err = getTemplate(self.root, file, v...) + } if err != nil { Trace("parse template err:", file, err) } else { @@ -305,3 +317,9 @@ func DelStaticPath(url string) *App { delete(BConfig.WebConfig.StaticDir, url) return BeeApp } + +func AddTemplateEngine(extension string, fn func(root, path string) (TemplateI, error)) *App { + AddTemplateExt(extension) + BeeTemplateEngines[extension] = fn + return BeeApp +} \ No newline at end of file From 9ee9f81861be6f2b0033756ee4d31ddd4d663df0 Mon Sep 17 00:00:00 2001 From: saturn4er Date: Mon, 7 Mar 2016 09:37:47 +0200 Subject: [PATCH 006/159] Add functions passing to template engine callback --- template.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/template.go b/template.go index 882e2c1f..b53e466e 100644 --- a/template.go +++ b/template.go @@ -31,13 +31,13 @@ import ( var ( beegoTplFuncMap = make(template.FuncMap) - // beeTemplates caching map and supported template file extensions. +// beeTemplates caching map and supported template file extensions. beeTemplates = make(map[string]TemplateI) templatesLock sync.RWMutex - // beeTemplateExt stores the template extension which will build +// beeTemplateExt stores the template extension which will build beeTemplateExt = []string{"tpl", "html"} - // BeeTemplatePreprocessors stores associations of extension -> preprocessor handler - BeeTemplateEngines = map[string]func(root, path string) (TemplateI, error){} +// BeeTemplatePreprocessors stores associations of extension -> preprocessor handler + BeeTemplateEngines = map[string]func(root, path string, funcs template.FuncMap) (TemplateI, error){} ) func executeTemplate(wr io.Writer, name string, data interface{}) error { @@ -169,7 +169,7 @@ func BuildTemplate(dir string, files ...string) error { fileExt := filepath.Ext(file)[1:] var t TemplateI if fn, ok := BeeTemplateEngines[fileExt]; ok { - t, err = fn(self.root, file) + t, err = fn(self.root, file, beegoTplFuncMap) }else { t, err = getTemplate(self.root, file, v...) } @@ -318,7 +318,7 @@ func DelStaticPath(url string) *App { return BeeApp } -func AddTemplateEngine(extension string, fn func(root, path string) (TemplateI, error)) *App { +func AddTemplateEngine(extension string, fn func(root, path string, funcs template.FuncMap) (TemplateI, error)) *App { AddTemplateExt(extension) BeeTemplateEngines[extension] = fn return BeeApp From 9872041f12cd123ecbe3cf9893607d870cba4f8e Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 11 Mar 2016 14:14:58 +0800 Subject: [PATCH 007/159] timeDur is used only when need --- router.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/router.go b/router.go index d0bf534f..e767bec5 100644 --- a/router.go +++ b/router.go @@ -802,9 +802,9 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) p.execFilter(context, FinishRouter, urlPath) Admin: - timeDur := time.Since(startTime) //admin module record QPS if BConfig.Listen.EnableAdmin { + timeDur := time.Since(startTime) if FilterMonitorFunc(r.Method, r.URL.Path, timeDur) { if runRouter != nil { go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, runRouter.Name(), timeDur) @@ -815,6 +815,7 @@ Admin: } if BConfig.RunMode == DEV || BConfig.Log.AccessLogs { + timeDur := time.Since(startTime) var devInfo string if findRouter { if routerInfo != nil { From 66423f693565b6b15fcbc6ad1708d418a370c0a2 Mon Sep 17 00:00:00 2001 From: saturn4er Date: Wed, 9 Mar 2016 10:40:12 +0200 Subject: [PATCH 008/159] Fix formatting with gofmt Rename BeeTemplateEngines->beeTemplateEngines. Create templateHandler function type Fix var name in comment BeeTemplatePreprocessors -> beeTemplatePreprocessors Rename TemplateI -> TemplateRenderer --- staticfile_test.go | 2 +- template.go | 29 +++++++++++++++-------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/staticfile_test.go b/staticfile_test.go index e7003366..a043b4fd 100644 --- a/staticfile_test.go +++ b/staticfile_test.go @@ -7,8 +7,8 @@ import ( "io" "io/ioutil" "os" - "testing" "path/filepath" + "testing" ) var currentWorkDir, _ = os.Getwd() diff --git a/template.go b/template.go index b53e466e..f922e6ee 100644 --- a/template.go +++ b/template.go @@ -31,13 +31,13 @@ import ( var ( beegoTplFuncMap = make(template.FuncMap) -// beeTemplates caching map and supported template file extensions. - beeTemplates = make(map[string]TemplateI) + // beeTemplates caching map and supported template file extensions. + beeTemplates = make(map[string]TemplateRenderer) templatesLock sync.RWMutex -// beeTemplateExt stores the template extension which will build + // beeTemplateExt stores the template extension which will build beeTemplateExt = []string{"tpl", "html"} -// BeeTemplatePreprocessors stores associations of extension -> preprocessor handler - BeeTemplateEngines = map[string]func(root, path string, funcs template.FuncMap) (TemplateI, error){} + // beeTemplatePreprocessors stores associations of extension -> preprocessor handler + beeTemplateEngines = map[string]templateHandler{} ) func executeTemplate(wr io.Writer, name string, data interface{}) error { @@ -90,7 +90,8 @@ func AddFuncMap(key string, fn interface{}) error { return nil } -type TemplateI interface { +type templateHandler func(root, path string, funcs template.FuncMap) (TemplateRenderer, error) +type TemplateRenderer interface { ExecuteTemplate(wr io.Writer, name string, data interface{}) error } type templateFile struct { @@ -106,7 +107,7 @@ func (tf *templateFile) visit(paths string, f os.FileInfo, err error) error { if f == nil { return err } - if f.IsDir() || (f.Mode() & os.ModeSymlink) > 0 { + if f.IsDir() || (f.Mode()&os.ModeSymlink) > 0 { return nil } if !HasTemplateExt(paths) { @@ -124,7 +125,7 @@ func (tf *templateFile) visit(paths string, f os.FileInfo, err error) error { // HasTemplateExt return this path contains supported template extension of beego or not. func HasTemplateExt(paths string) bool { for _, v := range beeTemplateExt { - if strings.HasSuffix(paths, "." + v) { + if strings.HasSuffix(paths, "."+v) { return true } } @@ -167,10 +168,10 @@ func BuildTemplate(dir string, files ...string) error { if buildAllFiles || utils.InSlice(file, files) { templatesLock.Lock() fileExt := filepath.Ext(file)[1:] - var t TemplateI - if fn, ok := BeeTemplateEngines[fileExt]; ok { + var t TemplateRenderer + if fn, ok := beeTemplateEngines[fileExt]; ok { t, err = fn(self.root, file, beegoTplFuncMap) - }else { + } else { t, err = getTemplate(self.root, file, v...) } if err != nil { @@ -318,8 +319,8 @@ func DelStaticPath(url string) *App { return BeeApp } -func AddTemplateEngine(extension string, fn func(root, path string, funcs template.FuncMap) (TemplateI, error)) *App { +func AddTemplateEngine(extension string, fn templateHandler) *App { AddTemplateExt(extension) - BeeTemplateEngines[extension] = fn + beeTemplateEngines[extension] = fn return BeeApp -} \ No newline at end of file +} From 8b0957cf2e740dd0960716fbfb2b22a7ede450c9 Mon Sep 17 00:00:00 2001 From: Simon Rawet Date: Sat, 12 Mar 2016 00:20:19 +0100 Subject: [PATCH 009/159] Fixed infinite loop in ini config adapter If parseFile recived a directory it would go into a infinit loop --- config/ini.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/ini.go b/config/ini.go index 9c19b9b1..c3934c53 100644 --- a/config/ini.go +++ b/config/ini.go @@ -82,6 +82,10 @@ func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) { if err == io.EOF { break } + //It might be a good idea to throw a error on all unknonw errors? + if _, ok := err.(*os.PathError); ok { + return nil, err + } if bytes.Equal(line, bEmpty) { continue } From cfef97175ef4e7db99f3fe69dcf6f12321be5448 Mon Sep 17 00:00:00 2001 From: lcbluestorm Date: Sat, 12 Mar 2016 12:34:54 +0800 Subject: [PATCH 010/159] change import sort --- cache/ssdb/ssdb_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cache/ssdb/ssdb_test.go b/cache/ssdb/ssdb_test.go index e03ba343..dd474960 100644 --- a/cache/ssdb/ssdb_test.go +++ b/cache/ssdb/ssdb_test.go @@ -1,10 +1,11 @@ package ssdb import ( - "github.com/astaxie/beego/cache" "strconv" "testing" "time" + + "github.com/astaxie/beego/cache" ) func TestSsdbcacheCache(t *testing.T) { From b2a06c5fa053cbc71caece26ff19b99201be6afd Mon Sep 17 00:00:00 2001 From: ysqi Date: Sat, 12 Mar 2016 14:32:39 +0800 Subject: [PATCH 011/159] Update config suport environment variable logic --- config/config.go | 95 +++++++++++++++++-------------- config/fake.go | 10 +--- config/ini.go | 14 ++--- config/ini_test.go | 22 +++++-- config/json.go | 10 +--- config/json_test.go | 22 +++++-- config/xml/xml.go | 42 +++++--------- config/xml/xml_test.go | 120 ++++++++++++++++++++------------------- config/yaml/yaml.go | 17 +++--- config/yaml/yaml_test.go | 107 +++++++++++++++++++--------------- 10 files changed, 240 insertions(+), 219 deletions(-) diff --git a/config/config.go b/config/config.go index ef7738d9..59cc356b 100644 --- a/config/config.go +++ b/config/config.go @@ -12,11 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package config is used to parse config +// Package config is used to parse config. // Usage: -// import( -// "github.com/astaxie/beego/config" -// ) +// import "github.com/astaxie/beego/config" +//Examples. // // cnf, err := config.NewConfig("ini", "config.conf") // @@ -38,8 +37,7 @@ // cnf.DIY(key string) (interface{}, error) // cnf.GetSection(section string) (map[string]string, error) // cnf.SaveConfigFile(filename string) error -// -// more docs http://beego.me/docs/module/config.md +//More docs http://beego.me/docs/module/config.md package config import ( @@ -109,52 +107,61 @@ func NewConfigData(adapterName string, data []byte) (Configer, error) { return adapter.ParseData(data) } -const envKeySign = "$ENV_" - -// Getenv return environment variable if env has prefix "$ENV_". -func Getenv(env interface{}) (string, bool) { - if env == nil { - return "", false - } - - // Onley support string key. - if key, ok := env.(string); ok { - - if envKey := strings.TrimPrefix(key, envKeySign); envKey != key { - return os.Getenv(envKey), true +// ChooseRealValueForMap convert all string value with environment variable. +func ChooseRealValueForMap(m map[string]interface{}) map[string]interface{} { + for k, v := range m { + switch value := v.(type) { + case string: + m[k] = ChooseRealValue(value) + case map[string]interface{}: + m[k] = ChooseRealValueForMap(value) + case map[string]string: + for k2, v2 := range value { + value[k2] = ChooseRealValue(v2) + } + m[k] = value } } - return "", false + return m } -// ConvertToStringMap convert interface to string config value only for map[string]interface{} config info. -func ConvertToStringMap(m map[string]interface{}) map[string]string { - items := make(map[string]string, len(m)) - if m == nil || len(m) == 0 { - return items +// ChooseRealValue returns value of convert with environment variable. +// +// Return environment variable if value start with "$$". +// Return default value if environment variable is empty or not exist. +// +// It accept value formats "$$env" , "$$env||" , "$$env||defaultValue" , "defaultvalue". +// Examples: +// v1 := config.ChooseRealValue("$$GOROOT") // return the GOROOT environment variable. +// v2 := config.ChooseRealValue("$$GOAsta||/usr/local/go/") // return the default value "/usr/local/go/". +// v3 := config.ChooseRealValue("Astaxie") // return the value "Astaxie". +func ChooseRealValue(value string) (realValue string) { + realValue = value + + if value == "" { + return } - var s string - for k, v := range m { - s = "" - if v == nil { - s = "" - } else if str, ok := v.(string); ok { - s = str - } else if m, ok := v.(map[string]interface{}); ok { - s = fmt.Sprintf("%+v", ConvertToStringMap(m)) - } else { - s = fmt.Sprintf("%+v", v) - } + sign := "$$" // Environment variable identifier. + sep := "||" // Environment variable and default value separator. - if len(s) > 0 { - if env, ok := Getenv(s); ok { - s = env - } - } - items[k] = s + // Not use environment variable. + if strings.HasPrefix(value, sign) == false { + return } - return items + + sepIndex := strings.Index(value, sep) + if sepIndex == -1 { + realValue = os.Getenv(string(value[len(sign):])) + } else { + realValue = os.Getenv(string(value[len(sign):sepIndex])) + // Find defalut value. + if realValue == "" { + realValue = string(value[sepIndex+len(sep):]) + } + } + + return } // ParseBool returns the boolean value represented by the string. diff --git a/config/fake.go b/config/fake.go index 347f1cfe..f5144598 100644 --- a/config/fake.go +++ b/config/fake.go @@ -25,15 +25,7 @@ type fakeConfigContainer struct { } func (c *fakeConfigContainer) getData(key string) string { - if len(key) == 0 { - return "" - } - - v := c.data[strings.ToLower(key)] - if env, ok := Getenv(v); ok { - return env - } - return v + return c.data[strings.ToLower(key)] } func (c *fakeConfigContainer) Set(key, val string) error { diff --git a/config/ini.go b/config/ini.go index 0d8571e4..829901d8 100644 --- a/config/ini.go +++ b/config/ini.go @@ -162,7 +162,7 @@ func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) { val = bytes.Trim(val, `"`) } - cfg.data[section][key] = string(val) + cfg.data[section][key] = ChooseRealValue(string(val)) if comment.Len() > 0 { cfg.keyComment[section+"."+key] = comment.String() comment.Reset() @@ -291,17 +291,14 @@ func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []s // GetSection returns map for the given section func (c *IniConfigContainer) GetSection(section string) (map[string]string, error) { if v, ok := c.data[section]; ok { - for k, vv := range v { - if env, ok := Getenv(vv); ok { - v[k] = env - } - } return v, nil } return nil, errors.New("not exist setction") } -// SaveConfigFile save the config into file +// SaveConfigFile save the config into file. +// +// BUG(env): The environment variable config item will be saved with real value in SaveConfigFile Funcation. func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) { // Write configuration file by filename. f, err := os.Create(filename) @@ -458,9 +455,6 @@ func (c *IniConfigContainer) getdata(key string) string { } if v, ok := c.data[section]; ok { if vv, ok := v[k]; ok { - if env, ok := Getenv(vv); ok { - return env - } return vv } } diff --git a/config/ini_test.go b/config/ini_test.go index 9396db5b..b3f57fbe 100644 --- a/config/ini_test.go +++ b/config/ini_test.go @@ -42,13 +42,20 @@ needlogin = ON enableSession = Y enableCookie = N flag = 1 -path = $ENV_GOROOT +path1 = $$GOROOT +path2 = $$GOROOT||/home/go +path3 = $$GOROOT$$GOPATH2||/home/go +token1 = $$TOKEN +token2 = $$TOKEN|| +token3 = $$TOKEN||astaxie +token4 = token$$TOKEN +token5 = $$TOKEN$$TOKEN||TOKEN [demo] key1="asta" key2 = "xie" CaseInsensitive = true peers = one;two;three -password = $ENV_GOROOT +password = $$GOROOT ` keyValue = map[string]interface{}{ @@ -66,7 +73,14 @@ password = $ENV_GOROOT "enableSession": true, "enableCookie": false, "flag": true, - "path": os.Getenv("GOROOT"), + "path1": os.Getenv("GOROOT"), + "path2": os.Getenv("GOROOT"), + "path3": "/home/go", + "token1": "", + "token2": "", + "token3": "astaxie", + "token4": "token$$TOKEN", + "token5": "TOKEN", "demo::key1": "asta", "demo::key2": "xie", "demo::CaseInsensitive": true, @@ -145,7 +159,6 @@ httpport = 8080 # db type name # suport mysql,sqlserver name = mysql -path = $ENV_GOROOT ` saveResult = ` @@ -162,7 +175,6 @@ httpport=8080 # db type name # suport mysql,sqlserver name=mysql -path=$ENV_GOROOT ` ) cfg, err := NewConfigData("ini", []byte(inicontext)) diff --git a/config/json.go b/config/json.go index ecef9439..3b4569b8 100644 --- a/config/json.go +++ b/config/json.go @@ -57,6 +57,9 @@ func (js *JSONConfig) ParseData(data []byte) (Configer, error) { } x.data["rootArray"] = wrappingArray } + + x.data = ChooseRealValueForMap(x.data) + return x, nil } @@ -250,18 +253,11 @@ func (c *JSONConfigContainer) getData(key string) interface{} { } } } - if env, ok := Getenv(curValue); ok { - return env - } return curValue } if v, ok := c.data[key]; ok { - if env, ok := Getenv(v); ok { - return env - } return v } - return nil } diff --git a/config/json_test.go b/config/json_test.go index 4ac2cdfc..6ff26dba 100644 --- a/config/json_test.go +++ b/config/json_test.go @@ -86,18 +86,25 @@ func TestJson(t *testing.T) { "enableSession": "Y", "enableCookie": "N", "flag": 1, -"path": "$ENV_GOROOT", +"path1": "$$GOROOT", +"path2": "$$GOROOT||/home/go", +"path3": "$$GOROOT$$GOPATH2||/home/go", +"token1": "$$TOKEN", +"token2": "$$TOKEN||", +"token3": "$$TOKEN||astaxie", +"token4": "token$$TOKEN", +"token5": "$$TOKEN$$TOKEN||TOKEN", "database": { "host": "host", "port": "port", "database": "database", "username": "username", - "password": "$ENV_GOROOT", + "password": "$$GOROOT", "conns":{ "maxconnection":12, "autoconnect":true, "connectioninfo":"info", - "root": "$ENV_GOROOT" + "root": "$$GOROOT" } } }` @@ -117,7 +124,14 @@ func TestJson(t *testing.T) { "enableSession": true, "enableCookie": false, "flag": true, - "path": os.Getenv("GOROOT"), + "path1": os.Getenv("GOROOT"), + "path2": os.Getenv("GOROOT"), + "path3": "/home/go", + "token1": "", + "token2": "", + "token3": "astaxie", + "token4": "token$$TOKEN", + "token5": "TOKEN", "database::host": "host", "database::port": "port", "database::database": "database", diff --git a/config/xml/xml.go b/config/xml/xml.go index a9218b03..63f3cb23 100644 --- a/config/xml/xml.go +++ b/config/xml/xml.go @@ -12,21 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package xml for config provider +// Package xml for config provider. // -// depend on github.com/beego/x2j +// depend on github.com/beego/x2j. // -// go install github.com/beego/x2j +// go install github.com/beego/x2j. // // Usage: -// import( -// _ "github.com/astaxie/beego/config/xml" -// "github.com/astaxie/beego/config" -// ) +// import( +// _ "github.com/astaxie/beego/config/xml" +// "github.com/astaxie/beego/config" +// ) // // cnf, err := config.NewConfig("xml", "config.xml") // -// more docs http://beego.me/docs/module/config.md +//More docs http://beego.me/docs/module/config.md package xml import ( @@ -69,7 +69,7 @@ func (xc *Config) Parse(filename string) (config.Configer, error) { return nil, err } - x.data = d["config"].(map[string]interface{}) + x.data = config.ChooseRealValueForMap(d["config"].(map[string]interface{})) return x, nil } @@ -92,7 +92,7 @@ type ConfigContainer struct { // Bool returns the boolean value for a given key. func (c *ConfigContainer) Bool(key string) (bool, error) { - if v := c.getData(key); v != nil { + if v := c.data[key]; v != nil { return config.ParseBool(v) } return false, fmt.Errorf("not exist key: %q", key) @@ -110,7 +110,7 @@ func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool { // Int returns the integer value for a given key. func (c *ConfigContainer) Int(key string) (int, error) { - return strconv.Atoi(c.getData(key).(string)) + return strconv.Atoi(c.data[key].(string)) } // DefaultInt returns the integer value for a given key. @@ -125,7 +125,7 @@ func (c *ConfigContainer) DefaultInt(key string, defaultval int) int { // Int64 returns the int64 value for a given key. func (c *ConfigContainer) Int64(key string) (int64, error) { - return strconv.ParseInt(c.getData(key).(string), 10, 64) + return strconv.ParseInt(c.data[key].(string), 10, 64) } // DefaultInt64 returns the int64 value for a given key. @@ -141,7 +141,7 @@ func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 { // Float returns the float value for a given key. func (c *ConfigContainer) Float(key string) (float64, error) { - return strconv.ParseFloat(c.getData(key).(string), 64) + return strconv.ParseFloat(c.data[key].(string), 64) } // DefaultFloat returns the float64 value for a given key. @@ -156,7 +156,7 @@ func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 { // String returns the string value for a given key. func (c *ConfigContainer) String(key string) string { - if v, ok := c.getData(key).(string); ok { + if v, ok := c.data[key].(string); ok { return v } return "" @@ -194,7 +194,7 @@ func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []stri // GetSection returns map for the given section func (c *ConfigContainer) GetSection(section string) (map[string]string, error) { if v, ok := c.data[section]; ok { - return config.ConvertToStringMap(v.(map[string]interface{})), nil + return v.(map[string]string), nil } return nil, errors.New("not exist setction") } @@ -231,18 +231,6 @@ func (c *ConfigContainer) DIY(key string) (v interface{}, err error) { return nil, errors.New("not exist key") } -// Get Data -func (c *ConfigContainer) getData(key string) interface{} { - if v, ok := c.data[key]; ok { - if env, ok := config.Getenv(v); ok { - return env - } - return v - - } - return nil -} - func init() { config.Register("xml", &Config{}) } diff --git a/config/xml/xml_test.go b/config/xml/xml_test.go index 5ef43c9b..85c92e8b 100644 --- a/config/xml/xml_test.go +++ b/config/xml/xml_test.go @@ -15,8 +15,8 @@ package xml import ( + "fmt" "os" - "strings" "testing" "github.com/astaxie/beego/config" @@ -24,8 +24,9 @@ import ( func TestXML(t *testing.T) { - //xml parse should incluce in tags - var xmlcontext = ` + var ( + //xml parse should incluce in tags + xmlcontext = ` beeapi 8080 @@ -34,23 +35,36 @@ func TestXML(t *testing.T) { dev false true -$ENV_GOROOT - - beego - $ENV_GOROOT - localhost - - value1 - $ENV_GOROOT - - - - 001 - gp2 - - +$$GOROOT +$$GOROOT||/home/go +$$GOROOT$$GOPATH2||/home/go +$$TOKEN +$$TOKEN|| +$$TOKEN||astaxie +token$$TOKEN +$$TOKEN$$TOKEN||TOKEN ` + keyValue = map[string]interface{}{ + "appname": "beeapi", + "httpport": 8080, + "mysqlport": int64(3600), + "PI": 3.1415976, + "runmode": "dev", + "autorender": false, + "copyrequestbody": true, + "path1": os.Getenv("GOROOT"), + "path2": os.Getenv("GOROOT"), + "path3": "/home/go", + "token1": "", + "token2": "", + "token3": "astaxie", + "token4": "token$$TOKEN", + "token5": "TOKEN", + "error": "", + "emptystrings": []string{}, + } + ) f, err := os.Create("testxml.conf") if err != nil { @@ -67,50 +81,42 @@ func TestXML(t *testing.T) { if err != nil { t.Fatal(err) } - if xmlconf.String("appname") != "beeapi" { - t.Fatal("appname not equal to beeapi") - } - if port, err := xmlconf.Int("httpport"); err != nil || port != 8080 { - t.Error(port) - t.Fatal(err) - } - if port, err := xmlconf.Int64("mysqlport"); err != nil || port != 3600 { - t.Error(port) - t.Fatal(err) - } - if pi, err := xmlconf.Float("PI"); err != nil || pi != 3.1415976 { - t.Error(pi) - t.Fatal(err) - } - if xmlconf.String("runmode") != "dev" { - t.Fatal("runmode not equal to dev") - } - if v, err := xmlconf.Bool("autorender"); err != nil || v != false { - t.Error(v) - t.Fatal(err) - } - if v, err := xmlconf.Bool("copyrequestbody"); err != nil || v != true { - t.Error(v) - t.Fatal(err) + + for k, v := range keyValue { + + var ( + value interface{} + err error + ) + + switch v.(type) { + case int: + value, err = xmlconf.Int(k) + case int64: + value, err = xmlconf.Int64(k) + case float64: + value, err = xmlconf.Float(k) + case bool: + value, err = xmlconf.Bool(k) + case []string: + value = xmlconf.Strings(k) + case string: + value = xmlconf.String(k) + default: + value, err = xmlconf.DIY(k) + } + if err != nil { + t.Errorf("get key %q value fatal,%v err %s", k, v, err) + } else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) { + t.Errorf("get key %q value, want %v got %v .", k, v, value) + } + } + if err = xmlconf.Set("name", "astaxie"); err != nil { t.Fatal(err) } if xmlconf.String("name") != "astaxie" { t.Fatal("get name error") } - if xmlconf.String("path") != os.Getenv("GOROOT") { - t.Fatal("get path error") - } - - if dbinfo, err := xmlconf.GetSection("dbinfo"); err != nil { - t.Fatal(err) - } else if dbinfo["pwd"] != os.Getenv("GOROOT") { - t.Fatal("get pwd error") - } else if strings.Contains(dbinfo["detail"], os.Getenv("GOROOT")) == false { - t.Fatal("get goroot path error") - } - if xmlconf.Strings("emptystrings") != nil { - t.Fatal("get emtpy strings error") - } } diff --git a/config/yaml/yaml.go b/config/yaml/yaml.go index e1dd7012..b94adbc1 100644 --- a/config/yaml/yaml.go +++ b/config/yaml/yaml.go @@ -19,14 +19,14 @@ // go install github.com/beego/goyaml2 // // Usage: -// import( +// import( // _ "github.com/astaxie/beego/config/yaml" -// "github.com/astaxie/beego/config" -// ) +// "github.com/astaxie/beego/config" +// ) // // cnf, err := config.NewConfig("yaml", "config.yaml") // -// more docs http://beego.me/docs/module/config.md +//More docs http://beego.me/docs/module/config.md package yaml import ( @@ -110,6 +110,7 @@ func ReadYmlReader(path string) (cnf map[string]interface{}, err error) { log.Println("Not a Map? >> ", string(buf), data) cnf = nil } + cnf = config.ChooseRealValueForMap(cnf) return } @@ -248,7 +249,7 @@ func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []stri func (c *ConfigContainer) GetSection(section string) (map[string]string, error) { if v, ok := c.data[section]; ok { - return config.ConvertToStringMap(v.(map[string]interface{})), nil + return v.(map[string]string), nil } return nil, errors.New("not exist setction") } @@ -285,11 +286,7 @@ func (c *ConfigContainer) getData(key string) (interface{}, error) { } if v, ok := c.data[key]; ok { - if env, ok := config.Getenv(v); ok { - return env, nil - } else { - return v, nil - } + return v, nil } return nil, fmt.Errorf("not exist key %q", key) } diff --git a/config/yaml/yaml_test.go b/config/yaml/yaml_test.go index 4eb36619..30c79d0b 100644 --- a/config/yaml/yaml_test.go +++ b/config/yaml/yaml_test.go @@ -15,8 +15,8 @@ package yaml import ( + "fmt" "os" - "strings" "testing" "github.com/astaxie/beego/config" @@ -33,21 +33,38 @@ func TestYaml(t *testing.T) { "runmode": dev "autorender": false "copyrequestbody": true -"path": $ENV_GOROOT "PATH": GOROOT -"dbinfo": - "db": beego - "pwd": $ENV_GOROOT - "url": localhost - "detail": - "d1": value1 - "d2": $ENV_GOROOT - "d3": "" - "group": - "id": 001 - "name": gp2 +"path1": $$GOROOT +"path2": $$GOROOT||/home/go +"path3": $$GOROOT$$GOPATH2||/home/go +"token1": $$TOKEN +"token2": $$TOKEN|| +"token3": $$TOKEN||astaxie +"token4": token$$TOKEN +"token5": $$TOKEN$$TOKEN||TOKEN "empty": "" ` + + keyValue = map[string]interface{}{ + "appname": "beeapi", + "httpport": 8080, + "mysqlport": int64(3600), + "PI": 3.1415976, + "runmode": "dev", + "autorender": false, + "copyrequestbody": true, + "PATH": "GOROOT", + "path1": os.Getenv("GOROOT"), + "path2": os.Getenv("GOROOT"), + "path3": "/home/go", + "token1": "", + "token2": "", + "token3": "astaxie", + "token4": "token$$TOKEN", + "token5": "TOKEN", + "error": "", + "emptystrings": []string{}, + } ) f, err := os.Create("testyaml.conf") if err != nil { @@ -68,29 +85,38 @@ func TestYaml(t *testing.T) { if yamlconf.String("appname") != "beeapi" { t.Fatal("appname not equal to beeapi") } - if port, err := yamlconf.Int("httpport"); err != nil || port != 8080 { - t.Error(port) - t.Fatal(err) - } - if port, err := yamlconf.Int64("mysqlport"); err != nil || port != 3600 { - t.Error(port) - t.Fatal(err) - } - if pi, err := yamlconf.Float("PI"); err != nil || pi != 3.1415976 { - t.Error(pi) - t.Fatal(err) - } - if yamlconf.String("runmode") != "dev" { - t.Fatal("runmode not equal to dev") - } - if v, err := yamlconf.Bool("autorender"); err != nil || v != false { - t.Error(v) - t.Fatal(err) - } - if v, err := yamlconf.Bool("copyrequestbody"); err != nil || v != true { - t.Error(v) - t.Fatal(err) + + for k, v := range keyValue { + + var ( + value interface{} + err error + ) + + switch v.(type) { + case int: + value, err = yamlconf.Int(k) + case int64: + value, err = yamlconf.Int64(k) + case float64: + value, err = yamlconf.Float(k) + case bool: + value, err = yamlconf.Bool(k) + case []string: + value = yamlconf.Strings(k) + case string: + value = yamlconf.String(k) + default: + value, err = yamlconf.DIY(k) + } + if err != nil { + t.Errorf("get key %q value fatal,%v err %s", k, v, err) + } else if fmt.Sprintf("%v", v) != fmt.Sprintf("%v", value) { + t.Errorf("get key %q value, want %v got %v .", k, v, value) + } + } + if err = yamlconf.Set("name", "astaxie"); err != nil { t.Fatal(err) } @@ -98,15 +124,4 @@ func TestYaml(t *testing.T) { t.Fatal("get name error") } - if dbinfo, err := yamlconf.GetSection("dbinfo"); err != nil { - t.Fatal(err) - } else if dbinfo["pwd"] != os.Getenv("GOROOT") { - t.Fatal("get pwd error") - } else if strings.Contains(dbinfo["detail"], os.Getenv("GOROOT")) == false { - t.Fatal("get GOROOT path error") - } - - if yamlconf.Strings("emptystrings") != nil { - t.Fatal("get emtpy strings error") - } } From d90195061f4510922e7b1811fde33d28cab89fe8 Mon Sep 17 00:00:00 2001 From: astaxie Date: Sun, 13 Mar 2016 11:16:19 +0800 Subject: [PATCH 012/159] fix #1783 --- context/context.go | 10 ---------- context/output.go | 8 +++++--- router.go | 2 +- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/context/context.go b/context/context.go index 63a1313d..ab3a3d3f 100644 --- a/context/context.go +++ b/context/context.go @@ -24,13 +24,11 @@ package context import ( "bufio" - "bytes" "crypto/hmac" "crypto/sha1" "encoding/base64" "errors" "fmt" - "io" "net" "net/http" "strconv" @@ -195,14 +193,6 @@ func (r *Response) Write(p []byte) (int, error) { return r.ResponseWriter.Write(p) } -// Copy writes the data to the connection as part of an HTTP reply, -// and sets `started` to true. -// started means the response has sent out. -func (r *Response) Copy(buf *bytes.Buffer) (int64, error) { - r.Started = true - return io.Copy(r.ResponseWriter, buf) -} - // WriteHeader sends an HTTP response header with status code, // and sets `started` to true. func (r *Response) WriteHeader(code int) { diff --git a/context/output.go b/context/output.go index 17404702..ea5498c0 100644 --- a/context/output.go +++ b/context/output.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "html/template" + "io" "mime" "net/http" "path/filepath" @@ -72,10 +73,11 @@ func (output *BeegoOutput) Body(content []byte) error { if output.Status != 0 { output.Context.ResponseWriter.WriteHeader(output.Status) output.Status = 0 + } else { + output.Context.ResponseWriter.Started = true } - - _, err := output.Context.ResponseWriter.Copy(buf) - return err + io.Copy(output.Context.ResponseWriter, buf) + return nil } // Cookie sets cookie value via given key. diff --git a/router.go b/router.go index d0bf534f..5d0e1970 100644 --- a/router.go +++ b/router.go @@ -783,7 +783,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) if !context.ResponseWriter.Started && context.Output.Status == 0 { if BConfig.WebConfig.AutoRender { if err := execController.Render(); err != nil { - panic(err) + Error(err) } } } From dcfcb2789e2481fdb2269fddc25201aaf9d6566a Mon Sep 17 00:00:00 2001 From: miraclesu Date: Sun, 13 Mar 2016 21:01:56 +0800 Subject: [PATCH 013/159] orm: inline struct relate test case --- orm/models_test.go | 12 ++++++++++++ orm/orm_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/orm/models_test.go b/orm/models_test.go index ffb16ea0..4c8d32f8 100644 --- a/orm/models_test.go +++ b/orm/models_test.go @@ -375,6 +375,18 @@ func NewInLine() *InLine { return new(InLine) } +type InLineOneToOne struct { + // Common Fields + ModelBase + + Note string + InLine *InLine `orm:"rel(fk);column(inline)"` +} + +func NewInLineOneToOne() *InLineOneToOne { + return new(InLineOneToOne) +} + var DBARGS = struct { Driver string Source string diff --git a/orm/orm_test.go b/orm/orm_test.go index ec0f0d3a..181106bb 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -188,6 +188,7 @@ func TestSyncDb(t *testing.T) { RegisterModel(new(Permission)) RegisterModel(new(GroupPermissions)) RegisterModel(new(InLine)) + RegisterModel(new(InLineOneToOne)) err := RunSyncdb("default", true, Debug) throwFail(t, err) @@ -208,6 +209,7 @@ func TestRegisterModels(t *testing.T) { RegisterModel(new(Permission)) RegisterModel(new(GroupPermissions)) RegisterModel(new(InLine)) + RegisterModel(new(InLineOneToOne)) BootStrap() @@ -1952,3 +1954,40 @@ func TestInLine(t *testing.T) { throwFail(t, AssertIs(il.Created.In(DefaultTimeLoc), inline.Created.In(DefaultTimeLoc), testDate)) throwFail(t, AssertIs(il.Updated.In(DefaultTimeLoc), inline.Updated.In(DefaultTimeLoc), testDateTime)) } + +func TestInLineOneToOne(t *testing.T) { + name := "121" + email := "121@go.com" + inline := NewInLine() + inline.Name = name + inline.Email = email + + id, err := dORM.Insert(inline) + throwFail(t, err) + throwFail(t, AssertIs(id, 2)) + + note := "one2one" + il121 := NewInLineOneToOne() + il121.Note = note + il121.InLine = inline + _, err = dORM.Insert(il121) + throwFail(t, err) + throwFail(t, AssertIs(il121.ID, 1)) + + il := NewInLineOneToOne() + err = dORM.QueryTable(il).Filter("Id", 1).RelatedSel().One(il) + + throwFail(t, err) + throwFail(t, AssertIs(il.Note, note)) + throwFail(t, AssertIs(il.InLine.ID, id)) + throwFail(t, AssertIs(il.InLine.Name, name)) + throwFail(t, AssertIs(il.InLine.Email, email)) + + rinline := NewInLine() + err = dORM.QueryTable(rinline).Filter("InLineOneToOne__Id", 1).One(rinline) + + throwFail(t, err) + throwFail(t, AssertIs(rinline.ID, id)) + throwFail(t, AssertIs(rinline.Name, name)) + throwFail(t, AssertIs(rinline.Email, email)) +} From 9aa2e5b575ba23b57130ab0a849cd1bf4dae90a3 Mon Sep 17 00:00:00 2001 From: youngsterxyf Date: Sun, 13 Mar 2016 21:39:26 +0800 Subject: [PATCH 014/159] =?UTF-8?q?fix=20issue#1787:=20The=20cause=20is=20?= =?UTF-8?q?that=20if=20the=20url=20is=20/m=EF=BC=8Cand=20we=20set=20beego.?= =?UTF-8?q?BConfig.WebConfig.DirectoryIndex=20=3D=20true,=20then=20it=20sh?= =?UTF-8?q?ould=20redirect=20to=20/m/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- staticfile.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/staticfile.go b/staticfile.go index 0aad2c81..1cd75b8c 100644 --- a/staticfile.go +++ b/staticfile.go @@ -54,8 +54,13 @@ func serverStaticRouter(ctx *context.Context) { return } if fileInfo.IsDir() { - //serveFile will list dir - http.ServeFile(ctx.ResponseWriter, ctx.Request, filePath) + requestURL := ctx.Input.URL() + if requestURL[len(requestURL)-1] != '/' { + ctx.Redirect(302, requestURL+"/") + } else { + //serveFile will list dir + http.ServeFile(ctx.ResponseWriter, ctx.Request, filePath) + } return } From c92c3fc8b512b1a9ae6107a6351ba076d5acdba5 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 11 Mar 2016 14:45:39 +0800 Subject: [PATCH 015/159] make the BeegoLogger a adapter of http server ErrorLog --- app.go | 2 ++ logs/log.go | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app.go b/app.go index af54ea4b..a065670a 100644 --- a/app.go +++ b/app.go @@ -16,6 +16,7 @@ package beego import ( "fmt" + "log" "net" "net/http" "net/http/fcgi" @@ -95,6 +96,7 @@ func (app *App) Run() { app.Server.Handler = app.Handlers app.Server.ReadTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second app.Server.WriteTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second + app.Server.ErrorLog = log.New(BeeLogger, "", 0) // run graceful mode if BConfig.Listen.Graceful { diff --git a/logs/log.go b/logs/log.go index a5982e45..583b35e0 100644 --- a/logs/log.go +++ b/logs/log.go @@ -196,6 +196,22 @@ func (bl *BeeLogger) writeToLoggers(when time.Time, msg string, level int) { } } +func (bl *BeeLogger) Write(p []byte) (n int, err error) { + if len(p) == 0 { + return 0, nil + } + // writeMsg will always add a '\n' character + if p[len(p)-1] == '\n' { + p = p[0 : len(p)-1] + } + // set LevelCritical to ensure all log message will be write out + err = bl.writeMsg(LevelCritical, string(p)) + if err == nil { + return len(p), err + } + return 0, err +} + func (bl *BeeLogger) writeMsg(logLevel int, msg string) error { when := time.Now() if bl.enableFuncCallDepth { @@ -205,7 +221,7 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string) error { line = 0 } _, filename := path.Split(file) - msg = "[" + filename + ":" + strconv.FormatInt(int64(line), 10) + "]" + msg + msg = "[" + filename + ":" + strconv.FormatInt(int64(line), 10) + "] " + msg } if bl.asynchronous { lm := logMsgPool.Get().(*logMsg) From 549a39c4787afe9ab377d3373a271f94da3ba33a Mon Sep 17 00:00:00 2001 From: youngsterxyf Date: Mon, 14 Mar 2016 11:26:26 +0800 Subject: [PATCH 016/159] fix issue1789: when testing, load config explicitly and forcibly --- beego.go | 1 + config.go | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/beego.go b/beego.go index 8f82cdcf..a6074d22 100644 --- a/beego.go +++ b/beego.go @@ -87,5 +87,6 @@ func TestBeegoInit(ap string) { os.Setenv("BEEGO_RUNMODE", "test") appConfigPath = filepath.Join(ap, "conf", "app.conf") os.Chdir(ap) + LoadAppConfig(appConfigProvider, appConfigPath) initBeforeHTTPRun() } diff --git a/config.go b/config.go index 2761e7cb..0d4df95c 100644 --- a/config.go +++ b/config.go @@ -316,10 +316,6 @@ func LoadAppConfig(adapterName, configPath string) error { return fmt.Errorf("the target config file: %s don't exist", configPath) } - if absConfigPath == appConfigPath { - return nil - } - appConfigPath = absConfigPath appConfigProvider = adapterName From 9c7d95b0710a41bc715554306be43a194560e621 Mon Sep 17 00:00:00 2001 From: ysqi Date: Mon, 14 Mar 2016 19:21:09 +0800 Subject: [PATCH 017/159] go vet --- config/yaml/yaml.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/config/yaml/yaml.go b/config/yaml/yaml.go index b94adbc1..6a6f07c7 100644 --- a/config/yaml/yaml.go +++ b/config/yaml/yaml.go @@ -122,12 +122,11 @@ type ConfigContainer struct { // Bool returns the boolean value for a given key. func (c *ConfigContainer) Bool(key string) (bool, error) { - - if v, err := c.getData(key); err != nil { + v, err := c.getData(key) + if err != nil { return false, err - } else { - return config.ParseBool(v) } + return config.ParseBool(v) } // DefaultBool return the bool value if has no error From 1b04571c0b493ff61da488e357b05f84747249ce Mon Sep 17 00:00:00 2001 From: ysqi Date: Mon, 14 Mar 2016 19:22:00 +0800 Subject: [PATCH 018/159] test the env use GOPATH not GOROOT --- config/config.go | 2 +- config/ini_test.go | 14 +++++++------- config/json_test.go | 18 +++++++++--------- config/xml/xml_test.go | 10 +++++----- config/yaml/yaml_test.go | 14 +++++++------- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/config/config.go b/config/config.go index 59cc356b..6a159f82 100644 --- a/config/config.go +++ b/config/config.go @@ -132,7 +132,7 @@ func ChooseRealValueForMap(m map[string]interface{}) map[string]interface{} { // // It accept value formats "$$env" , "$$env||" , "$$env||defaultValue" , "defaultvalue". // Examples: -// v1 := config.ChooseRealValue("$$GOROOT") // return the GOROOT environment variable. +// v1 := config.ChooseRealValue("$$GOPATH") // return the GOPATH environment variable. // v2 := config.ChooseRealValue("$$GOAsta||/usr/local/go/") // return the default value "/usr/local/go/". // v3 := config.ChooseRealValue("Astaxie") // return the value "Astaxie". func ChooseRealValue(value string) (realValue string) { diff --git a/config/ini_test.go b/config/ini_test.go index b3f57fbe..a6a66198 100644 --- a/config/ini_test.go +++ b/config/ini_test.go @@ -42,9 +42,9 @@ needlogin = ON enableSession = Y enableCookie = N flag = 1 -path1 = $$GOROOT -path2 = $$GOROOT||/home/go -path3 = $$GOROOT$$GOPATH2||/home/go +path1 = $$GOPATH +path2 = $$GOPATH||/home/go +path3 = $$GOPATH$$GOPATH2||/home/go token1 = $$TOKEN token2 = $$TOKEN|| token3 = $$TOKEN||astaxie @@ -55,7 +55,7 @@ key1="asta" key2 = "xie" CaseInsensitive = true peers = one;two;three -password = $$GOROOT +password = $$GOPATH ` keyValue = map[string]interface{}{ @@ -73,8 +73,8 @@ password = $$GOROOT "enableSession": true, "enableCookie": false, "flag": true, - "path1": os.Getenv("GOROOT"), - "path2": os.Getenv("GOROOT"), + "path1": os.Getenv("GOPATH"), + "path2": os.Getenv("GOPATH"), "path3": "/home/go", "token1": "", "token2": "", @@ -85,7 +85,7 @@ password = $$GOROOT "demo::key2": "xie", "demo::CaseInsensitive": true, "demo::peers": []string{"one", "two", "three"}, - "demo::password": os.Getenv("GOROOT"), + "demo::password": os.Getenv("GOPATH"), "null": "", "demo2::key1": "", "error": "", diff --git a/config/json_test.go b/config/json_test.go index 6ff26dba..940916a1 100644 --- a/config/json_test.go +++ b/config/json_test.go @@ -86,9 +86,9 @@ func TestJson(t *testing.T) { "enableSession": "Y", "enableCookie": "N", "flag": 1, -"path1": "$$GOROOT", -"path2": "$$GOROOT||/home/go", -"path3": "$$GOROOT$$GOPATH2||/home/go", +"path1": "$$GOPATH", +"path2": "$$GOPATH||/home/go", +"path3": "$$GOPATH$$GOPATH2||/home/go", "token1": "$$TOKEN", "token2": "$$TOKEN||", "token3": "$$TOKEN||astaxie", @@ -99,12 +99,12 @@ func TestJson(t *testing.T) { "port": "port", "database": "database", "username": "username", - "password": "$$GOROOT", + "password": "$$GOPATH", "conns":{ "maxconnection":12, "autoconnect":true, "connectioninfo":"info", - "root": "$$GOROOT" + "root": "$$GOPATH" } } }` @@ -124,8 +124,8 @@ func TestJson(t *testing.T) { "enableSession": true, "enableCookie": false, "flag": true, - "path1": os.Getenv("GOROOT"), - "path2": os.Getenv("GOROOT"), + "path1": os.Getenv("GOPATH"), + "path2": os.Getenv("GOPATH"), "path3": "/home/go", "token1": "", "token2": "", @@ -135,11 +135,11 @@ func TestJson(t *testing.T) { "database::host": "host", "database::port": "port", "database::database": "database", - "database::password": os.Getenv("GOROOT"), + "database::password": os.Getenv("GOPATH"), "database::conns::maxconnection": 12, "database::conns::autoconnect": true, "database::conns::connectioninfo": "info", - "database::conns::root": os.Getenv("GOROOT"), + "database::conns::root": os.Getenv("GOPATH"), "unknown": "", } ) diff --git a/config/xml/xml_test.go b/config/xml/xml_test.go index 85c92e8b..825f4d0d 100644 --- a/config/xml/xml_test.go +++ b/config/xml/xml_test.go @@ -35,9 +35,9 @@ func TestXML(t *testing.T) { dev false true -$$GOROOT -$$GOROOT||/home/go -$$GOROOT$$GOPATH2||/home/go +$$GOPATH +$$GOPATH||/home/go +$$GOPATH$$GOPATH2||/home/go $$TOKEN $$TOKEN|| $$TOKEN||astaxie @@ -53,8 +53,8 @@ func TestXML(t *testing.T) { "runmode": "dev", "autorender": false, "copyrequestbody": true, - "path1": os.Getenv("GOROOT"), - "path2": os.Getenv("GOROOT"), + "path1": os.Getenv("GOPATH"), + "path2": os.Getenv("GOPATH"), "path3": "/home/go", "token1": "", "token2": "", diff --git a/config/yaml/yaml_test.go b/config/yaml/yaml_test.go index 30c79d0b..0731778f 100644 --- a/config/yaml/yaml_test.go +++ b/config/yaml/yaml_test.go @@ -33,10 +33,10 @@ func TestYaml(t *testing.T) { "runmode": dev "autorender": false "copyrequestbody": true -"PATH": GOROOT -"path1": $$GOROOT -"path2": $$GOROOT||/home/go -"path3": $$GOROOT$$GOPATH2||/home/go +"PATH": GOPATH +"path1": $$GOPATH +"path2": $$GOPATH||/home/go +"path3": $$GOPATH$$GOPATH2||/home/go "token1": $$TOKEN "token2": $$TOKEN|| "token3": $$TOKEN||astaxie @@ -53,9 +53,9 @@ func TestYaml(t *testing.T) { "runmode": "dev", "autorender": false, "copyrequestbody": true, - "PATH": "GOROOT", - "path1": os.Getenv("GOROOT"), - "path2": os.Getenv("GOROOT"), + "PATH": "GOPATH", + "path1": os.Getenv("GOPATH"), + "path2": os.Getenv("GOPATH"), "path3": "/home/go", "token1": "", "token2": "", From 8660a54facfff34b6f6297921fbe4808c8a7e8bc Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 15 Mar 2016 11:49:23 +0800 Subject: [PATCH 019/159] make router fast --- admin.go | 2 +- namespace.go | 4 ++-- router.go | 55 +++++++++++++++++++++++++--------------------------- 3 files changed, 29 insertions(+), 32 deletions(-) diff --git a/admin.go b/admin.go index 031e6421..cf5bc63a 100644 --- a/admin.go +++ b/admin.go @@ -196,7 +196,7 @@ func listConf(rw http.ResponseWriter, r *http.Request) { BeforeExec: "Before Exec", AfterExec: "After Exec", FinishRouter: "Finish Router"} { - if bf, ok := BeeApp.Handlers.filters[k]; ok { + if bf := BeeApp.Handlers.filters[k]; len(bf) > 0 { filterType = fr filterTypes = append(filterTypes, filterType) resultList := new([][]string) diff --git a/namespace.go b/namespace.go index 4007d44c..cfde0111 100644 --- a/namespace.go +++ b/namespace.go @@ -44,7 +44,7 @@ func NewNamespace(prefix string, params ...LinkNamespace) *Namespace { return ns } -// Cond set condtion function +// Cond set condition function // if cond return true can run this namespace, else can't // usage: // ns.Cond(func (ctx *context.Context) bool{ @@ -60,7 +60,7 @@ func (n *Namespace) Cond(cond namespaceCond) *Namespace { exception("405", ctx) } } - if v, ok := n.handlers.filters[BeforeRouter]; ok { + if v := n.handlers.filters[BeforeRouter]; len(v) > 0 { mr := new(FilterRouter) mr.tree = NewTree() mr.pattern = "*" diff --git a/router.go b/router.go index 5b4b1ff9..597acbb9 100644 --- a/router.go +++ b/router.go @@ -114,7 +114,7 @@ type controllerInfo struct { type ControllerRegister struct { routers map[string]*Tree enableFilter bool - filters map[int][]*FilterRouter + filters [5][]*FilterRouter pool sync.Pool } @@ -122,7 +122,6 @@ type ControllerRegister struct { func NewControllerRegister() *ControllerRegister { cr := &ControllerRegister{ routers: make(map[string]*Tree), - filters: make(map[int][]*FilterRouter), } cr.pool.New = func() interface{} { return beecontext.NewContext() @@ -408,7 +407,6 @@ func (p *ControllerRegister) AddAutoPrefix(prefix string, c ControllerInterface) // InsertFilter Add a FilterFunc with pattern rule and action constant. // The bool params is for setting the returnOnOutput value (false allows multiple filters to execute) func (p *ControllerRegister) InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) error { - mr := new(FilterRouter) mr.tree = NewTree() mr.pattern = pattern @@ -426,9 +424,13 @@ func (p *ControllerRegister) InsertFilter(pattern string, pos int, filter Filter } // add Filter into -func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) error { - p.filters[pos] = append(p.filters[pos], mr) +func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) (err error) { + if pos < BeforeStatic || pos > FinishRouter { + err = fmt.Errorf("can not find your filter postion") + return + } p.enableFilter = true + p.filters[pos] = append(p.filters[pos], mr) return nil } @@ -577,20 +579,16 @@ func (p *ControllerRegister) geturl(t *Tree, url, controllName, methodName strin return false, "" } -func (p *ControllerRegister) execFilter(context *beecontext.Context, pos int, urlPath string) (started bool) { - if p.enableFilter { - if l, ok := p.filters[pos]; ok { - for _, filterR := range l { - if filterR.returnOnOutput && context.ResponseWriter.Started { - return true - } - if ok := filterR.ValidRouter(urlPath, context); ok { - filterR.filterFunc(context) - } - if filterR.returnOnOutput && context.ResponseWriter.Started { - return true - } - } +func (p *ControllerRegister) execFilter(context *beecontext.Context, urlPath string, l []*FilterRouter) (started bool) { + for _, filterR := range l { + if filterR.returnOnOutput && context.ResponseWriter.Started { + return true + } + if ok := filterR.ValidRouter(urlPath, context); ok { + filterR.filterFunc(context) + } + if filterR.returnOnOutput && context.ResponseWriter.Started { + return true } } return false @@ -617,11 +615,10 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) context.Output.Header("Server", BConfig.ServerName) } - var urlPath string + var urlPath = r.URL.Path + if !BConfig.RouterCaseSensitive { urlPath = strings.ToLower(r.URL.Path) - } else { - urlPath = r.URL.Path } // filter wrong http method @@ -631,7 +628,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } // filter for static file - if p.execFilter(context, BeforeStatic, urlPath) { + if fs := p.filters[BeforeStatic]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { goto Admin } @@ -663,8 +660,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } }() } - - if p.execFilter(context, BeforeRouter, urlPath) { + if fs := p.filters[BeforeRouter]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { goto Admin } @@ -693,7 +689,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) if findRouter { //execute middleware filters - if p.execFilter(context, BeforeExec, urlPath) { + if fs := p.filters[BeforeExec]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { goto Admin } isRunnable := false @@ -794,12 +790,13 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } //execute middleware filters - if p.execFilter(context, AfterExec, urlPath) { + if fs := p.filters[AfterExec]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { goto Admin } } - - p.execFilter(context, FinishRouter, urlPath) + if fs := p.filters[FinishRouter]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { + goto Admin + } Admin: //admin module record QPS From c51bc86d3fd0dc38596017f8869b0bb2ff2b6733 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 15 Mar 2016 16:51:21 +0800 Subject: [PATCH 020/159] goto bug fixed --- router.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/router.go b/router.go index 597acbb9..9b62c4cc 100644 --- a/router.go +++ b/router.go @@ -652,7 +652,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) if err != nil { Error(err) exception("503", context) - return + goto Admin } defer func() { if context.Input.CruSession != nil { From 34615ee8fcbb485574b181bd2bf9be86e3a97e87 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 15 Mar 2016 18:37:54 +0800 Subject: [PATCH 021/159] add router filter enable flag --- router.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/router.go b/router.go index 9b62c4cc..9e75e013 100644 --- a/router.go +++ b/router.go @@ -114,7 +114,8 @@ type controllerInfo struct { type ControllerRegister struct { routers map[string]*Tree enableFilter bool - filters [5][]*FilterRouter + filters [FinishRouter + 1][]*FilterRouter + filterFlag [FinishRouter + 1]bool pool sync.Pool } @@ -430,6 +431,7 @@ func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) (err return } p.enableFilter = true + p.filterFlag[pos] = true p.filters[pos] = append(p.filters[pos], mr) return nil } @@ -579,8 +581,8 @@ func (p *ControllerRegister) geturl(t *Tree, url, controllName, methodName strin return false, "" } -func (p *ControllerRegister) execFilter(context *beecontext.Context, urlPath string, l []*FilterRouter) (started bool) { - for _, filterR := range l { +func (p *ControllerRegister) execFilter(context *beecontext.Context, urlPath string, pos int) (started bool) { + for _, filterR := range p.filters[pos] { if filterR.returnOnOutput && context.ResponseWriter.Started { return true } @@ -628,11 +630,12 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } // filter for static file - if fs := p.filters[BeforeStatic]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { + if p.filterFlag[BeforeStatic] && p.execFilter(context, urlPath, BeforeStatic) { goto Admin } serverStaticRouter(context) + if context.ResponseWriter.Started { findRouter = true goto Admin @@ -660,7 +663,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } }() } - if fs := p.filters[BeforeRouter]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { + if p.filterFlag[BeforeRouter] && p.execFilter(context, urlPath, BeforeRouter) { goto Admin } @@ -689,7 +692,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) if findRouter { //execute middleware filters - if fs := p.filters[BeforeExec]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { + if p.filterFlag[BeforeExec] && p.execFilter(context, urlPath, BeforeExec) { goto Admin } isRunnable := false @@ -790,11 +793,11 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } //execute middleware filters - if fs := p.filters[AfterExec]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { + if p.filterFlag[AfterExec] && p.execFilter(context, urlPath, AfterExec) { goto Admin } } - if fs := p.filters[FinishRouter]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { + if p.filterFlag[FinishRouter] && p.execFilter(context, urlPath, FinishRouter) { goto Admin } From 565c4a4d592cf196610a3759d88b00822c87fef8 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 15 Mar 2016 18:50:18 +0800 Subject: [PATCH 022/159] make the code run more fast --- router.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/router.go b/router.go index 9e75e013..0da56464 100644 --- a/router.go +++ b/router.go @@ -115,7 +115,6 @@ type ControllerRegister struct { routers map[string]*Tree enableFilter bool filters [FinishRouter + 1][]*FilterRouter - filterFlag [FinishRouter + 1]bool pool sync.Pool } @@ -431,7 +430,6 @@ func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) (err return } p.enableFilter = true - p.filterFlag[pos] = true p.filters[pos] = append(p.filters[pos], mr) return nil } @@ -630,7 +628,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } // filter for static file - if p.filterFlag[BeforeStatic] && p.execFilter(context, urlPath, BeforeStatic) { + if len(p.filters[BeforeStatic]) > 0 && p.execFilter(context, urlPath, BeforeStatic) { goto Admin } @@ -663,7 +661,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } }() } - if p.filterFlag[BeforeRouter] && p.execFilter(context, urlPath, BeforeRouter) { + if len(p.filters[BeforeRouter]) > 0 && p.execFilter(context, urlPath, BeforeRouter) { goto Admin } @@ -692,7 +690,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) if findRouter { //execute middleware filters - if p.filterFlag[BeforeExec] && p.execFilter(context, urlPath, BeforeExec) { + if len(p.filters[BeforeExec]) > 0 && p.execFilter(context, urlPath, BeforeExec) { goto Admin } isRunnable := false @@ -793,11 +791,11 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } //execute middleware filters - if p.filterFlag[AfterExec] && p.execFilter(context, urlPath, AfterExec) { + if len(p.filters[AfterExec]) > 0 && p.execFilter(context, urlPath, AfterExec) { goto Admin } } - if p.filterFlag[FinishRouter] && p.execFilter(context, urlPath, FinishRouter) { + if len(p.filters[FinishRouter]) > 0 && p.execFilter(context, urlPath, FinishRouter) { goto Admin } From 94599013fc8a932de20bba7ce2fce91f61634c16 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 16 Mar 2016 07:53:36 +0800 Subject: [PATCH 023/159] url to lower case --- router.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/router.go b/router.go index 0da56464..71be4c16 100644 --- a/router.go +++ b/router.go @@ -618,7 +618,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) var urlPath = r.URL.Path if !BConfig.RouterCaseSensitive { - urlPath = strings.ToLower(r.URL.Path) + urlPath = strings.ToLower(urlPath) } // filter wrong http method From 2b1316c73826c8bfdbe34fa194f18770930599af Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 16 Mar 2016 18:04:07 +0800 Subject: [PATCH 024/159] data race bug fixed --- logs/file.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/logs/file.go b/logs/file.go index 9d3f78a0..672823fa 100644 --- a/logs/file.go +++ b/logs/file.go @@ -30,7 +30,7 @@ import ( // fileLogWriter implements LoggerInterface. // It writes messages by lines limit, file size limit, or time frequency. type fileLogWriter struct { - sync.Mutex // write log order by order and atomic incr maxLinesCurLines and maxSizeCurSize + sync.RWMutex // write log order by order and atomic incr maxLinesCurLines and maxSizeCurSize // The opened file Filename string `json:"filename"` fileWriter *os.File @@ -77,7 +77,7 @@ func newFileWriter() Logger { // { // "filename":"logs/beego.log", // "maxLines":10000, -// "maxsize":1<<30, +// "maxsize":1024, // "daily":true, // "maxDays":15, // "rotate":true, @@ -128,7 +128,9 @@ func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error { h, d := formatTimeHeader(when) msg = string(h) + msg + "\n" if w.Rotate { + w.RLock() if w.needRotate(len(msg), d) { + w.RUnlock() w.Lock() if w.needRotate(len(msg), d) { if err := w.doRotate(when); err != nil { @@ -136,6 +138,8 @@ func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error { } } w.Unlock() + } else { + w.RUnlock() } } From ec35bd0c28aecbba2d6e26f049166b76f264e542 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 16 Mar 2016 18:04:27 +0800 Subject: [PATCH 025/159] orm log header flag --- orm/orm_log.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orm/orm_log.go b/orm/orm_log.go index 712eb219..54723273 100644 --- a/orm/orm_log.go +++ b/orm/orm_log.go @@ -31,7 +31,7 @@ type Log struct { // NewLog set io.Writer to create a Logger. func NewLog(out io.Writer) *Log { d := new(Log) - d.Logger = log.New(out, "[ORM]", 1e9) + d.Logger = log.New(out, "[ORM]", log.LstdFlags) return d } From 443d71397cd33f8b18c7fc82b7b372bdf5b36539 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 09:35:14 +0800 Subject: [PATCH 026/159] write error to response --- error.go | 208 +++++++++++++++++++++++++------------------------------ 1 file changed, 94 insertions(+), 114 deletions(-) diff --git a/error.go b/error.go index 4f48fab2..6488fc6c 100644 --- a/error.go +++ b/error.go @@ -210,159 +210,139 @@ var ErrorMaps = make(map[string]*errorInfo, 10) // show 401 unauthorized error. func unauthorized(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(401), - "BeegoVersion": VERSION, - } - data["Content"] = template.HTML("
The page you have requested can't be authorized." + - "
Perhaps you are here because:" + - "

    " + - "
    The credentials you supplied are incorrect" + - "
    There are errors in the website address" + - "
") - t.Execute(rw, data) + responseError(rw, r, + 401, + "
The page you have requested can't be authorized."+ + "
Perhaps you are here because:"+ + "

    "+ + "
    The credentials you supplied are incorrect"+ + "
    There are errors in the website address"+ + "
", + ) } // show 402 Payment Required func paymentRequired(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(402), - "BeegoVersion": VERSION, - } - data["Content"] = template.HTML("
The page you have requested Payment Required." + - "
Perhaps you are here because:" + - "

    " + - "
    The credentials you supplied are incorrect" + - "
    There are errors in the website address" + - "
") - t.Execute(rw, data) + responseError(rw, r, + 402, + "
The page you have requested Payment Required."+ + "
Perhaps you are here because:"+ + "

    "+ + "
    The credentials you supplied are incorrect"+ + "
    There are errors in the website address"+ + "
", + ) } // show 403 forbidden error. func forbidden(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(403), - "BeegoVersion": VERSION, - } - data["Content"] = template.HTML("
The page you have requested is forbidden." + - "
Perhaps you are here because:" + - "

    " + - "
    Your address may be blocked" + - "
    The site may be disabled" + - "
    You need to log in" + - "
") - t.Execute(rw, data) + responseError(rw, r, + 403, + "
The page you have requested is forbidden."+ + "
Perhaps you are here because:"+ + "

    "+ + "
    Your address may be blocked"+ + "
    The site may be disabled"+ + "
    You need to log in"+ + "
", + ) } -// show 404 notfound error. +// show 404 not found error. func notFound(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(404), - "BeegoVersion": VERSION, - } - data["Content"] = template.HTML("
The page you have requested has flown the coop." + - "
Perhaps you are here because:" + - "

    " + - "
    The page has moved" + - "
    The page no longer exists" + - "
    You were looking for your puppy and got lost" + - "
    You like 404 pages" + - "
") - t.Execute(rw, data) + responseError(rw, r, + 404, + "
The page you have requested has flown the coop."+ + "
Perhaps you are here because:"+ + "

    "+ + "
    The page has moved"+ + "
    The page no longer exists"+ + "
    You were looking for your puppy and got lost"+ + "
    You like 404 pages"+ + "
", + ) } // show 405 Method Not Allowed func methodNotAllowed(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(405), - "BeegoVersion": VERSION, - } - data["Content"] = template.HTML("
The method you have requested Not Allowed." + - "
Perhaps you are here because:" + - "

    " + - "
    The method specified in the Request-Line is not allowed for the resource identified by the Request-URI" + - "
    The response MUST include an Allow header containing a list of valid methods for the requested resource." + - "
") - t.Execute(rw, data) + responseError(rw, r, + 405, + "
The method you have requested Not Allowed."+ + "
Perhaps you are here because:"+ + "

    "+ + "
    The method specified in the Request-Line is not allowed for the resource identified by the Request-URI"+ + "
    The response MUST include an Allow header containing a list of valid methods for the requested resource."+ + "
", + ) } // show 500 internal server error. func internalServerError(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(500), - "BeegoVersion": VERSION, - } - data["Content"] = template.HTML("
The page you have requested is down right now." + - "

    " + - "
    Please try again later and report the error to the website administrator" + - "
") - t.Execute(rw, data) + responseError(rw, r, + 500, + "
The page you have requested is down right now."+ + "

    "+ + "
    Please try again later and report the error to the website administrator"+ + "
", + ) } // show 501 Not Implemented. func notImplemented(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(504), - "BeegoVersion": VERSION, - } - data["Content"] = template.HTML("
The page you have requested is Not Implemented." + - "

    " + - "
    Please try again later and report the error to the website administrator" + - "
") - t.Execute(rw, data) + responseError(rw, r, + 501, + "
The page you have requested is Not Implemented."+ + "

    "+ + "
    Please try again later and report the error to the website administrator"+ + "
", + ) } // show 502 Bad Gateway. func badGateway(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(502), - "BeegoVersion": VERSION, - } - data["Content"] = template.HTML("
The page you have requested is down right now." + - "

    " + - "
    The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request." + - "
    Please try again later and report the error to the website administrator" + - "
") - t.Execute(rw, data) + responseError(rw, r, + 502, + "
The page you have requested is down right now."+ + "

    "+ + "
    The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request."+ + "
    Please try again later and report the error to the website administrator"+ + "
", + ) } // show 503 service unavailable error. func serviceUnavailable(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(503), - "BeegoVersion": VERSION, - } - data["Content"] = template.HTML("
The page you have requested is unavailable." + - "
Perhaps you are here because:" + - "

    " + - "

    The page is overloaded" + - "
    Please try again later." + - "
") - t.Execute(rw, data) + responseError(rw, r, + 503, + "
The page you have requested is unavailable."+ + "
Perhaps you are here because:"+ + "

    "+ + "

    The page is overloaded"+ + "
    Please try again later."+ + "
", + ) } // show 504 Gateway Timeout. func gatewayTimeout(rw http.ResponseWriter, r *http.Request) { + responseError(rw, r, + 504, + "
The page you have requested is unavailable"+ + "
Perhaps you are here because:"+ + "

    "+ + "

    The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI."+ + "
    Please try again later."+ + "
", + ) +} + +func responseError(rw http.ResponseWriter, r *http.Request, errCode int, errContent string) { t, _ := template.New("beegoerrortemp").Parse(errtpl) data := map[string]interface{}{ - "Title": http.StatusText(504), + "Title": http.StatusText(errCode), "BeegoVersion": VERSION, + "Content": errContent, } - data["Content"] = template.HTML("
The page you have requested is unavailable." + - "
Perhaps you are here because:" + - "

    " + - "

    The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI." + - "
    Please try again later." + - "
") t.Execute(rw, data) } From 0859ec570cba6327faf6881efc2eff2a136ced79 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 09:46:34 +0800 Subject: [PATCH 027/159] refactor of error response and fix err code bug --- controller.go | 3 ++- error.go | 5 ++++- router.go | 37 ++++++++++++++++++------------------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/controller.go b/controller.go index 85894275..9d265758 100644 --- a/controller.go +++ b/controller.go @@ -261,12 +261,13 @@ func (c *Controller) Abort(code string) { // CustomAbort stops controller handler and show the error data, it's similar Aborts, but support status code and body. func (c *Controller) CustomAbort(status int, body string) { - c.Ctx.Output.Status = status // first panic from ErrorMaps, is is user defined error functions. if _, ok := ErrorMaps[body]; ok { + c.Ctx.Output.Status = status panic(body) } // last panic user string + c.Ctx.ResponseWriter.WriteHeader(status) c.Ctx.ResponseWriter.Write([]byte(body)) panic(ErrAbort) } diff --git a/error.go b/error.go index 6488fc6c..8cfa0c67 100644 --- a/error.go +++ b/error.go @@ -388,7 +388,10 @@ func exception(errCode string, ctx *context.Context) { if err == nil { return v } - return 503 + if ctx.Output.Status == 0 { + return 503 + } + return ctx.Output.Status } for _, ec := range []string{errCode, "503", "500"} { diff --git a/router.go b/router.go index 5b4b1ff9..99780b5c 100644 --- a/router.go +++ b/router.go @@ -844,27 +844,26 @@ func (p *ControllerRegister) recoverPanic(context *beecontext.Context) { } if !BConfig.RecoverPanic { panic(err) - } else { - if BConfig.EnableErrorsShow { - if _, ok := ErrorMaps[fmt.Sprint(err)]; ok { - exception(fmt.Sprint(err), context) - return - } + } + if BConfig.EnableErrorsShow { + if _, ok := ErrorMaps[fmt.Sprint(err)]; ok { + exception(fmt.Sprint(err), context) + return } - var stack string - Critical("the request url is ", context.Input.URL()) - Critical("Handler crashed with error", err) - for i := 1; ; i++ { - _, file, line, ok := runtime.Caller(i) - if !ok { - break - } - Critical(fmt.Sprintf("%s:%d", file, line)) - stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line)) - } - if BConfig.RunMode == DEV { - showErr(err, context, stack) + } + var stack string + Critical("the request url is ", context.Input.URL()) + Critical("Handler crashed with error", err) + for i := 1; ; i++ { + _, file, line, ok := runtime.Caller(i) + if !ok { + break } + Critical(fmt.Sprintf("%s:%d", file, line)) + stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line)) + } + if BConfig.RunMode == DEV { + showErr(err, context, stack) } } } From 48147f50d8e65838938adeffb239de45da4f91aa Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 19:09:21 +0800 Subject: [PATCH 028/159] add some gzip future --- context/acceptencoder.go | 93 ++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 31 deletions(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index 033d9ca8..2e5af83a 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -25,8 +25,35 @@ import ( "strconv" "strings" "sync" + + "github.com/astaxie/beego/config" ) +var ( +//Content will only be compressed if content length is either unknown or greater than minGzipSize. + gzipMinLength int +//Default size==20B like nginx + defaultGzipMinLength=20 +//The compression level used for deflate compression. (0-9). + gzipCompressLevel int +//List of HTTP methods to compress. If not set, only GET requests are compressed. + includedMethods map[string]bool + getMethodOnly bool +) + +func InitGzip(cf config.Configer) { + gzipMinLength = cf.DefaultInt("gzipMinLength", defaultGzipMinLength) + gzipCompressLevel = cf.DefaultInt("gzipCompressLevel", flate.DefaultCompression) + if gzipCompressLevel < flate.DefaultCompression || gzipCompressLevel > flate.BestCompression { + gzipCompressLevel = flate.BestSpeed + } + methods := cf.DefaultStrings("includedMethods", []string{"GET"}) + getMethodOnly = len(methods) == 1 && strings.ToUpper(methods[0]) == "GET" + for _, v := range methods { + includedMethods[strings.ToUpper(v)] = true + } +} + type resetWriter interface { io.Writer Reset(w io.Writer) @@ -41,20 +68,20 @@ func (n nopResetWriter) Reset(w io.Writer) { } type acceptEncoder struct { - name string - levelEncode func(int) resetWriter - bestSpeedPool *sync.Pool - bestCompressionPool *sync.Pool + name string + levelEncode func(int) resetWriter + customCompressLevelPool *sync.Pool + bestCompressionPool *sync.Pool } func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter { - if ac.bestSpeedPool == nil || ac.bestCompressionPool == nil { + if ac.customCompressLevelPool == nil || ac.bestCompressionPool == nil { return nopResetWriter{wr} } var rwr resetWriter switch level { case flate.BestSpeed: - rwr = ac.bestSpeedPool.Get().(resetWriter) + rwr = ac.customCompressLevelPool.Get().(resetWriter) case flate.BestCompression: rwr = ac.bestCompressionPool.Get().(resetWriter) default: @@ -65,13 +92,16 @@ func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter { } func (ac acceptEncoder) put(wr resetWriter, level int) { - if ac.bestSpeedPool == nil || ac.bestCompressionPool == nil { + if ac.customCompressLevelPool == nil || ac.bestCompressionPool == nil { return } wr.Reset(nil) + //notice + //compressionLevel==BestCompression DOES NOT MATTER + //sync.Pool will not memory leak switch level { - case flate.BestSpeed: - ac.bestSpeedPool.Put(wr) + case gzipCompressLevel: + ac.customCompressLevelPool.Put(wr) case flate.BestCompression: ac.bestCompressionPool.Put(wr) } @@ -79,28 +109,22 @@ func (ac acceptEncoder) put(wr resetWriter, level int) { var ( noneCompressEncoder = acceptEncoder{"", nil, nil, nil} - gzipCompressEncoder = acceptEncoder{"gzip", - func(level int) resetWriter { wr, _ := gzip.NewWriterLevel(nil, level); return wr }, - &sync.Pool{ - New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestSpeed); return wr }, - }, - &sync.Pool{ - New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr }, - }, + gzipCompressEncoder = acceptEncoder{ + name: "gzip", + levelEncode: func(level int) resetWriter { wr, _ := gzip.NewWriterLevel(nil, level); return wr }, + customCompressLevelPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, gzipCompressLevel); return wr }}, + bestCompressionPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr }}, } - //according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed - //deflate - //The "zlib" format defined in RFC 1950 [31] in combination with - //the "deflate" compression mechanism described in RFC 1951 [29]. - deflateCompressEncoder = acceptEncoder{"deflate", - func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr }, - &sync.Pool{ - New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestSpeed); return wr }, - }, - &sync.Pool{ - New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestCompression); return wr }, - }, +//according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed +//deflate +//The "zlib" format defined in RFC 1950 [31] in combination with +//the "deflate" compression mechanism described in RFC 1951 [29]. + deflateCompressEncoder = acceptEncoder{ + name: "deflate", + levelEncode: func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr }, + customCompressLevelPool: &sync.Pool{New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, gzipCompressLevel); return wr }}, + bestCompressionPool: &sync.Pool{New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestCompression); return wr }}, } ) @@ -120,7 +144,11 @@ func WriteFile(encoding string, writer io.Writer, file *os.File) (bool, string, // WriteBody reads writes content to writer by the specific encoding(gzip/deflate) func WriteBody(encoding string, writer io.Writer, content []byte) (bool, string, error) { - return writeLevel(encoding, writer, bytes.NewReader(content), flate.BestSpeed) + if encoding == "" || len(content) < gzipMinLength { + _, err := writer.Write(content) + return false, "", err + } + return writeLevel(encoding, writer, bytes.NewReader(content), gzipCompressLevel) } // writeLevel reads from reader,writes to writer by specific encoding and compress level @@ -156,7 +184,10 @@ func ParseEncoding(r *http.Request) string { if r == nil { return "" } - return parseEncoding(r) + if (getMethodOnly && r.Method == "GET") || includedMethods[r.Method] { + return parseEncoding(r) + } + return "" } type q struct { From 5a9bff2000701fd565027c184cfa010c7c820592 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 19:09:38 +0800 Subject: [PATCH 029/159] init gzip level --- beego.go | 8 +++++--- hooks.go | 8 ++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/beego.go b/beego.go index 8f82cdcf..89e4f671 100644 --- a/beego.go +++ b/beego.go @@ -22,12 +22,12 @@ import ( ) const ( - // VERSION represent beego web framework version. +// VERSION represent beego web framework version. VERSION = "1.6.1" - // DEV is for develop +// DEV is for develop DEV = "dev" - // PROD is for production +// PROD is for production PROD = "prod" ) @@ -51,6 +51,7 @@ func AddAPPStartHook(hf hookfunc) { // beego.Run(":8089") // beego.Run("127.0.0.1:8089") func Run(params ...string) { + initBeforeHTTPRun() if len(params) > 0 && params[0] != "" { @@ -74,6 +75,7 @@ func initBeforeHTTPRun() { AddAPPStartHook(registerDocs) AddAPPStartHook(registerTemplate) AddAPPStartHook(registerAdmin) + AddAPPStartHook(registerGzip) for _, hk := range hooks { if err := hk(); err != nil { diff --git a/hooks.go b/hooks.go index 59b10b32..1a7937b5 100644 --- a/hooks.go +++ b/hooks.go @@ -6,6 +6,7 @@ import ( "net/http" "path/filepath" + "github.com/astaxie/beego/context" "github.com/astaxie/beego/session" ) @@ -91,3 +92,10 @@ func registerAdmin() error { } return nil } + +func registerGzip() error { + if BConfig.EnableGzip { + context.InitGzip(AppConfig) + } + return nil +} From 35e34261abd45205becb700e302c7a5972c98fa1 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 19:40:29 +0800 Subject: [PATCH 030/159] gzip method support --- context/acceptencoder.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index 2e5af83a..21ede1a5 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -30,13 +30,13 @@ import ( ) var ( -//Content will only be compressed if content length is either unknown or greater than minGzipSize. + //Content will only be compressed if content length is either unknown or greater than minGzipSize. gzipMinLength int -//Default size==20B like nginx - defaultGzipMinLength=20 -//The compression level used for deflate compression. (0-9). + //Default size==20B like nginx + defaultGzipMinLength = 20 + //The compression level used for deflate compression. (0-9). gzipCompressLevel int -//List of HTTP methods to compress. If not set, only GET requests are compressed. + //List of HTTP methods to compress. If not set, only GET requests are compressed. includedMethods map[string]bool getMethodOnly bool ) @@ -96,9 +96,11 @@ func (ac acceptEncoder) put(wr resetWriter, level int) { return } wr.Reset(nil) + //notice //compressionLevel==BestCompression DOES NOT MATTER //sync.Pool will not memory leak + switch level { case gzipCompressLevel: ac.customCompressLevelPool.Put(wr) @@ -116,10 +118,10 @@ var ( bestCompressionPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr }}, } -//according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed -//deflate -//The "zlib" format defined in RFC 1950 [31] in combination with -//the "deflate" compression mechanism described in RFC 1951 [29]. + //according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed + //deflate + //The "zlib" format defined in RFC 1950 [31] in combination with + //the "deflate" compression mechanism described in RFC 1951 [29]. deflateCompressEncoder = acceptEncoder{ name: "deflate", levelEncode: func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr }, From 57eace07a79f80aaeab7b0d06058a8e81ee05af3 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 19:52:09 +0800 Subject: [PATCH 031/159] comment update --- context/acceptencoder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index 21ede1a5..bc67bb5e 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -30,7 +30,7 @@ import ( ) var ( - //Content will only be compressed if content length is either unknown or greater than minGzipSize. + //Content will only be compressed if content length is either unknown or greater than gzipMinLength. gzipMinLength int //Default size==20B like nginx defaultGzipMinLength = 20 From 0b401481ef1c9abc920996d6cbe67818970984bf Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 19:59:48 +0800 Subject: [PATCH 032/159] go fmt the comment --- beego.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/beego.go b/beego.go index 89e4f671..65dd79cb 100644 --- a/beego.go +++ b/beego.go @@ -22,12 +22,12 @@ import ( ) const ( -// VERSION represent beego web framework version. + // VERSION represent beego web framework version. VERSION = "1.6.1" -// DEV is for develop + // DEV is for develop DEV = "dev" -// PROD is for production + // PROD is for production PROD = "prod" ) From 9f21928a90e6782e92cfc26462d66223557b680d Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 20:07:24 +0800 Subject: [PATCH 033/159] some typo fixed --- context/acceptencoder.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index bc67bb5e..bc048e77 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -32,7 +32,7 @@ import ( var ( //Content will only be compressed if content length is either unknown or greater than gzipMinLength. gzipMinLength int - //Default size==20B like nginx + //Default size==20B same as nginx defaultGzipMinLength = 20 //The compression level used for deflate compression. (0-9). gzipCompressLevel int @@ -43,7 +43,7 @@ var ( func InitGzip(cf config.Configer) { gzipMinLength = cf.DefaultInt("gzipMinLength", defaultGzipMinLength) - gzipCompressLevel = cf.DefaultInt("gzipCompressLevel", flate.DefaultCompression) + gzipCompressLevel = cf.DefaultInt("gzipCompressLevel", flate.BestSpeed) if gzipCompressLevel < flate.DefaultCompression || gzipCompressLevel > flate.BestCompression { gzipCompressLevel = flate.BestSpeed } From a3d4218d9df28355dcfd0b1042e8dfae4615d97c Mon Sep 17 00:00:00 2001 From: miraclesu Date: Thu, 17 Mar 2016 21:34:49 +0800 Subject: [PATCH 034/159] orm: fix miss pk when pk is negative --- orm/db.go | 8 ++++---- orm/db_utils.go | 4 ++-- orm/models_fields.go | 8 ++++---- orm/orm.go | 2 +- orm/orm_object.go | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/orm/db.go b/orm/db.go index 314c3535..9ff84411 100644 --- a/orm/db.go +++ b/orm/db.go @@ -181,7 +181,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val } default: switch { - case fi.fieldType&IsPostiveIntegerField > 0: + case fi.fieldType&IsPositiveIntegerField > 0: if field.Kind() == reflect.Ptr { if field.IsNil() { value = nil @@ -516,7 +516,7 @@ func (d *dbBase) Delete(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time. } if num > 0 { if mi.fields.pk.auto { - if mi.fields.pk.fieldType&IsPostiveIntegerField > 0 { + if mi.fields.pk.fieldType&IsPositiveIntegerField > 0 { ind.FieldByIndex(mi.fields.pk.fieldIndex).SetUint(0) } else { ind.FieldByIndex(mi.fields.pk.fieldIndex).SetInt(0) @@ -1140,7 +1140,7 @@ setValue: tErr = err goto end } - if fieldType&IsPostiveIntegerField > 0 { + if fieldType&IsPositiveIntegerField > 0 { v, _ := str.Uint64() value = v } else { @@ -1292,7 +1292,7 @@ setValue: field.Set(reflect.ValueOf(&v)) } case fieldType&IsIntegerField > 0: - if fieldType&IsPostiveIntegerField > 0 { + if fieldType&IsPositiveIntegerField > 0 { if isNative { if value == nil { value = uint64(0) diff --git a/orm/db_utils.go b/orm/db_utils.go index c97caf36..ff36b286 100644 --- a/orm/db_utils.go +++ b/orm/db_utils.go @@ -33,13 +33,13 @@ func getExistPk(mi *modelInfo, ind reflect.Value) (column string, value interfac fi := mi.fields.pk v := ind.FieldByIndex(fi.fieldIndex) - if fi.fieldType&IsPostiveIntegerField > 0 { + if fi.fieldType&IsPositiveIntegerField > 0 { vu := v.Uint() exist = vu > 0 value = vu } else if fi.fieldType&IsIntegerField > 0 { vu := v.Int() - exist = vu > 0 + exist = true value = vu } else { vu := v.String() diff --git a/orm/models_fields.go b/orm/models_fields.go index a8cf8e4f..ad1fb6f9 100644 --- a/orm/models_fields.go +++ b/orm/models_fields.go @@ -46,10 +46,10 @@ const ( // Define some logic enum const ( - IsIntegerField = ^-TypePositiveBigIntegerField >> 4 << 5 - IsPostiveIntegerField = ^-TypePositiveBigIntegerField >> 8 << 9 - IsRelField = ^-RelReverseMany >> 14 << 15 - IsFieldType = ^-RelReverseMany<<1 + 1 + IsIntegerField = ^-TypePositiveBigIntegerField >> 4 << 5 + IsPositiveIntegerField = ^-TypePositiveBigIntegerField >> 8 << 9 + IsRelField = ^-RelReverseMany >> 14 << 15 + IsFieldType = ^-RelReverseMany<<1 + 1 ) // BooleanField A true/false field. diff --git a/orm/orm.go b/orm/orm.go index 0ffb6b86..38c89334 100644 --- a/orm/orm.go +++ b/orm/orm.go @@ -159,7 +159,7 @@ func (o *orm) Insert(md interface{}) (int64, error) { // set auto pk field func (o *orm) setPk(mi *modelInfo, ind reflect.Value, id int64) { if mi.fields.pk.auto { - if mi.fields.pk.fieldType&IsPostiveIntegerField > 0 { + if mi.fields.pk.fieldType&IsPositiveIntegerField > 0 { ind.FieldByIndex(mi.fields.pk.fieldIndex).SetUint(uint64(id)) } else { ind.FieldByIndex(mi.fields.pk.fieldIndex).SetInt(id) diff --git a/orm/orm_object.go b/orm/orm_object.go index 8a5d85e2..de3181ce 100644 --- a/orm/orm_object.go +++ b/orm/orm_object.go @@ -50,7 +50,7 @@ func (o *insertSet) Insert(md interface{}) (int64, error) { } if id > 0 { if o.mi.fields.pk.auto { - if o.mi.fields.pk.fieldType&IsPostiveIntegerField > 0 { + if o.mi.fields.pk.fieldType&IsPositiveIntegerField > 0 { ind.FieldByIndex(o.mi.fields.pk.fieldIndex).SetUint(uint64(id)) } else { ind.FieldByIndex(o.mi.fields.pk.fieldIndex).SetInt(id) From 4caf044be2e7b18d52a6c525c7d5d209ed7d987a Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 18 Mar 2016 15:18:00 +0800 Subject: [PATCH 035/159] getMethodOnly assign fixed --- context/acceptencoder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index bc048e77..e73744f5 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -48,7 +48,7 @@ func InitGzip(cf config.Configer) { gzipCompressLevel = flate.BestSpeed } methods := cf.DefaultStrings("includedMethods", []string{"GET"}) - getMethodOnly = len(methods) == 1 && strings.ToUpper(methods[0]) == "GET" + getMethodOnly = (len(methods) == 0) || (len(methods) == 1 && strings.ToUpper(methods[0]) == "GET") for _, v := range methods { includedMethods[strings.ToUpper(v)] = true } From 84ae930c6490b1aa9b62ae7a6591ab859c6f150f Mon Sep 17 00:00:00 2001 From: miraclesu Date: Fri, 18 Mar 2016 21:58:11 +0800 Subject: [PATCH 036/159] orm: Add test case for integer pk --- orm/models_test.go | 5 +++++ orm/orm_test.go | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/orm/models_test.go b/orm/models_test.go index 4c8d32f8..b6ae21cf 100644 --- a/orm/models_test.go +++ b/orm/models_test.go @@ -387,6 +387,11 @@ func NewInLineOneToOne() *InLineOneToOne { return new(InLineOneToOne) } +type IntegerPk struct { + Id int64 `orm:"pk"` + Value string +} + var DBARGS = struct { Driver string Source string diff --git a/orm/orm_test.go b/orm/orm_test.go index 181106bb..832c7301 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" "io/ioutil" + "math" "os" "path/filepath" "reflect" @@ -189,6 +190,7 @@ func TestSyncDb(t *testing.T) { RegisterModel(new(GroupPermissions)) RegisterModel(new(InLine)) RegisterModel(new(InLineOneToOne)) + RegisterModel(new(IntegerPk)) err := RunSyncdb("default", true, Debug) throwFail(t, err) @@ -210,6 +212,7 @@ func TestRegisterModels(t *testing.T) { RegisterModel(new(GroupPermissions)) RegisterModel(new(InLine)) RegisterModel(new(InLineOneToOne)) + RegisterModel(new(IntegerPk)) BootStrap() @@ -1991,3 +1994,22 @@ func TestInLineOneToOne(t *testing.T) { throwFail(t, AssertIs(rinline.Name, name)) throwFail(t, AssertIs(rinline.Email, email)) } + +func TestIntegerPk(t *testing.T) { + its := []IntegerPk{ + {Id: math.MinInt64, Value: "-"}, + {Id: 0, Value: "0"}, + {Id: math.MaxInt64, Value: "+"}, + } + + num, err := dORM.InsertMulti(len(its), its) + throwFail(t, err) + throwFail(t, AssertIs(num, len(its))) + + for _, intPk := range its { + out := IntegerPk{Id: intPk.Id} + err = dORM.Read(&out) + throwFail(t, err) + throwFail(t, AssertIs(out.Value, intPk.Value)) + } +} From 33ae75b25197ee6f678b07a7d8970985c2e39510 Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 21 Mar 2016 08:50:56 +0800 Subject: [PATCH 037/159] golint check only works on Go 1.5 --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3c821dcd..fbcb8a24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ before_install: - cd ssdb - make - cd .. + - '[[ $(go version) == *1.[5-9]* ]] && go get github.com/golang/lint/golint' install: - go get github.com/lib/pq - go get github.com/go-sql-driver/mysql @@ -32,7 +33,6 @@ install: - go get github.com/siddontang/ledisdb/config - go get github.com/siddontang/ledisdb/ledis - go get golang.org/x/tools/cmd/vet - - go get github.com/golang/lint/golint - go get github.com/ssdb/gossdb/ssdb before_script: - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" @@ -45,7 +45,7 @@ after_script: - rm -rf ./res/var/* script: - go vet -x ./... - - $HOME/gopath/bin/golint ./... + - '[[ $(go version) == *1.[5-9]* ]] && $HOME/gopath/bin/golint ./...' - go test -v ./... notifications: webhooks: https://hooks.pubu.im/services/z7m9bvybl3rgtg9 From 959b9a5a580e2e232b92680f640b1865bf3af24d Mon Sep 17 00:00:00 2001 From: JessonChan Date: Mon, 21 Mar 2016 09:32:41 +0800 Subject: [PATCH 038/159] config index out of range bug fixed --- config.go | 2 +- context/acceptencoder.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config.go b/config.go index 2761e7cb..15d11386 100644 --- a/config.go +++ b/config.go @@ -353,7 +353,7 @@ func (b *beegoAppConfig) String(key string) string { } func (b *beegoAppConfig) Strings(key string) []string { - if v := b.innerConfig.Strings(BConfig.RunMode + "::" + key); v[0] != "" { + if v := b.innerConfig.Strings(BConfig.RunMode + "::" + key); len(v) > 0 { return v } return b.innerConfig.Strings(key) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index e73744f5..fc2775ce 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -49,6 +49,7 @@ func InitGzip(cf config.Configer) { } methods := cf.DefaultStrings("includedMethods", []string{"GET"}) getMethodOnly = (len(methods) == 0) || (len(methods) == 1 && strings.ToUpper(methods[0]) == "GET") + includedMethods = make(map[string]bool, len(methods)) for _, v := range methods { includedMethods[strings.ToUpper(v)] = true } From f2ed27cc8f6aabcc779009e1c670d1154df89afa Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 21 Mar 2016 11:10:57 +0800 Subject: [PATCH 039/159] make sure works for travis --- .travis.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index fbcb8a24..d01dc3a9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,8 @@ language: go go: - - tip - - 1.6.0 + - 1.6 - 1.5.3 - - 1.4.3 services: - redis-server - mysql @@ -19,7 +17,6 @@ before_install: - cd ssdb - make - cd .. - - '[[ $(go version) == *1.[5-9]* ]] && go get github.com/golang/lint/golint' install: - go get github.com/lib/pq - go get github.com/go-sql-driver/mysql @@ -34,6 +31,7 @@ install: - go get github.com/siddontang/ledisdb/ledis - go get golang.org/x/tools/cmd/vet - go get github.com/ssdb/gossdb/ssdb + - go get github.com/golang/lint/golint before_script: - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" - sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi" @@ -45,7 +43,5 @@ after_script: - rm -rf ./res/var/* script: - go vet -x ./... - - '[[ $(go version) == *1.[5-9]* ]] && $HOME/gopath/bin/golint ./...' + - golint ./...' - go test -v ./... -notifications: - webhooks: https://hooks.pubu.im/services/z7m9bvybl3rgtg9 From 630f77bca34c353a713ea6c7d5a475ec41129907 Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 21 Mar 2016 11:18:38 +0800 Subject: [PATCH 040/159] update travis --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d01dc3a9..92d9ac8b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: go go: - 1.6 - 1.5.3 + - 1.4.3 services: - redis-server - mysql @@ -31,11 +32,11 @@ install: - go get github.com/siddontang/ledisdb/ledis - go get golang.org/x/tools/cmd/vet - go get github.com/ssdb/gossdb/ssdb - - go get github.com/golang/lint/golint before_script: - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" - sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi" - sh -c "if [ '$ORM_DRIVER' = 'sqlite' ]; then touch $TRAVIS_BUILD_DIR/orm_test.db; fi" + - sh -c "if [ $(go version) == *1.[5-9]* ]; then go get github.com/golang/lint/golint; golint ./...; fi" - mkdir -p res/var - ./ssdb/ssdb-server ./ssdb/ssdb.conf -d after_script: @@ -43,5 +44,4 @@ after_script: - rm -rf ./res/var/* script: - go vet -x ./... - - golint ./...' - go test -v ./... From 4db78f243e90b1eab3c4b78b6fb186ad0d18cbec Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 22 Mar 2016 16:42:42 +0800 Subject: [PATCH 041/159] change the function args of init gzip method --- context/acceptencoder.go | 15 +++++++-------- hooks.go | 6 +++++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index fc2775ce..1c3cf1d5 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -25,15 +25,13 @@ import ( "strconv" "strings" "sync" - - "github.com/astaxie/beego/config" ) var ( - //Content will only be compressed if content length is either unknown or greater than gzipMinLength. - gzipMinLength int //Default size==20B same as nginx defaultGzipMinLength = 20 + //Content will only be compressed if content length is either unknown or greater than gzipMinLength. + gzipMinLength = defaultGzipMinLength //The compression level used for deflate compression. (0-9). gzipCompressLevel int //List of HTTP methods to compress. If not set, only GET requests are compressed. @@ -41,13 +39,14 @@ var ( getMethodOnly bool ) -func InitGzip(cf config.Configer) { - gzipMinLength = cf.DefaultInt("gzipMinLength", defaultGzipMinLength) - gzipCompressLevel = cf.DefaultInt("gzipCompressLevel", flate.BestSpeed) +func InitGzip(minLength, compressLevel int, methods []string) { + if minLength >= 0 { + gzipMinLength = minLength + } + gzipCompressLevel = compressLevel if gzipCompressLevel < flate.DefaultCompression || gzipCompressLevel > flate.BestCompression { gzipCompressLevel = flate.BestSpeed } - methods := cf.DefaultStrings("includedMethods", []string{"GET"}) getMethodOnly = (len(methods) == 0) || (len(methods) == 1 && strings.ToUpper(methods[0]) == "GET") includedMethods = make(map[string]bool, len(methods)) for _, v := range methods { diff --git a/hooks.go b/hooks.go index 1a7937b5..674f2858 100644 --- a/hooks.go +++ b/hooks.go @@ -95,7 +95,11 @@ func registerAdmin() error { func registerGzip() error { if BConfig.EnableGzip { - context.InitGzip(AppConfig) + context.InitGzip( + AppConfig.DefaultInt("gzipMinLength", -1), + AppConfig.DefaultInt("gzipCompressLevel", -1), + AppConfig.DefaultStrings("includedMethods", []string{"GET"}), + ) } return nil } From 7bad3d1c67f8d3da1ef12071e48e31c2d82f8095 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 22 Mar 2016 16:47:11 +0800 Subject: [PATCH 042/159] change the compress leve to [0~9] --- context/acceptencoder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index 1c3cf1d5..cb735445 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -44,7 +44,7 @@ func InitGzip(minLength, compressLevel int, methods []string) { gzipMinLength = minLength } gzipCompressLevel = compressLevel - if gzipCompressLevel < flate.DefaultCompression || gzipCompressLevel > flate.BestCompression { + if gzipCompressLevel < flate.NoCompression || gzipCompressLevel > flate.BestCompression { gzipCompressLevel = flate.BestSpeed } getMethodOnly = (len(methods) == 0) || (len(methods) == 1 && strings.ToUpper(methods[0]) == "GET") From b2098266a30d58acfffb4542c090eb173783828b Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 22 Mar 2016 18:27:29 +0800 Subject: [PATCH 043/159] add error test --- context/context.go | 1 + error_test.go | 73 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 error_test.go diff --git a/context/context.go b/context/context.go index ab3a3d3f..fee5e1c5 100644 --- a/context/context.go +++ b/context/context.go @@ -77,6 +77,7 @@ func (ctx *Context) Redirect(status int, localurl string) { // Abort stops this request. // if beego.ErrorMaps exists, panic body. func (ctx *Context) Abort(status int, body string) { + ctx.Output.SetStatus(status) panic(body) } diff --git a/error_test.go b/error_test.go new file mode 100644 index 00000000..85b6268d --- /dev/null +++ b/error_test.go @@ -0,0 +1,73 @@ +package beego + +import ( + "net/http" + "net/http/httptest" + "strconv" + "strings" + "testing" +) + +type errorTestController struct { + Controller +} + +func (ec *errorTestController) Get() { + errorCode, err := ec.GetInt("code") + if err != nil { + ec.Abort("parse code error") + } + if errorCode != 0 { + ec.CustomAbort(errorCode, ec.GetString("code")) + } + ec.Abort("404") +} + +func TestErrorCode_01(t *testing.T) { + registerDefaultErrorHandler() + for k, _ := range ErrorMaps { + r, _ := http.NewRequest("GET", "/error?code="+k, nil) + w := httptest.NewRecorder() + + handler := NewControllerRegister() + handler.Add("/error", &errorTestController{}) + handler.ServeHTTP(w, r) + code, _ := strconv.Atoi(k) + if w.Code != code { + t.Fail() + } + if !strings.Contains(string(w.Body.Bytes()), http.StatusText(code)) { + t.Fail() + } + } +} + +func TestErrorCode_02(t *testing.T) { + registerDefaultErrorHandler() + r, _ := http.NewRequest("GET", "/error?code=0", nil) + w := httptest.NewRecorder() + + handler := NewControllerRegister() + handler.Add("/error", &errorTestController{}) + handler.ServeHTTP(w, r) + if w.Code != 404 { + t.Fail() + + } +} + +func TestErrorCode_03(t *testing.T) { + registerDefaultErrorHandler() + r, _ := http.NewRequest("GET", "/error?code=crash", nil) + w := httptest.NewRecorder() + + handler := NewControllerRegister() + handler.Add("/error", &errorTestController{}) + handler.ServeHTTP(w, r) + if w.Code != 200 { + t.Fail() + } + if string(w.Body.Bytes()) != "parse code error" { + t.Fail() + } +} From 1a401af23bd9f5e3e005216abbda8de8966b2846 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 22 Mar 2016 18:28:44 +0800 Subject: [PATCH 044/159] copyright --- error_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/error_test.go b/error_test.go index 85b6268d..713c0a45 100644 --- a/error_test.go +++ b/error_test.go @@ -1,3 +1,17 @@ +// Copyright 2016 beego Author. All Rights Reserved. +// +// 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 beego import ( From 5858607f49000b095506a46255653f586714df5c Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 22 Mar 2016 18:32:14 +0800 Subject: [PATCH 045/159] go fmt error_test.go --- error_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/error_test.go b/error_test.go index 713c0a45..f6e40c80 100644 --- a/error_test.go +++ b/error_test.go @@ -26,10 +26,12 @@ type errorTestController struct { Controller } +const parseCodeError = "parse code error" + func (ec *errorTestController) Get() { errorCode, err := ec.GetInt("code") if err != nil { - ec.Abort("parse code error") + ec.Abort(parseCodeError) } if errorCode != 0 { ec.CustomAbort(errorCode, ec.GetString("code")) @@ -66,13 +68,12 @@ func TestErrorCode_02(t *testing.T) { handler.ServeHTTP(w, r) if w.Code != 404 { t.Fail() - } } func TestErrorCode_03(t *testing.T) { registerDefaultErrorHandler() - r, _ := http.NewRequest("GET", "/error?code=crash", nil) + r, _ := http.NewRequest("GET", "/error?code=panic", nil) w := httptest.NewRecorder() handler := NewControllerRegister() @@ -81,7 +82,7 @@ func TestErrorCode_03(t *testing.T) { if w.Code != 200 { t.Fail() } - if string(w.Body.Bytes()) != "parse code error" { + if string(w.Body.Bytes()) != parseCodeError { t.Fail() } } From 1786b16e61c8763b6ad5f6ff478652182bcb621c Mon Sep 17 00:00:00 2001 From: miraclesu Date: Wed, 23 Mar 2016 20:13:38 +0800 Subject: [PATCH 046/159] orm: support insert a specified value to auto field --- orm/db.go | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/orm/db.go b/orm/db.go index 9ff84411..af05e686 100644 --- a/orm/db.go +++ b/orm/db.go @@ -72,11 +72,11 @@ var _ dbBaser = new(dbBase) // get struct columns values as interface slice. func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string, skipAuto bool, insert bool, names *[]string, tz *time.Location) (values []interface{}, err error) { - var columns []string - - if names != nil { - columns = *names + if names == nil { + ns := make([]string, 0, len(cols)) + names = &ns } + values = make([]interface{}, 0, len(cols)) for _, column := range cols { var fi *fieldInfo @@ -93,15 +93,20 @@ func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string, return nil, err } - if names != nil { - columns = append(columns, column) + // ignore empty value auto field + if fi.auto { + if fi.fieldType&IsPositiveIntegerField > 0 { + if vu, ok := value.(uint64); !ok || vu == 0 { + continue + } + } else { + if vu, ok := value.(int64); !ok || vu == 0 { + continue + } + } } - values = append(values, value) - } - - if names != nil { - *names = columns + *names, values = append(*names, column), append(values, value) } return @@ -349,8 +354,8 @@ func (d *dbBase) Read(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Lo // execute insert sql dbQuerier with given struct reflect.Value. func (d *dbBase) Insert(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Location) (int64, error) { - names := make([]string, 0, len(mi.fields.dbcols)-1) - values, err := d.collectValues(mi, ind, mi.fields.dbcols, true, true, &names, tz) + names := make([]string, 0, len(mi.fields.dbcols)) + values, err := d.collectValues(mi, ind, mi.fields.dbcols, false, true, &names, tz) if err != nil { return 0, err } From 8f70df6c7b6218b5627cc838074e3eb94a9c2fc6 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Wed, 23 Mar 2016 20:28:22 +0800 Subject: [PATCH 047/159] orm: add test case for insert specified value to auto field --- orm/orm_test.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/orm/orm_test.go b/orm/orm_test.go index 832c7301..5ae9a0a4 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -2013,3 +2013,24 @@ func TestIntegerPk(t *testing.T) { throwFail(t, AssertIs(out.Value, intPk.Value)) } } + +func TestInsertAuto(t *testing.T) { + u := &User{ + UserName: "autoPre", + Email: "autoPre@gmail.com", + } + + id, err := dORM.Insert(u) + throwFail(t, err) + + id += 100 + su := &User{ + ID: int(id), + UserName: "auto", + Email: "auto@gmail.com", + } + + sid, err := dORM.Insert(su) + throwFail(t, err) + throwFail(t, AssertIs(id, sid)) +} From 1eab11ca900538d85e2af0260e1ba70e22721d0b Mon Sep 17 00:00:00 2001 From: ysqi Date: Wed, 23 Mar 2016 21:27:28 +0800 Subject: [PATCH 048/159] fixed #1815 check file before download --- context/output.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/context/output.go b/context/output.go index ea5498c0..0de3085c 100644 --- a/context/output.go +++ b/context/output.go @@ -24,6 +24,7 @@ import ( "io" "mime" "net/http" + "os" "path/filepath" "strconv" "strings" @@ -237,6 +238,13 @@ func (output *BeegoOutput) XML(data interface{}, hasIndent bool) error { // Download forces response for download file. // it prepares the download response header automatically. func (output *BeegoOutput) Download(file string, filename ...string) { + + // check get file error, file not found or other error. + if _, err := os.Stat(file); err != nil { + http.ServeFile(output.Context.ResponseWriter, output.Context.Request, file) + return + } + output.Header("Content-Description", "File Transfer") output.Header("Content-Type", "application/octet-stream") if len(filename) > 0 && filename[0] != "" { From 3be6688cd1f8b178f2e7f80e67f7e50d81b53b61 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Wed, 23 Mar 2016 21:18:54 +0800 Subject: [PATCH 049/159] orm: fix painc when pk is uint on ReadOrCreate --- orm/orm.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/orm/orm.go b/orm/orm.go index 38c89334..26ebb7c1 100644 --- a/orm/orm.go +++ b/orm/orm.go @@ -140,7 +140,14 @@ func (o *orm) ReadOrCreate(md interface{}, col1 string, cols ...string) (bool, i return (err == nil), id, err } - return false, ind.FieldByIndex(mi.fields.pk.fieldIndex).Int(), err + id, vid := int64(0), ind.FieldByIndex(mi.fields.pk.fieldIndex) + if mi.fields.pk.fieldType&IsPostiveIntegerField > 0 { + id = int64(vid.Uint()) + } else { + id = vid.Int() + } + + return false, id, err } // insert model data to database From eaf38bb09605106db60365efdfa70a6ac873419d Mon Sep 17 00:00:00 2001 From: miraclesu Date: Wed, 23 Mar 2016 21:32:52 +0800 Subject: [PATCH 050/159] orm: add test case for uint pk read or create --- orm/models_test.go | 5 +++++ orm/orm.go | 2 +- orm/orm_test.go | 25 +++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/orm/models_test.go b/orm/models_test.go index b6ae21cf..f42d725e 100644 --- a/orm/models_test.go +++ b/orm/models_test.go @@ -392,6 +392,11 @@ type IntegerPk struct { Value string } +type UintPk struct { + Id uint32 `orm:"pk"` + Name string +} + var DBARGS = struct { Driver string Source string diff --git a/orm/orm.go b/orm/orm.go index 26ebb7c1..6f4b7731 100644 --- a/orm/orm.go +++ b/orm/orm.go @@ -141,7 +141,7 @@ func (o *orm) ReadOrCreate(md interface{}, col1 string, cols ...string) (bool, i } id, vid := int64(0), ind.FieldByIndex(mi.fields.pk.fieldIndex) - if mi.fields.pk.fieldType&IsPostiveIntegerField > 0 { + if mi.fields.pk.fieldType&IsPositiveIntegerField > 0 { id = int64(vid.Uint()) } else { id = vid.Int() diff --git a/orm/orm_test.go b/orm/orm_test.go index 832c7301..0c827c2a 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -191,6 +191,7 @@ func TestSyncDb(t *testing.T) { RegisterModel(new(InLine)) RegisterModel(new(InLineOneToOne)) RegisterModel(new(IntegerPk)) + RegisterModel(new(UintPk)) err := RunSyncdb("default", true, Debug) throwFail(t, err) @@ -213,6 +214,7 @@ func TestRegisterModels(t *testing.T) { RegisterModel(new(InLine)) RegisterModel(new(InLineOneToOne)) RegisterModel(new(IntegerPk)) + RegisterModel(new(UintPk)) BootStrap() @@ -2013,3 +2015,26 @@ func TestIntegerPk(t *testing.T) { throwFail(t, AssertIs(out.Value, intPk.Value)) } } + +func TestUintPk(t *testing.T) { + name := "go" + u := &UintPk{ + Id: 8, + Name: name, + } + + created, pk, err := dORM.ReadOrCreate(u, "Id") + throwFail(t, err) + throwFail(t, AssertIs(created, true)) + throwFail(t, AssertIs(u.Name, name)) + + nu := &UintPk{Id: 8} + created, pk, err = dORM.ReadOrCreate(nu, "Id") + throwFail(t, err) + throwFail(t, AssertIs(created, false)) + throwFail(t, AssertIs(nu.Id, u.Id)) + throwFail(t, AssertIs(pk, u.Id)) + throwFail(t, AssertIs(nu.Name, name)) + + dORM.Delete(u) +} From b7d1afbf86117a5e85dcddf390ef62d3c850f854 Mon Sep 17 00:00:00 2001 From: YuShuangqi Date: Thu, 24 Mar 2016 08:35:42 +0800 Subject: [PATCH 051/159] Remote empty line --- context/output.go | 1 - 1 file changed, 1 deletion(-) diff --git a/context/output.go b/context/output.go index 0de3085c..3568d89c 100644 --- a/context/output.go +++ b/context/output.go @@ -238,7 +238,6 @@ func (output *BeegoOutput) XML(data interface{}, hasIndent bool) error { // Download forces response for download file. // it prepares the download response header automatically. func (output *BeegoOutput) Download(file string, filename ...string) { - // check get file error, file not found or other error. if _, err := os.Stat(file); err != nil { http.ServeFile(output.Context.ResponseWriter, output.Context.Request, file) From 2e6a23743b73cd514411c0c647dbdb6acfd9753b Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 24 Mar 2016 17:37:56 +0800 Subject: [PATCH 052/159] refactor logs package --- logs/log.go | 178 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 167 insertions(+), 11 deletions(-) diff --git a/logs/log.go b/logs/log.go index 583b35e0..1ec7dd1d 100644 --- a/logs/log.go +++ b/logs/log.go @@ -35,10 +35,12 @@ package logs import ( "fmt" + "log" "os" "path" "runtime" "strconv" + "strings" "sync" "time" ) @@ -55,6 +57,15 @@ const ( LevelDebug ) +const ( + AdapterConsole = "console" + AdapterFile = "file" + AdapterMultiFile = "multifile" + AdapterMail = "stmp" + AdapterConn = "conn" + AdaterEs = "es" +) + // Legacy loglevel constants to ensure backwards compatibility. // // Deprecated: will be removed in 1.5.0. @@ -94,6 +105,7 @@ func Register(name string, log loggerType) { type BeeLogger struct { lock sync.Mutex level int + msgChanLen int64 enableFuncCallDepth bool loggerFuncCallDepth int asynchronous bool @@ -119,11 +131,14 @@ var logMsgPool *sync.Pool // NewLogger returns a new BeeLogger. // channelLen means the number of messages in chan(used where asynchronous is true). // if the buffering chan is full, logger adapters write to file or other way. -func NewLogger(channelLen int64) *BeeLogger { +func NewLogger(channelLens ...int64) *BeeLogger { bl := new(BeeLogger) bl.level = LevelDebug bl.loggerFuncCallDepth = 2 - bl.msgChan = make(chan *logMsg, channelLen) + bl.msgChanLen = append(channelLens, 0)[0] + if bl.msgChanLen < 0 { + bl.msgChanLen = 0 + } bl.signalChan = make(chan string, 1) return bl } @@ -131,6 +146,7 @@ func NewLogger(channelLen int64) *BeeLogger { // Async set the log to asynchronous and start the goroutine func (bl *BeeLogger) Async() *BeeLogger { bl.asynchronous = true + bl.msgChan = make(chan *logMsg, bl.msgChanLen) logMsgPool = &sync.Pool{ New: func() interface{} { return &logMsg{} @@ -143,7 +159,8 @@ func (bl *BeeLogger) Async() *BeeLogger { // SetLogger provides a given logger adapter into BeeLogger with config string. // config need to be correct JSON as string: {"interval":360}. -func (bl *BeeLogger) SetLogger(adapterName string, config string) error { +func (bl *BeeLogger) SetLogger(adapterName string, configs ...string) error { + config := append(configs, "{}")[0] bl.lock.Lock() defer bl.lock.Unlock() @@ -402,6 +419,7 @@ func (bl *BeeLogger) Close() { if bl.asynchronous { bl.signalChan <- "close" bl.wg.Wait() + close(bl.msgChan) } else { bl.flush() for _, l := range bl.outputs { @@ -409,7 +427,6 @@ func (bl *BeeLogger) Close() { } bl.outputs = nil } - close(bl.msgChan) close(bl.signalChan) } @@ -423,16 +440,155 @@ func (bl *BeeLogger) Reset() { } func (bl *BeeLogger) flush() { - for { - if len(bl.msgChan) > 0 { - bm := <-bl.msgChan - bl.writeToLoggers(bm.when, bm.msg, bm.level) - logMsgPool.Put(bm) - continue + if bl.asynchronous { + for { + if len(bl.msgChan) > 0 { + bm := <-bl.msgChan + bl.writeToLoggers(bm.when, bm.msg, bm.level) + logMsgPool.Put(bm) + continue + } + break } - break } for _, l := range bl.outputs { l.Flush() } } + +// BeeLogger references the used application logger. +var beeLogger = NewLogger(100) + +// GetLogger returns the default BeeLogger +func GetBeeLogger() *BeeLogger { + return beeLogger +} + +var beeLoggerMap = struct { + sync.RWMutex + logs map[string]*log.Logger +}{ + logs: map[string]*log.Logger{}, +} + +// GetLogger returns the default BeeLogger +func GetLogger(prefixes ...string) *log.Logger { + prefix := append(prefixes, "")[0] + if prefix != "" { + prefix = fmt.Sprintf(`[%s] `, prefix) + } + beeLoggerMap.RLock() + l, ok := beeLoggerMap.logs[prefix] + if ok { + beeLoggerMap.RUnlock() + return l + } + beeLoggerMap.RUnlock() + beeLoggerMap.Lock() + defer beeLoggerMap.Unlock() + l, ok = beeLoggerMap.logs[prefix] + if !ok { + l = log.New(beeLogger, prefix, 0) + beeLoggerMap.logs[prefix] = l + } + return l +} + +// Reset will remove all the adapter +func Reset() { + beeLogger.Reset() +} + +// SetLevel sets the global log level used by the simple logger. +func SetLevel(l int) { + beeLogger.SetLevel(l) +} + +// SetLogFuncCall set the CallDepth, default is 3 +func SetLogFuncCall(b bool) { + beeLogger.EnableFuncCallDepth(b) + beeLogger.SetLogFuncCallDepth(3) +} + +// SetLogger sets a new logger. +func SetLogger(adaptername string, config string) error { + err := beeLogger.SetLogger(adaptername, config) + if err != nil { + return err + } + return nil +} + +// Emergency logs a message at emergency level. +func Emergency(f interface{}, v ...interface{}) { + beeLogger.Emergency(logf(f, v...)) +} + +// Alert logs a message at alert level. +func Alert(f interface{}, v ...interface{}) { + beeLogger.Alert(logf(f, v...)) +} + +// Critical logs a message at critical level. +func Critical(f interface{}, v ...interface{}) { + beeLogger.Critical(logf(f, v...)) +} + +// Error logs a message at error level. +func Error(f interface{}, v ...interface{}) { + beeLogger.Error(logf(f, v...)) +} + +// Warning logs a message at warning level. +func Warning(f interface{}, v ...interface{}) { + beeLogger.Warning(logf(f, v...)) +} + +// Warn compatibility alias for Warning() +func Warn(f interface{}, v ...interface{}) { + beeLogger.Warn(logf(f, v...)) +} + +// Notice logs a message at notice level. +func Notice(f interface{}, v ...interface{}) { + beeLogger.Notice(logf(f, v...)) +} + +// Informational logs a message at info level. +func Informational(f interface{}, v ...interface{}) { + beeLogger.Informational(logf(f, v...)) +} + +// Info compatibility alias for Warning() +func Info(f interface{}, v ...interface{}) { + fmt.Print() + beeLogger.Info(logf(f, v...)) +} + +// Debug logs a message at debug level. +func Debug(f interface{}, v ...interface{}) { + beeLogger.Debug(logf(f, v...)) +} + +// Trace logs a message at trace level. +// compatibility alias for Warning() +func Trace(f interface{}, v ...interface{}) { + beeLogger.Trace(logf(f, v...)) +} + +func logf(f interface{}, v ...interface{}) string { + var msg string + switch f.(type) { + case string: + msg = f.(string) + if strings.Contains(msg, "%") && !strings.Contains(msg, "%%") { + //format string + } else { + //do not contain format char + msg += strings.Repeat(" %v", len(v)) + } + default: + msg = fmt.Sprint(f) + strings.Repeat(" %v", len(v)) + } + return fmt.Sprintf(msg, v...) +} From 03840f3fe88cb9ca9f3c59045adfd730acc07564 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 24 Mar 2016 17:38:26 +0800 Subject: [PATCH 053/159] give each of the adapter a neme --- logs/conn.go | 2 +- logs/console.go | 2 +- logs/es/es.go | 2 +- logs/file.go | 2 +- logs/multifile.go | 2 +- logs/smtp.go | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/logs/conn.go b/logs/conn.go index 1db1a427..6d5bf6bf 100644 --- a/logs/conn.go +++ b/logs/conn.go @@ -113,5 +113,5 @@ func (c *connWriter) needToConnectOnMsg() bool { } func init() { - Register("conn", NewConn) + Register(AdapterConn, NewConn) } diff --git a/logs/console.go b/logs/console.go index dc41dd7d..e6bf6c29 100644 --- a/logs/console.go +++ b/logs/console.go @@ -97,5 +97,5 @@ func (c *consoleWriter) Flush() { } func init() { - Register("console", NewConsole) + Register(AdapterConsole, NewConsole) } diff --git a/logs/es/es.go b/logs/es/es.go index 397ca2ef..ceebe71a 100644 --- a/logs/es/es.go +++ b/logs/es/es.go @@ -76,5 +76,5 @@ func (el *esLogger) Flush() { } func init() { - logs.Register("es", NewES) + logs.Register(logs.AdaterEs, NewES) } diff --git a/logs/file.go b/logs/file.go index 672823fa..159d4970 100644 --- a/logs/file.go +++ b/logs/file.go @@ -282,5 +282,5 @@ func (w *fileLogWriter) Flush() { } func init() { - Register("file", newFileWriter) + Register(AdapterFile, newFileWriter) } diff --git a/logs/multifile.go b/logs/multifile.go index b82ba274..63204e17 100644 --- a/logs/multifile.go +++ b/logs/multifile.go @@ -112,5 +112,5 @@ func newFilesWriter() Logger { } func init() { - Register("multifile", newFilesWriter) + Register(AdapterMultiFile, newFilesWriter) } diff --git a/logs/smtp.go b/logs/smtp.go index 47f5a0c6..834130ef 100644 --- a/logs/smtp.go +++ b/logs/smtp.go @@ -156,5 +156,5 @@ func (s *SMTPWriter) Destroy() { } func init() { - Register("smtp", newSMTPWriter) + Register(AdapterMail, newSMTPWriter) } From 98dfecfd8a0de2c6e2852bf019d7a01bc21b88cc Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 24 Mar 2016 17:39:29 +0800 Subject: [PATCH 054/159] change beego log function to logs function --- admin.go | 5 ++- app.go | 28 ++++++------ config.go | 7 +-- hooks.go | 3 +- log.go | 116 -------------------------------------------------- parser.go | 5 ++- router.go | 17 ++++---- staticfile.go | 5 ++- template.go | 9 ++-- 9 files changed, 43 insertions(+), 152 deletions(-) delete mode 100644 log.go diff --git a/admin.go b/admin.go index cf5bc63a..94fa55b9 100644 --- a/admin.go +++ b/admin.go @@ -24,6 +24,7 @@ import ( "time" "github.com/astaxie/beego/grace" + "github.com/astaxie/beego/logs" "github.com/astaxie/beego/toolbox" "github.com/astaxie/beego/utils" ) @@ -410,7 +411,7 @@ func (admin *adminApp) Run() { for p, f := range admin.routers { http.Handle(p, f) } - BeeLogger.Info("Admin server Running on %s", addr) + logs.Info("Admin server Running on %s", addr) var err error if BConfig.Listen.Graceful { @@ -419,6 +420,6 @@ func (admin *adminApp) Run() { err = http.ListenAndServe(addr, nil) } if err != nil { - BeeLogger.Critical("Admin ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid())) + logs.Critical("Admin ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid())) } } diff --git a/app.go b/app.go index a065670a..77116a81 100644 --- a/app.go +++ b/app.go @@ -16,7 +16,6 @@ package beego import ( "fmt" - "log" "net" "net/http" "net/http/fcgi" @@ -25,6 +24,7 @@ import ( "time" "github.com/astaxie/beego/grace" + "github.com/astaxie/beego/logs" "github.com/astaxie/beego/utils" ) @@ -69,9 +69,9 @@ func (app *App) Run() { if BConfig.Listen.EnableFcgi { if BConfig.Listen.EnableStdIo { if err = fcgi.Serve(nil, app.Handlers); err == nil { // standard I/O - BeeLogger.Info("Use FCGI via standard I/O") + logs.Info("Use FCGI via standard I/O") } else { - BeeLogger.Critical("Cannot use FCGI via standard I/O", err) + logs.Critical("Cannot use FCGI via standard I/O", err) } return } @@ -85,10 +85,10 @@ func (app *App) Run() { l, err = net.Listen("tcp", addr) } if err != nil { - BeeLogger.Critical("Listen: ", err) + logs.Critical("Listen: ", err) } if err = fcgi.Serve(l, app.Handlers); err != nil { - BeeLogger.Critical("fcgi.Serve: ", err) + logs.Critical("fcgi.Serve: ", err) } return } @@ -96,7 +96,7 @@ func (app *App) Run() { app.Server.Handler = app.Handlers app.Server.ReadTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second app.Server.WriteTimeout = time.Duration(BConfig.Listen.ServerTimeOut) * time.Second - app.Server.ErrorLog = log.New(BeeLogger, "", 0) + app.Server.ErrorLog = logs.GetLogger("HTTP") // run graceful mode if BConfig.Listen.Graceful { @@ -113,7 +113,7 @@ func (app *App) Run() { server.Server.ReadTimeout = app.Server.ReadTimeout server.Server.WriteTimeout = app.Server.WriteTimeout if err := server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil { - BeeLogger.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid())) + logs.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid())) time.Sleep(100 * time.Microsecond) endRunning <- true } @@ -128,7 +128,7 @@ func (app *App) Run() { server.Network = "tcp4" } if err := server.ListenAndServe(); err != nil { - BeeLogger.Critical("ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid())) + logs.Critical("ListenAndServe: ", err, fmt.Sprintf("%d", os.Getpid())) time.Sleep(100 * time.Microsecond) endRunning <- true } @@ -146,9 +146,9 @@ func (app *App) Run() { if BConfig.Listen.HTTPSPort != 0 { app.Server.Addr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPSAddr, BConfig.Listen.HTTPSPort) } - BeeLogger.Info("https server Running on %s", app.Server.Addr) + logs.Info("https server Running on %s", app.Server.Addr) if err := app.Server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil { - BeeLogger.Critical("ListenAndServeTLS: ", err) + logs.Critical("ListenAndServeTLS: ", err) time.Sleep(100 * time.Microsecond) endRunning <- true } @@ -157,24 +157,24 @@ func (app *App) Run() { if BConfig.Listen.EnableHTTP { go func() { app.Server.Addr = addr - BeeLogger.Info("http server Running on %s", app.Server.Addr) + logs.Info("http server Running on %s", app.Server.Addr) if BConfig.Listen.ListenTCP4 { ln, err := net.Listen("tcp4", app.Server.Addr) if err != nil { - BeeLogger.Critical("ListenAndServe: ", err) + logs.Critical("ListenAndServe: ", err) time.Sleep(100 * time.Microsecond) endRunning <- true return } if err = app.Server.Serve(ln); err != nil { - BeeLogger.Critical("ListenAndServe: ", err) + logs.Critical("ListenAndServe: ", err) time.Sleep(100 * time.Microsecond) endRunning <- true return } } else { if err := app.Server.ListenAndServe(); err != nil { - BeeLogger.Critical("ListenAndServe: ", err) + logs.Critical("ListenAndServe: ", err) time.Sleep(100 * time.Microsecond) endRunning <- true } diff --git a/config.go b/config.go index f0316a62..72045fd3 100644 --- a/config.go +++ b/config.go @@ -21,6 +21,7 @@ import ( "strings" "github.com/astaxie/beego/config" + "github.com/astaxie/beego/logs" "github.com/astaxie/beego/session" "github.com/astaxie/beego/utils" ) @@ -293,14 +294,14 @@ func parseConfig(appConfigPath string) (err error) { } //init log - BeeLogger.Reset() + logs.Reset() for adaptor, config := range BConfig.Log.Outputs { - err = BeeLogger.SetLogger(adaptor, config) + err = logs.SetLogger(adaptor, config) if err != nil { fmt.Printf("%s with the config `%s` got err:%s\n", adaptor, config, err) } } - SetLogFuncCall(BConfig.Log.FileLineNum) + logs.SetLogFuncCall(BConfig.Log.FileLineNum) return nil } diff --git a/hooks.go b/hooks.go index 674f2858..3d784467 100644 --- a/hooks.go +++ b/hooks.go @@ -7,6 +7,7 @@ import ( "path/filepath" "github.com/astaxie/beego/context" + "github.com/astaxie/beego/logs" "github.com/astaxie/beego/session" ) @@ -71,7 +72,7 @@ func registerSession() error { func registerTemplate() error { if err := BuildTemplate(BConfig.WebConfig.ViewsPath); err != nil { if BConfig.RunMode == DEV { - Warn(err) + logs.Warn(err) } return err } diff --git a/log.go b/log.go deleted file mode 100644 index 46ec57dd..00000000 --- a/log.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2014 beego Author. All Rights Reserved. -// -// 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 beego - -import ( - "strings" - - "github.com/astaxie/beego/logs" -) - -// Log levels to control the logging output. -const ( - LevelEmergency = iota - LevelAlert - LevelCritical - LevelError - LevelWarning - LevelNotice - LevelInformational - LevelDebug -) - -// BeeLogger references the used application logger. -var BeeLogger = logs.NewLogger(100) - -// SetLevel sets the global log level used by the simple logger. -func SetLevel(l int) { - BeeLogger.SetLevel(l) -} - -// SetLogFuncCall set the CallDepth, default is 3 -func SetLogFuncCall(b bool) { - BeeLogger.EnableFuncCallDepth(b) - BeeLogger.SetLogFuncCallDepth(3) -} - -// SetLogger sets a new logger. -func SetLogger(adaptername string, config string) error { - err := BeeLogger.SetLogger(adaptername, config) - if err != nil { - return err - } - return nil -} - -// Emergency logs a message at emergency level. -func Emergency(v ...interface{}) { - BeeLogger.Emergency(generateFmtStr(len(v)), v...) -} - -// Alert logs a message at alert level. -func Alert(v ...interface{}) { - BeeLogger.Alert(generateFmtStr(len(v)), v...) -} - -// Critical logs a message at critical level. -func Critical(v ...interface{}) { - BeeLogger.Critical(generateFmtStr(len(v)), v...) -} - -// Error logs a message at error level. -func Error(v ...interface{}) { - BeeLogger.Error(generateFmtStr(len(v)), v...) -} - -// Warning logs a message at warning level. -func Warning(v ...interface{}) { - BeeLogger.Warning(generateFmtStr(len(v)), v...) -} - -// Warn compatibility alias for Warning() -func Warn(v ...interface{}) { - BeeLogger.Warn(generateFmtStr(len(v)), v...) -} - -// Notice logs a message at notice level. -func Notice(v ...interface{}) { - BeeLogger.Notice(generateFmtStr(len(v)), v...) -} - -// Informational logs a message at info level. -func Informational(v ...interface{}) { - BeeLogger.Informational(generateFmtStr(len(v)), v...) -} - -// Info compatibility alias for Warning() -func Info(v ...interface{}) { - BeeLogger.Info(generateFmtStr(len(v)), v...) -} - -// Debug logs a message at debug level. -func Debug(v ...interface{}) { - BeeLogger.Debug(generateFmtStr(len(v)), v...) -} - -// Trace logs a message at trace level. -// compatibility alias for Warning() -func Trace(v ...interface{}) { - BeeLogger.Trace(generateFmtStr(len(v)), v...) -} - -func generateFmtStr(n int) string { - return strings.Repeat("%v ", n) -} diff --git a/parser.go b/parser.go index 46d02320..24f7549b 100644 --- a/parser.go +++ b/parser.go @@ -27,6 +27,7 @@ import ( "sort" "strings" + "github.com/astaxie/beego/logs" "github.com/astaxie/beego/utils" ) @@ -58,7 +59,7 @@ func parserPkg(pkgRealpath, pkgpath string) error { rep := strings.NewReplacer("/", "_", ".", "_") commentFilename = coomentPrefix + rep.Replace(pkgpath) + ".go" if !compareFile(pkgRealpath) { - Info(pkgRealpath + " no changed") + logs.Info(pkgRealpath + " no changed") return nil } genInfoList = make(map[string][]ControllerComments) @@ -131,7 +132,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat func genRouterCode() { os.Mkdir(path.Join(AppPath, "routers"), 0755) - Info("generate router from comments") + logs.Info("generate router from comments") var ( globalinfo string sortKey []string diff --git a/router.go b/router.go index 5516ecda..960cd104 100644 --- a/router.go +++ b/router.go @@ -28,6 +28,7 @@ import ( "time" beecontext "github.com/astaxie/beego/context" + "github.com/astaxie/beego/logs" "github.com/astaxie/beego/toolbox" "github.com/astaxie/beego/utils" ) @@ -439,11 +440,11 @@ func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) (err func (p *ControllerRegister) URLFor(endpoint string, values ...interface{}) string { paths := strings.Split(endpoint, ".") if len(paths) <= 1 { - Warn("urlfor endpoint must like path.controller.method") + logs.Warn("urlfor endpoint must like path.controller.method") return "" } if len(values)%2 != 0 { - Warn("urlfor params must key-value pair") + logs.Warn("urlfor params must key-value pair") return "" } params := make(map[string]string) @@ -651,7 +652,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) var err error context.Input.CruSession, err = GlobalSessions.SessionStart(rw, r) if err != nil { - Error(err) + logs.Error(err) exception("503", context) goto Admin } @@ -780,7 +781,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) if !context.ResponseWriter.Started && context.Output.Status == 0 { if BConfig.WebConfig.AutoRender { if err := execController.Render(); err != nil { - Error(err) + logs.Error(err) } } } @@ -825,7 +826,7 @@ Admin: devInfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeDur.String(), "notmatch") } if DefaultAccessLogFilter == nil || !DefaultAccessLogFilter.Filter(context) { - Debug(devInfo) + logs.Debug(devInfo) } } @@ -850,14 +851,14 @@ func (p *ControllerRegister) recoverPanic(context *beecontext.Context) { } } var stack string - Critical("the request url is ", context.Input.URL()) - Critical("Handler crashed with error", err) + logs.Critical("the request url is ", context.Input.URL()) + logs.Critical("Handler crashed with error", err) for i := 1; ; i++ { _, file, line, ok := runtime.Caller(i) if !ok { break } - Critical(fmt.Sprintf("%s:%d", file, line)) + logs.Critical(fmt.Sprintf("%s:%d", file, line)) stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line)) } if BConfig.RunMode == DEV { diff --git a/staticfile.go b/staticfile.go index 1cd75b8c..8a1bc57b 100644 --- a/staticfile.go +++ b/staticfile.go @@ -27,6 +27,7 @@ import ( "time" "github.com/astaxie/beego/context" + "github.com/astaxie/beego/logs" ) var errNotStaticRequest = errors.New("request not a static file request") @@ -48,7 +49,7 @@ func serverStaticRouter(ctx *context.Context) { if filePath == "" || fileInfo == nil { if BConfig.RunMode == DEV { - Warn("Can't find/open the file:", filePath, err) + logs.Warn("Can't find/open the file:", filePath, err) } http.NotFound(ctx.ResponseWriter, ctx.Request) return @@ -72,7 +73,7 @@ func serverStaticRouter(ctx *context.Context) { b, n, sch, err := openFile(filePath, fileInfo, acceptEncoding) if err != nil { if BConfig.RunMode == DEV { - Warn("Can't compress the file:", filePath, err) + logs.Warn("Can't compress the file:", filePath, err) } http.NotFound(ctx.ResponseWriter, ctx.Request) return diff --git a/template.go b/template.go index e6c43f87..a7c719e8 100644 --- a/template.go +++ b/template.go @@ -26,6 +26,7 @@ import ( "strings" "sync" + "github.com/astaxie/beego/logs" "github.com/astaxie/beego/utils" ) @@ -46,7 +47,7 @@ func executeTemplate(wr io.Writer, name string, data interface{}) error { if t, ok := beeTemplates[name]; ok { err := t.ExecuteTemplate(wr, name, data) if err != nil { - Trace("template Execute err:", err) + logs.Trace("template Execute err:", err) } return err } @@ -162,7 +163,7 @@ func BuildTemplate(dir string, files ...string) error { templatesLock.Lock() t, err := getTemplate(self.root, file, v...) if err != nil { - Trace("parse template err:", file, err) + logs.Trace("parse template err:", file, err) } else { beeTemplates[file] = t } @@ -240,7 +241,7 @@ func _getTemplate(t0 *template.Template, root string, subMods [][]string, others var subMods1 [][]string t, subMods1, err = getTplDeep(root, otherFile, "", t) if err != nil { - Trace("template parse file err:", err) + logs.Trace("template parse file err:", err) } else if subMods1 != nil && len(subMods1) > 0 { t, err = _getTemplate(t, root, subMods1, others...) } @@ -261,7 +262,7 @@ func _getTemplate(t0 *template.Template, root string, subMods [][]string, others var subMods1 [][]string t, subMods1, err = getTplDeep(root, otherFile, "", t) if err != nil { - Trace("template parse file err:", err) + logs.Trace("template parse file err:", err) } else if subMods1 != nil && len(subMods1) > 0 { t, err = _getTemplate(t, root, subMods1, others...) } From cdfd830f659e210ec4ed3e70c72dedbef8ec8736 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 24 Mar 2016 17:43:16 +0800 Subject: [PATCH 055/159] rename log format --- logs/log.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/logs/log.go b/logs/log.go index 1ec7dd1d..44bcfac1 100644 --- a/logs/log.go +++ b/logs/log.go @@ -521,62 +521,62 @@ func SetLogger(adaptername string, config string) error { // Emergency logs a message at emergency level. func Emergency(f interface{}, v ...interface{}) { - beeLogger.Emergency(logf(f, v...)) + beeLogger.Emergency(formatLog(f, v...)) } // Alert logs a message at alert level. func Alert(f interface{}, v ...interface{}) { - beeLogger.Alert(logf(f, v...)) + beeLogger.Alert(formatLog(f, v...)) } // Critical logs a message at critical level. func Critical(f interface{}, v ...interface{}) { - beeLogger.Critical(logf(f, v...)) + beeLogger.Critical(formatLog(f, v...)) } // Error logs a message at error level. func Error(f interface{}, v ...interface{}) { - beeLogger.Error(logf(f, v...)) + beeLogger.Error(formatLog(f, v...)) } // Warning logs a message at warning level. func Warning(f interface{}, v ...interface{}) { - beeLogger.Warning(logf(f, v...)) + beeLogger.Warning(formatLog(f, v...)) } // Warn compatibility alias for Warning() func Warn(f interface{}, v ...interface{}) { - beeLogger.Warn(logf(f, v...)) + beeLogger.Warn(formatLog(f, v...)) } // Notice logs a message at notice level. func Notice(f interface{}, v ...interface{}) { - beeLogger.Notice(logf(f, v...)) + beeLogger.Notice(formatLog(f, v...)) } // Informational logs a message at info level. func Informational(f interface{}, v ...interface{}) { - beeLogger.Informational(logf(f, v...)) + beeLogger.Informational(formatLog(f, v...)) } // Info compatibility alias for Warning() func Info(f interface{}, v ...interface{}) { fmt.Print() - beeLogger.Info(logf(f, v...)) + beeLogger.Info(formatLog(f, v...)) } // Debug logs a message at debug level. func Debug(f interface{}, v ...interface{}) { - beeLogger.Debug(logf(f, v...)) + beeLogger.Debug(formatLog(f, v...)) } // Trace logs a message at trace level. // compatibility alias for Warning() func Trace(f interface{}, v ...interface{}) { - beeLogger.Trace(logf(f, v...)) + beeLogger.Trace(formatLog(f, v...)) } -func logf(f interface{}, v ...interface{}) string { +func formatLog(f interface{}, v ...interface{}) string { var msg string switch f.(type) { case string: From a6c1377f91add359dd281405e2d7d297485f441e Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 24 Mar 2016 17:43:45 +0800 Subject: [PATCH 056/159] change to 0 logger --- logs/log.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logs/log.go b/logs/log.go index 44bcfac1..cdd82a02 100644 --- a/logs/log.go +++ b/logs/log.go @@ -457,7 +457,7 @@ func (bl *BeeLogger) flush() { } // BeeLogger references the used application logger. -var beeLogger = NewLogger(100) +var beeLogger = NewLogger() // GetLogger returns the default BeeLogger func GetBeeLogger() *BeeLogger { From 0fb4a8af24a788c5d8ba9731ee5f19b9f5815214 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 24 Mar 2016 17:46:52 +0800 Subject: [PATCH 057/159] function change --- logs/log.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logs/log.go b/logs/log.go index cdd82a02..67bf2a73 100644 --- a/logs/log.go +++ b/logs/log.go @@ -511,8 +511,8 @@ func SetLogFuncCall(b bool) { } // SetLogger sets a new logger. -func SetLogger(adaptername string, config string) error { - err := beeLogger.SetLogger(adaptername, config) +func SetLogger(adapter string, config ...string) error { + err := beeLogger.SetLogger(adapter, config...) if err != nil { return err } From 8344a60552bd010385cc208157a215e6cb253705 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 24 Mar 2016 17:49:39 +0800 Subject: [PATCH 058/159] add to upper case --- logs/log.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logs/log.go b/logs/log.go index 67bf2a73..7b65dbc3 100644 --- a/logs/log.go +++ b/logs/log.go @@ -475,7 +475,7 @@ var beeLoggerMap = struct { func GetLogger(prefixes ...string) *log.Logger { prefix := append(prefixes, "")[0] if prefix != "" { - prefix = fmt.Sprintf(`[%s] `, prefix) + prefix = fmt.Sprintf(`[%s] `, strings.ToUpper(prefix)) } beeLoggerMap.RLock() l, ok := beeLoggerMap.logs[prefix] From 0814eefa6293f21f487ebe3e3085b844435d9053 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 24 Mar 2016 18:21:52 +0800 Subject: [PATCH 059/159] refactor writeMsg function --- logs/es/es.go | 2 +- logs/log.go | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/logs/es/es.go b/logs/es/es.go index ceebe71a..22f4f650 100644 --- a/logs/es/es.go +++ b/logs/es/es.go @@ -76,5 +76,5 @@ func (el *esLogger) Flush() { } func init() { - logs.Register(logs.AdaterEs, NewES) + logs.Register(logs.AdapterEs, NewES) } diff --git a/logs/log.go b/logs/log.go index 7b65dbc3..32e441f4 100644 --- a/logs/log.go +++ b/logs/log.go @@ -56,14 +56,16 @@ const ( LevelInformational LevelDebug ) +const levelCustom = -1 +// Name for adapter with beego official support const ( AdapterConsole = "console" AdapterFile = "file" AdapterMultiFile = "multifile" AdapterMail = "stmp" AdapterConn = "conn" - AdaterEs = "es" + AdapterEs = "es" ) // Legacy loglevel constants to ensure backwards compatibility. @@ -75,7 +77,7 @@ const ( LevelWarn = LevelWarning ) -type loggerType func() Logger +type newLoggerFunc func() Logger // Logger defines the behavior of a log provider. type Logger interface { @@ -85,12 +87,13 @@ type Logger interface { Flush() } -var adapters = make(map[string]loggerType) +var adapters = make(map[string]newLoggerFunc) +var levelPrefix = [LevelDebug + 1]string{"[M] ", "[A] ", "[C] ", "[E] ", "[W] ", "[N] ", "[I] ", "[D] "} // Register makes a log provide available by the provided name. // If Register is called twice with the same name or if driver is nil, // it panics. -func Register(name string, log loggerType) { +func Register(name string, log newLoggerFunc) { if log == nil { panic("logs: Register provide is nil") } @@ -222,14 +225,18 @@ func (bl *BeeLogger) Write(p []byte) (n int, err error) { p = p[0 : len(p)-1] } // set LevelCritical to ensure all log message will be write out - err = bl.writeMsg(LevelCritical, string(p)) + err = bl.writeMsg(levelCustom, string(p)) if err == nil { return len(p), err } return 0, err } -func (bl *BeeLogger) writeMsg(logLevel int, msg string) error { +func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error { + if logLevel != levelCustom { + msg = levelPrefix[logLevel] + msg + } + msg = fmt.Sprintf(msg, v...) when := time.Now() if bl.enableFuncCallDepth { _, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth) @@ -561,7 +568,6 @@ func Informational(f interface{}, v ...interface{}) { // Info compatibility alias for Warning() func Info(f interface{}, v ...interface{}) { - fmt.Print() beeLogger.Info(formatLog(f, v...)) } From d8bed89c442838ddcbfc75b6c1c645d5219c79ef Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 24 Mar 2016 19:15:14 +0800 Subject: [PATCH 060/159] set console as default logger --- logs/log.go | 98 ++++++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/logs/log.go b/logs/log.go index 32e441f4..0f5fa052 100644 --- a/logs/log.go +++ b/logs/log.go @@ -56,7 +56,10 @@ const ( LevelInformational LevelDebug ) -const levelCustom = -1 + +// levelLogLogger is defined to implement log.Logger +// the real log level will be LevelEmergency +const levelLoggerImpl = -1 // Name for adapter with beego official support const ( @@ -68,9 +71,7 @@ const ( AdapterEs = "es" ) -// Legacy loglevel constants to ensure backwards compatibility. -// -// Deprecated: will be removed in 1.5.0. +// Legacy log level constants to ensure backwards compatibility. const ( LevelInfo = LevelInformational LevelTrace = LevelDebug @@ -108,10 +109,11 @@ func Register(name string, log newLoggerFunc) { type BeeLogger struct { lock sync.Mutex level int - msgChanLen int64 + init bool enableFuncCallDepth bool loggerFuncCallDepth int asynchronous bool + msgChanLen int64 msgChan chan *logMsg signalChan chan string wg sync.WaitGroup @@ -143,11 +145,17 @@ func NewLogger(channelLens ...int64) *BeeLogger { bl.msgChanLen = 0 } bl.signalChan = make(chan string, 1) + bl.setLogger(AdapterConsole) return bl } // Async set the log to asynchronous and start the goroutine func (bl *BeeLogger) Async() *BeeLogger { + bl.lock.Lock() + defer bl.lock.Unlock() + if bl.asynchronous { + return bl + } bl.asynchronous = true bl.msgChan = make(chan *logMsg, bl.msgChanLen) logMsgPool = &sync.Pool{ @@ -162,11 +170,8 @@ func (bl *BeeLogger) Async() *BeeLogger { // SetLogger provides a given logger adapter into BeeLogger with config string. // config need to be correct JSON as string: {"interval":360}. -func (bl *BeeLogger) SetLogger(adapterName string, configs ...string) error { +func (bl *BeeLogger) setLogger(adapterName string, configs ...string) error { config := append(configs, "{}")[0] - bl.lock.Lock() - defer bl.lock.Unlock() - for _, l := range bl.outputs { if l.name == adapterName { return fmt.Errorf("logs: duplicate adaptername %q (you have set this logger before)", adapterName) @@ -188,6 +193,18 @@ func (bl *BeeLogger) SetLogger(adapterName string, configs ...string) error { return nil } +// SetLogger provides a given logger adapter into BeeLogger with config string. +// config need to be correct JSON as string: {"interval":360}. +func (bl *BeeLogger) SetLogger(adapterName string, configs ...string) error { + bl.lock.Lock() + defer bl.lock.Unlock() + if !bl.init { + bl.outputs = []*nameLogger{} + bl.init = true + } + return bl.setLogger(adapterName, configs...) +} + // DelLogger remove a logger adapter in BeeLogger. func (bl *BeeLogger) DelLogger(adapterName string) error { bl.lock.Lock() @@ -224,8 +241,8 @@ func (bl *BeeLogger) Write(p []byte) (n int, err error) { if p[len(p)-1] == '\n' { p = p[0 : len(p)-1] } - // set LevelCritical to ensure all log message will be write out - err = bl.writeMsg(levelCustom, string(p)) + // set levelLoggerImpl to ensure all log message will be write out + err = bl.writeMsg(levelLoggerImpl, string(p)) if err == nil { return len(p), err } @@ -233,7 +250,10 @@ func (bl *BeeLogger) Write(p []byte) (n int, err error) { } func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error { - if logLevel != levelCustom { + if logLevel == levelLoggerImpl { + // set to emergency to ensure all log will be print out correctly + logLevel = LevelEmergency + } else { msg = levelPrefix[logLevel] + msg } msg = fmt.Sprintf(msg, v...) @@ -313,8 +333,7 @@ func (bl *BeeLogger) Emergency(format string, v ...interface{}) { if LevelEmergency > bl.level { return } - msg := fmt.Sprintf("[M] "+format, v...) - bl.writeMsg(LevelEmergency, msg) + bl.writeMsg(LevelEmergency, format, v...) } // Alert Log ALERT level message. @@ -322,8 +341,7 @@ func (bl *BeeLogger) Alert(format string, v ...interface{}) { if LevelAlert > bl.level { return } - msg := fmt.Sprintf("[A] "+format, v...) - bl.writeMsg(LevelAlert, msg) + bl.writeMsg(LevelAlert, format, v...) } // Critical Log CRITICAL level message. @@ -331,8 +349,7 @@ func (bl *BeeLogger) Critical(format string, v ...interface{}) { if LevelCritical > bl.level { return } - msg := fmt.Sprintf("[C] "+format, v...) - bl.writeMsg(LevelCritical, msg) + bl.writeMsg(LevelCritical, format, v...) } // Error Log ERROR level message. @@ -340,17 +357,12 @@ func (bl *BeeLogger) Error(format string, v ...interface{}) { if LevelError > bl.level { return } - msg := fmt.Sprintf("[E] "+format, v...) - bl.writeMsg(LevelError, msg) + bl.writeMsg(LevelError, format, v...) } // Warning Log WARNING level message. func (bl *BeeLogger) Warning(format string, v ...interface{}) { - if LevelWarning > bl.level { - return - } - msg := fmt.Sprintf("[W] "+format, v...) - bl.writeMsg(LevelWarning, msg) + bl.Warn(format, v...) } // Notice Log NOTICE level message. @@ -358,17 +370,12 @@ func (bl *BeeLogger) Notice(format string, v ...interface{}) { if LevelNotice > bl.level { return } - msg := fmt.Sprintf("[N] "+format, v...) - bl.writeMsg(LevelNotice, msg) + bl.writeMsg(LevelNotice, format, v...) } // Informational Log INFORMATIONAL level message. func (bl *BeeLogger) Informational(format string, v ...interface{}) { - if LevelInformational > bl.level { - return - } - msg := fmt.Sprintf("[I] "+format, v...) - bl.writeMsg(LevelInformational, msg) + bl.Info(format, v...) } // Debug Log DEBUG level message. @@ -376,38 +383,31 @@ func (bl *BeeLogger) Debug(format string, v ...interface{}) { if LevelDebug > bl.level { return } - msg := fmt.Sprintf("[D] "+format, v...) - bl.writeMsg(LevelDebug, msg) + bl.writeMsg(LevelDebug, format, v...) } // Warn Log WARN level message. // compatibility alias for Warning() func (bl *BeeLogger) Warn(format string, v ...interface{}) { - if LevelWarning > bl.level { + if LevelWarn > bl.level { return } - msg := fmt.Sprintf("[W] "+format, v...) - bl.writeMsg(LevelWarning, msg) + bl.writeMsg(LevelWarn, format, v...) } // Info Log INFO level message. // compatibility alias for Informational() func (bl *BeeLogger) Info(format string, v ...interface{}) { - if LevelInformational > bl.level { + if LevelInfo > bl.level { return } - msg := fmt.Sprintf("[I] "+format, v...) - bl.writeMsg(LevelInformational, msg) + bl.writeMsg(LevelInfo, format, v...) } // Trace Log TRACE level message. // compatibility alias for Debug() func (bl *BeeLogger) Trace(format string, v ...interface{}) { - if LevelDebug > bl.level { - return - } - msg := fmt.Sprintf("[D] "+format, v...) - bl.writeMsg(LevelDebug, msg) + bl.Debug(format, v...) } // Flush flush all chan data. @@ -506,6 +506,10 @@ func Reset() { beeLogger.Reset() } +func Async() *BeeLogger { + return beeLogger.Async() +} + // SetLevel sets the global log level used by the simple logger. func SetLevel(l int) { beeLogger.SetLevel(l) @@ -548,7 +552,7 @@ func Error(f interface{}, v ...interface{}) { // Warning logs a message at warning level. func Warning(f interface{}, v ...interface{}) { - beeLogger.Warning(formatLog(f, v...)) + beeLogger.Warn(formatLog(f, v...)) } // Warn compatibility alias for Warning() @@ -563,7 +567,7 @@ func Notice(f interface{}, v ...interface{}) { // Informational logs a message at info level. func Informational(f interface{}, v ...interface{}) { - beeLogger.Informational(formatLog(f, v...)) + beeLogger.Info(formatLog(f, v...)) } // Info compatibility alias for Warning() From 06299fa47bf81f21a6989bf4a5819808b6c56b18 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 24 Mar 2016 19:32:29 +0800 Subject: [PATCH 061/159] makes console as default logger --- logs/log.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/logs/log.go b/logs/log.go index 0f5fa052..cf0f6346 100644 --- a/logs/log.go +++ b/logs/log.go @@ -464,7 +464,11 @@ func (bl *BeeLogger) flush() { } // BeeLogger references the used application logger. -var beeLogger = NewLogger() +var beeLogger *BeeLogger + +func init() { + beeLogger = NewLogger() +} // GetLogger returns the default BeeLogger func GetBeeLogger() *BeeLogger { From 3e2ffa545f5717c7b8dc76a5a68126fcd43b8891 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Thu, 24 Mar 2016 20:03:45 +0800 Subject: [PATCH 062/159] orm: fix postgres returning id error --- orm/db_postgres.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/orm/db_postgres.go b/orm/db_postgres.go index 7dbef95a..be4cd0bc 100644 --- a/orm/db_postgres.go +++ b/orm/db_postgres.go @@ -123,14 +123,16 @@ func (d *dbBasePostgres) ReplaceMarks(query *string) { } // make returning sql support for postgresql. -func (d *dbBasePostgres) HasReturningID(mi *modelInfo, query *string) (has bool) { - if mi.fields.pk.auto { - if query != nil { - *query = fmt.Sprintf(`%s RETURNING "%s"`, *query, mi.fields.pk.column) - } - has = true +func (d *dbBasePostgres) HasReturningID(mi *modelInfo, query *string) bool { + fi := mi.fields.pk + if fi.fieldType&IsPositiveIntegerField == 0 && fi.fieldType&IsIntegerField == 0 { + return false } - return + + if query != nil { + *query = fmt.Sprintf(`%s RETURNING "%s"`, *query, fi.column) + } + return true } // show table sql for postgresql. From f02ff0420d75a3d1d09e1e400e6bf0250848d6f7 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 24 Mar 2016 20:22:42 +0800 Subject: [PATCH 063/159] no need to call Sprintf when no args --- logs/log.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/logs/log.go b/logs/log.go index cf0f6346..3d4a4d60 100644 --- a/logs/log.go +++ b/logs/log.go @@ -256,7 +256,9 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error } else { msg = levelPrefix[logLevel] + msg } - msg = fmt.Sprintf(msg, v...) + if len(v) > 0 { + msg = fmt.Sprintf(msg, v...) + } when := time.Now() if bl.enableFuncCallDepth { _, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth) From 52a0b657b7764530178ac36ca22af8df24e921e4 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 24 Mar 2016 20:27:00 +0800 Subject: [PATCH 064/159] for better performance --- logs/log.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/logs/log.go b/logs/log.go index 3d4a4d60..506e712d 100644 --- a/logs/log.go +++ b/logs/log.go @@ -597,6 +597,9 @@ func formatLog(f interface{}, v ...interface{}) string { switch f.(type) { case string: msg = f.(string) + if len(v) == 0 { + return msg + } if strings.Contains(msg, "%") && !strings.Contains(msg, "%%") { //format string } else { @@ -604,7 +607,11 @@ func formatLog(f interface{}, v ...interface{}) string { msg += strings.Repeat(" %v", len(v)) } default: - msg = fmt.Sprint(f) + strings.Repeat(" %v", len(v)) + msg = fmt.Sprint(f) + if len(v) == 0 { + return msg + } + msg += strings.Repeat(" %v", len(v)) } return fmt.Sprintf(msg, v...) } From 3300db832bdbb37500c7d499b1a279d45172aa31 Mon Sep 17 00:00:00 2001 From: youngsterxyf Date: Thu, 24 Mar 2016 22:43:57 +0800 Subject: [PATCH 065/159] in `session` package, add a helpful variable `SLogger` to help subpackage logging information --- session/ledis/ledis_session.go | 2 +- session/mysql/sess_mysql.go | 10 ++++++++-- session/sess_file.go | 10 +++++----- session/session.go | 17 +++++++++++++++++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/session/ledis/ledis_session.go b/session/ledis/ledis_session.go index 68f37b08..6b201f56 100644 --- a/session/ledis/ledis_session.go +++ b/session/ledis/ledis_session.go @@ -100,7 +100,7 @@ func (lp *Provider) SessionInit(maxlifetime int64, savePath string) error { nowLedis, err := ledis.Open(cfg) c, err = nowLedis.Select(lp.db) if err != nil { - println(err) + session.SLogger.Println(err) return nil } return nil diff --git a/session/mysql/sess_mysql.go b/session/mysql/sess_mysql.go index 969d26c9..93ea31ed 100644 --- a/session/mysql/sess_mysql.go +++ b/session/mysql/sess_mysql.go @@ -1,3 +1,4 @@ + // Copyright 2014 beego Author. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -111,11 +112,14 @@ func (st *SessionStore) SessionRelease(w http.ResponseWriter) { defer st.c.Close() b, err := session.EncodeGob(st.values) if err != nil { + session.SLogger.Println(err) return } - st.c.Exec("UPDATE "+TableName+" set `session_data`=?, `session_expiry`=? where session_key=?", + _, err = st.c.Exec("UPDATE "+TableName+" set `session_data`=?, `session_expiry`=? where session_key=?", b, time.Now().Unix(), st.sid) - + if err != nil { + session.SLogger.Println(err) + } } // Provider mysql session provider @@ -128,6 +132,7 @@ type Provider struct { func (mp *Provider) connectInit() *sql.DB { db, e := sql.Open("mysql", mp.savePath) if e != nil { + session.SLogger.Println(e) return nil } return db @@ -223,6 +228,7 @@ func (mp *Provider) SessionAll() int { var total int err := c.QueryRow("SELECT count(*) as num from " + TableName).Scan(&total) if err != nil { + session.SLogger.Println(err) return 0 } return total diff --git a/session/sess_file.go b/session/sess_file.go index 9265b030..dda56b3a 100644 --- a/session/sess_file.go +++ b/session/sess_file.go @@ -16,7 +16,6 @@ package session import ( "errors" - "fmt" "io" "io/ioutil" "net/http" @@ -82,6 +81,7 @@ func (fs *FileSessionStore) SessionID() string { func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) { b, err := EncodeGob(fs.values) if err != nil { + SLogger.Println(err) return } _, err = os.Stat(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid)) @@ -123,7 +123,7 @@ func (fp *FileProvider) SessionRead(sid string) (Store, error) { err := os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777) if err != nil { - println(err.Error()) + SLogger.Println(err.Error()) } _, err = os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) var f *os.File @@ -191,7 +191,7 @@ func (fp *FileProvider) SessionAll() int { return a.visit(path, f, err) }) if err != nil { - fmt.Printf("filepath.Walk() returned %v\n", err) + SLogger.Printf("filepath.Walk() returned %v\n", err) return 0 } return a.total @@ -205,11 +205,11 @@ func (fp *FileProvider) SessionRegenerate(oldsid, sid string) (Store, error) { err := os.MkdirAll(path.Join(fp.savePath, string(oldsid[0]), string(oldsid[1])), 0777) if err != nil { - println(err.Error()) + SLogger.Println(err.Error()) } err = os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777) if err != nil { - println(err.Error()) + SLogger.Println(err.Error()) } _, err = os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) var newf *os.File diff --git a/session/session.go b/session/session.go index 9fe99a17..09c200c5 100644 --- a/session/session.go +++ b/session/session.go @@ -32,8 +32,11 @@ import ( "encoding/hex" "encoding/json" "fmt" + "io" + "log" "net/http" "net/url" + "os" "time" ) @@ -61,6 +64,8 @@ type Provider interface { var provides = make(map[string]Provider) +var SLogger = newSessionLog(os.Stderr) + // Register makes a session provide available by the provided name. // If Register is called twice with the same name or if driver is nil, // it panics. @@ -296,3 +301,15 @@ func (manager *Manager) isSecure(req *http.Request) bool { } return true } + +// Log implement the log.Logger +type sessionLog struct { + *log.Logger +} + +// NewLog set io.Writer to create a Logger for session. +func newSessionLog(out io.Writer) *sessionLog { + sl := new(sessionLog) + sl.Logger = log.New(out, "[SESSION]", 1e9) + return sl +} From 94bde3a77768f6285b852240d8669f37a86d7966 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 25 Mar 2016 10:31:48 +0800 Subject: [PATCH 066/159] change to logs --- filter_test.go | 6 ------ router_test.go | 11 ++++++----- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/filter_test.go b/filter_test.go index d9928d8d..4ca4d2b8 100644 --- a/filter_test.go +++ b/filter_test.go @@ -20,14 +20,8 @@ import ( "testing" "github.com/astaxie/beego/context" - "github.com/astaxie/beego/logs" ) -func init() { - BeeLogger = logs.NewLogger(10000) - BeeLogger.SetLogger("console", "") -} - var FilterUser = func(ctx *context.Context) { ctx.Output.Body([]byte("i am " + ctx.Input.Param(":last") + ctx.Input.Param(":first"))) } diff --git a/router_test.go b/router_test.go index f26f0c86..9f11286c 100644 --- a/router_test.go +++ b/router_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/astaxie/beego/context" + "github.com/astaxie/beego/logs" ) type TestController struct { @@ -94,7 +95,7 @@ func TestUrlFor(t *testing.T) { handler.Add("/api/list", &TestController{}, "*:List") handler.Add("/person/:last/:first", &TestController{}, "*:Param") if a := handler.URLFor("TestController.List"); a != "/api/list" { - Info(a) + logs.Info(a) t.Errorf("TestController.List must equal to /api/list") } if a := handler.URLFor("TestController.Param", ":last", "xie", ":first", "asta"); a != "/person/xie/asta" { @@ -120,24 +121,24 @@ func TestUrlFor2(t *testing.T) { handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, "*:Param") handler.Add("/:year:int/:month:int/:title/:entid", &TestController{}) if handler.URLFor("TestController.GetURL", ":username", "astaxie") != "/v1/astaxie/edit" { - Info(handler.URLFor("TestController.GetURL")) + logs.Info(handler.URLFor("TestController.GetURL")) t.Errorf("TestController.List must equal to /v1/astaxie/edit") } if handler.URLFor("TestController.List", ":v", "za", ":id", "12", ":page", "123") != "/v1/za/cms_12_123.html" { - Info(handler.URLFor("TestController.List")) + logs.Info(handler.URLFor("TestController.List")) t.Errorf("TestController.List must equal to /v1/za/cms_12_123.html") } if handler.URLFor("TestController.Param", ":v", "za", ":id", "12", ":page", "123") != "/v1/za_cms/ttt_12_123.html" { - Info(handler.URLFor("TestController.Param")) + logs.Info(handler.URLFor("TestController.Param")) t.Errorf("TestController.List must equal to /v1/za_cms/ttt_12_123.html") } if handler.URLFor("TestController.Get", ":year", "1111", ":month", "11", ":title", "aaaa", ":entid", "aaaa") != "/1111/11/aaaa/aaaa" { - Info(handler.URLFor("TestController.Get")) + logs.Info(handler.URLFor("TestController.Get")) t.Errorf("TestController.Get must equal to /1111/11/aaaa/aaaa") } } From 56860d1feacaae15cd1cd53d5b600516bb978b61 Mon Sep 17 00:00:00 2001 From: youngsterxyf Date: Fri, 25 Mar 2016 10:48:59 +0800 Subject: [PATCH 067/159] not just export a variable --- session/ledis/ledis_session.go | 2 +- session/mysql/sess_mysql.go | 9 +-------- session/sess_file.go | 2 ++ session/session.go | 11 ++++++----- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/session/ledis/ledis_session.go b/session/ledis/ledis_session.go index 6b201f56..68f37b08 100644 --- a/session/ledis/ledis_session.go +++ b/session/ledis/ledis_session.go @@ -100,7 +100,7 @@ func (lp *Provider) SessionInit(maxlifetime int64, savePath string) error { nowLedis, err := ledis.Open(cfg) c, err = nowLedis.Select(lp.db) if err != nil { - session.SLogger.Println(err) + println(err) return nil } return nil diff --git a/session/mysql/sess_mysql.go b/session/mysql/sess_mysql.go index 93ea31ed..838ec669 100644 --- a/session/mysql/sess_mysql.go +++ b/session/mysql/sess_mysql.go @@ -1,4 +1,3 @@ - // Copyright 2014 beego Author. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -112,14 +111,10 @@ func (st *SessionStore) SessionRelease(w http.ResponseWriter) { defer st.c.Close() b, err := session.EncodeGob(st.values) if err != nil { - session.SLogger.Println(err) return } - _, err = st.c.Exec("UPDATE "+TableName+" set `session_data`=?, `session_expiry`=? where session_key=?", + st.c.Exec("UPDATE "+TableName+" set `session_data`=?, `session_expiry`=? where session_key=?", b, time.Now().Unix(), st.sid) - if err != nil { - session.SLogger.Println(err) - } } // Provider mysql session provider @@ -132,7 +127,6 @@ type Provider struct { func (mp *Provider) connectInit() *sql.DB { db, e := sql.Open("mysql", mp.savePath) if e != nil { - session.SLogger.Println(e) return nil } return db @@ -228,7 +222,6 @@ func (mp *Provider) SessionAll() int { var total int err := c.QueryRow("SELECT count(*) as num from " + TableName).Scan(&total) if err != nil { - session.SLogger.Println(err) return 0 } return total diff --git a/session/sess_file.go b/session/sess_file.go index dda56b3a..91acfcd4 100644 --- a/session/sess_file.go +++ b/session/sess_file.go @@ -88,8 +88,10 @@ func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) { var f *os.File if err == nil { f, err = os.OpenFile(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid), os.O_RDWR, 0777) + SLogger.Println(err) } else if os.IsNotExist(err) { f, err = os.Create(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid)) + SLogger.Println(err) } else { return } diff --git a/session/session.go b/session/session.go index 09c200c5..2c4b9351 100644 --- a/session/session.go +++ b/session/session.go @@ -64,7 +64,8 @@ type Provider interface { var provides = make(map[string]Provider) -var SLogger = newSessionLog(os.Stderr) +// SLogger a helpful variable to log information about session +var SLogger = NewSessionLog(os.Stderr) // Register makes a session provide available by the provided name. // If Register is called twice with the same name or if driver is nil, @@ -303,13 +304,13 @@ func (manager *Manager) isSecure(req *http.Request) bool { } // Log implement the log.Logger -type sessionLog struct { +type Log struct { *log.Logger } -// NewLog set io.Writer to create a Logger for session. -func newSessionLog(out io.Writer) *sessionLog { - sl := new(sessionLog) +// NewSessionLog set io.Writer to create a Logger for session. +func NewSessionLog(out io.Writer) *Log { + sl := new(Log) sl.Logger = log.New(out, "[SESSION]", 1e9) return sl } From 2db8c753fd3fa8c28d134a74fd0002a63841f52f Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 25 Mar 2016 10:56:15 +0800 Subject: [PATCH 068/159] bee fix --- cache/cache_test.go | 14 +++++++------- cache/memcache/memcache_test.go | 8 ++++---- cache/redis/redis_test.go | 8 ++++---- cache/ssdb/ssdb_test.go | 8 ++++---- context/input_test.go | 2 +- migration/migration.go | 34 ++++++++++++++++----------------- utils/captcha/captcha.go | 7 ++++--- utils/pagination/controller.go | 2 +- 8 files changed, 42 insertions(+), 41 deletions(-) diff --git a/cache/cache_test.go b/cache/cache_test.go index 9ceb606a..40a9d60a 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -26,7 +26,7 @@ func TestCache(t *testing.T) { t.Error("init err") } timeoutDuration := 10 * time.Second - if err = bm.Put("astaxie", 1, timeoutDuration); err != nil { + if err = bm.Put("astaxie", 1, timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -43,7 +43,7 @@ func TestCache(t *testing.T) { t.Error("check err") } - if err = bm.Put("astaxie", 1, timeoutDuration); err != nil { + if err = bm.Put("astaxie", 1, timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } @@ -68,7 +68,7 @@ func TestCache(t *testing.T) { } //test GetMulti - if err = bm.Put("astaxie", "author", timeoutDuration); err != nil { + if err = bm.Put("astaxie", "author", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -78,7 +78,7 @@ func TestCache(t *testing.T) { t.Error("get err") } - if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil { + if err = bm.Put("astaxie1", "author1", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie1") { @@ -103,7 +103,7 @@ func TestFileCache(t *testing.T) { t.Error("init err") } timeoutDuration := 10 * time.Second - if err = bm.Put("astaxie", 1, timeoutDuration); err != nil { + if err = bm.Put("astaxie", 1, timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -135,7 +135,7 @@ func TestFileCache(t *testing.T) { } //test string - if err = bm.Put("astaxie", "author", timeoutDuration); err != nil { + if err = bm.Put("astaxie", "author", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -146,7 +146,7 @@ func TestFileCache(t *testing.T) { } //test GetMulti - if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil { + if err = bm.Put("astaxie1", "author1", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie1") { diff --git a/cache/memcache/memcache_test.go b/cache/memcache/memcache_test.go index 0c8c57f2..ce16f066 100644 --- a/cache/memcache/memcache_test.go +++ b/cache/memcache/memcache_test.go @@ -30,7 +30,7 @@ func TestMemcacheCache(t *testing.T) { t.Error("init err") } timeoutDuration := 10 * time.Second - if err = bm.Put("astaxie", "1", timeoutDuration); err != nil { + if err = bm.Put("astaxie", "1", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -42,7 +42,7 @@ func TestMemcacheCache(t *testing.T) { if bm.IsExist("astaxie") { t.Error("check err") } - if err = bm.Put("astaxie", "1", timeoutDuration); err != nil { + if err = bm.Put("astaxie", "1", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } @@ -71,7 +71,7 @@ func TestMemcacheCache(t *testing.T) { } //test string - if err = bm.Put("astaxie", "author", timeoutDuration); err != nil { + if err = bm.Put("astaxie", "author", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -83,7 +83,7 @@ func TestMemcacheCache(t *testing.T) { } //test GetMulti - if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil { + if err = bm.Put("astaxie1", "author1", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie1") { diff --git a/cache/redis/redis_test.go b/cache/redis/redis_test.go index 47c5acc6..1fcba81d 100644 --- a/cache/redis/redis_test.go +++ b/cache/redis/redis_test.go @@ -29,7 +29,7 @@ func TestRedisCache(t *testing.T) { t.Error("init err") } timeoutDuration := 10 * time.Second - if err = bm.Put("astaxie", 1, timeoutDuration); err != nil { + if err = bm.Put("astaxie", 1, timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -41,7 +41,7 @@ func TestRedisCache(t *testing.T) { if bm.IsExist("astaxie") { t.Error("check err") } - if err = bm.Put("astaxie", 1, timeoutDuration); err != nil { + if err = bm.Put("astaxie", 1, timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } @@ -70,7 +70,7 @@ func TestRedisCache(t *testing.T) { } //test string - if err = bm.Put("astaxie", "author", timeoutDuration); err != nil { + if err = bm.Put("astaxie", "author", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -82,7 +82,7 @@ func TestRedisCache(t *testing.T) { } //test GetMulti - if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil { + if err = bm.Put("astaxie1", "author1", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie1") { diff --git a/cache/ssdb/ssdb_test.go b/cache/ssdb/ssdb_test.go index e03ba343..c389a357 100644 --- a/cache/ssdb/ssdb_test.go +++ b/cache/ssdb/ssdb_test.go @@ -19,7 +19,7 @@ func TestSsdbcacheCache(t *testing.T) { } timeoutDuration := 10 * time.Second //timeoutDuration := -10*time.Second if timeoutDuration is negtive,it means permanent - if err = ssdb.Put("ssdb", "ssdb", timeoutDuration); err != nil { + if err = ssdb.Put("ssdb", "ssdb", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if !ssdb.IsExist("ssdb") { @@ -27,7 +27,7 @@ func TestSsdbcacheCache(t *testing.T) { } // Get test done - if err = ssdb.Put("ssdb", "ssdb", timeoutDuration); err != nil { + if err = ssdb.Put("ssdb", "ssdb", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } @@ -36,7 +36,7 @@ func TestSsdbcacheCache(t *testing.T) { } //inc/dec test done - if err = ssdb.Put("ssdb", "2", timeoutDuration); err != nil { + if err = ssdb.Put("ssdb", "2", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if err = ssdb.Incr("ssdb"); err != nil { @@ -52,7 +52,7 @@ func TestSsdbcacheCache(t *testing.T) { } // test del - if err = ssdb.Put("ssdb", "3", timeoutDuration); err != nil { + if err = ssdb.Put("ssdb", "3", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } if v, err := strconv.Atoi(ssdb.Get("ssdb").(string)); err != nil || v != 3 { diff --git a/context/input_test.go b/context/input_test.go index 24f6fd99..8887aec4 100644 --- a/context/input_test.go +++ b/context/input_test.go @@ -100,7 +100,7 @@ func TestSubDomain(t *testing.T) { /* TODO Fix this r, _ = http.NewRequest("GET", "http://127.0.0.1/", nil) - beegoInput.Request = r + beegoInput.Context.Request = r if beegoInput.SubDomains() != "" { t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains()) } diff --git a/migration/migration.go b/migration/migration.go index 1591bc50..c9ca1bc6 100644 --- a/migration/migration.go +++ b/migration/migration.go @@ -33,7 +33,7 @@ import ( "strings" "time" - "github.com/astaxie/beego" + "github.com/astaxie/beego/logs" "github.com/astaxie/beego/orm" ) @@ -90,7 +90,7 @@ func (m *Migration) Reset() { func (m *Migration) Exec(name, status string) error { o := orm.NewOrm() for _, s := range m.sqls { - beego.Info("exec sql:", s) + logs.Info("exec sql:", s) r := o.Raw(s) _, err := r.Exec() if err != nil { @@ -144,20 +144,20 @@ func Upgrade(lasttime int64) error { i := 0 for _, v := range sm { if v.created > lasttime { - beego.Info("start upgrade", v.name) + logs.Info("start upgrade", v.name) v.m.Reset() v.m.Up() err := v.m.Exec(v.name, "up") if err != nil { - beego.Error("execute error:", err) + logs.Error("execute error:", err) time.Sleep(2 * time.Second) return err } - beego.Info("end upgrade:", v.name) + logs.Info("end upgrade:", v.name) i++ } } - beego.Info("total success upgrade:", i, " migration") + logs.Info("total success upgrade:", i, " migration") time.Sleep(2 * time.Second) return nil } @@ -165,20 +165,20 @@ func Upgrade(lasttime int64) error { // Rollback rollback the migration by the name func Rollback(name string) error { if v, ok := migrationMap[name]; ok { - beego.Info("start rollback") + logs.Info("start rollback") v.Reset() v.Down() err := v.Exec(name, "down") if err != nil { - beego.Error("execute error:", err) + logs.Error("execute error:", err) time.Sleep(2 * time.Second) return err } - beego.Info("end rollback") + logs.Info("end rollback") time.Sleep(2 * time.Second) return nil } - beego.Error("not exist the migrationMap name:" + name) + logs.Error("not exist the migrationMap name:" + name) time.Sleep(2 * time.Second) return errors.New("not exist the migrationMap name:" + name) } @@ -191,23 +191,23 @@ func Reset() error { for j := len(sm) - 1; j >= 0; j-- { v := sm[j] if isRollBack(v.name) { - beego.Info("skip the", v.name) + logs.Info("skip the", v.name) time.Sleep(1 * time.Second) continue } - beego.Info("start reset:", v.name) + logs.Info("start reset:", v.name) v.m.Reset() v.m.Down() err := v.m.Exec(v.name, "down") if err != nil { - beego.Error("execute error:", err) + logs.Error("execute error:", err) time.Sleep(2 * time.Second) return err } i++ - beego.Info("end reset:", v.name) + logs.Info("end reset:", v.name) } - beego.Info("total success reset:", i, " migration") + logs.Info("total success reset:", i, " migration") time.Sleep(2 * time.Second) return nil } @@ -216,7 +216,7 @@ func Reset() error { func Refresh() error { err := Reset() if err != nil { - beego.Error("execute error:", err) + logs.Error("execute error:", err) time.Sleep(2 * time.Second) return err } @@ -265,7 +265,7 @@ func isRollBack(name string) bool { var maps []orm.Params num, err := o.Raw("select * from migrations where `name` = ? order by id_migration desc", name).Values(&maps) if err != nil { - beego.Info("get name has error", err) + logs.Info("get name has error", err) return false } if num <= 0 { diff --git a/utils/captcha/captcha.go b/utils/captcha/captcha.go index 1a4a6edc..42ac70d3 100644 --- a/utils/captcha/captcha.go +++ b/utils/captcha/captcha.go @@ -69,6 +69,7 @@ import ( "github.com/astaxie/beego" "github.com/astaxie/beego/cache" "github.com/astaxie/beego/context" + "github.com/astaxie/beego/logs" "github.com/astaxie/beego/utils" ) @@ -139,7 +140,7 @@ func (c *Captcha) Handler(ctx *context.Context) { if err := c.store.Put(key, chars, c.Expiration); err != nil { ctx.Output.SetStatus(500) ctx.WriteString("captcha reload error") - beego.Error("Reload Create Captcha Error:", err) + logs.Error("Reload Create Captcha Error:", err) return } } else { @@ -154,7 +155,7 @@ func (c *Captcha) Handler(ctx *context.Context) { img := NewImage(chars, c.StdWidth, c.StdHeight) if _, err := img.WriteTo(ctx.ResponseWriter); err != nil { - beego.Error("Write Captcha Image Error:", err) + logs.Error("Write Captcha Image Error:", err) } } @@ -162,7 +163,7 @@ func (c *Captcha) Handler(ctx *context.Context) { func (c *Captcha) CreateCaptchaHTML() template.HTML { value, err := c.CreateCaptcha() if err != nil { - beego.Error("Create Captcha Error:", err) + logs.Error("Create Captcha Error:", err) return "" } diff --git a/utils/pagination/controller.go b/utils/pagination/controller.go index 1d99cac5..2f022d0c 100644 --- a/utils/pagination/controller.go +++ b/utils/pagination/controller.go @@ -18,7 +18,7 @@ import ( "github.com/astaxie/beego/context" ) -// SetPaginator Instantiates a Paginator and assigns it to context.Input.Data["paginator"]. +// SetPaginator Instantiates a Paginator and assigns it to context.Input.Data("paginator"). func SetPaginator(context *context.Context, per int, nums int64) (paginator *Paginator) { paginator = NewPaginator(context.Request, per, nums) context.Input.SetData("paginator", &paginator) From 6d0fe8c4f44ff2e89d4d8c00b4e1931e96eb395b Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 25 Mar 2016 11:05:20 +0800 Subject: [PATCH 069/159] go fmt cache file --- cache/redis/redis_test.go | 1 - cache/ssdb/ssdb_test.go | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cache/redis/redis_test.go b/cache/redis/redis_test.go index 1fcba81d..e7aa78cb 100644 --- a/cache/redis/redis_test.go +++ b/cache/redis/redis_test.go @@ -19,7 +19,6 @@ import ( "time" "github.com/garyburd/redigo/redis" - "github.com/astaxie/beego/cache" ) diff --git a/cache/ssdb/ssdb_test.go b/cache/ssdb/ssdb_test.go index c389a357..8083f52d 100644 --- a/cache/ssdb/ssdb_test.go +++ b/cache/ssdb/ssdb_test.go @@ -1,10 +1,11 @@ package ssdb import ( - "github.com/astaxie/beego/cache" "strconv" "testing" "time" + + "github.com/astaxie/beego/cache" ) func TestSsdbcacheCache(t *testing.T) { From 850dc59b6e2610a589b3fd11c48b5b857c42a57a Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 25 Mar 2016 11:13:39 +0800 Subject: [PATCH 070/159] should remove when 2.0 is released --- log.go | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 log.go diff --git a/log.go b/log.go new file mode 100644 index 00000000..214f6d14 --- /dev/null +++ b/log.go @@ -0,0 +1,108 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// 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 beego + +import ( + "strings" + + "github.com/astaxie/beego/logs" +) + +// Log levels to control the logging output. +const ( + LevelEmergency = iota + LevelAlert + LevelCritical + LevelError + LevelWarning + LevelNotice + LevelInformational + LevelDebug +) + +// SetLevel sets the global log level used by the simple logger. +func SetLevel(l int) { + logs.SetLevel(l) +} + +// SetLogFuncCall set the CallDepth, default is 3 +func SetLogFuncCall(b bool) { + logs.SetLogFuncCall(b) +} + +// SetLogger sets a new logger. +func SetLogger(adaptername string, config string) error { + return logs.SetLogger(adaptername, config) +} + +// Emergency logs a message at emergency level. +func Emergency(v ...interface{}) { + logs.Emergency(generateFmtStr(len(v)), v...) +} + +// Alert logs a message at alert level. +func Alert(v ...interface{}) { + logs.Alert(generateFmtStr(len(v)), v...) +} + +// Critical logs a message at critical level. +func Critical(v ...interface{}) { + logs.Critical(generateFmtStr(len(v)), v...) +} + +// Error logs a message at error level. +func Error(v ...interface{}) { + logs.Error(generateFmtStr(len(v)), v...) +} + +// Warning logs a message at warning level. +func Warning(v ...interface{}) { + logs.Warning(generateFmtStr(len(v)), v...) +} + +// Warn compatibility alias for Warning() +func Warn(v ...interface{}) { + logs.Warn(generateFmtStr(len(v)), v...) +} + +// Notice logs a message at notice level. +func Notice(v ...interface{}) { + logs.Notice(generateFmtStr(len(v)), v...) +} + +// Informational logs a message at info level. +func Informational(v ...interface{}) { + logs.Informational(generateFmtStr(len(v)), v...) +} + +// Info compatibility alias for Warning() +func Info(v ...interface{}) { + logs.Info(generateFmtStr(len(v)), v...) +} + +// Debug logs a message at debug level. +func Debug(v ...interface{}) { + logs.Debug(generateFmtStr(len(v)), v...) +} + +// Trace logs a message at trace level. +// compatibility alias for Warning() +func Trace(v ...interface{}) { + logs.Trace(generateFmtStr(len(v)), v...) +} + +func generateFmtStr(n int) string { + return strings.Repeat("%v ", n) +} From fa4a231cd4248e80a08ef7965be0b0c421bf8784 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 25 Mar 2016 11:46:19 +0800 Subject: [PATCH 071/159] duration change to second --- cache/cache_test.go | 4 ++-- cache/memcache/memcache_test.go | 2 +- cache/redis/redis_test.go | 4 ++-- cache/ssdb/ssdb_test.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cache/cache_test.go b/cache/cache_test.go index 40a9d60a..ec344cb1 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -25,7 +25,7 @@ func TestCache(t *testing.T) { if err != nil { t.Error("init err") } - timeoutDuration := 10 * time.Second + timeoutDuration := 10 if err = bm.Put("astaxie", 1, timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } @@ -102,7 +102,7 @@ func TestFileCache(t *testing.T) { if err != nil { t.Error("init err") } - timeoutDuration := 10 * time.Second + timeoutDuration := 10 if err = bm.Put("astaxie", 1, timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } diff --git a/cache/memcache/memcache_test.go b/cache/memcache/memcache_test.go index ce16f066..9b9582f7 100644 --- a/cache/memcache/memcache_test.go +++ b/cache/memcache/memcache_test.go @@ -29,7 +29,7 @@ func TestMemcacheCache(t *testing.T) { if err != nil { t.Error("init err") } - timeoutDuration := 10 * time.Second + timeoutDuration := 10 if err = bm.Put("astaxie", "1", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } diff --git a/cache/redis/redis_test.go b/cache/redis/redis_test.go index e7aa78cb..91efbb3e 100644 --- a/cache/redis/redis_test.go +++ b/cache/redis/redis_test.go @@ -18,8 +18,8 @@ import ( "testing" "time" - "github.com/garyburd/redigo/redis" "github.com/astaxie/beego/cache" + "github.com/garyburd/redigo/redis" ) func TestRedisCache(t *testing.T) { @@ -27,7 +27,7 @@ func TestRedisCache(t *testing.T) { if err != nil { t.Error("init err") } - timeoutDuration := 10 * time.Second + timeoutDuration := 10 if err = bm.Put("astaxie", 1, timeoutDuration*time.Second); err != nil { t.Error("set Error", err) } diff --git a/cache/ssdb/ssdb_test.go b/cache/ssdb/ssdb_test.go index 8083f52d..4fea6fd8 100644 --- a/cache/ssdb/ssdb_test.go +++ b/cache/ssdb/ssdb_test.go @@ -18,7 +18,7 @@ func TestSsdbcacheCache(t *testing.T) { if ssdb.IsExist("ssdb") { t.Error("check err") } - timeoutDuration := 10 * time.Second + timeoutDuration := 10 //timeoutDuration := -10*time.Second if timeoutDuration is negtive,it means permanent if err = ssdb.Put("ssdb", "ssdb", timeoutDuration*time.Second); err != nil { t.Error("set Error", err) From e59271662cb815ad644e92a50c81ed38bdb7be8a Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 25 Mar 2016 13:25:29 +0800 Subject: [PATCH 072/159] fix bee fix --- cache/cache_test.go | 18 +++++++++--------- cache/memcache/memcache_test.go | 10 +++++----- cache/redis/redis_test.go | 10 +++++----- cache/ssdb/ssdb_test.go | 10 +++++----- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/cache/cache_test.go b/cache/cache_test.go index ec344cb1..9ceb606a 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -25,8 +25,8 @@ func TestCache(t *testing.T) { if err != nil { t.Error("init err") } - timeoutDuration := 10 - if err = bm.Put("astaxie", 1, timeoutDuration*time.Second); err != nil { + timeoutDuration := 10 * time.Second + if err = bm.Put("astaxie", 1, timeoutDuration); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -43,7 +43,7 @@ func TestCache(t *testing.T) { t.Error("check err") } - if err = bm.Put("astaxie", 1, timeoutDuration*time.Second); err != nil { + if err = bm.Put("astaxie", 1, timeoutDuration); err != nil { t.Error("set Error", err) } @@ -68,7 +68,7 @@ func TestCache(t *testing.T) { } //test GetMulti - if err = bm.Put("astaxie", "author", timeoutDuration*time.Second); err != nil { + if err = bm.Put("astaxie", "author", timeoutDuration); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -78,7 +78,7 @@ func TestCache(t *testing.T) { t.Error("get err") } - if err = bm.Put("astaxie1", "author1", timeoutDuration*time.Second); err != nil { + if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie1") { @@ -102,8 +102,8 @@ func TestFileCache(t *testing.T) { if err != nil { t.Error("init err") } - timeoutDuration := 10 - if err = bm.Put("astaxie", 1, timeoutDuration*time.Second); err != nil { + timeoutDuration := 10 * time.Second + if err = bm.Put("astaxie", 1, timeoutDuration); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -135,7 +135,7 @@ func TestFileCache(t *testing.T) { } //test string - if err = bm.Put("astaxie", "author", timeoutDuration*time.Second); err != nil { + if err = bm.Put("astaxie", "author", timeoutDuration); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -146,7 +146,7 @@ func TestFileCache(t *testing.T) { } //test GetMulti - if err = bm.Put("astaxie1", "author1", timeoutDuration*time.Second); err != nil { + if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie1") { diff --git a/cache/memcache/memcache_test.go b/cache/memcache/memcache_test.go index 9b9582f7..0c8c57f2 100644 --- a/cache/memcache/memcache_test.go +++ b/cache/memcache/memcache_test.go @@ -29,8 +29,8 @@ func TestMemcacheCache(t *testing.T) { if err != nil { t.Error("init err") } - timeoutDuration := 10 - if err = bm.Put("astaxie", "1", timeoutDuration*time.Second); err != nil { + timeoutDuration := 10 * time.Second + if err = bm.Put("astaxie", "1", timeoutDuration); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -42,7 +42,7 @@ func TestMemcacheCache(t *testing.T) { if bm.IsExist("astaxie") { t.Error("check err") } - if err = bm.Put("astaxie", "1", timeoutDuration*time.Second); err != nil { + if err = bm.Put("astaxie", "1", timeoutDuration); err != nil { t.Error("set Error", err) } @@ -71,7 +71,7 @@ func TestMemcacheCache(t *testing.T) { } //test string - if err = bm.Put("astaxie", "author", timeoutDuration*time.Second); err != nil { + if err = bm.Put("astaxie", "author", timeoutDuration); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -83,7 +83,7 @@ func TestMemcacheCache(t *testing.T) { } //test GetMulti - if err = bm.Put("astaxie1", "author1", timeoutDuration*time.Second); err != nil { + if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie1") { diff --git a/cache/redis/redis_test.go b/cache/redis/redis_test.go index 91efbb3e..6b81da4d 100644 --- a/cache/redis/redis_test.go +++ b/cache/redis/redis_test.go @@ -27,8 +27,8 @@ func TestRedisCache(t *testing.T) { if err != nil { t.Error("init err") } - timeoutDuration := 10 - if err = bm.Put("astaxie", 1, timeoutDuration*time.Second); err != nil { + timeoutDuration := 10 * time.Second + if err = bm.Put("astaxie", 1, timeoutDuration); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -40,7 +40,7 @@ func TestRedisCache(t *testing.T) { if bm.IsExist("astaxie") { t.Error("check err") } - if err = bm.Put("astaxie", 1, timeoutDuration*time.Second); err != nil { + if err = bm.Put("astaxie", 1, timeoutDuration); err != nil { t.Error("set Error", err) } @@ -69,7 +69,7 @@ func TestRedisCache(t *testing.T) { } //test string - if err = bm.Put("astaxie", "author", timeoutDuration*time.Second); err != nil { + if err = bm.Put("astaxie", "author", timeoutDuration); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie") { @@ -81,7 +81,7 @@ func TestRedisCache(t *testing.T) { } //test GetMulti - if err = bm.Put("astaxie1", "author1", timeoutDuration*time.Second); err != nil { + if err = bm.Put("astaxie1", "author1", timeoutDuration); err != nil { t.Error("set Error", err) } if !bm.IsExist("astaxie1") { diff --git a/cache/ssdb/ssdb_test.go b/cache/ssdb/ssdb_test.go index 4fea6fd8..dd474960 100644 --- a/cache/ssdb/ssdb_test.go +++ b/cache/ssdb/ssdb_test.go @@ -18,9 +18,9 @@ func TestSsdbcacheCache(t *testing.T) { if ssdb.IsExist("ssdb") { t.Error("check err") } - timeoutDuration := 10 + timeoutDuration := 10 * time.Second //timeoutDuration := -10*time.Second if timeoutDuration is negtive,it means permanent - if err = ssdb.Put("ssdb", "ssdb", timeoutDuration*time.Second); err != nil { + if err = ssdb.Put("ssdb", "ssdb", timeoutDuration); err != nil { t.Error("set Error", err) } if !ssdb.IsExist("ssdb") { @@ -28,7 +28,7 @@ func TestSsdbcacheCache(t *testing.T) { } // Get test done - if err = ssdb.Put("ssdb", "ssdb", timeoutDuration*time.Second); err != nil { + if err = ssdb.Put("ssdb", "ssdb", timeoutDuration); err != nil { t.Error("set Error", err) } @@ -37,7 +37,7 @@ func TestSsdbcacheCache(t *testing.T) { } //inc/dec test done - if err = ssdb.Put("ssdb", "2", timeoutDuration*time.Second); err != nil { + if err = ssdb.Put("ssdb", "2", timeoutDuration); err != nil { t.Error("set Error", err) } if err = ssdb.Incr("ssdb"); err != nil { @@ -53,7 +53,7 @@ func TestSsdbcacheCache(t *testing.T) { } // test del - if err = ssdb.Put("ssdb", "3", timeoutDuration*time.Second); err != nil { + if err = ssdb.Put("ssdb", "3", timeoutDuration); err != nil { t.Error("set Error", err) } if v, err := strconv.Atoi(ssdb.Get("ssdb").(string)); err != nil || v != 3 { From 826f81f47951b568088dd709a0407d32474c7f5d Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 25 Mar 2016 15:04:52 +0800 Subject: [PATCH 073/159] remove from init method --- log.go | 3 +++ logs/log.go | 18 ++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/log.go b/log.go index 214f6d14..e9412f92 100644 --- a/log.go +++ b/log.go @@ -32,6 +32,9 @@ const ( LevelDebug ) +// BeeLogger references the used application logger. +var BeeLogger = logs.GetBeeLogger() + // SetLevel sets the global log level used by the simple logger. func SetLevel(l int) { logs.SetLevel(l) diff --git a/logs/log.go b/logs/log.go index 506e712d..11d54ef8 100644 --- a/logs/log.go +++ b/logs/log.go @@ -120,6 +120,8 @@ type BeeLogger struct { outputs []*nameLogger } +const defaultAsyncMsgLen = 1e3 + type nameLogger struct { Logger name string @@ -157,6 +159,9 @@ func (bl *BeeLogger) Async() *BeeLogger { return bl } bl.asynchronous = true + if bl.msgChanLen <= 0 { + bl.msgChanLen = defaultAsyncMsgLen + } bl.msgChan = make(chan *logMsg, bl.msgChanLen) logMsgPool = &sync.Pool{ New: func() interface{} { @@ -250,6 +255,11 @@ func (bl *BeeLogger) Write(p []byte) (n int, err error) { } func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error { + if !beeLogger.init { + bl.lock.Lock() + bl.setLogger(AdapterConsole) + bl.lock.Unlock() + } if logLevel == levelLoggerImpl { // set to emergency to ensure all log will be print out correctly logLevel = LevelEmergency @@ -465,12 +475,8 @@ func (bl *BeeLogger) flush() { } } -// BeeLogger references the used application logger. -var beeLogger *BeeLogger - -func init() { - beeLogger = NewLogger() -} +// beeLogger references the used application logger. +var beeLogger *BeeLogger = NewLogger() // GetLogger returns the default BeeLogger func GetBeeLogger() *BeeLogger { From 45f239012855c4b363dc07ab929ad021dfd97db7 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 25 Mar 2016 15:13:28 +0800 Subject: [PATCH 074/159] logger changed --- logs/log.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/logs/log.go b/logs/log.go index 11d54ef8..107c3b20 100644 --- a/logs/log.go +++ b/logs/log.go @@ -143,8 +143,8 @@ func NewLogger(channelLens ...int64) *BeeLogger { bl.level = LevelDebug bl.loggerFuncCallDepth = 2 bl.msgChanLen = append(channelLens, 0)[0] - if bl.msgChanLen < 0 { - bl.msgChanLen = 0 + if bl.msgChanLen <= 0 { + bl.msgChanLen = defaultAsyncMsgLen } bl.signalChan = make(chan string, 1) bl.setLogger(AdapterConsole) @@ -159,9 +159,6 @@ func (bl *BeeLogger) Async() *BeeLogger { return bl } bl.asynchronous = true - if bl.msgChanLen <= 0 { - bl.msgChanLen = defaultAsyncMsgLen - } bl.msgChan = make(chan *logMsg, bl.msgChanLen) logMsgPool = &sync.Pool{ New: func() interface{} { From 3ca44071e62e31ad1f4e0bbd8750dc95ca2662af Mon Sep 17 00:00:00 2001 From: miraclesu Date: Sat, 26 Mar 2016 21:51:05 +0800 Subject: [PATCH 075/159] orm: insert specified values for insertMulti --- orm/db.go | 6 ++---- orm/orm_test.go | 21 +++++++++++++++++++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/orm/db.go b/orm/db.go index af05e686..8c3b82c2 100644 --- a/orm/db.go +++ b/orm/db.go @@ -386,16 +386,14 @@ func (d *dbBase) InsertMulti(q dbQuerier, mi *modelInfo, sind reflect.Value, bul // } if i == 1 { - vus, err := d.collectValues(mi, ind, mi.fields.dbcols, true, true, &names, tz) + vus, err := d.collectValues(mi, ind, mi.fields.dbcols, false, true, &names, tz) if err != nil { return cnt, err } values = make([]interface{}, bulk*len(vus)) nums += copy(values, vus) - } else { - - vus, err := d.collectValues(mi, ind, mi.fields.dbcols, true, true, nil, tz) + vus, err := d.collectValues(mi, ind, mi.fields.dbcols, false, true, nil, tz) if err != nil { return cnt, err } diff --git a/orm/orm_test.go b/orm/orm_test.go index 2df93729..3f6e1566 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -2032,9 +2032,26 @@ func TestInsertAuto(t *testing.T) { Email: "auto@gmail.com", } - sid, err := dORM.Insert(su) + nid, err := dORM.Insert(su) throwFail(t, err) - throwFail(t, AssertIs(id, sid)) + throwFail(t, AssertIs(nid, id)) + + users := []User{ + {ID: int(id + 100), UserName: "auto_100"}, + {ID: int(id + 110), UserName: "auto_110"}, + {ID: int(id + 120), UserName: "auto_120"}, + } + num, err := dORM.InsertMulti(100, users) + throwFail(t, err) + throwFail(t, AssertIs(num, 3)) + + u = &User{ + UserName: "auto_121", + } + + nid, err = dORM.Insert(u) + throwFail(t, err) + throwFail(t, AssertIs(nid, id+120+1)) } func TestUintPk(t *testing.T) { From 1794c52d651cfc04b0655976ae3458f0c4d3df5c Mon Sep 17 00:00:00 2001 From: miraclesu Date: Sun, 27 Mar 2016 15:06:57 +0800 Subject: [PATCH 076/159] orm: fix postgres sequence value --- orm/db.go | 47 ++++++++++++++++++++++++++++++++++------------ orm/db_postgres.go | 19 +++++++++++++++++++ orm/types.go | 1 + 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/orm/db.go b/orm/db.go index 8c3b82c2..efc90e6e 100644 --- a/orm/db.go +++ b/orm/db.go @@ -71,7 +71,7 @@ type dbBase struct { var _ dbBaser = new(dbBase) // get struct columns values as interface slice. -func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string, skipAuto bool, insert bool, names *[]string, tz *time.Location) (values []interface{}, err error) { +func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string, skipAuto bool, insert bool, names *[]string, tz *time.Location) (values []interface{}, autoFields []string, err error) { if names == nil { ns := make([]string, 0, len(cols)) names = &ns @@ -90,11 +90,11 @@ func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string, } value, err := d.collectFieldValue(mi, fi, ind, insert, tz) if err != nil { - return nil, err + return nil, nil, err } // ignore empty value auto field - if fi.auto { + if insert && fi.auto { if fi.fieldType&IsPositiveIntegerField > 0 { if vu, ok := value.(uint64); !ok || vu == 0 { continue @@ -104,6 +104,7 @@ func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string, continue } } + autoFields = append(autoFields, fi.column) } *names, values = append(*names, column), append(values, value) @@ -278,7 +279,7 @@ func (d *dbBase) PrepareInsert(q dbQuerier, mi *modelInfo) (stmtQuerier, string, // insert struct with prepared statement and given struct reflect value. func (d *dbBase) InsertStmt(stmt stmtQuerier, mi *modelInfo, ind reflect.Value, tz *time.Location) (int64, error) { - values, err := d.collectValues(mi, ind, mi.fields.dbcols, true, true, nil, tz) + values, _, err := d.collectValues(mi, ind, mi.fields.dbcols, true, true, nil, tz) if err != nil { return 0, err } @@ -305,7 +306,7 @@ func (d *dbBase) Read(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Lo if len(cols) > 0 { var err error whereCols = make([]string, 0, len(cols)) - args, err = d.collectValues(mi, ind, cols, false, false, &whereCols, tz) + args, _, err = d.collectValues(mi, ind, cols, false, false, &whereCols, tz) if err != nil { return err } @@ -355,12 +356,20 @@ func (d *dbBase) Read(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Lo // execute insert sql dbQuerier with given struct reflect.Value. func (d *dbBase) Insert(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Location) (int64, error) { names := make([]string, 0, len(mi.fields.dbcols)) - values, err := d.collectValues(mi, ind, mi.fields.dbcols, false, true, &names, tz) + values, autoFields, err := d.collectValues(mi, ind, mi.fields.dbcols, false, true, &names, tz) if err != nil { return 0, err } - return d.InsertValue(q, mi, false, names, values) + id, err := d.InsertValue(q, mi, false, names, values) + if err != nil { + return 0, err + } + + if len(autoFields) > 0 { + err = d.ins.setval(q, mi, autoFields) + } + return id, err } // multi-insert sql with given slice struct reflect.Value. @@ -374,7 +383,7 @@ func (d *dbBase) InsertMulti(q dbQuerier, mi *modelInfo, sind reflect.Value, bul // typ := reflect.Indirect(mi.addrField).Type() - length := sind.Len() + length, autoFields := sind.Len(), make([]string, 0, 1) for i := 1; i <= length; i++ { @@ -386,14 +395,18 @@ func (d *dbBase) InsertMulti(q dbQuerier, mi *modelInfo, sind reflect.Value, bul // } if i == 1 { - vus, err := d.collectValues(mi, ind, mi.fields.dbcols, false, true, &names, tz) + var ( + vus []interface{} + err error + ) + vus, autoFields, err = d.collectValues(mi, ind, mi.fields.dbcols, false, true, &names, tz) if err != nil { return cnt, err } values = make([]interface{}, bulk*len(vus)) nums += copy(values, vus) } else { - vus, err := d.collectValues(mi, ind, mi.fields.dbcols, false, true, nil, tz) + vus, _, err := d.collectValues(mi, ind, mi.fields.dbcols, false, true, nil, tz) if err != nil { return cnt, err } @@ -415,7 +428,12 @@ func (d *dbBase) InsertMulti(q dbQuerier, mi *modelInfo, sind reflect.Value, bul } } - return cnt, nil + var err error + if len(autoFields) > 0 { + err = d.ins.setval(q, mi, autoFields) + } + + return cnt, err } // execute insert sql with given struct and given values. @@ -475,7 +493,7 @@ func (d *dbBase) Update(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time. setNames = make([]string, 0, len(cols)) } - setValues, err := d.collectValues(mi, ind, cols, true, false, &setNames, tz) + setValues, _, err := d.collectValues(mi, ind, cols, true, false, &setNames, tz) if err != nil { return 0, err } @@ -1565,6 +1583,11 @@ func (d *dbBase) HasReturningID(*modelInfo, *string) bool { return false } +// sync auto key +func (d *dbBase) setval(db dbQuerier, mi *modelInfo, autoFields []string) error { + return nil +} + // convert time from db. func (d *dbBase) TimeFromDB(t *time.Time, tz *time.Location) { *t = t.In(tz) diff --git a/orm/db_postgres.go b/orm/db_postgres.go index be4cd0bc..8fbcb88d 100644 --- a/orm/db_postgres.go +++ b/orm/db_postgres.go @@ -135,6 +135,25 @@ func (d *dbBasePostgres) HasReturningID(mi *modelInfo, query *string) bool { return true } +// sync auto key +func (d *dbBasePostgres) setval(db dbQuerier, mi *modelInfo, autoFields []string) error { + if len(autoFields) == 0 { + return nil + } + + Q := d.ins.TableQuote() + for _, name := range autoFields { + query := fmt.Sprintf("SELECT setval(pg_get_serial_sequence('%s', '%s'), (SELECT MAX(%s%s%s) FROM %s%s%s));", + mi.table, name, + Q, name, Q, + Q, mi.table, Q) + if _, err := db.Exec(query); err != nil { + return err + } + } + return nil +} + // show table sql for postgresql. func (d *dbBasePostgres) ShowTablesQuery() string { return "SELECT table_name FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema')" diff --git a/orm/types.go b/orm/types.go index 41933dd1..cb55e71a 100644 --- a/orm/types.go +++ b/orm/types.go @@ -420,4 +420,5 @@ type dbBaser interface { ShowColumnsQuery(string) string IndexExists(dbQuerier, string, string) bool collectFieldValue(*modelInfo, *fieldInfo, reflect.Value, bool, *time.Location) (interface{}, error) + setval(dbQuerier, *modelInfo, []string) error } From fb77464d69cb7cce2e0420482efb8e03f90fd272 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Sun, 27 Mar 2016 15:07:51 +0800 Subject: [PATCH 077/159] golink: map range only key stlye --- error_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/error_test.go b/error_test.go index f6e40c80..2fb8f962 100644 --- a/error_test.go +++ b/error_test.go @@ -41,7 +41,7 @@ func (ec *errorTestController) Get() { func TestErrorCode_01(t *testing.T) { registerDefaultErrorHandler() - for k, _ := range ErrorMaps { + for k := range ErrorMaps { r, _ := http.NewRequest("GET", "/error?code="+k, nil) w := httptest.NewRecorder() From f05bb2ecd33f4f38d21da165e122fcf2011964db Mon Sep 17 00:00:00 2001 From: JessonChan Date: Mon, 28 Mar 2016 15:18:51 +0800 Subject: [PATCH 078/159] add function of beego/logs --- logs/log.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/logs/log.go b/logs/log.go index 107c3b20..695691b2 100644 --- a/logs/log.go +++ b/logs/log.go @@ -152,13 +152,16 @@ func NewLogger(channelLens ...int64) *BeeLogger { } // Async set the log to asynchronous and start the goroutine -func (bl *BeeLogger) Async() *BeeLogger { +func (bl *BeeLogger) Async(msgLen ...int64) *BeeLogger { bl.lock.Lock() defer bl.lock.Unlock() if bl.asynchronous { return bl } bl.asynchronous = true + if len(msgLen) > 0 && msgLen[0] > 0 { + bl.msgChanLen = msgLen[0] + } bl.msgChan = make(chan *logMsg, bl.msgChanLen) logMsgPool = &sync.Pool{ New: func() interface{} { @@ -515,8 +518,8 @@ func Reset() { beeLogger.Reset() } -func Async() *BeeLogger { - return beeLogger.Async() +func Async(msgLen ...int64) *BeeLogger { + return beeLogger.Async(msgLen...) } // SetLevel sets the global log level used by the simple logger. @@ -524,12 +527,22 @@ func SetLevel(l int) { beeLogger.SetLevel(l) } +// EnableFuncCallDepth enable log funcCallDepth +func EnableFuncCallDepth(b bool) { + beeLogger.enableFuncCallDepth = b +} + // SetLogFuncCall set the CallDepth, default is 3 func SetLogFuncCall(b bool) { beeLogger.EnableFuncCallDepth(b) beeLogger.SetLogFuncCallDepth(3) } +// SetLogFuncCallDepth set log funcCallDepth +func SetLogFuncCallDepth(d int) { + beeLogger.loggerFuncCallDepth = d +} + // SetLogger sets a new logger. func SetLogger(adapter string, config ...string) error { err := beeLogger.SetLogger(adapter, config...) From 221306fff4a2614a6717e53f471f03fc275ac30a Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 29 Mar 2016 10:05:56 +0800 Subject: [PATCH 079/159] file rotate bug --- logs/file.go | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/logs/file.go b/logs/file.go index 159d4970..5901143b 100644 --- a/logs/file.go +++ b/logs/file.go @@ -60,14 +60,11 @@ type fileLogWriter struct { // newFileWriter create a FileLogWriter returning as LoggerInterface. func newFileWriter() Logger { w := &fileLogWriter{ - Filename: "", - MaxLines: 1000000, - MaxSize: 1 << 28, //256 MB - Daily: true, - MaxDays: 7, - Rotate: true, - Level: LevelTrace, - Perm: 0660, + Daily: true, + MaxDays: 7, + Rotate: true, + Level: LevelTrace, + Perm: 0660, } return w } @@ -259,8 +256,8 @@ func (w *fileLogWriter) deleteOldLog() { } }() - if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*w.MaxDays) { - if strings.HasPrefix(filepath.Base(path), w.fileNameOnly) && + if !info.IsDir() && info.ModTime().Add(24*time.Hour*time.Duration(w.MaxDays)).Before(time.Now()) { + if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) && strings.HasSuffix(filepath.Base(path), w.suffix) { os.Remove(path) } From 561e7115f37e454600f5ef842a0f65c08a0e88cb Mon Sep 17 00:00:00 2001 From: youngsterxyf Date: Tue, 29 Mar 2016 18:16:38 +0800 Subject: [PATCH 080/159] To support `go run` --- config.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/config.go b/config.go index 72045fd3..c1ee7ae6 100644 --- a/config.go +++ b/config.go @@ -106,6 +106,8 @@ var ( AppConfig *beegoAppConfig // AppPath is the absolute path to the app AppPath string + // workPath is the absolute path of the current dir + workPath string // GlobalSessions is the instance for the session manager GlobalSessions *session.Manager @@ -118,7 +120,8 @@ var ( func init() { AppPath, _ = filepath.Abs(filepath.Dir(os.Args[0])) - os.Chdir(AppPath) + workPath, _ = os.Getwd() + workPath, _ = filepath.Abs(workPath) BConfig = &Config{ AppName: "beego", @@ -180,10 +183,13 @@ func init() { }, } - appConfigPath = filepath.Join(AppPath, "conf", "app.conf") + appConfigPath = filepath.Join(workPath, "conf", "app.conf") if !utils.FileExists(appConfigPath) { - AppConfig = &beegoAppConfig{innerConfig: config.NewFakeConfig()} - return + appConfigPath = filepath.Join(AppPath, "conf", "app.conf") + if !utils.FileExists(appConfigPath) { + AppConfig = &beegoAppConfig{innerConfig: config.NewFakeConfig()} + return + } } if err := parseConfig(appConfigPath); err != nil { From 7e65338c871527f43ce02342588a58503f089afa Mon Sep 17 00:00:00 2001 From: ysqi Date: Tue, 29 Mar 2016 21:47:33 +0800 Subject: [PATCH 081/159] Change key format key format : ${ENV_PART||defaultValue} or ${ENV_PART} --- config/config.go | 65 +++++++++++++++++++++------------------- config/config_test.go | 55 ++++++++++++++++++++++++++++++++++ config/ini.go | 2 +- config/ini_test.go | 18 ++--------- config/json.go | 2 +- config/json_test.go | 20 +++---------- config/xml/xml.go | 2 +- config/xml/xml_test.go | 16 ++-------- config/yaml/yaml.go | 2 +- config/yaml/yaml_test.go | 16 ++-------- 10 files changed, 105 insertions(+), 93 deletions(-) create mode 100644 config/config_test.go diff --git a/config/config.go b/config/config.go index 6a159f82..9f41fb79 100644 --- a/config/config.go +++ b/config/config.go @@ -43,7 +43,6 @@ package config import ( "fmt" "os" - "strings" ) // Configer defines how to get and set value from configuration raw data. @@ -107,17 +106,17 @@ func NewConfigData(adapterName string, data []byte) (Configer, error) { return adapter.ParseData(data) } -// ChooseRealValueForMap convert all string value with environment variable. -func ChooseRealValueForMap(m map[string]interface{}) map[string]interface{} { +// ExpandValueEnvForMap convert all string value with environment variable. +func ExpandValueEnvForMap(m map[string]interface{}) map[string]interface{} { for k, v := range m { switch value := v.(type) { case string: - m[k] = ChooseRealValue(value) + m[k] = ExpandValueEnv(value) case map[string]interface{}: - m[k] = ChooseRealValueForMap(value) + m[k] = ExpandValueEnvForMap(value) case map[string]string: for k2, v2 := range value { - value[k2] = ChooseRealValue(v2) + value[k2] = ExpandValueEnv(v2) } m[k] = value } @@ -125,42 +124,48 @@ func ChooseRealValueForMap(m map[string]interface{}) map[string]interface{} { return m } -// ChooseRealValue returns value of convert with environment variable. +// ExpandValueEnv returns value of convert with environment variable. // -// Return environment variable if value start with "$$". +// Return environment variable if value start with "${" and end with "}". // Return default value if environment variable is empty or not exist. // -// It accept value formats "$$env" , "$$env||" , "$$env||defaultValue" , "defaultvalue". +// It accept value formats "${env}" , "${env||}}" , "${env||defaultValue}" , "defaultvalue". // Examples: -// v1 := config.ChooseRealValue("$$GOPATH") // return the GOPATH environment variable. -// v2 := config.ChooseRealValue("$$GOAsta||/usr/local/go/") // return the default value "/usr/local/go/". -// v3 := config.ChooseRealValue("Astaxie") // return the value "Astaxie". -func ChooseRealValue(value string) (realValue string) { +// v1 := config.ExpandValueEnv("${GOPATH}") // return the GOPATH environment variable. +// v2 := config.ExpandValueEnv("${GOAsta||/usr/local/go}") // return the default value "/usr/local/go/". +// v3 := config.ExpandValueEnv("Astaxie") // return the value "Astaxie". +func ExpandValueEnv(value string) (realValue string) { realValue = value - if value == "" { + vLen := len(value) + // 3 = ${} + if vLen < 3 { + return + } + // Need start with "${" and end with "}", then return. + if value[0] != '$' || value[1] != '{' || value[vLen-1] != '}' { return } - sign := "$$" // Environment variable identifier. - sep := "||" // Environment variable and default value separator. - - // Not use environment variable. - if strings.HasPrefix(value, sign) == false { - return - } - - sepIndex := strings.Index(value, sep) - if sepIndex == -1 { - realValue = os.Getenv(string(value[len(sign):])) - } else { - realValue = os.Getenv(string(value[len(sign):sepIndex])) - // Find defalut value. - if realValue == "" { - realValue = string(value[sepIndex+len(sep):]) + key := "" + defalutV := "" + // value start with "${" + for i := 2; i < vLen; i++ { + if value[i] == '|' && (i+1 < vLen && value[i+1] == '|') { + key = value[2:i] + defalutV = value[i+2 : vLen-1] // other string is default value. + break + } else if value[i] == '}' { + key = value[2:i] + break } } + realValue = os.Getenv(key) + if realValue == "" { + realValue = defalutV + } + return } diff --git a/config/config_test.go b/config/config_test.go new file mode 100644 index 00000000..15d6ffa6 --- /dev/null +++ b/config/config_test.go @@ -0,0 +1,55 @@ +// Copyright 2016 beego Author. All Rights Reserved. +// +// 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 config + +import ( + "os" + "testing" +) + +func TestExpandValueEnv(t *testing.T) { + + testCases := []struct { + item string + want string + }{ + {"", ""}, + {"$", "$"}, + {"{", "{"}, + {"{}", "{}"}, + {"${}", ""}, + {"${|}", ""}, + {"${}", ""}, + {"${{}}", ""}, + {"${{||}}", "}"}, + {"${pwd||}", ""}, + {"${pwd||}", ""}, + {"${pwd||}", ""}, + {"${pwd||}}", "}"}, + {"${pwd||{{||}}}", "{{||}}"}, + {"${GOPATH}", os.Getenv("GOPATH")}, + {"${GOPATH||}", os.Getenv("GOPATH")}, + {"${GOPATH||root}", os.Getenv("GOPATH")}, + {"${GOPATH_NOT||root}", "root"}, + {"${GOPATH_NOT||||root}", "||root"}, + } + + for _, c := range testCases { + if got := ExpandValueEnv(c.item); got != c.want { + t.Errorf("expand value error, item %q want %q, got %q", c.item, c.want, got) + } + } + +} diff --git a/config/ini.go b/config/ini.go index 1ec56238..53bd992d 100644 --- a/config/ini.go +++ b/config/ini.go @@ -166,7 +166,7 @@ func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) { val = bytes.Trim(val, `"`) } - cfg.data[section][key] = ChooseRealValue(string(val)) + cfg.data[section][key] = ExpandValueEnv(string(val)) if comment.Len() > 0 { cfg.keyComment[section+"."+key] = comment.String() comment.Reset() diff --git a/config/ini_test.go b/config/ini_test.go index a6a66198..83ff3668 100644 --- a/config/ini_test.go +++ b/config/ini_test.go @@ -42,20 +42,14 @@ needlogin = ON enableSession = Y enableCookie = N flag = 1 -path1 = $$GOPATH -path2 = $$GOPATH||/home/go -path3 = $$GOPATH$$GOPATH2||/home/go -token1 = $$TOKEN -token2 = $$TOKEN|| -token3 = $$TOKEN||astaxie -token4 = token$$TOKEN -token5 = $$TOKEN$$TOKEN||TOKEN +path1 = ${GOPATH} +path2 = ${GOPATH||/home/go} [demo] key1="asta" key2 = "xie" CaseInsensitive = true peers = one;two;three -password = $$GOPATH +password = ${GOPATH} ` keyValue = map[string]interface{}{ @@ -75,12 +69,6 @@ password = $$GOPATH "flag": true, "path1": os.Getenv("GOPATH"), "path2": os.Getenv("GOPATH"), - "path3": "/home/go", - "token1": "", - "token2": "", - "token3": "astaxie", - "token4": "token$$TOKEN", - "token5": "TOKEN", "demo::key1": "asta", "demo::key2": "xie", "demo::CaseInsensitive": true, diff --git a/config/json.go b/config/json.go index 3b4569b8..a0d93210 100644 --- a/config/json.go +++ b/config/json.go @@ -58,7 +58,7 @@ func (js *JSONConfig) ParseData(data []byte) (Configer, error) { x.data["rootArray"] = wrappingArray } - x.data = ChooseRealValueForMap(x.data) + x.data = ExpandValueEnvForMap(x.data) return x, nil } diff --git a/config/json_test.go b/config/json_test.go index 940916a1..24ff9644 100644 --- a/config/json_test.go +++ b/config/json_test.go @@ -86,25 +86,19 @@ func TestJson(t *testing.T) { "enableSession": "Y", "enableCookie": "N", "flag": 1, -"path1": "$$GOPATH", -"path2": "$$GOPATH||/home/go", -"path3": "$$GOPATH$$GOPATH2||/home/go", -"token1": "$$TOKEN", -"token2": "$$TOKEN||", -"token3": "$$TOKEN||astaxie", -"token4": "token$$TOKEN", -"token5": "$$TOKEN$$TOKEN||TOKEN", +"path1": "${GOPATH}", +"path2": "${GOPATH||/home/go}", "database": { "host": "host", "port": "port", "database": "database", "username": "username", - "password": "$$GOPATH", + "password": "${GOPATH}", "conns":{ "maxconnection":12, "autoconnect":true, "connectioninfo":"info", - "root": "$$GOPATH" + "root": "${GOPATH}" } } }` @@ -126,12 +120,6 @@ func TestJson(t *testing.T) { "flag": true, "path1": os.Getenv("GOPATH"), "path2": os.Getenv("GOPATH"), - "path3": "/home/go", - "token1": "", - "token2": "", - "token3": "astaxie", - "token4": "token$$TOKEN", - "token5": "TOKEN", "database::host": "host", "database::port": "port", "database::database": "database", diff --git a/config/xml/xml.go b/config/xml/xml.go index 63f3cb23..0c4e4d27 100644 --- a/config/xml/xml.go +++ b/config/xml/xml.go @@ -69,7 +69,7 @@ func (xc *Config) Parse(filename string) (config.Configer, error) { return nil, err } - x.data = config.ChooseRealValueForMap(d["config"].(map[string]interface{})) + x.data = config.ExpandValueEnvForMap(d["config"].(map[string]interface{})) return x, nil } diff --git a/config/xml/xml_test.go b/config/xml/xml_test.go index 825f4d0d..d8a09a59 100644 --- a/config/xml/xml_test.go +++ b/config/xml/xml_test.go @@ -35,14 +35,8 @@ func TestXML(t *testing.T) { dev false true -$$GOPATH -$$GOPATH||/home/go -$$GOPATH$$GOPATH2||/home/go -$$TOKEN -$$TOKEN|| -$$TOKEN||astaxie -token$$TOKEN -$$TOKEN$$TOKEN||TOKEN +${GOPATH} +${GOPATH||/home/go} ` keyValue = map[string]interface{}{ @@ -55,12 +49,6 @@ func TestXML(t *testing.T) { "copyrequestbody": true, "path1": os.Getenv("GOPATH"), "path2": os.Getenv("GOPATH"), - "path3": "/home/go", - "token1": "", - "token2": "", - "token3": "astaxie", - "token4": "token$$TOKEN", - "token5": "TOKEN", "error": "", "emptystrings": []string{}, } diff --git a/config/yaml/yaml.go b/config/yaml/yaml.go index 6a6f07c7..64e25cb3 100644 --- a/config/yaml/yaml.go +++ b/config/yaml/yaml.go @@ -110,7 +110,7 @@ func ReadYmlReader(path string) (cnf map[string]interface{}, err error) { log.Println("Not a Map? >> ", string(buf), data) cnf = nil } - cnf = config.ChooseRealValueForMap(cnf) + cnf = config.ExpandValueEnvForMap(cnf) return } diff --git a/config/yaml/yaml_test.go b/config/yaml/yaml_test.go index 0731778f..49cc1d1e 100644 --- a/config/yaml/yaml_test.go +++ b/config/yaml/yaml_test.go @@ -34,14 +34,8 @@ func TestYaml(t *testing.T) { "autorender": false "copyrequestbody": true "PATH": GOPATH -"path1": $$GOPATH -"path2": $$GOPATH||/home/go -"path3": $$GOPATH$$GOPATH2||/home/go -"token1": $$TOKEN -"token2": $$TOKEN|| -"token3": $$TOKEN||astaxie -"token4": token$$TOKEN -"token5": $$TOKEN$$TOKEN||TOKEN +"path1": ${GOPATH} +"path2": ${GOPATH||/home/go} "empty": "" ` @@ -56,12 +50,6 @@ func TestYaml(t *testing.T) { "PATH": "GOPATH", "path1": os.Getenv("GOPATH"), "path2": os.Getenv("GOPATH"), - "path3": "/home/go", - "token1": "", - "token2": "", - "token3": "astaxie", - "token4": "token$$TOKEN", - "token5": "TOKEN", "error": "", "emptystrings": []string{}, } From adaa4ab929cd3cdca95010a7a77885cf373e7155 Mon Sep 17 00:00:00 2001 From: saturn4er Date: Tue, 29 Mar 2016 17:15:43 +0300 Subject: [PATCH 082/159] Fix index out of range if there is no file extension --- template.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/template.go b/template.go index f922e6ee..5cc627a5 100644 --- a/template.go +++ b/template.go @@ -167,9 +167,11 @@ func BuildTemplate(dir string, files ...string) error { for _, file := range v { if buildAllFiles || utils.InSlice(file, files) { templatesLock.Lock() - fileExt := filepath.Ext(file)[1:] + ext := filepath.Ext(file) var t TemplateRenderer - if fn, ok := beeTemplateEngines[fileExt]; ok { + if len(ext) == 0 { + t, err = getTemplate(self.root, file, v...) + } else if fn, ok := beeTemplateEngines[ext[1:]]; ok { t, err = fn(self.root, file, beegoTplFuncMap) } else { t, err = getTemplate(self.root, file, v...) From e281b6e82a49be5bfe5e0137f1d5c5101ca8ef0d Mon Sep 17 00:00:00 2001 From: youngsterxyf Date: Wed, 30 Mar 2016 10:49:39 +0800 Subject: [PATCH 083/159] improve --- config.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/config.go b/config.go index c1ee7ae6..22074bd7 100644 --- a/config.go +++ b/config.go @@ -106,8 +106,6 @@ var ( AppConfig *beegoAppConfig // AppPath is the absolute path to the app AppPath string - // workPath is the absolute path of the current dir - workPath string // GlobalSessions is the instance for the session manager GlobalSessions *session.Manager @@ -118,11 +116,6 @@ var ( ) func init() { - AppPath, _ = filepath.Abs(filepath.Dir(os.Args[0])) - - workPath, _ = os.Getwd() - workPath, _ = filepath.Abs(workPath) - BConfig = &Config{ AppName: "beego", RunMode: DEV, @@ -183,6 +176,16 @@ func init() { }, } + var err error + + if AppPath, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil { + panic(err) + } + workPath, err := os.Getwd() + if err != nil { + panic(err) + } + appConfigPath = filepath.Join(workPath, "conf", "app.conf") if !utils.FileExists(appConfigPath) { appConfigPath = filepath.Join(AppPath, "conf", "app.conf") @@ -192,7 +195,7 @@ func init() { } } - if err := parseConfig(appConfigPath); err != nil { + if err = parseConfig(appConfigPath); err != nil { panic(err) } } From eae2147735b8af0633c75b0b3ddabf8f74a43b80 Mon Sep 17 00:00:00 2001 From: mishudark Date: Tue, 29 Mar 2016 23:28:53 -0600 Subject: [PATCH 084/159] chore(output.go): delete not used variable (status int) in check status functions --- context/output.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/context/output.go b/context/output.go index 17404702..0de0a60c 100644 --- a/context/output.go +++ b/context/output.go @@ -269,55 +269,55 @@ func (output *BeegoOutput) SetStatus(status int) { // IsCachable returns boolean of this request is cached. // HTTP 304 means cached. -func (output *BeegoOutput) IsCachable(status int) bool { +func (output *BeegoOutput) IsCachable() bool { return output.Status >= 200 && output.Status < 300 || output.Status == 304 } // IsEmpty returns boolean of this request is empty. // HTTP 201,204 and 304 means empty. -func (output *BeegoOutput) IsEmpty(status int) bool { +func (output *BeegoOutput) IsEmpty() bool { return output.Status == 201 || output.Status == 204 || output.Status == 304 } // IsOk returns boolean of this request runs well. // HTTP 200 means ok. -func (output *BeegoOutput) IsOk(status int) bool { +func (output *BeegoOutput) IsOk() bool { return output.Status == 200 } // IsSuccessful returns boolean of this request runs successfully. // HTTP 2xx means ok. -func (output *BeegoOutput) IsSuccessful(status int) bool { +func (output *BeegoOutput) IsSuccessful() bool { return output.Status >= 200 && output.Status < 300 } // IsRedirect returns boolean of this request is redirection header. // HTTP 301,302,307 means redirection. -func (output *BeegoOutput) IsRedirect(status int) bool { +func (output *BeegoOutput) IsRedirect() bool { return output.Status == 301 || output.Status == 302 || output.Status == 303 || output.Status == 307 } // IsForbidden returns boolean of this request is forbidden. // HTTP 403 means forbidden. -func (output *BeegoOutput) IsForbidden(status int) bool { +func (output *BeegoOutput) IsForbidden() bool { return output.Status == 403 } // IsNotFound returns boolean of this request is not found. // HTTP 404 means forbidden. -func (output *BeegoOutput) IsNotFound(status int) bool { +func (output *BeegoOutput) IsNotFound() bool { return output.Status == 404 } // IsClientError returns boolean of this request client sends error data. // HTTP 4xx means forbidden. -func (output *BeegoOutput) IsClientError(status int) bool { +func (output *BeegoOutput) IsClientError() bool { return output.Status >= 400 && output.Status < 500 } // IsServerError returns boolean of this server handler errors. // HTTP 5xx means server internal error. -func (output *BeegoOutput) IsServerError(status int) bool { +func (output *BeegoOutput) IsServerError() bool { return output.Status >= 500 && output.Status < 600 } From 8e82ed319b11293a50f6f4d94ee26f5f72e4b8c8 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 30 Mar 2016 14:31:16 +0800 Subject: [PATCH 085/159] beelog bug fixed --- logs/log.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logs/log.go b/logs/log.go index 695691b2..c43782f3 100644 --- a/logs/log.go +++ b/logs/log.go @@ -255,7 +255,7 @@ func (bl *BeeLogger) Write(p []byte) (n int, err error) { } func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error { - if !beeLogger.init { + if !bl.init { bl.lock.Lock() bl.setLogger(AdapterConsole) bl.lock.Unlock() From 99436a75b169fae6b29b2a7746a6cd4b8688da12 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 30 Mar 2016 14:31:28 +0800 Subject: [PATCH 086/159] format time header 5% faster than before --- logs/logger.go | 57 +++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/logs/logger.go b/logs/logger.go index b25bfaef..0d1125a8 100644 --- a/logs/logger.go +++ b/logs/logger.go @@ -36,43 +36,44 @@ func (lg *logWriter) println(when time.Time, msg string) { lg.Unlock() } +const y1 = `0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999` +const y2 = `0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789` +const mo1 = `000000000111` +const mo2 = `123456789012` +const d1 = `0000000001111111111222222222233` +const d2 = `1234567890123456789012345678901` +const h1 = `000000000011111111112222` +const h2 = `012345678901234567890123` +const mi1 = `000000000011111111112222222222333333333344444444445555555555` +const mi2 = `012345678901234567890123456789012345678901234567890123456789` +const s1 = `000000000011111111112222222222333333333344444444445555555555` +const s2 = `012345678901234567890123456789012345678901234567890123456789` + func formatTimeHeader(when time.Time) ([]byte, int) { y, mo, d := when.Date() h, mi, s := when.Clock() - //len(2006/01/02 15:03:04)==19 + //len("2006/01/02 15:03:04 ")==20 var buf [20]byte - t := 3 - for y >= 10 { - p := y / 10 - buf[t] = byte('0' + y - p*10) - y = p - t-- - } - buf[0] = byte('0' + y) + + buf[0] = '2' + buf[1] = '0' + buf[2] = y1[y-2000] + buf[3] = y2[y-2000] buf[4] = '/' - if mo > 9 { - buf[5] = '1' - buf[6] = byte('0' + mo - 9) - } else { - buf[5] = '0' - buf[6] = byte('0' + mo) - } + buf[5] = mo1[mo] + buf[6] = mo2[mo] buf[7] = '/' - t = d / 10 - buf[8] = byte('0' + t) - buf[9] = byte('0' + d - t*10) + buf[8] = d1[d] + buf[9] = d2[d] buf[10] = ' ' - t = h / 10 - buf[11] = byte('0' + t) - buf[12] = byte('0' + h - t*10) + buf[11] = h1[h] + buf[12] = h2[h] buf[13] = ':' - t = mi / 10 - buf[14] = byte('0' + t) - buf[15] = byte('0' + mi - t*10) + buf[14] = mi1[mi] + buf[15] = mi2[mi] buf[16] = ':' - t = s / 10 - buf[17] = byte('0' + t) - buf[18] = byte('0' + s - t*10) + buf[17] = s1[s] + buf[18] = s2[s] buf[19] = ' ' return buf[0:], d From 814b673e3ce24e5880f4686abaffaf4d4e037685 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 30 Mar 2016 14:34:52 +0800 Subject: [PATCH 087/159] add a comment to the future bug --- logs/logger.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/logs/logger.go b/logs/logger.go index 0d1125a8..2f47e569 100644 --- a/logs/logger.go +++ b/logs/logger.go @@ -52,19 +52,21 @@ const s2 = `012345678901234567890123456789012345678901234567890123456789` func formatTimeHeader(when time.Time) ([]byte, int) { y, mo, d := when.Date() h, mi, s := when.Clock() - //len("2006/01/02 15:03:04 ")==20 + //len("2006/01/02 15:04:05 ")==20 var buf [20]byte + //change to '3' after 984 years, LOL buf[0] = '2' + //change to '1' after 84 years, LOL buf[1] = '0' buf[2] = y1[y-2000] buf[3] = y2[y-2000] buf[4] = '/' - buf[5] = mo1[mo] - buf[6] = mo2[mo] + buf[5] = mo1[mo-1] + buf[6] = mo2[mo-1] buf[7] = '/' - buf[8] = d1[d] - buf[9] = d2[d] + buf[8] = d1[d-1] + buf[9] = d2[d-1] buf[10] = ' ' buf[11] = h1[h] buf[12] = h2[h] From 96a5d09ef0f9c19ecba5555ad06fe0f8708ad944 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 30 Mar 2016 15:13:01 +0800 Subject: [PATCH 088/159] add format header test --- logs/logger_test.go | 57 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 logs/logger_test.go diff --git a/logs/logger_test.go b/logs/logger_test.go new file mode 100644 index 00000000..4627853a --- /dev/null +++ b/logs/logger_test.go @@ -0,0 +1,57 @@ +// Copyright 2016 beego Author. All Rights Reserved. +// +// 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 logs + +import ( + "testing" + "time" +) + +func TestFormatHeader_0(t *testing.T) { + tm := time.Now() + if tm.Year() >= 2100 { + t.FailNow() + } + dur := time.Second + for { + if tm.Year() >= 2100 { + break + } + h, _ := formatTimeHeader(tm) + if tm.Format("2006/01/02 15:04:05 ") != string(h) { + t.Log(tm) + t.FailNow() + } + tm = tm.Add(dur) + dur *= 2 + } +} + +func TestFormatHeader_1(t *testing.T) { + tm := time.Now() + year := tm.Year() + dur := time.Second + for { + if tm.Year() >= year+1 { + break + } + h, _ := formatTimeHeader(tm) + if tm.Format("2006/01/02 15:04:05 ") != string(h) { + t.Log(tm) + t.FailNow() + } + tm = tm.Add(dur) + } +} From 734bbb33379cf17441b26f76aa90b756f7eb0a8f Mon Sep 17 00:00:00 2001 From: astaxie Date: Wed, 30 Mar 2016 15:48:38 +0800 Subject: [PATCH 089/159] remove some space --- config.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config.go b/config.go index 22074bd7..2c91ffd1 100644 --- a/config.go +++ b/config.go @@ -175,9 +175,7 @@ func init() { Outputs: map[string]string{"console": ""}, }, } - var err error - if AppPath, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil { panic(err) } @@ -185,7 +183,6 @@ func init() { if err != nil { panic(err) } - appConfigPath = filepath.Join(workPath, "conf", "app.conf") if !utils.FileExists(appConfigPath) { appConfigPath = filepath.Join(AppPath, "conf", "app.conf") @@ -194,7 +191,6 @@ func init() { return } } - if err = parseConfig(appConfigPath); err != nil { panic(err) } From 8ec6dd93cf750e2fd4bacd360072f19280d96449 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 1 Apr 2016 18:10:00 +0800 Subject: [PATCH 090/159] make template execution be expected --- controller.go | 6 +++--- template.go | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/controller.go b/controller.go index 9d265758..d3abdf38 100644 --- a/controller.go +++ b/controller.go @@ -208,7 +208,7 @@ func (c *Controller) RenderBytes() ([]byte, error) { continue } buf.Reset() - err = executeTemplate(&buf, sectionTpl, c.Data) + err = ExecuteTemplate(&buf, sectionTpl, c.Data) if err != nil { return nil, err } @@ -217,7 +217,7 @@ func (c *Controller) RenderBytes() ([]byte, error) { } buf.Reset() - executeTemplate(&buf, c.Layout, c.Data) + ExecuteTemplate(&buf, c.Layout, c.Data) } return buf.Bytes(), err } @@ -242,7 +242,7 @@ func (c *Controller) renderTemplate() (bytes.Buffer, error) { } BuildTemplate(BConfig.WebConfig.ViewsPath, buildFiles...) } - return buf, executeTemplate(&buf, c.TplName, c.Data) + return buf, ExecuteTemplate(&buf, c.TplName, c.Data) } // Redirect sends the redirection response to url with status code. diff --git a/template.go b/template.go index f91222cd..63eae741 100644 --- a/template.go +++ b/template.go @@ -41,7 +41,10 @@ var ( beeTemplateEngines = map[string]templateHandler{} ) -func executeTemplate(wr io.Writer, name string, data interface{}) error { +// ExecuteTemplate applies the template with name to the specified data object, +// writing the output to wr. +// A template will be executed safely in parallel. +func ExecuteTemplate(wr io.Writer, name string, data interface{}) error { if BConfig.RunMode == DEV { templatesLock.RLock() defer templatesLock.RUnlock() From d49c7f96cb746ea2c6ce74badd92b7357d86d616 Mon Sep 17 00:00:00 2001 From: Ivan Cadri Date: Sat, 2 Apr 2016 19:57:47 +0200 Subject: [PATCH 091/159] added functionality for column type time updated the model_fields to cater for the time field type --- namespace_test.go | 12 ++++----- orm/cmd_utils.go | 4 ++- orm/db.go | 18 ++++++++----- orm/db_utils.go | 18 ++++++++++--- orm/models_fields.go | 60 +++++++++++++++++++++++++++++++++++++++++--- orm/models_info_f.go | 7 ++++-- orm/models_test.go | 2 ++ orm/orm_test.go | 21 +++++++++++++--- 8 files changed, 117 insertions(+), 25 deletions(-) diff --git a/namespace_test.go b/namespace_test.go index a92ae3ef..fc02b5fb 100644 --- a/namespace_test.go +++ b/namespace_test.go @@ -61,8 +61,8 @@ func TestNamespaceNest(t *testing.T) { ns.Namespace( NewNamespace("/admin"). Get("/order", func(ctx *context.Context) { - ctx.Output.Body([]byte("order")) - }), + ctx.Output.Body([]byte("order")) + }), ) AddNamespace(ns) BeeApp.Handlers.ServeHTTP(w, r) @@ -79,8 +79,8 @@ func TestNamespaceNestParam(t *testing.T) { ns.Namespace( NewNamespace("/admin"). Get("/order/:id", func(ctx *context.Context) { - ctx.Output.Body([]byte(ctx.Input.Param(":id"))) - }), + ctx.Output.Body([]byte(ctx.Input.Param(":id"))) + }), ) AddNamespace(ns) BeeApp.Handlers.ServeHTTP(w, r) @@ -124,8 +124,8 @@ func TestNamespaceFilter(t *testing.T) { ctx.Output.Body([]byte("this is Filter")) }). Get("/user/:id", func(ctx *context.Context) { - ctx.Output.Body([]byte(ctx.Input.Param(":id"))) - }) + ctx.Output.Body([]byte(ctx.Input.Param(":id"))) + }) AddNamespace(ns) BeeApp.Handlers.ServeHTTP(w, r) if w.Body.String() != "this is Filter" { diff --git a/orm/cmd_utils.go b/orm/cmd_utils.go index da0ee8ab..13f35722 100644 --- a/orm/cmd_utils.go +++ b/orm/cmd_utils.go @@ -55,6 +55,8 @@ checkColumn: col = fmt.Sprintf(T["string"], fieldSize) case TypeTextField: col = T["string-text"] + case TypeTimeField: + col = T["time.Time-clock"] case TypeDateField: col = T["time.Time-date"] case TypeDateTimeField: @@ -264,7 +266,7 @@ func getColumnDefault(fi *fieldInfo) string { // These defaults will be useful if there no config value orm:"default" and NOT NULL is on switch fi.fieldType { - case TypeDateField, TypeDateTimeField, TypeTextField: + case TypeTimeField, TypeDateField, TypeDateTimeField, TypeTextField: return v case TypeBitField, TypeSmallIntegerField, TypeIntegerField, diff --git a/orm/db.go b/orm/db.go index efc90e6e..04cdc30a 100644 --- a/orm/db.go +++ b/orm/db.go @@ -24,6 +24,7 @@ import ( ) const ( + formatTime = "15:04:05" formatDate = "2006-01-02" formatDateTime = "2006-01-02 15:04:05" ) @@ -175,7 +176,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val value = field.Float() } } - case TypeDateField, TypeDateTimeField: + case TypeTimeField, TypeDateField, TypeDateTimeField: value = field.Interface() if t, ok := value.(time.Time); ok { d.ins.TimeToDB(&t, tz) @@ -229,7 +230,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val } } switch fi.fieldType { - case TypeDateField, TypeDateTimeField: + case TypeTimeField, TypeDateField, TypeDateTimeField: if fi.autoNow || fi.autoNowAdd && insert { if insert { if t, ok := value.(time.Time); ok && !t.IsZero() { @@ -1098,7 +1099,7 @@ setValue: } else { value = str.String() } - case fieldType == TypeDateField || fieldType == TypeDateTimeField: + case fieldType == TypeTimeField || fieldType == TypeDateField || fieldType == TypeDateTimeField: if str == nil { switch t := val.(type) { case time.Time: @@ -1118,15 +1119,20 @@ setValue: if len(s) >= 19 { s = s[:19] t, err = time.ParseInLocation(formatDateTime, s, tz) - } else { + } else if len(s) >= 10 { if len(s) > 10 { s = s[:10] } t, err = time.ParseInLocation(formatDate, s, tz) + } else if len(s) >= 8 { + if len(s) > 8 { + s = s[:8] + } + t, err = time.ParseInLocation(formatTime, s, tz) } t = t.In(DefaultTimeLoc) - if err != nil && s != "0000-00-00" && s != "0000-00-00 00:00:00" { + if err != nil && s != "00:00:00" && s != "0000-00-00" && s != "0000-00-00 00:00:00" { tErr = err goto end } @@ -1255,7 +1261,7 @@ setValue: field.SetString(value.(string)) } } - case fieldType == TypeDateField || fieldType == TypeDateTimeField: + case fieldType == TypeTimeField || fieldType == TypeDateField || fieldType == TypeDateTimeField: if isNative { if value == nil { value = time.Time{} diff --git a/orm/db_utils.go b/orm/db_utils.go index ff36b286..cf465d02 100644 --- a/orm/db_utils.go +++ b/orm/db_utils.go @@ -74,24 +74,32 @@ outFor: case reflect.String: v := val.String() if fi != nil { - if fi.fieldType == TypeDateField || fi.fieldType == TypeDateTimeField { + if fi.fieldType == TypeTimeField || fi.fieldType == TypeDateField || fi.fieldType == TypeDateTimeField { var t time.Time var err error if len(v) >= 19 { s := v[:19] t, err = time.ParseInLocation(formatDateTime, s, DefaultTimeLoc) - } else { + } else if len(v) >= 10 { s := v if len(v) > 10 { s = v[:10] } t, err = time.ParseInLocation(formatDate, s, tz) + } else { + s := v + if len(s) > 8 { + s = v[:8] + } + t, err = time.ParseInLocation(formatTime, s, tz) } if err == nil { if fi.fieldType == TypeDateField { v = t.In(tz).Format(formatDate) - } else { + } else if fi.fieldType == TypeDateTimeField { v = t.In(tz).Format(formatDateTime) + } else { + v = t.In(tz).Format(formatTime) } } } @@ -137,8 +145,10 @@ outFor: if v, ok := arg.(time.Time); ok { if fi != nil && fi.fieldType == TypeDateField { arg = v.In(tz).Format(formatDate) - } else { + } else if fi.fieldType == TypeDateTimeField { arg = v.In(tz).Format(formatDateTime) + } else { + arg = v.In(tz).Format(formatTime) } } else { typ := val.Type() diff --git a/orm/models_fields.go b/orm/models_fields.go index ad1fb6f9..1bfbfb2f 100644 --- a/orm/models_fields.go +++ b/orm/models_fields.go @@ -25,6 +25,7 @@ const ( TypeBooleanField = 1 << iota TypeCharField TypeTextField + TypeTimeField TypeDateField TypeDateTimeField TypeBitField @@ -46,9 +47,9 @@ const ( // Define some logic enum const ( - IsIntegerField = ^-TypePositiveBigIntegerField >> 4 << 5 - IsPositiveIntegerField = ^-TypePositiveBigIntegerField >> 8 << 9 - IsRelField = ^-RelReverseMany >> 14 << 15 + IsIntegerField = ^-TypePositiveBigIntegerField >> 5 << 6 + IsPositiveIntegerField = ^-TypePositiveBigIntegerField >> 9 << 10 + IsRelField = ^-RelReverseMany >> 15 << 16 IsFieldType = ^-RelReverseMany<<1 + 1 ) @@ -145,6 +146,59 @@ func (e *CharField) RawValue() interface{} { // verify CharField implement Fielder var _ Fielder = new(CharField) +// A time, represented in go by a time.Time instance. +// only time values like 10:00:00 +// Has a few extra, optional attr tag: +// +// auto_now: +// Automatically set the field to now every time the object is saved. Useful for “last-modified” timestamps. +// Note that the current date is always used; it’s not just a default value that you can override. +// +// auto_now_add: +// Automatically set the field to now when the object is first created. Useful for creation of timestamps. +// Note that the current date is always used; it’s not just a default value that you can override. +// +// eg: `orm:"auto_now"` or `orm:"auto_now_add"` +type TimeField time.Time + +func (e TimeField) Value() time.Time { + return time.Time(e) +} + +func (e *TimeField) Set(d time.Time) { + *e = TimeField(d) +} + +func (e *TimeField) String() string { + return e.Value().String() +} + +func (e *TimeField) FieldType() int { + return TypeDateField +} + +func (e *TimeField) SetRaw(value interface{}) error { + switch d := value.(type) { + case time.Time: + e.Set(d) + case string: + v, err := timeParse(d, formatTime) + if err != nil { + e.Set(v) + } + return err + default: + return fmt.Errorf(" unknown value `%s`", value) + } + return nil +} + +func (e *TimeField) RawValue() interface{} { + return e.Value() +} + +var _ Fielder = new(TimeField) + // DateField A date, represented in go by a time.Time instance. // only date values like 2006-01-02 // Has a few extra, optional attr tag: diff --git a/orm/models_info_f.go b/orm/models_info_f.go index 996a2f40..20a7c9d6 100644 --- a/orm/models_info_f.go +++ b/orm/models_info_f.go @@ -248,6 +248,9 @@ checkType: if fieldType == TypeDateTimeField && tags["type"] == "date" { fieldType = TypeDateField } + if fieldType == TypeTimeField && tags["type"] == "time" { + fieldType = TypeTimeField + } } switch fieldType { @@ -353,7 +356,7 @@ checkType: case TypeTextField: fi.index = false fi.unique = false - case TypeDateField, TypeDateTimeField: + case TypeTimeField, TypeDateField, TypeDateTimeField: if attrs["auto_now"] { fi.autoNow = true } else if attrs["auto_now_add"] { @@ -406,7 +409,7 @@ checkType: fi.index = false } - if fi.auto || fi.pk || fi.unique || fieldType == TypeDateField || fieldType == TypeDateTimeField { + if fi.auto || fi.pk || fi.unique || fieldType == TypeTimeField || fieldType == TypeDateField || fieldType == TypeDateTimeField { // can not set default initial.Clear() } diff --git a/orm/models_test.go b/orm/models_test.go index f42d725e..cbc51dcc 100644 --- a/orm/models_test.go +++ b/orm/models_test.go @@ -112,6 +112,7 @@ type Data struct { Boolean bool Char string `orm:"size(50)"` Text string `orm:"type(text)"` + Time time.Time `orm:"type(time)"` Date time.Time `orm:"type(date)"` DateTime time.Time `orm:"column(datetime)"` Byte byte @@ -136,6 +137,7 @@ type DataNull struct { Boolean bool `orm:"null"` Char string `orm:"null;size(50)"` Text string `orm:"null;type(text)"` + Time time.Time `orm:"null;type(time)"` Date time.Time `orm:"null;type(date)"` DateTime time.Time `orm:"null;column(datetime)"` Byte byte `orm:"null"` diff --git a/orm/orm_test.go b/orm/orm_test.go index 3f6e1566..0c615328 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -34,6 +34,7 @@ var _ = os.PathSeparator var ( testDate = formatDate + " -0700" testDateTime = formatDateTime + " -0700" + testTime = formatTime + " -0700" ) type argAny []interface{} @@ -240,6 +241,7 @@ var DataValues = map[string]interface{}{ "Boolean": true, "Char": "char", "Text": "text", + "Time": time.Now(), "Date": time.Now(), "DateTime": time.Now(), "Byte": byte(1<<8 - 1), @@ -267,7 +269,6 @@ func TestDataTypes(t *testing.T) { e := ind.FieldByName(name) e.Set(reflect.ValueOf(value)) } - id, err := dORM.Insert(&d) throwFail(t, err) throwFail(t, AssertIs(id, 1)) @@ -288,6 +289,9 @@ func TestDataTypes(t *testing.T) { case "DateTime": vu = vu.(time.Time).In(DefaultTimeLoc).Format(testDateTime) value = value.(time.Time).In(DefaultTimeLoc).Format(testDateTime) + case "Time": + vu = vu.(time.Time).In(DefaultTimeLoc).Format(testTime) + value = value.(time.Time).In(DefaultTimeLoc).Format(testTime) } throwFail(t, AssertIs(vu == value, true), value, vu) } @@ -1521,6 +1525,7 @@ func TestRawQueryRow(t *testing.T) { Boolean bool Char string Text string + Time time.Time Date time.Time DateTime time.Time Byte byte @@ -1549,14 +1554,14 @@ func TestRawQueryRow(t *testing.T) { Q := dDbBaser.TableQuote() cols := []string{ - "id", "boolean", "char", "text", "date", "datetime", "byte", "rune", "int", "int8", "int16", "int32", + "id", "boolean", "char", "text", "time", "date", "datetime", "byte", "rune", "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64", "decimal", } sep := fmt.Sprintf("%s, %s", Q, Q) query := fmt.Sprintf("SELECT %s%s%s FROM data WHERE id = ?", Q, strings.Join(cols, sep), Q) var id int values := []interface{}{ - &id, &Boolean, &Char, &Text, &Date, &DateTime, &Byte, &Rune, &Int, &Int8, &Int16, &Int32, + &id, &Boolean, &Char, &Text, &Time, &Date, &DateTime, &Byte, &Rune, &Int, &Int8, &Int16, &Int32, &Int64, &Uint, &Uint8, &Uint16, &Uint32, &Uint64, &Float32, &Float64, &Decimal, } err := dORM.Raw(query, 1).QueryRow(values...) @@ -1567,6 +1572,10 @@ func TestRawQueryRow(t *testing.T) { switch col { case "id": throwFail(t, AssertIs(id, 1)) + case "time": + v = v.(time.Time).In(DefaultTimeLoc) + value := dataValues[col].(time.Time).In(DefaultTimeLoc) + throwFail(t, AssertIs(v, value, testTime)) case "date": v = v.(time.Time).In(DefaultTimeLoc) value := dataValues[col].(time.Time).In(DefaultTimeLoc) @@ -1614,6 +1623,9 @@ func TestQueryRows(t *testing.T) { e := ind.FieldByName(name) vu := e.Interface() switch name { + case "Time": + vu = vu.(time.Time).In(DefaultTimeLoc).Format(testTime) + value = value.(time.Time).In(DefaultTimeLoc).Format(testTime) case "Date": vu = vu.(time.Time).In(DefaultTimeLoc).Format(testDate) value = value.(time.Time).In(DefaultTimeLoc).Format(testDate) @@ -1638,6 +1650,9 @@ func TestQueryRows(t *testing.T) { e := ind.FieldByName(name) vu := e.Interface() switch name { + case "Time": + vu = vu.(time.Time).In(DefaultTimeLoc).Format(testTime) + value = value.(time.Time).In(DefaultTimeLoc).Format(testTime) case "Date": vu = vu.(time.Time).In(DefaultTimeLoc).Format(testDate) value = value.(time.Time).In(DefaultTimeLoc).Format(testDate) From 885d45db052eb5d73625a683b0d0c7c220de82ec Mon Sep 17 00:00:00 2001 From: ysqi Date: Mon, 4 Apr 2016 21:32:43 +0800 Subject: [PATCH 092/159] fix the issue #1850,the source of the problem is PR #1805 --- error.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/error.go b/error.go index 8cfa0c67..bad08d86 100644 --- a/error.go +++ b/error.go @@ -341,7 +341,7 @@ func responseError(rw http.ResponseWriter, r *http.Request, errCode int, errCont data := map[string]interface{}{ "Title": http.StatusText(errCode), "BeegoVersion": VERSION, - "Content": errContent, + "Content": template.HTML(errContent), } t.Execute(rw, data) } From 813f47fd4150544f6346107277d39376076a4ea5 Mon Sep 17 00:00:00 2001 From: astaxie Date: Tue, 5 Apr 2016 15:38:42 +0800 Subject: [PATCH 093/159] gofmt test files --- namespace_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/namespace_test.go b/namespace_test.go index a92ae3ef..fc02b5fb 100644 --- a/namespace_test.go +++ b/namespace_test.go @@ -61,8 +61,8 @@ func TestNamespaceNest(t *testing.T) { ns.Namespace( NewNamespace("/admin"). Get("/order", func(ctx *context.Context) { - ctx.Output.Body([]byte("order")) - }), + ctx.Output.Body([]byte("order")) + }), ) AddNamespace(ns) BeeApp.Handlers.ServeHTTP(w, r) @@ -79,8 +79,8 @@ func TestNamespaceNestParam(t *testing.T) { ns.Namespace( NewNamespace("/admin"). Get("/order/:id", func(ctx *context.Context) { - ctx.Output.Body([]byte(ctx.Input.Param(":id"))) - }), + ctx.Output.Body([]byte(ctx.Input.Param(":id"))) + }), ) AddNamespace(ns) BeeApp.Handlers.ServeHTTP(w, r) @@ -124,8 +124,8 @@ func TestNamespaceFilter(t *testing.T) { ctx.Output.Body([]byte("this is Filter")) }). Get("/user/:id", func(ctx *context.Context) { - ctx.Output.Body([]byte(ctx.Input.Param(":id"))) - }) + ctx.Output.Body([]byte(ctx.Input.Param(":id"))) + }) AddNamespace(ns) BeeApp.Handlers.ServeHTTP(w, r) if w.Body.String() != "this is Filter" { From 301dcfb6264dad78521481a146b6c46214d36650 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 8 Apr 2016 14:04:10 +0800 Subject: [PATCH 094/159] context xsrf bug fixed --- context/context.go | 1 + 1 file changed, 1 insertion(+) diff --git a/context/context.go b/context/context.go index fee5e1c5..2735a5b3 100644 --- a/context/context.go +++ b/context/context.go @@ -65,6 +65,7 @@ func (ctx *Context) Reset(rw http.ResponseWriter, r *http.Request) { ctx.ResponseWriter.reset(rw) ctx.Input.Reset(ctx) ctx.Output.Reset(ctx) + ctx._xsrfToken = "" } // Redirect does redirection to localurl with http header status code. From a99c0d4025e41881bed27276c5a035a410ae879e Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 8 Apr 2016 14:04:25 +0800 Subject: [PATCH 095/159] context xsrf test --- context/context_test.go | 48 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 context/context_test.go diff --git a/context/context_test.go b/context/context_test.go new file mode 100644 index 00000000..82bb3342 --- /dev/null +++ b/context/context_test.go @@ -0,0 +1,48 @@ +// Copyright 2016 beego Author. All Rights Reserved. +// +// 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 context + +import ( + "fmt" + "net/http" + "net/http/httptest" + "testing" +) + +func TestXsrfReset_01(t *testing.T) { + r := &http.Request{} + c := NewContext() + c.Request = r + c.ResponseWriter = &Response{} + c.ResponseWriter.reset(httptest.NewRecorder()) + c.Output.Reset(c) + c.Input.Reset(c) + c.XSRFToken("key", 16) + if c._xsrfToken == "" { + t.FailNow() + } + token := c._xsrfToken + c.Reset(&Response{ResponseWriter: httptest.NewRecorder()}, r) + if c._xsrfToken != "" { + t.FailNow() + } + c.XSRFToken("key", 16) + if c._xsrfToken == "" { + t.FailNow() + } + if token == c._xsrfToken { + t.FailNow() + } +} From ed0e6419f0ba606ae68b839e4ad961d23fcb55ca Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 8 Apr 2016 14:07:39 +0800 Subject: [PATCH 096/159] context xsrf test --- context/context_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/context/context_test.go b/context/context_test.go index 82bb3342..7c0535e0 100644 --- a/context/context_test.go +++ b/context/context_test.go @@ -15,7 +15,6 @@ package context import ( - "fmt" "net/http" "net/http/httptest" "testing" From 53d680a493e4b14deee5fd27ac3f01ef7af3800c Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 8 Apr 2016 14:24:23 +0800 Subject: [PATCH 097/159] rand func modify --- utils/rand.go | 24 ++++++++++-------------- utils/rand_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 utils/rand_test.go diff --git a/utils/rand.go b/utils/rand.go index 74bb4121..344d1cd5 100644 --- a/utils/rand.go +++ b/utils/rand.go @@ -20,28 +20,24 @@ import ( "time" ) +var alphaNum = []byte(`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`) + // RandomCreateBytes generate random []byte by specify chars. func RandomCreateBytes(n int, alphabets ...byte) []byte { - const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + if len(alphabets) == 0 { + alphabets = alphaNum + } var bytes = make([]byte, n) - var randby bool + var randBy bool if num, err := rand.Read(bytes); num != n || err != nil { r.Seed(time.Now().UnixNano()) - randby = true + randBy = true } for i, b := range bytes { - if len(alphabets) == 0 { - if randby { - bytes[i] = alphanum[r.Intn(len(alphanum))] - } else { - bytes[i] = alphanum[b%byte(len(alphanum))] - } + if randBy { + bytes[i] = alphabets[r.Intn(len(alphabets))] } else { - if randby { - bytes[i] = alphabets[r.Intn(len(alphabets))] - } else { - bytes[i] = alphabets[b%byte(len(alphabets))] - } + bytes[i] = alphabets[b%byte(len(alphabets))] } } return bytes diff --git a/utils/rand_test.go b/utils/rand_test.go new file mode 100644 index 00000000..6c238b5e --- /dev/null +++ b/utils/rand_test.go @@ -0,0 +1,33 @@ +// Copyright 2016 beego Author. All Rights Reserved. +// +// 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 utils + +import "testing" + +func TestRand_01(t *testing.T) { + bs0 := RandomCreateBytes(16) + bs1 := RandomCreateBytes(16) + + t.Log(string(bs0), string(bs1)) + if string(bs0) == string(bs1) { + t.FailNow() + } + + bs0 = RandomCreateBytes(4, []byte(`a`)...) + + if string(bs0) != "aaaa" { + t.FailNow() + } +} From 528f273e583802738fb4804491fa2462594df627 Mon Sep 17 00:00:00 2001 From: Yoki Date: Fri, 8 Apr 2016 14:28:45 +0800 Subject: [PATCH 098/159] Update README.md fix url --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6c589584..fbd7ccb7 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ func main(){ ``` ######Congratulations! You just built your first beego app. -Open your browser and visit `http://localhost:8000`. +Open your browser and visit `http://localhost:8080`. Please see [Documentation](http://beego.me/docs) for more. ## Features From 881d010c018c318de3701eef4c07942f07a1d29f Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 11 Apr 2016 11:56:43 +0800 Subject: [PATCH 099/159] upgrade swagger from 1.2 to 2.0 --- beego.go | 1 - docs.go | 39 ----------- hooks.go | 8 --- swagger/docs_spec.go | 160 ------------------------------------------- swagger/swagger.go | 155 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 155 insertions(+), 208 deletions(-) delete mode 100644 docs.go delete mode 100644 swagger/docs_spec.go create mode 100644 swagger/swagger.go diff --git a/beego.go b/beego.go index 16601ecc..db5db3f5 100644 --- a/beego.go +++ b/beego.go @@ -72,7 +72,6 @@ func initBeforeHTTPRun() { AddAPPStartHook(registerMime) AddAPPStartHook(registerDefaultErrorHandler) AddAPPStartHook(registerSession) - AddAPPStartHook(registerDocs) AddAPPStartHook(registerTemplate) AddAPPStartHook(registerAdmin) AddAPPStartHook(registerGzip) diff --git a/docs.go b/docs.go deleted file mode 100644 index 72532876..00000000 --- a/docs.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2014 beego Author. All Rights Reserved. -// -// 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 beego - -import ( - "github.com/astaxie/beego/context" -) - -// GlobalDocAPI store the swagger api documents -var GlobalDocAPI = make(map[string]interface{}) - -func serverDocs(ctx *context.Context) { - var obj interface{} - if splat := ctx.Input.Param(":splat"); splat == "" { - obj = GlobalDocAPI["Root"] - } else { - if v, ok := GlobalDocAPI[splat]; ok { - obj = v - } - } - if obj != nil { - ctx.Output.Header("Access-Control-Allow-Origin", "*") - ctx.Output.JSON(obj, false, false) - return - } - ctx.Output.SetStatus(404) -} diff --git a/hooks.go b/hooks.go index 3d784467..610226b4 100644 --- a/hooks.go +++ b/hooks.go @@ -79,14 +79,6 @@ func registerTemplate() error { return nil } -func registerDocs() error { - if BConfig.WebConfig.EnableDocs { - Get("/docs", serverDocs) - Get("/docs/*", serverDocs) - } - return nil -} - func registerAdmin() error { if BConfig.Listen.EnableAdmin { go beeAdminApp.Run() diff --git a/swagger/docs_spec.go b/swagger/docs_spec.go deleted file mode 100644 index 680324dc..00000000 --- a/swagger/docs_spec.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2014 beego Author. All Rights Reserved. -// -// 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 swagger struct definition -package swagger - -// SwaggerVersion show the current swagger version -const SwaggerVersion = "1.2" - -// ResourceListing list the resource -type ResourceListing struct { - APIVersion string `json:"apiVersion"` - SwaggerVersion string `json:"swaggerVersion"` // e.g 1.2 - // BasePath string `json:"basePath"` obsolete in 1.1 - APIs []APIRef `json:"apis"` - Info Information `json:"info"` -} - -// APIRef description the api path and description -type APIRef struct { - Path string `json:"path"` // relative or absolute, must start with / - Description string `json:"description"` -} - -// Information show the API Information -type Information struct { - Title string `json:"title,omitempty"` - Description string `json:"description,omitempty"` - Contact string `json:"contact,omitempty"` - TermsOfServiceURL string `json:"termsOfServiceUrl,omitempty"` - License string `json:"license,omitempty"` - LicenseURL string `json:"licenseUrl,omitempty"` -} - -// APIDeclaration see https://github.com/wordnik/swagger-core/blob/scala_2.10-1.3-RC3/schemas/api-declaration-schema.json -type APIDeclaration struct { - APIVersion string `json:"apiVersion"` - SwaggerVersion string `json:"swaggerVersion"` - BasePath string `json:"basePath"` - ResourcePath string `json:"resourcePath"` // must start with / - Consumes []string `json:"consumes,omitempty"` - Produces []string `json:"produces,omitempty"` - APIs []API `json:"apis,omitempty"` - Models map[string]Model `json:"models,omitempty"` -} - -// API show tha API struct -type API struct { - Path string `json:"path"` // relative or absolute, must start with / - Description string `json:"description"` - Operations []Operation `json:"operations,omitempty"` -} - -// Operation desc the Operation -type Operation struct { - HTTPMethod string `json:"httpMethod"` - Nickname string `json:"nickname"` - Type string `json:"type"` // in 1.1 = DataType - // ResponseClass string `json:"responseClass"` obsolete in 1.2 - Summary string `json:"summary,omitempty"` - Notes string `json:"notes,omitempty"` - Parameters []Parameter `json:"parameters,omitempty"` - ResponseMessages []ResponseMessage `json:"responseMessages,omitempty"` // optional - Consumes []string `json:"consumes,omitempty"` - Produces []string `json:"produces,omitempty"` - Authorizations []Authorization `json:"authorizations,omitempty"` - Protocols []Protocol `json:"protocols,omitempty"` -} - -// Protocol support which Protocol -type Protocol struct { -} - -// ResponseMessage Show the -type ResponseMessage struct { - Code int `json:"code"` - Message string `json:"message"` - ResponseModel string `json:"responseModel"` -} - -// Parameter desc the request parameters -type Parameter struct { - ParamType string `json:"paramType"` // path,query,body,header,form - Name string `json:"name"` - Description string `json:"description"` - DataType string `json:"dataType"` // 1.2 needed? - Type string `json:"type"` // integer - Format string `json:"format"` // int64 - AllowMultiple bool `json:"allowMultiple"` - Required bool `json:"required"` - Minimum int `json:"minimum"` - Maximum int `json:"maximum"` -} - -// ErrorResponse desc response -type ErrorResponse struct { - Code int `json:"code"` - Reason string `json:"reason"` -} - -// Model define the data model -type Model struct { - ID string `json:"id"` - Required []string `json:"required,omitempty"` - Properties map[string]ModelProperty `json:"properties"` -} - -// ModelProperty define the properties -type ModelProperty struct { - Type string `json:"type"` - Description string `json:"description"` - Items map[string]string `json:"items,omitempty"` - Format string `json:"format"` -} - -// Authorization see https://github.com/wordnik/swagger-core/wiki/authorizations -type Authorization struct { - LocalOAuth OAuth `json:"local-oauth"` - APIKey APIKey `json:"apiKey"` -} - -// OAuth see https://github.com/wordnik/swagger-core/wiki/authorizations -type OAuth struct { - Type string `json:"type"` // e.g. oauth2 - Scopes []string `json:"scopes"` // e.g. PUBLIC - GrantTypes map[string]GrantType `json:"grantTypes"` -} - -// GrantType see https://github.com/wordnik/swagger-core/wiki/authorizations -type GrantType struct { - LoginEndpoint Endpoint `json:"loginEndpoint"` - TokenName string `json:"tokenName"` // e.g. access_code - TokenRequestEndpoint Endpoint `json:"tokenRequestEndpoint"` - TokenEndpoint Endpoint `json:"tokenEndpoint"` -} - -// Endpoint see https://github.com/wordnik/swagger-core/wiki/authorizations -type Endpoint struct { - URL string `json:"url"` - ClientIDName string `json:"clientIdName"` - ClientSecretName string `json:"clientSecretName"` - TokenName string `json:"tokenName"` -} - -// APIKey see https://github.com/wordnik/swagger-core/wiki/authorizations -type APIKey struct { - Type string `json:"type"` // e.g. apiKey - PassAs string `json:"passAs"` // e.g. header -} diff --git a/swagger/swagger.go b/swagger/swagger.go new file mode 100644 index 00000000..e48dcf1e --- /dev/null +++ b/swagger/swagger.go @@ -0,0 +1,155 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// 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. +// +// Swagger™ is a project used to describe and document RESTful APIs. +// +// The Swagger specification defines a set of files required to describe such an API. These files can then be used by the Swagger-UI project to display the API and Swagger-Codegen to generate clients in various languages. Additional utilities can also take advantage of the resulting files, such as testing tools. +// Now in version 2.0, Swagger is more enabling than ever. And it's 100% open source software. + +// Package swagger struct definition +package swagger + +// Swagger list the resource +type Swagger struct { + SwaggerVersion string `json:"swagger,omitempty"` + Infos Information `json:"info"` + Host string `json:"host,omitempty"` + BasePath string `json:"basePath,omitempty"` + Schemes []string `json:"schemes,omitempty"` + Consumes []string `json:"consumes,omitempty"` + Produces []string `json:"produces,omitempty"` + Paths map[string]Item `json:"paths"` + Definitions map[string]Schema `json:"definitions,omitempty"` + SecurityDefinitions map[string]Scurity `json:"securityDefinitions,omitempty"` + Security map[string][]string `json:"security,omitempty"` + Tags []Tag `json:"tags,omitempty"` + ExternalDocs ExternalDocs `json:"externalDocs,omitempty"` +} + +// Information Provides metadata about the API. The metadata can be used by the clients if needed. +type Information struct { + Title string `json:"title,omitempty"` + Description string `json:"description,omitempty"` + Version string `json:"version,omitempty"` + TermsOfServiceURL string `json:"termsOfServiceUrl,omitempty"` + + Contact Contact `json:"contact,omitempty"` + License License `json:"license,omitempty"` +} + +// Contact information for the exposed API. +type Contact struct { + Name string `json:"name,omitempty"` + URL string `json:"url,omitempty"` + EMail string `json:"email,omitempty"` +} + +// License information for the exposed API. +type License struct { + Name string `json:"name,omitempty"` + URL string `json:"url,omitempty"` +} + +// Item Describes the operations available on a single path. +type Item struct { + Ref string `json:"$ref,omitempty"` + Get *Operation `json:"get,omitempty"` + Put *Operation `json:"put,omitempty"` + Post *Operation `json:"post,omitempty"` + Delete *Operation `json:"delete,omitempty"` + Options *Operation `json:"options,omitempty"` + Head *Operation `json:"head,omitempty"` + Patch *Operation `json:"patch,omitempty"` +} + +// Operation Describes a single API operation on a path. +type Operation struct { + Tags []string `json:"tags,omitempty"` + Summary string `json:"summary,omitempty"` + Description string `json:"description,omitempty"` + OperationID string `json:"operationId,omitempty"` + Consumes []string `json:"consumes,omitempty"` + Produces []string `json:"produces,omitempty"` + Schemes []string `json:"schemes,omitempty"` + Parameters []Parameter `json:"parameters,omitempty"` + Responses map[string]Response `json:"responses,omitempty"` + Deprecated bool `json:"deprecated,omitempty"` +} + +// Parameter Describes a single operation parameter. +type Parameter struct { + In string `json:"in,omitempty"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Required bool `json:"required,omitempty"` + Schema Schema `json:"schema,omitempty"` + Type string `json:"type,omitempty"` + Format string `json:"format,omitempty"` +} + +// Schema Object allows the definition of input and output data types. +type Schema struct { + Ref string `json:"$ref,omitempty"` + Title string `json:"title,omitempty"` + Format string `json:"format,omitempty"` + Description string `json:"description,omitempty"` + Required []string `json:"required,omitempty"` + Type string `json:"type,omitempty"` + Properties map[string]Propertie `json:"properties,omitempty"` +} + +// Propertie are taken from the JSON Schema definition but their definitions were adjusted to the Swagger Specification +type Propertie struct { + Title string `json:"title,omitempty"` + Description string `json:"description,omitempty"` + Default string `json:"default,omitempty"` + Type string `json:"type,omitempty"` + Example string `json:"example,omitempty"` + Required []string `json:"required,omitempty"` + Format string `json:"format,omitempty"` + ReadOnly bool `json:"readOnly,omitempty"` + Properties map[string]Propertie `json:"properties,omitempty"` +} + +// Response as they are returned from executing this operation. +type Response struct { + Description string `json:"description,omitempty"` + Schema Schema `json:"schema,omitempty"` + Ref string `json:"$ref,omitempty"` +} + +// Scurity Allows the definition of a security scheme that can be used by the operations +type Scurity struct { + Type string `json:"type,omitempty"` // Valid values are "basic", "apiKey" or "oauth2". + Description string `json:"description,omitempty"` + Name string `json:"name,omitempty"` + In string `json:"in,omitempty"` // Valid values are "query" or "header". + Flow string `json:"flow,omitempty"` // Valid values are "implicit", "password", "application" or "accessCode". + AuthorizationURL string `json:"authorizationUrl,omitempty"` + TokenURL string `json:"tokenUrl,omitempty"` + Scopes map[string]string `json:"scopes,omitempty"` // The available scopes for the OAuth2 security scheme. +} + +// Tag Allows adding meta data to a single tag that is used by the Operation Object +type Tag struct { + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + ExternalDocs ExternalDocs `json:"externalDocs,omitempty"` +} + +// ExternalDocs include Additional external documentation +type ExternalDocs struct { + Description string `json:"description,omitempty"` + URL string `json:"url,omitempty"` +} From d7f41ccd0caed23c51309080581f69a5f12a1d9b Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 11 Apr 2016 12:51:44 +0800 Subject: [PATCH 100/159] update vet --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 92d9ac8b..00ae7a48 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,6 @@ install: - go get github.com/belogik/goes - go get github.com/siddontang/ledisdb/config - go get github.com/siddontang/ledisdb/ledis - - go get golang.org/x/tools/cmd/vet - go get github.com/ssdb/gossdb/ssdb before_script: - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" @@ -43,5 +42,5 @@ after_script: -killall -w ssdb-server - rm -rf ./res/var/* script: - - go vet -x ./... + - go tool vet . - go test -v ./... From ba3a1f84572c58edd153f5760afbc8aab1ce1cd7 Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 11 Apr 2016 13:15:14 +0800 Subject: [PATCH 101/159] update go vet --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 00ae7a48..c72bb052 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,11 +36,11 @@ before_script: - sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi" - sh -c "if [ '$ORM_DRIVER' = 'sqlite' ]; then touch $TRAVIS_BUILD_DIR/orm_test.db; fi" - sh -c "if [ $(go version) == *1.[5-9]* ]; then go get github.com/golang/lint/golint; golint ./...; fi" + - sh -c "if [ $(go version) == *1.[5-9]* ]; then go tool vet .; fi" - mkdir -p res/var - ./ssdb/ssdb-server ./ssdb/ssdb.conf -d after_script: -killall -w ssdb-server - rm -rf ./res/var/* script: - - go tool vet . - go test -v ./... From 1cac38b664756a1b6ddd129bafb49a2b07572bba Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 11 Apr 2016 21:19:10 +0800 Subject: [PATCH 102/159] show postgres versionn --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index c72bb052..88d8fd52 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,7 @@ install: - go get github.com/siddontang/ledisdb/ledis - go get github.com/ssdb/gossdb/ssdb before_script: + - psql --version - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" - sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi" - sh -c "if [ '$ORM_DRIVER' = 'sqlite' ]; then touch $TRAVIS_BUILD_DIR/orm_test.db; fi" From 6da765c465fe31ddae1a4bc0e7efad1ba34e7364 Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 11 Apr 2016 23:12:35 +0800 Subject: [PATCH 103/159] Using a different PostgreSQL Version --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 88d8fd52..93536488 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,3 +45,5 @@ after_script: - rm -rf ./res/var/* script: - go test -v ./... +addons: + postgresql: "9.4" From 657744efb16d473360942d45fd7ea86cc23f84a9 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Fri, 8 Apr 2016 21:53:27 +0800 Subject: [PATCH 104/159] orm: add json & jsonb type support --- orm/cmd_utils.go | 14 +++++++ orm/db.go | 14 +++++-- orm/db_postgres.go | 2 + orm/models_fields.go | 88 +++++++++++++++++++++++++++++++++++++++++++- orm/models_info_f.go | 13 +++++-- 5 files changed, 124 insertions(+), 7 deletions(-) diff --git a/orm/cmd_utils.go b/orm/cmd_utils.go index 13f35722..51e9b8d2 100644 --- a/orm/cmd_utils.go +++ b/orm/cmd_utils.go @@ -90,6 +90,18 @@ checkColumn: } else { col = fmt.Sprintf(s, fi.digits, fi.decimals) } + case TypeJsonField: + if al.Driver != DRPostgres { + fieldType = TypeCharField + goto checkColumn + } + col = T["json"] + case TypeJsonbField: + if al.Driver != DRPostgres { + fieldType = TypeCharField + goto checkColumn + } + col = T["jsonb"] case RelForeignKey, RelOneToOne: fieldType = fi.relModelInfo.fields.pk.fieldType fieldSize = fi.relModelInfo.fields.pk.size @@ -278,6 +290,8 @@ func getColumnDefault(fi *fieldInfo) string { case TypeBooleanField: t = " DEFAULT %s " d = "FALSE" + case TypeJsonField, TypeJsonbField: + d = "{}" } if fi.colDefault { diff --git a/orm/db.go b/orm/db.go index 04cdc30a..0ff97cda 100644 --- a/orm/db.go +++ b/orm/db.go @@ -141,7 +141,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val } else { value = field.Bool() } - case TypeCharField, TypeTextField: + case TypeCharField, TypeTextField, TypeJsonField, TypeJsonbField: if ns, ok := field.Interface().(sql.NullString); ok { value = nil if ns.Valid { @@ -247,6 +247,14 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val field.Set(reflect.ValueOf(tnow.In(DefaultTimeLoc))) } } + case TypeJsonField, TypeJsonbField: + if s, ok := value.(string); (ok && len(s) == 0) || value == nil { + if fi.colDefault && fi.initial.Exist() { + value = fi.initial.String() + } else { + value = nil + } + } } } return value, nil @@ -1093,7 +1101,7 @@ setValue: } value = b } - case fieldType == TypeCharField || fieldType == TypeTextField: + case fieldType == TypeCharField || fieldType == TypeTextField || fieldType == TypeJsonField || fieldType == TypeJsonbField: if str == nil { value = ToStr(val) } else { @@ -1239,7 +1247,7 @@ setValue: field.SetBool(value.(bool)) } } - case fieldType == TypeCharField || fieldType == TypeTextField: + case fieldType == TypeCharField || fieldType == TypeTextField || fieldType == TypeJsonField || fieldType == TypeJsonbField: if isNative { if ns, ok := field.Interface().(sql.NullString); ok { if value == nil { diff --git a/orm/db_postgres.go b/orm/db_postgres.go index 8fbcb88d..e972c4a2 100644 --- a/orm/db_postgres.go +++ b/orm/db_postgres.go @@ -56,6 +56,8 @@ var postgresTypes = map[string]string{ "uint64": `bigint CHECK("%COL%" >= 0)`, "float64": "double precision", "float64-decimal": "numeric(%d, %d)", + "json": "json", + "jsonb": "jsonb", } // postgresql dbBaser. diff --git a/orm/models_fields.go b/orm/models_fields.go index 1bfbfb2f..a49cde4d 100644 --- a/orm/models_fields.go +++ b/orm/models_fields.go @@ -38,6 +38,8 @@ const ( TypePositiveBigIntegerField TypeFloatField TypeDecimalField + TypeJsonField + TypeJsonbField RelForeignKey RelOneToOne RelManyToMany @@ -49,7 +51,7 @@ const ( const ( IsIntegerField = ^-TypePositiveBigIntegerField >> 5 << 6 IsPositiveIntegerField = ^-TypePositiveBigIntegerField >> 9 << 10 - IsRelField = ^-RelReverseMany >> 15 << 16 + IsRelField = ^-RelReverseMany >> 17 << 18 IsFieldType = ^-RelReverseMany<<1 + 1 ) @@ -681,3 +683,87 @@ func (e *TextField) RawValue() interface{} { // verify TextField implement Fielder var _ Fielder = new(TextField) + +// JsonField postgres json field. +type JsonField string + +// Value return JsonField value +func (j JsonField) Value() string { + return string(j) +} + +// Set the JsonField value +func (j *JsonField) Set(d string) { + *j = JsonField(d) +} + +// String convert JsonField to string +func (j *JsonField) String() string { + return j.Value() +} + +// FieldType return enum type +func (j *JsonField) FieldType() int { + return TypeJsonField +} + +// SetRaw convert interface string to string +func (j *JsonField) SetRaw(value interface{}) error { + switch d := value.(type) { + case string: + j.Set(d) + default: + return fmt.Errorf(" unknown value `%s`", value) + } + return nil +} + +// RawValue return JsonField value +func (j *JsonField) RawValue() interface{} { + return j.Value() +} + +// verify JsonField implement Fielder +var _ Fielder = new(JsonField) + +// JsonbField postgres json field. +type JsonbField string + +// Value return JsonbField value +func (j JsonbField) Value() string { + return string(j) +} + +// Set the JsonbField value +func (j *JsonbField) Set(d string) { + *j = JsonbField(d) +} + +// String convert JsonbField to string +func (j *JsonbField) String() string { + return j.Value() +} + +// FieldType return enum type +func (j *JsonbField) FieldType() int { + return TypeJsonbField +} + +// SetRaw convert interface string to string +func (j *JsonbField) SetRaw(value interface{}) error { + switch d := value.(type) { + case string: + j.Set(d) + default: + return fmt.Errorf(" unknown value `%s`", value) + } + return nil +} + +// RawValue return JsonbField value +func (j *JsonbField) RawValue() interface{} { + return j.Value() +} + +// verify JsonbField implement Fielder +var _ Fielder = new(JsonbField) diff --git a/orm/models_info_f.go b/orm/models_info_f.go index 20a7c9d6..1d4d267e 100644 --- a/orm/models_info_f.go +++ b/orm/models_info_f.go @@ -239,8 +239,15 @@ checkType: if err != nil { goto end } - if fieldType == TypeCharField && tags["type"] == "text" { - fieldType = TypeTextField + if fieldType == TypeCharField { + switch tags["type"] { + case "text": + fieldType = TypeTextField + case "json": + fieldType = TypeJsonField + case "jsonb": + fieldType = TypeJsonbField + } } if fieldType == TypeFloatField && (digits != "" || decimals != "") { fieldType = TypeDecimalField @@ -342,7 +349,7 @@ checkType: switch fieldType { case TypeBooleanField: - case TypeCharField: + case TypeCharField, TypeJsonField, TypeJsonbField: if size != "" { v, e := StrTo(size).Int32() if e != nil { From e95bef13315c3f5b4c49fe2f26633c3d66676d35 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Fri, 8 Apr 2016 22:26:28 +0800 Subject: [PATCH 105/159] orm: add test case for json & jsonb type support --- orm/models_test.go | 4 ++++ orm/orm_test.go | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/orm/models_test.go b/orm/models_test.go index cbc51dcc..d1e3e66e 100644 --- a/orm/models_test.go +++ b/orm/models_test.go @@ -112,6 +112,8 @@ type Data struct { Boolean bool Char string `orm:"size(50)"` Text string `orm:"type(text)"` + Json string `orm:"type(json);default({\"name\":\"json\"})"` + Jsonb string `orm:"type(jsonb)"` Time time.Time `orm:"type(time)"` Date time.Time `orm:"type(date)"` DateTime time.Time `orm:"column(datetime)"` @@ -137,6 +139,8 @@ type DataNull struct { Boolean bool `orm:"null"` Char string `orm:"null;size(50)"` Text string `orm:"null;type(text)"` + Json string `orm:"type(json);null"` + Jsonb string `orm:"type(jsonb);null"` Time time.Time `orm:"null;type(time)"` Date time.Time `orm:"null;type(date)"` DateTime time.Time `orm:"null;column(datetime)"` diff --git a/orm/orm_test.go b/orm/orm_test.go index 0c615328..e8909da8 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -241,6 +241,8 @@ var DataValues = map[string]interface{}{ "Boolean": true, "Char": "char", "Text": "text", + "Json": `{"name":"json"}`, + "Jsonb": `{"name": "jsonb"}`, "Time": time.Now(), "Date": time.Now(), "DateTime": time.Now(), @@ -266,6 +268,9 @@ func TestDataTypes(t *testing.T) { ind := reflect.Indirect(reflect.ValueOf(&d)) for name, value := range DataValues { + if name == "Json" { + continue + } e := ind.FieldByName(name) e.Set(reflect.ValueOf(value)) } @@ -310,10 +315,18 @@ func TestNullDataTypes(t *testing.T) { throwFail(t, err) throwFail(t, AssertIs(id, 1)) + data := `{"ok":1,"data":{"arr":[1,2],"msg":"gopher"}}` + d = DataNull{ID: 1, Json: data} + num, err := dORM.Update(&d) + throwFail(t, err) + throwFail(t, AssertIs(num, 1)) + d = DataNull{ID: 1} err = dORM.Read(&d) throwFail(t, err) + throwFail(t, AssertIs(d.Json, data)) + throwFail(t, AssertIs(d.NullBool.Valid, false)) throwFail(t, AssertIs(d.NullString.Valid, false)) throwFail(t, AssertIs(d.NullInt64.Valid, false)) From 99f1e6c8b5683ef789d72d1b0e684ac658890fb0 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Sat, 9 Apr 2016 10:22:40 +0800 Subject: [PATCH 106/159] orm: fix golint --- orm/cmd_utils.go | 4 ++-- orm/db.go | 8 ++++---- orm/models_fields.go | 44 +++++++++++++++++++++++++------------------- orm/models_info_f.go | 4 ++-- orm/models_test.go | 24 ++++++++++++------------ orm/orm_test.go | 28 ++++++++++++++-------------- 6 files changed, 59 insertions(+), 53 deletions(-) diff --git a/orm/cmd_utils.go b/orm/cmd_utils.go index 51e9b8d2..94e6070b 100644 --- a/orm/cmd_utils.go +++ b/orm/cmd_utils.go @@ -90,7 +90,7 @@ checkColumn: } else { col = fmt.Sprintf(s, fi.digits, fi.decimals) } - case TypeJsonField: + case TypeJSONField: if al.Driver != DRPostgres { fieldType = TypeCharField goto checkColumn @@ -290,7 +290,7 @@ func getColumnDefault(fi *fieldInfo) string { case TypeBooleanField: t = " DEFAULT %s " d = "FALSE" - case TypeJsonField, TypeJsonbField: + case TypeJSONField, TypeJsonbField: d = "{}" } diff --git a/orm/db.go b/orm/db.go index 0ff97cda..7796686a 100644 --- a/orm/db.go +++ b/orm/db.go @@ -141,7 +141,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val } else { value = field.Bool() } - case TypeCharField, TypeTextField, TypeJsonField, TypeJsonbField: + case TypeCharField, TypeTextField, TypeJSONField, TypeJsonbField: if ns, ok := field.Interface().(sql.NullString); ok { value = nil if ns.Valid { @@ -247,7 +247,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val field.Set(reflect.ValueOf(tnow.In(DefaultTimeLoc))) } } - case TypeJsonField, TypeJsonbField: + case TypeJSONField, TypeJsonbField: if s, ok := value.(string); (ok && len(s) == 0) || value == nil { if fi.colDefault && fi.initial.Exist() { value = fi.initial.String() @@ -1101,7 +1101,7 @@ setValue: } value = b } - case fieldType == TypeCharField || fieldType == TypeTextField || fieldType == TypeJsonField || fieldType == TypeJsonbField: + case fieldType == TypeCharField || fieldType == TypeTextField || fieldType == TypeJSONField || fieldType == TypeJsonbField: if str == nil { value = ToStr(val) } else { @@ -1247,7 +1247,7 @@ setValue: field.SetBool(value.(bool)) } } - case fieldType == TypeCharField || fieldType == TypeTextField || fieldType == TypeJsonField || fieldType == TypeJsonbField: + case fieldType == TypeCharField || fieldType == TypeTextField || fieldType == TypeJSONField || fieldType == TypeJsonbField: if isNative { if ns, ok := field.Interface().(sql.NullString); ok { if value == nil { diff --git a/orm/models_fields.go b/orm/models_fields.go index a49cde4d..57820600 100644 --- a/orm/models_fields.go +++ b/orm/models_fields.go @@ -38,7 +38,7 @@ const ( TypePositiveBigIntegerField TypeFloatField TypeDecimalField - TypeJsonField + TypeJSONField TypeJsonbField RelForeignKey RelOneToOne @@ -148,7 +148,7 @@ func (e *CharField) RawValue() interface{} { // verify CharField implement Fielder var _ Fielder = new(CharField) -// A time, represented in go by a time.Time instance. +// TimeField A time, represented in go by a time.Time instance. // only time values like 10:00:00 // Has a few extra, optional attr tag: // @@ -163,22 +163,27 @@ var _ Fielder = new(CharField) // eg: `orm:"auto_now"` or `orm:"auto_now_add"` type TimeField time.Time +// Value return the time.Time func (e TimeField) Value() time.Time { return time.Time(e) } +// Set set the TimeField's value func (e *TimeField) Set(d time.Time) { *e = TimeField(d) } +// String convert time to string func (e *TimeField) String() string { return e.Value().String() } +// FieldType return enum type Date func (e *TimeField) FieldType() int { return TypeDateField } +// SetRaw convert the interface to time.Time. Allow string and time.Time func (e *TimeField) SetRaw(value interface{}) error { switch d := value.(type) { case time.Time: @@ -195,6 +200,7 @@ func (e *TimeField) SetRaw(value interface{}) error { return nil } +// RawValue return time value func (e *TimeField) RawValue() interface{} { return e.Value() } @@ -684,47 +690,47 @@ func (e *TextField) RawValue() interface{} { // verify TextField implement Fielder var _ Fielder = new(TextField) -// JsonField postgres json field. -type JsonField string +// JSONField postgres json field. +type JSONField string -// Value return JsonField value -func (j JsonField) Value() string { +// Value return JSONField value +func (j JSONField) Value() string { return string(j) } -// Set the JsonField value -func (j *JsonField) Set(d string) { - *j = JsonField(d) +// Set the JSONField value +func (j *JSONField) Set(d string) { + *j = JSONField(d) } -// String convert JsonField to string -func (j *JsonField) String() string { +// String convert JSONField to string +func (j *JSONField) String() string { return j.Value() } // FieldType return enum type -func (j *JsonField) FieldType() int { - return TypeJsonField +func (j *JSONField) FieldType() int { + return TypeJSONField } // SetRaw convert interface string to string -func (j *JsonField) SetRaw(value interface{}) error { +func (j *JSONField) SetRaw(value interface{}) error { switch d := value.(type) { case string: j.Set(d) default: - return fmt.Errorf(" unknown value `%s`", value) + return fmt.Errorf(" unknown value `%s`", value) } return nil } -// RawValue return JsonField value -func (j *JsonField) RawValue() interface{} { +// RawValue return JSONField value +func (j *JSONField) RawValue() interface{} { return j.Value() } -// verify JsonField implement Fielder -var _ Fielder = new(JsonField) +// verify JSONField implement Fielder +var _ Fielder = new(JSONField) // JsonbField postgres json field. type JsonbField string diff --git a/orm/models_info_f.go b/orm/models_info_f.go index 1d4d267e..366473ce 100644 --- a/orm/models_info_f.go +++ b/orm/models_info_f.go @@ -244,7 +244,7 @@ checkType: case "text": fieldType = TypeTextField case "json": - fieldType = TypeJsonField + fieldType = TypeJSONField case "jsonb": fieldType = TypeJsonbField } @@ -349,7 +349,7 @@ checkType: switch fieldType { case TypeBooleanField: - case TypeCharField, TypeJsonField, TypeJsonbField: + case TypeCharField, TypeJSONField, TypeJsonbField: if size != "" { v, e := StrTo(size).Int32() if e != nil { diff --git a/orm/models_test.go b/orm/models_test.go index d1e3e66e..c68c7339 100644 --- a/orm/models_test.go +++ b/orm/models_test.go @@ -78,41 +78,41 @@ func (e *SliceStringField) RawValue() interface{} { var _ Fielder = new(SliceStringField) // A json field. -type JSONField struct { +type JSONFieldTest struct { Name string Data string } -func (e *JSONField) String() string { +func (e *JSONFieldTest) String() string { data, _ := json.Marshal(e) return string(data) } -func (e *JSONField) FieldType() int { +func (e *JSONFieldTest) FieldType() int { return TypeTextField } -func (e *JSONField) SetRaw(value interface{}) error { +func (e *JSONFieldTest) SetRaw(value interface{}) error { switch d := value.(type) { case string: return json.Unmarshal([]byte(d), e) default: - return fmt.Errorf(" unknown value `%v`", value) + return fmt.Errorf(" unknown value `%v`", value) } } -func (e *JSONField) RawValue() interface{} { +func (e *JSONFieldTest) RawValue() interface{} { return e.String() } -var _ Fielder = new(JSONField) +var _ Fielder = new(JSONFieldTest) type Data struct { ID int `orm:"column(id)"` Boolean bool Char string `orm:"size(50)"` Text string `orm:"type(text)"` - Json string `orm:"type(json);default({\"name\":\"json\"})"` + JSON string `orm:"type(json);default({\"name\":\"json\"})"` Jsonb string `orm:"type(jsonb)"` Time time.Time `orm:"type(time)"` Date time.Time `orm:"type(date)"` @@ -139,7 +139,7 @@ type DataNull struct { Boolean bool `orm:"null"` Char string `orm:"null;size(50)"` Text string `orm:"null;type(text)"` - Json string `orm:"type(json);null"` + JSON string `orm:"type(json);null"` Jsonb string `orm:"type(jsonb);null"` Time time.Time `orm:"null;type(time)"` Date time.Time `orm:"null;type(date)"` @@ -243,7 +243,7 @@ type User struct { ShouldSkip string `orm:"-"` Nums int Langs SliceStringField `orm:"size(100)"` - Extra JSONField `orm:"type(text)"` + Extra JSONFieldTest `orm:"type(text)"` unexport bool `orm:"-"` unexportBool bool } @@ -394,12 +394,12 @@ func NewInLineOneToOne() *InLineOneToOne { } type IntegerPk struct { - Id int64 `orm:"pk"` + ID int64 `orm:"pk"` Value string } type UintPk struct { - Id uint32 `orm:"pk"` + ID uint32 `orm:"pk"` Name string } diff --git a/orm/orm_test.go b/orm/orm_test.go index e8909da8..fa1147f6 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -241,7 +241,7 @@ var DataValues = map[string]interface{}{ "Boolean": true, "Char": "char", "Text": "text", - "Json": `{"name":"json"}`, + "JSON": `{"name":"json"}`, "Jsonb": `{"name": "jsonb"}`, "Time": time.Now(), "Date": time.Now(), @@ -268,7 +268,7 @@ func TestDataTypes(t *testing.T) { ind := reflect.Indirect(reflect.ValueOf(&d)) for name, value := range DataValues { - if name == "Json" { + if name == "JSON" { continue } e := ind.FieldByName(name) @@ -316,7 +316,7 @@ func TestNullDataTypes(t *testing.T) { throwFail(t, AssertIs(id, 1)) data := `{"ok":1,"data":{"arr":[1,2],"msg":"gopher"}}` - d = DataNull{ID: 1, Json: data} + d = DataNull{ID: 1, JSON: data} num, err := dORM.Update(&d) throwFail(t, err) throwFail(t, AssertIs(num, 1)) @@ -325,7 +325,7 @@ func TestNullDataTypes(t *testing.T) { err = dORM.Read(&d) throwFail(t, err) - throwFail(t, AssertIs(d.Json, data)) + throwFail(t, AssertIs(d.JSON, data)) throwFail(t, AssertIs(d.NullBool.Valid, false)) throwFail(t, AssertIs(d.NullString.Valid, false)) @@ -2027,9 +2027,9 @@ func TestInLineOneToOne(t *testing.T) { func TestIntegerPk(t *testing.T) { its := []IntegerPk{ - {Id: math.MinInt64, Value: "-"}, - {Id: 0, Value: "0"}, - {Id: math.MaxInt64, Value: "+"}, + {ID: math.MinInt64, Value: "-"}, + {ID: 0, Value: "0"}, + {ID: math.MaxInt64, Value: "+"}, } num, err := dORM.InsertMulti(len(its), its) @@ -2037,7 +2037,7 @@ func TestIntegerPk(t *testing.T) { throwFail(t, AssertIs(num, len(its))) for _, intPk := range its { - out := IntegerPk{Id: intPk.Id} + out := IntegerPk{ID: intPk.ID} err = dORM.Read(&out) throwFail(t, err) throwFail(t, AssertIs(out.Value, intPk.Value)) @@ -2085,21 +2085,21 @@ func TestInsertAuto(t *testing.T) { func TestUintPk(t *testing.T) { name := "go" u := &UintPk{ - Id: 8, + ID: 8, Name: name, } - created, pk, err := dORM.ReadOrCreate(u, "Id") + created, pk, err := dORM.ReadOrCreate(u, "ID") throwFail(t, err) throwFail(t, AssertIs(created, true)) throwFail(t, AssertIs(u.Name, name)) - nu := &UintPk{Id: 8} - created, pk, err = dORM.ReadOrCreate(nu, "Id") + nu := &UintPk{ID: 8} + created, pk, err = dORM.ReadOrCreate(nu, "ID") throwFail(t, err) throwFail(t, AssertIs(created, false)) - throwFail(t, AssertIs(nu.Id, u.Id)) - throwFail(t, AssertIs(pk, u.Id)) + throwFail(t, AssertIs(nu.ID, u.ID)) + throwFail(t, AssertIs(pk, u.ID)) throwFail(t, AssertIs(nu.Name, name)) dORM.Delete(u) From 22617aeb1380e7be2371406d9d2ba61405c715f3 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 12 Apr 2016 15:05:35 +0800 Subject: [PATCH 107/159] file rotate name fixed --- logs/file.go | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/logs/file.go b/logs/file.go index 5901143b..37edecf0 100644 --- a/logs/file.go +++ b/logs/file.go @@ -47,6 +47,7 @@ type fileLogWriter struct { Daily bool `json:"daily"` MaxDays int64 `json:"maxdays"` dailyOpenDate int + dailyOpenTime time.Time Rotate bool `json:"rotate"` @@ -163,7 +164,8 @@ func (w *fileLogWriter) initFd() error { return fmt.Errorf("get stat err: %s\n", err) } w.maxSizeCurSize = int(fInfo.Size()) - w.dailyOpenDate = time.Now().Day() + w.dailyOpenTime = time.Now() + w.dailyOpenDate = w.dailyOpenTime.Day() w.maxLinesCurLines = 0 if fInfo.Size() > 0 { count, err := w.lines() @@ -205,22 +207,29 @@ func (w *fileLogWriter) lines() (int, error) { // DoRotate means it need to write file in new file. // new file name like xx.2013-01-01.log (daily) or xx.001.log (by line or size) func (w *fileLogWriter) doRotate(logTime time.Time) error { - _, err := os.Lstat(w.Filename) - if err != nil { - return err - } // file exists // Find the next available number num := 1 fName := "" + + _, err := os.Lstat(w.Filename) + if err != nil { + //even if the file is not exist or other ,we should RESTART the logger + goto RESTART_LOGGER + } + if w.MaxLines > 0 || w.MaxSize > 0 { for ; err == nil && num <= 999; num++ { fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", logTime.Format("2006-01-02"), num, w.suffix) _, err = os.Lstat(fName) } } else { - fName = fmt.Sprintf("%s.%s%s", w.fileNameOnly, logTime.Format("2006-01-02"), w.suffix) + fName = fmt.Sprintf("%s.%s%s", w.fileNameOnly, w.dailyOpenTime.Format("2006-01-02"), w.suffix) _, err = os.Lstat(fName) + for ; err == nil && num <= 999; num++ { + fName = w.fileNameOnly + fmt.Sprintf(".%s.%03d%s", w.dailyOpenTime.Format("2006-01-02"), num, w.suffix) + _, err = os.Lstat(fName) + } } // return error if the last file checked still existed if err == nil { @@ -232,16 +241,18 @@ func (w *fileLogWriter) doRotate(logTime time.Time) error { // Rename the file to its new found name // even if occurs error,we MUST guarantee to restart new logger - renameErr := os.Rename(w.Filename, fName) + err = os.Rename(w.Filename, fName) // re-start logger +RESTART_LOGGER: + startLoggerErr := w.startLogger() go w.deleteOldLog() if startLoggerErr != nil { return fmt.Errorf("Rotate StartLogger: %s\n", startLoggerErr) } - if renameErr != nil { - return fmt.Errorf("Rotate: %s\n", renameErr) + if err != nil { + return fmt.Errorf("Rotate: %s\n", err) } return nil From 51858169424ab750be8bcf924645bd7679926419 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Tue, 12 Apr 2016 21:19:43 +0800 Subject: [PATCH 108/159] orm: use `text` as postgres default type --- orm/cmd_utils.go | 6 +++++- orm/models_info_f.go | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/orm/cmd_utils.go b/orm/cmd_utils.go index 94e6070b..8119b70b 100644 --- a/orm/cmd_utils.go +++ b/orm/cmd_utils.go @@ -52,7 +52,11 @@ checkColumn: case TypeBooleanField: col = T["bool"] case TypeCharField: - col = fmt.Sprintf(T["string"], fieldSize) + if al.Driver == DRPostgres && fi.toText { + col = T["string-text"] + } else { + col = fmt.Sprintf(T["string"], fieldSize) + } case TypeTextField: col = T["string-text"] case TypeTimeField: diff --git a/orm/models_info_f.go b/orm/models_info_f.go index 366473ce..be6c9aa4 100644 --- a/orm/models_info_f.go +++ b/orm/models_info_f.go @@ -119,6 +119,7 @@ type fieldInfo struct { colDefault bool initial StrTo size int + toText bool autoNow bool autoNowAdd bool rel bool @@ -359,6 +360,7 @@ checkType: } } else { fi.size = 255 + fi.toText = true } case TypeTextField: fi.index = false From abaa1bbcac9c0714903f3e586e50fddd91213571 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 13 Apr 2016 09:05:16 +0800 Subject: [PATCH 109/159] file rotate file test --- logs/file.go | 4 ++++ logs/file_test.go | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/logs/file.go b/logs/file.go index 37edecf0..8cf20372 100644 --- a/logs/file.go +++ b/logs/file.go @@ -267,6 +267,10 @@ func (w *fileLogWriter) deleteOldLog() { } }() + if info == nil { + return + } + if !info.IsDir() && info.ModTime().Add(24*time.Hour*time.Duration(w.MaxDays)).Before(time.Now()) { if strings.HasPrefix(filepath.Base(path), filepath.Base(w.fileNameOnly)) && strings.HasSuffix(filepath.Base(path), w.suffix) { diff --git a/logs/file_test.go b/logs/file_test.go index 1fa6cdaa..176f4c1e 100644 --- a/logs/file_test.go +++ b/logs/file_test.go @@ -89,7 +89,7 @@ func TestFile2(t *testing.T) { os.Remove("test2.log") } -func TestFileRotate(t *testing.T) { +func TestFileRotate_01(t *testing.T) { log := NewLogger(10000) log.SetLogger("file", `{"filename":"test3.log","maxlines":4}`) log.Debug("debug") @@ -110,6 +110,43 @@ func TestFileRotate(t *testing.T) { os.Remove("test3.log") } +func TestFileRotate_02(t *testing.T) { + fn1 := "rotate_day.log" + fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".log" + testFileRotate(t, fn1, fn2) +} + +func TestFileRotate_03(t *testing.T) { + fn1 := "rotate_day.log" + fn := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".log" + os.Create(fn) + fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".001.log" + testFileRotate(t, fn1, fn2) + os.Remove(fn) +} + +func testFileRotate(t *testing.T, fn1, fn2 string) { + fw := &fileLogWriter{ + Daily: true, + MaxDays: 7, + Rotate: true, + Level: LevelTrace, + Perm: 0660, + } + fw.Init(fmt.Sprintf(`{"filename":"%v","maxdays":1}`, fn1)) + fw.dailyOpenTime = time.Now().Add(-24 * time.Hour) + fw.dailyOpenDate = fw.dailyOpenTime.Day() + fw.WriteMsg(time.Now(), "this is a msg for test", LevelDebug) + + for _, file := range []string{fn1, fn2} { + _, err := os.Stat(file) + if err != nil { + t.FailNow() + } + os.Remove(file) + } +} + func exists(path string) (bool, error) { _, err := os.Stat(path) if err == nil { From ce4fc7bfcda675baf0a2943c17e1eefebf8c2866 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 13 Apr 2016 17:51:54 +0800 Subject: [PATCH 110/159] simplify the value assign --- config.go | 82 +++++++++++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 45 deletions(-) diff --git a/config.go b/config.go index 2c91ffd1..d22059cb 100644 --- a/config.go +++ b/config.go @@ -18,6 +18,7 @@ import ( "fmt" "os" "path/filepath" + "reflect" "strings" "github.com/astaxie/beego/config" @@ -209,51 +210,9 @@ func parseConfig(appConfigPath string) (err error) { BConfig.RunMode = runMode } - BConfig.AppName = AppConfig.DefaultString("AppName", BConfig.AppName) - BConfig.RecoverPanic = AppConfig.DefaultBool("RecoverPanic", BConfig.RecoverPanic) - BConfig.RouterCaseSensitive = AppConfig.DefaultBool("RouterCaseSensitive", BConfig.RouterCaseSensitive) - BConfig.ServerName = AppConfig.DefaultString("ServerName", BConfig.ServerName) - BConfig.EnableGzip = AppConfig.DefaultBool("EnableGzip", BConfig.EnableGzip) - BConfig.EnableErrorsShow = AppConfig.DefaultBool("EnableErrorsShow", BConfig.EnableErrorsShow) - BConfig.CopyRequestBody = AppConfig.DefaultBool("CopyRequestBody", BConfig.CopyRequestBody) - BConfig.MaxMemory = AppConfig.DefaultInt64("MaxMemory", BConfig.MaxMemory) - BConfig.Listen.Graceful = AppConfig.DefaultBool("Graceful", BConfig.Listen.Graceful) - BConfig.Listen.HTTPAddr = AppConfig.String("HTTPAddr") - BConfig.Listen.HTTPPort = AppConfig.DefaultInt("HTTPPort", BConfig.Listen.HTTPPort) - BConfig.Listen.ListenTCP4 = AppConfig.DefaultBool("ListenTCP4", BConfig.Listen.ListenTCP4) - BConfig.Listen.EnableHTTP = AppConfig.DefaultBool("EnableHTTP", BConfig.Listen.EnableHTTP) - BConfig.Listen.EnableHTTPS = AppConfig.DefaultBool("EnableHTTPS", BConfig.Listen.EnableHTTPS) - BConfig.Listen.HTTPSAddr = AppConfig.DefaultString("HTTPSAddr", BConfig.Listen.HTTPSAddr) - BConfig.Listen.HTTPSPort = AppConfig.DefaultInt("HTTPSPort", BConfig.Listen.HTTPSPort) - BConfig.Listen.HTTPSCertFile = AppConfig.DefaultString("HTTPSCertFile", BConfig.Listen.HTTPSCertFile) - BConfig.Listen.HTTPSKeyFile = AppConfig.DefaultString("HTTPSKeyFile", BConfig.Listen.HTTPSKeyFile) - BConfig.Listen.EnableAdmin = AppConfig.DefaultBool("EnableAdmin", BConfig.Listen.EnableAdmin) - BConfig.Listen.AdminAddr = AppConfig.DefaultString("AdminAddr", BConfig.Listen.AdminAddr) - BConfig.Listen.AdminPort = AppConfig.DefaultInt("AdminPort", BConfig.Listen.AdminPort) - BConfig.Listen.EnableFcgi = AppConfig.DefaultBool("EnableFcgi", BConfig.Listen.EnableFcgi) - BConfig.Listen.EnableStdIo = AppConfig.DefaultBool("EnableStdIo", BConfig.Listen.EnableStdIo) - BConfig.Listen.ServerTimeOut = AppConfig.DefaultInt64("ServerTimeOut", BConfig.Listen.ServerTimeOut) - BConfig.WebConfig.AutoRender = AppConfig.DefaultBool("AutoRender", BConfig.WebConfig.AutoRender) - BConfig.WebConfig.ViewsPath = AppConfig.DefaultString("ViewsPath", BConfig.WebConfig.ViewsPath) - BConfig.WebConfig.DirectoryIndex = AppConfig.DefaultBool("DirectoryIndex", BConfig.WebConfig.DirectoryIndex) - BConfig.WebConfig.FlashName = AppConfig.DefaultString("FlashName", BConfig.WebConfig.FlashName) - BConfig.WebConfig.FlashSeparator = AppConfig.DefaultString("FlashSeparator", BConfig.WebConfig.FlashSeparator) - BConfig.WebConfig.EnableDocs = AppConfig.DefaultBool("EnableDocs", BConfig.WebConfig.EnableDocs) - BConfig.WebConfig.XSRFKey = AppConfig.DefaultString("XSRFKEY", BConfig.WebConfig.XSRFKey) - BConfig.WebConfig.EnableXSRF = AppConfig.DefaultBool("EnableXSRF", BConfig.WebConfig.EnableXSRF) - BConfig.WebConfig.XSRFExpire = AppConfig.DefaultInt("XSRFExpire", BConfig.WebConfig.XSRFExpire) - BConfig.WebConfig.TemplateLeft = AppConfig.DefaultString("TemplateLeft", BConfig.WebConfig.TemplateLeft) - BConfig.WebConfig.TemplateRight = AppConfig.DefaultString("TemplateRight", BConfig.WebConfig.TemplateRight) - BConfig.WebConfig.Session.SessionOn = AppConfig.DefaultBool("SessionOn", BConfig.WebConfig.Session.SessionOn) - BConfig.WebConfig.Session.SessionProvider = AppConfig.DefaultString("SessionProvider", BConfig.WebConfig.Session.SessionProvider) - BConfig.WebConfig.Session.SessionName = AppConfig.DefaultString("SessionName", BConfig.WebConfig.Session.SessionName) - BConfig.WebConfig.Session.SessionProviderConfig = AppConfig.DefaultString("SessionProviderConfig", BConfig.WebConfig.Session.SessionProviderConfig) - BConfig.WebConfig.Session.SessionGCMaxLifetime = AppConfig.DefaultInt64("SessionGCMaxLifetime", BConfig.WebConfig.Session.SessionGCMaxLifetime) - BConfig.WebConfig.Session.SessionCookieLifeTime = AppConfig.DefaultInt("SessionCookieLifeTime", BConfig.WebConfig.Session.SessionCookieLifeTime) - BConfig.WebConfig.Session.SessionAutoSetCookie = AppConfig.DefaultBool("SessionAutoSetCookie", BConfig.WebConfig.Session.SessionAutoSetCookie) - BConfig.WebConfig.Session.SessionDomain = AppConfig.DefaultString("SessionDomain", BConfig.WebConfig.Session.SessionDomain) - BConfig.Log.AccessLogs = AppConfig.DefaultBool("LogAccessLogs", BConfig.Log.AccessLogs) - BConfig.Log.FileLineNum = AppConfig.DefaultBool("LogFileLineNum", BConfig.Log.FileLineNum) + for _, i := range []interface{}{BConfig, &BConfig.Listen, &BConfig.WebConfig, &BConfig.Log} { + assignConfig(i, AppConfig) + } if sd := AppConfig.String("StaticDir"); sd != "" { for k := range BConfig.WebConfig.StaticDir { @@ -311,6 +270,39 @@ func parseConfig(appConfigPath string) (err error) { return nil } +func assignConfig(p interface{}, ac config.Configer) { + pt := reflect.TypeOf(p) + if pt.Kind() != reflect.Ptr { + return + } + pt = pt.Elem() + if pt.Kind() != reflect.Struct { + return + } + pv := reflect.ValueOf(p).Elem() + + for i := 0; i < pt.NumField(); i++ { + pf := pv.Field(i) + if !pf.CanSet() { + continue + } + name := pt.Field(i).Name + switch pf.Kind() { + case reflect.String: + pf.SetString(ac.DefaultString(name, pf.String())) + case reflect.Int, reflect.Int64: + pf.SetInt(int64(ac.DefaultInt64(name, pf.Int()))) + case reflect.Bool: + pf.SetBool(ac.DefaultBool(name, pf.Bool())) + case reflect.Struct: + //do nothing here + default: + logs.Critical("beego not support such kind of config filed", pt.Name(), pf.Kind()) + } + } + +} + // LoadAppConfig allow developer to apply a config file func LoadAppConfig(adapterName, configPath string) error { absConfigPath, err := filepath.Abs(configPath) From cb0c006cfa19fe4f157013446f26d103c077f7da Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 13 Apr 2016 19:37:55 +0800 Subject: [PATCH 111/159] add session config --- config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.go b/config.go index d22059cb..c4bafed7 100644 --- a/config.go +++ b/config.go @@ -210,7 +210,7 @@ func parseConfig(appConfigPath string) (err error) { BConfig.RunMode = runMode } - for _, i := range []interface{}{BConfig, &BConfig.Listen, &BConfig.WebConfig, &BConfig.Log} { + for _, i := range []interface{}{BConfig, &BConfig.Listen, &BConfig.WebConfig, &BConfig.Log, &BConfig.WebConfig.Session} { assignConfig(i, AppConfig) } From 4cd2408248fa35759dec7cee39a5668d256b5d2f Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 13 Apr 2016 19:41:07 +0800 Subject: [PATCH 112/159] log to Stderr --- config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.go b/config.go index c4bafed7..3335ab33 100644 --- a/config.go +++ b/config.go @@ -262,7 +262,7 @@ func parseConfig(appConfigPath string) (err error) { for adaptor, config := range BConfig.Log.Outputs { err = logs.SetLogger(adaptor, config) if err != nil { - fmt.Printf("%s with the config `%s` got err:%s\n", adaptor, config, err) + fmt.Fprintln(os.Stderr, "%s with the config `%s` got err:%s\n", adaptor, config, err) } } logs.SetLogFuncCall(BConfig.Log.FileLineNum) From 3a3f70027c33331bc998bd35408c87a1de4a948c Mon Sep 17 00:00:00 2001 From: miraclesu Date: Wed, 13 Apr 2016 20:14:02 +0800 Subject: [PATCH 113/159] orm: fix panic multi insert when slice lenght is 1 & the value is pointer --- orm/orm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orm/orm.go b/orm/orm.go index 6f4b7731..5e43ae59 100644 --- a/orm/orm.go +++ b/orm/orm.go @@ -191,7 +191,7 @@ func (o *orm) InsertMulti(bulk int, mds interface{}) (int64, error) { if bulk <= 1 { for i := 0; i < sind.Len(); i++ { - ind := sind.Index(i) + ind := reflect.Indirect(sind.Index(i)) mi, _ := o.getMiInd(ind.Interface(), false) id, err := o.alias.DbBaser.Insert(o.db, mi, ind, o.alias.TZ) if err != nil { From 903e21bef2fd8f0297d5c2eb88187cbeebc8493b Mon Sep 17 00:00:00 2001 From: miraclesu Date: Wed, 13 Apr 2016 20:20:49 +0800 Subject: [PATCH 114/159] orm: add test case for InsertMulti --- orm/orm_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/orm/orm_test.go b/orm/orm_test.go index fa1147f6..3b854f5c 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -2042,6 +2042,12 @@ func TestIntegerPk(t *testing.T) { throwFail(t, err) throwFail(t, AssertIs(out.Value, intPk.Value)) } + + num, err = dORM.InsertMulti(1, []*IntegerPk{&IntegerPk{ + ID: 1, Value: "ok", + }}) + throwFail(t, err) + throwFail(t, AssertIs(num, 1)) } func TestInsertAuto(t *testing.T) { From 0c32255d14782b399fe9bca26bb6f2bf45771c28 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 14 Apr 2016 11:51:00 +0800 Subject: [PATCH 115/159] config test --- config.go | 69 ++++++++++++++++-------------- config_test.go | 113 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 32 deletions(-) diff --git a/config.go b/config.go index 3335ab33..94e94a5f 100644 --- a/config.go +++ b/config.go @@ -117,7 +117,30 @@ var ( ) func init() { - BConfig = &Config{ + BConfig = newBConfig() + var err error + if AppPath, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil { + panic(err) + } + workPath, err := os.Getwd() + if err != nil { + panic(err) + } + appConfigPath = filepath.Join(workPath, "conf", "app.conf") + if !utils.FileExists(appConfigPath) { + appConfigPath = filepath.Join(AppPath, "conf", "app.conf") + if !utils.FileExists(appConfigPath) { + AppConfig = &beegoAppConfig{innerConfig: config.NewFakeConfig()} + return + } + } + if err = parseConfig(appConfigPath); err != nil { + panic(err) + } +} + +func newBConfig() *Config { + return &Config{ AppName: "beego", RunMode: DEV, RouterCaseSensitive: true, @@ -176,25 +199,6 @@ func init() { Outputs: map[string]string{"console": ""}, }, } - var err error - if AppPath, err = filepath.Abs(filepath.Dir(os.Args[0])); err != nil { - panic(err) - } - workPath, err := os.Getwd() - if err != nil { - panic(err) - } - appConfigPath = filepath.Join(workPath, "conf", "app.conf") - if !utils.FileExists(appConfigPath) { - appConfigPath = filepath.Join(AppPath, "conf", "app.conf") - if !utils.FileExists(appConfigPath) { - AppConfig = &beegoAppConfig{innerConfig: config.NewFakeConfig()} - return - } - } - if err = parseConfig(appConfigPath); err != nil { - panic(err) - } } // now only support ini, next will support json. @@ -203,21 +207,23 @@ func parseConfig(appConfigPath string) (err error) { if err != nil { return err } + return assignConfig(AppConfig) +} + +func assignConfig(ac config.Configer) error { // set the run mode first if envRunMode := os.Getenv("BEEGO_RUNMODE"); envRunMode != "" { BConfig.RunMode = envRunMode - } else if runMode := AppConfig.String("RunMode"); runMode != "" { + } else if runMode := ac.String("RunMode"); runMode != "" { BConfig.RunMode = runMode } for _, i := range []interface{}{BConfig, &BConfig.Listen, &BConfig.WebConfig, &BConfig.Log, &BConfig.WebConfig.Session} { - assignConfig(i, AppConfig) + assignSingleConfig(i, ac) } - if sd := AppConfig.String("StaticDir"); sd != "" { - for k := range BConfig.WebConfig.StaticDir { - delete(BConfig.WebConfig.StaticDir, k) - } + if sd := ac.String("StaticDir"); sd != "" { + BConfig.WebConfig.StaticDir = map[string]string{} sds := strings.Fields(sd) for _, v := range sds { if url2fsmap := strings.SplitN(v, ":", 2); len(url2fsmap) == 2 { @@ -228,7 +234,7 @@ func parseConfig(appConfigPath string) (err error) { } } - if sgz := AppConfig.String("StaticExtensionsToGzip"); sgz != "" { + if sgz := ac.String("StaticExtensionsToGzip"); sgz != "" { extensions := strings.Split(sgz, ",") fileExts := []string{} for _, ext := range extensions { @@ -246,7 +252,7 @@ func parseConfig(appConfigPath string) (err error) { } } - if lo := AppConfig.String("LogOutputs"); lo != "" { + if lo := ac.String("LogOutputs"); lo != "" { los := strings.Split(lo, ";") for _, v := range los { if logType2Config := strings.SplitN(v, ",", 2); len(logType2Config) == 2 { @@ -260,7 +266,7 @@ func parseConfig(appConfigPath string) (err error) { //init log logs.Reset() for adaptor, config := range BConfig.Log.Outputs { - err = logs.SetLogger(adaptor, config) + err := logs.SetLogger(adaptor, config) if err != nil { fmt.Fprintln(os.Stderr, "%s with the config `%s` got err:%s\n", adaptor, config, err) } @@ -270,7 +276,7 @@ func parseConfig(appConfigPath string) (err error) { return nil } -func assignConfig(p interface{}, ac config.Configer) { +func assignSingleConfig(p interface{}, ac config.Configer) { pt := reflect.TypeOf(p) if pt.Kind() != reflect.Ptr { return @@ -295,9 +301,8 @@ func assignConfig(p interface{}, ac config.Configer) { case reflect.Bool: pf.SetBool(ac.DefaultBool(name, pf.Bool())) case reflect.Struct: - //do nothing here default: - logs.Critical("beego not support such kind of config filed", pt.Name(), pf.Kind()) + //do nothing here } } diff --git a/config_test.go b/config_test.go index cf4a781d..0fa85f54 100644 --- a/config_test.go +++ b/config_test.go @@ -15,7 +15,11 @@ package beego import ( + "encoding/json" + "reflect" "testing" + + "github.com/astaxie/beego/config" ) func TestDefaults(t *testing.T) { @@ -27,3 +31,112 @@ func TestDefaults(t *testing.T) { t.Errorf("FlashName was not set to default.") } } + +func TestAssignConfig_01(t *testing.T) { + _BConfig := &Config{} + _BConfig.AppName = "beego_test" + jcf := &config.JSONConfig{} + ac, _ := jcf.ParseData([]byte(`{"AppName":"beego_json"}`)) + assignSingleConfig(_BConfig, ac) + if _BConfig.AppName != "beego_json" { + t.Log(_BConfig) + t.FailNow() + } +} + +func TestAssignConfig_02(t *testing.T) { + _BConfig := &Config{} + bs, _ := json.Marshal(newBConfig()) + + jsonMap := map[string]interface{}{} + json.Unmarshal(bs, &jsonMap) + + configMap := map[string]interface{}{} + for k, v := range jsonMap { + if reflect.TypeOf(v).Kind() == reflect.Map { + for k1, v1 := range v.(map[string]interface{}) { + if reflect.TypeOf(v1).Kind() == reflect.Map { + for k2, v2 := range v1.(map[string]interface{}) { + configMap[k2] = v2 + } + } else { + configMap[k1] = v1 + } + } + } else { + configMap[k] = v + } + } + configMap["MaxMemory"] = 1024 + configMap["Graceful"] = true + configMap["XSRFExpire"] = 32 + configMap["SessionProviderConfig"] = "file" + configMap["FileLineNum"] = true + + jcf := &config.JSONConfig{} + bs, _ = json.Marshal(configMap) + ac, _ := jcf.ParseData([]byte(bs)) + + for _, i := range []interface{}{_BConfig, &_BConfig.Listen, &_BConfig.WebConfig, &_BConfig.Log, &_BConfig.WebConfig.Session} { + assignSingleConfig(i, ac) + } + + if _BConfig.MaxMemory != 1024 { + t.Log(_BConfig.MaxMemory) + t.FailNow() + } + + if !_BConfig.Listen.Graceful { + t.Log(_BConfig.Listen.Graceful) + t.FailNow() + } + + if _BConfig.WebConfig.XSRFExpire != 32 { + t.Log(_BConfig.WebConfig.XSRFExpire) + t.FailNow() + } + + if _BConfig.WebConfig.Session.SessionProviderConfig != "file" { + t.Log(_BConfig.WebConfig.Session.SessionProviderConfig) + t.FailNow() + } + + if !_BConfig.Log.FileLineNum { + t.Log(_BConfig.Log.FileLineNum) + t.FailNow() + } + +} + +func TestAssignConfig_03(t *testing.T) { + jcf := &config.JSONConfig{} + ac, _ := jcf.ParseData([]byte(`{"AppName":"beego"}`)) + ac.Set("AppName", "test_app") + ac.Set("RunMode", "online") + ac.Set("StaticDir", "download:down download2:down2") + ac.Set("StaticExtensionsToGzip", ".css,.js,.html,.jpg,.png") + ac.Set("LogOutputs", `"file": ""`) + assignConfig(ac) + + + //t.Logf("%#v",BConfig) + if BConfig.AppName != "test_app" { + t.FailNow() + } + + if BConfig.RunMode != "online" { + t.FailNow() + } + if BConfig.WebConfig.StaticDir["download"] != "down" { + t.FailNow() + } + if BConfig.WebConfig.StaticDir["download2"] != "down2" { + t.FailNow() + } + if len(BConfig.WebConfig.StaticExtensionsToGzip) != 5 { + t.FailNow() + } + if _, ok := BConfig.Log.Outputs["file"]; !ok { + t.FailNow() + } +} From 203ab3eba8e5e2803fa03818e8d7d0fd712a59cf Mon Sep 17 00:00:00 2001 From: JessonChan Date: Mon, 18 Apr 2016 18:41:40 +0800 Subject: [PATCH 116/159] ut fix --- config_test.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/config_test.go b/config_test.go index 0fa85f54..a365199a 100644 --- a/config_test.go +++ b/config_test.go @@ -115,11 +115,11 @@ func TestAssignConfig_03(t *testing.T) { ac.Set("RunMode", "online") ac.Set("StaticDir", "download:down download2:down2") ac.Set("StaticExtensionsToGzip", ".css,.js,.html,.jpg,.png") - ac.Set("LogOutputs", `"file": ""`) assignConfig(ac) - //t.Logf("%#v",BConfig) + t.Logf("%#v",BConfig) + if BConfig.AppName != "test_app" { t.FailNow() } @@ -127,7 +127,7 @@ func TestAssignConfig_03(t *testing.T) { if BConfig.RunMode != "online" { t.FailNow() } - if BConfig.WebConfig.StaticDir["download"] != "down" { + if BConfig.WebConfig.StaticDir["/download"] != "down" { t.FailNow() } if BConfig.WebConfig.StaticDir["download2"] != "down2" { @@ -136,7 +136,4 @@ func TestAssignConfig_03(t *testing.T) { if len(BConfig.WebConfig.StaticExtensionsToGzip) != 5 { t.FailNow() } - if _, ok := BConfig.Log.Outputs["file"]; !ok { - t.FailNow() - } } From 423f2dad35e429209d26f6fdc50b5782dee42891 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Mon, 18 Apr 2016 19:16:39 +0800 Subject: [PATCH 117/159] list the config to map --- admin.go | 74 +++++++++++++++++---------------------------------- admin_test.go | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 49 deletions(-) create mode 100644 admin_test.go diff --git a/admin.go b/admin.go index 94fa55b9..a2b2f53a 100644 --- a/admin.go +++ b/admin.go @@ -23,6 +23,8 @@ import ( "text/template" "time" + "reflect" + "github.com/astaxie/beego/grace" "github.com/astaxie/beego/logs" "github.com/astaxie/beego/toolbox" @@ -91,57 +93,9 @@ func listConf(rw http.ResponseWriter, r *http.Request) { switch command { case "conf": m := make(map[string]interface{}) + list("BConfig", BConfig, m) m["AppConfigPath"] = appConfigPath m["AppConfigProvider"] = appConfigProvider - m["BConfig.AppName"] = BConfig.AppName - m["BConfig.RunMode"] = BConfig.RunMode - m["BConfig.RouterCaseSensitive"] = BConfig.RouterCaseSensitive - m["BConfig.ServerName"] = BConfig.ServerName - m["BConfig.RecoverPanic"] = BConfig.RecoverPanic - m["BConfig.CopyRequestBody"] = BConfig.CopyRequestBody - m["BConfig.EnableGzip"] = BConfig.EnableGzip - m["BConfig.MaxMemory"] = BConfig.MaxMemory - m["BConfig.EnableErrorsShow"] = BConfig.EnableErrorsShow - m["BConfig.Listen.Graceful"] = BConfig.Listen.Graceful - m["BConfig.Listen.ServerTimeOut"] = BConfig.Listen.ServerTimeOut - m["BConfig.Listen.ListenTCP4"] = BConfig.Listen.ListenTCP4 - m["BConfig.Listen.EnableHTTP"] = BConfig.Listen.EnableHTTP - m["BConfig.Listen.HTTPAddr"] = BConfig.Listen.HTTPAddr - m["BConfig.Listen.HTTPPort"] = BConfig.Listen.HTTPPort - m["BConfig.Listen.EnableHTTPS"] = BConfig.Listen.EnableHTTPS - m["BConfig.Listen.HTTPSAddr"] = BConfig.Listen.HTTPSAddr - m["BConfig.Listen.HTTPSPort"] = BConfig.Listen.HTTPSPort - m["BConfig.Listen.HTTPSCertFile"] = BConfig.Listen.HTTPSCertFile - m["BConfig.Listen.HTTPSKeyFile"] = BConfig.Listen.HTTPSKeyFile - m["BConfig.Listen.EnableAdmin"] = BConfig.Listen.EnableAdmin - m["BConfig.Listen.AdminAddr"] = BConfig.Listen.AdminAddr - m["BConfig.Listen.AdminPort"] = BConfig.Listen.AdminPort - m["BConfig.Listen.EnableFcgi"] = BConfig.Listen.EnableFcgi - m["BConfig.Listen.EnableStdIo"] = BConfig.Listen.EnableStdIo - m["BConfig.WebConfig.AutoRender"] = BConfig.WebConfig.AutoRender - m["BConfig.WebConfig.EnableDocs"] = BConfig.WebConfig.EnableDocs - m["BConfig.WebConfig.FlashName"] = BConfig.WebConfig.FlashName - m["BConfig.WebConfig.FlashSeparator"] = BConfig.WebConfig.FlashSeparator - m["BConfig.WebConfig.DirectoryIndex"] = BConfig.WebConfig.DirectoryIndex - m["BConfig.WebConfig.StaticDir"] = BConfig.WebConfig.StaticDir - m["BConfig.WebConfig.StaticExtensionsToGzip"] = BConfig.WebConfig.StaticExtensionsToGzip - m["BConfig.WebConfig.TemplateLeft"] = BConfig.WebConfig.TemplateLeft - m["BConfig.WebConfig.TemplateRight"] = BConfig.WebConfig.TemplateRight - m["BConfig.WebConfig.ViewsPath"] = BConfig.WebConfig.ViewsPath - m["BConfig.WebConfig.EnableXSRF"] = BConfig.WebConfig.EnableXSRF - m["BConfig.WebConfig.XSRFKEY"] = BConfig.WebConfig.XSRFKey - m["BConfig.WebConfig.XSRFExpire"] = BConfig.WebConfig.XSRFExpire - m["BConfig.WebConfig.Session.SessionOn"] = BConfig.WebConfig.Session.SessionOn - m["BConfig.WebConfig.Session.SessionProvider"] = BConfig.WebConfig.Session.SessionProvider - m["BConfig.WebConfig.Session.SessionName"] = BConfig.WebConfig.Session.SessionName - m["BConfig.WebConfig.Session.SessionGCMaxLifetime"] = BConfig.WebConfig.Session.SessionGCMaxLifetime - m["BConfig.WebConfig.Session.SessionProviderConfig"] = BConfig.WebConfig.Session.SessionProviderConfig - m["BConfig.WebConfig.Session.SessionCookieLifeTime"] = BConfig.WebConfig.Session.SessionCookieLifeTime - m["BConfig.WebConfig.Session.SessionAutoSetCookie"] = BConfig.WebConfig.Session.SessionAutoSetCookie - m["BConfig.WebConfig.Session.SessionDomain"] = BConfig.WebConfig.Session.SessionDomain - m["BConfig.Log.AccessLogs"] = BConfig.Log.AccessLogs - m["BConfig.Log.FileLineNum"] = BConfig.Log.FileLineNum - m["BConfig.Log.Outputs"] = BConfig.Log.Outputs tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) tmpl = template.Must(tmpl.Parse(configTpl)) tmpl = template.Must(tmpl.Parse(defaultScriptsTpl)) @@ -224,6 +178,28 @@ func listConf(rw http.ResponseWriter, r *http.Request) { } } +func list(root string, p interface{}, m map[string]interface{}) { + pt := reflect.TypeOf(p) + pv := reflect.ValueOf(p) + if pt.Kind() == reflect.Ptr { + pt = pt.Elem() + pv = pv.Elem() + } + for i := 0; i < pv.NumField(); i++ { + var key string + if root == "" { + key = pt.Field(i).Name + } else { + key = root + "." + pt.Field(i).Name + } + if pv.Field(i).Kind() == reflect.Struct { + list(key, pv.Field(i).Interface(), m) + } else { + m[key] = pv.Field(i).Interface() + } + } +} + func printTree(resultList *[][]string, t *Tree) { for _, tr := range t.fixrouters { printTree(resultList, tr) diff --git a/admin_test.go b/admin_test.go new file mode 100644 index 00000000..04744f8c --- /dev/null +++ b/admin_test.go @@ -0,0 +1,72 @@ +package beego + +import ( + "testing" + "fmt" +) + +func TestList_01(t *testing.T) { + m := make(map[string]interface{}) + list("BConfig", BConfig, m) + t.Log(m) + om := oldMap() + for k, v := range om { + if fmt.Sprint(m[k])!= fmt.Sprint(v) { + t.Log(k, "old-key",v,"new-key", m[k]) + t.FailNow() + } + } +} + +func oldMap() map[string]interface{} { + m := make(map[string]interface{}) + m["BConfig.AppName"] = BConfig.AppName + m["BConfig.RunMode"] = BConfig.RunMode + m["BConfig.RouterCaseSensitive"] = BConfig.RouterCaseSensitive + m["BConfig.ServerName"] = BConfig.ServerName + m["BConfig.RecoverPanic"] = BConfig.RecoverPanic + m["BConfig.CopyRequestBody"] = BConfig.CopyRequestBody + m["BConfig.EnableGzip"] = BConfig.EnableGzip + m["BConfig.MaxMemory"] = BConfig.MaxMemory + m["BConfig.EnableErrorsShow"] = BConfig.EnableErrorsShow + m["BConfig.Listen.Graceful"] = BConfig.Listen.Graceful + m["BConfig.Listen.ServerTimeOut"] = BConfig.Listen.ServerTimeOut + m["BConfig.Listen.ListenTCP4"] = BConfig.Listen.ListenTCP4 + m["BConfig.Listen.EnableHTTP"] = BConfig.Listen.EnableHTTP + m["BConfig.Listen.HTTPAddr"] = BConfig.Listen.HTTPAddr + m["BConfig.Listen.HTTPPort"] = BConfig.Listen.HTTPPort + m["BConfig.Listen.EnableHTTPS"] = BConfig.Listen.EnableHTTPS + m["BConfig.Listen.HTTPSAddr"] = BConfig.Listen.HTTPSAddr + m["BConfig.Listen.HTTPSPort"] = BConfig.Listen.HTTPSPort + m["BConfig.Listen.HTTPSCertFile"] = BConfig.Listen.HTTPSCertFile + m["BConfig.Listen.HTTPSKeyFile"] = BConfig.Listen.HTTPSKeyFile + m["BConfig.Listen.EnableAdmin"] = BConfig.Listen.EnableAdmin + m["BConfig.Listen.AdminAddr"] = BConfig.Listen.AdminAddr + m["BConfig.Listen.AdminPort"] = BConfig.Listen.AdminPort + m["BConfig.Listen.EnableFcgi"] = BConfig.Listen.EnableFcgi + m["BConfig.Listen.EnableStdIo"] = BConfig.Listen.EnableStdIo + m["BConfig.WebConfig.AutoRender"] = BConfig.WebConfig.AutoRender + m["BConfig.WebConfig.EnableDocs"] = BConfig.WebConfig.EnableDocs + m["BConfig.WebConfig.FlashName"] = BConfig.WebConfig.FlashName + m["BConfig.WebConfig.FlashSeparator"] = BConfig.WebConfig.FlashSeparator + m["BConfig.WebConfig.DirectoryIndex"] = BConfig.WebConfig.DirectoryIndex + m["BConfig.WebConfig.StaticDir"] = BConfig.WebConfig.StaticDir + m["BConfig.WebConfig.StaticExtensionsToGzip"] = BConfig.WebConfig.StaticExtensionsToGzip + m["BConfig.WebConfig.TemplateLeft"] = BConfig.WebConfig.TemplateLeft + m["BConfig.WebConfig.TemplateRight"] = BConfig.WebConfig.TemplateRight + m["BConfig.WebConfig.ViewsPath"] = BConfig.WebConfig.ViewsPath + m["BConfig.WebConfig.EnableXSRF"] = BConfig.WebConfig.EnableXSRF + m["BConfig.WebConfig.XSRFExpire"] = BConfig.WebConfig.XSRFExpire + m["BConfig.WebConfig.Session.SessionOn"] = BConfig.WebConfig.Session.SessionOn + m["BConfig.WebConfig.Session.SessionProvider"] = BConfig.WebConfig.Session.SessionProvider + m["BConfig.WebConfig.Session.SessionName"] = BConfig.WebConfig.Session.SessionName + m["BConfig.WebConfig.Session.SessionGCMaxLifetime"] = BConfig.WebConfig.Session.SessionGCMaxLifetime + m["BConfig.WebConfig.Session.SessionProviderConfig"] = BConfig.WebConfig.Session.SessionProviderConfig + m["BConfig.WebConfig.Session.SessionCookieLifeTime"] = BConfig.WebConfig.Session.SessionCookieLifeTime + m["BConfig.WebConfig.Session.SessionAutoSetCookie"] = BConfig.WebConfig.Session.SessionAutoSetCookie + m["BConfig.WebConfig.Session.SessionDomain"] = BConfig.WebConfig.Session.SessionDomain + m["BConfig.Log.AccessLogs"] = BConfig.Log.AccessLogs + m["BConfig.Log.FileLineNum"] = BConfig.Log.FileLineNum + m["BConfig.Log.Outputs"] = BConfig.Log.Outputs + return m +} From 5ac254bf612d535934d992054fc2d38107087885 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Mon, 18 Apr 2016 19:18:46 +0800 Subject: [PATCH 118/159] ut bug fixed --- config_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config_test.go b/config_test.go index a365199a..c9576afd 100644 --- a/config_test.go +++ b/config_test.go @@ -130,7 +130,7 @@ func TestAssignConfig_03(t *testing.T) { if BConfig.WebConfig.StaticDir["/download"] != "down" { t.FailNow() } - if BConfig.WebConfig.StaticDir["download2"] != "down2" { + if BConfig.WebConfig.StaticDir["/download2"] != "down2" { t.FailNow() } if len(BConfig.WebConfig.StaticExtensionsToGzip) != 5 { From df27c96102ee898afe0e045150b79435cc4b2902 Mon Sep 17 00:00:00 2001 From: Leon Chan Date: Mon, 18 Apr 2016 19:37:38 +0800 Subject: [PATCH 119/159] fix spell error --- controller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller.go b/controller.go index d3abdf38..3a9d1618 100644 --- a/controller.go +++ b/controller.go @@ -261,7 +261,7 @@ func (c *Controller) Abort(code string) { // CustomAbort stops controller handler and show the error data, it's similar Aborts, but support status code and body. func (c *Controller) CustomAbort(status int, body string) { - // first panic from ErrorMaps, is is user defined error functions. + // first panic from ErrorMaps, it is user defined error functions. if _, ok := ErrorMaps[body]; ok { c.Ctx.Output.Status = status panic(body) From 5aa085bf419ec21ab110eebb8b6de7fd3ccfe6c7 Mon Sep 17 00:00:00 2001 From: yuyongsheng <173409900@qq.com> Date: Thu, 21 Apr 2016 09:57:44 +0800 Subject: [PATCH 120/159] 1. remove the invalid comments. 2. allow the user to config "Enable" store/get sessionId into/from http header 3. allow the user to config "Enable" get sessionId from Url query 4. when enable sessionId in http header, check the sessionName format as CanonicalMIMRHeaderKey, then panic if not. --- config.go | 38 +++++++++++++---------- hooks.go | 17 ++++++----- session/session.go | 76 ++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 95 insertions(+), 36 deletions(-) diff --git a/config.go b/config.go index 94e94a5f..f2c79634 100644 --- a/config.go +++ b/config.go @@ -83,14 +83,17 @@ type WebConfig struct { // SessionConfig holds session related config type SessionConfig struct { - SessionOn bool - SessionProvider string - SessionName string - SessionGCMaxLifetime int64 - SessionProviderConfig string - SessionCookieLifeTime int - SessionAutoSetCookie bool - SessionDomain string + SessionOn bool + SessionProvider string + SessionName string + SessionGCMaxLifetime int64 + SessionProviderConfig string + SessionCookieLifeTime int + SessionAutoSetCookie bool + SessionDomain string + EnableSidInHttpHeader bool // enable store/get the sessionId into/from http headers + SessionNameInHttpHeader string + EnableSidInUrlQuery bool // enable get the sessionId from Url Query params } // LogConfig holds Log related config @@ -183,14 +186,17 @@ func newBConfig() *Config { XSRFKey: "beegoxsrf", XSRFExpire: 0, Session: SessionConfig{ - SessionOn: false, - SessionProvider: "memory", - SessionName: "beegosessionID", - SessionGCMaxLifetime: 3600, - SessionProviderConfig: "", - SessionCookieLifeTime: 0, //set cookie default is the browser life - SessionAutoSetCookie: true, - SessionDomain: "", + SessionOn: false, + SessionProvider: "memory", + SessionName: "beegosessionID", + SessionGCMaxLifetime: 3600, + SessionProviderConfig: "", + SessionCookieLifeTime: 0, //set cookie default is the browser life + SessionAutoSetCookie: true, + SessionDomain: "", + EnableSidInHttpHeader: false, // enable store/get the sessionId into/from http headers + SessionNameInHttpHeader: "Beegosessionid", + EnableSidInUrlQuery: false, // enable get the sessionId from Url Query params }, }, Log: LogConfig{ diff --git a/hooks.go b/hooks.go index 610226b4..3dca1b8d 100644 --- a/hooks.go +++ b/hooks.go @@ -47,13 +47,16 @@ func registerSession() error { sessionConfig := AppConfig.String("sessionConfig") if sessionConfig == "" { conf := map[string]interface{}{ - "cookieName": BConfig.WebConfig.Session.SessionName, - "gclifetime": BConfig.WebConfig.Session.SessionGCMaxLifetime, - "providerConfig": filepath.ToSlash(BConfig.WebConfig.Session.SessionProviderConfig), - "secure": BConfig.Listen.EnableHTTPS, - "enableSetCookie": BConfig.WebConfig.Session.SessionAutoSetCookie, - "domain": BConfig.WebConfig.Session.SessionDomain, - "cookieLifeTime": BConfig.WebConfig.Session.SessionCookieLifeTime, + "cookieName": BConfig.WebConfig.Session.SessionName, + "gclifetime": BConfig.WebConfig.Session.SessionGCMaxLifetime, + "providerConfig": filepath.ToSlash(BConfig.WebConfig.Session.SessionProviderConfig), + "secure": BConfig.Listen.EnableHTTPS, + "enableSetCookie": BConfig.WebConfig.Session.SessionAutoSetCookie, + "domain": BConfig.WebConfig.Session.SessionDomain, + "cookieLifeTime": BConfig.WebConfig.Session.SessionCookieLifeTime, + "enableSidInHttpHeader": BConfig.WebConfig.Session.EnableSidInHttpHeader, + "sessionNameInHttpHeader": BConfig.WebConfig.Session.SessionNameInHttpHeader, + "enableSidInUrlQuery": BConfig.WebConfig.Session.EnableSidInUrlQuery, } confBytes, err := json.Marshal(conf) if err != nil { diff --git a/session/session.go b/session/session.go index 2c4b9351..53d89a27 100644 --- a/session/session.go +++ b/session/session.go @@ -31,10 +31,12 @@ import ( "crypto/rand" "encoding/hex" "encoding/json" + "errors" "fmt" "io" "log" "net/http" + "net/textproto" "net/url" "os" "time" @@ -81,15 +83,18 @@ func Register(name string, provide Provider) { } type managerConfig struct { - CookieName string `json:"cookieName"` - EnableSetCookie bool `json:"enableSetCookie,omitempty"` - Gclifetime int64 `json:"gclifetime"` - Maxlifetime int64 `json:"maxLifetime"` - Secure bool `json:"secure"` - CookieLifeTime int `json:"cookieLifeTime"` - ProviderConfig string `json:"providerConfig"` - Domain string `json:"domain"` - SessionIDLength int64 `json:"sessionIDLength"` + CookieName string `json:"cookieName"` + EnableSetCookie bool `json:"enableSetCookie,omitempty"` + Gclifetime int64 `json:"gclifetime"` + Maxlifetime int64 `json:"maxLifetime"` + Secure bool `json:"secure"` + CookieLifeTime int `json:"cookieLifeTime"` + ProviderConfig string `json:"providerConfig"` + Domain string `json:"domain"` + SessionIDLength int64 `json:"sessionIDLength"` + EnableSidInHttpHeader bool `json:"enableSidInHttpHeader"` + SessionNameInHttpHeader string `json:"sessionNameInHttpHeader"` + EnableSidInUrlQuery bool `json:"enableSidInUrlQuery"` } // Manager contains Provider and its configuration. @@ -124,6 +129,23 @@ func NewManager(provideName, config string) (*Manager, error) { if cf.Maxlifetime == 0 { cf.Maxlifetime = cf.Gclifetime } + + if cf.EnableSidInHttpHeader { + if cf.SessionNameInHttpHeader == "" { + err = errors.New("SessionNameInHttpHeader is empty") + panic(err) + return nil, err + } + + strMimeHeader := textproto.CanonicalMIMEHeaderKey(cf.SessionNameInHttpHeader) + if cf.SessionNameInHttpHeader != strMimeHeader { + strErrMsg := "SessionNameInHttpHeader (" + cf.SessionNameInHttpHeader + ") has the wrong format, it should be like this : " + strMimeHeader + err = errors.New(strErrMsg) + panic(err) + return nil, err + } + } + err = provider.SessionInit(cf.Maxlifetime, cf.ProviderConfig) if err != nil { return nil, err @@ -149,12 +171,24 @@ func NewManager(provideName, config string) (*Manager, error) { func (manager *Manager) getSid(r *http.Request) (string, error) { cookie, errs := r.Cookie(manager.config.CookieName) if errs != nil || cookie.Value == "" || cookie.MaxAge < 0 { - errs := r.ParseForm() - if errs != nil { - return "", errs + var sid string + if manager.config.EnableSidInUrlQuery { + errs := r.ParseForm() + if errs != nil { + return "", errs + } + + sid = r.FormValue(manager.config.CookieName) + } + + // if not found in Cookie / param, then read it from request headers + if manager.config.EnableSidInHttpHeader && sid == "" { + sids, isFound := r.Header[manager.config.SessionNameInHttpHeader] + if isFound && len(sids) != 0 { + return sids[0], nil + } } - sid := r.FormValue(manager.config.CookieName) return sid, nil } @@ -198,11 +232,21 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se } r.AddCookie(cookie) + if manager.config.EnableSidInHttpHeader { + r.Header.Set(manager.config.SessionNameInHttpHeader, sid) + w.Header().Set(manager.config.SessionNameInHttpHeader, sid) + } + return } // SessionDestroy Destroy session by its id in http request cookie. func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) { + if manager.config.EnableSidInHttpHeader { + r.Header.Del(manager.config.SessionNameInHttpHeader) + w.Header().Del(manager.config.SessionNameInHttpHeader) + } + cookie, err := r.Cookie(manager.config.CookieName) if err != nil || cookie.Value == "" { return @@ -267,6 +311,12 @@ func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Reque http.SetCookie(w, cookie) } r.AddCookie(cookie) + + if manager.config.EnableSidInHttpHeader { + r.Header.Set(manager.config.SessionNameInHttpHeader, sid) + w.Header().Set(manager.config.SessionNameInHttpHeader, sid) + } + return } From 5402c753fb2ad21c8e62498ec67c5435512addec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?maxin=5B=E9=A9=AC=E9=91=AB=5D?= Date: Tue, 26 Apr 2016 10:16:53 +0800 Subject: [PATCH 121/159] remove redundancy code and add port confict tip --- app.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app.go b/app.go index af54ea4b..cdcfbe94 100644 --- a/app.go +++ b/app.go @@ -137,12 +137,14 @@ func (app *App) Run() { } // run normal mode - app.Server.Addr = addr if BConfig.Listen.EnableHTTPS { go func() { time.Sleep(20 * time.Microsecond) if BConfig.Listen.HTTPSPort != 0 { app.Server.Addr = fmt.Sprintf("%s:%d", BConfig.Listen.HTTPSAddr, BConfig.Listen.HTTPSPort) + } else if BConfig.Listen.EnableHTTP { + BeeLogger.Info("Start https server error, confict with http.Please reset https port") + return } BeeLogger.Info("https server Running on %s", app.Server.Addr) if err := app.Server.ListenAndServeTLS(BConfig.Listen.HTTPSCertFile, BConfig.Listen.HTTPSKeyFile); err != nil { From 710c7c79d4cc613965dc5c3b5f3860959caaa6b1 Mon Sep 17 00:00:00 2001 From: albertma Date: Tue, 26 Apr 2016 18:11:49 +0800 Subject: [PATCH 122/159] 1.fix start task twice issue --- toolbox/task.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/toolbox/task.go b/toolbox/task.go index 537de428..f9492f8f 100644 --- a/toolbox/task.go +++ b/toolbox/task.go @@ -389,11 +389,16 @@ func dayMatches(s *Schedule, t time.Time) bool { // StartTask start all tasks func StartTask() { + if isstart { + //If already started, no need to start another goroutine. + return + } isstart = true go run() } func run() { + now := time.Now().Local() for _, t := range AdminTaskList { t.SetNext(now) @@ -417,7 +422,7 @@ func run() { if e.GetNext() != effective { break } - go e.Run() + go e.Run() e.SetPrev(e.GetNext()) e.SetNext(effective) } @@ -432,8 +437,11 @@ func run() { // StopTask stop all tasks func StopTask() { - isstart = false - stop <- true + if(isstart){ + isstart = false + stop <- true + } + } // AddTask add task with name From a271d67ba4d4401a550cce0d5ffdb126dd9c2820 Mon Sep 17 00:00:00 2001 From: albertma Date: Tue, 26 Apr 2016 18:13:52 +0800 Subject: [PATCH 123/159] 1.fix blank issue --- toolbox/task.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolbox/task.go b/toolbox/task.go index f9492f8f..90bd2a0d 100644 --- a/toolbox/task.go +++ b/toolbox/task.go @@ -422,7 +422,7 @@ func run() { if e.GetNext() != effective { break } - go e.Run() + go e.Run() e.SetPrev(e.GetNext()) e.SetNext(effective) } From 830985b90b9ab49bebc4687fb276d3ff1b745f21 Mon Sep 17 00:00:00 2001 From: ysqi Date: Wed, 27 Apr 2016 22:05:31 +0800 Subject: [PATCH 124/159] QueryEscape Download File Name --- context/output.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/context/output.go b/context/output.go index f0e210a2..e1ad23e0 100644 --- a/context/output.go +++ b/context/output.go @@ -24,6 +24,7 @@ import ( "io" "mime" "net/http" + "net/url" "os" "path/filepath" "strconv" @@ -244,13 +245,15 @@ func (output *BeegoOutput) Download(file string, filename ...string) { return } + var fName string + if len(filename) > 0 && filename[0] != "" { + fName = filename[0] + } else { + fName = filepath.Base(file) + } + output.Header("Content-Disposition", "attachment; filename="+url.QueryEscape(fName)) output.Header("Content-Description", "File Transfer") output.Header("Content-Type", "application/octet-stream") - if len(filename) > 0 && filename[0] != "" { - output.Header("Content-Disposition", "attachment; filename="+filename[0]) - } else { - output.Header("Content-Disposition", "attachment; filename="+filepath.Base(file)) - } output.Header("Content-Transfer-Encoding", "binary") output.Header("Expires", "0") output.Header("Cache-Control", "must-revalidate") From 9e17f518b842b60021a6d912409770d191f059cc Mon Sep 17 00:00:00 2001 From: ysqi Date: Wed, 27 Apr 2016 22:17:53 +0800 Subject: [PATCH 125/159] Fixed print format error info --- config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.go b/config.go index f2c79634..ead538b0 100644 --- a/config.go +++ b/config.go @@ -274,7 +274,7 @@ func assignConfig(ac config.Configer) error { for adaptor, config := range BConfig.Log.Outputs { err := logs.SetLogger(adaptor, config) if err != nil { - fmt.Fprintln(os.Stderr, "%s with the config `%s` got err:%s\n", adaptor, config, err) + fmt.Fprintln(os.Stderr, fmt.Sprintf("%s with the config %q got err:%s", adaptor, config, err.Error())) } } logs.SetLogFuncCall(BConfig.Log.FileLineNum) From 245664010cf15aee6f22e2ac1039df3af4c83953 Mon Sep 17 00:00:00 2001 From: ysqi Date: Wed, 27 Apr 2016 22:18:22 +0800 Subject: [PATCH 126/159] Go Vet --- session/session.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/session/session.go b/session/session.go index 53d89a27..73f0d677 100644 --- a/session/session.go +++ b/session/session.go @@ -132,17 +132,13 @@ func NewManager(provideName, config string) (*Manager, error) { if cf.EnableSidInHttpHeader { if cf.SessionNameInHttpHeader == "" { - err = errors.New("SessionNameInHttpHeader is empty") - panic(err) - return nil, err + panic(errors.New("SessionNameInHttpHeader is empty")) } strMimeHeader := textproto.CanonicalMIMEHeaderKey(cf.SessionNameInHttpHeader) if cf.SessionNameInHttpHeader != strMimeHeader { strErrMsg := "SessionNameInHttpHeader (" + cf.SessionNameInHttpHeader + ") has the wrong format, it should be like this : " + strMimeHeader - err = errors.New(strErrMsg) - panic(err) - return nil, err + panic(errors.New(strErrMsg)) } } From fa7416452e3a722226484975160097cd238d7ed7 Mon Sep 17 00:00:00 2001 From: ysqi Date: Wed, 27 Apr 2016 22:26:32 +0800 Subject: [PATCH 127/159] Change set test mode way --- beego.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/beego.go b/beego.go index db5db3f5..32b64f75 100644 --- a/beego.go +++ b/beego.go @@ -85,9 +85,11 @@ func initBeforeHTTPRun() { // TestBeegoInit is for test package init func TestBeegoInit(ap string) { - os.Setenv("BEEGO_RUNMODE", "test") appConfigPath = filepath.Join(ap, "conf", "app.conf") os.Chdir(ap) - LoadAppConfig(appConfigProvider, appConfigPath) + if err := LoadAppConfig(appConfigProvider, appConfigPath); err != nil { + panic(err) + } + BConfig.RunMode = "test" initBeforeHTTPRun() } From 272271f588d265892421d00480c5af7e3d804b82 Mon Sep 17 00:00:00 2001 From: ysqi Date: Wed, 27 Apr 2016 23:57:22 +0800 Subject: [PATCH 128/159] Change comment router file info --- parser.go | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/parser.go b/parser.go index 46d02320..b19b2705 100644 --- a/parser.go +++ b/parser.go @@ -24,6 +24,7 @@ import ( "io/ioutil" "os" "path" + "path/filepath" "sort" "strings" @@ -56,7 +57,7 @@ func init() { func parserPkg(pkgRealpath, pkgpath string) error { rep := strings.NewReplacer("/", "_", ".", "_") - commentFilename = coomentPrefix + rep.Replace(pkgpath) + ".go" + commentFilename = coomentPrefix + rep.Replace(strings.Replace(pkgRealpath, AppPath, "", -1)) + ".go" if !compareFile(pkgRealpath) { Info(pkgRealpath + " no changed") return nil @@ -86,7 +87,7 @@ func parserPkg(pkgRealpath, pkgpath string) error { } } } - genRouterCode() + genRouterCode(pkgRealpath) savetoFile(pkgRealpath) return nil } @@ -129,8 +130,8 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat return nil } -func genRouterCode() { - os.Mkdir(path.Join(AppPath, "routers"), 0755) +func genRouterCode(pkgRealpath string) { + os.Mkdir(getRouterDir(pkgRealpath), 0755) Info("generate router from comments") var ( globalinfo string @@ -172,7 +173,7 @@ func genRouterCode() { } } if globalinfo != "" { - f, err := os.Create(path.Join(AppPath, "routers", commentFilename)) + f, err := os.Create(path.Join(getRouterDir(pkgRealpath), commentFilename)) if err != nil { panic(err) } @@ -182,7 +183,7 @@ func genRouterCode() { } func compareFile(pkgRealpath string) bool { - if !utils.FileExists(path.Join(AppPath, "routers", commentFilename)) { + if !utils.FileExists(path.Join(getRouterDir(pkgRealpath), commentFilename)) { return true } if utils.FileExists(lastupdateFilename) { @@ -229,3 +230,18 @@ func getpathTime(pkgRealpath string) (lastupdate int64, err error) { } return lastupdate, nil } + +func getRouterDir(pkgRealpath string) string { + dir := filepath.Dir(pkgRealpath) + for { + d := path.Join(dir, "routers") + if dir == AppPath { + return d + } + if utils.FileExists(d) { + return d + } + // Parent dir. + dir = filepath.Dir(dir) + } +} From 2a2b433e1987509076a1c7713c8954589d55778b Mon Sep 17 00:00:00 2001 From: ysqi Date: Wed, 27 Apr 2016 23:57:36 +0800 Subject: [PATCH 129/159] go fmt --- namespace_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/namespace_test.go b/namespace_test.go index a92ae3ef..fc02b5fb 100644 --- a/namespace_test.go +++ b/namespace_test.go @@ -61,8 +61,8 @@ func TestNamespaceNest(t *testing.T) { ns.Namespace( NewNamespace("/admin"). Get("/order", func(ctx *context.Context) { - ctx.Output.Body([]byte("order")) - }), + ctx.Output.Body([]byte("order")) + }), ) AddNamespace(ns) BeeApp.Handlers.ServeHTTP(w, r) @@ -79,8 +79,8 @@ func TestNamespaceNestParam(t *testing.T) { ns.Namespace( NewNamespace("/admin"). Get("/order/:id", func(ctx *context.Context) { - ctx.Output.Body([]byte(ctx.Input.Param(":id"))) - }), + ctx.Output.Body([]byte(ctx.Input.Param(":id"))) + }), ) AddNamespace(ns) BeeApp.Handlers.ServeHTTP(w, r) @@ -124,8 +124,8 @@ func TestNamespaceFilter(t *testing.T) { ctx.Output.Body([]byte("this is Filter")) }). Get("/user/:id", func(ctx *context.Context) { - ctx.Output.Body([]byte(ctx.Input.Param(":id"))) - }) + ctx.Output.Body([]byte(ctx.Input.Param(":id"))) + }) AddNamespace(ns) BeeApp.Handlers.ServeHTTP(w, r) if w.Body.String() != "this is Filter" { From e607be6fa62b1d3207166e870f20309c981b7122 Mon Sep 17 00:00:00 2001 From: albertma Date: Fri, 29 Apr 2016 10:28:10 +0800 Subject: [PATCH 130/159] gofmt the code --- toolbox/task.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/toolbox/task.go b/toolbox/task.go index 90bd2a0d..abd411c8 100644 --- a/toolbox/task.go +++ b/toolbox/task.go @@ -389,16 +389,15 @@ func dayMatches(s *Schedule, t time.Time) bool { // StartTask start all tasks func StartTask() { - if isstart { - //If already started, no need to start another goroutine. - return - } + if isstart { + //If already started, no need to start another goroutine. + return + } isstart = true go run() } func run() { - now := time.Now().Local() for _, t := range AdminTaskList { t.SetNext(now) @@ -422,7 +421,7 @@ func run() { if e.GetNext() != effective { break } - go e.Run() + go e.Run() e.SetPrev(e.GetNext()) e.SetNext(effective) } @@ -437,10 +436,10 @@ func run() { // StopTask stop all tasks func StopTask() { - if(isstart){ - isstart = false - stop <- true - } + if isstart { + isstart = false + stop <- true + } } From 77ff15ee33be54a36f0a36054220ad902c1622c2 Mon Sep 17 00:00:00 2001 From: ysqi Date: Thu, 5 May 2016 19:26:03 +0800 Subject: [PATCH 131/159] Implement Error interface for validation error --- validation/validation.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validation/validation.go b/validation/validation.go index 2b020aa8..489dfa5e 100644 --- a/validation/validation.go +++ b/validation/validation.go @@ -73,6 +73,10 @@ func (e *Error) String() string { return e.Message } +// Implement Error interface. +// Return e.String() +func (e *Error) Error() string { return e.String() } + // Result is returned from every validation method. // It provides an indication of success, and a pointer to the Error (if any). type Result struct { From 8210fd12d17ce5e5e9e2d88f2d718b1d5d482855 Mon Sep 17 00:00:00 2001 From: ysqi Date: Thu, 5 May 2016 19:28:09 +0800 Subject: [PATCH 132/159] Fixed router fileName error in window --- parser.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser.go b/parser.go index b19b2705..4d5b5653 100644 --- a/parser.go +++ b/parser.go @@ -56,7 +56,7 @@ func init() { } func parserPkg(pkgRealpath, pkgpath string) error { - rep := strings.NewReplacer("/", "_", ".", "_") + rep := strings.NewReplacer("\\", "_", "/", "_", ".", "_") commentFilename = coomentPrefix + rep.Replace(strings.Replace(pkgRealpath, AppPath, "", -1)) + ".go" if !compareFile(pkgRealpath) { Info(pkgRealpath + " no changed") From fa8d94fa699511e47e20431fc9d2510e155c9d45 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 6 May 2016 12:09:00 +0800 Subject: [PATCH 133/159] file rotate by day test --- logs/file.go | 19 +++++++++++++++++++ logs/file_test.go | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/logs/file.go b/logs/file.go index 8cf20372..42a1cb46 100644 --- a/logs/file.go +++ b/logs/file.go @@ -174,9 +174,28 @@ func (w *fileLogWriter) initFd() error { } w.maxLinesCurLines = count } + if w.Daily { + go w.dailyRotate(w.dailyOpenTime) + } return nil } +func (w *fileLogWriter) dailyRotate(openTime time.Time) { + y, m, d := openTime.Add(24 * time.Hour).Date() + nextDay := time.Date(y, m, d, 0, 0, 0, 0, openTime.Location()) + tm := time.NewTimer(time.Duration(nextDay.UnixNano() - openTime.UnixNano() + 100)) + select { + case <-tm.C: + w.Lock() + if w.needRotate(0, time.Now().Day()) { + if err := w.doRotate(time.Now()); err != nil { + fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err) + } + } + w.Unlock() + } +} + func (w *fileLogWriter) lines() (int, error) { fd, err := os.Open(w.Filename) if err != nil { diff --git a/logs/file_test.go b/logs/file_test.go index 176f4c1e..d468606c 100644 --- a/logs/file_test.go +++ b/logs/file_test.go @@ -17,6 +17,7 @@ package logs import ( "bufio" "fmt" + "io/ioutil" "os" "strconv" "testing" @@ -125,6 +126,21 @@ func TestFileRotate_03(t *testing.T) { os.Remove(fn) } +func TestFileRotate_04(t *testing.T) { + fn1 := "rotate_day.log" + fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".log" + testFileDailyRotate(t, fn1, fn2) +} + +func TestFileRotate_05(t *testing.T) { + fn1 := "rotate_day.log" + fn := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".log" + os.Create(fn) + fn2 := "rotate_day." + time.Now().Add(-24*time.Hour).Format("2006-01-02") + ".001.log" + testFileDailyRotate(t, fn1, fn2) + os.Remove(fn) +} + func testFileRotate(t *testing.T, fn1, fn2 string) { fw := &fileLogWriter{ Daily: true, @@ -145,6 +161,38 @@ func testFileRotate(t *testing.T, fn1, fn2 string) { } os.Remove(file) } + fw.Destroy() +} + +func testFileDailyRotate(t *testing.T, fn1, fn2 string) { + fw := &fileLogWriter{ + Daily: true, + MaxDays: 7, + Rotate: true, + Level: LevelTrace, + Perm: 0660, + } + fw.Init(fmt.Sprintf(`{"filename":"%v","maxdays":1}`, fn1)) + fw.dailyOpenTime = time.Now().Add(-24 * time.Hour) + fw.dailyOpenDate = fw.dailyOpenTime.Day() + today, _ := time.ParseInLocation("2006-01-02", time.Now().Format("2006-01-02"), fw.dailyOpenTime.Location()) + today = today.Add(-1 * time.Second) + fw.dailyRotate(today) + for _, file := range []string{fn1, fn2} { + _, err := os.Stat(file) + if err != nil { + t.FailNow() + } + content, err := ioutil.ReadFile(file) + if err != nil { + t.FailNow() + } + if len(content) > 0 { + t.FailNow() + } + os.Remove(file) + } + fw.Destroy() } func exists(path string) (bool, error) { From b28581a463dbefccd8bea73461a2958874afbebe Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 6 May 2016 12:11:14 +0800 Subject: [PATCH 134/159] make daily rotate --- logs/file.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/logs/file.go b/logs/file.go index 42a1cb46..b87664bd 100644 --- a/logs/file.go +++ b/logs/file.go @@ -167,6 +167,9 @@ func (w *fileLogWriter) initFd() error { w.dailyOpenTime = time.Now() w.dailyOpenDate = w.dailyOpenTime.Day() w.maxLinesCurLines = 0 + if w.Daily { + go w.dailyRotate(w.dailyOpenTime) + } if fInfo.Size() > 0 { count, err := w.lines() if err != nil { @@ -174,9 +177,6 @@ func (w *fileLogWriter) initFd() error { } w.maxLinesCurLines = count } - if w.Daily { - go w.dailyRotate(w.dailyOpenTime) - } return nil } From 7ceff43db6a11e426726ed1c66afcad44388f44b Mon Sep 17 00:00:00 2001 From: ysqi Date: Fri, 6 May 2016 13:26:48 +0800 Subject: [PATCH 135/159] Fixed error in window os --- parser.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/parser.go b/parser.go index fe719dce..3bf3cf6b 100644 --- a/parser.go +++ b/parser.go @@ -23,7 +23,6 @@ import ( "go/token" "io/ioutil" "os" - "path" "path/filepath" "sort" "strings" @@ -58,7 +57,8 @@ func init() { func parserPkg(pkgRealpath, pkgpath string) error { rep := strings.NewReplacer("\\", "_", "/", "_", ".", "_") - commentFilename = coomentPrefix + rep.Replace(strings.Replace(pkgRealpath, AppPath, "", -1)) + ".go" + commentFilename, _ = filepath.Rel(AppPath, pkgRealpath) + commentFilename = coomentPrefix + rep.Replace(commentFilename) + ".go" if !compareFile(pkgRealpath) { logs.Info(pkgRealpath + " no changed") return nil @@ -174,7 +174,7 @@ func genRouterCode(pkgRealpath string) { } } if globalinfo != "" { - f, err := os.Create(path.Join(getRouterDir(pkgRealpath), commentFilename)) + f, err := os.Create(filepath.Join(getRouterDir(pkgRealpath), commentFilename)) if err != nil { panic(err) } @@ -184,7 +184,7 @@ func genRouterCode(pkgRealpath string) { } func compareFile(pkgRealpath string) bool { - if !utils.FileExists(path.Join(getRouterDir(pkgRealpath), commentFilename)) { + if !utils.FileExists(filepath.Join(getRouterDir(pkgRealpath), commentFilename)) { return true } if utils.FileExists(lastupdateFilename) { @@ -235,11 +235,12 @@ func getpathTime(pkgRealpath string) (lastupdate int64, err error) { func getRouterDir(pkgRealpath string) string { dir := filepath.Dir(pkgRealpath) for { - d := path.Join(dir, "routers") - if dir == AppPath { + d := filepath.Join(dir, "routers") + if utils.FileExists(d) { return d } - if utils.FileExists(d) { + + if r, _ := filepath.Rel(dir, AppPath); r == "." { return d } // Parent dir. From a4d4b8de779fdc79f841f431f5be4ef0b16a1eff Mon Sep 17 00:00:00 2001 From: wincss Date: Tue, 10 May 2016 17:45:06 +0800 Subject: [PATCH 136/159] fix #1936 --- orm/db.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/orm/db.go b/orm/db.go index 7796686a..78c72e87 100644 --- a/orm/db.go +++ b/orm/db.go @@ -1475,7 +1475,11 @@ func (d *dbBase) ReadValues(q dbQuerier, qs *querySet, mi *modelInfo, cond *Cond sels := strings.Join(cols, ", ") - query := fmt.Sprintf("SELECT %s FROM %s%s%s T0 %s%s%s%s%s", sels, Q, mi.table, Q, join, where, groupBy, orderBy, limit) + sqlSelect := "SELECT" + if qs.distinct { + sqlSelect += " DISTINCT" + } + query := fmt.Sprintf("%s %s FROM %s%s%s T0 %s%s%s%s%s", sqlSelect, sels, Q, mi.table, Q, join, where, groupBy, orderBy, limit) d.ins.ReplaceMarks(&query) From 27be1e7ca3ce2e52efc38b4757623be3041817c2 Mon Sep 17 00:00:00 2001 From: lcbluestorm Date: Tue, 10 May 2016 19:56:45 +0800 Subject: [PATCH 137/159] add ssdb-session interface --- session/ssdb/sess_ssdb.go | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 session/ssdb/sess_ssdb.go diff --git a/session/ssdb/sess_ssdb.go b/session/ssdb/sess_ssdb.go new file mode 100644 index 00000000..109f3416 --- /dev/null +++ b/session/ssdb/sess_ssdb.go @@ -0,0 +1,55 @@ +package ssdb + +import ( + "net/http" + + "github.com/astaxie/beego/session" + "github.com/ssdb/gossdb/ssdb" +) + +var ssdbSsdbProvider = &SsdbSsdbProvider{} + +type SsdbProvider struct { +} + +func (r *SsdbProvider) SessionInit(maxlifetime int64, savePath string) error { +} + +func (r *SsdbProvider) SessionRead(sid string) (session.Store, error) { +} + +func (r *SsdbProvider) SessionExist(sid string) bool { +} +func (r *SsdbProvider) SessionRegenerate(oldsid, sid string) (session.Store, error) { +} + +func (r *SsdbProvider) SessionDestroy(sid string) error { +} + +func (r *SsdbProvider) SessionGC() { + return +} + +func (r *SsdbProvider) SessionAll() int { + return 0 +} + +type SessionStore struct { +} + +func (s *SessionStore) Set(key, value interface{}) error { +} +func (s *SessionStore) Get(key interface{}) interface{} { +} +func (s *SessionStore) Delete(key interface{}) error { +} +func (s *SessionStore) Flush() error { +} +func (s *SessionStore) SessionID() string { +} + +func (s *SessionStore) SessionRelease(w http.ResponseWriter) { +} +func init() { + session.Register("redis", redispder) +} From 0e4b9563ae42173f49182168b2d4bc77aed3add9 Mon Sep 17 00:00:00 2001 From: lcbluestorm Date: Tue, 10 May 2016 20:08:15 +0800 Subject: [PATCH 138/159] add test file --- session/ssdb/sess_ssdb_test.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 session/ssdb/sess_ssdb_test.go diff --git a/session/ssdb/sess_ssdb_test.go b/session/ssdb/sess_ssdb_test.go new file mode 100644 index 00000000..e69de29b From 153d76e20071f4e963088c9f815aa003e15c4eb9 Mon Sep 17 00:00:00 2001 From: Mark Mindenhall Date: Tue, 10 May 2016 22:54:33 -0600 Subject: [PATCH 139/159] More flexible support for template engines --- template.go | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/template.go b/template.go index 63eae741..3d07ec55 100644 --- a/template.go +++ b/template.go @@ -33,13 +33,12 @@ import ( var ( beegoTplFuncMap = make(template.FuncMap) // beeTemplates caching map and supported template file extensions. - beeTemplates = make(map[string]TemplateRenderer) + beeTemplates = make(map[string]*template.Template) templatesLock sync.RWMutex // beeTemplateExt stores the template extension which will build beeTemplateExt = []string{"tpl", "html"} // beeTemplatePreprocessors stores associations of extension -> preprocessor handler - beeTemplateEngines = map[string]templateHandler{} -) + beeTemplateEngines = map[string]templatePreProcessor{}) // ExecuteTemplate applies the template with name to the specified data object, // writing the output to wr. @@ -50,11 +49,22 @@ func ExecuteTemplate(wr io.Writer, name string, data interface{}) error { defer templatesLock.RUnlock() } if t, ok := beeTemplates[name]; ok { - err := t.ExecuteTemplate(wr, name, data) - if err != nil { - logs.Trace("template Execute err:", err) + if t.Lookup(name) != nil { + err := t.ExecuteTemplate(wr, name, data) + if err != nil { + logs.Trace("template Execute err:", err) + } + return err + } else { + err := t.Execute(wr, data) + if err != nil { + if err != nil { + logs.Trace("template Execute err:", err) + } + return err + } } - return err + return nil } panic("can't find templatefile in the path:" + name) } @@ -94,10 +104,8 @@ func AddFuncMap(key string, fn interface{}) error { return nil } -type templateHandler func(root, path string, funcs template.FuncMap) (TemplateRenderer, error) -type TemplateRenderer interface { - ExecuteTemplate(wr io.Writer, name string, data interface{}) error -} +type templatePreProcessor func(root, path string, funcs template.FuncMap) (*template.Template, error) + type templateFile struct { root string files map[string][]string @@ -172,7 +180,7 @@ func BuildTemplate(dir string, files ...string) error { if buildAllFiles || utils.InSlice(file, files) { templatesLock.Lock() ext := filepath.Ext(file) - var t TemplateRenderer + var t *template.Template if len(ext) == 0 { t, err = getTemplate(self.root, file, v...) } else if fn, ok := beeTemplateEngines[ext[1:]]; ok { @@ -325,7 +333,7 @@ func DelStaticPath(url string) *App { return BeeApp } -func AddTemplateEngine(extension string, fn templateHandler) *App { +func AddTemplateEngine(extension string, fn templatePreProcessor) *App { AddTemplateExt(extension) beeTemplateEngines[extension] = fn return BeeApp From d679a4b865f24a806ec6e4a3d3b9a977eded9f5f Mon Sep 17 00:00:00 2001 From: nullne Date: Sat, 14 May 2016 10:54:09 +0800 Subject: [PATCH 140/159] fix bug with file permission in log module --- logs/file.go | 14 +++++++++++--- logs/file_test.go | 25 +++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/logs/file.go b/logs/file.go index b87664bd..f75e5bae 100644 --- a/logs/file.go +++ b/logs/file.go @@ -22,6 +22,7 @@ import ( "io" "os" "path/filepath" + "strconv" "strings" "sync" "time" @@ -53,7 +54,8 @@ type fileLogWriter struct { Level int `json:"level"` - Perm os.FileMode `json:"perm"` + Perm string `json:"perm"` + perm os.FileMode fileNameOnly, suffix string // like "project.log", project is fileNameOnly and .log is suffix } @@ -65,7 +67,8 @@ func newFileWriter() Logger { MaxDays: 7, Rotate: true, Level: LevelTrace, - Perm: 0660, + Perm: "0660", + perm: 0660, } return w } @@ -89,6 +92,11 @@ func (w *fileLogWriter) Init(jsonConfig string) error { if len(w.Filename) == 0 { return errors.New("jsonconfig must have filename") } + perm, err := strconv.ParseInt(w.Perm, 8, 64) + if err != nil { + return err + } + w.perm = os.FileMode(perm) w.suffix = filepath.Ext(w.Filename) w.fileNameOnly = strings.TrimSuffix(w.Filename, w.suffix) if w.suffix == "" { @@ -153,7 +161,7 @@ func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error { func (w *fileLogWriter) createLogFile() (*os.File, error) { // Open the log file - fd, err := os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, w.Perm) + fd, err := os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, w.perm) return fd, err } diff --git a/logs/file_test.go b/logs/file_test.go index d468606c..23370947 100644 --- a/logs/file_test.go +++ b/logs/file_test.go @@ -24,6 +24,27 @@ import ( "time" ) +func TestFilePerm(t *testing.T) { + log := NewLogger(10000) + log.SetLogger("file", `{"filename":"test.log", "perm": "0600"}`) + log.Debug("debug") + log.Informational("info") + log.Notice("notice") + log.Warning("warning") + log.Error("error") + log.Alert("alert") + log.Critical("critical") + log.Emergency("emergency") + file, err := os.Stat("test.log") + if err != nil { + t.Fatal(err) + } + if file.Mode() != 0600 { + t.Fatal("unexpected log file permission") + } + os.Remove("test.log") +} + func TestFile1(t *testing.T) { log := NewLogger(10000) log.SetLogger("file", `{"filename":"test.log"}`) @@ -147,7 +168,7 @@ func testFileRotate(t *testing.T, fn1, fn2 string) { MaxDays: 7, Rotate: true, Level: LevelTrace, - Perm: 0660, + Perm: "0660", } fw.Init(fmt.Sprintf(`{"filename":"%v","maxdays":1}`, fn1)) fw.dailyOpenTime = time.Now().Add(-24 * time.Hour) @@ -170,7 +191,7 @@ func testFileDailyRotate(t *testing.T, fn1, fn2 string) { MaxDays: 7, Rotate: true, Level: LevelTrace, - Perm: 0660, + Perm: "0660", } fw.Init(fmt.Sprintf(`{"filename":"%v","maxdays":1}`, fn1)) fw.dailyOpenTime = time.Now().Add(-24 * time.Hour) From e50f4f5631957a741589398f0d14a9e6df241d53 Mon Sep 17 00:00:00 2001 From: lcbluestorm Date: Sun, 15 May 2016 12:15:40 +0800 Subject: [PATCH 141/159] complete sess_ssdb.go --- session/ssdb/sess_ssdb.go | 148 +++++++++++++++++++++++++++++++++++--- 1 file changed, 138 insertions(+), 10 deletions(-) diff --git a/session/ssdb/sess_ssdb.go b/session/ssdb/sess_ssdb.go index 109f3416..26dd3e8a 100644 --- a/session/ssdb/sess_ssdb.go +++ b/session/ssdb/sess_ssdb.go @@ -2,54 +2,182 @@ package ssdb import ( "net/http" + "strconv" + "strings" + "sync" "github.com/astaxie/beego/session" "github.com/ssdb/gossdb/ssdb" ) -var ssdbSsdbProvider = &SsdbSsdbProvider{} +var ssdbProvider = &SsdbProvider{} type SsdbProvider struct { + client *ssdb.Client + host string + port int32 + maxLifetime int64 } -func (r *SsdbProvider) SessionInit(maxlifetime int64, savePath string) error { +func (p *SsdbProvider) connectInit() error { + var err error + p.client, err = ssdb.Connect(p.host, p.port) + if err != nil { + return err + } + return nil } -func (r *SsdbProvider) SessionRead(sid string) (session.Store, error) { +func (p *SsdbProvider) SessionInit(maxLifetime int64, savePath string) error { + p.maxLifetime = maxLifetime + address := strings.Split(savePath, ":") + p.host = address[0] + port, e := strconv.Atoi(address[1]) + if e != nil { + return e + } + p.port = address[1] + err := p.connectinit() + if err != nil { + return err + } + return nil } -func (r *SsdbProvider) SessionExist(sid string) bool { -} -func (r *SsdbProvider) SessionRegenerate(oldsid, sid string) (session.Store, error) { +func (p *SsdbProvider) SessionRead(sid string) (session.Store, error) { + if p.client == nil { + if err := p.connectInit(); err != nil { + return nil, err + } + } + var kv map[interface{}]interface{} + value, err := p.client.Get(sid) + if err != nil { + return nil, err + } + if value == nil || len(value) == 0 { + kv = make(map[interface{}]interface{}) + } else { + kv, err = session.DecodeGob([]byte(value)) + if err != nil { + return nil, err + } + } + rs := &SessionStore{sid: sid, values: kv, maxLifetime: p.maxLifetime, client: p.client} + return rs, nil } -func (r *SsdbProvider) SessionDestroy(sid string) error { +func (p *SsdbProvider) SessionExist(sid string) bool { + if p.client == nil { + if err := p.connectInit(); err != nil { + return nil, err + } + } + if value == nil || len(value) == 0 { + return false + } + return true + +} +func (p *SsdbProvider) SessionRegenerate(oldsid, sid string) (session.Store, error) { + //conn.Do("setx", key, v, ttl) + if p.client == nil { + if err := p.connectInit(); err != nil { + return nil, err + } + } + value, err := p.client.Get(oldsid) + if err != nil || len(value) == 0 { + value = "" + } else { + err = p.client.Del(sid) + } + _, e := p.client.Do("setx", sid, value, p.maxLifetime) + if e != nil { + return nil, e + } + var kv map[interface{}]interface{} + if value == nil || len(value) == 0 { + kv = make(map[interface{}]interface{}) + } else { + var err error + kv, err = session.DecodeGob(value) + if err != nil { + return nil, err + } + } + rs := &SessionStore{sid: sid, values: kv, maxLifetime: p.maxLifetime, client: p.client} + return rs, nil } -func (r *SsdbProvider) SessionGC() { +func (p *SsdbProvider) SessionDestroy(sid string) error { + if p.client == nil { + if err := p.connectInit(); err != nil { + return nil, err + } + } + flag, err := p.client.Del(sid) + if err != nil { + return err + } + return nil +} + +func (p *SsdbProvider) SessionGC() { return } -func (r *SsdbProvider) SessionAll() int { +func (p *SsdbProvider) SessionAll() int { return 0 } type SessionStore struct { + sid string + lock sync.RWMutex + values map[interface{}]interface{} + maxLifetime int64 + client *ssdb.Client } func (s *SessionStore) Set(key, value interface{}) error { + s.lock.Lock() + defer s.lock.Unlock() + s.values[key] = value + return nil } func (s *SessionStore) Get(key interface{}) interface{} { + s.lock.Lock() + defer s.lock.Unlock() + if value, ok := rs.values[key]; ok { + return value + } + return nil } + func (s *SessionStore) Delete(key interface{}) error { + s.lock.Lock() + defer s.lock.Unlock() + delete(s.values, key) + return nil } func (s *SessionStore) Flush() error { + s.lock.Lock() + defer s.lock.Unlock() + s.values = make(map[interface{}]interface{}) + return nil } func (s *SessionStore) SessionID() string { + return s.sid } func (s *SessionStore) SessionRelease(w http.ResponseWriter) { + b, err := session.EncodeGob(s.values) + if err != nil { + return + } + s.client.Do("setx", s.sid, s.values, s.maxLifetime) + } func init() { - session.Register("redis", redispder) + session.Register("ssdb", ssdbProvider) } From 2c12383263fdd1247dbca150eb32abd1176115e7 Mon Sep 17 00:00:00 2001 From: nullne Date: Tue, 17 May 2016 10:29:05 +0800 Subject: [PATCH 142/159] remove attribute perm to make it more brief --- logs/file.go | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/logs/file.go b/logs/file.go index f75e5bae..7798a221 100644 --- a/logs/file.go +++ b/logs/file.go @@ -55,7 +55,6 @@ type fileLogWriter struct { Level int `json:"level"` Perm string `json:"perm"` - perm os.FileMode fileNameOnly, suffix string // like "project.log", project is fileNameOnly and .log is suffix } @@ -68,7 +67,6 @@ func newFileWriter() Logger { Rotate: true, Level: LevelTrace, Perm: "0660", - perm: 0660, } return w } @@ -82,7 +80,7 @@ func newFileWriter() Logger { // "daily":true, // "maxDays":15, // "rotate":true, -// "perm":0600 +// "perm":"0600" // } func (w *fileLogWriter) Init(jsonConfig string) error { err := json.Unmarshal([]byte(jsonConfig), w) @@ -92,11 +90,6 @@ func (w *fileLogWriter) Init(jsonConfig string) error { if len(w.Filename) == 0 { return errors.New("jsonconfig must have filename") } - perm, err := strconv.ParseInt(w.Perm, 8, 64) - if err != nil { - return err - } - w.perm = os.FileMode(perm) w.suffix = filepath.Ext(w.Filename) w.fileNameOnly = strings.TrimSuffix(w.Filename, w.suffix) if w.suffix == "" { @@ -161,7 +154,11 @@ func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error { func (w *fileLogWriter) createLogFile() (*os.File, error) { // Open the log file - fd, err := os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, w.perm) + perm, err := strconv.ParseInt(w.Perm, 8, 64) + if err != nil { + return nil, err + } + fd, err := os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(perm)) return fd, err } From 6234b50111b867a34ad8fa9b1bde4450bc6eed80 Mon Sep 17 00:00:00 2001 From: lcbluestorm Date: Thu, 19 May 2016 21:00:04 +0800 Subject: [PATCH 143/159] test done --- session/ssdb/sess_ssdb.go | 50 +++++++++++++++------------- session/ssdb/sess_ssdb_test.go | 60 ++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 22 deletions(-) diff --git a/session/ssdb/sess_ssdb.go b/session/ssdb/sess_ssdb.go index 26dd3e8a..cbb94840 100644 --- a/session/ssdb/sess_ssdb.go +++ b/session/ssdb/sess_ssdb.go @@ -15,7 +15,7 @@ var ssdbProvider = &SsdbProvider{} type SsdbProvider struct { client *ssdb.Client host string - port int32 + port int maxLifetime int64 } @@ -29,15 +29,15 @@ func (p *SsdbProvider) connectInit() error { } func (p *SsdbProvider) SessionInit(maxLifetime int64, savePath string) error { + var e error = nil p.maxLifetime = maxLifetime address := strings.Split(savePath, ":") p.host = address[0] - port, e := strconv.Atoi(address[1]) + p.port, e = strconv.Atoi(address[1]) if e != nil { return e } - p.port = address[1] - err := p.connectinit() + err := p.connectInit() if err != nil { return err } @@ -55,10 +55,10 @@ func (p *SsdbProvider) SessionRead(sid string) (session.Store, error) { if err != nil { return nil, err } - if value == nil || len(value) == 0 { + if value == nil || len(value.(string)) == 0 { kv = make(map[interface{}]interface{}) } else { - kv, err = session.DecodeGob([]byte(value)) + kv, err = session.DecodeGob([]byte(value.(string))) if err != nil { return nil, err } @@ -70,10 +70,14 @@ func (p *SsdbProvider) SessionRead(sid string) (session.Store, error) { func (p *SsdbProvider) SessionExist(sid string) bool { if p.client == nil { if err := p.connectInit(); err != nil { - return nil, err + panic(err) } } - if value == nil || len(value) == 0 { + value, err := p.client.Get(sid) + if err != nil { + panic(err) + } + if value == nil || len(value.(string)) == 0 { return false } return true @@ -87,24 +91,26 @@ func (p *SsdbProvider) SessionRegenerate(oldsid, sid string) (session.Store, err } } value, err := p.client.Get(oldsid) - if err != nil || len(value) == 0 { - value = "" - } else { - err = p.client.Del(sid) - } - _, e := p.client.Do("setx", sid, value, p.maxLifetime) - if e != nil { - return nil, e + if err != nil { + return nil, err } var kv map[interface{}]interface{} - if value == nil || len(value) == 0 { + if value == nil || len(value.(string)) == 0 { kv = make(map[interface{}]interface{}) } else { var err error - kv, err = session.DecodeGob(value) + kv, err = session.DecodeGob([]byte(value.(string))) if err != nil { return nil, err } + _, err = p.client.Del(oldsid) + if err != nil { + return nil, err + } + } + _, e := p.client.Do("setx", sid, value.(string), p.maxLifetime) + if e != nil { + return nil, e } rs := &SessionStore{sid: sid, values: kv, maxLifetime: p.maxLifetime, client: p.client} return rs, nil @@ -113,10 +119,10 @@ func (p *SsdbProvider) SessionRegenerate(oldsid, sid string) (session.Store, err func (p *SsdbProvider) SessionDestroy(sid string) error { if p.client == nil { if err := p.connectInit(); err != nil { - return nil, err + return err } } - flag, err := p.client.Del(sid) + _, err := p.client.Del(sid) if err != nil { return err } @@ -148,7 +154,7 @@ func (s *SessionStore) Set(key, value interface{}) error { func (s *SessionStore) Get(key interface{}) interface{} { s.lock.Lock() defer s.lock.Unlock() - if value, ok := rs.values[key]; ok { + if value, ok := s.values[key]; ok { return value } return nil @@ -175,7 +181,7 @@ func (s *SessionStore) SessionRelease(w http.ResponseWriter) { if err != nil { return } - s.client.Do("setx", s.sid, s.values, s.maxLifetime) + s.client.Do("setx", s.sid, string(b), s.maxLifetime) } func init() { diff --git a/session/ssdb/sess_ssdb_test.go b/session/ssdb/sess_ssdb_test.go index e69de29b..dfeba4a3 100644 --- a/session/ssdb/sess_ssdb_test.go +++ b/session/ssdb/sess_ssdb_test.go @@ -0,0 +1,60 @@ +package ssdb + +import ( + "fmt" + "net/http" + "testing" +) + +func Test(t *testing.T) { + p := &SsdbProvider{} + p.SessionInit(300, "127.0.0.1:8888") + if p.host != "127.0.0.1" || p.port != 8888 { + t.Error("host:port err") + } + if p.client == nil { + t.Error("client err") + } + ss, err := p.SessionRead("1") + if err != nil { + t.Error(err) + } + err = ss.Set("key", "value") + if err != nil { + t.Error(err) + } + if ss.Get("key") != "value" { + t.Error("Get err") + } + err = ss.Delete("key") + //err = ss.Flush() + if err != nil { + t.Error(err) + } + if ss.Get("key") == "value" { + t.Error("Delete/Flush err") + } + if ss.SessionID() != "1" { + t.Error("id err") + } + + ss.Set("key1", "value1") + var w http.ResponseWriter + ss.SessionRelease(w) + new, e := p.SessionRead("1") + if new == nil || e != nil { + t.Error(e) + } + if !p.SessionExist("1") { + t.Error("SessionExist err") + } + newS, er := p.SessionRegenerate("1", "3") + if er != nil || newS == nil { + t.Error("SessionRegenerate err") + } + if p.SessionExist("1") { + t.Error("SessionExist err") + } + fmt.Println(newS) + +} From 4890dd708c9b9245ed969339e12d2c70a5c4303d Mon Sep 17 00:00:00 2001 From: lcbluestorm Date: Fri, 20 May 2016 10:27:18 +0800 Subject: [PATCH 144/159] clear code --- session/ssdb/sess_ssdb.go | 7 +++++-- session/ssdb/sess_ssdb_test.go | 3 --- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/session/ssdb/sess_ssdb.go b/session/ssdb/sess_ssdb.go index cbb94840..4dcf160a 100644 --- a/session/ssdb/sess_ssdb.go +++ b/session/ssdb/sess_ssdb.go @@ -1,6 +1,7 @@ package ssdb import ( + "errors" "net/http" "strconv" "strings" @@ -21,6 +22,9 @@ type SsdbProvider struct { func (p *SsdbProvider) connectInit() error { var err error + if p.host == "" || p.port == 0 { + return errors.New("SessionInit First") + } p.client, err = ssdb.Connect(p.host, p.port) if err != nil { return err @@ -98,7 +102,6 @@ func (p *SsdbProvider) SessionRegenerate(oldsid, sid string) (session.Store, err if value == nil || len(value.(string)) == 0 { kv = make(map[interface{}]interface{}) } else { - var err error kv, err = session.DecodeGob([]byte(value.(string))) if err != nil { return nil, err @@ -108,7 +111,7 @@ func (p *SsdbProvider) SessionRegenerate(oldsid, sid string) (session.Store, err return nil, err } } - _, e := p.client.Do("setx", sid, value.(string), p.maxLifetime) + _, e := p.client.Do("setx", sid, value, p.maxLifetime) if e != nil { return nil, e } diff --git a/session/ssdb/sess_ssdb_test.go b/session/ssdb/sess_ssdb_test.go index dfeba4a3..4a5933f2 100644 --- a/session/ssdb/sess_ssdb_test.go +++ b/session/ssdb/sess_ssdb_test.go @@ -1,7 +1,6 @@ package ssdb import ( - "fmt" "net/http" "testing" ) @@ -55,6 +54,4 @@ func Test(t *testing.T) { if p.SessionExist("1") { t.Error("SessionExist err") } - fmt.Println(newS) - } From e77a591a6c28d90cc0c9daf23f2cb5030878362e Mon Sep 17 00:00:00 2001 From: lcbluestorm Date: Fri, 20 May 2016 17:25:22 +0800 Subject: [PATCH 145/159] delete test file --- session/ssdb/sess_ssdb_test.go | 57 ---------------------------------- 1 file changed, 57 deletions(-) delete mode 100644 session/ssdb/sess_ssdb_test.go diff --git a/session/ssdb/sess_ssdb_test.go b/session/ssdb/sess_ssdb_test.go deleted file mode 100644 index 4a5933f2..00000000 --- a/session/ssdb/sess_ssdb_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package ssdb - -import ( - "net/http" - "testing" -) - -func Test(t *testing.T) { - p := &SsdbProvider{} - p.SessionInit(300, "127.0.0.1:8888") - if p.host != "127.0.0.1" || p.port != 8888 { - t.Error("host:port err") - } - if p.client == nil { - t.Error("client err") - } - ss, err := p.SessionRead("1") - if err != nil { - t.Error(err) - } - err = ss.Set("key", "value") - if err != nil { - t.Error(err) - } - if ss.Get("key") != "value" { - t.Error("Get err") - } - err = ss.Delete("key") - //err = ss.Flush() - if err != nil { - t.Error(err) - } - if ss.Get("key") == "value" { - t.Error("Delete/Flush err") - } - if ss.SessionID() != "1" { - t.Error("id err") - } - - ss.Set("key1", "value1") - var w http.ResponseWriter - ss.SessionRelease(w) - new, e := p.SessionRead("1") - if new == nil || e != nil { - t.Error(e) - } - if !p.SessionExist("1") { - t.Error("SessionExist err") - } - newS, er := p.SessionRegenerate("1", "3") - if er != nil || newS == nil { - t.Error("SessionRegenerate err") - } - if p.SessionExist("1") { - t.Error("SessionExist err") - } -} From f32392e956316f001e4d7e2e47890d22fc9b2c7a Mon Sep 17 00:00:00 2001 From: tinyproxy Date: Sat, 21 May 2016 15:19:21 +0800 Subject: [PATCH 146/159] net/http will do it better --- context/context.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/context/context.go b/context/context.go index 63a1313d..d5226ec0 100644 --- a/context/context.go +++ b/context/context.go @@ -70,10 +70,8 @@ func (ctx *Context) Reset(rw http.ResponseWriter, r *http.Request) { } // Redirect does redirection to localurl with http header status code. -// It sends http response header directly. func (ctx *Context) Redirect(status int, localurl string) { - ctx.Output.Header("Location", localurl) - ctx.ResponseWriter.WriteHeader(status) + http.Redirect(ctx.ResponseWriter, ctx.Request, localurl, status) } // Abort stops this request. From 24b887063728f4f93d8d6d9a91bf612b3032d303 Mon Sep 17 00:00:00 2001 From: Mark Mindenhall Date: Mon, 23 May 2016 21:43:18 -0600 Subject: [PATCH 147/159] move paren to new line --- template.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/template.go b/template.go index 3d07ec55..494acc4f 100644 --- a/template.go +++ b/template.go @@ -38,7 +38,8 @@ var ( // beeTemplateExt stores the template extension which will build beeTemplateExt = []string{"tpl", "html"} // beeTemplatePreprocessors stores associations of extension -> preprocessor handler - beeTemplateEngines = map[string]templatePreProcessor{}) + beeTemplateEngines = map[string]templatePreProcessor{} +) // ExecuteTemplate applies the template with name to the specified data object, // writing the output to wr. From d4d7621942907818d40e51f61576f20bfaa51d91 Mon Sep 17 00:00:00 2001 From: wy65701436 Date: Fri, 27 May 2016 02:03:58 -0700 Subject: [PATCH 148/159] modify the error log for registerModel to tell user the default hard code PK is 'id'. --- orm/models_boot.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orm/models_boot.go b/orm/models_boot.go index 3690557b..c9905330 100644 --- a/orm/models_boot.go +++ b/orm/models_boot.go @@ -66,7 +66,7 @@ func registerModel(prefix string, model interface{}) { } if info.fields.pk == nil { - fmt.Printf(" `%s` need a primary key field\n", name) + fmt.Printf(" `%s` need a primary key field, default use 'id' if not set\n", name) os.Exit(2) } From d528fafd43a2bd202024a9986ef8bb9617623bd1 Mon Sep 17 00:00:00 2001 From: ysqi Date: Fri, 3 Jun 2016 22:06:43 +0800 Subject: [PATCH 149/159] ignore case of tag and fixed bug for columName --- orm/models_utils.go | 6 +++--- orm/orm_test.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ orm/utils.go | 32 +++++++++++++++++++++++++------- 3 files changed, 72 insertions(+), 10 deletions(-) diff --git a/orm/models_utils.go b/orm/models_utils.go index ec11d516..1dc17f81 100644 --- a/orm/models_utils.go +++ b/orm/models_utils.go @@ -192,10 +192,10 @@ func parseStructTag(data string, attrs *map[string]bool, tags *map[string]string tag := make(map[string]string) for _, v := range strings.Split(data, defaultStructTagDelim) { v = strings.TrimSpace(v) - if supportTag[v] == 1 { - attr[v] = true + if t := strings.ToLower(v); supportTag[t] == 1 { + attr[t] = true } else if i := strings.Index(v, "("); i > 0 && strings.Index(v, ")") == len(v)-1 { - name := v[:i] + name := t[:i] if supportTag[name] == 2 { v = v[i+1 : len(v)-1] tag[name] = v diff --git a/orm/orm_test.go b/orm/orm_test.go index 11f6bd56..c029999f 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -2117,3 +2117,47 @@ func TestUintPk(t *testing.T) { dORM.Delete(u) } + +func TestSnake(t *testing.T) { + cases := map[string]string{ + "i": "i", + "I": "i", + "iD": "i_d", //01 + "ID": "id", //11 pre+curent=2 + "NO": "no", //11 + "NOO": "noo", //111 10 + "NOOooOOoo": "noo_oo_oo_oo", //111_00_11_00 + "OrderNO": "order_no", //10000_11 + "tagName": "tag_name", //000_1000 + "tag_Name": "tag_name", + "tag_name": "tag_name", + "_tag_name": "_tag_name", + "tag_666name": "tag_666name", + "tag_666Name": "tag_666_name", + } + for name, want := range cases { + got := snakeString(name) + throwFail(t, AssertIs(got, want)) + } +} + +func TestIgnoreCaseTag(t *testing.T) { + type testTagModel struct { + ID int `orm:"pk"` + NOO string `orm:"column(n)"` + Name01 string `orm:"NULL"` + Name02 string `orm:"COLUMN(Name)"` + Name03 string `orm:"Column(name)"` + } + RegisterModel(&testTagModel{}) + info, ok := modelCache.get("test_tag_model") + throwFail(t, AssertIs(ok, true)) + throwFail(t, AssertNot(info, nil)) + if t == nil { + return + } + throwFail(t, AssertIs(info.fields.GetByName("NOO").column, "n")) + throwFail(t, AssertIs(info.fields.GetByName("Name01").null, true)) + throwFail(t, AssertIs(info.fields.GetByName("Name02").column, "Name")) + throwFail(t, AssertIs(info.fields.GetByName("Name03").column, "name")) +} diff --git a/orm/utils.go b/orm/utils.go index 99437c7b..e3cd8ad6 100644 --- a/orm/utils.go +++ b/orm/utils.go @@ -181,18 +181,36 @@ func ToInt64(value interface{}) (d int64) { return } -// snake string, XxYy to xx_yy +// snake string, XxYy to xx_yy , XxYY to xx_yy func snakeString(s string) string { data := make([]byte, 0, len(s)*2) - j := false num := len(s) for i := 0; i < num; i++ { d := s[i] - if i > 0 && d >= 'A' && d <= 'Z' && j { - data = append(data, '_') - } - if d != '_' { - j = true + if i > 0 && d != '_' && s[i-1] != '_' { + need := false + // upper as 1, lower as 0 + // XX -> 11 -> 11 + // Xx -> 10 -> 10 + // XxYyZZ -> 101011 -> 10_10_11 + isUpper := d >= 'A' && d <= 'Z' + preIsUpper := s[i-1] >= 'A' && s[i-1] <= 'Z' + if isUpper { + // like : xxYy + if !preIsUpper { + need = true + } + } else { + if preIsUpper { + // ignore "Xy" in "xxXyy" + if i-2 >= 0 && s[i-2] >= 'A' && s[i-2] <= 'Z' { + need = true + } + } + } + if need { + data = append(data, '_') + } } data = append(data, d) } From 3f016840db8da93a98705527e502a8fa19469704 Mon Sep 17 00:00:00 2001 From: ysqi Date: Sat, 4 Jun 2016 10:41:55 +0800 Subject: [PATCH 150/159] fixed test error --- orm/orm_test.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/orm/orm_test.go b/orm/orm_test.go index c029999f..e1ecdfd1 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -2122,13 +2122,13 @@ func TestSnake(t *testing.T) { cases := map[string]string{ "i": "i", "I": "i", - "iD": "i_d", //01 - "ID": "id", //11 pre+curent=2 - "NO": "no", //11 - "NOO": "noo", //111 10 - "NOOooOOoo": "noo_oo_oo_oo", //111_00_11_00 - "OrderNO": "order_no", //10000_11 - "tagName": "tag_name", //000_1000 + "iD": "i_d", + "ID": "id", + "NO": "no", + "NOO": "noo", + "NOOooOOoo": "noo_oo_oo_oo", + "OrderNO": "order_no", + "tagName": "tag_name", "tag_Name": "tag_name", "tag_name": "tag_name", "_tag_name": "_tag_name", @@ -2149,6 +2149,7 @@ func TestIgnoreCaseTag(t *testing.T) { Name02 string `orm:"COLUMN(Name)"` Name03 string `orm:"Column(name)"` } + modelCache.clean() RegisterModel(&testTagModel{}) info, ok := modelCache.get("test_tag_model") throwFail(t, AssertIs(ok, true)) From 0d3a806c238ebd9f37e5bc28d36037223480c980 Mon Sep 17 00:00:00 2001 From: Joshua Santos Date: Wed, 15 Jun 2016 17:17:50 -0700 Subject: [PATCH 151/159] Add meta fields with required flag --- templatefunc.go | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/templatefunc.go b/templatefunc.go index 8558733f..0f9af481 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -422,17 +422,18 @@ func RenderForm(obj interface{}) template.HTML { fieldT := objT.Field(i) label, name, fType, id, class, ignored := parseFormTag(fieldT) + required := parseMetaTag(fieldT) if ignored { continue } - raw = append(raw, renderFormField(label, name, fType, fieldV.Interface(), id, class)) + raw = append(raw, renderFormField(label, name, fType, fieldV.Interface(), id, class, required)) } return template.HTML(strings.Join(raw, "
")) } // renderFormField returns a string containing HTML of a single form field. -func renderFormField(label, name, fType string, value interface{}, id string, class string) string { +func renderFormField(label, name, fType string, value interface{}, id string, class string, required bool) string { if id != "" { id = " id=\"" + id + "\"" } @@ -441,8 +442,13 @@ func renderFormField(label, name, fType string, value interface{}, id string, cl class = " class=\"" + class + "\"" } + requiredString := "" + if required { + requiredString = " required" + } + if isValidForInput(fType) { - return fmt.Sprintf(`%v`, label, id, class, name, fType, value) + return fmt.Sprintf(`%v`, label, id, class, name, fType, value, requiredString) } return fmt.Sprintf(`%v<%v%v%v name="%v">%v`, label, fType, id, class, name, value, fType) @@ -496,6 +502,21 @@ func parseFormTag(fieldT reflect.StructField) (label, name, fType string, id str label = tags[2] } } + + return +} + +// parseMetaTag takes the stuct-tag of a StructField and parses the `meta` value. +// returned is the boolean of whether the field is required +func parseMetaTag(fieldT reflect.StructField) (required bool) { + meta := strings.Split(fieldT.Tag.Get("meta"), ",") + required = false + switch len(meta) { + case 1: + if len(meta[0]) > 0 && meta[0] != "-" { + required = true + } + } return } From 415b9cf310e73a12a73f59f7d63439e0702df5b0 Mon Sep 17 00:00:00 2001 From: Victor Popkov Date: Wed, 22 Jun 2016 16:32:37 +0300 Subject: [PATCH 152/159] add support for time.Time pointer in struct types Allow to use pointer *time.Time as a type in combination with orm tags in struct. This enables to treat them as "empty" in JSON marshaling/unmarshaling when using 'json:"null,omitempty'. --- orm/db.go | 11 ++++++++++- orm/models_test.go | 3 +++ orm/models_utils.go | 2 ++ orm/orm_test.go | 12 ++++++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/orm/db.go b/orm/db.go index 78c72e87..9964e263 100644 --- a/orm/db.go +++ b/orm/db.go @@ -243,6 +243,9 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val if fi.isFielder { f := field.Addr().Interface().(Fielder) f.SetRaw(tnow.In(DefaultTimeLoc)) + } else if field.Kind() == reflect.Ptr { + v := tnow.In(DefaultTimeLoc) + field.Set(reflect.ValueOf(&v)) } else { field.Set(reflect.ValueOf(tnow.In(DefaultTimeLoc))) } @@ -1273,8 +1276,14 @@ setValue: if isNative { if value == nil { value = time.Time{} + } else if field.Kind() == reflect.Ptr { + if value != nil { + v := value.(time.Time) + field.Set(reflect.ValueOf(&v)) + } + } else { + field.Set(reflect.ValueOf(value)) } - field.Set(reflect.ValueOf(value)) } case fieldType == TypePositiveBitField && field.Kind() == reflect.Ptr: if value != nil { diff --git a/orm/models_test.go b/orm/models_test.go index c68c7339..462370b2 100644 --- a/orm/models_test.go +++ b/orm/models_test.go @@ -181,6 +181,9 @@ type DataNull struct { Float32Ptr *float32 `orm:"null"` Float64Ptr *float64 `orm:"null"` DecimalPtr *float64 `orm:"digits(8);decimals(4);null"` + TimePtr *time.Time `orm:"null;type(time)"` + DatePtr *time.Time `orm:"null;type(date)"` + DateTimePtr *time.Time `orm:"null"` } type String string diff --git a/orm/models_utils.go b/orm/models_utils.go index 1dc17f81..4c4b0f24 100644 --- a/orm/models_utils.go +++ b/orm/models_utils.go @@ -137,6 +137,8 @@ func getFieldType(val reflect.Value) (ft int, err error) { ft = TypeBooleanField case reflect.TypeOf(new(string)): ft = TypeCharField + case reflect.TypeOf(new(time.Time)): + ft = TypeDateTimeField default: elm := reflect.Indirect(val) switch elm.Kind() { diff --git a/orm/orm_test.go b/orm/orm_test.go index e1ecdfd1..b5973448 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -350,6 +350,9 @@ func TestNullDataTypes(t *testing.T) { throwFail(t, AssertIs(d.Float32Ptr, nil)) throwFail(t, AssertIs(d.Float64Ptr, nil)) throwFail(t, AssertIs(d.DecimalPtr, nil)) + throwFail(t, AssertIs(d.TimePtr, nil)) + throwFail(t, AssertIs(d.DatePtr, nil)) + throwFail(t, AssertIs(d.DateTimePtr, nil)) _, err = dORM.Raw(`INSERT INTO data_null (boolean) VALUES (?)`, nil).Exec() throwFail(t, err) @@ -376,6 +379,9 @@ func TestNullDataTypes(t *testing.T) { float32Ptr := float32(42.0) float64Ptr := float64(42.0) decimalPtr := float64(42.0) + timePtr := time.Now() + datePtr := time.Now() + dateTimePtr := time.Now() d = DataNull{ DateTime: time.Now(), @@ -401,6 +407,9 @@ func TestNullDataTypes(t *testing.T) { Float32Ptr: &float32Ptr, Float64Ptr: &float64Ptr, DecimalPtr: &decimalPtr, + TimePtr: &timePtr, + DatePtr: &datePtr, + DateTimePtr: &dateTimePtr, } id, err = dORM.Insert(&d) @@ -441,6 +450,9 @@ func TestNullDataTypes(t *testing.T) { throwFail(t, AssertIs(*d.Float32Ptr, float32Ptr)) throwFail(t, AssertIs(*d.Float64Ptr, float64Ptr)) throwFail(t, AssertIs(*d.DecimalPtr, decimalPtr)) + throwFail(t, AssertIs((*d.TimePtr).Format(testTime), timePtr.Format(testTime))) + throwFail(t, AssertIs((*d.DatePtr).Format(testDate), datePtr.Format(testDate))) + throwFail(t, AssertIs((*d.DateTimePtr).Format(testDateTime), dateTimePtr.Format(testDateTime))) } func TestDataCustomTypes(t *testing.T) { From f9f92b4f61709fc673e9c081cc4f5740a7b13d72 Mon Sep 17 00:00:00 2001 From: Joshua Santos Date: Tue, 28 Jun 2016 15:19:58 -0700 Subject: [PATCH 153/159] Merge meta tag into parseFormField --- templatefunc.go | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/templatefunc.go b/templatefunc.go index 0f9af481..827c9b6b 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -421,8 +421,7 @@ func RenderForm(obj interface{}) template.HTML { fieldT := objT.Field(i) - label, name, fType, id, class, ignored := parseFormTag(fieldT) - required := parseMetaTag(fieldT) + label, name, fType, id, class, ignored, required := parseFormTag(fieldT) if ignored { continue } @@ -467,7 +466,7 @@ func isValidForInput(fType string) bool { // parseFormTag takes the stuct-tag of a StructField and parses the `form` value. // returned are the form label, name-property, type and wether the field should be ignored. -func parseFormTag(fieldT reflect.StructField) (label, name, fType string, id string, class string, ignored bool) { +func parseFormTag(fieldT reflect.StructField) (label, name, fType string, id string, class string, ignored bool, required bool) { tags := strings.Split(fieldT.Tag.Get("form"), ",") label = fieldT.Name + ": " name = fieldT.Name @@ -476,6 +475,15 @@ func parseFormTag(fieldT reflect.StructField) (label, name, fType string, id str id = fieldT.Tag.Get("id") class = fieldT.Tag.Get("class") + meta := strings.Split(fieldT.Tag.Get("meta"), ",") + required = false + switch len(meta) { + case 1: + if len(meta[0]) > 0 && meta[0] != "-" { + required = true + } + } + switch len(tags) { case 1: if tags[0] == "-" { @@ -506,20 +514,6 @@ func parseFormTag(fieldT reflect.StructField) (label, name, fType string, id str return } -// parseMetaTag takes the stuct-tag of a StructField and parses the `meta` value. -// returned is the boolean of whether the field is required -func parseMetaTag(fieldT reflect.StructField) (required bool) { - meta := strings.Split(fieldT.Tag.Get("meta"), ",") - required = false - switch len(meta) { - case 1: - if len(meta[0]) > 0 && meta[0] != "-" { - required = true - } - } - return -} - func isStructPtr(t reflect.Type) bool { return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct } From 21c78216923d0a507d7f7740a931f495f8f31cc5 Mon Sep 17 00:00:00 2001 From: Joshua Santos Date: Tue, 28 Jun 2016 16:24:32 -0700 Subject: [PATCH 154/159] Add test function --- templatefunc_test.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/templatefunc_test.go b/templatefunc_test.go index 98fbf7ab..a4a2c237 100644 --- a/templatefunc_test.go +++ b/templatefunc_test.go @@ -195,15 +195,20 @@ func TestRenderForm(t *testing.T) { } func TestRenderFormField(t *testing.T) { - html := renderFormField("Label: ", "Name", "text", "Value", "", "") + html := renderFormField("Label: ", "Name", "text", "Value", "", "", false) if html != `Label: ` { t.Errorf("Wrong html output for input[type=text]: %v ", html) } - html = renderFormField("Label: ", "Name", "textarea", "Value", "", "") + html = renderFormField("Label: ", "Name", "textarea", "Value", "", "", false) if html != `Label: ` { t.Errorf("Wrong html output for textarea: %v ", html) } + + html = renderFormField("Label: ", "Name", "textarea", "Value", "", "", true) + if html != `Label: ` { + t.Errorf("Wrong html output for textarea: %v ", html) + } } func TestParseFormTag(t *testing.T) { From 8917fe44a91505457494631f267757b8b7e57508 Mon Sep 17 00:00:00 2001 From: Joshua Santos Date: Tue, 28 Jun 2016 16:31:45 -0700 Subject: [PATCH 155/159] Add test functions --- templatefunc_test.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/templatefunc_test.go b/templatefunc_test.go index a4a2c237..6f337928 100644 --- a/templatefunc_test.go +++ b/templatefunc_test.go @@ -219,35 +219,42 @@ func TestParseFormTag(t *testing.T) { OnlyLabel int `form:",,年龄:"` OnlyName int `form:"name" id:"name" class:"form-name"` Ignored int `form:"-"` + Required int `form:"name" meta:"true"` } objT := reflect.TypeOf(&user{}).Elem() - label, name, fType, id, class, ignored := parseFormTag(objT.Field(0)) + label, name, fType, id, class, ignored, required := parseFormTag(objT.Field(0)) if !(name == "name" && label == "年龄:" && fType == "text" && ignored == false) { t.Errorf("Form Tag with name, label and type was not correctly parsed.") } - label, name, fType, id, class, ignored = parseFormTag(objT.Field(1)) + label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(1)) if !(name == "NoName" && label == "年龄:" && fType == "hidden" && ignored == false) { t.Errorf("Form Tag with label and type but without name was not correctly parsed.") } - label, name, fType, id, class, ignored = parseFormTag(objT.Field(2)) + label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(2)) if !(name == "OnlyLabel" && label == "年龄:" && fType == "text" && ignored == false) { t.Errorf("Form Tag containing only label was not correctly parsed.") } - label, name, fType, id, class, ignored = parseFormTag(objT.Field(3)) + label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(3)) if !(name == "name" && label == "OnlyName: " && fType == "text" && ignored == false && id == "name" && class == "form-name") { t.Errorf("Form Tag containing only name was not correctly parsed.") } - label, name, fType, id, class, ignored = parseFormTag(objT.Field(4)) + label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(4)) if ignored == false { t.Errorf("Form Tag that should be ignored was not correctly parsed.") } + + label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(5)) + if !(name == "name" && required == true) { + t.Errorf("Form Tag containing only name and required was not correctly parsed.") + } + } func TestMapGet(t *testing.T) { From 84b6bef7d064371365822d60928e163f54988b0d Mon Sep 17 00:00:00 2001 From: Joshua Santos Date: Tue, 28 Jun 2016 16:39:09 -0700 Subject: [PATCH 156/159] Required field useful for not only input --- templatefunc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templatefunc.go b/templatefunc.go index 827c9b6b..d6afaf15 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -450,7 +450,7 @@ func renderFormField(label, name, fType string, value interface{}, id string, cl return fmt.Sprintf(`%v`, label, id, class, name, fType, value, requiredString) } - return fmt.Sprintf(`%v<%v%v%v name="%v">%v`, label, fType, id, class, name, value, fType) + return fmt.Sprintf(`%v<%v%v%v name="%v"%v>%v`, label, fType, id, class, name, requiredString, value, fType) } // isValidForInput checks if fType is a valid value for the `type` property of an HTML input element. From e0393b721ced07de32ae3d57e20b1fcd214d97e6 Mon Sep 17 00:00:00 2001 From: Joshua Santos Date: Thu, 30 Jun 2016 10:32:53 -0700 Subject: [PATCH 157/159] Change meta to required, and refactor a bit to cover edge cases --- templatefunc.go | 9 +++------ templatefunc_test.go | 24 ++++++++++++++++++------ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/templatefunc.go b/templatefunc.go index d6afaf15..36442984 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -475,13 +475,10 @@ func parseFormTag(fieldT reflect.StructField) (label, name, fType string, id str id = fieldT.Tag.Get("id") class = fieldT.Tag.Get("class") - meta := strings.Split(fieldT.Tag.Get("meta"), ",") required = false - switch len(meta) { - case 1: - if len(meta[0]) > 0 && meta[0] != "-" { - required = true - } + required_field := fieldT.Tag.Get("required") + if required_field != "-" && required_field != "" { + required, _ = strconv.ParseBool(required_field) } switch len(tags) { diff --git a/templatefunc_test.go b/templatefunc_test.go index 6f337928..86de37ae 100644 --- a/templatefunc_test.go +++ b/templatefunc_test.go @@ -214,12 +214,14 @@ func TestRenderFormField(t *testing.T) { func TestParseFormTag(t *testing.T) { // create struct to contain field with different types of struct-tag `form` type user struct { - All int `form:"name,text,年龄:"` - NoName int `form:",hidden,年龄:"` - OnlyLabel int `form:",,年龄:"` - OnlyName int `form:"name" id:"name" class:"form-name"` - Ignored int `form:"-"` - Required int `form:"name" meta:"true"` + All int `form:"name,text,年龄:"` + NoName int `form:",hidden,年龄:"` + OnlyLabel int `form:",,年龄:"` + OnlyName int `form:"name" id:"name" class:"form-name"` + Ignored int `form:"-"` + Required int `form:"name" required:"true"` + IgnoreRequired int `form:"name"` + NotRequired int `form:"name" required:"false"` } objT := reflect.TypeOf(&user{}).Elem() @@ -255,6 +257,16 @@ func TestParseFormTag(t *testing.T) { t.Errorf("Form Tag containing only name and required was not correctly parsed.") } + label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(6)) + if !(name == "name" && required == false) { + t.Errorf("Form Tag containing only name and ignore required was not correctly parsed.") + } + + label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(7)) + if !(name == "name" && required == false) { + t.Errorf("Form Tag containing only name and not required was not correctly parsed.") + } + } func TestMapGet(t *testing.T) { From 9ab5f6d8083b06a325ea1d3cc0018dad664ea168 Mon Sep 17 00:00:00 2001 From: shev_yan Date: Wed, 6 Jul 2016 12:53:47 +0800 Subject: [PATCH 158/159] use keyed fields to pass go vet --- parser.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/parser.go b/parser.go index 46d02320..1719cd34 100644 --- a/parser.go +++ b/parser.go @@ -164,10 +164,10 @@ func genRouterCode() { globalinfo = globalinfo + ` beego.GlobalControllerRouter["` + k + `"] = append(beego.GlobalControllerRouter["` + k + `"], beego.ControllerComments{ - "` + strings.TrimSpace(c.Method) + `", - ` + "`" + c.Router + "`" + `, - ` + allmethod + `, - ` + params + `}) + Method: "` + strings.TrimSpace(c.Method) + `", + ` + "Router: `" + c.Router + "`" + `, + AllowHTTPMethods: ` + allmethod + `, + Params: ` + params + `}) ` } } From ee2627931190249840e1bcd3c84df6c94add17a4 Mon Sep 17 00:00:00 2001 From: simsun Date: Mon, 18 Jul 2016 22:57:13 +0800 Subject: [PATCH 159/159] fix(context): retrieve scheme from X-Forwarded-Proto when it isn't none --- context/input.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/context/input.go b/context/input.go index edfdf530..c47996c9 100644 --- a/context/input.go +++ b/context/input.go @@ -89,6 +89,9 @@ func (input *BeegoInput) Site() string { // Scheme returns request scheme as "http" or "https". func (input *BeegoInput) Scheme() string { + if scheme := input.Header("X-Forwarded-Proto"); scheme != "" { + return scheme + } if input.Context.Request.URL.Scheme != "" { return input.Context.Request.URL.Scheme }