diff options
Diffstat (limited to 'vendor/github.com/unknwon')
39 files changed, 4121 insertions, 0 deletions
diff --git a/vendor/github.com/unknwon/cae/.gitignore b/vendor/github.com/unknwon/cae/.gitignore new file mode 100644 index 0000000000..b6c97b1593 --- /dev/null +++ b/vendor/github.com/unknwon/cae/.gitignore @@ -0,0 +1,25 @@ +# 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 + +cae.iml +*.exe +.DS_Store diff --git a/vendor/github.com/unknwon/cae/LICENSE b/vendor/github.com/unknwon/cae/LICENSE new file mode 100644 index 0000000000..8405e89a0b --- /dev/null +++ b/vendor/github.com/unknwon/cae/LICENSE @@ -0,0 +1,191 @@ +Apache 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.
\ No newline at end of file diff --git a/vendor/github.com/unknwon/cae/README.md b/vendor/github.com/unknwon/cae/README.md new file mode 100644 index 0000000000..ff6f97ec15 --- /dev/null +++ b/vendor/github.com/unknwon/cae/README.md @@ -0,0 +1,37 @@ +Compression and Archive Extensions +================================== + +[![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/unknwon/cae) + +[中文文档](README_ZH.md) + +Package cae implements PHP-like Compression and Archive Extensions. + +But this package has some modifications depends on Go-style. + +Reference: [PHP:Compression and Archive Extensions](http://www.php.net/manual/en/refs.compression.php). + +Code Convention: based on [Go Code Convention](https://github.com/unknwon/go-code-convention). + +### Implementations + +Package `zip`([Go Walker](http://gowalker.org/github.com/unknwon/cae/zip)) and `tz`([Go Walker](http://gowalker.org/github.com/unknwon/cae/tz)) both enable you to transparently read or write ZIP/TAR.GZ compressed archives and the files inside them. + +- Features: + - Add file or directory from everywhere to archive, no one-to-one limitation. + - Extract part of entries, not all at once. + - Stream data directly into `io.Writer` without any file system storage. + +### Test cases and Coverage + +All subpackages use [GoConvey](http://goconvey.co/) to write test cases, and coverage is more than 80 percent. + +### Use cases + +- [Gogs](https://github.com/gogits/gogs): self hosted Git service in the Go Programming Language. +- [GoBlog](https://github.com/fuxiaohei/GoBlog): personal blogging application. +- [GoBuild](https://github.com/shxsun/gobuild/): online Go cross-platform compilation and download service. + +## License + +This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text.
\ No newline at end of file diff --git a/vendor/github.com/unknwon/cae/README_ZH.md b/vendor/github.com/unknwon/cae/README_ZH.md new file mode 100644 index 0000000000..d5c361e3dc --- /dev/null +++ b/vendor/github.com/unknwon/cae/README_ZH.md @@ -0,0 +1,29 @@ +压缩与打包扩展 +============= + +[![Go Walker](http://gowalker.org/api/v1/badge)](http://gowalker.org/github.com/unknwon/cae) + +包 cae 实现了 PHP 风格的压缩与打包扩展。 + +但本包依据 Go 语言的风格进行了一些修改。 + +引用:[PHP:Compression and Archive Extensions](http://www.php.net/manual/en/refs.compression.php) + +编码规范:基于 [Go 编码规范](https://github.com/unknwon/go-code-convention) + +### 实现 + +包 `zip`([Go Walker](http://gowalker.org/github.com/unknwon/cae/zip)) 和 `tz`([Go Walker](http://gowalker.org/github.com/unknwon/cae/tz)) 都允许你轻易的读取或写入 ZIP/TAR.GZ 压缩档案和其内部文件。 + +- 特性: + - 将任意位置的文件或目录加入档案,没有一对一的操作限制。 + - 只解压部分文件,而非一次性解压全部。 + - 将数据以流的形式直接写入 `io.Writer` 而不需经过文件系统的存储。 + +### 测试用例与覆盖率 + +所有子包均采用 [GoConvey](http://goconvey.co/) 来书写测试用例,覆盖率均超过 80%。 + +## 授权许可 + +本项目采用 Apache v2 开源授权许可证,完整的授权说明已放置在 [LICENSE](LICENSE) 文件中。
\ No newline at end of file diff --git a/vendor/github.com/unknwon/cae/cae.go b/vendor/github.com/unknwon/cae/cae.go new file mode 100644 index 0000000000..60e295a9cb --- /dev/null +++ b/vendor/github.com/unknwon/cae/cae.go @@ -0,0 +1,108 @@ +// Copyright 2013 Unknown +// +// 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 cae implements PHP-like Compression and Archive Extensions. +package cae + +import ( + "io" + "os" + "strings" +) + +// A Streamer describes an streamable archive object. +type Streamer interface { + StreamFile(string, os.FileInfo, []byte) error + StreamReader(string, os.FileInfo, io.Reader) error + Close() error +} + +// A HookFunc represents a middleware for packing and extracting archive. +type HookFunc func(string, os.FileInfo) error + +// HasPrefix returns true if name has any string in given slice as prefix. +func HasPrefix(name string, prefixes []string) bool { + for _, prefix := range prefixes { + if strings.HasPrefix(name, prefix) { + return true + } + } + return false +} + +// IsEntry returns true if name equals to any string in given slice. +func IsEntry(name string, entries []string) bool { + for _, e := range entries { + if e == name { + return true + } + } + return false +} + +// IsFilter returns true if given name matches any of global filter rule. +func IsFilter(name string) bool { + if strings.Contains(name, ".DS_Store") { + return true + } + return false +} + +// IsExist returns true if given path is a file or directory. +func IsExist(path string) bool { + _, err := os.Stat(path) + return err == nil || os.IsExist(err) +} + +// Copy copies file from source to target path. +func Copy(dest, src 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()) +} diff --git a/vendor/github.com/unknwon/cae/zip/read.go b/vendor/github.com/unknwon/cae/zip/read.go new file mode 100644 index 0000000000..c4825ef6d5 --- /dev/null +++ b/vendor/github.com/unknwon/cae/zip/read.go @@ -0,0 +1,67 @@ +// Copyright 2013 Unknown +// +// 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 zip + +import ( + "archive/zip" + "os" + "strings" +) + +// OpenFile is the generalized open call; most users will use Open +// instead. It opens the named zip file with specified flag +// (O_RDONLY etc.) if applicable. If successful, +// methods on the returned ZipArchive can be used for I/O. +// If there is an error, it will be of type *PathError. +func (z *ZipArchive) Open(name string, flag int, perm os.FileMode) error { + // Create a new archive if it's specified and not exist. + if flag&os.O_CREATE != 0 { + f, err := os.Create(name) + if err != nil { + return err + } + zw := zip.NewWriter(f) + if err = zw.Close(); err != nil { + return err + } + } + + rc, err := zip.OpenReader(name) + if err != nil { + return err + } + + z.ReadCloser = rc + z.FileName = name + z.Comment = rc.Comment + z.NumFiles = len(rc.File) + z.Flag = flag + z.Permission = perm + z.isHasChanged = false + + z.files = make([]*File, z.NumFiles) + for i, f := range rc.File { + z.files[i] = &File{} + z.files[i].FileHeader, err = zip.FileInfoHeader(f.FileInfo()) + if err != nil { + return err + } + z.files[i].Name = strings.Replace(f.Name, "\\", "/", -1) + if f.FileInfo().IsDir() && !strings.HasSuffix(z.files[i].Name, "/") { + z.files[i].Name += "/" + } + } + return nil +} diff --git a/vendor/github.com/unknwon/cae/zip/stream.go b/vendor/github.com/unknwon/cae/zip/stream.go new file mode 100644 index 0000000000..18d8cc2250 --- /dev/null +++ b/vendor/github.com/unknwon/cae/zip/stream.go @@ -0,0 +1,77 @@ +// Copyright 2014 Unknown +// +// 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 zip + +import ( + "archive/zip" + "io" + "os" + "path/filepath" +) + +// A StreamArchive represents a streamable archive. +type StreamArchive struct { + *zip.Writer +} + +// NewStreamArachive returns a new streamable archive with given io.Writer. +// It's caller's responsibility to close io.Writer and streamer after operation. +func NewStreamArachive(w io.Writer) *StreamArchive { + return &StreamArchive{zip.NewWriter(w)} +} + +// StreamFile streams a file or directory entry into StreamArchive. +func (s *StreamArchive) StreamFile(relPath string, fi os.FileInfo, data []byte) error { + if fi.IsDir() { + fh, err := zip.FileInfoHeader(fi) + if err != nil { + return err + } + fh.Name = relPath + "/" + if _, err = s.Writer.CreateHeader(fh); err != nil { + return err + } + } else { + fh, err := zip.FileInfoHeader(fi) + if err != nil { + return err + } + fh.Name = filepath.Join(relPath, fi.Name()) + fh.Method = zip.Deflate + fw, err := s.Writer.CreateHeader(fh) + if err != nil { + return err + } else if _, err = fw.Write(data); err != nil { + return err + } + } + return nil +} + +// StreamReader streams data from io.Reader to StreamArchive. +func (s *StreamArchive) StreamReader(relPath string, fi os.FileInfo, r io.Reader) (err error) { + fh, err := zip.FileInfoHeader(fi) + if err != nil { + return err + } + fh.Name = filepath.Join(relPath, fi.Name()) + + fw, err := s.Writer.CreateHeader(fh) + if err != nil { + return err + } + _, err = io.Copy(fw, r) + return err +} diff --git a/vendor/github.com/unknwon/cae/zip/write.go b/vendor/github.com/unknwon/cae/zip/write.go new file mode 100644 index 0000000000..5d4679602c --- /dev/null +++ b/vendor/github.com/unknwon/cae/zip/write.go @@ -0,0 +1,364 @@ +// Copyright 2013 Unknown +// +// 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 zip + +import ( + "archive/zip" + "fmt" + "io" + "os" + "path" + "path/filepath" + "strings" + + "github.com/unknwon/cae" +) + +// Switcher of printing trace information when pack and extract. +var Verbose = true + +// extractFile extracts zip.File to file system. +func extractFile(f *zip.File, destPath string) error { + filePath := path.Join(destPath, f.Name) + os.MkdirAll(path.Dir(filePath), os.ModePerm) + + rc, err := f.Open() + if err != nil { + return err + } + defer rc.Close() + + fw, err := os.Create(filePath) + if err != nil { + return err + } + defer fw.Close() + + if _, err = io.Copy(fw, rc); err != nil { + return err + } + + // Skip symbolic links. + if f.FileInfo().Mode()&os.ModeSymlink != 0 { + return nil + } + // Set back file information. + if err = os.Chtimes(filePath, f.ModTime(), f.ModTime()); err != nil { + return err + } + return os.Chmod(filePath, f.FileInfo().Mode()) +} + +var defaultExtractFunc = func(fullName string, fi os.FileInfo) error { + if !Verbose { + return nil + } + + fmt.Println("Extracting file..." + fullName) + return nil +} + +// ExtractToFunc extracts the whole archive or the given files to the +// specified destination. +// It accepts a function as a middleware for custom operations. +func (z *ZipArchive) ExtractToFunc(destPath string, fn cae.HookFunc, entries ...string) (err error) { + destPath = strings.Replace(destPath, "\\", "/", -1) + isHasEntry := len(entries) > 0 + if Verbose { + fmt.Println("Unzipping " + z.FileName + "...") + } + os.MkdirAll(destPath, os.ModePerm) + for _, f := range z.File { + f.Name = strings.Replace(f.Name, "\\", "/", -1) + + // Directory. + if strings.HasSuffix(f.Name, "/") { + if isHasEntry { + if cae.IsEntry(f.Name, entries) { + if err = fn(f.Name, f.FileInfo()); err != nil { + continue + } + os.MkdirAll(path.Join(destPath, f.Name), os.ModePerm) + } + continue + } + if err = fn(f.Name, f.FileInfo()); err != nil { + continue + } + os.MkdirAll(path.Join(destPath, f.Name), os.ModePerm) + continue + } + + // File. + if isHasEntry { + if cae.IsEntry(f.Name, entries) { + if err = fn(f.Name, f.FileInfo()); err != nil { + continue + } + err = extractFile(f, destPath) + } + } else { + if err = fn(f.Name, f.FileInfo()); err != nil { + continue + } + err = extractFile(f, destPath) + } + if err != nil { + return err + } + } + return nil +} + +// ExtractToFunc extracts the whole archive or the given files to the +// specified destination. +// It accepts a function as a middleware for custom operations. +func ExtractToFunc(srcPath, destPath string, fn cae.HookFunc, entries ...string) (err error) { + z, err := Open(srcPath) + if err != nil { + return err + } + defer z.Close() + return z.ExtractToFunc(destPath, fn, entries...) +} + +// ExtractTo extracts the whole archive or the given files to the +// specified destination. +// Call Flush() to apply changes before this. +func (z *ZipArchive) ExtractTo(destPath string, entries ...string) (err error) { + return z.ExtractToFunc(destPath, defaultExtractFunc, entries...) +} + +// ExtractTo extracts given archive or the given files to the +// specified destination. +func ExtractTo(srcPath, destPath string, entries ...string) (err error) { + return ExtractToFunc(srcPath, destPath, defaultExtractFunc, entries...) +} + +// extractFile extracts file from ZipArchive to file system. +func (z *ZipArchive) extractFile(f *File) error { + if !z.isHasWriter { + for _, zf := range z.ReadCloser.File { + if f.Name == zf.Name { + return extractFile(zf, path.Dir(f.tmpPath)) + } + } + } + return cae.Copy(f.tmpPath, f.absPath) +} + +// Flush saves changes to original zip file if any. +func (z *ZipArchive) Flush() error { + if !z.isHasChanged || (z.ReadCloser == nil && !z.isHasWriter) { + return nil + } + + // Extract to tmp path and pack back. + tmpPath := path.Join(os.TempDir(), "cae", path.Base(z.FileName)) + os.RemoveAll(tmpPath) + defer os.RemoveAll(tmpPath) + + for _, f := range z.files { + if strings.HasSuffix(f.Name, "/") { + os.MkdirAll(path.Join(tmpPath, f.Name), os.ModePerm) + continue + } + + // Relative path inside zip temporary changed. + f.tmpPath = path.Join(tmpPath, f.Name) + if err := z.extractFile(f); err != nil { + return err + } + } + + if z.isHasWriter { + return packToWriter(tmpPath, z.writer, defaultPackFunc, true) + } + + if err := PackTo(tmpPath, z.FileName); err != nil { + return err + } + return z.Open(z.FileName, os.O_RDWR|os.O_TRUNC, z.Permission) +} + +// packFile packs a file or directory to zip.Writer. +func packFile(srcFile string, recPath string, zw *zip.Writer, fi os.FileInfo) error { + if fi.IsDir() { + fh, err := zip.FileInfoHeader(fi) + if err != nil { + return err + } + fh.Name = recPath + "/" + if _, err = zw.CreateHeader(fh); err != nil { + return err + } + } else { + fh, err := zip.FileInfoHeader(fi) + if err != nil { + return err + } + fh.Name = recPath + fh.Method = zip.Deflate + + fw, err := zw.CreateHeader(fh) + if err != nil { + return err + } + + if fi.Mode()&os.ModeSymlink != 0 { + target, err := os.Readlink(srcFile) + if err != nil { + return err + } + if _, err = fw.Write([]byte(target)); err != nil { + return err + } + } else { + f, err := os.Open(srcFile) + if err != nil { + return err + } + defer f.Close() + + if _, err = io.Copy(fw, f); err != nil { + return err + } + } + } + return nil +} + +// packDir packs a directory and its subdirectories and files +// recursively to zip.Writer. +func packDir(srcPath string, recPath string, zw *zip.Writer, fn cae.HookFunc) error { + dir, err := os.Open(srcPath) + if err != nil { + return err + } + defer dir.Close() + + fis, err := dir.Readdir(0) + if err != nil { + return err + } + for _, fi := range fis { + if cae.IsFilter(fi.Name()) { + continue + } + curPath := srcPath + "/" + fi.Name() + tmpRecPath := filepath.Join(recPath, fi.Name()) + if err = fn(curPath, fi); err != nil { + continue + } + + if fi.IsDir() { + if err = packFile(srcPath, tmpRecPath, zw, fi); err != nil { + return err + } + err = packDir(curPath, tmpRecPath, zw, fn) + } else { + err = packFile(curPath, tmpRecPath, zw, fi) + } + if err != nil { + return err + } + } + return nil +} + +// packToWriter packs given path object to io.Writer. +func packToWriter(srcPath string, w io.Writer, fn func(fullName string, fi os.FileInfo) error, includeDir bool) error { + zw := zip.NewWriter(w) + defer zw.Close() + + f, err := os.Open(srcPath) + if err != nil { + return err + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + return err + } + + basePath := path.Base(srcPath) + if fi.IsDir() { + if includeDir { + if err = packFile(srcPath, basePath, zw, fi); err != nil { + return err + } + } else { + basePath = "" + } + return packDir(srcPath, basePath, zw, fn) + } + return packFile(srcPath, basePath, zw, fi) +} + +// packTo packs given source path object to target path. +func packTo(srcPath, destPath string, fn cae.HookFunc, includeDir bool) error { + fw, err := os.Create(destPath) + if err != nil { + return err + } + defer fw.Close() + + return packToWriter(srcPath, fw, fn, includeDir) +} + +// PackToFunc packs the complete archive to the specified destination. +// It accepts a function as a middleware for custom operations. +func PackToFunc(srcPath, destPath string, fn func(fullName string, fi os.FileInfo) error, includeDir ...bool) error { + isIncludeDir := false + if len(includeDir) > 0 && includeDir[0] { + isIncludeDir = true + } + return packTo(srcPath, destPath, fn, isIncludeDir) +} + +var defaultPackFunc = func(fullName string, fi os.FileInfo) error { + if !Verbose { + return nil + } + + if fi.IsDir() { + fmt.Printf("Adding dir...%s\n", fullName) + } else { + fmt.Printf("Adding file...%s\n", fullName) + } + return nil +} + +// PackTo packs the whole archive to the specified destination. +// Call Flush() will automatically call this in the end. +func PackTo(srcPath, destPath string, includeDir ...bool) error { + return PackToFunc(srcPath, destPath, defaultPackFunc, includeDir...) +} + +// Close opens or creates archive and save changes. +func (z *ZipArchive) Close() (err error) { + if err = z.Flush(); err != nil { + return err + } + + if z.ReadCloser != nil { + if err = z.ReadCloser.Close(); err != nil { + return err + } + z.ReadCloser = nil + } + return nil +} diff --git a/vendor/github.com/unknwon/cae/zip/zip.go b/vendor/github.com/unknwon/cae/zip/zip.go new file mode 100644 index 0000000000..b5d7d1071c --- /dev/null +++ b/vendor/github.com/unknwon/cae/zip/zip.go @@ -0,0 +1,238 @@ +// Copyright 2013 Unknown +// +// 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 zip enables you to transparently read or write ZIP compressed archives and the files inside them. +package zip + +import ( + "archive/zip" + "errors" + "io" + "os" + "path" + "strings" + + "github.com/unknwon/cae" +) + +// A File represents a file or directory entry in archive. +type File struct { + *zip.FileHeader + oldName string // NOTE: unused, for future change name feature. + oldComment string // NOTE: unused, for future change comment feature. + absPath string // Absolute path of local file system. + tmpPath string +} + +// A ZipArchive represents a file archive, compressed with Zip. +type ZipArchive struct { + *zip.ReadCloser + FileName string + Comment string + NumFiles int + Flag int + Permission os.FileMode + + files []*File + isHasChanged bool + + // For supporting flushing to io.Writer. + writer io.Writer + isHasWriter bool +} + +// OpenFile is the generalized open call; most users will use Open +// instead. It opens the named zip file with specified flag +// (O_RDONLY etc.) if applicable. If successful, +// methods on the returned ZipArchive can be used for I/O. +// If there is an error, it will be of type *PathError. +func OpenFile(name string, flag int, perm os.FileMode) (*ZipArchive, error) { + z := new(ZipArchive) + err := z.Open(name, flag, perm) + return z, err +} + +// Create creates the named zip file, truncating +// it if it already exists. If successful, methods on the returned +// ZipArchive can be used for I/O; the associated file descriptor has mode +// O_RDWR. +// If there is an error, it will be of type *PathError. +func Create(name string) (*ZipArchive, error) { + os.MkdirAll(path.Dir(name), os.ModePerm) + return OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) +} + +// Open opens the named zip file for reading. If successful, methods on +// the returned ZipArchive can be used for reading; the associated file +// descriptor has mode O_RDONLY. +// If there is an error, it will be of type *PathError. +func Open(name string) (*ZipArchive, error) { + return OpenFile(name, os.O_RDONLY, 0) +} + +// New accepts a variable that implemented interface io.Writer +// for write-only purpose operations. +func New(w io.Writer) *ZipArchive { + return &ZipArchive{ + writer: w, + isHasWriter: true, + } +} + +// List returns a string slice of files' name in ZipArchive. +// Specify prefixes will be used as filters. +func (z *ZipArchive) List(prefixes ...string) []string { + isHasPrefix := len(prefixes) > 0 + names := make([]string, 0, z.NumFiles) + for _, f := range z.files { + if isHasPrefix && !cae.HasPrefix(f.Name, prefixes) { + continue + } + names = append(names, f.Name) + } + return names +} + +// AddEmptyDir adds a raw directory entry to ZipArchive, +// it returns false if same directory enry already existed. +func (z *ZipArchive) AddEmptyDir(dirPath string) bool { + dirPath = strings.Replace(dirPath, "\\", "/", -1) + + if !strings.HasSuffix(dirPath, "/") { + dirPath += "/" + } + + for _, f := range z.files { + if dirPath == f.Name { + return false + } + } + + dirPath = strings.TrimSuffix(dirPath, "/") + if strings.Contains(dirPath, "/") { + // Auto add all upper level directories. + z.AddEmptyDir(path.Dir(dirPath)) + } + z.files = append(z.files, &File{ + FileHeader: &zip.FileHeader{ + Name: dirPath + "/", + UncompressedSize: 0, + }, + }) + z.updateStat() + return true +} + +// AddDir adds a directory and subdirectories entries to ZipArchive. +func (z *ZipArchive) AddDir(dirPath, absPath string) error { + dir, err := os.Open(absPath) + if err != nil { + return err + } + defer dir.Close() + + // Make sure we have all upper level directories. + z.AddEmptyDir(dirPath) + + fis, err := dir.Readdir(0) + if err != nil { + return err + } + for _, fi := range fis { + curPath := absPath + "/" + fi.Name() + tmpRecPath := path.Join(dirPath, fi.Name()) + if fi.IsDir() { + if err = z.AddDir(tmpRecPath, curPath); err != nil { + return err + } + } else { + if err = z.AddFile(tmpRecPath, curPath); err != nil { + return err + } + } + } + return nil +} + +// updateStat should be called after every change for rebuilding statistic. +func (z *ZipArchive) updateStat() { + z.NumFiles = len(z.files) + z.isHasChanged = true +} + +// AddFile adds a file entry to ZipArchive. +func (z *ZipArchive) AddFile(fileName, absPath string) error { + fileName = strings.Replace(fileName, "\\", "/", -1) + absPath = strings.Replace(absPath, "\\", "/", -1) + + if cae.IsFilter(absPath) { + return nil + } + + f, err := os.Open(absPath) + if err != nil { + return err + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + return err + } + + file := new(File) + file.FileHeader, err = zip.FileInfoHeader(fi) + if err != nil { + return err + } + file.Name = fileName + file.absPath = absPath + + z.AddEmptyDir(path.Dir(fileName)) + + isExist := false + for _, f := range z.files { + if fileName == f.Name { + f = file + isExist = true + break + } + } + if !isExist { + z.files = append(z.files, file) + } + + z.updateStat() + return nil +} + +// DeleteIndex deletes an entry in the archive by its index. +func (z *ZipArchive) DeleteIndex(idx int) error { + if idx >= z.NumFiles { + return errors.New("index out of range of number of files") + } + + z.files = append(z.files[:idx], z.files[idx+1:]...) + return nil +} + +// DeleteName deletes an entry in the archive by its name. +func (z *ZipArchive) DeleteName(name string) error { + for i, f := range z.files { + if f.Name == name { + return z.DeleteIndex(i) + } + } + return errors.New("entry with given name not found") +} diff --git a/vendor/github.com/unknwon/com/.gitignore b/vendor/github.com/unknwon/com/.gitignore new file mode 100644 index 0000000000..0da157fe9c --- /dev/null +++ b/vendor/github.com/unknwon/com/.gitignore @@ -0,0 +1,24 @@ +# 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 diff --git a/vendor/github.com/unknwon/com/.travis.yml b/vendor/github.com/unknwon/com/.travis.yml new file mode 100644 index 0000000000..b36cd5c197 --- /dev/null +++ b/vendor/github.com/unknwon/com/.travis.yml @@ -0,0 +1,15 @@ +language: 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 diff --git a/vendor/github.com/unknwon/com/LICENSE b/vendor/github.com/unknwon/com/LICENSE new file mode 100644 index 0000000000..8405e89a0b --- /dev/null +++ b/vendor/github.com/unknwon/com/LICENSE @@ -0,0 +1,191 @@ +Apache 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.
\ No newline at end of file diff --git a/vendor/github.com/unknwon/com/README.md b/vendor/github.com/unknwon/com/README.md new file mode 100644 index 0000000000..da0a23bc99 --- /dev/null +++ b/vendor/github.com/unknwon/com/README.md @@ -0,0 +1,20 @@ +Common 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** . diff --git a/vendor/github.com/unknwon/com/cmd.go b/vendor/github.com/unknwon/com/cmd.go new file mode 100644 index 0000000000..5b4bbaee97 --- /dev/null +++ b/vendor/github.com/unknwon/com/cmd.go @@ -0,0 +1,161 @@ +// +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: <level> <content [highlight][path]> [ error ]. +// Level: TRAC -> blue; ERRO -> red; WARN -> Magenta; SUCC -> green; others -> default. +// Content: default; path: yellow; error -> red. +// Level has to be surrounded by "[" and "]". +// Highlights have to be surrounded by "# " and " #"(space), "#" will be deleted. +// Paths have to be surrounded by "( " and " )"(space). +// Errors have to be surrounded by "[ " and " ]"(space). +// Note: it hasn't support windows yet, contribute is welcome. +func ColorLogS(format string, a ...interface{}) string { + log := fmt.Sprintf(format, a...) + + var clog string + + if runtime.GOOS != "windows" { + // Level. + i := strings.Index(log, "]") + if log[0] == '[' && i > -1 { + clog += "[" + getColorLevel(log[1:i]) + "]" + } + + log = log[i+1:] + + // Error. + log = strings.Replace(log, "[ ", fmt.Sprintf("[\033[%dm", Red), -1) + log = strings.Replace(log, " ]", EndColor+"]", -1) + + // Path. + log = strings.Replace(log, "( ", fmt.Sprintf("(\033[%dm", Yellow), -1) + log = strings.Replace(log, " )", EndColor+")", -1) + + // Highlights. + log = strings.Replace(log, "# ", fmt.Sprintf("\033[%dm", Gray), -1) + log = strings.Replace(log, " #", EndColor, -1) + + } 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...)) +} diff --git a/vendor/github.com/unknwon/com/convert.go b/vendor/github.com/unknwon/com/convert.go new file mode 100644 index 0000000000..bf24aa8bc3 --- /dev/null +++ b/vendor/github.com/unknwon/com/convert.go @@ -0,0 +1,167 @@ +// 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 +} diff --git a/vendor/github.com/unknwon/com/dir.go b/vendor/github.com/unknwon/com/dir.go new file mode 100644 index 0000000000..c16e9de333 --- /dev/null +++ b/vendor/github.com/unknwon/com/dir.go @@ -0,0 +1,218 @@ +// 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 +} diff --git a/vendor/github.com/unknwon/com/file.go b/vendor/github.com/unknwon/com/file.go new file mode 100644 index 0000000000..b51502c917 --- /dev/null +++ b/vendor/github.com/unknwon/com/file.go @@ -0,0 +1,145 @@ +// 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) +} diff --git a/vendor/github.com/unknwon/com/go.mod b/vendor/github.com/unknwon/com/go.mod new file mode 100644 index 0000000000..43834a963c --- /dev/null +++ b/vendor/github.com/unknwon/com/go.mod @@ -0,0 +1,8 @@ +module 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 +) diff --git a/vendor/github.com/unknwon/com/go.sum b/vendor/github.com/unknwon/com/go.sum new file mode 100644 index 0000000000..3fcc30358b --- /dev/null +++ b/vendor/github.com/unknwon/com/go.sum @@ -0,0 +1,8 @@ +github.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= diff --git a/vendor/github.com/unknwon/com/html.go b/vendor/github.com/unknwon/com/html.go new file mode 100644 index 0000000000..8a99df4e08 --- /dev/null +++ b/vendor/github.com/unknwon/com/html.go @@ -0,0 +1,60 @@ +// 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>", "<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)[^<>]*>.*?</(?:style|script)>|</?[a-z][a-z0-9]*[^<>]*>|<!--.*?-->`) + 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 <br/> +func Nl2br(str string) string { + return strings.Replace(str, "\n", "<br/>", -1) +} diff --git a/vendor/github.com/unknwon/com/http.go b/vendor/github.com/unknwon/com/http.go new file mode 100644 index 0000000000..cf0820f378 --- /dev/null +++ b/vendor/github.com/unknwon/com/http.go @@ -0,0 +1,201 @@ +// 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 +} diff --git a/vendor/github.com/unknwon/com/math.go b/vendor/github.com/unknwon/com/math.go new file mode 100644 index 0000000000..62b77e87c8 --- /dev/null +++ b/vendor/github.com/unknwon/com/math.go @@ -0,0 +1,29 @@ +// 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 + } + } +} diff --git a/vendor/github.com/unknwon/com/path.go b/vendor/github.com/unknwon/com/path.go new file mode 100644 index 0000000000..b1e860def4 --- /dev/null +++ b/vendor/github.com/unknwon/com/path.go @@ -0,0 +1,80 @@ +// 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 +} diff --git a/vendor/github.com/unknwon/com/regex.go b/vendor/github.com/unknwon/com/regex.go new file mode 100644 index 0000000000..14926474e0 --- /dev/null +++ b/vendor/github.com/unknwon/com/regex.go @@ -0,0 +1,56 @@ +// 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) +} diff --git a/vendor/github.com/unknwon/com/slice.go b/vendor/github.com/unknwon/com/slice.go new file mode 100644 index 0000000000..c3c9ab2e72 --- /dev/null +++ b/vendor/github.com/unknwon/com/slice.go @@ -0,0 +1,87 @@ +// 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 +} diff --git a/vendor/github.com/unknwon/com/string.go b/vendor/github.com/unknwon/com/string.go new file mode 100644 index 0000000000..7080d174a8 --- /dev/null +++ b/vendor/github.com/unknwon/com/string.go @@ -0,0 +1,253 @@ +// 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() +} diff --git a/vendor/github.com/unknwon/com/time.go b/vendor/github.com/unknwon/com/time.go new file mode 100644 index 0000000000..dd1cdbcf2a --- /dev/null +++ b/vendor/github.com/unknwon/com/time.go @@ -0,0 +1,115 @@ +// 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) +} diff --git a/vendor/github.com/unknwon/com/url.go b/vendor/github.com/unknwon/com/url.go new file mode 100644 index 0000000000..b0b7c0e12b --- /dev/null +++ b/vendor/github.com/unknwon/com/url.go @@ -0,0 +1,41 @@ +// 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 +} diff --git a/vendor/github.com/unknwon/i18n/.gitignore b/vendor/github.com/unknwon/i18n/.gitignore new file mode 100644 index 0000000000..00268614f0 --- /dev/null +++ b/vendor/github.com/unknwon/i18n/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/vendor/github.com/unknwon/i18n/LICENSE b/vendor/github.com/unknwon/i18n/LICENSE new file mode 100644 index 0000000000..8405e89a0b --- /dev/null +++ b/vendor/github.com/unknwon/i18n/LICENSE @@ -0,0 +1,191 @@ +Apache 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.
\ No newline at end of file diff --git a/vendor/github.com/unknwon/i18n/Makefile b/vendor/github.com/unknwon/i18n/Makefile new file mode 100644 index 0000000000..8ff1ac4399 --- /dev/null +++ b/vendor/github.com/unknwon/i18n/Makefile @@ -0,0 +1,12 @@ +.PHONY: build test bench vet + +build: vet bench + +test: + go test -v -cover + +bench: + go test -v -cover -test.bench=. -test.benchmem + +vet: + go vet
\ No newline at end of file diff --git a/vendor/github.com/unknwon/i18n/README.md b/vendor/github.com/unknwon/i18n/README.md new file mode 100644 index 0000000000..4e3bff7526 --- /dev/null +++ b/vendor/github.com/unknwon/i18n/README.md @@ -0,0 +1,135 @@ +# i18n [![GoDoc](https://godoc.org/github.com/unknwon/i18n?status.svg)](https://godoc.org/github.com/unknwon/i18n) + +Package i18n is for app Internationalization and Localization. + +## Introduction + +This package provides multiple-language options to improve user experience. Sites like [Go Walker](http://gowalker.org) and [gogs.io](http://gogs.io) are using this module to implement Chinese and English user interfaces. + +You can use following command to install this module: + + go get github.com/Unknwon/i18n + +## Usage + +First of all, you have to import this package: + +```go +import "github.com/unknwon/i18n" +``` + +The format of locale files is very like INI format configuration file, which is basically key-value pairs. But this module has some improvements. Every language corresponding to a locale file, for example, suppose there are two files called `locale_en-US.ini` and `locale_zh-CN.ini`. + +The name and extensions of locale files can be anything, but we strongly recommend you to follow the style of gogsweb. + +## Minimal example + +Here are two simplest locale file examples: + +File `locale_en-US.ini`: + +```ini +hi = hello, %s +bye = goodbye +``` + +File `locale_zh-CN.ini`: + +```ini +hi = 您好,%s +bye = 再见 +``` + +### Do Translation + +There are two ways to do translation depends on which way is the best fit for your application or framework. + +Directly use package function to translate: + +```go +i18n.Tr("en-US", "hi", "Unknwon") +i18n.Tr("en-US", "bye") +``` + +Or create a struct and embed it: + +```go +type MyController struct{ + // ...other fields + i18n.Locale +} + +//... + +func ... { + c := &MyController{ + Locale: i18n.Locale{"en-US"}, + } + _ = c.Tr("hi", "Unknwon") + _ = c.Tr("bye") +} +``` + +Code above will produce correspondingly: + +- English `en-US`:`hello, Unknwon`, `goodbye` +- Chinese `zh-CN`:`您好,Unknwon`, `再见` + +## Section + +For different pages, one key may map to different values. Therefore, i18n module also uses the section feature of INI format configuration to achieve section. + +For example, the key name is `about`, and we want to show `About` in the home page and `About Us` in about page. Then you can do following: + +Content in locale file: + +```ini +about = About + +[about] +about = About Us +``` + +Get `about` in home page: + +```go +i18n.Tr("en-US", "about") +``` + +Get `about` in about page: + +```go +i18n.Tr("en-US", "about.about") +``` + +### Ambiguity + +Because dot `.` is sign of section in both [INI parser](https://github.com/go-ini/ini) and locale files, so when your key name contains `.` will cause ambiguity. At this point, you just need to add one more `.` in front of the key. + +For example, the key name is `about.`, then we can use: + +```go +i18n.Tr("en-US", ".about.") +``` + +to get expect result. + +## Helper tool + +Module i18n provides a command line helper tool beei18n for simplify steps of your development. You can install it as follows: + + go get github.com/unknwon/i18n/ui18n + +### Sync locale files + +Command `sync` allows you use a exist local file as the template to create or sync other locale files: + + ui18n sync srouce_file.ini other1.ini other2.ini + +This command can operate 1 or more files in one command. + +## More information + +- The first locale you load to the module is considered as **default locale**. +- When matching non-default locale and didn't find the string, i18n will have a second try on default locale. +- If i18n still cannot find string in the default locale, raw string will be returned. For instance, when the string is `hi` and it does not exist in locale file, simply return `hi` as output. diff --git a/vendor/github.com/unknwon/i18n/go.mod b/vendor/github.com/unknwon/i18n/go.mod new file mode 100644 index 0000000000..4d252d68ea --- /dev/null +++ b/vendor/github.com/unknwon/i18n/go.mod @@ -0,0 +1,9 @@ +module github.com/unknwon/i18n + +go 1.12 + +require ( + github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect + github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e + gopkg.in/ini.v1 v1.46.0 +) diff --git a/vendor/github.com/unknwon/i18n/go.sum b/vendor/github.com/unknwon/i18n/go.sum new file mode 100644 index 0000000000..8bb9e76563 --- /dev/null +++ b/vendor/github.com/unknwon/i18n/go.sum @@ -0,0 +1,21 @@ +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +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/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e h1:GSGeB9EAKY2spCABz6xOX5DbxZEXolK+nBSvmsQwRjM= +github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +gopkg.in/ini.v1 v1.46.0 h1:VeDZbLYGaupuvIrsYCEOe/L/2Pcs5n7hdO1ZTjporag= +gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/vendor/github.com/unknwon/i18n/i18n.go b/vendor/github.com/unknwon/i18n/i18n.go new file mode 100644 index 0000000000..38f0899dd3 --- /dev/null +++ b/vendor/github.com/unknwon/i18n/i18n.go @@ -0,0 +1,231 @@ +// Copyright 2013 Unknwon +// +// 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 i18n is for app Internationalization and Localization. +package i18n + +import ( + "errors" + "fmt" + "reflect" + "strings" + + "gopkg.in/ini.v1" +) + +var ( + ErrLangAlreadyExist = errors.New("Lang already exists") + + locales = &localeStore{store: make(map[string]*locale)} +) + +type locale struct { + id int + lang string + langDesc string + message *ini.File +} + +type localeStore struct { + langs []string + langDescs []string + store map[string]*locale + defaultLang string +} + +// Get target language string +func (d *localeStore) Get(lang, section, format string) (string, bool) { + if locale, ok := d.store[lang]; ok { + if key, err := locale.message.Section(section).GetKey(format); err == nil { + return key.Value(), true + } + } + + if len(d.defaultLang) > 0 && lang != d.defaultLang { + return d.Get(d.defaultLang, section, format) + } + + return "", false +} + +func (d *localeStore) Add(lc *locale) bool { + if _, ok := d.store[lc.lang]; ok { + return false + } + + lc.id = len(d.langs) + d.langs = append(d.langs, lc.lang) + d.langDescs = append(d.langDescs, lc.langDesc) + d.store[lc.lang] = lc + + return true +} + +func (d *localeStore) Reload(langs ...string) (err error) { + if len(langs) == 0 { + for _, lc := range d.store { + if err = lc.message.Reload(); err != nil { + return err + } + } + } else { + for _, lang := range langs { + if lc, ok := d.store[lang]; ok { + if err = lc.message.Reload(); err != nil { + return err + } + } + } + } + return nil +} + +// SetDefaultLang sets default language which is a indicator that +// when target language is not found, try find in default language again. +func SetDefaultLang(lang string) { + locales.defaultLang = lang +} + +// ReloadLangs reloads locale files. +func ReloadLangs(langs ...string) error { + return locales.Reload(langs...) +} + +// Count returns number of languages that are registered. +func Count() int { + return len(locales.langs) +} + +// ListLangs returns list of all locale languages. +func ListLangs() []string { + langs := make([]string, len(locales.langs)) + copy(langs, locales.langs) + return langs +} + +func ListLangDescs() []string { + langDescs := make([]string, len(locales.langDescs)) + copy(langDescs, locales.langDescs) + return langDescs +} + +// IsExist returns true if given language locale exists. +func IsExist(lang string) bool { + _, ok := locales.store[lang] + return ok +} + +// IndexLang returns index of language locale, +// it returns -1 if locale not exists. +func IndexLang(lang string) int { + if lc, ok := locales.store[lang]; ok { + return lc.id + } + return -1 +} + +// GetLangByIndex return language by given index. +func GetLangByIndex(index int) string { + if index < 0 || index >= len(locales.langs) { + return "" + } + return locales.langs[index] +} + +func GetDescriptionByIndex(index int) string { + if index < 0 || index >= len(locales.langDescs) { + return "" + } + + return locales.langDescs[index] +} + +func GetDescriptionByLang(lang string) string { + return GetDescriptionByIndex(IndexLang(lang)) +} + +func SetMessageWithDesc(lang, langDesc string, localeFile interface{}, otherLocaleFiles ...interface{}) error { + message, err := ini.LoadSources(ini.LoadOptions{ + IgnoreInlineComment: true, + UnescapeValueCommentSymbols: true, + }, localeFile, otherLocaleFiles...) + if err == nil { + message.BlockMode = false + lc := new(locale) + lc.lang = lang + lc.langDesc = langDesc + lc.message = message + + if locales.Add(lc) == false { + return ErrLangAlreadyExist + } + } + return err +} + +// SetMessage sets the message file for localization. +func SetMessage(lang string, localeFile interface{}, otherLocaleFiles ...interface{}) error { + return SetMessageWithDesc(lang, lang, localeFile, otherLocaleFiles...) +} + +// Locale represents the information of localization. +type Locale struct { + Lang string +} + +// Tr translates content to target language. +func (l Locale) Tr(format string, args ...interface{}) string { + return Tr(l.Lang, format, args...) +} + +// Index returns lang index of LangStore. +func (l Locale) Index() int { + return IndexLang(l.Lang) +} + +// Tr translates content to target language. +func Tr(lang, format string, args ...interface{}) string { + var section string + + idx := strings.IndexByte(format, '.') + if idx > 0 { + section = format[:idx] + format = format[idx+1:] + } + + value, ok := locales.Get(lang, section, format) + if ok { + format = value + } + + if len(args) > 0 { + params := make([]interface{}, 0, len(args)) + for _, arg := range args { + if arg == nil { + continue + } + + val := reflect.ValueOf(arg) + if val.Kind() == reflect.Slice { + for i := 0; i < val.Len(); i++ { + params = append(params, val.Index(i).Interface()) + } + } else { + params = append(params, arg) + } + } + return fmt.Sprintf(format, params...) + } + return format +} diff --git a/vendor/github.com/unknwon/paginater/.gitignore b/vendor/github.com/unknwon/paginater/.gitignore new file mode 100644 index 0000000000..e947a9a78b --- /dev/null +++ b/vendor/github.com/unknwon/paginater/.gitignore @@ -0,0 +1,26 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof +paginater.sublime-project +paginater.sublime-workspace diff --git a/vendor/github.com/unknwon/paginater/LICENSE b/vendor/github.com/unknwon/paginater/LICENSE new file mode 100644 index 0000000000..8f71f43fee --- /dev/null +++ b/vendor/github.com/unknwon/paginater/LICENSE @@ -0,0 +1,202 @@ + Apache 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: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) 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 + + (d) 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. + diff --git a/vendor/github.com/unknwon/paginater/README.md b/vendor/github.com/unknwon/paginater/README.md new file mode 100644 index 0000000000..8e608ed3ea --- /dev/null +++ b/vendor/github.com/unknwon/paginater/README.md @@ -0,0 +1,65 @@ +Paginater [![Build Status](https://drone.io/github.com/Unknwon/paginater/status.png)](https://drone.io/github.com/Unknwon/paginater/latest) [![](http://gocover.io/_badge/github.com/Unknwon/paginater)](http://gocover.io/github.com/Unknwon/paginater) +========= + +Package paginater is a helper module for custom pagination calculation. + +## Installation + + go get github.com/Unknwon/paginater + +## Getting Started + +The following code shows an example of how to use paginater: + +```go +package main + +import "github.com/Unknwon/paginater" + +func main() { + // Arguments: + // - Total number of rows + // - Number of rows in one page + // - Current page number + // - Number of page links + p := paginater.New(45, 10, 3, 3) + + // Then use p as a template object named "Page" in "demo.html" + // ... +} +``` + +`demo.html` + +```html +{{if not .Page.IsFirst}}[First](1){{end}} +{{if .Page.HasPrevious}}[Previous]({{.Page.Previous}}){{end}} + +{{range .Page.Pages}} + {{if eq .Num -1}} + ... + {{else}} + {{.Num}}{{if .IsCurrent}}(current){{end}} + {{end}} +{{end}} + +{{if .Page.HasNext}}[Next]({{.Page.Next}}){{end}} +{{if not .Page.IsLast}}[Last]({{.Page.TotalPages}}){{end}} +``` + +Possible output: + +``` +[First](1) [Previous](2) ... 2 3(current) 4 ... [Next](4) [Last](5) +``` + +As you may guess, if the `Page` value is `-1`, you should print `...` in the HTML as common practice. + +## Getting Help + +- [API Documentation](https://gowalker.org/github.com/Unknwon/paginater) +- [File An Issue](https://github.com/Unknwon/paginater/issues/new) + +## License + +This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text.
\ No newline at end of file diff --git a/vendor/github.com/unknwon/paginater/paginater.go b/vendor/github.com/unknwon/paginater/paginater.go new file mode 100644 index 0000000000..ca52a39980 --- /dev/null +++ b/vendor/github.com/unknwon/paginater/paginater.go @@ -0,0 +1,192 @@ +// Copyright 2015 Unknwon +// +// 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 paginater is a helper module for custom pagination calculation. +package paginater + +// Paginater represents a set of results of pagination calculations. +type Paginater struct { + total int + pagingNum int + current int + numPages int +} + +// New initialize a new pagination calculation and returns a Paginater as result. +func New(total, pagingNum, current, numPages int) *Paginater { + if pagingNum <= 0 { + pagingNum = 1 + } + if current <= 0 { + current = 1 + } + p := &Paginater{total, pagingNum, current, numPages} + if p.current > p.TotalPages() { + p.current = p.TotalPages() + } + return p +} + +// IsFirst returns true if current page is the first page. +func (p *Paginater) IsFirst() bool { + return p.current == 1 +} + +// HasPrevious returns true if there is a previous page relative to current page. +func (p *Paginater) HasPrevious() bool { + return p.current > 1 +} + +func (p *Paginater) Previous() int { + if !p.HasPrevious() { + return p.current + } + return p.current - 1 +} + +// HasNext returns true if there is a next page relative to current page. +func (p *Paginater) HasNext() bool { + return p.total > p.current*p.pagingNum +} + +func (p *Paginater) Next() int { + if !p.HasNext() { + return p.current + } + return p.current + 1 +} + +// IsLast returns true if current page is the last page. +func (p *Paginater) IsLast() bool { + if p.total == 0 { + return true + } + return p.total > (p.current-1)*p.pagingNum && !p.HasNext() +} + +// Total returns number of total rows. +func (p *Paginater) Total() int { + return p.total +} + +// TotalPage returns number of total pages. +func (p *Paginater) TotalPages() int { + if p.total == 0 { + return 1 + } + if p.total%p.pagingNum == 0 { + return p.total / p.pagingNum + } + return p.total/p.pagingNum + 1 +} + +// Current returns current page number. +func (p *Paginater) Current() int { + return p.current +} + +// Page presents a page in the paginater. +type Page struct { + num int + isCurrent bool +} + +func (p *Page) Num() int { + return p.num +} + +func (p *Page) IsCurrent() bool { + return p.isCurrent +} + +func getMiddleIdx(numPages int) int { + if numPages%2 == 0 { + return numPages / 2 + } + return numPages/2 + 1 +} + +// Pages returns a list of nearby page numbers relative to current page. +// If value is -1 means "..." that more pages are not showing. +func (p *Paginater) Pages() []*Page { + if p.numPages == 0 { + return []*Page{} + } else if p.numPages == 1 && p.TotalPages() == 1 { + // Only show current page. + return []*Page{{1, true}} + } + + // Total page number is less or equal. + if p.TotalPages() <= p.numPages { + pages := make([]*Page, p.TotalPages()) + for i := range pages { + pages[i] = &Page{i + 1, i+1 == p.current} + } + return pages + } + + numPages := p.numPages + maxIdx := numPages - 1 + offsetIdx := 0 + hasMoreNext := false + + // Check more previous and next pages. + previousNum := getMiddleIdx(p.numPages) - 1 + if previousNum > p.current-1 { + previousNum -= previousNum - (p.current - 1) + } + nextNum := p.numPages - previousNum - 1 + if p.current+nextNum > p.TotalPages() { + delta := nextNum - (p.TotalPages() - p.current) + nextNum -= delta + previousNum += delta + } + + offsetVal := p.current - previousNum + if offsetVal > 1 { + numPages++ + maxIdx++ + offsetIdx = 1 + } + + if p.current+nextNum < p.TotalPages() { + numPages++ + hasMoreNext = true + } + + pages := make([]*Page, numPages) + + // There are more previous pages. + if offsetIdx == 1 { + pages[0] = &Page{-1, false} + } + // There are more next pages. + if hasMoreNext { + pages[len(pages)-1] = &Page{-1, false} + } + + // Check previous pages. + for i := 0; i < previousNum; i++ { + pages[offsetIdx+i] = &Page{i + offsetVal, false} + } + + pages[offsetIdx+previousNum] = &Page{p.current, true} + + // Check next pages. + for i := 1; i <= nextNum; i++ { + pages[offsetIdx+previousNum+i] = &Page{p.current + i, false} + } + + return pages +} |