diff --git a/admin.go b/admin.go index 3effc582..031e6421 100644 --- a/admin.go +++ b/admin.go @@ -90,8 +90,8 @@ func listConf(rw http.ResponseWriter, r *http.Request) { switch command { case "conf": m := make(map[string]interface{}) - m["AppConfigPath"] = AppConfigPath - m["AppConfigProvider"] = AppConfigProvider + m["AppConfigPath"] = appConfigPath + m["AppConfigProvider"] = appConfigProvider m["BConfig.AppName"] = BConfig.AppName m["BConfig.RunMode"] = BConfig.RunMode m["BConfig.RouterCaseSensitive"] = BConfig.RouterCaseSensitive diff --git a/beego.go b/beego.go index 04f02071..fb628e5f 100644 --- a/beego.go +++ b/beego.go @@ -15,7 +15,6 @@ package beego import ( - "fmt" "os" "path/filepath" "strconv" @@ -68,21 +67,6 @@ func Run(params ...string) { } func initBeforeHTTPRun() { - // if AppConfigPath is setted or conf/app.conf exist - err := ParseConfig() - if err != nil { - panic(err) - } - //init log - for adaptor, config := range BConfig.Log.Outputs { - err = BeeLogger.SetLogger(adaptor, config) - if err != nil { - fmt.Printf("%s with the config `%s` got err:%s\n", adaptor, config, err) - } - } - - SetLogFuncCall(BConfig.Log.FileLineNum) - //init hooks AddAPPStartHook(registerMime) AddAPPStartHook(registerDefaultErrorHandler) @@ -101,7 +85,7 @@ func initBeforeHTTPRun() { // TestBeegoInit is for test package init func TestBeegoInit(ap string) { os.Setenv("BEEGO_RUNMODE", "test") - AppConfigPath = filepath.Join(ap, "conf", "app.conf") + appConfigPath = filepath.Join(ap, "conf", "app.conf") os.Chdir(ap) initBeforeHTTPRun() } diff --git a/config.go b/config.go index bf9077a7..7e2b3ee7 100644 --- a/config.go +++ b/config.go @@ -19,6 +19,7 @@ import ( "os" "path/filepath" "strings" + "fmt" "github.com/astaxie/beego/config" "github.com/astaxie/beego/session" @@ -105,16 +106,16 @@ var ( AppConfig *beegoAppConfig // AppPath is the absolute path to the app AppPath string - // AppConfigPath is the path to the config files - AppConfigPath string - // AppConfigProvider is the provider for the config, default is ini - AppConfigProvider = "ini" // TemplateCache stores template caching TemplateCache map[string]*template.Template // GlobalSessions is the instance for the session manager GlobalSessions *session.Manager workPath string + // appConfigPath is the path to the config files + appConfigPath string + // appConfigProvider is the provider for the config, default is ini + appConfigProvider = "ini" ) func init() { @@ -122,6 +123,10 @@ func init() { workPath, _ = os.Getwd() workPath, _ = filepath.Abs(workPath) + if workPath != AppPath { + os.Chdir(AppPath) + } + BConfig = &Config{ AppName: "beego", RunMode: DEV, @@ -181,26 +186,19 @@ func init() { Outputs: map[string]string{"console": ""}, }, } - ParseConfig() + + appConfigPath = filepath.Join(AppPath, "conf", "app.conf") + if !utils.FileExists(appConfigPath) { + AppConfig = &beegoAppConfig{config.NewFakeConfig()} + return + } + + parseConfig(appConfigPath) } -// ParseConfig parsed default config file. // now only support ini, next will support json. -func ParseConfig() (err error) { - if AppConfigPath == "" { - // initialize default configurations - AppConfigPath = filepath.Join(AppPath, "conf", "app.conf") - if !utils.FileExists(AppConfigPath) { - AppConfig = &beegoAppConfig{config.NewFakeConfig()} - return - } - } - - if workPath != AppPath { - os.Chdir(AppPath) - } - - AppConfig, err = newAppConfig(AppConfigProvider, AppConfigPath) +func parseConfig(appConfigPath string) (err error) { + AppConfig, err = newAppConfig(appConfigProvider, appConfigPath) if err != nil { return err } @@ -254,6 +252,8 @@ func ParseConfig() (err error) { 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) if sd := AppConfig.String("StaticDir"); sd != "" { for k := range BConfig.WebConfig.StaticDir { @@ -286,15 +286,58 @@ func ParseConfig() (err error) { BConfig.WebConfig.StaticExtensionsToGzip = fileExts } } + + if lo := AppConfig.String("LogOutputs"); lo != "" { + los := strings.Split(lo, ";") + for _, v := range los { + if logType2Config := strings.SplitN(v, ",", 2); len(logType2Config) == 2 { + BConfig.Log.Outputs[logType2Config[0]] = logType2Config[1] + } else { + continue + } + } + } + + //init log + BeeLogger.Close() + for adaptor, config := range BConfig.Log.Outputs { + err = BeeLogger.SetLogger(adaptor, config) + if err != nil { + fmt.Printf("%s with the config `%s` got err:%s\n", adaptor, config, err) + } + } + SetLogFuncCall(BConfig.Log.FileLineNum) + return nil } +// LoadAppConfig allow developer to apply a config file +func LoadAppConfig(adapterName, configPath string) error { + absConfigPath, err := filepath.Abs(configPath) + if err != nil { + return err + } + + if !utils.FileExists(absConfigPath) { + return fmt.Errorf("the target config file: %s don't exist!", configPath) + } + + if absConfigPath == appConfigPath { + return nil + } + + appConfigPath = absConfigPath + appConfigProvider = adapterName + + return parseConfig(appConfigPath) +} + type beegoAppConfig struct { innerConfig config.Configer } -func newAppConfig(AppConfigProvider, AppConfigPath string) (*beegoAppConfig, error) { - ac, err := config.NewConfig(AppConfigProvider, AppConfigPath) +func newAppConfig(appConfigProvider, appConfigPath string) (*beegoAppConfig, error) { + ac, err := config.NewConfig(appConfigProvider, appConfigPath) if err != nil { return nil, err } diff --git a/context/input.go b/context/input.go index c37204bd..edfdf530 100644 --- a/context/input.go +++ b/context/input.go @@ -287,6 +287,13 @@ func (input *BeegoInput) Params() map[string]string { // SetParam will set the param with key and value func (input *BeegoInput) SetParam(key, val string) { + // check if already exists + for i, v := range input.pnames { + if v == key && i <= len(input.pvalues) { + input.pvalues[i] = val + return + } + } input.pvalues = append(input.pvalues, val) input.pnames = append(input.pnames, key) } diff --git a/context/input_test.go b/context/input_test.go index 618e1254..24f6fd99 100644 --- a/context/input_test.go +++ b/context/input_test.go @@ -18,6 +18,7 @@ import ( "fmt" "net/http" "net/http/httptest" + "reflect" "testing" ) @@ -117,3 +118,56 @@ func TestSubDomain(t *testing.T) { t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains()) } } + +func TestParams(t *testing.T) { + inp := NewInput() + + inp.SetParam("p1", "val1_ver1") + inp.SetParam("p2", "val2_ver1") + inp.SetParam("p3", "val3_ver1") + if l := inp.ParamsLen(); l != 3 { + t.Fatalf("Input.ParamsLen wrong value: %d, expected %d", l, 3) + } + + if val := inp.Param("p1"); val != "val1_ver1" { + t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val1_ver1") + } + if val := inp.Param("p3"); val != "val3_ver1" { + t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val3_ver1") + } + vals := inp.Params() + expected := map[string]string{ + "p1": "val1_ver1", + "p2": "val2_ver1", + "p3": "val3_ver1", + } + if !reflect.DeepEqual(vals, expected) { + t.Fatalf("Input.Params wrong value: %s, expected %s", vals, expected) + } + + // overwriting existing params + inp.SetParam("p1", "val1_ver2") + inp.SetParam("p2", "val2_ver2") + expected = map[string]string{ + "p1": "val1_ver2", + "p2": "val2_ver2", + "p3": "val3_ver1", + } + vals = inp.Params() + if !reflect.DeepEqual(vals, expected) { + t.Fatalf("Input.Params wrong value: %s, expected %s", vals, expected) + } + + if l := inp.ParamsLen(); l != 3 { + t.Fatalf("Input.ParamsLen wrong value: %d, expected %d", l, 3) + } + + if val := inp.Param("p1"); val != "val1_ver2" { + t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val1_ver2") + } + + if val := inp.Param("p2"); val != "val2_ver2" { + t.Fatalf("Input.Param wrong value: %s, expected %s", val, "val1_ver2") + } + +} diff --git a/logs/console.go b/logs/console.go index 10d8e8b2..d7ed8d8e 100644 --- a/logs/console.go +++ b/logs/console.go @@ -48,7 +48,8 @@ var colors = []brush{ // consoleWriter implements LoggerInterface and writes messages to terminal. type consoleWriter struct { lg *log.Logger - Level int `json:"level"` + Level int `json:"level"` + Color bool `json:"color"` } // NewConsole create ConsoleWriter returning as LoggerInterface. @@ -56,6 +57,7 @@ func NewConsole() Logger { cw := &consoleWriter{ lg: log.New(os.Stdout, "", 0), Level: LevelDebug, + Color: true, } return cw } @@ -75,7 +77,7 @@ func (c *consoleWriter) WriteMsg(when time.Time, msg string, level int) error { return nil } msg = formatLogTime(when) + msg - if runtime.GOOS == "windows" { + if runtime.GOOS == "windows" || !c.Color { c.lg.Println(msg) return nil } diff --git a/logs/console_test.go b/logs/console_test.go index ce8937d4..04f2bd7e 100644 --- a/logs/console_test.go +++ b/logs/console_test.go @@ -42,3 +42,10 @@ func TestConsole(t *testing.T) { log2.SetLogger("console", `{"level":3}`) testConsoleCalls(log2) } + +// Test console without color +func TestConsoleNoColor(t *testing.T) { + log := NewLogger(100) + log.SetLogger("console", `{"color":false}`) + testConsoleCalls(log) +} diff --git a/logs/log.go b/logs/log.go index 076a9766..2a12ed79 100644 --- a/logs/log.go +++ b/logs/log.go @@ -365,6 +365,7 @@ func (bl *BeeLogger) Close() { l.Flush() l.Destroy() } + bl.outputs = nil } func formatLogTime(when time.Time) string { diff --git a/staticfile_test.go b/staticfile_test.go index d3333570..e7003366 100644 --- a/staticfile_test.go +++ b/staticfile_test.go @@ -8,9 +8,11 @@ import ( "io/ioutil" "os" "testing" + "path/filepath" ) -const licenseFile = "./LICENSE" +var currentWorkDir, _ = os.Getwd() +var licenseFile = filepath.Join(currentWorkDir, "LICENSE") func testOpenFile(encoding string, content []byte, t *testing.T) { fi, _ := os.Stat(licenseFile)