mirror of
https://github.com/beego/bee.git
synced 2024-06-28 18:44:14 +00:00
![Faissal Elamraoui](/assets/img/avatar_default.png)
Added enhanced logging while using bee to scaffold code Fixed some typos and errors Added more error handling Added more docs
269 lines
6.6 KiB
Go
269 lines
6.6 KiB
Go
// Copyright 2013 bee authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
|
// not use this file except in compliance with the License. You may obtain
|
|
// a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Go is a basic promise implementation: it wraps calls a function in a goroutine
|
|
// and returns a channel which will later return the function's return value.
|
|
func Go(f func() error) chan error {
|
|
ch := make(chan error)
|
|
go func() {
|
|
ch <- f()
|
|
}()
|
|
return ch
|
|
}
|
|
|
|
// if os.env DEBUG set, debug is on
|
|
func Debugf(format string, a ...interface{}) {
|
|
if os.Getenv("DEBUG") != "" {
|
|
_, file, line, ok := runtime.Caller(1)
|
|
if !ok {
|
|
file = "<unknown>"
|
|
line = -1
|
|
} else {
|
|
file = filepath.Base(file)
|
|
}
|
|
fmt.Fprintf(os.Stderr, fmt.Sprintf("[debug] %s:%d %s\n", file, line, format), a...)
|
|
}
|
|
}
|
|
|
|
const (
|
|
Gray = uint8(iota + 90)
|
|
Red
|
|
Green
|
|
Yellow
|
|
Blue
|
|
Magenta
|
|
//NRed = uint8(31) // Normal
|
|
EndColor = "\033[0m"
|
|
|
|
INFO = "INFO"
|
|
TRAC = "TRAC"
|
|
ERRO = "ERRO"
|
|
WARN = "WARN"
|
|
SUCC = "SUCC"
|
|
)
|
|
|
|
// ColorLog colors log and print to stdout.
|
|
// See color rules in function 'ColorLogS'.
|
|
func ColorLog(format string, a ...interface{}) {
|
|
fmt.Print(ColorLogS(format, a...))
|
|
}
|
|
|
|
// ColorLogS colors log and return colored content.
|
|
// Log format: <level> <content [highlight][path]> [ error ].
|
|
// Level: TRAC -> blue; ERRO -> red; WARN -> Magenta; SUCC -> green; others -> default.
|
|
// Content: default; path: yellow; error -> red.
|
|
// Level has to be surrounded by "[" and "]".
|
|
// Highlights have to be surrounded by "# " and " #"(space), "#" will be deleted.
|
|
// Paths have to be surrounded by "( " and " )"(space).
|
|
// Errors have to be surrounded by "[ " and " ]"(space).
|
|
// Note: it hasn't support windows yet, contribute is welcome.
|
|
func ColorLogS(format string, a ...interface{}) string {
|
|
log := fmt.Sprintf(format, a...)
|
|
|
|
var clog string
|
|
|
|
if runtime.GOOS != "windows" {
|
|
// Level.
|
|
i := strings.Index(log, "]")
|
|
if log[0] == '[' && i > -1 {
|
|
clog += "[" + getColorLevel(log[1:i]) + "]"
|
|
}
|
|
|
|
log = log[i+1:]
|
|
|
|
// Error.
|
|
log = strings.Replace(log, "[ ", fmt.Sprintf("[\033[%dm", Red), -1)
|
|
log = strings.Replace(log, " ]", EndColor+"]", -1)
|
|
|
|
// Path.
|
|
log = strings.Replace(log, "( ", fmt.Sprintf("(\033[%dm", Yellow), -1)
|
|
log = strings.Replace(log, " )", EndColor+")", -1)
|
|
|
|
// Highlights.
|
|
log = strings.Replace(log, "# ", fmt.Sprintf("\033[%dm", Gray), -1)
|
|
log = strings.Replace(log, " #", EndColor, -1)
|
|
|
|
log = clog + log
|
|
|
|
} else {
|
|
// Level.
|
|
i := strings.Index(log, "]")
|
|
if log[0] == '[' && i > -1 {
|
|
clog += "[" + log[1:i] + "]"
|
|
}
|
|
|
|
log = log[i+1:]
|
|
|
|
// Error.
|
|
log = strings.Replace(log, "[ ", "[", -1)
|
|
log = strings.Replace(log, " ]", "]", -1)
|
|
|
|
// Path.
|
|
log = strings.Replace(log, "( ", "(", -1)
|
|
log = strings.Replace(log, " )", ")", -1)
|
|
|
|
// Highlights.
|
|
log = strings.Replace(log, "# ", "", -1)
|
|
log = strings.Replace(log, " #", "", -1)
|
|
|
|
log = clog + log
|
|
}
|
|
|
|
return time.Now().Format("2006/01/02 15:04:05 ") + log
|
|
}
|
|
|
|
// getColorLevel returns colored level string by given level.
|
|
func getColorLevel(level string) string {
|
|
level = strings.ToUpper(level)
|
|
switch level {
|
|
case INFO:
|
|
return fmt.Sprintf("\033[%dm%s\033[0m", Blue, level)
|
|
case TRAC:
|
|
return fmt.Sprintf("\033[%dm%s\033[0m", Blue, level)
|
|
case ERRO:
|
|
return fmt.Sprintf("\033[%dm%s\033[0m", Red, level)
|
|
case WARN:
|
|
return fmt.Sprintf("\033[%dm%s\033[0m", Magenta, level)
|
|
case SUCC:
|
|
return fmt.Sprintf("\033[%dm%s\033[0m", Green, level)
|
|
default:
|
|
return level
|
|
}
|
|
}
|
|
|
|
// IsExist returns whether a file or directory exists.
|
|
func isExist(path string) bool {
|
|
_, err := os.Stat(path)
|
|
return err == nil || os.IsExist(err)
|
|
}
|
|
|
|
// GetGOPATHs returns all paths in GOPATH variable.
|
|
func GetGOPATHs() []string {
|
|
gopath := os.Getenv("GOPATH")
|
|
var paths []string
|
|
if runtime.GOOS == "windows" {
|
|
gopath = strings.Replace(gopath, "\\", "/", -1)
|
|
paths = strings.Split(gopath, ";")
|
|
} else {
|
|
paths = strings.Split(gopath, ":")
|
|
}
|
|
return paths
|
|
}
|
|
|
|
// askForConfirmation uses Scanln to parse user input. A user must type in "yes" or "no" and
|
|
// then press enter. It has fuzzy matching, so "y", "Y", "yes", "YES", and "Yes" all count as
|
|
// confirmations. If the input is not recognized, it will ask again. The function does not return
|
|
// until it gets a valid response from the user. Typically, you should use fmt to print out a question
|
|
// before calling askForConfirmation. E.g. fmt.Println("WARNING: Are you sure? (yes/no)")
|
|
func askForConfirmation() bool {
|
|
var response string
|
|
_, err := fmt.Scanln(&response)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
okayResponses := []string{"y", "Y", "yes", "Yes", "YES"}
|
|
nokayResponses := []string{"n", "N", "no", "No", "NO"}
|
|
if containsString(okayResponses, response) {
|
|
return true
|
|
} else if containsString(nokayResponses, response) {
|
|
return false
|
|
} else {
|
|
fmt.Println("Please type yes or no and then press enter:")
|
|
return askForConfirmation()
|
|
}
|
|
}
|
|
|
|
func containsString(slice []string, element string) bool {
|
|
for _, elem := range slice {
|
|
if elem == element {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// snake string, 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
|
|
}
|
|
data = append(data, d)
|
|
}
|
|
return strings.ToLower(string(data[:len(data)]))
|
|
}
|
|
|
|
func camelString(s string) string {
|
|
data := make([]byte, 0, len(s))
|
|
j := false
|
|
k := false
|
|
num := len(s) - 1
|
|
for i := 0; i <= num; i++ {
|
|
d := s[i]
|
|
if k == false && d >= 'A' && d <= 'Z' {
|
|
k = true
|
|
}
|
|
if d >= 'a' && d <= 'z' && (j || k == false) {
|
|
d = d - 32
|
|
j = false
|
|
k = true
|
|
}
|
|
if k && d == '_' && num > i && s[i+1] >= 'a' && s[i+1] <= 'z' {
|
|
j = true
|
|
continue
|
|
}
|
|
data = append(data, d)
|
|
}
|
|
return string(data[:len(data)])
|
|
}
|
|
|
|
// The string flag list, implemented flag.Value interface
|
|
type strFlags []string
|
|
|
|
func (s *strFlags) String() string {
|
|
return fmt.Sprintf("%s", *s)
|
|
}
|
|
|
|
func (s *strFlags) Set(value string) error {
|
|
*s = append(*s, value)
|
|
return nil
|
|
}
|
|
|
|
// CloseFile attempts to close the passed file
|
|
// or panics with the actual error
|
|
func CloseFile(f *os.File) {
|
|
if err := f.Close(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|