├── testdata
├── sample_file.txt
├── SaveFile.txt
├── statDir
│ ├── sample_file.txt
│ ├── SaveFile.txt
│ ├── SaveFileS.txt
│ └── secondLevel
│ │ ├── sample_file.txt
│ │ ├── SaveFile.txt
│ │ └── SaveFileS.txt
└── SaveFileS.txt
├── .travis.yml
├── go.mod
├── .gitignore
├── go.sum
├── math.go
├── README.md
├── html_test.go
├── url.go
├── math_test.go
├── convert_test.go
├── dir_test.go
├── file_test.go
├── path_test.go
├── html.go
├── regex.go
├── regex_test.go
├── slice.go
├── path.go
├── slice_test.go
├── http_test.go
├── file.go
├── time.go
├── convert.go
├── string_test.go
├── cmd_test.go
├── cmd.go
├── http.go
├── string.go
├── dir.go
├── example_test.go
└── LICENSE
/testdata/sample_file.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/testdata/SaveFile.txt:
--------------------------------------------------------------------------------
1 | TestSaveFile
--------------------------------------------------------------------------------
/testdata/statDir/sample_file.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/testdata/SaveFileS.txt:
--------------------------------------------------------------------------------
1 | TestSaveFileS
--------------------------------------------------------------------------------
/testdata/statDir/SaveFile.txt:
--------------------------------------------------------------------------------
1 | TestSaveFile
--------------------------------------------------------------------------------
/testdata/statDir/SaveFileS.txt:
--------------------------------------------------------------------------------
1 | TestSaveFileS
--------------------------------------------------------------------------------
/testdata/statDir/secondLevel/sample_file.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/testdata/statDir/secondLevel/SaveFile.txt:
--------------------------------------------------------------------------------
1 | TestSaveFile
--------------------------------------------------------------------------------
/testdata/statDir/secondLevel/SaveFileS.txt:
--------------------------------------------------------------------------------
1 | TestSaveFileS
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 |
3 | go:
4 | - 1.3.x
5 | - 1.4.x
6 | - 1.5.x
7 | - 1.6.x
8 | - 1.7.x
9 | - 1.8.x
10 | - 1.9.x
11 | - 1.10.x
12 | - 1.11.x
13 | - 1.12.x
14 |
15 | install: go get -v -t
16 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/unknwon/com
2 |
3 | require (
4 | github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect
5 | github.com/jtolds/gls v4.2.1+incompatible // indirect
6 | github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 // indirect
7 | github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c
8 | )
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files, Static and Dynamic libs (Shared Objects)
2 | *.o
3 | *.a
4 | *.so
5 |
6 | # Folders
7 | _obj
8 | _test
9 | .idea
10 |
11 | # Architecture specific extensions/prefixes
12 | *.[568vq]
13 | [568vq].out
14 |
15 | *.cgo1.go
16 | *.cgo2.c
17 | _cgo_defun.c
18 | _cgo_gotypes.go
19 | _cgo_export.*
20 |
21 | _testmain.go
22 |
23 | *.exe
24 | *.iml
25 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg=
2 | github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
3 | github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE=
4 | github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
5 | github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY=
6 | github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
7 | github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w=
8 | github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
9 |
--------------------------------------------------------------------------------
/math.go:
--------------------------------------------------------------------------------
1 | // Copyright 2014 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | // PowInt is int type of math.Pow function.
18 | func PowInt(x int, y int) int {
19 | if y <= 0 {
20 | return 1
21 | } else {
22 | if y%2 == 0 {
23 | sqrt := PowInt(x, y/2)
24 | return sqrt * sqrt
25 | } else {
26 | return PowInt(x, y-1) * x
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Common Functions
2 | ================
3 |
4 | [](https://travis-ci.org/unknwon/com) [](http://gowalker.org/github.com/unknwon/com)
5 |
6 | This is an open source project for commonly used functions for the Go programming language.
7 |
8 | This package need >= **go 1.3**
9 |
10 | Code Convention: based on [Go Code Convention](https://github.com/unknwon/go-code-convention).
11 |
12 | ## Contribute
13 |
14 | Your contribute is welcome, but you have to check following steps after you added some functions and commit them:
15 |
16 | 1. Make sure you wrote user-friendly comments for **all functions** .
17 | 2. Make sure you wrote test cases with any possible condition for **all functions** in file `*_test.go`.
18 | 3. Make sure you wrote benchmarks for **all functions** in file `*_test.go`.
19 | 4. Make sure you wrote useful examples for **all functions** in file `example_test.go`.
20 | 5. Make sure you ran `go test` and got **PASS** .
21 |
--------------------------------------------------------------------------------
/html_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "testing"
19 | )
20 |
21 | func TestHtml2JS(t *testing.T) {
22 | htm := "
Click me
\n\r"
23 | js := string(Html2JS([]byte(htm)))
24 | jsR := `Click me
\n`
25 | if js != jsR {
26 | t.Errorf("Html2JS:\n Expect => %s\n Got => %s\n", jsR, js)
27 | }
28 | }
29 |
30 | func BenchmarkHtml2JS(b *testing.B) {
31 | htm := "Click me
\n\r"
32 | for i := 0; i < b.N; i++ {
33 | Html2JS([]byte(htm))
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/url.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "encoding/base64"
19 | "net/url"
20 | )
21 |
22 | // url encode string, is + not %20
23 | func UrlEncode(str string) string {
24 | return url.QueryEscape(str)
25 | }
26 |
27 | // url decode string
28 | func UrlDecode(str string) (string, error) {
29 | return url.QueryUnescape(str)
30 | }
31 |
32 | // base64 encode
33 | func Base64Encode(str string) string {
34 | return base64.StdEncoding.EncodeToString([]byte(str))
35 | }
36 |
37 | // base64 decode
38 | func Base64Decode(str string) (string, error) {
39 | s, e := base64.StdEncoding.DecodeString(str)
40 | return string(s), e
41 | }
42 |
--------------------------------------------------------------------------------
/math_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "math"
19 | "math/rand"
20 | "testing"
21 |
22 | . "github.com/smartystreets/goconvey/convey"
23 | )
24 |
25 | func Test_Pow(t *testing.T) {
26 | Convey("Power int", t, func() {
27 | for x := 0; x < 10; x++ {
28 | for y := 0; y < 8; y++ {
29 | result := PowInt(x, y)
30 | result_float := math.Pow(float64(x), float64(y))
31 | So(result, ShouldEqual, int(result_float))
32 | }
33 | }
34 | })
35 | }
36 |
37 | func BenchmarkPow(b *testing.B) {
38 | x := rand.Intn(100)
39 | y := rand.Intn(6)
40 | b.ResetTimer()
41 | for n := 0; n < b.N; n++ {
42 | PowInt(x, y)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/convert_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2014 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "testing"
19 |
20 | . "github.com/smartystreets/goconvey/convey"
21 | )
22 |
23 | func TestHexStr2int(t *testing.T) {
24 | Convey("Convert hex format string to decimal", t, func() {
25 | hexDecs := map[string]int{
26 | "1": 1,
27 | "002": 2,
28 | "011": 17,
29 | "0a1": 161,
30 | "35e": 862,
31 | }
32 |
33 | for hex, dec := range hexDecs {
34 | val, err := HexStr2int(hex)
35 | So(err, ShouldBeNil)
36 | So(val, ShouldEqual, dec)
37 | }
38 | })
39 | }
40 |
41 | func TestInt2HexStr(t *testing.T) {
42 | Convey("Convert decimal to hex format string", t, func() {
43 | decHexs := map[int]string{
44 | 1: "1",
45 | 2: "2",
46 | 17: "11",
47 | 161: "a1",
48 | 862: "35e",
49 | }
50 |
51 | for dec, hex := range decHexs {
52 | val := Int2HexStr(dec)
53 | So(val, ShouldEqual, hex)
54 | }
55 | })
56 | }
57 |
--------------------------------------------------------------------------------
/dir_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "os"
19 | "testing"
20 |
21 | . "github.com/smartystreets/goconvey/convey"
22 | )
23 |
24 | func TestIsDir(t *testing.T) {
25 | Convey("Check if given path is a directory", t, func() {
26 | Convey("Pass a file name", func() {
27 | So(IsDir("file.go"), ShouldEqual, false)
28 | })
29 | Convey("Pass a directory name", func() {
30 | So(IsDir("testdata"), ShouldEqual, true)
31 | })
32 | Convey("Pass a invalid path", func() {
33 | So(IsDir("foo"), ShouldEqual, false)
34 | })
35 | })
36 | }
37 |
38 | func TestCopyDir(t *testing.T) {
39 | Convey("Items of two slices should be same", t, func() {
40 | _, err := StatDir("testdata", true)
41 | So(err, ShouldEqual, nil)
42 |
43 | err = CopyDir("testdata", "testdata2")
44 | So(err, ShouldEqual, nil)
45 |
46 | _, err = StatDir("testdata2", true)
47 | os.RemoveAll("testdata2")
48 | So(err, ShouldEqual, nil)
49 | })
50 | }
51 |
52 | func BenchmarkIsDir(b *testing.B) {
53 | for i := 0; i < b.N; i++ {
54 | IsDir("file.go")
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/file_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "testing"
19 |
20 | . "github.com/smartystreets/goconvey/convey"
21 | )
22 |
23 | func TestIsFile(t *testing.T) {
24 | if !IsFile("file.go") {
25 | t.Errorf("IsExist:\n Expect => %v\n Got => %v\n", true, false)
26 | }
27 |
28 | if IsFile("testdata") {
29 | t.Errorf("IsExist:\n Expect => %v\n Got => %v\n", false, true)
30 | }
31 |
32 | if IsFile("files.go") {
33 | t.Errorf("IsExist:\n Expect => %v\n Got => %v\n", false, true)
34 | }
35 | }
36 |
37 | func TestIsExist(t *testing.T) {
38 | Convey("Check if file or directory exists", t, func() {
39 | Convey("Pass a file name that exists", func() {
40 | So(IsExist("file.go"), ShouldEqual, true)
41 | })
42 | Convey("Pass a directory name that exists", func() {
43 | So(IsExist("testdata"), ShouldEqual, true)
44 | })
45 | Convey("Pass a directory name that does not exist", func() {
46 | So(IsExist(".hg"), ShouldEqual, false)
47 | })
48 | })
49 | }
50 |
51 | func BenchmarkIsFile(b *testing.B) {
52 | for i := 0; i < b.N; i++ {
53 | IsFile("file.go")
54 | }
55 | }
56 |
57 | func BenchmarkIsExist(b *testing.B) {
58 | for i := 0; i < b.N; i++ {
59 | IsExist("file.go")
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/path_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "os"
19 | "runtime"
20 | "testing"
21 | )
22 |
23 | func TestGetGOPATHs(t *testing.T) {
24 | var gpsR []string
25 |
26 | if runtime.GOOS != "windows" {
27 | gpsR = []string{"path/to/gopath1", "path/to/gopath2", "path/to/gopath3"}
28 | os.Setenv("GOPATH", "path/to/gopath1:path/to/gopath2:path/to/gopath3")
29 | } else {
30 | gpsR = []string{"path/to/gopath1", "path/to/gopath2", "path/to/gopath3"}
31 | os.Setenv("GOPATH", "path\\to\\gopath1;path\\to\\gopath2;path\\to\\gopath3")
32 | }
33 |
34 | gps := GetGOPATHs()
35 | if !CompareSliceStr(gps, gpsR) {
36 | t.Errorf("GetGOPATHs:\n Expect => %s\n Got => %s\n", gpsR, gps)
37 | }
38 | }
39 |
40 | func TestGetSrcPath(t *testing.T) {
41 |
42 | }
43 |
44 | func TestHomeDir(t *testing.T) {
45 | _, err := HomeDir()
46 | if err != nil {
47 | t.Errorf("HomeDir:\n Expect => %v\n Got => %s\n", nil, err)
48 | }
49 | }
50 |
51 | func BenchmarkGetGOPATHs(b *testing.B) {
52 | for i := 0; i < b.N; i++ {
53 | GetGOPATHs()
54 | }
55 | }
56 |
57 | func BenchmarkGetSrcPath(b *testing.B) {
58 | for i := 0; i < b.N; i++ {
59 | GetSrcPath("github.com/unknwon/com")
60 | }
61 | }
62 |
63 | func BenchmarkHomeDir(b *testing.B) {
64 | for i := 0; i < b.N; i++ {
65 | HomeDir()
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/html.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "html"
19 | "regexp"
20 | "strings"
21 | )
22 |
23 | // Html2JS converts []byte type of HTML content into JS format.
24 | func Html2JS(data []byte) []byte {
25 | s := string(data)
26 | s = strings.Replace(s, `\`, `\\`, -1)
27 | s = strings.Replace(s, "\n", `\n`, -1)
28 | s = strings.Replace(s, "\r", "", -1)
29 | s = strings.Replace(s, "\"", `\"`, -1)
30 | s = strings.Replace(s, "", "<table>", -1)
31 | return []byte(s)
32 | }
33 |
34 | // encode html chars to string
35 | func HtmlEncode(str string) string {
36 | return html.EscapeString(str)
37 | }
38 |
39 | // HtmlDecode decodes string to html chars
40 | func HtmlDecode(str string) string {
41 | return html.UnescapeString(str)
42 | }
43 |
44 | // strip tags in html string
45 | func StripTags(src string) string {
46 | //去除style,script,html tag
47 | re := regexp.MustCompile(`(?s)<(?:style|script)[^<>]*>.*?(?:style|script)>|?[a-z][a-z0-9]*[^<>]*>|`)
48 | src = re.ReplaceAllString(src, "")
49 |
50 | //trim all spaces(2+) into \n
51 | re = regexp.MustCompile(`\s{2,}`)
52 | src = re.ReplaceAllString(src, "\n")
53 |
54 | return strings.TrimSpace(src)
55 | }
56 |
57 | // change \n to
58 | func Nl2br(str string) string {
59 | return strings.Replace(str, "\n", "
", -1)
60 | }
61 |
--------------------------------------------------------------------------------
/regex.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import "regexp"
18 |
19 | const (
20 | regex_email_pattern = `(?i)[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}`
21 | regex_strict_email_pattern = `(?i)[A-Z0-9!#$%&'*+/=?^_{|}~-]+` +
22 | `(?:\.[A-Z0-9!#$%&'*+/=?^_{|}~-]+)*` +
23 | `@(?:[A-Z0-9](?:[A-Z0-9-]*[A-Z0-9])?\.)+` +
24 | `[A-Z0-9](?:[A-Z0-9-]*[A-Z0-9])?`
25 | regex_url_pattern = `(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?`
26 | )
27 |
28 | var (
29 | regex_email *regexp.Regexp
30 | regex_strict_email *regexp.Regexp
31 | regex_url *regexp.Regexp
32 | )
33 |
34 | func init() {
35 | regex_email = regexp.MustCompile(regex_email_pattern)
36 | regex_strict_email = regexp.MustCompile(regex_strict_email_pattern)
37 | regex_url = regexp.MustCompile(regex_url_pattern)
38 | }
39 |
40 | // IsEmail validates string is an email address, if not return false
41 | // basically validation can match 99% cases
42 | func IsEmail(email string) bool {
43 | return regex_email.MatchString(email)
44 | }
45 |
46 | // IsEmailRFC validates string is an email address, if not return false
47 | // this validation omits RFC 2822
48 | func IsEmailRFC(email string) bool {
49 | return regex_strict_email.MatchString(email)
50 | }
51 |
52 | // IsUrl validates string is a url link, if not return false
53 | // simple validation can match 99% cases
54 | func IsUrl(url string) bool {
55 | return regex_url.MatchString(url)
56 | }
57 |
--------------------------------------------------------------------------------
/regex_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "testing"
19 | )
20 |
21 | func TestIsEmail(t *testing.T) {
22 | emails := map[string]bool{
23 | `test@example.com`: true,
24 | `single-character@b.org`: true,
25 | `uncommon_address@test.museum`: true,
26 | `local@sld.UPPER`: true,
27 | `@missing.org`: false,
28 | `missing@.com`: false,
29 | `missing@qq.`: false,
30 | `wrong-ip@127.1.1.1.26`: false,
31 | }
32 | for e, r := range emails {
33 | b := IsEmail(e)
34 | if b != r {
35 | t.Errorf("IsEmail:\n Expect => %v\n Got => %v\n", r, b)
36 | }
37 | }
38 | }
39 |
40 | func TestIsUrl(t *testing.T) {
41 | urls := map[string]bool{
42 | "http://www.example.com": true,
43 | "http://example.com": true,
44 | "http://example.com?user=test&password=test": true,
45 | "http://example.com?user=test#login": true,
46 | "ftp://example.com": true,
47 | "https://example.com": true,
48 | "htp://example.com": false,
49 | "http//example.com": false,
50 | "http://example": true,
51 | }
52 | for u, r := range urls {
53 | b := IsUrl(u)
54 | if b != r {
55 | t.Errorf("IsUrl:\n Expect => %v\n Got => %v\n", r, b)
56 | }
57 | }
58 | }
59 |
60 | func BenchmarkIsEmail(b *testing.B) {
61 | for i := 0; i < b.N; i++ {
62 | IsEmail("test@example.com")
63 | }
64 | }
65 |
66 | func BenchmarkIsUrl(b *testing.B) {
67 | for i := 0; i < b.N; i++ {
68 | IsEmail("http://example.com")
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/slice.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "strings"
19 | )
20 |
21 | // AppendStr appends string to slice with no duplicates.
22 | func AppendStr(strs []string, str string) []string {
23 | for _, s := range strs {
24 | if s == str {
25 | return strs
26 | }
27 | }
28 | return append(strs, str)
29 | }
30 |
31 | // CompareSliceStr compares two 'string' type slices.
32 | // It returns true if elements and order are both the same.
33 | func CompareSliceStr(s1, s2 []string) bool {
34 | if len(s1) != len(s2) {
35 | return false
36 | }
37 |
38 | for i := range s1 {
39 | if s1[i] != s2[i] {
40 | return false
41 | }
42 | }
43 |
44 | return true
45 | }
46 |
47 | // CompareSliceStrU compares two 'string' type slices.
48 | // It returns true if elements are the same, and ignores the order.
49 | func CompareSliceStrU(s1, s2 []string) bool {
50 | if len(s1) != len(s2) {
51 | return false
52 | }
53 |
54 | for i := range s1 {
55 | for j := len(s2) - 1; j >= 0; j-- {
56 | if s1[i] == s2[j] {
57 | s2 = append(s2[:j], s2[j+1:]...)
58 | break
59 | }
60 | }
61 | }
62 | if len(s2) > 0 {
63 | return false
64 | }
65 | return true
66 | }
67 |
68 | // IsSliceContainsStr returns true if the string exists in given slice, ignore case.
69 | func IsSliceContainsStr(sl []string, str string) bool {
70 | str = strings.ToLower(str)
71 | for _, s := range sl {
72 | if strings.ToLower(s) == str {
73 | return true
74 | }
75 | }
76 | return false
77 | }
78 |
79 | // IsSliceContainsInt64 returns true if the int64 exists in given slice.
80 | func IsSliceContainsInt64(sl []int64, i int64) bool {
81 | for _, s := range sl {
82 | if s == i {
83 | return true
84 | }
85 | }
86 | return false
87 | }
88 |
--------------------------------------------------------------------------------
/path.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "errors"
19 | "os"
20 | "path/filepath"
21 | "runtime"
22 | "strings"
23 | )
24 |
25 | // GetGOPATHs returns all paths in GOPATH variable.
26 | func GetGOPATHs() []string {
27 | gopath := os.Getenv("GOPATH")
28 | var paths []string
29 | if runtime.GOOS == "windows" {
30 | gopath = strings.Replace(gopath, "\\", "/", -1)
31 | paths = strings.Split(gopath, ";")
32 | } else {
33 | paths = strings.Split(gopath, ":")
34 | }
35 | return paths
36 | }
37 |
38 | // GetSrcPath returns app. source code path.
39 | // It only works when you have src. folder in GOPATH,
40 | // it returns error not able to locate source folder path.
41 | func GetSrcPath(importPath string) (appPath string, err error) {
42 | paths := GetGOPATHs()
43 | for _, p := range paths {
44 | if IsExist(p + "/src/" + importPath + "/") {
45 | appPath = p + "/src/" + importPath + "/"
46 | break
47 | }
48 | }
49 |
50 | if len(appPath) == 0 {
51 | return "", errors.New("Unable to locate source folder path")
52 | }
53 |
54 | appPath = filepath.Dir(appPath) + "/"
55 | if runtime.GOOS == "windows" {
56 | // Replace all '\' to '/'.
57 | appPath = strings.Replace(appPath, "\\", "/", -1)
58 | }
59 |
60 | return appPath, nil
61 | }
62 |
63 | // HomeDir returns path of '~'(in Linux) on Windows,
64 | // it returns error when the variable does not exist.
65 | func HomeDir() (home string, err error) {
66 | if runtime.GOOS == "windows" {
67 | home = os.Getenv("USERPROFILE")
68 | if len(home) == 0 {
69 | home = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
70 | }
71 | } else {
72 | home = os.Getenv("HOME")
73 | }
74 |
75 | if len(home) == 0 {
76 | return "", errors.New("Cannot specify home directory because it's empty")
77 | }
78 |
79 | return home, nil
80 | }
81 |
--------------------------------------------------------------------------------
/slice_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "fmt"
19 | "testing"
20 |
21 | . "github.com/smartystreets/goconvey/convey"
22 | )
23 |
24 | func TestAppendStr(t *testing.T) {
25 | Convey("Append a string to a slice with no duplicates", t, func() {
26 | s := []string{"a"}
27 |
28 | Convey("Append a string that does not exist in slice", func() {
29 | s = AppendStr(s, "b")
30 | So(len(s), ShouldEqual, 2)
31 | })
32 |
33 | Convey("Append a string that does exist in slice", func() {
34 | s = AppendStr(s, "b")
35 | So(len(s), ShouldEqual, 2)
36 | })
37 | })
38 | }
39 |
40 | func TestCompareSliceStr(t *testing.T) {
41 | Convey("Compares two 'string' type slices with elements and order", t, func() {
42 | Convey("Compare two slices that do have same elements and order", func() {
43 | So(CompareSliceStr(
44 | []string{"1", "2", "3"}, []string{"1", "2", "3"}), ShouldBeTrue)
45 | })
46 |
47 | Convey("Compare two slices that do have same elements but does not have same order", func() {
48 | So(!CompareSliceStr(
49 | []string{"2", "1", "3"}, []string{"1", "2", "3"}), ShouldBeTrue)
50 | })
51 |
52 | Convey("Compare two slices that have different number of elements", func() {
53 | So(!CompareSliceStr(
54 | []string{"2", "1"}, []string{"1", "2", "3"}), ShouldBeTrue)
55 | })
56 | })
57 | }
58 |
59 | func TestCompareSliceStrU(t *testing.T) {
60 | Convey("Compare two 'string' type slices with elements and ignore the order", t, func() {
61 | Convey("Compare two slices that do have same elements and order", func() {
62 | So(CompareSliceStrU(
63 | []string{"1", "2", "3"}, []string{"1", "2", "3"}), ShouldBeTrue)
64 | })
65 |
66 | Convey("Compare two slices that do have same elements but does not have same order", func() {
67 | So(CompareSliceStrU(
68 | []string{"2", "1", "3"}, []string{"1", "2", "3"}), ShouldBeTrue)
69 | })
70 |
71 | Convey("Compare two slices that have different number of elements", func() {
72 | So(!CompareSliceStrU(
73 | []string{"2", "1"}, []string{"1", "2", "3"}), ShouldBeTrue)
74 | })
75 | })
76 | }
77 |
78 | func BenchmarkAppendStr(b *testing.B) {
79 | s := []string{"a"}
80 | for i := 0; i < b.N; i++ {
81 | s = AppendStr(s, fmt.Sprint(b.N%3))
82 | }
83 | }
84 |
85 | func BenchmarkCompareSliceStr(b *testing.B) {
86 | s1 := []string{"1", "2", "3"}
87 | s2 := []string{"1", "2", "3"}
88 | for i := 0; i < b.N; i++ {
89 | CompareSliceStr(s1, s2)
90 | }
91 | }
92 |
93 | func BenchmarkCompareSliceStrU(b *testing.B) {
94 | s1 := []string{"1", "4", "2", "3"}
95 | s2 := []string{"1", "2", "3", "4"}
96 | for i := 0; i < b.N; i++ {
97 | CompareSliceStrU(s1, s2)
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/http_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "io/ioutil"
19 | "net/http"
20 | "strings"
21 | "testing"
22 | )
23 |
24 | var examplePrefix = `
25 |
26 |
27 | Example Domain
28 | `
29 |
30 | func TestHttpGet(t *testing.T) {
31 | // 200.
32 | rc, err := HttpGet(&http.Client{}, "http://example.com", nil)
33 | if err != nil {
34 | t.Fatalf("HttpGet:\n Expect => %v\n Got => %s\n", nil, err)
35 | }
36 | p, err := ioutil.ReadAll(rc)
37 | if err != nil {
38 | t.Errorf("HttpGet:\n Expect => %v\n Got => %s\n", nil, err)
39 | }
40 | s := string(p)
41 | if !strings.HasPrefix(s, examplePrefix) {
42 | t.Errorf("HttpGet:\n Expect => %s\n Got => %s\n", examplePrefix, s)
43 | }
44 | }
45 |
46 | func TestHttpGetBytes(t *testing.T) {
47 | p, err := HttpGetBytes(&http.Client{}, "http://example.com", nil)
48 | if err != nil {
49 | t.Errorf("HttpGetBytes:\n Expect => %v\n Got => %s\n", nil, err)
50 | }
51 | s := string(p)
52 | if !strings.HasPrefix(s, examplePrefix) {
53 | t.Errorf("HttpGet:\n Expect => %s\n Got => %s\n", examplePrefix, s)
54 | }
55 | }
56 |
57 | func TestHttpGetJSON(t *testing.T) {
58 |
59 | }
60 |
61 | type rawFile struct {
62 | name string
63 | rawURL string
64 | data []byte
65 | }
66 |
67 | func (rf *rawFile) Name() string {
68 | return rf.name
69 | }
70 |
71 | func (rf *rawFile) RawUrl() string {
72 | return rf.rawURL
73 | }
74 |
75 | func (rf *rawFile) Data() []byte {
76 | return rf.data
77 | }
78 |
79 | func (rf *rawFile) SetData(p []byte) {
80 | rf.data = p
81 | }
82 |
83 | func TestFetchFiles(t *testing.T) {
84 | files := []RawFile{
85 | &rawFile{rawURL: "http://example.com"},
86 | &rawFile{rawURL: "http://example.com"},
87 | }
88 | err := FetchFiles(&http.Client{}, files, nil)
89 | if err != nil {
90 | t.Errorf("FetchFiles:\n Expect => %v\n Got => %s\n", nil, err)
91 | } else if len(files[0].Data()) != 1270 {
92 | t.Errorf("FetchFiles:\n Expect => %d\n Got => %d\n", 1270, len(files[0].Data()))
93 | } else if len(files[1].Data()) != 1270 {
94 | t.Errorf("FetchFiles:\n Expect => %d\n Got => %d\n", 1270, len(files[1].Data()))
95 | }
96 | }
97 |
98 | func TestFetchFilesCurl(t *testing.T) {
99 | files := []RawFile{
100 | &rawFile{rawURL: "http://example.com"},
101 | &rawFile{rawURL: "http://example.com"},
102 | }
103 | err := FetchFilesCurl(files)
104 | if err != nil {
105 | t.Errorf("FetchFilesCurl:\n Expect => %v\n Got => %s\n", nil, err)
106 | } else if len(files[0].Data()) != 1270 {
107 | t.Errorf("FetchFilesCurl:\n Expect => %d\n Got => %d\n", 1270, len(files[0].Data()))
108 | } else if len(files[1].Data()) != 1270 {
109 | t.Errorf("FetchFilesCurl:\n Expect => %d\n Got => %d\n", 1270, len(files[1].Data()))
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/file.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "fmt"
19 | "io"
20 | "io/ioutil"
21 | "math"
22 | "os"
23 | "path"
24 | )
25 |
26 | // Storage unit constants.
27 | const (
28 | Byte = 1
29 | KByte = Byte * 1024
30 | MByte = KByte * 1024
31 | GByte = MByte * 1024
32 | TByte = GByte * 1024
33 | PByte = TByte * 1024
34 | EByte = PByte * 1024
35 | )
36 |
37 | func logn(n, b float64) float64 {
38 | return math.Log(n) / math.Log(b)
39 | }
40 |
41 | func humanateBytes(s uint64, base float64, sizes []string) string {
42 | if s < 10 {
43 | return fmt.Sprintf("%dB", s)
44 | }
45 | e := math.Floor(logn(float64(s), base))
46 | suffix := sizes[int(e)]
47 | val := float64(s) / math.Pow(base, math.Floor(e))
48 | f := "%.0f"
49 | if val < 10 {
50 | f = "%.1f"
51 | }
52 |
53 | return fmt.Sprintf(f+"%s", val, suffix)
54 | }
55 |
56 | // HumaneFileSize calculates the file size and generate user-friendly string.
57 | func HumaneFileSize(s uint64) string {
58 | sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"}
59 | return humanateBytes(s, 1024, sizes)
60 | }
61 |
62 | // FileMTime returns file modified time and possible error.
63 | func FileMTime(file string) (int64, error) {
64 | f, err := os.Stat(file)
65 | if err != nil {
66 | return 0, err
67 | }
68 | return f.ModTime().Unix(), nil
69 | }
70 |
71 | // FileSize returns file size in bytes and possible error.
72 | func FileSize(file string) (int64, error) {
73 | f, err := os.Stat(file)
74 | if err != nil {
75 | return 0, err
76 | }
77 | return f.Size(), nil
78 | }
79 |
80 | // Copy copies file from source to target path.
81 | func Copy(src, dest string) error {
82 | // Gather file information to set back later.
83 | si, err := os.Lstat(src)
84 | if err != nil {
85 | return err
86 | }
87 |
88 | // Handle symbolic link.
89 | if si.Mode()&os.ModeSymlink != 0 {
90 | target, err := os.Readlink(src)
91 | if err != nil {
92 | return err
93 | }
94 | // NOTE: os.Chmod and os.Chtimes don't recoganize symbolic link,
95 | // which will lead "no such file or directory" error.
96 | return os.Symlink(target, dest)
97 | }
98 |
99 | sr, err := os.Open(src)
100 | if err != nil {
101 | return err
102 | }
103 | defer sr.Close()
104 |
105 | dw, err := os.Create(dest)
106 | if err != nil {
107 | return err
108 | }
109 | defer dw.Close()
110 |
111 | if _, err = io.Copy(dw, sr); err != nil {
112 | return err
113 | }
114 |
115 | // Set back file information.
116 | if err = os.Chtimes(dest, si.ModTime(), si.ModTime()); err != nil {
117 | return err
118 | }
119 | return os.Chmod(dest, si.Mode())
120 | }
121 |
122 | // WriteFile writes data to a file named by filename.
123 | // If the file does not exist, WriteFile creates it
124 | // and its upper level paths.
125 | func WriteFile(filename string, data []byte) error {
126 | os.MkdirAll(path.Dir(filename), os.ModePerm)
127 | return ioutil.WriteFile(filename, data, 0655)
128 | }
129 |
130 | // IsFile returns true if given path is a file,
131 | // or returns false when it's a directory or does not exist.
132 | func IsFile(filePath string) bool {
133 | f, e := os.Stat(filePath)
134 | if e != nil {
135 | return false
136 | }
137 | return !f.IsDir()
138 | }
139 |
140 | // IsExist checks whether a file or directory exists.
141 | // It returns false when the file or directory does not exist.
142 | func IsExist(path string) bool {
143 | _, err := os.Stat(path)
144 | return err == nil || os.IsExist(err)
145 | }
146 |
--------------------------------------------------------------------------------
/time.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "fmt"
19 | "strconv"
20 | "strings"
21 | "time"
22 | )
23 |
24 | // Format unix time int64 to string
25 | func Date(ti int64, format string) string {
26 | t := time.Unix(int64(ti), 0)
27 | return DateT(t, format)
28 | }
29 |
30 | // Format unix time string to string
31 | func DateS(ts string, format string) string {
32 | i, _ := strconv.ParseInt(ts, 10, 64)
33 | return Date(i, format)
34 | }
35 |
36 | // Format time.Time struct to string
37 | // MM - month - 01
38 | // M - month - 1, single bit
39 | // DD - day - 02
40 | // D - day 2
41 | // YYYY - year - 2006
42 | // YY - year - 06
43 | // HH - 24 hours - 03
44 | // H - 24 hours - 3
45 | // hh - 12 hours - 03
46 | // h - 12 hours - 3
47 | // mm - minute - 04
48 | // m - minute - 4
49 | // ss - second - 05
50 | // s - second = 5
51 | func DateT(t time.Time, format string) string {
52 | res := strings.Replace(format, "MM", t.Format("01"), -1)
53 | res = strings.Replace(res, "M", t.Format("1"), -1)
54 | res = strings.Replace(res, "DD", t.Format("02"), -1)
55 | res = strings.Replace(res, "D", t.Format("2"), -1)
56 | res = strings.Replace(res, "YYYY", t.Format("2006"), -1)
57 | res = strings.Replace(res, "YY", t.Format("06"), -1)
58 | res = strings.Replace(res, "HH", fmt.Sprintf("%02d", t.Hour()), -1)
59 | res = strings.Replace(res, "H", fmt.Sprintf("%d", t.Hour()), -1)
60 | res = strings.Replace(res, "hh", t.Format("03"), -1)
61 | res = strings.Replace(res, "h", t.Format("3"), -1)
62 | res = strings.Replace(res, "mm", t.Format("04"), -1)
63 | res = strings.Replace(res, "m", t.Format("4"), -1)
64 | res = strings.Replace(res, "ss", t.Format("05"), -1)
65 | res = strings.Replace(res, "s", t.Format("5"), -1)
66 | return res
67 | }
68 |
69 | // DateFormat pattern rules.
70 | var datePatterns = []string{
71 | // year
72 | "Y", "2006", // A full numeric representation of a year, 4 digits Examples: 1999 or 2003
73 | "y", "06", //A two digit representation of a year Examples: 99 or 03
74 |
75 | // month
76 | "m", "01", // Numeric representation of a month, with leading zeros 01 through 12
77 | "n", "1", // Numeric representation of a month, without leading zeros 1 through 12
78 | "M", "Jan", // A short textual representation of a month, three letters Jan through Dec
79 | "F", "January", // A full textual representation of a month, such as January or March January through December
80 |
81 | // day
82 | "d", "02", // Day of the month, 2 digits with leading zeros 01 to 31
83 | "j", "2", // Day of the month without leading zeros 1 to 31
84 |
85 | // week
86 | "D", "Mon", // A textual representation of a day, three letters Mon through Sun
87 | "l", "Monday", // A full textual representation of the day of the week Sunday through Saturday
88 |
89 | // time
90 | "g", "3", // 12-hour format of an hour without leading zeros 1 through 12
91 | "G", "15", // 24-hour format of an hour without leading zeros 0 through 23
92 | "h", "03", // 12-hour format of an hour with leading zeros 01 through 12
93 | "H", "15", // 24-hour format of an hour with leading zeros 00 through 23
94 |
95 | "a", "pm", // Lowercase Ante meridiem and Post meridiem am or pm
96 | "A", "PM", // Uppercase Ante meridiem and Post meridiem AM or PM
97 |
98 | "i", "04", // Minutes with leading zeros 00 to 59
99 | "s", "05", // Seconds, with leading zeros 00 through 59
100 |
101 | // time zone
102 | "T", "MST",
103 | "P", "-07:00",
104 | "O", "-0700",
105 |
106 | // RFC 2822
107 | "r", time.RFC1123Z,
108 | }
109 |
110 | // Parse Date use PHP time format.
111 | func DateParse(dateString, format string) (time.Time, error) {
112 | replacer := strings.NewReplacer(datePatterns...)
113 | format = replacer.Replace(format)
114 | return time.ParseInLocation(format, dateString, time.Local)
115 | }
116 |
--------------------------------------------------------------------------------
/convert.go:
--------------------------------------------------------------------------------
1 | // Copyright 2014 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "fmt"
19 | "strconv"
20 | )
21 |
22 | // Convert string to specify type.
23 | type StrTo string
24 |
25 | func (f StrTo) Exist() bool {
26 | return string(f) != string(rune(0x1E))
27 | }
28 |
29 | func (f StrTo) Uint8() (uint8, error) {
30 | v, err := strconv.ParseUint(f.String(), 10, 8)
31 | return uint8(v), err
32 | }
33 |
34 | func (f StrTo) Int() (int, error) {
35 | v, err := strconv.ParseInt(f.String(), 10, 0)
36 | return int(v), err
37 | }
38 |
39 | func (f StrTo) Int64() (int64, error) {
40 | v, err := strconv.ParseInt(f.String(), 10, 64)
41 | return int64(v), err
42 | }
43 |
44 | func (f StrTo) Float64() (float64, error) {
45 | v, err := strconv.ParseFloat(f.String(), 64)
46 | return float64(v), err
47 | }
48 |
49 | func (f StrTo) MustUint8() uint8 {
50 | v, _ := f.Uint8()
51 | return v
52 | }
53 |
54 | func (f StrTo) MustInt() int {
55 | v, _ := f.Int()
56 | return v
57 | }
58 |
59 | func (f StrTo) MustInt64() int64 {
60 | v, _ := f.Int64()
61 | return v
62 | }
63 |
64 | func (f StrTo) MustFloat64() float64 {
65 | v, _ := f.Float64()
66 | return v
67 | }
68 |
69 | func (f StrTo) String() string {
70 | if f.Exist() {
71 | return string(f)
72 | }
73 | return ""
74 | }
75 |
76 | // Convert any type to string.
77 | func ToStr(value interface{}, args ...int) (s string) {
78 | switch v := value.(type) {
79 | case bool:
80 | s = strconv.FormatBool(v)
81 | case float32:
82 | s = strconv.FormatFloat(float64(v), 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 32))
83 | case float64:
84 | s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64))
85 | case int:
86 | s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
87 | case int8:
88 | s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
89 | case int16:
90 | s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
91 | case int32:
92 | s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10))
93 | case int64:
94 | s = strconv.FormatInt(v, argInt(args).Get(0, 10))
95 | case uint:
96 | s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
97 | case uint8:
98 | s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
99 | case uint16:
100 | s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
101 | case uint32:
102 | s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10))
103 | case uint64:
104 | s = strconv.FormatUint(v, argInt(args).Get(0, 10))
105 | case string:
106 | s = v
107 | case []byte:
108 | s = string(v)
109 | default:
110 | s = fmt.Sprintf("%v", v)
111 | }
112 | return s
113 | }
114 |
115 | type argInt []int
116 |
117 | func (a argInt) Get(i int, args ...int) (r int) {
118 | if i >= 0 && i < len(a) {
119 | r = a[i]
120 | } else if len(args) > 0 {
121 | r = args[0]
122 | }
123 | return
124 | }
125 |
126 | // HexStr2int converts hex format string to decimal number.
127 | func HexStr2int(hexStr string) (int, error) {
128 | num := 0
129 | length := len(hexStr)
130 | for i := 0; i < length; i++ {
131 | char := hexStr[length-i-1]
132 | factor := -1
133 |
134 | switch {
135 | case char >= '0' && char <= '9':
136 | factor = int(char) - '0'
137 | case char >= 'a' && char <= 'f':
138 | factor = int(char) - 'a' + 10
139 | default:
140 | return -1, fmt.Errorf("invalid hex: %s", string(char))
141 | }
142 |
143 | num += factor * PowInt(16, i)
144 | }
145 | return num, nil
146 | }
147 |
148 | // Int2HexStr converts decimal number to hex format string.
149 | func Int2HexStr(num int) (hex string) {
150 | if num == 0 {
151 | return "0"
152 | }
153 |
154 | for num > 0 {
155 | r := num % 16
156 |
157 | c := "?"
158 | if r >= 0 && r <= 9 {
159 | c = string(rune(r + '0'))
160 | } else {
161 | c = string(rune(r + 'a' - 10))
162 | }
163 | hex = c + hex
164 | num = num / 16
165 | }
166 | return hex
167 | }
168 |
--------------------------------------------------------------------------------
/string_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "bytes"
19 | "crypto/rand"
20 | "testing"
21 |
22 | . "github.com/smartystreets/goconvey/convey"
23 | )
24 |
25 | func TestAESEncrypt(t *testing.T) {
26 | t.Parallel()
27 |
28 | key := make([]byte, 16) // AES-128
29 | _, err := rand.Read(key)
30 | if err != nil {
31 | t.Fatal("Failed to create 128 bit AES key: " + err.Error())
32 | }
33 |
34 | plaintext := []byte("this will be encrypted")
35 |
36 | _, err = AESGCMEncrypt(key, plaintext)
37 | if err != nil {
38 | t.Fatal("Failed to encrypt plaintext: " + err.Error())
39 | }
40 | }
41 |
42 | func TestAESDecrypt(t *testing.T) {
43 | t.Parallel()
44 |
45 | key := make([]byte, 16) // AES-128
46 | _, err := rand.Read(key)
47 | if err != nil {
48 | t.Fatal("Failed to create 128 bit AES key: " + err.Error())
49 | }
50 |
51 | plaintext := []byte("this will be encrypted")
52 |
53 | ciphertext, err := AESGCMEncrypt(key, plaintext)
54 | if err != nil {
55 | t.Fatal("Failed to encrypt plaintext: " + err.Error())
56 | }
57 |
58 | decrypted, err := AESGCMDecrypt(key, ciphertext)
59 | if err != nil {
60 | t.Fatal("Failed to decrypt ciphertext: " + err.Error())
61 | }
62 |
63 | if bytes.Compare(decrypted, plaintext) != 0 {
64 | t.Fatal("Decryption was not performed correctly")
65 | }
66 | }
67 |
68 | func TestIsLetter(t *testing.T) {
69 | if IsLetter('1') {
70 | t.Errorf("IsLetter:\n Expect => %v\n Got => %v\n", false, true)
71 | }
72 |
73 | if IsLetter('[') {
74 | t.Errorf("IsLetter:\n Expect => %v\n Got => %v\n", false, true)
75 | }
76 |
77 | if !IsLetter('a') {
78 | t.Errorf("IsLetter:\n Expect => %v\n Got => %v\n", true, false)
79 | }
80 |
81 | if !IsLetter('Z') {
82 | t.Errorf("IsLetter:\n Expect => %v\n Got => %v\n", true, false)
83 | }
84 | }
85 |
86 | func TestExpand(t *testing.T) {
87 | match := map[string]string{
88 | "domain": "gowalker.org",
89 | "subdomain": "github.com",
90 | }
91 | s := "http://{domain}/{subdomain}/{0}/{1}"
92 | sR := "http://gowalker.org/github.com/unknwon/gowalker"
93 | if Expand(s, match, "unknwon", "gowalker") != sR {
94 | t.Errorf("Expand:\n Expect => %s\n Got => %s\n", sR, s)
95 | }
96 | }
97 |
98 | func TestReverse(t *testing.T) {
99 | if Reverse("abcdefg") != "gfedcba" {
100 | t.Errorf("Reverse:\n Except => %s\n Got =>%s\n", "gfedcba", Reverse("abcdefg"))
101 | }
102 | if Reverse("上善若水厚德载物") != "物载德厚水若善上" {
103 | t.Errorf("Reverse:\n Except => %s\n Got =>%s\n", "物载德厚水若善上", Reverse("上善若水厚德载物"))
104 | }
105 | }
106 |
107 | func Test_ToSnakeCase(t *testing.T) {
108 | cases := map[string]string{
109 | "HTTPServer": "http_server",
110 | "_camelCase": "_camel_case",
111 | "NoHTTPS": "no_https",
112 | "Wi_thF": "wi_th_f",
113 | "_AnotherTES_TCaseP": "_another_tes_t_case_p",
114 | "ALL": "all",
115 | "_HELLO_WORLD_": "_hello_world_",
116 | "HELLO_WORLD": "hello_world",
117 | "HELLO____WORLD": "hello____world",
118 | "TW": "tw",
119 | "_C": "_c",
120 |
121 | " sentence case ": "__sentence_case__",
122 | " Mixed-hyphen case _and SENTENCE_case and UPPER-case": "_mixed_hyphen_case__and_sentence_case_and_upper_case",
123 | }
124 | Convey("Convert string into snake case", t, func() {
125 | for old, new := range cases {
126 | So(ToSnakeCase(old), ShouldEqual, new)
127 | }
128 | })
129 | }
130 |
131 | func BenchmarkIsLetter(b *testing.B) {
132 | for i := 0; i < b.N; i++ {
133 | IsLetter('a')
134 | }
135 | }
136 |
137 | func BenchmarkExpand(b *testing.B) {
138 | match := map[string]string{
139 | "domain": "gowalker.org",
140 | "subdomain": "github.com",
141 | }
142 | s := "http://{domain}/{subdomain}/{0}/{1}"
143 | for i := 0; i < b.N; i++ {
144 | Expand(s, match, "Unknwon", "gowalker")
145 | }
146 | }
147 |
148 | func BenchmarkReverse(b *testing.B) {
149 | s := "abscef中文"
150 | for i := 0; i < b.N; i++ {
151 | Reverse(s)
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/cmd_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "fmt"
19 | "runtime"
20 | "strings"
21 | "testing"
22 | )
23 |
24 | func TestColorLogS(t *testing.T) {
25 | if runtime.GOOS != "windows" {
26 | // Trace + path.
27 | cls := ColorLogS("[TRAC] Trace level test with path( %s )", "/path/to/somethere")
28 | clsR := fmt.Sprintf(
29 | "[\033[%dmTRAC%s] Trace level test with path(\033[%dm%s%s)",
30 | Blue, EndColor, Yellow, "/path/to/somethere", EndColor)
31 | if cls != clsR {
32 | t.Errorf("ColorLogS:\n Expect => %s\n Got => %s\n", clsR, cls)
33 | }
34 |
35 | // Error + error.
36 | cls = ColorLogS("[ERRO] Error level test with error[ %s ]", "test error")
37 | clsR = fmt.Sprintf(
38 | "[\033[%dmERRO%s] Error level test with error[\033[%dm%s%s]",
39 | Red, EndColor, Red, "test error", EndColor)
40 | if cls != clsR {
41 | t.Errorf("ColorLogS:\n Expect => %s\n Got => %s\n", clsR, cls)
42 | }
43 |
44 | // Warning + highlight.
45 | cls = ColorLogS("[WARN] Warnning level test with highlight # %s #", "special offer!")
46 | clsR = fmt.Sprintf(
47 | "[\033[%dmWARN%s] Warnning level test with highlight \033[%dm%s%s",
48 | Magenta, EndColor, Gray, "special offer!", EndColor)
49 | if cls != clsR {
50 | t.Errorf("ColorLogS:\n Expect => %s\n Got => %s\n", clsR, cls)
51 | }
52 |
53 | // Success.
54 | cls = ColorLogS("[SUCC] Success level test")
55 | clsR = fmt.Sprintf(
56 | "[\033[%dmSUCC%s] Success level test",
57 | Green, EndColor)
58 | if cls != clsR {
59 | t.Errorf("ColorLogS:\n Expect => %s\n Got => %s\n", clsR, cls)
60 | }
61 |
62 | // Default.
63 | cls = ColorLogS("[INFO] Default level test")
64 | clsR = fmt.Sprintf(
65 | "[INFO] Default level test")
66 | if cls != clsR {
67 | t.Errorf("ColorLogS:\n Expect => %s\n Got => %s\n", clsR, cls)
68 | }
69 | } else {
70 | // Trace + path.
71 | cls := ColorLogS("[TRAC] Trace level test with path( %s )", "/path/to/somethere")
72 | clsR := fmt.Sprintf(
73 | "[TRAC] Trace level test with path(%s)",
74 | "/path/to/somethere")
75 | if cls != clsR {
76 | t.Errorf("ColorLogS:\n Expect => %s\n Got => %s\n", clsR, cls)
77 | }
78 |
79 | // Error + error.
80 | cls = ColorLogS("[ERRO] Error level test with error[ %s ]", "test error")
81 | clsR = fmt.Sprintf(
82 | "[ERRO] Error level test with error[%s]",
83 | "test error")
84 | if cls != clsR {
85 | t.Errorf("ColorLogS:\n Expect => %s\n Got => %s\n", clsR, cls)
86 | }
87 |
88 | // Warning + highlight.
89 | cls = ColorLogS("[WARN] Warnning level test with highlight # %s #", "special offer!")
90 | clsR = fmt.Sprintf(
91 | "[WARN] Warnning level test with highlight %s",
92 | "special offer!")
93 | if cls != clsR {
94 | t.Errorf("ColorLogS:\n Expect => %s\n Got => %s\n", clsR, cls)
95 | }
96 |
97 | // Success.
98 | cls = ColorLogS("[SUCC] Success level test")
99 | clsR = fmt.Sprintf(
100 | "[SUCC] Success level test")
101 | if cls != clsR {
102 | t.Errorf("ColorLogS:\n Expect => %s\n Got => %s\n", clsR, cls)
103 | }
104 |
105 | // Default.
106 | cls = ColorLogS("[INFO] Default level test")
107 | clsR = fmt.Sprintf(
108 | "[INFO] Default level test")
109 | if cls != clsR {
110 | t.Errorf("ColorLogS:\n Expect => %s\n Got => %s\n", clsR, cls)
111 | }
112 | }
113 | }
114 |
115 | func TestExecCmd(t *testing.T) {
116 | stdout, stderr, err := ExecCmd("go", "help", "get")
117 | if err != nil {
118 | t.Errorf("ExecCmd:\n Expect => %v\n Got => %v\n", nil, err)
119 | } else if len(stderr) != 0 {
120 | t.Errorf("ExecCmd:\n Expect => %s\n Got => %s\n", "", stderr)
121 | } else if !strings.HasPrefix(stdout, "usage: go get") {
122 | t.Errorf("ExecCmd:\n Expect => %s\n Got => %s\n", "usage: go get", stdout)
123 | }
124 | }
125 |
126 | func BenchmarkColorLogS(b *testing.B) {
127 | log := fmt.Sprintf(
128 | "[WARN] This is a tesing log that should be colored, path( %s ),"+
129 | " highlight # %s #, error [ %s ].",
130 | "path to somewhere", "highlighted content", "tesing error")
131 | for i := 0; i < b.N; i++ {
132 | ColorLogS(log)
133 | }
134 | }
135 |
136 | func BenchmarkExecCmd(b *testing.B) {
137 | for i := 0; i < b.N; i++ {
138 | ExecCmd("go", "help", "get")
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/cmd.go:
--------------------------------------------------------------------------------
1 | // +build go1.3
2 |
3 | // Copyright 2013 com authors
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
6 | // not use this file except in compliance with the License. You may obtain
7 | // a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 | // License for the specific language governing permissions and limitations
15 | // under the License.
16 |
17 | // Package com is an open source project for commonly used functions for the Go programming language.
18 | package com
19 |
20 | import (
21 | "bytes"
22 | "fmt"
23 | "os/exec"
24 | "runtime"
25 | "strings"
26 | )
27 |
28 | // ExecCmdDirBytes executes system command in given directory
29 | // and return stdout, stderr in bytes type, along with possible error.
30 | func ExecCmdDirBytes(dir, cmdName string, args ...string) ([]byte, []byte, error) {
31 | bufOut := new(bytes.Buffer)
32 | bufErr := new(bytes.Buffer)
33 |
34 | cmd := exec.Command(cmdName, args...)
35 | cmd.Dir = dir
36 | cmd.Stdout = bufOut
37 | cmd.Stderr = bufErr
38 |
39 | err := cmd.Run()
40 | return bufOut.Bytes(), bufErr.Bytes(), err
41 | }
42 |
43 | // ExecCmdBytes executes system command
44 | // and return stdout, stderr in bytes type, along with possible error.
45 | func ExecCmdBytes(cmdName string, args ...string) ([]byte, []byte, error) {
46 | return ExecCmdDirBytes("", cmdName, args...)
47 | }
48 |
49 | // ExecCmdDir executes system command in given directory
50 | // and return stdout, stderr in string type, along with possible error.
51 | func ExecCmdDir(dir, cmdName string, args ...string) (string, string, error) {
52 | bufOut, bufErr, err := ExecCmdDirBytes(dir, cmdName, args...)
53 | return string(bufOut), string(bufErr), err
54 | }
55 |
56 | // ExecCmd executes system command
57 | // and return stdout, stderr in string type, along with possible error.
58 | func ExecCmd(cmdName string, args ...string) (string, string, error) {
59 | return ExecCmdDir("", cmdName, args...)
60 | }
61 |
62 | // _________ .__ .____
63 | // \_ ___ \ ____ | | ___________ | | ____ ____
64 | // / \ \/ / _ \| | / _ \_ __ \ | | / _ \ / ___\
65 | // \ \___( <_> ) |_( <_> ) | \/ | |__( <_> ) /_/ >
66 | // \______ /\____/|____/\____/|__| |_______ \____/\___ /
67 | // \/ \/ /_____/
68 |
69 | // Color number constants.
70 | const (
71 | Gray = uint8(iota + 90)
72 | Red
73 | Green
74 | Yellow
75 | Blue
76 | Magenta
77 | //NRed = uint8(31) // Normal
78 | EndColor = "\033[0m"
79 | )
80 |
81 | // getColorLevel returns colored level string by given level.
82 | func getColorLevel(level string) string {
83 | level = strings.ToUpper(level)
84 | switch level {
85 | case "TRAC":
86 | return fmt.Sprintf("\033[%dm%s\033[0m", Blue, level)
87 | case "ERRO":
88 | return fmt.Sprintf("\033[%dm%s\033[0m", Red, level)
89 | case "WARN":
90 | return fmt.Sprintf("\033[%dm%s\033[0m", Magenta, level)
91 | case "SUCC":
92 | return fmt.Sprintf("\033[%dm%s\033[0m", Green, level)
93 | default:
94 | return level
95 | }
96 | }
97 |
98 | // ColorLogS colors log and return colored content.
99 | // Log format: [ error ].
100 | // Level: TRAC -> blue; ERRO -> red; WARN -> Magenta; SUCC -> green; others -> default.
101 | // Content: default; path: yellow; error -> red.
102 | // Level has to be surrounded by "[" and "]".
103 | // Highlights have to be surrounded by "# " and " #"(space), "#" will be deleted.
104 | // Paths have to be surrounded by "( " and " )"(space).
105 | // Errors have to be surrounded by "[ " and " ]"(space).
106 | // Note: it hasn't support windows yet, contribute is welcome.
107 | func ColorLogS(format string, a ...interface{}) string {
108 | log := fmt.Sprintf(format, a...)
109 |
110 | var clog string
111 |
112 | if runtime.GOOS != "windows" {
113 | // Level.
114 | i := strings.Index(log, "]")
115 | if log[0] == '[' && i > -1 {
116 | clog += "[" + getColorLevel(log[1:i]) + "]"
117 | }
118 |
119 | log = log[i+1:]
120 |
121 | // Error.
122 | log = strings.Replace(log, "[ ", fmt.Sprintf("[\033[%dm", Red), -1)
123 | log = strings.Replace(log, " ]", EndColor+"]", -1)
124 |
125 | // Path.
126 | log = strings.Replace(log, "( ", fmt.Sprintf("(\033[%dm", Yellow), -1)
127 | log = strings.Replace(log, " )", EndColor+")", -1)
128 |
129 | // Highlights.
130 | log = strings.Replace(log, "# ", fmt.Sprintf("\033[%dm", Gray), -1)
131 | log = strings.Replace(log, " #", EndColor, -1)
132 |
133 | } else {
134 | // Level.
135 | i := strings.Index(log, "]")
136 | if log[0] == '[' && i > -1 {
137 | clog += "[" + log[1:i] + "]"
138 | }
139 |
140 | log = log[i+1:]
141 |
142 | // Error.
143 | log = strings.Replace(log, "[ ", "[", -1)
144 | log = strings.Replace(log, " ]", "]", -1)
145 |
146 | // Path.
147 | log = strings.Replace(log, "( ", "(", -1)
148 | log = strings.Replace(log, " )", ")", -1)
149 |
150 | // Highlights.
151 | log = strings.Replace(log, "# ", "", -1)
152 | log = strings.Replace(log, " #", "", -1)
153 | }
154 | return clog + log
155 | }
156 |
157 | // ColorLog prints colored log to stdout.
158 | // See color rules in function 'ColorLogS'.
159 | func ColorLog(format string, a ...interface{}) {
160 | fmt.Print(ColorLogS(format, a...))
161 | }
162 |
--------------------------------------------------------------------------------
/http.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "bytes"
19 | "encoding/json"
20 | "fmt"
21 | "io"
22 | "io/ioutil"
23 | "net/http"
24 | "os"
25 | "path"
26 | )
27 |
28 | type NotFoundError struct {
29 | Message string
30 | }
31 |
32 | func (e NotFoundError) Error() string {
33 | return e.Message
34 | }
35 |
36 | type RemoteError struct {
37 | Host string
38 | Err error
39 | }
40 |
41 | func (e *RemoteError) Error() string {
42 | return e.Err.Error()
43 | }
44 |
45 | var UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1541.0 Safari/537.36"
46 |
47 | // HttpCall makes HTTP method call.
48 | func HttpCall(client *http.Client, method, url string, header http.Header, body io.Reader) (io.ReadCloser, error) {
49 | req, err := http.NewRequest(method, url, body)
50 | if err != nil {
51 | return nil, err
52 | }
53 | req.Header.Set("User-Agent", UserAgent)
54 | for k, vs := range header {
55 | req.Header[k] = vs
56 | }
57 | resp, err := client.Do(req)
58 | if err != nil {
59 | return nil, err
60 | }
61 | if resp.StatusCode == 200 {
62 | return resp.Body, nil
63 | }
64 | resp.Body.Close()
65 | if resp.StatusCode == 404 { // 403 can be rate limit error. || resp.StatusCode == 403 {
66 | err = fmt.Errorf("resource not found: %s", url)
67 | } else {
68 | err = fmt.Errorf("%s %s -> %d", method, url, resp.StatusCode)
69 | }
70 | return nil, err
71 | }
72 |
73 | // HttpGet gets the specified resource.
74 | // ErrNotFound is returned if the server responds with status 404.
75 | func HttpGet(client *http.Client, url string, header http.Header) (io.ReadCloser, error) {
76 | return HttpCall(client, "GET", url, header, nil)
77 | }
78 |
79 | // HttpPost posts the specified resource.
80 | // ErrNotFound is returned if the server responds with status 404.
81 | func HttpPost(client *http.Client, url string, header http.Header, body []byte) (io.ReadCloser, error) {
82 | return HttpCall(client, "POST", url, header, bytes.NewBuffer(body))
83 | }
84 |
85 | // HttpGetToFile gets the specified resource and writes to file.
86 | // ErrNotFound is returned if the server responds with status 404.
87 | func HttpGetToFile(client *http.Client, url string, header http.Header, fileName string) error {
88 | rc, err := HttpGet(client, url, header)
89 | if err != nil {
90 | return err
91 | }
92 | defer rc.Close()
93 |
94 | os.MkdirAll(path.Dir(fileName), os.ModePerm)
95 | f, err := os.Create(fileName)
96 | if err != nil {
97 | return err
98 | }
99 | defer f.Close()
100 | _, err = io.Copy(f, rc)
101 | return err
102 | }
103 |
104 | // HttpGetBytes gets the specified resource. ErrNotFound is returned if the server
105 | // responds with status 404.
106 | func HttpGetBytes(client *http.Client, url string, header http.Header) ([]byte, error) {
107 | rc, err := HttpGet(client, url, header)
108 | if err != nil {
109 | return nil, err
110 | }
111 | defer rc.Close()
112 | return ioutil.ReadAll(rc)
113 | }
114 |
115 | // HttpGetJSON gets the specified resource and mapping to struct.
116 | // ErrNotFound is returned if the server responds with status 404.
117 | func HttpGetJSON(client *http.Client, url string, v interface{}) error {
118 | rc, err := HttpGet(client, url, nil)
119 | if err != nil {
120 | return err
121 | }
122 | defer rc.Close()
123 | err = json.NewDecoder(rc).Decode(v)
124 | if _, ok := err.(*json.SyntaxError); ok {
125 | return fmt.Errorf("JSON syntax error at %s", url)
126 | }
127 | return nil
128 | }
129 |
130 | // HttpPostJSON posts the specified resource with struct values,
131 | // and maps results to struct.
132 | // ErrNotFound is returned if the server responds with status 404.
133 | func HttpPostJSON(client *http.Client, url string, body, v interface{}) error {
134 | data, err := json.Marshal(body)
135 | if err != nil {
136 | return err
137 | }
138 | rc, err := HttpPost(client, url, http.Header{"content-type": []string{"application/json"}}, data)
139 | if err != nil {
140 | return err
141 | }
142 | defer rc.Close()
143 | err = json.NewDecoder(rc).Decode(v)
144 | if _, ok := err.(*json.SyntaxError); ok {
145 | return fmt.Errorf("JSON syntax error at %s", url)
146 | }
147 | return nil
148 | }
149 |
150 | // A RawFile describes a file that can be downloaded.
151 | type RawFile interface {
152 | Name() string
153 | RawUrl() string
154 | Data() []byte
155 | SetData([]byte)
156 | }
157 |
158 | // FetchFiles fetches files specified by the rawURL field in parallel.
159 | func FetchFiles(client *http.Client, files []RawFile, header http.Header) error {
160 | ch := make(chan error, len(files))
161 | for i := range files {
162 | go func(i int) {
163 | p, err := HttpGetBytes(client, files[i].RawUrl(), nil)
164 | if err != nil {
165 | ch <- err
166 | return
167 | }
168 | files[i].SetData(p)
169 | ch <- nil
170 | }(i)
171 | }
172 | for _ = range files {
173 | if err := <-ch; err != nil {
174 | return err
175 | }
176 | }
177 | return nil
178 | }
179 |
180 | // FetchFilesCurl uses command `curl` to fetch files specified by the rawURL field in parallel.
181 | func FetchFilesCurl(files []RawFile, curlOptions ...string) error {
182 | ch := make(chan error, len(files))
183 | for i := range files {
184 | go func(i int) {
185 | stdout, _, err := ExecCmd("curl", append(curlOptions, files[i].RawUrl())...)
186 | if err != nil {
187 | ch <- err
188 | return
189 | }
190 |
191 | files[i].SetData([]byte(stdout))
192 | ch <- nil
193 | }(i)
194 | }
195 | for _ = range files {
196 | if err := <-ch; err != nil {
197 | return err
198 | }
199 | }
200 | return nil
201 | }
202 |
--------------------------------------------------------------------------------
/string.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "bytes"
19 | "crypto/aes"
20 | "crypto/cipher"
21 | "crypto/rand"
22 | "errors"
23 | r "math/rand"
24 | "strconv"
25 | "strings"
26 | "time"
27 | "unicode"
28 | "unicode/utf8"
29 | )
30 |
31 | // AESGCMEncrypt encrypts plaintext with the given key using AES in GCM mode.
32 | func AESGCMEncrypt(key, plaintext []byte) ([]byte, error) {
33 | block, err := aes.NewCipher(key)
34 | if err != nil {
35 | return nil, err
36 | }
37 |
38 | gcm, err := cipher.NewGCM(block)
39 | if err != nil {
40 | return nil, err
41 | }
42 |
43 | nonce := make([]byte, gcm.NonceSize())
44 | if _, err := rand.Read(nonce); err != nil {
45 | return nil, err
46 | }
47 |
48 | ciphertext := gcm.Seal(nil, nonce, plaintext, nil)
49 | return append(nonce, ciphertext...), nil
50 | }
51 |
52 | // AESGCMDecrypt decrypts ciphertext with the given key using AES in GCM mode.
53 | func AESGCMDecrypt(key, ciphertext []byte) ([]byte, error) {
54 | block, err := aes.NewCipher(key)
55 | if err != nil {
56 | return nil, err
57 | }
58 |
59 | gcm, err := cipher.NewGCM(block)
60 | if err != nil {
61 | return nil, err
62 | }
63 |
64 | size := gcm.NonceSize()
65 | if len(ciphertext)-size <= 0 {
66 | return nil, errors.New("Ciphertext is empty")
67 | }
68 |
69 | nonce := ciphertext[:size]
70 | ciphertext = ciphertext[size:]
71 |
72 | plainText, err := gcm.Open(nil, nonce, ciphertext, nil)
73 | if err != nil {
74 | return nil, err
75 | }
76 |
77 | return plainText, nil
78 | }
79 |
80 | // IsLetter returns true if the 'l' is an English letter.
81 | func IsLetter(l uint8) bool {
82 | n := (l | 0x20) - 'a'
83 | if n >= 0 && n < 26 {
84 | return true
85 | }
86 | return false
87 | }
88 |
89 | // Expand replaces {k} in template with match[k] or subs[atoi(k)] if k is not in match.
90 | func Expand(template string, match map[string]string, subs ...string) string {
91 | var p []byte
92 | var i int
93 | for {
94 | i = strings.Index(template, "{")
95 | if i < 0 {
96 | break
97 | }
98 | p = append(p, template[:i]...)
99 | template = template[i+1:]
100 | i = strings.Index(template, "}")
101 | if s, ok := match[template[:i]]; ok {
102 | p = append(p, s...)
103 | } else {
104 | j, _ := strconv.Atoi(template[:i])
105 | if j >= len(subs) {
106 | p = append(p, []byte("Missing")...)
107 | } else {
108 | p = append(p, subs[j]...)
109 | }
110 | }
111 | template = template[i+1:]
112 | }
113 | p = append(p, template...)
114 | return string(p)
115 | }
116 |
117 | // Reverse s string, support unicode
118 | func Reverse(s string) string {
119 | n := len(s)
120 | runes := make([]rune, n)
121 | for _, rune := range s {
122 | n--
123 | runes[n] = rune
124 | }
125 | return string(runes[n:])
126 | }
127 |
128 | // RandomCreateBytes generate random []byte by specify chars.
129 | func RandomCreateBytes(n int, alphabets ...byte) []byte {
130 | const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
131 | var bytes = make([]byte, n)
132 | var randby bool
133 | if num, err := rand.Read(bytes); num != n || err != nil {
134 | r.Seed(time.Now().UnixNano())
135 | randby = true
136 | }
137 | for i, b := range bytes {
138 | if len(alphabets) == 0 {
139 | if randby {
140 | bytes[i] = alphanum[r.Intn(len(alphanum))]
141 | } else {
142 | bytes[i] = alphanum[b%byte(len(alphanum))]
143 | }
144 | } else {
145 | if randby {
146 | bytes[i] = alphabets[r.Intn(len(alphabets))]
147 | } else {
148 | bytes[i] = alphabets[b%byte(len(alphabets))]
149 | }
150 | }
151 | }
152 | return bytes
153 | }
154 |
155 | // ToSnakeCase can convert all upper case characters in a string to
156 | // underscore format.
157 | //
158 | // Some samples.
159 | // "FirstName" => "first_name"
160 | // "HTTPServer" => "http_server"
161 | // "NoHTTPS" => "no_https"
162 | // "GO_PATH" => "go_path"
163 | // "GO PATH" => "go_path" // space is converted to underscore.
164 | // "GO-PATH" => "go_path" // hyphen is converted to underscore.
165 | //
166 | // From https://github.com/huandu/xstrings
167 | func ToSnakeCase(str string) string {
168 | if len(str) == 0 {
169 | return ""
170 | }
171 |
172 | buf := &bytes.Buffer{}
173 | var prev, r0, r1 rune
174 | var size int
175 |
176 | r0 = '_'
177 |
178 | for len(str) > 0 {
179 | prev = r0
180 | r0, size = utf8.DecodeRuneInString(str)
181 | str = str[size:]
182 |
183 | switch {
184 | case r0 == utf8.RuneError:
185 | buf.WriteByte(byte(str[0]))
186 |
187 | case unicode.IsUpper(r0):
188 | if prev != '_' {
189 | buf.WriteRune('_')
190 | }
191 |
192 | buf.WriteRune(unicode.ToLower(r0))
193 |
194 | if len(str) == 0 {
195 | break
196 | }
197 |
198 | r0, size = utf8.DecodeRuneInString(str)
199 | str = str[size:]
200 |
201 | if !unicode.IsUpper(r0) {
202 | buf.WriteRune(r0)
203 | break
204 | }
205 |
206 | // find next non-upper-case character and insert `_` properly.
207 | // it's designed to convert `HTTPServer` to `http_server`.
208 | // if there are more than 2 adjacent upper case characters in a word,
209 | // treat them as an abbreviation plus a normal word.
210 | for len(str) > 0 {
211 | r1 = r0
212 | r0, size = utf8.DecodeRuneInString(str)
213 | str = str[size:]
214 |
215 | if r0 == utf8.RuneError {
216 | buf.WriteRune(unicode.ToLower(r1))
217 | buf.WriteByte(byte(str[0]))
218 | break
219 | }
220 |
221 | if !unicode.IsUpper(r0) {
222 | if r0 == '_' || r0 == ' ' || r0 == '-' {
223 | r0 = '_'
224 |
225 | buf.WriteRune(unicode.ToLower(r1))
226 | } else {
227 | buf.WriteRune('_')
228 | buf.WriteRune(unicode.ToLower(r1))
229 | buf.WriteRune(r0)
230 | }
231 |
232 | break
233 | }
234 |
235 | buf.WriteRune(unicode.ToLower(r1))
236 | }
237 |
238 | if len(str) == 0 || r0 == '_' {
239 | buf.WriteRune(unicode.ToLower(r0))
240 | break
241 | }
242 |
243 | default:
244 | if r0 == ' ' || r0 == '-' {
245 | r0 = '_'
246 | }
247 |
248 | buf.WriteRune(r0)
249 | }
250 | }
251 |
252 | return buf.String()
253 | }
254 |
--------------------------------------------------------------------------------
/dir.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com
16 |
17 | import (
18 | "errors"
19 | "fmt"
20 | "os"
21 | "path"
22 | "strings"
23 | )
24 |
25 | // IsDir returns true if given path is a directory,
26 | // or returns false when it's a file or does not exist.
27 | func IsDir(dir string) bool {
28 | f, e := os.Stat(dir)
29 | if e != nil {
30 | return false
31 | }
32 | return f.IsDir()
33 | }
34 |
35 | func statDir(dirPath, recPath string, includeDir, isDirOnly, followSymlinks bool) ([]string, error) {
36 | dir, err := os.Open(dirPath)
37 | if err != nil {
38 | return nil, err
39 | }
40 | defer dir.Close()
41 |
42 | fis, err := dir.Readdir(0)
43 | if err != nil {
44 | return nil, err
45 | }
46 |
47 | statList := make([]string, 0)
48 | for _, fi := range fis {
49 | if strings.Contains(fi.Name(), ".DS_Store") {
50 | continue
51 | }
52 |
53 | relPath := path.Join(recPath, fi.Name())
54 | curPath := path.Join(dirPath, fi.Name())
55 | if fi.IsDir() {
56 | if includeDir {
57 | statList = append(statList, relPath+"/")
58 | }
59 | s, err := statDir(curPath, relPath, includeDir, isDirOnly, followSymlinks)
60 | if err != nil {
61 | return nil, err
62 | }
63 | statList = append(statList, s...)
64 | } else if !isDirOnly {
65 | statList = append(statList, relPath)
66 | } else if followSymlinks && fi.Mode()&os.ModeSymlink != 0 {
67 | link, err := os.Readlink(curPath)
68 | if err != nil {
69 | return nil, err
70 | }
71 |
72 | if IsDir(link) {
73 | if includeDir {
74 | statList = append(statList, relPath+"/")
75 | }
76 | s, err := statDir(curPath, relPath, includeDir, isDirOnly, followSymlinks)
77 | if err != nil {
78 | return nil, err
79 | }
80 | statList = append(statList, s...)
81 | }
82 | }
83 | }
84 | return statList, nil
85 | }
86 |
87 | // StatDir gathers information of given directory by depth-first.
88 | // It returns slice of file list and includes subdirectories if enabled;
89 | // it returns error and nil slice when error occurs in underlying functions,
90 | // or given path is not a directory or does not exist.
91 | //
92 | // Slice does not include given path itself.
93 | // If subdirectories is enabled, they will have suffix '/'.
94 | func StatDir(rootPath string, includeDir ...bool) ([]string, error) {
95 | if !IsDir(rootPath) {
96 | return nil, errors.New("not a directory or does not exist: " + rootPath)
97 | }
98 |
99 | isIncludeDir := false
100 | if len(includeDir) >= 1 {
101 | isIncludeDir = includeDir[0]
102 | }
103 | return statDir(rootPath, "", isIncludeDir, false, false)
104 | }
105 |
106 | // LstatDir gathers information of given directory by depth-first.
107 | // It returns slice of file list, follows symbolic links and includes subdirectories if enabled;
108 | // it returns error and nil slice when error occurs in underlying functions,
109 | // or given path is not a directory or does not exist.
110 | //
111 | // Slice does not include given path itself.
112 | // If subdirectories is enabled, they will have suffix '/'.
113 | func LstatDir(rootPath string, includeDir ...bool) ([]string, error) {
114 | if !IsDir(rootPath) {
115 | return nil, errors.New("not a directory or does not exist: " + rootPath)
116 | }
117 |
118 | isIncludeDir := false
119 | if len(includeDir) >= 1 {
120 | isIncludeDir = includeDir[0]
121 | }
122 | return statDir(rootPath, "", isIncludeDir, false, true)
123 | }
124 |
125 | // GetAllSubDirs returns all subdirectories of given root path.
126 | // Slice does not include given path itself.
127 | func GetAllSubDirs(rootPath string) ([]string, error) {
128 | if !IsDir(rootPath) {
129 | return nil, errors.New("not a directory or does not exist: " + rootPath)
130 | }
131 | return statDir(rootPath, "", true, true, false)
132 | }
133 |
134 | // LgetAllSubDirs returns all subdirectories of given root path, including
135 | // following symbolic links, if any.
136 | // Slice does not include given path itself.
137 | func LgetAllSubDirs(rootPath string) ([]string, error) {
138 | if !IsDir(rootPath) {
139 | return nil, errors.New("not a directory or does not exist: " + rootPath)
140 | }
141 | return statDir(rootPath, "", true, true, true)
142 | }
143 |
144 | // GetFileListBySuffix returns an ordered list of file paths.
145 | // It recognize if given path is a file, and don't do recursive find.
146 | func GetFileListBySuffix(dirPath, suffix string) ([]string, error) {
147 | if !IsExist(dirPath) {
148 | return nil, fmt.Errorf("given path does not exist: %s", dirPath)
149 | } else if IsFile(dirPath) {
150 | return []string{dirPath}, nil
151 | }
152 |
153 | // Given path is a directory.
154 | dir, err := os.Open(dirPath)
155 | if err != nil {
156 | return nil, err
157 | }
158 |
159 | fis, err := dir.Readdir(0)
160 | if err != nil {
161 | return nil, err
162 | }
163 |
164 | files := make([]string, 0, len(fis))
165 | for _, fi := range fis {
166 | if strings.HasSuffix(fi.Name(), suffix) {
167 | files = append(files, path.Join(dirPath, fi.Name()))
168 | }
169 | }
170 |
171 | return files, nil
172 | }
173 |
174 | // CopyDir copy files recursively from source to target directory.
175 | //
176 | // The filter accepts a function that process the path info.
177 | // and should return true for need to filter.
178 | //
179 | // It returns error when error occurs in underlying functions.
180 | func CopyDir(srcPath, destPath string, filters ...func(filePath string) bool) error {
181 | // Check if target directory exists.
182 | if IsExist(destPath) {
183 | return errors.New("file or directory alreay exists: " + destPath)
184 | }
185 |
186 | err := os.MkdirAll(destPath, os.ModePerm)
187 | if err != nil {
188 | return err
189 | }
190 |
191 | // Gather directory info.
192 | infos, err := StatDir(srcPath, true)
193 | if err != nil {
194 | return err
195 | }
196 |
197 | var filter func(filePath string) bool
198 | if len(filters) > 0 {
199 | filter = filters[0]
200 | }
201 |
202 | for _, info := range infos {
203 | if filter != nil && filter(info) {
204 | continue
205 | }
206 |
207 | curPath := path.Join(destPath, info)
208 | if strings.HasSuffix(info, "/") {
209 | err = os.MkdirAll(curPath, os.ModePerm)
210 | } else {
211 | err = Copy(path.Join(srcPath, info), curPath)
212 | }
213 | if err != nil {
214 | return err
215 | }
216 | }
217 | return nil
218 | }
219 |
--------------------------------------------------------------------------------
/example_test.go:
--------------------------------------------------------------------------------
1 | // Copyright 2013 com authors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 | // not use this file except in compliance with the License. You may obtain
5 | // a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | // License for the specific language governing permissions and limitations
13 | // under the License.
14 |
15 | package com_test
16 |
17 | import (
18 | "fmt"
19 | "io/ioutil"
20 | "net/http"
21 |
22 | "github.com/unknwon/com"
23 | )
24 |
25 | // ------------------------------
26 | // cmd.go
27 | // ------------------------------
28 |
29 | func ExampleColorLogS() {
30 | coloredLog := com.ColorLogS(fmt.Sprintf(
31 | "[WARN] This is a tesing log that should be colored, path( %s ),"+
32 | " highlight # %s #, error [ %s ].",
33 | "path to somewhere", "highlighted content", "tesing error"))
34 | fmt.Println(coloredLog)
35 | }
36 |
37 | func ExampleColorLog() {
38 | com.ColorLog(fmt.Sprintf(
39 | "[WARN] This is a tesing log that should be colored, path( %s ),"+
40 | " highlight # %s #, error [ %s ].",
41 | "path to somewhere", "highlighted content", "tesing error"))
42 | }
43 |
44 | func ExampleExecCmd() {
45 | stdout, stderr, err := com.ExecCmd("go", "help", "get")
46 | fmt.Println(stdout, stderr, err)
47 | }
48 |
49 | // ------------- END ------------
50 |
51 | // ------------------------------
52 | // html.go
53 | // ------------------------------
54 |
55 | func ExampleHtml2JS() {
56 | htm := "Click me
\n\r"
57 | js := string(com.Html2JS([]byte(htm)))
58 | fmt.Println(js)
59 | // Output: Click me
\n
60 | }
61 |
62 | // ------------- END ------------
63 |
64 | // ------------------------------
65 | // path.go
66 | // ------------------------------
67 |
68 | func ExampleGetGOPATHs() {
69 | gps := com.GetGOPATHs()
70 | fmt.Println(gps)
71 | }
72 |
73 | func ExampleGetSrcPath() {
74 | srcPath, err := com.GetSrcPath("github.com/unknwon/com")
75 | if err != nil {
76 | fmt.Println(err)
77 | return
78 | }
79 | fmt.Println(srcPath)
80 | }
81 |
82 | func ExampleHomeDir() {
83 | hd, err := com.HomeDir()
84 | fmt.Println(hd, err)
85 | }
86 |
87 | // ------------- END ------------
88 |
89 | // ------------------------------
90 | // file.go
91 | // ------------------------------
92 |
93 | func ExampleIsFile() {
94 | if com.IsFile("file.go") {
95 | fmt.Println("file.go exists")
96 | return
97 | }
98 | fmt.Println("file.go is not a file or does not exist")
99 | }
100 |
101 | func ExampleIsExist() {
102 | if com.IsExist("file.go") {
103 | fmt.Println("file.go exists")
104 | return
105 | }
106 | fmt.Println("file.go does not exist")
107 | }
108 |
109 | // ------------- END ------------
110 |
111 | // ------------------------------
112 | // dir.go
113 | // ------------------------------
114 |
115 | func ExampleIsDir() {
116 | if com.IsDir("files") {
117 | fmt.Println("directory 'files' exists")
118 | return
119 | }
120 | fmt.Println("'files' is not a directory or does not exist")
121 | }
122 |
123 | // ------------- END ------------
124 |
125 | // ------------------------------
126 | // string.go
127 | // ------------------------------
128 |
129 | func ExampleIsLetter() {
130 | fmt.Println(com.IsLetter('1'))
131 | fmt.Println(com.IsLetter('['))
132 | fmt.Println(com.IsLetter('a'))
133 | fmt.Println(com.IsLetter('Z'))
134 | // Output:
135 | // false
136 | // false
137 | // true
138 | // true
139 | }
140 |
141 | func ExampleExpand() {
142 | match := map[string]string{
143 | "domain": "gowalker.org",
144 | "subdomain": "github.com",
145 | }
146 | s := "http://{domain}/{subdomain}/{0}/{1}"
147 | fmt.Println(com.Expand(s, match, "unknwon", "gowalker"))
148 | // Output: http://gowalker.org/github.com/unknwon/gowalker
149 | }
150 |
151 | // ------------- END ------------
152 |
153 | // ------------------------------
154 | // http.go
155 | // ------------------------------
156 |
157 | func ExampleHttpGet() ([]byte, error) {
158 | rc, err := com.HttpGet(&http.Client{}, "http://gowalker.org", nil)
159 | if err != nil {
160 | return nil, err
161 | }
162 | p, err := ioutil.ReadAll(rc)
163 | rc.Close()
164 | return p, err
165 | }
166 |
167 | func ExampleHttpGetBytes() ([]byte, error) {
168 | p, err := com.HttpGetBytes(&http.Client{}, "http://gowalker.org", nil)
169 | return p, err
170 | }
171 |
172 | func ExampleHttpGetJSON() interface{} {
173 | j := com.HttpGetJSON(&http.Client{}, "http://gowalker.org", nil)
174 | return j
175 | }
176 |
177 | type rawFile struct {
178 | name string
179 | rawURL string
180 | data []byte
181 | }
182 |
183 | func (rf *rawFile) Name() string {
184 | return rf.name
185 | }
186 |
187 | func (rf *rawFile) RawUrl() string {
188 | return rf.rawURL
189 | }
190 |
191 | func (rf *rawFile) Data() []byte {
192 | return rf.data
193 | }
194 |
195 | func (rf *rawFile) SetData(p []byte) {
196 | rf.data = p
197 | }
198 |
199 | func ExampleFetchFiles() {
200 | // Code that should be outside of your function body.
201 | // type rawFile struct {
202 | // name string
203 | // rawURL string
204 | // data []byte
205 | // }
206 |
207 | // func (rf *rawFile) Name() string {
208 | // return rf.name
209 | // }
210 |
211 | // func (rf *rawFile) RawUrl() string {
212 | // return rf.rawURL
213 | // }
214 |
215 | // func (rf *rawFile) Data() []byte {
216 | // return rf.data
217 | // }
218 |
219 | // func (rf *rawFile) SetData(p []byte) {
220 | // rf.data = p
221 | // }
222 |
223 | files := []com.RawFile{
224 | &rawFile{rawURL: "http://example.com"},
225 | &rawFile{rawURL: "http://example.com/foo"},
226 | }
227 | err := com.FetchFiles(&http.Client{}, files, nil)
228 | fmt.Println(err, len(files[0].Data()), len(files[1].Data()))
229 | }
230 |
231 | func ExampleFetchFilesCurl() {
232 | // Code that should be outside of your function body.
233 | // type rawFile struct {
234 | // name string
235 | // rawURL string
236 | // data []byte
237 | // }
238 |
239 | // func (rf *rawFile) Name() string {
240 | // return rf.name
241 | // }
242 |
243 | // func (rf *rawFile) RawUrl() string {
244 | // return rf.rawURL
245 | // }
246 |
247 | // func (rf *rawFile) Data() []byte {
248 | // return rf.data
249 | // }
250 |
251 | // func (rf *rawFile) SetData(p []byte) {
252 | // rf.data = p
253 | // }
254 |
255 | files := []com.RawFile{
256 | &rawFile{rawURL: "http://example.com"},
257 | &rawFile{rawURL: "http://example.com/foo"},
258 | }
259 | err := com.FetchFilesCurl(files)
260 | fmt.Println(err, len(files[0].Data()), len(files[1].Data()))
261 | }
262 |
263 | // ------------- END ------------
264 |
265 | // ------------------------------
266 | // regex.go
267 | // ------------------------------
268 |
269 | func ExampleIsEmail() {
270 | fmt.Println(com.IsEmail("test@example.com"))
271 | fmt.Println(com.IsEmail("@example.com"))
272 | // Output:
273 | // true
274 | // false
275 | }
276 |
277 | func ExampleIsUrl() {
278 | fmt.Println(com.IsUrl("http://example.com"))
279 | fmt.Println(com.IsUrl("http//example.com"))
280 | // Output:
281 | // true
282 | // false
283 | }
284 |
285 | // ------------- END ------------
286 |
287 | // ------------------------------
288 | // slice.go
289 | // ------------------------------
290 |
291 | func ExampleAppendStr() {
292 | s := []string{"a"}
293 | s = com.AppendStr(s, "a")
294 | s = com.AppendStr(s, "b")
295 | fmt.Println(s)
296 | // Output: [a b]
297 | }
298 |
299 | // ------------- END ------------
300 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction, and
10 | distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright
13 | owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all other entities
16 | that control, are controlled by, or are under common control with that entity.
17 | For the purposes of this definition, "control" means (i) the power, direct or
18 | indirect, to cause the direction or management of such entity, whether by
19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
20 | outstanding shares, or (iii) beneficial ownership of such entity.
21 |
22 | "You" (or "Your") shall mean an individual or Legal Entity exercising
23 | permissions granted by this License.
24 |
25 | "Source" form shall mean the preferred form for making modifications, including
26 | but not limited to software source code, documentation source, and configuration
27 | files.
28 |
29 | "Object" form shall mean any form resulting from mechanical transformation or
30 | translation of a Source form, including but not limited to compiled object code,
31 | generated documentation, and conversions to other media types.
32 |
33 | "Work" shall mean the work of authorship, whether in Source or Object form, made
34 | available under the License, as indicated by a copyright notice that is included
35 | in or attached to the work (an example is provided in the Appendix below).
36 |
37 | "Derivative Works" shall mean any work, whether in Source or Object form, that
38 | is based on (or derived from) the Work and for which the editorial revisions,
39 | annotations, elaborations, or other modifications represent, as a whole, an
40 | original work of authorship. For the purposes of this License, Derivative Works
41 | shall not include works that remain separable from, or merely link (or bind by
42 | name) to the interfaces of, the Work and Derivative Works thereof.
43 |
44 | "Contribution" shall mean any work of authorship, including the original version
45 | of the Work and any modifications or additions to that Work or Derivative Works
46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work
47 | by the copyright owner or by an individual or Legal Entity authorized to submit
48 | on behalf of the copyright owner. For the purposes of this definition,
49 | "submitted" means any form of electronic, verbal, or written communication sent
50 | to the Licensor or its representatives, including but not limited to
51 | communication on electronic mailing lists, source code control systems, and
52 | issue tracking systems that are managed by, or on behalf of, the Licensor for
53 | the purpose of discussing and improving the Work, but excluding communication
54 | that is conspicuously marked or otherwise designated in writing by the copyright
55 | owner as "Not a Contribution."
56 |
57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
58 | of whom a Contribution has been received by Licensor and subsequently
59 | incorporated within the Work.
60 |
61 | 2. Grant of Copyright License.
62 |
63 | Subject to the terms and conditions of this License, each Contributor hereby
64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
65 | irrevocable copyright license to reproduce, prepare Derivative Works of,
66 | publicly display, publicly perform, sublicense, and distribute the Work and such
67 | Derivative Works in Source or Object form.
68 |
69 | 3. Grant of Patent License.
70 |
71 | Subject to the terms and conditions of this License, each Contributor hereby
72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
73 | irrevocable (except as stated in this section) patent license to make, have
74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where
75 | such license applies only to those patent claims licensable by such Contributor
76 | that are necessarily infringed by their Contribution(s) alone or by combination
77 | of their Contribution(s) with the Work to which such Contribution(s) was
78 | submitted. If You institute patent litigation against any entity (including a
79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a
80 | Contribution incorporated within the Work constitutes direct or contributory
81 | patent infringement, then any patent licenses granted to You under this License
82 | for that Work shall terminate as of the date such litigation is filed.
83 |
84 | 4. Redistribution.
85 |
86 | You may reproduce and distribute copies of the Work or Derivative Works thereof
87 | in any medium, with or without modifications, and in Source or Object form,
88 | provided that You meet the following conditions:
89 |
90 | You must give any other recipients of the Work or Derivative Works a copy of
91 | this License; and
92 | You must cause any modified files to carry prominent notices stating that You
93 | changed the files; and
94 | You must retain, in the Source form of any Derivative Works that You distribute,
95 | all copyright, patent, trademark, and attribution notices from the Source form
96 | of the Work, excluding those notices that do not pertain to any part of the
97 | Derivative Works; and
98 | If the Work includes a "NOTICE" text file as part of its distribution, then any
99 | Derivative Works that You distribute must include a readable copy of the
100 | attribution notices contained within such NOTICE file, excluding those notices
101 | that do not pertain to any part of the Derivative Works, in at least one of the
102 | following places: within a NOTICE text file distributed as part of the
103 | Derivative Works; within the Source form or documentation, if provided along
104 | with the Derivative Works; or, within a display generated by the Derivative
105 | Works, if and wherever such third-party notices normally appear. The contents of
106 | the NOTICE file are for informational purposes only and do not modify the
107 | License. You may add Your own attribution notices within Derivative Works that
108 | You distribute, alongside or as an addendum to the NOTICE text from the Work,
109 | provided that such additional attribution notices cannot be construed as
110 | modifying the License.
111 | You may add Your own copyright statement to Your modifications and may provide
112 | additional or different license terms and conditions for use, reproduction, or
113 | distribution of Your modifications, or for any such Derivative Works as a whole,
114 | provided Your use, reproduction, and distribution of the Work otherwise complies
115 | with the conditions stated in this License.
116 |
117 | 5. Submission of Contributions.
118 |
119 | Unless You explicitly state otherwise, any Contribution intentionally submitted
120 | for inclusion in the Work by You to the Licensor shall be under the terms and
121 | conditions of this License, without any additional terms or conditions.
122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of
123 | any separate license agreement you may have executed with Licensor regarding
124 | such Contributions.
125 |
126 | 6. Trademarks.
127 |
128 | This License does not grant permission to use the trade names, trademarks,
129 | service marks, or product names of the Licensor, except as required for
130 | reasonable and customary use in describing the origin of the Work and
131 | reproducing the content of the NOTICE file.
132 |
133 | 7. Disclaimer of Warranty.
134 |
135 | Unless required by applicable law or agreed to in writing, Licensor provides the
136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
138 | including, without limitation, any warranties or conditions of TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
140 | solely responsible for determining the appropriateness of using or
141 | redistributing the Work and assume any risks associated with Your exercise of
142 | permissions under this License.
143 |
144 | 8. Limitation of Liability.
145 |
146 | In no event and under no legal theory, whether in tort (including negligence),
147 | contract, or otherwise, unless required by applicable law (such as deliberate
148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be
149 | liable to You for damages, including any direct, indirect, special, incidental,
150 | or consequential damages of any character arising as a result of this License or
151 | out of the use or inability to use the Work (including but not limited to
152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or
153 | any and all other commercial damages or losses), even if such Contributor has
154 | been advised of the possibility of such damages.
155 |
156 | 9. Accepting Warranty or Additional Liability.
157 |
158 | While redistributing the Work or Derivative Works thereof, You may choose to
159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or
160 | other liability obligations and/or rights consistent with this License. However,
161 | in accepting such obligations, You may act only on Your own behalf and on Your
162 | sole responsibility, not on behalf of any other Contributor, and only if You
163 | agree to indemnify, defend, and hold each Contributor harmless for any liability
164 | incurred by, or claims asserted against, such Contributor by reason of your
165 | accepting any such warranty or additional liability.
166 |
167 | END OF TERMS AND CONDITIONS
168 |
169 | APPENDIX: How to apply the Apache License to your work
170 |
171 | To apply the Apache License to your work, attach the following boilerplate
172 | notice, with the fields enclosed by brackets "[]" replaced with your own
173 | identifying information. (Don't include the brackets!) The text should be
174 | enclosed in the appropriate comment syntax for the file format. We also
175 | recommend that a file or class name and description of purpose be included on
176 | the same "printed page" as the copyright notice for easier identification within
177 | third-party archives.
178 |
179 | Copyright [yyyy] [name of copyright owner]
180 |
181 | Licensed under the Apache License, Version 2.0 (the "License");
182 | you may not use this file except in compliance with the License.
183 | You may obtain a copy of the License at
184 |
185 | http://www.apache.org/licenses/LICENSE-2.0
186 |
187 | Unless required by applicable law or agreed to in writing, software
188 | distributed under the License is distributed on an "AS IS" BASIS,
189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190 | See the License for the specific language governing permissions and
191 | limitations under the License.
--------------------------------------------------------------------------------