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