mirror of
https://github.com/astaxie/beego.git
synced 2024-11-22 12:10:55 +00:00
Merge remote-tracking branch 'astaxie.beego/master'
This commit is contained in:
commit
9f2327ee57
9
admin.go
9
admin.go
@ -40,7 +40,14 @@ func init() {
|
||||
}
|
||||
|
||||
func AdminIndex(rw http.ResponseWriter, r *http.Request) {
|
||||
rw.Write([]byte("Welcome to Admin Dashboard"))
|
||||
rw.Write([]byte("Welcome to Admin Dashboard\n"))
|
||||
rw.Write([]byte("There are servral functions:\n"))
|
||||
rw.Write([]byte("1. Record all request and request time, http://localhost:8088/qps\n"))
|
||||
rw.Write([]byte("2. Get runtime profiling data by the pprof, http://localhost:8088/prof\n"))
|
||||
rw.Write([]byte("3. Get healthcheck result from http://localhost:8088/prof\n"))
|
||||
rw.Write([]byte("4. Get current task infomation from taskhttp://localhost:8088/task \n"))
|
||||
rw.Write([]byte("5. To run a task passed a param http://localhost:8088/runtask\n"))
|
||||
|
||||
}
|
||||
|
||||
func QpsIndex(rw http.ResponseWriter, r *http.Request) {
|
||||
|
@ -3,6 +3,7 @@ package beego
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
@ -370,7 +371,7 @@ func (c *Controller) XsrfToken() string {
|
||||
} else {
|
||||
expire = int64(XSRFExpire)
|
||||
}
|
||||
token = GetRandomString(15)
|
||||
token = getRandomString(15)
|
||||
c.SetSecureCookie(XSRFKEY, "_xsrf", token, expire)
|
||||
}
|
||||
c._xsrf_token = token
|
||||
@ -405,3 +406,14 @@ func (c *Controller) GoToFunc(funcname string) {
|
||||
}
|
||||
c.gotofunc = funcname
|
||||
}
|
||||
|
||||
//utils func for controller internal
|
||||
func getRandomString(n int) string {
|
||||
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
var bytes = make([]byte, n)
|
||||
rand.Read(bytes)
|
||||
for i, b := range bytes {
|
||||
bytes[i] = alphanum[b%byte(len(alphanum))]
|
||||
}
|
||||
return string(bytes)
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
beecontext "github.com/astaxie/beego/context"
|
||||
"github.com/astaxie/beego/middleware"
|
||||
"github.com/astaxie/beego/toolbox"
|
||||
"github.com/astaxie/beego/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -159,7 +160,7 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM
|
||||
}
|
||||
comma := strings.Split(colon[0], ",")
|
||||
for _, m := range comma {
|
||||
if m == "*" || inSlice(strings.ToLower(m), HTTPMETHOD) {
|
||||
if m == "*" || utils.InSlice(strings.ToLower(m), HTTPMETHOD) {
|
||||
if val := reflectVal.MethodByName(colon[1]); val.IsValid() {
|
||||
methods[strings.ToLower(m)] = colon[1]
|
||||
} else {
|
||||
@ -272,7 +273,7 @@ func (p *ControllerRegistor) UrlFor(endpoint string, values ...string) string {
|
||||
for _, route := range p.fixrouters {
|
||||
if route.controllerType.Name() == controllName {
|
||||
var finded bool
|
||||
if inSlice(strings.ToLower(methodName), HTTPMETHOD) {
|
||||
if utils.InSlice(strings.ToLower(methodName), HTTPMETHOD) {
|
||||
if route.hasMethod {
|
||||
if m, ok := route.methods[strings.ToLower(methodName)]; ok && m != methodName {
|
||||
finded = false
|
||||
@ -303,7 +304,7 @@ func (p *ControllerRegistor) UrlFor(endpoint string, values ...string) string {
|
||||
for _, route := range p.routers {
|
||||
if route.controllerType.Name() == controllName {
|
||||
var finded bool
|
||||
if inSlice(strings.ToLower(methodName), HTTPMETHOD) {
|
||||
if utils.InSlice(strings.ToLower(methodName), HTTPMETHOD) {
|
||||
if route.hasMethod {
|
||||
if m, ok := route.methods[strings.ToLower(methodName)]; ok && m != methodName {
|
||||
finded = false
|
||||
@ -419,7 +420,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
|
||||
context.Output = beecontext.NewOutput(rw)
|
||||
}
|
||||
|
||||
if !inSlice(strings.ToLower(r.Method), HTTPMETHOD) {
|
||||
if !utils.InSlice(strings.ToLower(r.Method), HTTPMETHOD) {
|
||||
http.Error(w, "Method Not Allowed", 405)
|
||||
goto Admin
|
||||
}
|
||||
|
158
template.go
158
template.go
@ -9,9 +9,10 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/astaxie/beego/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -144,7 +145,7 @@ func getTplDeep(root, file, parent string, t *template.Template) (*template.Temp
|
||||
} else {
|
||||
fileabspath = filepath.Join(root, file)
|
||||
}
|
||||
if e, _ := FileExists(fileabspath); !e {
|
||||
if e := utils.FileExists(fileabspath); !e {
|
||||
panic("can't find template file" + file)
|
||||
}
|
||||
data, err := ioutil.ReadFile(fileabspath)
|
||||
@ -238,156 +239,3 @@ func _getTemplate(t0 *template.Template, root string, submods [][]string, others
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// go1.2 added template funcs. begin
|
||||
var (
|
||||
errBadComparisonType = errors.New("invalid type for comparison")
|
||||
errBadComparison = errors.New("incompatible types for comparison")
|
||||
errNoComparison = errors.New("missing argument for comparison")
|
||||
)
|
||||
|
||||
type kind int
|
||||
|
||||
const (
|
||||
invalidKind kind = iota
|
||||
boolKind
|
||||
complexKind
|
||||
intKind
|
||||
floatKind
|
||||
integerKind
|
||||
stringKind
|
||||
uintKind
|
||||
)
|
||||
|
||||
func basicKind(v reflect.Value) (kind, error) {
|
||||
switch v.Kind() {
|
||||
case reflect.Bool:
|
||||
return boolKind, nil
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return intKind, nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return uintKind, nil
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return floatKind, nil
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
return complexKind, nil
|
||||
case reflect.String:
|
||||
return stringKind, nil
|
||||
}
|
||||
return invalidKind, errBadComparisonType
|
||||
}
|
||||
|
||||
// eq evaluates the comparison a == b || a == c || ...
|
||||
func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
|
||||
v1 := reflect.ValueOf(arg1)
|
||||
k1, err := basicKind(v1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(arg2) == 0 {
|
||||
return false, errNoComparison
|
||||
}
|
||||
for _, arg := range arg2 {
|
||||
v2 := reflect.ValueOf(arg)
|
||||
k2, err := basicKind(v2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if k1 != k2 {
|
||||
return false, errBadComparison
|
||||
}
|
||||
truth := false
|
||||
switch k1 {
|
||||
case boolKind:
|
||||
truth = v1.Bool() == v2.Bool()
|
||||
case complexKind:
|
||||
truth = v1.Complex() == v2.Complex()
|
||||
case floatKind:
|
||||
truth = v1.Float() == v2.Float()
|
||||
case intKind:
|
||||
truth = v1.Int() == v2.Int()
|
||||
case stringKind:
|
||||
truth = v1.String() == v2.String()
|
||||
case uintKind:
|
||||
truth = v1.Uint() == v2.Uint()
|
||||
default:
|
||||
panic("invalid kind")
|
||||
}
|
||||
if truth {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// ne evaluates the comparison a != b.
|
||||
func ne(arg1, arg2 interface{}) (bool, error) {
|
||||
// != is the inverse of ==.
|
||||
equal, err := eq(arg1, arg2)
|
||||
return !equal, err
|
||||
}
|
||||
|
||||
// lt evaluates the comparison a < b.
|
||||
func lt(arg1, arg2 interface{}) (bool, error) {
|
||||
v1 := reflect.ValueOf(arg1)
|
||||
k1, err := basicKind(v1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
v2 := reflect.ValueOf(arg2)
|
||||
k2, err := basicKind(v2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if k1 != k2 {
|
||||
return false, errBadComparison
|
||||
}
|
||||
truth := false
|
||||
switch k1 {
|
||||
case boolKind, complexKind:
|
||||
return false, errBadComparisonType
|
||||
case floatKind:
|
||||
truth = v1.Float() < v2.Float()
|
||||
case intKind:
|
||||
truth = v1.Int() < v2.Int()
|
||||
case stringKind:
|
||||
truth = v1.String() < v2.String()
|
||||
case uintKind:
|
||||
truth = v1.Uint() < v2.Uint()
|
||||
default:
|
||||
panic("invalid kind")
|
||||
}
|
||||
return truth, nil
|
||||
}
|
||||
|
||||
// le evaluates the comparison <= b.
|
||||
func le(arg1, arg2 interface{}) (bool, error) {
|
||||
// <= is < or ==.
|
||||
lessThan, err := lt(arg1, arg2)
|
||||
if lessThan || err != nil {
|
||||
return lessThan, err
|
||||
}
|
||||
return eq(arg1, arg2)
|
||||
}
|
||||
|
||||
// gt evaluates the comparison a > b.
|
||||
func gt(arg1, arg2 interface{}) (bool, error) {
|
||||
// > is the inverse of <=.
|
||||
lessOrEqual, err := le(arg1, arg2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return !lessOrEqual, nil
|
||||
}
|
||||
|
||||
// ge evaluates the comparison a >= b.
|
||||
func ge(arg1, arg2 interface{}) (bool, error) {
|
||||
// >= is the inverse of <.
|
||||
lessThan, err := lt(arg1, arg2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return !lessThan, nil
|
||||
}
|
||||
|
||||
// go1.2 added template funcs. end
|
||||
|
@ -1,409 +1,509 @@
|
||||
package beego
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func webTime(t time.Time) string {
|
||||
ftime := t.Format(time.RFC1123)
|
||||
if strings.HasSuffix(ftime, "UTC") {
|
||||
ftime = ftime[0:len(ftime)-3] + "GMT"
|
||||
}
|
||||
return ftime
|
||||
}
|
||||
|
||||
func Substr(s string, start, length int) string {
|
||||
bt := []rune(s)
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
var end int
|
||||
if (start + length) > (len(bt) - 1) {
|
||||
end = len(bt)
|
||||
} else {
|
||||
end = start + length
|
||||
}
|
||||
return string(bt[start:end])
|
||||
}
|
||||
|
||||
// Html2str() returns escaping text convert from html
|
||||
func Html2str(html string) string {
|
||||
src := string(html)
|
||||
|
||||
//将HTML标签全转换成小写
|
||||
re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
|
||||
src = re.ReplaceAllStringFunc(src, strings.ToLower)
|
||||
|
||||
//去除STYLE
|
||||
re, _ = regexp.Compile("\\<style[\\S\\s]+?\\</style\\>")
|
||||
src = re.ReplaceAllString(src, "")
|
||||
|
||||
//去除SCRIPT
|
||||
re, _ = regexp.Compile("\\<script[\\S\\s]+?\\</script\\>")
|
||||
src = re.ReplaceAllString(src, "")
|
||||
|
||||
//去除所有尖括号内的HTML代码,并换成换行符
|
||||
re, _ = regexp.Compile("\\<[\\S\\s]+?\\>")
|
||||
src = re.ReplaceAllString(src, "\n")
|
||||
|
||||
//去除连续的换行符
|
||||
re, _ = regexp.Compile("\\s{2,}")
|
||||
src = re.ReplaceAllString(src, "\n")
|
||||
|
||||
return strings.TrimSpace(src)
|
||||
}
|
||||
|
||||
// DateFormat takes a time and a layout string and returns a string with the formatted date. Used by the template parser as "dateformat"
|
||||
func DateFormat(t time.Time, layout string) (datestring string) {
|
||||
datestring = t.Format(layout)
|
||||
return
|
||||
}
|
||||
|
||||
var DatePatterns = []string{
|
||||
// year
|
||||
"Y", "2006", // A full numeric representation of a year, 4 digits Examples: 1999 or 2003
|
||||
"y", "06", //A two digit representation of a year Examples: 99 or 03
|
||||
|
||||
// month
|
||||
"m", "01", // Numeric representation of a month, with leading zeros 01 through 12
|
||||
"n", "1", // Numeric representation of a month, without leading zeros 1 through 12
|
||||
"M", "Jan", // A short textual representation of a month, three letters Jan through Dec
|
||||
"F", "January", // A full textual representation of a month, such as January or March January through December
|
||||
|
||||
// day
|
||||
"d", "02", // Day of the month, 2 digits with leading zeros 01 to 31
|
||||
"j", "2", // Day of the month without leading zeros 1 to 31
|
||||
|
||||
// week
|
||||
"D", "Mon", // A textual representation of a day, three letters Mon through Sun
|
||||
"l", "Monday", // A full textual representation of the day of the week Sunday through Saturday
|
||||
|
||||
// time
|
||||
"g", "3", // 12-hour format of an hour without leading zeros 1 through 12
|
||||
"G", "15", // 24-hour format of an hour without leading zeros 0 through 23
|
||||
"h", "03", // 12-hour format of an hour with leading zeros 01 through 12
|
||||
"H", "15", // 24-hour format of an hour with leading zeros 00 through 23
|
||||
|
||||
"a", "pm", // Lowercase Ante meridiem and Post meridiem am or pm
|
||||
"A", "PM", // Uppercase Ante meridiem and Post meridiem AM or PM
|
||||
|
||||
"i", "04", // Minutes with leading zeros 00 to 59
|
||||
"s", "05", // Seconds, with leading zeros 00 through 59
|
||||
|
||||
// time zone
|
||||
"T", "MST",
|
||||
"P", "-07:00",
|
||||
"O", "-0700",
|
||||
|
||||
// RFC 2822
|
||||
"r", time.RFC1123Z,
|
||||
}
|
||||
|
||||
// Parse Date use PHP time format
|
||||
func DateParse(dateString, format string) (time.Time, error) {
|
||||
replacer := strings.NewReplacer(DatePatterns...)
|
||||
format = replacer.Replace(format)
|
||||
return time.ParseInLocation(format, dateString, time.Local)
|
||||
}
|
||||
|
||||
// Date takes a PHP like date func to Go's time format
|
||||
func Date(t time.Time, format string) string {
|
||||
replacer := strings.NewReplacer(DatePatterns...)
|
||||
format = replacer.Replace(format)
|
||||
return t.Format(format)
|
||||
}
|
||||
|
||||
// Compare is a quick and dirty comparison function. It will convert whatever you give it to strings and see if the two values are equal.
|
||||
// Whitespace is trimmed. Used by the template parser as "eq"
|
||||
func Compare(a, b interface{}) (equal bool) {
|
||||
equal = false
|
||||
if strings.TrimSpace(fmt.Sprintf("%v", a)) == strings.TrimSpace(fmt.Sprintf("%v", b)) {
|
||||
equal = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Str2html(raw string) template.HTML {
|
||||
return template.HTML(raw)
|
||||
}
|
||||
|
||||
func Htmlquote(src string) string {
|
||||
//HTML编码为实体符号
|
||||
/*
|
||||
Encodes `text` for raw use in HTML.
|
||||
>>> htmlquote("<'&\\">")
|
||||
'<'&">'
|
||||
*/
|
||||
|
||||
text := string(src)
|
||||
|
||||
text = strings.Replace(text, "&", "&", -1) // Must be done first!
|
||||
text = strings.Replace(text, "<", "<", -1)
|
||||
text = strings.Replace(text, ">", ">", -1)
|
||||
text = strings.Replace(text, "'", "'", -1)
|
||||
text = strings.Replace(text, "\"", """, -1)
|
||||
text = strings.Replace(text, "“", "“", -1)
|
||||
text = strings.Replace(text, "”", "”", -1)
|
||||
text = strings.Replace(text, " ", " ", -1)
|
||||
|
||||
return strings.TrimSpace(text)
|
||||
}
|
||||
|
||||
func Htmlunquote(src string) string {
|
||||
//实体符号解释为HTML
|
||||
/*
|
||||
Decodes `text` that's HTML quoted.
|
||||
>>> htmlunquote('<'&">')
|
||||
'<\\'&">'
|
||||
*/
|
||||
|
||||
// strings.Replace(s, old, new, n)
|
||||
// 在s字符串中,把old字符串替换为new字符串,n表示替换的次数,小于0表示全部替换
|
||||
|
||||
text := string(src)
|
||||
text = strings.Replace(text, " ", " ", -1)
|
||||
text = strings.Replace(text, "”", "”", -1)
|
||||
text = strings.Replace(text, "“", "“", -1)
|
||||
text = strings.Replace(text, """, "\"", -1)
|
||||
text = strings.Replace(text, "'", "'", -1)
|
||||
text = strings.Replace(text, ">", ">", -1)
|
||||
text = strings.Replace(text, "<", "<", -1)
|
||||
text = strings.Replace(text, "&", "&", -1) // Must be done last!
|
||||
|
||||
return strings.TrimSpace(text)
|
||||
}
|
||||
|
||||
func inSlice(v string, sl []string) bool {
|
||||
for _, vv := range sl {
|
||||
if vv == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// parse form values to struct via tag
|
||||
func ParseForm(form url.Values, obj interface{}) error {
|
||||
objT := reflect.TypeOf(obj)
|
||||
objV := reflect.ValueOf(obj)
|
||||
if !isStructPtr(objT) {
|
||||
return fmt.Errorf("%v must be a struct pointer", obj)
|
||||
}
|
||||
objT = objT.Elem()
|
||||
objV = objV.Elem()
|
||||
|
||||
for i := 0; i < objT.NumField(); i++ {
|
||||
fieldV := objV.Field(i)
|
||||
if !fieldV.CanSet() {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldT := objT.Field(i)
|
||||
tags := strings.Split(fieldT.Tag.Get("form"), ",")
|
||||
var tag string
|
||||
if len(tags) == 0 || len(tags[0]) == 0 {
|
||||
tag = fieldT.Name
|
||||
} else if tags[0] == "-" {
|
||||
continue
|
||||
} else {
|
||||
tag = tags[0]
|
||||
}
|
||||
|
||||
value := form.Get(tag)
|
||||
if len(value) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
switch fieldT.Type.Kind() {
|
||||
case reflect.Bool:
|
||||
b, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fieldV.SetBool(b)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
x, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fieldV.SetInt(x)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
x, err := strconv.ParseUint(value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fieldV.SetUint(x)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
x, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fieldV.SetFloat(x)
|
||||
case reflect.Interface:
|
||||
fieldV.Set(reflect.ValueOf(value))
|
||||
case reflect.String:
|
||||
fieldV.SetString(value)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// form types for RenderForm function
|
||||
var FormType = map[string]bool{
|
||||
"text": true,
|
||||
"textarea": true,
|
||||
"hidden": true,
|
||||
"password": true,
|
||||
}
|
||||
|
||||
var unKind = map[reflect.Kind]bool{
|
||||
reflect.Uintptr: true,
|
||||
reflect.Complex64: true,
|
||||
reflect.Complex128: true,
|
||||
reflect.Array: true,
|
||||
reflect.Chan: true,
|
||||
reflect.Func: true,
|
||||
reflect.Map: true,
|
||||
reflect.Ptr: true,
|
||||
reflect.Slice: true,
|
||||
reflect.Struct: true,
|
||||
reflect.UnsafePointer: true,
|
||||
}
|
||||
|
||||
// obj must be a struct pointer
|
||||
func RenderForm(obj interface{}) template.HTML {
|
||||
objT := reflect.TypeOf(obj)
|
||||
objV := reflect.ValueOf(obj)
|
||||
if !isStructPtr(objT) {
|
||||
return template.HTML("")
|
||||
}
|
||||
objT = objT.Elem()
|
||||
objV = objV.Elem()
|
||||
|
||||
var raw []string
|
||||
for i := 0; i < objT.NumField(); i++ {
|
||||
fieldV := objV.Field(i)
|
||||
if !fieldV.CanSet() || unKind[fieldV.Kind()] {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldT := objT.Field(i)
|
||||
tags := strings.Split(fieldT.Tag.Get("form"), ",")
|
||||
label := fieldT.Name + ": "
|
||||
name := fieldT.Name
|
||||
fType := "text"
|
||||
|
||||
switch len(tags) {
|
||||
case 1:
|
||||
if tags[0] == "-" {
|
||||
continue
|
||||
}
|
||||
if len(tags[0]) > 0 {
|
||||
name = tags[0]
|
||||
}
|
||||
case 2:
|
||||
if len(tags[0]) > 0 {
|
||||
name = tags[0]
|
||||
}
|
||||
if len(tags[1]) > 0 {
|
||||
fType = tags[1]
|
||||
}
|
||||
case 3:
|
||||
if len(tags[0]) > 0 {
|
||||
name = tags[0]
|
||||
}
|
||||
if len(tags[1]) > 0 {
|
||||
fType = tags[1]
|
||||
}
|
||||
if len(tags[2]) > 0 {
|
||||
label = tags[2]
|
||||
}
|
||||
}
|
||||
|
||||
raw = append(raw, fmt.Sprintf(`%v<input name="%v" type="%v" value="%v">`,
|
||||
label, name, fType, fieldV.Interface()))
|
||||
}
|
||||
return template.HTML(strings.Join(raw, "</br>"))
|
||||
}
|
||||
|
||||
func isStructPtr(t reflect.Type) bool {
|
||||
return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
|
||||
}
|
||||
|
||||
func stringsToJson(str string) string {
|
||||
rs := []rune(str)
|
||||
jsons := ""
|
||||
for _, r := range rs {
|
||||
rint := int(r)
|
||||
if rint < 128 {
|
||||
jsons += string(r)
|
||||
} else {
|
||||
jsons += "\\u" + strconv.FormatInt(int64(rint), 16) // json
|
||||
}
|
||||
}
|
||||
return jsons
|
||||
}
|
||||
|
||||
func FileExists(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
func GetRandomString(n int) string {
|
||||
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
var bytes = make([]byte, n)
|
||||
rand.Read(bytes)
|
||||
for i, b := range bytes {
|
||||
bytes[i] = alphanum[b%byte(len(alphanum))]
|
||||
}
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
// This will reference the index function local to the current blueprint:
|
||||
// UrlFor(".index")
|
||||
// ... print UrlFor("index")
|
||||
// ... print UrlFor("login")
|
||||
// ... print UrlFor("login", "next","/"")
|
||||
// ... print UrlFor("profile", "username","John Doe")
|
||||
// ...
|
||||
// /
|
||||
// /login
|
||||
// /login?next=/
|
||||
// /user/John%20Doe
|
||||
func UrlFor(endpoint string, values ...string) string {
|
||||
return BeeApp.UrlFor(endpoint, values...)
|
||||
}
|
||||
|
||||
|
||||
//This can be changed to a better name
|
||||
func AssetsJs(src string) template.HTML {
|
||||
text := string(src)
|
||||
|
||||
text = "<script src=\""+src+"\"></script>"
|
||||
|
||||
return template.HTML(text)
|
||||
}
|
||||
|
||||
//This can be changed to a better name
|
||||
func AssetsCss(src string) template.HTML {
|
||||
text := string(src)
|
||||
|
||||
text = "<link href=\""+src+"\" rel=\"stylesheet\" />"
|
||||
|
||||
return template.HTML(text)
|
||||
}
|
||||
package beego
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Substr() return the substr from start to length
|
||||
func Substr(s string, start, length int) string {
|
||||
bt := []rune(s)
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
var end int
|
||||
if (start + length) > (len(bt) - 1) {
|
||||
end = len(bt)
|
||||
} else {
|
||||
end = start + length
|
||||
}
|
||||
return string(bt[start:end])
|
||||
}
|
||||
|
||||
// Html2str() returns escaping text convert from html
|
||||
func Html2str(html string) string {
|
||||
src := string(html)
|
||||
|
||||
//将HTML标签全转换成小写
|
||||
re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
|
||||
src = re.ReplaceAllStringFunc(src, strings.ToLower)
|
||||
|
||||
//去除STYLE
|
||||
re, _ = regexp.Compile("\\<style[\\S\\s]+?\\</style\\>")
|
||||
src = re.ReplaceAllString(src, "")
|
||||
|
||||
//去除SCRIPT
|
||||
re, _ = regexp.Compile("\\<script[\\S\\s]+?\\</script\\>")
|
||||
src = re.ReplaceAllString(src, "")
|
||||
|
||||
//去除所有尖括号内的HTML代码,并换成换行符
|
||||
re, _ = regexp.Compile("\\<[\\S\\s]+?\\>")
|
||||
src = re.ReplaceAllString(src, "\n")
|
||||
|
||||
//去除连续的换行符
|
||||
re, _ = regexp.Compile("\\s{2,}")
|
||||
src = re.ReplaceAllString(src, "\n")
|
||||
|
||||
return strings.TrimSpace(src)
|
||||
}
|
||||
|
||||
// DateFormat takes a time and a layout string and returns a string with the formatted date. Used by the template parser as "dateformat"
|
||||
func DateFormat(t time.Time, layout string) (datestring string) {
|
||||
datestring = t.Format(layout)
|
||||
return
|
||||
}
|
||||
|
||||
var DatePatterns = []string{
|
||||
// year
|
||||
"Y", "2006", // A full numeric representation of a year, 4 digits Examples: 1999 or 2003
|
||||
"y", "06", //A two digit representation of a year Examples: 99 or 03
|
||||
|
||||
// month
|
||||
"m", "01", // Numeric representation of a month, with leading zeros 01 through 12
|
||||
"n", "1", // Numeric representation of a month, without leading zeros 1 through 12
|
||||
"M", "Jan", // A short textual representation of a month, three letters Jan through Dec
|
||||
"F", "January", // A full textual representation of a month, such as January or March January through December
|
||||
|
||||
// day
|
||||
"d", "02", // Day of the month, 2 digits with leading zeros 01 to 31
|
||||
"j", "2", // Day of the month without leading zeros 1 to 31
|
||||
|
||||
// week
|
||||
"D", "Mon", // A textual representation of a day, three letters Mon through Sun
|
||||
"l", "Monday", // A full textual representation of the day of the week Sunday through Saturday
|
||||
|
||||
// time
|
||||
"g", "3", // 12-hour format of an hour without leading zeros 1 through 12
|
||||
"G", "15", // 24-hour format of an hour without leading zeros 0 through 23
|
||||
"h", "03", // 12-hour format of an hour with leading zeros 01 through 12
|
||||
"H", "15", // 24-hour format of an hour with leading zeros 00 through 23
|
||||
|
||||
"a", "pm", // Lowercase Ante meridiem and Post meridiem am or pm
|
||||
"A", "PM", // Uppercase Ante meridiem and Post meridiem AM or PM
|
||||
|
||||
"i", "04", // Minutes with leading zeros 00 to 59
|
||||
"s", "05", // Seconds, with leading zeros 00 through 59
|
||||
|
||||
// time zone
|
||||
"T", "MST",
|
||||
"P", "-07:00",
|
||||
"O", "-0700",
|
||||
|
||||
// RFC 2822
|
||||
"r", time.RFC1123Z,
|
||||
}
|
||||
|
||||
// Parse Date use PHP time format
|
||||
func DateParse(dateString, format string) (time.Time, error) {
|
||||
replacer := strings.NewReplacer(DatePatterns...)
|
||||
format = replacer.Replace(format)
|
||||
return time.ParseInLocation(format, dateString, time.Local)
|
||||
}
|
||||
|
||||
// Date takes a PHP like date func to Go's time format
|
||||
func Date(t time.Time, format string) string {
|
||||
replacer := strings.NewReplacer(DatePatterns...)
|
||||
format = replacer.Replace(format)
|
||||
return t.Format(format)
|
||||
}
|
||||
|
||||
// Compare is a quick and dirty comparison function. It will convert whatever you give it to strings and see if the two values are equal.
|
||||
// Whitespace is trimmed. Used by the template parser as "eq"
|
||||
func Compare(a, b interface{}) (equal bool) {
|
||||
equal = false
|
||||
if strings.TrimSpace(fmt.Sprintf("%v", a)) == strings.TrimSpace(fmt.Sprintf("%v", b)) {
|
||||
equal = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Str2html(raw string) template.HTML {
|
||||
return template.HTML(raw)
|
||||
}
|
||||
|
||||
func Htmlquote(src string) string {
|
||||
//HTML编码为实体符号
|
||||
/*
|
||||
Encodes `text` for raw use in HTML.
|
||||
>>> htmlquote("<'&\\">")
|
||||
'<'&">'
|
||||
*/
|
||||
|
||||
text := string(src)
|
||||
|
||||
text = strings.Replace(text, "&", "&", -1) // Must be done first!
|
||||
text = strings.Replace(text, "<", "<", -1)
|
||||
text = strings.Replace(text, ">", ">", -1)
|
||||
text = strings.Replace(text, "'", "'", -1)
|
||||
text = strings.Replace(text, "\"", """, -1)
|
||||
text = strings.Replace(text, "“", "“", -1)
|
||||
text = strings.Replace(text, "”", "”", -1)
|
||||
text = strings.Replace(text, " ", " ", -1)
|
||||
|
||||
return strings.TrimSpace(text)
|
||||
}
|
||||
|
||||
func Htmlunquote(src string) string {
|
||||
//实体符号解释为HTML
|
||||
/*
|
||||
Decodes `text` that's HTML quoted.
|
||||
>>> htmlunquote('<'&">')
|
||||
'<\\'&">'
|
||||
*/
|
||||
|
||||
// strings.Replace(s, old, new, n)
|
||||
// 在s字符串中,把old字符串替换为new字符串,n表示替换的次数,小于0表示全部替换
|
||||
|
||||
text := string(src)
|
||||
text = strings.Replace(text, " ", " ", -1)
|
||||
text = strings.Replace(text, "”", "”", -1)
|
||||
text = strings.Replace(text, "“", "“", -1)
|
||||
text = strings.Replace(text, """, "\"", -1)
|
||||
text = strings.Replace(text, "'", "'", -1)
|
||||
text = strings.Replace(text, ">", ">", -1)
|
||||
text = strings.Replace(text, "<", "<", -1)
|
||||
text = strings.Replace(text, "&", "&", -1) // Must be done last!
|
||||
|
||||
return strings.TrimSpace(text)
|
||||
}
|
||||
|
||||
// This will reference the index function local to the current blueprint:
|
||||
// UrlFor(".index")
|
||||
// ... print UrlFor("index")
|
||||
// ... print UrlFor("login")
|
||||
// ... print UrlFor("login", "next","/"")
|
||||
// ... print UrlFor("profile", "username","John Doe")
|
||||
// ...
|
||||
// /
|
||||
// /login
|
||||
// /login?next=/
|
||||
// /user/John%20Doe
|
||||
func UrlFor(endpoint string, values ...string) string {
|
||||
return BeeApp.UrlFor(endpoint, values...)
|
||||
}
|
||||
|
||||
//This can be changed to a better name
|
||||
func AssetsJs(src string) template.HTML {
|
||||
text := string(src)
|
||||
|
||||
text = "<script src=\"" + src + "\"></script>"
|
||||
|
||||
return template.HTML(text)
|
||||
}
|
||||
|
||||
//This can be changed to a better name
|
||||
func AssetsCss(src string) template.HTML {
|
||||
text := string(src)
|
||||
|
||||
text = "<link href=\"" + src + "\" rel=\"stylesheet\" />"
|
||||
|
||||
return template.HTML(text)
|
||||
}
|
||||
|
||||
// parse form values to struct via tag
|
||||
func ParseForm(form url.Values, obj interface{}) error {
|
||||
objT := reflect.TypeOf(obj)
|
||||
objV := reflect.ValueOf(obj)
|
||||
if !isStructPtr(objT) {
|
||||
return fmt.Errorf("%v must be a struct pointer", obj)
|
||||
}
|
||||
objT = objT.Elem()
|
||||
objV = objV.Elem()
|
||||
|
||||
for i := 0; i < objT.NumField(); i++ {
|
||||
fieldV := objV.Field(i)
|
||||
if !fieldV.CanSet() {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldT := objT.Field(i)
|
||||
tags := strings.Split(fieldT.Tag.Get("form"), ",")
|
||||
var tag string
|
||||
if len(tags) == 0 || len(tags[0]) == 0 {
|
||||
tag = fieldT.Name
|
||||
} else if tags[0] == "-" {
|
||||
continue
|
||||
} else {
|
||||
tag = tags[0]
|
||||
}
|
||||
|
||||
value := form.Get(tag)
|
||||
if len(value) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
switch fieldT.Type.Kind() {
|
||||
case reflect.Bool:
|
||||
b, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fieldV.SetBool(b)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
x, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fieldV.SetInt(x)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
x, err := strconv.ParseUint(value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fieldV.SetUint(x)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
x, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fieldV.SetFloat(x)
|
||||
case reflect.Interface:
|
||||
fieldV.Set(reflect.ValueOf(value))
|
||||
case reflect.String:
|
||||
fieldV.SetString(value)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// form types for RenderForm function
|
||||
var FormType = map[string]bool{
|
||||
"text": true,
|
||||
"textarea": true,
|
||||
"hidden": true,
|
||||
"password": true,
|
||||
}
|
||||
|
||||
var unKind = map[reflect.Kind]bool{
|
||||
reflect.Uintptr: true,
|
||||
reflect.Complex64: true,
|
||||
reflect.Complex128: true,
|
||||
reflect.Array: true,
|
||||
reflect.Chan: true,
|
||||
reflect.Func: true,
|
||||
reflect.Map: true,
|
||||
reflect.Ptr: true,
|
||||
reflect.Slice: true,
|
||||
reflect.Struct: true,
|
||||
reflect.UnsafePointer: true,
|
||||
}
|
||||
|
||||
// obj must be a struct pointer
|
||||
func RenderForm(obj interface{}) template.HTML {
|
||||
objT := reflect.TypeOf(obj)
|
||||
objV := reflect.ValueOf(obj)
|
||||
if !isStructPtr(objT) {
|
||||
return template.HTML("")
|
||||
}
|
||||
objT = objT.Elem()
|
||||
objV = objV.Elem()
|
||||
|
||||
var raw []string
|
||||
for i := 0; i < objT.NumField(); i++ {
|
||||
fieldV := objV.Field(i)
|
||||
if !fieldV.CanSet() || unKind[fieldV.Kind()] {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldT := objT.Field(i)
|
||||
tags := strings.Split(fieldT.Tag.Get("form"), ",")
|
||||
label := fieldT.Name + ": "
|
||||
name := fieldT.Name
|
||||
fType := "text"
|
||||
|
||||
switch len(tags) {
|
||||
case 1:
|
||||
if tags[0] == "-" {
|
||||
continue
|
||||
}
|
||||
if len(tags[0]) > 0 {
|
||||
name = tags[0]
|
||||
}
|
||||
case 2:
|
||||
if len(tags[0]) > 0 {
|
||||
name = tags[0]
|
||||
}
|
||||
if len(tags[1]) > 0 {
|
||||
fType = tags[1]
|
||||
}
|
||||
case 3:
|
||||
if len(tags[0]) > 0 {
|
||||
name = tags[0]
|
||||
}
|
||||
if len(tags[1]) > 0 {
|
||||
fType = tags[1]
|
||||
}
|
||||
if len(tags[2]) > 0 {
|
||||
label = tags[2]
|
||||
}
|
||||
}
|
||||
|
||||
raw = append(raw, fmt.Sprintf(`%v<input name="%v" type="%v" value="%v">`,
|
||||
label, name, fType, fieldV.Interface()))
|
||||
}
|
||||
return template.HTML(strings.Join(raw, "</br>"))
|
||||
}
|
||||
|
||||
func isStructPtr(t reflect.Type) bool {
|
||||
return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
|
||||
}
|
||||
|
||||
// go1.2 added template funcs. begin
|
||||
var (
|
||||
errBadComparisonType = errors.New("invalid type for comparison")
|
||||
errBadComparison = errors.New("incompatible types for comparison")
|
||||
errNoComparison = errors.New("missing argument for comparison")
|
||||
)
|
||||
|
||||
type kind int
|
||||
|
||||
const (
|
||||
invalidKind kind = iota
|
||||
boolKind
|
||||
complexKind
|
||||
intKind
|
||||
floatKind
|
||||
integerKind
|
||||
stringKind
|
||||
uintKind
|
||||
)
|
||||
|
||||
func basicKind(v reflect.Value) (kind, error) {
|
||||
switch v.Kind() {
|
||||
case reflect.Bool:
|
||||
return boolKind, nil
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return intKind, nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return uintKind, nil
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return floatKind, nil
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
return complexKind, nil
|
||||
case reflect.String:
|
||||
return stringKind, nil
|
||||
}
|
||||
return invalidKind, errBadComparisonType
|
||||
}
|
||||
|
||||
// eq evaluates the comparison a == b || a == c || ...
|
||||
func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
|
||||
v1 := reflect.ValueOf(arg1)
|
||||
k1, err := basicKind(v1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(arg2) == 0 {
|
||||
return false, errNoComparison
|
||||
}
|
||||
for _, arg := range arg2 {
|
||||
v2 := reflect.ValueOf(arg)
|
||||
k2, err := basicKind(v2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if k1 != k2 {
|
||||
return false, errBadComparison
|
||||
}
|
||||
truth := false
|
||||
switch k1 {
|
||||
case boolKind:
|
||||
truth = v1.Bool() == v2.Bool()
|
||||
case complexKind:
|
||||
truth = v1.Complex() == v2.Complex()
|
||||
case floatKind:
|
||||
truth = v1.Float() == v2.Float()
|
||||
case intKind:
|
||||
truth = v1.Int() == v2.Int()
|
||||
case stringKind:
|
||||
truth = v1.String() == v2.String()
|
||||
case uintKind:
|
||||
truth = v1.Uint() == v2.Uint()
|
||||
default:
|
||||
panic("invalid kind")
|
||||
}
|
||||
if truth {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// ne evaluates the comparison a != b.
|
||||
func ne(arg1, arg2 interface{}) (bool, error) {
|
||||
// != is the inverse of ==.
|
||||
equal, err := eq(arg1, arg2)
|
||||
return !equal, err
|
||||
}
|
||||
|
||||
// lt evaluates the comparison a < b.
|
||||
func lt(arg1, arg2 interface{}) (bool, error) {
|
||||
v1 := reflect.ValueOf(arg1)
|
||||
k1, err := basicKind(v1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
v2 := reflect.ValueOf(arg2)
|
||||
k2, err := basicKind(v2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if k1 != k2 {
|
||||
return false, errBadComparison
|
||||
}
|
||||
truth := false
|
||||
switch k1 {
|
||||
case boolKind, complexKind:
|
||||
return false, errBadComparisonType
|
||||
case floatKind:
|
||||
truth = v1.Float() < v2.Float()
|
||||
case intKind:
|
||||
truth = v1.Int() < v2.Int()
|
||||
case stringKind:
|
||||
truth = v1.String() < v2.String()
|
||||
case uintKind:
|
||||
truth = v1.Uint() < v2.Uint()
|
||||
default:
|
||||
panic("invalid kind")
|
||||
}
|
||||
return truth, nil
|
||||
}
|
||||
|
||||
// le evaluates the comparison <= b.
|
||||
func le(arg1, arg2 interface{}) (bool, error) {
|
||||
// <= is < or ==.
|
||||
lessThan, err := lt(arg1, arg2)
|
||||
if lessThan || err != nil {
|
||||
return lessThan, err
|
||||
}
|
||||
return eq(arg1, arg2)
|
||||
}
|
||||
|
||||
// gt evaluates the comparison a > b.
|
||||
func gt(arg1, arg2 interface{}) (bool, error) {
|
||||
// > is the inverse of <=.
|
||||
lessOrEqual, err := le(arg1, arg2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return !lessOrEqual, nil
|
||||
}
|
||||
|
||||
// ge evaluates the comparison a >= b.
|
||||
func ge(arg1, arg2 interface{}) (bool, error) {
|
||||
// >= is the inverse of <.
|
||||
lessThan, err := lt(arg1, arg2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return !lessThan, nil
|
||||
}
|
||||
|
||||
// go1.2 added template funcs. end
|
@ -7,18 +7,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestWebTime(t *testing.T) {
|
||||
ts := "Fri, 26 Jul 2013 12:27:42 CST"
|
||||
l, _ := time.LoadLocation("GST")
|
||||
tt, _ := time.ParseInLocation(time.RFC1123, ts, l)
|
||||
if ts != webTime(tt) {
|
||||
t.Error("should be equal")
|
||||
}
|
||||
if "Fri, 26 Jul 2013 12:27:42 GMT" != webTime(tt.UTC()) {
|
||||
t.Error("should be equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubstr(t *testing.T) {
|
||||
s := `012345`
|
||||
if Substr(s, 0, 2) != "01" {
|
||||
@ -92,16 +80,6 @@ func TestHtmlunquote(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestInSlice(t *testing.T) {
|
||||
sl := []string{"A", "b"}
|
||||
if !inSlice("A", sl) {
|
||||
t.Error("should be true")
|
||||
}
|
||||
if inSlice("B", sl) {
|
||||
t.Error("should be false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseForm(t *testing.T) {
|
||||
type user struct {
|
||||
Id int `form:"-"`
|
@ -30,7 +30,7 @@ func FileExists(name string) bool {
|
||||
|
||||
// search a file in paths.
|
||||
// this is offen used in search config file in /etc ~/
|
||||
func LookFile(filename string, paths ...string) (fullpath string, err error) {
|
||||
func SearchFile(filename string, paths ...string) (fullpath string, err error) {
|
||||
for _, path := range paths {
|
||||
if fullpath = filepath.Join(path, filename); FileExists(fullpath) {
|
||||
return
|
||||
@ -41,7 +41,7 @@ func LookFile(filename string, paths ...string) (fullpath string, err error) {
|
||||
}
|
||||
|
||||
// like command grep -E
|
||||
// for example: GrepE(`^hello`, "hello.txt")
|
||||
// for example: GrepFile(`^hello`, "hello.txt")
|
||||
// \n is striped while read
|
||||
func GrepFile(patten string, filename string) (lines []string, err error) {
|
||||
re, err := regexp.Compile(patten)
|
||||
|
@ -23,7 +23,7 @@ func TestSelfDir(t *testing.T) {
|
||||
|
||||
func TestFileExists(t *testing.T) {
|
||||
if !FileExists("./file.go") {
|
||||
t.Errorf("/bin/echo should exists, but it didn't")
|
||||
t.Errorf("./file.go should exists, but it didn't")
|
||||
}
|
||||
|
||||
if FileExists(noExistedFile) {
|
||||
@ -31,14 +31,14 @@ func TestFileExists(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLookFile(t *testing.T) {
|
||||
path, err := LookFile(filepath.Base(SelfPath()), SelfDir())
|
||||
func TestSearchFile(t *testing.T) {
|
||||
path, err := SearchFile(filepath.Base(SelfPath()), SelfDir())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log(path)
|
||||
|
||||
path, err = LookFile(noExistedFile, ".")
|
||||
path, err = SearchFile(noExistedFile, ".")
|
||||
if err == nil {
|
||||
t.Errorf("err shouldnot be nil, got path: %s", SelfDir())
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package beego
|
||||
package utils
|
||||
|
||||
import (
|
||||
"sync"
|
@ -1,4 +1,4 @@
|
||||
package beego
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
141
utils/slice.go
Normal file
141
utils/slice.go
Normal file
@ -0,0 +1,141 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
type reducetype func(interface{}) interface{}
|
||||
type filtertype func(interface{}) bool
|
||||
|
||||
func InSlice(v string, sl []string) bool {
|
||||
for _, vv := range sl {
|
||||
if vv == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func InSliceIface(v interface{}, sl []interface{}) bool {
|
||||
for _, vv := range sl {
|
||||
if vv == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func SliceRandList(min, max int) []int {
|
||||
if max < min {
|
||||
min, max = max, min
|
||||
}
|
||||
length := max - min + 1
|
||||
t0 := time.Now()
|
||||
rand.Seed(int64(t0.Nanosecond()))
|
||||
list := rand.Perm(length)
|
||||
for index, _ := range list {
|
||||
list[index] += min
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func SliceMerge(slice1, slice2 []interface{}) (c []interface{}) {
|
||||
c = append(slice1, slice2...)
|
||||
return
|
||||
}
|
||||
|
||||
func SliceReduce(slice []interface{}, a reducetype) (dslice []interface{}) {
|
||||
for _, v := range slice {
|
||||
dslice = append(dslice, a(v))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SliceRand(a []interface{}) (b interface{}) {
|
||||
randnum := rand.Intn(len(a))
|
||||
b = a[randnum]
|
||||
return
|
||||
}
|
||||
|
||||
func SliceSum(intslice []int64) (sum int64) {
|
||||
for _, v := range intslice {
|
||||
sum += v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SliceFilter(slice []interface{}, a filtertype) (ftslice []interface{}) {
|
||||
for _, v := range slice {
|
||||
if a(v) {
|
||||
ftslice = append(ftslice, v)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SliceDiff(slice1, slice2 []interface{}) (diffslice []interface{}) {
|
||||
for _, v := range slice1 {
|
||||
if !InSliceIface(v, slice2) {
|
||||
diffslice = append(diffslice, v)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SliceIntersect(slice1, slice2 []interface{}) (diffslice []interface{}) {
|
||||
for _, v := range slice1 {
|
||||
if !InSliceIface(v, slice2) {
|
||||
diffslice = append(diffslice, v)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SliceChunk(slice []interface{}, size int) (chunkslice [][]interface{}) {
|
||||
if size >= len(slice) {
|
||||
chunkslice = append(chunkslice, slice)
|
||||
return
|
||||
}
|
||||
end := size
|
||||
for i := 0; i <= (len(slice) - size); i += size {
|
||||
chunkslice = append(chunkslice, slice[i:end])
|
||||
end += size
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SliceRange(start, end, step int64) (intslice []int64) {
|
||||
for i := start; i <= end; i += step {
|
||||
intslice = append(intslice, i)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SlicePad(slice []interface{}, size int, val interface{}) []interface{} {
|
||||
if size <= len(slice) {
|
||||
return slice
|
||||
}
|
||||
for i := 0; i < (size - len(slice)); i++ {
|
||||
slice = append(slice, val)
|
||||
}
|
||||
return slice
|
||||
}
|
||||
|
||||
func SliceUnique(slice []interface{}) (uniqueslice []interface{}) {
|
||||
for _, v := range slice {
|
||||
if !InSliceIface(v, uniqueslice) {
|
||||
uniqueslice = append(uniqueslice, v)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SliceShuffle(slice []interface{}) []interface{} {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
a := rand.Intn(len(slice))
|
||||
b := rand.Intn(len(slice))
|
||||
slice[a], slice[b] = slice[b], slice[a]
|
||||
}
|
||||
return slice
|
||||
}
|
15
utils/slice_test.go
Normal file
15
utils/slice_test.go
Normal file
@ -0,0 +1,15 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInSlice(t *testing.T) {
|
||||
sl := []string{"A", "b"}
|
||||
if !InSlice("A", sl) {
|
||||
t.Error("should be true")
|
||||
}
|
||||
if InSlice("B", sl) {
|
||||
t.Error("should be false")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user