Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
B
beego
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
beego
Commits
c59a029c
Commit
c59a029c
authored
Jan 27, 2016
by
youngsterxyf
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into config-logic
parents
20efd523
4ce094a2
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
545 additions
and
277 deletions
+545
-277
.travis.yml
.travis.yml
+9
-2
memcache_test.go
cache/memcache/memcache_test.go
+1
-1
config.go
config.go
+16
-12
config.go
config/config.go
+36
-0
fake.go
config/fake.go
+1
-1
ini.go
config/ini.go
+32
-10
ini_test.go
config/ini_test.go
+119
-39
json.go
config/json.go
+3
-5
json_test.go
config/json_test.go
+88
-65
xml.go
config/xml/xml.go
+4
-1
yaml.go
config/yaml/yaml.go
+3
-3
hooks.go
hooks.go
+4
-6
conn.go
logs/conn.go
+6
-2
console.go
logs/console.go
+17
-15
es.go
logs/es/es.go
+4
-4
file.go
logs/file.go
+6
-45
log.go
logs/log.go
+52
-6
smtp.go
logs/smtp.go
+2
-2
types.go
orm/types.go
+6
-0
parser.go
parser.go
+3
-3
cors.go
plugins/cors/cors.go
+2
-0
tree.go
tree.go
+18
-6
tree_test.go
tree_test.go
+29
-42
mail.go
utils/mail.go
+84
-7
No files found.
.travis.yml
View file @
c59a029c
language
:
go
go
:
-
1.5.1
-
1.5.3
-
1.4.3
-
1.3.3
services
:
-
redis-server
-
mysql
...
...
@@ -24,7 +25,13 @@ install:
-
go get github.com/couchbase/go-couchbase
-
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
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"
script
:
-
go vet -x ./...
-
$HOME/gopath/bin/golint ./...
-
go test -v ./...
cache/memcache/memcache_test.go
View file @
c59a029c
...
...
@@ -37,7 +37,7 @@ func TestMemcacheCache(t *testing.T) {
t
.
Error
(
"check err"
)
}
time
.
Sleep
(
1
0
*
time
.
Second
)
time
.
Sleep
(
1
1
*
time
.
Second
)
if
bm
.
IsExist
(
"astaxie"
)
{
t
.
Error
(
"check err"
)
...
...
config.go
View file @
c59a029c
...
...
@@ -105,18 +105,25 @@ var (
BConfig
*
Config
// AppConfig is the instance of Config, store the config information from file
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
// AppConfigPath is the path to the config files
AppConfigPath
string
// AppConfigProvider is the provider for the config, default is ini
AppConfigProvider
=
"ini"
workPath
string
)
func
init
()
{
AppPath
,
_
=
filepath
.
Abs
(
filepath
.
Dir
(
os
.
Args
[
0
]))
workPath
,
_
=
os
.
Getwd
()
workPath
,
_
=
filepath
.
Abs
(
workPath
)
BConfig
=
&
Config
{
AppName
:
"beego"
,
RunMode
:
DEV
,
...
...
@@ -177,8 +184,7 @@ func init() {
},
}
AppConfigPath
=
getDefaultAppConfigPath
()
AppConfigPath
=
filepath
.
Join
(
AppPath
,
"conf"
,
"app.conf"
)
if
!
utils
.
FileExists
(
AppConfigPath
)
{
AppConfig
=
&
beegoAppConfig
{
config
.
NewFakeConfig
()}
return
...
...
@@ -187,14 +193,12 @@ func init() {
parseConfig
(
AppConfigPath
)
}
func
getDefaultAppConfigPath
()
string
{
// default config path
AppPath
,
_
:=
filepath
.
Abs
(
filepath
.
Dir
(
os
.
Args
[
0
]))
return
filepath
.
Join
(
AppPath
,
"conf"
,
"app.conf"
)
}
// now only support ini, next will support json.
func
parseConfig
(
appConfigPath
string
)
(
err
error
)
{
if
workPath
!=
AppPath
{
os
.
Chdir
(
AppPath
)
}
AppConfig
,
err
=
newAppConfig
(
AppConfigProvider
,
appConfigPath
)
if
err
!=
nil
{
return
err
...
...
config/config.go
View file @
c59a029c
...
...
@@ -106,3 +106,39 @@ func NewConfigData(adapterName string, data []byte) (Configer, error) {
}
return
adapter
.
ParseData
(
data
)
}
// 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,
// 0, 0.0, f, F, FALSE, false, False, NO, no, No, N,n, OFF, off, Off.
// Any other value returns an error.
func
ParseBool
(
val
interface
{})
(
value
bool
,
err
error
)
{
if
val
!=
nil
{
switch
v
:=
val
.
(
type
)
{
case
bool
:
return
v
,
nil
case
string
:
switch
v
{
case
"1"
,
"t"
,
"T"
,
"true"
,
"TRUE"
,
"True"
,
"YES"
,
"yes"
,
"Yes"
,
"Y"
,
"y"
,
"ON"
,
"on"
,
"On"
:
return
true
,
nil
case
"0"
,
"f"
,
"F"
,
"false"
,
"FALSE"
,
"False"
,
"NO"
,
"no"
,
"No"
,
"N"
,
"n"
,
"OFF"
,
"off"
,
"Off"
:
return
false
,
nil
}
case
int8
,
int32
,
int64
:
strV
:=
fmt
.
Sprintf
(
"%s"
,
v
)
if
strV
==
"1"
{
return
true
,
nil
}
else
if
strV
==
"0"
{
return
false
,
nil
}
case
float64
:
if
v
==
1
{
return
true
,
nil
}
else
if
v
==
0
{
return
false
,
nil
}
}
return
false
,
fmt
.
Errorf
(
"parsing %q: invalid syntax"
,
val
)
}
return
false
,
fmt
.
Errorf
(
"parsing <nil>: invalid syntax"
)
}
config/fake.go
View file @
c59a029c
...
...
@@ -82,7 +82,7 @@ func (c *fakeConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
}
func
(
c
*
fakeConfigContainer
)
Bool
(
key
string
)
(
bool
,
error
)
{
return
strconv
.
ParseBool
(
c
.
getData
(
key
))
return
ParseBool
(
c
.
getData
(
key
))
}
func
(
c
*
fakeConfigContainer
)
DefaultBool
(
key
string
,
defaultval
bool
)
bool
{
...
...
config/ini.go
View file @
c59a029c
...
...
@@ -27,7 +27,6 @@ import (
"strings"
"sync"
"time"
"unicode"
)
var
(
...
...
@@ -97,9 +96,11 @@ func (ini *IniConfig) parseFile(name string) (*IniConfigContainer, error) {
}
if
bComment
!=
nil
{
line
=
bytes
.
TrimLeft
(
line
,
string
(
bComment
))
line
=
bytes
.
TrimLeftFunc
(
line
,
unicode
.
IsSpace
)
// Need append to a new line if multi-line comments.
if
comment
.
Len
()
>
0
{
comment
.
WriteByte
(
'\n'
)
}
comment
.
Write
(
line
)
comment
.
WriteByte
(
'\n'
)
continue
}
...
...
@@ -194,7 +195,7 @@ type IniConfigContainer struct {
// Bool returns the boolean value for a given key.
func
(
c
*
IniConfigContainer
)
Bool
(
key
string
)
(
bool
,
error
)
{
return
strconv
.
ParseBool
(
c
.
getdata
(
key
))
return
ParseBool
(
c
.
getdata
(
key
))
}
// DefaultBool returns the boolean value for a given key.
...
...
@@ -299,14 +300,35 @@ func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) {
}
defer
f
.
Close
()
// Get section or key comments. Fixed #1607
getCommentStr
:=
func
(
section
,
key
string
)
string
{
comment
,
ok
:=
""
,
false
if
len
(
key
)
==
0
{
comment
,
ok
=
c
.
sectionComment
[
section
]
}
else
{
comment
,
ok
=
c
.
keyComment
[
section
+
"."
+
key
]
}
if
ok
{
// Empty comment
if
len
(
comment
)
==
0
||
len
(
strings
.
TrimSpace
(
comment
))
==
0
{
return
string
(
bNumComment
)
}
prefix
:=
string
(
bNumComment
)
// Add the line head character "#"
return
prefix
+
strings
.
Replace
(
comment
,
lineBreak
,
lineBreak
+
prefix
,
-
1
)
}
return
""
}
buf
:=
bytes
.
NewBuffer
(
nil
)
// Save default section at first place
if
dt
,
ok
:=
c
.
data
[
defaultSection
];
ok
{
for
key
,
val
:=
range
dt
{
if
key
!=
" "
{
// Write key comments.
if
v
,
ok
:=
c
.
keyComment
[
key
];
ok
{
if
_
,
err
=
buf
.
WriteString
(
string
(
bNumComment
)
+
v
+
lineBreak
);
err
!=
nil
{
if
v
:=
getCommentStr
(
defaultSection
,
key
);
len
(
v
)
>
0
{
if
_
,
err
=
buf
.
WriteString
(
v
+
lineBreak
);
err
!=
nil
{
return
err
}
}
...
...
@@ -327,8 +349,8 @@ func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) {
for
section
,
dt
:=
range
c
.
data
{
if
section
!=
defaultSection
{
// Write section comments.
if
v
,
ok
:=
c
.
sectionComment
[
section
];
ok
{
if
_
,
err
=
buf
.
WriteString
(
string
(
bNumComment
)
+
v
+
lineBreak
);
err
!=
nil
{
if
v
:=
getCommentStr
(
section
,
""
);
len
(
v
)
>
0
{
if
_
,
err
=
buf
.
WriteString
(
v
+
lineBreak
);
err
!=
nil
{
return
err
}
}
...
...
@@ -341,8 +363,8 @@ func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) {
for
key
,
val
:=
range
dt
{
if
key
!=
" "
{
// Write key comments.
if
v
,
ok
:=
c
.
keyComment
[
key
];
ok
{
if
_
,
err
=
buf
.
WriteString
(
string
(
bNumComment
)
+
v
+
lineBreak
);
err
!=
nil
{
if
v
:=
getCommentStr
(
section
,
key
);
len
(
v
)
>
0
{
if
_
,
err
=
buf
.
WriteString
(
v
+
lineBreak
);
err
!=
nil
{
return
err
}
}
...
...
config/ini_test.go
View file @
c59a029c
...
...
@@ -15,11 +15,17 @@
package
config
import
(
"fmt"
"io/ioutil"
"os"
"strings"
"testing"
)
var
inicontext
=
`
func
TestIni
(
t
*
testing
.
T
)
{
var
(
inicontext
=
`
;comment one
#comment two
appname = beeapi
...
...
@@ -29,6 +35,13 @@ PI = 3.1415976
runmode = "dev"
autorender = false
copyrequestbody = true
session= on
cookieon= off
newreg = OFF
needlogin = ON
enableSession = Y
enableCookie = N
flag = 1
[demo]
key1="asta"
key2 = "xie"
...
...
@@ -36,7 +49,31 @@ CaseInsensitive = true
peers = one;two;three
`
func
TestIni
(
t
*
testing
.
T
)
{
keyValue
=
map
[
string
]
interface
{}{
"appname"
:
"beeapi"
,
"httpport"
:
8080
,
"mysqlport"
:
int64
(
3600
),
"pi"
:
3.1415976
,
"runmode"
:
"dev"
,
"autorender"
:
false
,
"copyrequestbody"
:
true
,
"session"
:
true
,
"cookieon"
:
false
,
"newreg"
:
false
,
"needlogin"
:
true
,
"enableSession"
:
true
,
"enableCookie"
:
false
,
"flag"
:
true
,
"demo::key1"
:
"asta"
,
"demo::key2"
:
"xie"
,
"demo::CaseInsensitive"
:
true
,
"demo::peers"
:
[]
string
{
"one"
,
"two"
,
"three"
},
"null"
:
""
,
"demo2::key1"
:
""
,
"error"
:
""
,
}
)
f
,
err
:=
os
.
Create
(
"testini.conf"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
...
...
@@ -52,31 +89,31 @@ func TestIni(t *testing.T) {
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
iniconf
.
String
(
"appname"
)
!=
"beeapi"
{
t
.
Fatal
(
"appname not equal to beeapi"
)
}
if
port
,
err
:=
iniconf
.
Int
(
"httpport"
);
err
!=
nil
||
port
!=
8080
{
t
.
Error
(
port
)
t
.
Fatal
(
err
)
}
if
port
,
err
:=
iniconf
.
Int64
(
"mysqlport"
);
err
!=
nil
||
port
!=
3600
{
t
.
Error
(
port
)
t
.
Fatal
(
err
)
}
if
pi
,
err
:=
iniconf
.
Float
(
"PI"
);
err
!=
nil
||
pi
!=
3.1415976
{
t
.
Error
(
pi
)
t
.
Fatal
(
err
)
}
if
iniconf
.
String
(
"runmode"
)
!=
"dev"
{
t
.
Fatal
(
"runmode not equal to dev"
)
}
if
v
,
err
:=
iniconf
.
Bool
(
"autorender"
);
err
!=
nil
||
v
!=
false
{
t
.
Error
(
v
)
t
.
Fatal
(
err
)
}
if
v
,
err
:=
iniconf
.
Bool
(
"copyrequestbody"
);
err
!=
nil
||
v
!=
true
{
t
.
Error
(
v
)
t
.
Fatal
(
err
)
for
k
,
v
:=
range
keyValue
{
var
err
error
var
value
interface
{
}
switch
v
.
(
type
)
{
case
int
:
value
,
err
=
iniconf
.
Int
(
k
)
case
int64
:
value
,
err
=
iniconf
.
Int64
(
k
)
case
float64
:
value
,
err
=
iniconf
.
Float
(
k
)
case
bool
:
value
,
err
=
iniconf
.
Bool
(
k
)
case
[]
string
:
value
=
iniconf
.
Strings
(
k
)
case
string
:
value
=
iniconf
.
String
(
k
)
default
:
value
,
err
=
iniconf
.
DIY
(
k
)
}
if
err
!=
nil
{
t
.
Fatalf
(
"get key %q value fail,err %s"
,
k
,
err
)
}
else
if
fmt
.
Sprintf
(
"%v"
,
v
)
!=
fmt
.
Sprintf
(
"%v"
,
value
)
{
t
.
Fatalf
(
"get key %q value, want %v got %v ."
,
k
,
v
,
value
)
}
}
if
err
=
iniconf
.
Set
(
"name"
,
"astaxie"
);
err
!=
nil
{
t
.
Fatal
(
err
)
...
...
@@ -84,20 +121,63 @@ func TestIni(t *testing.T) {
if
iniconf
.
String
(
"name"
)
!=
"astaxie"
{
t
.
Fatal
(
"get name error"
)
}
if
iniconf
.
String
(
"demo::key1"
)
!=
"asta"
{
t
.
Fatal
(
"get demo.key1 error"
)
}
if
iniconf
.
String
(
"demo::key2"
)
!=
"xie"
{
t
.
Fatal
(
"get demo.key2 error"
)
}
func
TestIniSave
(
t
*
testing
.
T
)
{
const
(
inicontext
=
`
app = app
;comment one
#comment two
# comment three
appname = beeapi
httpport = 8080
# DB Info
# enable db
[dbinfo]
# db type name
# suport mysql,sqlserver
name = mysql
`
saveResult
=
`
app=app
#comment one
#comment two
# comment three
appname=beeapi
httpport=8080
# DB Info
# enable db
[dbinfo]
# db type name
# suport mysql,sqlserver
name=mysql
`
)
cfg
,
err
:=
NewConfigData
(
"ini"
,
[]
byte
(
inicontext
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
v
,
err
:=
iniconf
.
Bool
(
"demo::caseinsensitive"
);
err
!=
nil
||
v
!=
true
{
t
.
Fatal
(
"get demo.caseinsensitive error"
)
name
:=
"newIniConfig.ini"
if
err
:=
cfg
.
SaveConfigFile
(
name
);
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
os
.
Remove
(
name
)
if
data
:=
iniconf
.
Strings
(
"demo::peers"
);
len
(
data
)
!=
3
{
t
.
Fatal
(
"get strings error"
,
data
)
}
else
if
data
[
0
]
!=
"one"
{
t
.
Fatal
(
"get first params error not equat to one"
)
}
if
data
,
err
:=
ioutil
.
ReadFile
(
name
);
err
!=
nil
{
t
.
Fatal
(
err
)
}
else
{
cfgData
:=
string
(
data
)
datas
:=
strings
.
Split
(
saveResult
,
"
\n
"
)
for
_
,
line
:=
range
datas
{
if
strings
.
Contains
(
cfgData
,
line
+
"
\n
"
)
==
false
{
t
.
Fatalf
(
"different after save ini config file. need contains %q"
,
line
)
}
}
}
}
config/json.go
View file @
c59a029c
...
...
@@ -17,6 +17,7 @@ package config
import
(
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"strings"
...
...
@@ -70,12 +71,9 @@ type JSONConfigContainer struct {
func
(
c
*
JSONConfigContainer
)
Bool
(
key
string
)
(
bool
,
error
)
{
val
:=
c
.
getData
(
key
)
if
val
!=
nil
{
if
v
,
ok
:=
val
.
(
bool
);
ok
{
return
v
,
nil
}
return
false
,
errors
.
New
(
"not bool value"
)
return
ParseBool
(
val
)
}
return
false
,
errors
.
New
(
"not exist key:"
+
key
)
return
false
,
fmt
.
Errorf
(
"not exist key: %q"
,
key
)
}
// DefaultBool return the bool value if has no error
...
...
config/json_test.go
View file @
c59a029c
...
...
@@ -15,34 +15,14 @@
package
config
import
(
"fmt"
"os"
"testing"
)
var
jsoncontext
=
`{
"appname": "beeapi",
"testnames": "foo;bar",
"httpport": 8080,
"mysqlport": 3600,
"PI": 3.1415976,
"runmode": "dev",
"autorender": false,
"copyrequestbody": true,
"database": {
"host": "host",
"port": "port",
"database": "database",
"username": "username",
"password": "password",
"conns":{
"maxconnection":12,
"autoconnect":true,
"connectioninfo":"info"
}
}
}`
func
TestJsonStartsWithArray
(
t
*
testing
.
T
)
{
var
jsoncontextwitharray
=
`[
const
jsoncontextwitharray
=
`[
{
"url": "user",
"serviceAPI": "http://www.test.com/user"
...
...
@@ -52,8 +32,6 @@ var jsoncontextwitharray = `[
"serviceAPI": "http://www.test.com/employee"
}
]`
func
TestJsonStartsWithArray
(
t
*
testing
.
T
)
{
f
,
err
:=
os
.
Create
(
"testjsonWithArray.conf"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
...
...
@@ -90,6 +68,64 @@ func TestJsonStartsWithArray(t *testing.T) {
}
func
TestJson
(
t
*
testing
.
T
)
{
var
(
jsoncontext
=
`{
"appname": "beeapi",
"testnames": "foo;bar",
"httpport": 8080,
"mysqlport": 3600,
"PI": 3.1415976,
"runmode": "dev",
"autorender": false,
"copyrequestbody": true,
"session": "on",
"cookieon": "off",
"newreg": "OFF",
"needlogin": "ON",
"enableSession": "Y",
"enableCookie": "N",
"flag": 1,
"database": {
"host": "host",
"port": "port",
"database": "database",
"username": "username",
"password": "password",
"conns":{
"maxconnection":12,
"autoconnect":true,
"connectioninfo":"info"
}
}
}`
keyValue
=
map
[
string
]
interface
{}{
"appname"
:
"beeapi"
,
"testnames"
:
[]
string
{
"foo"
,
"bar"
},
"httpport"
:
8080
,
"mysqlport"
:
int64
(
3600
),
"PI"
:
3.1415976
,
"runmode"
:
"dev"
,
"autorender"
:
false
,
"copyrequestbody"
:
true
,
"session"
:
true
,
"cookieon"
:
false
,
"newreg"
:
false
,
"needlogin"
:
true
,
"enableSession"
:
true
,
"enableCookie"
:
false
,
"flag"
:
true
,
"database::host"
:
"host"
,
"database::port"
:
"port"
,
"database::database"
:
"database"
,
"database::password"
:
"password"
,
"database::conns::maxconnection"
:
12
,
"database::conns::autoconnect"
:
true
,
"database::conns::connectioninfo"
:
"info"
,
"unknown"
:
""
,
}
)
f
,
err
:=
os
.
Create
(
"testjson.conf"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
...
...
@@ -105,37 +141,32 @@ func TestJson(t *testing.T) {
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
jsonconf
.
String
(
"appname"
)
!=
"beeapi"
{
t
.
Fatal
(
"appname not equal to beeapi"
)
}
if
port
,
err
:=
jsonconf
.
Int
(
"httpport"
);
err
!=
nil
||
port
!=
8080
{
t
.
Error
(
port
)
t
.
Fatal
(
err
)
}
if
port
,
err
:=
jsonconf
.
Int64
(
"mysqlport"
);
err
!=
nil
||
port
!=
3600
{
t
.
Error
(
port
)
t
.
Fatal
(
err
)
}
if
pi
,
err
:=
jsonconf
.
Float
(
"PI"
);
err
!=
nil
||
pi
!=
3.1415976
{
t
.
Error
(
pi
)
t
.
Fatal
(
err
)
}
if
jsonconf
.
String
(
"runmode"
)
!=
"dev"
{
t
.
Fatal
(
"runmode not equal to dev"
)
}
if
v
:=
jsonconf
.
Strings
(
"unknown"
);
len
(
v
)
>
0
{
t
.
Fatal
(
"unknown strings, the length should be 0"
)
}
if
v
:=
jsonconf
.
Strings
(
"testnames"
);
len
(
v
)
!=
2
{
t
.
Fatal
(
"testnames length should be 2"
)
}
if
v
,
err
:=
jsonconf
.
Bool
(
"autorender"
);
err
!=
nil
||
v
!=
false
{
t
.
Error
(
v
)
t
.
Fatal
(
err
)
}
if
v
,
err
:=
jsonconf
.
Bool
(
"copyrequestbody"
);
err
!=
nil
||
v
!=
true
{
t
.
Error
(
v
)
t
.
Fatal
(
err
)
for
k
,
v
:=
range
keyValue
{
var
err
error
var
value
interface
{}
switch
v
.
(
type
)
{
case
int
:
value
,
err
=
jsonconf
.
Int
(
k
)
case
int64
:
value
,
err
=
jsonconf
.
Int64
(
k
)
case
float64
:
value
,
err
=
jsonconf
.
Float
(
k
)
case
bool
:
value
,
err
=
jsonconf
.
Bool
(
k
)
case
[]
string
:
value
=
jsonconf
.
Strings
(
k
)
case
string
:
value
=
jsonconf
.
String
(
k
)
default
:
value
,
err
=
jsonconf
.
DIY
(
k
)
}
if
err
!=
nil
{
t
.
Fatalf
(
"get key %q value fatal,%v err %s"
,
k
,
v
,
err
)
}
else
if
fmt
.
Sprintf
(
"%v"
,
v
)
!=
fmt
.
Sprintf
(
"%v"
,
value
)
{
t
.
Fatalf
(
"get key %q value, want %v got %v ."
,
k
,
v
,
value
)
}
}
if
err
=
jsonconf
.
Set
(
"name"
,
"astaxie"
);
err
!=
nil
{
t
.
Fatal
(
err
)
...
...
@@ -143,15 +174,7 @@ func TestJson(t *testing.T) {
if
jsonconf
.
String
(
"name"
)
!=
"astaxie"
{
t
.
Fatal
(
"get name error"
)
}
if
jsonconf
.
String
(
"database::host"
)
!=
"host"
{
t
.
Fatal
(
"get database::host error"
)
}
if
jsonconf
.
String
(
"database::conns::connectioninfo"
)
!=
"info"
{
t
.
Fatal
(
"get database::conns::connectioninfo error"
)
}
if
maxconnection
,
err
:=
jsonconf
.
Int
(
"database::conns::maxconnection"
);
err
!=
nil
||
maxconnection
!=
12
{
t
.
Fatal
(
"get database::conns::maxconnection error"
)
}
if
db
,
err
:=
jsonconf
.
DIY
(
"database"
);
err
!=
nil
{
t
.
Fatal
(
err
)
}
else
if
m
,
ok
:=
db
.
(
map
[
string
]
interface
{});
!
ok
{
...
...
config/xml/xml.go
View file @
c59a029c
...
...
@@ -92,7 +92,10 @@ type ConfigContainer struct {
// Bool returns the boolean value for a given key.
func
(
c
*
ConfigContainer
)
Bool
(
key
string
)
(
bool
,
error
)
{
return
strconv
.
ParseBool
(
c
.
data
[
key
]
.
(
string
))
if
v
,
ok
:=
c
.
data
[
key
];
ok
{
return
config
.
ParseBool
(
v
)
}
return
false
,
fmt
.
Errorf
(
"not exist key: %q"
,
key
)
}
// DefaultBool return the bool value if has no error
...
...
config/yaml/yaml.go
View file @
c59a029c
...
...
@@ -121,10 +121,10 @@ 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
]
.
(
bool
)
;
ok
{
return
v
,
nil
if
v
,
ok
:=
c
.
data
[
key
];
ok
{
return
config
.
ParseBool
(
v
)
}
return
false
,
errors
.
New
(
"not bool value"
)
return
false
,
fmt
.
Errorf
(
"not exist key: %q"
,
key
)
}
// DefaultBool return the bool value if has no error
...
...
hooks.go
View file @
c59a029c
...
...
@@ -68,13 +68,11 @@ func registerSession() error {
}
func
registerTemplate
()
error
{
if
BConfig
.
WebConfig
.
AutoRender
{
if
err
:=
BuildTemplate
(
BConfig
.
WebConfig
.
ViewsPath
);
err
!=
nil
{
if
BConfig
.
RunMode
==
DEV
{
Warn
(
err
)
}
return
err
if
err
:=
BuildTemplate
(
BConfig
.
WebConfig
.
ViewsPath
);
err
!=
nil
{
if
BConfig
.
RunMode
==
DEV
{
Warn
(
err
)
}
return
err
}
return
nil
}
...
...
logs/conn.go
View file @
c59a029c
...
...
@@ -19,6 +19,7 @@ import (
"io"
"log"
"net"
"time"
)
// connWriter implements LoggerInterface.
...
...
@@ -48,7 +49,7 @@ func (c *connWriter) Init(jsonconfig string) error {
// WriteMsg write message in connection.
// if connection is down, try to re-connect.
func
(
c
*
connWriter
)
WriteMsg
(
msg
string
,
level
int
)
error
{
func
(
c
*
connWriter
)
WriteMsg
(
when
time
.
Time
,
msg
string
,
level
int
)
error
{
if
level
>
c
.
Level
{
return
nil
}
...
...
@@ -62,6 +63,9 @@ func (c *connWriter) WriteMsg(msg string, level int) error {
if
c
.
ReconnectOnMsg
{
defer
c
.
innerWriter
.
Close
()
}
msg
=
formatLogTime
(
when
)
+
msg
c
.
lg
.
Println
(
msg
)
return
nil
}
...
...
@@ -94,7 +98,7 @@ func (c *connWriter) connect() error {
}
c
.
innerWriter
=
conn
c
.
lg
=
log
.
New
(
conn
,
""
,
log
.
Ldate
|
log
.
Ltime
)
c
.
lg
=
log
.
New
(
conn
,
""
,
0
)
return
nil
}
...
...
logs/console.go
View file @
c59a029c
...
...
@@ -19,6 +19,7 @@ import (
"log"
"os"
"runtime"
"time"
)
// brush is a color join function
...
...
@@ -34,14 +35,14 @@ func newBrush(color string) brush {
}
var
colors
=
[]
brush
{
newBrush
(
"1;37"
),
// Emergency
white
newBrush
(
"1;36"
),
// Alert
cyan
newBrush
(
"1;35"
),
// Critical magenta
newBrush
(
"1;31"
),
// Error red
newBrush
(
"1;33"
),
// Warning yellow
newBrush
(
"1;32"
),
// Notice
green
newBrush
(
"1;34"
),
// Informational
blue
newBrush
(
"1;34"
),
// Debug blue
newBrush
(
"1;37"
),
// Emergency
white
newBrush
(
"1;36"
),
// Alert
cyan
newBrush
(
"1;35"
),
// Critical
magenta
newBrush
(
"1;31"
),
// Error
red
newBrush
(
"1;33"
),
// Warning
yellow
newBrush
(
"1;32"
),
// Notice
green
newBrush
(
"1;34"
),
// Informational
blue
newBrush
(
"1;34"
),
// Debug
blue
}
// consoleWriter implements LoggerInterface and writes messages to terminal.
...
...
@@ -53,27 +54,28 @@ type consoleWriter struct {
// NewConsole create ConsoleWriter returning as LoggerInterface.
func
NewConsole
()
Logger
{
cw
:=
&
consoleWriter
{
lg
:
log
.
New
(
os
.
Stdout
,
""
,
log
.
Ldate
|
log
.
Ltime
),
lg
:
log
.
New
(
os
.
Stdout
,
""
,
0
),
Level
:
LevelDebug
,
}
return
cw
}
// Init init console logger.
// json
c
onfig like '{"level":LevelTrace}'.
func
(
c
*
consoleWriter
)
Init
(
json
c
onfig
string
)
error
{
if
len
(
json
c
onfig
)
==
0
{
// json
C
onfig like '{"level":LevelTrace}'.
func
(
c
*
consoleWriter
)
Init
(
json
C
onfig
string
)
error
{
if
len
(
json
C
onfig
)
==
0
{
return
nil
}
return
json
.
Unmarshal
([]
byte
(
json
c
onfig
),
c
)
return
json
.
Unmarshal
([]
byte
(
json
C
onfig
),
c
)
}
// WriteMsg write message in console.
func
(
c
*
consoleWriter
)
WriteMsg
(
msg
string
,
level
int
)
error
{
func
(
c
*
consoleWriter
)
WriteMsg
(
when
time
.
Time
,
msg
string
,
level
int
)
error
{
if
level
>
c
.
Level
{
return
nil
}
if
goos
:=
runtime
.
GOOS
;
goos
==
"windows"
{
msg
=
formatLogTime
(
when
)
+
msg
if
runtime
.
GOOS
==
"windows"
{
c
.
lg
.
Println
(
msg
)
return
nil
}
...
...
logs/es/es.go
View file @
c59a029c
...
...
@@ -48,16 +48,16 @@ func (el *esLogger) Init(jsonconfig string) error {
}
// WriteMsg will write the msg and level into es
func
(
el
*
esLogger
)
WriteMsg
(
msg
string
,
level
int
)
error
{
func
(
el
*
esLogger
)
WriteMsg
(
when
time
.
Time
,
msg
string
,
level
int
)
error
{
if
level
>
el
.
Level
{
return
nil
}
t
:=
time
.
Now
()
vals
:=
make
(
map
[
string
]
interface
{})
vals
[
"@timestamp"
]
=
t
.
Format
(
time
.
RFC3339
)
vals
[
"@timestamp"
]
=
when
.
Format
(
time
.
RFC3339
)
vals
[
"@msg"
]
=
msg
d
:=
goes
.
Document
{
Index
:
fmt
.
Sprintf
(
"%04d.%02d.%02d"
,
t
.
Year
(),
t
.
Month
(),
t
.
Day
()),
Index
:
fmt
.
Sprintf
(
"%04d.%02d.%02d"
,
when
.
Year
(),
when
.
Month
(),
when
.
Day
()),
Type
:
"logs"
,
Fields
:
vals
,
}
...
...
logs/file.go
View file @
c59a029c
...
...
@@ -114,59 +114,20 @@ func (w *fileLogWriter) needRotate(size int, day int) bool {
}
// WriteMsg write logger message into file.
func
(
w
*
fileLogWriter
)
WriteMsg
(
msg
string
,
level
int
)
error
{
func
(
w
*
fileLogWriter
)
WriteMsg
(
when
time
.
Time
,
msg
string
,
level
int
)
error
{
if
level
>
w
.
Level
{
return
nil
}
//2016/01/12 21:34:33
now
:=
time
.
Now
()
y
,
mo
,
d
:=
now
.
Date
()
h
,
mi
,
s
:=
now
.
Clock
()
//len(2006/01/02 15:03:04)==19
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
[
4
]
=
'/'
if
mo
>
9
{
buf
[
5
]
=
'1'
buf
[
6
]
=
byte
(
'0'
+
mo
-
9
)
}
else
{
buf
[
5
]
=
'0'
buf
[
6
]
=
byte
(
'0'
+
mo
)
}
buf
[
7
]
=
'/'
t
=
d
/
10
buf
[
8
]
=
byte
(
'0'
+
t
)
buf
[
9
]
=
byte
(
'0'
+
d
-
t
*
10
)
buf
[
10
]
=
' '
t
=
h
/
10
buf
[
11
]
=
byte
(
'0'
+
t
)
buf
[
12
]
=
byte
(
'0'
+
h
-
t
*
10
)
buf
[
13
]
=
':'
t
=
mi
/
10
buf
[
14
]
=
byte
(
'0'
+
t
)
buf
[
15
]
=
byte
(
'0'
+
mi
-
t
*
10
)
buf
[
16
]
=
':'
t
=
s
/
10
buf
[
17
]
=
byte
(
'0'
+
t
)
buf
[
18
]
=
byte
(
'0'
+
s
-
t
*
10
)
buf
[
19
]
=
' '
msg
=
string
(
buf
[
0
:
])
+
msg
+
"
\n
"
msg
=
formatLogTime
(
when
)
+
msg
+
"
\n
"
if
w
.
Rotate
{
d
:=
when
.
Day
()
if
w
.
needRotate
(
len
(
msg
),
d
)
{
w
.
Lock
()
if
w
.
needRotate
(
len
(
msg
),
d
)
{
if
err
:=
w
.
doRotate
();
err
!=
nil
{
if
err
:=
w
.
doRotate
(
when
);
err
!=
nil
{
fmt
.
Fprintf
(
os
.
Stderr
,
"FileLogWriter(%q): %s
\n
"
,
w
.
Filename
,
err
)
}
}
w
.
Unlock
()
}
...
...
@@ -236,7 +197,7 @@ func (w *fileLogWriter) lines() (int, error) {
// DoRotate means it need to write file in new file.
// new file name like xx.2013-01-01.2.log
func
(
w
*
fileLogWriter
)
doRotate
()
error
{
func
(
w
*
fileLogWriter
)
doRotate
(
logTime
time
.
Time
)
error
{
_
,
err
:=
os
.
Lstat
(
w
.
Filename
)
if
err
!=
nil
{
return
err
...
...
@@ -251,7 +212,7 @@ func (w *fileLogWriter) doRotate() error {
suffix
=
".log"
}
for
;
err
==
nil
&&
num
<=
999
;
num
++
{
fName
=
filenameOnly
+
fmt
.
Sprintf
(
".%s.%03d%s"
,
time
.
Now
()
.
Format
(
"2006-01-02"
),
num
,
suffix
)
fName
=
filenameOnly
+
fmt
.
Sprintf
(
".%s.%03d%s"
,
logTime
.
Format
(
"2006-01-02"
),
num
,
suffix
)
_
,
err
=
os
.
Lstat
(
fName
)
}
// return error if the last file checked still existed
...
...
logs/log.go
View file @
c59a029c
...
...
@@ -40,6 +40,7 @@ import (
"runtime"
"strconv"
"sync"
"time"
)
// RFC5424 log message levels.
...
...
@@ -68,7 +69,7 @@ type loggerType func() Logger
// Logger defines the behavior of a log provider.
type
Logger
interface
{
Init
(
config
string
)
error
WriteMsg
(
msg
string
,
level
int
)
error
WriteMsg
(
when
time
.
Time
,
msg
string
,
level
int
)
error
Destroy
()
Flush
()
}
...
...
@@ -108,6 +109,7 @@ type nameLogger struct {
type
logMsg
struct
{
level
int
msg
string
when
time
.
Time
}
var
logMsgPool
*
sync
.
Pool
...
...
@@ -173,9 +175,9 @@ func (bl *BeeLogger) DelLogger(adapterName string) error {
return
nil
}
func
(
bl
*
BeeLogger
)
writeToLoggers
(
msg
string
,
level
int
)
{
func
(
bl
*
BeeLogger
)
writeToLoggers
(
when
time
.
Time
,
msg
string
,
level
int
)
{
for
_
,
l
:=
range
bl
.
outputs
{
err
:=
l
.
WriteMsg
(
msg
,
level
)
err
:=
l
.
WriteMsg
(
when
,
msg
,
level
)
if
err
!=
nil
{
fmt
.
Fprintf
(
os
.
Stderr
,
"unable to WriteMsg to adapter:%v,error:%v
\n
"
,
l
.
name
,
err
)
}
...
...
@@ -183,6 +185,7 @@ func (bl *BeeLogger) writeToLoggers(msg string, level int) {
}
func
(
bl
*
BeeLogger
)
writeMsg
(
logLevel
int
,
msg
string
)
error
{
when
:=
time
.
Now
()
if
bl
.
enableFuncCallDepth
{
_
,
file
,
line
,
ok
:=
runtime
.
Caller
(
bl
.
loggerFuncCallDepth
)
if
!
ok
{
...
...
@@ -196,9 +199,10 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string) error {
lm
:=
logMsgPool
.
Get
()
.
(
*
logMsg
)
lm
.
level
=
logLevel
lm
.
msg
=
msg
lm
.
when
=
when
bl
.
msgChan
<-
lm
}
else
{
bl
.
writeToLoggers
(
msg
,
logLevel
)
bl
.
writeToLoggers
(
when
,
msg
,
logLevel
)
}
return
nil
}
...
...
@@ -231,7 +235,7 @@ func (bl *BeeLogger) startLogger() {
for
{
select
{
case
bm
:=
<-
bl
.
msgChan
:
bl
.
writeToLoggers
(
bm
.
msg
,
bm
.
level
)
bl
.
writeToLoggers
(
bm
.
when
,
bm
.
msg
,
bm
.
level
)
logMsgPool
.
Put
(
bm
)
}
}
...
...
@@ -351,7 +355,7 @@ func (bl *BeeLogger) Close() {
for
{
if
len
(
bl
.
msgChan
)
>
0
{
bm
:=
<-
bl
.
msgChan
bl
.
writeToLoggers
(
bm
.
msg
,
bm
.
level
)
bl
.
writeToLoggers
(
bm
.
when
,
bm
.
msg
,
bm
.
level
)
logMsgPool
.
Put
(
bm
)
continue
}
...
...
@@ -363,3 +367,45 @@ func (bl *BeeLogger) Close() {
}
bl
.
outputs
=
nil
}
func
formatLogTime
(
when
time
.
Time
)
string
{
y
,
mo
,
d
:=
when
.
Date
()
h
,
mi
,
s
:=
when
.
Clock
()
//len(2006/01/02 15:03:04)==19
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
[
4
]
=
'/'
if
mo
>
9
{
buf
[
5
]
=
'1'
buf
[
6
]
=
byte
(
'0'
+
mo
-
9
)
}
else
{
buf
[
5
]
=
'0'
buf
[
6
]
=
byte
(
'0'
+
mo
)
}
buf
[
7
]
=
'/'
t
=
d
/
10
buf
[
8
]
=
byte
(
'0'
+
t
)
buf
[
9
]
=
byte
(
'0'
+
d
-
t
*
10
)
buf
[
10
]
=
' '
t
=
h
/
10
buf
[
11
]
=
byte
(
'0'
+
t
)
buf
[
12
]
=
byte
(
'0'
+
h
-
t
*
10
)
buf
[
13
]
=
':'
t
=
mi
/
10
buf
[
14
]
=
byte
(
'0'
+
t
)
buf
[
15
]
=
byte
(
'0'
+
mi
-
t
*
10
)
buf
[
16
]
=
':'
t
=
s
/
10
buf
[
17
]
=
byte
(
'0'
+
t
)
buf
[
18
]
=
byte
(
'0'
+
s
-
t
*
10
)
buf
[
19
]
=
' '
return
string
(
buf
[
0
:
])
}
logs/smtp.go
View file @
c59a029c
...
...
@@ -126,7 +126,7 @@ func (s *SMTPWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAd
// WriteMsg write message in smtp writer.
// it will send an email with subject and only this message.
func
(
s
*
SMTPWriter
)
WriteMsg
(
msg
string
,
level
int
)
error
{
func
(
s
*
SMTPWriter
)
WriteMsg
(
when
time
.
Time
,
msg
string
,
level
int
)
error
{
if
level
>
s
.
Level
{
return
nil
}
...
...
@@ -140,7 +140,7 @@ func (s *SMTPWriter) WriteMsg(msg string, level int) error {
// and send the email all in one step.
contentType
:=
"Content-Type: text/plain"
+
"; charset=UTF-8"
mailmsg
:=
[]
byte
(
"To: "
+
strings
.
Join
(
s
.
RecipientAddresses
,
";"
)
+
"
\r\n
From: "
+
s
.
FromAddress
+
"<"
+
s
.
FromAddress
+
">
\r\n
Subject: "
+
s
.
Subject
+
"
\r\n
"
+
contentType
+
"
\r\n\r\n
"
+
fmt
.
Sprintf
(
".%s"
,
time
.
Now
()
.
Format
(
"2006-01-02 15:04:05"
))
+
msg
)
">
\r\n
Subject: "
+
s
.
Subject
+
"
\r\n
"
+
contentType
+
"
\r\n\r\n
"
+
fmt
.
Sprintf
(
".%s"
,
when
.
Format
(
"2006-01-02 15:04:05"
))
+
msg
)
return
s
.
sendMail
(
s
.
Host
,
auth
,
s
.
FromAddress
,
s
.
RecipientAddresses
,
mailmsg
)
}
...
...
orm/types.go
View file @
c59a029c
...
...
@@ -162,6 +162,12 @@ type QuerySeter interface {
// qs.RelatedSel("profile").One(&user)
// user.Profile.Age = 32
RelatedSel
(
params
...
interface
{})
QuerySeter
// Set Distinct
// for example:
// o.QueryTable("policy").Filter("Groups__Group__Users__User", user).
// Distinct().
// All(&permissions)
Distinct
()
QuerySeter
// return QuerySeter execution result number
// for example:
// num, err = qs.Filter("profile__age__gt", 28).Count()
...
...
parser.go
View file @
c59a029c
...
...
@@ -130,7 +130,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
}
func
genRouterCode
()
{
os
.
Mkdir
(
"routers"
,
0755
)
os
.
Mkdir
(
path
.
Join
(
AppPath
,
"routers"
)
,
0755
)
Info
(
"generate router from comments"
)
var
(
globalinfo
string
...
...
@@ -172,7 +172,7 @@ func genRouterCode() {
}
}
if
globalinfo
!=
""
{
f
,
err
:=
os
.
Create
(
path
.
Join
(
"routers"
,
commentFilename
))
f
,
err
:=
os
.
Create
(
path
.
Join
(
AppPath
,
"routers"
,
commentFilename
))
if
err
!=
nil
{
panic
(
err
)
}
...
...
@@ -182,7 +182,7 @@ func genRouterCode() {
}
func
compareFile
(
pkgRealpath
string
)
bool
{
if
!
utils
.
FileExists
(
path
.
Join
(
"routers"
,
commentFilename
))
{
if
!
utils
.
FileExists
(
path
.
Join
(
AppPath
,
"routers"
,
commentFilename
))
{
return
true
}
if
utils
.
FileExists
(
lastupdateFilename
)
{
...
...
plugins/cors/cors.go
View file @
c59a029c
...
...
@@ -36,6 +36,7 @@
package
cors
import
(
"net/http"
"regexp"
"strconv"
"strings"
...
...
@@ -215,6 +216,7 @@ func Allow(opts *Options) beego.FilterFunc {
for
key
,
value
:=
range
headers
{
ctx
.
Output
.
Header
(
key
,
value
)
}
ctx
.
ResponseWriter
.
WriteHeader
(
http
.
StatusOK
)
return
}
headers
=
opts
.
Header
(
origin
)
...
...
tree.go
View file @
c59a029c
...
...
@@ -141,7 +141,7 @@ func (t *Tree) addtree(segments []string, tree *Tree, wildcards []string, reg st
regexpStr
=
"([^.]+).(.+)"
params
=
params
[
1
:
]
}
else
{
for
range
params
{
for
_
=
range
params
{
regexpStr
=
"([^/]+)/"
+
regexpStr
}
}
...
...
@@ -254,7 +254,7 @@ func (t *Tree) addseg(segments []string, route interface{}, wildcards []string,
regexpStr
=
"/([^.]+).(.+)"
params
=
params
[
1
:
]
}
else
{
for
range
params
{
for
_
=
range
params
{
regexpStr
=
"/([^/]+)"
+
regexpStr
}
}
...
...
@@ -420,7 +420,11 @@ func (leaf *leafInfo) match(wildcardValues []string, ctx *context.Context) (ok b
if
len
(
strs
)
==
2
{
ctx
.
Input
.
SetParam
(
":ext"
,
strs
[
1
])
}
ctx
.
Input
.
SetParam
(
":path"
,
path
.
Join
(
path
.
Join
(
wildcardValues
[
index
:
len
(
wildcardValues
)
-
1
]
...
),
strs
[
0
]))
if
index
>
(
len
(
wildcardValues
)
-
1
)
{
ctx
.
Input
.
SetParam
(
":path"
,
""
)
}
else
{
ctx
.
Input
.
SetParam
(
":path"
,
path
.
Join
(
path
.
Join
(
wildcardValues
[
index
:
len
(
wildcardValues
)
-
1
]
...
),
strs
[
0
]))
}
return
true
}
// match :id
...
...
@@ -438,7 +442,9 @@ func (leaf *leafInfo) match(wildcardValues []string, ctx *context.Context) (ok b
}
matches
:=
leaf
.
regexps
.
FindStringSubmatch
(
path
.
Join
(
wildcardValues
...
))
for
i
,
match
:=
range
matches
[
1
:
]
{
ctx
.
Input
.
SetParam
(
leaf
.
wildcards
[
i
],
match
)
if
i
<
len
(
leaf
.
wildcards
)
{
ctx
.
Input
.
SetParam
(
leaf
.
wildcards
[
i
],
match
)
}
}
return
true
}
...
...
@@ -536,13 +542,19 @@ func splitSegment(key string) (bool, []string, string) {
continue
}
}
if
v
==
':'
{
// Escape Sequence '\'
if
i
>
0
&&
key
[
i
-
1
]
==
'\\'
{
out
=
append
(
out
,
v
)
}
else
if
v
==
':'
{
param
=
make
([]
rune
,
0
)
start
=
true
}
else
if
v
==
'('
{
startexp
=
true
start
=
false
params
=
append
(
params
,
":"
+
string
(
param
))
if
len
(
param
)
>
0
{
params
=
append
(
params
,
":"
+
string
(
param
))
param
=
make
([]
rune
,
0
)
}
paramsNum
++
expt
=
make
([]
rune
,
0
)
expt
=
append
(
expt
,
'('
)
...
...
tree_test.go
View file @
c59a029c
...
...
@@ -15,6 +15,7 @@
package
beego
import
(
"strings"
"testing"
"github.com/astaxie/beego/context"
...
...
@@ -57,6 +58,9 @@ func init() {
"/dl/48/48/05ac66d9bda00a3acf948c43e306fc9a.jpg"
,
map
[
string
]
string
{
":width"
:
"48"
,
":height"
:
"48"
,
":ext"
:
"jpg"
,
":path"
:
"05ac66d9bda00a3acf948c43e306fc9a"
}})
routers
=
append
(
routers
,
testinfo
{
"/v1/shop/:id:int"
,
"/v1/shop/123"
,
map
[
string
]
string
{
":id"
:
"123"
}})
routers
=
append
(
routers
,
testinfo
{
"/v1/shop/:id
\\
((a|b|c)
\\
)"
,
"/v1/shop/123(a)"
,
map
[
string
]
string
{
":id"
:
"123"
}})
routers
=
append
(
routers
,
testinfo
{
"/v1/shop/:id
\\
((a|b|c)
\\
)"
,
"/v1/shop/123(b)"
,
map
[
string
]
string
{
":id"
:
"123"
}})
routers
=
append
(
routers
,
testinfo
{
"/v1/shop/:id
\\
((a|b|c)
\\
)"
,
"/v1/shop/123(c)"
,
map
[
string
]
string
{
":id"
:
"123"
}})
routers
=
append
(
routers
,
testinfo
{
"/:year:int/:month:int/:id/:endid"
,
"/1111/111/aaa/aaa"
,
map
[
string
]
string
{
":year"
:
"1111"
,
":month"
:
"111"
,
":id"
:
"aaa"
,
":endid"
:
"aaa"
}})
routers
=
append
(
routers
,
testinfo
{
"/v1/shop/:id/:name"
,
"/v1/shop/123/nike"
,
map
[
string
]
string
{
":id"
:
"123"
,
":name"
:
"nike"
}})
routers
=
append
(
routers
,
testinfo
{
"/v1/shop/:id/account"
,
"/v1/shop/123/account"
,
map
[
string
]
string
{
":id"
:
"123"
}})
...
...
@@ -245,48 +249,31 @@ func TestSplitPath(t *testing.T) {
}
func
TestSplitSegment
(
t
*
testing
.
T
)
{
b
,
w
,
r
:=
splitSegment
(
"admin"
)
if
b
||
len
(
w
)
!=
0
||
r
!=
""
{
t
.
Fatal
(
"admin should return false, nil, ''"
)
}
b
,
w
,
r
=
splitSegment
(
"*"
)
if
!
b
||
len
(
w
)
!=
1
||
w
[
0
]
!=
":splat"
||
r
!=
""
{
t
.
Fatal
(
"* should return true, [:splat], ''"
)
}
b
,
w
,
r
=
splitSegment
(
"*.*"
)
if
!
b
||
len
(
w
)
!=
3
||
w
[
1
]
!=
":path"
||
w
[
2
]
!=
":ext"
||
w
[
0
]
!=
"."
||
r
!=
""
{
t
.
Fatal
(
"admin should return true,[. :path :ext], ''"
)
}
b
,
w
,
r
=
splitSegment
(
":id"
)
if
!
b
||
len
(
w
)
!=
1
||
w
[
0
]
!=
":id"
||
r
!=
""
{
t
.
Fatal
(
":id should return true, [:id], ''"
)
}
b
,
w
,
r
=
splitSegment
(
"?:id"
)
if
!
b
||
len
(
w
)
!=
2
||
w
[
0
]
!=
":"
||
w
[
1
]
!=
":id"
||
r
!=
""
{
t
.
Fatal
(
"?:id should return true, [: :id], ''"
)
}
b
,
w
,
r
=
splitSegment
(
":id:int"
)
if
!
b
||
len
(
w
)
!=
1
||
w
[
0
]
!=
":id"
||
r
!=
"([0-9]+)"
{
t
.
Fatal
(
":id:int should return true, [:id], '([0-9]+)'"
)
}
b
,
w
,
r
=
splitSegment
(
":name:string"
)
if
!
b
||
len
(
w
)
!=
1
||
w
[
0
]
!=
":name"
||
r
!=
`([\w]+)`
{
t
.
Fatal
(
`:name:string should return true, [:name], '([\w]+)'`
)
}
b
,
w
,
r
=
splitSegment
(
":id([0-9]+)"
)
if
!
b
||
len
(
w
)
!=
1
||
w
[
0
]
!=
":id"
||
r
!=
`([0-9]+)`
{
t
.
Fatal
(
`:id([0-9]+) should return true, [:id], '([0-9]+)'`
)
}
b
,
w
,
r
=
splitSegment
(
":id([0-9]+)_:name"
)
if
!
b
||
len
(
w
)
!=
2
||
w
[
0
]
!=
":id"
||
w
[
1
]
!=
":name"
||
r
!=
`([0-9]+)_(.+)`
{
t
.
Fatal
(
`:id([0-9]+)_:name should return true, [:id :name], '([0-9]+)_(.+)'`
)
}
b
,
w
,
r
=
splitSegment
(
":id(.+)_cms.html"
)
if
!
b
||
len
(
w
)
!=
1
||
w
[
0
]
!=
":id"
||
r
!=
`(.+)_cms.html`
{
t
.
Fatal
(
":id_cms.html should return true, [:id], '(.+)_cms.html'"
)
items
:=
map
[
string
]
struct
{
isReg
bool
params
[]
string
regStr
string
}{
"admin"
:
{
false
,
nil
,
""
},
"*"
:
{
true
,
[]
string
{
":splat"
},
""
},
"*.*"
:
{
true
,
[]
string
{
"."
,
":path"
,
":ext"
},
""
},
":id"
:
{
true
,
[]
string
{
":id"
},
""
},
"?:id"
:
{
true
,
[]
string
{
":"
,
":id"
},
""
},
":id:int"
:
{
true
,
[]
string
{
":id"
},
"([0-9]+)"
},
":name:string"
:
{
true
,
[]
string
{
":name"
},
`([\w]+)`
},
":id([0-9]+)"
:
{
true
,
[]
string
{
":id"
},
`([0-9]+)`
},
":id([0-9]+)_:name"
:
{
true
,
[]
string
{
":id"
,
":name"
},
`([0-9]+)_(.+)`
},
":id(.+)_cms.html"
:
{
true
,
[]
string
{
":id"
},
`(.+)_cms.html`
},
"cms_:id(.+)_:page(.+).html"
:
{
true
,
[]
string
{
":id"
,
":page"
},
`cms_(.+)_(.+).html`
},
`:app(a|b|c)`
:
{
true
,
[]
string
{
":app"
},
`(a|b|c)`
},
`:app\((a|b|c)\)`
:
{
true
,
[]
string
{
":app"
},
`(.+)\((a|b|c)\)`
},
}
b
,
w
,
r
=
splitSegment
(
"cms_:id(.+)_:page(.+).html"
)
if
!
b
||
len
(
w
)
!=
2
||
w
[
0
]
!=
":id"
||
w
[
1
]
!=
":page"
||
r
!=
`cms_(.+)_(.+).html`
{
t
.
Fatal
(
":id_cms.html should return true, [:id :page], cms_(.+)_(.+).html"
)
for
pattern
,
v
:=
range
items
{
b
,
w
,
r
:=
splitSegment
(
pattern
)
if
b
!=
v
.
isReg
||
r
!=
v
.
regStr
||
strings
.
Join
(
w
,
","
)
!=
strings
.
Join
(
v
.
params
,
","
)
{
t
.
Fatalf
(
"%s should return %t,%s,%q, got %t,%s,%q"
,
pattern
,
v
.
isReg
,
v
.
params
,
v
.
regStr
,
b
,
w
,
r
)
}
}
}
utils/mail.go
View file @
c59a029c
...
...
@@ -31,10 +31,13 @@ import (
"path/filepath"
"strconv"
"strings"
"sync"
)
const
(
maxLineLength
=
76
upperhex
=
"0123456789ABCDEF"
)
// Email is the type used for email messages
...
...
@@ -74,9 +77,6 @@ func NewEMail(config string) *Email {
if
err
!=
nil
{
return
nil
}
if
e
.
From
==
""
{
e
.
From
=
e
.
Username
}
return
e
}
...
...
@@ -228,14 +228,21 @@ func (e *Email) Send() error {
to
:=
make
([]
string
,
0
,
len
(
e
.
To
)
+
len
(
e
.
Cc
)
+
len
(
e
.
Bcc
))
to
=
append
(
append
(
append
(
to
,
e
.
To
...
),
e
.
Cc
...
),
e
.
Bcc
...
)
// Check to make sure there is at least one recipient and one "From" address
if
e
.
From
==
""
||
len
(
to
)
==
0
{
return
errors
.
New
(
"Must specify at least one
From address and one
To address"
)
if
len
(
to
)
==
0
{
return
errors
.
New
(
"Must specify at least one To address"
)
}
from
,
err
:=
mail
.
ParseAddress
(
e
.
From
)
from
,
err
:=
mail
.
ParseAddress
(
e
.
Username
)
if
err
!=
nil
{
return
err
}
e
.
From
=
from
.
String
()
if
len
(
e
.
From
)
==
0
{
e
.
From
=
e
.
Username
}
// use mail's RFC 2047 to encode any string
e
.
Subject
=
qEncode
(
"utf-8"
,
e
.
Subject
)
raw
,
err
:=
e
.
Bytes
()
if
err
!=
nil
{
return
err
...
...
@@ -342,3 +349,73 @@ func base64Wrap(w io.Writer, b []byte) {
w
.
Write
(
out
)
}
}
// Encode returns the encoded-word form of s. If s is ASCII without special
// characters, it is returned unchanged. The provided charset is the IANA
// charset name of s. It is case insensitive.
// RFC 2047 encoded-word
func
qEncode
(
charset
,
s
string
)
string
{
if
!
needsEncoding
(
s
)
{
return
s
}
return
encodeWord
(
charset
,
s
)
}
func
needsEncoding
(
s
string
)
bool
{
for
_
,
b
:=
range
s
{
if
(
b
<
' '
||
b
>
'~'
)
&&
b
!=
'\t'
{
return
true
}
}
return
false
}
// encodeWord encodes a string into an encoded-word.
func
encodeWord
(
charset
,
s
string
)
string
{
buf
:=
getBuffer
()
buf
.
WriteString
(
"=?"
)
buf
.
WriteString
(
charset
)
buf
.
WriteByte
(
'?'
)
buf
.
WriteByte
(
'q'
)
buf
.
WriteByte
(
'?'
)
enc
:=
make
([]
byte
,
3
)
for
i
:=
0
;
i
<
len
(
s
);
i
++
{
b
:=
s
[
i
]
switch
{
case
b
==
' '
:
buf
.
WriteByte
(
'_'
)
case
b
<=
'~'
&&
b
>=
'!'
&&
b
!=
'='
&&
b
!=
'?'
&&
b
!=
'_'
:
buf
.
WriteByte
(
b
)
default
:
enc
[
0
]
=
'='
enc
[
1
]
=
upperhex
[
b
>>
4
]
enc
[
2
]
=
upperhex
[
b
&
0x0f
]
buf
.
Write
(
enc
)
}
}
buf
.
WriteString
(
"?="
)
es
:=
buf
.
String
()
putBuffer
(
buf
)
return
es
}
var
bufPool
=
sync
.
Pool
{
New
:
func
()
interface
{}
{
return
new
(
bytes
.
Buffer
)
},
}
func
getBuffer
()
*
bytes
.
Buffer
{
return
bufPool
.
Get
()
.
(
*
bytes
.
Buffer
)
}
func
putBuffer
(
buf
*
bytes
.
Buffer
)
{
if
buf
.
Len
()
>
1024
{
return
}
buf
.
Reset
()
bufPool
.
Put
(
buf
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment