From 92726264135f46bc9976a2d67e0623e571f2e6a7 Mon Sep 17 00:00:00 2001 From: andeya Date: Mon, 27 Jun 2022 01:02:55 +0800 Subject: [PATCH] chore: rename mod --- README.md | 56 +- README_ZH.md | 54 +- _syso/index.html | 4 +- apidoc.go | 2 +- apiware/README.md | 6 +- context.go | 10 +- context_input.go | 2 +- context_output.go | 4 +- doc.go | 2 +- ext/barcode/codabar/encoder.go | 4 +- ext/barcode/code128/encode.go | 4 +- ext/barcode/code39/encoder.go | 4 +- ext/barcode/datamatrix/codelayout.go | 10 +- ext/barcode/datamatrix/datamatrixcode.go | 5 +- ext/barcode/datamatrix/encoder.go | 2 +- ext/barcode/datamatrix/errorcorrection.go | 2 +- ext/barcode/ean/encoder.go | 4 +- ext/barcode/qr/alphanumeric.go | 2 +- ext/barcode/qr/automatic.go | 2 +- ext/barcode/qr/encoder.go | 6 +- ext/barcode/qr/encoder_test.go | 2 +- ext/barcode/qr/errorcorrection.go | 2 +- ext/barcode/qr/helper.go | 2 +- ext/barcode/qr/numeric.go | 2 +- ext/barcode/qr/qrcode.go | 4 +- ext/barcode/qr/unicode.go | 2 +- ext/barcode/twooffive/encoder.go | 4 +- ext/barcode/utils/base1dcode.go | 2 +- ext/db/directsql/checkparameter.go | 96 +- ext/db/directsql/resultcache.go | 45 +- ext/db/directsql/snowflake.go | 16 +- ext/db/directsql/sqlcontext.go | 10 +- ext/db/directsql/sqlengine.go | 74 +- ext/db/directsql/sqlhandle.go | 242 +- ext/db/directsql/sqlmanage.go | 298 +- ext/db/directsql/sqlrouter.go | 2 +- ext/db/directsql/sqlservice.go | 94 +- ext/db/directsql/sqlwatcher.go | 15 +- ext/db/directsqlx/checkparameter.go | 94 +- ext/db/directsqlx/resultcache.go | 41 +- ext/db/directsqlx/sqlcontext.go | 10 +- ext/db/directsqlx/sqlengine.go | 52 +- ext/db/directsqlx/sqlhandle.go | 242 +- ext/db/directsqlx/sqlmanage.go | 272 +- ext/db/directsqlx/sqlrouter.go | 2 +- ext/db/directsqlx/sqlservice.go | 88 +- ext/db/directsqlx/sqlwatcher.go | 15 +- ext/db/gorm/config.go | 4 +- ext/db/gorm/helper.go | 2 +- ext/db/gorm/service.go | 6 +- ext/db/sqlx/config.go | 4 +- ext/db/sqlx/helper.go | 2 +- ext/db/sqlx/service.go | 6 +- ext/db/xorm/config.go | 4 +- ext/db/xorm/helper.go | 2 +- ext/db/xorm/logger.go | 4 +- ext/db/xorm/service.go | 6 +- ext/middleware/attachment.go | 2 +- ext/middleware/cross_origin.go | 2 +- ext/middleware/html_suffix.go | 4 +- ext/middleware/ip_filter.go | 2 +- ext/middleware/jwt/jwt.go | 10 +- ext/middleware/jwt/sample/server.go | 14 +- ext/otp/doc.go | 4 +- ext/otp/example/main.go | 4 +- ext/otp/hotp/hotp.go | 2 +- ext/otp/hotp/hotp_test.go | 2 +- ext/otp/otp.go | 4 +- ext/otp/totp/totp.go | 4 +- ext/otp/totp/totp_test.go | 2 +- ext/surfer/README.md | 14 +- ext/surfer/README_ZH.md | 14 +- ext/surfer/agent.go | 2 +- ext/surfer/body.go | 2 +- ext/surfer/example/example.go | 3 +- ext/surfer/phantom.go | 8 +- ext/surfer/request.go | 2 +- ext/surfer/surf.go | 2 +- ext/surfer/surfer.go | 10 +- ext/surfer/surfer_test.go | 2 +- ext/surfer/util.go | 2 +- ext/task/README.md | 2 +- ext/websocket/helper.go | 3 +- faygo.go | 8 +- framework.go | 10 +- freecache/cache.go | 2 +- freecache/server/main.go | 4 +- fs.go | 6 +- go.mod | 65 +- go.sum | 58 +- handler.go | 2 +- helper.go | 6 +- log.go | 4 +- log/app.pid | 1 + logging/examples/example.go | 2 +- render_pongo2.go | 2 +- samples/MultiUsage/main.go | 5 +- samples/demo/handler/body.go | 2 +- samples/demo/handler/param.go | 2 +- samples/demo/handler/proxy.go | 2 +- samples/demo/handler/render.go | 2 +- samples/demo/handler/websocket.go | 4 +- samples/demo/main.go | 4 +- samples/demo/middleware/index.go | 2 +- samples/demo/router/router.go | 8 +- samples/demo/static/markdown/README.md | 40 +- samples/demo/static/markdown/README.txt | 40 +- samples/directsql/common/pongo2func.go | 28 +- samples/directsql/handler/index.go | 2 +- samples/directsql/main.go | 8 +- samples/directsql/router/router.go | 6 +- samples/directsqlx/common/pongo2func.go | 28 +- samples/directsqlx/handler/index.go | 2 +- samples/directsqlx/main.go | 8 +- samples/directsqlx/router/router.go | 6 +- samples/myconfig/main.go | 2 +- server.go | 4 +- session/README.md | 2 +- session/couchbase/sess_couchbase.go | 4 +- session/ledis/ledis_session.go | 4 +- session/memcache/sess_memcache.go | 4 +- session/mysql/sess_mysql.go | 4 +- session/postgres/sess_postgresql.go | 4 +- session/redis/sess_redis.go | 4 +- session/sess_cookie.go | 2 +- session/sess_test.go | 2 +- session/sess_utils.go | 2 +- session/ssdb/sess_ssdb.go | 8 +- syso_windows_386.go | 2 +- tree.go | 2 +- .../{henrylee2cn => andeya}/goutil/.gitignore | 3 + vendor/github.com/andeya/goutil/.travis.yml | 19 + vendor/github.com/andeya/goutil/LICENSE | 21 + vendor/github.com/andeya/goutil/README.md | 9 + .../{henrylee2cn => andeya}/goutil/currip.go | 6 +- .../{henrylee2cn => andeya}/goutil/doc.go | 2 +- vendor/github.com/andeya/goutil/encrypt.go | 274 + .../goutil/errors/errors.go | 2 +- .../{henrylee2cn => andeya}/goutil/file.go | 24 +- vendor/github.com/andeya/goutil/gopath.go | 75 + vendor/github.com/andeya/goutil/gotest.go | 41 + .../{henrylee2cn => andeya}/goutil/js_url.go | 0 vendor/github.com/andeya/goutil/kvdata.go | 109 + .../{henrylee2cn => andeya}/goutil/map.go | 16 +- vendor/github.com/andeya/goutil/other.go | 135 + .../goutil/pid_file.go | 0 .../{henrylee2cn => andeya}/goutil/random.go | 41 +- vendor/github.com/andeya/goutil/sets.go | 233 + .../{henrylee2cn => andeya}/goutil/string.go | 176 +- .../{henrylee2cn => andeya}/goutil/targz.go | 0 .../{henrylee2cn => andeya}/goutil/trace.go | 0 .../exported.go => andeya/goutil/type.go} | 22 + .../{henrylee2cn => andeya}/ini/.gitignore | 0 .../{henrylee2cn => andeya}/ini/.travis.yml | 0 .../{henrylee2cn => andeya}/ini/LICENSE | 0 .../{henrylee2cn => andeya}/ini/Makefile | 0 .../{henrylee2cn => andeya}/ini/README.md | 0 .../{henrylee2cn => andeya}/ini/README_ZH.md | 0 .../{henrylee2cn => andeya}/ini/error.go | 0 .../{henrylee2cn => andeya}/ini/helper.go | 6 +- .../{henrylee2cn => andeya}/ini/ini.go | 0 .../{henrylee2cn => andeya}/ini/key.go | 0 .../{henrylee2cn => andeya}/ini/parser.go | 0 .../{henrylee2cn => andeya}/ini/section.go | 0 .../{henrylee2cn => andeya}/ini/struct.go | 0 vendor/github.com/facebookgo/ensure/patents | 33 - vendor/github.com/flosch/pongo2/go.mod | 13 - .../github.com/gorilla/websocket/.travis.yml | 19 - vendor/github.com/gorilla/websocket/README.md | 47 +- vendor/github.com/gorilla/websocket/client.go | 81 +- .../gorilla/websocket/client_clone.go | 16 - .../gorilla/websocket/client_clone_legacy.go | 38 - vendor/github.com/gorilla/websocket/conn.go | 189 +- .../gorilla/websocket/conn_write.go | 15 - .../gorilla/websocket/conn_write_legacy.go | 18 - vendor/github.com/gorilla/websocket/doc.go | 47 + vendor/github.com/gorilla/websocket/join.go | 42 + vendor/github.com/gorilla/websocket/mask.go | 1 + .../github.com/gorilla/websocket/mask_safe.go | 1 + .../github.com/gorilla/websocket/prepared.go | 4 +- vendor/github.com/gorilla/websocket/proxy.go | 10 +- vendor/github.com/gorilla/websocket/server.go | 12 +- .../gorilla/websocket/tls_handshake.go | 21 + .../gorilla/websocket/tls_handshake_116.go | 21 + vendor/github.com/gorilla/websocket/trace.go | 19 - .../github.com/gorilla/websocket/trace_17.go | 12 - vendor/github.com/gorilla/websocket/util.go | 132 +- .../github.com/henrylee2cn/ameda/.gitignore | 21 + vendor/github.com/henrylee2cn/ameda/LICENSE | 21 + vendor/github.com/henrylee2cn/ameda/README.md | 3 + vendor/github.com/henrylee2cn/ameda/atoi62.go | 253 + vendor/github.com/henrylee2cn/ameda/atoi_x.go | 27 + vendor/github.com/henrylee2cn/ameda/bool.go | 200 + vendor/github.com/henrylee2cn/ameda/bools.go | 580 ++ .../github.com/henrylee2cn/ameda/float32.go | 217 + .../github.com/henrylee2cn/ameda/float32s.go | 680 ++ .../github.com/henrylee2cn/ameda/float64.go | 220 + .../github.com/henrylee2cn/ameda/float64s.go | 684 ++ .../henrylee2cn/ameda/initialize.go | 299 + vendor/github.com/henrylee2cn/ameda/int.go | 206 + vendor/github.com/henrylee2cn/ameda/int16.go | 186 + vendor/github.com/henrylee2cn/ameda/int16s.go | 678 ++ vendor/github.com/henrylee2cn/ameda/int32.go | 192 + vendor/github.com/henrylee2cn/ameda/int32s.go | 682 ++ vendor/github.com/henrylee2cn/ameda/int64.go | 201 + vendor/github.com/henrylee2cn/ameda/int64s.go | 692 ++ vendor/github.com/henrylee2cn/ameda/int8.go | 179 + vendor/github.com/henrylee2cn/ameda/int8s.go | 679 ++ .../github.com/henrylee2cn/ameda/interface.go | 812 ++ .../henrylee2cn/ameda/interfaces.go | 643 ++ vendor/github.com/henrylee2cn/ameda/ints.go | 682 ++ vendor/github.com/henrylee2cn/ameda/itoa62.go | 210 + vendor/github.com/henrylee2cn/ameda/itoa_x.go | 21 + vendor/github.com/henrylee2cn/ameda/string.go | 242 + .../github.com/henrylee2cn/ameda/strings.go | 710 ++ .../github.com/henrylee2cn/ameda/typconv.go | 138 + vendor/github.com/henrylee2cn/ameda/uint.go | 203 + vendor/github.com/henrylee2cn/ameda/uint16.go | 174 + .../github.com/henrylee2cn/ameda/uint16s.go | 668 ++ vendor/github.com/henrylee2cn/ameda/uint32.go | 180 + .../github.com/henrylee2cn/ameda/uint32s.go | 676 ++ vendor/github.com/henrylee2cn/ameda/uint64.go | 189 + .../github.com/henrylee2cn/ameda/uint64s.go | 688 ++ vendor/github.com/henrylee2cn/ameda/uint8.go | 168 + vendor/github.com/henrylee2cn/ameda/uint8s.go | 658 ++ vendor/github.com/henrylee2cn/ameda/uints.go | 686 ++ vendor/github.com/henrylee2cn/ameda/utils.go | 107 + vendor/github.com/henrylee2cn/ameda/value.go | 301 + .../github.com/henrylee2cn/goutil/README.md | 27 - .../github.com/henrylee2cn/goutil/encrypt.go | 91 - .../github.com/henrylee2cn/goutil/gopath.go | 47 - .../github.com/henrylee2cn/goutil/gotest.go | 31 - vendor/github.com/henrylee2cn/goutil/other.go | 67 - vendor/github.com/henrylee2cn/goutil/sets.go | 462 - vendor/github.com/jinzhu/gorm/go.mod | 13 - vendor/github.com/jinzhu/gorm/go.sum | 131 - vendor/github.com/jinzhu/inflection/go.mod | 1 - vendor/github.com/jmoiron/sqlx/go.mod | 7 - vendor/github.com/jmoiron/sqlx/go.sum | 6 - vendor/github.com/json-iterator/go/go.mod | 11 - vendor/github.com/json-iterator/go/go.sum | 14 - vendor/github.com/kr/pretty/go.mod | 3 - vendor/github.com/kr/text/go.mod | 3 - vendor/github.com/lib/pq/go.mod | 1 - vendor/github.com/pelletier/go-toml/go.mod | 9 - vendor/github.com/pelletier/go-toml/go.sum | 7 - vendor/github.com/stretchr/testify/LICENSE | 2 +- .../testify/assert/assertion_compare.go | 458 + .../assert/assertion_compare_can_convert.go | 16 + .../assert/assertion_compare_legacy.go | 16 + .../testify/assert/assertion_format.go | 227 +- .../testify/assert/assertion_forward.go | 436 +- .../testify/assert/assertion_order.go | 332 +- .../stretchr/testify/assert/assertions.go | 597 +- .../testify/assert/forward_assertions.go | 2 +- .../testify/assert/http_assertions.go | 25 +- .../testify/require/forward_requirements.go | 2 +- .../stretchr/testify/require/require.go | 558 +- .../testify/require/require_forward.go | 436 +- .../stretchr/testify/require/requirements.go | 2 +- vendor/golang.org/x/crypto/acme/acme.go | 482 +- .../x/crypto/acme/autocert/autocert.go | 345 +- .../x/crypto/acme/autocert/cache.go | 14 +- .../x/crypto/acme/autocert/listener.go | 4 +- .../x/crypto/acme/autocert/renewal.go | 35 +- vendor/golang.org/x/crypto/acme/http.go | 32 +- vendor/golang.org/x/crypto/acme/jws.go | 155 +- vendor/golang.org/x/crypto/acme/rfc8555.go | 477 + vendor/golang.org/x/crypto/acme/types.go | 381 +- .../golang.org/x/crypto/acme/version_go112.go | 1 + vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go | 2 +- vendor/golang.org/x/net/context/context.go | 6 +- vendor/golang.org/x/net/context/go17.go | 11 +- vendor/golang.org/x/net/context/go19.go | 1 + vendor/golang.org/x/net/context/pre_go17.go | 11 +- vendor/golang.org/x/net/context/pre_go19.go | 1 + vendor/golang.org/x/net/html/const.go | 3 +- vendor/golang.org/x/net/html/foreign.go | 120 +- vendor/golang.org/x/net/html/node.go | 5 + vendor/golang.org/x/net/html/parse.go | 337 +- vendor/golang.org/x/net/html/render.go | 34 +- vendor/golang.org/x/net/html/token.go | 9 +- vendor/golang.org/x/net/idna/go118.go | 14 + vendor/golang.org/x/net/idna/idna10.0.0.go | 118 +- vendor/golang.org/x/net/idna/idna9.0.0.go | 98 +- vendor/golang.org/x/net/idna/pre_go118.go | 12 + vendor/golang.org/x/net/idna/punycode.go | 36 +- vendor/golang.org/x/net/idna/tables10.0.0.go | 1 + vendor/golang.org/x/net/idna/tables11.0.0.go | 3 +- vendor/golang.org/x/net/idna/tables12.0.0.go | 4734 ++++++++++ vendor/golang.org/x/net/idna/tables13.0.0.go | 4840 ++++++++++ vendor/golang.org/x/net/idna/tables9.0.0.go | 1 + vendor/golang.org/x/net/idna/trieval.go | 34 +- .../sys/internal/unsafeheader/unsafeheader.go | 30 + vendor/golang.org/x/sys/unix/README.md | 21 +- .../golang.org/x/sys/unix/affinity_linux.go | 46 +- vendor/golang.org/x/sys/unix/aliases.go | 3 +- vendor/golang.org/x/sys/unix/asm_aix_ppc64.s | 3 +- .../unix/{asm_netbsd_386.s => asm_bsd_386.s} | 12 +- .../{asm_openbsd_amd64.s => asm_bsd_amd64.s} | 10 +- .../unix/{asm_darwin_arm.s => asm_bsd_arm.s} | 11 +- .../{asm_netbsd_amd64.s => asm_bsd_arm64.s} | 10 +- vendor/golang.org/x/sys/unix/asm_darwin_386.s | 29 - .../golang.org/x/sys/unix/asm_darwin_amd64.s | 29 - .../golang.org/x/sys/unix/asm_darwin_arm64.s | 30 - .../x/sys/unix/asm_dragonfly_amd64.s | 29 - .../golang.org/x/sys/unix/asm_freebsd_386.s | 29 - .../golang.org/x/sys/unix/asm_freebsd_amd64.s | 29 - .../golang.org/x/sys/unix/asm_freebsd_arm.s | 29 - .../golang.org/x/sys/unix/asm_freebsd_arm64.s | 29 - vendor/golang.org/x/sys/unix/asm_linux_386.s | 3 +- .../golang.org/x/sys/unix/asm_linux_amd64.s | 3 +- vendor/golang.org/x/sys/unix/asm_linux_arm.s | 3 +- .../golang.org/x/sys/unix/asm_linux_arm64.s | 3 +- .../golang.org/x/sys/unix/asm_linux_loong64.s | 54 + .../golang.org/x/sys/unix/asm_linux_mips64x.s | 3 +- .../golang.org/x/sys/unix/asm_linux_mipsx.s | 3 +- .../golang.org/x/sys/unix/asm_linux_ppc64x.s | 3 +- .../golang.org/x/sys/unix/asm_linux_riscv64.s | 11 +- .../golang.org/x/sys/unix/asm_linux_s390x.s | 5 +- vendor/golang.org/x/sys/unix/asm_netbsd_arm.s | 29 - .../golang.org/x/sys/unix/asm_netbsd_arm64.s | 29 - .../golang.org/x/sys/unix/asm_openbsd_386.s | 29 - .../golang.org/x/sys/unix/asm_openbsd_arm.s | 29 - ...m_openbsd_arm64.s => asm_openbsd_mips64.s} | 5 +- .../golang.org/x/sys/unix/asm_solaris_amd64.s | 3 +- vendor/golang.org/x/sys/unix/asm_zos_s390x.s | 426 + .../golang.org/x/sys/unix/bluetooth_linux.go | 1 + vendor/golang.org/x/sys/unix/cap_freebsd.go | 1 + vendor/golang.org/x/sys/unix/constants.go | 3 +- vendor/golang.org/x/sys/unix/dev_aix_ppc.go | 4 +- vendor/golang.org/x/sys/unix/dev_aix_ppc64.go | 4 +- vendor/golang.org/x/sys/unix/dev_zos.go | 29 + vendor/golang.org/x/sys/unix/dirent.go | 1 + vendor/golang.org/x/sys/unix/endian_big.go | 3 +- vendor/golang.org/x/sys/unix/endian_little.go | 3 +- vendor/golang.org/x/sys/unix/env_unix.go | 3 +- vendor/golang.org/x/sys/unix/epoll_zos.go | 221 + .../x/sys/unix/errors_freebsd_386.go | 6 + .../x/sys/unix/errors_freebsd_amd64.go | 6 + .../x/sys/unix/errors_freebsd_arm64.go | 17 + vendor/golang.org/x/sys/unix/fcntl.go | 13 +- vendor/golang.org/x/sys/unix/fcntl_darwin.go | 6 + .../x/sys/unix/fcntl_linux_32bit.go | 5 +- vendor/golang.org/x/sys/unix/fdset.go | 30 + vendor/golang.org/x/sys/unix/fstatfs_zos.go | 164 + vendor/golang.org/x/sys/unix/gccgo.go | 6 +- vendor/golang.org/x/sys/unix/gccgo_c.c | 6 + .../x/sys/unix/gccgo_linux_amd64.go | 1 + vendor/golang.org/x/sys/unix/ifreq_linux.go | 142 + vendor/golang.org/x/sys/unix/ioctl.go | 51 +- vendor/golang.org/x/sys/unix/ioctl_linux.go | 219 + vendor/golang.org/x/sys/unix/ioctl_zos.go | 74 + vendor/golang.org/x/sys/unix/mkall.sh | 44 +- vendor/golang.org/x/sys/unix/mkerrors.sh | 158 +- vendor/golang.org/x/sys/unix/pagesize_unix.go | 1 + vendor/golang.org/x/sys/unix/ptrace_darwin.go | 12 + vendor/golang.org/x/sys/unix/ptrace_ios.go | 12 + vendor/golang.org/x/sys/unix/race.go | 1 + vendor/golang.org/x/sys/unix/race0.go | 3 +- .../x/sys/unix/readdirent_getdents.go | 1 + .../x/sys/unix/readdirent_getdirentries.go | 1 + .../x/sys/unix/sockcmsg_dragonfly.go | 16 + .../golang.org/x/sys/unix/sockcmsg_linux.go | 51 +- vendor/golang.org/x/sys/unix/sockcmsg_unix.go | 39 +- .../x/sys/unix/sockcmsg_unix_other.go | 47 + vendor/golang.org/x/sys/unix/str.go | 1 + vendor/golang.org/x/sys/unix/syscall.go | 46 +- vendor/golang.org/x/sys/unix/syscall_aix.go | 118 +- .../golang.org/x/sys/unix/syscall_aix_ppc.go | 8 +- .../x/sys/unix/syscall_aix_ppc64.go | 8 +- vendor/golang.org/x/sys/unix/syscall_bsd.go | 169 +- .../x/sys/unix/syscall_darwin.1_12.go | 32 + .../x/sys/unix/syscall_darwin.1_13.go | 108 + .../golang.org/x/sys/unix/syscall_darwin.go | 362 +- .../x/sys/unix/syscall_darwin_386.go | 63 - .../x/sys/unix/syscall_darwin_amd64.go | 26 +- .../x/sys/unix/syscall_darwin_arm.go | 64 - .../x/sys/unix/syscall_darwin_arm64.go | 29 +- .../x/sys/unix/syscall_darwin_libSystem.go | 12 +- .../x/sys/unix/syscall_dragonfly.go | 116 +- .../x/sys/unix/syscall_dragonfly_amd64.go | 5 + .../golang.org/x/sys/unix/syscall_freebsd.go | 107 +- .../x/sys/unix/syscall_freebsd_386.go | 15 + .../x/sys/unix/syscall_freebsd_amd64.go | 15 + .../x/sys/unix/syscall_freebsd_arm.go | 11 + .../x/sys/unix/syscall_freebsd_arm64.go | 11 + .../golang.org/x/sys/unix/syscall_illumos.go | 185 + vendor/golang.org/x/sys/unix/syscall_linux.go | 1063 ++- .../x/sys/unix/syscall_linux_386.go | 70 +- .../x/sys/unix/syscall_linux_alarm.go | 14 + .../x/sys/unix/syscall_linux_amd64.go | 63 +- .../x/sys/unix/syscall_linux_amd64_gc.go | 4 +- .../x/sys/unix/syscall_linux_arm.go | 69 +- .../x/sys/unix/syscall_linux_arm64.go | 76 +- .../golang.org/x/sys/unix/syscall_linux_gc.go | 3 +- .../x/sys/unix/syscall_linux_gc_386.go | 3 +- .../x/sys/unix/syscall_linux_gc_arm.go | 14 + .../x/sys/unix/syscall_linux_gccgo_386.go | 1 + .../x/sys/unix/syscall_linux_gccgo_arm.go | 1 + .../x/sys/unix/syscall_linux_loong64.go | 226 + .../x/sys/unix/syscall_linux_mips64x.go | 49 +- .../x/sys/unix/syscall_linux_mipsx.go | 57 +- .../x/sys/unix/syscall_linux_ppc.go | 236 + .../x/sys/unix/syscall_linux_ppc64x.go | 52 +- .../x/sys/unix/syscall_linux_riscv64.go | 66 +- .../x/sys/unix/syscall_linux_s390x.go | 64 +- .../x/sys/unix/syscall_linux_sparc64.go | 51 +- .../golang.org/x/sys/unix/syscall_netbsd.go | 112 +- .../x/sys/unix/syscall_netbsd_386.go | 5 + .../x/sys/unix/syscall_netbsd_amd64.go | 5 + .../x/sys/unix/syscall_netbsd_arm.go | 5 + .../x/sys/unix/syscall_netbsd_arm64.go | 5 + .../golang.org/x/sys/unix/syscall_openbsd.go | 106 +- .../x/sys/unix/syscall_openbsd_386.go | 5 + .../x/sys/unix/syscall_openbsd_amd64.go | 5 + .../x/sys/unix/syscall_openbsd_arm.go | 5 + .../x/sys/unix/syscall_openbsd_arm64.go | 5 + .../x/sys/unix/syscall_openbsd_mips64.go | 35 + .../golang.org/x/sys/unix/syscall_solaris.go | 439 +- .../x/sys/unix/syscall_solaris_amd64.go | 5 + vendor/golang.org/x/sys/unix/syscall_unix.go | 145 +- .../golang.org/x/sys/unix/syscall_unix_gc.go | 5 +- .../x/sys/unix/syscall_unix_gc_ppc64x.go | 3 +- .../x/sys/unix/syscall_zos_s390x.go | 1823 ++++ vendor/golang.org/x/sys/unix/sysvshm_linux.go | 21 + vendor/golang.org/x/sys/unix/sysvshm_unix.go | 61 + .../x/sys/unix/sysvshm_unix_other.go | 14 + vendor/golang.org/x/sys/unix/timestruct.go | 29 +- vendor/golang.org/x/sys/unix/xattr_bsd.go | 1 + .../golang.org/x/sys/unix/zerrors_aix_ppc.go | 13 +- .../x/sys/unix/zerrors_aix_ppc64.go | 13 +- .../x/sys/unix/zerrors_darwin_amd64.go | 3047 +++---- .../x/sys/unix/zerrors_darwin_arm.go | 1783 ---- .../x/sys/unix/zerrors_darwin_arm64.go | 3047 +++---- .../x/sys/unix/zerrors_dragonfly_amd64.go | 140 +- .../x/sys/unix/zerrors_freebsd_386.go | 181 +- .../x/sys/unix/zerrors_freebsd_amd64.go | 179 +- .../x/sys/unix/zerrors_freebsd_arm.go | 46 +- .../x/sys/unix/zerrors_freebsd_arm64.go | 180 +- vendor/golang.org/x/sys/unix/zerrors_linux.go | 3107 +++++++ .../x/sys/unix/zerrors_linux_386.go | 3206 ++----- .../x/sys/unix/zerrors_linux_amd64.go | 3206 ++----- .../x/sys/unix/zerrors_linux_arm.go | 3218 ++----- .../x/sys/unix/zerrors_linux_arm64.go | 3195 ++----- .../x/sys/unix/zerrors_linux_loong64.go | 818 ++ .../x/sys/unix/zerrors_linux_mips.go | 3210 ++----- .../x/sys/unix/zerrors_linux_mips64.go | 3210 ++----- .../x/sys/unix/zerrors_linux_mips64le.go | 3210 ++----- .../x/sys/unix/zerrors_linux_mipsle.go | 3210 ++----- .../x/sys/unix/zerrors_linux_ppc.go | 887 ++ .../x/sys/unix/zerrors_linux_ppc64.go | 3329 ++----- .../x/sys/unix/zerrors_linux_ppc64le.go | 3329 ++----- .../x/sys/unix/zerrors_linux_riscv64.go | 3180 ++----- .../x/sys/unix/zerrors_linux_s390x.go | 3328 ++----- .../x/sys/unix/zerrors_linux_sparc64.go | 3307 ++----- .../x/sys/unix/zerrors_netbsd_386.go | 10 +- .../x/sys/unix/zerrors_netbsd_amd64.go | 10 +- .../x/sys/unix/zerrors_netbsd_arm.go | 10 +- .../x/sys/unix/zerrors_netbsd_arm64.go | 10 +- .../x/sys/unix/zerrors_openbsd_386.go | 28 +- .../x/sys/unix/zerrors_openbsd_amd64.go | 14 +- .../x/sys/unix/zerrors_openbsd_arm.go | 22 +- .../x/sys/unix/zerrors_openbsd_arm64.go | 9 + ...arwin_386.go => zerrors_openbsd_mips64.go} | 1666 ++-- .../x/sys/unix/zerrors_solaris_amd64.go | 29 +- .../x/sys/unix/zerrors_zos_s390x.go | 860 ++ ...acearm_linux.go => zptrace_armnn_linux.go} | 3 +- .../x/sys/unix/zptrace_linux_arm64.go | 17 + ...emips_linux.go => zptrace_mipsnn_linux.go} | 3 +- ...sle_linux.go => zptrace_mipsnnle_linux.go} | 3 +- ...trace386_linux.go => zptrace_x86_linux.go} | 3 +- .../golang.org/x/sys/unix/zsyscall_aix_ppc.go | 27 +- .../x/sys/unix/zsyscall_aix_ppc64.go | 25 +- .../x/sys/unix/zsyscall_aix_ppc64_gc.go | 24 +- .../x/sys/unix/zsyscall_aix_ppc64_gccgo.go | 22 +- .../x/sys/unix/zsyscall_darwin_386.1_11.go | 1810 ---- .../x/sys/unix/zsyscall_darwin_386.go | 2505 ------ .../x/sys/unix/zsyscall_darwin_386.s | 284 - .../x/sys/unix/zsyscall_darwin_amd64.1_11.go | 1810 ---- .../x/sys/unix/zsyscall_darwin_amd64.1_13.go | 40 + .../x/sys/unix/zsyscall_darwin_amd64.1_13.s | 25 + .../x/sys/unix/zsyscall_darwin_amd64.go | 1033 ++- .../x/sys/unix/zsyscall_darwin_amd64.s | 897 +- .../x/sys/unix/zsyscall_darwin_arm.1_11.go | 1793 ---- .../x/sys/unix/zsyscall_darwin_arm.go | 2483 ------ .../x/sys/unix/zsyscall_darwin_arm.s | 282 - .../x/sys/unix/zsyscall_darwin_arm64.1_13.go | 40 + .../x/sys/unix/zsyscall_darwin_arm64.1_13.s | 25 + .../x/sys/unix/zsyscall_darwin_arm64.go | 1022 +-- .../x/sys/unix/zsyscall_darwin_arm64.s | 895 +- .../x/sys/unix/zsyscall_dragonfly_amd64.go | 61 +- .../x/sys/unix/zsyscall_freebsd_386.go | 73 +- .../x/sys/unix/zsyscall_freebsd_amd64.go | 71 +- .../x/sys/unix/zsyscall_freebsd_arm.go | 61 +- .../x/sys/unix/zsyscall_freebsd_arm64.go | 63 +- .../x/sys/unix/zsyscall_illumos_amd64.go | 128 + .../golang.org/x/sys/unix/zsyscall_linux.go | 2153 +++++ .../x/sys/unix/zsyscall_linux_386.go | 1767 +--- .../x/sys/unix/zsyscall_linux_amd64.go | 1807 +--- .../x/sys/unix/zsyscall_linux_arm.go | 1787 +--- .../x/sys/unix/zsyscall_linux_arm64.go | 1743 +--- .../x/sys/unix/zsyscall_linux_loong64.go | 527 ++ .../x/sys/unix/zsyscall_linux_mips.go | 1786 +--- .../x/sys/unix/zsyscall_linux_mips64.go | 1757 +--- .../x/sys/unix/zsyscall_linux_mips64le.go | 1760 +--- .../x/sys/unix/zsyscall_linux_mipsle.go | 1786 +--- .../x/sys/unix/zsyscall_linux_ppc.go | 709 ++ .../x/sys/unix/zsyscall_linux_ppc64.go | 1800 +--- .../x/sys/unix/zsyscall_linux_ppc64le.go | 1800 +--- .../x/sys/unix/zsyscall_linux_riscv64.go | 1739 +--- .../x/sys/unix/zsyscall_linux_s390x.go | 1769 +--- .../x/sys/unix/zsyscall_linux_sparc64.go | 1767 +--- .../x/sys/unix/zsyscall_netbsd_386.go | 94 +- .../x/sys/unix/zsyscall_netbsd_amd64.go | 94 +- .../x/sys/unix/zsyscall_netbsd_arm.go | 94 +- .../x/sys/unix/zsyscall_netbsd_arm64.go | 94 +- .../x/sys/unix/zsyscall_openbsd_386.go | 67 +- .../x/sys/unix/zsyscall_openbsd_amd64.go | 67 +- .../x/sys/unix/zsyscall_openbsd_arm.go | 67 +- .../x/sys/unix/zsyscall_openbsd_arm64.go | 67 +- ...m64.1_11.go => zsyscall_openbsd_mips64.go} | 550 +- .../x/sys/unix/zsyscall_solaris_amd64.go | 140 +- .../x/sys/unix/zsyscall_zos_s390x.go | 1255 +++ .../x/sys/unix/zsysctl_openbsd_386.go | 4 +- .../x/sys/unix/zsysctl_openbsd_amd64.go | 2 + .../x/sys/unix/zsysctl_openbsd_arm.go | 2 + .../x/sys/unix/zsysctl_openbsd_arm64.go | 1 + .../x/sys/unix/zsysctl_openbsd_mips64.go | 280 + .../x/sys/unix/zsysnum_darwin_386.go | 436 - .../x/sys/unix/zsysnum_darwin_amd64.go | 2 + .../x/sys/unix/zsysnum_darwin_arm.go | 436 - .../x/sys/unix/zsysnum_darwin_arm64.go | 2 + .../x/sys/unix/zsysnum_dragonfly_amd64.go | 256 +- .../x/sys/unix/zsysnum_freebsd_386.go | 1 + .../x/sys/unix/zsysnum_freebsd_amd64.go | 1 + .../x/sys/unix/zsysnum_freebsd_arm.go | 1 + .../x/sys/unix/zsysnum_freebsd_arm64.go | 1 + .../x/sys/unix/zsysnum_linux_386.go | 18 + .../x/sys/unix/zsysnum_linux_amd64.go | 708 +- .../x/sys/unix/zsysnum_linux_arm.go | 18 + .../x/sys/unix/zsysnum_linux_arm64.go | 598 +- .../x/sys/unix/zsysnum_linux_loong64.go | 311 + .../x/sys/unix/zsysnum_linux_mips.go | 17 + .../x/sys/unix/zsysnum_linux_mips64.go | 693 +- .../x/sys/unix/zsysnum_linux_mips64le.go | 693 +- .../x/sys/unix/zsysnum_linux_mipsle.go | 17 + .../x/sys/unix/zsysnum_linux_ppc.go | 441 + .../x/sys/unix/zsysnum_linux_ppc64.go | 791 +- .../x/sys/unix/zsysnum_linux_ppc64le.go | 791 +- .../x/sys/unix/zsysnum_linux_riscv64.go | 596 +- .../x/sys/unix/zsysnum_linux_s390x.go | 721 +- .../x/sys/unix/zsysnum_linux_sparc64.go | 750 +- .../x/sys/unix/zsysnum_netbsd_386.go | 1 + .../x/sys/unix/zsysnum_netbsd_amd64.go | 1 + .../x/sys/unix/zsysnum_netbsd_arm.go | 1 + .../x/sys/unix/zsysnum_netbsd_arm64.go | 1 + .../x/sys/unix/zsysnum_openbsd_386.go | 1 + .../x/sys/unix/zsysnum_openbsd_amd64.go | 1 + .../x/sys/unix/zsysnum_openbsd_arm.go | 1 + .../x/sys/unix/zsysnum_openbsd_arm64.go | 1 + .../x/sys/unix/zsysnum_openbsd_mips64.go | 221 + .../x/sys/unix/zsysnum_zos_s390x.go | 2670 ++++++ .../golang.org/x/sys/unix/ztypes_aix_ppc.go | 2 + .../golang.org/x/sys/unix/ztypes_aix_ppc64.go | 2 + .../x/sys/unix/ztypes_darwin_386.go | 499 -- .../x/sys/unix/ztypes_darwin_amd64.go | 346 +- .../x/sys/unix/ztypes_darwin_arm.go | 500 -- .../x/sys/unix/ztypes_darwin_arm64.go | 346 +- .../x/sys/unix/ztypes_dragonfly_amd64.go | 61 +- .../x/sys/unix/ztypes_freebsd_386.go | 69 +- .../x/sys/unix/ztypes_freebsd_amd64.go | 54 +- .../x/sys/unix/ztypes_freebsd_arm.go | 42 +- .../x/sys/unix/ztypes_freebsd_arm64.go | 84 +- .../x/sys/unix/ztypes_illumos_amd64.go | 42 + vendor/golang.org/x/sys/unix/ztypes_linux.go | 5596 ++++++++++++ .../golang.org/x/sys/unix/ztypes_linux_386.go | 2055 +---- .../x/sys/unix/ztypes_linux_amd64.go | 2056 +---- .../golang.org/x/sys/unix/ztypes_linux_arm.go | 2059 +---- .../x/sys/unix/ztypes_linux_arm64.go | 2056 +---- .../x/sys/unix/ztypes_linux_loong64.go | 685 ++ .../x/sys/unix/ztypes_linux_mips.go | 2058 +---- .../x/sys/unix/ztypes_linux_mips64.go | 2057 +---- .../x/sys/unix/ztypes_linux_mips64le.go | 2057 +---- .../x/sys/unix/ztypes_linux_mipsle.go | 2058 +---- .../golang.org/x/sys/unix/ztypes_linux_ppc.go | 698 ++ .../x/sys/unix/ztypes_linux_ppc64.go | 2055 +---- .../x/sys/unix/ztypes_linux_ppc64le.go | 2055 +---- .../x/sys/unix/ztypes_linux_riscv64.go | 2057 +---- .../x/sys/unix/ztypes_linux_s390x.go | 2059 +---- .../x/sys/unix/ztypes_linux_sparc64.go | 2055 +---- .../x/sys/unix/ztypes_netbsd_386.go | 38 +- .../x/sys/unix/ztypes_netbsd_amd64.go | 39 +- .../x/sys/unix/ztypes_netbsd_arm.go | 38 +- .../x/sys/unix/ztypes_netbsd_arm64.go | 39 +- .../x/sys/unix/ztypes_openbsd_386.go | 25 +- .../x/sys/unix/ztypes_openbsd_amd64.go | 25 +- .../x/sys/unix/ztypes_openbsd_arm.go | 25 +- .../x/sys/unix/ztypes_openbsd_arm64.go | 25 +- .../x/sys/unix/ztypes_openbsd_mips64.go | 568 ++ .../x/sys/unix/ztypes_solaris_amd64.go | 82 +- .../golang.org/x/sys/unix/ztypes_zos_s390x.go | 406 + vendor/golang.org/x/sys/windows/aliases.go | 4 +- .../x/sys/windows/asm_windows_386.s | 13 - .../x/sys/windows/asm_windows_amd64.s | 13 - .../x/sys/windows/asm_windows_arm.s | 11 - .../golang.org/x/sys/windows/dll_windows.go | 52 +- vendor/golang.org/x/sys/windows/empty.s | 9 + .../golang.org/x/sys/windows/env_windows.go | 11 +- vendor/golang.org/x/sys/windows/eventlog.go | 1 + .../golang.org/x/sys/windows/exec_windows.go | 91 +- .../x/sys/windows/memory_windows.go | 36 +- vendor/golang.org/x/sys/windows/mkerrors.bash | 7 + vendor/golang.org/x/sys/windows/mksyscall.go | 3 +- vendor/golang.org/x/sys/windows/race.go | 1 + vendor/golang.org/x/sys/windows/race0.go | 1 + .../x/sys/windows/security_windows.go | 646 +- vendor/golang.org/x/sys/windows/service.go | 22 +- .../x/sys/windows/setupapi_windows.go | 1425 +++ vendor/golang.org/x/sys/windows/str.go | 1 + vendor/golang.org/x/sys/windows/syscall.go | 47 +- .../x/sys/windows/syscall_windows.go | 528 +- .../golang.org/x/sys/windows/types_windows.go | 1624 +++- .../x/sys/windows/types_windows_386.go | 13 + .../x/sys/windows/types_windows_amd64.go | 12 + .../x/sys/windows/types_windows_arm.go | 13 + .../x/sys/windows/types_windows_arm64.go | 34 + .../x/sys/windows/zerrors_windows.go | 2619 +++++- .../x/sys/windows/zsyscall_windows.go | 5265 ++++++----- .../encoding/simplifiedchinese/hzgb2312.go | 2 +- .../x/text/encoding/unicode/unicode.go | 94 +- .../text/internal/language/compact/tables.go | 36 +- .../x/text/internal/language/language.go | 133 +- .../x/text/internal/language/parse.go | 44 +- .../x/text/internal/language/tables.go | 4089 ++++----- vendor/golang.org/x/text/language/go1_1.go | 1 + vendor/golang.org/x/text/language/go1_2.go | 1 + vendor/golang.org/x/text/language/language.go | 4 + vendor/golang.org/x/text/language/parse.go | 22 + vendor/golang.org/x/text/language/tables.go | 86 +- .../x/text/secure/bidirule/bidirule10.0.0.go | 1 + .../x/text/secure/bidirule/bidirule9.0.0.go | 1 + .../golang.org/x/text/transform/transform.go | 6 +- vendor/golang.org/x/text/unicode/bidi/bidi.go | 221 +- vendor/golang.org/x/text/unicode/bidi/core.go | 71 +- .../x/text/unicode/bidi/tables10.0.0.go | 1 + .../x/text/unicode/bidi/tables11.0.0.go | 3 +- .../x/text/unicode/bidi/tables12.0.0.go | 1924 ++++ .../x/text/unicode/bidi/tables13.0.0.go | 1956 +++++ .../x/text/unicode/bidi/tables9.0.0.go | 1 + .../x/text/unicode/norm/tables10.0.0.go | 1 + .../x/text/unicode/norm/tables11.0.0.go | 3 +- .../x/text/unicode/norm/tables12.0.0.go | 7711 ++++++++++++++++ .../x/text/unicode/norm/tables13.0.0.go | 7761 +++++++++++++++++ .../x/text/unicode/norm/tables9.0.0.go | 1 + vendor/gopkg.in/yaml.v2/.travis.yml | 12 - vendor/gopkg.in/yaml.v2/LICENSE | 201 - vendor/gopkg.in/yaml.v2/decode.go | 775 -- vendor/gopkg.in/yaml.v2/encode.go | 390 - vendor/gopkg.in/yaml.v2/go.mod | 5 - vendor/gopkg.in/yaml.v2/writerc.go | 26 - .../LICENSE.libyaml => yaml.v3/LICENSE} | 39 +- vendor/gopkg.in/{yaml.v2 => yaml.v3}/NOTICE | 0 .../gopkg.in/{yaml.v2 => yaml.v3}/README.md | 31 +- vendor/gopkg.in/{yaml.v2 => yaml.v3}/apic.go | 56 +- vendor/gopkg.in/yaml.v3/decode.go | 1000 +++ .../gopkg.in/{yaml.v2 => yaml.v3}/emitterc.go | 413 +- vendor/gopkg.in/yaml.v3/encode.go | 577 ++ .../gopkg.in/{yaml.v2 => yaml.v3}/parserc.go | 165 +- .../gopkg.in/{yaml.v2 => yaml.v3}/readerc.go | 24 +- .../gopkg.in/{yaml.v2 => yaml.v3}/resolve.go | 140 +- .../gopkg.in/{yaml.v2 => yaml.v3}/scannerc.go | 476 +- .../gopkg.in/{yaml.v2 => yaml.v3}/sorter.go | 25 +- vendor/gopkg.in/yaml.v3/writerc.go | 48 + vendor/gopkg.in/{yaml.v2 => yaml.v3}/yaml.go | 342 +- vendor/gopkg.in/{yaml.v2 => yaml.v3}/yamlh.go | 81 +- .../{yaml.v2 => yaml.v3}/yamlprivateh.go | 37 +- vendor/modules.txt | 84 +- vendor/xorm.io/builder/go.mod | 8 - vendor/xorm.io/builder/go.sum | 9 - vendor/xorm.io/core/go.mod | 8 - vendor/xorm.io/core/go.sum | 20 - vendor/xorm.io/xorm/go.mod | 15 - vendor/xorm.io/xorm/go.sum | 149 - 684 files changed, 117974 insertions(+), 120148 deletions(-) create mode 100644 log/app.pid rename vendor/github.com/{henrylee2cn => andeya}/goutil/.gitignore (97%) create mode 100644 vendor/github.com/andeya/goutil/.travis.yml create mode 100644 vendor/github.com/andeya/goutil/LICENSE create mode 100644 vendor/github.com/andeya/goutil/README.md rename vendor/github.com/{henrylee2cn => andeya}/goutil/currip.go (88%) rename vendor/github.com/{henrylee2cn => andeya}/goutil/doc.go (68%) create mode 100644 vendor/github.com/andeya/goutil/encrypt.go rename vendor/github.com/{henrylee2cn => andeya}/goutil/errors/errors.go (98%) rename vendor/github.com/{henrylee2cn => andeya}/goutil/file.go (94%) create mode 100644 vendor/github.com/andeya/goutil/gopath.go create mode 100644 vendor/github.com/andeya/goutil/gotest.go rename vendor/github.com/{henrylee2cn => andeya}/goutil/js_url.go (100%) create mode 100644 vendor/github.com/andeya/goutil/kvdata.go rename vendor/github.com/{henrylee2cn => andeya}/goutil/map.go (98%) create mode 100644 vendor/github.com/andeya/goutil/other.go rename vendor/github.com/{henrylee2cn => andeya}/goutil/pid_file.go (100%) rename vendor/github.com/{henrylee2cn => andeya}/goutil/random.go (61%) create mode 100644 vendor/github.com/andeya/goutil/sets.go rename vendor/github.com/{henrylee2cn => andeya}/goutil/string.go (63%) rename vendor/github.com/{henrylee2cn => andeya}/goutil/targz.go (100%) rename vendor/github.com/{henrylee2cn => andeya}/goutil/trace.go (100%) rename vendor/github.com/{henrylee2cn/goutil/exported.go => andeya/goutil/type.go} (55%) rename vendor/github.com/{henrylee2cn => andeya}/ini/.gitignore (100%) rename vendor/github.com/{henrylee2cn => andeya}/ini/.travis.yml (100%) rename vendor/github.com/{henrylee2cn => andeya}/ini/LICENSE (100%) rename vendor/github.com/{henrylee2cn => andeya}/ini/Makefile (100%) rename vendor/github.com/{henrylee2cn => andeya}/ini/README.md (100%) rename vendor/github.com/{henrylee2cn => andeya}/ini/README_ZH.md (100%) rename vendor/github.com/{henrylee2cn => andeya}/ini/error.go (100%) rename vendor/github.com/{henrylee2cn => andeya}/ini/helper.go (91%) rename vendor/github.com/{henrylee2cn => andeya}/ini/ini.go (100%) rename vendor/github.com/{henrylee2cn => andeya}/ini/key.go (100%) rename vendor/github.com/{henrylee2cn => andeya}/ini/parser.go (100%) rename vendor/github.com/{henrylee2cn => andeya}/ini/section.go (100%) rename vendor/github.com/{henrylee2cn => andeya}/ini/struct.go (100%) delete mode 100644 vendor/github.com/facebookgo/ensure/patents delete mode 100644 vendor/github.com/flosch/pongo2/go.mod delete mode 100644 vendor/github.com/gorilla/websocket/.travis.yml delete mode 100644 vendor/github.com/gorilla/websocket/client_clone.go delete mode 100644 vendor/github.com/gorilla/websocket/client_clone_legacy.go delete mode 100644 vendor/github.com/gorilla/websocket/conn_write.go delete mode 100644 vendor/github.com/gorilla/websocket/conn_write_legacy.go create mode 100644 vendor/github.com/gorilla/websocket/join.go create mode 100644 vendor/github.com/gorilla/websocket/tls_handshake.go create mode 100644 vendor/github.com/gorilla/websocket/tls_handshake_116.go delete mode 100644 vendor/github.com/gorilla/websocket/trace.go delete mode 100644 vendor/github.com/gorilla/websocket/trace_17.go create mode 100644 vendor/github.com/henrylee2cn/ameda/.gitignore create mode 100644 vendor/github.com/henrylee2cn/ameda/LICENSE create mode 100644 vendor/github.com/henrylee2cn/ameda/README.md create mode 100644 vendor/github.com/henrylee2cn/ameda/atoi62.go create mode 100644 vendor/github.com/henrylee2cn/ameda/atoi_x.go create mode 100644 vendor/github.com/henrylee2cn/ameda/bool.go create mode 100644 vendor/github.com/henrylee2cn/ameda/bools.go create mode 100644 vendor/github.com/henrylee2cn/ameda/float32.go create mode 100644 vendor/github.com/henrylee2cn/ameda/float32s.go create mode 100644 vendor/github.com/henrylee2cn/ameda/float64.go create mode 100644 vendor/github.com/henrylee2cn/ameda/float64s.go create mode 100644 vendor/github.com/henrylee2cn/ameda/initialize.go create mode 100644 vendor/github.com/henrylee2cn/ameda/int.go create mode 100644 vendor/github.com/henrylee2cn/ameda/int16.go create mode 100644 vendor/github.com/henrylee2cn/ameda/int16s.go create mode 100644 vendor/github.com/henrylee2cn/ameda/int32.go create mode 100644 vendor/github.com/henrylee2cn/ameda/int32s.go create mode 100644 vendor/github.com/henrylee2cn/ameda/int64.go create mode 100644 vendor/github.com/henrylee2cn/ameda/int64s.go create mode 100644 vendor/github.com/henrylee2cn/ameda/int8.go create mode 100644 vendor/github.com/henrylee2cn/ameda/int8s.go create mode 100644 vendor/github.com/henrylee2cn/ameda/interface.go create mode 100644 vendor/github.com/henrylee2cn/ameda/interfaces.go create mode 100644 vendor/github.com/henrylee2cn/ameda/ints.go create mode 100644 vendor/github.com/henrylee2cn/ameda/itoa62.go create mode 100644 vendor/github.com/henrylee2cn/ameda/itoa_x.go create mode 100644 vendor/github.com/henrylee2cn/ameda/string.go create mode 100644 vendor/github.com/henrylee2cn/ameda/strings.go create mode 100644 vendor/github.com/henrylee2cn/ameda/typconv.go create mode 100644 vendor/github.com/henrylee2cn/ameda/uint.go create mode 100644 vendor/github.com/henrylee2cn/ameda/uint16.go create mode 100644 vendor/github.com/henrylee2cn/ameda/uint16s.go create mode 100644 vendor/github.com/henrylee2cn/ameda/uint32.go create mode 100644 vendor/github.com/henrylee2cn/ameda/uint32s.go create mode 100644 vendor/github.com/henrylee2cn/ameda/uint64.go create mode 100644 vendor/github.com/henrylee2cn/ameda/uint64s.go create mode 100644 vendor/github.com/henrylee2cn/ameda/uint8.go create mode 100644 vendor/github.com/henrylee2cn/ameda/uint8s.go create mode 100644 vendor/github.com/henrylee2cn/ameda/uints.go create mode 100644 vendor/github.com/henrylee2cn/ameda/utils.go create mode 100644 vendor/github.com/henrylee2cn/ameda/value.go delete mode 100644 vendor/github.com/henrylee2cn/goutil/README.md delete mode 100644 vendor/github.com/henrylee2cn/goutil/encrypt.go delete mode 100644 vendor/github.com/henrylee2cn/goutil/gopath.go delete mode 100644 vendor/github.com/henrylee2cn/goutil/gotest.go delete mode 100644 vendor/github.com/henrylee2cn/goutil/other.go delete mode 100644 vendor/github.com/henrylee2cn/goutil/sets.go delete mode 100644 vendor/github.com/jinzhu/gorm/go.mod delete mode 100644 vendor/github.com/jinzhu/gorm/go.sum delete mode 100644 vendor/github.com/jinzhu/inflection/go.mod delete mode 100644 vendor/github.com/jmoiron/sqlx/go.mod delete mode 100644 vendor/github.com/jmoiron/sqlx/go.sum delete mode 100644 vendor/github.com/json-iterator/go/go.mod delete mode 100644 vendor/github.com/json-iterator/go/go.sum delete mode 100644 vendor/github.com/kr/pretty/go.mod delete mode 100644 vendor/github.com/kr/text/go.mod delete mode 100644 vendor/github.com/lib/pq/go.mod delete mode 100644 vendor/github.com/pelletier/go-toml/go.mod delete mode 100644 vendor/github.com/pelletier/go-toml/go.sum create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_compare.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go create mode 100644 vendor/golang.org/x/crypto/acme/rfc8555.go create mode 100644 vendor/golang.org/x/net/idna/go118.go create mode 100644 vendor/golang.org/x/net/idna/pre_go118.go create mode 100644 vendor/golang.org/x/net/idna/tables12.0.0.go create mode 100644 vendor/golang.org/x/net/idna/tables13.0.0.go create mode 100644 vendor/golang.org/x/sys/internal/unsafeheader/unsafeheader.go rename vendor/golang.org/x/sys/unix/{asm_netbsd_386.s => asm_bsd_386.s} (70%) rename vendor/golang.org/x/sys/unix/{asm_openbsd_amd64.s => asm_bsd_amd64.s} (71%) rename vendor/golang.org/x/sys/unix/{asm_darwin_arm.s => asm_bsd_arm.s} (74%) rename vendor/golang.org/x/sys/unix/{asm_netbsd_amd64.s => asm_bsd_arm64.s} (73%) delete mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_386.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_amd64.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_arm64.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_386.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_arm.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_linux_loong64.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_arm.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_386.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_arm.s rename vendor/golang.org/x/sys/unix/{asm_openbsd_arm64.s => asm_openbsd_mips64.s} (89%) create mode 100644 vendor/golang.org/x/sys/unix/asm_zos_s390x.s create mode 100644 vendor/golang.org/x/sys/unix/dev_zos.go create mode 100644 vendor/golang.org/x/sys/unix/epoll_zos.go create mode 100644 vendor/golang.org/x/sys/unix/errors_freebsd_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/fdset.go create mode 100644 vendor/golang.org/x/sys/unix/fstatfs_zos.go create mode 100644 vendor/golang.org/x/sys/unix/ifreq_linux.go create mode 100644 vendor/golang.org/x/sys/unix/ioctl_linux.go create mode 100644 vendor/golang.org/x/sys/unix/ioctl_zos.go create mode 100644 vendor/golang.org/x/sys/unix/ptrace_darwin.go create mode 100644 vendor/golang.org/x/sys/unix/ptrace_ios.go create mode 100644 vendor/golang.org/x/sys/unix/sockcmsg_dragonfly.go create mode 100644 vendor/golang.org/x/sys/unix/sockcmsg_unix_other.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin.1_12.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go delete mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_386.go delete mode 100644 vendor/golang.org/x/sys/unix/syscall_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_illumos.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_alarm.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_gc_arm.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_loong64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_linux_ppc.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_openbsd_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_zos_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/sysvshm_linux.go create mode 100644 vendor/golang.org/x/sys/unix/sysvshm_unix.go create mode 100644 vendor/golang.org/x/sys/unix/sysvshm_unix_other.go delete mode 100644 vendor/golang.org/x/sys/unix/zerrors_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go rename vendor/golang.org/x/sys/unix/{zerrors_darwin_386.go => zerrors_openbsd_mips64.go} (51%) create mode 100644 vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go rename vendor/golang.org/x/sys/unix/{zptracearm_linux.go => zptrace_armnn_linux.go} (90%) create mode 100644 vendor/golang.org/x/sys/unix/zptrace_linux_arm64.go rename vendor/golang.org/x/sys/unix/{zptracemips_linux.go => zptrace_mipsnn_linux.go} (91%) rename vendor/golang.org/x/sys/unix/{zptracemipsle_linux.go => zptrace_mipsnnle_linux.go} (91%) rename vendor/golang.org/x/sys/unix/{zptrace386_linux.go => zptrace_x86_linux.go} (93%) delete mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_386.1_11.go delete mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go delete mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_386.s delete mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_11.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.1_13.s delete mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.1_11.go delete mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go delete mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.s create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.1_13.s create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_illumos_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go rename vendor/golang.org/x/sys/unix/{zsyscall_darwin_arm64.1_11.go => zsyscall_openbsd_mips64.go} (84%) create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_zos_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/zsysctl_openbsd_mips64.go delete mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go delete mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_openbsd_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_zos_s390x.go delete mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_386.go delete mode 100644 vendor/golang.org/x/sys/unix/ztypes_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_illumos_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go delete mode 100644 vendor/golang.org/x/sys/windows/asm_windows_386.s delete mode 100644 vendor/golang.org/x/sys/windows/asm_windows_amd64.s delete mode 100644 vendor/golang.org/x/sys/windows/asm_windows_arm.s create mode 100644 vendor/golang.org/x/sys/windows/empty.s create mode 100644 vendor/golang.org/x/sys/windows/setupapi_windows.go create mode 100644 vendor/golang.org/x/sys/windows/types_windows_arm64.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/norm/tables12.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/norm/tables13.0.0.go delete mode 100644 vendor/gopkg.in/yaml.v2/.travis.yml delete mode 100644 vendor/gopkg.in/yaml.v2/LICENSE delete mode 100644 vendor/gopkg.in/yaml.v2/decode.go delete mode 100644 vendor/gopkg.in/yaml.v2/encode.go delete mode 100644 vendor/gopkg.in/yaml.v2/go.mod delete mode 100644 vendor/gopkg.in/yaml.v2/writerc.go rename vendor/gopkg.in/{yaml.v2/LICENSE.libyaml => yaml.v3/LICENSE} (51%) rename vendor/gopkg.in/{yaml.v2 => yaml.v3}/NOTICE (100%) rename vendor/gopkg.in/{yaml.v2 => yaml.v3}/README.md (66%) rename vendor/gopkg.in/{yaml.v2 => yaml.v3}/apic.go (93%) create mode 100644 vendor/gopkg.in/yaml.v3/decode.go rename vendor/gopkg.in/{yaml.v2 => yaml.v3}/emitterc.go (80%) create mode 100644 vendor/gopkg.in/yaml.v3/encode.go rename vendor/gopkg.in/{yaml.v2 => yaml.v3}/parserc.go (85%) rename vendor/gopkg.in/{yaml.v2 => yaml.v3}/readerc.go (91%) rename vendor/gopkg.in/{yaml.v2 => yaml.v3}/resolve.go (59%) rename vendor/gopkg.in/{yaml.v2 => yaml.v3}/scannerc.go (84%) rename vendor/gopkg.in/{yaml.v2 => yaml.v3}/sorter.go (76%) create mode 100644 vendor/gopkg.in/yaml.v3/writerc.go rename vendor/gopkg.in/{yaml.v2 => yaml.v3}/yaml.go (55%) rename vendor/gopkg.in/{yaml.v2 => yaml.v3}/yamlh.go (88%) rename vendor/gopkg.in/{yaml.v2 => yaml.v3}/yamlprivateh.go (78%) delete mode 100644 vendor/xorm.io/builder/go.mod delete mode 100644 vendor/xorm.io/builder/go.sum delete mode 100644 vendor/xorm.io/core/go.mod delete mode 100644 vendor/xorm.io/core/go.sum delete mode 100644 vendor/xorm.io/xorm/go.mod delete mode 100644 vendor/xorm.io/xorm/go.sum diff --git a/README.md b/README.md index b20a821..f360a73 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ -# Faygo [![report card](https://goreportcard.com/badge/github.com/henrylee2cn/faygo?style=flat-square)](http://goreportcard.com/report/henrylee2cn/faygo) [![github issues](https://img.shields.io/github/issues/henrylee2cn/faygo.svg?style=flat-square)](https://github.com/henrylee2cn/faygo/issues?q=is%3Aopen+is%3Aissue) [![github closed issues](https://img.shields.io/github/issues-closed-raw/henrylee2cn/faygo.svg?style=flat-square)](https://github.com/henrylee2cn/faygo/issues?q=is%3Aissue+is%3Aclosed) [![GitHub release](https://img.shields.io/github/release/henrylee2cn/faygo.svg?style=flat-square)](https://github.com/henrylee2cn/faygo/releases) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/henrylee2cn/faygo) [![view Go网络编程群](https://img.shields.io/badge/官方QQ群-Go网络编程(42730308)-27a5ea.svg?style=flat-square)](http://jq.qq.com/?_wv=1027&k=fzi4p1) +# Faygo [![report card](https://goreportcard.com/badge/github.com/andeya/faygo?style=flat-square)](http://goreportcard.com/report/andeya/faygo) [![github issues](https://img.shields.io/github/issues/andeya/faygo.svg?style=flat-square)](https://github.com/andeya/faygo/issues?q=is%3Aopen+is%3Aissue) [![github closed issues](https://img.shields.io/github/issues-closed-raw/andeya/faygo.svg?style=flat-square)](https://github.com/andeya/faygo/issues?q=is%3Aissue+is%3Aclosed) [![GitHub release](https://img.shields.io/github/release/andeya/faygo.svg?style=flat-square)](https://github.com/andeya/faygo/releases) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/andeya/faygo) [![view Go网络编程群](https://img.shields.io/badge/官方QQ群-Go网络编程(42730308)-27a5ea.svg?style=flat-square)](http://jq.qq.com/?_wv=1027&k=fzi4p1) -![Faygo Favicon](https://github.com/henrylee2cn/faygo/raw/master/doc/faygo_96x96.png) +![Faygo Favicon](https://github.com/andeya/faygo/raw/master/doc/faygo_96x96.png) -Faygo is a fast and concise Go Web framework that can be used to develop high-performance web app(especially API) with fewer codes. Just define a struct Handler, Faygo will automatically bind/verify the request parameters and generate the online API doc. [Go to \](https://github.com/henrylee2cn/faydoc) +Faygo is a fast and concise Go Web framework that can be used to develop high-performance web app(especially API) with fewer codes. Just define a struct Handler, Faygo will automatically bind/verify the request parameters and generate the online API doc. [Go to \](https://github.com/andeya/faydoc) -[简体中文](https://github.com/henrylee2cn/faygo/blob/master/README_ZH.md) +[简体中文](https://github.com/andeya/faygo/blob/master/README_ZH.md) -![faygo index](https://github.com/henrylee2cn/faygo/raw/master/doc/index.png) +![faygo index](https://github.com/andeya/faygo/raw/master/doc/index.png) -![faygo apidoc](https://github.com/henrylee2cn/faygo/raw/master/doc/apidoc.png) +![faygo apidoc](https://github.com/andeya/faygo/raw/master/doc/apidoc.png) -![faygo server](https://github.com/henrylee2cn/faygo/raw/master/doc/server.png) +![faygo server](https://github.com/andeya/faygo/raw/master/doc/server.png) ## Latest version @@ -28,13 +28,13 @@ Go Version ≥ 1.8 - Way 1: download source ```sh -go get -u -v github.com/henrylee2cn/faygo +go get -u -v github.com/andeya/faygo ``` -- Way 2: deployment tools ([Go to fay](https://github.com/henrylee2cn/fay)) +- Way 2: deployment tools ([Go to fay](https://github.com/andeya/fay)) ```sh -go get -u -v github.com/henrylee2cn/fay +go get -u -v github.com/andeya/fay ``` ``` @@ -84,7 +84,7 @@ HTTPS/HTTP2(TLS on UNIX socket) | `unix_https` - Most features try to use simple ini configs to avoid unnecessary recompilation, and these profiles can be automatically assigned default values - Provide `gorm`, ` xorm`, `sqlx`, ` directSQL`, `Websocket`, ` ini`, `http client` and many other commonly used expansion packages -![faygo handler multi-usage](https://github.com/henrylee2cn/faygo/raw/master/doc/MultiUsage.png) +![faygo handler multi-usage](https://github.com/andeya/faygo/raw/master/doc/MultiUsage.png) ## Simple example @@ -94,7 +94,7 @@ package main import ( // "mime/multipart" "time" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) type Index struct { @@ -143,7 +143,7 @@ response: */ ``` -[All samples](https://github.com/henrylee2cn/faygo/raw/master/samples) +[All samples](https://github.com/andeya/faygo/raw/master/samples) ## Handler and middleware @@ -413,19 +413,19 @@ float64 | []float64 | package summary | import path -----------------|----------------------------------------------------------------------------------------------------------------- -[barcode](https://github.com/henrylee2cn/faygo/raw/master/ext/barcode) | `github.com/henrylee2cn/faygo/ext/barcode` -[Bit unit conversion](https://github.com/henrylee2cn/faygo/raw/master/ext/bitconv) | `github.com/henrylee2cn/faygo/ext/bitconv` -[gorm(DB ORM)](https://github.com/henrylee2cn/faygo/raw/master/ext/db/gorm) | `github.com/henrylee2cn/faygo/ext/db/gorm` -[sqlx(DB ext)](https://github.com/henrylee2cn/faygo/raw/master/ext/db/sqlx) | `github.com/henrylee2cn/faygo/ext/db/sqlx` -[xorm(DB ORM)](https://github.com/henrylee2cn/faygo/raw/master/ext/db/xorm) | `github.com/henrylee2cn/faygo/ext/db/xorm` -[directSQL(Configured SQL engine)](https://github.com/henrylee2cn/faygo/raw/master/ext/db/directsql) | `github.com/henrylee2cn/faygo/ext/db/directsql` -[One-time Password](https://github.com/henrylee2cn/faygo/raw/master/ext/otp) | `github.com/henrylee2cn/faygo/ext/otp` -[UUID](https://github.com/henrylee2cn/faygo/raw/master/ext/uuid) | `github.com/henrylee2cn/faygo/ext/uuid` -[Websocket](https://github.com/henrylee2cn/faygo/raw/master/ext/websocket) | `github.com/henrylee2cn/faygo/ext/websocket` -[ini](https://github.com/henrylee2cn/faygo/raw/master/ini) | `github.com/henrylee2cn/faygo/ini` -[cron](https://github.com/henrylee2cn/faygo/raw/master/ext/cron) | `github.com/henrylee2cn/faygo/ext/cron` -[task](https://github.com/henrylee2cn/faygo/raw/master/ext/task) | `github.com/henrylee2cn/faygo/ext/task` -[http client](https://github.com/henrylee2cn/faygo/raw/master/ext/surfer) | `github.com/henrylee2cn/faygo/ext/surfer` +[barcode](https://github.com/andeya/faygo/raw/master/ext/barcode) | `github.com/andeya/faygo/ext/barcode` +[Bit unit conversion](https://github.com/andeya/faygo/raw/master/ext/bitconv) | `github.com/andeya/faygo/ext/bitconv` +[gorm(DB ORM)](https://github.com/andeya/faygo/raw/master/ext/db/gorm) | `github.com/andeya/faygo/ext/db/gorm` +[sqlx(DB ext)](https://github.com/andeya/faygo/raw/master/ext/db/sqlx) | `github.com/andeya/faygo/ext/db/sqlx` +[xorm(DB ORM)](https://github.com/andeya/faygo/raw/master/ext/db/xorm) | `github.com/andeya/faygo/ext/db/xorm` +[directSQL(Configured SQL engine)](https://github.com/andeya/faygo/raw/master/ext/db/directsql) | `github.com/andeya/faygo/ext/db/directsql` +[One-time Password](https://github.com/andeya/faygo/raw/master/ext/otp) | `github.com/andeya/faygo/ext/otp` +[UUID](https://github.com/andeya/faygo/raw/master/ext/uuid) | `github.com/andeya/faygo/ext/uuid` +[Websocket](https://github.com/andeya/faygo/raw/master/ext/websocket) | `github.com/andeya/faygo/ext/websocket` +[ini](https://github.com/andeya/faygo/raw/master/ini) | `github.com/andeya/faygo/ini` +[cron](https://github.com/andeya/faygo/raw/master/ext/cron) | `github.com/andeya/faygo/ext/cron` +[task](https://github.com/andeya/faygo/raw/master/ext/task) | `github.com/andeya/faygo/ext/task` +[http client](https://github.com/andeya/faygo/raw/master/ext/surfer) | `github.com/andeya/faygo/ext/surfer` ## Know Cases @@ -443,7 +443,7 @@ OneFor | App | https://fir.im/eqb 平安科技    -Followme +Followme
杭州盯房科技有限公司    @@ -453,4 +453,4 @@ OneFor | App | https://fir.im/eqb ## License -Faygo is under Apache v2 License. See the [LICENSE](https://github.com/henrylee2cn/faygo/raw/master/LICENSE) file for the full license text +Faygo is under Apache v2 License. See the [LICENSE](https://github.com/andeya/faygo/raw/master/LICENSE) file for the full license text diff --git a/README_ZH.md b/README_ZH.md index 89d5c9b..ba91170 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -1,17 +1,17 @@ -# Faygo [![report card](https://goreportcard.com/badge/github.com/henrylee2cn/faygo?style=flat-square)](http://goreportcard.com/report/henrylee2cn/faygo) [![github issues](https://img.shields.io/github/issues/henrylee2cn/faygo.svg?style=flat-square)](https://github.com/henrylee2cn/faygo/issues?q=is%3Aopen+is%3Aissue) [![github closed issues](https://img.shields.io/github/issues-closed-raw/henrylee2cn/faygo.svg?style=flat-square)](https://github.com/henrylee2cn/faygo/issues?q=is%3Aissue+is%3Aclosed) [![GitHub release](https://img.shields.io/github/release/henrylee2cn/faygo.svg?style=flat-square)](https://github.com/henrylee2cn/faygo/releases) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/henrylee2cn/faygo) [![view Go网络编程群](https://img.shields.io/badge/官方QQ群-Go网络编程(42730308)-27a5ea.svg?style=flat-square)](http://jq.qq.com/?_wv=1027&k=fzi4p1) +# Faygo [![report card](https://goreportcard.com/badge/github.com/andeya/faygo?style=flat-square)](http://goreportcard.com/report/andeya/faygo) [![github issues](https://img.shields.io/github/issues/andeya/faygo.svg?style=flat-square)](https://github.com/andeya/faygo/issues?q=is%3Aopen+is%3Aissue) [![github closed issues](https://img.shields.io/github/issues-closed-raw/andeya/faygo.svg?style=flat-square)](https://github.com/andeya/faygo/issues?q=is%3Aissue+is%3Aclosed) [![GitHub release](https://img.shields.io/github/release/andeya/faygo.svg?style=flat-square)](https://github.com/andeya/faygo/releases) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/andeya/faygo) [![view Go网络编程群](https://img.shields.io/badge/官方QQ群-Go网络编程(42730308)-27a5ea.svg?style=flat-square)](http://jq.qq.com/?_wv=1027&k=fzi4p1) -![Faygo Favicon](https://github.com/henrylee2cn/faygo/raw/master/doc/faygo_96x96.png) +![Faygo Favicon](https://github.com/andeya/faygo/raw/master/doc/faygo_96x96.png) Faygo 是一款快速、简洁的Go Web框架,可用极少的代码开发出高性能的Web应用程序(尤其是API接口)。只需定义 struct Handler,Faygo 就能自动绑定、验证请求参数并生成在线API文档。 -[查看《用户手册》](https://github.com/henrylee2cn/faydoc) +[查看《用户手册》](https://github.com/andeya/faydoc) -![faygo index](https://github.com/henrylee2cn/faygo/raw/master/doc/index.png) +![faygo index](https://github.com/andeya/faygo/raw/master/doc/index.png) -![faygo apidoc](https://github.com/henrylee2cn/faygo/raw/master/doc/apidoc.png) +![faygo apidoc](https://github.com/andeya/faygo/raw/master/doc/apidoc.png) -![faygo server](https://github.com/henrylee2cn/faygo/raw/master/doc/server.png) +![faygo server](https://github.com/andeya/faygo/raw/master/doc/server.png) ## 最新版本 @@ -28,13 +28,13 @@ Go Version ≥ 1.8 - 方式一 源码下载 ```sh -go get -u -v github.com/henrylee2cn/faygo +go get -u -v github.com/andeya/faygo ``` -- 方式二 部署工具 ([Go to fay](https://github.com/henrylee2cn/fay)) +- 方式二 部署工具 ([Go to fay](https://github.com/andeya/fay)) ```sh -go get -u -v github.com/henrylee2cn/fay +go get -u -v github.com/andeya/fay ``` ``` @@ -84,7 +84,7 @@ HTTPS/HTTP2(TLS on UNIX socket) | `unix_https` - 大多数功能尽量使用简洁的ini进行配置来避免不必要的重新编译,并且这些配置文件支持自动补填默认值 - 提供 `gorm`、`xorm`、`sqlx`、`directSQL`、`Websocket`、`ini` 、`http client` 等很多常用扩展包 -![faygo struct handler 多重用途合一](https://github.com/henrylee2cn/faygo/raw/master/doc/MultiUsage.png) +![faygo struct handler 多重用途合一](https://github.com/andeya/faygo/raw/master/doc/MultiUsage.png) ## 简单示例 @@ -94,7 +94,7 @@ package main import ( // "mime/multipart" "time" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) type Index struct { @@ -143,7 +143,7 @@ response: */ ``` -[示例库](https://github.com/henrylee2cn/faygo/raw/master/samples) +[示例库](https://github.com/andeya/faygo/raw/master/samples) ## 操作和中间件 @@ -413,19 +413,19 @@ float64 | []float64 | 扩展包 | 导入路径 -----------------|----------------------------------------------------------------------------------------------------------------- -[各种条码](https://github.com/henrylee2cn/faygo/raw/master/ext/barcode) | `github.com/henrylee2cn/faygo/ext/barcode` -[比特单位](https://github.com/henrylee2cn/faygo/raw/master/ext/bitconv) | `github.com/henrylee2cn/faygo/ext/bitconv` -[gorm数据库引擎](https://github.com/henrylee2cn/faygo/raw/master/ext/db/gorm) | `github.com/henrylee2cn/faygo/ext/db/gorm` -[sqlx数据库引擎](https://github.com/henrylee2cn/faygo/raw/master/ext/db/sqlx) | `github.com/henrylee2cn/faygo/ext/db/sqlx` -[xorm数据库引擎](https://github.com/henrylee2cn/faygo/raw/master/ext/db/xorm) | `github.com/henrylee2cn/faygo/ext/db/xorm` -[directSQL(配置化SQL引擎)](https://github.com/henrylee2cn/faygo/raw/master/ext/db/directsql) | `github.com/henrylee2cn/faygo/ext/db/directsql` -[口令算法](https://github.com/henrylee2cn/faygo/raw/master/ext/otp) | `github.com/henrylee2cn/faygo/ext/otp` -[UUID](https://github.com/henrylee2cn/faygo/raw/master/ext/uuid) | `github.com/henrylee2cn/faygo/ext/uuid` -[Websocket](https://github.com/henrylee2cn/faygo/raw/master/ext/websocket) | `github.com/henrylee2cn/faygo/ext/websocket` -[ini配置](https://github.com/henrylee2cn/faygo/raw/master/ini) | `github.com/henrylee2cn/faygo/ini` -[定时器](https://github.com/henrylee2cn/faygo/raw/master/ext/cron) | `github.com/henrylee2cn/faygo/ext/cron` -[任务工具](https://github.com/henrylee2cn/faygo/raw/master/ext/task) | `github.com/henrylee2cn/faygo/ext/task` -[HTTP客户端](https://github.com/henrylee2cn/faygo/raw/master/ext/surfer) | `github.com/henrylee2cn/faygo/ext/surfer` +[各种条码](https://github.com/andeya/faygo/raw/master/ext/barcode) | `github.com/andeya/faygo/ext/barcode` +[比特单位](https://github.com/andeya/faygo/raw/master/ext/bitconv) | `github.com/andeya/faygo/ext/bitconv` +[gorm数据库引擎](https://github.com/andeya/faygo/raw/master/ext/db/gorm) | `github.com/andeya/faygo/ext/db/gorm` +[sqlx数据库引擎](https://github.com/andeya/faygo/raw/master/ext/db/sqlx) | `github.com/andeya/faygo/ext/db/sqlx` +[xorm数据库引擎](https://github.com/andeya/faygo/raw/master/ext/db/xorm) | `github.com/andeya/faygo/ext/db/xorm` +[directSQL(配置化SQL引擎)](https://github.com/andeya/faygo/raw/master/ext/db/directsql) | `github.com/andeya/faygo/ext/db/directsql` +[口令算法](https://github.com/andeya/faygo/raw/master/ext/otp) | `github.com/andeya/faygo/ext/otp` +[UUID](https://github.com/andeya/faygo/raw/master/ext/uuid) | `github.com/andeya/faygo/ext/uuid` +[Websocket](https://github.com/andeya/faygo/raw/master/ext/websocket) | `github.com/andeya/faygo/ext/websocket` +[ini配置](https://github.com/andeya/faygo/raw/master/ini) | `github.com/andeya/faygo/ini` +[定时器](https://github.com/andeya/faygo/raw/master/ext/cron) | `github.com/andeya/faygo/ext/cron` +[任务工具](https://github.com/andeya/faygo/raw/master/ext/task) | `github.com/andeya/faygo/ext/task` +[HTTP客户端](https://github.com/andeya/faygo/raw/master/ext/surfer) | `github.com/andeya/faygo/ext/surfer` ## 已知案例 @@ -442,7 +442,7 @@ e交易 | App | https://fir.im/ejy 平安科技    -Followme +Followme
杭州盯房科技有限公司    @@ -452,4 +452,4 @@ e交易 | App | https://fir.im/ejy ## 开源协议 -Faygo 项目采用商业应用友好的 [Apache2.0](https://github.com/henrylee2cn/faygo/raw/master/LICENSE) 协议发布 +Faygo 项目采用商业应用友好的 [Apache2.0](https://github.com/andeya/faygo/raw/master/LICENSE) 协议发布 diff --git a/_syso/index.html b/_syso/index.html index a52f624..7f37cb6 100644 --- a/_syso/index.html +++ b/_syso/index.html @@ -18,12 +18,12 @@

{{CONTENT}}

-
+
diff --git a/apidoc.go b/apidoc.go index bf9c18e..32992d6 100644 --- a/apidoc.go +++ b/apidoc.go @@ -26,7 +26,7 @@ import ( "regexp" "strings" - "github.com/henrylee2cn/faygo/swagger" + "github.com/andeya/faygo/swagger" ) type swaggerFS struct { diff --git a/apiware/README.md b/apiware/README.md index c203422..530e1c1 100644 --- a/apiware/README.md +++ b/apiware/README.md @@ -1,4 +1,4 @@ -# Apiware [![GoDoc](https://godoc.org/github.com/tsuna/gohbase?status.png)](https://godoc.org/github.com/henrylee2cn/faygo/apiware) +# Apiware [![GoDoc](https://godoc.org/github.com/tsuna/gohbase?status.png)](https://godoc.org/github.com/andeya/faygo/apiware) Apiware binds the specified parameters of the Golang `net/http` and `fasthttp` requests to the structure and verifies the validity of the parameter values. @@ -14,7 +14,7 @@ package main import ( "encoding/json" - "github.com/henrylee2cn/faygo/apiware" + "github.com/andeya/faygo/apiware" // "mime/multipart" "net/http" "strings" @@ -57,7 +57,7 @@ func testHandler(resp http.ResponseWriter, req *http.Request) { // set cookies http.SetCookie(resp, &http.Cookie{ Name: "apiwareid", - Value: "http_henrylee2cn", + Value: "http_andeya", }) // bind params diff --git a/context.go b/context.go index 6324142..87e186e 100644 --- a/context.go +++ b/context.go @@ -26,8 +26,8 @@ import ( "path" "sync" - "github.com/henrylee2cn/faygo/logging" - "github.com/henrylee2cn/faygo/session" + "github.com/andeya/faygo/logging" + "github.com/andeya/faygo/session" ) // Headers @@ -365,7 +365,7 @@ func (ctx *Context) doHandler(handlerChain HandlerChain, pathParams PathParams) // Called before the start func (ctx *Context) prepare() bool { var pass = true - //if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf + // if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf if ctx.enableXSRF { ctx.XSRFToken() switch ctx.R.Method { @@ -389,9 +389,9 @@ func (ctx *Context) posReset() { // Next calls all the next handler from the middleware stack, it used inside a middleware. // Notes: Non-concurrent security. func (ctx *Context) Next() { - //set position to the next + // set position to the next ctx.pos++ - //run the next + // run the next if ctx.pos < ctx.handlerChainLen { if err := ctx.handlerChain[ctx.pos].Serve(ctx); err != nil { global.errorFunc(ctx, err.Error(), http.StatusInternalServerError) diff --git a/context_input.go b/context_input.go index 12dde6a..7b3f746 100644 --- a/context_input.go +++ b/context_input.go @@ -35,7 +35,7 @@ import ( "strconv" "strings" - "github.com/henrylee2cn/faygo/apiware" + "github.com/andeya/faygo/apiware" ) // Regexes for checking the accept headers diff --git a/context_output.go b/context_output.go index 9e6e015..3101b43 100644 --- a/context_output.go +++ b/context_output.go @@ -29,7 +29,7 @@ import ( "time" "unsafe" - "github.com/henrylee2cn/faygo/acceptencoder" + "github.com/andeya/faygo/acceptencoder" ) // Size returns the current size, in bytes, of the response. @@ -111,7 +111,7 @@ func (ctx *Context) SetHeader(key, val string) { func (ctx *Context) SetCookie(name string, value string, others ...interface{}) { var b bytes.Buffer fmt.Fprintf(&b, "%s=%s", sanitizeName(name), sanitizeValue(value)) - //fix cookie not work in IE + // fix cookie not work in IE if len(others) > 0 { var maxAge int64 switch v := others[0].(type) { diff --git a/doc.go b/doc.go index 6e92dd0..5da2bcb 100644 --- a/doc.go +++ b/doc.go @@ -23,7 +23,7 @@ A trivial example is: import ( // "mime/multipart" "time" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) type Index struct { diff --git a/ext/barcode/codabar/encoder.go b/ext/barcode/codabar/encoder.go index d8042be..3671e2c 100644 --- a/ext/barcode/codabar/encoder.go +++ b/ext/barcode/codabar/encoder.go @@ -5,8 +5,8 @@ import ( "fmt" "regexp" - "github.com/henrylee2cn/faygo/ext/barcode" - "github.com/henrylee2cn/faygo/ext/barcode/utils" + "github.com/andeya/faygo/ext/barcode" + "github.com/andeya/faygo/ext/barcode/utils" ) var encodingTable = map[rune][]bool{ diff --git a/ext/barcode/code128/encode.go b/ext/barcode/code128/encode.go index 9624ab6..172e1f8 100644 --- a/ext/barcode/code128/encode.go +++ b/ext/barcode/code128/encode.go @@ -6,8 +6,8 @@ import ( "strings" "unicode/utf8" - "github.com/henrylee2cn/faygo/ext/barcode" - "github.com/henrylee2cn/faygo/ext/barcode/utils" + "github.com/andeya/faygo/ext/barcode" + "github.com/andeya/faygo/ext/barcode/utils" ) func strToRunes(str string) []rune { diff --git a/ext/barcode/code39/encoder.go b/ext/barcode/code39/encoder.go index 5416218..e61eb75 100644 --- a/ext/barcode/code39/encoder.go +++ b/ext/barcode/code39/encoder.go @@ -6,8 +6,8 @@ import ( "strconv" "strings" - "github.com/henrylee2cn/faygo/ext/barcode" - "github.com/henrylee2cn/faygo/ext/barcode/utils" + "github.com/andeya/faygo/ext/barcode" + "github.com/andeya/faygo/ext/barcode/utils" ) type encodeInfo struct { diff --git a/ext/barcode/datamatrix/codelayout.go b/ext/barcode/datamatrix/codelayout.go index 87e596f..22de91a 100644 --- a/ext/barcode/datamatrix/codelayout.go +++ b/ext/barcode/datamatrix/codelayout.go @@ -1,7 +1,7 @@ package datamatrix import ( - "github.com/henrylee2cn/faygo/ext/barcode/utils" + "github.com/andeya/faygo/ext/barcode/utils" ) type setValFunc func(byte) @@ -161,28 +161,28 @@ func (l *codeLayout) IterateSetter() <-chan setValFunc { func (l *codeLayout) Merge() *datamatrixCode { result := newDataMatrixCode(l.size) - //dotted horizontal lines + // dotted horizontal lines for r := 0; r < l.size.Rows; r += (l.size.RegionRows() + 2) { for c := 0; c < l.size.Columns; c += 2 { result.set(c, r, true) } } - //solid horizontal line + // solid horizontal line for r := l.size.RegionRows() + 1; r < l.size.Rows; r += (l.size.RegionRows() + 2) { for c := 0; c < l.size.Columns; c++ { result.set(c, r, true) } } - //dotted vertical lines + // dotted vertical lines for c := l.size.RegionColumns() + 1; c < l.size.Columns; c += (l.size.RegionColumns() + 2) { for r := 1; r < l.size.Rows; r += 2 { result.set(c, r, true) } } - //solid vertical line + // solid vertical line for c := 0; c < l.size.Columns; c += (l.size.RegionColumns() + 2) { for r := 0; r < l.size.Rows; r++ { result.set(c, r, true) diff --git a/ext/barcode/datamatrix/datamatrixcode.go b/ext/barcode/datamatrix/datamatrixcode.go index 82fa87d..b00972d 100644 --- a/ext/barcode/datamatrix/datamatrixcode.go +++ b/ext/barcode/datamatrix/datamatrixcode.go @@ -1,10 +1,11 @@ package datamatrix import ( - "github.com/henrylee2cn/faygo/ext/barcode" - "github.com/henrylee2cn/faygo/ext/barcode/utils" "image" "image/color" + + "github.com/andeya/faygo/ext/barcode" + "github.com/andeya/faygo/ext/barcode/utils" ) type datamatrixCode struct { diff --git a/ext/barcode/datamatrix/encoder.go b/ext/barcode/datamatrix/encoder.go index eaabe5e..65ec9c6 100644 --- a/ext/barcode/datamatrix/encoder.go +++ b/ext/barcode/datamatrix/encoder.go @@ -4,7 +4,7 @@ package datamatrix import ( "errors" - "github.com/henrylee2cn/faygo/ext/barcode" + "github.com/andeya/faygo/ext/barcode" ) // Encode returns a Datamatrix barcode for the given content diff --git a/ext/barcode/datamatrix/errorcorrection.go b/ext/barcode/datamatrix/errorcorrection.go index 74bf322..9dc2aaf 100644 --- a/ext/barcode/datamatrix/errorcorrection.go +++ b/ext/barcode/datamatrix/errorcorrection.go @@ -1,7 +1,7 @@ package datamatrix import ( - "github.com/henrylee2cn/faygo/ext/barcode/utils" + "github.com/andeya/faygo/ext/barcode/utils" ) type errorCorrection struct { diff --git a/ext/barcode/ean/encoder.go b/ext/barcode/ean/encoder.go index 39688e5..65ad762 100644 --- a/ext/barcode/ean/encoder.go +++ b/ext/barcode/ean/encoder.go @@ -4,8 +4,8 @@ package ean import ( "errors" - "github.com/henrylee2cn/faygo/ext/barcode" - "github.com/henrylee2cn/faygo/ext/barcode/utils" + "github.com/andeya/faygo/ext/barcode" + "github.com/andeya/faygo/ext/barcode/utils" ) type encodedNumber struct { diff --git a/ext/barcode/qr/alphanumeric.go b/ext/barcode/qr/alphanumeric.go index 9a7732d..63d7abd 100644 --- a/ext/barcode/qr/alphanumeric.go +++ b/ext/barcode/qr/alphanumeric.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/henrylee2cn/faygo/ext/barcode/utils" + "github.com/andeya/faygo/ext/barcode/utils" ) const charSet string = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:" diff --git a/ext/barcode/qr/automatic.go b/ext/barcode/qr/automatic.go index 34659e6..4682475 100644 --- a/ext/barcode/qr/automatic.go +++ b/ext/barcode/qr/automatic.go @@ -3,7 +3,7 @@ package qr import ( "fmt" - "github.com/henrylee2cn/faygo/ext/barcode/utils" + "github.com/andeya/faygo/ext/barcode/utils" ) func encodeAuto(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) { diff --git a/ext/barcode/qr/encoder.go b/ext/barcode/qr/encoder.go index 9dd05cc..76afb0a 100644 --- a/ext/barcode/qr/encoder.go +++ b/ext/barcode/qr/encoder.go @@ -4,8 +4,8 @@ package qr import ( "image" - "github.com/henrylee2cn/faygo/ext/barcode" - "github.com/henrylee2cn/faygo/ext/barcode/utils" + "github.com/andeya/faygo/ext/barcode" + "github.com/andeya/faygo/ext/barcode/utils" ) type encodeFn func(content string, eccLevel ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) @@ -87,7 +87,7 @@ func render(data []byte, vi *versionInfo) *qrcode { drawFinderPatterns(vi, setAll) drawAlignmentPatterns(occupied, vi, setAll) - //Timing Pattern: + // Timing Pattern: var i int for i = 0; i < dim; i++ { if !occupied.Get(i, 6) { diff --git a/ext/barcode/qr/encoder_test.go b/ext/barcode/qr/encoder_test.go index 77fd237..3e22667 100644 --- a/ext/barcode/qr/encoder_test.go +++ b/ext/barcode/qr/encoder_test.go @@ -6,7 +6,7 @@ import ( "os" "testing" - "github.com/henrylee2cn/faygo/ext/barcode" + "github.com/andeya/faygo/ext/barcode" ) type test struct { diff --git a/ext/barcode/qr/errorcorrection.go b/ext/barcode/qr/errorcorrection.go index 7098e81..d1b0aa0 100644 --- a/ext/barcode/qr/errorcorrection.go +++ b/ext/barcode/qr/errorcorrection.go @@ -1,7 +1,7 @@ package qr import ( - "github.com/henrylee2cn/faygo/ext/barcode/utils" + "github.com/andeya/faygo/ext/barcode/utils" ) type errorCorrection struct { diff --git a/ext/barcode/qr/helper.go b/ext/barcode/qr/helper.go index abc69b3..f1d8a19 100644 --- a/ext/barcode/qr/helper.go +++ b/ext/barcode/qr/helper.go @@ -6,7 +6,7 @@ import ( "image/jpeg" "image/png" - "github.com/henrylee2cn/faygo/ext/barcode" + "github.com/andeya/faygo/ext/barcode" ) // 常见二维码边长 diff --git a/ext/barcode/qr/numeric.go b/ext/barcode/qr/numeric.go index a029303..07f688c 100644 --- a/ext/barcode/qr/numeric.go +++ b/ext/barcode/qr/numeric.go @@ -5,7 +5,7 @@ import ( "fmt" "strconv" - "github.com/henrylee2cn/faygo/ext/barcode/utils" + "github.com/andeya/faygo/ext/barcode/utils" ) func encodeNumeric(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) { diff --git a/ext/barcode/qr/qrcode.go b/ext/barcode/qr/qrcode.go index 9347d9b..12bf7c5 100644 --- a/ext/barcode/qr/qrcode.go +++ b/ext/barcode/qr/qrcode.go @@ -5,8 +5,8 @@ import ( "image/color" "math" - "github.com/henrylee2cn/faygo/ext/barcode" - "github.com/henrylee2cn/faygo/ext/barcode/utils" + "github.com/andeya/faygo/ext/barcode" + "github.com/andeya/faygo/ext/barcode/utils" ) type qrcode struct { diff --git a/ext/barcode/qr/unicode.go b/ext/barcode/qr/unicode.go index dc598ad..4298b7a 100644 --- a/ext/barcode/qr/unicode.go +++ b/ext/barcode/qr/unicode.go @@ -3,7 +3,7 @@ package qr import ( "errors" - "github.com/henrylee2cn/faygo/ext/barcode/utils" + "github.com/andeya/faygo/ext/barcode/utils" ) func encodeUnicode(content string, ecl ErrorCorrectionLevel) (*utils.BitList, *versionInfo, error) { diff --git a/ext/barcode/twooffive/encoder.go b/ext/barcode/twooffive/encoder.go index acb8eca..aebfc16 100644 --- a/ext/barcode/twooffive/encoder.go +++ b/ext/barcode/twooffive/encoder.go @@ -5,8 +5,8 @@ import ( "errors" "fmt" - "github.com/henrylee2cn/faygo/ext/barcode" - "github.com/henrylee2cn/faygo/ext/barcode/utils" + "github.com/andeya/faygo/ext/barcode" + "github.com/andeya/faygo/ext/barcode/utils" ) const patternWidth = 5 diff --git a/ext/barcode/utils/base1dcode.go b/ext/barcode/utils/base1dcode.go index 2f214f6..5a116b5 100644 --- a/ext/barcode/utils/base1dcode.go +++ b/ext/barcode/utils/base1dcode.go @@ -5,7 +5,7 @@ import ( "image" "image/color" - "github.com/henrylee2cn/faygo/ext/barcode" + "github.com/andeya/faygo/ext/barcode" ) type base1DCode struct { diff --git a/ext/db/directsql/checkparameter.go b/ext/db/directsql/checkparameter.go index fec3762..60cab8e 100644 --- a/ext/db/directsql/checkparameter.go +++ b/ext/db/directsql/checkparameter.go @@ -18,8 +18,8 @@ import ( "time" "unicode/utf8" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/ext/uuid" + "github.com/andeya/faygo" + "github.com/andeya/faygo/ext/uuid" ) // 类型判断正则表达式定义 @@ -29,12 +29,12 @@ const ( Email string = "^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" ) -//字符串是否合法Email地址 +// 字符串是否合法Email地址 func IsEmail(str string) bool { return regexp.MustCompile(Email).MatchString(str) } -//字符串是否整数,空也是合法的. +// 字符串是否整数,空也是合法的. func IsInt(str interface{}) bool { if _, ok := str.(float64); ok { return regexp.MustCompile(Int).MatchString(strconv.FormatFloat(str.(float64), 'f', -1, 64)) @@ -42,33 +42,33 @@ func IsInt(str interface{}) bool { return false } -//字符串是否浮点数 +// 字符串是否浮点数 func IsFloat(str interface{}) bool { _, ok := str.(float64) return ok } -//字符串是否有效的长度 +// 字符串是否有效的长度 func IsVaildLength(str string, min, max int) bool { - //min,max都未定义或都为0则不校验长度 + // min,max都未定义或都为0则不校验长度 if min <= 0 && max <= 0 { return true } strLength := utf8.RuneCountInString(str) - //只验证最小长度,最大长度不验证 + // 只验证最小长度,最大长度不验证 if min > 0 && max <= 0 { return strLength >= min } return strLength >= min && strLength <= max } -//给定的数值是否在范围内 +// 给定的数值是否在范围内 func IsVaildValue(value, min, max float64) bool { - //min,max都未定义或都为0则不校验大小 + // min,max都未定义或都为0则不校验大小 if min <= 0 && max <= 0 { return true } - //只验证最小值,最大值不验证 + // 只验证最小值,最大值不验证 if min > 0 && max <= 0 { return value >= min } @@ -78,44 +78,44 @@ func IsVaildValue(value, min, max float64) bool { return value >= min && value <= max } -//给定的字符串是否合法的日期时间 +// 给定的字符串是否合法的日期时间 func IsVaildDatetime(str string) bool { _, err := time.Parse("2006-01-02 15:04", str) return err == nil } -//给定的字符串是否合法的日期(YYYY-MM-DD) +// 给定的字符串是否合法的日期(YYYY-MM-DD) func IsVaildDate(str string) bool { _, err := time.Parse("2006-01-02", str) return err == nil } -//检查是否必须的 +// 检查是否必须的 func CheckRequired(str string) bool { return len(str) > 0 } -//检查并处理参数 +// 检查并处理参数 //paras:sql的cmd中的参数定义slice;mp:客户端提交的参数map;ctx *lessgo.Context当前执行该功能的上下文 -//根据待默认值的参数是否需要返回构造返回到客户端的值 +// 根据待默认值的参数是否需要返回构造返回到客户端的值 func dealwithParameter(paras []*TSqlParameter, mp map[string]interface{}, ctx *faygo.Context) (map[string]interface{}, error) { - //没有参数处理定义返回 + // 没有参数处理定义返回 if len(paras) == 0 { - //faygo.Debug("Check sql parameters - nil") + // faygo.Debug("Check sql parameters - nil") return nil, nil } - //将在服务端生成的默认值需要返回的放入到该结果map中。 + // 将在服务端生成的默认值需要返回的放入到该结果map中。 var result map[string]interface{} result = make(map[string]interface{}) - //循环处理参数 + // 循环处理参数 for _, para := range paras { - //默认值处理,存在就不处理使用存在的值,不存在就增加并返回给客户端 + // 默认值处理,存在就不处理使用存在的值,不存在就增加并返回给客户端 _, exists := mp[para.Name] - //不是从客户的传入的并且有默认值设置 + // 不是从客户的传入的并且有默认值设置 if (!exists) && (para.Default != DT_UNDEFINED) { - //根据默认值类型分别处理 + // 根据默认值类型分别处理 switch para.Default { - case DT_UUID: //uuid + case DT_UUID: // uuid mp[para.Name] = uuid.New().String() case DT_SHORTUUID: // mp[para.Name] = UUIDService().GetShortStrId() @@ -123,50 +123,50 @@ func dealwithParameter(paras []*TSqlParameter, mp map[string]interface{}, ctx *f mp[para.Name] = UUIDService().GetInt64Id() case DT_NOWDATE: // now date mp[para.Name] = time.Now().Format("2006-01-02") - case DT_NOWDATETIME: //now(date +time) + case DT_NOWDATETIME: // now(date +time) mp[para.Name] = time.Now().Format("2006-01-02 15:04:05") - case DT_NOW_UNIX: //当前日期时间unix值 int64 now datetime + case DT_NOW_UNIX: // 当前日期时间unix值 int64 now datetime mp[para.Name] = time.Now().Unix() - case DT_VALUE: //直接值类型,将处理后的值赋值到参数值 + case DT_VALUE: // 直接值类型,将处理后的值赋值到参数值 mp[para.Name] = para.Defaultstr - case DT_CUSTOM: //通过RegAny注册的变量或函数 + case DT_CUSTOM: // 通过RegAny注册的变量或函数 value, err := contextcall(para.Defaultstr, ctx) - //faygo.Debug("SQL Default parameter value:", value) + // faygo.Debug("SQL Default parameter value:", value) if err == nil { mp[para.Name] = value.Interface() } else { faygo.Error("Error: sql default parameter error,", err) } - //如果是parentid则从 临时缓存的取值。 + // 如果是parentid则从 临时缓存的取值。 case DT_PARENTID: mp[para.Name] = ctx.Data("__directsql__parentid") faygo.Debug("Read parentid value:", mp[para.Name]) } - //如果需要返回 + // 如果需要返回 if para.Return { result[para.Name] = mp[para.Name] } - //如果作为从表的关联主表的id使用,则将值临时放到ctx,以便从表取值时用。 + // 如果作为从表的关联主表的id使用,则将值临时放到ctx,以便从表取值时用。 if para.Parentid { ctx.SetData("__directsql__parentid", mp[para.Name]) faygo.Debug("Write parentid value:", mp[para.Name]) } - //如果不是从客户的传入的并且有默认值设置则后边的验证规则不执行了,如果是从客户的传入的则需要进行进行后边的默认值校验 + // 如果不是从客户的传入的并且有默认值设置则后边的验证规则不执行了,如果是从客户的传入的则需要进行进行后边的默认值校验 continue } - //根据参数名称从提交的参数中获取值循环验证类型、长度、是否为空等信息 + // 根据参数名称从提交的参数中获取值循环验证类型、长度、是否为空等信息 if v, ok := mp[para.Name]; ok { - //是否必须的 + // 是否必须的 if _, ok := v.(string); ok && (para.Required) && (len(v.(string)) == 0) { return nil, errors.New("错误:参数[" + para.Name + "]不能为空!") } - //faygo.Debug("Check sql parameters - get value") - //参数类型处理 + // faygo.Debug("Check sql parameters - get value") + // 参数类型处理 switch para.Paratype { case PT_STRING: - //验证长度,是否必须的 + // 验证长度,是否必须的 if IsVaildLength(v.(string), para.Minlen, para.Maxlen) { continue } else { @@ -174,13 +174,13 @@ func dealwithParameter(paras []*TSqlParameter, mp map[string]interface{}, ctx *f } case PT_INT: - //faygo.Debug("Check sql int parameter -", v) - //验证是否整数 + // faygo.Debug("Check sql int parameter -", v) + // 验证是否整数 if IsInt(v) { } else { return nil, errors.New("错误:参数[" + para.Name + "]不是有效的整数!") } - //验证数值范围 + // 验证数值范围 if IsVaildValue(v.(float64), para.MinValue, para.MaxValue) { continue } else { @@ -188,12 +188,12 @@ func dealwithParameter(paras []*TSqlParameter, mp map[string]interface{}, ctx *f } case PT_FLOAT: - //验证是否浮点数 + // 验证是否浮点数 if IsFloat(v) { } else { return nil, errors.New("错误:参数[" + para.Name + "]不是有效的浮点数!") } - //验证数值范围 + // 验证数值范围 if IsVaildValue(v.(float64), para.MinValue, para.MaxValue) { continue } else { @@ -201,30 +201,30 @@ func dealwithParameter(paras []*TSqlParameter, mp map[string]interface{}, ctx *f } case PT_DATE: - //验证日期格式 + // 验证日期格式 if IsVaildDate(v.(string)) { continue } else { return nil, errors.New("错误:参数[" + para.Name + "]不是有效的日期!") } case PT_DATETIME: - //验证日期时间格式 + // 验证日期时间格式 if IsVaildDatetime(v.(string)) { continue } else { return nil, errors.New("错误:参数[" + para.Name + "]不是有效的日期时间!") } case PT_EMAIL: - //验证email格式 + // 验证email格式 if IsEmail(v.(string)) { continue } else { return nil, errors.New("错误:参数[" + para.Name + "]不是有效的电子信箱!") } } - //faygo.Debug("Check sql parameters - " + para.Name + ": " + v.(string)) + // faygo.Debug("Check sql parameters - " + para.Name + ": " + v.(string)) } else { - //sql的cmd参数中存在该参数定义但传入的post参数不存在则返回错误 + // sql的cmd参数中存在该参数定义但传入的post参数不存在则返回错误 return nil, errors.New("错误:配置的参数[" + para.Name + "]客户端未提交,请检查!") } } diff --git a/ext/db/directsql/resultcache.go b/ext/db/directsql/resultcache.go index 0dff4c8..608daeb 100644 --- a/ext/db/directsql/resultcache.go +++ b/ext/db/directsql/resultcache.go @@ -9,40 +9,41 @@ package directsql import ( - "github.com/henrylee2cn/faygo" "sync" "time" + + "github.com/andeya/faygo" ) -//缓存结果对象 +// 缓存结果对象 type memo struct { Timeout time.Time - Result []byte //interface{} - Suffix string //附加的标识,对于有参数的sql使用该后缀标识参数差异,只缓存第一次查询默认参数的情况,其他的不缓存,缓存的刷新也依赖该 + Result []byte // interface{} + Suffix string // 附加的标识,对于有参数的sql使用该后缀标识参数差异,只缓存第一次查询默认参数的情况,其他的不缓存,缓存的刷新也依赖该 } -//缓存池对象 +// 缓存池对象 type MemoPool struct { pool map[string]*memo mutex *sync.RWMutex } -//全局缓存池 +// 全局缓存池 var mp *MemoPool func init() { mp = &MemoPool{pool: map[string]*memo{}, mutex: new(sync.RWMutex)} } -//根据key以及suffix后缀获取缓存的结果 has 表示存在有效的result,result为结果 +// 根据key以及suffix后缀获取缓存的结果 has 表示存在有效的result,result为结果 func GetCache(key string, suffix string) (ok bool, result []byte) { mp.mutex.RLock() memoized := mp.pool[key] mp.mutex.RUnlock() - //lessgo.Log.Debug("Get Cache:[" + key + " - " + suffix + "]") + // lessgo.Log.Debug("Get Cache:[" + key + " - " + suffix + "]") // 有缓存,并且后缀标识相同,且未到期则返回 true 以及缓存值 if (memoized != nil) && (memoized.Suffix == suffix) && memoized.Timeout.After(time.Now()) { - //lessgo.Log.Debug("Get Cache Result:["+key+" - "+suffix+"] ", memoized.Result) + // lessgo.Log.Debug("Get Cache Result:["+key+" - "+suffix+"] ", memoized.Result) faygo.Debug("Get Cache time:["+key+" - "+suffix+"]", time.Now()) faygo.Debug("Get Cache timeout:["+key+" - "+suffix+"]", memoized.Timeout) return true, memoized.Result @@ -50,31 +51,31 @@ func GetCache(key string, suffix string) (ok bool, result []byte) { return false, nil } -//将key以及suffix后缀的值放入到缓存中,如果存在则替换,并记录失效日期 +// 将key以及suffix后缀的值放入到缓存中,如果存在则替换,并记录失效日期 func SetCache(key string, suffix string, value []byte, timeout int) { if value != nil { mp.mutex.RLock() memoized := mp.pool[key] mp.mutex.RUnlock() - //缓存key存在值但后缀不同则退出 + // 缓存key存在值但后缀不同则退出 if (memoized != nil) && (memoized.Suffix != suffix) { return } - //faygo.Debug("Set Cache:[" + key + " - " + suffix + "]") - //缓存不存在或虽然存在但suffix后缀相同则修改之 + // faygo.Debug("Set Cache:[" + key + " - " + suffix + "]") + // 缓存不存在或虽然存在但suffix后缀相同则修改之 var duration time.Duration - //-1为一直有效,-2为一月,-3为一周 -4为一天,单位为分钟 + // -1为一直有效,-2为一月,-3为一周 -4为一天,单位为分钟 switch timeout { case -1: - duration = 365 * time.Duration(24) * time.Hour //一年 + duration = 365 * time.Duration(24) * time.Hour // 一年 case -2: - duration = 30 * time.Duration(24) * time.Hour //一月 + duration = 30 * time.Duration(24) * time.Hour // 一月 case -3: - duration = 7 * time.Duration(24) * time.Hour //一周 + duration = 7 * time.Duration(24) * time.Hour // 一周 case -4: - duration = time.Duration(24) * time.Hour //一天 + duration = time.Duration(24) * time.Hour // 一天 default: - duration = time.Duration(timeout) * time.Minute //分钟 + duration = time.Duration(timeout) * time.Minute // 分钟 } mp.mutex.Lock() mp.pool[key] = &memo{ @@ -83,18 +84,18 @@ func SetCache(key string, suffix string, value []byte, timeout int) { Result: value, } mp.mutex.Unlock() - //faygo.Debug("Set Cache Result:["+key+" - "+suffix+"]", mp.pool[key]) + // faygo.Debug("Set Cache Result:["+key+" - "+suffix+"]", mp.pool[key]) } } -//清除key的缓存 +// 清除key的缓存 func RemoveCache(key string) { mp.mutex.Lock() delete(mp.pool, key) mp.mutex.Unlock() } -//清除全部缓存 +// 清除全部缓存 func ClearCache() { mp.mutex.Lock() for key, _ := range mp.pool { diff --git a/ext/db/directsql/snowflake.go b/ext/db/directsql/snowflake.go index c5c99e4..2ba8e53 100644 --- a/ext/db/directsql/snowflake.go +++ b/ext/db/directsql/snowflake.go @@ -13,12 +13,12 @@ import ( "sync" "time" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) const ( workerBits uint8 = 6 // 10 // 每台机器(节点)的ID位数 10位最大可以有2^10=1024个节点,6位支持64个节点 - numberBits uint8 = 12 //12 // 表示每个集群下的每个节点,1毫秒内可生成的id序号的二进制位数 即每毫秒可生成 2^12-1=4096个唯一ID + numberBits uint8 = 12 // 12 // 表示每个集群下的每个节点,1毫秒内可生成的id序号的二进制位数 即每毫秒可生成 2^12-1=4096个唯一ID // 这里求最大值使用了位运算,-1 的二进制表示为 1 的补码,感兴趣的同学可以自己算算试试 -1 ^ (-1 << nodeBits) 这里是不是等于 1023 workerMax int64 = -1 ^ (-1 << workerBits) // 节点ID的最大值,用于防止溢出 numberMax int64 = -1 ^ (-1 << numberBits) // 同上,用来表示生成id序号的最大值 @@ -27,7 +27,7 @@ const ( // 41位字节作为时间戳数值的话 大约68年就会用完,如果 45位呢??? // 假如你2010年1月1日开始开发系统 如果不减去2010年1月1日的时间戳 那么白白浪费40年的时间戳啊! // 这个一旦定义且开始生成ID后千万不要改了 不然可能会生成相同的ID - //epoch int64 = 1535252860333 //1525705533000 // 这个是我在写epoch这个变量时的时间戳(毫秒) + // epoch int64 = 1535252860333 //1525705533000 // 这个是我在写epoch这个变量时的时间戳(毫秒) ) // 定义一个woker工作节点所需要的基本参数 @@ -36,20 +36,20 @@ type Worker struct { timestamp int64 // 记录时间戳 workerId int64 // 该节点的ID number int64 // 当前毫秒已经生成的id序列号(从0开始累加) 1毫秒内最多生成4096个ID - starttimestamp int64 //这个一旦定义且开始生成ID后千万不要改了 不然可能会生成相同的ID + starttimestamp int64 // 这个一旦定义且开始生成ID后千万不要改了 不然可能会生成相同的ID } -//单件模式,确保生成唯一一个IDService的实例 +// 单件模式,确保生成唯一一个IDService的实例 var once sync.Once var _uuidservice *Worker -//UUIDService 获取uuid的入口函数 +// UUIDService 获取uuid的入口函数 func UUIDService() *Worker { once.Do(func() { // 要先检测workerId是否在上面定义的范围内 if models.servernodeid < 0 || models.servernodeid > workerMax { faygo.Error("directsql uuidservice: Worker ID excess of quantity") - //return nil //, errors.New("Worker ID excess of quantity") + // return nil //, errors.New("Worker ID excess of quantity") } _uuidservice = &Worker{ timestamp: 0, @@ -115,6 +115,6 @@ func (w *Worker) GetShortStrId() string { } // 如果在程序跑了一段时间修改了epoch这个值 可能会导致生成相同的ID ID := int64((now-w.starttimestamp)< 0) { return ctx.JSONMsg(200, 200, result) } else { return ctx.JSONMsg(200, 200, "Info: Exec sql ok!") } - case ST_BATCHEXEC: //批量执行--原来的批量插入 - //.1.获取 Ajax post json 参数 + case ST_BATCHEXEC: // 批量执行--原来的批量插入 + // .1.获取 Ajax post json 参数 var jsonpara []map[string]interface{} - err := ctx.BindJSON(&jsonpara) //从Body获取 json参数 + err := ctx.BindJSON(&jsonpara) // 从Body获取 json参数 if err != nil { faygo.Info("Info: POST para is empty," + err.Error()) - //return ctx.JSONMsg(404, 404, err.Error()) - //如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 + // return ctx.JSONMsg(404, 404, err.Error()) + // 如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 if jsonpara == nil { jsonpara = make([]map[string]interface{}, 0) } } - //.2.SQL定义参数验证并处理---OK,考虑将通过参数默认值处理的数据返回给客户端 - //将在服务端生成的uuid返回到客户端的变量 + // .2.SQL定义参数验证并处理---OK,考虑将通过参数默认值处理的数据返回给客户端 + // 将在服务端生成的uuid返回到客户端的变量 var results []map[string]interface{} - //未配置参数则直接忽略 + // 未配置参数则直接忽略 if len(se.Cmds[0].Parameters) > 0 { results = make([]map[string]interface{}, 0) for _, jp := range jsonpara { @@ -352,42 +352,42 @@ func DirectSQL() faygo.HandlerFunc { } } - //.3.执行sql并返回结果 + // .3.执行sql并返回结果 err = m.bacthExecMap(se, jsonpara) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //如果存在服务端生成的uuid参数的则返回到客户端 + // 如果存在服务端生成的uuid参数的则返回到客户端 if (results != nil) && (len(results) > 0) { return ctx.JSONMsg(200, 200, results) } else { return ctx.JSONMsg(200, 200, "Bacth exec sql ok!") } - case ST_BATCHMULTIEXEC: //批量複合語句 - //.1.获取 Ajax post json 参数 + case ST_BATCHMULTIEXEC: // 批量複合語句 + // .1.获取 Ajax post json 参数 var jsonpara map[string][]map[string]interface{} - err := ctx.BindJSON(&jsonpara) //从Body获取 json参数 + err := ctx.BindJSON(&jsonpara) // 从Body获取 json参数 if err != nil { faygo.Info("Info: POST para is empty," + err.Error()) - //return ctx.JSONMsg(404, 404, err.Error()) - //如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 + // return ctx.JSONMsg(404, 404, err.Error()) + // 如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 if jsonpara == nil { jsonpara = make(map[string][]map[string]interface{}) } } - //.2.SQL定义参数验证并处理---OK,考虑将通过参数默认值处理的数据返回给客户端 - //将在服务端生成的uuid返回到客户端的变量 + // .2.SQL定义参数验证并处理---OK,考虑将通过参数默认值处理的数据返回给客户端 + // 将在服务端生成的uuid返回到客户端的变量 var results map[string][]map[string]interface{} results = make(map[string][]map[string]interface{}) - //循環每個sql定義 + // 循環每個sql定義 for _, cmd := range se.Cmds { - //未配置参数则直接忽略 + // 未配置参数则直接忽略 if len(cmd.Parameters) == 0 { continue } - //循環其批量參數 + // 循環其批量參數 if sp, ok := jsonpara[cmd.Pin]; ok { result1 := make([]map[string]interface{}, 0) for _, p := range sp { @@ -405,20 +405,20 @@ func DirectSQL() faygo.HandlerFunc { } } } - //.3.执行sql并返回结果 + // .3.执行sql并返回结果 err = m.bacthMultiExecMap(se, jsonpara) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //如果存在服务端生成的uuid参数的则返回到客户端 + // 如果存在服务端生成的uuid参数的则返回到客户端 if (results != nil) && (len(results) > 0) { return ctx.JSONMsg(200, 200, results) } else { return ctx.JSONMsg(200, 200, "Bacth Multi Exec sql ok!") } - case ST_GETBLOB: //执行sql从数据库中获取BLOB字段的二进制流 - //faygo.Info("Info: getblob sql") + case ST_GETBLOB: // 执行sql从数据库中获取BLOB字段的二进制流 + // faygo.Info("Info: getblob sql") var jsonpara map[string]interface{} // query paramaters sp := ctx.QueryParamAll() @@ -426,20 +426,20 @@ func DirectSQL() faygo.HandlerFunc { for i, v := range sp { jsonpara[i] = v[0] } - //参数验证并处理 + // 参数验证并处理 _, err := dealwithParameter(se.Cmds[0].Parameters, jsonpara, ctx) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(400, 400, err.Error()) } - //執行並返回結果 + // 執行並返回結果 data, err := m.getBLOB(se, jsonpara) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //faygo.Debug("getblob :", data) - //流方式返回二进制结果 + // faygo.Debug("getblob :", data) + // 流方式返回二进制结果 err = ctx.Bytes(200, "application/octet-stream", data) if err != nil { faygo.Error(err.Error()) @@ -447,14 +447,14 @@ func DirectSQL() faygo.HandlerFunc { } return nil - case ST_SETBLOB: //执行sql保存二进制流到数据库BLOB字段 - //faygo.Info("Info: setblob sql") + case ST_SETBLOB: // 执行sql保存二进制流到数据库BLOB字段 + // faygo.Info("Info: setblob sql") // 如果不存在提交的文件 if !ctx.HasFormFile("inputfile") { - //faygo.Error(err.Error()) + // faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, errors.New("error: Not has inputfile tag!")) } - //获取提交的二进制数据 + // 获取提交的二进制数据 f, _, err := ctx.R.FormFile("inputfile") if err != nil { faygo.Error(err.Error()) @@ -466,7 +466,7 @@ func DirectSQL() faygo.HandlerFunc { err = err2 } }() - //将文件内容读取到[]Bytes + // 将文件内容读取到[]Bytes blobdata, err := ioutil.ReadAll(f) if err != nil { faygo.Error(err.Error()) @@ -479,8 +479,8 @@ func DirectSQL() faygo.HandlerFunc { for i, v := range sp { jsonpara[i] = v[0] } - //循环处理参数,将第一个blob类型参数的值设置为二进制文件 - //faygo.Debug("setblob sql paras:", se.Cmds[0].Parameters) + // 循环处理参数,将第一个blob类型参数的值设置为二进制文件 + // faygo.Debug("setblob sql paras:", se.Cmds[0].Parameters) for _, para := range se.Cmds[0].Parameters { if para.Paratype == PT_BLOB { faygo.Debug("setblob sql blob para :", para.Name) @@ -488,22 +488,22 @@ func DirectSQL() faygo.HandlerFunc { break } } - //参数验证并处理 + // 参数验证并处理 result, err := dealwithParameter(se.Cmds[0].Parameters, jsonpara, ctx) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(400, 400, err.Error()) } - //jsonpara["doc"] = blobdata - //faygo.Debug("setblob para:", jsonpara) - //执行 setBLOB 操作,保存数据。 + // jsonpara["doc"] = blobdata + // faygo.Debug("setblob para:", jsonpara) + // 执行 setBLOB 操作,保存数据。 err = m.setBLOB(se, jsonpara) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //如果存在服务端生成并需要返回的参数的则返回到客户端 + // 如果存在服务端生成并需要返回的参数的则返回到客户端 if (result != nil) && (len(result) > 0) { return ctx.JSONMsg(200, 200, result) } @@ -514,7 +514,7 @@ func DirectSQL() faygo.HandlerFunc { } } -//重新载入全部ModelSql配置文件 +// 重新载入全部ModelSql配置文件 func DirectSQLReloadAll() faygo.HandlerFunc { return func(c *faygo.Context) error { ReloadAll() @@ -522,10 +522,10 @@ func DirectSQLReloadAll() faygo.HandlerFunc { } } -//重新载入单个ModelSql配置文件 +// 重新载入单个ModelSql配置文件 func DirectSQLReloadModel() faygo.HandlerFunc { return func(c *faygo.Context) error { - //ctx.Path(), '/', 2) 去掉 /bom/reload/ + // ctx.Path(), '/', 2) 去掉 /bom/reload/ err := ReloadModel(trimBefore(c.Path(), '/', 3)) if err != nil { return err @@ -534,9 +534,9 @@ func DirectSQLReloadModel() faygo.HandlerFunc { } } -//发送JSON(P)响应 +// 发送JSON(P)响应 func sendJSON(ctx *faygo.Context, callback string, b []byte) error { - //发送JSONP响应 + // 发送JSONP响应 if len(callback) > 0 { callback = template.JSEscapeString(callback) callbackContent := bytes.NewBufferString(" if(window." + callback + ")" + callback) @@ -545,6 +545,6 @@ func sendJSON(ctx *faygo.Context, callback string, b []byte) error { callbackContent.WriteString(");\r\n") return ctx.Bytes(200, faygo.MIMEApplicationJavaScriptCharsetUTF8, callbackContent.Bytes()) } - //正常有数据JSON响应 + // 正常有数据JSON响应 return ctx.JSONBlob(200, b) } diff --git a/ext/db/directsql/sqlmanage.go b/ext/db/directsql/sqlmanage.go index 8339ec0..8ea48a8 100644 --- a/ext/db/directsql/sqlmanage.go +++ b/ext/db/directsql/sqlmanage.go @@ -29,164 +29,164 @@ import ( "strings" "sync" + "github.com/andeya/faygo" + faygoxorm "github.com/andeya/faygo/ext/db/xorm" + confpkg "github.com/andeya/ini" "github.com/fsnotify/fsnotify" "xorm.io/core" - "github.com/henrylee2cn/faygo" - faygoxorm "github.com/henrylee2cn/faygo/ext/db/xorm" - confpkg "github.com/henrylee2cn/ini" ) -//var modelsqls map[string]*TModel +// var modelsqls map[string]*TModel -//配置文件配置参数 +// 配置文件配置参数 const MSCONFIGFILE = "./config/directsql.ini" // 全部业务SQL路由表,不根据目录分层次,直接放在map sqlmodels中,key=带路径不带扩展名的文件名 type TModels struct { - roots map[string]string //需要载入的根目录(可以多个)-短名=实际路径名 - modelsqls map[string]*TModel //全部定义模型对象 - extension string //模型定义文件的扩展名(默认为.msql) - lazyload bool //true / false 配置项 true 则一开始不全部加载,只根据第一次请求才加载然后缓存,false=一开始就根据配置的roots目录全部加载 - loadLock sync.RWMutex //读写锁 - watcher *fsnotify.Watcher //监控文件变化的wather - cached bool //是否启用查询数据缓存功能,启用则配置sql中配置属性cached=true 才有效,否则一律不缓存 - cachetime int //默认缓存的时间,如果使用缓存并且未配置缓存时间则使用该默认时间,单位为分钟,-1为一直有效,-2为一月,-3为一周 -4为一天,单位为分钟 - servernodeid int64 //服务器节点id(必须为整数):必须介于0~63之间 - starttimestamp int64 //生成shortuuit,int64uuid号码开始时间戳,必须是当前时间的过往日期,一旦使用后绝对不能修改,否则会产生重号!!! + roots map[string]string // 需要载入的根目录(可以多个)-短名=实际路径名 + modelsqls map[string]*TModel // 全部定义模型对象 + extension string // 模型定义文件的扩展名(默认为.msql) + lazyload bool // true / false 配置项 true 则一开始不全部加载,只根据第一次请求才加载然后缓存,false=一开始就根据配置的roots目录全部加载 + loadLock sync.RWMutex // 读写锁 + watcher *fsnotify.Watcher // 监控文件变化的wather + cached bool // 是否启用查询数据缓存功能,启用则配置sql中配置属性cached=true 才有效,否则一律不缓存 + cachetime int // 默认缓存的时间,如果使用缓存并且未配置缓存时间则使用该默认时间,单位为分钟,-1为一直有效,-2为一月,-3为一周 -4为一天,单位为分钟 + servernodeid int64 // 服务器节点id(必须为整数):必须介于0~63之间 + starttimestamp int64 // 生成shortuuit,int64uuid号码开始时间戳,必须是当前时间的过往日期,一旦使用后绝对不能修改,否则会产生重号!!! } -//全局所有业务模型对象 +// 全局所有业务模型对象 var models = &TModels{ modelsqls: make(map[string]*TModel)} -//sqlmodel 一个配置文件的SQLModel对应的结构 +// sqlmodel 一个配置文件的SQLModel对应的结构 type TModel struct { - Id string //root起用映射、不带扩展名的文件名 - DB *core.DB //本模块的db引擎 *xorm.Engine.DB() - Sqls map[string]*TSql //sqlentity key=sqlentity.id + Id string // root起用映射、不带扩展名的文件名 + DB *core.DB // 本模块的db引擎 *xorm.Engine.DB() + Sqls map[string]*TSql // sqlentity key=sqlentity.id } -//临时转换用,因为 XML 不支持解析到 map,所以先读入到[]然后再根据[]创建map +// 临时转换用,因为 XML 不支持解析到 map,所以先读入到[]然后再根据[]创建map type tempTModel struct { XMLName xml.Name `xml:"model"` - Id string `xml:"id,attr"` //不带扩展名的文件名 + Id string `xml:"id,attr"` // 不带扩展名的文件名 Database string `xml:"database,attr"` Sqls []*TSql `xml:"sql"` } -//sql 等节点对应的结构 type TSql struct { XMLName xml.Name `xml:"sql"` - Id string `xml:"id,attr"` //sqlid + Id string `xml:"id,attr"` // sqlid Sqltypestr string `xml:"type,attr"` - Sqltype TSqltype `xml:"-"` //SQL类型 - Idfield string `xml:"idfield,attr"` //SQlType为6=嵌套jsoin树时的ID字段 - Pidfield string `xml:"pidfield,attr"` //SQlType为6=嵌套jsoin树时的ParentID字段 + Sqltype TSqltype `xml:"-"` // SQL类型 + Idfield string `xml:"idfield,attr"` // SQlType为6=嵌套jsoin树时的ID字段 + Pidfield string `xml:"pidfield,attr"` // SQlType为6=嵌套jsoin树时的ParentID字段 Cmds []*TCmd `xml:"cmd"` // sqlcmd(sqltype为分页查询时的计数SQL放第一个,结果SQL放第二个) - Cached bool `xml:"cached,attr"` //是否启用查询数据缓存功能 - Cachetime int `xml:"cachetime,attr"` //默认缓存的时间,单位为分钟,-1为一直有效,-2为一月,-3为一周 -4为一天,单位为分钟 - Eachtran bool `xml:"eachtran,attr"` //对于 batchexec、batchmultiexec类型SQL 如果为 false则所有SQL在一个事务执行,true则每一个批次在一个事务中 + Cached bool `xml:"cached,attr"` // 是否启用查询数据缓存功能 + Cachetime int `xml:"cachetime,attr"` // 默认缓存的时间,单位为分钟,-1为一直有效,-2为一月,-3为一周 -4为一天,单位为分钟 + Eachtran bool `xml:"eachtran,attr"` // 对于 batchexec、batchmultiexec类型SQL 如果为 false则所有SQL在一个事务执行,true则每一个批次在一个事务中 } -//TCmd 等节点的下级节点对应结构 type TCmd struct { XMLName xml.Name `xml:"cmd"` - Pin string `xml:"in,attr"` //输入参数标示 - Rout string `xml:"out,attr"` //输出结果标示 - Sql string `xml:",chardata"` //SQL + Pin string `xml:"in,attr"` // 输入参数标示 + Rout string `xml:"out,attr"` // 输出结果标示 + Sql string `xml:",chardata"` // SQL Parameters []*TSqlParameter `xml:"parameters>parameter"` } -//TSql 类型 +// TSql 类型 type TSqltype int const ( - ST_SELECT TSqltype = iota //0 普通查询 ---OK! - ST_PAGINGSELECT //1 分页查询 ---OK! - ST_NESTEDSELECT //2 嵌套jsoin树---------未实现 - ST_MULTISELECT //3 多结果集查询---OK! - ST_EXEC //4 执行SQL,可以一个事务内批量执行多个cmd - ST_BATCHEXEC //5 根据传入参数在一个事务内多次执行SQL - ST_BATCHMULTIEXEC //6 批量执行复合SQL(多数据集批量插入、更新、删除)---OK! - ST_IMPORT //7 导入数据的SQL:通过xlsx导入数据配置的SQL - ST_EXPORT //8 导出数据的SQL:导出excel格式文件数据 - ST_REPORT //9 报表用的SQL:通过xlsx模板创建报表的SQL - ST_GETBLOB //10 获取BLOB (binary large object),二进制大对象从数据库 - ST_SETBLOB //11 保存BLOB (binary large object),二进制大对象到数据库 + ST_SELECT TSqltype = iota // 0 普通查询 ---OK! + ST_PAGINGSELECT // 1 分页查询 ---OK! + ST_NESTEDSELECT // 2 嵌套jsoin树---------未实现 + ST_MULTISELECT // 3 多结果集查询---OK! + ST_EXEC // 4 执行SQL,可以一个事务内批量执行多个cmd + ST_BATCHEXEC // 5 根据传入参数在一个事务内多次执行SQL + ST_BATCHMULTIEXEC // 6 批量执行复合SQL(多数据集批量插入、更新、删除)---OK! + ST_IMPORT // 7 导入数据的SQL:通过xlsx导入数据配置的SQL + ST_EXPORT // 8 导出数据的SQL:导出excel格式文件数据 + ST_REPORT // 9 报表用的SQL:通过xlsx模板创建报表的SQL + ST_GETBLOB // 10 获取BLOB (binary large object),二进制大对象从数据库 + ST_SETBLOB // 11 保存BLOB (binary large object),二进制大对象到数据库 ) -//TSqlParameter 参数校验定义 +// TSqlParameter 参数校验定义 type TSqlParameter struct { - Name string `xml:"name,attr"` //参数名称必须与cmd中的对应 - Paratypestr string `xml:"type,attr"` //string/number/email/date/datetime/time -不定义则不需要验证 - Paratype TParaType `-` //数值类型 - Required bool `xml:"required,attr"` //0=不是必须的 1=必须的不能为空 - Minlen int `xml:"minlen,attr"` //最小长度 - Maxlen int `xml:"maxlen,attr"` //最大长度 - MinValue float64 `xml:"minvalue,attr"` //最小值 - MaxValue float64 `xml:"maxvalue,attr"` //最大值 + Name string `xml:"name,attr"` // 参数名称必须与cmd中的对应 + Paratypestr string `xml:"type,attr"` // string/number/email/date/datetime/time -不定义则不需要验证 + Paratype TParaType `-` // 数值类型 + Required bool `xml:"required,attr"` // 0=不是必须的 1=必须的不能为空 + Minlen int `xml:"minlen,attr"` // 最小长度 + Maxlen int `xml:"maxlen,attr"` // 最大长度 + MinValue float64 `xml:"minvalue,attr"` // 最小值 + MaxValue float64 `xml:"maxvalue,attr"` // 最大值 Defaultstr string `xml:"default,attr"` // 默认值 undefined/uuid/userid/usercode/username/rootgroupid/rootgroupname/groupid/groupname/nowdate/nowtime - Default TDefaultType `-` //数值类型 - Return bool `xml:"return,attr"` //服务端生成的默认值是否返回到客户端: 0(false)=默认,不返回 1(true)=返回到客户端 - Parentid bool `xml:"parentid,attr"` //是否作为从表的关联本表(主表)的id的值 + Default TDefaultType `-` // 数值类型 + Return bool `xml:"return,attr"` // 服务端生成的默认值是否返回到客户端: 0(false)=默认,不返回 1(true)=返回到客户端 + Parentid bool `xml:"parentid,attr"` // 是否作为从表的关联本表(主表)的id的值 } -//参数类型:string/number/email/date/datetime/time +// 参数类型:string/number/email/date/datetime/time type TParaType int const ( - PT_STRING TParaType = iota //0=字符串,默认就是按照字符串处理 - PT_INT //1=整数数值 - PT_FLOAT //2=浮点数 - PT_DATE //3=日期 - PT_DATETIME //4=日期时间 - PT_EMAIL //5=电子邮件 - PT_BLOB //6=二进制 + PT_STRING TParaType = iota // 0=字符串,默认就是按照字符串处理 + PT_INT // 1=整数数值 + PT_FLOAT // 2=浮点数 + PT_DATE // 3=日期 + PT_DATETIME // 4=日期时间 + PT_EMAIL // 5=电子邮件 + PT_BLOB // 6=二进制 ) -//---------------------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------------------- // 默认值类型:uuid/nowdate/now/nowunix type TDefaultType int const ( - DT_UNDEFINED TDefaultType = iota //0=未定义,不处理默认值 - DT_UUID //uuid + DT_UNDEFINED TDefaultType = iota // 0=未定义,不处理默认值 + DT_UUID // uuid DT_INT64UUID // 64位整数长度的唯一id (具体说明见 readme) - DT_SHORTUUID //短字符串的唯一id(将int64uuid转为36进制的值(10个数字+26个字母组成的)) - DT_NOWDATE //当前日期 now date - DT_NOWDATETIME //当前日期时间 now datetime - DT_NOW_UNIX //当前时间的unix值 int64 now date - DT_CUSTOM //自定义变量,采用注册自定义函数获取变量实现 - DT_PARENTID //关联的主表的Id的值 - DT_VALUE //直接设置默认值,比如字符串设置{""},数值设置 {0} 用大括号括起来 + DT_SHORTUUID // 短字符串的唯一id(将int64uuid转为36进制的值(10个数字+26个字母组成的)) + DT_NOWDATE // 当前日期 now date + DT_NOWDATETIME // 当前日期时间 now datetime + DT_NOW_UNIX // 当前时间的unix值 int64 now date + DT_CUSTOM // 自定义变量,采用注册自定义函数获取变量实现 + DT_PARENTID // 关联的主表的Id的值 + DT_VALUE // 直接设置默认值,比如字符串设置{""},数值设置 {0} 用大括号括起来 ) -//--------------------------------------------------------------------------------------------------- -//读入全部模型sql定义 +// --------------------------------------------------------------------------------------------------- +// 读入全部模型sql定义 func init() { models.loadTModels() } -//首先读取配置参数,读入全部模型 +// 首先读取配置参数,读入全部模型 func (ms *TModels) loadTModels() { ms.loadLock.Lock() defer ms.loadLock.Unlock() - //打开directsql的配置文件 + // 打开directsql的配置文件 cfg, err := confpkg.Load(MSCONFIGFILE) if err != nil { faygo.Error(err.Error()) return } - //是否缓存与缓存时间 + // 是否缓存与缓存时间 ms.cached = cfg.Section("").Key("cached").MustBool(false) ms.cachetime = cfg.Section("").Key("cachetime").MustInt(30) - //SQL参数默认值 shortuuit,int64uuid的配置参数 + // SQL参数默认值 shortuuit,int64uuid的配置参数 ms.servernodeid = cfg.Section("uuid").Key("servernodeid").MustInt64(0) ms.starttimestamp = cfg.Section("uuid").Key("starttimestamp").MustInt64(1535252860333) - //读取ModelSQL文件的根目录 + // 读取ModelSQL文件的根目录 roots, err := cfg.GetSection("roots") if err != nil { faygo.Error(err.Error()) @@ -201,11 +201,11 @@ func (ms *TModels) loadTModels() { } } - //读取扩展名,读取不到就用默认的.msql + // 读取扩展名,读取不到就用默认的.msql ext := cfg.Section("").Key("ext").MustString(".msql") ms.extension = ext - //根据路径遍历加载 + // 根据路径遍历加载 for _, value := range ms.roots { faygo.Debug(value) err = filepath.Walk(value, ms.walkFunc) @@ -214,7 +214,7 @@ func (ms *TModels) loadTModels() { } } - //是否监控文件变化 + // 是否监控文件变化 watch := cfg.Section("").Key("watch").MustBool(false) if watch { err := ms.StartWatcher() @@ -225,20 +225,20 @@ func (ms *TModels) loadTModels() { } -//将带路径文件名处理成 TModel的 id 示例: bizmodel\demo.msql --> biz/demo +// 将带路径文件名处理成 TModel的 id 示例: bizmodel\demo.msql --> biz/demo func (ms *TModels) filenameToModelId(path string) string { key := strings.Replace(path, "\\", "/", -1) - key = strings.TrimSuffix(key, ms.extension) //去掉扩展名 + key = strings.TrimSuffix(key, ms.extension) // 去掉扩展名 for root, value := range ms.roots { if strings.HasPrefix(key, value) { - key = strings.Replace(key, value, root, 1) //处理前缀,将定义的根路径替换为名称 + key = strings.Replace(key, value, root, 1) // 处理前缀,将定义的根路径替换为名称 break } } return key } -//遍历子目录文件处理函数 +// 遍历子目录文件处理函数 func (ms *TModels) walkFunc(path string, info os.FileInfo, err error) error { if err != nil { return err @@ -250,18 +250,18 @@ func (ms *TModels) walkFunc(path string, info os.FileInfo, err error) error { m, err := ms.parseTModel(path) if err != nil { faygo.Error("Model file: " + path + " --- " + err.Error()) - return nil //单个文件解析出错继续加载其他的文件 + return nil // 单个文件解析出错继续加载其他的文件 } - //将本文件对应的TModel放入到TModels + // 将本文件对应的TModel放入到TModels ms.modelsqls[ms.filenameToModelId(path)] = m faygo.Debug("Model file: " + path + " ------> " + ms.filenameToModelId(path) + " loaded. ") } return nil } -//解析单个ModelSQL定义文件 +// 解析单个ModelSQL定义文件 func (ms *TModels) parseTModel(msqlfile string) (*TModel, error) { - //读取文件 + // 读取文件 content, err := ioutil.ReadFile(msqlfile) if err != nil { return nil, err @@ -271,46 +271,46 @@ func (ms *TModels) parseTModel(msqlfile string) (*TModel, error) { if err != nil { return nil, err } - //设置数据库 + // 设置数据库 dbe, ok := faygoxorm.DB(tempresult.Database) if ok == false { dbe = faygoxorm.MustDB() - //faygo.Log.Debug("database:", tempresult.Database) + // faygo.Log.Debug("database:", tempresult.Database) } - //定义一个 TModel将 tempTModel 转换为 TModel + // 定义一个 TModel将 tempTModel 转换为 TModel result := &TModel{Id: tempresult.Id, DB: dbe.DB(), Sqls: make(map[string]*TSql)} - //处理一遍:设置数据库访问引擎,设置TSql的类型 + // 处理一遍:设置数据库访问引擎,设置TSql的类型 for _, se := range tempresult.Sqls { - //处理SQL类型与查询类语句缓存的配置参数 + // 处理SQL类型与查询类语句缓存的配置参数 switch se.Sqltypestr { case "select": se.Sqltype = ST_SELECT - //缓存设置处理 + // 缓存设置处理 se.Cached = se.Cached && ms.cached if se.Cached && se.Cachetime == 0 { se.Cachetime = ms.cachetime } case "pagingselect": se.Sqltype = ST_PAGINGSELECT - //缓存设置处理 + // 缓存设置处理 se.Cached = se.Cached && ms.cached if se.Cached && se.Cachetime == 0 { se.Cachetime = ms.cachetime } case "nestedselect": se.Sqltype = ST_NESTEDSELECT - //缓存设置处理 + // 缓存设置处理 se.Cached = se.Cached && ms.cached if se.Cached && se.Cachetime == 0 { se.Cachetime = ms.cachetime } case "multiselect": se.Sqltype = ST_MULTISELECT - //缓存设置处理 + // 缓存设置处理 if !ms.cached { se.Cached = false } - //se.cached = se.cached && ms.cached + // se.cached = se.cached && ms.cached if se.Cached && se.Cachetime == 0 { se.Cachetime = ms.cachetime } @@ -334,58 +334,58 @@ func (ms *TModels) parseTModel(msqlfile string) (*TModel, error) { faygo.Error(errors.New("错误:配置文件[ " + msqlfile + " ]中存在无效的sql节点类型[ " + se.Sqltypestr + " ]!")) } result.Sqls[se.Id] = se - //faygo.Debug(se) - //sql下的每个cmd循环处理 + // faygo.Debug(se) + // sql下的每个cmd循环处理 for _, cmd := range se.Cmds { - //每个cmd下的参数循环处理参数类型与默认值类型 + // 每个cmd下的参数循环处理参数类型与默认值类型 for _, para := range cmd.Parameters { - //参数类型 - switch para.Paratypestr { //string/int/float/email/date/datetime/blob + // 参数类型 + switch para.Paratypestr { // string/int/float/email/date/datetime/blob case "string": - para.Paratype = PT_STRING //0=字符串,默认就是按照字符串处理 + para.Paratype = PT_STRING // 0=字符串,默认就是按照字符串处理 case "int": - para.Paratype = PT_INT //1=整数数值 + para.Paratype = PT_INT // 1=整数数值 case "float": - para.Paratype = PT_FLOAT //2=浮点数 + para.Paratype = PT_FLOAT // 2=浮点数 case "date": - para.Paratype = PT_DATE //3=日期 + para.Paratype = PT_DATE // 3=日期 case "datetime": - para.Paratype = PT_DATETIME //4=日期时间 + para.Paratype = PT_DATETIME // 4=日期时间 case "email": - para.Paratype = PT_EMAIL //5=电子邮件 + para.Paratype = PT_EMAIL // 5=电子邮件 case "blob": para.Paratype = PT_BLOB } - //默认值类型 + // 默认值类型 switch para.Defaultstr { case "uuid": - para.Default = DT_UUID //1=uuid + para.Default = DT_UUID // 1=uuid case "shortuuid": - para.Default = DT_SHORTUUID //短字符uuid + para.Default = DT_SHORTUUID // 短字符uuid case "int64uuid": - para.Default = DT_INT64UUID //int64唯一id + para.Default = DT_INT64UUID // int64唯一id case "nowdate": - para.Default = DT_NOWDATE //当前日期 now date + para.Default = DT_NOWDATE // 当前日期 now date case "now": - para.Default = DT_NOWDATETIME //当前时间 + para.Default = DT_NOWDATETIME // 当前时间 case "nowunix": - para.Default = DT_NOW_UNIX //当前日期时间unix值 int64 now datetime + para.Default = DT_NOW_UNIX // 当前日期时间unix值 int64 now datetime case "parentid": - para.Default = DT_PARENTID //主表的id的值 (parentid value) + para.Default = DT_PARENTID // 主表的id的值 (parentid value) default: if len(strings.TrimSpace(para.Defaultstr)) > 0 { - //DT_VALUE 直接值类型 {value} + // DT_VALUE 直接值类型 {value} if strings.HasPrefix(para.Defaultstr, "{") && strings.HasSuffix(para.Defaultstr, "}") { para.Default = DT_VALUE - //同时将值的前后缀去掉 {value}=>value + // 同时将值的前后缀去掉 {value}=>value para.Defaultstr = strings.TrimRight(strings.TrimLeft(para.Defaultstr, "{"), "}") } else { - //DT_CUSTOM自定义注册函数值类型 - para.Default = DT_CUSTOM //如果参数的默认值来源标识不为空且不是{vaule}则说明是通过自定义函数注册的默认值 + // DT_CUSTOM自定义注册函数值类型 + para.Default = DT_CUSTOM // 如果参数的默认值来源标识不为空且不是{vaule}则说明是通过自定义函数注册的默认值 } } else { - para.Default = DT_UNDEFINED //未定义默认值 + para.Default = DT_UNDEFINED // 未定义默认值 } } } @@ -394,7 +394,7 @@ func (ms *TModels) parseTModel(msqlfile string) (*TModel, error) { return result, nil } -//获取sqlentity SQL的执行实体 +// 获取sqlentity SQL的执行实体 func (ms *TModels) findsql(modelid string, sqlid string) *TSql { if sm, ok := ms.modelsqls[modelid]; ok { if se, ok := sm.Sqls[sqlid]; ok { @@ -404,7 +404,7 @@ func (ms *TModels) findsql(modelid string, sqlid string) *TSql { return nil } -//获取sqlentity SQL的执行实体与DB执行引擎 +// 获取sqlentity SQL的执行实体与DB执行引擎 func (ms *TModels) findsqlanddb(modelid string, sqlid string) (*TSql, *core.DB) { if sm, ok := ms.modelsqls[modelid]; ok { if se, ok := sm.Sqls[sqlid]; ok { @@ -414,7 +414,7 @@ func (ms *TModels) findsqlanddb(modelid string, sqlid string) (*TSql, *core.DB) return nil, nil } -//获取sqlentity 的类型 +// 获取sqlentity 的类型 func (ms *TModels) getSqlType(modelid string, sqlid string) TSqltype { if sm, ok := ms.modelsqls[modelid]; ok { if se, ok := sm.Sqls[sqlid]; ok { @@ -432,22 +432,22 @@ func (ms *TModels) findmodel(modelid string) *TModel { return nil } -//文件内容改变重新载入(新增、修改的都触发) +// 文件内容改变重新载入(新增、修改的都触发) func (ms *TModels) refreshModelFile(msqlfile string) error { ms.loadLock.Lock() defer ms.loadLock.Unlock() - //重新解析 + // 重新解析 m, err := ms.parseTModel(msqlfile) if err != nil { faygo.Error(err.Error()) - return err //单个文件解析出错继续加载其他的文件 + return err // 单个文件解析出错继续加载其他的文件 } - //将本文件对应的TModel放入到TModels + // 将本文件对应的TModel放入到TModels ms.modelsqls[ms.filenameToModelId(msqlfile)] = m return nil } -//文件已经被移除,从内存中删除 +// 文件已经被移除,从内存中删除 func (ms *TModels) removeModelFile(msqlfile string) error { ms.loadLock.Lock() defer ms.loadLock.Unlock() @@ -455,15 +455,15 @@ func (ms *TModels) removeModelFile(msqlfile string) error { return nil } -//文件改名---暂无实现 +// 文件改名---暂无实现 func (ms *TModels) renameModelFile(msqlfile, newfilename string) error { - //err := ms.removeModelFile(msqlfile) - //err = ms.refreshModelFile(newfilename) + // err := ms.removeModelFile(msqlfile) + // err = ms.refreshModelFile(newfilename) return nil } -//单元访问文件-------------------------------------------------------------- -//获取sqlentity SQL的执行实体与数据库引擎 +// 单元访问文件-------------------------------------------------------------- +// 获取sqlentity SQL的执行实体与数据库引擎 func findSqlAndDB(modelid string, sqlid string) (*TSql, *core.DB) { return models.findsqlanddb(modelid, sqlid) } @@ -473,27 +473,27 @@ func GetSqlType(modelid string, sqlid string) TSqltype { return models.getSqlType(modelid, sqlid) } -//获取sqlentity SQL的执行实体 +// 获取sqlentity SQL的执行实体 func findSql(modelid string, sqlid string) *TSql { - //faygo.Debug("Model Path: " + modelid + " ,SqlId: " + sqlid) + // faygo.Debug("Model Path: " + modelid + " ,SqlId: " + sqlid) return models.findsql(modelid, sqlid) } -//根据TModel文件路径获取 TModel +// 根据TModel文件路径获取 TModel func findModel(modelid string) *TModel { - //faygo.Debug("Model Path: " + modelid) + // faygo.Debug("Model Path: " + modelid) return models.findmodel(modelid) } -//重置配置文件全部重新载入,API:/bom/reload handle调用 +// 重置配置文件全部重新载入,API:/bom/reload handle调用 func ReloadAll() { models = &TModels{ modelsqls: make(map[string]*TModel)} models.loadTModels() } -//重新载入单个模型文件---未测试!!! +// 重新载入单个模型文件---未测试!!! func ReloadModel(msqlfile string) error { - //已经去掉 "/bom/reload/",需要加上扩展名 + // 已经去掉 "/bom/reload/",需要加上扩展名 return models.refreshModelFile(msqlfile + models.extension) } diff --git a/ext/db/directsql/sqlrouter.go b/ext/db/directsql/sqlrouter.go index 8c7e7be..24d22d2 100644 --- a/ext/db/directsql/sqlrouter.go +++ b/ext/db/directsql/sqlrouter.go @@ -6,7 +6,7 @@ package directsql /* import ( - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) //注册路由 diff --git a/ext/db/directsql/sqlservice.go b/ext/db/directsql/sqlservice.go index 557dc93..6b36f32 100644 --- a/ext/db/directsql/sqlservice.go +++ b/ext/db/directsql/sqlservice.go @@ -19,8 +19,8 @@ import ( "errors" "reflect" + "github.com/andeya/faygo" "xorm.io/core" - "github.com/henrylee2cn/faygo" ) var notFoundError = func(sqlid string) error { @@ -32,7 +32,7 @@ var notMatchError = func() error { // 默认参数处理 func DealwithParameter(modelId, sqlId string, mp map[string]interface{}, sqlindex int, ctx *faygo.Context) error { - //获取Sqlentity,db + // 获取Sqlentity,db se, _ := findSqlAndDB(modelId, sqlId) if se == nil { return notFoundError(modelId + "/" + sqlId) @@ -45,29 +45,29 @@ func DealwithParameter(modelId, sqlId string, mp map[string]interface{}, sqlinde return nil } -//查询 根据modelId,sqlId ,mp:map[string]interface{}命名参数,返回*core.Rows +// 查询 根据modelId,sqlId ,mp:map[string]interface{}命名参数,返回*core.Rows func SelectMapToRows(modelId, sqlId string, mp map[string]interface{}) (*core.Rows, error) { - //获取Sqlentity,db + // 获取Sqlentity,db se, db := findSqlAndDB(modelId, sqlId) if se == nil { return nil, notFoundError(modelId + "/" + sqlId) } - //判断类型不是Select 就返回错误 + // 判断类型不是Select 就返回错误 if se.Sqltype != ST_SELECT { return nil, notMatchError() } return db.QueryMap(se.Cmds[0].Sql, &mp) } -//判断记录是否存在,根据modelId,sqlId ,mp:map[string]interface{}命名参数,返回*core.Row +// 判断记录是否存在,根据modelId,sqlId ,mp:map[string]interface{}命名参数,返回*core.Row func SelectMapIsExist(modelId, sqlId string, mp map[string]interface{}) (bool, error) { - //获取Sqlentity,db + // 获取Sqlentity,db se, db := findSqlAndDB(modelId, sqlId) if se == nil { return false, notFoundError(modelId + "/" + sqlId) } - //判断类型不是Select 就返回错误 + // 判断类型不是Select 就返回错误 if se.Sqltype != ST_SELECT { return false, notMatchError() } @@ -78,7 +78,7 @@ func SelectMapIsExist(modelId, sqlId string, mp map[string]interface{}) (bool, e return rows.Next(), nil } -//查询 根据modelId,sqlId ,SQL参数 map 返回 []map[string]interface{} +// 查询 根据modelId,sqlId ,SQL参数 map 返回 []map[string]interface{} func SelectMapToMap(modelId, sqlId string, mp map[string]interface{}) ([]map[string]interface{}, error) { rows, err := SelectMapToRows(modelId, sqlId, mp) if err != nil { @@ -88,8 +88,8 @@ func SelectMapToMap(modelId, sqlId string, mp map[string]interface{}) ([]map[str return rows2mapObjects(rows) } -//查询 根据modelId,sqlId ,SQL参数是map, 返回 []struct -//目前使用比较繁琐:st --是结构体的一个空实例,返回的是 改结构体的实例的slice,再使用返还结果时还的需要转换下类型。 +// 查询 根据modelId,sqlId ,SQL参数是map, 返回 []struct +// 目前使用比较繁琐:st --是结构体的一个空实例,返回的是 改结构体的实例的slice,再使用返还结果时还的需要转换下类型。 func SelectMapToStruct(modelId, sqlId string, mp map[string]interface{}, st interface{}) (*[]interface{}, error) { s := reflect.ValueOf(st).Elem() @@ -108,7 +108,7 @@ func SelectMapToStruct(modelId, sqlId string, mp map[string]interface{}, st inte err = rows.Scan(onerow...) if err != nil { return nil, err - //panic(err) + // panic(err) } result = append(result, s.Interface()) } @@ -116,24 +116,24 @@ func SelectMapToStruct(modelId, sqlId string, mp map[string]interface{}, st inte return &result, nil } -//查询 根据modelId,sqlId ,SQL参数是map,dest 是待填充的返回结果 []*Struct ---未完成 +// 查询 根据modelId,sqlId ,SQL参数是map,dest 是待填充的返回结果 []*Struct ---未完成 func SelectMapToStructPro(modelId, sqlId string, mp map[string]interface{}, dest interface{}) error { return nil } -//执行返回多個結果集的多個查询根据modelId,sqlId ,SQLmp:map[string]interface{}命名参数 返回结果 map[string]*Rows +// 执行返回多個結果集的多個查询根据modelId,sqlId ,SQLmp:map[string]interface{}命名参数 返回结果 map[string]*Rows func MultiSelectMapToRows(modelId, sqlId string, mp map[string]interface{}) (map[string]*core.Rows, error) { result := make(map[string]*core.Rows) - //获取Sqlentity,db + // 获取Sqlentity,db se, db := findSqlAndDB(modelId, sqlId) if se == nil { return nil, notFoundError(modelId + "/" + sqlId) } - //判断类型不是MULTISELECT 就返回错误 + // 判断类型不是MULTISELECT 就返回错误 if se.Sqltype != ST_MULTISELECT { return nil, notMatchError() } - //循環每個sql定義 + // 循環每個sql定義 for i, cmd := range se.Cmds { faygo.Debug("MultiSelectMap :" + cmd.Sql) rows, err := db.QueryMap(cmd.Sql, &mp) @@ -149,16 +149,16 @@ func MultiSelectMapToRows(modelId, sqlId string, mp map[string]interface{}) (map return result, nil } -//分頁查詢的返回結果 +// 分頁查詢的返回結果 type PagingSelectRows struct { Total int `json:"total"` Rows *core.Rows } -//执行分页查询SQL mp 是MAP类型命名参数 返回结果 int,[]map[string][]interface{} +// 执行分页查询SQL mp 是MAP类型命名参数 返回结果 int,[]map[string][]interface{} func PagingSelectMapToMap(modelId, sqlId string, mp map[string]interface{}) (*PagingSelectResult, error) { se, db := findSqlAndDB(modelId, sqlId) - //获取总页数,約定該SQL放到第二條,並且只返回一條記錄一個字段 + // 获取总页数,約定該SQL放到第二條,並且只返回一條記錄一個字段 trows, err := db.QueryMap(se.Cmds[0].Sql, &mp) if err != nil { return nil, err @@ -173,7 +173,7 @@ func PagingSelectMapToMap(modelId, sqlId string, mp map[string]interface{}) (*Pa if len(total) != 1 { return nil, errors.New("错误:获取总页数的SQL执行结果非唯一记录!") } - //2.获取当前页數據,約定該SQL放到第二條 + // 2.获取当前页數據,約定該SQL放到第二條 rows, err := db.QueryMap(se.Cmds[1].Sql, &mp) if err != nil { return nil, err @@ -183,15 +183,15 @@ func PagingSelectMapToMap(modelId, sqlId string, mp map[string]interface{}) (*Pa if err != nil { return nil, err } - return &PagingSelectResult{Total: total[0], Data: result}, nil //最終的結果 + return &PagingSelectResult{Total: total[0], Data: result}, nil // 最終的結果 } return nil, err } -//执行分页查询SQL mp 是MAP类型命名参数 返回结果 int,Rows +// 执行分页查询SQL mp 是MAP类型命名参数 返回结果 int,Rows func PagingSelectMapToRows(modelId, sqlId string, mp map[string]interface{}) (*PagingSelectRows, error) { se, db := findSqlAndDB(modelId, sqlId) - //获取总页数,約定該SQL放到第二條,並且只返回一條記錄一個字段 + // 获取总页数,約定該SQL放到第二條,並且只返回一條記錄一個字段 trows, err := db.QueryMap(se.Cmds[0].Sql, &mp) if err != nil { return nil, err @@ -206,17 +206,17 @@ func PagingSelectMapToRows(modelId, sqlId string, mp map[string]interface{}) (*P if len(total) != 1 { return nil, errors.New("错误:获取总页数的SQL执行结果非唯一记录!") } - //2.获取当前页數據,約定該SQL放到第二條 + // 2.获取当前页數據,約定該SQL放到第二條 rows, err := db.QueryMap(se.Cmds[1].Sql, &mp) if err != nil { return nil, err } - return &PagingSelectRows{Total: total[0], Rows: rows}, nil //最終的結果 + return &PagingSelectRows{Total: total[0], Rows: rows}, nil // 最終的結果 } return nil, err } -//多個查询 返回 map[string][]map[string]interface{} +// 多個查询 返回 map[string][]map[string]interface{} func MultiSelectMapToMap(modelId, sqlId string, mp map[string]interface{}) (map[string][]map[string]interface{}, error) { multirows, err := MultiSelectMapToRows(modelId, sqlId, mp) if err != nil { @@ -233,22 +233,22 @@ func MultiSelectMapToMap(modelId, sqlId string, mp map[string]interface{}) (map[ return result, nil } -//执行EXEC (UPDATE、DELETE、INSERT),mp 是MAP类型命名参数 返回结果 sql.Result +// 执行EXEC (UPDATE、DELETE、INSERT),mp 是MAP类型命名参数 返回结果 sql.Result func ExecMap(modelId, sqlId string, mp map[string]interface{}) (sql.Result, error) { - //获取Sqlentity,db + // 获取Sqlentity,db se, db := findSqlAndDB(modelId, sqlId) if se == nil { return nil, notFoundError(modelId + "/" + sqlId) } - //判断类型不是EXEC(UPDATE、DELETE、INSERT)就返回错误 + // 判断类型不是EXEC(UPDATE、DELETE、INSERT)就返回错误 if se.Sqltype != ST_EXEC { return nil, notMatchError() } - //return db.ExecMap(se.Cmds[0].Sql, &mp) + // return db.ExecMap(se.Cmds[0].Sql, &mp) return nil, transact(db, func(tx *core.Tx) error { - //循環每個sql定義 + // 循環每個sql定義 for _, cmd := range se.Cmds { - //faygo.Debug("ExecMap sql:" + cmd.Sql) + // faygo.Debug("ExecMap sql:" + cmd.Sql) if _, err := tx.ExecMap(cmd.Sql, &mp); err != nil { return err } @@ -257,22 +257,22 @@ func ExecMap(modelId, sqlId string, mp map[string]interface{}) (sql.Result, erro }) } -//执行EXEC (UPDATE、DELETE、INSERT),SQL参数是struct 返回结果 sql.Result +// 执行EXEC (UPDATE、DELETE、INSERT),SQL参数是struct 返回结果 sql.Result func ExecStruct(modelId, sqlId string, st interface{}) (sql.Result, error) { - //获取Sqlentity,db + // 获取Sqlentity,db se, db := findSqlAndDB(modelId, sqlId) if se == nil { return nil, notFoundError(modelId + "/" + sqlId) } - //判断类型不是EXEC 就返回错误 + // 判断类型不是EXEC 就返回错误 if se.Sqltype != ST_EXEC { return nil, notMatchError() } - //return db.ExecStruct(se.Cmds[0].Sql, st) + // return db.ExecStruct(se.Cmds[0].Sql, st) return nil, transact(db, func(tx *core.Tx) error { - //循環每個sql定義 + // 循環每個sql定義 for _, cmd := range se.Cmds { - //faygo.Debug("ExecMap sql:" + cmd.Sql) + // faygo.Debug("ExecMap sql:" + cmd.Sql) if _, err := tx.ExecStruct(cmd.Sql, st); err != nil { return err } @@ -281,14 +281,14 @@ func ExecStruct(modelId, sqlId string, st interface{}) (sql.Result, error) { }) } -//批量执行 UPDATE、INSERT、DELETE、mp 是MAP类型命名参数 +// 批量执行 UPDATE、INSERT、DELETE、mp 是MAP类型命名参数 func BacthExecMap(modelId, sqlId string, sp []map[string]interface{}) error { - //获取Sqlentity,db + // 获取Sqlentity,db se, db := findSqlAndDB(modelId, sqlId) if se == nil { return notFoundError(modelId + "/" + sqlId) } - //判断类型不是BATCHEXEC 就返回错误 + // 判断类型不是BATCHEXEC 就返回错误 if se.Sqltype != ST_BATCHEXEC { return notMatchError() } @@ -303,21 +303,21 @@ func BacthExecMap(modelId, sqlId string, sp []map[string]interface{}) error { }) } -//批量执行 BacthComplex、mp 是MAP类型命名参数,事务中依次执行 +// 批量执行 BacthComplex、mp 是MAP类型命名参数,事务中依次执行 func BacthMultiExecMap(modelId, sqlId string, mp map[string][]map[string]interface{}) error { - //获取Sqlentity,db + // 获取Sqlentity,db se, db := findSqlAndDB(modelId, sqlId) if se == nil { return notFoundError(modelId + "/" + sqlId) } - //判断类型不是 ST_BATCHMULTIEXEC 就返回错误 + // 判断类型不是 ST_BATCHMULTIEXEC 就返回错误 if se.Sqltype != ST_BATCHMULTIEXEC { return notMatchError() } return transact(db, func(tx *core.Tx) error { - //循環每個sql定義 + // 循環每個sql定義 for _, cmd := range se.Cmds { - //循環其批量參數 + // 循環其批量參數 if sp, ok := mp[cmd.Pin]; ok { for _, p := range sp { faygo.Debug("BacthMultiExecMap :" + cmd.Sql) diff --git a/ext/db/directsql/sqlwatcher.go b/ext/db/directsql/sqlwatcher.go index b323476..f1a41ee 100644 --- a/ext/db/directsql/sqlwatcher.go +++ b/ext/db/directsql/sqlwatcher.go @@ -9,12 +9,13 @@ package directsql import ( - "github.com/fsnotify/fsnotify" - "github.com/henrylee2cn/faygo" "strings" + + "github.com/andeya/faygo" + "github.com/fsnotify/fsnotify" ) -//start filesytem watcher +// start filesytem watcher func (mss *TModels) StartWatcher() error { var err error mss.watcher, err = fsnotify.NewWatcher() @@ -26,7 +27,7 @@ func (mss *TModels) StartWatcher() error { for { select { case event := <-mss.watcher.Events: - //如果变更的文件是 .msql文件 + // 如果变更的文件是 .msql文件 if strings.HasSuffix(event.Name, mss.extension) { if event.Op&fsnotify.Write == fsnotify.Write { faygo.Debug("Modified file:" + event.Name) @@ -59,18 +60,18 @@ func (mss *TModels) StartWatcher() error { } } }() - //增加监控路径 + // 增加监控路径 for _, value := range mss.roots { err = mss.watcher.Add(value) if err != nil { faygo.Error(err.Error()) - //return + // return } } return nil } -//stop filesytem watcher +// stop filesytem watcher func (mss *TModels) StopWatcher() error { if mss.watcher != nil { faygo.Info("Directsql stop watching.....................") diff --git a/ext/db/directsqlx/checkparameter.go b/ext/db/directsqlx/checkparameter.go index 47c67f3..82475cf 100644 --- a/ext/db/directsqlx/checkparameter.go +++ b/ext/db/directsqlx/checkparameter.go @@ -16,8 +16,8 @@ import ( "time" "unicode/utf8" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/ext/uuid" + "github.com/andeya/faygo" + "github.com/andeya/faygo/ext/uuid" ) // 类型判断正则表达式定义 @@ -27,12 +27,12 @@ const ( Email string = "^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$" ) -//字符串是否合法Email地址 +// 字符串是否合法Email地址 func IsEmail(str string) bool { return regexp.MustCompile(Email).MatchString(str) } -//字符串是否整数,空也是合法的. +// 字符串是否整数,空也是合法的. func IsInt(str interface{}) bool { if _, ok := str.(float64); ok { return regexp.MustCompile(Int).MatchString(strconv.FormatFloat(str.(float64), 'f', -1, 64)) @@ -40,33 +40,33 @@ func IsInt(str interface{}) bool { return false } -//字符串是否浮点数 +// 字符串是否浮点数 func IsFloat(str interface{}) bool { _, ok := str.(float64) return ok } -//字符串是否有效的长度 +// 字符串是否有效的长度 func IsVaildLength(str string, min, max int) bool { - //min,max都未定义或都为0则不校验长度 + // min,max都未定义或都为0则不校验长度 if min <= 0 && max <= 0 { return true } strLength := utf8.RuneCountInString(str) - //只验证最小长度,最大长度不验证 + // 只验证最小长度,最大长度不验证 if min > 0 && max <= 0 { return strLength >= min } return strLength >= min && strLength <= max } -//给定的数值是否在范围内 +// 给定的数值是否在范围内 func IsVaildValue(value, min, max float64) bool { - //min,max都未定义或都为0则不校验大小 + // min,max都未定义或都为0则不校验大小 if min <= 0 && max <= 0 { return true } - //只验证最小值,最大值不验证 + // 只验证最小值,最大值不验证 if min > 0 && max <= 0 { return value >= min } @@ -76,89 +76,89 @@ func IsVaildValue(value, min, max float64) bool { return value >= min && value <= max } -//给定的字符串是否合法的日期时间 +// 给定的字符串是否合法的日期时间 func IsVaildDatetime(str string) bool { _, err := time.Parse("2006-01-02 15:04", str) return err == nil } -//给定的字符串是否合法的日期(YYYY-MM-DD) +// 给定的字符串是否合法的日期(YYYY-MM-DD) func IsVaildDate(str string) bool { _, err := time.Parse("2006-01-02", str) return err == nil } -//检查是否必须的 +// 检查是否必须的 func CheckRequired(str string) bool { return len(str) > 0 } -//检查并处理参数 +// 检查并处理参数 //paras:sql的cmd中的参数定义slice;mp:客户端提交的参数map;ctx *lessgo.Context当前执行该功能的上下文 -//根据待默认值的参数是否需要返回构造返回到客户端的值 +// 根据待默认值的参数是否需要返回构造返回到客户端的值 func dealwithParameter(paras []*TSqlParameter, mp map[string]interface{}, ctx *faygo.Context) (map[string]interface{}, error) { - //没有参数处理定义返回 + // 没有参数处理定义返回 if len(paras) == 0 { - //faygo.Debug("Check sql parameters - nil") + // faygo.Debug("Check sql parameters - nil") return nil, nil } - //将在服务端生成的默认值需要返回的放入到该结果map中。 + // 将在服务端生成的默认值需要返回的放入到该结果map中。 var result map[string]interface{} result = make(map[string]interface{}) - //循环处理参数 + // 循环处理参数 for _, para := range paras { - //默认值处理,存在就不处理使用存在的值,不存在就增加并返回给客户端 + // 默认值处理,存在就不处理使用存在的值,不存在就增加并返回给客户端 _, exists := mp[para.Name] - //不是从客户的传入的并且有默认值设置 + // 不是从客户的传入的并且有默认值设置 if (!exists) && (para.Default != DT_UNDEFINED) { - //根据默认值类型分别处理 + // 根据默认值类型分别处理 switch para.Default { - case DT_UUID: //uuid + case DT_UUID: // uuid mp[para.Name] = uuid.New().String() case DT_NOWDATE: // now date mp[para.Name] = time.Now().Format("2006-01-02") - case DT_NOWDATETIME: //now(date +time) + case DT_NOWDATETIME: // now(date +time) mp[para.Name] = time.Now().Format("2006-01-02 15:04:05") - case DT_NOW_UNIX: //当前日期时间unix值 int64 now datetime + case DT_NOW_UNIX: // 当前日期时间unix值 int64 now datetime mp[para.Name] = time.Now().Unix() - case DT_CUSTOM: //通过RegAny注册的变量或函数 + case DT_CUSTOM: // 通过RegAny注册的变量或函数 value, err := contextcall(para.Defaultstr, ctx) - //faygo.Debug("SQL Default parameter value:", value) + // faygo.Debug("SQL Default parameter value:", value) if err == nil { mp[para.Name] = value.Interface() } else { faygo.Error("Error: sql default parameter error,", err) } - //如果是parentid则从 临时缓存的取值。 + // 如果是parentid则从 临时缓存的取值。 case DT_PARENTID: mp[para.Name] = ctx.Data("__directsqlx__parentid") faygo.Debug("Read parentid value:", mp[para.Name]) } - //如果需要返回 + // 如果需要返回 if para.Return { result[para.Name] = mp[para.Name] } - //如果作为从表的关联主表的id使用,则将值临时放到ctx,以便从表取值时用。 + // 如果作为从表的关联主表的id使用,则将值临时放到ctx,以便从表取值时用。 if para.Parentid { ctx.SetData("__directsqlx__parentid", mp[para.Name]) faygo.Debug("Write parentid value:", mp[para.Name]) } - //如果不是从客户的传入的并且有默认值设置则后边的验证规则不执行了,如果是从客户的传入的则需要进行进行后边的默认值校验 + // 如果不是从客户的传入的并且有默认值设置则后边的验证规则不执行了,如果是从客户的传入的则需要进行进行后边的默认值校验 continue } - //根据参数名称从提交的参数中获取值循环验证类型、长度、是否为空等信息 + // 根据参数名称从提交的参数中获取值循环验证类型、长度、是否为空等信息 if v, ok := mp[para.Name]; ok { - //是否必须的 + // 是否必须的 if _, ok := v.(string); ok && (para.Required) && (len(v.(string)) == 0) { return nil, errors.New("错误:参数[" + para.Name + "]不能为空!") } - //faygo.Debug("Check sql parameters - get value") - //参数类型处理 + // faygo.Debug("Check sql parameters - get value") + // 参数类型处理 switch para.Paratype { case PT_STRING: - //验证长度,是否必须的 + // 验证长度,是否必须的 if IsVaildLength(v.(string), para.Minlen, para.Maxlen) { continue } else { @@ -166,13 +166,13 @@ func dealwithParameter(paras []*TSqlParameter, mp map[string]interface{}, ctx *f } case PT_INT: - //faygo.Debug("Check sql int parameter -", v) - //验证是否整数 + // faygo.Debug("Check sql int parameter -", v) + // 验证是否整数 if IsInt(v) { } else { return nil, errors.New("错误:参数[" + para.Name + "]不是有效的整数!") } - //验证数值范围 + // 验证数值范围 if IsVaildValue(v.(float64), para.MinValue, para.MaxValue) { continue } else { @@ -180,12 +180,12 @@ func dealwithParameter(paras []*TSqlParameter, mp map[string]interface{}, ctx *f } case PT_FLOAT: - //验证是否浮点数 + // 验证是否浮点数 if IsFloat(v) { } else { return nil, errors.New("错误:参数[" + para.Name + "]不是有效的浮点数!") } - //验证数值范围 + // 验证数值范围 if IsVaildValue(v.(float64), para.MinValue, para.MaxValue) { continue } else { @@ -193,30 +193,30 @@ func dealwithParameter(paras []*TSqlParameter, mp map[string]interface{}, ctx *f } case PT_DATE: - //验证日期格式 + // 验证日期格式 if IsVaildDate(v.(string)) { continue } else { return nil, errors.New("错误:参数[" + para.Name + "]不是有效的日期!") } case PT_DATETIME: - //验证日期时间格式 + // 验证日期时间格式 if IsVaildDatetime(v.(string)) { continue } else { return nil, errors.New("错误:参数[" + para.Name + "]不是有效的日期时间!") } case PT_EMAIL: - //验证email格式 + // 验证email格式 if IsEmail(v.(string)) { continue } else { return nil, errors.New("错误:参数[" + para.Name + "]不是有效的电子信箱!") } } - //faygo.Debug("Check sql parameters - " + para.Name + ": " + v.(string)) + // faygo.Debug("Check sql parameters - " + para.Name + ": " + v.(string)) } else { - //sql的cmd参数中存在该参数定义但传入的post参数不存在则返回错误 + // sql的cmd参数中存在该参数定义但传入的post参数不存在则返回错误 return nil, errors.New("错误:配置的参数[" + para.Name + "]客户端未提交,请检查!") } } diff --git a/ext/db/directsqlx/resultcache.go b/ext/db/directsqlx/resultcache.go index 846f3f3..4028a51 100644 --- a/ext/db/directsqlx/resultcache.go +++ b/ext/db/directsqlx/resultcache.go @@ -9,32 +9,33 @@ package directsqlx import ( - "github.com/henrylee2cn/faygo" "sync" "time" + + "github.com/andeya/faygo" ) -//缓存结果对象 +// 缓存结果对象 type memo struct { Timeout time.Time - Result []byte //interface{} - Suffix string //附加的标识,对于有参数的sql使用该后缀标识参数差异,只缓存第一次查询默认参数的情况,其他的不缓存,缓存的刷新也依赖该 + Result []byte // interface{} + Suffix string // 附加的标识,对于有参数的sql使用该后缀标识参数差异,只缓存第一次查询默认参数的情况,其他的不缓存,缓存的刷新也依赖该 } -//缓存池对象 +// 缓存池对象 type MemoPool struct { pool map[string]*memo mutex *sync.RWMutex } -//全局缓存池 +// 全局缓存池 var mp *MemoPool func init() { mp = &MemoPool{pool: map[string]*memo{}, mutex: new(sync.RWMutex)} } -//根据key以及suffix后缀获取缓存的结果 has 表示存在有效的result,result为结果 +// 根据key以及suffix后缀获取缓存的结果 has 表示存在有效的result,result为结果 func GetCache(key string, suffix string) (ok bool, result []byte) { mp.mutex.RLock() memoized := mp.pool[key] @@ -48,31 +49,31 @@ func GetCache(key string, suffix string) (ok bool, result []byte) { return false, nil } -//将key以及suffix后缀的值放入到缓存中,如果存在则替换,并记录失效日期 +// 将key以及suffix后缀的值放入到缓存中,如果存在则替换,并记录失效日期 func SetCache(key string, suffix string, value []byte, timeout int) { if value != nil { mp.mutex.RLock() memoized := mp.pool[key] mp.mutex.RUnlock() - //缓存key存在值但后缀不同则退出 + // 缓存key存在值但后缀不同则退出 if (memoized != nil) && (memoized.Suffix != suffix) { return } - //faygo.Debug("Set Cache:[" + key + " - " + suffix + "]") - //缓存不存在或虽然存在但suffix后缀相同则修改之 + // faygo.Debug("Set Cache:[" + key + " - " + suffix + "]") + // 缓存不存在或虽然存在但suffix后缀相同则修改之 var duration time.Duration - //-1为一直有效,-2为一月,-3为一周 -4为一天,单位为分钟 + // -1为一直有效,-2为一月,-3为一周 -4为一天,单位为分钟 switch timeout { case -1: - duration = 365 * time.Duration(24) * time.Hour //一年 + duration = 365 * time.Duration(24) * time.Hour // 一年 case -2: - duration = 30 * time.Duration(24) * time.Hour //一月 + duration = 30 * time.Duration(24) * time.Hour // 一月 case -3: - duration = 7 * time.Duration(24) * time.Hour //一周 + duration = 7 * time.Duration(24) * time.Hour // 一周 case -4: - duration = time.Duration(24) * time.Hour //一天 + duration = time.Duration(24) * time.Hour // 一天 default: - duration = time.Duration(timeout) * time.Minute //分钟 + duration = time.Duration(timeout) * time.Minute // 分钟 } mp.mutex.Lock() mp.pool[key] = &memo{ @@ -81,18 +82,18 @@ func SetCache(key string, suffix string, value []byte, timeout int) { Result: value, } mp.mutex.Unlock() - //faygo.Debug("Set Cache Result:["+key+" - "+suffix+"]", mp.pool[key]) + // faygo.Debug("Set Cache Result:["+key+" - "+suffix+"]", mp.pool[key]) } } -//清除key的缓存 +// 清除key的缓存 func RemoveCache(key string) { mp.mutex.Lock() delete(mp.pool, key) mp.mutex.Unlock() } -//清除全部缓存 +// 清除全部缓存 func ClearCache() { mp.mutex.Lock() for key, _ := range mp.pool { diff --git a/ext/db/directsqlx/sqlcontext.go b/ext/db/directsqlx/sqlcontext.go index 96dd9fb..4463a06 100644 --- a/ext/db/directsqlx/sqlcontext.go +++ b/ext/db/directsqlx/sqlcontext.go @@ -15,7 +15,7 @@ import ( "regexp" "time" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) var reIdentifiers = regexp.MustCompile("^[a-zA-Z0-9_]+$") @@ -34,9 +34,9 @@ func gettime() string { return time.Now().Format("2006-01-02 15:04:05") } -//注册新的变量或函数到map +// 注册新的变量或函数到map func RegAny(name string, fn interface{}) (err error) { - //判断名称是否合法 + // 判断名称是否合法 if !reIdentifiers.MatchString(name) { return errors.New(fmt.Sprintf("SQLContext-key '%s' (value: '%+v') is not a valid identifier.", name, fn)) } @@ -62,7 +62,7 @@ func contextcall(name string, params ...interface{}) (result reflect.Value, err if fv.Kind() == reflect.Func { t := fv.Type() faygo.Debug("Context Func: ", t) - //Check input arguments + // Check input arguments if len(params) != t.NumIn() { err = errors.New("parameters of function not adapted") return @@ -76,7 +76,7 @@ func contextcall(name string, params ...interface{}) (result reflect.Value, err for k, param := range params { in[k] = reflect.ValueOf(param) } - //return result + // return result result = fv.Call(in)[0] faygo.Debug("Context func value : ", result) } else { diff --git a/ext/db/directsqlx/sqlengine.go b/ext/db/directsqlx/sqlengine.go index af67447..57aa15c 100644 --- a/ext/db/directsqlx/sqlengine.go +++ b/ext/db/directsqlx/sqlengine.go @@ -16,11 +16,11 @@ import ( "errors" "fmt" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" "github.com/jmoiron/sqlx" ) -//根据sqlid获取 *TSql +// 根据sqlid获取 *TSql func (m *TModel) findSql(sqlid string) *TSql { if se, ok := m.Sqls[sqlid]; ok { return se @@ -28,10 +28,10 @@ func (m *TModel) findSql(sqlid string) *TSql { return nil } -//执行普通的单个查询SQL mp 是MAP类型命名参数 map[string]interface{},返回结果 []map[string][]interface{} +// 执行普通的单个查询SQL mp 是MAP类型命名参数 map[string]interface{},返回结果 []map[string][]interface{} func (m *TModel) selectMap(se *TSql, mp map[string]interface{}) ([]map[string]interface{}, error) { faygo.Debug("selectMap parameters :", mp) - //执行sql + // 执行sql rows, err := m.DB.NamedQuery(se.Cmds[0].Sql, mp) if err != nil { return nil, err @@ -40,16 +40,16 @@ func (m *TModel) selectMap(se *TSql, mp map[string]interface{}) ([]map[string]in return rows2mapObjects(rows) } -//分頁查詢的返回結果 +// 分頁查詢的返回結果 type PagingSelectResult struct { Total int `json:"total"` Data []map[string]interface{} `json:"data"` } -//执行分页查询SQL mp 是MAP类型命名参数 返回结果 int,[]map[string][]interface{} +// 执行分页查询SQL mp 是MAP类型命名参数 返回结果 int,[]map[string][]interface{} func (m *TModel) pagingSelectMap(se *TSql, mp map[string]interface{}) (*PagingSelectResult, error) { faygo.Debug("pagingSelectMap parameters :", mp) - //获取总页数,約定該SQL放到第二條,並且只返回一條記錄一個字段 + // 获取总页数,約定該SQL放到第二條,並且只返回一條記錄一個字段 trows, err := m.DB.NamedQuery(se.Cmds[0].Sql, mp) if err != nil { return nil, err @@ -64,7 +64,7 @@ func (m *TModel) pagingSelectMap(se *TSql, mp map[string]interface{}) (*PagingSe if len(total) != 1 { return nil, errors.New("错误:获取总页数的SQL执行结果非唯一记录!") } - //2.获取当前页數據,約定該SQL放到第二條 + // 2.获取当前页數據,約定該SQL放到第二條 rows, err := m.DB.NamedQuery(se.Cmds[1].Sql, mp) if err != nil { return nil, err @@ -74,16 +74,16 @@ func (m *TModel) pagingSelectMap(se *TSql, mp map[string]interface{}) (*PagingSe if err != nil { return nil, err } - return &PagingSelectResult{Total: total[0].(int), Data: result}, nil //最終的結果 + return &PagingSelectResult{Total: total[0].(int), Data: result}, nil // 最終的結果 } return nil, err } -//执行返回多個結果集的多個查询SQL, mp 是MAP类型命名参数 返回结果 map[string][]map[string][]string +// 执行返回多個結果集的多個查询SQL, mp 是MAP类型命名参数 返回结果 map[string][]map[string][]string func (m *TModel) multiSelectMap(se *TSql, mp map[string]interface{}) (map[string][]map[string]interface{}, error) { result := make(map[string][]map[string]interface{}) faygo.Debug("MultiSelectMap parameters :", mp) - //循環每個sql定義 + // 循環每個sql定義 for i, cmd := range se.Cmds { faygo.Debug("MultiSelectMap :" + cmd.Sql) rows, err := m.DB.NamedQuery(cmd.Sql, mp) @@ -104,8 +104,8 @@ func (m *TModel) multiSelectMap(se *TSql, mp map[string]interface{}) (map[string return result, nil } -//执行单个查询SQL返回JSON父子嵌套結果集 mp 是MAP类型命名参数 map[string]interface{},返回结果 []map[string][]interface{} -//根据 Idfield、Pidfield 构建嵌套的 map 结果集 +// 执行单个查询SQL返回JSON父子嵌套結果集 mp 是MAP类型命名参数 map[string]interface{},返回结果 []map[string][]interface{} +// 根据 Idfield、Pidfield 构建嵌套的 map 结果集 func (m *TModel) nestedSelectMap(se *TSql, mp map[string]interface{}) ([]map[string]interface{}, error) { faygo.Debug("NestedSelectMap :" + se.Cmds[0].Sql) rows, err := m.DB.NamedQuery(se.Cmds[0].Sql, mp) @@ -123,7 +123,7 @@ type Execresult struct { Info string `json:"info"` } -//执行 UPDATE、DELETE、INSERT,mp 是 map[string]interface{}, 返回结果 execresult +// 执行 UPDATE、DELETE、INSERT,mp 是 map[string]interface{}, 返回结果 execresult /*func (m *TModel) execMap(se *TSql, mp map[string]interface{}) (*Execresult, error) { faygo.Debug("ExecMap :" + se.Cmds[0].Sql) faygo.Debug("map paras :", mp) @@ -136,12 +136,12 @@ type Execresult struct { return &Execresult{LastInsertId: LIId, RowsAffected: RAffected, Info: "Exec sql ok!"}, nil } */ -//说明,将执行sql的execMap修改该可以执行多个配置的cmd,采用相同的参数---2016.11.20 -//执行 UPDATE、DELETE、INSERT,mp 是 map[string]interface{},可以配置多个sql语句,使用相同的参数执行。 +// 说明,将执行sql的execMap修改该可以执行多个配置的cmd,采用相同的参数---2016.11.20 +// 执行 UPDATE、DELETE、INSERT,mp 是 map[string]interface{},可以配置多个sql语句,使用相同的参数执行。 func (m *TModel) execMap(se *TSql, mp map[string]interface{}) error { faygo.Debug("ExecMap parameters :", mp) return transact(m.DB, func(tx *sqlx.Tx) error { - //循環每個sql定義 + // 循環每個sql定義 for _, cmd := range se.Cmds { faygo.Debug("ExecMap sql:" + cmd.Sql) if _, err := tx.NamedExec(cmd.Sql, mp); err != nil { @@ -152,7 +152,7 @@ func (m *TModel) execMap(se *TSql, mp map[string]interface{}) error { }) } -//批量执行 UPDATE、INSERT、sp 是MAP类型命名参数 +// 批量执行 UPDATE、INSERT、sp 是MAP类型命名参数 func (m *TModel) bacthExecMap(se *TSql, sp []map[string]interface{}) error { faygo.Debug("BacthExecMap parameters :", sp) return transact(m.DB, func(tx *sqlx.Tx) error { @@ -166,12 +166,12 @@ func (m *TModel) bacthExecMap(se *TSql, sp []map[string]interface{}) error { }) } -//批量执行 BacthMultiExec、mp 是map[string][]map[string]interface{}参数,事务中依次执行 +// 批量执行 BacthMultiExec、mp 是map[string][]map[string]interface{}参数,事务中依次执行 func (m *TModel) bacthMultiExecMap(se *TSql, mp map[string][]map[string]interface{}) error { return transact(m.DB, func(tx *sqlx.Tx) error { - //循環每個sql定義 + // 循環每個sql定義 for _, cmd := range se.Cmds { - //循環其批量參數 + // 循環其批量參數 if sp, ok := mp[cmd.Pin]; ok { for _, p := range sp { faygo.Debug("BacthMultiExecMap :" + cmd.Sql) @@ -201,22 +201,22 @@ func (m *TModel) setBLOB(se *TSql, mp map[string]interface{}) error { return nil } -//执行普通的查询SQL返回一个二进制字段的值 mp 是MAP类型命名参数 map[string]interface{},返回结果 []byte +// 执行普通的查询SQL返回一个二进制字段的值 mp 是MAP类型命名参数 map[string]interface{},返回结果 []byte func (m *TModel) getBLOB(se *TSql, mp map[string]interface{}) ([]byte, error) { faygo.Debug("getBLOB parameters :", mp) - //执行sql + // 执行sql rows, err := m.DB.NamedQuery(se.Cmds[0].Sql, mp) if err != nil { return nil, err } defer rows.Close() - //字段slice + // 字段slice fields, err := rows.Columns() if err != nil { faygo.Error(err) return nil, err } - //只能返回一个字段,即要获取的二进制字段 + // 只能返回一个字段,即要获取的二进制字段 if len(fields) != 1 { return nil, errors.New("error: getBLOB sql only return one field") } @@ -232,7 +232,7 @@ func (m *TModel) getBLOB(se *TSql, mp map[string]interface{}) ([]byte, error) { return nil, errors.New("error: getBLOB sql result is empty!") } -//ransaction handler 封装在一个事务中执行多个SQL语句 +// ransaction handler 封装在一个事务中执行多个SQL语句 func transact(db *sqlx.DB, txFunc func(*sqlx.Tx) error) (err error) { tx, err := db.Beginx() if err != nil { diff --git a/ext/db/directsqlx/sqlhandle.go b/ext/db/directsqlx/sqlhandle.go index 4788c64..280d87e 100644 --- a/ext/db/directsqlx/sqlhandle.go +++ b/ext/db/directsqlx/sqlhandle.go @@ -17,41 +17,41 @@ import ( json "github.com/json-iterator/go" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) -//DirectSQL handler 定义 +// DirectSQL handler 定义 func DirectSQL() faygo.HandlerFunc { return func(ctx *faygo.Context) error { - //1.根据路径获取sqlentity:去掉/bos/,再拆分成 modelId,sqlId + // 1.根据路径获取sqlentity:去掉/bos/,再拆分成 modelId,sqlId modelId, sqlId := trimBeforeSplitRight(ctx.Path(), '/', 2) faygo.Debug("Model file: " + modelId + " - sqlId:" + sqlId) - //2.获取ModelSql + // 2.获取ModelSql m := findModel(modelId) if m == nil { - faygo.Error("Error: model file does not exist,") //("错误:未定义的Model文件: " + modelId) + faygo.Error("Error: model file does not exist,") // ("错误:未定义的Model文件: " + modelId) return ctx.JSONMsg(404, 404, "Error:model file does not exist: "+modelId) } - //3.获取Sql + // 3.获取Sql se := m.findSql(sqlId) if se == nil { // - faygo.Error("Error: sql is not defined in the model file, " + modelId + "/" + sqlId) //错误:Model文件中未定义sql: + faygo.Error("Error: sql is not defined in the model file, " + modelId + "/" + sqlId) // 错误:Model文件中未定义sql: return ctx.JSONMsg(404, 404, "Error: sql is not defined in the model file, "+modelId+"/"+sqlId) } - //4.根据SQL类型分别处理执行并返回结果信息 + // 4.根据SQL类型分别处理执行并返回结果信息 switch se.Sqltype { - case ST_PAGINGSELECT: //分页选择SQL,分頁查詢結果cache第一次查询的结果 - //.1 获取POST参数並轉換 + case ST_PAGINGSELECT: // 分页选择SQL,分頁查詢結果cache第一次查询的结果 + // .1 获取POST参数並轉換 var jsonpara map[string]interface{} - err := ctx.BindJSON(&jsonpara) //从Body获取JSON参数 + err := ctx.BindJSON(&jsonpara) // 从Body获取JSON参数 if err != nil { faygo.Debug("Info:POST para is empty," + err.Error()) - //如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 + // 如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 if jsonpara == nil { jsonpara = make(map[string]interface{}) } } - //. 常規參數處理 + // . 常規參數處理 var callback string if v, ok := jsonpara["callback"]; ok { s, ok := v.(string) @@ -60,48 +60,48 @@ func DirectSQL() faygo.HandlerFunc { delete(jsonpara, "callback") } } - //.2 判断是否是缓存的并存在有效缓存,存在则直接从缓存返回 + // .2 判断是否是缓存的并存在有效缓存,存在则直接从缓存返回 if se.Cached { - //构造缓存查询key + // 构造缓存查询key key := modelId + "/" + sqlId - //缓存识别的后缀 + // 缓存识别的后缀 sf, err := json.Marshal(jsonpara) if err != nil { sf = nil } suffix := string(sf) - //如果OK则直接返回缓存 + // 如果OK则直接返回缓存 if ok, jsonb := GetCache(key, suffix); ok { faygo.Debug("Directsqlx getCache:[" + key + " - " + suffix + "] result from cache.") - //发送JSON(P)响应 + // 发送JSON(P)响应 return sendJSON(ctx, callback, jsonb) } } - //.3 检查sql语句配置个数 + // .3 检查sql语句配置个数 if len(se.Cmds) != 2 { - faygo.Error("Error: paging query must define two sql nodes, one for total number and one for data query!") //错误:分页查询必须定义2个SQL节点,一个获取总页数另一个用于查询数据! + faygo.Error("Error: paging query must define two sql nodes, one for total number and one for data query!") // 错误:分页查询必须定义2个SQL节点,一个获取总页数另一个用于查询数据! return ctx.JSONMsg(404, 404, "Error: paging query must define two sql nodes, one for total number and one for data query!") } - //.5 参数验证并处理(参数定义到真正查询结果的cmd下)-OK + // .5 参数验证并处理(参数定义到真正查询结果的cmd下)-OK _, err = dealwithParameter(se.Cmds[1].Parameters, jsonpara, ctx) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(400, 400, err.Error()) } - //.6 執行並返回結果 + // .6 執行並返回結果 data, err := m.pagingSelectMap(se, jsonpara) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //.7 如果需要缓存则缓存结果集(cached=true 并且缓存不存在或失效才会执行) + // .7 如果需要缓存则缓存结果集(cached=true 并且缓存不存在或失效才会执行) jsonb, err := intface2json(data) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //结果集为空响应 + // 结果集为空响应 if data.Total == 0 { err := ctx.JSONBlob(200, []byte(`{"total":0,"data":[]}`)) if err != nil { @@ -109,11 +109,11 @@ func DirectSQL() faygo.HandlerFunc { } return nil } - //如果需要缓存则 + // 如果需要缓存则 if se.Cached { - //构造缓存查询key + // 构造缓存查询key key := modelId + "/" + sqlId - //缓存识别的后缀 + // 缓存识别的后缀 sf, err := json.Marshal(jsonpara) if err != nil { sf = nil @@ -122,22 +122,22 @@ func DirectSQL() faygo.HandlerFunc { SetCache(key, suffix, jsonb, se.Cachetime) faygo.Debug("Directsqlx setCache:[" + key + "] result to cache.") } - //发送JSON(P)响应 + // 发送JSON(P)响应 return sendJSON(ctx, callback, jsonb) - //一般选择SQL,嵌套选择暂时未实现跟一般选择一样,增强的插入后返回sysid ----OK + // 一般选择SQL,嵌套选择暂时未实现跟一般选择一样,增强的插入后返回sysid ----OK case ST_SELECT, ST_NESTEDSELECT: - //.1 获取POST参数並轉換 + // .1 获取POST参数並轉換 var jsonpara map[string]interface{} - err := ctx.BindJSON(&jsonpara) //从Body获取JSON参数 + err := ctx.BindJSON(&jsonpara) // 从Body获取JSON参数 if err != nil { faygo.Debug("Info: POST para is empty," + err.Error()) - //如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 + // 如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 if jsonpara == nil { jsonpara = make(map[string]interface{}) } } - //. 常規參數處理 + // . 常規參數處理 var callback string if v, ok := jsonpara["callback"]; ok { s, ok := v.(string) @@ -146,42 +146,42 @@ func DirectSQL() faygo.HandlerFunc { delete(jsonpara, "callback") } } - //.2 判断是否是缓存的并存在有效缓存,存在则直接从缓存返回 + // .2 判断是否是缓存的并存在有效缓存,存在则直接从缓存返回 if se.Cached { - //构造缓存查询key + // 构造缓存查询key key := modelId + "/" + sqlId - //缓存识别的后缀 + // 缓存识别的后缀 sf, err := json.Marshal(jsonpara) if err != nil { sf = nil } suffix := string(sf) - //如果OK则直接返回缓存 + // 如果OK则直接返回缓存 if ok, jsonb := GetCache(key, suffix); ok { faygo.Debug("Directsqlx getCache:[" + key + "] result from cache.") - //发送JSON(P)响应 + // 发送JSON(P)响应 return sendJSON(ctx, callback, jsonb) } } - //.3 参数验证并处理,-OK + // .3 参数验证并处理,-OK _, err = dealwithParameter(se.Cmds[0].Parameters, jsonpara, ctx) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(400, 400, err.Error()) } - //.4 執行並返回結果 + // .4 執行並返回結果 data, err := m.selectMap(se, jsonpara) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //.7 如果需要缓存则缓存结果集(cached=true 并且缓存不存在或失效才会执行) + // .7 如果需要缓存则缓存结果集(cached=true 并且缓存不存在或失效才会执行) jsonb, err := intface2json(data) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //结果集为空响应 + // 结果集为空响应 if len(data) == 0 { err := ctx.JSONBlob(200, []byte(`[]`)) if err != nil { @@ -189,11 +189,11 @@ func DirectSQL() faygo.HandlerFunc { } return nil } - //如果需要缓存则 + // 如果需要缓存则 if se.Cached { - //构造缓存查询key + // 构造缓存查询key key := modelId + "/" + sqlId - //缓存识别的后缀 + // 缓存识别的后缀 sf, err := json.Marshal(jsonpara) if err != nil { sf = nil @@ -202,21 +202,21 @@ func DirectSQL() faygo.HandlerFunc { SetCache(key, suffix, jsonb, se.Cachetime) faygo.Debug("Directsqlx setCache:[" + key + "] result to cache.") } - //发送JSON(P)响应 + // 发送JSON(P)响应 return sendJSON(ctx, callback, jsonb) - case ST_MULTISELECT: //返回多結果集選擇 - //.1 获取POST参数並轉換 + case ST_MULTISELECT: // 返回多結果集選擇 + // .1 获取POST参数並轉換 var jsonpara map[string]interface{} - err := ctx.BindJSON(&jsonpara) //从Body获取JSON参数 + err := ctx.BindJSON(&jsonpara) // 从Body获取JSON参数 if err != nil { faygo.Info("Info:POST para is empty," + err.Error()) - //return ctx.JSONMsg(404, 404, err.Error()) - //如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 + // return ctx.JSONMsg(404, 404, err.Error()) + // 如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 if jsonpara == nil { jsonpara = make(map[string]interface{}) } } - //. 常規參數處理 + // . 常規參數處理 var callback string if v, ok := jsonpara["callback"]; ok { s, ok := v.(string) @@ -225,26 +225,26 @@ func DirectSQL() faygo.HandlerFunc { delete(jsonpara, "callback") } } - //.2 判断是否是缓存的并存在有效缓存,存在则直接从缓存返回 + // .2 判断是否是缓存的并存在有效缓存,存在则直接从缓存返回 if se.Cached { - //构造缓存查询key + // 构造缓存查询key key := modelId + "/" + sqlId - //缓存识别的后缀 + // 缓存识别的后缀 sf, err := json.Marshal(jsonpara) if err != nil { sf = nil } suffix := string(sf) - //如果OK则直接返回缓存 + // 如果OK则直接返回缓存 if ok, jsonb := GetCache(key, suffix); ok { faygo.Debug("GetCache:[" + key + " - " + suffix + "] result from cache.") - //发送JSON(P)响应 + // 发送JSON(P)响应 return sendJSON(ctx, callback, jsonb) } } - //.3 参数验证并处理-OK + // .3 参数验证并处理-OK for _, cmd := range se.Cmds { - //未配置参数则直接忽略 + // 未配置参数则直接忽略 if len(cmd.Parameters) == 0 { continue } @@ -254,19 +254,19 @@ func DirectSQL() faygo.HandlerFunc { return ctx.JSONMsg(400, 400, err.Error()) } } - //.4 執行並返回結果 + // .4 執行並返回結果 data, err := m.multiSelectMap(se, jsonpara) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //.7 如果需要缓存则缓存结果集(cached=true 并且缓存不存在或失效才会执行) + // .7 如果需要缓存则缓存结果集(cached=true 并且缓存不存在或失效才会执行) jsonb, err := intface2json(data) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //结果集为空响应 + // 结果集为空响应 if len(data) == 0 { err := ctx.JSONBlob(200, []byte(`[]`)) if err != nil { @@ -274,11 +274,11 @@ func DirectSQL() faygo.HandlerFunc { } return nil } - //如果需要缓存则 + // 如果需要缓存则 if se.Cached { - //构造缓存查询key + // 构造缓存查询key key := modelId + "/" + sqlId - //缓存识别的后缀 + // 缓存识别的后缀 sf, err := json.Marshal(jsonpara) if err != nil { sf = nil @@ -287,57 +287,57 @@ func DirectSQL() faygo.HandlerFunc { SetCache(key, suffix, jsonb, se.Cachetime) faygo.Debug("Directsqlx setCache:[" + key + " - " + suffix + "] result to cache.") } - //发送JSON(P)响应 + // 发送JSON(P)响应 return sendJSON(ctx, callback, jsonb) - case ST_EXEC: //执行SQL(插入、删除、更新sql) - //.1.获取 Ajax post json 参数 + case ST_EXEC: // 执行SQL(插入、删除、更新sql) + // .1.获取 Ajax post json 参数 var jsonpara map[string]interface{} - err := ctx.BindJSON(&jsonpara) //从Body获取 json参数 + err := ctx.BindJSON(&jsonpara) // 从Body获取 json参数 if err != nil { faygo.Info("Info: POST para is empty," + err.Error()) - //return ctx.JSONMsg(404, 404, err.Error()) - //如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 + // return ctx.JSONMsg(404, 404, err.Error()) + // 如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 if jsonpara == nil { jsonpara = make(map[string]interface{}) } } - //.2.SQL定义参数验证并处理---OK,服务端生成的uuid返回给客户端 + // .2.SQL定义参数验证并处理---OK,服务端生成的uuid返回给客户端 result, err := dealwithParameter(se.Cmds[0].Parameters, jsonpara, ctx) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(400, 400, err.Error()) } - //.3.执行sql + // .3.执行sql err = m.execMap(se, jsonpara) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //return ctx.JSON(200, result) - //如果存在服务端生成的uuid参数的则返回到客户端 + // return ctx.JSON(200, result) + // 如果存在服务端生成的uuid参数的则返回到客户端 if (result != nil) && (len(result) > 0) { return ctx.JSONMsg(200, 200, result) } else { return ctx.JSONMsg(200, 200, "Info: Exec sql ok!") } - case ST_BATCHEXEC: //批量执行--原来的批量插入 - //.1.获取 Ajax post json 参数 + case ST_BATCHEXEC: // 批量执行--原来的批量插入 + // .1.获取 Ajax post json 参数 var jsonpara []map[string]interface{} - err := ctx.BindJSON(&jsonpara) //从Body获取 json参数 + err := ctx.BindJSON(&jsonpara) // 从Body获取 json参数 if err != nil { faygo.Info("Info: POST para is empty," + err.Error()) - //return ctx.JSONMsg(404, 404, err.Error()) - //如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 + // return ctx.JSONMsg(404, 404, err.Error()) + // 如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 if jsonpara == nil { jsonpara = make([]map[string]interface{}, 0) } } - //.2.SQL定义参数验证并处理---OK,考虑将通过参数默认值处理的数据返回给客户端 - //将在服务端生成的uuid返回到客户端的变量 + // .2.SQL定义参数验证并处理---OK,考虑将通过参数默认值处理的数据返回给客户端 + // 将在服务端生成的uuid返回到客户端的变量 var results []map[string]interface{} - //未配置参数则直接忽略 + // 未配置参数则直接忽略 if len(se.Cmds[0].Parameters) > 0 { results = make([]map[string]interface{}, 0) for _, jp := range jsonpara { @@ -353,42 +353,42 @@ func DirectSQL() faygo.HandlerFunc { } } - //.3.执行sql并返回结果 + // .3.执行sql并返回结果 err = m.bacthExecMap(se, jsonpara) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //如果存在服务端生成的uuid参数的则返回到客户端 + // 如果存在服务端生成的uuid参数的则返回到客户端 if (results != nil) && (len(results) > 0) { return ctx.JSONMsg(200, 200, results) } else { return ctx.JSONMsg(200, 200, "Bacth exec sql ok!") } - case ST_BATCHMULTIEXEC: //批量複合語句 - //.1.获取 Ajax post json 参数 + case ST_BATCHMULTIEXEC: // 批量複合語句 + // .1.获取 Ajax post json 参数 var jsonpara map[string][]map[string]interface{} - err := ctx.BindJSON(&jsonpara) //从Body获取 json参数 + err := ctx.BindJSON(&jsonpara) // 从Body获取 json参数 if err != nil { faygo.Info("Info: POST para is empty," + err.Error()) - //return ctx.JSONMsg(404, 404, err.Error()) - //如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 + // return ctx.JSONMsg(404, 404, err.Error()) + // 如果参数为空则会触发EOF错误,不应该退出因为可能本来就没有参数,也就是jsonpara仍旧为空,需要创建该变量,后续sql中的参数处理需要 if jsonpara == nil { jsonpara = make(map[string][]map[string]interface{}) } } - //.2.SQL定义参数验证并处理---OK,考虑将通过参数默认值处理的数据返回给客户端 - //将在服务端生成的uuid返回到客户端的变量 + // .2.SQL定义参数验证并处理---OK,考虑将通过参数默认值处理的数据返回给客户端 + // 将在服务端生成的uuid返回到客户端的变量 var results map[string][]map[string]interface{} results = make(map[string][]map[string]interface{}) - //循環每個sql定義 + // 循環每個sql定義 for _, cmd := range se.Cmds { - //未配置参数则直接忽略 + // 未配置参数则直接忽略 if len(cmd.Parameters) == 0 { continue } - //循環其批量參數 + // 循環其批量參數 if sp, ok := jsonpara[cmd.Pin]; ok { result1 := make([]map[string]interface{}, 0) for _, p := range sp { @@ -406,20 +406,20 @@ func DirectSQL() faygo.HandlerFunc { } } } - //.3.执行sql并返回结果 + // .3.执行sql并返回结果 err = m.bacthMultiExecMap(se, jsonpara) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //如果存在服务端生成的uuid参数的则返回到客户端 + // 如果存在服务端生成的uuid参数的则返回到客户端 if (results != nil) && (len(results) > 0) { return ctx.JSONMsg(200, 200, results) } else { return ctx.JSONMsg(200, 200, "Bacth Multi Exec sql ok!") } - case ST_GETBLOB: //执行sql从数据库中获取BLOB字段的二进制流 - //faygo.Info("Info: getblob sql") + case ST_GETBLOB: // 执行sql从数据库中获取BLOB字段的二进制流 + // faygo.Info("Info: getblob sql") var jsonpara map[string]interface{} // query paramaters sp := ctx.QueryParamAll() @@ -427,20 +427,20 @@ func DirectSQL() faygo.HandlerFunc { for i, v := range sp { jsonpara[i] = v[0] } - //参数验证并处理 + // 参数验证并处理 _, err := dealwithParameter(se.Cmds[0].Parameters, jsonpara, ctx) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(400, 400, err.Error()) } - //執行並返回結果 + // 執行並返回結果 data, err := m.getBLOB(se, jsonpara) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //faygo.Debug("getblob :", data) - //流方式返回二进制结果 + // faygo.Debug("getblob :", data) + // 流方式返回二进制结果 err = ctx.Bytes(200, "application/octet-stream", data) if err != nil { faygo.Error(err.Error()) @@ -448,14 +448,14 @@ func DirectSQL() faygo.HandlerFunc { } return nil - case ST_SETBLOB: //执行sql保存二进制流到数据库BLOB字段 - //faygo.Info("Info: setblob sql") + case ST_SETBLOB: // 执行sql保存二进制流到数据库BLOB字段 + // faygo.Info("Info: setblob sql") // 如果不存在提交的文件 if !ctx.HasFormFile("inputfile") { - //faygo.Error(err.Error()) + // faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, errors.New("error: Not has inputfile tag!")) } - //获取提交的二进制数据 + // 获取提交的二进制数据 f, _, err := ctx.R.FormFile("inputfile") if err != nil { faygo.Error(err.Error()) @@ -467,7 +467,7 @@ func DirectSQL() faygo.HandlerFunc { err = err2 } }() - //将文件内容读取到[]Bytes + // 将文件内容读取到[]Bytes blobdata, err := ioutil.ReadAll(f) if err != nil { faygo.Error(err.Error()) @@ -480,8 +480,8 @@ func DirectSQL() faygo.HandlerFunc { for i, v := range sp { jsonpara[i] = v[0] } - //循环处理参数,将第一个blob类型参数的值设置为二进制文件 - //faygo.Debug("setblob sql paras:", se.Cmds[0].Parameters) + // 循环处理参数,将第一个blob类型参数的值设置为二进制文件 + // faygo.Debug("setblob sql paras:", se.Cmds[0].Parameters) for _, para := range se.Cmds[0].Parameters { if para.Paratype == PT_BLOB { faygo.Debug("setblob sql blob para :", para.Name) @@ -489,22 +489,22 @@ func DirectSQL() faygo.HandlerFunc { break } } - //参数验证并处理 + // 参数验证并处理 result, err := dealwithParameter(se.Cmds[0].Parameters, jsonpara, ctx) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(400, 400, err.Error()) } - //jsonpara["doc"] = blobdata - //faygo.Debug("setblob para:", jsonpara) - //执行 setBLOB 操作,保存数据。 + // jsonpara["doc"] = blobdata + // faygo.Debug("setblob para:", jsonpara) + // 执行 setBLOB 操作,保存数据。 err = m.setBLOB(se, jsonpara) if err != nil { faygo.Error(err.Error()) return ctx.JSONMsg(404, 404, err.Error()) } - //如果存在服务端生成并需要返回的参数的则返回到客户端 + // 如果存在服务端生成并需要返回的参数的则返回到客户端 if (result != nil) && (len(result) > 0) { return ctx.JSONMsg(200, 200, result) } @@ -515,7 +515,7 @@ func DirectSQL() faygo.HandlerFunc { } } -//重新载入全部ModelSql配置文件 +// 重新载入全部ModelSql配置文件 func DirectSQLReloadAll() faygo.HandlerFunc { return func(c *faygo.Context) error { ReloadAll() @@ -523,10 +523,10 @@ func DirectSQLReloadAll() faygo.HandlerFunc { } } -//重新载入单个ModelSql配置文件 +// 重新载入单个ModelSql配置文件 func DirectSQLReloadModel() faygo.HandlerFunc { return func(c *faygo.Context) error { - //ctx.Path(), '/', 2) 去掉 /bom/reload/ + // ctx.Path(), '/', 2) 去掉 /bom/reload/ err := ReloadModel(trimBefore(c.Path(), '/', 3)) if err != nil { return err @@ -535,9 +535,9 @@ func DirectSQLReloadModel() faygo.HandlerFunc { } } -//发送JSON(P)响应 +// 发送JSON(P)响应 func sendJSON(ctx *faygo.Context, callback string, b []byte) error { - //发送JSONP响应 + // 发送JSONP响应 if len(callback) > 0 { callback = template.JSEscapeString(callback) callbackContent := bytes.NewBufferString(" if(window." + callback + ")" + callback) @@ -546,6 +546,6 @@ func sendJSON(ctx *faygo.Context, callback string, b []byte) error { callbackContent.WriteString(");\r\n") return ctx.Bytes(200, faygo.MIMEApplicationJavaScriptCharsetUTF8, callbackContent.Bytes()) } - //正常有数据JSON响应 + // 正常有数据JSON响应 return ctx.JSONBlob(200, b) } diff --git a/ext/db/directsqlx/sqlmanage.go b/ext/db/directsqlx/sqlmanage.go index 3660b93..ca8ef5f 100644 --- a/ext/db/directsqlx/sqlmanage.go +++ b/ext/db/directsqlx/sqlmanage.go @@ -22,154 +22,154 @@ import ( "strings" "sync" + "github.com/andeya/faygo" + faygosqlx "github.com/andeya/faygo/ext/db/sqlx" + confpkg "github.com/andeya/ini" "github.com/fsnotify/fsnotify" - "github.com/henrylee2cn/faygo" - faygosqlx "github.com/henrylee2cn/faygo/ext/db/sqlx" - confpkg "github.com/henrylee2cn/ini" "github.com/jmoiron/sqlx" ) -//var modelsqls map[string]*TModel +// var modelsqls map[string]*TModel -//配置文件配置参数 +// 配置文件配置参数 const MSCONFIGFILE = "./config/directsql.ini" // 全部业务SQL路由表,不根据目录分层次,直接放在map sqlmodels中,key=带路径不带扩展名的文件名 type TModels struct { - roots map[string]string //需要载入的根目录(可以多个)-短名=实际路径名 - modelsqls map[string]*TModel //全部定义模型对象 - extension string //模型定义文件的扩展名(默认为.msql) - lazyload bool //true / false 配置项 true 则一开始不全部加载,只根据第一次请求才加载然后缓存,false=一开始就根据配置的roots目录全部加载 - loadLock sync.RWMutex //读写锁 - watcher *fsnotify.Watcher //监控文件变化的wather - cached bool //是否启用查询数据缓存功能,启用则配置sql中配置属性cached=true 才有效,否则一律不缓存 - cachetime int //默认缓存的时间,如果使用缓存并且未配置缓存时间则使用该默认时间,单位为分钟,-1为一直有效,-2为一月,-3为一周 -4为一天,单位为分钟 + roots map[string]string // 需要载入的根目录(可以多个)-短名=实际路径名 + modelsqls map[string]*TModel // 全部定义模型对象 + extension string // 模型定义文件的扩展名(默认为.msql) + lazyload bool // true / false 配置项 true 则一开始不全部加载,只根据第一次请求才加载然后缓存,false=一开始就根据配置的roots目录全部加载 + loadLock sync.RWMutex // 读写锁 + watcher *fsnotify.Watcher // 监控文件变化的wather + cached bool // 是否启用查询数据缓存功能,启用则配置sql中配置属性cached=true 才有效,否则一律不缓存 + cachetime int // 默认缓存的时间,如果使用缓存并且未配置缓存时间则使用该默认时间,单位为分钟,-1为一直有效,-2为一月,-3为一周 -4为一天,单位为分钟 } -//全局所有业务模型对象 +// 全局所有业务模型对象 var models = &TModels{ modelsqls: make(map[string]*TModel)} -//sqlmodel 一个配置文件的SQLModel对应的结构 +// sqlmodel 一个配置文件的SQLModel对应的结构 type TModel struct { - Id string //root起用映射、不带扩展名的文件名 - DB *sqlx.DB //本模块的db引擎 *sqlx.DB() - Sqls map[string]*TSql //sqlentity key=sqlentity.id + Id string // root起用映射、不带扩展名的文件名 + DB *sqlx.DB // 本模块的db引擎 *sqlx.DB() + Sqls map[string]*TSql // sqlentity key=sqlentity.id } -//临时转换用,因为 XML 不支持解析到 map,所以先读入到[]然后再根据[]创建map +// 临时转换用,因为 XML 不支持解析到 map,所以先读入到[]然后再根据[]创建map type tempTModel struct { XMLName xml.Name `xml:"model"` - Id string `xml:"id,attr"` //不带扩展名的文件名 + Id string `xml:"id,attr"` // 不带扩展名的文件名 Database string `xml:"database,attr"` Sqls []*TSql `xml:"sql"` } -//sql 等节点对应的结构 type TSql struct { XMLName xml.Name `xml:"sql"` - Id string `xml:"id,attr"` //sqlid + Id string `xml:"id,attr"` // sqlid Sqltypestr string `xml:"type,attr"` - Sqltype TSqltype `xml:"-"` //SQL类型 - Idfield string `xml:"idfield,attr"` //SQlType为6=嵌套jsoin树时的ID字段 - Pidfield string `xml:"pidfield,attr"` //SQlType为6=嵌套jsoin树时的ParentID字段 + Sqltype TSqltype `xml:"-"` // SQL类型 + Idfield string `xml:"idfield,attr"` // SQlType为6=嵌套jsoin树时的ID字段 + Pidfield string `xml:"pidfield,attr"` // SQlType为6=嵌套jsoin树时的ParentID字段 Cmds []*TCmd `xml:"cmd"` // sqlcmd(sqltype为分页查询时的计数SQL放第一个,结果SQL放第二个) - Cached bool `xml:"cached,attr"` //是否启用查询数据缓存功能 - Cachetime int `xml:"cachetime,attr"` //默认缓存的时间,单位为分钟,-1为一直有效,-2为一月,-3为一周 -4为一天,单位为分钟 + Cached bool `xml:"cached,attr"` // 是否启用查询数据缓存功能 + Cachetime int `xml:"cachetime,attr"` // 默认缓存的时间,单位为分钟,-1为一直有效,-2为一月,-3为一周 -4为一天,单位为分钟 } -//TCmd 等节点的下级节点对应结构 type TCmd struct { XMLName xml.Name `xml:"cmd"` - Pin string `xml:"in,attr"` //输入参数标示 - Rout string `xml:"out,attr"` //输出结果标示 - Sql string `xml:",chardata"` //SQL + Pin string `xml:"in,attr"` // 输入参数标示 + Rout string `xml:"out,attr"` // 输出结果标示 + Sql string `xml:",chardata"` // SQL Parameters []*TSqlParameter `xml:"parameters>parameter"` } -//TSql 类型 +// TSql 类型 type TSqltype int const ( - ST_SELECT TSqltype = iota //0 普通查询 ---OK! - ST_PAGINGSELECT //1 分页查询 ---OK! - ST_NESTEDSELECT //2 嵌套jsoin树---------未实现 - ST_MULTISELECT //3 多结果集查询---OK! - ST_EXEC //4 执行SQL,可以一个事务内批量执行多个cmd - ST_BATCHEXEC //5 根据传入参数在一个事务内多次执行SQL - ST_BATCHMULTIEXEC //6 批量执行复合SQL(多数据集批量插入、更新、删除)---OK! - ST_IMPORT //7 导入数据的SQL:通过xlsx导入数据配置的SQL - ST_EXPORT //8 导出数据的SQL:导出excel格式文件数据 - ST_REPORT //9 报表用的SQL:通过xlsx模板创建报表的SQL - ST_GETBLOB //10 获取BLOB (binary large object),二进制大对象从数据库 - ST_SETBLOB //11 保存BLOB (binary large object),二进制大对象到数据库 + ST_SELECT TSqltype = iota // 0 普通查询 ---OK! + ST_PAGINGSELECT // 1 分页查询 ---OK! + ST_NESTEDSELECT // 2 嵌套jsoin树---------未实现 + ST_MULTISELECT // 3 多结果集查询---OK! + ST_EXEC // 4 执行SQL,可以一个事务内批量执行多个cmd + ST_BATCHEXEC // 5 根据传入参数在一个事务内多次执行SQL + ST_BATCHMULTIEXEC // 6 批量执行复合SQL(多数据集批量插入、更新、删除)---OK! + ST_IMPORT // 7 导入数据的SQL:通过xlsx导入数据配置的SQL + ST_EXPORT // 8 导出数据的SQL:导出excel格式文件数据 + ST_REPORT // 9 报表用的SQL:通过xlsx模板创建报表的SQL + ST_GETBLOB // 10 获取BLOB (binary large object),二进制大对象从数据库 + ST_SETBLOB // 11 保存BLOB (binary large object),二进制大对象到数据库 ) -//TSqlParameter 参数校验定义 +// TSqlParameter 参数校验定义 type TSqlParameter struct { - Name string `xml:"name,attr"` //参数名称必须与cmd中的对应 - Paratypestr string `xml:"type,attr"` //string/number/email/date/datetime/time -不定义则不需要验证 - Paratype TParaType `-` //数值类型 - Required bool `xml:"required,attr"` //0=不是必须的 1=必须的不能为空 - Minlen int `xml:"minlen,attr"` //最小长度 - Maxlen int `xml:"maxlen,attr"` //最大长度 - MinValue float64 `xml:"minvalue,attr"` //最小值 - MaxValue float64 `xml:"maxvalue,attr"` //最大值 + Name string `xml:"name,attr"` // 参数名称必须与cmd中的对应 + Paratypestr string `xml:"type,attr"` // string/number/email/date/datetime/time -不定义则不需要验证 + Paratype TParaType `-` // 数值类型 + Required bool `xml:"required,attr"` // 0=不是必须的 1=必须的不能为空 + Minlen int `xml:"minlen,attr"` // 最小长度 + Maxlen int `xml:"maxlen,attr"` // 最大长度 + MinValue float64 `xml:"minvalue,attr"` // 最小值 + MaxValue float64 `xml:"maxvalue,attr"` // 最大值 Defaultstr string `xml:"default,attr"` // 默认值 undefined/uuid/userid/usercode/username/rootgroupid/rootgroupname/groupid/groupname/nowdate/nowtime - Default TDefaultType `-` //数值类型 - Return bool `xml:"return,attr"` //服务端生成的默认值是否返回到客户端: 0(false)=默认,不返回 1(true)=返回到客户端 - Parentid bool `xml:"parentid,attr"` //是否作为从表的关联本表(主表)的id的值 + Default TDefaultType `-` // 数值类型 + Return bool `xml:"return,attr"` // 服务端生成的默认值是否返回到客户端: 0(false)=默认,不返回 1(true)=返回到客户端 + Parentid bool `xml:"parentid,attr"` // 是否作为从表的关联本表(主表)的id的值 } -//参数类型:string/number/email/date/datetime/time +// 参数类型:string/number/email/date/datetime/time type TParaType int const ( - PT_STRING TParaType = iota //0=字符串,默认就是按照字符串处理 - PT_INT //1=整数数值 - PT_FLOAT //2=浮点数 - PT_DATE //3=日期 - PT_DATETIME //4=日期时间 - PT_EMAIL //5=电子邮件 - PT_BLOB //6=二进制 + PT_STRING TParaType = iota // 0=字符串,默认就是按照字符串处理 + PT_INT // 1=整数数值 + PT_FLOAT // 2=浮点数 + PT_DATE // 3=日期 + PT_DATETIME // 4=日期时间 + PT_EMAIL // 5=电子邮件 + PT_BLOB // 6=二进制 ) -//---------------------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------------------- // 默认值类型:uuid/nowdate/now/nowunix type TDefaultType int const ( - DT_UNDEFINED TDefaultType = iota //0=未定义,不处理默认值 - DT_UUID //1=uuid - DT_NOWDATE //2=当前日期 now date - DT_NOWDATETIME //3=当前日期时间 now datetime - DT_NOW_UNIX //4=当前时间的unix值 int64 now date - DT_CUSTOM //5=自定义,采用注册自定义变量实现 - DT_PARENTID //6=关联的主表的Id的值 + DT_UNDEFINED TDefaultType = iota // 0=未定义,不处理默认值 + DT_UUID // 1=uuid + DT_NOWDATE // 2=当前日期 now date + DT_NOWDATETIME // 3=当前日期时间 now datetime + DT_NOW_UNIX // 4=当前时间的unix值 int64 now date + DT_CUSTOM // 5=自定义,采用注册自定义变量实现 + DT_PARENTID // 6=关联的主表的Id的值 ) -//--------------------------------------------------------------------------------------------------- -//读入全部模型sql定义 +// --------------------------------------------------------------------------------------------------- +// 读入全部模型sql定义 func init() { models.loadTModels() } -//读入全部模型 +// 读入全部模型 func (ms *TModels) loadTModels() { ms.loadLock.Lock() defer ms.loadLock.Unlock() - //打开directsql的配置文件 + // 打开directsql的配置文件 cfg, err := confpkg.Load(MSCONFIGFILE) if err != nil { faygo.Error(err.Error()) return } - //是否缓存与缓存时间 + // 是否缓存与缓存时间 ms.cached = cfg.Section("").Key("cached").MustBool(false) ms.cachetime = cfg.Section("").Key("cachetime").MustInt(30) - //读取ModelSQL文件的根目录 + // 读取ModelSQL文件的根目录 roots, err := cfg.GetSection("roots") if err != nil { faygo.Error(err.Error()) @@ -184,11 +184,11 @@ func (ms *TModels) loadTModels() { } } - //读取扩展名,读取不到就用默认的.msql + // 读取扩展名,读取不到就用默认的.msql ext := cfg.Section("").Key("ext").MustString(".msql") ms.extension = ext - //根据路径遍历加载 + // 根据路径遍历加载 for _, value := range ms.roots { faygo.Debug(value) err = filepath.Walk(value, ms.walkFunc) @@ -197,7 +197,7 @@ func (ms *TModels) loadTModels() { } } - //是否监控文件变化 + // 是否监控文件变化 watch := cfg.Section("").Key("watch").MustBool(false) if watch { err := ms.StartWatcher() @@ -208,20 +208,20 @@ func (ms *TModels) loadTModels() { } -//将带路径文件名处理成 TModel的 id 示例: bizmodel\demo.msql --> biz/demo +// 将带路径文件名处理成 TModel的 id 示例: bizmodel\demo.msql --> biz/demo func (ms *TModels) filenameToModelId(path string) string { key := strings.Replace(path, "\\", "/", -1) - key = strings.TrimSuffix(key, ms.extension) //去掉扩展名 + key = strings.TrimSuffix(key, ms.extension) // 去掉扩展名 for root, value := range ms.roots { if strings.HasPrefix(key, value) { - key = strings.Replace(key, value, root, 1) //处理前缀,将定义的根路径替换为名称 + key = strings.Replace(key, value, root, 1) // 处理前缀,将定义的根路径替换为名称 break } } return key } -//遍历子目录文件处理函数 +// 遍历子目录文件处理函数 func (ms *TModels) walkFunc(path string, info os.FileInfo, err error) error { if err != nil { return err @@ -233,18 +233,18 @@ func (ms *TModels) walkFunc(path string, info os.FileInfo, err error) error { m, err := ms.parseTModel(path) if err != nil { faygo.Error("Model file: " + path + " --- " + err.Error()) - return nil //单个文件解析出错继续加载其他的文件 + return nil // 单个文件解析出错继续加载其他的文件 } - //将本文件对应的TModel放入到TModels + // 将本文件对应的TModel放入到TModels ms.modelsqls[ms.filenameToModelId(path)] = m faygo.Debug("Model file: " + path + " ------> " + ms.filenameToModelId(path) + " loaded. ") } return nil } -//解析单个ModelSQL定义文件 +// 解析单个ModelSQL定义文件 func (ms *TModels) parseTModel(msqlfile string) (*TModel, error) { - //读取文件 + // 读取文件 content, err := ioutil.ReadFile(msqlfile) if err != nil { return nil, err @@ -254,46 +254,46 @@ func (ms *TModels) parseTModel(msqlfile string) (*TModel, error) { if err != nil { return nil, err } - //设置数据库 + // 设置数据库 dbe, ok := faygosqlx.DB(tempresult.Database) if ok == false { dbe = faygosqlx.MustDB() - //faygo.Log.Debug("database:", tempresult.Database) + // faygo.Log.Debug("database:", tempresult.Database) } - //定义一个 TModel将 tempTModel 转换为 TModel + // 定义一个 TModel将 tempTModel 转换为 TModel result := &TModel{Id: tempresult.Id, DB: dbe, Sqls: make(map[string]*TSql)} - //处理一遍:设置数据库访问引擎,设置TSql的类型 + // 处理一遍:设置数据库访问引擎,设置TSql的类型 for _, se := range tempresult.Sqls { - //处理SQL类型与查询类语句缓存的配置参数 + // 处理SQL类型与查询类语句缓存的配置参数 switch se.Sqltypestr { case "select": se.Sqltype = ST_SELECT - //缓存设置处理 + // 缓存设置处理 se.Cached = se.Cached && ms.cached if se.Cached && se.Cachetime == 0 { se.Cachetime = ms.cachetime } case "pagingselect": se.Sqltype = ST_PAGINGSELECT - //缓存设置处理 + // 缓存设置处理 se.Cached = se.Cached && ms.cached if se.Cached && se.Cachetime == 0 { se.Cachetime = ms.cachetime } case "nestedselect": se.Sqltype = ST_NESTEDSELECT - //缓存设置处理 + // 缓存设置处理 se.Cached = se.Cached && ms.cached if se.Cached && se.Cachetime == 0 { se.Cachetime = ms.cachetime } case "multiselect": se.Sqltype = ST_MULTISELECT - //缓存设置处理 + // 缓存设置处理 if !ms.cached { se.Cached = false } - //se.cached = se.cached && ms.cached + // se.cached = se.cached && ms.cached if se.Cached && se.Cachetime == 0 { se.Cachetime = ms.cachetime } @@ -317,40 +317,40 @@ func (ms *TModels) parseTModel(msqlfile string) (*TModel, error) { faygo.Error(errors.New("错误:配置文件[ " + msqlfile + " ]中存在无效的sql节点类型[ " + se.Sqltypestr + " ]!")) } result.Sqls[se.Id] = se - //faygo.Debug(se) - //sql下的每个cmd循环处理 + // faygo.Debug(se) + // sql下的每个cmd循环处理 for _, cmd := range se.Cmds { - //每个cmd下的参数循环处理参数类型与默认值类型 + // 每个cmd下的参数循环处理参数类型与默认值类型 for _, para := range cmd.Parameters { - //参数类型 - switch para.Paratypestr { //string/int/float/email/date/datetime/blob + // 参数类型 + switch para.Paratypestr { // string/int/float/email/date/datetime/blob case "string": - para.Paratype = PT_STRING //0=字符串,默认就是按照字符串处理 + para.Paratype = PT_STRING // 0=字符串,默认就是按照字符串处理 case "int": - para.Paratype = PT_INT //1=整数数值 + para.Paratype = PT_INT // 1=整数数值 case "float": - para.Paratype = PT_FLOAT //2=浮点数 + para.Paratype = PT_FLOAT // 2=浮点数 case "date": - para.Paratype = PT_DATE //3=日期 + para.Paratype = PT_DATE // 3=日期 case "datetime": - para.Paratype = PT_DATETIME //4=日期时间 + para.Paratype = PT_DATETIME // 4=日期时间 case "email": - para.Paratype = PT_EMAIL //5=电子邮件 + para.Paratype = PT_EMAIL // 5=电子邮件 case "blob": para.Paratype = PT_BLOB } - //默认值类型 + // 默认值类型 switch para.Defaultstr { case "uuid": - para.Default = DT_UUID //1=uuid + para.Default = DT_UUID // 1=uuid case "nowdate": - para.Default = DT_NOWDATE //12=当前日期 now date + para.Default = DT_NOWDATE // 12=当前日期 now date case "now": - para.Default = DT_NOWDATETIME //当前时间 + para.Default = DT_NOWDATETIME // 当前时间 case "nowunix": - para.Default = DT_NOW_UNIX //=当前日期时间unix值 int64 now datetime + para.Default = DT_NOW_UNIX // =当前日期时间unix值 int64 now datetime case "parentid": - para.Default = DT_PARENTID //主表的id的值 (parentid value) + para.Default = DT_PARENTID // 主表的id的值 (parentid value) default: if len(strings.TrimSpace(para.Defaultstr)) > 0 { para.Default = DT_CUSTOM @@ -364,7 +364,7 @@ func (ms *TModels) parseTModel(msqlfile string) (*TModel, error) { return result, nil } -//获取sqlentity SQL的执行实体 +// 获取sqlentity SQL的执行实体 func (ms *TModels) findsql(modelid string, sqlid string) *TSql { if sm, ok := ms.modelsqls[modelid]; ok { if se, ok := sm.Sqls[sqlid]; ok { @@ -374,7 +374,7 @@ func (ms *TModels) findsql(modelid string, sqlid string) *TSql { return nil } -//获取sqlentity SQL的执行实体与DB执行引擎 +// 获取sqlentity SQL的执行实体与DB执行引擎 func (ms *TModels) findsqlanddb(modelid string, sqlid string) (*TSql, *sqlx.DB) { if sm, ok := ms.modelsqls[modelid]; ok { if se, ok := sm.Sqls[sqlid]; ok { @@ -384,7 +384,7 @@ func (ms *TModels) findsqlanddb(modelid string, sqlid string) (*TSql, *sqlx.DB) return nil, nil } -//获取sqlentity 的类型 +// 获取sqlentity 的类型 func (ms *TModels) getSqlType(modelid string, sqlid string) TSqltype { if sm, ok := ms.modelsqls[modelid]; ok { if se, ok := sm.Sqls[sqlid]; ok { @@ -402,22 +402,22 @@ func (ms *TModels) findmodel(modelid string) *TModel { return nil } -//文件内容改变重新载入(新增、修改的都触发) +// 文件内容改变重新载入(新增、修改的都触发) func (ms *TModels) refreshModelFile(msqlfile string) error { ms.loadLock.Lock() defer ms.loadLock.Unlock() - //重新解析 + // 重新解析 m, err := ms.parseTModel(msqlfile) if err != nil { faygo.Error(err.Error()) - return err //单个文件解析出错继续加载其他的文件 + return err // 单个文件解析出错继续加载其他的文件 } - //将本文件对应的TModel放入到TModels + // 将本文件对应的TModel放入到TModels ms.modelsqls[ms.filenameToModelId(msqlfile)] = m return nil } -//文件已经被移除,从内存中删除 +// 文件已经被移除,从内存中删除 func (ms *TModels) removeModelFile(msqlfile string) error { ms.loadLock.Lock() defer ms.loadLock.Unlock() @@ -425,15 +425,15 @@ func (ms *TModels) removeModelFile(msqlfile string) error { return nil } -//文件改名---暂无实现 +// 文件改名---暂无实现 func (ms *TModels) renameModelFile(msqlfile, newfilename string) error { - //err := ms.removeModelFile(msqlfile) - //err = ms.refreshModelFile(newfilename) + // err := ms.removeModelFile(msqlfile) + // err = ms.refreshModelFile(newfilename) return nil } -//单元访问文件-------------------------------------------------------------- -//获取sqlentity SQL的执行实体与数据库引擎 +// 单元访问文件-------------------------------------------------------------- +// 获取sqlentity SQL的执行实体与数据库引擎 func findSqlAndDB(modelid string, sqlid string) (*TSql, *sqlx.DB) { return models.findsqlanddb(modelid, sqlid) } @@ -443,27 +443,27 @@ func GetSqlType(modelid string, sqlid string) TSqltype { return models.getSqlType(modelid, sqlid) } -//获取sqlentity SQL的执行实体 +// 获取sqlentity SQL的执行实体 func findSql(modelid string, sqlid string) *TSql { - //faygo.Debug("Model Path: " + modelid + " ,SqlId: " + sqlid) + // faygo.Debug("Model Path: " + modelid + " ,SqlId: " + sqlid) return models.findsql(modelid, sqlid) } -//根据TModel文件路径获取 TModel +// 根据TModel文件路径获取 TModel func findModel(modelid string) *TModel { - //faygo.Debug("Model Path: " + modelid) + // faygo.Debug("Model Path: " + modelid) return models.findmodel(modelid) } -//重置配置文件全部重新载入,API:/bom/reload handle调用 +// 重置配置文件全部重新载入,API:/bom/reload handle调用 func ReloadAll() { models = &TModels{ modelsqls: make(map[string]*TModel)} models.loadTModels() } -//重新载入单个模型文件---未测试!!! +// 重新载入单个模型文件---未测试!!! func ReloadModel(msqlfile string) error { - //已经去掉 "/bom/reload/",需要加上扩展名 + // 已经去掉 "/bom/reload/",需要加上扩展名 return models.refreshModelFile(msqlfile + models.extension) } diff --git a/ext/db/directsqlx/sqlrouter.go b/ext/db/directsqlx/sqlrouter.go index b66a76c..677e530 100644 --- a/ext/db/directsqlx/sqlrouter.go +++ b/ext/db/directsqlx/sqlrouter.go @@ -6,7 +6,7 @@ package directsqlx /* import ( - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) //注册路由 diff --git a/ext/db/directsqlx/sqlservice.go b/ext/db/directsqlx/sqlservice.go index f1a902f..824c6bb 100644 --- a/ext/db/directsqlx/sqlservice.go +++ b/ext/db/directsqlx/sqlservice.go @@ -16,7 +16,7 @@ import ( "errors" "reflect" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" "github.com/jmoiron/sqlx" ) @@ -29,7 +29,7 @@ var notMatchError = func() error { // 默认参数处理 func DealwithParameter(modelId, sqlId string, mp map[string]interface{}, sqlindex int, ctx *faygo.Context) error { - //获取Sqlentity,db + // 获取Sqlentity,db se, _ := findSqlAndDB(modelId, sqlId) if se == nil { return notFoundError(modelId + "/" + sqlId) @@ -42,21 +42,21 @@ func DealwithParameter(modelId, sqlId string, mp map[string]interface{}, sqlinde return nil } -//查询 根据modelId,sqlId ,mp:map[string]interface{}命名参数,返回*core.Rows +// 查询 根据modelId,sqlId ,mp:map[string]interface{}命名参数,返回*core.Rows func SelectMapToRows(modelId, sqlId string, mp map[string]interface{}) (*sqlx.Rows, error) { - //获取Sqlentity,db + // 获取Sqlentity,db se, db := findSqlAndDB(modelId, sqlId) if se == nil { return nil, notFoundError(modelId + "/" + sqlId) } - //判断类型不是Select 就返回错误 + // 判断类型不是Select 就返回错误 if se.Sqltype != ST_SELECT { return nil, notMatchError() } return db.NamedQuery(se.Cmds[0].Sql, mp) } -//查询 根据modelId,sqlId ,SQL参数 map 返回 []map[string]interface{} +// 查询 根据modelId,sqlId ,SQL参数 map 返回 []map[string]interface{} func SelectMapToMap(modelId, sqlId string, mp map[string]interface{}) ([]map[string]interface{}, error) { rows, err := SelectMapToRows(modelId, sqlId, mp) if err != nil { @@ -66,8 +66,8 @@ func SelectMapToMap(modelId, sqlId string, mp map[string]interface{}) ([]map[str return rows2mapObjects(rows) } -//查询 根据modelId,sqlId ,SQL参数是map, 返回 []struct -//目前使用比较繁琐:st --是结构体的一个空实例,返回的是 改结构体的实例的slice,再使用返还结果时还的需要转换下类型。 +// 查询 根据modelId,sqlId ,SQL参数是map, 返回 []struct +// 目前使用比较繁琐:st --是结构体的一个空实例,返回的是 改结构体的实例的slice,再使用返还结果时还的需要转换下类型。 func SelectMapToStruct(modelId, sqlId string, mp map[string]interface{}, st interface{}) (*[]interface{}, error) { s := reflect.ValueOf(st).Elem() @@ -86,7 +86,7 @@ func SelectMapToStruct(modelId, sqlId string, mp map[string]interface{}, st inte err = rows.Scan(onerow...) if err != nil { return nil, err - //panic(err) + // panic(err) } result = append(result, s.Interface()) } @@ -94,24 +94,24 @@ func SelectMapToStruct(modelId, sqlId string, mp map[string]interface{}, st inte return &result, nil } -//查询 根据modelId,sqlId ,SQL参数是map,dest 是待填充的返回结果 []*Struct ---未完成 +// 查询 根据modelId,sqlId ,SQL参数是map,dest 是待填充的返回结果 []*Struct ---未完成 func SelectMapToStructPro(modelId, sqlId string, mp map[string]interface{}, dest interface{}) error { return nil } -//执行返回多個結果集的多個查询根据modelId,sqlId ,SQLmp:map[string]interface{}命名参数 返回结果 map[string]*Rows +// 执行返回多個結果集的多個查询根据modelId,sqlId ,SQLmp:map[string]interface{}命名参数 返回结果 map[string]*Rows func MultiSelectMapToRows(modelId, sqlId string, mp map[string]interface{}) (map[string]*sqlx.Rows, error) { result := make(map[string]*sqlx.Rows) - //获取Sqlentity,db + // 获取Sqlentity,db se, db := findSqlAndDB(modelId, sqlId) if se == nil { return nil, notFoundError(modelId + "/" + sqlId) } - //判断类型不是MULTISELECT 就返回错误 + // 判断类型不是MULTISELECT 就返回错误 if se.Sqltype != ST_MULTISELECT { return nil, notMatchError() } - //循環每個sql定義 + // 循環每個sql定義 for i, cmd := range se.Cmds { faygo.Debug("MultiSelectMap :" + cmd.Sql) rows, err := db.NamedQuery(cmd.Sql, mp) @@ -127,16 +127,16 @@ func MultiSelectMapToRows(modelId, sqlId string, mp map[string]interface{}) (map return result, nil } -//分頁查詢的返回結果 +// 分頁查詢的返回結果 type PagingSelectRows struct { Total int `json:"total"` Rows *sqlx.Rows } -//执行分页查询SQL mp 是MAP类型命名参数 返回结果 int,[]map[string][]interface{} +// 执行分页查询SQL mp 是MAP类型命名参数 返回结果 int,[]map[string][]interface{} func PagingSelectMapToMap(modelId, sqlId string, mp map[string]interface{}) (*PagingSelectResult, error) { se, db := findSqlAndDB(modelId, sqlId) - //获取总页数,約定該SQL放到第二條,並且只返回一條記錄一個字段 + // 获取总页数,約定該SQL放到第二條,並且只返回一條記錄一個字段 trows, err := db.NamedQuery(se.Cmds[0].Sql, mp) if err != nil { return nil, err @@ -150,7 +150,7 @@ func PagingSelectMapToMap(modelId, sqlId string, mp map[string]interface{}) (*Pa if len(total) != 1 { return nil, errors.New("错误:获取总页数的SQL执行结果非唯一记录!") } - //2.获取当前页數據,約定該SQL放到第二條 + // 2.获取当前页數據,約定該SQL放到第二條 rows, err := db.NamedQuery(se.Cmds[1].Sql, mp) if err != nil { return nil, err @@ -160,15 +160,15 @@ func PagingSelectMapToMap(modelId, sqlId string, mp map[string]interface{}) (*Pa if err != nil { return nil, err } - return &PagingSelectResult{Total: total[0].(int), Data: result}, nil //最終的結果 + return &PagingSelectResult{Total: total[0].(int), Data: result}, nil // 最終的結果 } return nil, err } -//执行分页查询SQL mp 是MAP类型命名参数 返回结果 int,Rows +// 执行分页查询SQL mp 是MAP类型命名参数 返回结果 int,Rows func PagingSelectMapToRows(modelId, sqlId string, mp map[string]interface{}) (*PagingSelectRows, error) { se, db := findSqlAndDB(modelId, sqlId) - //获取总页数,約定該SQL放到第二條,並且只返回一條記錄一個字段 + // 获取总页数,約定該SQL放到第二條,並且只返回一條記錄一個字段 trows, err := db.NamedQuery(se.Cmds[0].Sql, mp) if err != nil { return nil, err @@ -182,17 +182,17 @@ func PagingSelectMapToRows(modelId, sqlId string, mp map[string]interface{}) (*P if len(total) != 1 { return nil, errors.New("错误:获取总页数的SQL执行结果非唯一记录!") } - //2.获取当前页數據,約定該SQL放到第二條 + // 2.获取当前页數據,約定該SQL放到第二條 rows, err := db.NamedQuery(se.Cmds[1].Sql, &mp) if err != nil { return nil, err } - return &PagingSelectRows{Total: total[0].(int), Rows: rows}, nil //最終的結果 + return &PagingSelectRows{Total: total[0].(int), Rows: rows}, nil // 最終的結果 } return nil, err } -//多個查询 返回 map[string][]map[string]interface{} +// 多個查询 返回 map[string][]map[string]interface{} func MultiSelectMapToMap(modelId, sqlId string, mp map[string]interface{}) (map[string][]map[string]interface{}, error) { multirows, err := MultiSelectMapToRows(modelId, sqlId, mp) if err != nil { @@ -209,22 +209,22 @@ func MultiSelectMapToMap(modelId, sqlId string, mp map[string]interface{}) (map[ return result, nil } -//执行EXEC (UPDATE、DELETE、INSERT),mp 是MAP类型命名参数 返回结果 sql.Result +// 执行EXEC (UPDATE、DELETE、INSERT),mp 是MAP类型命名参数 返回结果 sql.Result func ExecMap(modelId, sqlId string, mp map[string]interface{}) (sql.Result, error) { - //获取Sqlentity,db + // 获取Sqlentity,db se, db := findSqlAndDB(modelId, sqlId) if se == nil { return nil, notFoundError(modelId + "/" + sqlId) } - //判断类型不是EXEC(UPDATE、DELETE、INSERT)就返回错误 + // 判断类型不是EXEC(UPDATE、DELETE、INSERT)就返回错误 if se.Sqltype != ST_EXEC { return nil, notMatchError() } - //return db.ExecMap(se.Cmds[0].Sql, &mp) + // return db.ExecMap(se.Cmds[0].Sql, &mp) return nil, transact(db, func(tx *sqlx.Tx) error { - //循環每個sql定義 + // 循環每個sql定義 for _, cmd := range se.Cmds { - //faygo.Debug("ExecMap sql:" + cmd.Sql) + // faygo.Debug("ExecMap sql:" + cmd.Sql) if _, err := tx.NamedExec(cmd.Sql, mp); err != nil { return err } @@ -233,22 +233,22 @@ func ExecMap(modelId, sqlId string, mp map[string]interface{}) (sql.Result, erro }) } -//执行EXEC (UPDATE、DELETE、INSERT),SQL参数是struct 返回结果 sql.Result +// 执行EXEC (UPDATE、DELETE、INSERT),SQL参数是struct 返回结果 sql.Result func ExecStruct(modelId, sqlId string, st interface{}) (sql.Result, error) { - //获取Sqlentity,db + // 获取Sqlentity,db se, db := findSqlAndDB(modelId, sqlId) if se == nil { return nil, notFoundError(modelId + "/" + sqlId) } - //判断类型不是EXEC 就返回错误 + // 判断类型不是EXEC 就返回错误 if se.Sqltype != ST_EXEC { return nil, notMatchError() } - //return db.ExecStruct(se.Cmds[0].Sql, st) + // return db.ExecStruct(se.Cmds[0].Sql, st) return nil, transact(db, func(tx *sqlx.Tx) error { - //循環每個sql定義 + // 循環每個sql定義 for _, cmd := range se.Cmds { - //faygo.Debug("ExecMap sql:" + cmd.Sql) + // faygo.Debug("ExecMap sql:" + cmd.Sql) if _, err := tx.NamedExec(cmd.Sql, st); err != nil { return err } @@ -257,14 +257,14 @@ func ExecStruct(modelId, sqlId string, st interface{}) (sql.Result, error) { }) } -//批量执行 UPDATE、INSERT、DELETE、mp 是MAP类型命名参数 +// 批量执行 UPDATE、INSERT、DELETE、mp 是MAP类型命名参数 func BacthExecMap(modelId, sqlId string, sp []map[string]interface{}) error { - //获取Sqlentity,db + // 获取Sqlentity,db se, db := findSqlAndDB(modelId, sqlId) if se == nil { return notFoundError(modelId + "/" + sqlId) } - //判断类型不是BATCHEXEC 就返回错误 + // 判断类型不是BATCHEXEC 就返回错误 if se.Sqltype != ST_BATCHEXEC { return notMatchError() } @@ -279,21 +279,21 @@ func BacthExecMap(modelId, sqlId string, sp []map[string]interface{}) error { }) } -//批量执行 BacthComplex、mp 是MAP类型命名参数,事务中依次执行 +// 批量执行 BacthComplex、mp 是MAP类型命名参数,事务中依次执行 func BacthMultiExecMap(modelId, sqlId string, mp map[string][]map[string]interface{}) error { - //获取Sqlentity,db + // 获取Sqlentity,db se, db := findSqlAndDB(modelId, sqlId) if se == nil { return notFoundError(modelId + "/" + sqlId) } - //判断类型不是 ST_BATCHMULTIEXEC 就返回错误 + // 判断类型不是 ST_BATCHMULTIEXEC 就返回错误 if se.Sqltype != ST_BATCHMULTIEXEC { return notMatchError() } return transact(db, func(tx *sqlx.Tx) error { - //循環每個sql定義 + // 循環每個sql定義 for _, cmd := range se.Cmds { - //循環其批量參數 + // 循環其批量參數 if sp, ok := mp[cmd.Pin]; ok { for _, p := range sp { faygo.Debug("BacthMultiExecMap :" + cmd.Sql) diff --git a/ext/db/directsqlx/sqlwatcher.go b/ext/db/directsqlx/sqlwatcher.go index b2758f7..3db866b 100644 --- a/ext/db/directsqlx/sqlwatcher.go +++ b/ext/db/directsqlx/sqlwatcher.go @@ -9,12 +9,13 @@ package directsqlx import ( - "github.com/fsnotify/fsnotify" - "github.com/henrylee2cn/faygo" "strings" + + "github.com/andeya/faygo" + "github.com/fsnotify/fsnotify" ) -//start filesytem watcher +// start filesytem watcher func (mss *TModels) StartWatcher() error { var err error mss.watcher, err = fsnotify.NewWatcher() @@ -26,7 +27,7 @@ func (mss *TModels) StartWatcher() error { for { select { case event := <-mss.watcher.Events: - //如果变更的文件是 .msql文件 + // 如果变更的文件是 .msql文件 if strings.HasSuffix(event.Name, mss.extension) { if event.Op&fsnotify.Write == fsnotify.Write { faygo.Debug("Modified file:" + event.Name) @@ -59,18 +60,18 @@ func (mss *TModels) StartWatcher() error { } } }() - //增加监控路径 + // 增加监控路径 for _, value := range mss.roots { err = mss.watcher.Add(value) if err != nil { faygo.Error(err.Error()) - //return + // return } } return nil } -//stop filesytem watcher +// stop filesytem watcher func (mss *TModels) StopWatcher() error { if mss.watcher != nil { faygo.Info("Directsql stop watching.....................") diff --git a/ext/db/gorm/config.go b/ext/db/gorm/config.go index 5ca9aeb..68fd7f8 100644 --- a/ext/db/gorm/config.go +++ b/ext/db/gorm/config.go @@ -4,8 +4,8 @@ import ( "os" "path/filepath" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/ini" + "github.com/andeya/faygo" + "github.com/andeya/ini" ) // DBConfig is database connection config diff --git a/ext/db/gorm/helper.go b/ext/db/gorm/helper.go index 595aebf..0f8d0d6 100644 --- a/ext/db/gorm/helper.go +++ b/ext/db/gorm/helper.go @@ -3,7 +3,7 @@ package gorm import ( "errors" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" "github.com/jinzhu/gorm" ) diff --git a/ext/db/gorm/service.go b/ext/db/gorm/service.go index b44a7be..d840806 100644 --- a/ext/db/gorm/service.go +++ b/ext/db/gorm/service.go @@ -8,11 +8,11 @@ import ( "github.com/jinzhu/gorm" // _ "github.com/jinzhu/gorm/dialects/mssql" //github.com/denisenkom/go-mssqldb - _ "github.com/jinzhu/gorm/dialects/mysql" //github.com/go-sql-driver/mysql - _ "github.com/jinzhu/gorm/dialects/postgres" //github.com/lib/pq + _ "github.com/jinzhu/gorm/dialects/mysql" // github.com/go-sql-driver/mysql + _ "github.com/jinzhu/gorm/dialects/postgres" // github.com/lib/pq // _ "github.com/jinzhu/gorm/dialects/sqlite" //github.com/mattn/go-sqlite3 - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) // DBService is a database engine object. diff --git a/ext/db/sqlx/config.go b/ext/db/sqlx/config.go index 002bd49..01ed9b7 100644 --- a/ext/db/sqlx/config.go +++ b/ext/db/sqlx/config.go @@ -4,8 +4,8 @@ import ( "os" "path/filepath" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/ini" + "github.com/andeya/faygo" + "github.com/andeya/ini" ) // DBConfig is database connection config diff --git a/ext/db/sqlx/helper.go b/ext/db/sqlx/helper.go index c1038df..a7a5887 100644 --- a/ext/db/sqlx/helper.go +++ b/ext/db/sqlx/helper.go @@ -4,7 +4,7 @@ import ( "database/sql" "errors" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" "github.com/jmoiron/sqlx" ) diff --git a/ext/db/sqlx/service.go b/ext/db/sqlx/service.go index 0e98b2f..79948f9 100644 --- a/ext/db/sqlx/service.go +++ b/ext/db/sqlx/service.go @@ -9,12 +9,12 @@ import ( "github.com/jmoiron/sqlx/reflectx" // _ "github.com/denisenkom/go-mssqldb" //mssql - _ "github.com/go-sql-driver/mysql" //mysql - _ "github.com/lib/pq" //postgres + _ "github.com/go-sql-driver/mysql" // mysql + _ "github.com/lib/pq" // postgres // _ "github.com/mattn/go-oci8" //oracle(need to install the pkg-config utility) // _ "github.com/mattn/go-sqlite3" //sqlite - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) // DBService is a database engine object. diff --git a/ext/db/xorm/config.go b/ext/db/xorm/config.go index 7fcb49f..e3b8551 100644 --- a/ext/db/xorm/config.go +++ b/ext/db/xorm/config.go @@ -4,8 +4,8 @@ import ( "os" "path/filepath" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/ini" + "github.com/andeya/faygo" + "github.com/andeya/ini" ) // DBConfig is database connection config diff --git a/ext/db/xorm/helper.go b/ext/db/xorm/helper.go index 0786de3..6522760 100644 --- a/ext/db/xorm/helper.go +++ b/ext/db/xorm/helper.go @@ -3,8 +3,8 @@ package xorm import ( "errors" + "github.com/andeya/faygo" "xorm.io/xorm" - "github.com/henrylee2cn/faygo" ) // MustDB gets the specified database engine, diff --git a/ext/db/xorm/logger.go b/ext/db/xorm/logger.go index 6e8f486..0d94c4b 100644 --- a/ext/db/xorm/logger.go +++ b/ext/db/xorm/logger.go @@ -3,8 +3,8 @@ package xorm import ( "xorm.io/core" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/logging" + "github.com/andeya/faygo" + "github.com/andeya/faygo/logging" ) // ILogger logger diff --git a/ext/db/xorm/service.go b/ext/db/xorm/service.go index 1197e47..cb07c64 100644 --- a/ext/db/xorm/service.go +++ b/ext/db/xorm/service.go @@ -9,12 +9,12 @@ import ( "xorm.io/xorm" // _ "github.com/denisenkom/go-mssqldb" //mssql - _ "github.com/go-sql-driver/mysql" //mysql - _ "github.com/lib/pq" //postgres + _ "github.com/go-sql-driver/mysql" // mysql + _ "github.com/lib/pq" // postgres // _ "github.com/mattn/go-oci8" //oracle(need to install the pkg-config utility) // _ "github.com/mattn/go-sqlite3" //sqlite - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) // DBService is a database engine object. diff --git a/ext/middleware/attachment.go b/ext/middleware/attachment.go index 696512a..88f44ba 100644 --- a/ext/middleware/attachment.go +++ b/ext/middleware/attachment.go @@ -20,7 +20,7 @@ import ( "regexp" "strings" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) // NewAttachment has the response content downloaded as an attachment file. diff --git a/ext/middleware/cross_origin.go b/ext/middleware/cross_origin.go index d5fcd5a..c412857 100644 --- a/ext/middleware/cross_origin.go +++ b/ext/middleware/cross_origin.go @@ -17,7 +17,7 @@ package middleware import ( - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) // CrossOrigin creates Cross-Domain middleware. diff --git a/ext/middleware/html_suffix.go b/ext/middleware/html_suffix.go index 0d5fe64..46ec359 100644 --- a/ext/middleware/html_suffix.go +++ b/ext/middleware/html_suffix.go @@ -20,10 +20,10 @@ import ( "path" "strings" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) -//AutoHTMLSuffix adds smartly .html suffix to static route +// AutoHTMLSuffix adds smartly .html suffix to static route func AutoHTMLSuffix() faygo.HandlerFunc { return func(c *faygo.Context) error { ps := c.PathParamAll() diff --git a/ext/middleware/ip_filter.go b/ext/middleware/ip_filter.go index c413108..781564e 100644 --- a/ext/middleware/ip_filter.go +++ b/ext/middleware/ip_filter.go @@ -20,7 +20,7 @@ import ( "net/http" "strings" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) // NewIPFilter creates middleware that intercepts the specified IP prefix. diff --git a/ext/middleware/jwt/jwt.go b/ext/middleware/jwt/jwt.go index 2ec2eb5..44d08a5 100644 --- a/ext/middleware/jwt/jwt.go +++ b/ext/middleware/jwt/jwt.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" "gopkg.in/dgrijalva/jwt-go.v3" ) @@ -291,7 +291,7 @@ func (mw *FaygoJWTMiddleware) MiddlewareInit() error { // MiddlewareFunc makes FaygoJWTMiddleware implement the Middleware interface. func (mw *FaygoJWTMiddleware) MiddlewareFunc() faygo.HandlerFunc { - //初始设置改为手动调用 + // 初始设置改为手动调用 /*if err := mw.MiddlewareInit(); err != nil { return func(c *faygo.Context) error { mw.unauthorized(c, http.StatusInternalServerError, mw.HTTPStatusMessageFunc(err, nil)) @@ -396,7 +396,7 @@ func (mw *FaygoJWTMiddleware) signedString(token *jwt.Token) (string, error) { // Reply will be of the form {"token": "TOKEN"}. func (mw *FaygoJWTMiddleware) RefreshHandler(c *faygo.Context) error { token, err := mw.parseToken(c) - //如果有错误并不是过期则触发错误并返回 + // 如果有错误并不是过期则触发错误并返回 if (err != nil) && (err.Error() != "Token is expired") { faygo.Error(err) return mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, c)) @@ -404,7 +404,7 @@ func (mw *FaygoJWTMiddleware) RefreshHandler(c *faygo.Context) error { claims := token.Claims.(jwt.MapClaims) origIat := int64(claims["orig_iat"].(float64)) - //如果超过 刷新期则触发过期错误并返回 + // 如果超过 刷新期则触发过期错误并返回 if origIat < mw.TimeFunc().Add(-mw.MaxRefresh).Unix() { return mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(ErrExpiredToken, c)) @@ -421,7 +421,7 @@ func (mw *FaygoJWTMiddleware) RefreshHandler(c *faygo.Context) error { expire := mw.TimeFunc().Add(mw.Timeout) newClaims["id"] = claims["id"] newClaims["exp"] = expire.Unix() - newClaims["orig_iat"] = mw.TimeFunc().Unix() //原来是 origIat貌似不正确 + newClaims["orig_iat"] = mw.TimeFunc().Unix() // 原来是 origIat貌似不正确 tokenString, err := mw.signedString(newToken) if err != nil { diff --git a/ext/middleware/jwt/sample/server.go b/ext/middleware/jwt/sample/server.go index f784731..c86ae76 100644 --- a/ext/middleware/jwt/sample/server.go +++ b/ext/middleware/jwt/sample/server.go @@ -3,8 +3,8 @@ package main import ( "time" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/ext/middleware/jwt" + "github.com/andeya/faygo" + "github.com/andeya/faygo/ext/middleware/jwt" ) func helloHandler(c *faygo.Context) error { @@ -23,7 +23,7 @@ func main() { Key: []byte("secret key"), Timeout: time.Minute, MaxRefresh: time.Minute * 3, - //登录响应 + // 登录响应 LoginResponse: func(c *faygo.Context, code int, token string, expire time.Time) error { faygo.Debug("LoginResponse") return c.JSON(code, faygo.Map{ @@ -38,7 +38,7 @@ func main() { "custom2": "custom info2 ", } },*/ - //认证 + // 认证 Authenticator: func(userId string, password string, c *faygo.Context) (interface{}, bool) { faygo.Debug("Authenticator认证") if (userId == "admin" && password == "admin") || (userId == "test" && password == "test") { @@ -48,7 +48,7 @@ func main() { return userId, false }, - //授权 + // 授权 Authorizator: func(userId interface{}, c *faygo.Context) bool { faygo.Debug("Authorizator 授权") if userId == "admin" { @@ -81,7 +81,7 @@ func main() { // TimeFunc provides the current time. You can override it to use another time value. This is useful for testing or if your server uses a different time zone than your tokens. TimeFunc: time.Now, } - //调用初始设置函数,必须的。 + // 调用初始设置函数,必须的。 err := authMiddleware.MiddlewareInit() if err != nil { faygo.Error(err) @@ -89,7 +89,7 @@ func main() { r.POST("/login", faygo.HandlerFunc(authMiddleware.LoginHandler)) auth := r.Group("/auth") - //auth.Use(authMiddleware.MiddlewareFunc()) + // auth.Use(authMiddleware.MiddlewareFunc()) { auth.GET("/hello", faygo.HandlerFunc(helloHandler)).Use(authMiddleware.MiddlewareFunc()) auth.GET("/refreshtoken", faygo.HandlerFunc(authMiddleware.RefreshHandler)) diff --git a/ext/otp/doc.go b/ext/otp/doc.go index b791929..a7fd49a 100644 --- a/ext/otp/doc.go +++ b/ext/otp/doc.go @@ -27,7 +27,7 @@ // Authenticator supports using a QR code as an enrollment method: // // import ( -// "github.com/henrylee2cn/faygo/ext/otp/totp" +// "github.com/andeya/faygo/ext/otp/totp" // // "bytes" // "image/png" @@ -57,7 +57,7 @@ // // Validating a TOTP passcode is very easy, just prompt the user for a passcode // and retrieve the associated user's previously stored secret. -// import "github.com/henrylee2cn/faygo/ext/otp/totp" +// import "github.com/andeya/faygo/ext/otp/totp" // // passcode := promptForPasscode() // secret := getSecret("alice@example.com") diff --git a/ext/otp/example/main.go b/ext/otp/example/main.go index e77bde6..4011be5 100644 --- a/ext/otp/example/main.go +++ b/ext/otp/example/main.go @@ -1,8 +1,8 @@ package main import ( - "github.com/henrylee2cn/faygo/ext/otp" - "github.com/henrylee2cn/faygo/ext/otp/totp" + "github.com/andeya/faygo/ext/otp" + "github.com/andeya/faygo/ext/otp/totp" "bufio" "bytes" diff --git a/ext/otp/hotp/hotp.go b/ext/otp/hotp/hotp.go index 5cbddf4..9a2aede 100644 --- a/ext/otp/hotp/hotp.go +++ b/ext/otp/hotp/hotp.go @@ -18,7 +18,7 @@ package hotp import ( - "github.com/henrylee2cn/faygo/ext/otp" + "github.com/andeya/faygo/ext/otp" "crypto/hmac" "crypto/rand" diff --git a/ext/otp/hotp/hotp_test.go b/ext/otp/hotp/hotp_test.go index 655f798..ddea3a9 100644 --- a/ext/otp/hotp/hotp_test.go +++ b/ext/otp/hotp/hotp_test.go @@ -18,7 +18,7 @@ package hotp import ( - "github.com/henrylee2cn/faygo/ext/otp" + "github.com/andeya/faygo/ext/otp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/ext/otp/otp.go b/ext/otp/otp.go index c20910e..292c8ba 100644 --- a/ext/otp/otp.go +++ b/ext/otp/otp.go @@ -18,8 +18,8 @@ package otp import ( - "github.com/henrylee2cn/faygo/ext/barcode" - "github.com/henrylee2cn/faygo/ext/barcode/qr" + "github.com/andeya/faygo/ext/barcode" + "github.com/andeya/faygo/ext/barcode/qr" "crypto/md5" "crypto/sha1" diff --git a/ext/otp/totp/totp.go b/ext/otp/totp/totp.go index 0a2971d..394bf02 100644 --- a/ext/otp/totp/totp.go +++ b/ext/otp/totp/totp.go @@ -18,8 +18,8 @@ package totp import ( - "github.com/henrylee2cn/faygo/ext/otp" - "github.com/henrylee2cn/faygo/ext/otp/hotp" + "github.com/andeya/faygo/ext/otp" + "github.com/andeya/faygo/ext/otp/hotp" "crypto/rand" "encoding/base32" diff --git a/ext/otp/totp/totp_test.go b/ext/otp/totp/totp_test.go index 1aaa534..4880899 100644 --- a/ext/otp/totp/totp_test.go +++ b/ext/otp/totp/totp_test.go @@ -18,7 +18,7 @@ package totp import ( - "github.com/henrylee2cn/faygo/ext/otp" + "github.com/andeya/faygo/ext/otp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/ext/surfer/README.md b/ext/surfer/README.md index 4127152..8eba94b 100644 --- a/ext/surfer/README.md +++ b/ext/surfer/README.md @@ -1,9 +1,9 @@ -# Surfer [![GoDoc](https://godoc.org/github.com/tsuna/gohbase?status.png)](https://godoc.org/github.com/henrylee2cn/surfer) [![GitHub release](https://img.shields.io/github/release/henrylee2cn/surfer.svg)](https://github.com/henrylee2cn/surfer/releases) +# Surfer [![GoDoc](https://godoc.org/github.com/tsuna/gohbase?status.png)](https://godoc.org/github.com/andeya/surfer) [![GitHub release](https://img.shields.io/github/release/andeya/surfer.svg)](https://github.com/andeya/surfer/releases) Package surfer is a high level concurrency http client. It has `surf` and` phantom` download engines, highly simulated browser behavior, the function of analog login and so on. -[简体中文](https://github.com/henrylee2cn/surfer/blob/master/README_ZH.md) +[简体中文](https://github.com/andeya/surfer/blob/master/README_ZH.md) ## Features - Both `surf` and `phantomjs` engines are supported @@ -16,7 +16,7 @@ It has `surf` and` phantom` download engines, highly simulated browser behavior, package main import ( - "github.com/henrylee2cn/surfer" + "github.com/andeya/surfer" "io/ioutil" "log" ) @@ -24,7 +24,7 @@ import ( func main() { // Use surf engine resp, err := surfer.Download(&surfer.Request{ - Url: "http://github.com/henrylee2cn/surfer", + Url: "http://github.com/andeya/surfer", }) if err != nil { log.Fatal(err) @@ -34,7 +34,7 @@ func main() { // Use phantomjs engine resp, err = surfer.Download(&surfer.Request{ - Url: "http://github.com/henrylee2cn", + Url: "http://github.com/andeya", DownloaderID: 1, }) if err != nil { @@ -47,8 +47,8 @@ func main() { surfer.DestroyJsFiles() } ``` -[Full example](https://github.com/henrylee2cn/faygo/raw/master/samples) +[Full example](https://github.com/andeya/faygo/raw/master/samples) ## License -Surfer is under Apache v2 License. See the [LICENSE](https://github.com/henrylee2cn/faygo/raw/master/LICENSE) file for the full license text +Surfer is under Apache v2 License. See the [LICENSE](https://github.com/andeya/faygo/raw/master/LICENSE) file for the full license text diff --git a/ext/surfer/README_ZH.md b/ext/surfer/README_ZH.md index 55e7d62..41f06a9 100644 --- a/ext/surfer/README_ZH.md +++ b/ext/surfer/README_ZH.md @@ -1,9 +1,9 @@ -# surfer [![GoDoc](https://godoc.org/github.com/tsuna/gohbase?status.png)](https://godoc.org/github.com/henrylee2cn/surfer) [![GitHub release](https://img.shields.io/github/release/henrylee2cn/surfer.svg)](https://github.com/henrylee2cn/surfer/releases) +# surfer [![GoDoc](https://godoc.org/github.com/tsuna/gohbase?status.png)](https://godoc.org/github.com/andeya/surfer) [![GitHub release](https://img.shields.io/github/release/andeya/surfer.svg)](https://github.com/andeya/surfer/releases) Surfer 是一款Go语言编写的高并发 web 客户端,拥有surf与phantom两种下载内核,高度模拟浏览器行为,可实现模拟登录等功能。 -高并发爬虫[Pholcus](https://github.com/henrylee2cn/pholcus)的专用下载器。(官方QQ群:Go大数据 42731170,欢迎加入我们的讨论) +高并发爬虫[Pholcus](https://github.com/andeya/pholcus)的专用下载器。(官方QQ群:Go大数据 42731170,欢迎加入我们的讨论) ## 特性 @@ -17,7 +17,7 @@ Surfer 是一款Go语言编写的高并发 web 客户端,拥有surf与phantom package main import ( - "github.com/henrylee2cn/surfer" + "github.com/andeya/surfer" "io/ioutil" "log" ) @@ -25,7 +25,7 @@ import ( func main() { // 默认使用surf内核下载 resp, err := surfer.Download(&surfer.Request{ - Url: "http://github.com/henrylee2cn/surfer", + Url: "http://github.com/andeya/surfer", }) if err != nil { log.Fatal(err) @@ -35,7 +35,7 @@ func main() { // 指定使用phantomjs内核下载 resp, err = surfer.Download(&surfer.Request{ - Url: "http://github.com/henrylee2cn", + Url: "http://github.com/andeya", DownloaderID: 1, }) if err != nil { @@ -49,9 +49,9 @@ func main() { } ``` -[完整示例](https://github.com/henrylee2cn/surfer/blob/master/example/example.go) +[完整示例](https://github.com/andeya/surfer/blob/master/example/example.go) ## 开源协议 -Surfer 项目采用商业应用友好的[Apache License v2](https://github.com/henrylee2cn/surfer/raw/master/LICENSE).发布 +Surfer 项目采用商业应用友好的[Apache License v2](https://github.com/andeya/surfer/raw/master/LICENSE).发布 diff --git a/ext/surfer/agent.go b/ext/surfer/agent.go index 8a16a36..a4ecfb9 100644 --- a/ext/surfer/agent.go +++ b/ext/surfer/agent.go @@ -1,4 +1,4 @@ -// Copyright 2015 henrylee2cn Author. All Rights Reserved. +// Copyright 2015 andeya Author. All Rights Reserved. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/ext/surfer/body.go b/ext/surfer/body.go index 7b2ea06..195661f 100644 --- a/ext/surfer/body.go +++ b/ext/surfer/body.go @@ -1,4 +1,4 @@ -// Copyright 2015 henrylee2cn Author. All Rights Reserved. +// Copyright 2015 andeya Author. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/ext/surfer/example/example.go b/ext/surfer/example/example.go index 41117db..f567f4a 100644 --- a/ext/surfer/example/example.go +++ b/ext/surfer/example/example.go @@ -1,11 +1,12 @@ package main import ( - "github.com/henrylee2cn/faygo/ext/surfer" "io/ioutil" "log" "net/url" "time" + + "github.com/andeya/faygo/ext/surfer" ) func main() { diff --git a/ext/surfer/phantom.go b/ext/surfer/phantom.go index 5200270..7876eb2 100644 --- a/ext/surfer/phantom.go +++ b/ext/surfer/phantom.go @@ -1,4 +1,4 @@ -// Copyright 2015 henrylee2cn Author. All Rights Reserved. +// Copyright 2015 andeya Author. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -32,9 +32,9 @@ type ( // 效率较surfer会慢很多,但是因为模拟浏览器,破防性更好 // 支持UserAgent/TryTimes/RetryPause/自定义js Phantom struct { - PhantomjsFile string //Phantomjs完整文件名 - TempJsDir string //临时js存放目录 - jsFileMap map[string]string //已存在的js文件 + PhantomjsFile string // Phantomjs完整文件名 + TempJsDir string // 临时js存放目录 + jsFileMap map[string]string // 已存在的js文件 } // Response 用于解析Phantomjs的响应内容 Response struct { diff --git a/ext/surfer/request.go b/ext/surfer/request.go index 724c8dd..48c915c 100644 --- a/ext/surfer/request.go +++ b/ext/surfer/request.go @@ -1,4 +1,4 @@ -// Copyright 2015 henrylee2cn Author. All Rights Reserved. +// Copyright 2015 andeya Author. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/ext/surfer/surf.go b/ext/surfer/surf.go index 040145b..d3b3403 100644 --- a/ext/surfer/surf.go +++ b/ext/surfer/surf.go @@ -1,4 +1,4 @@ -// Copyright 2015 henrylee2cn Author. All Rights Reserved. +// Copyright 2015 andeya Author. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/ext/surfer/surfer.go b/ext/surfer/surfer.go index 05372fc..d1949b0 100644 --- a/ext/surfer/surfer.go +++ b/ext/surfer/surfer.go @@ -1,4 +1,4 @@ -// Copyright 2015 henrylee2cn Author. All Rights Reserved. +// Copyright 2015 andeya Author. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ // package main // import ( -// "github.com/henrylee2cn/surfer" +// "github.com/andeya/surfer" // "io/ioutil" // "log" // ) @@ -32,7 +32,7 @@ // func main() { // // Use surf engine // resp, err := surfer.Download(&surfer.Request{ -// Url: "http://github.com/henrylee2cn/surfer", +// Url: "http://github.com/andeya/surfer", // }) // if err != nil { // log.Fatal(err) @@ -42,7 +42,7 @@ // // // Use phantomjs engine // resp, err = surfer.Download(&surfer.Request{ -// Url: "http://github.com/henrylee2cn", +// Url: "http://github.com/andeya", // DownloaderID: 1, // }) // if err != nil { @@ -69,7 +69,7 @@ var ( once_surf sync.Once once_phantom sync.Once tempJsDir = "./tmp" - // phantomjsFile = filepath.Clean(path.Join(os.Getenv("GOPATH"), `/src/github.com/henrylee2cn/surfer/phantomjs/phantomjs`)) + // phantomjsFile = filepath.Clean(path.Join(os.Getenv("GOPATH"), `/src/github.com/andeya/surfer/phantomjs/phantomjs`)) phantomjsFile = `./phantomjs` ) diff --git a/ext/surfer/surfer_test.go b/ext/surfer/surfer_test.go index 0257d1c..eb199e7 100644 --- a/ext/surfer/surfer_test.go +++ b/ext/surfer/surfer_test.go @@ -1,4 +1,4 @@ -// Copyright 2015 henrylee2cn Author. All Rights Reserved. +// Copyright 2015 andeya Author. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/ext/surfer/util.go b/ext/surfer/util.go index 4934b1e..74d9096 100644 --- a/ext/surfer/util.go +++ b/ext/surfer/util.go @@ -1,4 +1,4 @@ -// Copyright 2015 henrylee2cn Author. All Rights Reserved. +// Copyright 2015 andeya Author. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/ext/task/README.md b/ext/task/README.md index bc584fe..f3916f6 100644 --- a/ext/task/README.md +++ b/ext/task/README.md @@ -1,6 +1,6 @@ # Task -[![GoDoc](http://godoc.org/github.com/henrylee2cn/faygo/ext/task?status.svg)](http://godoc.org/github.com/henrylee2cn/faygo/ext/task) +[![GoDoc](http://godoc.org/github.com/andeya/faygo/ext/task?status.svg)](http://godoc.org/github.com/andeya/faygo/ext/task) Task是一个非常易用的定时任务管理工具(移植自beego框架)。 diff --git a/ext/websocket/helper.go b/ext/websocket/helper.go index 21d3568..a6c348f 100644 --- a/ext/websocket/helper.go +++ b/ext/websocket/helper.go @@ -1,8 +1,9 @@ package websocket import ( - "github.com/henrylee2cn/faygo" "net/http" + + "github.com/andeya/faygo" ) // FayUpgrade upgrades the faygo server connection to the WebSocket protocol. diff --git a/faygo.go b/faygo.go index b9ae7bf..1fec76a 100644 --- a/faygo.go +++ b/faygo.go @@ -26,9 +26,9 @@ import ( "sync/atomic" "time" - "github.com/henrylee2cn/faygo/acceptencoder" - "github.com/henrylee2cn/faygo/apiware" - "github.com/henrylee2cn/faygo/logging" + "github.com/andeya/faygo/acceptencoder" + "github.com/andeya/faygo/apiware" + "github.com/andeya/faygo/logging" ) const ( @@ -43,7 +43,7 @@ const ( | | \/ /\ \/ / |/ / |/ / / / \_/\\ \ / \_ / \__/ / / / / _\ \ - \_/ \_/ \_\_/ VERSION ` + VERSION + " URL https://github.com/henrylee2cn/faygo\n" + \_/ \_/ \_\_/ VERSION ` + VERSION + " URL https://github.com/andeya/faygo\n" ) // New uses the faygo web framework to create a new application. diff --git a/framework.go b/framework.go index 0c04552..7bf6b72 100644 --- a/framework.go +++ b/framework.go @@ -25,10 +25,10 @@ import ( "sync/atomic" "time" - "github.com/henrylee2cn/faygo/logging" - "github.com/henrylee2cn/faygo/logging/color" - "github.com/henrylee2cn/faygo/session" - "github.com/henrylee2cn/faygo/swagger" + "github.com/andeya/faygo/logging" + "github.com/andeya/faygo/logging/color" + "github.com/andeya/faygo/session" + "github.com/andeya/faygo/swagger" ) // Framework is the faygo web framework. @@ -694,7 +694,7 @@ func panicHandler(ctx *Context, rcv interface{}) { s := []byte("/src/runtime/panic.go") e := []byte("\ngoroutine ") line := []byte("\n") - stack := make([]byte, 4<<10) //4KB + stack := make([]byte, 4<<10) // 4KB length := runtime.Stack(stack, true) start := bytes.Index(stack, s) stack = stack[start:length] diff --git a/freecache/cache.go b/freecache/cache.go index 4caec8a..5e241eb 100644 --- a/freecache/cache.go +++ b/freecache/cache.go @@ -5,7 +5,7 @@ import ( "sync" "sync/atomic" - "github.com/henrylee2cn/faygo/freecache/murmur3" + "github.com/andeya/faygo/freecache/murmur3" ) type Cache struct { diff --git a/freecache/server/main.go b/freecache/server/main.go index 159901a..5fb59ce 100644 --- a/freecache/server/main.go +++ b/freecache/server/main.go @@ -1,4 +1,4 @@ -//A basic freecache server supports redis protocol +// A basic freecache server supports redis protocol package main import ( @@ -15,7 +15,7 @@ import ( "strconv" "time" - "github.com/henrylee2cn/faygo/freecache" + "github.com/andeya/faygo/freecache" ) var ( diff --git a/fs.go b/fs.go index d283649..17ced19 100644 --- a/fs.go +++ b/fs.go @@ -36,9 +36,9 @@ import ( "sync" "time" - "github.com/henrylee2cn/faygo/acceptencoder" - "github.com/henrylee2cn/faygo/freecache" - "github.com/henrylee2cn/faygo/markdown" + "github.com/andeya/faygo/acceptencoder" + "github.com/andeya/faygo/freecache" + "github.com/andeya/faygo/markdown" ) const indexPage = "/index.html" diff --git a/go.mod b/go.mod index 2be64ca..e498dfd 100644 --- a/go.mod +++ b/go.mod @@ -1,48 +1,61 @@ -// Deprecated: Use the "github.com/andeya/faygo" module instead. -module github.com/henrylee2cn/faygo +module github.com/andeya/faygo require ( + github.com/andeya/goutil v0.0.0-20220626152529-9b7868da7b6d + github.com/andeya/ini v1.30.0 github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 github.com/couchbase/go-couchbase v0.0.0-20190808141609-0a5dfbe71f2f - github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d // indirect - github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b // indirect - github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76 // indirect - github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect - github.com/edsrzf/mmap-go v1.0.0 // indirect github.com/elazarl/go-bindata-assetfs v1.0.0 - github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 + github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9 - github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect - github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4 github.com/fsnotify/fsnotify v1.4.7 github.com/garyburd/redigo v1.6.0 github.com/go-sql-driver/mysql v1.4.1 - github.com/golang/protobuf v1.3.1 // indirect - github.com/gorilla/websocket v1.4.0 - github.com/henrylee2cn/goutil v0.0.0-20190807075143-e8afa09140e9 - github.com/henrylee2cn/ini v1.29.0 + github.com/gorilla/websocket v1.5.0 github.com/jinzhu/gorm v1.9.10 github.com/jmoiron/sqlx v1.2.0 github.com/json-iterator/go v1.1.7 github.com/lib/pq v1.2.0 - github.com/pelletier/go-toml v1.4.0 // indirect - github.com/pkg/errors v0.8.1 // indirect - github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92 - github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d // indirect - github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec - github.com/stretchr/testify v1.4.0 - github.com/syndtr/goleveldb v1.0.0 // indirect - golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 - golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 - golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa - golang.org/x/text v0.3.2 // indirect + github.com/stretchr/testify v1.7.5 + golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d + golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e + golang.org/x/sys v0.0.0-20220624220833-87e55d714810 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 gopkg.in/dgrijalva/jwt-go.v3 v3.2.0 xorm.io/core v0.7.2 xorm.io/xorm v0.8.0 ) -go 1.13 +require ( + github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d // indirect + github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b // indirect + github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect + github.com/edsrzf/mmap-go v1.0.0 // indirect + github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect + github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect + github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect + github.com/henrylee2cn/ameda v1.4.10 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 // indirect + github.com/kr/pretty v0.1.0 // indirect + github.com/kr/text v0.1.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect + github.com/pelletier/go-toml v1.4.0 // indirect + github.com/pkg/errors v0.8.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect + github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d // indirect + github.com/syndtr/goleveldb v1.0.0 // indirect + golang.org/x/text v0.3.7 // indirect + google.golang.org/appengine v1.6.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + xorm.io/builder v0.3.6 // indirect +) + +go 1.18 diff --git a/go.sum b/go.sum index 2c2f3e4..b599eb6 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,10 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andeya/goutil v0.0.0-20220626152529-9b7868da7b6d h1:SFmlknB2bt6VEND93Uu55IP1HK5CXEk0sTUtxdr+CJQ= +github.com/andeya/goutil v0.0.0-20220626152529-9b7868da7b6d/go.mod h1:29HngAq7SN4CEJuycvNReDnCGYgCUzB9JzrFTj/u0xg= +github.com/andeya/ini v1.30.0 h1:7Pm5gksVuEa3dZJ5xDizxfSbm/Ju+esfZ/MYykZdp8Y= +github.com/andeya/ini v1.30.0/go.mod h1:mAFUS5iFmGTan8OWeyOS5ql+2kaN5YcDgJS0OX2XQ3g= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA= @@ -38,8 +42,8 @@ github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3C github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= -github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= -github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= +github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= +github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9 h1:wWke/RUCl7VRjQhwPlR/v0glZXNYzBHdNUzf/Am2Nmg= github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9/go.mod h1:uPmAp6Sws4L7+Q/OokbWDAK1ibXYhB3PXFP1kol5hPg= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= @@ -68,28 +72,22 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/henrylee2cn/goutil v0.0.0-20190807075143-e8afa09140e9 h1:a2H8nokxD0y7RtMAD0c0iyRjIc6PPBopF2/8zw5kFiE= -github.com/henrylee2cn/goutil v0.0.0-20190807075143-e8afa09140e9/go.mod h1:I9qYeMYwdKC7UFXMECNzCEv0fYuolqLeBMqsmeG7IVo= -github.com/henrylee2cn/ini v1.29.0 h1:qlvyhAtpeRDG7qlBEdCQFzElyBjCgAFJSxEVnFFEgHc= -github.com/henrylee2cn/ini v1.29.0/go.mod h1:ucAh/Gt/gt+AIbD75B7tfRz4w9QzAHlmvDzXrWGonYE= +github.com/henrylee2cn/ameda v1.4.10 h1:JdvI2Ekq7tapdPsuhrc4CaFiqw6QXFvZIULWJgQyCAk= +github.com/henrylee2cn/ameda v1.4.10/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jinzhu/gorm v1.9.10 h1:HvrsqdhCW78xpJF67g1hMxS6eCToo9PZH4LDB8WKPac= @@ -104,7 +102,6 @@ github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62F github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 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/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 h1:rhqTjzJlm7EbkELJDKMTU7udov+Se0xZkWmugr6zGok= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20180524022052-584905176618 h1:MK144iBQF9hTSwBW/9eJm034bVoG30IshVm688T2hi8= @@ -163,19 +160,19 @@ github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1Dp github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d h1:NVwnfyR3rENtlz62bcrkXME3INVUa4lcdGt+opvxExs= github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -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/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/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec h1:q6XVwXmKvCRHRqesF3cSv6lNqqHi0QWOvgDlSohg8UA= github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q= +github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= @@ -184,8 +181,8 @@ go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -198,9 +195,8 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -213,21 +209,18 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M= -golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810 h1:rHZQSjJdAI4Xf5Qzeh2bBc5YJIkPFVM6oDtMFYmgws0= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -253,6 +246,9 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/handler.go b/handler.go index aca3457..c14d5cb 100644 --- a/handler.go +++ b/handler.go @@ -19,7 +19,7 @@ import ( "reflect" "sort" - "github.com/henrylee2cn/faygo/apiware" + "github.com/andeya/faygo/apiware" ) type ( diff --git a/helper.go b/helper.go index 1cae432..49f3982 100644 --- a/helper.go +++ b/helper.go @@ -24,10 +24,10 @@ import ( "reflect" "strings" - "github.com/henrylee2cn/ini" + "github.com/andeya/ini" - "github.com/henrylee2cn/goutil" - "github.com/henrylee2cn/goutil/errors" + "github.com/andeya/goutil" + "github.com/andeya/goutil/errors" ) // JoinStatic adds the static directory prefix to the file name. diff --git a/log.go b/log.go index d456b86..d0deff4 100644 --- a/log.go +++ b/log.go @@ -19,8 +19,8 @@ import ( "os" "strings" - "github.com/henrylee2cn/faygo/logging" - "github.com/henrylee2cn/faygo/logging/color" + "github.com/andeya/faygo/logging" + "github.com/andeya/faygo/logging/color" ) // NewLog gets a global logger diff --git a/log/app.pid b/log/app.pid new file mode 100644 index 0000000..4da934e --- /dev/null +++ b/log/app.pid @@ -0,0 +1 @@ +22132 diff --git a/logging/examples/example.go b/logging/examples/example.go index 8ae9abc..5e1face 100644 --- a/logging/examples/example.go +++ b/logging/examples/example.go @@ -3,7 +3,7 @@ package main import ( "os" - "github.com/henrylee2cn/faygo/logging" + "github.com/andeya/faygo/logging" ) var log = logging.NewLogger("example") diff --git a/render_pongo2.go b/render_pongo2.go index dbeff8c..099ee16 100644 --- a/render_pongo2.go +++ b/render_pongo2.go @@ -9,7 +9,7 @@ import ( "sync" "time" - "github.com/henrylee2cn/faygo/pongo2" + "github.com/andeya/faygo/pongo2" ) type ( diff --git a/samples/MultiUsage/main.go b/samples/MultiUsage/main.go index 71261e0..f93b5d5 100644 --- a/samples/MultiUsage/main.go +++ b/samples/MultiUsage/main.go @@ -1,9 +1,10 @@ package main import ( - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/ext/db/xorm" "mime/multipart" + + "github.com/andeya/faygo" + "github.com/andeya/faygo/ext/db/xorm" ) // MultiUsage multi usage handler diff --git a/samples/demo/handler/body.go b/samples/demo/handler/body.go index a4266d5..3c4fe4d 100644 --- a/samples/demo/handler/body.go +++ b/samples/demo/handler/body.go @@ -1,7 +1,7 @@ package handler import ( - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) type Body struct { diff --git a/samples/demo/handler/param.go b/samples/demo/handler/param.go index 38ff4a0..bb1c5a3 100644 --- a/samples/demo/handler/param.go +++ b/samples/demo/handler/param.go @@ -5,7 +5,7 @@ import ( "net/http" "sync" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) type Param struct { diff --git a/samples/demo/handler/proxy.go b/samples/demo/handler/proxy.go index df0effc..c57e075 100644 --- a/samples/demo/handler/proxy.go +++ b/samples/demo/handler/proxy.go @@ -1,7 +1,7 @@ package handler import ( - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) type Search int diff --git a/samples/demo/handler/render.go b/samples/demo/handler/render.go index 5967cc7..339f2c6 100644 --- a/samples/demo/handler/render.go +++ b/samples/demo/handler/render.go @@ -1,7 +1,7 @@ package handler import ( - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" // "time" ) diff --git a/samples/demo/handler/websocket.go b/samples/demo/handler/websocket.go index 98087ec..9b22cb0 100644 --- a/samples/demo/handler/websocket.go +++ b/samples/demo/handler/websocket.go @@ -3,8 +3,8 @@ package handler import ( "time" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/ext/websocket" + "github.com/andeya/faygo" + "github.com/andeya/faygo/ext/websocket" ) func WebsocketPage() faygo.HandlerFunc { diff --git a/samples/demo/main.go b/samples/demo/main.go index f2dcead..463635f 100644 --- a/samples/demo/main.go +++ b/samples/demo/main.go @@ -5,8 +5,8 @@ import ( _ "net/http/pprof" "time" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/samples/demo/router" + "github.com/andeya/faygo" + "github.com/andeya/faygo/samples/demo/router" ) // Browse 'http://localhost:8080/apidoc' and 'http://localhost:8081/apidoc' to test. diff --git a/samples/demo/middleware/index.go b/samples/demo/middleware/index.go index bfdd4ac..9622b9b 100644 --- a/samples/demo/middleware/index.go +++ b/samples/demo/middleware/index.go @@ -3,7 +3,7 @@ package middleware import ( // "net/http" - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) func Root2Index(ctx *faygo.Context) error { diff --git a/samples/demo/router/router.go b/samples/demo/router/router.go index 1e01b58..85fa7dd 100644 --- a/samples/demo/router/router.go +++ b/samples/demo/router/router.go @@ -1,10 +1,10 @@ package router import ( - "github.com/henrylee2cn/faygo" - mw "github.com/henrylee2cn/faygo/ext/middleware" - "github.com/henrylee2cn/faygo/samples/demo/handler" - "github.com/henrylee2cn/faygo/samples/demo/middleware" + "github.com/andeya/faygo" + mw "github.com/andeya/faygo/ext/middleware" + "github.com/andeya/faygo/samples/demo/handler" + "github.com/andeya/faygo/samples/demo/middleware" ) // Register the route in a tree style diff --git a/samples/demo/static/markdown/README.md b/samples/demo/static/markdown/README.md index ad3af83..34d094e 100644 --- a/samples/demo/static/markdown/README.md +++ b/samples/demo/static/markdown/README.md @@ -1,16 +1,16 @@ -# Faygo [![GoDoc](https://godoc.org/github.com/tsuna/gohbase?status.png)](https://godoc.org/github.com/henrylee2cn/faygo) +# Faygo [![GoDoc](https://godoc.org/github.com/tsuna/gohbase?status.png)](https://godoc.org/github.com/andeya/faygo) -![Lessgo Favicon](https://github.com/henrylee2cn/faygo/raw/master/doc/faygo_96x96.png) +![Lessgo Favicon](https://github.com/andeya/faygo/raw/master/doc/faygo_96x96.png) Faygo is a Golang Web framework that handler is middleware, supports intelligent parameter mapping and validation, and automates API documentation. -[简体中文](https://github.com/henrylee2cn/faygo/blob/master/README_ZH.md) +[简体中文](https://github.com/andeya/faygo/blob/master/README_ZH.md) -![faygo server](https://github.com/henrylee2cn/faygo/raw/master/doc/server.png) +![faygo server](https://github.com/andeya/faygo/raw/master/doc/server.png) -![faygo apidoc](https://github.com/henrylee2cn/faygo/raw/master/doc/apidoc.png) +![faygo apidoc](https://github.com/andeya/faygo/raw/master/doc/apidoc.png) -![faygo index](https://github.com/henrylee2cn/faygo/raw/master/doc/index.png) +![faygo index](https://github.com/andeya/faygo/raw/master/doc/index.png) ## Quick Start @@ -21,7 +21,7 @@ Go Version ≥1.6 ### Download and install ```sh -go get -u -v github.com/henrylee2cn/faygo +go get -u -v github.com/andeya/faygo ``` ### Simple example @@ -29,7 +29,7 @@ go get -u -v github.com/henrylee2cn/faygo package main import ( - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" "time" ) @@ -78,7 +78,7 @@ response: } */ ``` -[Full example](https://github.com/henrylee2cn/faygo/raw/master/demo) +[Full example](https://github.com/andeya/faygo/raw/master/demo) ## Features @@ -221,17 +221,17 @@ float32 | []float32 | float64 | []float64 | # Expansion package -- [barcode](https://github.com/henrylee2cn/faygo/raw/master/ext/barcode): `github.com/henrylee2cn/faygo/ext/barcode` -- [Bit unit conversion](https://github.com/henrylee2cn/faygo/raw/master/ext/bitconv): `github.com/henrylee2cn/faygo/ext/bitconv` -- [timer](https://github.com/henrylee2cn/faygo/raw/master/ext/cron): `github.com/henrylee2cn/faygo/ext/cron` -- [gorm(DB ORM)](https://github.com/henrylee2cn/faygo/raw/master/ext/db/gorm): `github.com/henrylee2cn/faygo/ext/db/gorm` -- [sqlx(DB ext)](https://github.com/henrylee2cn/faygo/raw/master/ext/db/sqlx): `github.com/henrylee2cn/faygo/ext/db/sqlx` -- [xorm(DB ORM)](https://github.com/henrylee2cn/faygo/raw/master/ext/db/xorm): `github.com/henrylee2cn/faygo/ext/db/xorm` -- [One-time Password](https://github.com/henrylee2cn/faygo/raw/master/ext/otp): `github.com/henrylee2cn/faygo/ext/otp` -- [UUID](https://github.com/henrylee2cn/faygo/raw/master/ext/uuid): `github.com/henrylee2cn/faygo/ext/uuid` -- [Websocket](https://github.com/henrylee2cn/faygo/raw/master/ext/websocket): `github.com/henrylee2cn/faygo/ext/websocket` -- [ini](https://github.com/henrylee2cn/faygo/raw/master/ini): `github.com/henrylee2cn/faygo/ini` +- [barcode](https://github.com/andeya/faygo/raw/master/ext/barcode): `github.com/andeya/faygo/ext/barcode` +- [Bit unit conversion](https://github.com/andeya/faygo/raw/master/ext/bitconv): `github.com/andeya/faygo/ext/bitconv` +- [timer](https://github.com/andeya/faygo/raw/master/ext/cron): `github.com/andeya/faygo/ext/cron` +- [gorm(DB ORM)](https://github.com/andeya/faygo/raw/master/ext/db/gorm): `github.com/andeya/faygo/ext/db/gorm` +- [sqlx(DB ext)](https://github.com/andeya/faygo/raw/master/ext/db/sqlx): `github.com/andeya/faygo/ext/db/sqlx` +- [xorm(DB ORM)](https://github.com/andeya/faygo/raw/master/ext/db/xorm): `github.com/andeya/faygo/ext/db/xorm` +- [One-time Password](https://github.com/andeya/faygo/raw/master/ext/otp): `github.com/andeya/faygo/ext/otp` +- [UUID](https://github.com/andeya/faygo/raw/master/ext/uuid): `github.com/andeya/faygo/ext/uuid` +- [Websocket](https://github.com/andeya/faygo/raw/master/ext/websocket): `github.com/andeya/faygo/ext/websocket` +- [ini](https://github.com/andeya/faygo/raw/master/ini): `github.com/andeya/faygo/ini` # License -Faygo is under Apache v2 License. See the [LICENSE](https://github.com/henrylee2cn/faygo/raw/master/LICENSE) file for the full license text +Faygo is under Apache v2 License. See the [LICENSE](https://github.com/andeya/faygo/raw/master/LICENSE) file for the full license text diff --git a/samples/demo/static/markdown/README.txt b/samples/demo/static/markdown/README.txt index ef13637..20c718a 100644 --- a/samples/demo/static/markdown/README.txt +++ b/samples/demo/static/markdown/README.txt @@ -1,16 +1,16 @@ -# Faygo [![GoDoc](https://godoc.org/github.com/tsuna/gohbase?status.png)](https://godoc.org/github.com/henrylee2cn/faygo) +# Faygo [![GoDoc](https://godoc.org/github.com/tsuna/gohbase?status.png)](https://godoc.org/github.com/andeya/faygo) -![Lessgo Favicon](https://github.com/henrylee2cn/faygo/raw/master/doc/faygo_96x96.png) +![Lessgo Favicon](https://github.com/andeya/faygo/raw/master/doc/faygo_96x96.png) Faygo is a Golang Web framework that handler is middleware, supports intelligent parameter mapping and validation, and automates API documentation. -[简体中文](https://github.com/henrylee2cn/faygo/blob/master/README_ZH.md) +[简体中文](https://github.com/andeya/faygo/blob/master/README_ZH.md) -![faygo server](https://github.com/henrylee2cn/faygo/raw/master/doc/server.png) +![faygo server](https://github.com/andeya/faygo/raw/master/doc/server.png) -![faygo apidoc](https://github.com/henrylee2cn/faygo/raw/master/doc/apidoc.png) +![faygo apidoc](https://github.com/andeya/faygo/raw/master/doc/apidoc.png) -![faygo index](https://github.com/henrylee2cn/faygo/raw/master/doc/index.png) +![faygo index](https://github.com/andeya/faygo/raw/master/doc/index.png) ## Quick Start @@ -21,7 +21,7 @@ Go Version ≥1.6 ### Download and install ```sh -go get -u -v github.com/henrylee2cn/faygo +go get -u -v github.com/andeya/faygo ``` ### Simple example @@ -29,7 +29,7 @@ go get -u -v github.com/henrylee2cn/faygo package main import ( - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" "time" ) @@ -78,7 +78,7 @@ response: } */ ``` -[Full example](https://github.com/henrylee2cn/faygo/raw/master/demo) +[Full example](https://github.com/andeya/faygo/raw/master/demo) ## Features @@ -221,17 +221,17 @@ float32 | []float32 | float64 | []float64 | # Expansion package -- [barcode](https://github.com/henrylee2cn/faygo/raw/master/ext/barcode): `github.com/henrylee2cn/faygo/ext/barcode` -- [Bit unit conversion](https://github.com/henrylee2cn/faygo/raw/master/ext/bitconv): `github.com/henrylee2cn/faygo/ext/bitconv` -- [timer](https://github.com/henrylee2cn/faygo/raw/master/ext/cron): `github.com/henrylee2cn/faygo/ext/cron` -- [gorm(DB ORM)](https://github.com/henrylee2cn/faygo/raw/master/ext/db/gorm): `github.com/henrylee2cn/faygo/ext/db/gorm` -- [sqlx(DB ext)](https://github.com/henrylee2cn/faygo/raw/master/ext/db/sqlx): `github.com/henrylee2cn/faygo/ext/db/sqlx` -- [xorm(DB ORM)](https://github.com/henrylee2cn/faygo/raw/master/ext/db/xorm): `github.com/henrylee2cn/faygo/ext/db/xorm` -- [One-time Password](https://github.com/henrylee2cn/faygo/raw/master/ext/otp): `github.com/henrylee2cn/faygo/ext/otp` -- [UUID](https://github.com/henrylee2cn/faygo/raw/master/ext/uuid): `github.com/henrylee2cn/faygo/ext/uuid` -- [Websocket](https://github.com/henrylee2cn/faygo/raw/master/ext/websocket): `github.com/henrylee2cn/faygo/ext/websocket` -- [ini](https://github.com/henrylee2cn/faygo/raw/master/ini): `github.com/henrylee2cn/faygo/ini` +- [barcode](https://github.com/andeya/faygo/raw/master/ext/barcode): `github.com/andeya/faygo/ext/barcode` +- [Bit unit conversion](https://github.com/andeya/faygo/raw/master/ext/bitconv): `github.com/andeya/faygo/ext/bitconv` +- [timer](https://github.com/andeya/faygo/raw/master/ext/cron): `github.com/andeya/faygo/ext/cron` +- [gorm(DB ORM)](https://github.com/andeya/faygo/raw/master/ext/db/gorm): `github.com/andeya/faygo/ext/db/gorm` +- [sqlx(DB ext)](https://github.com/andeya/faygo/raw/master/ext/db/sqlx): `github.com/andeya/faygo/ext/db/sqlx` +- [xorm(DB ORM)](https://github.com/andeya/faygo/raw/master/ext/db/xorm): `github.com/andeya/faygo/ext/db/xorm` +- [One-time Password](https://github.com/andeya/faygo/raw/master/ext/otp): `github.com/andeya/faygo/ext/otp` +- [UUID](https://github.com/andeya/faygo/raw/master/ext/uuid): `github.com/andeya/faygo/ext/uuid` +- [Websocket](https://github.com/andeya/faygo/raw/master/ext/websocket): `github.com/andeya/faygo/ext/websocket` +- [ini](https://github.com/andeya/faygo/raw/master/ini): `github.com/andeya/faygo/ini` # License -Faygo is under Apache v2 License. See the [LICENSE](https://github.com/henrylee2cn/faygo/raw/master/LICENSE) file for the full license text. \ No newline at end of file +Faygo is under Apache v2 License. See the [LICENSE](https://github.com/andeya/faygo/raw/master/LICENSE) file for the full license text. \ No newline at end of file diff --git a/samples/directsql/common/pongo2func.go b/samples/directsql/common/pongo2func.go index 26effc5..bdb8fd3 100644 --- a/samples/directsql/common/pongo2func.go +++ b/samples/directsql/common/pongo2func.go @@ -9,9 +9,9 @@ import ( "encoding/json" "strings" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/ext/db/directsql" - "github.com/henrylee2cn/faygo/pongo2" + "github.com/andeya/faygo" + "github.com/andeya/faygo/ext/db/directsql" + "github.com/andeya/faygo/pongo2" ) /* tpl @@ -20,17 +20,17 @@ import ( {% endfor %} */ -//单个查询 参数 map[string]interface{} 返回 []map[string]interface{} +// 单个查询 参数 map[string]interface{} 返回 []map[string]interface{} func SimpleData(modelId, sqlId string, mp string) *pongo2.Value { - //参数处理 - //faygo.Debug("SimpleData mp:", mp) + // 参数处理 + // faygo.Debug("SimpleData mp:", mp) para := make(map[string]interface{}) if err := json.Unmarshal([]byte(strings.Replace(mp, "`", `"`, -1)), ¶); err != nil { faygo.Error(err.Error()) return pongo2.AsValue(err.Error()) } faygo.Debug("SimpleData para:", para) - //执行sql获取结果 + // 执行sql获取结果 result, err := directsql.SelectMapToMap(modelId, sqlId, para) if err != nil { faygo.Error(err.Error()) @@ -40,22 +40,22 @@ func SimpleData(modelId, sqlId string, mp string) *pongo2.Value { return pongo2.AsValue(result) } -//单个查询 参数 map[string]interface{} 返回 []map[string]interface{} +// 单个查询 参数 map[string]interface{} 返回 []map[string]interface{} func SimpleData2(modelId, sqlId string, mp string) []map[string]interface{} { - //参数处理 - //faygo.Debug("SimpleData mp:", mp) + // 参数处理 + // faygo.Debug("SimpleData mp:", mp) result := make([]map[string]interface{}, 0) para := make(map[string]interface{}) if err := json.Unmarshal([]byte(strings.Replace(mp, "`", `"`, -1)), ¶); err != nil { faygo.Error(err.Error()) - //result=append(result,err) + // result=append(result,err) } faygo.Debug("SimpleData para:", para) - //执行sql获取结果 + // 执行sql获取结果 result, err := directsql.SelectMapToMap(modelId, sqlId, para) if err != nil { faygo.Error(err.Error()) - //result=append(result,err.Error()) + // result=append(result,err.Error()) } faygo.Debug("SimpleData result :", result) return result @@ -71,7 +71,7 @@ func Test(str1, str2, str3 string) string { func init() { // 测试函数 faygo.RenderVar("Test", Test) - //获取单表数据 返回 []map[string]interface{} + // 获取单表数据 返回 []map[string]interface{} faygo.RenderVar("SimpleData", SimpleData) faygo.RenderVar("SimpleData2", SimpleData2) } diff --git a/samples/directsql/handler/index.go b/samples/directsql/handler/index.go index 4c1d3e4..43f80e3 100644 --- a/samples/directsql/handler/index.go +++ b/samples/directsql/handler/index.go @@ -9,7 +9,7 @@ package handler import ( - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) func Index() faygo.HandlerFunc { diff --git a/samples/directsql/main.go b/samples/directsql/main.go index 98ea057..378e883 100644 --- a/samples/directsql/main.go +++ b/samples/directsql/main.go @@ -1,10 +1,10 @@ package main import ( - _ "github.com/go-sql-driver/mysql" //mysql driver - "github.com/henrylee2cn/faygo" - _ "github.com/henrylee2cn/faygo/samples/directsql/common" - "github.com/henrylee2cn/faygo/samples/directsql/router" + "github.com/andeya/faygo" + _ "github.com/andeya/faygo/samples/directsql/common" + "github.com/andeya/faygo/samples/directsql/router" + _ "github.com/go-sql-driver/mysql" // mysql driver ) func main() { diff --git a/samples/directsql/router/router.go b/samples/directsql/router/router.go index 81be164..fe08481 100644 --- a/samples/directsql/router/router.go +++ b/samples/directsql/router/router.go @@ -8,9 +8,9 @@ package router import ( - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/ext/db/directsql" - "github.com/henrylee2cn/faygo/samples/directsql/handler" + "github.com/andeya/faygo" + "github.com/andeya/faygo/ext/db/directsql" + "github.com/andeya/faygo/samples/directsql/handler" ) // Register the system router in a chain style diff --git a/samples/directsqlx/common/pongo2func.go b/samples/directsqlx/common/pongo2func.go index dc12b61..24a741a 100644 --- a/samples/directsqlx/common/pongo2func.go +++ b/samples/directsqlx/common/pongo2func.go @@ -10,9 +10,9 @@ import ( json "github.com/json-iterator/go" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/ext/db/directsqlx" - "github.com/henrylee2cn/faygo/pongo2" + "github.com/andeya/faygo" + "github.com/andeya/faygo/ext/db/directsqlx" + "github.com/andeya/faygo/pongo2" ) /* tpl @@ -21,17 +21,17 @@ import ( {% endfor %} */ -//单个查询 参数 map[string]interface{} 返回 []map[string]interface{} +// 单个查询 参数 map[string]interface{} 返回 []map[string]interface{} func SimpleData(modelId, sqlId string, mp string) *pongo2.Value { - //参数处理 - //faygo.Debug("SimpleData mp:", mp) + // 参数处理 + // faygo.Debug("SimpleData mp:", mp) para := make(map[string]interface{}) if err := json.Unmarshal([]byte(strings.Replace(mp, "`", `"`, -1)), ¶); err != nil { faygo.Error(err.Error()) return pongo2.AsValue(err.Error()) } faygo.Debug("SimpleData para:", para) - //执行sql获取结果 + // 执行sql获取结果 result, err := directsqlx.SelectMapToMap(modelId, sqlId, para) if err != nil { faygo.Error(err.Error()) @@ -41,22 +41,22 @@ func SimpleData(modelId, sqlId string, mp string) *pongo2.Value { return pongo2.AsValue(result) } -//单个查询 参数 map[string]interface{} 返回 []map[string]interface{} +// 单个查询 参数 map[string]interface{} 返回 []map[string]interface{} func SimpleData2(modelId, sqlId string, mp string) []map[string]interface{} { - //参数处理 - //faygo.Debug("SimpleData mp:", mp) + // 参数处理 + // faygo.Debug("SimpleData mp:", mp) result := make([]map[string]interface{}, 0) para := make(map[string]interface{}) if err := json.Unmarshal([]byte(strings.Replace(mp, "`", `"`, -1)), ¶); err != nil { faygo.Error(err.Error()) - //result=append(result,err) + // result=append(result,err) } faygo.Debug("SimpleData para:", para) - //执行sql获取结果 + // 执行sql获取结果 result, err := directsqlx.SelectMapToMap(modelId, sqlId, para) if err != nil { faygo.Error(err.Error()) - //result=append(result,err.Error()) + // result=append(result,err.Error()) } faygo.Debug("SimpleData result :", result) return result @@ -72,7 +72,7 @@ func Test(str1, str2, str3 string) string { func init() { // 测试函数 faygo.RenderVar("Test", Test) - //获取单表数据 返回 []map[string]interface{} + // 获取单表数据 返回 []map[string]interface{} faygo.RenderVar("SimpleData", SimpleData) faygo.RenderVar("SimpleData2", SimpleData2) } diff --git a/samples/directsqlx/handler/index.go b/samples/directsqlx/handler/index.go index 4c1d3e4..43f80e3 100644 --- a/samples/directsqlx/handler/index.go +++ b/samples/directsqlx/handler/index.go @@ -9,7 +9,7 @@ package handler import ( - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) func Index() faygo.HandlerFunc { diff --git a/samples/directsqlx/main.go b/samples/directsqlx/main.go index 83893e0..72d3373 100644 --- a/samples/directsqlx/main.go +++ b/samples/directsqlx/main.go @@ -1,10 +1,10 @@ package main import ( - _ "github.com/go-sql-driver/mysql" //mysql driver - "github.com/henrylee2cn/faygo" - _ "github.com/henrylee2cn/faygo/samples/directsqlx/common" - "github.com/henrylee2cn/faygo/samples/directsqlx/router" + "github.com/andeya/faygo" + _ "github.com/andeya/faygo/samples/directsqlx/common" + "github.com/andeya/faygo/samples/directsqlx/router" + _ "github.com/go-sql-driver/mysql" // mysql driver ) func main() { diff --git a/samples/directsqlx/router/router.go b/samples/directsqlx/router/router.go index a077790..79269c4 100644 --- a/samples/directsqlx/router/router.go +++ b/samples/directsqlx/router/router.go @@ -8,9 +8,9 @@ package router import ( - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/ext/db/directsqlx" - "github.com/henrylee2cn/faygo/samples/directsql/handler" + "github.com/andeya/faygo" + "github.com/andeya/faygo/ext/db/directsql" + "github.com/andeya/faygo/samples/directsql/handler" ) // Register the system router in a chain style diff --git a/samples/myconfig/main.go b/samples/myconfig/main.go index 290de0d..40217b4 100644 --- a/samples/myconfig/main.go +++ b/samples/myconfig/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/henrylee2cn/faygo" + "github.com/andeya/faygo" ) func main() { diff --git a/server.go b/server.go index f3f33b4..7b87582 100644 --- a/server.go +++ b/server.go @@ -22,8 +22,8 @@ import ( "strings" "time" - "github.com/henrylee2cn/faygo/gracenet" - "github.com/henrylee2cn/faygo/logging" + "github.com/andeya/faygo/gracenet" + "github.com/andeya/faygo/logging" "golang.org/x/crypto/acme/autocert" ) diff --git a/session/README.md b/session/README.md index 5a95edd..4c57c38 100644 --- a/session/README.md +++ b/session/README.md @@ -18,7 +18,7 @@ As of now this session manager support memory, file, Redis and MySQL. First you must import it import ( - "github.com/henrylee2cn/faygo/session" + "github.com/andeya/faygo/session" ) Then in you web app init the global session manager diff --git a/session/couchbase/sess_couchbase.go b/session/couchbase/sess_couchbase.go index 50c9381..d47e33f 100644 --- a/session/couchbase/sess_couchbase.go +++ b/session/couchbase/sess_couchbase.go @@ -39,8 +39,8 @@ import ( couchbase "github.com/couchbase/go-couchbase" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/session" + "github.com/andeya/faygo" + "github.com/andeya/faygo/session" ) var couchbpder = &Provider{} diff --git a/session/ledis/ledis_session.go b/session/ledis/ledis_session.go index 018887a..12d53d3 100644 --- a/session/ledis/ledis_session.go +++ b/session/ledis/ledis_session.go @@ -10,8 +10,8 @@ import ( "github.com/siddontang/ledisdb/config" "github.com/siddontang/ledisdb/ledis" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/session" + "github.com/andeya/faygo" + "github.com/andeya/faygo/session" ) var ledispder = &Provider{} diff --git a/session/memcache/sess_memcache.go b/session/memcache/sess_memcache.go index aa22fc3..e4dbe64 100644 --- a/session/memcache/sess_memcache.go +++ b/session/memcache/sess_memcache.go @@ -39,8 +39,8 @@ import ( "github.com/bradfitz/gomemcache/memcache" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/session" + "github.com/andeya/faygo" + "github.com/andeya/faygo/session" ) var mempder = &MemProvider{} diff --git a/session/mysql/sess_mysql.go b/session/mysql/sess_mysql.go index fcda61c..0faf672 100644 --- a/session/mysql/sess_mysql.go +++ b/session/mysql/sess_mysql.go @@ -48,8 +48,8 @@ import ( _ "github.com/go-sql-driver/mysql" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/session" + "github.com/andeya/faygo" + "github.com/andeya/faygo/session" ) var ( diff --git a/session/postgres/sess_postgresql.go b/session/postgres/sess_postgresql.go index a44ba2b..4a22f26 100644 --- a/session/postgres/sess_postgresql.go +++ b/session/postgres/sess_postgresql.go @@ -59,8 +59,8 @@ import ( // import postgresql Driver _ "github.com/lib/pq" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/session" + "github.com/andeya/faygo" + "github.com/andeya/faygo/session" ) var postgresqlpder = &Provider{} diff --git a/session/redis/sess_redis.go b/session/redis/sess_redis.go index 5a35de0..39613ab 100644 --- a/session/redis/sess_redis.go +++ b/session/redis/sess_redis.go @@ -40,8 +40,8 @@ import ( "github.com/garyburd/redigo/redis" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/session" + "github.com/andeya/faygo" + "github.com/andeya/faygo/session" ) var redispder = &Provider{} diff --git a/session/sess_cookie.go b/session/sess_cookie.go index b810c38..edc383d 100644 --- a/session/sess_cookie.go +++ b/session/sess_cookie.go @@ -22,7 +22,7 @@ import ( "net/url" "sync" - "github.com/henrylee2cn/goutil" + "github.com/andeya/goutil" ) var cookiepder = &CookieProvider{} diff --git a/session/sess_test.go b/session/sess_test.go index a656d32..9f1f7f4 100644 --- a/session/sess_test.go +++ b/session/sess_test.go @@ -19,7 +19,7 @@ import ( "encoding/json" "testing" - "github.com/henrylee2cn/goutil" + "github.com/andeya/goutil" ) func Test_gob(t *testing.T) { diff --git a/session/sess_utils.go b/session/sess_utils.go index f5e1526..0abc608 100644 --- a/session/sess_utils.go +++ b/session/sess_utils.go @@ -27,7 +27,7 @@ import ( "strconv" "time" - "github.com/henrylee2cn/goutil" + "github.com/andeya/goutil" ) func init() { diff --git a/session/ssdb/sess_ssdb.go b/session/ssdb/sess_ssdb.go index 652dcb6..73a14b2 100644 --- a/session/ssdb/sess_ssdb.go +++ b/session/ssdb/sess_ssdb.go @@ -7,11 +7,11 @@ import ( "strings" "sync" - "github.com/henrylee2cn/goutil" + "github.com/andeya/goutil" "github.com/ssdb/gossdb/ssdb" - "github.com/henrylee2cn/faygo" - "github.com/henrylee2cn/faygo/session" + "github.com/andeya/faygo" + "github.com/andeya/faygo/session" ) var ssdbProvider = &SsdbProvider{} @@ -91,7 +91,7 @@ func (p *SsdbProvider) SessionExist(sid string) bool { } func (p *SsdbProvider) SessionRegenerate(oldsid, sid string) (session.Store, error) { - //conn.Do("setx", key, v, ttl) + // conn.Do("setx", key, v, ttl) if p.client == nil { if err := p.connectInit(); err != nil { return nil, err diff --git a/syso_windows_386.go b/syso_windows_386.go index 0d5e2ce..845222f 100644 --- a/syso_windows_386.go +++ b/syso_windows_386.go @@ -15,5 +15,5 @@ package faygo import ( - _ "github.com/henrylee2cn/faygo/_syso" + _ "github.com/andeya/faygo/_syso" ) diff --git a/tree.go b/tree.go index 4ab8e97..d0e1045 100644 --- a/tree.go +++ b/tree.go @@ -9,7 +9,7 @@ import ( "unicode" "unicode/utf8" - "github.com/henrylee2cn/faygo/apiware" + "github.com/andeya/faygo/apiware" ) // Handle is a function that can be registered to a route to handle HTTP requests. diff --git a/vendor/github.com/henrylee2cn/goutil/.gitignore b/vendor/github.com/andeya/goutil/.gitignore similarity index 97% rename from vendor/github.com/henrylee2cn/goutil/.gitignore rename to vendor/github.com/andeya/goutil/.gitignore index 87b70ba..6740a7e 100644 --- a/vendor/github.com/henrylee2cn/goutil/.gitignore +++ b/vendor/github.com/andeya/goutil/.gitignore @@ -37,3 +37,6 @@ _testmain.go *.sublime-project *.sublime-workspace .DS_Store +.idea +.vscode + diff --git a/vendor/github.com/andeya/goutil/.travis.yml b/vendor/github.com/andeya/goutil/.travis.yml new file mode 100644 index 0000000..883bebb --- /dev/null +++ b/vendor/github.com/andeya/goutil/.travis.yml @@ -0,0 +1,19 @@ +language: go +os: + - linux + - osx +go: + - "1.9" + - "1.10" + - "1.11" + - "1.12" + - "1.13" +go_import_path: github.com/andeya/goutil +env: + - GIMME_ARCH=amd64 GO111MODULE=on + - GIMME_ARCH=386 GO111MODULE=on +script: + - go get -d -t ./... + - go test -v ./... +after_success: + - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/vendor/github.com/andeya/goutil/LICENSE b/vendor/github.com/andeya/goutil/LICENSE new file mode 100644 index 0000000..dd72658 --- /dev/null +++ b/vendor/github.com/andeya/goutil/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2022 AndeyaLee + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/andeya/goutil/README.md b/vendor/github.com/andeya/goutil/README.md new file mode 100644 index 0000000..590943c --- /dev/null +++ b/vendor/github.com/andeya/goutil/README.md @@ -0,0 +1,9 @@ +# goutil [![Build Status](https://travis-ci.org/andeya/goutil.svg?branch=mgoutil)](https://travis-ci.org/andeya/goutil) [![report card](https://goreportcard.com/badge/github.com/andeya/goutil?style=flat-square)](http://goreportcard.com/report/andeya/goutil) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/andeya/goutil) + +Golang common tool functions or components. + +## Inclusion criteria + +- Only rely on the Go standard package +- Functions or lightweight packages +- Non-business related general tools diff --git a/vendor/github.com/henrylee2cn/goutil/currip.go b/vendor/github.com/andeya/goutil/currip.go similarity index 88% rename from vendor/github.com/henrylee2cn/goutil/currip.go rename to vendor/github.com/andeya/goutil/currip.go index 5bfdea8..b67d263 100644 --- a/vendor/github.com/henrylee2cn/goutil/currip.go +++ b/vendor/github.com/andeya/goutil/currip.go @@ -14,9 +14,9 @@ import ( func ExtranetIP() (ip string, err error) { defer func() { if p := recover(); p != nil { - err = fmt.Errorf("Get external IP error: %v", p) + err = fmt.Errorf("get external IP error: %v", p) } else if err != nil { - err = errors.New("Get external IP error: " + err.Error()) + err = errors.New("get external IP error: " + err.Error()) } }() resp, err := http.Get("http://pv.sohu.com/cityjson?ie=utf-8") @@ -71,5 +71,5 @@ func IntranetIP() (string, error) { return ip.String(), nil } } - return "", errors.New("Are you connected to the network?") + return "", errors.New("no network connection") } diff --git a/vendor/github.com/henrylee2cn/goutil/doc.go b/vendor/github.com/andeya/goutil/doc.go similarity index 68% rename from vendor/github.com/henrylee2cn/goutil/doc.go rename to vendor/github.com/andeya/goutil/doc.go index db00e1f..9be9076 100644 --- a/vendor/github.com/henrylee2cn/goutil/doc.go +++ b/vendor/github.com/andeya/goutil/doc.go @@ -1,4 +1,4 @@ -// Common and useful utils for the Go project development. +// Package goutil is a common and useful toolkit for Go project development. // // Inclusion criteria: // - Only rely on the Go standard package diff --git a/vendor/github.com/andeya/goutil/encrypt.go b/vendor/github.com/andeya/goutil/encrypt.go new file mode 100644 index 0000000..e6014e5 --- /dev/null +++ b/vendor/github.com/andeya/goutil/encrypt.go @@ -0,0 +1,274 @@ +package goutil + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/md5" + "crypto/rand" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "encoding/base64" + "encoding/hex" + "errors" + "hash/fnv" + "io" + + "github.com/henrylee2cn/ameda" +) + +// Md5 returns the MD5 checksum string of the data. +func Md5(b []byte) string { + checksum := md5.Sum(b) + return hex.EncodeToString(checksum[:]) +} + +// Sha1 returns the sha1 checksum string of the data. +func Sha1(b []byte) string { + checksum := sha1.Sum(b) + return hex.EncodeToString(checksum[:]) +} + +// Sha256 returns the sha256 checksum string of the data. +func Sha256(b []byte) string { + checksum := sha256.Sum256(b) + return hex.EncodeToString(checksum[:]) +} + +// Sha512 returns the sha512 checksum string of the data. +func Sha512(b []byte) string { + checksum := sha512.Sum512(b) + return hex.EncodeToString(checksum[:]) +} + +// Fnv1aToUint64 returns the 64-bit FNV-1a hash sum of b. +func Fnv1aToUint64(b []byte) uint64 { + h := fnv.New64a() + h.Reset() + h.Write(b) + return h.Sum64() +} + +// Fnv1aToUint32 returns the 32-bit FNV-1a hash sum of b. +func Fnv1aToUint32(b []byte) uint32 { + h := fnv.New32a() + h.Reset() + h.Write(b) + return h.Sum32() +} + +// AESEncrypt uses ECB mode to encrypt a piece of data and then encodes it in hex. +// The cipherkey argument should be the AES key, +// either 16, 24, or 32 bytes to select +// AES-128, AES-192, or AES-256. +func AESEncrypt(cipherkey, plaintext []byte, useBase64 ...bool) []byte { + block := mustNewCipher(cipherkey) + blockSize := block.BlockSize() + plaintext = pkcs5Padding(plaintext, blockSize) + r := make([]byte, len(plaintext)) + dst := r + for len(plaintext) > 0 { + block.Encrypt(dst, plaintext) + plaintext = plaintext[blockSize:] + dst = dst[blockSize:] + } + return encode(r, useBase64) +} + +// AESDecrypt hex decodes a piece of data and then decrypts it using ECB mode. +// The cipherkey argument should be the AES key, +// either 16, 24, or 32 bytes to select +// AES-128, AES-192, or AES-256. +func AESDecrypt(cipherkey, ciphertext []byte, useBase64 ...bool) ([]byte, error) { + src, err := decode(ciphertext, useBase64) + if err != nil { + return nil, err + } + block, err := aes.NewCipher(cipherkey) + if err != nil { + return nil, err + } + blockSize := block.BlockSize() + r := make([]byte, len(src)) + dst := r + for len(src) > 0 { + block.Decrypt(dst, src) + src = src[blockSize:] + dst = dst[blockSize:] + } + return pkcs5Unpadding(r) +} + +// AESCBCEncrypt uses CBC mode to encrypt a piece of data and then encodes it in hex. +// The cipherkey argument should be the AES key, +// either 16, 24, or 32 bytes to select +// AES-128, AES-192, or AES-256. +func AESCBCEncrypt(cipherkey, plaintext []byte, useBase64 ...bool) []byte { + block := mustNewCipher(cipherkey) + blockSize := block.BlockSize() + plaintext = pkcs5Padding(plaintext, blockSize) + // The IV needs to be unique, but not secure. Therefore it's common to + // include it at the beginning of the ciphertext. + ciphertext := make([]byte, aes.BlockSize+len(plaintext)) + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + panic(err) + } + mode := cipher.NewCBCEncrypter(block, iv) + mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext) + return encode(ciphertext, useBase64) +} + +// AESCBCDecrypt hex decodes a piece of data and then decrypts it using CBC mode. +// The cipherkey argument should be the AES key, +// either 16, 24, or 32 bytes to select +// AES-128, AES-192, or AES-256. +func AESCBCDecrypt(cipherkey, ciphertext []byte, useBase64 ...bool) ([]byte, error) { + ciphertext, err := decode(ciphertext, useBase64) + if err != nil { + return nil, err + } + // The IV needs to be unique, but not secure. Therefore it's common to + // include it at the beginning of the ciphertext. + if len(ciphertext) < aes.BlockSize { + return nil, errors.New("ciphertext too short") + } + iv := ciphertext[:aes.BlockSize] + ciphertext = ciphertext[aes.BlockSize:] + // CBC mode always works in whole blocks. + if len(ciphertext)%aes.BlockSize != 0 { + return nil, errors.New("ciphertext is not a multiple of the block size") + } + block, err := aes.NewCipher(cipherkey) + if err != nil { + return nil, err + } + mode := cipher.NewCBCDecrypter(block, iv) + // CryptBlocks can work in-place if the two arguments are the same. + plaintext := ciphertext + mode.CryptBlocks(plaintext, ciphertext) + return pkcs5Unpadding(plaintext) +} + +// AESCTREncrypt uses CTR mode to encrypt a piece of data and then encodes it in hex. +// The cipherkey argument should be the AES key, +// either 16, 24, or 32 bytes to select +// AES-128, AES-192, or AES-256. +func AESCTREncrypt(cipherkey, plaintext []byte, useBase64 ...bool) []byte { + block := mustNewCipher(cipherkey) + // The IV needs to be unique, but not secure. Therefore it's common to + // include it at the beginning of the ciphertext. + ciphertext := make([]byte, aes.BlockSize+len(plaintext)) + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + panic(err) + } + stream := cipher.NewCTR(block, iv) + stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) + return encode(ciphertext, useBase64) +} + +// AESCTRDecrypt hex decodes a piece of data and then decrypts it using CTR mode. +// The cipherkey argument should be the AES key, +// either 16, 24, or 32 bytes to select +// AES-128, AES-192, or AES-256. +func AESCTRDecrypt(cipherkey, ciphertext []byte, useBase64 ...bool) ([]byte, error) { + ciphertext, err := decode(ciphertext, useBase64) + if err != nil { + return nil, err + } + // The IV needs to be unique, but not secure. Therefore it's common to + // include it at the beginning of the ciphertext. + if len(ciphertext) < aes.BlockSize { + return nil, errors.New("ciphertext too short") + } + iv := ciphertext[:aes.BlockSize] + ciphertext = ciphertext[aes.BlockSize:] + block, err := aes.NewCipher(cipherkey) + if err != nil { + return nil, err + } + stream := cipher.NewCTR(block, iv) + plaintext := ciphertext + // XORKeyStream can work in-place if the two arguments are the same. + stream.XORKeyStream(plaintext, ciphertext) + return plaintext, nil +} + +func mustNewCipher(cipherkey []byte) cipher.Block { + block, err := aes.NewCipher(cipherkey) + if err != nil { + panic(err) + } + return block +} + +func pkcs5Padding(plaintext []byte, blockSize int) []byte { + n := byte(blockSize - len(plaintext)%blockSize) + for i := byte(0); i < n; i++ { + plaintext = append(plaintext, n) + } + return plaintext +} + +func pkcs5Unpadding(r []byte) ([]byte, error) { + l := len(r) + if l == 0 { + return nil, errors.New("input padded bytes is empty") + } + last := int(r[l-1]) + if l-last < 0 { + return nil, errors.New("input padded bytes is invalid") + } + n := byte(last) + pad := r[l-last : l] + isPad := true + for _, v := range pad { + if v != n { + isPad = false + break + } + } + if !isPad { + return nil, errors.New("remove pad error") + } + return r[:l-last], nil +} + +func encode(src []byte, useBase64 []bool) []byte { + if ameda.OneBool(useBase64) { + return base64Encode(src) + } + return hexEncode(src) +} + +func decode(src []byte, useBase64 []bool) ([]byte, error) { + if ameda.OneBool(useBase64) { + return base64Decode(src) + } + return hexDecode(src) +} + +func hexEncode(src []byte) []byte { + dst := make([]byte, hex.EncodedLen(len(src))) + hex.Encode(dst, src) + return dst +} + +func hexDecode(src []byte) ([]byte, error) { + dst := make([]byte, hex.DecodedLen(len(src))) + _, err := hex.Decode(dst, src) + return dst, err +} + +func base64Encode(src []byte) []byte { + buf := make([]byte, base64.RawURLEncoding.EncodedLen(len(src))) + base64.RawURLEncoding.Encode(buf, src) + return buf +} + +func base64Decode(src []byte) ([]byte, error) { + dst := make([]byte, base64.RawURLEncoding.DecodedLen(len(src))) + n, err := base64.RawURLEncoding.Decode(dst, src) + return dst[:n], err +} diff --git a/vendor/github.com/henrylee2cn/goutil/errors/errors.go b/vendor/github.com/andeya/goutil/errors/errors.go similarity index 98% rename from vendor/github.com/henrylee2cn/goutil/errors/errors.go rename to vendor/github.com/andeya/goutil/errors/errors.go index fa0ef74..1b220ce 100644 --- a/vendor/github.com/henrylee2cn/goutil/errors/errors.go +++ b/vendor/github.com/andeya/goutil/errors/errors.go @@ -6,7 +6,7 @@ import ( "fmt" "strconv" - "github.com/henrylee2cn/goutil" + "github.com/andeya/goutil" ) // New returns an error that formats as the given text. diff --git a/vendor/github.com/henrylee2cn/goutil/file.go b/vendor/github.com/andeya/goutil/file.go similarity index 94% rename from vendor/github.com/henrylee2cn/goutil/file.go rename to vendor/github.com/andeya/goutil/file.go index 1f604ca..9573f81 100644 --- a/vendor/github.com/henrylee2cn/goutil/file.go +++ b/vendor/github.com/andeya/goutil/file.go @@ -2,6 +2,7 @@ package goutil import ( "bufio" + "bytes" "errors" "fmt" "io" @@ -376,14 +377,17 @@ func RewriteFile(filename string, fn func(content []byte) (newContent []byte, er return err } defer f.Close() - cnt, err := ioutil.ReadAll(f) + content, err := ioutil.ReadAll(f) if err != nil { return err } - newContent, err := fn(cnt) + newContent, err := fn(content) if err != nil { return err } + if bytes.Equal(content, newContent) { + return nil + } f.Seek(0, 0) f.Truncate(0) _, err = f.Write(newContent) @@ -415,3 +419,19 @@ func RewriteToFile(filename, newfilename string, fn func(content []byte) (newCon } return WriteFile(newfilename, newContent, info.Mode()) } + +// ReplaceFile replaces the bytes selected by [start, end] with the new content. +func ReplaceFile(filename string, start, end int, newContent string) error { + if start < 0 || (end >= 0 && start > end) { + return nil + } + return RewriteFile(filename, func(content []byte) ([]byte, error) { + if end < 0 || end > len(content) { + end = len(content) + } + if start > end { + start = end + } + return bytes.Replace(content, content[start:end], StringToBytes(newContent), 1), nil + }) +} diff --git a/vendor/github.com/andeya/goutil/gopath.go b/vendor/github.com/andeya/goutil/gopath.go new file mode 100644 index 0000000..bd43098 --- /dev/null +++ b/vendor/github.com/andeya/goutil/gopath.go @@ -0,0 +1,75 @@ +package goutil + +import ( + "errors" + "go/build" + "os" + "path/filepath" + "strings" +) + +// GetGopaths returns the list of Go path directories. +func GetGopaths() []string { + var all []string + for _, p := range filepath.SplitList(build.Default.GOPATH) { + if p == "" || p == build.Default.GOROOT { + // Empty paths are uninteresting. + // If the path is the GOROOT, ignore it. + // People sometimes set GOPATH=$GOROOT. + // Do not get confused by this common mistake. + continue + } + if strings.HasPrefix(p, "~") { + // Path segments starting with ~ on Unix are almost always + // users who have incorrectly quoted ~ while setting GOPATH, + // preventing it from expanding to $HOME. + // The situation is made more confusing by the fact that + // bash allows quoted ~ in $PATH (most shells do not). + // Do not get confused by this, and do not try to use the path. + // It does not exist, and printing errors about it confuses + // those users even more, because they think "sure ~ exists!". + // The go command diagnoses this situation and prints a + // useful error. + // On Windows, ~ is used in short names, such as c:\progra~1 + // for c:\program files. + continue + } + all = append(all, p) + } + for k, v := range all { + // GOPATH should end with / or \ + if strings.HasSuffix(v, "/") || strings.HasSuffix(v, string(os.PathSeparator)) { + continue + } + v += string(os.PathSeparator) + all[k] = v + } + return all +} + +// GetFirstGopath gets the first $GOPATH value. +func GetFirstGopath(allowAutomaticGuessing bool) (gopath string, err error) { + a := GetGopaths() + if len(a) > 0 { + gopath = a[0] + } + defer func() { + gopath = strings.Replace(gopath, "/", string(os.PathSeparator), -1) + }() + if gopath != "" { + return + } + if !allowAutomaticGuessing { + err = errors.New("not found GOPATH") + return + } + p, _ := os.Getwd() + p = strings.Replace(p, "\\", "/", -1) + "/" + i := strings.LastIndex(p, "/src/") + if i == -1 { + err = errors.New("not found GOPATH") + return + } + gopath = p[:i+1] + return +} diff --git a/vendor/github.com/andeya/goutil/gotest.go b/vendor/github.com/andeya/goutil/gotest.go new file mode 100644 index 0000000..f2ec806 --- /dev/null +++ b/vendor/github.com/andeya/goutil/gotest.go @@ -0,0 +1,41 @@ +package goutil + +import ( + "os" + "strings" +) + +// IsGoTest returns whether the current process is a test. +func IsGoTest() bool { + return isGoTest +} + +var isGoTest bool + +func init() { + isGoTest = checkGoTestEnv() +} + +const IS_GO_TEST = "IS_GO_TEST" + +func checkGoTestEnv() bool { + for _, arg := range os.Args[1:] { + for _, s := range []string{ + "-test.timeout=", + "-test.timeout", + "-test.run=", + "-test.run", + "-test.bench=", + "-test.bench", + "-test.v=", + "-test.v", + } { + if strings.HasPrefix(arg, s) || arg == s { + return true + } + } + } + env := os.Getenv(IS_GO_TEST) + return env == "1" || env == "true" + // return strings.HasSuffix(os.Args[0], ".test") +} diff --git a/vendor/github.com/henrylee2cn/goutil/js_url.go b/vendor/github.com/andeya/goutil/js_url.go similarity index 100% rename from vendor/github.com/henrylee2cn/goutil/js_url.go rename to vendor/github.com/andeya/goutil/js_url.go diff --git a/vendor/github.com/andeya/goutil/kvdata.go b/vendor/github.com/andeya/goutil/kvdata.go new file mode 100644 index 0000000..8449d2c --- /dev/null +++ b/vendor/github.com/andeya/goutil/kvdata.go @@ -0,0 +1,109 @@ +package goutil + +import "time" + +// KVData key-value data +type KVData map[string]interface{} + +// Get returns the value for the given key, ie: (value, true). +// If the value does not exists it returns (nil, false) +func (k KVData) Get(key string) (value interface{}, exists bool) { + value, exists = k[key] + return +} + +// MustGet returns the value for the given key if it exists, otherwise it panics. +func (k KVData) MustGet(key string) interface{} { + if value, exists := k.Get(key); exists { + return value + } + panic("Key \"" + key + "\" does not exist") +} + +// GetString returns the value associated with the key as a string. +func (k KVData) GetString(key string) (s string) { + if val, ok := k.Get(key); ok && val != nil { + s, _ = val.(string) + } + return +} + +// GetBool returns the value associated with the key as a boolean. +func (k KVData) GetBool(key string) (b bool) { + if val, ok := k.Get(key); ok && val != nil { + b, _ = val.(bool) + } + return +} + +// GetInt returns the value associated with the key as an integer. +func (k KVData) GetInt(key string) (i int) { + if val, ok := k.Get(key); ok && val != nil { + i, _ = val.(int) + } + return +} + +// GetInt64 returns the value associated with the key as an integer. +func (k KVData) GetInt64(key string) (i64 int64) { + if val, ok := k.Get(key); ok && val != nil { + i64, _ = val.(int64) + } + return +} + +// GetFloat64 returns the value associated with the key as a float64. +func (k KVData) GetFloat64(key string) (f64 float64) { + if val, ok := k.Get(key); ok && val != nil { + f64, _ = val.(float64) + } + return +} + +// GetTime returns the value associated with the key as time. +func (k KVData) GetTime(key string) (t time.Time) { + if val, ok := k.Get(key); ok && val != nil { + t, _ = val.(time.Time) + } + return +} + +// GetDuration returns the value associated with the key as a duration. +func (k KVData) GetDuration(key string) (d time.Duration) { + if val, ok := k.Get(key); ok && val != nil { + d, _ = val.(time.Duration) + } + return +} + +// GetStringSlice returns the value associated with the key as a slice of strings. +func (k KVData) GetStringSlice(key string) (ss []string) { + if val, ok := k.Get(key); ok && val != nil { + ss, _ = val.([]string) + } + return +} + +// GetStringMap returns the value associated with the key as a map of interfaces. +func (k KVData) GetStringMap(key string) (sm map[string]interface{}) { + if val, ok := k.Get(key); ok && val != nil { + sm, _ = val.(map[string]interface{}) + } + return +} + +// GetStringMapString returns the value associated with the key as a map of strings. +func (k KVData) GetStringMapString(key string) (sms map[string]string) { + if val, ok := k.Get(key); ok && val != nil { + sms, _ = val.(map[string]string) + } + return +} + +// GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings. +func (k KVData) GetStringMapStringSlice(key string) (smss map[string][]string) { + if val, ok := k.Get(key); ok && val != nil { + smss, _ = val.(map[string][]string) + } + return +} diff --git a/vendor/github.com/henrylee2cn/goutil/map.go b/vendor/github.com/andeya/goutil/map.go similarity index 98% rename from vendor/github.com/henrylee2cn/goutil/map.go rename to vendor/github.com/andeya/goutil/map.go index fc20f19..beb71c9 100644 --- a/vendor/github.com/henrylee2cn/goutil/map.go +++ b/vendor/github.com/andeya/goutil/map.go @@ -204,7 +204,7 @@ type atomicMap struct { // state) and the next store to the map will make a new dirty copy. misses int - // @added by henrylee2cn 2017/11/17 + // @added by andeya 2017/11/17 length int32 } @@ -289,7 +289,7 @@ func (m *atomicMap) Store(key, value interface{}) { case 1: return case 2: - // @added by henrylee2cn 2017/11/17 + // @added by andeya 2017/11/17 atomic.AddInt32(&m.length, 1) return } @@ -303,7 +303,7 @@ func (m *atomicMap) Store(key, value interface{}) { m.mu.Unlock() return case 2: - // @added by henrylee2cn 2017/11/17 + // @added by andeya 2017/11/17 atomic.AddInt32(&m.length, 1) m.mu.Unlock() return @@ -312,7 +312,7 @@ func (m *atomicMap) Store(key, value interface{}) { // The entry was previously expunged, which implies that there is a // non-nil dirty map and this entry is not in it. m.dirty[key] = e - // @added by henrylee2cn 2017/11/17 + // @added by andeya 2017/11/17 atomic.AddInt32(&m.length, 1) } e.storeLocked(&value) @@ -380,7 +380,7 @@ func (m *atomicMap) LoadOrStore(key, value interface{}) (actual interface{}, loa if e, ok := read.m[key]; ok { actual, loaded, ok := e.tryLoadOrStore(value) if ok { - // @added by henrylee2cn 2017/11/17 + // @added by andeya 2017/11/17 if !loaded { atomic.AddInt32(&m.length, 1) } @@ -395,7 +395,7 @@ func (m *atomicMap) LoadOrStore(key, value interface{}) (actual interface{}, loa m.dirty[key] = e } actual, loaded, ok = e.tryLoadOrStore(value) - // @added by henrylee2cn 2017/12/01 + // @added by andeya 2017/12/01 if ok && !loaded { atomic.AddInt32(&m.length, 1) } @@ -600,14 +600,14 @@ func (e *entry) tryExpungeLocked() (isExpunged bool) { // Len returns the length of the map. // Note: // the length may be inaccurate. -// @added by henrylee2cn 2017/11/17 +// @added by andeya 2017/11/17 func (m *atomicMap) Len() int { return int(atomic.LoadInt32(&m.length)) } // Random returns a pair kv randomly. // If exist=false, no kv data is exist. -// @added by henrylee2cn 2017/08/10 +// @added by andeya 2017/08/10 func (m *atomicMap) Random() (key, value interface{}, exist bool) { var ( length, i int diff --git a/vendor/github.com/andeya/goutil/other.go b/vendor/github.com/andeya/goutil/other.go new file mode 100644 index 0000000..69cc626 --- /dev/null +++ b/vendor/github.com/andeya/goutil/other.go @@ -0,0 +1,135 @@ +package goutil + +import ( + "reflect" + "unsafe" + + "github.com/henrylee2cn/ameda" +) + +// AddrInt returns a pointer int representing the address of i. +func AddrInt(i int) *int { + return &i +} + +// InitAndGetString if strPtr is empty string, initialize it with def, +// and return the final value. +func InitAndGetString(strPtr *string, def string) string { + if strPtr == nil { + return def + } + if *strPtr == "" { + *strPtr = def + } + return *strPtr +} + +// InitPointer initializes null pointer. +func InitPointer(v reflect.Value) bool { + return ameda.InitPointer(v) +} + +// DereferenceType dereference, get the underlying non-pointer type. +func DereferenceType(t reflect.Type) reflect.Type { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t +} + +// DereferenceValue dereference and unpack interface, +// get the underlying non-pointer and non-interface value. +func DereferenceValue(v reflect.Value) reflect.Value { + for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { + v = v.Elem() + } + return v +} + +// DereferencePtrValue returns the underlying non-pointer type value. +func DereferencePtrValue(v reflect.Value) reflect.Value { + for v.Kind() == reflect.Ptr { + v = v.Elem() + } + return v +} + +// DereferenceIfaceValue returns the value of the underlying type that implements the interface v. +func DereferenceIfaceValue(v reflect.Value) reflect.Value { + for v.Kind() == reflect.Interface { + v = v.Elem() + } + return v +} + +// DereferenceImplementType returns the underlying type of the value that implements the interface v. +func DereferenceImplementType(v reflect.Value) reflect.Type { + return DereferenceType(DereferenceIfaceValue(v).Type()) +} + +// DereferenceSlice convert []*T to []T. +func DereferenceSlice(v reflect.Value) reflect.Value { + m := v.Len() - 1 + if m < 0 { + return reflect.New(reflect.SliceOf(DereferenceType(v.Type().Elem()))).Elem() + } + s := make([]reflect.Value, m+1) + for ; m >= 0; m-- { + s[m] = DereferenceValue(v.Index(m)) + } + v = reflect.New(reflect.SliceOf(s[0].Type())).Elem() + v = reflect.Append(v, s...) + return v +} + +// ReferenceSlice convert []T to []*T, the ptrDepth is the count of '*'. +func ReferenceSlice(v reflect.Value, ptrDepth int) reflect.Value { + if ptrDepth <= 0 { + return v + } + m := v.Len() - 1 + if m < 0 { + return reflect.New(reflect.SliceOf(ReferenceType(v.Type().Elem(), ptrDepth))).Elem() + } + s := make([]reflect.Value, m+1) + for ; m >= 0; m-- { + s[m] = ReferenceValue(v.Index(m), ptrDepth) + } + v = reflect.New(reflect.SliceOf(s[0].Type())).Elem() + v = reflect.Append(v, s...) + return v +} + +// ReferenceType convert T to *T, the ptrDepth is the count of '*'. +func ReferenceType(t reflect.Type, ptrDepth int) reflect.Type { + for ; ptrDepth > 0; ptrDepth-- { + t = reflect.PtrTo(t) + } + return t +} + +// ReferenceValue convert T to *T, the ptrDepth is the count of '*'. +func ReferenceValue(v reflect.Value, ptrDepth int) reflect.Value { + for ; ptrDepth > 0; ptrDepth-- { + vv := reflect.New(v.Type()) + vv.Elem().Set(v) + v = vv + } + return v +} + +// IsLittleEndian determine whether the current system is little endian. +func IsLittleEndian() bool { + var i int32 = 0x01020304 + u := unsafe.Pointer(&i) + pb := (*byte)(u) + b := *pb + return (b == 0x04) +} + +const ( + // Is64BitPlatform Whether the current system is a 64-bit platform + Is64BitPlatform bool = (32 << (^uint(0) >> 63)) == 64 + // Is32BitPlatform Whether the current system is a 32-bit platform + Is32BitPlatform bool = (32 << (^uint(0) >> 63)) == 0 +) diff --git a/vendor/github.com/henrylee2cn/goutil/pid_file.go b/vendor/github.com/andeya/goutil/pid_file.go similarity index 100% rename from vendor/github.com/henrylee2cn/goutil/pid_file.go rename to vendor/github.com/andeya/goutil/pid_file.go diff --git a/vendor/github.com/henrylee2cn/goutil/random.go b/vendor/github.com/andeya/goutil/random.go similarity index 61% rename from vendor/github.com/henrylee2cn/goutil/random.go rename to vendor/github.com/andeya/goutil/random.go index 08a5019..0d12afe 100644 --- a/vendor/github.com/henrylee2cn/goutil/random.go +++ b/vendor/github.com/andeya/goutil/random.go @@ -4,7 +4,10 @@ import ( "bytes" "crypto/rand" "encoding/base64" + "errors" mrand "math/rand" + + "github.com/henrylee2cn/ameda" ) // NewRandom creates a new padded Encoding defined by the given alphabet string. @@ -26,7 +29,7 @@ func NewRandom(alphabet string) *Random { return r } -// Random random string creater. +// Random random string creator. type Random struct { encoding *base64.Encoding substitute []byte @@ -37,16 +40,39 @@ type Random struct { // random string. It will panic if the system's secure random number generator // fails to function correctly. // The length n must be an integer multiple of 4, otherwise the last character will be padded with `=`. -func (r *Random) RandomString(n int) string { - d := r.encoding.DecodedLen(n) - buf := make([]byte, n) +func (r *Random) RandomString(length int) string { + d := r.encoding.DecodedLen(length) + buf := make([]byte, length) r.encoding.Encode(buf, RandomBytes(d)) for k, v := range buf { if v == 0x00 { buf[k] = r.substitute[mrand.Intn(r.substituteLen)] } } - return BytesToString(buf) + return ameda.UnsafeBytesToString(buf) +} + +const tsLen = 6 // base62=ZZZZZZ, unix=56800235583, time=3769-12-05 11:13:03 +0800 CST + +// RandomStringWithTime returns a random string with UNIX timestamp(in second). +// unixTs: range [0,56800235583], that is 56800235583 3769-12-05 11:13:03 +0800 CST to 3769-12-05 11:13:03 +0800 CST +func (r *Random) RandomStringWithTime(length int, unixTs int64) (string, error) { + if length <= tsLen { + return "", errors.New("length is less than 7") + } + if unixTs < 0 || unixTs > 56800235583 { + return "", errors.New("unixTs is out of range [0,56800235583]") + } + return r.RandomString(length-tsLen) + ameda.FormatInt(unixTs, 62), nil +} + +// ParseTime parses UNIX timestamp(in second) from stringWithTime. +func (r *Random) ParseTime(stringWithTime string) (unixTs int64, err error) { + length := len(stringWithTime) + if length <= tsLen { + return 0, errors.New("stringWithTime length is less than 7") + } + return ameda.ParseInt(stringWithTime[length-6:], 62, 64) } const urlEncoder = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" @@ -57,6 +83,11 @@ var urlRandom = &Random{ substituteLen: len(urlEncoder), } +// URLRandom returns Random object with URL encoder. +func URLRandom() *Random { + return urlRandom +} + // URLRandomString returns a URL-safe, base64 encoded securely generated // random string. It will panic if the system's secure random number generator // fails to function correctly. diff --git a/vendor/github.com/andeya/goutil/sets.go b/vendor/github.com/andeya/goutil/sets.go new file mode 100644 index 0000000..b2ecc49 --- /dev/null +++ b/vendor/github.com/andeya/goutil/sets.go @@ -0,0 +1,233 @@ +package goutil + +import ( + "github.com/henrylee2cn/ameda" +) + +// CopyStrings creates a copy of the string slice. +func CopyStrings(a []string) []string { + return ameda.StringsCopy(a) +} + +// StringsToBools converts string slice to bool slice. +func StringsToBools(a []string, emptyAsZero ...bool) ([]bool, error) { + return ameda.StringsToBools(a, emptyAsZero...) +} + +// StringsToFloat32s converts string slice to float32 slice. +func StringsToFloat32s(a []string, emptyAsZero ...bool) ([]float32, error) { + return ameda.StringsToFloat32s(a, emptyAsZero...) +} + +// StringsToFloat64s converts string slice to float64 slice. +func StringsToFloat64s(a []string, emptyAsZero ...bool) ([]float64, error) { + return ameda.StringsToFloat64s(a, emptyAsZero...) +} + +// StringsToInts converts string slice to int slice. +func StringsToInts(a []string, emptyAsZero ...bool) ([]int, error) { + return ameda.StringsToInts(a, emptyAsZero...) +} + +// StringsToInt64s converts string slice to int64 slice. +func StringsToInt64s(a []string, emptyAsZero ...bool) ([]int64, error) { + return ameda.StringsToInt64s(a, emptyAsZero...) +} + +// StringsToInt32s converts string slice to int32 slice. +func StringsToInt32s(a []string, emptyAsZero ...bool) ([]int32, error) { + return ameda.StringsToInt32s(a, emptyAsZero...) +} + +// StringsToInt16s converts string slice to int16 slice. +func StringsToInt16s(a []string, emptyAsZero ...bool) ([]int16, error) { + return ameda.StringsToInt16s(a, emptyAsZero...) +} + +// StringsToInt8s converts string slice to int8 slice. +func StringsToInt8s(a []string, emptyAsZero ...bool) ([]int8, error) { + return ameda.StringsToInt8s(a, emptyAsZero...) +} + +// StringsToUint8s converts string slice to uint8 slice. +func StringsToUint8s(a []string, emptyAsZero ...bool) ([]uint8, error) { + return ameda.StringsToUint8s(a, emptyAsZero...) +} + +// StringsToUint16s converts string slice to uint16 slice. +func StringsToUint16s(a []string, emptyAsZero ...bool) ([]uint16, error) { + return ameda.StringsToUint16s(a, emptyAsZero...) +} + +// StringsToUint32s converts string slice to uint32 slice. +func StringsToUint32s(a []string, emptyAsZero ...bool) ([]uint32, error) { + return ameda.StringsToUint32s(a, emptyAsZero...) +} + +// StringsToUint64s converts string slice to uint64 slice. +func StringsToUint64s(a []string, emptyAsZero ...bool) ([]uint64, error) { + return ameda.StringsToUint64s(a, emptyAsZero...) +} + +// StringsToUints converts string slice to uint slice. +func StringsToUints(a []string, emptyAsZero ...bool) ([]uint, error) { + return ameda.StringsToUints(a, emptyAsZero...) +} + +// StringsConvert converts the string slice to a new slice using fn. +// If fn returns error, exit the conversion and return the error. +func StringsConvert(a []string, fn func(string) (string, error)) ([]string, error) { + ret := make([]string, len(a)) + for i, s := range a { + r, err := fn(s) + if err != nil { + return nil, err + } + ret[i] = r + } + return ret, nil +} + +// StringsConvertMap converts the string slice to a new map using fn. +// If fn returns error, exit the conversion and return the error. +func StringsConvertMap(a []string, fn func(string) (string, error)) (map[string]string, error) { + ret := make(map[string]string, len(a)) + for _, s := range a { + r, err := fn(s) + if err != nil { + return nil, err + } + ret[s] = r + } + return ret, nil +} + +// IntersectStrings calculate intersection of two sets. +func IntersectStrings(set1, set2 []string) []string { + return ameda.StringSetIntersect(set1, set2) +} + +// StringsDistinct creates a string set that +// removes the same elements and returns them in their original order. +func StringsDistinct(a []string) (set []string) { + set = ameda.StringsCopy(a) + ameda.StringsDistinct(&set, true) + return set +} + +// SetToStrings sets a element to the string set. +func SetToStrings(set []string, a ...string) []string { + return ameda.StringsPushDistinct(set, a...) +} + +// RemoveFromStrings removes the first element from the string set. +func RemoveFromStrings(set []string, a string) []string { + ameda.StringsRemoveFirst(&set, a) + return set +} + +// RemoveAllFromStrings removes all the a element from the string set. +func RemoveAllFromStrings(set []string, a string) []string { + ameda.StringsRemoveEvery(&set, a) + return set +} + +// IntsDistinct creates a int set that +// removes the same elements and returns them in their original order. +func IntsDistinct(a []int) (set []int) { + set = ameda.IntsCopy(a) + ameda.IntsDistinct(&set, true) + return set +} + +// SetToInts sets a element to the int set. +func SetToInts(set []int, a int) []int { + return ameda.IntsPushDistinct(set, a) +} + +// RemoveFromInts removes the first element from the int set. +func RemoveFromInts(set []int, a int) []int { + ameda.IntsRemoveFirst(&set, a) + return set +} + +// RemoveAllFromInts removes all the a element from the int set. +func RemoveAllFromInts(set []int, a int) []int { + ameda.IntsRemoveEvery(&set, a) + return set +} + +// Int32sDistinct creates a int32 set that +// removes the same element32s and returns them in their original order. +func Int32sDistinct(a []int32) (set []int32) { + set = ameda.Int32sCopy(a) + ameda.Int32sDistinct(&set, true) + return set +} + +// SetToInt32s sets a element to the int32 set. +func SetToInt32s(set []int32, a int32) []int32 { + return ameda.Int32sPushDistinct(set, a) +} + +// RemoveFromInt32s removes the first element from the int32 set. +func RemoveFromInt32s(set []int32, a int32) []int32 { + ameda.Int32sRemoveFirst(&set, a) + return set +} + +// RemoveAllFromInt32s removes all the a element from the int32 set. +func RemoveAllFromInt32s(set []int32, a int32) []int32 { + ameda.Int32sRemoveEvery(&set, a) + return set +} + +// Int64sDistinct creates a int64 set that +// removes the same element64s and returns them in their original order. +func Int64sDistinct(a []int64) (set []int64) { + set = ameda.Int64sCopy(a) + ameda.Int64sDistinct(&set, true) + return set +} + +// SetToInt64s sets a element to the int64 set. +func SetToInt64s(set []int64, a int64) []int64 { + return ameda.Int64sPushDistinct(set, a) +} + +// RemoveFromInt64s removes the first element from the int64 set. +func RemoveFromInt64s(set []int64, a int64) []int64 { + ameda.Int64sRemoveFirst(&set, a) + return set +} + +// RemoveAllFromInt64s removes all the a element from the int64 set. +func RemoveAllFromInt64s(set []int64, a int64) []int64 { + ameda.Int64sRemoveEvery(&set, a) + return set +} + +// InterfacesDistinct creates a interface{} set that +// removes the same elements and returns them in their original order. +func InterfacesDistinct(a []interface{}) (set []interface{}) { + set = ameda.InterfacesCopy(a) + ameda.InterfacesDistinct(&set, true) + return set +} + +// SetToInterfaces sets a element to the interface{} set. +func SetToInterfaces(set []interface{}, a interface{}) []interface{} { + return ameda.InterfacesPushDistinct(set, a) +} + +// RemoveFromInterfaces removes the first element from the interface{} set. +func RemoveFromInterfaces(set []interface{}, a interface{}) []interface{} { + ameda.InterfacesRemoveFirst(&set, a) + return set +} + +// RemoveAllFromInterfaces removes all the a element from the interface{} set. +func RemoveAllFromInterfaces(set []interface{}, a interface{}) []interface{} { + ameda.InterfacesRemoveEvery(&set, a) + return set +} diff --git a/vendor/github.com/henrylee2cn/goutil/string.go b/vendor/github.com/andeya/goutil/string.go similarity index 63% rename from vendor/github.com/henrylee2cn/goutil/string.go rename to vendor/github.com/andeya/goutil/string.go index 6ff6a9a..23b79aa 100644 --- a/vendor/github.com/henrylee2cn/goutil/string.go +++ b/vendor/github.com/andeya/goutil/string.go @@ -2,11 +2,27 @@ package goutil import ( "bytes" + "regexp" + "strconv" "strings" + "unicode" "unicode/utf8" "unsafe" ) +// Indent inserts prefix at the beginning of each line +func Indent(text, prefix string) string { + if len(prefix) == 0 { + return text + } + has := strings.HasSuffix(text, "\n") + text = prefix + strings.Replace(text, "\n", "\n"+prefix, -1) + if has { + return text[:len(text)-len(prefix)] + } + return text +} + // BytesToString convert []byte type to string type. func BytesToString(b []byte) string { return *(*string)(unsafe.Pointer(&b)) @@ -60,7 +76,165 @@ func CamelString(s string) string { } data = append(data, d) } - return string(data[:]) + return BytesToString(data[:]) +} + +// LintCamelString converts the accepted string to a camel string (xx_id to XxID) +// NOTE: +// support common initialisms +func LintCamelString(name string) string { + // Fast path for simple cases: "_" and all lowercase. + if name == "_" { + return "_" + } + runes := []rune(name) + var i int + for k, v := range runes { + if v != '_' { + i = k + runes[k] = unicode.ToUpper(v) + break + } + } + r := string(toInitialisms(runes[i:])) + return r +} + +func toInitialisms(runes []rune) []rune { + // Split camelCase at any lower->upper transition, and split on underscores. + // Check each word for common initialisms. + w, i := 0, 0 // index of start of word, scan + for i+1 <= len(runes) { + eow := false // whether we hit the end of a word + if i+1 == len(runes) { + eow = true + } else if runes[i+1] == '_' { + // underscore; shift the remainder forward over any run of underscores + eow = true + n := 1 + for i+n+1 < len(runes) && runes[i+n+1] == '_' { + n++ + } + + // Leave at most one underscore if the underscore is between two digits + if i+n+1 < len(runes) && unicode.IsDigit(runes[i]) && unicode.IsDigit(runes[i+n+1]) { + n-- + } + + copy(runes[i+1:], runes[i+n+1:]) + runes = runes[:len(runes)-n] + } else if unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]) { + // lower->non-lower + eow = true + } + i++ + if !eow { + continue + } + + // [w,i) is a word. + word := string(runes[w:i]) + if u := strings.ToUpper(word); commonInitialisms[u] { + // Keep consistent case, which is lowercase only at the start. + if w == 0 && unicode.IsLower(runes[w]) { + u = strings.ToLower(u) + } + // All the common initialisms are ASCII, + // so we can replace the bytes exactly. + copy(runes[w:], []rune(u)) + } else if w > 0 && strings.ToLower(word) == word { + // already all lowercase, and not the first word, so uppercase the first character. + runes[w] = unicode.ToUpper(runes[w]) + } + w = i + } + return runes +} + +// commonInitialisms is a set of common initialisms. +// Only add entries that are highly unlikely to be non-initialisms. +// For instance, "ID" is fine (Freudian code is rare), but "AND" is not. +var commonInitialisms = map[string]bool{ + "ACL": true, + "API": true, + "ASCII": true, + "CPU": true, + "CSS": true, + "DNS": true, + "EOF": true, + "GUID": true, + "HTML": true, + "HTTP": true, + "HTTPS": true, + "ID": true, + "IP": true, + "JSON": true, + "LHS": true, + "QPS": true, + "RAM": true, + "RHS": true, + "RPC": true, + "SLA": true, + "SMTP": true, + "SQL": true, + "SSH": true, + "TCP": true, + "TLS": true, + "TTL": true, + "UDP": true, + "UI": true, + "UID": true, + "UUID": true, + "URI": true, + "URL": true, + "UTF8": true, + "VM": true, + "XML": true, + "XMPP": true, + "XSRF": true, + "XSS": true, +} + +var htmlEntityRegexp = regexp.MustCompile(`&#([0-9a-zA-Z]+);*`) + +// HTMLEntityToUTF8 converts HTML Unicode to UTF-8. +// e.g.: HTMLEntityToUTF8(`{"info":[["color","ᕸᖹ⁐c;eff;⁐"]]}`, 16) +// => `{"info":[["color","咖啡色|绿色"]]}` +func HTMLEntityToUTF8(str string, base int) string { + a := htmlEntityRegexp.FindAllStringSubmatch(str, -1) + if len(a) == 0 { + return str + } + oldnew := make([]string, 0, len(a)*2) + for _, s := range a { + if i, err := strconv.ParseInt(s[1], base, 32); err == nil { + oldnew = append(oldnew, s[0], string(i)) + } + } + r := strings.NewReplacer(oldnew...) + return r.Replace(str) +} + +// CodePointToUTF8 converts Unicode Code Point to UTF-8. +// e.g.: CodePointToUTF8(`{"info":[["color","\u5496\u5561\u8272\u7c\u7eff\u8272"]]}`, 16) +// => `{"info":[["color","咖啡色|绿色"]]}` +func CodePointToUTF8(str string, base int) string { + i := 0 + if strings.Index(str, `\u`) > 0 { + i = 1 + } + strSlice := strings.Split(str, `\u`) + last := len(strSlice) - 1 + if len(strSlice[last]) > 4 { + strSlice = append(strSlice, string(strSlice[last][4:])) + strSlice[last] = string(strSlice[last][:4]) + } + for ; i <= last; i++ { + if x, err := strconv.ParseInt(strSlice[i], base, 32); err == nil { + strSlice[i] = string(x) + } + } + return strings.Join(strSlice, "") } var spaceReplacer = strings.NewReplacer( diff --git a/vendor/github.com/henrylee2cn/goutil/targz.go b/vendor/github.com/andeya/goutil/targz.go similarity index 100% rename from vendor/github.com/henrylee2cn/goutil/targz.go rename to vendor/github.com/andeya/goutil/targz.go diff --git a/vendor/github.com/henrylee2cn/goutil/trace.go b/vendor/github.com/andeya/goutil/trace.go similarity index 100% rename from vendor/github.com/henrylee2cn/goutil/trace.go rename to vendor/github.com/andeya/goutil/trace.go diff --git a/vendor/github.com/henrylee2cn/goutil/exported.go b/vendor/github.com/andeya/goutil/type.go similarity index 55% rename from vendor/github.com/henrylee2cn/goutil/exported.go rename to vendor/github.com/andeya/goutil/type.go index c9ae69f..db7f662 100644 --- a/vendor/github.com/henrylee2cn/goutil/exported.go +++ b/vendor/github.com/andeya/goutil/type.go @@ -32,3 +32,25 @@ func ObjectName(obj interface{}) string { } return t.String() } + +// IsCompositionMethod determines whether the method inherits from the anonymous field of the struct. +func IsCompositionMethod(method reflect.Method) bool { + fn := runtime.FuncForPC(method.Func.Pointer()) + file, _ := fn.FileLine(fn.Entry()) + if file != "" { + return false + } + recv := method.Type.In(0) + var found bool + if recv.Kind() == reflect.Ptr { + method, found = recv.Elem().MethodByName(method.Name) + } else { + method, found = reflect.PtrTo(recv).MethodByName(method.Name) + } + if !found { + return true + } + fn = runtime.FuncForPC(method.Func.Pointer()) + file, _ = fn.FileLine(fn.Entry()) + return file == "" +} diff --git a/vendor/github.com/henrylee2cn/ini/.gitignore b/vendor/github.com/andeya/ini/.gitignore similarity index 100% rename from vendor/github.com/henrylee2cn/ini/.gitignore rename to vendor/github.com/andeya/ini/.gitignore diff --git a/vendor/github.com/henrylee2cn/ini/.travis.yml b/vendor/github.com/andeya/ini/.travis.yml similarity index 100% rename from vendor/github.com/henrylee2cn/ini/.travis.yml rename to vendor/github.com/andeya/ini/.travis.yml diff --git a/vendor/github.com/henrylee2cn/ini/LICENSE b/vendor/github.com/andeya/ini/LICENSE similarity index 100% rename from vendor/github.com/henrylee2cn/ini/LICENSE rename to vendor/github.com/andeya/ini/LICENSE diff --git a/vendor/github.com/henrylee2cn/ini/Makefile b/vendor/github.com/andeya/ini/Makefile similarity index 100% rename from vendor/github.com/henrylee2cn/ini/Makefile rename to vendor/github.com/andeya/ini/Makefile diff --git a/vendor/github.com/henrylee2cn/ini/README.md b/vendor/github.com/andeya/ini/README.md similarity index 100% rename from vendor/github.com/henrylee2cn/ini/README.md rename to vendor/github.com/andeya/ini/README.md diff --git a/vendor/github.com/henrylee2cn/ini/README_ZH.md b/vendor/github.com/andeya/ini/README_ZH.md similarity index 100% rename from vendor/github.com/henrylee2cn/ini/README_ZH.md rename to vendor/github.com/andeya/ini/README_ZH.md diff --git a/vendor/github.com/henrylee2cn/ini/error.go b/vendor/github.com/andeya/ini/error.go similarity index 100% rename from vendor/github.com/henrylee2cn/ini/error.go rename to vendor/github.com/andeya/ini/error.go diff --git a/vendor/github.com/henrylee2cn/ini/helper.go b/vendor/github.com/andeya/ini/helper.go similarity index 91% rename from vendor/github.com/henrylee2cn/ini/helper.go rename to vendor/github.com/andeya/ini/helper.go index 4c55930..92b4d95 100644 --- a/vendor/github.com/henrylee2cn/ini/helper.go +++ b/vendor/github.com/andeya/ini/helper.go @@ -7,12 +7,12 @@ import ( "strings" "sync" - "github.com/henrylee2cn/goutil" - "github.com/henrylee2cn/goutil/errors" + "github.com/andeya/goutil" + "github.com/andeya/goutil/errors" ) // SyncINI quickly create your own configuration files. -// Struct tags reference `https://github.com/henrylee2cn/ini` +// Struct tags reference `https://github.com/andeya/ini` func SyncINI(structPtr interface{}, f func(onecUpdateFunc func() error) error, filename ...string) error { t := reflect.TypeOf(structPtr) if t.Kind() != reflect.Ptr { diff --git a/vendor/github.com/henrylee2cn/ini/ini.go b/vendor/github.com/andeya/ini/ini.go similarity index 100% rename from vendor/github.com/henrylee2cn/ini/ini.go rename to vendor/github.com/andeya/ini/ini.go diff --git a/vendor/github.com/henrylee2cn/ini/key.go b/vendor/github.com/andeya/ini/key.go similarity index 100% rename from vendor/github.com/henrylee2cn/ini/key.go rename to vendor/github.com/andeya/ini/key.go diff --git a/vendor/github.com/henrylee2cn/ini/parser.go b/vendor/github.com/andeya/ini/parser.go similarity index 100% rename from vendor/github.com/henrylee2cn/ini/parser.go rename to vendor/github.com/andeya/ini/parser.go diff --git a/vendor/github.com/henrylee2cn/ini/section.go b/vendor/github.com/andeya/ini/section.go similarity index 100% rename from vendor/github.com/henrylee2cn/ini/section.go rename to vendor/github.com/andeya/ini/section.go diff --git a/vendor/github.com/henrylee2cn/ini/struct.go b/vendor/github.com/andeya/ini/struct.go similarity index 100% rename from vendor/github.com/henrylee2cn/ini/struct.go rename to vendor/github.com/andeya/ini/struct.go diff --git a/vendor/github.com/facebookgo/ensure/patents b/vendor/github.com/facebookgo/ensure/patents deleted file mode 100644 index 808ef85..0000000 --- a/vendor/github.com/facebookgo/ensure/patents +++ /dev/null @@ -1,33 +0,0 @@ -Additional Grant of Patent Rights Version 2 - -"Software" means the ensure software distributed by Facebook, Inc. - -Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software -("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable -(subject to the termination provision below) license under any Necessary -Claims, to make, have made, use, sell, offer to sell, import, and otherwise -transfer the Software. For avoidance of doubt, no license is granted under -Facebook’s rights in any patent claims that are infringed by (i) modifications -to the Software made by you or any third party or (ii) the Software in -combination with any software or other technology. - -The license granted hereunder will terminate, automatically and without notice, -if you (or any of your subsidiaries, corporate affiliates or agents) initiate -directly or indirectly, or take a direct financial interest in, any Patent -Assertion: (i) against Facebook or any of its subsidiaries or corporate -affiliates, (ii) against any party if such Patent Assertion arises in whole or -in part from any software, technology, product or service of Facebook or any of -its subsidiaries or corporate affiliates, or (iii) against any party relating -to the Software. Notwithstanding the foregoing, if Facebook or any of its -subsidiaries or corporate affiliates files a lawsuit alleging patent -infringement against you in the first instance, and you respond by filing a -patent infringement counterclaim in that lawsuit against that party that is -unrelated to the Software, the license granted hereunder will not terminate -under section (i) of this paragraph due to such counterclaim. - -A "Necessary Claim" is a claim of a patent owned by Facebook that is -necessarily infringed by the Software standing alone. - -A "Patent Assertion" is any lawsuit or other action alleging direct, indirect, -or contributory infringement or inducement to infringe any patent, including a -cross-claim or counterclaim. diff --git a/vendor/github.com/flosch/pongo2/go.mod b/vendor/github.com/flosch/pongo2/go.mod deleted file mode 100644 index 06b6c25..0000000 --- a/vendor/github.com/flosch/pongo2/go.mod +++ /dev/null @@ -1,13 +0,0 @@ -module github.com/flosch/pongo2 - -require ( - github.com/go-check/check v0.0.0-20180628173108-788fd7840127 - github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 - github.com/juju/loggo v0.0.0-20180524022052-584905176618 // indirect - github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073 // indirect - github.com/kr/pretty v0.1.0 // indirect - github.com/mattn/goveralls v0.0.2 // indirect - golang.org/x/tools v0.0.0-20181221001348-537d06c36207 // indirect - gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect - gopkg.in/yaml.v2 v2.2.2 // indirect -) diff --git a/vendor/github.com/gorilla/websocket/.travis.yml b/vendor/github.com/gorilla/websocket/.travis.yml deleted file mode 100644 index a49db51..0000000 --- a/vendor/github.com/gorilla/websocket/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: go -sudo: false - -matrix: - include: - - go: 1.7.x - - go: 1.8.x - - go: 1.9.x - - go: 1.10.x - - go: 1.11.x - - go: tip - allow_failures: - - go: tip - -script: - - go get -t -v ./... - - diff -u <(echo -n) <(gofmt -d .) - - go vet $(go list ./... | grep -v /vendor/) - - go test -v -race ./... diff --git a/vendor/github.com/gorilla/websocket/README.md b/vendor/github.com/gorilla/websocket/README.md index 20e391f..2517a28 100644 --- a/vendor/github.com/gorilla/websocket/README.md +++ b/vendor/github.com/gorilla/websocket/README.md @@ -1,14 +1,21 @@ # Gorilla WebSocket +[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket) +[![CircleCI](https://circleci.com/gh/gorilla/websocket.svg?style=svg)](https://circleci.com/gh/gorilla/websocket) + Gorilla WebSocket is a [Go](http://golang.org/) implementation of the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. -[![Build Status](https://travis-ci.org/gorilla/websocket.svg?branch=master)](https://travis-ci.org/gorilla/websocket) -[![GoDoc](https://godoc.org/github.com/gorilla/websocket?status.svg)](https://godoc.org/github.com/gorilla/websocket) + +--- + +⚠️ **[The Gorilla WebSocket Package is looking for a new maintainer](https://github.com/gorilla/websocket/issues/370)** + +--- ### Documentation -* [API Reference](http://godoc.org/github.com/gorilla/websocket) +* [API Reference](https://pkg.go.dev/github.com/gorilla/websocket?tab=doc) * [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat) * [Command example](https://github.com/gorilla/websocket/tree/master/examples/command) * [Client and server example](https://github.com/gorilla/websocket/tree/master/examples/echo) @@ -27,38 +34,6 @@ package API is stable. ### Protocol Compliance The Gorilla WebSocket package passes the server tests in the [Autobahn Test -Suite](http://autobahn.ws/testsuite) using the application in the [examples/autobahn +Suite](https://github.com/crossbario/autobahn-testsuite) using the application in the [examples/autobahn subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn). -### Gorilla WebSocket compared with other packages - - - - - - - - - - - - - - - - - - -
github.com/gorillagolang.org/x/net
RFC 6455 Features
Passes Autobahn Test SuiteYesNo
Receive fragmented messageYesNo, see note 1
Send close messageYesNo
Send pings and receive pongsYesNo
Get the type of a received data messageYesYes, see note 2
Other Features
Compression ExtensionsExperimentalNo
Read message using io.ReaderYesNo, see note 3
Write message using io.WriteCloserYesNo, see note 3
- -Notes: - -1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html). -2. The application can get the type of a received data message by implementing - a [Codec marshal](http://godoc.org/golang.org/x/net/websocket#Codec.Marshal) - function. -3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries. - Read returns when the input buffer is full or a frame boundary is - encountered. Each call to Write sends a single frame message. The Gorilla - io.Reader and io.WriteCloser operate on a single WebSocket message. - diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go index 2e32fd5..2efd835 100644 --- a/vendor/github.com/gorilla/websocket/client.go +++ b/vendor/github.com/gorilla/websocket/client.go @@ -48,15 +48,23 @@ func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufS } // A Dialer contains options for connecting to WebSocket server. +// +// It is safe to call Dialer's methods concurrently. type Dialer struct { // NetDial specifies the dial function for creating TCP connections. If // NetDial is nil, net.Dial is used. NetDial func(network, addr string) (net.Conn, error) // NetDialContext specifies the dial function for creating TCP connections. If - // NetDialContext is nil, net.DialContext is used. + // NetDialContext is nil, NetDial is used. NetDialContext func(ctx context.Context, network, addr string) (net.Conn, error) + // NetDialTLSContext specifies the dial function for creating TLS/TCP connections. If + // NetDialTLSContext is nil, NetDialContext is used. + // If NetDialTLSContext is set, Dial assumes the TLS handshake is done there and + // TLSClientConfig is ignored. + NetDialTLSContext func(ctx context.Context, network, addr string) (net.Conn, error) + // Proxy specifies a function to return a proxy for a given // Request. If the function returns a non-nil error, the // request is aborted with the provided error. @@ -65,12 +73,14 @@ type Dialer struct { // TLSClientConfig specifies the TLS configuration to use with tls.Client. // If nil, the default configuration is used. + // If either NetDialTLS or NetDialTLSContext are set, Dial assumes the TLS handshake + // is done there and TLSClientConfig is ignored. TLSClientConfig *tls.Config // HandshakeTimeout specifies the duration for the handshake to complete. HandshakeTimeout time.Duration - // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer + // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer // size is zero, then a useful default size is used. The I/O buffer sizes // do not limit the size of the messages that can be sent or received. ReadBufferSize, WriteBufferSize int @@ -140,7 +150,7 @@ var nilDialer = *DefaultDialer // Use the response.Header to get the selected subprotocol // (Sec-WebSocket-Protocol) and cookies (Set-Cookie). // -// The context will be used in the request and in the Dialer +// The context will be used in the request and in the Dialer. // // If the WebSocket handshake fails, ErrBadHandshake is returned along with a // non-nil *http.Response so that callers can handle redirects, authentication, @@ -176,7 +186,7 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h } req := &http.Request{ - Method: "GET", + Method: http.MethodGet, URL: u, Proto: "HTTP/1.1", ProtoMajor: 1, @@ -237,13 +247,32 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h // Get network dial function. var netDial func(network, add string) (net.Conn, error) - if d.NetDialContext != nil { - netDial = func(network, addr string) (net.Conn, error) { - return d.NetDialContext(ctx, network, addr) + switch u.Scheme { + case "http": + if d.NetDialContext != nil { + netDial = func(network, addr string) (net.Conn, error) { + return d.NetDialContext(ctx, network, addr) + } + } else if d.NetDial != nil { + netDial = d.NetDial } - } else if d.NetDial != nil { - netDial = d.NetDial - } else { + case "https": + if d.NetDialTLSContext != nil { + netDial = func(network, addr string) (net.Conn, error) { + return d.NetDialTLSContext(ctx, network, addr) + } + } else if d.NetDialContext != nil { + netDial = func(network, addr string) (net.Conn, error) { + return d.NetDialContext(ctx, network, addr) + } + } else if d.NetDial != nil { + netDial = d.NetDial + } + default: + return nil, nil, errMalformedURL + } + + if netDial == nil { netDialer := &net.Dialer{} netDial = func(network, addr string) (net.Conn, error) { return netDialer.DialContext(ctx, network, addr) @@ -304,7 +333,9 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h } }() - if u.Scheme == "https" { + if u.Scheme == "https" && d.NetDialTLSContext == nil { + // If NetDialTLSContext is set, assume that the TLS handshake has already been done + cfg := cloneTLSConfig(d.TLSClientConfig) if cfg.ServerName == "" { cfg.ServerName = hostNoPort @@ -312,11 +343,12 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h tlsConn := tls.Client(netConn, cfg) netConn = tlsConn - var err error - if trace != nil { - err = doHandshakeWithTrace(trace, tlsConn, cfg) - } else { - err = doHandshake(tlsConn, cfg) + if trace != nil && trace.TLSHandshakeStart != nil { + trace.TLSHandshakeStart() + } + err := doHandshake(ctx, tlsConn, cfg) + if trace != nil && trace.TLSHandshakeDone != nil { + trace.TLSHandshakeDone(tlsConn.ConnectionState(), err) } if err != nil { @@ -348,8 +380,8 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h } if resp.StatusCode != 101 || - !strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") || - !strings.EqualFold(resp.Header.Get("Connection"), "upgrade") || + !tokenListContainsValue(resp.Header, "Upgrade", "websocket") || + !tokenListContainsValue(resp.Header, "Connection", "upgrade") || resp.Header.Get("Sec-Websocket-Accept") != computeAcceptKey(challengeKey) { // Before closing the network connection on return from this // function, slurp up some of the response to aid application @@ -382,14 +414,9 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h return conn, resp, nil } -func doHandshake(tlsConn *tls.Conn, cfg *tls.Config) error { - if err := tlsConn.Handshake(); err != nil { - return err - } - if !cfg.InsecureSkipVerify { - if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { - return err - } +func cloneTLSConfig(cfg *tls.Config) *tls.Config { + if cfg == nil { + return &tls.Config{} } - return nil + return cfg.Clone() } diff --git a/vendor/github.com/gorilla/websocket/client_clone.go b/vendor/github.com/gorilla/websocket/client_clone.go deleted file mode 100644 index 4f0d943..0000000 --- a/vendor/github.com/gorilla/websocket/client_clone.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.8 - -package websocket - -import "crypto/tls" - -func cloneTLSConfig(cfg *tls.Config) *tls.Config { - if cfg == nil { - return &tls.Config{} - } - return cfg.Clone() -} diff --git a/vendor/github.com/gorilla/websocket/client_clone_legacy.go b/vendor/github.com/gorilla/websocket/client_clone_legacy.go deleted file mode 100644 index babb007..0000000 --- a/vendor/github.com/gorilla/websocket/client_clone_legacy.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.8 - -package websocket - -import "crypto/tls" - -// cloneTLSConfig clones all public fields except the fields -// SessionTicketsDisabled and SessionTicketKey. This avoids copying the -// sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a -// config in active use. -func cloneTLSConfig(cfg *tls.Config) *tls.Config { - if cfg == nil { - return &tls.Config{} - } - return &tls.Config{ - Rand: cfg.Rand, - Time: cfg.Time, - Certificates: cfg.Certificates, - NameToCertificate: cfg.NameToCertificate, - GetCertificate: cfg.GetCertificate, - RootCAs: cfg.RootCAs, - NextProtos: cfg.NextProtos, - ServerName: cfg.ServerName, - ClientAuth: cfg.ClientAuth, - ClientCAs: cfg.ClientCAs, - InsecureSkipVerify: cfg.InsecureSkipVerify, - CipherSuites: cfg.CipherSuites, - PreferServerCipherSuites: cfg.PreferServerCipherSuites, - ClientSessionCache: cfg.ClientSessionCache, - MinVersion: cfg.MinVersion, - MaxVersion: cfg.MaxVersion, - CurvePreferences: cfg.CurvePreferences, - } -} diff --git a/vendor/github.com/gorilla/websocket/conn.go b/vendor/github.com/gorilla/websocket/conn.go index d2a21c1..331eebc 100644 --- a/vendor/github.com/gorilla/websocket/conn.go +++ b/vendor/github.com/gorilla/websocket/conn.go @@ -13,6 +13,7 @@ import ( "math/rand" "net" "strconv" + "strings" "sync" "time" "unicode/utf8" @@ -244,8 +245,8 @@ type Conn struct { subprotocol string // Write fields - mu chan bool // used as mutex to protect write to conn - writeBuf []byte // frame is constructed in this buffer. + mu chan struct{} // used as mutex to protect write to conn + writeBuf []byte // frame is constructed in this buffer. writePool BufferPool writeBufSize int writeDeadline time.Time @@ -260,10 +261,12 @@ type Conn struct { newCompressionWriter func(io.WriteCloser, int) io.WriteCloser // Read fields - reader io.ReadCloser // the current reader returned to the application - readErr error - br *bufio.Reader - readRemaining int64 // bytes remaining in current frame. + reader io.ReadCloser // the current reader returned to the application + readErr error + br *bufio.Reader + // bytes remaining in current frame. + // set setReadRemaining to safely update this value and prevent overflow + readRemaining int64 readFinal bool // true the current message has more frames. readLength int64 // Message size. readLimit int64 // Maximum message size. @@ -300,8 +303,8 @@ func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, writeBuf = make([]byte, writeBufferSize) } - mu := make(chan bool, 1) - mu <- true + mu := make(chan struct{}, 1) + mu <- struct{}{} c := &Conn{ isServer: isServer, br: br, @@ -320,6 +323,17 @@ func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, return c } +// setReadRemaining tracks the number of bytes remaining on the connection. If n +// overflows, an ErrReadLimit is returned. +func (c *Conn) setReadRemaining(n int64) error { + if n < 0 { + return ErrReadLimit + } + + c.readRemaining = n + return nil +} + // Subprotocol returns the negotiated protocol for the connection. func (c *Conn) Subprotocol() string { return c.subprotocol @@ -364,7 +378,7 @@ func (c *Conn) read(n int) ([]byte, error) { func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error { <-c.mu - defer func() { c.mu <- true }() + defer func() { c.mu <- struct{}{} }() c.writeErrMu.Lock() err := c.writeErr @@ -388,6 +402,12 @@ func (c *Conn) write(frameType int, deadline time.Time, buf0, buf1 []byte) error return nil } +func (c *Conn) writeBufs(bufs ...[]byte) error { + b := net.Buffers(bufs) + _, err := b.WriteTo(c.conn) + return err +} + // WriteControl writes a control message with the given deadline. The allowed // message types are CloseMessage, PingMessage and PongMessage. func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) error { @@ -416,7 +436,7 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er maskBytes(key, 0, buf[6:]) } - d := time.Hour * 1000 + d := 1000 * time.Hour if !deadline.IsZero() { d = deadline.Sub(time.Now()) if d < 0 { @@ -431,7 +451,7 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er case <-timer.C: return errWriteTimeout } - defer func() { c.mu <- true }() + defer func() { c.mu <- struct{}{} }() c.writeErrMu.Lock() err := c.writeErr @@ -451,7 +471,8 @@ func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) er return err } -func (c *Conn) prepWrite(messageType int) error { +// beginMessage prepares a connection and message writer for a new message. +func (c *Conn) beginMessage(mw *messageWriter, messageType int) error { // Close previous writer if not already closed by the application. It's // probably better to return an error in this situation, but we cannot // change this without breaking existing applications. @@ -471,6 +492,10 @@ func (c *Conn) prepWrite(messageType int) error { return err } + mw.c = c + mw.frameType = messageType + mw.pos = maxFrameHeaderSize + if c.writeBuf == nil { wpd, ok := c.writePool.Get().(writePoolData) if ok { @@ -491,16 +516,11 @@ func (c *Conn) prepWrite(messageType int) error { // All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and // PongMessage) are supported. func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) { - if err := c.prepWrite(messageType); err != nil { + var mw messageWriter + if err := c.beginMessage(&mw, messageType); err != nil { return nil, err } - - mw := &messageWriter{ - c: c, - frameType: messageType, - pos: maxFrameHeaderSize, - } - c.writer = mw + c.writer = &mw if c.newCompressionWriter != nil && c.enableWriteCompression && isData(messageType) { w := c.newCompressionWriter(c.writer, c.compressionLevel) mw.compress = true @@ -517,10 +537,16 @@ type messageWriter struct { err error } -func (w *messageWriter) fatal(err error) error { +func (w *messageWriter) endMessage(err error) error { if w.err != nil { - w.err = err - w.c.writer = nil + return err + } + c := w.c + w.err = err + c.writer = nil + if c.writePool != nil { + c.writePool.Put(writePoolData{buf: c.writeBuf}) + c.writeBuf = nil } return err } @@ -534,7 +560,7 @@ func (w *messageWriter) flushFrame(final bool, extra []byte) error { // Check for invalid control frames. if isControl(w.frameType) && (!final || length > maxControlFramePayloadSize) { - return w.fatal(errInvalidControlFrame) + return w.endMessage(errInvalidControlFrame) } b0 := byte(w.frameType) @@ -579,7 +605,7 @@ func (w *messageWriter) flushFrame(final bool, extra []byte) error { copy(c.writeBuf[maxFrameHeaderSize-4:], key[:]) maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:w.pos]) if len(extra) > 0 { - return c.writeFatal(errors.New("websocket: internal error, extra used in client mode")) + return w.endMessage(c.writeFatal(errors.New("websocket: internal error, extra used in client mode"))) } } @@ -600,15 +626,11 @@ func (w *messageWriter) flushFrame(final bool, extra []byte) error { c.isWriting = false if err != nil { - return w.fatal(err) + return w.endMessage(err) } if final { - c.writer = nil - if c.writePool != nil { - c.writePool.Put(writePoolData{buf: c.writeBuf}) - c.writeBuf = nil - } + w.endMessage(errWriteClosed) return nil } @@ -706,11 +728,7 @@ func (w *messageWriter) Close() error { if w.err != nil { return w.err } - if err := w.flushFrame(true, nil); err != nil { - return err - } - w.err = errWriteClosed - return nil + return w.flushFrame(true, nil) } // WritePreparedMessage writes prepared message into connection. @@ -742,10 +760,10 @@ func (c *Conn) WriteMessage(messageType int, data []byte) error { if c.isServer && (c.newCompressionWriter == nil || !c.enableWriteCompression) { // Fast path with no allocations and single frame. - if err := c.prepWrite(messageType); err != nil { + var mw messageWriter + if err := c.beginMessage(&mw, messageType); err != nil { return err } - mw := messageWriter{c: c, frameType: messageType, pos: maxFrameHeaderSize} n := copy(c.writeBuf[mw.pos:], data) mw.pos += n data = data[n:] @@ -783,50 +801,82 @@ func (c *Conn) advanceFrame() (int, error) { } // 2. Read and parse first two bytes of frame header. + // To aid debugging, collect and report all errors in the first two bytes + // of the header. + + var errors []string p, err := c.read(2) if err != nil { return noFrame, err } - final := p[0]&finalBit != 0 frameType := int(p[0] & 0xf) + final := p[0]&finalBit != 0 + rsv1 := p[0]&rsv1Bit != 0 + rsv2 := p[0]&rsv2Bit != 0 + rsv3 := p[0]&rsv3Bit != 0 mask := p[1]&maskBit != 0 - c.readRemaining = int64(p[1] & 0x7f) + c.setReadRemaining(int64(p[1] & 0x7f)) c.readDecompress = false - if c.newDecompressionReader != nil && (p[0]&rsv1Bit) != 0 { - c.readDecompress = true - p[0] &^= rsv1Bit + if rsv1 { + if c.newDecompressionReader != nil { + c.readDecompress = true + } else { + errors = append(errors, "RSV1 set") + } + } + + if rsv2 { + errors = append(errors, "RSV2 set") } - if rsv := p[0] & (rsv1Bit | rsv2Bit | rsv3Bit); rsv != 0 { - return noFrame, c.handleProtocolError("unexpected reserved bits 0x" + strconv.FormatInt(int64(rsv), 16)) + if rsv3 { + errors = append(errors, "RSV3 set") } switch frameType { case CloseMessage, PingMessage, PongMessage: if c.readRemaining > maxControlFramePayloadSize { - return noFrame, c.handleProtocolError("control frame length > 125") + errors = append(errors, "len > 125 for control") } if !final { - return noFrame, c.handleProtocolError("control frame not final") + errors = append(errors, "FIN not set on control") } case TextMessage, BinaryMessage: if !c.readFinal { - return noFrame, c.handleProtocolError("message start before final message frame") + errors = append(errors, "data before FIN") } c.readFinal = final case continuationFrame: if c.readFinal { - return noFrame, c.handleProtocolError("continuation after final message frame") + errors = append(errors, "continuation after FIN") } c.readFinal = final default: - return noFrame, c.handleProtocolError("unknown opcode " + strconv.Itoa(frameType)) + errors = append(errors, "bad opcode "+strconv.Itoa(frameType)) + } + + if mask != c.isServer { + errors = append(errors, "bad MASK") } - // 3. Read and parse frame length. + if len(errors) > 0 { + return noFrame, c.handleProtocolError(strings.Join(errors, ", ")) + } + + // 3. Read and parse frame length as per + // https://tools.ietf.org/html/rfc6455#section-5.2 + // + // The length of the "Payload data", in bytes: if 0-125, that is the payload + // length. + // - If 126, the following 2 bytes interpreted as a 16-bit unsigned + // integer are the payload length. + // - If 127, the following 8 bytes interpreted as + // a 64-bit unsigned integer (the most significant bit MUST be 0) are the + // payload length. Multibyte length quantities are expressed in network byte + // order. switch c.readRemaining { case 126: @@ -834,21 +884,23 @@ func (c *Conn) advanceFrame() (int, error) { if err != nil { return noFrame, err } - c.readRemaining = int64(binary.BigEndian.Uint16(p)) + + if err := c.setReadRemaining(int64(binary.BigEndian.Uint16(p))); err != nil { + return noFrame, err + } case 127: p, err := c.read(8) if err != nil { return noFrame, err } - c.readRemaining = int64(binary.BigEndian.Uint64(p)) + + if err := c.setReadRemaining(int64(binary.BigEndian.Uint64(p))); err != nil { + return noFrame, err + } } // 4. Handle frame masking. - if mask != c.isServer { - return noFrame, c.handleProtocolError("incorrect mask flag") - } - if mask { c.readMaskPos = 0 p, err := c.read(len(c.readMaskKey)) @@ -863,6 +915,12 @@ func (c *Conn) advanceFrame() (int, error) { if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage { c.readLength += c.readRemaining + // Don't allow readLength to overflow in the presence of a large readRemaining + // counter. + if c.readLength < 0 { + return noFrame, ErrReadLimit + } + if c.readLimit > 0 && c.readLength > c.readLimit { c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait)) return noFrame, ErrReadLimit @@ -876,7 +934,7 @@ func (c *Conn) advanceFrame() (int, error) { var payload []byte if c.readRemaining > 0 { payload, err = c.read(int(c.readRemaining)) - c.readRemaining = 0 + c.setReadRemaining(0) if err != nil { return noFrame, err } @@ -902,7 +960,7 @@ func (c *Conn) advanceFrame() (int, error) { if len(payload) >= 2 { closeCode = int(binary.BigEndian.Uint16(payload)) if !isValidReceivedCloseCode(closeCode) { - return noFrame, c.handleProtocolError("invalid close code") + return noFrame, c.handleProtocolError("bad close code " + strconv.Itoa(closeCode)) } closeText = string(payload[2:]) if !utf8.ValidString(closeText) { @@ -919,7 +977,11 @@ func (c *Conn) advanceFrame() (int, error) { } func (c *Conn) handleProtocolError(message string) error { - c.WriteControl(CloseMessage, FormatCloseMessage(CloseProtocolError, message), time.Now().Add(writeWait)) + data := FormatCloseMessage(CloseProtocolError, message) + if len(data) > maxControlFramePayloadSize { + data = data[:maxControlFramePayloadSize] + } + c.WriteControl(CloseMessage, data, time.Now().Add(writeWait)) return errors.New("websocket: " + message) } @@ -949,6 +1011,7 @@ func (c *Conn) NextReader() (messageType int, r io.Reader, err error) { c.readErr = hideTempErr(err) break } + if frameType == TextMessage || frameType == BinaryMessage { c.messageReader = &messageReader{c} c.reader = c.messageReader @@ -989,7 +1052,9 @@ func (r *messageReader) Read(b []byte) (int, error) { if c.isServer { c.readMaskPos = maskBytes(c.readMaskKey, c.readMaskPos, b[:n]) } - c.readRemaining -= int64(n) + rem := c.readRemaining + rem -= int64(n) + c.setReadRemaining(rem) if c.readRemaining > 0 && c.readErr == io.EOF { c.readErr = errUnexpectedEOF } @@ -1041,7 +1106,7 @@ func (c *Conn) SetReadDeadline(t time.Time) error { return c.conn.SetReadDeadline(t) } -// SetReadLimit sets the maximum size for a message read from the peer. If a +// SetReadLimit sets the maximum size in bytes for a message read from the peer. If a // message exceeds the limit, the connection sends a close message to the peer // and returns ErrReadLimit to the application. func (c *Conn) SetReadLimit(limit int64) { diff --git a/vendor/github.com/gorilla/websocket/conn_write.go b/vendor/github.com/gorilla/websocket/conn_write.go deleted file mode 100644 index a509a21..0000000 --- a/vendor/github.com/gorilla/websocket/conn_write.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.8 - -package websocket - -import "net" - -func (c *Conn) writeBufs(bufs ...[]byte) error { - b := net.Buffers(bufs) - _, err := b.WriteTo(c.conn) - return err -} diff --git a/vendor/github.com/gorilla/websocket/conn_write_legacy.go b/vendor/github.com/gorilla/websocket/conn_write_legacy.go deleted file mode 100644 index 37edaff..0000000 --- a/vendor/github.com/gorilla/websocket/conn_write_legacy.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.8 - -package websocket - -func (c *Conn) writeBufs(bufs ...[]byte) error { - for _, buf := range bufs { - if len(buf) > 0 { - if _, err := c.conn.Write(buf); err != nil { - return err - } - } - } - return nil -} diff --git a/vendor/github.com/gorilla/websocket/doc.go b/vendor/github.com/gorilla/websocket/doc.go index dcce1a6..8db0cef 100644 --- a/vendor/github.com/gorilla/websocket/doc.go +++ b/vendor/github.com/gorilla/websocket/doc.go @@ -151,6 +151,53 @@ // checking. The application is responsible for checking the Origin header // before calling the Upgrade function. // +// Buffers +// +// Connections buffer network input and output to reduce the number +// of system calls when reading or writing messages. +// +// Write buffers are also used for constructing WebSocket frames. See RFC 6455, +// Section 5 for a discussion of message framing. A WebSocket frame header is +// written to the network each time a write buffer is flushed to the network. +// Decreasing the size of the write buffer can increase the amount of framing +// overhead on the connection. +// +// The buffer sizes in bytes are specified by the ReadBufferSize and +// WriteBufferSize fields in the Dialer and Upgrader. The Dialer uses a default +// size of 4096 when a buffer size field is set to zero. The Upgrader reuses +// buffers created by the HTTP server when a buffer size field is set to zero. +// The HTTP server buffers have a size of 4096 at the time of this writing. +// +// The buffer sizes do not limit the size of a message that can be read or +// written by a connection. +// +// Buffers are held for the lifetime of the connection by default. If the +// Dialer or Upgrader WriteBufferPool field is set, then a connection holds the +// write buffer only when writing a message. +// +// Applications should tune the buffer sizes to balance memory use and +// performance. Increasing the buffer size uses more memory, but can reduce the +// number of system calls to read or write the network. In the case of writing, +// increasing the buffer size can reduce the number of frame headers written to +// the network. +// +// Some guidelines for setting buffer parameters are: +// +// Limit the buffer sizes to the maximum expected message size. Buffers larger +// than the largest message do not provide any benefit. +// +// Depending on the distribution of message sizes, setting the buffer size to +// a value less than the maximum expected message size can greatly reduce memory +// use with a small impact on performance. Here's an example: If 99% of the +// messages are smaller than 256 bytes and the maximum message size is 512 +// bytes, then a buffer size of 256 bytes will result in 1.01 more system calls +// than a buffer size of 512 bytes. The memory savings is 50%. +// +// A write buffer pool is useful when the application has a modest number +// writes over a large number of connections. when buffers are pooled, a larger +// buffer size has a reduced impact on total memory use and has the benefit of +// reducing system calls and frame overhead. +// // Compression EXPERIMENTAL // // Per message compression extensions (RFC 7692) are experimentally supported diff --git a/vendor/github.com/gorilla/websocket/join.go b/vendor/github.com/gorilla/websocket/join.go new file mode 100644 index 0000000..c64f8c8 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/join.go @@ -0,0 +1,42 @@ +// Copyright 2019 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "io" + "strings" +) + +// JoinMessages concatenates received messages to create a single io.Reader. +// The string term is appended to each message. The returned reader does not +// support concurrent calls to the Read method. +func JoinMessages(c *Conn, term string) io.Reader { + return &joinReader{c: c, term: term} +} + +type joinReader struct { + c *Conn + term string + r io.Reader +} + +func (r *joinReader) Read(p []byte) (int, error) { + if r.r == nil { + var err error + _, r.r, err = r.c.NextReader() + if err != nil { + return 0, err + } + if r.term != "" { + r.r = io.MultiReader(r.r, strings.NewReader(r.term)) + } + } + n, err := r.r.Read(p) + if err == io.EOF { + err = nil + r.r = nil + } + return n, err +} diff --git a/vendor/github.com/gorilla/websocket/mask.go b/vendor/github.com/gorilla/websocket/mask.go index 577fce9..d0742bf 100644 --- a/vendor/github.com/gorilla/websocket/mask.go +++ b/vendor/github.com/gorilla/websocket/mask.go @@ -2,6 +2,7 @@ // this source code is governed by a BSD-style license that can be found in the // LICENSE file. +//go:build !appengine // +build !appengine package websocket diff --git a/vendor/github.com/gorilla/websocket/mask_safe.go b/vendor/github.com/gorilla/websocket/mask_safe.go index 2aac060..36250ca 100644 --- a/vendor/github.com/gorilla/websocket/mask_safe.go +++ b/vendor/github.com/gorilla/websocket/mask_safe.go @@ -2,6 +2,7 @@ // this source code is governed by a BSD-style license that can be found in the // LICENSE file. +//go:build appengine // +build appengine package websocket diff --git a/vendor/github.com/gorilla/websocket/prepared.go b/vendor/github.com/gorilla/websocket/prepared.go index 74ec565..c854225 100644 --- a/vendor/github.com/gorilla/websocket/prepared.go +++ b/vendor/github.com/gorilla/websocket/prepared.go @@ -73,8 +73,8 @@ func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) { // Prepare a frame using a 'fake' connection. // TODO: Refactor code in conn.go to allow more direct construction of // the frame. - mu := make(chan bool, 1) - mu <- true + mu := make(chan struct{}, 1) + mu <- struct{}{} var nc prepareConn c := &Conn{ conn: &nc, diff --git a/vendor/github.com/gorilla/websocket/proxy.go b/vendor/github.com/gorilla/websocket/proxy.go index bf2478e..e0f466b 100644 --- a/vendor/github.com/gorilla/websocket/proxy.go +++ b/vendor/github.com/gorilla/websocket/proxy.go @@ -22,18 +22,18 @@ func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) { func init() { proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) { - return &httpProxyDialer{proxyURL: proxyURL, fowardDial: forwardDialer.Dial}, nil + return &httpProxyDialer{proxyURL: proxyURL, forwardDial: forwardDialer.Dial}, nil }) } type httpProxyDialer struct { - proxyURL *url.URL - fowardDial func(network, addr string) (net.Conn, error) + proxyURL *url.URL + forwardDial func(network, addr string) (net.Conn, error) } func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) { hostPort, _ := hostPortNoPort(hpd.proxyURL) - conn, err := hpd.fowardDial(network, hostPort) + conn, err := hpd.forwardDial(network, hostPort) if err != nil { return nil, err } @@ -48,7 +48,7 @@ func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) } connectReq := &http.Request{ - Method: "CONNECT", + Method: http.MethodConnect, URL: &url.URL{Opaque: addr}, Host: addr, Header: connectHeader, diff --git a/vendor/github.com/gorilla/websocket/server.go b/vendor/github.com/gorilla/websocket/server.go index a761824..24d53b3 100644 --- a/vendor/github.com/gorilla/websocket/server.go +++ b/vendor/github.com/gorilla/websocket/server.go @@ -23,11 +23,13 @@ func (e HandshakeError) Error() string { return e.message } // Upgrader specifies parameters for upgrading an HTTP connection to a // WebSocket connection. +// +// It is safe to call Upgrader's methods concurrently. type Upgrader struct { // HandshakeTimeout specifies the duration for the handshake to complete. HandshakeTimeout time.Duration - // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer + // ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. If a buffer // size is zero, then buffers allocated by the HTTP server are used. The // I/O buffer sizes do not limit the size of the messages that can be sent // or received. @@ -115,8 +117,8 @@ func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header // Upgrade upgrades the HTTP server connection to the WebSocket protocol. // // The responseHeader is included in the response to the client's upgrade -// request. Use the responseHeader to specify cookies (Set-Cookie) and the -// application negotiated subprotocol (Sec-WebSocket-Protocol). +// request. Use the responseHeader to specify cookies (Set-Cookie). To specify +// subprotocols supported by the server, set Upgrader.Subprotocols directly. // // If the upgrade fails, then Upgrade replies to the client with an HTTP error // response. @@ -131,7 +133,7 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'websocket' token not found in 'Upgrade' header") } - if r.Method != "GET" { + if r.Method != http.MethodGet { return u.returnError(w, r, http.StatusMethodNotAllowed, badHandshake+"request method is not GET") } @@ -153,7 +155,7 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade challengeKey := r.Header.Get("Sec-Websocket-Key") if challengeKey == "" { - return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: `Sec-WebSocket-Key' header is missing or blank") + return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'Sec-WebSocket-Key' header is missing or blank") } subprotocol := u.selectSubprotocol(r, responseHeader) diff --git a/vendor/github.com/gorilla/websocket/tls_handshake.go b/vendor/github.com/gorilla/websocket/tls_handshake.go new file mode 100644 index 0000000..a62b68c --- /dev/null +++ b/vendor/github.com/gorilla/websocket/tls_handshake.go @@ -0,0 +1,21 @@ +//go:build go1.17 +// +build go1.17 + +package websocket + +import ( + "context" + "crypto/tls" +) + +func doHandshake(ctx context.Context, tlsConn *tls.Conn, cfg *tls.Config) error { + if err := tlsConn.HandshakeContext(ctx); err != nil { + return err + } + if !cfg.InsecureSkipVerify { + if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/gorilla/websocket/tls_handshake_116.go b/vendor/github.com/gorilla/websocket/tls_handshake_116.go new file mode 100644 index 0000000..e1b2b44 --- /dev/null +++ b/vendor/github.com/gorilla/websocket/tls_handshake_116.go @@ -0,0 +1,21 @@ +//go:build !go1.17 +// +build !go1.17 + +package websocket + +import ( + "context" + "crypto/tls" +) + +func doHandshake(ctx context.Context, tlsConn *tls.Conn, cfg *tls.Config) error { + if err := tlsConn.Handshake(); err != nil { + return err + } + if !cfg.InsecureSkipVerify { + if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/gorilla/websocket/trace.go b/vendor/github.com/gorilla/websocket/trace.go deleted file mode 100644 index 834f122..0000000 --- a/vendor/github.com/gorilla/websocket/trace.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build go1.8 - -package websocket - -import ( - "crypto/tls" - "net/http/httptrace" -) - -func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error { - if trace.TLSHandshakeStart != nil { - trace.TLSHandshakeStart() - } - err := doHandshake(tlsConn, cfg) - if trace.TLSHandshakeDone != nil { - trace.TLSHandshakeDone(tlsConn.ConnectionState(), err) - } - return err -} diff --git a/vendor/github.com/gorilla/websocket/trace_17.go b/vendor/github.com/gorilla/websocket/trace_17.go deleted file mode 100644 index 77d05a0..0000000 --- a/vendor/github.com/gorilla/websocket/trace_17.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build !go1.8 - -package websocket - -import ( - "crypto/tls" - "net/http/httptrace" -) - -func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error { - return doHandshake(tlsConn, cfg) -} diff --git a/vendor/github.com/gorilla/websocket/util.go b/vendor/github.com/gorilla/websocket/util.go index 354001e..7bf2f66 100644 --- a/vendor/github.com/gorilla/websocket/util.go +++ b/vendor/github.com/gorilla/websocket/util.go @@ -31,68 +31,113 @@ func generateChallengeKey() (string, error) { return base64.StdEncoding.EncodeToString(p), nil } -// Octet types from RFC 2616. -var octetTypes [256]byte - -const ( - isTokenOctet = 1 << iota - isSpaceOctet -) - -func init() { - // From RFC 2616 - // - // OCTET = - // CHAR = - // CTL = - // CR = - // LF = - // SP = - // HT = - // <"> = - // CRLF = CR LF - // LWS = [CRLF] 1*( SP | HT ) - // TEXT = - // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> - // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT - // token = 1* - // qdtext = > - - for c := 0; c < 256; c++ { - var t byte - isCtl := c <= 31 || c == 127 - isChar := 0 <= c && c <= 127 - isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0 - if strings.IndexRune(" \t\r\n", rune(c)) >= 0 { - t |= isSpaceOctet - } - if isChar && !isCtl && !isSeparator { - t |= isTokenOctet - } - octetTypes[c] = t - } +// Token octets per RFC 2616. +var isTokenOctet = [256]bool{ + '!': true, + '#': true, + '$': true, + '%': true, + '&': true, + '\'': true, + '*': true, + '+': true, + '-': true, + '.': true, + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + 'A': true, + 'B': true, + 'C': true, + 'D': true, + 'E': true, + 'F': true, + 'G': true, + 'H': true, + 'I': true, + 'J': true, + 'K': true, + 'L': true, + 'M': true, + 'N': true, + 'O': true, + 'P': true, + 'Q': true, + 'R': true, + 'S': true, + 'T': true, + 'U': true, + 'W': true, + 'V': true, + 'X': true, + 'Y': true, + 'Z': true, + '^': true, + '_': true, + '`': true, + 'a': true, + 'b': true, + 'c': true, + 'd': true, + 'e': true, + 'f': true, + 'g': true, + 'h': true, + 'i': true, + 'j': true, + 'k': true, + 'l': true, + 'm': true, + 'n': true, + 'o': true, + 'p': true, + 'q': true, + 'r': true, + 's': true, + 't': true, + 'u': true, + 'v': true, + 'w': true, + 'x': true, + 'y': true, + 'z': true, + '|': true, + '~': true, } +// skipSpace returns a slice of the string s with all leading RFC 2616 linear +// whitespace removed. func skipSpace(s string) (rest string) { i := 0 for ; i < len(s); i++ { - if octetTypes[s[i]]&isSpaceOctet == 0 { + if b := s[i]; b != ' ' && b != '\t' { break } } return s[i:] } +// nextToken returns the leading RFC 2616 token of s and the string following +// the token. func nextToken(s string) (token, rest string) { i := 0 for ; i < len(s); i++ { - if octetTypes[s[i]]&isTokenOctet == 0 { + if !isTokenOctet[s[i]] { break } } return s[:i], s[i:] } +// nextTokenOrQuoted returns the leading token or quoted string per RFC 2616 +// and the string following the token or quoted string. func nextTokenOrQuoted(s string) (value string, rest string) { if !strings.HasPrefix(s, "\"") { return nextToken(s) @@ -128,7 +173,8 @@ func nextTokenOrQuoted(s string) (value string, rest string) { return "", "" } -// equalASCIIFold returns true if s is equal to t with ASCII case folding. +// equalASCIIFold returns true if s is equal to t with ASCII case folding as +// defined in RFC 4790. func equalASCIIFold(s, t string) bool { for s != "" && t != "" { sr, size := utf8.DecodeRuneInString(s) diff --git a/vendor/github.com/henrylee2cn/ameda/.gitignore b/vendor/github.com/henrylee2cn/ameda/.gitignore new file mode 100644 index 0000000..6857290 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/.gitignore @@ -0,0 +1,21 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +vendor/ + +*.sublime-project +*.sublime-workspace +.DS_Store +.idea +*.zip diff --git a/vendor/github.com/henrylee2cn/ameda/LICENSE b/vendor/github.com/henrylee2cn/ameda/LICENSE new file mode 100644 index 0000000..6346807 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 henrylee2cn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/henrylee2cn/ameda/README.md b/vendor/github.com/henrylee2cn/ameda/README.md new file mode 100644 index 0000000..27026de --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/README.md @@ -0,0 +1,3 @@ +# ameda [![report card](https://goreportcard.com/badge/github.com/henrylee2cn/ameda?style=flat-square)](http://goreportcard.com/report/henrylee2cn/ameda) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/henrylee2cn/ameda) + +Powerful toolbox for golang data types. diff --git a/vendor/github.com/henrylee2cn/ameda/atoi62.go b/vendor/github.com/henrylee2cn/ameda/atoi62.go new file mode 100644 index 0000000..3129466 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/atoi62.go @@ -0,0 +1,253 @@ +package ameda + +import ( + "errors" + "math" + "strconv" +) + +// ParseUint is like ParseInt but for unsigned numbers. +// NOTE: +// Compatible with standard package strconv. +func ParseUint(s string, base int, bitSize int) (uint64, error) { + // Ignore letter case + if base <= 36 { + return strconv.ParseUint(s, base, bitSize) + } + + const fnParseUint = "ParseUint" + + if base > 62 { + return 0, baseError(fnParseUint, s, base) + } + + if s == "" || !underscoreOK(s) { + return 0, syntaxError(fnParseUint, s) + } + + if bitSize == 0 { + bitSize = int(strconv.IntSize) + } else if bitSize < 0 || bitSize > 64 { + return 0, bitSizeError(fnParseUint, s, bitSize) + } + + // Cutoff is the smallest number such that cutoff*base > maxUint64. + // Use compile-time constants for common cases. + cutoff := math.MaxUint64/uint64(base) + 1 + + maxVal := uint64(1)<= byte(base) { + return 0, syntaxError(fnParseUint, s) + } + + if n >= cutoff { + // n*base overflows + return maxVal, rangeError(fnParseUint, s) + } + n *= uint64(base) + + n1 := n + uint64(d) + if n1 < n || n1 > maxVal { + // n+v overflows + return maxVal, rangeError(fnParseUint, s) + } + n = n1 + } + + return n, nil +} + +// ParseInt interprets a string s in the given base (0, 2 to 62) and +// bit size (0 to 64) and returns the corresponding value i. +// +// If base == 0, the base is implied by the string's prefix: +// base 2 for "0b", base 8 for "0" or "0o", base 16 for "0x", +// and base 10 otherwise. Also, for base == 0 only, underscore +// characters are permitted per the Go integer literal syntax. +// If base is below 0, is 1, or is above 62, an error is returned. +// +// The bitSize argument specifies the integer type +// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64 +// correspond to int, int8, int16, int32, and int64. +// If bitSize is below 0 or above 64, an error is returned. +// +// The errors that ParseInt returns have concrete type *NumError +// and include err.Num = s. If s is empty or contains invalid +// digits, err.Err = ErrSyntax and the returned value is 0; +// if the value corresponding to s cannot be represented by a +// signed integer of the given size, err.Err = ErrRange and the +// returned value is the maximum magnitude integer of the +// appropriate bitSize and sign. +// NOTE: +// Compatible with standard package strconv. +func ParseInt(s string, base int, bitSize int) (i int64, err error) { + // Ignore letter case + if base <= 36 { + return strconv.ParseInt(s, base, bitSize) + } + + const fnParseInt = "ParseInt" + + if s == "" { + return 0, syntaxError(fnParseInt, s) + } + + // Pick off leading sign. + s0 := s + neg := false + if s[0] == '+' { + s = s[1:] + } else if s[0] == '-' { + neg = true + s = s[1:] + } + + // Convert unsigned and check range. + var un uint64 + un, err = ParseUint(s, base, bitSize) + if err != nil && err.(*strconv.NumError).Err != strconv.ErrRange { + err.(*strconv.NumError).Func = fnParseInt + err.(*strconv.NumError).Num = s0 + return 0, err + } + + if bitSize == 0 { + bitSize = int(strconv.IntSize) + } + + cutoff := uint64(1 << uint(bitSize-1)) + if !neg && un >= cutoff { + return int64(cutoff - 1), rangeError(fnParseInt, s0) + } + if neg && un > cutoff { + return -int64(cutoff), rangeError(fnParseInt, s0) + } + n := int64(un) + if neg { + n = -n + } + return n, nil +} + +// underscoreOK reports whether the underscores in s are allowed. +// Checking them in this one function lets all the parsers skip over them simply. +// Underscore must appear only between digits or between a base prefix and a digit. +func underscoreOK(s string) bool { + // saw tracks the last character (class) we saw: + // ^ for beginning of number, + // 0 for a digit or base prefix, + // _ for an underscore, + // ! for none of the above. + saw := '^' + i := 0 + + // Optional sign. + if len(s) >= 1 && (s[0] == '-' || s[0] == '+') { + s = s[1:] + } + + // Optional base prefix. + hex := false + if len(s) >= 2 && s[0] == '0' && (lower(s[1]) == 'b' || lower(s[1]) == 'o' || lower(s[1]) == 'x') { + i = 2 + saw = '0' // base prefix counts as a digit for "underscore as digit separator" + hex = lower(s[1]) == 'x' + } + + // Number proper. + for ; i < len(s); i++ { + // Digits are always okay. + if '0' <= s[i] && s[i] <= '9' || hex && 'a' <= lower(s[i]) && lower(s[i]) <= 'f' { + saw = '0' + continue + } + // Underscore must follow digit. + if s[i] == '_' { + if saw != '0' { + return false + } + saw = '_' + continue + } + // Underscore must also be followed by digit. + if saw == '_' { + return false + } + // Saw non-digit, non-underscore. + saw = '!' + } + return saw != '_' +} + +// Atoi is equivalent to ParseInt(s, 10, 0), converted to type int. +func Atoi(s string) (int, error) { + const fnAtoi = "Atoi" + + sLen := len(s) + if strconv.IntSize == 32 && (0 < sLen && sLen < 10) || + strconv.IntSize == 64 && (0 < sLen && sLen < 19) { + // Fast path for small integers that fit int type. + s0 := s + if s[0] == '-' || s[0] == '+' { + s = s[1:] + if len(s) < 1 { + return 0, &strconv.NumError{fnAtoi, s0, strconv.ErrSyntax} + } + } + + n := 0 + for _, ch := range []byte(s) { + ch -= '0' + if ch > 9 { + return 0, &strconv.NumError{fnAtoi, s0, strconv.ErrSyntax} + } + n = n*10 + int(ch) + } + if s0[0] == '-' { + n = -n + } + return n, nil + } + + // Slow path for invalid, big, or underscored integers. + i64, err := ParseInt(s, 10, 0) + if nerr, ok := err.(*strconv.NumError); ok { + nerr.Func = fnAtoi + } + return int(i64), err +} + +// lower(c) is a lower-case letter if and only if +// c is either that lower-case letter or the equivalent upper-case letter. +// Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'. +// Note that lower of non-letters can produce other non-letters. +func lower(c byte) byte { + return c | ('x' - 'X') +} +func syntaxError(fn, str string) *strconv.NumError { + return &strconv.NumError{fn, str, strconv.ErrSyntax} +} +func baseError(fn, str string, base int) *strconv.NumError { + return &strconv.NumError{fn, str, errors.New("invalid base " + strconv.Itoa(base))} +} +func rangeError(fn, str string) *strconv.NumError { + return &strconv.NumError{fn, str, strconv.ErrRange} +} +func bitSizeError(fn, str string, bitSize int) *strconv.NumError { + return &strconv.NumError{fn, str, errors.New("invalid bit size " + strconv.Itoa(bitSize))} +} diff --git a/vendor/github.com/henrylee2cn/ameda/atoi_x.go b/vendor/github.com/henrylee2cn/ameda/atoi_x.go new file mode 100644 index 0000000..221d110 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/atoi_x.go @@ -0,0 +1,27 @@ +package ameda + +import ( + "bytes" + "errors" + "fmt" + "math" +) + +// ParseUintByDict convert numStr into corresponding uint64 according to dict. +func ParseUintByDict(dict []byte, numStr string) (uint64, error) { + if len(dict) == 0 { + return 0, errors.New("dict is empty") + } + base := float64(len(dict)) + len := len(numStr) + var number float64 + for i := 0; i < len; i++ { + char := numStr[i : i+1] + pos := bytes.IndexAny(dict, char) + if pos == -1 { + return 0, fmt.Errorf("found a char not included in the dict: %q", char) + } + number = math.Pow(base, float64(len-i-1))*float64(pos) + number + } + return uint64(number), nil +} diff --git a/vendor/github.com/henrylee2cn/ameda/bool.go b/vendor/github.com/henrylee2cn/ameda/bool.go new file mode 100644 index 0000000..ed12802 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/bool.go @@ -0,0 +1,200 @@ +package ameda + +import ( + "strconv" +) + +// BoolToInterface converts bool to interface. +func BoolToInterface(v bool) interface{} { + return v +} + +// BoolToInterfacePtr converts bool to *interface. +func BoolToInterfacePtr(v bool) *interface{} { + r := BoolToInterface(v) + return &r +} + +// BoolToString converts bool to string. +func BoolToString(v bool) string { + return strconv.FormatBool(v) +} + +// BoolToStringPtr converts bool to *string. +func BoolToStringPtr(v bool) *string { + r := BoolToString(v) + return &r +} + +// BoolToBoolPtr converts bool to *bool. +func BoolToBoolPtr(v bool) *bool { + return &v +} + +// BoolToFloat32 converts bool to float32. +func BoolToFloat32(v bool) float32 { + if v { + return 1 + } + return 0 +} + +// BoolToFloat32Ptr converts bool to *float32. +func BoolToFloat32Ptr(v bool) *float32 { + r := BoolToFloat32(v) + return &r +} + +// BoolToFloat64 converts bool to float64. +func BoolToFloat64(v bool) float64 { + if v { + return 1 + } + return 0 +} + +// BoolToFloat64Ptr converts bool to *float64. +func BoolToFloat64Ptr(v bool) *float64 { + r := BoolToFloat64(v) + return &r +} + +// BoolToInt converts bool to int. +func BoolToInt(v bool) int { + if v { + return 1 + } + return 0 +} + +// BoolToIntPtr converts bool to *int. +func BoolToIntPtr(v bool) *int { + r := BoolToInt(v) + return &r +} + +// BoolToInt8 converts bool to int8. +func BoolToInt8(v bool) int8 { + if v { + return 1 + } + return 0 +} + +// BoolToInt8Ptr converts bool to *int8. +func BoolToInt8Ptr(v bool) *int8 { + r := BoolToInt8(v) + return &r +} + +// BoolToInt16 converts bool to int16. +func BoolToInt16(v bool) int16 { + if v { + return 1 + } + return 0 +} + +// BoolToInt16Ptr converts bool to *int16. +func BoolToInt16Ptr(v bool) *int16 { + r := BoolToInt16(v) + return &r +} + +// BoolToInt32 converts bool to int32. +func BoolToInt32(v bool) int32 { + if v { + return 1 + } + return 0 +} + +// BoolToInt32Ptr converts bool to *int32. +func BoolToInt32Ptr(v bool) *int32 { + r := BoolToInt32(v) + return &r +} + +// BoolToInt64 converts bool to int64. +func BoolToInt64(v bool) int64 { + if v { + return 1 + } + return 0 +} + +// BoolToInt64Ptr converts bool to *int64. +func BoolToInt64Ptr(v bool) *int64 { + r := BoolToInt64(v) + return &r +} + +// BoolToUint converts bool to uint. +func BoolToUint(v bool) uint { + if v { + return 1 + } + return 0 +} + +// BoolToUintPtr converts bool to *uint. +func BoolToUintPtr(v bool) *uint { + r := BoolToUint(v) + return &r +} + +// BoolToUint8 converts bool to uint8. +func BoolToUint8(v bool) uint8 { + if v { + return 1 + } + return 0 +} + +// BoolToUint8Ptr converts bool to *uint8. +func BoolToUint8Ptr(v bool) *uint8 { + r := BoolToUint8(v) + return &r +} + +// BoolToUint16 converts bool to uint16. +func BoolToUint16(v bool) uint16 { + if v { + return 1 + } + return 0 +} + +// BoolToUint16Ptr converts bool to *uint16. +func BoolToUint16Ptr(v bool) *uint16 { + r := BoolToUint16(v) + return &r +} + +// BoolToUint32 converts bool to uint32. +func BoolToUint32(v bool) uint32 { + if v { + return 1 + } + return 0 +} + +// BoolToUint32Ptr converts bool to *uint32. +func BoolToUint32Ptr(v bool) *uint32 { + r := BoolToUint32(v) + return &r +} + +// BoolToUint64 converts bool to uint64. +func BoolToUint64(v bool) uint64 { + if v { + return 1 + } + return 0 +} + +// BoolToUint64Ptr converts bool to *uint64. +func BoolToUint64Ptr(v bool) *uint64 { + r := BoolToUint64(v) + return &r +} diff --git a/vendor/github.com/henrylee2cn/ameda/bools.go b/vendor/github.com/henrylee2cn/ameda/bools.go new file mode 100644 index 0000000..1a734c1 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/bools.go @@ -0,0 +1,580 @@ +package ameda + +// OneBool try to return the first element, otherwise return zero value. +func OneBool(b []bool) bool { + if len(b) > 0 { + return b[0] + } + return false +} + +// BoolsCopy creates a copy of the bool slice. +func BoolsCopy(b []bool) []bool { + r := make([]bool, len(b)) + copy(r, b) + return r +} + +// BoolsToInterfaces converts int8 slice to interface slice. +func BoolsToInterfaces(b []bool) []interface{} { + r := make([]interface{}, len(b)) + for k, v := range b { + r[k] = v + } + return r +} + +// BoolsToStrings converts int8 slice to string slice. +func BoolsToStrings(b []bool) []string { + r := make([]string, len(b)) + for k, v := range b { + r[k] = BoolToString(v) + } + return r +} + +// BoolsToFloat32s converts int8 slice to float32 slice. +func BoolsToFloat32s(b []bool) []float32 { + r := make([]float32, len(b)) + for k, v := range b { + r[k] = BoolToFloat32(v) + } + return r +} + +// BoolsToFloat64s converts int8 slice to float64 slice. +func BoolsToFloat64s(b []bool) []float64 { + r := make([]float64, len(b)) + for k, v := range b { + r[k] = BoolToFloat64(v) + } + return r +} + +// BoolsToInts converts int8 slice to int slice. +func BoolsToInts(b []bool) []int { + r := make([]int, len(b)) + for k, v := range b { + r[k] = BoolToInt(v) + } + return r +} + +// BoolsToInt16s converts int8 slice to int16 slice. +func BoolsToInt16s(b []bool) []int16 { + r := make([]int16, len(b)) + for k, v := range b { + r[k] = BoolToInt16(v) + } + return r +} + +// BoolsToInt32s converts int8 slice to int32 slice. +func BoolsToInt32s(b []bool) []int32 { + r := make([]int32, len(b)) + for k, v := range b { + r[k] = BoolToInt32(v) + } + return r +} + +// BoolsToInt64s converts int8 slice to int64 slice. +func BoolsToInt64s(b []bool) []int64 { + r := make([]int64, len(b)) + for k, v := range b { + r[k] = BoolToInt64(v) + } + return r +} + +// BoolsToUints converts bool slice to uint slice. +func BoolsToUints(b []bool) []uint { + r := make([]uint, len(b)) + for k, v := range b { + r[k] = BoolToUint(v) + } + return r +} + +// BoolsToUint8s converts bool slice to uint8 slice. +func BoolsToUint8s(b []bool) []uint8 { + r := make([]uint8, len(b)) + for k, v := range b { + r[k] = BoolToUint8(v) + } + return r +} + +// BoolsToUint16s converts bool slice to uint16 slice. +func BoolsToUint16s(b []bool) []uint16 { + r := make([]uint16, len(b)) + for k, v := range b { + r[k] = BoolToUint16(v) + } + return r +} + +// BoolsToUint32s converts bool slice to uint32 slice. +func BoolsToUint32s(b []bool) []uint32 { + r := make([]uint32, len(b)) + for k, v := range b { + r[k] = BoolToUint32(v) + } + return r +} + +// BoolsToUint64s converts bool slice to uint64 slice. +func BoolsToUint64s(b []bool) []uint64 { + r := make([]uint64, len(b)) + for k, v := range b { + r[k] = BoolToUint64(v) + } + return r +} + +// BoolsCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func BoolsCopyWithin(b []bool, target, start int, end ...int) { + target = fixIndex(len(b), target, true) + if target == len(b) { + return + } + sub := BoolsSlice(b, start, end...) + for k, v := range sub { + b[target+k] = v + } +} + +// BoolsEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func BoolsEvery(b []bool, fn func(b []bool, k int, v bool) bool) bool { + for k, v := range b { + if !fn(b, k, v) { + return false + } + } + return true +} + +// BoolsFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func BoolsFill(b []bool, value bool, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(b), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + b[k] = value + } +} + +// BoolsFilter creates a new slice with all elements that pass the test implemented by the provided function. +func BoolsFilter(b []bool, fn func(b []bool, k int, v bool) bool) []bool { + ret := make([]bool, 0, 16) + for k, v := range b { + if fn(b, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// BoolsFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func BoolsFind(b []bool, fn func(b []bool, k int, v bool) bool) (k int, v bool) { + for k, v := range b { + if fn(b, k, v) { + return k, v + } + } + return -1, false +} + +// BoolsIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func BoolsIncludes(b []bool, valueToFind bool, fromIndex ...int) bool { + return BoolsIndexOf(b, valueToFind, fromIndex...) > -1 +} + +// BoolsIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func BoolsIndexOf(b []bool, searchElement bool, fromIndex ...int) int { + idx := getFromIndex(len(b), fromIndex...) + for k, v := range b[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// BoolsLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func BoolsLastIndexOf(b []bool, searchElement bool, fromIndex ...int) int { + idx := getFromIndex(len(b), fromIndex...) + for k := len(b) - 1; k >= idx; k-- { + if searchElement == b[k] { + return k + } + } + return -1 +} + +// BoolsMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func BoolsMap(b []bool, fn func(b []bool, k int, v bool) bool) []bool { + ret := make([]bool, len(b)) + for k, v := range b { + ret[k] = fn(b, k, v) + } + return ret +} + +// BoolsPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func BoolsPop(b *[]bool) (elem bool, found bool) { + a := *b + if len(a) == 0 { + return false, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *b = a[:len(a):len(a)] + return last, true +} + +// BoolsPush adds one or more elements to the end of an slice and returns the new length of the slice. +func BoolsPush(b *[]bool, element ...bool) int { + *b = append(*b, element...) + return len(*b) +} + +// BoolsPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func BoolsPushDistinct(b []bool, element ...bool) []bool { +L: + for _, v := range element { + for _, vv := range b { + if vv == v { + continue L + } + } + b = append(b, v) + } + return b +} + +// BoolsReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func BoolsReduce( + b []bool, + fn func(b []bool, k int, v, accumulator bool) bool, initialValue ...bool, +) bool { + if len(b) == 0 { + return false + } + start := 0 + acc := b[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(b); k++ { + acc = fn(b, k, b[k], acc) + } + return acc +} + +// BoolsReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func BoolsReduceRight( + b []bool, + fn func(b []bool, k int, v, accumulator bool) bool, initialValue ...bool, +) bool { + if len(b) == 0 { + return false + } + end := len(b) - 1 + acc := b[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(b, k, b[k], acc) + } + return acc +} + +// BoolsReverse reverses an slice in place. +func BoolsReverse(b []bool) { + first := 0 + last := len(b) - 1 + for first < last { + b[first], b[last] = b[last], b[first] + first++ + last-- + } +} + +// BoolsShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func BoolsShift(b *[]bool) (element bool, found bool) { + a := *b + if len(a) == 0 { + return false, false + } + first := a[0] + a = a[1:] + *b = a[:len(a):len(a)] + return first, true +} + +// BoolsSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func BoolsSlice(b []bool, begin int, end ...int) []bool { + fixedStart, fixedEnd, ok := fixRange(len(b), begin, end...) + if !ok { + return []bool{} + } + return BoolsCopy(b[fixedStart:fixedEnd]) +} + +// BoolsSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func BoolsSome(b []bool, fn func(b []bool, k int, v bool) bool) bool { + for k, v := range b { + if fn(b, k, v) { + return true + } + } + return false +} + +// BoolsSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func BoolsSplice(b *[]bool, start, deleteCount int, items ...bool) { + a := *b + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := BoolsCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *b = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *b = a[:len(a):len(a)] +} + +// BoolsUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func BoolsUnshift(b *[]bool, element ...bool) int { + *b = append(element, *b...) + return len(*b) +} + +// BoolsUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func BoolsUnshiftDistinct(b *[]bool, element ...bool) int { + a := *b + if len(element) == 0 { + return len(a) + } + m := make(map[bool]bool, len(element)) + r := make([]bool, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *b = r[:len(r):len(r)] + return len(r) +} + +// BoolsRemoveFirst removes the first matched element from the slice, +// and returns the new length of the slice. +func BoolsRemoveFirst(p *[]bool, elements ...bool) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// BoolsRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func BoolsRemoveEvery(p *[]bool, elements ...bool) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// BoolsConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func BoolsConcat(b ...[]bool) []bool { + var totalLen int + for _, v := range b { + totalLen += len(v) + } + ret := make([]bool, totalLen) + dst := ret + for _, v := range b { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// BoolsIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func BoolsIntersect(b ...[]bool) (intersectCount map[bool]int) { + if len(b) == 0 { + return nil + } + for _, v := range b { + if len(v) == 0 { + return nil + } + } + counts := make([]map[bool]int, len(b)) + for k, v := range b { + counts[k] = boolsDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// BoolsDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func BoolsDistinct(b *[]bool, changeSlice bool) (distinctCount map[bool]int) { + if !changeSlice { + return boolsDistinct(*b, nil) + } + a := (*b)[:0] + distinctCount = boolsDistinct(*b, &a) + n := len(distinctCount) + *b = a[:n:n] + return distinctCount +} + +func boolsDistinct(src []bool, dst *[]bool) map[bool]int { + m := make(map[bool]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} diff --git a/vendor/github.com/henrylee2cn/ameda/float32.go b/vendor/github.com/henrylee2cn/ameda/float32.go new file mode 100644 index 0000000..6bc9e67 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/float32.go @@ -0,0 +1,217 @@ +package ameda + +import ( + "fmt" + "math" +) + +// Float32ToInterface converts float32 to interface. +func Float32ToInterface(v float32) interface{} { + return v +} + +// Float32ToInterfacePtr converts float32 to *interface. +func Float32ToInterfacePtr(v float32) *interface{} { + r := Float32ToInterface(v) + return &r +} + +// Float32ToString converts float32 to string. +func Float32ToString(v float32) string { + return fmt.Sprintf("%f", v) +} + +// Float32ToStringPtr converts float32 to *string. +func Float32ToStringPtr(v float32) *string { + r := Float32ToString(v) + return &r +} + +// Float32ToBool converts float32 to bool. +func Float32ToBool(v float32) bool { + return v != 0 +} + +// Float32ToBoolPtr converts float32 to *bool. +func Float32ToBoolPtr(v float32) *bool { + r := Float32ToBool(v) + return &r +} + +// Float32ToFloat32Ptr converts float32 to *float32. +func Float32ToFloat32Ptr(v float32) *float32 { + return &v +} + +// Float32ToFloat64 converts float32 to float64. +func Float32ToFloat64(v float32) float64 { + return float64(v) +} + +// Float32ToFloat64Ptr converts float32 to *float64. +func Float32ToFloat64Ptr(v float32) *float64 { + r := Float32ToFloat64(v) + return &r +} + +// Float32ToInt converts float32 to int. +func Float32ToInt(v float32) (int, error) { + if Host64bit { + if v > math.MaxInt64 || v < math.MinInt64 { + return 0, errOverflowValue + } + } else { + if v > math.MaxInt32 || v < math.MinInt32 { + return 0, errOverflowValue + } + } + return int(v), nil + +} + +// Float32ToInt8 converts float32 to int8. +func Float32ToInt8(v float32) (int8, error) { + if v > math.MaxInt8 || v < math.MinInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Float32ToInt8Ptr converts float32 to *int8. +func Float32ToInt8Ptr(v float32) (*int8, error) { + r, err := Float32ToInt8(v) + return &r, err +} + +// Float32ToInt16 converts float32 to int16. +func Float32ToInt16(v float32) (int16, error) { + if v > math.MaxInt16 || v < math.MinInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// Float32ToInt16Ptr converts float32 to *int16. +func Float32ToInt16Ptr(v float32) (*int16, error) { + r, err := Float32ToInt16(v) + return &r, err +} + +// Float32ToInt32 converts float32 to int32. +func Float32ToInt32(v float32) (int32, error) { + if v > math.MaxInt32 || v < math.MinInt32 { + return 0, errOverflowValue + } + return int32(v), nil +} + +// Float32ToInt32Ptr converts float32 to *int32. +func Float32ToInt32Ptr(v float32) (*int32, error) { + r, err := Float32ToInt32(v) + return &r, err +} + +// Float32ToInt64 converts float32 to int64. +func Float32ToInt64(v float32) (int64, error) { + if v > math.MaxInt64 || v < math.MinInt64 { + return 0, errOverflowValue + } + return int64(v), nil +} + +// Float32ToInt64Ptr converts float32 to *int64. +func Float32ToInt64Ptr(v float32) (*int64, error) { + r, err := Float32ToInt64(v) + return &r, err +} + +// Float32ToUint converts float32 to uint. +func Float32ToUint(v float32) (uint, error) { + if v < 0 { + return 0, errNegativeValue + } + if Host64bit { + if v > math.MaxUint64 { + return 0, errOverflowValue + } + } else { + if v > math.MaxUint32 { + return 0, errOverflowValue + } + } + return uint(v), nil +} + +// Float32ToUintPtr converts float32 to *uint. +func Float32ToUintPtr(v float32) (*uint, error) { + r, err := Float32ToUint(v) + return &r, err +} + +// Float32ToUint8 converts float32 to uint8. +func Float32ToUint8(v float32) (uint8, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Float32ToUint8Ptr converts float32 to *uint8. +func Float32ToUint8Ptr(v float32) (*uint8, error) { + r, err := Float32ToUint8(v) + return &r, err +} + +// Float32ToUint16 converts float32 to uint16. +func Float32ToUint16(v float32) (uint16, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// Float32ToUint16Ptr converts float32 to *uint16. +func Float32ToUint16Ptr(v float32) (*uint16, error) { + r, err := Float32ToUint16(v) + return &r, err +} + +// Float32ToUint32 converts float32 to uint32. +func Float32ToUint32(v float32) (uint32, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint32 { + return 0, errOverflowValue + } + return uint32(v), nil +} + +// Float32ToUint32Ptr converts float32 to *uint32. +func Float32ToUint32Ptr(v float32) (*uint32, error) { + r, err := Float32ToUint32(v) + return &r, err +} + +// Float32ToUint64 converts float32 to uint64. +func Float32ToUint64(v float32) (uint64, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint64 { + return 0, errOverflowValue + } + return uint64(v), nil +} + +// Float32ToUint64Ptr converts float32 to *uint64. +func Float32ToUint64Ptr(v float32) (*uint64, error) { + r, err := Float32ToUint64(v) + return &r, err +} diff --git a/vendor/github.com/henrylee2cn/ameda/float32s.go b/vendor/github.com/henrylee2cn/ameda/float32s.go new file mode 100644 index 0000000..0aee67e --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/float32s.go @@ -0,0 +1,680 @@ +package ameda + +// OneFloat32 try to return the first element, otherwise return zero value. +func OneFloat32(f []float32) float32 { + if len(f) > 0 { + return f[0] + } + return 0 +} + +// Float32sCopy creates a copy of the float32 slice. +func Float32sCopy(f []float32) []float32 { + b := make([]float32, len(f)) + copy(b, f) + return b +} + +// Float32sToInterfaces converts float32 slice to interface slice. +func Float32sToInterfaces(f []float32) []interface{} { + r := make([]interface{}, len(f)) + for k, v := range f { + r[k] = Float32ToInterface(v) + } + return r +} + +// Float32sToStrings converts float32 slice to string slice. +func Float32sToStrings(f []float32) []string { + r := make([]string, len(f)) + for k, v := range f { + r[k] = Float32ToString(v) + } + return r +} + +// Float32sToBools converts float32 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Float32sToBools(f []float32) []bool { + r := make([]bool, len(f)) + for k, v := range f { + r[k] = Float32ToBool(v) + } + return r +} + +// Float32sToFloat64s converts float32 slice to float64 slice. +func Float32sToFloat64s(f []float32) []float64 { + r := make([]float64, len(f)) + for k, v := range f { + r[k] = Float32ToFloat64(v) + } + return r +} + +// Float32sToInts converts float32 slice to int slice. +func Float32sToInts(f []float32) ([]int, error) { + var err error + r := make([]int, len(f)) + for k, v := range f { + r[k], err = Float32ToInt(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToInt8s converts float32 slice to int8 slice. +func Float32sToInt8s(f []float32) ([]int8, error) { + var err error + r := make([]int8, len(f)) + for k, v := range f { + r[k], err = Float32ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToInt16s converts float32 slice to int16 slice. +func Float32sToInt16s(f []float32) ([]int16, error) { + var err error + r := make([]int16, len(f)) + for k, v := range f { + r[k], err = Float32ToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToInt32s converts float32 slice to int32 slice. +func Float32sToInt32s(f []float32) ([]int32, error) { + var err error + r := make([]int32, len(f)) + for k, v := range f { + r[k], err = Float32ToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToInt64s converts float32 slice to int64 slice. +func Float32sToInt64s(f []float32) ([]int64, error) { + var err error + r := make([]int64, len(f)) + for k, v := range f { + r[k], err = Float32ToInt64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToUints converts float32 slice to uint slice. +func Float32sToUints(f []float32) ([]uint, error) { + var err error + r := make([]uint, len(f)) + for k, v := range f { + r[k], err = Float32ToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToUint8s converts float32 slice to uint8 slice. +func Float32sToUint8s(f []float32) ([]uint8, error) { + var err error + r := make([]uint8, len(f)) + for k, v := range f { + r[k], err = Float32ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToUint16s converts float32 slice to uint16 slice. +func Float32sToUint16s(f []float32) ([]uint16, error) { + var err error + r := make([]uint16, len(f)) + for k, v := range f { + r[k], err = Float32ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToUint32s converts float32 slice to uint32 slice. +func Float32sToUint32s(f []float32) ([]uint32, error) { + var err error + r := make([]uint32, len(f)) + for k, v := range f { + r[k], err = Float32ToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sToUint64s converts float32 slice to uint64 slice. +func Float32sToUint64s(f []float32) ([]uint64, error) { + var err error + r := make([]uint64, len(f)) + for k, v := range f { + r[k], err = Float32ToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float32sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Float32sCopyWithin(f []float32, target, start int, end ...int) { + target = fixIndex(len(f), target, true) + if target == len(f) { + return + } + sub := Float32sSlice(f, start, end...) + for k, v := range sub { + f[target+k] = v + } +} + +// Float32sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Float32sEvery(f []float32, fn func(f []float32, k int, v float32) bool) bool { + for k, v := range f { + if !fn(f, k, v) { + return false + } + } + return true +} + +// Float32sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Float32sFill(f []float32, value float32, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(f), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + f[k] = value + } +} + +// Float32sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Float32sFilter(f []float32, fn func(f []float32, k int, v float32) bool) []float32 { + ret := make([]float32, 0) + for k, v := range f { + if fn(f, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Float32sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Float32sFind(f []float32, fn func(f []float32, k int, v float32) bool) (k int, v float32) { + for k, v := range f { + if fn(f, k, v) { + return k, v + } + } + return -1, 0 +} + +// Float32sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Float32sIncludes(f []float32, valueToFind float32, fromIndex ...int) bool { + return Float32sIndexOf(f, valueToFind, fromIndex...) > -1 +} + +// Float32sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Float32sIndexOf(f []float32, searchElement float32, fromIndex ...int) int { + idx := getFromIndex(len(f), fromIndex...) + for k, v := range f[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Float32sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Float32sLastIndexOf(f []float32, searchElement float32, fromIndex ...int) int { + idx := getFromIndex(len(f), fromIndex...) + for k := len(f) - 1; k >= idx; k-- { + if searchElement == f[k] { + return k + } + } + return -1 +} + +// Float32sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Float32sMap(f []float32, fn func(f []float32, k int, v float32) float32) []float32 { + ret := make([]float32, len(f)) + for k, v := range f { + ret[k] = fn(f, k, v) + } + return ret +} + +// Float32sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Float32sPop(f *[]float32) (float32, bool) { + a := *f + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *f = a[:len(a):len(a)] + return last, true +} + +// Float32sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Float32sPush(f *[]float32, element ...float32) int { + *f = append(*f, element...) + return len(*f) +} + +// Float32sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Float32sPushDistinct(f []float32, element ...float32) []float32 { +L: + for _, v := range element { + for _, vv := range f { + if vv == v { + continue L + } + } + f = append(f, v) + } + return f +} + +// Float32sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Float32sReduce( + f []float32, + fn func(f []float32, k int, v, accumulator float32) float32, initialValue ...float32, +) float32 { + if len(f) == 0 { + return 0 + } + start := 0 + acc := f[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(f); k++ { + acc = fn(f, k, f[k], acc) + } + return acc +} + +// Float32sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Float32sReduceRight( + f []float32, + fn func(f []float32, k int, v, accumulator float32) float32, initialValue ...float32, +) float32 { + if len(f) == 0 { + return 0 + } + end := len(f) - 1 + acc := f[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(f, k, f[k], acc) + } + return acc +} + +// Float32sReverse reverses an slice in place. +func Float32sReverse(f []float32) { + first := 0 + last := len(f) - 1 + for first < last { + f[first], f[last] = f[last], f[first] + first++ + last-- + } +} + +// Float32sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Float32sShift(f *[]float32) (float32, bool) { + a := *f + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *f = a[:len(a):len(a)] + return first, true +} + +// Float32sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Float32sSlice(f []float32, begin int, end ...int) []float32 { + fixedStart, fixedEnd, ok := fixRange(len(f), begin, end...) + if !ok { + return []float32{} + } + return Float32sCopy(f[fixedStart:fixedEnd]) +} + +// Float32sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Float32sSome(f []float32, fn func(f []float32, k int, v float32) bool) bool { + for k, v := range f { + if fn(f, k, v) { + return true + } + } + return false +} + +// Float32sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Float32sSplice(f *[]float32, start, deleteCount int, items ...float32) { + a := *f + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Float32sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *f = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *f = a[:len(a):len(a)] +} + +// Float32sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Float32sUnshift(f *[]float32, element ...float32) int { + *f = append(element, *f...) + return len(*f) +} + +// Float32sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Float32sUnshiftDistinct(f *[]float32, element ...float32) int { + a := *f + if len(element) == 0 { + return len(a) + } + m := make(map[float32]bool, len(element)) + r := make([]float32, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *f = r[:len(r):len(r)] + return len(r) +} + +// Float32sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Float32sRemoveFirst(p *[]float32, elements ...float32) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Float32sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Float32sRemoveEvery(p *[]float32, elements ...float32) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Float32sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Float32sIntersect(f ...[]float32) (intersectCount map[float32]int) { + if len(f) == 0 { + return nil + } + for _, v := range f { + if len(v) == 0 { + return nil + } + } + counts := make([]map[float32]int, len(f)) + for k, v := range f { + counts[k] = float32sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Float32sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Float32sDistinct(f *[]float32, changeSlice bool) (distinctCount map[float32]int) { + if !changeSlice { + return float32sDistinct(*f, nil) + } + a := (*f)[:0] + distinctCount = float32sDistinct(*f, &a) + n := len(distinctCount) + *f = a[:n:n] + return distinctCount +} + +func float32sDistinct(src []float32, dst *[]float32) map[float32]int { + m := make(map[float32]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Float32SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Float32SetUnion(set1, set2 []float32, others ...[]float32) []float32 { + m := make(map[float32]struct{}, len(set1)+len(set2)) + r := make([]float32, 0, len(m)) + for _, set := range append([][]float32{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Float32SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Float32SetIntersect(set1, set2 []float32, others ...[]float32) []float32 { + sets := append([][]float32{set2}, others...) + setsCount := make([]map[float32]int, len(sets)) + for k, v := range sets { + setsCount[k] = float32sDistinct(v, nil) + } + m := make(map[float32]struct{}, len(set1)) + r := make([]float32, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Float32SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Float32SetDifference(set1, set2 []float32, others ...[]float32) []float32 { + m := make(map[float32]struct{}, len(set1)) + r := make([]float32, 0, len(set1)) + sets := append([][]float32{set2}, others...) + for _, v := range sets { + inter := Float32SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/vendor/github.com/henrylee2cn/ameda/float64.go b/vendor/github.com/henrylee2cn/ameda/float64.go new file mode 100644 index 0000000..e5ea83d --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/float64.go @@ -0,0 +1,220 @@ +package ameda + +import ( + "fmt" + "math" +) + +// Float64ToInterface converts float64 to interface. +func Float64ToInterface(v float64) interface{} { + return v +} + +// Float64ToInterfacePtr converts float64 to *interface. +func Float64ToInterfacePtr(v float64) *interface{} { + r := Float64ToInterface(v) + return &r +} + +// Float64ToString converts float64 to string. +func Float64ToString(v float64) string { + return fmt.Sprintf("%f", v) +} + +// Float64ToStringPtr converts float64 to *string. +func Float64ToStringPtr(v float64) *string { + r := Float64ToString(v) + return &r +} + +// Float64ToBool converts float64 to bool. +func Float64ToBool(v float64) bool { + return v != 0 +} + +// Float64ToBoolPtr converts float64 to *bool. +func Float64ToBoolPtr(v float64) *bool { + r := Float64ToBool(v) + return &r +} + +// Float64ToFloat32 converts float64 to float32. +func Float64ToFloat32(v float64) (float32, error) { + if v > math.MaxFloat32 || v < -math.MaxFloat32 { + return 0, errOverflowValue + } + return float32(v), nil +} + +// Float64ToFloat32Ptr converts float64 to *float32. +func Float64ToFloat32Ptr(v float64) (*float32, error) { + r, err := Float64ToFloat32(v) + return &r, err +} + +// Float64ToFloat64Ptr converts float64 to *float64. +func Float64ToFloat64Ptr(v float64) *float64 { + return &v +} + +// Float64ToInt converts float64 to int. +func Float64ToInt(v float64) (int, error) { + if Host64bit { + if v > math.MaxInt64 || v < math.MinInt64 { + return 0, errOverflowValue + } + } else { + if v > math.MaxInt32 || v < math.MinInt32 { + return 0, errOverflowValue + } + } + return int(v), nil + +} + +// Float64ToInt8 converts float64 to int8. +func Float64ToInt8(v float64) (int8, error) { + if v > math.MaxInt8 || v < math.MinInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Float64ToInt8Ptr converts float64 to *int8. +func Float64ToInt8Ptr(v float64) (*int8, error) { + r, err := Float64ToInt8(v) + return &r, err +} + +// Float64ToInt16 converts float64 to int16. +func Float64ToInt16(v float64) (int16, error) { + if v > math.MaxInt16 || v < math.MinInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// Float64ToInt16Ptr converts float64 to *int16. +func Float64ToInt16Ptr(v float64) (*int16, error) { + r, err := Float64ToInt16(v) + return &r, err +} + +// Float64ToInt32 converts float64 to int32. +func Float64ToInt32(v float64) (int32, error) { + if v > math.MaxInt32 || v < math.MinInt32 { + return 0, errOverflowValue + } + return int32(v), nil +} + +// Float64ToInt32Ptr converts float64 to *int32. +func Float64ToInt32Ptr(v float64) (*int32, error) { + r, err := Float64ToInt32(v) + return &r, err +} + +// Float64ToInt64 converts float64 to int64. +func Float64ToInt64(v float64) (int64, error) { + if v > math.MaxInt64 || v < math.MinInt64 { + return 0, errOverflowValue + } + return int64(v), nil +} + +// Float64ToInt64Ptr converts float64 to *int64. +func Float64ToInt64Ptr(v float64) (*int64, error) { + r, err := Float64ToInt64(v) + return &r, err +} + +// Float64ToUint converts float64 to uint. +func Float64ToUint(v float64) (uint, error) { + if v < 0 { + return 0, errNegativeValue + } + if Host64bit { + if v > math.MaxUint64 { + return 0, errOverflowValue + } + } else { + if v > math.MaxUint32 { + return 0, errOverflowValue + } + } + return uint(v), nil +} + +// Float64ToUintPtr converts float64 to *uint. +func Float64ToUintPtr(v float64) (*uint, error) { + r, err := Float64ToUint(v) + return &r, err +} + +// Float64ToUint8 converts float64 to uint8. +func Float64ToUint8(v float64) (uint8, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Float64ToUint8Ptr converts float64 to *uint8. +func Float64ToUint8Ptr(v float64) (*uint8, error) { + r, err := Float64ToUint8(v) + return &r, err +} + +// Float64ToUint16 converts float64 to uint16. +func Float64ToUint16(v float64) (uint16, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// Float64ToUint16Ptr converts float64 to *uint16. +func Float64ToUint16Ptr(v float64) (*uint16, error) { + r, err := Float64ToUint16(v) + return &r, err +} + +// Float64ToUint32 converts float64 to uint32. +func Float64ToUint32(v float64) (uint32, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint32 { + return 0, errOverflowValue + } + return uint32(v), nil +} + +// Float64ToUint32Ptr converts float64 to *uint32. +func Float64ToUint32Ptr(v float64) (*uint32, error) { + r, err := Float64ToUint32(v) + return &r, err +} + +// Float64ToUint64 converts float64 to uint64. +func Float64ToUint64(v float64) (uint64, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint64 { + return 0, errOverflowValue + } + return uint64(v), nil +} + +// Float64ToUint64Ptr converts float64 to *uint64. +func Float64ToUint64Ptr(v float64) (*uint64, error) { + r, err := Float64ToUint64(v) + return &r, err +} diff --git a/vendor/github.com/henrylee2cn/ameda/float64s.go b/vendor/github.com/henrylee2cn/ameda/float64s.go new file mode 100644 index 0000000..2f456c4 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/float64s.go @@ -0,0 +1,684 @@ +package ameda + +// OneFloat64 try to return the first element, otherwise return zero value. +func OneFloat64(f []float64) float64 { + if len(f) > 0 { + return f[0] + } + return 0 +} + +// Float64sCopy creates a copy of the float64 slice. +func Float64sCopy(f []float64) []float64 { + b := make([]float64, len(f)) + copy(b, f) + return b +} + +// Float64sToInterfaces converts float64 slice to interface slice. +func Float64sToInterfaces(f []float64) []interface{} { + r := make([]interface{}, len(f)) + for k, v := range f { + r[k] = Float64ToInterface(v) + } + return r +} + +// Float64sToStrings converts float64 slice to string slice. +func Float64sToStrings(f []float64) []string { + r := make([]string, len(f)) + for k, v := range f { + r[k] = Float64ToString(v) + } + return r +} + +// Float64sToBools converts float64 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Float64sToBools(f []float64) []bool { + r := make([]bool, len(f)) + for k, v := range f { + r[k] = Float64ToBool(v) + } + return r +} + +// Float64sToFloat32s converts float64 slice to float32 slice. +func Float64sToFloat32s(f []float64) ([]float32, error) { + var err error + r := make([]float32, len(f)) + for k, v := range f { + r[k], err = Float64ToFloat32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToInts converts float64 slice to int slice. +func Float64sToInts(f []float64) ([]int, error) { + var err error + r := make([]int, len(f)) + for k, v := range f { + r[k], err = Float64ToInt(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToInt8s converts float64 slice to int8 slice. +func Float64sToInt8s(f []float64) ([]int8, error) { + var err error + r := make([]int8, len(f)) + for k, v := range f { + r[k], err = Float64ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToInt16s converts float64 slice to int16 slice. +func Float64sToInt16s(f []float64) ([]int16, error) { + var err error + r := make([]int16, len(f)) + for k, v := range f { + r[k], err = Float64ToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToInt32s converts float64 slice to int32 slice. +func Float64sToInt32s(f []float64) ([]int32, error) { + var err error + r := make([]int32, len(f)) + for k, v := range f { + r[k], err = Float64ToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToInt64s converts float64 slice to int64 slice. +func Float64sToInt64s(f []float64) ([]int64, error) { + var err error + r := make([]int64, len(f)) + for k, v := range f { + r[k], err = Float64ToInt64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToUints converts float64 slice to uint slice. +func Float64sToUints(f []float64) ([]uint, error) { + var err error + r := make([]uint, len(f)) + for k, v := range f { + r[k], err = Float64ToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToUint8s converts float64 slice to uint8 slice. +func Float64sToUint8s(f []float64) ([]uint8, error) { + var err error + r := make([]uint8, len(f)) + for k, v := range f { + r[k], err = Float64ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToUint16s converts float64 slice to uint16 slice. +func Float64sToUint16s(f []float64) ([]uint16, error) { + var err error + r := make([]uint16, len(f)) + for k, v := range f { + r[k], err = Float64ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToUint32s converts float64 slice to uint32 slice. +func Float64sToUint32s(f []float64) ([]uint32, error) { + var err error + r := make([]uint32, len(f)) + for k, v := range f { + r[k], err = Float64ToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sToUint64s converts float64 slice to uint64 slice. +func Float64sToUint64s(f []float64) ([]uint64, error) { + var err error + r := make([]uint64, len(f)) + for k, v := range f { + r[k], err = Float64ToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Float64sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Float64sCopyWithin(f []float64, target, start int, end ...int) { + target = fixIndex(len(f), target, true) + if target == len(f) { + return + } + sub := Float64sSlice(f, start, end...) + for k, v := range sub { + f[target+k] = v + } +} + +// Float64sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Float64sEvery(f []float64, fn func(f []float64, k int, v float64) bool) bool { + for k, v := range f { + if !fn(f, k, v) { + return false + } + } + return true +} + +// Float64sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Float64sFill(f []float64, value float64, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(f), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + f[k] = value + } +} + +// Float64sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Float64sFilter(f []float64, fn func(f []float64, k int, v float64) bool) []float64 { + ret := make([]float64, 0) + for k, v := range f { + if fn(f, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Float64sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Float64sFind(f []float64, fn func(f []float64, k int, v float64) bool) (k int, v float64) { + for k, v := range f { + if fn(f, k, v) { + return k, v + } + } + return -1, 0 +} + +// Float64sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Float64sIncludes(f []float64, valueToFind float64, fromIndex ...int) bool { + return Float64sIndexOf(f, valueToFind, fromIndex...) > -1 +} + +// Float64sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Float64sIndexOf(f []float64, searchElement float64, fromIndex ...int) int { + idx := getFromIndex(len(f), fromIndex...) + for k, v := range f[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Float64sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Float64sLastIndexOf(f []float64, searchElement float64, fromIndex ...int) int { + idx := getFromIndex(len(f), fromIndex...) + for k := len(f) - 1; k >= idx; k-- { + if searchElement == f[k] { + return k + } + } + return -1 +} + +// Float64sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Float64sMap(f []float64, fn func(f []float64, k int, v float64) float64) []float64 { + ret := make([]float64, len(f)) + for k, v := range f { + ret[k] = fn(f, k, v) + } + return ret +} + +// Float64sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Float64sPop(f *[]float64) (float64, bool) { + a := *f + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *f = a[:len(a):len(a)] + return last, true +} + +// Float64sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Float64sPush(f *[]float64, element ...float64) int { + *f = append(*f, element...) + return len(*f) +} + +// Float64sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Float64sPushDistinct(f []float64, element ...float64) []float64 { +L: + for _, v := range element { + for _, vv := range f { + if vv == v { + continue L + } + } + f = append(f, v) + } + return f +} + +// Float64sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Float64sReduce( + f []float64, + fn func(f []float64, k int, v, accumulator float64) float64, initialValue ...float64, +) float64 { + if len(f) == 0 { + return 0 + } + start := 0 + acc := f[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(f); k++ { + acc = fn(f, k, f[k], acc) + } + return acc +} + +// Float64sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Float64sReduceRight( + f []float64, + fn func(f []float64, k int, v, accumulator float64) float64, initialValue ...float64, +) float64 { + if len(f) == 0 { + return 0 + } + end := len(f) - 1 + acc := f[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(f, k, f[k], acc) + } + return acc +} + +// Float64sReverse reverses an slice in place. +func Float64sReverse(f []float64) { + first := 0 + last := len(f) - 1 + for first < last { + f[first], f[last] = f[last], f[first] + first++ + last-- + } +} + +// Float64sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Float64sShift(f *[]float64) (float64, bool) { + a := *f + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *f = a[:len(a):len(a)] + return first, true +} + +// Float64sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Float64sSlice(f []float64, begin int, end ...int) []float64 { + fixedStart, fixedEnd, ok := fixRange(len(f), begin, end...) + if !ok { + return []float64{} + } + return Float64sCopy(f[fixedStart:fixedEnd]) +} + +// Float64sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Float64sSome(f []float64, fn func(f []float64, k int, v float64) bool) bool { + for k, v := range f { + if fn(f, k, v) { + return true + } + } + return false +} + +// Float64sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Float64sSplice(f *[]float64, start, deleteCount int, items ...float64) { + a := *f + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Float64sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *f = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *f = a[:len(a):len(a)] +} + +// Float64sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Float64sUnshift(f *[]float64, element ...float64) int { + *f = append(element, *f...) + return len(*f) +} + +// Float64sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Float64sUnshiftDistinct(f *[]float64, element ...float64) int { + a := *f + if len(element) == 0 { + return len(a) + } + m := make(map[float64]bool, len(element)) + r := make([]float64, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *f = r[:len(r):len(r)] + return len(r) +} + +// Float64sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Float64sRemoveFirst(p *[]float64, elements ...float64) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Float64sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Float64sRemoveEvery(p *[]float64, elements ...float64) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Float64sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Float64sIntersect(f ...[]float64) (intersectCount map[float64]int) { + if len(f) == 0 { + return nil + } + for _, v := range f { + if len(v) == 0 { + return nil + } + } + counts := make([]map[float64]int, len(f)) + for k, v := range f { + counts[k] = float64sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Float64sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Float64sDistinct(f *[]float64, changeSlice bool) (distinctCount map[float64]int) { + if !changeSlice { + return float64sDistinct(*f, nil) + } + a := (*f)[:0] + distinctCount = float64sDistinct(*f, &a) + n := len(distinctCount) + *f = a[:n:n] + return distinctCount +} + +func float64sDistinct(src []float64, dst *[]float64) map[float64]int { + m := make(map[float64]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Float64SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Float64SetUnion(set1, set2 []float64, others ...[]float64) []float64 { + m := make(map[float64]struct{}, len(set1)+len(set2)) + r := make([]float64, 0, len(m)) + for _, set := range append([][]float64{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Float64SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Float64SetIntersect(set1, set2 []float64, others ...[]float64) []float64 { + sets := append([][]float64{set2}, others...) + setsCount := make([]map[float64]int, len(sets)) + for k, v := range sets { + setsCount[k] = float64sDistinct(v, nil) + } + m := make(map[float64]struct{}, len(set1)) + r := make([]float64, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Float64SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Float64SetDifference(set1, set2 []float64, others ...[]float64) []float64 { + m := make(map[float64]struct{}, len(set1)) + r := make([]float64, 0, len(set1)) + sets := append([][]float64{set2}, others...) + for _, v := range sets { + inter := Float64SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/vendor/github.com/henrylee2cn/ameda/initialize.go b/vendor/github.com/henrylee2cn/ameda/initialize.go new file mode 100644 index 0000000..204a9c5 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/initialize.go @@ -0,0 +1,299 @@ +package ameda + +import ( + "reflect" +) + +// InitPointer initializes nil pointer with zero value. +func InitPointer(v reflect.Value) (done bool) { + for { + kind := v.Kind() + if kind == reflect.Interface { + v = v.Elem() + continue + } + if kind != reflect.Ptr { + return true + } + u := v.Elem() + if u.IsValid() { + v = u + continue + } + if !v.CanSet() { + return false + } + v2 := reflect.New(v.Type().Elem()) + v.Set(v2) + v = v.Elem() + } +} + +// InitString initializes empty string pointer with def. +func InitString(p *string, def string) (done bool) { + if p == nil { + return false + } + if *p == "" { + *p = def + } + return true +} + +// InitBool initializes false bool pointer with def. +func InitBool(p *bool, def bool) (done bool) { + if p == nil { + return false + } + if *p == false { + *p = def + } + return true +} + +// InitByte initializes zero byte pointer with def. +func InitByte(p *byte, def byte) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitInt initializes zero int pointer with def. +func InitInt(p *int, def int) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitInt8 initializes zero int8 pointer with def. +func InitInt8(p *int8, def int8) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitInt16 initializes zero int16 pointer with def. +func InitInt16(p *int16, def int16) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitInt32 initializes zero int32 pointer with def. +func InitInt32(p *int32, def int32) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitInt64 initializes zero int64 pointer with def. +func InitInt64(p *int64, def int64) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitUint initializes zero uint pointer with def. +func InitUint(p *uint, def uint) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitUint8 initializes zero uint8 pointer with def. +func InitUint8(p *uint8, def uint8) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitUint16 initializes zero uint16 pointer with def. +func InitUint16(p *uint16, def uint16) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitUint32 initializes zero uint32 pointer with def. +func InitUint32(p *uint32, def uint32) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitUint64 initializes zero uint64 pointer with def. +func InitUint64(p *uint64, def uint64) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitFloat32 initializes zero float32 pointer with def. +func InitFloat32(p *float32, def float32) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitFloat64 initializes zero float64 pointer with def. +func InitFloat64(p *float64, def float64) (done bool) { + if p == nil { + return false + } + if *p == 0 { + *p = def + } + return true +} + +// InitSampleValue initialize the given type with some non-zero value( "?", $max_number, 0.1, true) +func InitSampleValue(t reflect.Type, maxNestingDeep int) reflect.Value { + if maxNestingDeep <= 0 { + maxNestingDeep = 10 + } + ptrDepth := 0 + for t.Kind() == reflect.Ptr { + t = t.Elem() + ptrDepth++ + } + v := reflect.New(t) + v = initValue(v, 1, maxNestingDeep) + return ReferenceValue(v, ptrDepth-1) +} + +func initValue(v reflect.Value, curDeep int, maxDeep int) reflect.Value { + InitPointer(v) + if curDeep >= maxDeep { + return v + } + var numPtr int + for v.Kind() == reflect.Ptr { + v = v.Elem() + numPtr++ + } + switch v.Kind() { + case reflect.Struct: + curDeep++ + fieldNum := v.Type().NumField() + for i := 0; i < fieldNum; i++ { + e := v.Field(i) + InitPointer(e) + e.Set(initValue(e, curDeep, maxDeep)) + } + case reflect.Slice: + if v.Len() == 0 { + e := reflect.New(v.Type().Elem()) + InitPointer(e) + e = e.Elem() + e = initValue(e, curDeep, maxDeep) + v.Set(reflect.Append(v, e)) + } + case reflect.Array: + if v.Len() > 0 { + e := reflect.New(v.Type().Elem()) + InitPointer(e) + e = e.Elem() + e = initValue(e, curDeep, maxDeep) + v.Index(0).Set(reflect.Append(v, e)) + } + case reflect.Map: + if v.Len() == 0 { + v.Set(reflect.MakeMap(v.Type())) + k := reflect.New(v.Type().Key()) + InitPointer(k) + k = k.Elem() + k = initValue(k, curDeep, maxDeep) + e := reflect.New(v.Type().Elem()) + InitPointer(e) + e = e.Elem() + e = initValue(e, curDeep, maxDeep) + v.SetMapIndex(k, e) + } + case reflect.Int: + if Host32bit { + v.SetInt(-32) + } else { + v.SetInt(-64) + } + case reflect.Int8: + v.SetInt(-8) + case reflect.Int16: + v.SetInt(-16) + case reflect.Int32: + v.SetInt(-32) + case reflect.Int64: + v.SetInt(-64) + case reflect.Uint, reflect.Uintptr: + if Host32bit { + v.SetUint(32) + } else { + v.SetUint(64) + } + case reflect.Uint8: + v.SetUint(8) + case reflect.Uint16: + v.SetUint(16) + case reflect.Uint32: + v.SetUint(32) + case reflect.Uint64: + v.SetUint(64) + case reflect.Float32: + v.SetFloat(-0.32) + case reflect.Float64: + v.SetFloat(-0.64) + case reflect.Bool: + v.SetBool(true) + case reflect.String: + v.SetString("?") + default: + } + return ReferenceValue(v, numPtr) +} diff --git a/vendor/github.com/henrylee2cn/ameda/int.go b/vendor/github.com/henrylee2cn/ameda/int.go new file mode 100644 index 0000000..7e0be14 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/int.go @@ -0,0 +1,206 @@ +package ameda + +import ( + "math" + "strconv" +) + +// MaxInt returns max int number for current os. +func MaxInt() int { + if Host32bit { + return math.MaxInt32 + } + return math.MaxInt64 +} + +// IntToInterface converts int to interface. +func IntToInterface(v int) interface{} { + return v +} + +// IntToInterfacePtr converts int to *interface. +func IntToInterfacePtr(v int) *interface{} { + r := IntToInterface(v) + return &r +} + +// IntToString converts int to string. +func IntToString(v int) string { + return strconv.Itoa(v) +} + +// IntToStringPtr converts int to *string. +func IntToStringPtr(v int) *string { + r := IntToString(v) + return &r +} + +// IntToBool converts int to bool. +func IntToBool(v int) bool { + return v != 0 +} + +// IntToBoolPtr converts int to *bool. +func IntToBoolPtr(v int) *bool { + r := IntToBool(v) + return &r +} + +// IntToFloat32 converts int to float32. +func IntToFloat32(v int) float32 { + return float32(v) +} + +// IntToFloat32Ptr converts int to *float32. +func IntToFloat32Ptr(v int) *float32 { + r := IntToFloat32(v) + return &r +} + +// IntToFloat64 converts int to float64. +func IntToFloat64(v int) float64 { + return float64(v) +} + +// IntToFloat64Ptr converts int to *float64. +func IntToFloat64Ptr(v int) *float64 { + r := IntToFloat64(v) + return &r +} + +// IntToIntPtr converts int to *int. +func IntToIntPtr(v int) *int { + return &v +} + +// IntToInt8 converts int to int8. +func IntToInt8(v int) (int8, error) { + if v > math.MaxInt8 || v < math.MinInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// IntToInt8Ptr converts int to *int8. +func IntToInt8Ptr(v int) (*int8, error) { + r, err := IntToInt8(v) + return &r, err +} + +// IntToInt16 converts int to int16. +func IntToInt16(v int) (int16, error) { + if v > math.MaxInt16 || v < math.MinInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// IntToInt16Ptr converts int to *int16. +func IntToInt16Ptr(v int) (*int16, error) { + r, err := IntToInt16(v) + return &r, err +} + +// IntToInt32 converts int to int32. +func IntToInt32(v int) (int32, error) { + if Host64bit && (v > math.MaxInt32 || v < math.MinInt32) { + return 0, errOverflowValue + } + return int32(v), nil +} + +// IntToInt32Ptr converts int to *int32. +func IntToInt32Ptr(v int) (*int32, error) { + r, err := IntToInt32(v) + return &r, err +} + +// IntToInt64 converts int to int64. +func IntToInt64(v int) int64 { + return int64(v) +} + +// IntToInt64Ptr converts int to *int64. +func IntToInt64Ptr(v int) *int64 { + r := IntToInt64(v) + return &r +} + +// IntToUint converts int to uint. +func IntToUint(v int) (uint, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint(v), nil +} + +// IntToUintPtr converts int to *uint. +func IntToUintPtr(v int) (*uint, error) { + r, err := IntToUint(v) + return &r, err +} + +// IntToUint8 converts int to uint8. +func IntToUint8(v int) (uint8, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// IntToUint8Ptr converts int to *uint8. +func IntToUint8Ptr(v int) (*uint8, error) { + r, err := IntToUint8(v) + return &r, err +} + +// IntToUint16 converts int to uint16. +func IntToUint16(v int) (uint16, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// IntToUint16Ptr converts int to *uint16. +func IntToUint16Ptr(v int) (*uint16, error) { + r, err := IntToUint16(v) + return &r, err +} + +// IntToUint32 converts int to uint32. +func IntToUint32(v int) (uint32, error) { + if v < 0 { + return 0, errNegativeValue + } + if Host64bit && v > int(maxUint32) { + return 0, errOverflowValue + } + return uint32(v), nil +} + +// IntToUint32Ptr converts int to *uint32. +func IntToUint32Ptr(v int) (*uint32, error) { + r, err := IntToUint32(v) + return &r, err +} + +// IntToUint64 converts int to uint64. +func IntToUint64(v int) (uint64, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint64(v), nil +} + +// IntToUint64Ptr converts int to *uint64. +func IntToUint64Ptr(v int) (*uint64, error) { + r, err := IntToUint64(v) + return &r, err +} diff --git a/vendor/github.com/henrylee2cn/ameda/int16.go b/vendor/github.com/henrylee2cn/ameda/int16.go new file mode 100644 index 0000000..73513d5 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/int16.go @@ -0,0 +1,186 @@ +package ameda + +import ( + "math" + "strconv" +) + +// Int16ToInterface converts int16 to interface. +func Int16ToInterface(v int16) interface{} { + return v +} + +// Int16ToInterfacePtr converts int16 to *interface. +func Int16ToInterfacePtr(v int16) *interface{} { + r := Int16ToInterface(v) + return &r +} + +// Int16ToString converts int16 to string. +func Int16ToString(v int16) string { + return strconv.FormatInt(int64(v), 10) +} + +// Int16ToStringPtr converts int16 to *string. +func Int16ToStringPtr(v int16) *string { + r := Int16ToString(v) + return &r +} + +// Int16ToBool converts int16 to bool. +func Int16ToBool(v int16) bool { + return v != 0 +} + +// Int16ToBoolPtr converts int16 to *bool. +func Int16ToBoolPtr(v int16) *bool { + r := Int16ToBool(v) + return &r +} + +// Int16ToFloat32 converts int16 to float32. +func Int16ToFloat32(v int16) float32 { + return float32(v) +} + +// Int16ToFloat32Ptr converts int16 to *float32. +func Int16ToFloat32Ptr(v int16) *float32 { + r := Int16ToFloat32(v) + return &r +} + +// Int16ToFloat64 converts int16 to float64. +func Int16ToFloat64(v int16) float64 { + return float64(v) +} + +// Int16ToFloat64Ptr converts int16 to *float64. +func Int16ToFloat64Ptr(v int16) *float64 { + r := Int16ToFloat64(v) + return &r +} + +// Int16ToInt converts int16 to int. +func Int16ToInt(v int16) int { + return int(v) +} + +// Int16ToIntPtr converts int16 to *int. +func Int16ToIntPtr(v int16) *int { + r := Int16ToInt(v) + return &r +} + +// Int16ToInt8 converts int16 to int8. +func Int16ToInt8(v int16) (int8, error) { + if v > math.MaxInt8 || v < math.MinInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Int16ToInt8Ptr converts int16 to *int8. +func Int16ToInt8Ptr(v int16) (*int8, error) { + r, err := Int16ToInt8(v) + return &r, err +} + +// Int16ToInt16Ptr converts int16 to *int16. +func Int16ToInt16Ptr(v int16) *int16 { + return &v +} + +// Int16ToInt32 converts int16 to int32. +func Int16ToInt32(v int16) int32 { + return int32(v) +} + +// Int16ToInt32Ptr converts int16 to *int32. +func Int16ToInt32Ptr(v int16) *int32 { + r := Int16ToInt32(v) + return &r +} + +// Int16ToInt64 converts int16 to int64. +func Int16ToInt64(v int16) int64 { + return int64(v) +} + +// Int16ToInt64Ptr converts int16 to *int64. +func Int16ToInt64Ptr(v int16) *int64 { + r := Int16ToInt64(v) + return &r +} + +// Int16ToUint converts int16 to uint. +func Int16ToUint(v int16) (uint, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint(v), nil +} + +// Int16ToUintPtr converts int16 to *uint. +func Int16ToUintPtr(v int16) (*uint, error) { + r, err := Int16ToUint(v) + return &r, err +} + +// Int16ToUint8 converts int16 to uint8. +func Int16ToUint8(v int16) (uint8, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Int16ToUint8Ptr converts int16 to *uint8. +func Int16ToUint8Ptr(v int16) (*uint8, error) { + r, err := Int16ToUint8(v) + return &r, err +} + +// Int16ToUint16 converts int16 to uint16. +func Int16ToUint16(v int16) (uint16, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint16(v), nil +} + +// Int16ToUint16Ptr converts int16 to *uint16. +func Int16ToUint16Ptr(v int16) (*uint16, error) { + r, err := Int16ToUint16(v) + return &r, err +} + +// Int16ToUint32 converts int16 to uint32. +func Int16ToUint32(v int16) (uint32, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint32(v), nil +} + +// Int16ToUint32Ptr converts int16 to *uint32. +func Int16ToUint32Ptr(v int16) (*uint32, error) { + r, err := Int16ToUint32(v) + return &r, err +} + +// Int16ToUint64 converts int16 to uint64. +func Int16ToUint64(v int16) (uint64, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint64(v), nil +} + +// Int16ToUint64Ptr converts int16 to *uint64. +func Int16ToUint64Ptr(v int16) (*uint64, error) { + r, err := Int16ToUint64(v) + return &r, err +} diff --git a/vendor/github.com/henrylee2cn/ameda/int16s.go b/vendor/github.com/henrylee2cn/ameda/int16s.go new file mode 100644 index 0000000..13b35e2 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/int16s.go @@ -0,0 +1,678 @@ +package ameda + +// OneInt16 try to return the first element, otherwise return zero value. +func OneInt16(i []int16) int16 { + if len(i) > 0 { + return i[0] + } + return 0 +} + +// Int16sCopy creates a copy of the int16 slice. +func Int16sCopy(i []int16) []int16 { + b := make([]int16, len(i)) + copy(b, i) + return b +} + +// Int16sToInterfaces converts int16 slice to interface slice. +func Int16sToInterfaces(i []int16) []interface{} { + r := make([]interface{}, len(i)) + for k, v := range i { + r[k] = v + } + return r +} + +// Int16sToStrings converts int16 slice to string slice. +func Int16sToStrings(i []int16) []string { + r := make([]string, len(i)) + for k, v := range i { + r[k] = Int16ToString(v) + } + return r +} + +// Int16sToBools converts int16 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Int16sToBools(i []int16) []bool { + r := make([]bool, len(i)) + for k, v := range i { + r[k] = Int16ToBool(v) + } + return r +} + +// Int16sToFloat32s converts int16 slice to float32 slice. +func Int16sToFloat32s(i []int16) []float32 { + r := make([]float32, len(i)) + for k, v := range i { + r[k] = Int16ToFloat32(v) + } + return r +} + +// Int16sToFloat64s converts int16 slice to float64 slice. +func Int16sToFloat64s(i []int16) []float64 { + r := make([]float64, len(i)) + for k, v := range i { + r[k] = Int16ToFloat64(v) + } + return r +} + +// Int16sToInts converts int16 slice to int slice. +func Int16sToInts(i []int16) []int { + r := make([]int, len(i)) + for k, v := range i { + r[k] = Int16ToInt(v) + } + return r +} + +// Int16sToInt8s converts int16 slice to int8 slice. +func Int16sToInt8s(i []int16) ([]int8, error) { + var err error + r := make([]int8, len(i)) + for k, v := range i { + r[k], err = Int16ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int16sToInt32s converts int16 slice to int32 slice. +func Int16sToInt32s(i []int16) []int32 { + r := make([]int32, len(i)) + for k, v := range i { + r[k] = Int16ToInt32(v) + } + return r +} + +// Int16sToInt64s converts int16 slice to int64 slice. +func Int16sToInt64s(i []int16) []int64 { + r := make([]int64, len(i)) + for k, v := range i { + r[k] = Int16ToInt64(v) + } + return r +} + +// Int16sToUints converts int16 slice to uint slice. +func Int16sToUints(i []int16) ([]uint, error) { + var err error + r := make([]uint, len(i)) + for k, v := range i { + r[k], err = Int16ToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int16sToUint8s converts int16 slice to uint8 slice. +func Int16sToUint8s(i []int16) ([]uint8, error) { + var err error + r := make([]uint8, len(i)) + for k, v := range i { + r[k], err = Int16ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int16sToUint16s converts int16 slice to uint16 slice. +func Int16sToUint16s(i []int16) ([]uint16, error) { + var err error + r := make([]uint16, len(i)) + for k, v := range i { + r[k], err = Int16ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int16sToUint32s converts int16 slice to uint32 slice. +func Int16sToUint32s(i []int16) ([]uint32, error) { + var err error + r := make([]uint32, len(i)) + for k, v := range i { + r[k], err = Int16ToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int16sToUint64s converts int16 slice to uint64 slice. +func Int16sToUint64s(i []int16) ([]uint64, error) { + var err error + r := make([]uint64, len(i)) + for k, v := range i { + r[k], err = Int16ToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int16sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int16sCopyWithin(i []int16, target, start int, end ...int) { + target = fixIndex(len(i), target, true) + if target == len(i) { + return + } + sub := Int16sSlice(i, start, end...) + for k, v := range sub { + i[target+k] = v + } +} + +// Int16sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Int16sEvery(i []int16, fn func(i []int16, k int, v int16) bool) bool { + for k, v := range i { + if !fn(i, k, v) { + return false + } + } + return true +} + +// Int16sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int16sFill(i []int16, value int16, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(i), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + i[k] = value + } +} + +// Int16sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Int16sFilter(i []int16, fn func(i []int16, k int, v int16) bool) []int16 { + ret := make([]int16, 0) + for k, v := range i { + if fn(i, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Int16sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Int16sFind(i []int16, fn func(i []int16, k int, v int16) bool) (k int, v int16) { + for k, v := range i { + if fn(i, k, v) { + return k, v + } + } + return -1, 0 +} + +// Int16sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int16sIncludes(i []int16, valueToFind int16, fromIndex ...int) bool { + return Int16sIndexOf(i, valueToFind, fromIndex...) > -1 +} + +// Int16sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int16sIndexOf(i []int16, searchElement int16, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k, v := range i[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Int16sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int16sLastIndexOf(i []int16, searchElement int16, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k := len(i) - 1; k >= idx; k-- { + if searchElement == i[k] { + return k + } + } + return -1 +} + +// Int16sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Int16sMap(i []int16, fn func(i []int16, k int, v int16) int16) []int16 { + ret := make([]int16, len(i)) + for k, v := range i { + ret[k] = fn(i, k, v) + } + return ret +} + +// Int16sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Int16sPop(i *[]int16) (int16, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *i = a[:len(a):len(a)] + return last, true +} + +// Int16sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Int16sPush(i *[]int16, element ...int16) int { + *i = append(*i, element...) + return len(*i) +} + +// Int16sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Int16sPushDistinct(i []int16, element ...int16) []int16 { +L: + for _, v := range element { + for _, vv := range i { + if vv == v { + continue L + } + } + i = append(i, v) + } + return i +} + +// Int16sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int16sReduce(i []int16, + fn func(i []int16, k int, v, accumulator int16) int16, initialValue ...int16, +) int16 { + if len(i) == 0 { + return 0 + } + start := 0 + acc := i[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(i); k++ { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int16sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int16sReduceRight(i []int16, + fn func(i []int16, k int, v, accumulator int16) int16, initialValue ...int16, +) int16 { + if len(i) == 0 { + return 0 + } + end := len(i) - 1 + acc := i[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int16sReverse reverses an slice in place. +func Int16sReverse(i []int16) { + first := 0 + last := len(i) - 1 + for first < last { + i[first], i[last] = i[last], i[first] + first++ + last-- + } +} + +// Int16sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Int16sShift(i *[]int16) (int16, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *i = a[:len(a):len(a)] + return first, true +} + +// Int16sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Int16sSlice(i []int16, begin int, end ...int) []int16 { + fixedStart, fixedEnd, ok := fixRange(len(i), begin, end...) + if !ok { + return []int16{} + } + return Int16sCopy(i[fixedStart:fixedEnd]) +} + +// Int16sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Int16sSome(i []int16, fn func(i []int16, k int, v int16) bool) bool { + for k, v := range i { + if fn(i, k, v) { + return true + } + } + return false +} + +// Int16sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Int16sSplice(i *[]int16, start, deleteCount int, items ...int16) { + a := *i + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Int16sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *i = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *i = a[:len(a):len(a)] +} + +// Int16sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Int16sUnshift(i *[]int16, element ...int16) int { + *i = append(element, *i...) + return len(*i) +} + +// Int16sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Int16sUnshiftDistinct(i *[]int16, element ...int16) int { + a := *i + if len(element) == 0 { + return len(a) + } + m := make(map[int16]bool, len(element)) + r := make([]int16, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *i = r[:len(r):len(r)] + return len(r) +} + +// Int16sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Int16sRemoveFirst(p *[]int16, elements ...int16) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int16sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Int16sRemoveEvery(p *[]int16, elements ...int16) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int16sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Int16sConcat(i ...[]int16) []int16 { + var totalLen int + for _, v := range i { + totalLen += len(v) + } + ret := make([]int16, totalLen) + dst := ret + for _, v := range i { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Int16sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Int16sIntersect(i ...[]int16) (intersectCount map[int16]int) { + if len(i) == 0 { + return nil + } + for _, v := range i { + if len(v) == 0 { + return nil + } + } + counts := make([]map[int16]int, len(i)) + for k, v := range i { + counts[k] = int16sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Int16sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Int16sDistinct(i *[]int16, changeSlice bool) (distinctCount map[int16]int) { + if !changeSlice { + return int16sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = int16sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func int16sDistinct(src []int16, dst *[]int16) map[int16]int { + m := make(map[int16]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Int16SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int16SetUnion(set1, set2 []int16, others ...[]int16) []int16 { + m := make(map[int16]struct{}, len(set1)+len(set2)) + r := make([]int16, 0, len(m)) + for _, set := range append([][]int16{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Int16SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int16SetIntersect(set1, set2 []int16, others ...[]int16) []int16 { + sets := append([][]int16{set2}, others...) + setsCount := make([]map[int16]int, len(sets)) + for k, v := range sets { + setsCount[k] = int16sDistinct(v, nil) + } + m := make(map[int16]struct{}, len(set1)) + r := make([]int16, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Int16SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Int16SetDifference(set1, set2 []int16, others ...[]int16) []int16 { + m := make(map[int16]struct{}, len(set1)) + r := make([]int16, 0, len(set1)) + sets := append([][]int16{set2}, others...) + for _, v := range sets { + inter := Int16SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/vendor/github.com/henrylee2cn/ameda/int32.go b/vendor/github.com/henrylee2cn/ameda/int32.go new file mode 100644 index 0000000..6719926 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/int32.go @@ -0,0 +1,192 @@ +package ameda + +import ( + "math" + "strconv" +) + +// Int32ToInterface converts int32 to interface. +func Int32ToInterface(v int32) interface{} { + return v +} + +// Int32ToInterfacePtr converts int32 to *interface. +func Int32ToInterfacePtr(v int32) *interface{} { + r := Int32ToInterface(v) + return &r +} + +// Int32ToString converts int32 to string. +func Int32ToString(v int32) string { + return strconv.FormatInt(int64(v), 10) +} + +// Int32ToStringPtr converts int32 to *string. +func Int32ToStringPtr(v int32) *string { + r := Int32ToString(v) + return &r +} + +// Int32ToBool converts int32 to bool. +func Int32ToBool(v int32) bool { + return v != 0 +} + +// Int32ToBoolPtr converts int32 to *bool. +func Int32ToBoolPtr(v int32) *bool { + r := Int32ToBool(v) + return &r +} + +// Int32ToFloat32 converts int32 to float32. +func Int32ToFloat32(v int32) float32 { + return float32(v) +} + +// Int32ToFloat32Ptr converts int32 to *float32. +func Int32ToFloat32Ptr(v int32) *float32 { + r := Int32ToFloat32(v) + return &r +} + +// Int32ToFloat64 converts int32 to float64. +func Int32ToFloat64(v int32) float64 { + return float64(v) +} + +// Int32ToFloat64Ptr converts int32 to *float64. +func Int32ToFloat64Ptr(v int32) *float64 { + r := Int32ToFloat64(v) + return &r +} + +// Int32ToInt converts int32 to int. +func Int32ToInt(v int32) int { + return int(v) +} + +// Int32ToIntPtr converts int32 to *int. +func Int32ToIntPtr(v int32) *int { + r := Int32ToInt(v) + return &r +} + +// Int32ToInt8 converts int32 to int8. +func Int32ToInt8(v int32) (int8, error) { + if v > math.MaxInt8 || v < math.MinInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Int32ToInt8Ptr converts int32 to *int8. +func Int32ToInt8Ptr(v int32) (*int8, error) { + r, err := Int32ToInt8(v) + return &r, err +} + +// Int32ToInt16 converts int32 to int16. +func Int32ToInt16(v int32) (int16, error) { + if v > math.MaxInt16 || v < math.MinInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// Int32ToInt16Ptr converts int32 to *int16. +func Int32ToInt16Ptr(v int32) (*int16, error) { + r, err := Int32ToInt16(v) + return &r, err +} + +// Int32ToInt32Ptr converts int32 to *int32. +func Int32ToInt32Ptr(v int32) *int32 { + return &v +} + +// Int32ToInt64 converts int32 to int64. +func Int32ToInt64(v int32) int64 { + return int64(v) +} + +// Int32ToInt64Ptr converts int32 to *int64. +func Int32ToInt64Ptr(v int32) *int64 { + r := Int32ToInt64(v) + return &r +} + +// Int32ToUint converts int32 to uint. +func Int32ToUint(v int32) (uint, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint(v), nil +} + +// Int32ToUintPtr converts int32 to *uint. +func Int32ToUintPtr(v int32) (*uint, error) { + r, err := Int32ToUint(v) + return &r, err +} + +// Int32ToUint8 converts int32 to uint8. +func Int32ToUint8(v int32) (uint8, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Int32ToUint8Ptr converts int32 to *uint8. +func Int32ToUint8Ptr(v int32) (*uint8, error) { + r, err := Int32ToUint8(v) + return &r, err +} + +// Int32ToUint16 converts int32 to uint16. +func Int32ToUint16(v int32) (uint16, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// Int32ToUint16Ptr converts int32 to *uint16. +func Int32ToUint16Ptr(v int32) (*uint16, error) { + r, err := Int32ToUint16(v) + return &r, err +} + +// Int32ToUint32 converts int32 to uint32. +func Int32ToUint32(v int32) (uint32, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint32(v), nil +} + +// Int32ToUint32Ptr converts int32 to *uint32. +func Int32ToUint32Ptr(v int32) (*uint32, error) { + r, err := Int32ToUint32(v) + return &r, err +} + +// Int32ToUint64 converts int32 to uint64. +func Int32ToUint64(v int32) (uint64, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint64(v), nil +} + +// Int32ToUint64Ptr converts int32 to *uint64. +func Int32ToUint64Ptr(v int32) (*uint64, error) { + r, err := Int32ToUint64(v) + return &r, err +} diff --git a/vendor/github.com/henrylee2cn/ameda/int32s.go b/vendor/github.com/henrylee2cn/ameda/int32s.go new file mode 100644 index 0000000..0b32f47 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/int32s.go @@ -0,0 +1,682 @@ +package ameda + +// OneInt32 try to return the first element, otherwise return zero value. +func OneInt32(i []int32) int32 { + if len(i) > 0 { + return i[0] + } + return 0 +} + +// Int32sCopy creates a copy of the int32 slice. +func Int32sCopy(i []int32) []int32 { + b := make([]int32, len(i)) + copy(b, i) + return b +} + +// Int32sToInterfaces converts int32 slice to interface slice. +func Int32sToInterfaces(i []int32) []interface{} { + r := make([]interface{}, len(i)) + for k, v := range i { + r[k] = Int32ToInterface(v) + } + return r +} + +// Int32sToStrings converts int32 slice to string slice. +func Int32sToStrings(i []int32) []string { + r := make([]string, len(i)) + for k, v := range i { + r[k] = Int32ToString(v) + } + return r +} + +// Int32sToBools converts int32 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Int32sToBools(i []int32) []bool { + r := make([]bool, len(i)) + for k, v := range i { + r[k] = Int32ToBool(v) + } + return r +} + +// Int32sToFloat32s converts int32 slice to float32 slice. +func Int32sToFloat32s(i []int32) []float32 { + r := make([]float32, len(i)) + for k, v := range i { + r[k] = Int32ToFloat32(v) + } + return r +} + +// Int32sToFloat64s converts int32 slice to float64 slice. +func Int32sToFloat64s(i []int32) []float64 { + r := make([]float64, len(i)) + for k, v := range i { + r[k] = Int32ToFloat64(v) + } + return r +} + +// Int32sToInts converts int32 slice to int slice. +func Int32sToInts(i []int32) []int { + r := make([]int, len(i)) + for k, v := range i { + r[k] = Int32ToInt(v) + } + return r +} + +// Int32sToInt8s converts int32 slice to int8 slice. +func Int32sToInt8s(i []int32) ([]int8, error) { + var err error + r := make([]int8, len(i)) + for k, v := range i { + r[k], err = Int32ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int32sToInt16s converts int32 slice to int16 slice. +func Int32sToInt16s(i []int32) ([]int16, error) { + var err error + r := make([]int16, len(i)) + for k, v := range i { + r[k], err = Int32ToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int32sToInt64s converts int32 slice to int64 slice. +func Int32sToInt64s(i []int32) []int64 { + r := make([]int64, len(i)) + for k, v := range i { + r[k] = Int32ToInt64(v) + } + return r +} + +// Int32sToUints converts int32 slice to uint slice. +func Int32sToUints(i []int32) ([]uint, error) { + var err error + r := make([]uint, len(i)) + for k, v := range i { + r[k], err = Int32ToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int32sToUint8s converts int32 slice to uint8 slice. +func Int32sToUint8s(i []int32) ([]uint8, error) { + var err error + r := make([]uint8, len(i)) + for k, v := range i { + r[k], err = Int32ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int32sToUint16s converts int32 slice to uint16 slice. +func Int32sToUint16s(i []int32) ([]uint16, error) { + var err error + r := make([]uint16, len(i)) + for k, v := range i { + r[k], err = Int32ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int32sToUint32s converts int32 slice to uint32 slice. +func Int32sToUint32s(i []int32) ([]uint32, error) { + var err error + r := make([]uint32, len(i)) + for k, v := range i { + r[k], err = Int32ToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int32sToUint64s converts int32 slice to uint64 slice. +func Int32sToUint64s(i []int32) ([]uint64, error) { + var err error + r := make([]uint64, len(i)) + for k, v := range i { + r[k], err = Int32ToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int32sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int32sCopyWithin(i []int32, target, start int, end ...int) { + target = fixIndex(len(i), target, true) + if target == len(i) { + return + } + sub := Int32sSlice(i, start, end...) + for k, v := range sub { + i[target+k] = v + } +} + +// Int32sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Int32sEvery(i []int32, fn func(i []int32, k int, v int32) bool) bool { + for k, v := range i { + if !fn(i, k, v) { + return false + } + } + return true +} + +// Int32sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int32sFill(i []int32, value int32, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(i), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + i[k] = value + } +} + +// Int32sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Int32sFilter(i []int32, fn func(i []int32, k int, v int32) bool) []int32 { + ret := make([]int32, 0) + for k, v := range i { + if fn(i, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Int32sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Int32sFind(i []int32, fn func(i []int32, k int, v int32) bool) (k int, v int32) { + for k, v := range i { + if fn(i, k, v) { + return k, v + } + } + return -1, 0 +} + +// Int32sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int32sIncludes(i []int32, valueToFind int32, fromIndex ...int) bool { + return Int32sIndexOf(i, valueToFind, fromIndex...) > -1 +} + +// Int32sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int32sIndexOf(i []int32, searchElement int32, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k, v := range i[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Int32sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int32sLastIndexOf(i []int32, searchElement int32, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k := len(i) - 1; k >= idx; k-- { + if searchElement == i[k] { + return k + } + } + return -1 +} + +// Int32sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Int32sMap(i []int32, fn func(i []int32, k int, v int32) int32) []int32 { + ret := make([]int32, len(i)) + for k, v := range i { + ret[k] = fn(i, k, v) + } + return ret +} + +// Int32sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Int32sPop(i *[]int32) (int32, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *i = a[:len(a):len(a)] + return last, true +} + +// Int32sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Int32sPush(i *[]int32, element ...int32) int { + *i = append(*i, element...) + return len(*i) +} + +// Int32sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Int32sPushDistinct(i []int32, element ...int32) []int32 { +L: + for _, v := range element { + for _, vv := range i { + if vv == v { + continue L + } + } + i = append(i, v) + } + return i +} + +// Int32sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int32sReduce(i []int32, + fn func(i []int32, k int, v, accumulator int32) int32, initialValue ...int32, +) int32 { + if len(i) == 0 { + return 0 + } + start := 0 + acc := i[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(i); k++ { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int32sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int32sReduceRight(i []int32, + fn func(i []int32, k int, v, accumulator int32) int32, initialValue ...int32, +) int32 { + if len(i) == 0 { + return 0 + } + end := len(i) - 1 + acc := i[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int32sReverse reverses an slice in place. +func Int32sReverse(i []int32) { + first := 0 + last := len(i) - 1 + for first < last { + i[first], i[last] = i[last], i[first] + first++ + last-- + } +} + +// Int32sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Int32sShift(i *[]int32) (int32, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *i = a[:len(a):len(a)] + return first, true +} + +// Int32sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Int32sSlice(i []int32, begin int, end ...int) []int32 { + fixedStart, fixedEnd, ok := fixRange(len(i), begin, end...) + if !ok { + return []int32{} + } + return Int32sCopy(i[fixedStart:fixedEnd]) +} + +// Int32sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Int32sSome(i []int32, fn func(i []int32, k int, v int32) bool) bool { + for k, v := range i { + if fn(i, k, v) { + return true + } + } + return false +} + +// Int32sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Int32sSplice(i *[]int32, start, deleteCount int, items ...int32) { + a := *i + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Int32sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *i = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *i = a[:len(a):len(a)] +} + +// Int32sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Int32sUnshift(i *[]int32, element ...int32) int { + *i = append(element, *i...) + return len(*i) +} + +// Int32sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Int32sUnshiftDistinct(i *[]int32, element ...int32) int { + a := *i + if len(element) == 0 { + return len(a) + } + m := make(map[int32]bool, len(element)) + r := make([]int32, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *i = r[:len(r):len(r)] + return len(r) +} + +// Int32sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Int32sRemoveFirst(p *[]int32, elements ...int32) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int32sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Int32sRemoveEvery(p *[]int32, elements ...int32) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int32sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Int32sConcat(i ...[]int32) []int32 { + var totalLen int + for _, v := range i { + totalLen += len(v) + } + ret := make([]int32, totalLen) + dst := ret + for _, v := range i { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Int32sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Int32sIntersect(i ...[]int32) (intersectCount map[int32]int) { + if len(i) == 0 { + return nil + } + for _, v := range i { + if len(v) == 0 { + return nil + } + } + counts := make([]map[int32]int, len(i)) + for k, v := range i { + counts[k] = int32sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Int32sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Int32sDistinct(i *[]int32, changeSlice bool) (distinctCount map[int32]int) { + if !changeSlice { + return int32sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = int32sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func int32sDistinct(src []int32, dst *[]int32) map[int32]int { + m := make(map[int32]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Int32SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int32SetUnion(set1, set2 []int32, others ...[]int32) []int32 { + m := make(map[int32]struct{}, len(set1)+len(set2)) + r := make([]int32, 0, len(m)) + for _, set := range append([][]int32{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Int32SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int32SetIntersect(set1, set2 []int32, others ...[]int32) []int32 { + sets := append([][]int32{set2}, others...) + setsCount := make([]map[int32]int, len(sets)) + for k, v := range sets { + setsCount[k] = int32sDistinct(v, nil) + } + m := make(map[int32]struct{}, len(set1)) + r := make([]int32, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Int32SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Int32SetDifference(set1, set2 []int32, others ...[]int32) []int32 { + m := make(map[int32]struct{}, len(set1)) + r := make([]int32, 0, len(set1)) + sets := append([][]int32{set2}, others...) + for _, v := range sets { + inter := Int32SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/vendor/github.com/henrylee2cn/ameda/int64.go b/vendor/github.com/henrylee2cn/ameda/int64.go new file mode 100644 index 0000000..c04e746 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/int64.go @@ -0,0 +1,201 @@ +package ameda + +import ( + "math" + "strconv" +) + +// Int64ToInterface converts int64 to interface. +func Int64ToInterface(v int64) interface{} { + return v +} + +// Int64ToInterfacePtr converts int64 to *interface. +func Int64ToInterfacePtr(v int64) *interface{} { + r := Int64ToInterface(v) + return &r +} + +// Int64ToString converts int64 to string. +func Int64ToString(v int64) string { + return strconv.FormatInt(v, 10) +} + +// Int64ToStringPtr converts int64 to *string. +func Int64ToStringPtr(v int64) *string { + r := Int64ToString(v) + return &r +} + +// Int64ToBool converts int64 to bool. +func Int64ToBool(v int64) bool { + return v != 0 +} + +// Int64ToBoolPtr converts int64 to *bool. +func Int64ToBoolPtr(v int64) *bool { + r := Int64ToBool(v) + return &r +} + +// Int64ToFloat32 converts int64 to float32. +func Int64ToFloat32(v int64) float32 { + return float32(v) +} + +// Int64ToFloat32Ptr converts int64 to *float32. +func Int64ToFloat32Ptr(v int64) *float32 { + r := Int64ToFloat32(v) + return &r +} + +// Int64ToFloat64 converts int64 to float64. +func Int64ToFloat64(v int64) float64 { + return float64(v) +} + +// Int64ToFloat64Ptr converts int64 to *float64. +func Int64ToFloat64Ptr(v int64) *float64 { + r := Int64ToFloat64(v) + return &r +} + +// Int64ToInt converts int64 to int. +func Int64ToInt(v int64) (int, error) { + if !Host64bit && v > math.MaxInt32 { + return 0, errOverflowValue + } + return int(v), nil +} + +// Int64ToIntPtr converts int64 to *int. +func Int64ToIntPtr(v int64) (*int, error) { + r, err := Int64ToInt(v) + return &r, err +} + +// Int64ToInt8 converts int64 to int8. +func Int64ToInt8(v int64) (int8, error) { + if v > math.MaxInt8 || v < math.MinInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Int64ToInt8Ptr converts int64 to *int8. +func Int64ToInt8Ptr(v int64) (*int8, error) { + r, err := Int64ToInt8(v) + return &r, err +} + +// Int64ToInt16 converts int64 to int16. +func Int64ToInt16(v int64) (int16, error) { + if v > math.MaxInt16 || v < math.MinInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// Int64ToInt16Ptr converts int64 to *int16. +func Int64ToInt16Ptr(v int64) (*int16, error) { + r, err := Int64ToInt16(v) + return &r, err +} + +// Int64ToInt32 converts int64 to int32. +func Int64ToInt32(v int64) (int32, error) { + if v > math.MaxInt32 || v < math.MinInt32 { + return 0, errOverflowValue + } + return int32(v), nil +} + +// Int64ToInt32Ptr converts int64 to *int32. +func Int64ToInt32Ptr(v int64) (*int32, error) { + r, err := Int64ToInt32(v) + return &r, err +} + +// Int64ToInt64Ptr converts int64 to *int64. +func Int64ToInt64Ptr(v int64) *int64 { + return &v +} + +// Int64ToUint converts int64 to uint. +func Int64ToUint(v int64) (uint, error) { + if v < 0 { + return 0, errNegativeValue + } + if !Host64bit && v > math.MaxUint32 { + return 0, errOverflowValue + } + return uint(v), nil +} + +// Int64ToUintPtr converts int64 to *uint. +func Int64ToUintPtr(v int64) (*uint, error) { + r, err := Int64ToUint(v) + return &r, err +} + +// Int64ToUint8 converts int64 to uint8. +func Int64ToUint8(v int64) (uint8, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Int64ToUint8Ptr converts int64 to *uint8. +func Int64ToUint8Ptr(v int64) (*uint8, error) { + r, err := Int64ToUint8(v) + return &r, err +} + +// Int64ToUint16 converts int64 to uint16. +func Int64ToUint16(v int64) (uint16, error) { + if v < 0 { + return 0, errNegativeValue + } + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// Int64ToUint16Ptr converts int64 to *uint16. +func Int64ToUint16Ptr(v int64) (*uint16, error) { + r, err := Int64ToUint16(v) + return &r, err +} + +// Int64ToUint32 converts int64 to uint32. +func Int64ToUint32(v int64) (uint32, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint32(v), nil +} + +// Int64ToUint32Ptr converts int64 to *uint32. +func Int64ToUint32Ptr(v int64) (*uint32, error) { + r, err := Int64ToUint32(v) + return &r, err +} + +// Int64ToUint64 converts int64 to uint64. +func Int64ToUint64(v int64) (uint64, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint64(v), nil +} + +// Int64ToUint64Ptr converts int64 to *uint64. +func Int64ToUint64Ptr(v int64) (*uint64, error) { + r, err := Int64ToUint64(v) + return &r, err +} diff --git a/vendor/github.com/henrylee2cn/ameda/int64s.go b/vendor/github.com/henrylee2cn/ameda/int64s.go new file mode 100644 index 0000000..6e62c55 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/int64s.go @@ -0,0 +1,692 @@ +package ameda + +// OneInt64 try to return the first element, otherwise return zero value. +func OneInt64(i []int64) int64 { + if len(i) > 0 { + return i[0] + } + return 0 +} + +// Int64sCopy creates a copy of the int64 slice. +func Int64sCopy(i []int64) []int64 { + b := make([]int64, len(i)) + copy(b, i) + return b +} + +// Int64sToInterfaces converts int64 slice to interface slice. +func Int64sToInterfaces(i []int64) []interface{} { + r := make([]interface{}, len(i)) + for k, v := range i { + r[k] = Int64ToInterface(v) + } + return r +} + +// Int64sToStrings converts int64 slice to string slice. +func Int64sToStrings(i []int64) []string { + r := make([]string, len(i)) + for k, v := range i { + r[k] = Int64ToString(v) + } + return r +} + +// Int64sToBools converts int64 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Int64sToBools(i []int64) []bool { + r := make([]bool, len(i)) + for k, v := range i { + r[k] = Int64ToBool(v) + } + return r +} + +// Int64sToFloat32s converts int64 slice to float32 slice. +func Int64sToFloat32s(i []int64) []float32 { + r := make([]float32, len(i)) + for k, v := range i { + r[k] = Int64ToFloat32(v) + } + return r +} + +// Int64sToFloat64s converts int64 slice to float64 slice. +func Int64sToFloat64s(i []int64) []float64 { + r := make([]float64, len(i)) + for k, v := range i { + r[k] = Int64ToFloat64(v) + } + return r +} + +// Int64sToInts converts int64 slice to int slice. +func Int64sToInts(i []int64) ([]int, error) { + var err error + r := make([]int, len(i)) + for k, v := range i { + r[k], err = Int64ToInt(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToInt8s converts int64 slice to int8 slice. +func Int64sToInt8s(i []int64) ([]int8, error) { + var err error + r := make([]int8, len(i)) + for k, v := range i { + r[k], err = Int64ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToInt16s converts int64 slice to int16 slice. +func Int64sToInt16s(i []int64) ([]int16, error) { + var err error + r := make([]int16, len(i)) + for k, v := range i { + r[k], err = Int64ToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToInt32s converts int64 slice to int32 slice. +func Int64sToInt32s(i []int64) ([]int32, error) { + var err error + r := make([]int32, len(i)) + for k, v := range i { + r[k], err = Int64ToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToUints converts int64 slice to uint slice. +func Int64sToUints(i []int64) ([]uint, error) { + var err error + r := make([]uint, len(i)) + for k, v := range i { + r[k], err = Int64ToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToUint8s converts int64 slice to uint8 slice. +func Int64sToUint8s(i []int64) ([]uint8, error) { + var err error + r := make([]uint8, len(i)) + for k, v := range i { + r[k], err = Int64ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToUint16s converts int64 slice to uint16 slice. +func Int64sToUint16s(i []int64) ([]uint16, error) { + var err error + r := make([]uint16, len(i)) + for k, v := range i { + r[k], err = Int64ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToUint32s converts int64 slice to uint32 slice. +func Int64sToUint32s(i []int64) ([]uint32, error) { + var err error + r := make([]uint32, len(i)) + for k, v := range i { + r[k], err = Int64ToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sToUint64s converts int64 slice to uint64 slice. +func Int64sToUint64s(i []int64) ([]uint64, error) { + var err error + r := make([]uint64, len(i)) + for k, v := range i { + r[k], err = Int64ToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int64sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int64sCopyWithin(i []int64, target, start int, end ...int) { + target = fixIndex(len(i), target, true) + if target == len(i) { + return + } + sub := Int64sSlice(i, start, end...) + for k, v := range sub { + i[target+k] = v + } +} + +// Int64sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Int64sEvery(i []int64, fn func(i []int64, k int, v int64) bool) bool { + for k, v := range i { + if !fn(i, k, v) { + return false + } + } + return true +} + +// Int64sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int64sFill(i []int64, value int64, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(i), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + i[k] = value + } +} + +// Int64sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Int64sFilter(i []int64, fn func(i []int64, k int, v int64) bool) []int64 { + ret := make([]int64, 0) + for k, v := range i { + if fn(i, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Int64sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Int64sFind(i []int64, fn func(i []int64, k int, v int64) bool) (k int, v int64) { + for k, v := range i { + if fn(i, k, v) { + return k, v + } + } + return -1, 0 +} + +// Int64sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int64sIncludes(i []int64, valueToFind int64, fromIndex ...int) bool { + return Int64sIndexOf(i, valueToFind, fromIndex...) > -1 +} + +// Int64sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int64sIndexOf(i []int64, searchElement int64, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k, v := range i[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Int64sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int64sLastIndexOf(i []int64, searchElement int64, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k := len(i) - 1; k >= idx; k-- { + if searchElement == i[k] { + return k + } + } + return -1 +} + +// Int64sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Int64sMap(i []int64, fn func(i []int64, k int, v int64) int64) []int64 { + ret := make([]int64, len(i)) + for k, v := range i { + ret[k] = fn(i, k, v) + } + return ret +} + +// Int64sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Int64sPop(i *[]int64) (int64, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *i = a[:len(a):len(a)] + return last, true +} + +// Int64sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Int64sPush(i *[]int64, element ...int64) int { + *i = append(*i, element...) + return len(*i) +} + +// Int64sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Int64sPushDistinct(i []int64, element ...int64) []int64 { +L: + for _, v := range element { + for _, vv := range i { + if vv == v { + continue L + } + } + i = append(i, v) + } + return i +} + +// Int64sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int64sReduce( + i []int64, + fn func(i []int64, k int, v, accumulator int64) int64, initialValue ...int64, +) int64 { + if len(i) == 0 { + return 0 + } + start := 0 + acc := i[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(i); k++ { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int64sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int64sReduceRight( + i []int64, + fn func(i []int64, k int, v, accumulator int64) int64, initialValue ...int64, +) int64 { + if len(i) == 0 { + return 0 + } + end := len(i) - 1 + acc := i[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int64sReverse reverses an slice in place. +func Int64sReverse(i []int64) { + first := 0 + last := len(i) - 1 + for first < last { + i[first], i[last] = i[last], i[first] + first++ + last-- + } +} + +// Int64sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Int64sShift(i *[]int64) (int64, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *i = a[:len(a):len(a)] + return first, true +} + +// Int64sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Int64sSlice(i []int64, begin int, end ...int) []int64 { + fixedStart, fixedEnd, ok := fixRange(len(i), begin, end...) + if !ok { + return []int64{} + } + return Int64sCopy(i[fixedStart:fixedEnd]) +} + +// Int64sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Int64sSome(i []int64, fn func(i []int64, k int, v int64) bool) bool { + for k, v := range i { + if fn(i, k, v) { + return true + } + } + return false +} + +// Int64sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Int64sSplice(i *[]int64, start, deleteCount int, items ...int64) { + a := *i + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Int64sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *i = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *i = a[:len(a):len(a)] +} + +// Int64sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Int64sUnshift(i *[]int64, element ...int64) int { + *i = append(element, *i...) + return len(*i) +} + +// Int64sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Int64sUnshiftDistinct(i *[]int64, element ...int64) int { + a := *i + if len(element) == 0 { + return len(a) + } + m := make(map[int64]bool, len(element)) + r := make([]int64, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *i = r[:len(r):len(r)] + return len(r) +} + +// Int64sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Int64sRemoveFirst(p *[]int64, elements ...int64) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int64sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Int64sRemoveEvery(p *[]int64, elements ...int64) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int64sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Int64sConcat(i ...[]int64) []int64 { + var totalLen int + for _, v := range i { + totalLen += len(v) + } + ret := make([]int64, totalLen) + dst := ret + for _, v := range i { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Int64sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Int64sIntersect(i ...[]int64) (intersectCount map[int64]int) { + if len(i) == 0 { + return nil + } + for _, v := range i { + if len(v) == 0 { + return nil + } + } + counts := make([]map[int64]int, len(i)) + for k, v := range i { + counts[k] = int64sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Int64sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Int64sDistinct(i *[]int64, changeSlice bool) (distinctCount map[int64]int) { + if !changeSlice { + return int64sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = int64sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func int64sDistinct(src []int64, dst *[]int64) map[int64]int { + m := make(map[int64]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Int64SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int64SetUnion(set1, set2 []int64, others ...[]int64) []int64 { + m := make(map[int64]struct{}, len(set1)+len(set2)) + r := make([]int64, 0, len(m)) + for _, set := range append([][]int64{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Int64SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int64SetIntersect(set1, set2 []int64, others ...[]int64) []int64 { + sets := append([][]int64{set2}, others...) + setsCount := make([]map[int64]int, len(sets)) + for k, v := range sets { + setsCount[k] = int64sDistinct(v, nil) + } + m := make(map[int64]struct{}, len(set1)) + r := make([]int64, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Int64SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Int64SetDifference(set1, set2 []int64, others ...[]int64) []int64 { + m := make(map[int64]struct{}, len(set1)) + r := make([]int64, 0, len(set1)) + sets := append([][]int64{set2}, others...) + for _, v := range sets { + inter := Int64SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/vendor/github.com/henrylee2cn/ameda/int8.go b/vendor/github.com/henrylee2cn/ameda/int8.go new file mode 100644 index 0000000..5c89c97 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/int8.go @@ -0,0 +1,179 @@ +package ameda + +import ( + "strconv" +) + +// Int8ToInterface converts int8 to interface. +func Int8ToInterface(v int8) interface{} { + return v +} + +// Int8ToInterfacePtr converts int8 to *interface. +func Int8ToInterfacePtr(v int8) *interface{} { + r := Int8ToInterface(v) + return &r +} + +// Int8ToString converts int8 to string. +func Int8ToString(v int8) string { + return strconv.FormatInt(int64(v), 10) +} + +// Int8ToStringPtr converts int8 to *string. +func Int8ToStringPtr(v int8) *string { + r := Int8ToString(v) + return &r +} + +// Int8ToBool converts int8 to bool. +func Int8ToBool(v int8) bool { + return v != 0 +} + +// Int8ToBoolPtr converts int8 to *bool. +func Int8ToBoolPtr(v int8) *bool { + r := Int8ToBool(v) + return &r +} + +// Int8ToFloat32 converts int8 to float32. +func Int8ToFloat32(v int8) float32 { + return float32(v) +} + +// Int8ToFloat32Ptr converts int8 to *float32. +func Int8ToFloat32Ptr(v int8) *float32 { + r := Int8ToFloat32(v) + return &r +} + +// Int8ToFloat64 converts int8 to float64. +func Int8ToFloat64(v int8) float64 { + return float64(v) +} + +// Int8ToFloat64Ptr converts int8 to *float64. +func Int8ToFloat64Ptr(v int8) *float64 { + r := Int8ToFloat64(v) + return &r +} + +// Int8ToInt converts int8 to int. +func Int8ToInt(v int8) int { + return int(v) +} + +// Int8ToIntPtr converts int8 to *int. +func Int8ToIntPtr(v int8) *int { + r := Int8ToInt(v) + return &r +} + +// Int8ToInt8Ptr converts int8 to *int8. +func Int8ToInt8Ptr(v int8) *int8 { + return &v +} + +// Int8ToInt16 converts int8 to int16. +func Int8ToInt16(v int8) int16 { + return int16(v) +} + +// Int8ToInt16Ptr converts int8 to *int16. +func Int8ToInt16Ptr(v int8) *int16 { + r := Int8ToInt16(v) + return &r +} + +// Int8ToInt32 converts int8 to int32. +func Int8ToInt32(v int8) int32 { + return int32(v) +} + +// Int8ToInt32Ptr converts int8 to *int32. +func Int8ToInt32Ptr(v int8) *int32 { + r := Int8ToInt32(v) + return &r +} + +// Int8ToInt64 converts int8 to int64. +func Int8ToInt64(v int8) int64 { + return int64(v) +} + +// Int8ToInt64Ptr converts int8 to *int64. +func Int8ToInt64Ptr(v int8) *int64 { + r := Int8ToInt64(v) + return &r +} + +// Int8ToUint converts int8 to uint. +func Int8ToUint(v int8) (uint, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint(v), nil +} + +// Int8ToUintPtr converts int8 to *uint. +func Int8ToUintPtr(v int8) (*uint, error) { + r, err := Int8ToUint(v) + return &r, err +} + +// Int8ToUint8 converts int8 to uint8. +func Int8ToUint8(v int8) (uint8, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint8(v), nil +} + +// Int8ToUint8Ptr converts int8 to *uint8. +func Int8ToUint8Ptr(v int8) (*uint8, error) { + r, err := Int8ToUint8(v) + return &r, err +} + +// Int8ToUint16 converts int8 to uint16. +func Int8ToUint16(v int8) (uint16, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint16(v), nil +} + +// Int8ToUint16Ptr converts int8 to *uint16. +func Int8ToUint16Ptr(v int8) (*uint16, error) { + r, err := Int8ToUint16(v) + return &r, err +} + +// Int8ToUint32 converts int8 to uint32. +func Int8ToUint32(v int8) (uint32, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint32(v), nil +} + +// Int8ToUint32Ptr converts int8 to *uint32. +func Int8ToUint32Ptr(v int8) (*uint32, error) { + r, err := Int8ToUint32(v) + return &r, err +} + +// Int8ToUint64 converts int8 to uint64. +func Int8ToUint64(v int8) (uint64, error) { + if v < 0 { + return 0, errNegativeValue + } + return uint64(v), nil +} + +// Int8ToUint64Ptr converts int8 to *uint64. +func Int8ToUint64Ptr(v int8) (*uint64, error) { + r, err := Int8ToUint64(v) + return &r, err +} diff --git a/vendor/github.com/henrylee2cn/ameda/int8s.go b/vendor/github.com/henrylee2cn/ameda/int8s.go new file mode 100644 index 0000000..1189b55 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/int8s.go @@ -0,0 +1,679 @@ +package ameda + +// OneInt8 try to return the first element, otherwise return zero value. +func OneInt8(i []int8) int8 { + if len(i) > 0 { + return i[0] + } + return 0 +} + +// Int8sCopy creates a copy of the int8 slice. +func Int8sCopy(i []int8) []int8 { + b := make([]int8, len(i)) + copy(b, i) + return b +} + +// Int8sToInterfaces converts int8 slice to interface slice. +func Int8sToInterfaces(i []int8) []interface{} { + r := make([]interface{}, len(i)) + for k, v := range i { + r[k] = v + } + return r +} + +// Int8sToStrings converts int8 slice to string slice. +func Int8sToStrings(i []int8) []string { + r := make([]string, len(i)) + for k, v := range i { + r[k] = Int8ToString(v) + } + return r +} + +// Int8sToBools converts int8 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Int8sToBools(i []int8) []bool { + r := make([]bool, len(i)) + for k, v := range i { + r[k] = Int8ToBool(v) + } + return r +} + +// Int8sToFloat32s converts int8 slice to float32 slice. +func Int8sToFloat32s(i []int8) []float32 { + r := make([]float32, len(i)) + for k, v := range i { + r[k] = Int8ToFloat32(v) + } + return r +} + +// Int8sToFloat64s converts int8 slice to float64 slice. +func Int8sToFloat64s(i []int8) []float64 { + r := make([]float64, len(i)) + for k, v := range i { + r[k] = Int8ToFloat64(v) + } + return r +} + +// Int8sToInts converts int8 slice to int slice. +func Int8sToInts(i []int8) []int { + r := make([]int, len(i)) + for k, v := range i { + r[k] = Int8ToInt(v) + } + return r +} + +// Ints converts int8 slice to int slice. +func Int8sInts(i []int8) []int { + return Int8sToInts(i) +} + +// Int8sToInt16s converts int8 slice to int16 slice. +func Int8sToInt16s(i []int8) []int16 { + r := make([]int16, len(i)) + for k, v := range i { + r[k] = Int8ToInt16(v) + } + return r +} + +// Int8sToInt32s converts int8 slice to int32 slice. +func Int8sToInt32s(i []int8) []int32 { + r := make([]int32, len(i)) + for k, v := range i { + r[k] = Int8ToInt32(v) + } + return r +} + +// Int8sToInt64s converts int8 slice to int64 slice. +func Int8sToInt64s(i []int8) []int64 { + r := make([]int64, len(i)) + for k, v := range i { + r[k] = Int8ToInt64(v) + } + return r +} + +// Int8sToUints converts int8 slice to uint slice. +func Int8sToUints(i []int8) ([]uint, error) { + var err error + r := make([]uint, len(i)) + for k, v := range i { + r[k], err = Int8ToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int8sToUint8s converts int8 slice to uint8 slice. +func Int8sToUint8s(i []int8) ([]uint8, error) { + var err error + r := make([]uint8, len(i)) + for k, v := range i { + r[k], err = Int8ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int8sToUint16s converts int8 slice to uint16 slice. +func Int8sToUint16s(i []int8) ([]uint16, error) { + var err error + r := make([]uint16, len(i)) + for k, v := range i { + r[k], err = Int8ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int8sToUint32s converts int8 slice to uint32 slice. +func Int8sToUint32s(i []int8) ([]uint32, error) { + var err error + r := make([]uint32, len(i)) + for k, v := range i { + r[k], err = Int8ToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int8sToUint64s converts int8 slice to uint64 slice. +func Int8sToUint64s(i []int8) ([]uint64, error) { + var err error + r := make([]uint64, len(i)) + for k, v := range i { + r[k], err = Int8ToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Int8sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int8sCopyWithin(i []int8, target, start int, end ...int) { + target = fixIndex(len(i), target, true) + if target == len(i) { + return + } + sub := Int8sSlice(i, start, end...) + for k, v := range sub { + i[target+k] = v + } +} + +// Int8sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Int8sEvery(i []int8, fn func(i []int8, k int, v int8) bool) bool { + for k, v := range i { + if !fn(i, k, v) { + return false + } + } + return true +} + +// Int8sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Int8sFill(i []int8, value int8, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(i), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + i[k] = value + } +} + +// Int8sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Int8sFilter(i []int8, fn func(i []int8, k int, v int8) bool) []int8 { + ret := make([]int8, 0) + for k, v := range i { + if fn(i, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Int8sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Int8sFind(i []int8, fn func(i []int8, k int, v int8) bool) (k int, v int8) { + for k, v := range i { + if fn(i, k, v) { + return k, v + } + } + return -1, 0 +} + +// Int8sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int8sIncludes(i []int8, valueToFind int8, fromIndex ...int) bool { + return Int8sIndexOf(i, valueToFind, fromIndex...) > -1 +} + +// Int8sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int8sIndexOf(i []int8, searchElement int8, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k, v := range i[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Int8sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Int8sLastIndexOf(i []int8, searchElement int8, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k := len(i) - 1; k >= idx; k-- { + if searchElement == i[k] { + return k + } + } + return -1 +} + +// Int8sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Int8sMap(i []int8, fn func(i []int8, k int, v int8) int8) []int8 { + ret := make([]int8, len(i)) + for k, v := range i { + ret[k] = fn(i, k, v) + } + return ret +} + +// Int8sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Int8sPop(i *[]int8) (int8, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *i = a[:len(a):len(a)] + return last, true +} + +// Int8sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Int8sPush(i *[]int8, element ...int8) int { + *i = append(*i, element...) + return len(*i) +} + +// Int8sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Int8sPushDistinct(i []int8, element ...int8) []int8 { +L: + for _, v := range element { + for _, vv := range i { + if vv == v { + continue L + } + } + i = append(i, v) + } + return i +} + +// Int8sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int8sReduce(i []int8, + fn func(i []int8, k int, v, accumulator int8) int8, initialValue ...int8, +) int8 { + if len(i) == 0 { + return 0 + } + start := 0 + acc := i[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(i); k++ { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int8sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Int8sReduceRight(i []int8, + fn func(i []int8, k int, v, accumulator int8) int8, initialValue ...int8, +) int8 { + if len(i) == 0 { + return 0 + } + end := len(i) - 1 + acc := i[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// Int8sReverse reverses an slice in place. +func Int8sReverse(i []int8) { + first := 0 + last := len(i) - 1 + for first < last { + i[first], i[last] = i[last], i[first] + first++ + last-- + } +} + +// Int8sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Int8sShift(i *[]int8) (int8, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *i = a[:len(a):len(a)] + return first, true +} + +// Int8sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Int8sSlice(i []int8, begin int, end ...int) []int8 { + fixedStart, fixedEnd, ok := fixRange(len(i), begin, end...) + if !ok { + return []int8{} + } + return Int8sCopy(i[fixedStart:fixedEnd]) +} + +// Int8sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Int8sSome(i []int8, fn func(i []int8, k int, v int8) bool) bool { + for k, v := range i { + if fn(i, k, v) { + return true + } + } + return false +} + +// Int8sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Int8sSplice(i *[]int8, start, deleteCount int, items ...int8) { + a := *i + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Int8sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *i = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *i = a[:len(a):len(a)] +} + +// Int8sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Int8sUnshift(i *[]int8, element ...int8) int { + *i = append(element, *i...) + return len(*i) +} + +// Int8sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Int8sUnshiftDistinct(i *[]int8, element ...int8) int { + a := *i + if len(element) == 0 { + return len(a) + } + m := make(map[int8]bool, len(element)) + r := make([]int8, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *i = r[:len(r):len(r)] + return len(r) +} + +// Int8sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Int8sRemoveFirst(p *[]int8, elements ...int8) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int8sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Int8sRemoveEvery(p *[]int8, elements ...int8) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Int8sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Int8sConcat(i ...[]int8) []int8 { + var totalLen int + for _, v := range i { + totalLen += len(v) + } + ret := make([]int8, totalLen) + dst := ret + for _, v := range i { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Int8sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Int8sIntersect(i ...[]int8) (intersectCount map[int8]int) { + if len(i) == 0 { + return nil + } + for _, v := range i { + if len(v) == 0 { + return nil + } + } + counts := make([]map[int8]int, len(i)) + for k, v := range i { + counts[k] = int8sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Int8sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Int8sDistinct(i *[]int8, changeSlice bool) (distinctCount map[int8]int) { + if !changeSlice { + return int8sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = int8sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func int8sDistinct(src []int8, dst *[]int8) map[int8]int { + m := make(map[int8]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Int8SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int8SetUnion(set1, set2 []int8, others ...[]int8) []int8 { + m := make(map[int8]struct{}, len(set1)+len(set2)) + r := make([]int8, 0, len(m)) + for _, set := range append([][]int8{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Int8SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Int8SetIntersect(set1, set2 []int8, others ...[]int8) []int8 { + sets := append([][]int8{set2}, others...) + setsCount := make([]map[int8]int, len(sets)) + for k, v := range sets { + setsCount[k] = int8sDistinct(v, nil) + } + m := make(map[int8]struct{}, len(set1)) + r := make([]int8, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Int8SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Int8SetDifference(set1, set2 []int8, others ...[]int8) []int8 { + m := make(map[int8]struct{}, len(set1)) + r := make([]int8, 0, len(set1)) + sets := append([][]int8{set2}, others...) + for _, v := range sets { + inter := Int8SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/vendor/github.com/henrylee2cn/ameda/interface.go b/vendor/github.com/henrylee2cn/ameda/interface.go new file mode 100644 index 0000000..1805a47 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/interface.go @@ -0,0 +1,812 @@ +package ameda + +import ( + "fmt" + "reflect" +) + +// InterfaceToInterfacePtr converts interface to *interface. +func InterfaceToInterfacePtr(i interface{}) *interface{} { + return &i +} + +// InterfaceToString converts interface to string. +func InterfaceToString(i interface{}) string { + return fmt.Sprintf("%v", i) +} + +// InterfaceToStringPtr converts interface to *string. +func InterfaceToStringPtr(i interface{}) *string { + v := InterfaceToString(i) + return &v +} + +// InterfaceToBool converts interface to bool. +// NOTE: +// 0 is false, other numbers are true +func InterfaceToBool(i interface{}, emptyAsFalse ...bool) (bool, error) { + switch v := i.(type) { + case bool: + return v, nil + case nil: + return false, nil + case float32: + return Float32ToBool(v), nil + case float64: + return Float64ToBool(v), nil + case int: + return IntToBool(v), nil + case int8: + return Int8ToBool(v), nil + case int16: + return Int16ToBool(v), nil + case int32: + return Int32ToBool(v), nil + case int64: + return Int64ToBool(v), nil + case uint: + return UintToBool(v), nil + case uint8: + return Uint8ToBool(v), nil + case uint16: + return Uint16ToBool(v), nil + case uint32: + return Uint32ToBool(v), nil + case uint64: + return Uint64ToBool(v), nil + case uintptr: + return v != 0, nil + case string: + return StringToBool(v, emptyAsFalse...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return r.Bool(), nil + case reflect.Invalid: + return false, nil + case reflect.Float32, reflect.Float64: + return Float64ToBool(r.Float()), nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToBool(r.Int()), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToBool(r.Uint()), nil + case reflect.String: + return StringToBool(r.String(), emptyAsFalse...) + } + if isEmptyAsZero(emptyAsFalse) { + return !isZero(r), nil + } + return false, fmt.Errorf("cannot convert %#v of type %T to bool", i, i) + } +} + +// InterfaceToBoolPtr converts interface to *bool. +// NOTE: +// 0 is false, other numbers are true +func InterfaceToBoolPtr(i interface{}, emptyAsFalse ...bool) (*bool, error) { + r, err := InterfaceToBool(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToFloat32 converts interface to float32. +func InterfaceToFloat32(i interface{}, emptyStringAsZero ...bool) (float32, error) { + switch v := i.(type) { + case bool: + return BoolToFloat32(v), nil + case nil: + return 0, nil + case int: + return IntToFloat32(v), nil + case int8: + return Int8ToFloat32(v), nil + case int16: + return Int16ToFloat32(v), nil + case int32: + return Int32ToFloat32(v), nil + case int64: + return Int64ToFloat32(v), nil + case uint: + return UintToFloat32(v), nil + case uint8: + return Uint8ToFloat32(v), nil + case uint16: + return Uint16ToFloat32(v), nil + case uint32: + return Uint32ToFloat32(v), nil + case uint64: + return Uint64ToFloat32(v), nil + case uintptr: + return UintToFloat32(uint(v)), nil + case string: + return StringToFloat32(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToFloat32(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32: + return float32(r.Float()), nil + case reflect.Float64: + return Float64ToFloat32(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToFloat32(r.Int()), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToFloat32(r.Uint()), nil + case reflect.String: + return StringToFloat32(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToFloat32(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to float32", i, i) + } +} + +// InterfaceToFloat32Ptr converts interface to *float32. +func InterfaceToFloat32Ptr(i interface{}, emptyAsFalse ...bool) (*float32, error) { + r, err := InterfaceToFloat32(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToFloat64 converts interface to float64. +func InterfaceToFloat64(i interface{}, emptyStringAsZero ...bool) (float64, error) { + switch v := i.(type) { + case bool: + return BoolToFloat64(v), nil + case nil: + return 0, nil + case int: + return IntToFloat64(v), nil + case int8: + return Int8ToFloat64(v), nil + case int16: + return Int16ToFloat64(v), nil + case int32: + return Int32ToFloat64(v), nil + case int64: + return Int64ToFloat64(v), nil + case uint: + return UintToFloat64(v), nil + case uint8: + return Uint8ToFloat64(v), nil + case uint16: + return Uint16ToFloat64(v), nil + case uint32: + return Uint32ToFloat64(v), nil + case uint64: + return Uint64ToFloat64(v), nil + case uintptr: + return UintToFloat64(uint(v)), nil + case string: + return StringToFloat64(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToFloat64(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return r.Float(), nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToFloat64(r.Int()), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToFloat64(r.Uint()), nil + case reflect.String: + return StringToFloat64(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToFloat64(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to float64", i, i) + } +} + +// InterfaceToFloat64Ptr converts interface to *float64. +func InterfaceToFloat64Ptr(i interface{}, emptyAsFalse ...bool) (*float64, error) { + r, err := InterfaceToFloat64(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToInt converts interface to int. +func InterfaceToInt(i interface{}, emptyStringAsZero ...bool) (int, error) { + switch v := i.(type) { + case bool: + return BoolToInt(v), nil + case nil: + return 0, nil + case int: + return v, nil + case int8: + return Int8ToInt(v), nil + case int16: + return Int16ToInt(v), nil + case int32: + return Int32ToInt(v), nil + case int64: + return Int64ToInt(v) + case uint: + return UintToInt(v) + case uint8: + return Uint8ToInt(v), nil + case uint16: + return Uint16ToInt(v), nil + case uint32: + return Uint32ToInt(v), nil + case uint64: + return Uint64ToInt(v), nil + case uintptr: + return UintToInt(uint(v)) + case string: + return StringToInt(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToInt(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToInt(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToInt(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToInt(r.Uint()), nil + case reflect.String: + return StringToInt(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToInt(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to int", i, i) + } +} + +// InterfaceToIntPtr converts interface to *float64. +func InterfaceToIntPtr(i interface{}, emptyAsFalse ...bool) (*int, error) { + r, err := InterfaceToInt(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToInt8 converts interface to int8. +func InterfaceToInt8(i interface{}, emptyStringAsZero ...bool) (int8, error) { + switch v := i.(type) { + case bool: + return BoolToInt8(v), nil + case nil: + return 0, nil + case int: + return IntToInt8(v) + case int8: + return v, nil + case int16: + return Int16ToInt8(v) + case int32: + return Int32ToInt8(v) + case int64: + return Int64ToInt8(v) + case uint: + return UintToInt8(v) + case uint8: + return Uint8ToInt8(v) + case uint16: + return Uint16ToInt8(v) + case uint32: + return Uint32ToInt8(v) + case uint64: + return Uint64ToInt8(v) + case uintptr: + return UintToInt8(uint(v)) + case string: + return StringToInt8(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToInt8(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToInt8(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToInt8(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToInt8(r.Uint()) + case reflect.String: + return StringToInt8(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToInt8(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to int8", i, i) + } +} + +// InterfaceToInt8Ptr converts interface to *int8. +func InterfaceToInt8Ptr(i interface{}, emptyAsFalse ...bool) (*int8, error) { + r, err := InterfaceToInt8(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToInt16 converts interface to int16. +func InterfaceToInt16(i interface{}, emptyStringAsZero ...bool) (int16, error) { + switch v := i.(type) { + case bool: + return BoolToInt16(v), nil + case nil: + return 0, nil + case int: + return IntToInt16(v) + case int8: + return Int8ToInt16(v), nil + case int16: + return v, nil + case int32: + return Int32ToInt16(v) + case int64: + return Int64ToInt16(v) + case uint: + return UintToInt16(v) + case uint8: + return Uint8ToInt16(v), nil + case uint16: + return Uint16ToInt16(v) + case uint32: + return Uint32ToInt16(v) + case uint64: + return Uint64ToInt16(v) + case uintptr: + return UintToInt16(uint(v)) + case string: + return StringToInt16(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToInt16(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToInt16(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToInt16(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToInt16(r.Uint()) + case reflect.String: + return StringToInt16(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToInt16(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to int16", i, i) + } +} + +// InterfaceToInt16Ptr converts interface to *int16. +func InterfaceToInt16Ptr(i interface{}, emptyAsFalse ...bool) (*int16, error) { + r, err := InterfaceToInt16(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToInt32 converts interface to int32. +func InterfaceToInt32(i interface{}, emptyStringAsZero ...bool) (int32, error) { + switch v := i.(type) { + case bool: + return BoolToInt32(v), nil + case nil: + return 0, nil + case int: + return IntToInt32(v) + case int8: + return Int8ToInt32(v), nil + case int16: + return Int16ToInt32(v), nil + case int32: + return v, nil + case int64: + return Int64ToInt32(v) + case uint: + return UintToInt32(v) + case uint8: + return Uint8ToInt32(v), nil + case uint16: + return Uint16ToInt32(v), nil + case uint32: + return Uint32ToInt32(v) + case uint64: + return Uint64ToInt32(v) + case uintptr: + return UintToInt32(uint(v)) + case string: + return StringToInt32(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToInt32(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToInt32(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToInt32(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToInt32(r.Uint()) + case reflect.String: + return StringToInt32(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToInt32(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to int32", i, i) + } +} + +// InterfaceToInt32Ptr converts interface to *int32. +func InterfaceToInt32Ptr(i interface{}, emptyAsFalse ...bool) (*int32, error) { + r, err := InterfaceToInt32(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToInt64 converts interface to int64. +func InterfaceToInt64(i interface{}, emptyStringAsZero ...bool) (int64, error) { + switch v := i.(type) { + case bool: + return BoolToInt64(v), nil + case nil: + return 0, nil + case int: + return IntToInt64(v), nil + case int8: + return Int8ToInt64(v), nil + case int16: + return Int16ToInt64(v), nil + case int32: + return Int32ToInt64(v), nil + case int64: + return v, nil + case uint: + return UintToInt64(v) + case uint8: + return Uint8ToInt64(v), nil + case uint16: + return Uint16ToInt64(v), nil + case uint32: + return Uint32ToInt64(v), nil + case uint64: + return Uint64ToInt64(v) + case uintptr: + return UintToInt64(uint(v)) + case string: + return StringToInt64(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToInt64(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToInt64(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return r.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToInt64(r.Uint()) + case reflect.String: + return StringToInt64(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToInt64(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to int64", i, i) + } +} + +// InterfaceToInt64Ptr converts interface to *int64. +func InterfaceToInt64Ptr(i interface{}, emptyAsFalse ...bool) (*int64, error) { + r, err := InterfaceToInt64(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToUint converts interface to uint. +func InterfaceToUint(i interface{}, emptyStringAsZero ...bool) (uint, error) { + switch v := i.(type) { + case bool: + return BoolToUint(v), nil + case nil: + return 0, nil + case int: + return IntToUint(v) + case int8: + return Int8ToUint(v) + case int16: + return Int16ToUint(v) + case int32: + return Int32ToUint(v) + case int64: + return Int64ToUint(v) + case uint: + return v, nil + case uint8: + return Uint8ToUint(v), nil + case uint16: + return Uint16ToUint(v), nil + case uint32: + return Uint32ToUint(v), nil + case uint64: + return Uint64ToUint(v) + case uintptr: + return uint(v), nil + case string: + return StringToUint(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToUint(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToUint(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToUint(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToUint(r.Uint()) + case reflect.String: + return StringToUint(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToUint(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to uint", i, i) + } +} + +// InterfaceToUintPtr converts interface to *uint. +func InterfaceToUintPtr(i interface{}, emptyAsFalse ...bool) (*uint, error) { + r, err := InterfaceToUint(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToUint8 converts interface to uint8. +func InterfaceToUint8(i interface{}, emptyStringAsZero ...bool) (uint8, error) { + switch v := i.(type) { + case bool: + return BoolToUint8(v), nil + case nil: + return 0, nil + case int: + return IntToUint8(v) + case int8: + return Int8ToUint8(v) + case int16: + return Int16ToUint8(v) + case int32: + return Int32ToUint8(v) + case int64: + return Int64ToUint8(v) + case uint: + return UintToUint8(v) + case uint8: + return v, nil + case uint16: + return Uint16ToUint8(v) + case uint32: + return Uint32ToUint8(v) + case uint64: + return Uint64ToUint8(v) + case uintptr: + return UintToUint8(uint(v)) + case string: + return StringToUint8(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToUint8(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToUint8(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToUint8(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToUint8(r.Uint()) + case reflect.String: + return StringToUint8(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToUint8(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to uint8", i, i) + } +} + +// InterfaceToUint8Ptr converts interface to *uint8. +func InterfaceToUint8Ptr(i interface{}, emptyAsFalse ...bool) (*uint8, error) { + r, err := InterfaceToUint8(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToUint16 converts interface to uint16. +func InterfaceToUint16(i interface{}, emptyStringAsZero ...bool) (uint16, error) { + switch v := i.(type) { + case bool: + return BoolToUint16(v), nil + case nil: + return 0, nil + case int: + return IntToUint16(v) + case int8: + return Int8ToUint16(v) + case int16: + return Int16ToUint16(v) + case int32: + return Int32ToUint16(v) + case int64: + return Int64ToUint16(v) + case uint: + return UintToUint16(v) + case uint8: + return Uint8ToUint16(v), nil + case uint16: + return v, nil + case uint32: + return Uint32ToUint16(v) + case uint64: + return Uint64ToUint16(v) + case uintptr: + return UintToUint16(uint(v)) + case string: + return StringToUint16(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToUint16(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToUint16(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToUint16(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToUint16(r.Uint()) + case reflect.String: + return StringToUint16(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToUint16(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to uint16", i, i) + } +} + +// InterfaceToUint16Ptr converts interface to *uint16. +func InterfaceToUint16Ptr(i interface{}, emptyAsFalse ...bool) (*uint16, error) { + r, err := InterfaceToUint16(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToUint32 converts interface to uint32. +func InterfaceToUint32(i interface{}, emptyStringAsZero ...bool) (uint32, error) { + switch v := i.(type) { + case bool: + return BoolToUint32(v), nil + case nil: + return 0, nil + case int: + return IntToUint32(v) + case int8: + return Int8ToUint32(v) + case int16: + return Int16ToUint32(v) + case int32: + return Int32ToUint32(v) + case int64: + return Int64ToUint32(v) + case uint: + return UintToUint32(v) + case uint8: + return Uint8ToUint32(v), nil + case uint16: + return Uint16ToUint32(v), nil + case uint32: + return v, nil + case uint64: + return Uint64ToUint32(v) + case uintptr: + return UintToUint32(uint(v)) + case string: + return StringToUint32(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToUint32(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToUint32(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToUint32(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return Uint64ToUint32(r.Uint()) + case reflect.String: + return StringToUint32(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToUint32(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to uint32", i, i) + } +} + +// InterfaceToUint32Ptr converts interface to *uint32. +func InterfaceToUint32Ptr(i interface{}, emptyAsFalse ...bool) (*uint32, error) { + r, err := InterfaceToUint32(i, emptyAsFalse...) + return &r, err +} + +// InterfaceToUint64 converts interface to uint64. +func InterfaceToUint64(i interface{}, emptyStringAsZero ...bool) (uint64, error) { + switch v := i.(type) { + case bool: + return BoolToUint64(v), nil + case nil: + return 0, nil + case int: + return IntToUint64(v) + case int8: + return Int8ToUint64(v) + case int16: + return Int16ToUint64(v) + case int32: + return Int32ToUint64(v) + case int64: + return Int64ToUint64(v) + case uint: + return UintToUint64(v), nil + case uint8: + return Uint8ToUint64(v), nil + case uint16: + return Uint16ToUint64(v), nil + case uint32: + return Uint32ToUint64(v), nil + case uint64: + return v, nil + case uintptr: + return UintToUint64(uint(v)), nil + case string: + return StringToUint64(v, emptyStringAsZero...) + default: + r := IndirectValue(reflect.ValueOf(i)) + switch r.Kind() { + case reflect.Bool: + return BoolToUint64(r.Bool()), nil + case reflect.Invalid: + return 0, nil + case reflect.Float32, reflect.Float64: + return Float64ToUint64(r.Float()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return Int64ToUint64(r.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return r.Uint(), nil + case reflect.String: + return StringToUint64(r.String(), emptyStringAsZero...) + } + if isEmptyAsZero(emptyStringAsZero) { + return BoolToUint64(!isZero(r)), nil + } + return 0, fmt.Errorf("cannot convert %#v of type %T to uint64", i, i) + } +} + +// InterfaceToUint64Ptr converts interface to *uint64. +func InterfaceToUint64Ptr(i interface{}, emptyAsFalse ...bool) (*uint64, error) { + r, err := InterfaceToUint64(i, emptyAsFalse...) + return &r, err +} diff --git a/vendor/github.com/henrylee2cn/ameda/interfaces.go b/vendor/github.com/henrylee2cn/ameda/interfaces.go new file mode 100644 index 0000000..5a1135f --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/interfaces.go @@ -0,0 +1,643 @@ +package ameda + +// OneInterface try to return the first element, otherwise return zero value. +func OneInterface(i []interface{}) interface{} { + if len(i) > 0 { + return i[0] + } + return nil +} + +// InterfacesCopy creates a copy of the interface slice. +func InterfacesCopy(i []interface{}) []interface{} { + b := make([]interface{}, len(i)) + copy(b, i) + return b +} + +// InterfacesToStrings converts interface slice to string slice. +func InterfacesToStrings(i []interface{}) []string { + r := make([]string, len(i)) + for k, v := range i { + r[k] = InterfaceToString(v) + } + return r +} + +// InterfacesToBools converts interface slice to bool slice. +// NOTE: +// 0 is false, other numbers are true +func InterfacesToBools(i []interface{}) ([]bool, error) { + var err error + r := make([]bool, len(i)) + for k, v := range i { + r[k], err = InterfaceToBool(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToFloat32s converts interface slice to float32 slice. +func InterfacesToFloat32s(i []interface{}) ([]float32, error) { + var err error + r := make([]float32, len(i)) + for k, v := range i { + r[k], err = InterfaceToFloat32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToFloat64s converts interface slice to float64 slice. +func InterfacesToFloat64s(i []interface{}) ([]float64, error) { + var err error + r := make([]float64, len(i)) + for k, v := range i { + r[k], err = InterfaceToFloat64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToInts converts interface slice to int slice. +func InterfacesToInts(i []interface{}) ([]int, error) { + var err error + r := make([]int, len(i)) + for k, v := range i { + r[k], err = InterfaceToInt(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToInt8s converts interface slice to int8 slice. +func InterfacesToInt8s(i []interface{}) ([]int8, error) { + var err error + r := make([]int8, len(i)) + for k, v := range i { + r[k], err = InterfaceToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToInt16s converts interface slice to int16 slice. +func InterfacesToInt16s(i []interface{}) ([]int16, error) { + var err error + r := make([]int16, len(i)) + for k, v := range i { + r[k], err = InterfaceToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToInt32s converts interface slice to int32 slice. +func InterfacesToInt32s(i []interface{}) ([]int32, error) { + var err error + r := make([]int32, len(i)) + for k, v := range i { + r[k], err = InterfaceToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToInt64s converts interface slice to int64 slice. +func InterfacesToInt64s(i []interface{}) ([]int64, error) { + var err error + r := make([]int64, len(i)) + for k, v := range i { + r[k], err = InterfaceToInt64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToUints converts interface slice to uint slice. +func InterfacesToUints(i []interface{}) ([]uint, error) { + var err error + r := make([]uint, len(i)) + for k, v := range i { + r[k], err = InterfaceToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToUint8s converts interface slice to uint8 slice. +func InterfacesToUint8s(i []interface{}) ([]uint8, error) { + var err error + r := make([]uint8, len(i)) + for k, v := range i { + r[k], err = InterfaceToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToUint16s converts interface slice to uint16 slice. +func InterfacesToUint16s(i []interface{}) ([]uint16, error) { + var err error + r := make([]uint16, len(i)) + for k, v := range i { + r[k], err = InterfaceToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToUint32s converts interface slice to uint32 slice. +func InterfacesToUint32s(i []interface{}) ([]uint32, error) { + var err error + r := make([]uint32, len(i)) + for k, v := range i { + r[k], err = InterfaceToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesToUint64s converts interface slice to uint64 slice. +func InterfacesToUint64s(i []interface{}) ([]uint64, error) { + var err error + r := make([]uint64, len(i)) + for k, v := range i { + r[k], err = InterfaceToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// InterfacesCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func InterfacesCopyWithin(i []interface{}, target, start int, end ...int) { + target = fixIndex(len(i), target, true) + if target == len(i) { + return + } + sub := InterfacesSlice(i, start, end...) + for k, v := range sub { + i[target+k] = v + } +} + +// InterfacesEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func InterfacesEvery(i []interface{}, fn func(i []interface{}, k int, v interface{}) bool) bool { + for k, v := range i { + if !fn(i, k, v) { + return false + } + } + return true +} + +// InterfacesFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func InterfacesFill(i []interface{}, value []interface{}, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(i), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + i[k] = value + } +} + +// InterfacesFilter creates a new slice with all elements that pass the test implemented by the provided function. +func InterfacesFilter(i []interface{}, fn func(i []interface{}, k int, v interface{}) bool) []interface{} { + ret := make([]interface{}, 0) + for k, v := range i { + if fn(i, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// InterfacesFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func InterfacesFind(i []interface{}, fn func(i []interface{}, k int, v interface{}) bool) (k int, v interface{}) { + for k, v := range i { + if fn(i, k, v) { + return k, v + } + } + return -1, 0 +} + +// InterfacesIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func InterfacesIncludes(i []interface{}, valueToFind int64, fromIndex ...int) bool { + return InterfacesIndexOf(i, valueToFind, fromIndex...) > -1 +} + +// InterfacesIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func InterfacesIndexOf(i []interface{}, searchElement int64, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k, v := range i[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// InterfacesLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func InterfacesLastIndexOf(i []interface{}, searchElement int64, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k := len(i) - 1; k >= idx; k-- { + if searchElement == i[k] { + return k + } + } + return -1 +} + +// InterfacesMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func InterfacesMap(i []interface{}, fn func(i []interface{}, k int, v interface{}) int64) []int64 { + ret := make([]int64, len(i)) + for k, v := range i { + ret[k] = fn(i, k, v) + } + return ret +} + +// InterfacesPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func InterfacesPop(i *[]interface{}) (interface{}, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *i = a[:len(a):len(a)] + return last, true +} + +// InterfacesPush adds one or more elements to the end of an slice and returns the new length of the slice. +func InterfacesPush(i *[]interface{}, element ...interface{}) int { + *i = append(*i, element...) + return len(*i) +} + +// InterfacesPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func InterfacesPushDistinct(i []interface{}, element ...interface{}) []interface{} { +L: + for _, v := range element { + for _, vv := range i { + if vv == v { + continue L + } + } + i = append(i, v) + } + return i +} + +// InterfacesReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func InterfacesReduce( + i []interface{}, + fn func(i []interface{}, k int, v, accumulator interface{}) interface{}, initialValue ...interface{}, +) interface{} { + if len(i) == 0 { + return 0 + } + start := 0 + acc := i[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(i); k++ { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// InterfacesReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func InterfacesReduceRight( + i []interface{}, + fn func(i []interface{}, k int, v, accumulator interface{}) interface{}, initialValue ...interface{}, +) interface{} { + if len(i) == 0 { + return 0 + } + end := len(i) - 1 + acc := i[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// InterfacesReverse reverses an slice in place. +func InterfacesReverse(i []interface{}) { + first := 0 + last := len(i) - 1 + for first < last { + i[first], i[last] = i[last], i[first] + first++ + last-- + } +} + +// InterfacesShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func InterfacesShift(i *[]interface{}) (interface{}, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *i = a[:len(a):len(a)] + return first, true +} + +// InterfacesSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func InterfacesSlice(i []interface{}, begin int, end ...int) []interface{} { + fixedStart, fixedEnd, ok := fixRange(len(i), begin, end...) + if !ok { + return []interface{}{} + } + return InterfacesCopy(i[fixedStart:fixedEnd]) +} + +// InterfacesSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func InterfacesSome(i []interface{}, fn func(i []interface{}, k int, v interface{}) bool) bool { + for k, v := range i { + if fn(i, k, v) { + return true + } + } + return false +} + +// InterfacesSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func InterfacesSplice(i *[]interface{}, start, deleteCount int, items ...interface{}) { + a := *i + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := InterfacesCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *i = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *i = a[:len(a):len(a)] +} + +// InterfacesUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func InterfacesUnshift(i *[]interface{}, element ...interface{}) int { + *i = append(element, *i...) + return len(*i) +} + +// InterfacesUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func InterfacesUnshiftDistinct(i *[]interface{}, element ...interface{}) int { + a := *i + if len(element) == 0 { + return len(a) + } + m := make(map[interface{}]bool, len(element)) + r := make([]interface{}, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *i = r[:len(r):len(r)] + return len(r) +} + +// InterfacesRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func InterfacesRemoveFirst(p *[]interface{}, elements ...interface{}) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// InterfacesRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func InterfacesRemoveEvery(p *[]interface{}, elements ...interface{}) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// InterfacesConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func InterfacesConcat(i ...[]interface{}) []interface{} { + var totalLen int + for _, v := range i { + totalLen += len(v) + } + ret := make([]interface{}, totalLen) + dst := ret + for _, v := range i { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// InterfacesIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func InterfacesIntersect(i ...[]interface{}) (intersectCount map[interface{}]int) { + if len(i) == 0 { + return nil + } + for _, v := range i { + if len(v) == 0 { + return nil + } + } + counts := make([]map[interface{}]int, len(i)) + for k, v := range i { + counts[k] = interfacesDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// InterfacesDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func InterfacesDistinct(i *[]interface{}, changeSlice bool) (distinctCount map[interface{}]int) { + if !changeSlice { + return interfacesDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = interfacesDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func interfacesDistinct(src []interface{}, dst *[]interface{}) map[interface{}]int { + m := make(map[interface{}]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} diff --git a/vendor/github.com/henrylee2cn/ameda/ints.go b/vendor/github.com/henrylee2cn/ameda/ints.go new file mode 100644 index 0000000..0bc8cb0 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/ints.go @@ -0,0 +1,682 @@ +package ameda + +// OneInt try to return the first element, otherwise return zero value. +func OneInt(i []int) int { + if len(i) > 0 { + return i[0] + } + return 0 +} + +// IntsCopy creates a copy of the int slice. +func IntsCopy(i []int) []int { + b := make([]int, len(i)) + copy(b, i) + return b +} + +// IntsToInterfaces converts int slice to interface slice. +func IntsToInterfaces(i []int) []interface{} { + r := make([]interface{}, len(i)) + for k, v := range i { + r[k] = IntToInterface(v) + } + return r +} + +// IntsToStrings converts int slice to string slice. +func IntsToStrings(i []int) []string { + r := make([]string, len(i)) + for k, v := range i { + r[k] = IntToString(v) + } + return r +} + +// IntsToBools converts int slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func IntsToBools(i []int) []bool { + r := make([]bool, len(i)) + for k, v := range i { + r[k] = IntToBool(v) + } + return r +} + +// IntsToFloat32s converts int slice to float32 slice. +func IntsToFloat32s(i []int) []float32 { + r := make([]float32, len(i)) + for k, v := range i { + r[k] = IntToFloat32(v) + } + return r +} + +// IntsToFloat64s converts int slice to float64 slice. +func IntsToFloat64s(i []int) []float64 { + r := make([]float64, len(i)) + for k, v := range i { + r[k] = IntToFloat64(v) + } + return r +} + +// IntsToInt8s converts int slice to int8 slice. +func IntsToInt8s(i []int) ([]int8, error) { + var err error + r := make([]int8, len(i)) + for k, v := range i { + r[k], err = IntToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsToInt16s converts int slice to int16 slice. +func IntsToInt16s(i []int) ([]int16, error) { + var err error + r := make([]int16, len(i)) + for k, v := range i { + r[k], err = IntToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsToInt32s converts int slice to int32 slice. +func IntsToInt32s(i []int) ([]int32, error) { + var err error + r := make([]int32, len(i)) + for k, v := range i { + r[k], err = IntToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsToInt64s converts int slice to int64 slice. +func IntsToInt64s(i []int) []int64 { + r := make([]int64, len(i)) + for k, v := range i { + r[k] = IntToInt64(v) + } + return r +} + +// IntsToUints converts int slice to uint slice. +func IntsToUints(i []int) ([]uint, error) { + var err error + r := make([]uint, len(i)) + for k, v := range i { + r[k], err = IntToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsToUint8s converts int slice to uint8 slice. +func IntsToUint8s(i []int) ([]uint8, error) { + var err error + r := make([]uint8, len(i)) + for k, v := range i { + r[k], err = IntToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsToUint16s converts int slice to uint16 slice. +func IntsToUint16s(i []int) ([]uint16, error) { + var err error + r := make([]uint16, len(i)) + for k, v := range i { + r[k], err = IntToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsToUint32s converts int slice to uint32 slice. +func IntsToUint32s(i []int) ([]uint32, error) { + var err error + r := make([]uint32, len(i)) + for k, v := range i { + r[k], err = IntToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsToUint64s converts int slice to uint64 slice. +func IntsToUint64s(i []int) ([]uint64, error) { + var err error + r := make([]uint64, len(i)) + for k, v := range i { + r[k], err = IntToUint64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// IntsCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func IntsCopyWithin(i []int, target, start int, end ...int) { + target = fixIndex(len(i), target, true) + if target == len(i) { + return + } + sub := IntsSlice(i, start, end...) + for k, v := range sub { + i[target+k] = v + } +} + +// IntsEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func IntsEvery(i []int, fn func(i []int, k int, v int) bool) bool { + for k, v := range i { + if !fn(i, k, v) { + return false + } + } + return true +} + +// IntsFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func IntsFill(i []int, value int, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(i), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + i[k] = value + } +} + +// IntsFilter creates a new slice with all elements that pass the test implemented by the provided function. +func IntsFilter(i []int, fn func(i []int, k int, v int) bool) []int { + ret := make([]int, 0) + for k, v := range i { + if fn(i, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// IntsFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func IntsFind(i []int, fn func(i []int, k int, v int) bool) (k int, v int) { + for k, v := range i { + if fn(i, k, v) { + return k, v + } + } + return -1, 0 +} + +// IntsIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func IntsIncludes(i []int, valueToFind int, fromIndex ...int) bool { + return IntsIndexOf(i, valueToFind, fromIndex...) > -1 +} + +// IntsIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func IntsIndexOf(i []int, searchElement int, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k, v := range i[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// IntsLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func IntsLastIndexOf(i []int, searchElement int, fromIndex ...int) int { + idx := getFromIndex(len(i), fromIndex...) + for k := len(i) - 1; k >= idx; k-- { + if searchElement == i[k] { + return k + } + } + return -1 +} + +// IntsMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func IntsMap(i []int, fn func(i []int, k int, v int) int) []int { + ret := make([]int, len(i)) + for k, v := range i { + ret[k] = fn(i, k, v) + } + return ret +} + +// IntsPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func IntsPop(i *[]int) (int, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *i = a[:len(a):len(a)] + return last, true +} + +// IntsPush adds one or more elements to the end of an slice and returns the new length of the slice. +func IntsPush(i *[]int, element ...int) int { + *i = append(*i, element...) + return len(*i) +} + +// IntsPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func IntsPushDistinct(i []int, element ...int) []int { +L: + for _, v := range element { + for _, vv := range i { + if vv == v { + continue L + } + } + i = append(i, v) + } + return i +} + +// IntsReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func IntsReduce(i []int, fn func(i []int, k int, v, accumulator int) int, initialValue ...int) int { + if len(i) == 0 { + return 0 + } + start := 0 + acc := i[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(i); k++ { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// IntsReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func IntsReduceRight(i []int, fn func(i []int, k int, v, accumulator int) int, initialValue ...int) int { + if len(i) == 0 { + return 0 + } + end := len(i) - 1 + acc := i[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(i, k, i[k], acc) + } + return acc +} + +// IntsReverse reverses an slice in place. +func IntsReverse(i []int) { + first := 0 + last := len(i) - 1 + for first < last { + i[first], i[last] = i[last], i[first] + first++ + last-- + } +} + +// IntsShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func IntsShift(i *[]int) (int, bool) { + a := *i + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *i = a[:len(a):len(a)] + return first, true +} + +// IntsSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func IntsSlice(i []int, begin int, end ...int) []int { + fixedStart, fixedEnd, ok := fixRange(len(i), begin, end...) + if !ok { + return []int{} + } + return IntsCopy(i[fixedStart:fixedEnd]) +} + +// IntsSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func IntsSome(i []int, fn func(i []int, k int, v int) bool) bool { + for k, v := range i { + if fn(i, k, v) { + return true + } + } + return false +} + +// IntsSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func IntsSplice(i *[]int, start, deleteCount int, items ...int) { + a := *i + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := IntsCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *i = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *i = a[:len(a):len(a)] +} + +// IntsUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func IntsUnshift(i *[]int, element ...int) int { + *i = append(element, *i...) + return len(*i) +} + +// IntsUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func IntsUnshiftDistinct(i *[]int, element ...int) int { + a := *i + if len(element) == 0 { + return len(a) + } + m := make(map[int]bool, len(element)) + r := make([]int, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *i = r[:len(r):len(r)] + return len(r) +} + +// IntsRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func IntsRemoveFirst(p *[]int, elements ...int) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// IntsRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func IntsRemoveEvery(p *[]int, elements ...int) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// IntsConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func IntsConcat(i ...[]int) []int { + var totalLen int + for _, v := range i { + totalLen += len(v) + } + ret := make([]int, totalLen) + dst := ret + for _, v := range i { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// IntsIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func IntsIntersect(i ...[]int) (intersectCount map[int]int) { + if len(i) == 0 { + return nil + } + for _, v := range i { + if len(v) == 0 { + return nil + } + } + counts := make([]map[int]int, len(i)) + for k, v := range i { + counts[k] = intsDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// IntsDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func IntsDistinct(i *[]int, changeSlice bool) (distinctCount map[int]int) { + if !changeSlice { + return intsDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = intsDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func intsDistinct(src []int, dst *[]int) map[int]int { + m := make(map[int]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// IntSetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func IntSetUnion(set1, set2 []int, others ...[]int) []int { + m := make(map[int]struct{}, len(set1)+len(set2)) + r := make([]int, 0, len(m)) + for _, set := range append([][]int{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// IntSetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func IntSetIntersect(set1, set2 []int, others ...[]int) []int { + sets := append([][]int{set2}, others...) + setsCount := make([]map[int]int, len(sets)) + for k, v := range sets { + setsCount[k] = intsDistinct(v, nil) + } + m := make(map[int]struct{}, len(set1)) + r := make([]int, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// IntSetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func IntSetDifference(set1, set2 []int, others ...[]int) []int { + m := make(map[int]struct{}, len(set1)) + r := make([]int, 0, len(set1)) + sets := append([][]int{set2}, others...) + for _, v := range sets { + inter := IntSetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/vendor/github.com/henrylee2cn/ameda/itoa62.go b/vendor/github.com/henrylee2cn/ameda/itoa62.go new file mode 100644 index 0000000..6aaa07a --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/itoa62.go @@ -0,0 +1,210 @@ +package ameda + +import "math/bits" + +// FormatUint returns the string representation of i in the given base, +// for 2 <= base <= 62. +// NOTE: +// Compatible with standard package strconv. +func FormatUint(i uint64, base int) string { + if fastSmalls && i < nSmalls && base == 10 { + return small(int(i)) + } + _, s := formatBits(nil, i, base, false, false) + return s +} + +// FormatInt returns the string representation of i in the given base, +// for 2 <= base <= 62. +// NOTE: +// Compatible with standard package strconv. +func FormatInt(i int64, base int) string { + if fastSmalls && 0 <= i && i < nSmalls && base == 10 { + return small(int(i)) + } + _, s := formatBits(nil, uint64(i), base, i < 0, false) + return s +} + +// Itoa is equivalent to FormatInt(int64(i), 10). +// NOTE: +// Compatible with standard package strconv. +func Itoa(i int) string { + return FormatInt(int64(i), 10) +} + +// AppendInt appends the string form of the integer i, +// as generated by FormatInt, to dst and returns the extended buffer. +// NOTE: +// Compatible with standard package strconv. +func AppendInt(dst []byte, i int64, base int) []byte { + if fastSmalls && 0 <= i && i < nSmalls && base == 10 { + return append(dst, small(int(i))...) + } + dst, _ = formatBits(dst, uint64(i), base, i < 0, true) + return dst +} + +// AppendUint appends the string form of the unsigned integer i, +// as generated by FormatUint, to dst and returns the extended buffer. +// NOTE: +// Compatible with standard package strconv. +func AppendUint(dst []byte, i uint64, base int) []byte { + if fastSmalls && i < nSmalls && base == 10 { + return append(dst, small(int(i))...) + } + dst, _ = formatBits(dst, i, base, false, true) + return dst +} + +const ( + digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +) + +const ( + fastSmalls = true // enable fast path for small integers + nSmalls = 100 + smallsString = "00010203040506070809" + + "10111213141516171819" + + "20212223242526272829" + + "30313233343536373839" + + "40414243444546474849" + + "50515253545556575859" + + "60616263646566676869" + + "70717273747576777879" + + "80818283848586878889" + + "90919293949596979899" +) + +// small returns the string for an i with 0 <= i < nSmalls. +func small(i int) string { + if i < 10 { + return digits[i : i+1] + } + return smallsString[i*2 : i*2+2] +} + +// formatBits computes the string representation of u in the given base. +// If neg is set, u is treated as negative int64 value. If append_ is +// set, the string is appended to dst and the resulting byte slice is +// returned as the first result value; otherwise the string is returned +// as the second result value. +// +func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s string) { + if base < 2 || base > len(digits) { + panic("ameda(strconv): illegal AppendInt/FormatInt base") + } + // 2 <= base && base <= len(digits) + + var a [64 + 1]byte // +1 for sign of 64bit value in base 2 + i := len(a) + + if neg { + u = -u + } + + // convert bits + // We use uint values where we can because those will + // fit into a single register even on a 32bit machine. + if base == 10 { + // common case: use constants for / because + // the compiler can optimize it into a multiply+shift + + if Host32bit { + // convert the lower digits using 32bit operations + for u >= 1e9 { + // Avoid using r = a%b in addition to q = a/b + // since 64bit division and modulo operations + // are calculated by runtime functions on 32bit machines. + q := u / 1e9 + us := uint(u - q*1e9) // u % 1e9 fits into a uint + for j := 4; j > 0; j-- { + is := us % 100 * 2 + us /= 100 + i -= 2 + a[i+1] = smallsString[is+1] + a[i+0] = smallsString[is+0] + } + + // us < 10, since it contains the last digit + // from the initial 9-digit us. + i-- + a[i] = smallsString[us*2+1] + + u = q + } + // u < 1e9 + } + + // u guaranteed to fit into a uint + us := uint(u) + for us >= 100 { + is := us % 100 * 2 + us /= 100 + i -= 2 + a[i+1] = smallsString[is+1] + a[i+0] = smallsString[is+0] + } + + // us < 100 + is := us * 2 + i-- + a[i] = smallsString[is+1] + if us >= 10 { + i-- + a[i] = smallsString[is] + } + + } else if isPowerOfTwo(base) { + // Use shifts and masks instead of / and %. + // Base is a power of 2 and 2 <= base <= len(digits) where len(digits) is 62. + // The largest power of 2 below or equal to 62 is 32, which is 1 << 5; + // i.e., the largest possible shift count is 5. By &-ind that value with + // the constant 7 we tell the compiler that the shift count is always + // less than 8 which is smaller than any register width. This allows + // the compiler to generate better code for the shift operation. + shift := uint(bits.TrailingZeros(uint(base))) & 7 + b := uint64(base) + m := uint(base) - 1 // == 1<= b { + i-- + a[i] = digits[uint(u)&m] + u >>= shift + } + // u < base + i-- + a[i] = digits[uint(u)] + } else { + // general case + b := uint64(base) + for u >= b { + i-- + // Avoid using r = a%b in addition to q = a/b + // since 64bit division and modulo operations + // are calculated by runtime functions on 32bit machines. + q := u / b + a[i] = digits[uint(u-q*b)] + u = q + } + // u < base + i-- + a[i] = digits[uint(u)] + } + + // add sign, if any + if neg { + i-- + a[i] = '-' + } + + if append_ { + d = append(dst, a[i:]...) + return + } + s = string(a[i:]) + return +} + +func isPowerOfTwo(x int) bool { + return x&(x-1) == 0 +} diff --git a/vendor/github.com/henrylee2cn/ameda/itoa_x.go b/vendor/github.com/henrylee2cn/ameda/itoa_x.go new file mode 100644 index 0000000..68aee00 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/itoa_x.go @@ -0,0 +1,21 @@ +package ameda + +// FormatUintByDict convert num into corresponding string according to dict. +func FormatUintByDict(dict []byte, num uint64) string { + var base = uint64(len(dict)) + if base == 0 { + return "" + } + var str []byte + for { + tmp := make([]byte, len(str)+1) + tmp[0] = dict[num%base] + copy(tmp[1:], str) + str = tmp + num = num / base + if num == 0 { + break + } + } + return string(str) +} diff --git a/vendor/github.com/henrylee2cn/ameda/string.go b/vendor/github.com/henrylee2cn/ameda/string.go new file mode 100644 index 0000000..f169b67 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/string.go @@ -0,0 +1,242 @@ +package ameda + +import ( + "strconv" +) + +// StringToInterface converts string to interface. +func StringToInterface(v string) interface{} { + return v +} + +// StringToInterfacePtr converts string to *interface. +func StringToInterfacePtr(v string) *interface{} { + r := StringToInterface(v) + return &r +} + +// StringToStringPtr converts string to *string. +func StringToStringPtr(v string) *string { + return &v +} + +// StringToBool converts string to bool. +func StringToBool(v string, emptyAsFalse ...bool) (bool, error) { + r, err := strconv.ParseBool(v) + if err != nil { + if !isEmptyAsZero(emptyAsFalse) { + return false, err + } + } + return r, nil +} + +// StringToBoolPtr converts string to *bool. +func StringToBoolPtr(v string, emptyAsFalse ...bool) (*bool, error) { + r, err := StringToBool(v, emptyAsFalse...) + return &r, err +} + +// StringToFloat32 converts string to float32. +func StringToFloat32(v string, emptyAsZero ...bool) (float32, error) { + i, err := strconv.ParseFloat(v, 32) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return float32(i), nil +} + +// StringToFloat32Ptr converts string to *float32. +func StringToFloat32Ptr(v string, emptyAsZero ...bool) (*float32, error) { + r, err := StringToFloat32(v, emptyAsZero...) + return &r, err +} + +// StringToFloat64 converts string to float64. +func StringToFloat64(v string, emptyAsZero ...bool) (float64, error) { + i, err := strconv.ParseFloat(v, 64) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return i, nil +} + +// StringToFloat64Ptr converts string to *float64. +func StringToFloat64Ptr(v string, emptyAsZero ...bool) (*float64, error) { + r, err := StringToFloat64(v, emptyAsZero...) + return &r, err +} + +// StringToInt converts string to int. +func StringToInt(v string, emptyAsZero ...bool) (int, error) { + i, err := strconv.Atoi(v) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return i, nil +} + +// StringToIntPtr converts string to *int. +func StringToIntPtr(v string, emptyAsZero ...bool) (*int, error) { + r, err := StringToInt(v, emptyAsZero...) + return &r, err +} + +// StringToInt8 converts string to int8. +func StringToInt8(v string, emptyAsZero ...bool) (int8, error) { + i, err := strconv.ParseInt(v, 10, 8) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return int8(i), nil +} + +// StringToInt8Ptr converts string to *int8. +func StringToInt8Ptr(v string, emptyAsZero ...bool) (*int8, error) { + r, err := StringToInt8(v, emptyAsZero...) + return &r, err +} + +// StringToInt16 converts string to int16. +func StringToInt16(v string, emptyAsZero ...bool) (int16, error) { + i, err := strconv.ParseInt(v, 10, 16) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return int16(i), nil +} + +// StringToInt16Ptr converts string to *int16. +func StringToInt16Ptr(v string, emptyAsZero ...bool) (*int16, error) { + r, err := StringToInt16(v, emptyAsZero...) + return &r, err +} + +// StringToInt32 converts string to int32. +func StringToInt32(v string, emptyAsZero ...bool) (int32, error) { + i, err := strconv.ParseInt(v, 10, 32) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return int32(i), nil +} + +// StringToInt32Ptr converts string to *int32. +func StringToInt32Ptr(v string, emptyAsZero ...bool) (*int32, error) { + r, err := StringToInt32(v, emptyAsZero...) + return &r, err +} + +// StringToInt64 converts string to int64. +func StringToInt64(v string, emptyAsZero ...bool) (int64, error) { + i, err := strconv.ParseInt(v, 10, 64) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return i, nil +} + +// StringToInt64Ptr converts string to *int64. +func StringToInt64Ptr(v string, emptyAsZero ...bool) (*int64, error) { + r, err := StringToInt64(v, emptyAsZero...) + return &r, err +} + +// StringToUint converts string to uint. +func StringToUint(v string, emptyAsZero ...bool) (uint, error) { + u, err := strconv.ParseUint(v, 10, strconv.IntSize) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return uint(u), nil +} + +// StringToUintPtr converts string to *uint. +func StringToUintPtr(v string, emptyAsZero ...bool) (*uint, error) { + r, err := StringToUint(v, emptyAsZero...) + return &r, err +} + +// StringToUint8 converts string to uint8. +func StringToUint8(v string, emptyAsZero ...bool) (uint8, error) { + u, err := strconv.ParseUint(v, 10, 8) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return uint8(u), nil +} + +// StringToUint8Ptr converts string to *uint8. +func StringToUint8Ptr(v string, emptyAsZero ...bool) (*uint8, error) { + r, err := StringToUint8(v, emptyAsZero...) + return &r, err +} + +// StringToUint16 converts string to uint16. +func StringToUint16(v string, emptyAsZero ...bool) (uint16, error) { + u, err := strconv.ParseUint(v, 10, 16) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return uint16(u), nil +} + +// StringToUint16Ptr converts string to *uint16. +func StringToUint16Ptr(v string, emptyAsZero ...bool) (*uint16, error) { + r, err := StringToUint16(v, emptyAsZero...) + return &r, err +} + +// StringToUint32 converts string to uint32. +func StringToUint32(v string, emptyAsZero ...bool) (uint32, error) { + u, err := strconv.ParseUint(v, 10, 32) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return uint32(u), nil +} + +// StringToUint32Ptr converts string to *uint32. +func StringToUint32Ptr(v string, emptyAsZero ...bool) (*uint32, error) { + r, err := StringToUint32(v, emptyAsZero...) + return &r, err +} + +// StringToUint64 converts string to uint64. +func StringToUint64(v string, emptyAsZero ...bool) (uint64, error) { + u, err := strconv.ParseUint(v, 10, 64) + if err != nil { + if !isEmptyAsZero(emptyAsZero) { + return 0, err + } + } + return u, nil +} + +// StringToUint64Ptr converts string to *uint64. +func StringToUint64Ptr(v string, emptyAsZero ...bool) (*uint64, error) { + r, err := StringToUint64(v, emptyAsZero...) + return &r, err +} diff --git a/vendor/github.com/henrylee2cn/ameda/strings.go b/vendor/github.com/henrylee2cn/ameda/strings.go new file mode 100644 index 0000000..2643b57 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/strings.go @@ -0,0 +1,710 @@ +package ameda + +import ( + "strings" +) + +// OneString try to return the first element, otherwise return zero value. +func OneString(s []string) string { + if len(s) > 0 { + return s[0] + } + return "" +} + +// StringsCopy creates a copy of the string slice. +func StringsCopy(s []string) []string { + b := make([]string, len(s)) + copy(b, s) + return b +} + +// StringsToInterfaces converts string slice to interface slice. +func StringsToInterfaces(s []string) []interface{} { + r := make([]interface{}, len(s)) + for k, v := range s { + r[k] = StringToInterface(v) + } + return r +} + +// StringsToBools converts string slice to bool slice. +func StringsToBools(s []string, emptyAsZero ...bool) ([]bool, error) { + var err error + r := make([]bool, len(s)) + for k, v := range s { + r[k], err = StringToBool(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToFloat32s converts string slice to float32 slice. +func StringsToFloat32s(s []string, emptyAsZero ...bool) ([]float32, error) { + var err error + r := make([]float32, len(s)) + for k, v := range s { + r[k], err = StringToFloat32(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToFloat64s converts string slice to float64 slice. +func StringsToFloat64s(s []string, emptyAsZero ...bool) ([]float64, error) { + var err error + r := make([]float64, len(s)) + for k, v := range s { + r[k], err = StringToFloat64(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToInts converts string slice to int slice. +func StringsToInts(s []string, emptyAsZero ...bool) ([]int, error) { + var err error + r := make([]int, len(s)) + for k, v := range s { + r[k], err = StringToInt(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToInt8s converts string slice to int8 slice. +func StringsToInt8s(s []string, emptyAsZero ...bool) ([]int8, error) { + var err error + r := make([]int8, len(s)) + for k, v := range s { + r[k], err = StringToInt8(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToInt16s converts string slice to int16 slice. +func StringsToInt16s(s []string, emptyAsZero ...bool) ([]int16, error) { + var err error + r := make([]int16, len(s)) + for k, v := range s { + r[k], err = StringToInt16(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToInt32s converts string slice to int32 slice. +func StringsToInt32s(s []string, emptyAsZero ...bool) ([]int32, error) { + var err error + r := make([]int32, len(s)) + for k, v := range s { + r[k], err = StringToInt32(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToInt64s converts string slice to int64 slice. +func StringsToInt64s(s []string, emptyAsZero ...bool) ([]int64, error) { + var err error + r := make([]int64, len(s)) + for k, v := range s { + r[k], err = StringToInt64(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToUints converts string slice to uint slice. +func StringsToUints(s []string, emptyAsZero ...bool) ([]uint, error) { + var err error + r := make([]uint, len(s)) + for k, v := range s { + r[k], err = StringToUint(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToUint8s converts string slice to uint8 slice. +func StringsToUint8s(s []string, emptyAsZero ...bool) ([]uint8, error) { + var err error + r := make([]uint8, len(s)) + for k, v := range s { + r[k], err = StringToUint8(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToUint16s converts string slice to uint16 slice. +func StringsToUint16s(s []string, emptyAsZero ...bool) ([]uint16, error) { + var err error + r := make([]uint16, len(s)) + for k, v := range s { + r[k], err = StringToUint16(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToUint32s converts string slice to uint32 slice. +func StringsToUint32s(s []string, emptyAsZero ...bool) ([]uint32, error) { + var err error + r := make([]uint32, len(s)) + for k, v := range s { + r[k], err = StringToUint32(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsToUint64s converts string slice to uint64 slice. +func StringsToUint64s(s []string, emptyAsZero ...bool) ([]uint64, error) { + var err error + r := make([]uint64, len(s)) + for k, v := range s { + r[k], err = StringToUint64(v, emptyAsZero...) + if err != nil { + return r, err + } + } + return r, nil +} + +// StringsCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func StringsCopyWithin(s []string, target, start int, end ...int) { + target = fixIndex(len(s), target, true) + if target == len(s) { + return + } + sub := StringsSlice(s, start, end...) + for i, v := range sub { + s[target+i] = v + } +} + +// StringsEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func StringsEvery(s []string, fn func(s []string, k int, v string) bool) bool { + for k, v := range s { + if !fn(s, k, v) { + return false + } + } + return true +} + +// StringsFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func StringsFill(s []string, value string, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(s), start, end...) + if !ok { + return + } + for i := fixedStart; i < fixedEnd; i++ { + s[i] = value + } +} + +// StringsFilter creates a new slice with all elements that pass the test implemented by the provided function. +func StringsFilter(s []string, fn func(s []string, k int, v string) bool) []string { + ret := make([]string, 0) + for k, v := range s { + if fn(s, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// StringsFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func StringsFind(s []string, fn func(s []string, k int, v string) bool) (k int, v string) { + for k, v := range s { + if fn(s, k, v) { + return k, v + } + } + return -1, "" +} + +// StringsIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func StringsIncludes(s []string, valueToFind string, fromIndex ...int) bool { + return StringsIndexOf(s, valueToFind, fromIndex...) > -1 +} + +// StringsIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func StringsIndexOf(s []string, searchElement string, fromIndex ...int) int { + idx := getFromIndex(len(s), fromIndex...) + for k, v := range s[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// StringsJoin concatenates the elements of s to create a single string. The separator string +// sep is placed between elements in the resulting string. +func StringsJoin(s []string, sep string) string { + return strings.Join(s, sep) +} + +// StringsLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func StringsLastIndexOf(s []string, searchElement string, fromIndex ...int) int { + idx := getFromIndex(len(s), fromIndex...) + for i := len(s) - 1; i >= idx; i-- { + if searchElement == s[i] { + return i + } + } + return -1 +} + +// StringsMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func StringsMap(s []string, fn func(s []string, k int, v string) string) []string { + ret := make([]string, len(s)) + for k, v := range s { + ret[k] = fn(s, k, v) + } + return ret +} + +// StringsPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func StringsPop(s *[]string) (string, bool) { + a := *s + if len(a) == 0 { + return "", false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *s = a[:len(a):len(a)] + return last, true +} + +// StringsPush adds one or more elements to the end of an slice and returns the new length of the slice. +func StringsPush(s *[]string, element ...string) int { + *s = append(*s, element...) + return len(*s) +} + +// StringsPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func StringsPushDistinct(s []string, element ...string) []string { +L: + for _, v := range element { + for _, vv := range s { + if vv == v { + continue L + } + } + s = append(s, v) + } + return s +} + +// StringsReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func StringsReduce(s []string, fn func(s []string, k int, v, accumulator string) string, initialValue ...string) string { + if len(s) == 0 { + return "" + } + start := 0 + acc := s[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for i := start; i < len(s); i++ { + acc = fn(s, i, s[i], acc) + } + return acc +} + +// StringsReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func StringsReduceRight(s []string, fn func(s []string, k int, v, accumulator string) string, initialValue ...string) string { + if len(s) == 0 { + return "" + } + end := len(s) - 1 + acc := s[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for i := end; i >= 0; i-- { + acc = fn(s, i, s[i], acc) + } + return acc +} + +// StringsReverse reverses an slice in place. +func StringsReverse(s []string) { + first := 0 + last := len(s) - 1 + for first < last { + s[first], s[last] = s[last], s[first] + first++ + last-- + } +} + +// StringsShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func StringsShift(s *[]string) (string, bool) { + a := *s + if len(a) == 0 { + return "", false + } + first := a[0] + a = a[1:] + *s = a[:len(a):len(a)] + return first, true +} + +// StringsSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func StringsSlice(s []string, begin int, end ...int) []string { + fixedStart, fixedEnd, ok := fixRange(len(s), begin, end...) + if !ok { + return []string{} + } + return StringsCopy(s[fixedStart:fixedEnd]) +} + +// StringsSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func StringsSome(s []string, fn func(s []string, k int, v string) bool) bool { + for k, v := range s { + if fn(s, k, v) { + return true + } + } + return false +} + +// StringsSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func StringsSplice(s *[]string, start, deleteCount int, items ...string) { + a := *s + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for i := 0; i < len(items); i++ { + if deleteCount > 0 { + // replace + a[start] = items[i] + deleteCount-- + start++ + } else { + // insert + lastSlice := StringsCopy(a[start:]) + items = items[i:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *s = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *s = a[:len(a):len(a)] +} + +// StringsUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func StringsUnshift(s *[]string, element ...string) int { + *s = append(element, *s...) + return len(*s) +} + +// StringsUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func StringsUnshiftDistinct(s *[]string, element ...string) int { + a := *s + if len(element) == 0 { + return len(a) + } + m := make(map[string]bool, len(element)) + r := make([]string, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *s = r[:len(r):len(r)] + return len(r) +} + +// StringsRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func StringsRemoveFirst(p *[]string, elements ...string) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// StringsRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func StringsRemoveEvery(p *[]string, elements ...string) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// StringsConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func StringsConcat(s ...[]string) []string { + var totalLen int + for _, v := range s { + totalLen += len(v) + } + ret := make([]string, totalLen) + dst := ret + for _, v := range s { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// StringsIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func StringsIntersect(s ...[]string) (intersectCount map[string]int) { + if len(s) == 0 { + return nil + } + for _, v := range s { + if len(v) == 0 { + return nil + } + } + counts := make([]map[string]int, len(s)) + for k, v := range s { + counts[k] = stringsDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// StringsDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func StringsDistinct(s *[]string, changeSlice bool) (distinctCount map[string]int) { + if !changeSlice { + return stringsDistinct(*s, nil) + } + a := (*s)[:0] + distinctCount = stringsDistinct(*s, &a) + n := len(distinctCount) + *s = a[:n:n] + return distinctCount +} + +func stringsDistinct(src []string, dst *[]string) map[string]int { + m := make(map[string]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// StringSetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func StringSetUnion(set1, set2 []string, others ...[]string) []string { + m := make(map[string]struct{}, len(set1)+len(set2)) + r := make([]string, 0, len(m)) + for _, set := range append([][]string{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// StringSetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func StringSetIntersect(set1, set2 []string, others ...[]string) []string { + sets := append([][]string{set2}, others...) + setsCount := make([]map[string]int, len(sets)) + for k, v := range sets { + setsCount[k] = stringsDistinct(v, nil) + } + m := make(map[string]struct{}, len(set1)) + r := make([]string, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// StringSetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func StringSetDifference(set1, set2 []string, others ...[]string) []string { + m := make(map[string]struct{}, len(set1)) + r := make([]string, 0, len(set1)) + sets := append([][]string{set2}, others...) + for _, v := range sets { + inter := StringSetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/vendor/github.com/henrylee2cn/ameda/typconv.go b/vendor/github.com/henrylee2cn/ameda/typconv.go new file mode 100644 index 0000000..7f972b0 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/typconv.go @@ -0,0 +1,138 @@ +package ameda + +import ( + "reflect" + "unsafe" +) + +// UnsafeBytesToString convert []byte type to string type. +func UnsafeBytesToString(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +// UnsafeStringToBytes convert string type to []byte type. +// NOTE: +// panic if modify the member value of the []byte. +func UnsafeStringToBytes(s string) []byte { + sh := (*reflect.StringHeader)(unsafe.Pointer(&s)) + bh := reflect.SliceHeader{Data: sh.Data, Len: sh.Len, Cap: sh.Len} + return *(*[]byte)(unsafe.Pointer(&bh)) +} + +// IndirectValue gets the indirect value. +func IndirectValue(v reflect.Value) reflect.Value { + if !v.IsValid() { + return v + } + if v.Kind() != reflect.Ptr { + // Avoid creating a reflect.Value if it's not a pointer. + return v + } + for v.Kind() == reflect.Ptr && !v.IsNil() { + v = v.Elem() + } + return v +} + +// DereferenceType dereference, get the underlying non-pointer type. +func DereferenceType(t reflect.Type) reflect.Type { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t +} + +// DereferenceValue dereference and unpack interface, +// get the underlying non-pointer and non-interface value. +func DereferenceValue(v reflect.Value) reflect.Value { + for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { + v = v.Elem() + } + return v +} + +// DereferencePtrValue returns the underlying non-pointer type value. +func DereferencePtrValue(v reflect.Value) reflect.Value { + for v.Kind() == reflect.Ptr { + v = v.Elem() + } + return v +} + +// DereferenceInterfaceValue returns the value of the underlying type that implements the interface v. +func DereferenceInterfaceValue(v reflect.Value) reflect.Value { + for v.Kind() == reflect.Interface { + v = v.Elem() + } + return v +} + +// DereferenceImplementType returns the underlying type of the value that implements the interface v. +func DereferenceImplementType(v reflect.Value) reflect.Type { + return DereferenceType(DereferenceInterfaceValue(v).Type()) +} + +// DereferenceSlice convert []*T to []T. +func DereferenceSlice(v reflect.Value) reflect.Value { + m := v.Len() - 1 + if m < 0 { + return reflect.New(reflect.SliceOf(DereferenceType(v.Type().Elem()))).Elem() + } + s := make([]reflect.Value, m+1) + for ; m >= 0; m-- { + s[m] = DereferenceValue(v.Index(m)) + } + v = reflect.New(reflect.SliceOf(s[0].Type())).Elem() + v = reflect.Append(v, s...) + return v +} + +// ReferenceSlice convert []T to []*T, the ptrDepth is the count of '*'. +func ReferenceSlice(v reflect.Value, ptrDepth int) reflect.Value { + if ptrDepth <= 0 { + return v + } + m := v.Len() - 1 + if m < 0 { + return reflect.New(reflect.SliceOf(ReferenceType(v.Type().Elem(), ptrDepth))).Elem() + } + s := make([]reflect.Value, m+1) + for ; m >= 0; m-- { + s[m] = ReferenceValue(v.Index(m), ptrDepth) + } + v = reflect.New(reflect.SliceOf(s[0].Type())).Elem() + v = reflect.Append(v, s...) + return v +} + +// ReferenceType convert T to *T, the ptrDepth is the count of '*'. +func ReferenceType(t reflect.Type, ptrDepth int) reflect.Type { + switch { + case ptrDepth > 0: + for ; ptrDepth > 0; ptrDepth-- { + t = reflect.PtrTo(t) + } + case ptrDepth < 0: + for ; ptrDepth < 0 && t.Kind() == reflect.Ptr; ptrDepth++ { + t = t.Elem() + } + } + return t +} + +// ReferenceValue convert T to *T, the ptrDepth is the count of '*'. +func ReferenceValue(v reflect.Value, ptrDepth int) reflect.Value { + switch { + case ptrDepth > 0: + for ; ptrDepth > 0; ptrDepth-- { + vv := reflect.New(v.Type()) + vv.Elem().Set(v) + v = vv + } + case ptrDepth < 0: + for ; ptrDepth < 0 && v.Kind() == reflect.Ptr; ptrDepth++ { + v = v.Elem() + } + } + return v +} diff --git a/vendor/github.com/henrylee2cn/ameda/uint.go b/vendor/github.com/henrylee2cn/ameda/uint.go new file mode 100644 index 0000000..7917ded --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/uint.go @@ -0,0 +1,203 @@ +package ameda + +import ( + "math" + "strconv" +) + +// MaxUint returns max uint number for current os. +func MaxUint() uint { + if Host32bit { + return math.MaxUint32 + } + return math.MaxUint64 +} + +// UintToInterface converts uint to interface. +func UintToInterface(v uint) interface{} { + return v +} + +// UintToInterfacePtr converts uint to *interface. +func UintToInterfacePtr(v uint) *interface{} { + r := UintToInterface(v) + return &r +} + +// UintToString converts uint to string. +func UintToString(v uint) string { + return strconv.FormatUint(uint64(v), 10) +} + +// UintToStringPtr converts uint to *string. +func UintToStringPtr(v uint) *string { + r := UintToString(v) + return &r +} + +// UintToBool converts uint to bool. +func UintToBool(v uint) bool { + return v != 0 +} + +// UintToBoolPtr converts uint to *bool. +func UintToBoolPtr(v uint) *bool { + r := UintToBool(v) + return &r +} + +// UintToFloat32 converts uint to float32. +func UintToFloat32(v uint) float32 { + return float32(v) +} + +// UintToFloat32Ptr converts uint to *float32. +func UintToFloat32Ptr(v uint) *float32 { + r := UintToFloat32(v) + return &r +} + +// UintToFloat64 converts uint to float64. +func UintToFloat64(v uint) float64 { + return float64(v) +} + +// UintToFloat64Ptr converts uint to *float64. +func UintToFloat64Ptr(v uint) *float64 { + r := UintToFloat64(v) + return &r +} + +// UintToInt converts uint to int. +func UintToInt(v uint) (int, error) { + if Host64bit { + if v > uint(maxInt64) { + return 0, errOverflowValue + } + } else { + if v > math.MaxInt32 { + return 0, errOverflowValue + } + } + return int(v), nil +} + +// UintToIntPtr converts uint to *int. +func UintToIntPtr(v uint) (*int, error) { + r, err := UintToInt(v) + return &r, err +} + +// UintToInt8 converts uint to int8. +func UintToInt8(v uint) (int8, error) { + if v > math.MaxInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// UintToInt8Ptr converts uint to *int8. +func UintToInt8Ptr(v uint) (*int8, error) { + r, err := UintToInt8(v) + return &r, err +} + +// UintToInt16 converts uint to int16. +func UintToInt16(v uint) (int16, error) { + if v > math.MaxInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// UintToInt16Ptr converts uint to *int16. +func UintToInt16Ptr(v uint) (*int16, error) { + r, err := UintToInt16(v) + return &r, err +} + +// UintToInt32 converts uint to int32. +func UintToInt32(v uint) (int32, error) { + if v > math.MaxInt32 { + return 0, errOverflowValue + } + return int32(v), nil +} + +// UintToInt32Ptr converts uint to *int32. +func UintToInt32Ptr(v uint) (*int32, error) { + r, err := UintToInt32(v) + return &r, err +} + +// UintToInt64 converts uint to int64. +func UintToInt64(v uint) (int64, error) { + if Host64bit && v > uint(maxInt64) { + return 0, errOverflowValue + } + return int64(v), nil +} + +// UintToInt64Ptr converts uint to *int64. +func UintToInt64Ptr(v uint) (*int64, error) { + r, err := UintToInt64(v) + return &r, err +} + +// UintToUintPtr converts uint to *uint. +func UintToUintPtr(v uint) *uint { + return &v +} + +// UintToUint8 converts uint to uint8. +func UintToUint8(v uint) (uint8, error) { + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// UintToUint8Ptr converts uint to *uint8. +func UintToUint8Ptr(v uint) (*uint8, error) { + r, err := UintToUint8(v) + return &r, err +} + +// UintToUint16 converts uint to uint16. +func UintToUint16(v uint) (uint16, error) { + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// UintToUint16Ptr converts uint to *uint16. +func UintToUint16Ptr(v uint) (*uint16, error) { + r, err := UintToUint16(v) + return &r, err +} + +// UintToUint32 converts uint to uint32. +func UintToUint32(v uint) (uint32, error) { + if Host64bit && v > math.MaxUint32 { + return 0, errOverflowValue + } + return uint32(v), nil +} + +// UintToUint32Ptr converts uint to *uint32. +func UintToUint32Ptr(v uint) (*uint32, error) { + r, err := UintToUint32(v) + return &r, err +} + +// UintToUint64 converts uint to uint64. +func UintToUint64(v uint) uint64 { + return uint64(v) +} + +// UintToUint64Ptr converts uint to *uint64. +func UintToUint64Ptr(v uint) *uint64 { + r := UintToUint64(v) + return &r +} diff --git a/vendor/github.com/henrylee2cn/ameda/uint16.go b/vendor/github.com/henrylee2cn/ameda/uint16.go new file mode 100644 index 0000000..3f2336e --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/uint16.go @@ -0,0 +1,174 @@ +package ameda + +import ( + "math" + "strconv" +) + +// Uint16ToInterface converts uint16 to interface. +func Uint16ToInterface(v uint16) interface{} { + return v +} + +// Uint16ToInterfacePtr converts uint16 to *interface. +func Uint16ToInterfacePtr(v uint16) *interface{} { + r := Uint16ToInterface(v) + return &r +} + +// Uint16ToString converts uint16 to string. +func Uint16ToString(v uint16) string { + return strconv.FormatUint(uint64(v), 10) +} + +// Uint16ToStringPtr converts uint16 to *string. +func Uint16ToStringPtr(v uint16) *string { + r := Uint16ToString(v) + return &r +} + +// Uint16ToBool converts uint16 to bool. +func Uint16ToBool(v uint16) bool { + return v != 0 +} + +// Uint16ToBoolPtr converts uint16 to *bool. +func Uint16ToBoolPtr(v uint16) *bool { + r := Uint16ToBool(v) + return &r +} + +// Uint16ToFloat32 converts uint16 to float32. +func Uint16ToFloat32(v uint16) float32 { + return float32(v) +} + +// Uint16ToFloat32Ptr converts uint16 to *float32. +func Uint16ToFloat32Ptr(v uint16) *float32 { + r := Uint16ToFloat32(v) + return &r +} + +// Uint16ToFloat64 converts uint16 to float64. +func Uint16ToFloat64(v uint16) float64 { + return float64(v) +} + +// Uint16ToFloat64Ptr converts uint16 to *float64. +func Uint16ToFloat64Ptr(v uint16) *float64 { + r := Uint16ToFloat64(v) + return &r +} + +// Uint16ToInt converts uint16 to int. +func Uint16ToInt(v uint16) int { + return int(v) +} + +// Uint16ToIntPtr converts uint16 to *int. +func Uint16ToIntPtr(v uint16) *int { + r := Uint16ToInt(v) + return &r +} + +// Uint16ToInt8 converts uint16 to int8. +func Uint16ToInt8(v uint16) (int8, error) { + if v > math.MaxInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Uint16ToInt8Ptr converts uint16 to *int8. +func Uint16ToInt8Ptr(v uint16) (*int8, error) { + r, err := Uint16ToInt8(v) + return &r, err +} + +// Uint16ToInt16 converts uint16 to int16. +func Uint16ToInt16(v uint16) (int16, error) { + if v > math.MaxInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// Uint16ToInt16Ptr converts uint16 to *int16. +func Uint16ToInt16Ptr(v uint16) (*int16, error) { + r, err := Uint16ToInt16(v) + return &r, err +} + +// Uint16ToInt32 converts uint16 to int32. +func Uint16ToInt32(v uint16) int32 { + return int32(v) +} + +// Uint16ToInt32Ptr converts uint16 to *int32. +func Uint16ToInt32Ptr(v uint16) *int32 { + r := Uint16ToInt32(v) + return &r +} + +// Uint16ToInt64 converts uint16 to int64. +func Uint16ToInt64(v uint16) int64 { + return int64(v) +} + +// Uint16ToInt64Ptr converts uint16 to *int64. +func Uint16ToInt64Ptr(v uint16) *int64 { + r := Uint16ToInt64(v) + return &r +} + +// Uint16ToUint converts uint16 to uint. +func Uint16ToUint(v uint16) uint { + return uint(v) +} + +// Uint16ToUintPtr converts uint16 to *uint. +func Uint16ToUintPtr(v uint16) *uint { + r := Uint16ToUint(v) + return &r +} + +// Uint16ToUint8 converts uint16 to uint8. +func Uint16ToUint8(v uint16) (uint8, error) { + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Uint16ToUint8Ptr converts uint16 to *uint8. +func Uint16ToUint8Ptr(v uint16) (*uint8, error) { + r, err := Uint16ToUint8(v) + return &r, err +} + +// Uint16ToUint16Ptr converts uint16 to *uint16. +func Uint16ToUint16Ptr(v uint16) *uint16 { + return &v +} + +// Uint16ToUint32 converts uint16 to uint32. +func Uint16ToUint32(v uint16) uint32 { + return uint32(v) +} + +// Uint16ToUint32Ptr converts uint16 to *uint32. +func Uint16ToUint32Ptr(v uint16) *uint32 { + r := Uint16ToUint32(v) + return &r +} + +// Uint16ToUint64 converts uint16 to uint64. +func Uint16ToUint64(v uint16) uint64 { + return uint64(v) +} + +// Uint16ToUint64Ptr converts uint16 to *uint64. +func Uint16ToUint64Ptr(v uint16) *uint64 { + r := Uint16ToUint64(v) + return &r +} diff --git a/vendor/github.com/henrylee2cn/ameda/uint16s.go b/vendor/github.com/henrylee2cn/ameda/uint16s.go new file mode 100644 index 0000000..af352d1 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/uint16s.go @@ -0,0 +1,668 @@ +package ameda + +// OneUint16 try to return the first element, otherwise return zero value. +func OneUint16(u []uint16) uint16 { + if len(u) > 0 { + return u[0] + } + return 0 +} + +// Uint16sCopy creates a copy of the uint16 slice. +func Uint16sCopy(u []uint16) []uint16 { + b := make([]uint16, len(u)) + copy(b, u) + return b +} + +// Uint16sToInterfaces converts uint16 slice to interface slice. +func Uint16sToInterfaces(u []uint16) []interface{} { + r := make([]interface{}, len(u)) + for k, v := range u { + r[k] = Uint16ToInterface(v) + } + return r +} + +// Uint16sToStrings converts uint16 slice to string slice. +func Uint16sToStrings(u []uint16) []string { + r := make([]string, len(u)) + for k, v := range u { + r[k] = Uint16ToString(v) + } + return r +} + +// Uint16sToBools converts uint16 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Uint16sToBools(u []uint16) []bool { + r := make([]bool, len(u)) + for k, v := range u { + r[k] = Uint16ToBool(v) + } + return r +} + +// Uint16sToFloat32s converts uint16 slice to float32 slice. +func Uint16sToFloat32s(u []uint16) []float32 { + r := make([]float32, len(u)) + for k, v := range u { + r[k] = Uint16ToFloat32(v) + } + return r +} + +// Uint16sToFloat64s converts uint16 slice to float64 slice. +func Uint16sToFloat64s(u []uint16) []float64 { + r := make([]float64, len(u)) + for k, v := range u { + r[k] = Uint16ToFloat64(v) + } + return r +} + +// Uint16sToInts converts uint16 slice to int slice. +func Uint16sToInts(u []uint16) []int { + r := make([]int, len(u)) + for k, v := range u { + r[k] = Uint16ToInt(v) + } + return r +} + +// Uint16sToInt8s converts uint16 slice to int8 slice. +func Uint16sToInt8s(u []uint16) ([]int8, error) { + var err error + r := make([]int8, len(u)) + for k, v := range u { + r[k], err = Uint16ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint16sToInt16s converts uint16 slice to int16 slice. +func Uint16sToInt16s(u []uint16) ([]int16, error) { + var err error + r := make([]int16, len(u)) + for k, v := range u { + r[k], err = Uint16ToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint16sToInt32s converts uint16 slice to int32 slice. +func Uint16sToInt32s(u []uint16) []int32 { + r := make([]int32, len(u)) + for k, v := range u { + r[k] = Uint16ToInt32(v) + } + return r +} + +// Uint16sToInt64s converts uint16 slice to int64 slice. +func Uint16sToInt64s(u []uint16) []int64 { + r := make([]int64, len(u)) + for k, v := range u { + r[k] = Uint16ToInt64(v) + } + return r +} + +// Uint16sToUints converts uint16 slice to uint slice. +func Uint16sToUints(u []uint16) []uint { + r := make([]uint, len(u)) + for k, v := range u { + r[k] = Uint16ToUint(v) + } + return r +} + +// Uint16sToUint8s converts uint16 slice to uint8 slice. +func Uint16sToUint8s(u []uint16) ([]uint8, error) { + var err error + r := make([]uint8, len(u)) + for k, v := range u { + r[k], err = Uint16ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint16sToUint32s converts uint16 slice to uint32 slice. +func Uint16sToUint32s(u []uint16) []uint32 { + r := make([]uint32, len(u)) + for k, v := range u { + r[k] = Uint16ToUint32(v) + } + return r +} + +// Uint16sToUint64s converts uint16 slice to uint64 slice. +func Uint16sToUint64s(u []uint16) []uint64 { + r := make([]uint64, len(u)) + for k, v := range u { + r[k] = Uint16ToUint64(v) + } + return r +} + +// Uint16sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint16sCopyWithin(u []uint16, target, start int, end ...int) { + target = fixIndex(len(u), target, true) + if target == len(u) { + return + } + sub := Uint16sSlice(u, start, end...) + for k, v := range sub { + u[target+k] = v + } +} + +// Uint16sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Uint16sEvery(u []uint16, fn func(u []uint16, k int, v uint16) bool) bool { + for k, v := range u { + if !fn(u, k, v) { + return false + } + } + return true +} + +// Uint16sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint16sFill(u []uint16, value uint16, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(u), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + u[k] = value + } +} + +// Uint16sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Uint16sFilter(u []uint16, fn func(u []uint16, k int, v uint16) bool) []uint16 { + ret := make([]uint16, 0) + for k, v := range u { + if fn(u, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Uint16sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Uint16sFind(u []uint16, fn func(u []uint16, k int, v uint16) bool) (k int, v uint16) { + for k, v := range u { + if fn(u, k, v) { + return k, v + } + } + return -1, 0 +} + +// Uint16sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint16sIncludes(u []uint16, valueToFind uint16, fromIndex ...int) bool { + return Uint16sIndexOf(u, valueToFind, fromIndex...) > -1 +} + +// Uint16sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint16sIndexOf(u []uint16, searchElement uint16, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k, v := range u[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Uint16sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint16sLastIndexOf(u []uint16, searchElement uint16, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k := len(u) - 1; k >= idx; k-- { + if searchElement == u[k] { + return k + } + } + return -1 +} + +// Uint16sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Uint16sMap(u []uint16, fn func(u []uint16, k int, v uint16) uint16) []uint16 { + ret := make([]uint16, len(u)) + for k, v := range u { + ret[k] = fn(u, k, v) + } + return ret +} + +// Uint16sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Uint16sPop(u *[]uint16) (uint16, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *u = a[:len(a):len(a)] + return last, true +} + +// Uint16sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Uint16sPush(u *[]uint16, element ...uint16) int { + *u = append(*u, element...) + return len(*u) +} + +// Uint16sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Uint16sPushDistinct(u []uint16, element ...uint16) []uint16 { +L: + for _, v := range element { + for _, vv := range u { + if vv == v { + continue L + } + } + u = append(u, v) + } + return u +} + +// Uint16sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint16sReduce( + u []uint16, + fn func(u []uint16, k int, v, accumulator uint16) uint16, initialValue ...uint16, +) uint16 { + if len(u) == 0 { + return 0 + } + start := 0 + acc := u[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(u); k++ { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint16sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint16sReduceRight( + u []uint16, + fn func(u []uint16, k int, v, accumulator uint16) uint16, initialValue ...uint16, +) uint16 { + if len(u) == 0 { + return 0 + } + end := len(u) - 1 + acc := u[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint16sReverse reverses an slice in place. +func Uint16sReverse(u []uint16) { + first := 0 + last := len(u) - 1 + for first < last { + u[first], u[last] = u[last], u[first] + first++ + last-- + } +} + +// Uint16sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Uint16sShift(u *[]uint16) (uint16, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *u = a[:len(a):len(a)] + return first, true +} + +// Uint16sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Uint16sSlice(u []uint16, begin int, end ...int) []uint16 { + fixedStart, fixedEnd, ok := fixRange(len(u), begin, end...) + if !ok { + return []uint16{} + } + return Uint16sCopy(u[fixedStart:fixedEnd]) +} + +// Uint16sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Uint16sSome(u []uint16, fn func(u []uint16, k int, v uint16) bool) bool { + for k, v := range u { + if fn(u, k, v) { + return true + } + } + return false +} + +// Uint16sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Uint16sSplice(u *[]uint16, start, deleteCount int, items ...uint16) { + a := *u + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Uint16sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *u = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *u = a[:len(a):len(a)] +} + +// Uint16sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Uint16sUnshift(u *[]uint16, element ...uint16) int { + *u = append(element, *u...) + return len(*u) +} + +// Uint16sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Uint16sUnshiftDistinct(u *[]uint16, element ...uint16) int { + a := *u + if len(element) == 0 { + return len(a) + } + m := make(map[uint16]bool, len(element)) + r := make([]uint16, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *u = r[:len(r):len(r)] + return len(r) +} + +// Uint16sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Uint16sRemoveFirst(p *[]uint16, elements ...uint16) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint16sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Uint16sRemoveEvery(p *[]uint16, elements ...uint16) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint16sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Uint16sConcat(u ...[]uint16) []uint16 { + var totalLen int + for _, v := range u { + totalLen += len(v) + } + ret := make([]uint16, totalLen) + dst := ret + for _, v := range u { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Uint16sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Uint16sIntersect(u ...[]uint16) (intersectCount map[uint16]int) { + if len(u) == 0 { + return nil + } + for _, v := range u { + if len(v) == 0 { + return nil + } + } + counts := make([]map[uint16]int, len(u)) + for k, v := range u { + counts[k] = uint16sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Uint16sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Uint16sDistinct(i *[]uint16, changeSlice bool) (distinctCount map[uint16]int) { + if !changeSlice { + return uint16sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = uint16sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func uint16sDistinct(src []uint16, dst *[]uint16) map[uint16]int { + m := make(map[uint16]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Uint16SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint16SetUnion(set1, set2 []uint16, others ...[]uint16) []uint16 { + m := make(map[uint16]struct{}, len(set1)+len(set2)) + r := make([]uint16, 0, len(m)) + for _, set := range append([][]uint16{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Uint16SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint16SetIntersect(set1, set2 []uint16, others ...[]uint16) []uint16 { + sets := append([][]uint16{set2}, others...) + setsCount := make([]map[uint16]int, len(sets)) + for k, v := range sets { + setsCount[k] = uint16sDistinct(v, nil) + } + m := make(map[uint16]struct{}, len(set1)) + r := make([]uint16, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Uint16SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint16SetDifference(set1, set2 []uint16, others ...[]uint16) []uint16 { + m := make(map[uint16]struct{}, len(set1)) + r := make([]uint16, 0, len(set1)) + sets := append([][]uint16{set2}, others...) + for _, v := range sets { + inter := Uint16SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/vendor/github.com/henrylee2cn/ameda/uint32.go b/vendor/github.com/henrylee2cn/ameda/uint32.go new file mode 100644 index 0000000..63b9775 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/uint32.go @@ -0,0 +1,180 @@ +package ameda + +import ( + "math" + "strconv" +) + +// Uint32ToInterface converts uint32 to interface. +func Uint32ToInterface(v uint32) interface{} { + return v +} + +// Uint32ToInterfacePtr converts uint32 to *interface. +func Uint32ToInterfacePtr(v uint32) *interface{} { + r := Uint32ToInterface(v) + return &r +} + +// Uint32ToString converts uint32 to string. +func Uint32ToString(v uint32) string { + return strconv.FormatUint(uint64(v), 10) +} + +// Uint32ToStringPtr converts uint32 to *string. +func Uint32ToStringPtr(v uint32) *string { + r := Uint32ToString(v) + return &r +} + +// Uint32ToBool converts uint32 to bool. +func Uint32ToBool(v uint32) bool { + return v != 0 +} + +// Uint32ToBoolPtr converts uint32 to *bool. +func Uint32ToBoolPtr(v uint32) *bool { + r := Uint32ToBool(v) + return &r +} + +// Uint32ToFloat32 converts uint32 to float32. +func Uint32ToFloat32(v uint32) float32 { + return float32(v) +} + +// Uint32ToFloat32Ptr converts uint32 to *float32. +func Uint32ToFloat32Ptr(v uint32) *float32 { + r := Uint32ToFloat32(v) + return &r +} + +// Uint32ToFloat64 converts uint32 to float64. +func Uint32ToFloat64(v uint32) float64 { + return float64(v) +} + +// Uint32ToFloat64Ptr converts uint32 to *float64. +func Uint32ToFloat64Ptr(v uint32) *float64 { + r := Uint32ToFloat64(v) + return &r +} + +// Uint32ToInt converts uint32 to int. +func Uint32ToInt(v uint32) int { + return int(v) +} + +// Uint32ToIntPtr converts uint32 to *int. +func Uint32ToIntPtr(v uint32) *int { + r := Uint32ToInt(v) + return &r +} + +// Uint32ToInt8 converts uint32 to int8. +func Uint32ToInt8(v uint32) (int8, error) { + if v > math.MaxInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Uint32ToInt8Ptr converts uint32 to *int8. +func Uint32ToInt8Ptr(v uint32) (*int8, error) { + r, err := Uint32ToInt8(v) + return &r, err +} + +// Uint32ToInt16 converts uint32 to int16. +func Uint32ToInt16(v uint32) (int16, error) { + if v > math.MaxInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// Uint32ToInt16Ptr converts uint32 to *int16. +func Uint32ToInt16Ptr(v uint32) (*int16, error) { + r, err := Uint32ToInt16(v) + return &r, err +} + +// Uint32ToInt32 converts uint32 to int32. +func Uint32ToInt32(v uint32) (int32, error) { + if v > math.MaxInt32 { + return 0, errOverflowValue + } + return int32(v), nil +} + +// Uint32ToInt32Ptr converts uint32 to *int32. +func Uint32ToInt32Ptr(v uint32) (*int32, error) { + r, err := Uint32ToInt32(v) + return &r, err +} + +// Uint32ToInt64 converts uint32 to int64. +func Uint32ToInt64(v uint32) int64 { + return int64(v) +} + +// Uint32ToInt64Ptr converts uint32 to *int64. +func Uint32ToInt64Ptr(v uint32) *int64 { + r := Uint32ToInt64(v) + return &r +} + +// Uint32ToUint converts uint32 to uint. +func Uint32ToUint(v uint32) uint { + return uint(v) +} + +// Uint32ToUintPtr converts uint32 to *uint. +func Uint32ToUintPtr(v uint32) *uint { + r := Uint32ToUint(v) + return &r +} + +// Uint32ToUint8 converts uint32 to uint8. +func Uint32ToUint8(v uint32) (uint8, error) { + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Uint32ToUint8Ptr converts uint32 to *uint8. +func Uint32ToUint8Ptr(v uint32) (*uint8, error) { + r, err := Uint32ToUint8(v) + return &r, err +} + +// Uint32ToUint16 converts uint32 to uint16. +func Uint32ToUint16(v uint32) (uint16, error) { + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// Uint32ToUint16Ptr converts uint32 to *uint16. +func Uint32ToUint16Ptr(v uint32) (*uint16, error) { + r, err := Uint32ToUint16(v) + return &r, err +} + +// Uint32ToUint32Ptr converts uint32 to *uint32. +func Uint32ToUint32Ptr(v uint32) *uint32 { + return &v +} + +// Uint32ToUint64 converts uint32 to uint64. +func Uint32ToUint64(v uint32) uint64 { + return uint64(v) +} + +// Uint32ToUint64Ptr converts uint32 to *uint64. +func Uint32ToUint64Ptr(v uint32) *uint64 { + r := Uint32ToUint64(v) + return &r +} diff --git a/vendor/github.com/henrylee2cn/ameda/uint32s.go b/vendor/github.com/henrylee2cn/ameda/uint32s.go new file mode 100644 index 0000000..075a305 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/uint32s.go @@ -0,0 +1,676 @@ +package ameda + +// OneUint32 try to return the first element, otherwise return zero value. +func OneUint32(u []uint32) uint32 { + if len(u) > 0 { + return u[0] + } + return 0 +} + +// Uint32sCopy creates a copy of the uint32 slice. +func Uint32sCopy(u []uint32) []uint32 { + b := make([]uint32, len(u)) + copy(b, u) + return b +} + +// Uint32sToInterfaces converts uint32 slice to interface slice. +func Uint32sToInterfaces(u []uint32) []interface{} { + r := make([]interface{}, len(u)) + for k, v := range u { + r[k] = Uint32ToInterface(v) + } + return r +} + +// Uint32sToStrings converts uint32 slice to string slice. +func Uint32sToStrings(u []uint32) []string { + r := make([]string, len(u)) + for k, v := range u { + r[k] = Uint32ToString(v) + } + return r +} + +// Uint32sToBools converts uint32 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Uint32sToBools(u []uint32) []bool { + r := make([]bool, len(u)) + for k, v := range u { + r[k] = Uint32ToBool(v) + } + return r +} + +// Uint32sToFloat32s converts uint32 slice to float32 slice. +func Uint32sToFloat32s(u []uint32) []float32 { + r := make([]float32, len(u)) + for k, v := range u { + r[k] = Uint32ToFloat32(v) + } + return r +} + +// Uint32sToFloat64s converts uint32 slice to float64 slice. +func Uint32sToFloat64s(u []uint32) []float64 { + r := make([]float64, len(u)) + for k, v := range u { + r[k] = Uint32ToFloat64(v) + } + return r +} + +// Uint32sToInts converts uint32 slice to int slice. +func Uint32sToInts(u []uint32) []int { + r := make([]int, len(u)) + for k, v := range u { + r[k] = Uint32ToInt(v) + } + return r +} + +// Uint32sToInt8s converts uint32 slice to int8 slice. +func Uint32sToInt8s(u []uint32) ([]int8, error) { + var err error + r := make([]int8, len(u)) + for k, v := range u { + r[k], err = Uint32ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint32sToInt16s converts uint32 slice to int16 slice. +func Uint32sToInt16s(u []uint32) ([]int16, error) { + var err error + r := make([]int16, len(u)) + for k, v := range u { + r[k], err = Uint32ToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint32sToInt32s converts uint32 slice to int32 slice. +func Uint32sToInt32s(u []uint32) ([]int32, error) { + var err error + r := make([]int32, len(u)) + for k, v := range u { + r[k], err = Uint32ToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint32sToInt64s converts uint32 slice to int64 slice. +func Uint32sToInt64s(u []uint32) []int64 { + r := make([]int64, len(u)) + for k, v := range u { + r[k] = Uint32ToInt64(v) + } + return r +} + +// Uint32sToUints converts uint32 slice to uint slice. +func Uint32sToUints(u []uint32) []uint { + r := make([]uint, len(u)) + for k, v := range u { + r[k] = Uint32ToUint(v) + } + return r +} + +// Uint32sToUint8s converts uint32 slice to uint8 slice. +func Uint32sToUint8s(u []uint32) ([]uint8, error) { + var err error + r := make([]uint8, len(u)) + for k, v := range u { + r[k], err = Uint32ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint32sToUint16s converts uint32 slice to uint16 slice. +func Uint32sToUint16s(u []uint32) ([]uint16, error) { + var err error + r := make([]uint16, len(u)) + for k, v := range u { + r[k], err = Uint32ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint32sToUint64s converts uint32 slice to uint64 slice. +func Uint32sToUint64s(u []uint32) []uint64 { + r := make([]uint64, len(u)) + for k, v := range u { + r[k] = Uint32ToUint64(v) + } + return r +} + +// Uint32sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint32sCopyWithin(u []uint32, target, start int, end ...int) { + target = fixIndex(len(u), target, true) + if target == len(u) { + return + } + sub := Uint32sSlice(u, start, end...) + for k, v := range sub { + u[target+k] = v + } +} + +// Uint32sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Uint32sEvery(u []uint32, fn func(u []uint32, k int, v uint32) bool) bool { + for k, v := range u { + if !fn(u, k, v) { + return false + } + } + return true +} + +// Uint32sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint32sFill(u []uint32, value uint32, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(u), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + u[k] = value + } +} + +// Uint32sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Uint32sFilter(u []uint32, fn func(u []uint32, k int, v uint32) bool) []uint32 { + ret := make([]uint32, 0) + for k, v := range u { + if fn(u, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Uint32sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Uint32sFind(u []uint32, fn func(u []uint32, k int, v uint32) bool) (k int, v uint32) { + for k, v := range u { + if fn(u, k, v) { + return k, v + } + } + return -1, 0 +} + +// Uint32sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint32sIncludes(u []uint32, valueToFind uint32, fromIndex ...int) bool { + return Uint32sIndexOf(u, valueToFind, fromIndex...) > -1 +} + +// Uint32sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint32sIndexOf(u []uint32, searchElement uint32, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k, v := range u[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Uint32sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint32sLastIndexOf(u []uint32, searchElement uint32, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k := len(u) - 1; k >= idx; k-- { + if searchElement == u[k] { + return k + } + } + return -1 +} + +// Uint32sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Uint32sMap(u []uint32, fn func(u []uint32, k int, v uint32) uint32) []uint32 { + ret := make([]uint32, len(u)) + for k, v := range u { + ret[k] = fn(u, k, v) + } + return ret +} + +// Uint32sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Uint32sPop(u *[]uint32) (uint32, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *u = a[:len(a):len(a)] + return last, true +} + +// Uint32sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Uint32sPush(u *[]uint32, element ...uint32) int { + *u = append(*u, element...) + return len(*u) +} + +// Uint32sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Uint32sPushDistinct(u []uint32, element ...uint32) []uint32 { +L: + for _, v := range element { + for _, vv := range u { + if vv == v { + continue L + } + } + u = append(u, v) + } + return u +} + +// Uint32sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint32sReduce( + u []uint32, + fn func(u []uint32, k int, v, accumulator uint32) uint32, initialValue ...uint32, +) uint32 { + if len(u) == 0 { + return 0 + } + start := 0 + acc := u[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(u); k++ { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint32sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint32sReduceRight( + u []uint32, + fn func(u []uint32, k int, v, accumulator uint32) uint32, initialValue ...uint32, +) uint32 { + if len(u) == 0 { + return 0 + } + end := len(u) - 1 + acc := u[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint32sReverse reverses an slice in place. +func Uint32sReverse(u []uint32) { + first := 0 + last := len(u) - 1 + for first < last { + u[first], u[last] = u[last], u[first] + first++ + last-- + } +} + +// Uint32sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Uint32sShift(u *[]uint32) (uint32, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *u = a[:len(a):len(a)] + return first, true +} + +// Uint32sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Uint32sSlice(u []uint32, begin int, end ...int) []uint32 { + fixedStart, fixedEnd, ok := fixRange(len(u), begin, end...) + if !ok { + return []uint32{} + } + return Uint32sCopy(u[fixedStart:fixedEnd]) +} + +// Uint32sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Uint32sSome(u []uint32, fn func(u []uint32, k int, v uint32) bool) bool { + for k, v := range u { + if fn(u, k, v) { + return true + } + } + return false +} + +// Uint32sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Uint32sSplice(u *[]uint32, start, deleteCount int, items ...uint32) { + a := *u + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Uint32sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *u = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *u = a[:len(a):len(a)] +} + +// Uint32sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Uint32sUnshift(u *[]uint32, element ...uint32) int { + *u = append(element, *u...) + return len(*u) +} + +// Uint32sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Uint32sUnshiftDistinct(u *[]uint32, element ...uint32) int { + a := *u + if len(element) == 0 { + return len(a) + } + m := make(map[uint32]bool, len(element)) + r := make([]uint32, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *u = r[:len(r):len(r)] + return len(r) +} + +// Uint32sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Uint32sRemoveFirst(p *[]uint32, elements ...uint32) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint32sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Uint32sRemoveEvery(p *[]uint32, elements ...uint32) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint32sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Uint32sConcat(u ...[]uint32) []uint32 { + var totalLen int + for _, v := range u { + totalLen += len(v) + } + ret := make([]uint32, totalLen) + dst := ret + for _, v := range u { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Uint32sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Uint32sIntersect(u ...[]uint32) (intersectCount map[uint32]int) { + if len(u) == 0 { + return nil + } + for _, v := range u { + if len(v) == 0 { + return nil + } + } + counts := make([]map[uint32]int, len(u)) + for k, v := range u { + counts[k] = uint32sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Uint32sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Uint32sDistinct(i *[]uint32, changeSlice bool) (distinctCount map[uint32]int) { + if !changeSlice { + return uint32sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = uint32sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func uint32sDistinct(src []uint32, dst *[]uint32) map[uint32]int { + m := make(map[uint32]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Uint32SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint32SetUnion(set1, set2 []uint32, others ...[]uint32) []uint32 { + m := make(map[uint32]struct{}, len(set1)+len(set2)) + r := make([]uint32, 0, len(m)) + for _, set := range append([][]uint32{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Uint32SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint32SetIntersect(set1, set2 []uint32, others ...[]uint32) []uint32 { + sets := append([][]uint32{set2}, others...) + setsCount := make([]map[uint32]int, len(sets)) + for k, v := range sets { + setsCount[k] = uint32sDistinct(v, nil) + } + m := make(map[uint32]struct{}, len(set1)) + r := make([]uint32, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Uint32SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint32SetDifference(set1, set2 []uint32, others ...[]uint32) []uint32 { + m := make(map[uint32]struct{}, len(set1)) + r := make([]uint32, 0, len(set1)) + sets := append([][]uint32{set2}, others...) + for _, v := range sets { + inter := Uint32SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/vendor/github.com/henrylee2cn/ameda/uint64.go b/vendor/github.com/henrylee2cn/ameda/uint64.go new file mode 100644 index 0000000..ece9446 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/uint64.go @@ -0,0 +1,189 @@ +package ameda + +import ( + "math" + "strconv" +) + +// Uint64ToInterface converts uint64 to interface. +func Uint64ToInterface(v uint64) interface{} { + return v +} + +// Uint64ToInterfacePtr converts uint64 to *interface. +func Uint64ToInterfacePtr(v uint64) *interface{} { + r := Uint64ToInterface(v) + return &r +} + +// Uint64ToString converts uint64 to string. +func Uint64ToString(v uint64) string { + return strconv.FormatUint(uint64(v), 10) +} + +// Uint64ToStringPtr converts uint64 to *string. +func Uint64ToStringPtr(v uint64) *string { + r := Uint64ToString(v) + return &r +} + +// Uint64ToBool converts uint64 to bool. +func Uint64ToBool(v uint64) bool { + return v != 0 +} + +// Uint64ToBoolPtr converts uint64 to *bool. +func Uint64ToBoolPtr(v uint64) *bool { + r := Uint64ToBool(v) + return &r +} + +// Uint64ToFloat32 converts uint64 to float32. +func Uint64ToFloat32(v uint64) float32 { + return float32(v) +} + +// Uint64ToFloat32Ptr converts uint64 to *float32. +func Uint64ToFloat32Ptr(v uint64) *float32 { + r := Uint64ToFloat32(v) + return &r +} + +// Uint64ToFloat64 converts uint64 to float64. +func Uint64ToFloat64(v uint64) float64 { + return float64(v) +} + +// Uint64ToFloat64Ptr converts uint64 to *float64. +func Uint64ToFloat64Ptr(v uint64) *float64 { + r := Uint64ToFloat64(v) + return &r +} + +// Uint64ToInt converts uint64 to int. +func Uint64ToInt(v uint64) int { + return int(v) +} + +// Uint64ToIntPtr converts uint64 to *int. +func Uint64ToIntPtr(v uint64) *int { + r := Uint64ToInt(v) + return &r +} + +// Uint64ToInt8 converts uint64 to int8. +func Uint64ToInt8(v uint64) (int8, error) { + if v > math.MaxInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Uint64ToInt8Ptr converts uint64 to *int8. +func Uint64ToInt8Ptr(v uint64) (*int8, error) { + r, err := Uint64ToInt8(v) + return &r, err +} + +// Uint64ToInt16 converts uint64 to int16. +func Uint64ToInt16(v uint64) (int16, error) { + if v > math.MaxInt16 { + return 0, errOverflowValue + } + return int16(v), nil +} + +// Uint64ToInt16Ptr converts uint64 to *int16. +func Uint64ToInt16Ptr(v uint64) (*int16, error) { + r, err := Uint64ToInt16(v) + return &r, err +} + +// Uint64ToInt32 converts uint64 to int32. +func Uint64ToInt32(v uint64) (int32, error) { + if v > math.MaxInt32 { + return 0, errOverflowValue + } + return int32(v), nil +} + +// Uint64ToInt32Ptr converts uint64 to *int32. +func Uint64ToInt32Ptr(v uint64) (*int32, error) { + r, err := Uint64ToInt32(v) + return &r, err +} + +// Uint64ToInt64 converts uint64 to int64. +func Uint64ToInt64(v uint64) (int64, error) { + if v > math.MaxInt64 { + return 0, errOverflowValue + } + return int64(v), nil +} + +// Uint64ToInt64Ptr converts uint64 to *int64. +func Uint64ToInt64Ptr(v uint64) (*int64, error) { + r, err := Uint64ToInt64(v) + return &r, err +} + +// Uint64ToUint converts uint64 to uint. +func Uint64ToUint(v uint64) (uint, error) { + if !Host64bit && v > math.MaxUint32 { + return 0, errOverflowValue + } + return uint(v), nil +} + +// Uint64ToUintPtr converts uint64 to *uint. +func Uint64ToUintPtr(v uint64) (*uint, error) { + r, err := Uint64ToUint(v) + return &r, err +} + +// Uint64ToUint8 converts uint64 to uint8. +func Uint64ToUint8(v uint64) (uint8, error) { + if v > math.MaxUint8 { + return 0, errOverflowValue + } + return uint8(v), nil +} + +// Uint64ToUint8Ptr converts uint64 to *uint8. +func Uint64ToUint8Ptr(v uint64) (*uint8, error) { + r, err := Uint64ToUint8(v) + return &r, err +} + +// Uint64ToUint16 converts uint64 to uint16. +func Uint64ToUint16(v uint64) (uint16, error) { + if v > math.MaxUint16 { + return 0, errOverflowValue + } + return uint16(v), nil +} + +// Uint64ToUint16Ptr converts uint64 to *uint16. +func Uint64ToUint16Ptr(v uint64) (*uint16, error) { + r, err := Uint64ToUint16(v) + return &r, err +} + +// Uint64ToUint32 converts uint64 to uint32. +func Uint64ToUint32(v uint64) (uint32, error) { + if v > math.MaxUint32 { + return 0, errOverflowValue + } + return uint32(v), nil +} + +// Uint64ToUint32Ptr converts uint64 to *uint32. +func Uint64ToUint32Ptr(v uint64) (*uint32, error) { + r, err := Uint64ToUint32(v) + return &r, err +} + +// Uint64ToUint64Ptr converts uint64 to *uint64. +func Uint64ToUint64Ptr(v uint64) *uint64 { + return &v +} diff --git a/vendor/github.com/henrylee2cn/ameda/uint64s.go b/vendor/github.com/henrylee2cn/ameda/uint64s.go new file mode 100644 index 0000000..4a0f535 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/uint64s.go @@ -0,0 +1,688 @@ +package ameda + +// OneUint64 try to return the first element, otherwise return zero value. +func OneUint64(u []uint64) uint64 { + if len(u) > 0 { + return u[0] + } + return 0 +} + +// Uint64sCopy creates a copy of the uint64 slice. +func Uint64sCopy(u []uint64) []uint64 { + b := make([]uint64, len(u)) + copy(b, u) + return b +} + +// Uint64sToInterfaces converts uint64 slice to interface slice. +func Uint64sToInterfaces(u []uint64) []interface{} { + r := make([]interface{}, len(u)) + for k, v := range u { + r[k] = Uint64ToInterface(v) + } + return r +} + +// Uint64sToStrings converts uint64 slice to string slice. +func Uint64sToStrings(u []uint64) []string { + r := make([]string, len(u)) + for k, v := range u { + r[k] = Uint64ToString(v) + } + return r +} + +// Uint64sToBools converts uint64 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Uint64sToBools(u []uint64) []bool { + r := make([]bool, len(u)) + for k, v := range u { + r[k] = Uint64ToBool(v) + } + return r +} + +// Uint64sToFloat32s converts uint64 slice to float32 slice. +func Uint64sToFloat32s(u []uint64) []float32 { + r := make([]float32, len(u)) + for k, v := range u { + r[k] = Uint64ToFloat32(v) + } + return r +} + +// Uint64sToFloat64s converts uint64 slice to float64 slice. +func Uint64sToFloat64s(u []uint64) []float64 { + r := make([]float64, len(u)) + for k, v := range u { + r[k] = Uint64ToFloat64(v) + } + return r +} + +// Uint64sToInts converts uint64 slice to int slice. +func Uint64sToInts(u []uint64) []int { + r := make([]int, len(u)) + for k, v := range u { + r[k] = Uint64ToInt(v) + } + return r +} + +// Uint64sToInt8s converts uint64 slice to int8 slice. +func Uint64sToInt8s(u []uint64) ([]int8, error) { + var err error + r := make([]int8, len(u)) + for k, v := range u { + r[k], err = Uint64ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sToInt16s converts uint64 slice to int16 slice. +func Uint64sToInt16s(u []uint64) ([]int16, error) { + var err error + r := make([]int16, len(u)) + for k, v := range u { + r[k], err = Uint64ToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sToInt32s converts uint64 slice to int32 slice. +func Uint64sToInt32s(u []uint64) ([]int32, error) { + var err error + r := make([]int32, len(u)) + for k, v := range u { + r[k], err = Uint64ToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sToInt64s converts uint64 slice to int64 slice. +func Uint64sToInt64s(u []uint64) ([]int64, error) { + var err error + r := make([]int64, len(u)) + for k, v := range u { + r[k], err = Uint64ToInt64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sToUints converts uint64 slice to uint slice. +func Uint64sToUints(u []uint64) ([]uint, error) { + var err error + r := make([]uint, len(u)) + for k, v := range u { + r[k], err = Uint64ToUint(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sToUint8s converts uint64 slice to uint8 slice. +func Uint64sToUint8s(u []uint64) ([]uint8, error) { + var err error + r := make([]uint8, len(u)) + for k, v := range u { + r[k], err = Uint64ToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sToUint16s converts uint64 slice to uint16 slice. +func Uint64sToUint16s(u []uint64) ([]uint16, error) { + var err error + r := make([]uint16, len(u)) + for k, v := range u { + r[k], err = Uint64ToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sToUint32s converts uint64 slice to uint32 slice. +func Uint64sToUint32s(u []uint64) ([]uint32, error) { + var err error + r := make([]uint32, len(u)) + for k, v := range u { + r[k], err = Uint64ToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint64sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint64sCopyWithin(u []uint64, target, start int, end ...int) { + target = fixIndex(len(u), target, true) + if target == len(u) { + return + } + sub := Uint64sSlice(u, start, end...) + for k, v := range sub { + u[target+k] = v + } +} + +// Uint64sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Uint64sEvery(u []uint64, fn func(u []uint64, k int, v uint64) bool) bool { + for k, v := range u { + if !fn(u, k, v) { + return false + } + } + return true +} + +// Uint64sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint64sFill(u []uint64, value uint64, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(u), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + u[k] = value + } +} + +// Uint64sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Uint64sFilter(u []uint64, fn func(u []uint64, k int, v uint64) bool) []uint64 { + ret := make([]uint64, 0) + for k, v := range u { + if fn(u, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Uint64sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Uint64sFind(u []uint64, fn func(u []uint64, k int, v uint64) bool) (k int, v uint64) { + for k, v := range u { + if fn(u, k, v) { + return k, v + } + } + return -1, 0 +} + +// Uint64sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint64sIncludes(u []uint64, valueToFind uint64, fromIndex ...int) bool { + return Uint64sIndexOf(u, valueToFind, fromIndex...) > -1 +} + +// Uint64sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint64sIndexOf(u []uint64, searchElement uint64, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k, v := range u[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Uint64sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint64sLastIndexOf(u []uint64, searchElement uint64, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k := len(u) - 1; k >= idx; k-- { + if searchElement == u[k] { + return k + } + } + return -1 +} + +// Uint64sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Uint64sMap(u []uint64, fn func(u []uint64, k int, v uint64) uint64) []uint64 { + ret := make([]uint64, len(u)) + for k, v := range u { + ret[k] = fn(u, k, v) + } + return ret +} + +// Uint64sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Uint64sPop(u *[]uint64) (uint64, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *u = a[:len(a):len(a)] + return last, true +} + +// Uint64sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Uint64sPush(u *[]uint64, element ...uint64) int { + *u = append(*u, element...) + return len(*u) +} + +// Uint64sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Uint64sPushDistinct(u []uint64, element ...uint64) []uint64 { +L: + for _, v := range element { + for _, vv := range u { + if vv == v { + continue L + } + } + u = append(u, v) + } + return u +} + +// Uint64sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint64sReduce( + u []uint64, + fn func(u []uint64, k int, v, accumulator uint64) uint64, initialValue ...uint64, +) uint64 { + if len(u) == 0 { + return 0 + } + start := 0 + acc := u[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(u); k++ { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint64sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint64sReduceRight( + u []uint64, + fn func(u []uint64, k int, v, accumulator uint64) uint64, initialValue ...uint64, +) uint64 { + if len(u) == 0 { + return 0 + } + end := len(u) - 1 + acc := u[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint64sReverse reverses an slice in place. +func Uint64sReverse(u []uint64) { + first := 0 + last := len(u) - 1 + for first < last { + u[first], u[last] = u[last], u[first] + first++ + last-- + } +} + +// Uint64sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Uint64sShift(u *[]uint64) (uint64, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *u = a[:len(a):len(a)] + return first, true +} + +// Uint64sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Uint64sSlice(u []uint64, begin int, end ...int) []uint64 { + fixedStart, fixedEnd, ok := fixRange(len(u), begin, end...) + if !ok { + return []uint64{} + } + return Uint64sCopy(u[fixedStart:fixedEnd]) +} + +// Uint64sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Uint64sSome(u []uint64, fn func(u []uint64, k int, v uint64) bool) bool { + for k, v := range u { + if fn(u, k, v) { + return true + } + } + return false +} + +// Uint64sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Uint64sSplice(u *[]uint64, start, deleteCount int, items ...uint64) { + a := *u + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Uint64sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *u = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *u = a[:len(a):len(a)] +} + +// Uint64sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Uint64sUnshift(u *[]uint64, element ...uint64) int { + *u = append(element, *u...) + return len(*u) +} + +// Uint64sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Uint64sUnshiftDistinct(u *[]uint64, element ...uint64) int { + a := *u + if len(element) == 0 { + return len(a) + } + m := make(map[uint64]bool, len(element)) + r := make([]uint64, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *u = r[:len(r):len(r)] + return len(r) +} + +// Uint64sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Uint64sRemoveFirst(p *[]uint64, elements ...uint64) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint64sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Uint64sRemoveEvery(p *[]uint64, elements ...uint64) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint64sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Uint64sConcat(u ...[]uint64) []uint64 { + var totalLen int + for _, v := range u { + totalLen += len(v) + } + ret := make([]uint64, totalLen) + dst := ret + for _, v := range u { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Uint64sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Uint64sIntersect(u ...[]uint64) (intersectCount map[uint64]int) { + if len(u) == 0 { + return nil + } + for _, v := range u { + if len(v) == 0 { + return nil + } + } + counts := make([]map[uint64]int, len(u)) + for k, v := range u { + counts[k] = uint64sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Uint64sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Uint64sDistinct(i *[]uint64, changeSlice bool) (distinctCount map[uint64]int) { + if !changeSlice { + return uint64sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = uint64sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func uint64sDistinct(src []uint64, dst *[]uint64) map[uint64]int { + m := make(map[uint64]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Uint64SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint64SetUnion(set1, set2 []uint64, others ...[]uint64) []uint64 { + m := make(map[uint64]struct{}, len(set1)+len(set2)) + r := make([]uint64, 0, len(m)) + for _, set := range append([][]uint64{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Uint64SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint64SetIntersect(set1, set2 []uint64, others ...[]uint64) []uint64 { + sets := append([][]uint64{set2}, others...) + setsCount := make([]map[uint64]int, len(sets)) + for k, v := range sets { + setsCount[k] = uint64sDistinct(v, nil) + } + m := make(map[uint64]struct{}, len(set1)) + r := make([]uint64, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Uint64SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint64SetDifference(set1, set2 []uint64, others ...[]uint64) []uint64 { + m := make(map[uint64]struct{}, len(set1)) + r := make([]uint64, 0, len(set1)) + sets := append([][]uint64{set2}, others...) + for _, v := range sets { + inter := Uint64SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/vendor/github.com/henrylee2cn/ameda/uint8.go b/vendor/github.com/henrylee2cn/ameda/uint8.go new file mode 100644 index 0000000..bb2d939 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/uint8.go @@ -0,0 +1,168 @@ +package ameda + +import ( + "math" + "strconv" +) + +// Uint8ToInterface converts uint8 to interface. +func Uint8ToInterface(v uint8) interface{} { + return v +} + +// Uint8ToInterfacePtr converts uint8 to *interface. +func Uint8ToInterfacePtr(v uint8) *interface{} { + r := Uint8ToInterface(v) + return &r +} + +// Uint8ToString converts uint8 to string. +func Uint8ToString(v uint8) string { + return strconv.FormatUint(uint64(v), 10) +} + +// Uint8ToStringPtr converts uint8 to *string. +func Uint8ToStringPtr(v uint8) *string { + r := Uint8ToString(v) + return &r +} + +// Uint8ToBool converts uint8 to bool. +func Uint8ToBool(v uint8) bool { + return v != 0 +} + +// Uint8ToBoolPtr converts uint8 to *bool. +func Uint8ToBoolPtr(v uint8) *bool { + r := Uint8ToBool(v) + return &r +} + +// Uint8ToFloat32 converts uint8 to float32. +func Uint8ToFloat32(v uint8) float32 { + return float32(v) +} + +// Uint8ToFloat32Ptr converts uint8 to *float32. +func Uint8ToFloat32Ptr(v uint8) *float32 { + r := Uint8ToFloat32(v) + return &r +} + +// Uint8ToFloat64 converts uint8 to float64. +func Uint8ToFloat64(v uint8) float64 { + return float64(v) +} + +// Uint8ToFloat64Ptr converts uint8 to *float64. +func Uint8ToFloat64Ptr(v uint8) *float64 { + r := Uint8ToFloat64(v) + return &r +} + +// Uint8ToInt converts uint8 to int. +func Uint8ToInt(v uint8) int { + return int(v) +} + +// Uint8ToIntPtr converts uint8 to *int. +func Uint8ToIntPtr(v uint8) *int { + r := Uint8ToInt(v) + return &r +} + +// Uint8ToInt8 converts uint8 to int8. +func Uint8ToInt8(v uint8) (int8, error) { + if v > math.MaxInt8 { + return 0, errOverflowValue + } + return int8(v), nil +} + +// Uint8ToInt8Ptr converts uint8 to *int8. +func Uint8ToInt8Ptr(v uint8) (*int8, error) { + r, err := Uint8ToInt8(v) + return &r, err +} + +// Uint8ToInt16 converts uint8 to int16. +func Uint8ToInt16(v uint8) int16 { + return int16(v) +} + +// Uint8ToInt16Ptr converts uint8 to *int16. +func Uint8ToInt16Ptr(v uint8) *int16 { + r := Uint8ToInt16(v) + return &r +} + +// Uint8ToInt32 converts uint8 to int32. +func Uint8ToInt32(v uint8) int32 { + return int32(v) +} + +// Uint8ToInt32Ptr converts uint8 to *int32. +func Uint8ToInt32Ptr(v uint8) *int32 { + r := Uint8ToInt32(v) + return &r +} + +// Uint8ToInt64 converts uint8 to int64. +func Uint8ToInt64(v uint8) int64 { + return int64(v) +} + +// Uint8ToInt64Ptr converts uint8 to *int64. +func Uint8ToInt64Ptr(v uint8) *int64 { + r := Uint8ToInt64(v) + return &r +} + +// Uint8ToUint converts uint8 to uint. +func Uint8ToUint(v uint8) uint { + return uint(v) +} + +// Uint8ToUintPtr converts uint8 to *uint. +func Uint8ToUintPtr(v uint8) *uint { + r := Uint8ToUint(v) + return &r +} + +// Uint8ToUint8Ptr converts uint8 to *uint8. +func Uint8ToUint8Ptr(v uint8) *uint8 { + return &v +} + +// Uint8ToUint16 converts uint8 to uint16. +func Uint8ToUint16(v uint8) uint16 { + return uint16(v) +} + +// Uint8ToUint16Ptr converts uint8 to *uint16. +func Uint8ToUint16Ptr(v uint8) *uint16 { + r := Uint8ToUint16(v) + return &r +} + +// Uint8ToUint32 converts uint8 to uint32. +func Uint8ToUint32(v uint8) uint32 { + return uint32(v) +} + +// Uint8ToUint32Ptr converts uint8 to *uint32. +func Uint8ToUint32Ptr(v uint8) *uint32 { + r := Uint8ToUint32(v) + return &r +} + +// Uint8ToUint64 converts uint8 to uint64. +func Uint8ToUint64(v uint8) uint64 { + return uint64(v) +} + +// Uint8ToUint64Ptr converts uint8 to *uint64. +func Uint8ToUint64Ptr(v uint8) *uint64 { + r := Uint8ToUint64(v) + return &r +} diff --git a/vendor/github.com/henrylee2cn/ameda/uint8s.go b/vendor/github.com/henrylee2cn/ameda/uint8s.go new file mode 100644 index 0000000..c30964a --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/uint8s.go @@ -0,0 +1,658 @@ +package ameda + +// OneUint8 try to return the first element, otherwise return zero value. +func OneUint8(u []uint8) uint8 { + if len(u) > 0 { + return u[0] + } + return 0 +} + +// Uint8sCopy creates a copy of the uint8 slice. +func Uint8sCopy(u []uint8) []uint8 { + b := make([]uint8, len(u)) + copy(b, u) + return b +} + +// Uint8sToInterfaces converts uint8 slice to interface slice. +func Uint8sToInterfaces(u []uint8) []interface{} { + r := make([]interface{}, len(u)) + for k, v := range u { + r[k] = Uint8ToInterface(v) + } + return r +} + +// Uint8sToStrings converts uint8 slice to string slice. +func Uint8sToStrings(u []uint8) []string { + r := make([]string, len(u)) + for k, v := range u { + r[k] = Uint8ToString(v) + } + return r +} + +// Uint8sToBools converts uint8 slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func Uint8sToBools(u []uint8) []bool { + r := make([]bool, len(u)) + for k, v := range u { + r[k] = Uint8ToBool(v) + } + return r +} + +// Uint8sToFloat32s converts uint8 slice to float32 slice. +func Uint8sToFloat32s(u []uint8) []float32 { + r := make([]float32, len(u)) + for k, v := range u { + r[k] = Uint8ToFloat32(v) + } + return r +} + +// Uint8sToFloat64s converts uint8 slice to float64 slice. +func Uint8sToFloat64s(u []uint8) []float64 { + r := make([]float64, len(u)) + for k, v := range u { + r[k] = Uint8ToFloat64(v) + } + return r +} + +// Uint8sToInts converts uint8 slice to int slice. +func Uint8sToInts(u []uint8) []int { + r := make([]int, len(u)) + for k, v := range u { + r[k] = Uint8ToInt(v) + } + return r +} + +// Uint8sToInt8s converts uint8 slice to int8 slice. +func Uint8sToInt8s(u []uint8) ([]int8, error) { + var err error + r := make([]int8, len(u)) + for k, v := range u { + r[k], err = Uint8ToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// Uint8sToInt16s converts uint8 slice to int16 slice. +func Uint8sToInt16s(u []uint8) []int16 { + r := make([]int16, len(u)) + for k, v := range u { + r[k] = Uint8ToInt16(v) + } + return r +} + +// Uint8sToInt32s converts uint8 slice to int32 slice. +func Uint8sToInt32s(u []uint8) []int32 { + r := make([]int32, len(u)) + for k, v := range u { + r[k] = Uint8ToInt32(v) + } + return r +} + +// Uint8sToInt64s converts uint8 slice to int64 slice. +func Uint8sToInt64s(u []uint8) []int64 { + r := make([]int64, len(u)) + for k, v := range u { + r[k] = Uint8ToInt64(v) + } + return r +} + +// Uint8sToUints converts uint8 slice to uint slice. +func Uint8sToUints(u []uint8) []uint { + r := make([]uint, len(u)) + for k, v := range u { + r[k] = Uint8ToUint(v) + } + return r +} + +// Uint8sToUint16s converts uint8 slice to uint16 slice. +func Uint8sToUint16s(u []uint8) []uint16 { + r := make([]uint16, len(u)) + for k, v := range u { + r[k] = Uint8ToUint16(v) + } + return r +} + +// Uint8sToUint32s converts uint8 slice to uint32 slice. +func Uint8sToUint32s(u []uint8) []uint32 { + r := make([]uint32, len(u)) + for k, v := range u { + r[k] = Uint8ToUint32(v) + } + return r +} + +// Uint8sToUint64s converts uint8 slice to uint64 slice. +func Uint8sToUint64s(u []uint8) []uint64 { + r := make([]uint64, len(u)) + for k, v := range u { + r[k] = Uint8ToUint64(v) + } + return r +} + +// Uint8sCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint8sCopyWithin(u []uint8, target, start int, end ...int) { + target = fixIndex(len(u), target, true) + if target == len(u) { + return + } + sub := Uint8sSlice(u, start, end...) + for k, v := range sub { + u[target+k] = v + } +} + +// Uint8sEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func Uint8sEvery(u []uint8, fn func(u []uint8, k int, v uint8) bool) bool { + for k, v := range u { + if !fn(u, k, v) { + return false + } + } + return true +} + +// Uint8sFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func Uint8sFill(u []uint8, value uint8, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(u), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + u[k] = value + } +} + +// Uint8sFilter creates a new slice with all elements that pass the test implemented by the provided function. +func Uint8sFilter(u []uint8, fn func(u []uint8, k int, v uint8) bool) []uint8 { + ret := make([]uint8, 0) + for k, v := range u { + if fn(u, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// Uint8sFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func Uint8sFind(u []uint8, fn func(u []uint8, k int, v uint8) bool) (k int, v uint8) { + for k, v := range u { + if fn(u, k, v) { + return k, v + } + } + return -1, 0 +} + +// Uint8sIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint8sIncludes(u []uint8, valueToFind uint8, fromIndex ...int) bool { + return Uint8sIndexOf(u, valueToFind, fromIndex...) > -1 +} + +// Uint8sIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint8sIndexOf(u []uint8, searchElement uint8, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k, v := range u[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// Uint8sLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func Uint8sLastIndexOf(u []uint8, searchElement uint8, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k := len(u) - 1; k >= idx; k-- { + if searchElement == u[k] { + return k + } + } + return -1 +} + +// Uint8sMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func Uint8sMap(u []uint8, fn func(u []uint8, k int, v uint8) uint8) []uint8 { + ret := make([]uint8, len(u)) + for k, v := range u { + ret[k] = fn(u, k, v) + } + return ret +} + +// Uint8sPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func Uint8sPop(u *[]uint8) (uint8, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *u = a[:len(a):len(a)] + return last, true +} + +// Uint8sPush adds one or more elements to the end of an slice and returns the new length of the slice. +func Uint8sPush(u *[]uint8, element ...uint8) int { + *u = append(*u, element...) + return len(*u) +} + +// Uint8sPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func Uint8sPushDistinct(u []uint8, element ...uint8) []uint8 { +L: + for _, v := range element { + for _, vv := range u { + if vv == v { + continue L + } + } + u = append(u, v) + } + return u +} + +// Uint8sReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint8sReduce(u []uint8, + fn func(u []uint8, k int, v, accumulator uint8) uint8, initialValue ...uint8, +) uint8 { + if len(u) == 0 { + return 0 + } + start := 0 + acc := u[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(u); k++ { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint8sReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func Uint8sReduceRight(u []uint8, + fn func(u []uint8, k int, v, accumulator uint8) uint8, initialValue ...uint8, +) uint8 { + if len(u) == 0 { + return 0 + } + end := len(u) - 1 + acc := u[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// Uint8sReverse reverses an slice in place. +func Uint8sReverse(u []uint8) { + first := 0 + last := len(u) - 1 + for first < last { + u[first], u[last] = u[last], u[first] + first++ + last-- + } +} + +// Uint8sShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func Uint8sShift(u *[]uint8) (uint8, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *u = a[:len(a):len(a)] + return first, true +} + +// Uint8sSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func Uint8sSlice(u []uint8, begin int, end ...int) []uint8 { + fixedStart, fixedEnd, ok := fixRange(len(u), begin, end...) + if !ok { + return []uint8{} + } + return Uint8sCopy(u[fixedStart:fixedEnd]) +} + +// Uint8sSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func Uint8sSome(u []uint8, fn func(u []uint8, k int, v uint8) bool) bool { + for k, v := range u { + if fn(u, k, v) { + return true + } + } + return false +} + +// Uint8sSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func Uint8sSplice(u *[]uint8, start, deleteCount int, items ...uint8) { + a := *u + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := Uint8sCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *u = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *u = a[:len(a):len(a)] +} + +// Uint8sUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func Uint8sUnshift(u *[]uint8, element ...uint8) int { + *u = append(element, *u...) + return len(*u) +} + +// Uint8sUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func Uint8sUnshiftDistinct(u *[]uint8, element ...uint8) int { + a := *u + if len(element) == 0 { + return len(a) + } + m := make(map[uint8]bool, len(element)) + r := make([]uint8, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *u = r[:len(r):len(r)] + return len(r) +} + +// Uint8sRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func Uint8sRemoveFirst(p *[]uint8, elements ...uint8) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint8sRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func Uint8sRemoveEvery(p *[]uint8, elements ...uint8) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// Uint8sConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func Uint8sConcat(u ...[]uint8) []uint8 { + var totalLen int + for _, v := range u { + totalLen += len(v) + } + ret := make([]uint8, totalLen) + dst := ret + for _, v := range u { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// Uint8sIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func Uint8sIntersect(u ...[]uint8) (intersectCount map[uint8]int) { + if len(u) == 0 { + return nil + } + for _, v := range u { + if len(v) == 0 { + return nil + } + } + counts := make([]map[uint8]int, len(u)) + for k, v := range u { + counts[k] = uint8sDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// Uint8sDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func Uint8sDistinct(i *[]uint8, changeSlice bool) (distinctCount map[uint8]int) { + if !changeSlice { + return uint8sDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = uint8sDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func uint8sDistinct(src []uint8, dst *[]uint8) map[uint8]int { + m := make(map[uint8]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// Uint8SetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint8SetUnion(set1, set2 []uint8, others ...[]uint8) []uint8 { + m := make(map[uint8]struct{}, len(set1)+len(set2)) + r := make([]uint8, 0, len(m)) + for _, set := range append([][]uint8{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// Uint8SetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint8SetIntersect(set1, set2 []uint8, others ...[]uint8) []uint8 { + sets := append([][]uint8{set2}, others...) + setsCount := make([]map[uint8]int, len(sets)) + for k, v := range sets { + setsCount[k] = uint8sDistinct(v, nil) + } + m := make(map[uint8]struct{}, len(set1)) + r := make([]uint8, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// Uint8SetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func Uint8SetDifference(set1, set2 []uint8, others ...[]uint8) []uint8 { + m := make(map[uint8]struct{}, len(set1)) + r := make([]uint8, 0, len(set1)) + sets := append([][]uint8{set2}, others...) + for _, v := range sets { + inter := Uint8SetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/vendor/github.com/henrylee2cn/ameda/uints.go b/vendor/github.com/henrylee2cn/ameda/uints.go new file mode 100644 index 0000000..c42d101 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/uints.go @@ -0,0 +1,686 @@ +package ameda + +// OneUint try to return the first element, otherwise return zero value. +func OneUint(u []uint) uint { + if len(u) > 0 { + return u[0] + } + return 0 +} + +// UintsCopy creates a copy of the uint slice. +func UintsCopy(u []uint) []uint { + b := make([]uint, len(u)) + copy(b, u) + return b +} + +// UintsToInterfaces converts uint slice to interface slice. +func UintsToInterfaces(u []uint) []interface{} { + r := make([]interface{}, len(u)) + for k, v := range u { + r[k] = UintToInterface(v) + } + return r +} + +// UintsToStrings converts uint slice to string slice. +func UintsToStrings(u []uint) []string { + r := make([]string, len(u)) + for k, v := range u { + r[k] = UintToString(v) + } + return r +} + +// UintsToBools converts uint slice to bool slice. +// NOTE: +// 0 is false, everything else is true +func UintsToBools(u []uint) []bool { + r := make([]bool, len(u)) + for k, v := range u { + r[k] = UintToBool(v) + } + return r +} + +// UintsToFloat32s converts uint slice to float32 slice. +func UintsToFloat32s(u []uint) []float32 { + r := make([]float32, len(u)) + for k, v := range u { + r[k] = UintToFloat32(v) + } + return r +} + +// UintsToFloat64s converts uint slice to float64 slice. +func UintsToFloat64s(u []uint) []float64 { + r := make([]float64, len(u)) + for k, v := range u { + r[k] = UintToFloat64(v) + } + return r +} + +// UintsToInts converts uint slice to int slice. +func UintsToInts(u []uint) ([]int, error) { + var err error + r := make([]int, len(u)) + for k, v := range u { + r[k], err = UintToInt(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToInt8s converts uint slice to int8 slice. +func UintsToInt8s(u []uint) ([]int8, error) { + var err error + r := make([]int8, len(u)) + for k, v := range u { + r[k], err = UintToInt8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToInt16s converts uint slice to int16 slice. +func UintsToInt16s(u []uint) ([]int16, error) { + var err error + r := make([]int16, len(u)) + for k, v := range u { + r[k], err = UintToInt16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToInt32s converts uint slice to int32 slice. +func UintsToInt32s(u []uint) ([]int32, error) { + var err error + r := make([]int32, len(u)) + for k, v := range u { + r[k], err = UintToInt32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToInt64s converts uint slice to int64 slice. +func UintsToInt64s(u []uint) ([]int64, error) { + var err error + r := make([]int64, len(u)) + for k, v := range u { + r[k], err = UintToInt64(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToUint8s converts uint slice to uint8 slice. +func UintsToUint8s(u []uint) ([]uint8, error) { + var err error + r := make([]uint8, len(u)) + for k, v := range u { + r[k], err = UintToUint8(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToUint16s converts uint slice to uint16 slice. +func UintsToUint16s(u []uint) ([]uint16, error) { + var err error + r := make([]uint16, len(u)) + for k, v := range u { + r[k], err = UintToUint16(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToUint32s converts uint slice to uint32 slice. +func UintsToUint32s(u []uint) ([]uint32, error) { + var err error + r := make([]uint32, len(u)) + for k, v := range u { + r[k], err = UintToUint32(v) + if err != nil { + return r, err + } + } + return r, nil +} + +// UintsToUint64s converts uint slice to uint64 slice. +func UintsToUint64s(u []uint) []uint64 { + r := make([]uint64, len(u)) + for k, v := range u { + r[k] = UintToUint64(v) + } + return r +} + +// UintsCopyWithin copies part of an slice to another location in the current slice. +// @target +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func UintsCopyWithin(u []uint, target, start int, end ...int) { + target = fixIndex(len(u), target, true) + if target == len(u) { + return + } + sub := UintsSlice(u, start, end...) + for k, v := range sub { + u[target+k] = v + } +} + +// UintsEvery tests whether all elements in the slice pass the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice will return true for any condition! +func UintsEvery(u []uint, fn func(u []uint, k int, v uint) bool) bool { + for k, v := range u { + if !fn(u, k, v) { + return false + } + } + return true +} + +// UintsFill changes all elements in the current slice to a value, from a start index to an end index. +// @value +// Zero-based index at which to copy the sequence to. If negative, target will be counted from the end. +// @start +// Zero-based index at which to start copying elements from. If negative, start will be counted from the end. +// @end +// Zero-based index at which to end copying elements from. CopyWithin copies up to but not including end. +// If negative, end will be counted from the end. +// If end is omitted, CopyWithin will copy until the last index (default to len(s)). +func UintsFill(u []uint, value uint, start int, end ...int) { + fixedStart, fixedEnd, ok := fixRange(len(u), start, end...) + if !ok { + return + } + for k := fixedStart; k < fixedEnd; k++ { + u[k] = value + } +} + +// UintsFilter creates a new slice with all elements that pass the test implemented by the provided function. +func UintsFilter(u []uint, fn func(u []uint, k int, v uint) bool) []uint { + ret := make([]uint, 0) + for k, v := range u { + if fn(u, k, v) { + ret = append(ret, v) + } + } + return ret +} + +// UintsFind returns the key-value of the first element in the provided slice that satisfies the provided testing function. +// NOTE: +// If not found, k = -1 +func UintsFind(u []uint, fn func(u []uint, k int, v uint) bool) (k int, v uint) { + for k, v := range u { + if fn(u, k, v) { + return k, v + } + } + return -1, 0 +} + +// UintsIncludes determines whether an slice includes a certain value among its entries. +// @fromIndex +// The index to start the search at. Defaults to 0. +func UintsIncludes(u []uint, valueToFind uint, fromIndex ...int) bool { + return UintsIndexOf(u, valueToFind, fromIndex...) > -1 +} + +// UintsIndexOf returns the first index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func UintsIndexOf(u []uint, searchElement uint, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k, v := range u[idx:] { + if searchElement == v { + return k + idx + } + } + return -1 +} + +// UintsLastIndexOf returns the last index at which a given element can be found in the slice, or -1 if it is not present. +// @fromIndex +// The index to start the search at. Defaults to 0. +func UintsLastIndexOf(u []uint, searchElement uint, fromIndex ...int) int { + idx := getFromIndex(len(u), fromIndex...) + for k := len(u) - 1; k >= idx; k-- { + if searchElement == u[k] { + return k + } + } + return -1 +} + +// UintsMap creates a new slice populated with the results of calling a provided function +// on every element in the calling slice. +func UintsMap(u []uint, fn func(u []uint, k int, v uint) uint) []uint { + ret := make([]uint, len(u)) + for k, v := range u { + ret[k] = fn(u, k, v) + } + return ret +} + +// UintsPop removes the last element from an slice and returns that element. +// This method changes the length of the slice. +func UintsPop(u *[]uint) (uint, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + lastIndex := len(a) - 1 + last := a[lastIndex] + a = a[:lastIndex] + *u = a[:len(a):len(a)] + return last, true +} + +// UintsPush adds one or more elements to the end of an slice and returns the new length of the slice. +func UintsPush(u *[]uint, element ...uint) int { + *u = append(*u, element...) + return len(*u) +} + +// UintsPushDistinct adds one or more new elements that do not exist in the current slice at the end. +func UintsPushDistinct(u []uint, element ...uint) []uint { +L: + for _, v := range element { + for _, vv := range u { + if vv == v { + continue L + } + } + u = append(u, v) + } + return u +} + +// UintsReduce executes a reducer function (that you provide) on each element of the slice, +// resulting in a single output value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func UintsReduce(u []uint, + fn func(u []uint, k int, v, accumulator uint) uint, initialValue ...uint, +) uint { + if len(u) == 0 { + return 0 + } + start := 0 + acc := u[start] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + start += 1 + } + for k := start; k < len(u); k++ { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// UintsReduceRight applies a function against an accumulator and each value of the slice (from right-to-left) +// to reduce it to a single value. +// @accumulator +// The accumulator accumulates callback's return values. +// It is the accumulated value previously returned in the last invocation of the callback—or initialValue, +// if it was supplied (see below). +// @initialValue +// A value to use as the first argument to the first call of the callback. +// If no initialValue is supplied, the first element in the slice will be used and skipped. +func UintsReduceRight(u []uint, + fn func(u []uint, k int, v, accumulator uint) uint, initialValue ...uint, +) uint { + if len(u) == 0 { + return 0 + } + end := len(u) - 1 + acc := u[end] + if len(initialValue) > 0 { + acc = initialValue[0] + } else { + end -= 1 + } + for k := end; k >= 0; k-- { + acc = fn(u, k, u[k], acc) + } + return acc +} + +// UintsReverse reverses an slice in place. +func UintsReverse(u []uint) { + first := 0 + last := len(u) - 1 + for first < last { + u[first], u[last] = u[last], u[first] + first++ + last-- + } +} + +// UintsShift removes the first element from an slice and returns that removed element. +// This method changes the length of the slice. +func UintsShift(u *[]uint) (uint, bool) { + a := *u + if len(a) == 0 { + return 0, false + } + first := a[0] + a = a[1:] + *u = a[:len(a):len(a)] + return first, true +} + +// UintsSlice returns a copy of a portion of an slice into a new slice object selected +// from begin to end (end not included) where begin and end represent the index of items in that slice. +// The original slice will not be modified. +func UintsSlice(u []uint, begin int, end ...int) []uint { + fixedStart, fixedEnd, ok := fixRange(len(u), begin, end...) + if !ok { + return []uint{} + } + return UintsCopy(u[fixedStart:fixedEnd]) +} + +// UintsSome tests whether at least one element in the slice passes the test implemented by the provided function. +// NOTE: +// Calling this method on an empty slice returns false for any condition! +func UintsSome(u []uint, fn func(u []uint, k int, v uint) bool) bool { + for k, v := range u { + if fn(u, k, v) { + return true + } + } + return false +} + +// UintsSplice changes the contents of an slice by removing or replacing +// existing elements and/or adding new elements in place. +func UintsSplice(u *[]uint, start, deleteCount int, items ...uint) { + a := *u + if deleteCount < 0 { + deleteCount = 0 + } + start, end, _ := fixRange(len(a), start, start+1+deleteCount) + deleteCount = end - start - 1 + for k := 0; k < len(items); k++ { + if deleteCount > 0 { + // replace + a[start] = items[k] + deleteCount-- + start++ + } else { + // insert + lastSlice := UintsCopy(a[start:]) + items = items[k:] + a = append(a[:start], items...) + a = append(a[:start+len(items)], lastSlice...) + *u = a[:len(a):len(a)] + return + } + } + if deleteCount > 0 { + a = append(a[:start], a[start+1+deleteCount:]...) + } + *u = a[:len(a):len(a)] +} + +// UintsUnshift adds one or more elements to the beginning of an slice and returns the new length of the slice. +func UintsUnshift(u *[]uint, element ...uint) int { + *u = append(element, *u...) + return len(*u) +} + +// UintsUnshiftDistinct adds one or more new elements that do not exist in the current slice to the beginning +// and returns the new length of the slice. +func UintsUnshiftDistinct(u *[]uint, element ...uint) int { + a := *u + if len(element) == 0 { + return len(a) + } + m := make(map[uint]bool, len(element)) + r := make([]uint, 0, len(a)+len(element)) +L: + for _, v := range element { + if m[v] { + continue + } + m[v] = true + for _, vv := range a { + if vv == v { + continue L + } + } + r = append(r, v) + } + r = append(r, a...) + *u = r[:len(r):len(r)] + return len(r) +} + +// UintsRemoveFirst removes the first matched elements from the slice, +// and returns the new length of the slice. +func UintsRemoveFirst(p *[]uint, elements ...uint) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for k, v := range a { + if v == element { + a = append(a[:k], a[k+1:]...) + break + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// UintsRemoveEvery removes all the elements from the slice, +// and returns the new length of the slice. +func UintsRemoveEvery(p *[]uint, elements ...uint) int { + a := *p + m := make(map[interface{}]struct{}, len(elements)) + for _, element := range elements { + if _, ok := m[element]; ok { + continue + } + m[element] = struct{}{} + for i := 0; i < len(a); i++ { + if a[i] == element { + a = append(a[:i], a[i+1:]...) + i-- + } + } + } + n := len(a) + *p = a[:n:n] + return n +} + +// UintsConcat is used to merge two or more slices. +// This method does not change the existing slices, but instead returns a new slice. +func UintsConcat(u ...[]uint) []uint { + var totalLen int + for _, v := range u { + totalLen += len(v) + } + ret := make([]uint, totalLen) + dst := ret + for _, v := range u { + n := copy(dst, v) + dst = dst[n:] + } + return ret +} + +// UintsIntersect calculates intersection of two or more slices, +// and returns the count of each element. +func UintsIntersect(u ...[]uint) (intersectCount map[uint]int) { + if len(u) == 0 { + return nil + } + for _, v := range u { + if len(v) == 0 { + return nil + } + } + counts := make([]map[uint]int, len(u)) + for k, v := range u { + counts[k] = uintsDistinct(v, nil) + } + intersectCount = counts[0] +L: + for k, v := range intersectCount { + for _, c := range counts[1:] { + v2 := c[k] + if v2 == 0 { + delete(intersectCount, k) + continue L + } + if v > v2 { + v = v2 + } + } + intersectCount[k] = v + } + return intersectCount +} + +// UintsDistinct calculates the count of each different element, +// and only saves these different elements in place if changeSlice is true. +func UintsDistinct(i *[]uint, changeSlice bool) (distinctCount map[uint]int) { + if !changeSlice { + return uintsDistinct(*i, nil) + } + a := (*i)[:0] + distinctCount = uintsDistinct(*i, &a) + n := len(distinctCount) + *i = a[:n:n] + return distinctCount +} + +func uintsDistinct(src []uint, dst *[]uint) map[uint]int { + m := make(map[uint]int, len(src)) + if dst == nil { + for _, v := range src { + n := m[v] + m[v] = n + 1 + } + } else { + a := *dst + for _, v := range src { + n := m[v] + m[v] = n + 1 + if n == 0 { + a = append(a, v) + } + } + *dst = a + } + return m +} + +// UintSetUnion calculates between multiple collections: set1 ∪ set2 ∪ others... +// This method does not change the existing slices, but instead returns a new slice. +func UintSetUnion(set1, set2 []uint, others ...[]uint) []uint { + m := make(map[uint]struct{}, len(set1)+len(set2)) + r := make([]uint, 0, len(m)) + for _, set := range append([][]uint{set1, set2}, others...) { + for _, v := range set { + _, ok := m[v] + if ok { + continue + } + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} + +// UintSetIntersect calculates between multiple collections: set1 ∩ set2 ∩ others... +// This method does not change the existing slices, but instead returns a new slice. +func UintSetIntersect(set1, set2 []uint, others ...[]uint) []uint { + sets := append([][]uint{set2}, others...) + setsCount := make([]map[uint]int, len(sets)) + for k, v := range sets { + setsCount[k] = uintsDistinct(v, nil) + } + m := make(map[uint]struct{}, len(set1)) + r := make([]uint, 0, len(m)) +L: + for _, v := range set1 { + if _, ok := m[v]; ok { + continue + } + m[v] = struct{}{} + for _, m2 := range setsCount { + if m2[v] == 0 { + continue L + } + } + r = append(r, v) + } + return r +} + +// UintSetDifference calculates between multiple collections: set1 - set2 - others... +// This method does not change the existing slices, but instead returns a new slice. +func UintSetDifference(set1, set2 []uint, others ...[]uint) []uint { + m := make(map[uint]struct{}, len(set1)) + r := make([]uint, 0, len(set1)) + sets := append([][]uint{set2}, others...) + for _, v := range sets { + inter := UintSetIntersect(set1, v) + for _, v := range inter { + m[v] = struct{}{} + } + } + for _, v := range set1 { + if _, ok := m[v]; !ok { + r = append(r, v) + m[v] = struct{}{} + } + } + return r +} diff --git a/vendor/github.com/henrylee2cn/ameda/utils.go b/vendor/github.com/henrylee2cn/ameda/utils.go new file mode 100644 index 0000000..546b440 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/utils.go @@ -0,0 +1,107 @@ +package ameda + +import ( + "errors" + "math" + "reflect" + "strconv" +) + +const ( + Host64bit = strconv.IntSize == 64 + Host32bit = ^uint(0)>>32 == 0 +) + +var ( + errNegativeValue = errors.New("contains negative value") + errOverflowValue = errors.New("contains overflow value") +) + +var ( + maxUint32 = uint32(math.MaxUint32) + maxInt64 = int64(math.MaxInt64) +) + +func isEmptyAsZero(emptyAsZero []bool) bool { + return len(emptyAsZero) > 0 && emptyAsZero[0] +} + +func getFromIndex(length int, fromIndex ...int) int { + if len(fromIndex) > 0 { + return fixIndex(length, fromIndex[0], true) + } + return 0 +} + +func fixRange(length, start int, end ...int) (fixedStart, fixedEnd int, ok bool) { + fixedStart = fixIndex(length, start, true) + if fixedStart == length { + return + } + fixedEnd = length + if len(end) > 0 { + fixedEnd = fixIndex(length, end[0], true) + } + if fixedEnd-fixedStart <= 0 { + return + } + ok = true + return +} + +func fixIndex(length int, idx int, canLen bool) int { + if idx < 0 { + idx = length + idx + if idx < 0 { + return 0 + } + return idx + } + if idx >= length { + if canLen { + return length + } + return length - 1 + } + return idx +} + +// isZero reports whether v is the zero value for its type. +// It panics if the argument is invalid. +func isZero(v reflect.Value) bool { + switch v.Kind() { + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return math.Float64bits(v.Float()) == 0 + case reflect.Complex64, reflect.Complex128: + c := v.Complex() + return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0 + case reflect.Array: + for i := 0; i < v.Len(); i++ { + if !isZero(v.Index(i)) { + return false + } + } + return true + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer: + return v.IsNil() + case reflect.String: + return v.Len() == 0 + case reflect.Struct: + for i := 0; i < v.NumField(); i++ { + if !isZero(v.Field(i)) { + return false + } + } + return true + default: + // This should never happens, but will act as a safeguard for + // later, as a default value doesn't makes sense here. + panic(&reflect.ValueError{"reflect.Value.IsZero", v.Kind()}) + } +} diff --git a/vendor/github.com/henrylee2cn/ameda/value.go b/vendor/github.com/henrylee2cn/ameda/value.go new file mode 100644 index 0000000..6a6bcd3 --- /dev/null +++ b/vendor/github.com/henrylee2cn/ameda/value.go @@ -0,0 +1,301 @@ +package ameda + +import ( + "fmt" + "reflect" + "runtime" + "strings" + "unsafe" +) + +// Value go underlying type data +type Value struct { + flag + typPtr uintptr + ptr unsafe.Pointer + _iPtr unsafe.Pointer // avoid being GC +} + +// ValueOf unpacks i to go underlying type data. +func ValueOf(i interface{}) Value { + checkValueUsable() + return newT(unsafe.Pointer(&i)) +} + +// ValueFrom gets go underlying type data from reflect.Value. +func ValueFrom(v reflect.Value) Value { + return ValueFrom2(&v) +} + +// ValueFrom2 gets go underlying type data from *reflect.Value. +func ValueFrom2(v *reflect.Value) Value { + checkValueUsable() + vv := newT(unsafe.Pointer(v)) + if v.CanAddr() { + vv.flag |= flagAddr + } + return vv +} + +//go:nocheckptr +func newT(iPtr unsafe.Pointer) Value { + typPtr := *(*uintptr)(iPtr) + return Value{ + typPtr: typPtr, + flag: getFlag(typPtr), + ptr: pointerElem(unsafe.Pointer(uintptr(iPtr) + ptrOffset)), + _iPtr: iPtr, + } +} + +// RuntimeTypeIDOf returns the underlying type ID in current runtime from interface object. +// NOTE: +// *A and A returns the different runtime type ID; +// It is 10 times performance of t.String(). +//go:nocheckptr +func RuntimeTypeIDOf(i interface{}) uintptr { + checkValueUsable() + iPtr := unsafe.Pointer(&i) + typPtr := *(*uintptr)(iPtr) + return typPtr +} + +// RuntimeTypeID returns the underlying type ID in current runtime from reflect.Type. +// NOTE: +// *A and A returns the different runtime type ID; +// It is 10 times performance of t.String(). +//go:nocheckptr +func RuntimeTypeID(t reflect.Type) uintptr { + checkValueUsable() + typPtr := uintptrElem(uintptr(unsafe.Pointer(&t)) + ptrOffset) + return typPtr +} + +// RuntimeTypeID gets the underlying type ID in current runtime. +// NOTE: +// *A and A gets the different runtime type ID; +// It is 10 times performance of reflect.TypeOf(i).String(). +//go:nocheckptr +func (v Value) RuntimeTypeID() uintptr { + return v.typPtr +} + +// Kind gets the reflect.Kind fastly. +func (v Value) Kind() reflect.Kind { + return reflect.Kind(v.flag & flagKindMask) +} + +// CanAddr reports whether the value's address can be obtained with Addr. +// Such values are called addressable. A value is addressable if it is +// an element of a slice, an element of an addressable array, +// a field of an addressable struct, or the result of dereferencing a pointer. +func (v Value) CanAddr() bool { + return v.flag&flagAddr != 0 +} + +// Elem returns the Value that the interface i contains +// or that the pointer i points to. +//go:nocheckptr +func (v Value) Elem() Value { + k := v.Kind() + switch k { + default: + return v + case reflect.Interface: + return newT(v.ptr) + case reflect.Ptr: + flag2, typPtr2, has := typeUnderlying(v.flag, v.typPtr) + if has { + v.typPtr = typPtr2 + v.flag = flag2 + if v.Kind() == reflect.Ptr { + v.ptr = pointerElem(v.ptr) + } + } + return v + } +} + +// UnderlyingElem returns the underlying Value that the interface i contains +// or that the pointer i points to. +//go:nocheckptr +func (v Value) UnderlyingElem() Value { + for kind := v.Kind(); kind == reflect.Ptr || kind == reflect.Interface; kind = v.Kind() { + v = v.Elem() + } + return v +} + +// Pointer gets the pointer of i. +// NOTE: +// *T and T, gets diffrent pointer +//go:nocheckptr +func (v Value) Pointer() uintptr { + switch v.Kind() { + case reflect.Invalid: + return 0 + case reflect.Slice: + return uintptrElem(uintptr(v.ptr)) + sliceDataOffset + default: + return uintptr(v.ptr) + } +} + +// IsNil reports whether its argument i is nil. +//go:nocheckptr +func (v Value) IsNil() bool { + return unsafe.Pointer(v.Pointer()) == nil +} + +// FuncForPC returns a *Func describing the function that contains the +// given program counter address, or else nil. +// +// If pc represents multiple functions because of inlining, it returns +// the a *Func describing the innermost function, but with an entry +// of the outermost function. +// +// NOTE: Its kind must be a reflect.Func, otherwise it returns nil +//go:nocheckptr +func (v Value) FuncForPC() *runtime.Func { + return runtime.FuncForPC(*(*uintptr)(v.ptr)) +} + +//go:nocheckptr +func typeUnderlying(flagVal flag, typPtr uintptr) (flag, uintptr, bool) { + typPtr2 := uintptrElem(typPtr + elemOffset) + if unsafe.Pointer(typPtr2) == nil { + return flagVal, typPtr, false + } + tt := (*ptrType)(unsafe.Pointer(typPtr2)) + flagVal2 := flagVal&flagRO | flagIndir | flagAddr + flagVal2 |= flag(tt.kind) & flagKindMask + return flagVal2, typPtr2, true +} + +//go:nocheckptr +func getFlag(typPtr uintptr) flag { + if unsafe.Pointer(typPtr) == nil { + return 0 + } + return *(*flag)(unsafe.Pointer(typPtr + kindOffset)) +} + +//go:nocheckptr +func uintptrElem(ptr uintptr) uintptr { + return *(*uintptr)(unsafe.Pointer(ptr)) +} + +//go:nocheckptr +func pointerElem(p unsafe.Pointer) unsafe.Pointer { + return *(*unsafe.Pointer)(p) +} + +var errValueUsable error + +func init() { + if errValueUsable == nil { + _, errValueUsable = checkGoVersion(runtime.Version()) + } +} + +func checkGoVersion(goVer string) (string, error) { + var rs []rune + for _, r := range strings.TrimPrefix(goVer, "go") { + if r >= '0' && r <= '9' || r == '.' { + rs = append(rs, r) + } else { + break + } + } + goVersion := strings.TrimRight(string(rs), ".") + a, err := StringsToInts(strings.Split(goVersion, ".")) + if err != nil { + return goVersion, err + } + if a[0] != 1 || a[1] < 9 { + return goVersion, fmt.Errorf("required 1.9≤go<2.0, but current version is go" + goVersion) + } + return goVersion, nil +} + +func checkValueUsable() { + if errValueUsable != nil { + panic(errValueUsable) + } +} + +var ( + e = emptyInterface{typ: new(rtype)} + ptrOffset = func() uintptr { + return unsafe.Offsetof(e.word) + }() + kindOffset = func() uintptr { + return unsafe.Offsetof(e.typ.kind) + }() + elemOffset = func() uintptr { + return unsafe.Offsetof(new(ptrType).elem) + }() + sliceDataOffset = func() uintptr { + return unsafe.Offsetof(new(reflect.SliceHeader).Data) + }() + // valueFlagOffset = func() uintptr { + // t := reflect.TypeOf(reflect.Value{}) + // s, ok := t.FieldByName("flag") + // if !ok { + // errValueUsable = errors.New("not found reflect.Value.flag field") + // return 0 + // } + // return s.Offset + // }() +) + +// NOTE: The following definitions must be consistent with those in the standard package!!! + +const ( + flagKindWidth = 5 // there are 27 kinds + flagKindMask flag = 1< 0 { - block.Encrypt(dst, src) - src = src[bs:] - dst = dst[bs:] - } - dst = make([]byte, hex.EncodedLen(len(r))) - hex.Encode(dst, r) - return dst -} - -// AESDecrypt decrypts a piece of data. -// The cipherkey argument should be the AES key, -// either 16, 24, or 32 bytes to select -// AES-128, AES-192, or AES-256. -func AESDecrypt(cipherkey, ciphertext []byte) ([]byte, error) { - block, err := aes.NewCipher(cipherkey) - if err != nil { - return nil, err - } - src := make([]byte, hex.DecodedLen(len(ciphertext))) - _, err = hex.Decode(src, ciphertext) - if err != nil { - return nil, err - } - bs := block.BlockSize() - r := make([]byte, len(src)) - dst := r - for len(src) > 0 { - block.Decrypt(dst, src) - src = src[bs:] - dst = dst[bs:] - } - return removePad(r) -} - -func padData(d []byte, bs int) []byte { - padedSize := ((len(d) / bs) + 1) * bs - pad := padedSize - len(d) - for i := len(d); i < padedSize; i++ { - d = append(d, byte(pad)) - } - return d -} - -func removePad(r []byte) ([]byte, error) { - l := len(r) - if l == 0 { - return []byte{}, errors.New("input []byte is empty") - } - last := int(r[l-1]) - pad := r[l-last : l] - isPad := true - for _, v := range pad { - if int(v) != last { - isPad = false - break - } - } - if !isPad { - return r, errors.New("remove pad error") - } - return r[:l-last], nil -} diff --git a/vendor/github.com/henrylee2cn/goutil/gopath.go b/vendor/github.com/henrylee2cn/goutil/gopath.go deleted file mode 100644 index 2da0cfd..0000000 --- a/vendor/github.com/henrylee2cn/goutil/gopath.go +++ /dev/null @@ -1,47 +0,0 @@ -package goutil - -import ( - "errors" - "os" - "path/filepath" - "runtime" - "strings" -) - -// GetFirstGopath gets the first $GOPATH value. -func GetFirstGopath(allowAutomaticGuessing bool) (goPath string, err error) { - goPath = os.Getenv("GOPATH") - defer func() { - goPath = strings.Replace(goPath, "/", string(os.PathSeparator), -1) - }() - if len(goPath) == 0 { - if !allowAutomaticGuessing { - err = errors.New("not found GOPATH") - return - } - p, _ := os.Getwd() - p = strings.Replace(p, "\\", "/", -1) + "/" - i := strings.LastIndex(p, "/src/") - if i == -1 { - err = errors.New("not found GOPATH") - return - } - goPath = p[:i+1] - return - } - var sep string - if runtime.GOOS == "windows" { - sep = ";" - } else { - sep = ":" - } - if goPaths := strings.Split(goPath, sep); len(goPaths) > 1 { - goPath = goPaths[0] - } - goPath, _ = filepath.Abs(goPath) - goPath = strings.Replace(goPath, "\\", "/", -1) - if goPath[len(goPath)-1] != '/' { - goPath += "/" - } - return -} diff --git a/vendor/github.com/henrylee2cn/goutil/gotest.go b/vendor/github.com/henrylee2cn/goutil/gotest.go deleted file mode 100644 index d5b68ee..0000000 --- a/vendor/github.com/henrylee2cn/goutil/gotest.go +++ /dev/null @@ -1,31 +0,0 @@ -package goutil - -import ( - "flag" - "os" - "strings" -) - -// IsGoTest returns whether the current process is a test. -func IsGoTest() bool { - return isGoTest -} - -var isGoTest bool - -func init() { - isGoTest = checkGoTestEnv() -} - -func checkGoTestEnv() bool { - maybe := flag.Lookup("test.v") != nil || - flag.Lookup("test.run") != nil || - flag.Lookup("test.bench") != nil - if !maybe { - return false - } - if len(os.Args) == 0 { - return false - } - return strings.HasSuffix(os.Args[0], ".test") -} diff --git a/vendor/github.com/henrylee2cn/goutil/other.go b/vendor/github.com/henrylee2cn/goutil/other.go deleted file mode 100644 index 393c268..0000000 --- a/vendor/github.com/henrylee2cn/goutil/other.go +++ /dev/null @@ -1,67 +0,0 @@ -package goutil - -import ( - "reflect" - "unsafe" -) - -// AddrInt returns a pointer int representing the address of i. -func AddrInt(i int) *int { - return &i -} - -// InitAndGetString if strPtr is empty string, initialize it with def, -// and return the final value. -func InitAndGetString(strPtr *string, def string) string { - if strPtr == nil { - return def - } - if *strPtr == "" { - *strPtr = def - } - return *strPtr -} - -// DereferenceType dereference, get the underlying non-pointer type. -func DereferenceType(t reflect.Type) reflect.Type { - for t.Kind() == reflect.Ptr { - t = t.Elem() - } - return t -} - -// DereferenceValue dereference and unpack interface, -// get the underlying non-pointer and non-interface value. -func DereferenceValue(v reflect.Value) reflect.Value { - for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { - v = v.Elem() - } - return v -} - -func DereferencePtrValue(v reflect.Value) reflect.Value { - for v.Kind() == reflect.Ptr { - v = v.Elem() - } - return v -} - -func DereferenceIfaceValue(v reflect.Value) reflect.Value { - for v.Kind() == reflect.Interface { - v = v.Elem() - } - return v -} - -func DereferenceImplementType(v reflect.Value) reflect.Type { - return DereferenceType(DereferenceIfaceValue(v).Type()) -} - -// IsLittleEndian determine whether the current system is little endian. -func IsLittleEndian() bool { - var i int32 = 0x01020304 - u := unsafe.Pointer(&i) - pb := (*byte)(u) - b := *pb - return (b == 0x04) -} diff --git a/vendor/github.com/henrylee2cn/goutil/sets.go b/vendor/github.com/henrylee2cn/goutil/sets.go deleted file mode 100644 index 393e4b4..0000000 --- a/vendor/github.com/henrylee2cn/goutil/sets.go +++ /dev/null @@ -1,462 +0,0 @@ -package goutil - -import "strconv" - -// StringsToBools converts string slice to bool slice. -func StringsToBools(a []string) ([]bool, error) { - r := make([]bool, len(a)) - for k, v := range a { - i, err := strconv.ParseBool(v) - if err != nil { - return nil, err - } - r[k] = i - } - return r, nil -} - -// StringsToFloat32s converts string slice to float32 slice. -func StringsToFloat32s(a []string) ([]float32, error) { - r := make([]float32, len(a)) - for k, v := range a { - i, err := strconv.ParseFloat(v, 32) - if err != nil { - return nil, err - } - r[k] = float32(i) - } - return r, nil -} - -// StringsToFloat64s converts string slice to float64 slice. -func StringsToFloat64s(a []string) ([]float64, error) { - r := make([]float64, len(a)) - for k, v := range a { - i, err := strconv.ParseFloat(v, 64) - if err != nil { - return nil, err - } - r[k] = i - } - return r, nil -} - -// StringsToInts converts string slice to int slice. -func StringsToInts(a []string) ([]int, error) { - r := make([]int, len(a)) - for k, v := range a { - i, err := strconv.Atoi(v) - if err != nil { - return nil, err - } - r[k] = i - } - return r, nil -} - -// StringsToInt64s converts string slice to int64 slice. -func StringsToInt64s(a []string) ([]int64, error) { - r := make([]int64, len(a)) - for k, v := range a { - i, err := strconv.ParseInt(v, 10, 64) - if err != nil { - return nil, err - } - r[k] = i - } - return r, nil -} - -// StringsToInt32s converts string slice to int32 slice. -func StringsToInt32s(a []string) ([]int32, error) { - r := make([]int32, len(a)) - for k, v := range a { - i, err := strconv.ParseInt(v, 10, 32) - if err != nil { - return nil, err - } - r[k] = int32(i) - } - return r, nil -} - -// StringsToInt16s converts string slice to int16 slice. -func StringsToInt16s(a []string) ([]int16, error) { - r := make([]int16, len(a)) - for k, v := range a { - i, err := strconv.ParseInt(v, 10, 16) - if err != nil { - return nil, err - } - r[k] = int16(i) - } - return r, nil -} - -// StringsToInt8s converts string slice to int8 slice. -func StringsToInt8s(a []string) ([]int8, error) { - r := make([]int8, len(a)) - for k, v := range a { - i, err := strconv.ParseInt(v, 10, 8) - if err != nil { - return nil, err - } - r[k] = int8(i) - } - return r, nil -} - -// StringsToUint8s converts string slice to uint8 slice. -func StringsToUint8s(a []string) ([]uint8, error) { - r := make([]uint8, len(a)) - for k, v := range a { - i, err := strconv.ParseUint(v, 10, 8) - if err != nil { - return nil, err - } - r[k] = uint8(i) - } - return r, nil -} - -// StringsToUint16s converts string slice to uint16 slice. -func StringsToUint16s(a []string) ([]uint16, error) { - r := make([]uint16, len(a)) - for k, v := range a { - i, err := strconv.ParseUint(v, 10, 16) - if err != nil { - return nil, err - } - r[k] = uint16(i) - } - return r, nil -} - -// StringsToUint32s converts string slice to uint32 slice. -func StringsToUint32s(a []string) ([]uint32, error) { - r := make([]uint32, len(a)) - for k, v := range a { - i, err := strconv.ParseUint(v, 10, 32) - if err != nil { - return nil, err - } - r[k] = uint32(i) - } - return r, nil -} - -// StringsToUint64s converts string slice to uint64 slice. -func StringsToUint64s(a []string) ([]uint64, error) { - r := make([]uint64, len(a)) - for k, v := range a { - i, err := strconv.ParseUint(v, 10, 64) - if err != nil { - return nil, err - } - r[k] = uint64(i) - } - return r, nil -} - -// StringsToUints converts string slice to uint slice. -func StringsToUints(a []string) ([]uint, error) { - r := make([]uint, len(a)) - for k, v := range a { - i, err := strconv.ParseUint(v, 10, 64) - if err != nil { - return nil, err - } - r[k] = uint(i) - } - return r, nil -} - -// StringsConvert converts the string slice to a new slice using fn. -// If fn returns error, exit the conversion and return the error. -func StringsConvert(a []string, fn func(string) (string, error)) ([]string, error) { - ret := make([]string, len(a)) - for i, s := range a { - r, err := fn(s) - if err != nil { - return nil, err - } - ret[i] = r - } - return ret, nil -} - -// StringsConvertMap converts the string slice to a new map using fn. -// If fn returns error, exit the conversion and return the error. -func StringsConvertMap(a []string, fn func(string) (string, error)) (map[string]string, error) { - ret := make(map[string]string, len(a)) - for _, s := range a { - r, err := fn(s) - if err != nil { - return nil, err - } - ret[s] = r - } - return ret, nil -} - -// IntersectStrings calculate intersection of two sets. -func IntersectStrings(set1, set2 []string) []string { - var intersect []string - var long, short = set1, set2 - if len(set1) < len(set2) { - long, short = set2, set1 - } - - buf := make([]string, len(short)) - copy(buf, short) - short = buf - - for _, m := range long { - if len(short) == 0 { - break - } - for j, n := range short { - if m == n { - intersect = append(intersect, n) - short = short[:j+copy(short[j:], short[j+1:])] - break - } - } - } - return intersect -} - -// StringsDistinct creates a string set that -// removes the same elements and returns them in their original order. -func StringsDistinct(a []string) (set []string) { - m := make(map[string]bool, len(a)) - set = make([]string, 0, len(a)) - for _, s := range a { - if m[s] { - continue - } - set = append(set, s) - m[s] = true - } - return set -} - -// SetToStrings sets a element to the string set. -func SetToStrings(set []string, a string) []string { - for _, s := range set { - if s == a { - return set - } - } - return append(set, a) -} - -// RemoveFromStrings removes the first element from the string set. -func RemoveFromStrings(set []string, a string) []string { - for i, s := range set { - if s == a { - return append(set[:i], set[i+1:]...) - } - } - return set -} - -// RemoveAllFromStrings removes all the a element from the string set. -func RemoveAllFromStrings(set []string, a string) []string { - length := len(set) - for { - set = RemoveFromStrings(set, a) - if length == len(set) { - return set - } - length = len(set) - } -} - -// IntsDistinct creates a int set that -// removes the same elements and returns them in their original order. -func IntsDistinct(a []int) (set []int) { - m := make(map[int]bool, len(a)) - set = make([]int, 0, len(a)) - for _, s := range a { - if m[s] { - continue - } - set = append(set, s) - m[s] = true - } - return set -} - -// SetToInts sets a element to the int set. -func SetToInts(set []int, a int) []int { - for _, s := range set { - if s == a { - return set - } - } - return append(set, a) -} - -// RemoveFromInts removes the first element from the int set. -func RemoveFromInts(set []int, a int) []int { - for i, s := range set { - if s == a { - return append(set[:i], set[i+1:]...) - } - } - return set -} - -// RemoveAllFromInts removes all the a element from the int set. -func RemoveAllFromInts(set []int, a int) []int { - length := len(set) - for { - set = RemoveFromInts(set, a) - if length == len(set) { - return set - } - length = len(set) - } -} - -// Int32sDistinct creates a int32 set that -// removes the same element32s and returns them in their original order. -func Int32sDistinct(a []int32) (set []int32) { - m := make(map[int32]bool, len(a)) - set = make([]int32, 0, len(a)) - for _, s := range a { - if m[s] { - continue - } - set = append(set, s) - m[s] = true - } - return set -} - -// SetToInt32s sets a element to the int32 set. -func SetToInt32s(set []int32, a int32) []int32 { - for _, s := range set { - if s == a { - return set - } - } - return append(set, a) -} - -// RemoveFromInt32s removes the first element from the int32 set. -func RemoveFromInt32s(set []int32, a int32) []int32 { - for i, s := range set { - if s == a { - return append(set[:i], set[i+1:]...) - } - } - return set -} - -// RemoveAllFromInt32s removes all the a element from the int32 set. -func RemoveAllFromInt32s(set []int32, a int32) []int32 { - length := len(set) - for { - set = RemoveFromInt32s(set, a) - if length == len(set) { - return set - } - length = len(set) - } -} - -// Int64sDistinct creates a int64 set that -// removes the same element64s and returns them in their original order. -func Int64sDistinct(a []int64) (set []int64) { - m := make(map[int64]bool, len(a)) - set = make([]int64, 0, len(a)) - for _, s := range a { - if m[s] { - continue - } - set = append(set, s) - m[s] = true - } - return set -} - -// SetToInt64s sets a element to the int64 set. -func SetToInt64s(set []int64, a int64) []int64 { - for _, s := range set { - if s == a { - return set - } - } - return append(set, a) -} - -// RemoveFromInt64s removes the first element from the int64 set. -func RemoveFromInt64s(set []int64, a int64) []int64 { - for i, s := range set { - if s == a { - return append(set[:i], set[i+1:]...) - } - } - return set -} - -// RemoveAllFromInt64s removes all the a element from the int64 set. -func RemoveAllFromInt64s(set []int64, a int64) []int64 { - length := len(set) - for { - set = RemoveFromInt64s(set, a) - if length == len(set) { - return set - } - length = len(set) - } -} - -// InterfacesDistinct creates a interface{} set that -// removes the same elementerface{}s and returns them in their original order. -func InterfacesDistinct(a []interface{}) (set []interface{}) { - m := make(map[interface{}]bool, len(a)) - set = make([]interface{}, 0, len(a)) - for _, s := range a { - if m[s] { - continue - } - set = append(set, s) - m[s] = true - } - return set -} - -// SetToInterfaces sets a element to the interface{} set. -func SetToInterfaces(set []interface{}, a interface{}) []interface{} { - for _, s := range set { - if s == a { - return set - } - } - return append(set, a) -} - -// RemoveFromInterfaces removes the first element from the interface{} set. -func RemoveFromInterfaces(set []interface{}, a interface{}) []interface{} { - for i, s := range set { - if s == a { - return append(set[:i], set[i+1:]...) - } - } - return set -} - -// RemoveAllFromInterfaces removes all the a element from the interface{} set. -func RemoveAllFromInterfaces(set []interface{}, a interface{}) []interface{} { - length := len(set) - for { - set = RemoveFromInterfaces(set, a) - if length == len(set) { - return set - } - length = len(set) - } -} diff --git a/vendor/github.com/jinzhu/gorm/go.mod b/vendor/github.com/jinzhu/gorm/go.mod deleted file mode 100644 index d2424b3..0000000 --- a/vendor/github.com/jinzhu/gorm/go.mod +++ /dev/null @@ -1,13 +0,0 @@ -module github.com/jinzhu/gorm - -go 1.12 - -require ( - github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 - github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 - github.com/go-sql-driver/mysql v1.4.1 - github.com/jinzhu/inflection v1.0.0 - github.com/jinzhu/now v1.0.1 - github.com/lib/pq v1.1.1 - github.com/mattn/go-sqlite3 v1.10.0 -) diff --git a/vendor/github.com/jinzhu/gorm/go.sum b/vendor/github.com/jinzhu/gorm/go.sum deleted file mode 100644 index d9d073e..0000000 --- a/vendor/github.com/jinzhu/gorm/go.sum +++ /dev/null @@ -1,131 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU= -cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 h1:tkum0XDgfR0jcVVXuTsYv/erY2NnEDqwRojbxR1rBYA= -github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= -github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= -github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= -github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= -github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -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/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/vendor/github.com/jinzhu/inflection/go.mod b/vendor/github.com/jinzhu/inflection/go.mod deleted file mode 100644 index 2fb7690..0000000 --- a/vendor/github.com/jinzhu/inflection/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/jinzhu/inflection diff --git a/vendor/github.com/jmoiron/sqlx/go.mod b/vendor/github.com/jmoiron/sqlx/go.mod deleted file mode 100644 index 66c6756..0000000 --- a/vendor/github.com/jmoiron/sqlx/go.mod +++ /dev/null @@ -1,7 +0,0 @@ -module github.com/jmoiron/sqlx - -require ( - github.com/go-sql-driver/mysql v1.4.0 - github.com/lib/pq v1.0.0 - github.com/mattn/go-sqlite3 v1.9.0 -) diff --git a/vendor/github.com/jmoiron/sqlx/go.sum b/vendor/github.com/jmoiron/sqlx/go.sum deleted file mode 100644 index a3239ad..0000000 --- a/vendor/github.com/jmoiron/sqlx/go.sum +++ /dev/null @@ -1,6 +0,0 @@ -github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= -github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= diff --git a/vendor/github.com/json-iterator/go/go.mod b/vendor/github.com/json-iterator/go/go.mod deleted file mode 100644 index e05c42f..0000000 --- a/vendor/github.com/json-iterator/go/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module github.com/json-iterator/go - -go 1.12 - -require ( - github.com/davecgh/go-spew v1.1.1 - github.com/google/gofuzz v1.0.0 - github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 - github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 - github.com/stretchr/testify v1.3.0 -) diff --git a/vendor/github.com/json-iterator/go/go.sum b/vendor/github.com/json-iterator/go/go.sum deleted file mode 100644 index d778b5a..0000000 --- a/vendor/github.com/json-iterator/go/go.sum +++ /dev/null @@ -1,14 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/vendor/github.com/kr/pretty/go.mod b/vendor/github.com/kr/pretty/go.mod deleted file mode 100644 index 1e29533..0000000 --- a/vendor/github.com/kr/pretty/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module "github.com/kr/pretty" - -require "github.com/kr/text" v0.1.0 diff --git a/vendor/github.com/kr/text/go.mod b/vendor/github.com/kr/text/go.mod deleted file mode 100644 index fa0528b..0000000 --- a/vendor/github.com/kr/text/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module "github.com/kr/text" - -require "github.com/kr/pty" v1.1.1 diff --git a/vendor/github.com/lib/pq/go.mod b/vendor/github.com/lib/pq/go.mod deleted file mode 100644 index edf0b34..0000000 --- a/vendor/github.com/lib/pq/go.mod +++ /dev/null @@ -1 +0,0 @@ -module github.com/lib/pq diff --git a/vendor/github.com/pelletier/go-toml/go.mod b/vendor/github.com/pelletier/go-toml/go.mod deleted file mode 100644 index f4690e1..0000000 --- a/vendor/github.com/pelletier/go-toml/go.mod +++ /dev/null @@ -1,9 +0,0 @@ -module github.com/pelletier/go-toml - -go 1.12 - -require ( - github.com/BurntSushi/toml v0.3.1 - github.com/davecgh/go-spew v1.1.1 - gopkg.in/yaml.v2 v2.2.2 -) diff --git a/vendor/github.com/pelletier/go-toml/go.sum b/vendor/github.com/pelletier/go-toml/go.sum deleted file mode 100644 index 8d91a47..0000000 --- a/vendor/github.com/pelletier/go-toml/go.sum +++ /dev/null @@ -1,7 +0,0 @@ -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/stretchr/testify/LICENSE b/vendor/github.com/stretchr/testify/LICENSE index f38ec59..4b0421c 100644 --- a/vendor/github.com/stretchr/testify/LICENSE +++ b/vendor/github.com/stretchr/testify/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2012-2018 Mat Ryer and Tyler Bunnell +Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare.go b/vendor/github.com/stretchr/testify/assert/assertion_compare.go new file mode 100644 index 0000000..95d8e59 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_compare.go @@ -0,0 +1,458 @@ +package assert + +import ( + "bytes" + "fmt" + "reflect" + "time" +) + +type CompareType int + +const ( + compareLess CompareType = iota - 1 + compareEqual + compareGreater +) + +var ( + intType = reflect.TypeOf(int(1)) + int8Type = reflect.TypeOf(int8(1)) + int16Type = reflect.TypeOf(int16(1)) + int32Type = reflect.TypeOf(int32(1)) + int64Type = reflect.TypeOf(int64(1)) + + uintType = reflect.TypeOf(uint(1)) + uint8Type = reflect.TypeOf(uint8(1)) + uint16Type = reflect.TypeOf(uint16(1)) + uint32Type = reflect.TypeOf(uint32(1)) + uint64Type = reflect.TypeOf(uint64(1)) + + float32Type = reflect.TypeOf(float32(1)) + float64Type = reflect.TypeOf(float64(1)) + + stringType = reflect.TypeOf("") + + timeType = reflect.TypeOf(time.Time{}) + bytesType = reflect.TypeOf([]byte{}) +) + +func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { + obj1Value := reflect.ValueOf(obj1) + obj2Value := reflect.ValueOf(obj2) + + // throughout this switch we try and avoid calling .Convert() if possible, + // as this has a pretty big performance impact + switch kind { + case reflect.Int: + { + intobj1, ok := obj1.(int) + if !ok { + intobj1 = obj1Value.Convert(intType).Interface().(int) + } + intobj2, ok := obj2.(int) + if !ok { + intobj2 = obj2Value.Convert(intType).Interface().(int) + } + if intobj1 > intobj2 { + return compareGreater, true + } + if intobj1 == intobj2 { + return compareEqual, true + } + if intobj1 < intobj2 { + return compareLess, true + } + } + case reflect.Int8: + { + int8obj1, ok := obj1.(int8) + if !ok { + int8obj1 = obj1Value.Convert(int8Type).Interface().(int8) + } + int8obj2, ok := obj2.(int8) + if !ok { + int8obj2 = obj2Value.Convert(int8Type).Interface().(int8) + } + if int8obj1 > int8obj2 { + return compareGreater, true + } + if int8obj1 == int8obj2 { + return compareEqual, true + } + if int8obj1 < int8obj2 { + return compareLess, true + } + } + case reflect.Int16: + { + int16obj1, ok := obj1.(int16) + if !ok { + int16obj1 = obj1Value.Convert(int16Type).Interface().(int16) + } + int16obj2, ok := obj2.(int16) + if !ok { + int16obj2 = obj2Value.Convert(int16Type).Interface().(int16) + } + if int16obj1 > int16obj2 { + return compareGreater, true + } + if int16obj1 == int16obj2 { + return compareEqual, true + } + if int16obj1 < int16obj2 { + return compareLess, true + } + } + case reflect.Int32: + { + int32obj1, ok := obj1.(int32) + if !ok { + int32obj1 = obj1Value.Convert(int32Type).Interface().(int32) + } + int32obj2, ok := obj2.(int32) + if !ok { + int32obj2 = obj2Value.Convert(int32Type).Interface().(int32) + } + if int32obj1 > int32obj2 { + return compareGreater, true + } + if int32obj1 == int32obj2 { + return compareEqual, true + } + if int32obj1 < int32obj2 { + return compareLess, true + } + } + case reflect.Int64: + { + int64obj1, ok := obj1.(int64) + if !ok { + int64obj1 = obj1Value.Convert(int64Type).Interface().(int64) + } + int64obj2, ok := obj2.(int64) + if !ok { + int64obj2 = obj2Value.Convert(int64Type).Interface().(int64) + } + if int64obj1 > int64obj2 { + return compareGreater, true + } + if int64obj1 == int64obj2 { + return compareEqual, true + } + if int64obj1 < int64obj2 { + return compareLess, true + } + } + case reflect.Uint: + { + uintobj1, ok := obj1.(uint) + if !ok { + uintobj1 = obj1Value.Convert(uintType).Interface().(uint) + } + uintobj2, ok := obj2.(uint) + if !ok { + uintobj2 = obj2Value.Convert(uintType).Interface().(uint) + } + if uintobj1 > uintobj2 { + return compareGreater, true + } + if uintobj1 == uintobj2 { + return compareEqual, true + } + if uintobj1 < uintobj2 { + return compareLess, true + } + } + case reflect.Uint8: + { + uint8obj1, ok := obj1.(uint8) + if !ok { + uint8obj1 = obj1Value.Convert(uint8Type).Interface().(uint8) + } + uint8obj2, ok := obj2.(uint8) + if !ok { + uint8obj2 = obj2Value.Convert(uint8Type).Interface().(uint8) + } + if uint8obj1 > uint8obj2 { + return compareGreater, true + } + if uint8obj1 == uint8obj2 { + return compareEqual, true + } + if uint8obj1 < uint8obj2 { + return compareLess, true + } + } + case reflect.Uint16: + { + uint16obj1, ok := obj1.(uint16) + if !ok { + uint16obj1 = obj1Value.Convert(uint16Type).Interface().(uint16) + } + uint16obj2, ok := obj2.(uint16) + if !ok { + uint16obj2 = obj2Value.Convert(uint16Type).Interface().(uint16) + } + if uint16obj1 > uint16obj2 { + return compareGreater, true + } + if uint16obj1 == uint16obj2 { + return compareEqual, true + } + if uint16obj1 < uint16obj2 { + return compareLess, true + } + } + case reflect.Uint32: + { + uint32obj1, ok := obj1.(uint32) + if !ok { + uint32obj1 = obj1Value.Convert(uint32Type).Interface().(uint32) + } + uint32obj2, ok := obj2.(uint32) + if !ok { + uint32obj2 = obj2Value.Convert(uint32Type).Interface().(uint32) + } + if uint32obj1 > uint32obj2 { + return compareGreater, true + } + if uint32obj1 == uint32obj2 { + return compareEqual, true + } + if uint32obj1 < uint32obj2 { + return compareLess, true + } + } + case reflect.Uint64: + { + uint64obj1, ok := obj1.(uint64) + if !ok { + uint64obj1 = obj1Value.Convert(uint64Type).Interface().(uint64) + } + uint64obj2, ok := obj2.(uint64) + if !ok { + uint64obj2 = obj2Value.Convert(uint64Type).Interface().(uint64) + } + if uint64obj1 > uint64obj2 { + return compareGreater, true + } + if uint64obj1 == uint64obj2 { + return compareEqual, true + } + if uint64obj1 < uint64obj2 { + return compareLess, true + } + } + case reflect.Float32: + { + float32obj1, ok := obj1.(float32) + if !ok { + float32obj1 = obj1Value.Convert(float32Type).Interface().(float32) + } + float32obj2, ok := obj2.(float32) + if !ok { + float32obj2 = obj2Value.Convert(float32Type).Interface().(float32) + } + if float32obj1 > float32obj2 { + return compareGreater, true + } + if float32obj1 == float32obj2 { + return compareEqual, true + } + if float32obj1 < float32obj2 { + return compareLess, true + } + } + case reflect.Float64: + { + float64obj1, ok := obj1.(float64) + if !ok { + float64obj1 = obj1Value.Convert(float64Type).Interface().(float64) + } + float64obj2, ok := obj2.(float64) + if !ok { + float64obj2 = obj2Value.Convert(float64Type).Interface().(float64) + } + if float64obj1 > float64obj2 { + return compareGreater, true + } + if float64obj1 == float64obj2 { + return compareEqual, true + } + if float64obj1 < float64obj2 { + return compareLess, true + } + } + case reflect.String: + { + stringobj1, ok := obj1.(string) + if !ok { + stringobj1 = obj1Value.Convert(stringType).Interface().(string) + } + stringobj2, ok := obj2.(string) + if !ok { + stringobj2 = obj2Value.Convert(stringType).Interface().(string) + } + if stringobj1 > stringobj2 { + return compareGreater, true + } + if stringobj1 == stringobj2 { + return compareEqual, true + } + if stringobj1 < stringobj2 { + return compareLess, true + } + } + // Check for known struct types we can check for compare results. + case reflect.Struct: + { + // All structs enter here. We're not interested in most types. + if !canConvert(obj1Value, timeType) { + break + } + + // time.Time can compared! + timeObj1, ok := obj1.(time.Time) + if !ok { + timeObj1 = obj1Value.Convert(timeType).Interface().(time.Time) + } + + timeObj2, ok := obj2.(time.Time) + if !ok { + timeObj2 = obj2Value.Convert(timeType).Interface().(time.Time) + } + + return compare(timeObj1.UnixNano(), timeObj2.UnixNano(), reflect.Int64) + } + case reflect.Slice: + { + // We only care about the []byte type. + if !canConvert(obj1Value, bytesType) { + break + } + + // []byte can be compared! + bytesObj1, ok := obj1.([]byte) + if !ok { + bytesObj1 = obj1Value.Convert(bytesType).Interface().([]byte) + + } + bytesObj2, ok := obj2.([]byte) + if !ok { + bytesObj2 = obj2Value.Convert(bytesType).Interface().([]byte) + } + + return CompareType(bytes.Compare(bytesObj1, bytesObj2)), true + } + } + + return compareEqual, false +} + +// Greater asserts that the first element is greater than the second +// +// assert.Greater(t, 2, 1) +// assert.Greater(t, float64(2), float64(1)) +// assert.Greater(t, "b", "a") +func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return compareTwoValues(t, e1, e2, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) +} + +// GreaterOrEqual asserts that the first element is greater than or equal to the second +// +// assert.GreaterOrEqual(t, 2, 1) +// assert.GreaterOrEqual(t, 2, 2) +// assert.GreaterOrEqual(t, "b", "a") +// assert.GreaterOrEqual(t, "b", "b") +func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return compareTwoValues(t, e1, e2, []CompareType{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) +} + +// Less asserts that the first element is less than the second +// +// assert.Less(t, 1, 2) +// assert.Less(t, float64(1), float64(2)) +// assert.Less(t, "a", "b") +func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return compareTwoValues(t, e1, e2, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) +} + +// LessOrEqual asserts that the first element is less than or equal to the second +// +// assert.LessOrEqual(t, 1, 2) +// assert.LessOrEqual(t, 2, 2) +// assert.LessOrEqual(t, "a", "b") +// assert.LessOrEqual(t, "b", "b") +func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) +} + +// Positive asserts that the specified element is positive +// +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) +func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + zero := reflect.Zero(reflect.TypeOf(e)) + return compareTwoValues(t, e, zero.Interface(), []CompareType{compareGreater}, "\"%v\" is not positive", msgAndArgs...) +} + +// Negative asserts that the specified element is negative +// +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) +func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + zero := reflect.Zero(reflect.TypeOf(e)) + return compareTwoValues(t, e, zero.Interface(), []CompareType{compareLess}, "\"%v\" is not negative", msgAndArgs...) +} + +func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + e1Kind := reflect.ValueOf(e1).Kind() + e2Kind := reflect.ValueOf(e2).Kind() + if e1Kind != e2Kind { + return Fail(t, "Elements should be the same type", msgAndArgs...) + } + + compareResult, isComparable := compare(e1, e2, e1Kind) + if !isComparable { + return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...) + } + + if !containsValue(allowedComparesResults, compareResult) { + return Fail(t, fmt.Sprintf(failMessage, e1, e2), msgAndArgs...) + } + + return true +} + +func containsValue(values []CompareType, value CompareType) bool { + for _, v := range values { + if v == value { + return true + } + } + + return false +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go b/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go new file mode 100644 index 0000000..da86790 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go @@ -0,0 +1,16 @@ +//go:build go1.17 +// +build go1.17 + +// TODO: once support for Go 1.16 is dropped, this file can be +// merged/removed with assertion_compare_go1.17_test.go and +// assertion_compare_legacy.go + +package assert + +import "reflect" + +// Wrapper around reflect.Value.CanConvert, for compatibility +// reasons. +func canConvert(value reflect.Value, to reflect.Type) bool { + return value.CanConvert(to) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go b/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go new file mode 100644 index 0000000..1701af2 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go @@ -0,0 +1,16 @@ +//go:build !go1.17 +// +build !go1.17 + +// TODO: once support for Go 1.16 is dropped, this file can be +// merged/removed with assertion_compare_go1.17_test.go and +// assertion_compare_can_convert.go + +package assert + +import "reflect" + +// Older versions of Go does not have the reflect.Value.CanConvert +// method. +func canConvert(value reflect.Value, to reflect.Type) bool { + return false +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go index e0364e9..27e2420 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_format.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go @@ -32,7 +32,8 @@ func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args return Contains(t, s, contains, append([]interface{}{msg}, args...)...) } -// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. +// DirExistsf checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -92,7 +93,7 @@ func EqualErrorf(t TestingT, theError error, errString string, msg string, args // EqualValuesf asserts that two objects are equal or convertable to the same types // and equal. // -// assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123)) +// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -113,6 +114,36 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) bool { return Error(t, err, append([]interface{}{msg}, args...)...) } +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return ErrorAs(t, err, target, append([]interface{}{msg}, args...)...) +} + +// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") +func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return ErrorContains(t, theError, contains, append([]interface{}{msg}, args...)...) +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return ErrorIs(t, err, target, append([]interface{}{msg}, args...)...) +} + // Eventuallyf asserts that given condition will be met in waitFor time, // periodically checking target function each tick. // @@ -126,7 +157,7 @@ func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick // Exactlyf asserts that two objects are equal in value and type. // -// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123)) +// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -160,7 +191,8 @@ func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool { return False(t, value, append([]interface{}{msg}, args...)...) } -// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. +// FileExistsf checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -171,7 +203,7 @@ func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool // Greaterf asserts that the first element is greater than the second // // assert.Greaterf(t, 2, 1, "error message %s", "formatted") -// assert.Greaterf(t, float64(2, "error message %s", "formatted"), float64(1)) +// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") // assert.Greaterf(t, "b", "a", "error message %s", "formatted") func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { @@ -223,7 +255,7 @@ func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, u // // assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // -// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). +// Returns whether the assertion was successful (true) or not (false). func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -235,7 +267,7 @@ func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, // // assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // -// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). +// Returns whether the assertion was successful (true) or not (false). func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -243,6 +275,18 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...) } +// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// +// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return HTTPStatusCode(t, handler, method, url, values, statuscode, append([]interface{}{msg}, args...)...) +} + // HTTPSuccessf asserts that a specified handler returns a success status code. // // assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") @@ -257,7 +301,7 @@ func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url strin // Implementsf asserts that an object is implemented by the specified interface. // -// assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject)) +// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -267,7 +311,7 @@ func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, ms // InDeltaf asserts that the two numerals are within delta of each other. // -// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01) +// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -307,6 +351,54 @@ func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsil return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...) } +// IsDecreasingf asserts that the collection is decreasing +// +// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsDecreasing(t, object, append([]interface{}{msg}, args...)...) +} + +// IsIncreasingf asserts that the collection is increasing +// +// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsIncreasing(t, object, append([]interface{}{msg}, args...)...) +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsNonDecreasing(t, object, append([]interface{}{msg}, args...)...) +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsNonIncreasing(t, object, append([]interface{}{msg}, args...)...) +} + // IsTypef asserts that the specified objects are of the same type. func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { @@ -325,14 +417,6 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...) } -// YAMLEqf asserts that two YAML strings are equivalent. -func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...) -} - // Lenf asserts that the specified object has specific length. // Lenf also fails if the object has a type that len() not accept. // @@ -347,7 +431,7 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf // Lessf asserts that the first element is less than the second // // assert.Lessf(t, 1, 2, "error message %s", "formatted") -// assert.Lessf(t, float64(1, "error message %s", "formatted"), float64(2)) +// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") // assert.Lessf(t, "a", "b", "error message %s", "formatted") func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { @@ -369,6 +453,28 @@ func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args . return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...) } +// Negativef asserts that the specified element is negative +// +// assert.Negativef(t, -1, "error message %s", "formatted") +// assert.Negativef(t, -1.23, "error message %s", "formatted") +func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Negative(t, e, append([]interface{}{msg}, args...)...) +} + +// Neverf asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Never(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...) +} + // Nilf asserts that the specified object is nil. // // assert.Nilf(t, err, "error message %s", "formatted") @@ -379,6 +485,15 @@ func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool return Nil(t, object, append([]interface{}{msg}, args...)...) } +// NoDirExistsf checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NoDirExists(t, path, append([]interface{}{msg}, args...)...) +} + // NoErrorf asserts that a function returned no error (i.e. `nil`). // // actualObj, err := SomeFunction() @@ -392,6 +507,15 @@ func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool { return NoError(t, err, append([]interface{}{msg}, args...)...) } +// NoFileExistsf checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NoFileExists(t, path, append([]interface{}{msg}, args...)...) +} + // NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // @@ -431,6 +555,25 @@ func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...) } +// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// +// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") +func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotErrorIs(t, err, target, append([]interface{}{msg}, args...)...) +} + // NotNilf asserts that the specified object is not nil. // // assert.NotNilf(t, err, "error message %s", "formatted") @@ -453,7 +596,7 @@ func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bo // NotRegexpf asserts that a specified regexp does not match a string. // -// assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting") +// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") // assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { @@ -462,6 +605,19 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args .. return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...) } +// NotSamef asserts that two pointers do not reference the same object. +// +// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotSame(t, expected, actual, append([]interface{}{msg}, args...)...) +} + // NotSubsetf asserts that the specified list(array, slice...) contains not all // elements given in the specified subset(array, slice...). // @@ -491,6 +647,18 @@ func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool return Panics(t, f, append([]interface{}{msg}, args...)...) } +// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return PanicsWithError(t, errString, f, append([]interface{}{msg}, args...)...) +} + // PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // @@ -502,9 +670,20 @@ func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg str return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...) } +// Positivef asserts that the specified element is positive +// +// assert.Positivef(t, 1, "error message %s", "formatted") +// assert.Positivef(t, 1.23, "error message %s", "formatted") +func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Positive(t, e, append([]interface{}{msg}, args...)...) +} + // Regexpf asserts that a specified regexp matches a string. // -// assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting") +// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") // assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { @@ -557,6 +736,14 @@ func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta tim return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...) } +// YAMLEqf asserts that two YAML strings are equivalent. +func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...) +} + // Zerof asserts that i is the zero value for its type. func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool { if h, ok := t.(tHelper); ok { diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go index 2683040..d9ea368 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go @@ -53,7 +53,8 @@ func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, return Containsf(a.t, s, contains, msg, args...) } -// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. +// DirExists checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -61,7 +62,8 @@ func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool { return DirExists(a.t, path, msgAndArgs...) } -// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. +// DirExistsf checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -167,7 +169,7 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn // EqualValuesf asserts that two objects are equal or convertable to the same types // and equal. // -// a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123)) +// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -202,6 +204,66 @@ func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool { return Error(a.t, err, msgAndArgs...) } +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorAs(a.t, err, target, msgAndArgs...) +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorAsf(a.t, err, target, msg, args...) +} + +// ErrorContains asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// a.ErrorContains(err, expectedErrorSubString) +func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorContains(a.t, theError, contains, msgAndArgs...) +} + +// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") +func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorContainsf(a.t, theError, contains, msg, args...) +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorIs(a.t, err, target, msgAndArgs...) +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorIsf(a.t, err, target, msg, args...) +} + // Errorf asserts that a function returned an error (i.e. not `nil`). // // actualObj, err := SomeFunction() @@ -249,7 +311,7 @@ func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArg // Exactlyf asserts that two objects are equal in value and type. // -// a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123)) +// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -309,7 +371,8 @@ func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool { return Falsef(a.t, value, msg, args...) } -// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. +// FileExists checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -317,7 +380,8 @@ func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool { return FileExists(a.t, path, msgAndArgs...) } -// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. +// FileExistsf checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -366,7 +430,7 @@ func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, // Greaterf asserts that the first element is greater than the second // // a.Greaterf(2, 1, "error message %s", "formatted") -// a.Greaterf(float64(2, "error message %s", "formatted"), float64(1)) +// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") // a.Greaterf("b", "a", "error message %s", "formatted") func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { @@ -443,7 +507,7 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri // // a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // -// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). +// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -467,7 +531,7 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s // // a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // -// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). +// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -475,6 +539,30 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url return HTTPRedirectf(a.t, handler, method, url, values, msg, args...) } +// HTTPStatusCode asserts that a specified handler returns a specified status code. +// +// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...) +} + +// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// +// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...) +} + // HTTPSuccess asserts that a specified handler returns a success status code. // // a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) @@ -511,7 +599,7 @@ func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, // Implementsf asserts that an object is implemented by the specified interface. // -// a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject)) +// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -521,7 +609,7 @@ func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{} // InDelta asserts that the two numerals are within delta of each other. // -// a.InDelta(math.Pi, (22 / 7.0), 0.01) +// a.InDelta(math.Pi, 22/7.0, 0.01) func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -563,7 +651,7 @@ func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, del // InDeltaf asserts that the two numerals are within delta of each other. // -// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01) +// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -603,6 +691,102 @@ func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilo return InEpsilonf(a.t, expected, actual, epsilon, msg, args...) } +// IsDecreasing asserts that the collection is decreasing +// +// a.IsDecreasing([]int{2, 1, 0}) +// a.IsDecreasing([]float{2, 1}) +// a.IsDecreasing([]string{"b", "a"}) +func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsDecreasing(a.t, object, msgAndArgs...) +} + +// IsDecreasingf asserts that the collection is decreasing +// +// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") +// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsDecreasingf(a.t, object, msg, args...) +} + +// IsIncreasing asserts that the collection is increasing +// +// a.IsIncreasing([]int{1, 2, 3}) +// a.IsIncreasing([]float{1, 2}) +// a.IsIncreasing([]string{"a", "b"}) +func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsIncreasing(a.t, object, msgAndArgs...) +} + +// IsIncreasingf asserts that the collection is increasing +// +// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") +// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsIncreasingf(a.t, object, msg, args...) +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// a.IsNonDecreasing([]int{1, 1, 2}) +// a.IsNonDecreasing([]float{1, 2}) +// a.IsNonDecreasing([]string{"a", "b"}) +func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonDecreasing(a.t, object, msgAndArgs...) +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonDecreasingf(a.t, object, msg, args...) +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// a.IsNonIncreasing([]int{2, 1, 1}) +// a.IsNonIncreasing([]float{2, 1}) +// a.IsNonIncreasing([]string{"b", "a"}) +func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonIncreasing(a.t, object, msgAndArgs...) +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonIncreasingf(a.t, object, msg, args...) +} + // IsType asserts that the specified objects are of the same type. func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { @@ -639,22 +823,6 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args .. return JSONEqf(a.t, expected, actual, msg, args...) } -// YAMLEq asserts that two YAML strings are equivalent. -func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return YAMLEq(a.t, expected, actual, msgAndArgs...) -} - -// YAMLEqf asserts that two YAML strings are equivalent. -func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - return YAMLEqf(a.t, expected, actual, msg, args...) -} - // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // @@ -718,7 +886,7 @@ func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, ar // Lessf asserts that the first element is less than the second // // a.Lessf(1, 2, "error message %s", "formatted") -// a.Lessf(float64(1, "error message %s", "formatted"), float64(2)) +// a.Lessf(float64(1), float64(2), "error message %s", "formatted") // a.Lessf("a", "b", "error message %s", "formatted") func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { @@ -727,6 +895,50 @@ func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...i return Lessf(a.t, e1, e2, msg, args...) } +// Negative asserts that the specified element is negative +// +// a.Negative(-1) +// a.Negative(-1.23) +func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Negative(a.t, e, msgAndArgs...) +} + +// Negativef asserts that the specified element is negative +// +// a.Negativef(-1, "error message %s", "formatted") +// a.Negativef(-1.23, "error message %s", "formatted") +func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Negativef(a.t, e, msg, args...) +} + +// Never asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) +func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Never(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Neverf asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Neverf(a.t, condition, waitFor, tick, msg, args...) +} + // Nil asserts that the specified object is nil. // // a.Nil(err) @@ -747,6 +959,24 @@ func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) b return Nilf(a.t, object, msg, args...) } +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoDirExists(a.t, path, msgAndArgs...) +} + +// NoDirExistsf checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoDirExistsf(a.t, path, msg, args...) +} + // NoError asserts that a function returned no error (i.e. `nil`). // // actualObj, err := SomeFunction() @@ -773,6 +1003,24 @@ func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool { return NoErrorf(a.t, err, msg, args...) } +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoFileExists(a.t, path, msgAndArgs...) +} + +// NoFileExistsf checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoFileExistsf(a.t, path, msg, args...) +} + // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // @@ -838,6 +1086,26 @@ func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndAr return NotEqual(a.t, expected, actual, msgAndArgs...) } +// NotEqualValues asserts that two objects are not equal even when converted to the same type +// +// a.NotEqualValues(obj1, obj2) +func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotEqualValues(a.t, expected, actual, msgAndArgs...) +} + +// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// +// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") +func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotEqualValuesf(a.t, expected, actual, msg, args...) +} + // NotEqualf asserts that the specified values are NOT equal. // // a.NotEqualf(obj1, obj2, "error message %s", "formatted") @@ -851,6 +1119,24 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str return NotEqualf(a.t, expected, actual, msg, args...) } +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotErrorIs(a.t, err, target, msgAndArgs...) +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotErrorIsf(a.t, err, target, msg, args...) +} + // NotNil asserts that the specified object is not nil. // // a.NotNil(err) @@ -904,7 +1190,7 @@ func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...in // NotRegexpf asserts that a specified regexp does not match a string. // -// a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting") +// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") // a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { @@ -913,6 +1199,32 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg return NotRegexpf(a.t, rx, str, msg, args...) } +// NotSame asserts that two pointers do not reference the same object. +// +// a.NotSame(ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotSame(a.t, expected, actual, msgAndArgs...) +} + +// NotSamef asserts that two pointers do not reference the same object. +// +// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotSamef(a.t, expected, actual, msg, args...) +} + // NotSubset asserts that the specified list(array, slice...) contains not all // elements given in the specified subset(array, slice...). // @@ -961,6 +1273,30 @@ func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool { return Panics(a.t, f, msgAndArgs...) } +// PanicsWithError asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// a.PanicsWithError("crazy error", func(){ GoCrazy() }) +func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return PanicsWithError(a.t, errString, f, msgAndArgs...) +} + +// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) PanicsWithErrorf(errString string, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return PanicsWithErrorf(a.t, errString, f, msg, args...) +} + // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // @@ -993,6 +1329,28 @@ func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) b return Panicsf(a.t, f, msg, args...) } +// Positive asserts that the specified element is positive +// +// a.Positive(1) +// a.Positive(1.23) +func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Positive(a.t, e, msgAndArgs...) +} + +// Positivef asserts that the specified element is positive +// +// a.Positivef(1, "error message %s", "formatted") +// a.Positivef(1.23, "error message %s", "formatted") +func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Positivef(a.t, e, msg, args...) +} + // Regexp asserts that a specified regexp matches a string. // // a.Regexp(regexp.MustCompile("start"), "it's starting") @@ -1006,7 +1364,7 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter // Regexpf asserts that a specified regexp matches a string. // -// a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting") +// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") // a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { if h, ok := a.t.(tHelper); ok { @@ -1103,6 +1461,22 @@ func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta return WithinDurationf(a.t, expected, actual, delta, msg, args...) } +// YAMLEq asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return YAMLEq(a.t, expected, actual, msgAndArgs...) +} + +// YAMLEqf asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return YAMLEqf(a.t, expected, actual, msg, args...) +} + // Zero asserts that i is the zero value for its type. func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool { if h, ok := a.t.(tHelper); ok { diff --git a/vendor/github.com/stretchr/testify/assert/assertion_order.go b/vendor/github.com/stretchr/testify/assert/assertion_order.go index 15a486c..7594487 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_order.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_order.go @@ -5,305 +5,77 @@ import ( "reflect" ) -func compare(obj1, obj2 interface{}, kind reflect.Kind) (int, bool) { - switch kind { - case reflect.Int: - { - intobj1 := obj1.(int) - intobj2 := obj2.(int) - if intobj1 > intobj2 { - return -1, true - } - if intobj1 == intobj2 { - return 0, true - } - if intobj1 < intobj2 { - return 1, true - } - } - case reflect.Int8: - { - int8obj1 := obj1.(int8) - int8obj2 := obj2.(int8) - if int8obj1 > int8obj2 { - return -1, true - } - if int8obj1 == int8obj2 { - return 0, true - } - if int8obj1 < int8obj2 { - return 1, true - } - } - case reflect.Int16: - { - int16obj1 := obj1.(int16) - int16obj2 := obj2.(int16) - if int16obj1 > int16obj2 { - return -1, true - } - if int16obj1 == int16obj2 { - return 0, true - } - if int16obj1 < int16obj2 { - return 1, true - } - } - case reflect.Int32: - { - int32obj1 := obj1.(int32) - int32obj2 := obj2.(int32) - if int32obj1 > int32obj2 { - return -1, true - } - if int32obj1 == int32obj2 { - return 0, true - } - if int32obj1 < int32obj2 { - return 1, true - } - } - case reflect.Int64: - { - int64obj1 := obj1.(int64) - int64obj2 := obj2.(int64) - if int64obj1 > int64obj2 { - return -1, true - } - if int64obj1 == int64obj2 { - return 0, true - } - if int64obj1 < int64obj2 { - return 1, true - } - } - case reflect.Uint: - { - uintobj1 := obj1.(uint) - uintobj2 := obj2.(uint) - if uintobj1 > uintobj2 { - return -1, true - } - if uintobj1 == uintobj2 { - return 0, true - } - if uintobj1 < uintobj2 { - return 1, true - } - } - case reflect.Uint8: - { - uint8obj1 := obj1.(uint8) - uint8obj2 := obj2.(uint8) - if uint8obj1 > uint8obj2 { - return -1, true - } - if uint8obj1 == uint8obj2 { - return 0, true - } - if uint8obj1 < uint8obj2 { - return 1, true - } - } - case reflect.Uint16: - { - uint16obj1 := obj1.(uint16) - uint16obj2 := obj2.(uint16) - if uint16obj1 > uint16obj2 { - return -1, true - } - if uint16obj1 == uint16obj2 { - return 0, true - } - if uint16obj1 < uint16obj2 { - return 1, true - } - } - case reflect.Uint32: - { - uint32obj1 := obj1.(uint32) - uint32obj2 := obj2.(uint32) - if uint32obj1 > uint32obj2 { - return -1, true - } - if uint32obj1 == uint32obj2 { - return 0, true - } - if uint32obj1 < uint32obj2 { - return 1, true - } - } - case reflect.Uint64: - { - uint64obj1 := obj1.(uint64) - uint64obj2 := obj2.(uint64) - if uint64obj1 > uint64obj2 { - return -1, true - } - if uint64obj1 == uint64obj2 { - return 0, true - } - if uint64obj1 < uint64obj2 { - return 1, true - } - } - case reflect.Float32: - { - float32obj1 := obj1.(float32) - float32obj2 := obj2.(float32) - if float32obj1 > float32obj2 { - return -1, true - } - if float32obj1 == float32obj2 { - return 0, true - } - if float32obj1 < float32obj2 { - return 1, true - } - } - case reflect.Float64: - { - float64obj1 := obj1.(float64) - float64obj2 := obj2.(float64) - if float64obj1 > float64obj2 { - return -1, true - } - if float64obj1 == float64obj2 { - return 0, true - } - if float64obj1 < float64obj2 { - return 1, true - } - } - case reflect.String: - { - stringobj1 := obj1.(string) - stringobj2 := obj2.(string) - if stringobj1 > stringobj2 { - return -1, true - } - if stringobj1 == stringobj2 { - return 0, true - } - if stringobj1 < stringobj2 { - return 1, true - } - } - } - - return 0, false -} - -// Greater asserts that the first element is greater than the second -// -// assert.Greater(t, 2, 1) -// assert.Greater(t, float64(2), float64(1)) -// assert.Greater(t, "b", "a") -func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() +// isOrdered checks that collection contains orderable elements. +func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { + objKind := reflect.TypeOf(object).Kind() + if objKind != reflect.Slice && objKind != reflect.Array { + return false } - e1Kind := reflect.ValueOf(e1).Kind() - e2Kind := reflect.ValueOf(e2).Kind() - if e1Kind != e2Kind { - return Fail(t, "Elements should be the same type", msgAndArgs...) - } + objValue := reflect.ValueOf(object) + objLen := objValue.Len() - res, isComparable := compare(e1, e2, e1Kind) - if !isComparable { - return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...) + if objLen <= 1 { + return true } - if res != -1 { - return Fail(t, fmt.Sprintf("\"%v\" is not greater than \"%v\"", e1, e2), msgAndArgs...) - } + value := objValue.Index(0) + valueInterface := value.Interface() + firstValueKind := value.Kind() - return true -} + for i := 1; i < objLen; i++ { + prevValue := value + prevValueInterface := valueInterface -// GreaterOrEqual asserts that the first element is greater than or equal to the second -// -// assert.GreaterOrEqual(t, 2, 1) -// assert.GreaterOrEqual(t, 2, 2) -// assert.GreaterOrEqual(t, "b", "a") -// assert.GreaterOrEqual(t, "b", "b") -func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } + value = objValue.Index(i) + valueInterface = value.Interface() - e1Kind := reflect.ValueOf(e1).Kind() - e2Kind := reflect.ValueOf(e2).Kind() - if e1Kind != e2Kind { - return Fail(t, "Elements should be the same type", msgAndArgs...) - } + compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind) - res, isComparable := compare(e1, e2, e1Kind) - if !isComparable { - return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...) - } + if !isComparable { + return Fail(t, fmt.Sprintf("Can not compare type \"%s\" and \"%s\"", reflect.TypeOf(value), reflect.TypeOf(prevValue)), msgAndArgs...) + } - if res != -1 && res != 0 { - return Fail(t, fmt.Sprintf("\"%v\" is not greater than or equal to \"%v\"", e1, e2), msgAndArgs...) + if !containsValue(allowedComparesResults, compareResult) { + return Fail(t, fmt.Sprintf(failMessage, prevValue, value), msgAndArgs...) + } } return true } -// Less asserts that the first element is less than the second +// IsIncreasing asserts that the collection is increasing // -// assert.Less(t, 1, 2) -// assert.Less(t, float64(1), float64(2)) -// assert.Less(t, "a", "b") -func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - - e1Kind := reflect.ValueOf(e1).Kind() - e2Kind := reflect.ValueOf(e2).Kind() - if e1Kind != e2Kind { - return Fail(t, "Elements should be the same type", msgAndArgs...) - } - - res, isComparable := compare(e1, e2, e1Kind) - if !isComparable { - return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...) - } - - if res != 1 { - return Fail(t, fmt.Sprintf("\"%v\" is not less than \"%v\"", e1, e2), msgAndArgs...) - } - - return true +// assert.IsIncreasing(t, []int{1, 2, 3}) +// assert.IsIncreasing(t, []float{1, 2}) +// assert.IsIncreasing(t, []string{"a", "b"}) +func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) } -// LessOrEqual asserts that the first element is less than or equal to the second +// IsNonIncreasing asserts that the collection is not increasing // -// assert.LessOrEqual(t, 1, 2) -// assert.LessOrEqual(t, 2, 2) -// assert.LessOrEqual(t, "a", "b") -// assert.LessOrEqual(t, "b", "b") -func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - - e1Kind := reflect.ValueOf(e1).Kind() - e2Kind := reflect.ValueOf(e2).Kind() - if e1Kind != e2Kind { - return Fail(t, "Elements should be the same type", msgAndArgs...) - } - - res, isComparable := compare(e1, e2, e1Kind) - if !isComparable { - return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...) - } +// assert.IsNonIncreasing(t, []int{2, 1, 1}) +// assert.IsNonIncreasing(t, []float{2, 1}) +// assert.IsNonIncreasing(t, []string{"b", "a"}) +func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) +} - if res != 1 && res != 0 { - return Fail(t, fmt.Sprintf("\"%v\" is not less than or equal to \"%v\"", e1, e2), msgAndArgs...) - } +// IsDecreasing asserts that the collection is decreasing +// +// assert.IsDecreasing(t, []int{2, 1, 0}) +// assert.IsDecreasing(t, []float{2, 1}) +// assert.IsDecreasing(t, []string{"b", "a"}) +func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) +} - return true +// IsNonDecreasing asserts that the collection is not decreasing +// +// assert.IsNonDecreasing(t, []int{1, 1, 2}) +// assert.IsNonDecreasing(t, []float{1, 2}) +// assert.IsNonDecreasing(t, []string{"a", "b"}) +func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) } diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go index 044da8b..580fdea 100644 --- a/vendor/github.com/stretchr/testify/assert/assertions.go +++ b/vendor/github.com/stretchr/testify/assert/assertions.go @@ -11,6 +11,7 @@ import ( "reflect" "regexp" "runtime" + "runtime/debug" "strings" "time" "unicode" @@ -18,10 +19,10 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/pmezard/go-difflib/difflib" - yaml "gopkg.in/yaml.v2" + yaml "gopkg.in/yaml.v3" ) -//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_format.go.tmpl +//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl" // TestingT is an interface wrapper around *testing.T type TestingT interface { @@ -44,7 +45,7 @@ type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool // for table driven tests. type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool -// Comparison a custom function that returns true on success and false on failure +// Comparison is a custom function that returns true on success and false on failure type Comparison func() (success bool) /* @@ -103,11 +104,11 @@ the problem actually occurred in calling code.*/ // failed. func CallerInfo() []string { - pc := uintptr(0) - file := "" - line := 0 - ok := false - name := "" + var pc uintptr + var ok bool + var file string + var line int + var name string callers := []string{} for i := 0; ; i++ { @@ -171,8 +172,8 @@ func isTest(name, prefix string) bool { if len(name) == len(prefix) { // "Test" is ok return true } - rune, _ := utf8.DecodeRuneInString(name[len(prefix):]) - return !unicode.IsLower(rune) + r, _ := utf8.DecodeRuneInString(name[len(prefix):]) + return !unicode.IsLower(r) } func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { @@ -351,6 +352,19 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) } +// validateEqualArgs checks whether provided arguments can be safely used in the +// Equal/NotEqual functions. +func validateEqualArgs(expected, actual interface{}) error { + if expected == nil && actual == nil { + return nil + } + + if isFunction(expected) || isFunction(actual) { + return errors.New("cannot take func type as argument") + } + return nil +} + // Same asserts that two pointers reference the same object. // // assert.Same(t, ptr1, ptr2) @@ -362,18 +376,7 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b h.Helper() } - expectedPtr, actualPtr := reflect.ValueOf(expected), reflect.ValueOf(actual) - if expectedPtr.Kind() != reflect.Ptr || actualPtr.Kind() != reflect.Ptr { - return Fail(t, "Invalid operation: both arguments must be pointers", msgAndArgs...) - } - - expectedType, actualType := reflect.TypeOf(expected), reflect.TypeOf(actual) - if expectedType != actualType { - return Fail(t, fmt.Sprintf("Pointer expected to be of type %v, but was %v", - expectedType, actualType), msgAndArgs...) - } - - if expected != actual { + if !samePointers(expected, actual) { return Fail(t, fmt.Sprintf("Not same: \n"+ "expected: %p %#v\n"+ "actual : %p %#v", expected, expected, actual, actual), msgAndArgs...) @@ -382,6 +385,42 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b return true } +// NotSame asserts that two pointers do not reference the same object. +// +// assert.NotSame(t, ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if samePointers(expected, actual) { + return Fail(t, fmt.Sprintf( + "Expected and actual point to the same object: %p %#v", + expected, expected), msgAndArgs...) + } + return true +} + +// samePointers compares two generic interface objects and returns whether +// they point to the same object +func samePointers(first, second interface{}) bool { + firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second) + if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr { + return false + } + + firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second) + if firstType != secondType { + return false + } + + // compare pointer addresses + return first == second +} + // formatUnequalValues takes two values of arbitrary types and returns string // representations appropriate to be presented to the user. // @@ -390,12 +429,27 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b // to a type conversion in the Go grammar. func formatUnequalValues(expected, actual interface{}) (e string, a string) { if reflect.TypeOf(expected) != reflect.TypeOf(actual) { - return fmt.Sprintf("%T(%#v)", expected, expected), - fmt.Sprintf("%T(%#v)", actual, actual) + return fmt.Sprintf("%T(%s)", expected, truncatingFormat(expected)), + fmt.Sprintf("%T(%s)", actual, truncatingFormat(actual)) + } + switch expected.(type) { + case time.Duration: + return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual) } + return truncatingFormat(expected), truncatingFormat(actual) +} - return fmt.Sprintf("%#v", expected), - fmt.Sprintf("%#v", actual) +// truncatingFormat formats the data and truncates it if it's too long. +// +// This helps keep formatted error messages lines from exceeding the +// bufio.MaxScanTokenSize max line length that the go testing framework imposes. +func truncatingFormat(data interface{}) string { + value := fmt.Sprintf("%#v", data) + max := bufio.MaxScanTokenSize - 100 // Give us some space the type info too if needed. + if len(value) > max { + value = value[0:max] + "<... truncated>" + } + return value } // EqualValues asserts that two objects are equal or convertable to the same types @@ -442,12 +496,12 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{} // // assert.NotNil(t, err) func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } if !isNil(object) { return true } + if h, ok := t.(tHelper); ok { + h.Helper() + } return Fail(t, "Expected value not to be nil.", msgAndArgs...) } @@ -488,12 +542,12 @@ func isNil(object interface{}) bool { // // assert.Nil(t, err) func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } if isNil(object) { return true } + if h, ok := t.(tHelper); ok { + h.Helper() + } return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...) } @@ -509,16 +563,17 @@ func isEmpty(object interface{}) bool { switch objValue.Kind() { // collection types are empty when they have no element - case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: + case reflect.Chan, reflect.Map, reflect.Slice: return objValue.Len() == 0 - // pointers are empty if nil or if the value they point to is empty + // pointers are empty if nil or if the value they point to is empty case reflect.Ptr: if objValue.IsNil() { return true } deref := objValue.Elem().Interface() return isEmpty(deref) - // for all other types, compare against the zero value + // for all other types, compare against the zero value + // array types are empty when they match their zero-initialized state default: zero := reflect.Zero(objValue.Type()) return reflect.DeepEqual(object, zero.Interface()) @@ -530,12 +585,11 @@ func isEmpty(object interface{}) bool { // // assert.Empty(t, obj) func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - pass := isEmpty(object) if !pass { + if h, ok := t.(tHelper); ok { + h.Helper() + } Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...) } @@ -550,12 +604,11 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { // assert.Equal(t, "two", obj[1]) // } func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - pass := !isEmpty(object) if !pass { + if h, ok := t.(tHelper); ok { + h.Helper() + } Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...) } @@ -598,16 +651,10 @@ func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) // // assert.True(t, myBool) func True(t TestingT, value bool, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if h, ok := t.(interface { - Helper() - }); ok { - h.Helper() - } - - if value != true { + if !value { + if h, ok := t.(tHelper); ok { + h.Helper() + } return Fail(t, "Should be true", msgAndArgs...) } @@ -619,11 +666,10 @@ func True(t TestingT, value bool, msgAndArgs ...interface{}) bool { // // assert.False(t, myBool) func False(t TestingT, value bool, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - - if value != false { + if value { + if h, ok := t.(tHelper); ok { + h.Helper() + } return Fail(t, "Should be false", msgAndArgs...) } @@ -654,14 +700,33 @@ func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{ } +// NotEqualValues asserts that two objects are not equal even when converted to the same type +// +// assert.NotEqualValues(t, obj1, obj2) +func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if ObjectsAreEqualValues(expected, actual) { + return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...) + } + + return true +} + // containsElement try loop over the list check if the list includes the element. // return (false, false) if impossible. // return (true, false) if element was not found. // return (true, true) if element was found. -func includeElement(list interface{}, element interface{}) (ok, found bool) { +func containsElement(list interface{}, element interface{}) (ok, found bool) { listValue := reflect.ValueOf(list) - listKind := reflect.TypeOf(list).Kind() + listType := reflect.TypeOf(list) + if listType == nil { + return false, false + } + listKind := listType.Kind() defer func() { if e := recover(); e != nil { ok = false @@ -704,12 +769,12 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo h.Helper() } - ok, found := includeElement(s, contains) + ok, found := containsElement(s, contains) if !ok { - return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...) + return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...) } if !found { - return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", s, contains), msgAndArgs...) + return Fail(t, fmt.Sprintf("%#v does not contain %#v", s, contains), msgAndArgs...) } return true @@ -727,7 +792,7 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) h.Helper() } - ok, found := includeElement(s, contains) + ok, found := containsElement(s, contains) if !ok { return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...) } @@ -771,7 +836,7 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok for i := 0; i < subsetValue.Len(); i++ { element := subsetValue.Index(i).Interface() - ok, found := includeElement(list, element) + ok, found := containsElement(list, element) if !ok { return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) } @@ -792,7 +857,7 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) h.Helper() } if subset == nil { - return Fail(t, fmt.Sprintf("nil is the empty set which is a subset of every set"), msgAndArgs...) + return Fail(t, "nil is the empty set which is a subset of every set", msgAndArgs...) } subsetValue := reflect.ValueOf(subset) @@ -815,7 +880,7 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) for i := 0; i < subsetValue.Len(); i++ { element := subsetValue.Index(i).Interface() - ok, found := includeElement(list, element) + ok, found := containsElement(list, element) if !ok { return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) } @@ -840,27 +905,39 @@ func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface return true } - aKind := reflect.TypeOf(listA).Kind() - bKind := reflect.TypeOf(listB).Kind() + if !isList(t, listA, msgAndArgs...) || !isList(t, listB, msgAndArgs...) { + return false + } + + extraA, extraB := diffLists(listA, listB) - if aKind != reflect.Array && aKind != reflect.Slice { - return Fail(t, fmt.Sprintf("%q has an unsupported type %s", listA, aKind), msgAndArgs...) + if len(extraA) == 0 && len(extraB) == 0 { + return true } - if bKind != reflect.Array && bKind != reflect.Slice { - return Fail(t, fmt.Sprintf("%q has an unsupported type %s", listB, bKind), msgAndArgs...) + return Fail(t, formatListDiff(listA, listB, extraA, extraB), msgAndArgs...) +} + +// isList checks that the provided value is array or slice. +func isList(t TestingT, list interface{}, msgAndArgs ...interface{}) (ok bool) { + kind := reflect.TypeOf(list).Kind() + if kind != reflect.Array && kind != reflect.Slice { + return Fail(t, fmt.Sprintf("%q has an unsupported type %s, expecting array or slice", list, kind), + msgAndArgs...) } + return true +} +// diffLists diffs two arrays/slices and returns slices of elements that are only in A and only in B. +// If some element is present multiple times, each instance is counted separately (e.g. if something is 2x in A and +// 5x in B, it will be 0x in extraA and 3x in extraB). The order of items in both lists is ignored. +func diffLists(listA, listB interface{}) (extraA, extraB []interface{}) { aValue := reflect.ValueOf(listA) bValue := reflect.ValueOf(listB) aLen := aValue.Len() bLen := bValue.Len() - if aLen != bLen { - return Fail(t, fmt.Sprintf("lengths don't match: %d != %d", aLen, bLen), msgAndArgs...) - } - // Mark indexes in bValue that we already used visited := make([]bool, bLen) for i := 0; i < aLen; i++ { @@ -877,11 +954,38 @@ func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface } } if !found { - return Fail(t, fmt.Sprintf("element %s appears more times in %s than in %s", element, aValue, bValue), msgAndArgs...) + extraA = append(extraA, element) } } - return true + for j := 0; j < bLen; j++ { + if visited[j] { + continue + } + extraB = append(extraB, bValue.Index(j).Interface()) + } + + return +} + +func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) string { + var msg bytes.Buffer + + msg.WriteString("elements differ") + if len(extraA) > 0 { + msg.WriteString("\n\nextra elements in list A:\n") + msg.WriteString(spewConfig.Sdump(extraA)) + } + if len(extraB) > 0 { + msg.WriteString("\n\nextra elements in list B:\n") + msg.WriteString(spewConfig.Sdump(extraB)) + } + msg.WriteString("\n\nlistA:\n") + msg.WriteString(spewConfig.Sdump(listA)) + msg.WriteString("\n\nlistB:\n") + msg.WriteString(spewConfig.Sdump(listB)) + + return msg.String() } // Condition uses a Comparison to assert a complex condition. @@ -901,25 +1005,21 @@ func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool { type PanicTestFunc func() // didPanic returns true if the function passed to it panics. Otherwise, it returns false. -func didPanic(f PanicTestFunc) (bool, interface{}) { - - didPanic := false - var message interface{} - func() { - - defer func() { - if message = recover(); message != nil { - didPanic = true - } - }() - - // call the target function - f() +func didPanic(f PanicTestFunc) (didPanic bool, message interface{}, stack string) { + didPanic = true + defer func() { + message = recover() + if didPanic { + stack = string(debug.Stack()) + } }() - return didPanic, message + // call the target function + f() + didPanic = false + return } // Panics asserts that the code inside the specified PanicTestFunc panics. @@ -930,7 +1030,7 @@ func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { h.Helper() } - if funcDidPanic, panicValue := didPanic(f); !funcDidPanic { + if funcDidPanic, panicValue, _ := didPanic(f); !funcDidPanic { return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) } @@ -946,12 +1046,34 @@ func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndAr h.Helper() } - funcDidPanic, panicValue := didPanic(f) + funcDidPanic, panicValue, panickedStack := didPanic(f) if !funcDidPanic { return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) } if panicValue != expected { - return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v", f, expected, panicValue), msgAndArgs...) + return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, expected, panicValue, panickedStack), msgAndArgs...) + } + + return true +} + +// PanicsWithError asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) +func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + funcDidPanic, panicValue, panickedStack := didPanic(f) + if !funcDidPanic { + return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) + } + panicErr, ok := panicValue.(error) + if !ok || panicErr.Error() != errString { + return Fail(t, fmt.Sprintf("func %#v should panic with error message:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, errString, panicValue, panickedStack), msgAndArgs...) } return true @@ -965,8 +1087,8 @@ func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { h.Helper() } - if funcDidPanic, panicValue := didPanic(f); funcDidPanic { - return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v", f, panicValue), msgAndArgs...) + if funcDidPanic, panicValue, panickedStack := didPanic(f); funcDidPanic { + return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v\n\tPanic stack:\t%s", f, panicValue, panickedStack), msgAndArgs...) } return true @@ -993,6 +1115,8 @@ func toFloat(x interface{}) (float64, bool) { xok := true switch xn := x.(type) { + case uint: + xf = float64(xn) case uint8: xf = float64(xn) case uint16: @@ -1014,7 +1138,7 @@ func toFloat(x interface{}) (float64, bool) { case float32: xf = float64(xn) case float64: - xf = float64(xn) + xf = xn case time.Duration: xf = float64(xn) default: @@ -1026,7 +1150,7 @@ func toFloat(x interface{}) (float64, bool) { // InDelta asserts that the two numerals are within delta of each other. // -// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01) +// assert.InDelta(t, math.Pi, 22/7.0, 0.01) func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1036,11 +1160,15 @@ func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs bf, bok := toFloat(actual) if !aok || !bok { - return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...) + return Fail(t, "Parameters must be numerical", msgAndArgs...) + } + + if math.IsNaN(af) && math.IsNaN(bf) { + return true } if math.IsNaN(af) { - return Fail(t, fmt.Sprintf("Expected must not be NaN"), msgAndArgs...) + return Fail(t, "Expected must not be NaN", msgAndArgs...) } if math.IsNaN(bf) { @@ -1063,7 +1191,7 @@ func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAn if expected == nil || actual == nil || reflect.TypeOf(actual).Kind() != reflect.Slice || reflect.TypeOf(expected).Kind() != reflect.Slice { - return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) + return Fail(t, "Parameters must be slice", msgAndArgs...) } actualSlice := reflect.ValueOf(actual) @@ -1125,15 +1253,21 @@ func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, m func calcRelativeError(expected, actual interface{}) (float64, error) { af, aok := toFloat(expected) - if !aok { - return 0, fmt.Errorf("expected value %q cannot be converted to float", expected) + bf, bok := toFloat(actual) + if !aok || !bok { + return 0, fmt.Errorf("Parameters must be numerical") + } + if math.IsNaN(af) && math.IsNaN(bf) { + return 0, nil + } + if math.IsNaN(af) { + return 0, errors.New("expected value must not be NaN") } if af == 0 { return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error") } - bf, bok := toFloat(actual) - if !bok { - return 0, fmt.Errorf("actual value %q cannot be converted to float", actual) + if math.IsNaN(bf) { + return 0, errors.New("actual value must not be NaN") } return math.Abs(af-bf) / math.Abs(af), nil @@ -1144,6 +1278,9 @@ func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAnd if h, ok := t.(tHelper); ok { h.Helper() } + if math.IsNaN(epsilon) { + return Fail(t, "epsilon must not be NaN") + } actualEpsilon, err := calcRelativeError(expected, actual) if err != nil { return Fail(t, err.Error(), msgAndArgs...) @@ -1164,7 +1301,7 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m if expected == nil || actual == nil || reflect.TypeOf(actual).Kind() != reflect.Slice || reflect.TypeOf(expected).Kind() != reflect.Slice { - return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) + return Fail(t, "Parameters must be slice", msgAndArgs...) } actualSlice := reflect.ValueOf(actual) @@ -1191,10 +1328,10 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m // assert.Equal(t, expectedObj, actualObj) // } func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } if err != nil { + if h, ok := t.(tHelper); ok { + h.Helper() + } return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...) } @@ -1208,11 +1345,10 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { // assert.Equal(t, expectedError, err) // } func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { - if h, ok := t.(tHelper); ok { - h.Helper() - } - if err == nil { + if h, ok := t.(tHelper); ok { + h.Helper() + } return Fail(t, "An error is expected but got nil.", msgAndArgs...) } @@ -1242,6 +1378,27 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte return true } +// ErrorContains asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// assert.ErrorContains(t, err, expectedErrorSubString) +func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if !Error(t, theError, msgAndArgs...) { + return false + } + + actual := theError.Error() + if !strings.Contains(actual, contains) { + return Fail(t, fmt.Sprintf("Error %#v does not contain %#v", actual, contains), msgAndArgs...) + } + + return true +} + // matchRegexp return true if a specified regexp matches a string. func matchRegexp(rx interface{}, str interface{}) bool { @@ -1314,7 +1471,8 @@ func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { return true } -// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. +// FileExists checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1332,7 +1490,24 @@ func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool { return true } -// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + info, err := os.Lstat(path) + if err != nil { + return true + } + if info.IsDir() { + return true + } + return Fail(t, fmt.Sprintf("file %q exists", path), msgAndArgs...) +} + +// DirExists checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool { if h, ok := t.(tHelper); ok { h.Helper() @@ -1350,6 +1525,25 @@ func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool { return true } +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + info, err := os.Lstat(path) + if err != nil { + if os.IsNotExist(err) { + return true + } + return true + } + if !info.IsDir() { + return true + } + return Fail(t, fmt.Sprintf("directory %q exists", path), msgAndArgs...) +} + // JSONEq asserts that two JSON strings are equivalent. // // assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) @@ -1418,12 +1612,17 @@ func diff(expected interface{}, actual interface{}) string { } var e, a string - if et != reflect.TypeOf("") { - e = spewConfig.Sdump(expected) - a = spewConfig.Sdump(actual) - } else { + + switch et { + case reflect.TypeOf(""): e = reflect.ValueOf(expected).String() a = reflect.ValueOf(actual).String() + case reflect.TypeOf(time.Time{}): + e = spewConfigStringerEnabled.Sdump(expected) + a = spewConfigStringerEnabled.Sdump(actual) + default: + e = spewConfig.Sdump(expected) + a = spewConfig.Sdump(actual) } diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ @@ -1439,15 +1638,6 @@ func diff(expected interface{}, actual interface{}) string { return "\n\nDiff:\n" + diff } -// validateEqualArgs checks whether provided arguments can be safely used in the -// Equal/NotEqual functions. -func validateEqualArgs(expected, actual interface{}) error { - if isFunction(expected) || isFunction(actual) { - return errors.New("cannot take func type as argument") - } - return nil -} - func isFunction(arg interface{}) bool { if arg == nil { return false @@ -1460,6 +1650,16 @@ var spewConfig = spew.ConfigState{ DisablePointerAddresses: true, DisableCapacities: true, SortKeys: true, + DisableMethods: true, + MaxDepth: 10, +} + +var spewConfigStringerEnabled = spew.ConfigState{ + Indent: " ", + DisablePointerAddresses: true, + DisableCapacities: true, + SortKeys: true, + MaxDepth: 10, } type tHelper interface { @@ -1475,24 +1675,137 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t h.Helper() } + ch := make(chan bool, 1) + timer := time.NewTimer(waitFor) - ticker := time.NewTicker(tick) - checkPassed := make(chan bool) defer timer.Stop() + + ticker := time.NewTicker(tick) defer ticker.Stop() - defer close(checkPassed) - for { + + for tick := ticker.C; ; { select { case <-timer.C: return Fail(t, "Condition never satisfied", msgAndArgs...) - case result := <-checkPassed: - if result { + case <-tick: + tick = nil + go func() { ch <- condition() }() + case v := <-ch: + if v { return true } - case <-ticker.C: - go func() { - checkPassed <- condition() - }() + tick = ticker.C } } } + +// Never asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) +func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + ch := make(chan bool, 1) + + timer := time.NewTimer(waitFor) + defer timer.Stop() + + ticker := time.NewTicker(tick) + defer ticker.Stop() + + for tick := ticker.C; ; { + select { + case <-timer.C: + return true + case <-tick: + tick = nil + go func() { ch <- condition() }() + case v := <-ch: + if v { + return Fail(t, "Condition satisfied", msgAndArgs...) + } + tick = ticker.C + } + } +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if errors.Is(err, target) { + return true + } + + var expectedText string + if target != nil { + expectedText = target.Error() + } + + chain := buildErrorChainString(err) + + return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+ + "expected: %q\n"+ + "in chain: %s", expectedText, chain, + ), msgAndArgs...) +} + +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if !errors.Is(err, target) { + return true + } + + var expectedText string + if target != nil { + expectedText = target.Error() + } + + chain := buildErrorChainString(err) + + return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+ + "found: %q\n"+ + "in chain: %s", expectedText, chain, + ), msgAndArgs...) +} + +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if errors.As(err, target) { + return true + } + + chain := buildErrorChainString(err) + + return Fail(t, fmt.Sprintf("Should be in error chain:\n"+ + "expected: %q\n"+ + "in chain: %s", target, chain, + ), msgAndArgs...) +} + +func buildErrorChainString(err error) string { + if err == nil { + return "" + } + + e := errors.Unwrap(err) + chain := fmt.Sprintf("%q", err.Error()) + for e != nil { + chain += fmt.Sprintf("\n\t%q", e.Error()) + e = errors.Unwrap(e) + } + return chain +} diff --git a/vendor/github.com/stretchr/testify/assert/forward_assertions.go b/vendor/github.com/stretchr/testify/assert/forward_assertions.go index 9ad5685..df189d2 100644 --- a/vendor/github.com/stretchr/testify/assert/forward_assertions.go +++ b/vendor/github.com/stretchr/testify/assert/forward_assertions.go @@ -13,4 +13,4 @@ func New(t TestingT) *Assertions { } } -//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs +//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs" diff --git a/vendor/github.com/stretchr/testify/assert/http_assertions.go b/vendor/github.com/stretchr/testify/assert/http_assertions.go index df46fa7..4ed341d 100644 --- a/vendor/github.com/stretchr/testify/assert/http_assertions.go +++ b/vendor/github.com/stretchr/testify/assert/http_assertions.go @@ -33,7 +33,6 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, value code, err := httpCode(handler, method, url, values) if err != nil { Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) - return false } isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent @@ -56,7 +55,6 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, valu code, err := httpCode(handler, method, url, values) if err != nil { Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) - return false } isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect @@ -79,7 +77,6 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values code, err := httpCode(handler, method, url, values) if err != nil { Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) - return false } isErrorCode := code >= http.StatusBadRequest @@ -90,6 +87,28 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values return isErrorCode } +// HTTPStatusCode asserts that a specified handler returns a specified status code. +// +// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + code, err := httpCode(handler, method, url, values) + if err != nil { + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) + } + + successful := code == statuscode + if !successful { + Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code)) + } + + return successful +} + // HTTPBody is a helper that returns HTTP body of the response. It returns // empty string if building a new request fails. func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string { diff --git a/vendor/github.com/stretchr/testify/require/forward_requirements.go b/vendor/github.com/stretchr/testify/require/forward_requirements.go index ac71d40..1dcb233 100644 --- a/vendor/github.com/stretchr/testify/require/forward_requirements.go +++ b/vendor/github.com/stretchr/testify/require/forward_requirements.go @@ -13,4 +13,4 @@ func New(t TestingT) *Assertions { } } -//go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl -include-format-funcs +//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs" diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go index c5903f5..59c4827 100644 --- a/vendor/github.com/stretchr/testify/require/require.go +++ b/vendor/github.com/stretchr/testify/require/require.go @@ -66,7 +66,8 @@ func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args t.FailNow() } -// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. +// DirExists checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. func DirExists(t TestingT, path string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -77,7 +78,8 @@ func DirExists(t TestingT, path string, msgAndArgs ...interface{}) { t.FailNow() } -// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. +// DirExistsf checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. func DirExistsf(t TestingT, path string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -210,7 +212,7 @@ func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArg // EqualValuesf asserts that two objects are equal or convertable to the same types // and equal. // -// assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123)) +// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -254,6 +256,84 @@ func Error(t TestingT, err error, msgAndArgs ...interface{}) { t.FailNow() } +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorAs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorAsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + +// ErrorContains asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// assert.ErrorContains(t, err, expectedErrorSubString) +func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorContains(t, theError, contains, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") +func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorContainsf(t, theError, contains, msg, args...) { + return + } + t.FailNow() +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorIs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorIsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + // Errorf asserts that a function returned an error (i.e. not `nil`). // // actualObj, err := SomeFunction() @@ -275,12 +355,12 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) { // // assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { - if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) { - return - } if h, ok := t.(tHelper); ok { h.Helper() } + if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) { + return + } t.FailNow() } @@ -289,12 +369,12 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t // // assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { - if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) { - return - } if h, ok := t.(tHelper); ok { h.Helper() } + if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) { + return + } t.FailNow() } @@ -313,7 +393,7 @@ func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs .. // Exactlyf asserts that two objects are equal in value and type. // -// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123)) +// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -394,7 +474,8 @@ func Falsef(t TestingT, value bool, msg string, args ...interface{}) { t.FailNow() } -// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. +// FileExists checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. func FileExists(t TestingT, path string, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -405,7 +486,8 @@ func FileExists(t TestingT, path string, msgAndArgs ...interface{}) { t.FailNow() } -// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. +// FileExistsf checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. func FileExistsf(t TestingT, path string, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -466,7 +548,7 @@ func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, arg // Greaterf asserts that the first element is greater than the second // // assert.Greaterf(t, 2, 1, "error message %s", "formatted") -// assert.Greaterf(t, float64(2, "error message %s", "formatted"), float64(1)) +// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") // assert.Greaterf(t, "b", "a", "error message %s", "formatted") func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { @@ -561,7 +643,7 @@ func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, // // assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // -// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). +// Returns whether the assertion was successful (true) or not (false). func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -591,7 +673,7 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url strin // // assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // -// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). +// Returns whether the assertion was successful (true) or not (false). func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -602,6 +684,36 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri t.FailNow() } +// HTTPStatusCode asserts that a specified handler returns a specified status code. +// +// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPStatusCode(t, handler, method, url, values, statuscode, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// +// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPStatusCodef(t, handler, method, url, values, statuscode, msg, args...) { + return + } + t.FailNow() +} + // HTTPSuccess asserts that a specified handler returns a success status code. // // assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) @@ -647,7 +759,7 @@ func Implements(t TestingT, interfaceObject interface{}, object interface{}, msg // Implementsf asserts that an object is implemented by the specified interface. // -// assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject)) +// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -660,7 +772,7 @@ func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, ms // InDelta asserts that the two numerals are within delta of each other. // -// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01) +// assert.InDelta(t, math.Pi, 22/7.0, 0.01) func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -717,7 +829,7 @@ func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta f // InDeltaf asserts that the two numerals are within delta of each other. // -// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01) +// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() @@ -772,71 +884,169 @@ func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon fl t.FailNow() } -// IsType asserts that the specified objects are of the same type. -func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { +// IsDecreasing asserts that the collection is decreasing +// +// assert.IsDecreasing(t, []int{2, 1, 0}) +// assert.IsDecreasing(t, []float{2, 1}) +// assert.IsDecreasing(t, []string{"b", "a"}) +func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } - if assert.IsType(t, expectedType, object, msgAndArgs...) { + if assert.IsDecreasing(t, object, msgAndArgs...) { return } t.FailNow() } -// IsTypef asserts that the specified objects are of the same type. -func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) { +// IsDecreasingf asserts that the collection is decreasing +// +// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } - if assert.IsTypef(t, expectedType, object, msg, args...) { + if assert.IsDecreasingf(t, object, msg, args...) { return } t.FailNow() } -// JSONEq asserts that two JSON strings are equivalent. +// IsIncreasing asserts that the collection is increasing // -// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) -func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { +// assert.IsIncreasing(t, []int{1, 2, 3}) +// assert.IsIncreasing(t, []float{1, 2}) +// assert.IsIncreasing(t, []string{"a", "b"}) +func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } - if assert.JSONEq(t, expected, actual, msgAndArgs...) { + if assert.IsIncreasing(t, object, msgAndArgs...) { return } t.FailNow() } -// JSONEqf asserts that two JSON strings are equivalent. +// IsIncreasingf asserts that the collection is increasing // -// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") -func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { +// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } - if assert.JSONEqf(t, expected, actual, msg, args...) { + if assert.IsIncreasingf(t, object, msg, args...) { return } t.FailNow() } -// YAMLEq asserts that two YAML strings are equivalent. -func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { +// IsNonDecreasing asserts that the collection is not decreasing +// +// assert.IsNonDecreasing(t, []int{1, 1, 2}) +// assert.IsNonDecreasing(t, []float{1, 2}) +// assert.IsNonDecreasing(t, []string{"a", "b"}) +func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } - if assert.YAMLEq(t, expected, actual, msgAndArgs...) { + if assert.IsNonDecreasing(t, object, msgAndArgs...) { return } t.FailNow() } -// YAMLEqf asserts that two YAML strings are equivalent. -func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { +// IsNonDecreasingf asserts that the collection is not decreasing +// +// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { h.Helper() } - if assert.YAMLEqf(t, expected, actual, msg, args...) { + if assert.IsNonDecreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// assert.IsNonIncreasing(t, []int{2, 1, 1}) +// assert.IsNonIncreasing(t, []float{2, 1}) +// assert.IsNonIncreasing(t, []string{"b", "a"}) +func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonIncreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonIncreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsType asserts that the specified objects are of the same type. +func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsType(t, expectedType, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsTypef asserts that the specified objects are of the same type. +func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsTypef(t, expectedType, object, msg, args...) { + return + } + t.FailNow() +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.JSONEq(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// JSONEqf asserts that two JSON strings are equivalent. +// +// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.JSONEqf(t, expected, actual, msg, args...) { return } t.FailNow() @@ -920,7 +1130,7 @@ func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args . // Lessf asserts that the first element is less than the second // // assert.Lessf(t, 1, 2, "error message %s", "formatted") -// assert.Lessf(t, float64(1, "error message %s", "formatted"), float64(2)) +// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") // assert.Lessf(t, "a", "b", "error message %s", "formatted") func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { @@ -932,6 +1142,62 @@ func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...inter t.FailNow() } +// Negative asserts that the specified element is negative +// +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) +func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Negative(t, e, msgAndArgs...) { + return + } + t.FailNow() +} + +// Negativef asserts that the specified element is negative +// +// assert.Negativef(t, -1, "error message %s", "formatted") +// assert.Negativef(t, -1.23, "error message %s", "formatted") +func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Negativef(t, e, msg, args...) { + return + } + t.FailNow() +} + +// Never asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) +func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Never(t, condition, waitFor, tick, msgAndArgs...) { + return + } + t.FailNow() +} + +// Neverf asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Neverf(t, condition, waitFor, tick, msg, args...) { + return + } + t.FailNow() +} + // Nil asserts that the specified object is nil. // // assert.Nil(t, err) @@ -958,6 +1224,30 @@ func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) { t.FailNow() } +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoDirExists(t, path, msgAndArgs...) { + return + } + t.FailNow() +} + +// NoDirExistsf checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoDirExistsf(t, path, msg, args...) { + return + } + t.FailNow() +} + // NoError asserts that a function returned no error (i.e. `nil`). // // actualObj, err := SomeFunction() @@ -990,6 +1280,30 @@ func NoErrorf(t TestingT, err error, msg string, args ...interface{}) { t.FailNow() } +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoFileExists(t, path, msgAndArgs...) { + return + } + t.FailNow() +} + +// NoFileExistsf checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoFileExistsf(t, path, msg, args...) { + return + } + t.FailNow() +} + // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // @@ -1070,6 +1384,32 @@ func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs . t.FailNow() } +// NotEqualValues asserts that two objects are not equal even when converted to the same type +// +// assert.NotEqualValues(t, obj1, obj2) +func NotEqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEqualValues(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// +// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") +func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEqualValuesf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + // NotEqualf asserts that the specified values are NOT equal. // // assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") @@ -1086,6 +1426,30 @@ func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, t.FailNow() } +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotErrorIs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotErrorIsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + // NotNil asserts that the specified object is not nil. // // assert.NotNil(t, err) @@ -1154,7 +1518,7 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf // NotRegexpf asserts that a specified regexp does not match a string. // -// assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting") +// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") // assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { @@ -1166,6 +1530,38 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args .. t.FailNow() } +// NotSame asserts that two pointers do not reference the same object. +// +// assert.NotSame(t, ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func NotSame(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotSame(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotSamef asserts that two pointers do not reference the same object. +// +// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotSamef(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + // NotSubset asserts that the specified list(array, slice...) contains not all // elements given in the specified subset(array, slice...). // @@ -1229,6 +1625,36 @@ func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { t.FailNow() } +// PanicsWithError asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) +func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithError(t, errString, f, msgAndArgs...) { + return + } + t.FailNow() +} + +// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithErrorf(t, errString, f, msg, args...) { + return + } + t.FailNow() +} + // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // @@ -1270,6 +1696,34 @@ func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{} t.FailNow() } +// Positive asserts that the specified element is positive +// +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) +func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Positive(t, e, msgAndArgs...) { + return + } + t.FailNow() +} + +// Positivef asserts that the specified element is positive +// +// assert.Positivef(t, 1, "error message %s", "formatted") +// assert.Positivef(t, 1.23, "error message %s", "formatted") +func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Positivef(t, e, msg, args...) { + return + } + t.FailNow() +} + // Regexp asserts that a specified regexp matches a string. // // assert.Regexp(t, regexp.MustCompile("start"), "it's starting") @@ -1286,7 +1740,7 @@ func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface // Regexpf asserts that a specified regexp matches a string. // -// assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting") +// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") // assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := t.(tHelper); ok { @@ -1410,6 +1864,28 @@ func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta tim t.FailNow() } +// YAMLEq asserts that two YAML strings are equivalent. +func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.YAMLEq(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// YAMLEqf asserts that two YAML strings are equivalent. +func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.YAMLEqf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + // Zero asserts that i is the zero value for its type. func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) { if h, ok := t.(tHelper); ok { diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go index 804fae0..5bb07c8 100644 --- a/vendor/github.com/stretchr/testify/require/require_forward.go +++ b/vendor/github.com/stretchr/testify/require/require_forward.go @@ -54,7 +54,8 @@ func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, Containsf(a.t, s, contains, msg, args...) } -// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. +// DirExists checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -62,7 +63,8 @@ func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) { DirExists(a.t, path, msgAndArgs...) } -// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. +// DirExistsf checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -168,7 +170,7 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn // EqualValuesf asserts that two objects are equal or convertable to the same types // and equal. // -// a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123)) +// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -203,6 +205,66 @@ func (a *Assertions) Error(err error, msgAndArgs ...interface{}) { Error(a.t, err, msgAndArgs...) } +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorAs(a.t, err, target, msgAndArgs...) +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorAsf(a.t, err, target, msg, args...) +} + +// ErrorContains asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// a.ErrorContains(err, expectedErrorSubString) +func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorContains(a.t, theError, contains, msgAndArgs...) +} + +// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") +func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorContainsf(a.t, theError, contains, msg, args...) +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorIs(a.t, err, target, msgAndArgs...) +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorIsf(a.t, err, target, msg, args...) +} + // Errorf asserts that a function returned an error (i.e. not `nil`). // // actualObj, err := SomeFunction() @@ -250,7 +312,7 @@ func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArg // Exactlyf asserts that two objects are equal in value and type. // -// a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123)) +// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -310,7 +372,8 @@ func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) { Falsef(a.t, value, msg, args...) } -// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. +// FileExists checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -318,7 +381,8 @@ func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) { FileExists(a.t, path, msgAndArgs...) } -// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. +// FileExistsf checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -367,7 +431,7 @@ func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, // Greaterf asserts that the first element is greater than the second // // a.Greaterf(2, 1, "error message %s", "formatted") -// a.Greaterf(float64(2, "error message %s", "formatted"), float64(1)) +// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") // a.Greaterf("b", "a", "error message %s", "formatted") func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { @@ -444,7 +508,7 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri // // a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} // -// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). +// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -468,7 +532,7 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s // // a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} // -// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). +// Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -476,6 +540,30 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url HTTPRedirectf(a.t, handler, method, url, values, msg, args...) } +// HTTPStatusCode asserts that a specified handler returns a specified status code. +// +// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...) +} + +// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// +// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...) +} + // HTTPSuccess asserts that a specified handler returns a success status code. // // a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) @@ -512,7 +600,7 @@ func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, // Implementsf asserts that an object is implemented by the specified interface. // -// a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject)) +// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -522,7 +610,7 @@ func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{} // InDelta asserts that the two numerals are within delta of each other. // -// a.InDelta(math.Pi, (22 / 7.0), 0.01) +// a.InDelta(math.Pi, 22/7.0, 0.01) func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -564,7 +652,7 @@ func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, del // InDeltaf asserts that the two numerals are within delta of each other. // -// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01) +// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { h.Helper() @@ -604,6 +692,102 @@ func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilo InEpsilonf(a.t, expected, actual, epsilon, msg, args...) } +// IsDecreasing asserts that the collection is decreasing +// +// a.IsDecreasing([]int{2, 1, 0}) +// a.IsDecreasing([]float{2, 1}) +// a.IsDecreasing([]string{"b", "a"}) +func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsDecreasing(a.t, object, msgAndArgs...) +} + +// IsDecreasingf asserts that the collection is decreasing +// +// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") +// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsDecreasingf(a.t, object, msg, args...) +} + +// IsIncreasing asserts that the collection is increasing +// +// a.IsIncreasing([]int{1, 2, 3}) +// a.IsIncreasing([]float{1, 2}) +// a.IsIncreasing([]string{"a", "b"}) +func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsIncreasing(a.t, object, msgAndArgs...) +} + +// IsIncreasingf asserts that the collection is increasing +// +// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") +// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsIncreasingf(a.t, object, msg, args...) +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// a.IsNonDecreasing([]int{1, 1, 2}) +// a.IsNonDecreasing([]float{1, 2}) +// a.IsNonDecreasing([]string{"a", "b"}) +func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonDecreasing(a.t, object, msgAndArgs...) +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonDecreasingf(a.t, object, msg, args...) +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// a.IsNonIncreasing([]int{2, 1, 1}) +// a.IsNonIncreasing([]float{2, 1}) +// a.IsNonIncreasing([]string{"b", "a"}) +func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonIncreasing(a.t, object, msgAndArgs...) +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonIncreasingf(a.t, object, msg, args...) +} + // IsType asserts that the specified objects are of the same type. func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { @@ -640,22 +824,6 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args .. JSONEqf(a.t, expected, actual, msg, args...) } -// YAMLEq asserts that two YAML strings are equivalent. -func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - YAMLEq(a.t, expected, actual, msgAndArgs...) -} - -// YAMLEqf asserts that two YAML strings are equivalent. -func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) { - if h, ok := a.t.(tHelper); ok { - h.Helper() - } - YAMLEqf(a.t, expected, actual, msg, args...) -} - // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. // @@ -719,7 +887,7 @@ func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, ar // Lessf asserts that the first element is less than the second // // a.Lessf(1, 2, "error message %s", "formatted") -// a.Lessf(float64(1, "error message %s", "formatted"), float64(2)) +// a.Lessf(float64(1), float64(2), "error message %s", "formatted") // a.Lessf("a", "b", "error message %s", "formatted") func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { @@ -728,6 +896,50 @@ func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...i Lessf(a.t, e1, e2, msg, args...) } +// Negative asserts that the specified element is negative +// +// a.Negative(-1) +// a.Negative(-1.23) +func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Negative(a.t, e, msgAndArgs...) +} + +// Negativef asserts that the specified element is negative +// +// a.Negativef(-1, "error message %s", "formatted") +// a.Negativef(-1.23, "error message %s", "formatted") +func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Negativef(a.t, e, msg, args...) +} + +// Never asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) +func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Never(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Neverf asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Neverf(a.t, condition, waitFor, tick, msg, args...) +} + // Nil asserts that the specified object is nil. // // a.Nil(err) @@ -748,6 +960,24 @@ func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) { Nilf(a.t, object, msg, args...) } +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoDirExists(a.t, path, msgAndArgs...) +} + +// NoDirExistsf checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoDirExistsf(a.t, path, msg, args...) +} + // NoError asserts that a function returned no error (i.e. `nil`). // // actualObj, err := SomeFunction() @@ -774,6 +1004,24 @@ func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) { NoErrorf(a.t, err, msg, args...) } +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoFileExists(a.t, path, msgAndArgs...) +} + +// NoFileExistsf checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoFileExistsf(a.t, path, msg, args...) +} + // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. // @@ -839,6 +1087,26 @@ func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndAr NotEqual(a.t, expected, actual, msgAndArgs...) } +// NotEqualValues asserts that two objects are not equal even when converted to the same type +// +// a.NotEqualValues(obj1, obj2) +func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEqualValues(a.t, expected, actual, msgAndArgs...) +} + +// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// +// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") +func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEqualValuesf(a.t, expected, actual, msg, args...) +} + // NotEqualf asserts that the specified values are NOT equal. // // a.NotEqualf(obj1, obj2, "error message %s", "formatted") @@ -852,6 +1120,24 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str NotEqualf(a.t, expected, actual, msg, args...) } +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotErrorIs(a.t, err, target, msgAndArgs...) +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotErrorIsf(a.t, err, target, msg, args...) +} + // NotNil asserts that the specified object is not nil. // // a.NotNil(err) @@ -905,7 +1191,7 @@ func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...in // NotRegexpf asserts that a specified regexp does not match a string. // -// a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting") +// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") // a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { @@ -914,6 +1200,32 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg NotRegexpf(a.t, rx, str, msg, args...) } +// NotSame asserts that two pointers do not reference the same object. +// +// a.NotSame(ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotSame(a.t, expected, actual, msgAndArgs...) +} + +// NotSamef asserts that two pointers do not reference the same object. +// +// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotSamef(a.t, expected, actual, msg, args...) +} + // NotSubset asserts that the specified list(array, slice...) contains not all // elements given in the specified subset(array, slice...). // @@ -962,6 +1274,30 @@ func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { Panics(a.t, f, msgAndArgs...) } +// PanicsWithError asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// a.PanicsWithError("crazy error", func(){ GoCrazy() }) +func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithError(a.t, errString, f, msgAndArgs...) +} + +// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithErrorf(a.t, errString, f, msg, args...) +} + // PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that // the recovered panic value equals the expected panic value. // @@ -994,6 +1330,28 @@ func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interfa Panicsf(a.t, f, msg, args...) } +// Positive asserts that the specified element is positive +// +// a.Positive(1) +// a.Positive(1.23) +func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Positive(a.t, e, msgAndArgs...) +} + +// Positivef asserts that the specified element is positive +// +// a.Positivef(1, "error message %s", "formatted") +// a.Positivef(1.23, "error message %s", "formatted") +func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Positivef(a.t, e, msg, args...) +} + // Regexp asserts that a specified regexp matches a string. // // a.Regexp(regexp.MustCompile("start"), "it's starting") @@ -1007,7 +1365,7 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter // Regexpf asserts that a specified regexp matches a string. // -// a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting") +// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") // a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { if h, ok := a.t.(tHelper); ok { @@ -1104,6 +1462,22 @@ func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta WithinDurationf(a.t, expected, actual, delta, msg, args...) } +// YAMLEq asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + YAMLEq(a.t, expected, actual, msgAndArgs...) +} + +// YAMLEqf asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + YAMLEqf(a.t, expected, actual, msg, args...) +} + // Zero asserts that i is the zero value for its type. func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) { if h, ok := a.t.(tHelper); ok { diff --git a/vendor/github.com/stretchr/testify/require/requirements.go b/vendor/github.com/stretchr/testify/require/requirements.go index 6b85c5e..91772df 100644 --- a/vendor/github.com/stretchr/testify/require/requirements.go +++ b/vendor/github.com/stretchr/testify/require/requirements.go @@ -26,4 +26,4 @@ type BoolAssertionFunc func(TestingT, bool, ...interface{}) // for table driven tests. type ErrorAssertionFunc func(TestingT, error, ...interface{}) -//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl -include-format-funcs +//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs" diff --git a/vendor/golang.org/x/crypto/acme/acme.go b/vendor/golang.org/x/crypto/acme/acme.go index fa365b7..df57430 100644 --- a/vendor/golang.org/x/crypto/acme/acme.go +++ b/vendor/golang.org/x/crypto/acme/acme.go @@ -3,14 +3,20 @@ // license that can be found in the LICENSE file. // Package acme provides an implementation of the -// Automatic Certificate Management Environment (ACME) spec. -// See https://tools.ietf.org/html/draft-ietf-acme-acme-02 for details. +// Automatic Certificate Management Environment (ACME) spec, +// most famously used by Let's Encrypt. +// +// The initial implementation of this package was based on an early version +// of the spec. The current implementation supports only the modern +// RFC 8555 but some of the old API surface remains for compatibility. +// While code using the old API will still compile, it will return an error. +// Note the deprecation comments to update your code. +// +// See https://tools.ietf.org/html/rfc8555 for the spec. // // Most common scenarios will want to use autocert subdirectory instead, // which provides automatic access to certificates from Let's Encrypt // and any other ACME-based CA. -// -// This package is a work in progress and makes no API stability promises. package acme import ( @@ -30,8 +36,6 @@ import ( "encoding/pem" "errors" "fmt" - "io" - "io/ioutil" "math/big" "net/http" "strings" @@ -41,7 +45,7 @@ import ( const ( // LetsEncryptURL is the Directory endpoint of Let's Encrypt CA. - LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory" + LetsEncryptURL = "https://acme-v02.api.letsencrypt.org/directory" // ALPNProto is the ALPN protocol name used by a CA server when validating // tls-alpn-01 challenges. @@ -52,12 +56,16 @@ const ( ALPNProto = "acme-tls/1" ) -// idPeACMEIdentifierV1 is the OID for the ACME extension for the TLS-ALPN challenge. -var idPeACMEIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1} +// idPeACMEIdentifier is the OID for the ACME extension for the TLS-ALPN challenge. +// https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05#section-5.1 +var idPeACMEIdentifier = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 31} const ( maxChainLen = 5 // max depth and breadth of a certificate chain - maxCertSize = 1 << 20 // max size of a certificate, in bytes + maxCertSize = 1 << 20 // max size of a certificate, in DER bytes + // Used for decoding certs from application/pem-certificate-chain response, + // the default when in RFC mode. + maxCertChainSize = maxCertSize * maxChainLen // Max number of collected nonces kept in memory. // Expect usual peak of 1 or 2. @@ -65,15 +73,15 @@ const ( ) // Client is an ACME client. +// // The only required field is Key. An example of creating a client with a new key // is as follows: // -// key, err := rsa.GenerateKey(rand.Reader, 2048) -// if err != nil { -// log.Fatal(err) -// } -// client := &Client{Key: key} -// +// key, err := rsa.GenerateKey(rand.Reader, 2048) +// if err != nil { +// log.Fatal(err) +// } +// client := &Client{Key: key} type Client struct { // Key is the account key used to register with a CA and sign requests. // Key.Public() must return a *rsa.PublicKey or *ecdsa.PublicKey. @@ -116,21 +124,49 @@ type Client struct { // identifiable by the server, in case they are causing issues. UserAgent string - dirMu sync.Mutex // guards writes to dir - dir *Directory // cached result of Client's Discover method + cacheMu sync.Mutex + dir *Directory // cached result of Client's Discover method + // KID is the key identifier provided by the CA. If not provided it will be + // retrieved from the CA by making a call to the registration endpoint. + KID KeyID noncesMu sync.Mutex nonces map[string]struct{} // nonces collected from previous responses } +// accountKID returns a key ID associated with c.Key, the account identity +// provided by the CA during RFC based registration. +// It assumes c.Discover has already been called. +// +// accountKID requires at most one network roundtrip. +// It caches only successful result. +// +// When in pre-RFC mode or when c.getRegRFC responds with an error, accountKID +// returns noKeyID. +func (c *Client) accountKID(ctx context.Context) KeyID { + c.cacheMu.Lock() + defer c.cacheMu.Unlock() + if c.KID != noKeyID { + return c.KID + } + a, err := c.getRegRFC(ctx) + if err != nil { + return noKeyID + } + c.KID = KeyID(a.URI) + return c.KID +} + +var errPreRFC = errors.New("acme: server does not support the RFC 8555 version of ACME") + // Discover performs ACME server discovery using c.DirectoryURL. // // It caches successful result. So, subsequent calls will not result in // a network round-trip. This also means mutating c.DirectoryURL after successful call // of this method will have no effect. func (c *Client) Discover(ctx context.Context) (Directory, error) { - c.dirMu.Lock() - defer c.dirMu.Unlock() + c.cacheMu.Lock() + defer c.cacheMu.Unlock() if c.dir != nil { return *c.dir, nil } @@ -143,27 +179,36 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) { c.addNonce(res.Header) var v struct { - Reg string `json:"new-reg"` - Authz string `json:"new-authz"` - Cert string `json:"new-cert"` - Revoke string `json:"revoke-cert"` - Meta struct { - Terms string `json:"terms-of-service"` - Website string `json:"website"` - CAA []string `json:"caa-identities"` + Reg string `json:"newAccount"` + Authz string `json:"newAuthz"` + Order string `json:"newOrder"` + Revoke string `json:"revokeCert"` + Nonce string `json:"newNonce"` + KeyChange string `json:"keyChange"` + Meta struct { + Terms string `json:"termsOfService"` + Website string `json:"website"` + CAA []string `json:"caaIdentities"` + ExternalAcct bool `json:"externalAccountRequired"` } } if err := json.NewDecoder(res.Body).Decode(&v); err != nil { return Directory{}, err } + if v.Order == "" { + return Directory{}, errPreRFC + } c.dir = &Directory{ - RegURL: v.Reg, - AuthzURL: v.Authz, - CertURL: v.Cert, - RevokeURL: v.Revoke, - Terms: v.Meta.Terms, - Website: v.Meta.Website, - CAA: v.Meta.CAA, + RegURL: v.Reg, + AuthzURL: v.Authz, + OrderURL: v.Order, + RevokeURL: v.Revoke, + NonceURL: v.Nonce, + KeyChangeURL: v.KeyChange, + Terms: v.Meta.Terms, + Website: v.Meta.Website, + CAA: v.Meta.CAA, + ExternalAccountRequired: v.Meta.ExternalAcct, } return *c.dir, nil } @@ -175,69 +220,28 @@ func (c *Client) directoryURL() string { return LetsEncryptURL } -// CreateCert requests a new certificate using the Certificate Signing Request csr encoded in DER format. -// The exp argument indicates the desired certificate validity duration. CA may issue a certificate -// with a different duration. -// If the bundle argument is true, the returned value will also contain the CA (issuer) certificate chain. +// CreateCert was part of the old version of ACME. It is incompatible with RFC 8555. // -// In the case where CA server does not provide the issued certificate in the response, -// CreateCert will poll certURL using c.FetchCert, which will result in additional round-trips. -// In such a scenario, the caller can cancel the polling with ctx. -// -// CreateCert returns an error if the CA's response or chain was unreasonably large. -// Callers are encouraged to parse the returned value to ensure the certificate is valid and has the expected features. +// Deprecated: this was for the pre-RFC 8555 version of ACME. Callers should use CreateOrderCert. func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, bundle bool) (der [][]byte, certURL string, err error) { - if _, err := c.Discover(ctx); err != nil { - return nil, "", err - } - - req := struct { - Resource string `json:"resource"` - CSR string `json:"csr"` - NotBefore string `json:"notBefore,omitempty"` - NotAfter string `json:"notAfter,omitempty"` - }{ - Resource: "new-cert", - CSR: base64.RawURLEncoding.EncodeToString(csr), - } - now := timeNow() - req.NotBefore = now.Format(time.RFC3339) - if exp > 0 { - req.NotAfter = now.Add(exp).Format(time.RFC3339) - } - - res, err := c.post(ctx, c.Key, c.dir.CertURL, req, wantStatus(http.StatusCreated)) - if err != nil { - return nil, "", err - } - defer res.Body.Close() - - curl := res.Header.Get("Location") // cert permanent URL - if res.ContentLength == 0 { - // no cert in the body; poll until we get it - cert, err := c.FetchCert(ctx, curl, bundle) - return cert, curl, err - } - // slurp issued cert and CA chain, if requested - cert, err := c.responseCert(ctx, res, bundle) - return cert, curl, err + return nil, "", errPreRFC } // FetchCert retrieves already issued certificate from the given url, in DER format. // It retries the request until the certificate is successfully retrieved, // context is cancelled by the caller or an error response is received. // -// The returned value will also contain the CA (issuer) certificate if the bundle argument is true. +// If the bundle argument is true, the returned value also contains the CA (issuer) +// certificate chain. // // FetchCert returns an error if the CA's response or chain was unreasonably large. // Callers are encouraged to parse the returned value to ensure the certificate is valid // and has expected features. func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) { - res, err := c.get(ctx, url, wantStatus(http.StatusOK)) - if err != nil { + if _, err := c.Discover(ctx); err != nil { return nil, err } - return c.responseCert(ctx, res, bundle) + return c.fetchCertRFC(ctx, url, bundle) } // RevokeCert revokes a previously issued certificate cert, provided in DER format. @@ -250,88 +254,87 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, if _, err := c.Discover(ctx); err != nil { return err } - - body := &struct { - Resource string `json:"resource"` - Cert string `json:"certificate"` - Reason int `json:"reason"` - }{ - Resource: "revoke-cert", - Cert: base64.RawURLEncoding.EncodeToString(cert), - Reason: int(reason), - } - if key == nil { - key = c.Key - } - res, err := c.post(ctx, key, c.dir.RevokeURL, body, wantStatus(http.StatusOK)) - if err != nil { - return err - } - defer res.Body.Close() - return nil + return c.revokeCertRFC(ctx, key, cert, reason) } // AcceptTOS always returns true to indicate the acceptance of a CA's Terms of Service // during account registration. See Register method of Client for more details. func AcceptTOS(tosURL string) bool { return true } -// Register creates a new account registration by following the "new-reg" flow. -// It returns the registered account. The account is not modified. +// Register creates a new account with the CA using c.Key. +// It returns the registered account. The account acct is not modified. // // The registration may require the caller to agree to the CA's Terms of Service (TOS). // If so, and the account has not indicated the acceptance of the terms (see Account for details), // Register calls prompt with a TOS URL provided by the CA. Prompt should report // whether the caller agrees to the terms. To always accept the terms, the caller can use AcceptTOS. -func (c *Client) Register(ctx context.Context, a *Account, prompt func(tosURL string) bool) (*Account, error) { - if _, err := c.Discover(ctx); err != nil { - return nil, err +// +// When interfacing with an RFC-compliant CA, non-RFC 8555 fields of acct are ignored +// and prompt is called if Directory's Terms field is non-zero. +// Also see Error's Instance field for when a CA requires already registered accounts to agree +// to an updated Terms of Service. +func (c *Client) Register(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) { + if c.Key == nil { + return nil, errors.New("acme: client.Key must be set to Register") } - - var err error - if a, err = c.doReg(ctx, c.dir.RegURL, "new-reg", a); err != nil { + if _, err := c.Discover(ctx); err != nil { return nil, err } - var accept bool - if a.CurrentTerms != "" && a.CurrentTerms != a.AgreedTerms { - accept = prompt(a.CurrentTerms) - } - if accept { - a.AgreedTerms = a.CurrentTerms - a, err = c.UpdateReg(ctx, a) - } - return a, err + return c.registerRFC(ctx, acct, prompt) } -// GetReg retrieves an existing registration. -// The url argument is an Account URI. +// GetReg retrieves an existing account associated with c.Key. +// +// The url argument is a legacy artifact of the pre-RFC 8555 API +// and is ignored. func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) { - a, err := c.doReg(ctx, url, "reg", nil) - if err != nil { + if _, err := c.Discover(ctx); err != nil { return nil, err } - a.URI = url - return a, nil + return c.getRegRFC(ctx) } // UpdateReg updates an existing registration. // It returns an updated account copy. The provided account is not modified. -func (c *Client) UpdateReg(ctx context.Context, a *Account) (*Account, error) { - uri := a.URI - a, err := c.doReg(ctx, uri, "reg", a) - if err != nil { +// +// The account's URI is ignored and the account URL associated with +// c.Key is used instead. +func (c *Client) UpdateReg(ctx context.Context, acct *Account) (*Account, error) { + if _, err := c.Discover(ctx); err != nil { return nil, err } - a.URI = uri - return a, nil + return c.updateRegRFC(ctx, acct) } -// Authorize performs the initial step in an authorization flow. +// AccountKeyRollover attempts to transition a client's account key to a new key. +// On success client's Key is updated which is not concurrency safe. +// On failure an error will be returned. +// The new key is already registered with the ACME provider if the following is true: +// - error is of type acme.Error +// - StatusCode should be 409 (Conflict) +// - Location header will have the KID of the associated account +// +// More about account key rollover can be found at +// https://tools.ietf.org/html/rfc8555#section-7.3.5. +func (c *Client) AccountKeyRollover(ctx context.Context, newKey crypto.Signer) error { + return c.accountKeyRollover(ctx, newKey) +} + +// Authorize performs the initial step in the pre-authorization flow, +// as opposed to order-based flow. // The caller will then need to choose from and perform a set of returned // challenges using c.Accept in order to successfully complete authorization. // +// Once complete, the caller can use AuthorizeOrder which the CA +// should provision with the already satisfied authorization. +// For pre-RFC CAs, the caller can proceed directly to requesting a certificate +// using CreateCert method. +// // If an authorization has been previously granted, the CA may return -// a valid authorization (Authorization.Status is StatusValid). If so, the caller -// need not fulfill any challenge and can proceed to requesting a certificate. +// a valid authorization which has its Status field set to StatusValid. +// +// More about pre-authorization can be found at +// https://tools.ietf.org/html/rfc8555#section-7.4.1. func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error) { return c.authorize(ctx, "dns", domain) } @@ -362,7 +365,7 @@ func (c *Client) authorize(ctx context.Context, typ, val string) (*Authorization Resource: "new-authz", Identifier: authzID{Type: typ, Value: val}, } - res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated)) + res, err := c.post(ctx, nil, c.dir.AuthzURL, req, wantStatus(http.StatusCreated)) if err != nil { return nil, err } @@ -383,7 +386,11 @@ func (c *Client) authorize(ctx context.Context, typ, val string) (*Authorization // If a caller needs to poll an authorization until its status is final, // see the WaitAuthorization method. func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) { - res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) + if _, err := c.Discover(ctx); err != nil { + return nil, err + } + + res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK)) if err != nil { return nil, err } @@ -400,11 +407,15 @@ func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorizati // The url argument is an Authorization.URI value. // // If successful, the caller will be required to obtain a new authorization -// using the Authorize method before being able to request a new certificate -// for the domain associated with the authorization. +// using the Authorize or AuthorizeOrder methods before being able to request +// a new certificate for the domain associated with the authorization. // // It does not revoke existing certificates. func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { + if _, err := c.Discover(ctx); err != nil { + return err + } + req := struct { Resource string `json:"resource"` Status string `json:"status"` @@ -414,7 +425,7 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { Status: "deactivated", Delete: true, } - res, err := c.post(ctx, c.Key, url, req, wantStatus(http.StatusOK)) + res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK)) if err != nil { return err } @@ -430,8 +441,11 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { // In all other cases WaitAuthorization returns an error. // If the Status is StatusInvalid, the returned error is of type *AuthorizationError. func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) { + if _, err := c.Discover(ctx); err != nil { + return nil, err + } for { - res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) + res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) if err != nil { return nil, err } @@ -474,10 +488,15 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat // // A client typically polls a challenge status using this method. func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) { - res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) + if _, err := c.Discover(ctx); err != nil { + return nil, err + } + + res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) if err != nil { return nil, err } + defer res.Body.Close() v := wireChallenge{URI: url} if err := json.NewDecoder(res.Body).Decode(&v); err != nil { @@ -491,21 +510,11 @@ func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, erro // // The server will then perform the validation asynchronously. func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error) { - auth, err := keyAuth(c.Key.Public(), chal.Token) - if err != nil { + if _, err := c.Discover(ctx); err != nil { return nil, err } - req := struct { - Resource string `json:"resource"` - Type string `json:"type"` - Auth string `json:"keyAuthorization"` - }{ - Resource: "challenge", - Type: chal.Type, - Auth: auth, - } - res, err := c.post(ctx, c.Key, chal.URI, req, wantStatus( + res, err := c.post(ctx, nil, chal.URI, json.RawMessage("{}"), wantStatus( http.StatusOK, // according to the spec http.StatusAccepted, // Let's Encrypt: see https://goo.gl/WsJ7VT (acme-divergences.md) )) @@ -555,21 +564,8 @@ func (c *Client) HTTP01ChallengePath(token string) string { } // TLSSNI01ChallengeCert creates a certificate for TLS-SNI-01 challenge response. -// Servers can present the certificate to validate the challenge and prove control -// over a domain name. -// -// The implementation is incomplete in that the returned value is a single certificate, -// computed only for Z0 of the key authorization. ACME CAs are expected to update -// their implementations to use the newer version, TLS-SNI-02. -// For more details on TLS-SNI-01 see https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-7.3. // -// The token argument is a Challenge.Token value. -// If a WithKey option is provided, its private part signs the returned cert, -// and the public part is used to specify the signee. -// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve. -// -// The returned certificate is valid for the next 24 hours and must be presented only when -// the server name of the TLS ClientHello matches exactly the returned name value. +// Deprecated: This challenge type is unused in both draft-02 and RFC versions of the ACME spec. func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) { ka, err := keyAuth(c.Key.Public(), token) if err != nil { @@ -586,17 +582,8 @@ func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tl } // TLSSNI02ChallengeCert creates a certificate for TLS-SNI-02 challenge response. -// Servers can present the certificate to validate the challenge and prove control -// over a domain name. For more details on TLS-SNI-02 see -// https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-7.3. // -// The token argument is a Challenge.Token value. -// If a WithKey option is provided, its private part signs the returned cert, -// and the public part is used to specify the signee. -// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve. -// -// The returned certificate is valid for the next 24 hours and must be presented only when -// the server name in the TLS ClientHello matches exactly the returned name value. +// Deprecated: This challenge type is unused in both draft-02 and RFC versions of the ACME spec. func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) { b := sha256.Sum256([]byte(token)) h := hex.EncodeToString(b[:]) @@ -641,7 +628,7 @@ func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption) return tls.Certificate{}, err } acmeExtension := pkix.Extension{ - Id: idPeACMEIdentifierV1, + Id: idPeACMEIdentifier, Critical: true, Value: extValue, } @@ -663,70 +650,17 @@ func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption) return tlsChallengeCert([]string{domain}, newOpt) } -// doReg sends all types of registration requests. -// The type of request is identified by typ argument, which is a "resource" -// in the ACME spec terms. -// -// A non-nil acct argument indicates whether the intention is to mutate data -// of the Account. Only Contact and Agreement of its fields are used -// in such cases. -func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Account) (*Account, error) { - req := struct { - Resource string `json:"resource"` - Contact []string `json:"contact,omitempty"` - Agreement string `json:"agreement,omitempty"` - }{ - Resource: typ, - } - if acct != nil { - req.Contact = acct.Contact - req.Agreement = acct.AgreedTerms - } - res, err := c.post(ctx, c.Key, url, req, wantStatus( - http.StatusOK, // updates and deletes - http.StatusCreated, // new account creation - http.StatusAccepted, // Let's Encrypt divergent implementation - )) - if err != nil { - return nil, err - } - defer res.Body.Close() - - var v struct { - Contact []string - Agreement string - Authorizations string - Certificates string - } - if err := json.NewDecoder(res.Body).Decode(&v); err != nil { - return nil, fmt.Errorf("acme: invalid response: %v", err) - } - var tos string - if v := linkHeader(res.Header, "terms-of-service"); len(v) > 0 { - tos = v[0] - } - var authz string - if v := linkHeader(res.Header, "next"); len(v) > 0 { - authz = v[0] - } - return &Account{ - URI: res.Header.Get("Location"), - Contact: v.Contact, - AgreedTerms: v.Agreement, - CurrentTerms: tos, - Authz: authz, - Authorizations: v.Authorizations, - Certificates: v.Certificates, - }, nil -} - // popNonce returns a nonce value previously stored with c.addNonce -// or fetches a fresh one from a URL by issuing a HEAD request. -// It first tries c.directoryURL() and then the provided url if the former fails. +// or fetches a fresh one from c.dir.NonceURL. +// If NonceURL is empty, it first tries c.directoryURL() and, failing that, +// the provided url. func (c *Client) popNonce(ctx context.Context, url string) (string, error) { c.noncesMu.Lock() defer c.noncesMu.Unlock() if len(c.nonces) == 0 { + if c.dir != nil && c.dir.NonceURL != "" { + return c.fetchNonce(ctx, c.dir.NonceURL) + } dirURL := c.directoryURL() v, err := c.fetchNonce(ctx, dirURL) if err != nil && url != dirURL { @@ -790,78 +724,6 @@ func nonceFromHeader(h http.Header) string { return h.Get("Replay-Nonce") } -func (c *Client) responseCert(ctx context.Context, res *http.Response, bundle bool) ([][]byte, error) { - b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1)) - if err != nil { - return nil, fmt.Errorf("acme: response stream: %v", err) - } - if len(b) > maxCertSize { - return nil, errors.New("acme: certificate is too big") - } - cert := [][]byte{b} - if !bundle { - return cert, nil - } - - // Append CA chain cert(s). - // At least one is required according to the spec: - // https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.3.1 - up := linkHeader(res.Header, "up") - if len(up) == 0 { - return nil, errors.New("acme: rel=up link not found") - } - if len(up) > maxChainLen { - return nil, errors.New("acme: rel=up link is too large") - } - for _, url := range up { - cc, err := c.chainCert(ctx, url, 0) - if err != nil { - return nil, err - } - cert = append(cert, cc...) - } - return cert, nil -} - -// chainCert fetches CA certificate chain recursively by following "up" links. -// Each recursive call increments the depth by 1, resulting in an error -// if the recursion level reaches maxChainLen. -// -// First chainCert call starts with depth of 0. -func (c *Client) chainCert(ctx context.Context, url string, depth int) ([][]byte, error) { - if depth >= maxChainLen { - return nil, errors.New("acme: certificate chain is too deep") - } - - res, err := c.get(ctx, url, wantStatus(http.StatusOK)) - if err != nil { - return nil, err - } - defer res.Body.Close() - b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1)) - if err != nil { - return nil, err - } - if len(b) > maxCertSize { - return nil, errors.New("acme: certificate is too big") - } - chain := [][]byte{b} - - uplink := linkHeader(res.Header, "up") - if len(uplink) > maxChainLen { - return nil, errors.New("acme: certificate chain is too large") - } - for _, up := range uplink { - cc, err := c.chainCert(ctx, up, depth+1) - if err != nil { - return nil, err - } - chain = append(chain, cc...) - } - - return chain, nil -} - // linkHeader returns URI-Reference values of all Link headers // with relation-type rel. // See https://tools.ietf.org/html/rfc5988#section-5 for details. @@ -952,5 +814,5 @@ func encodePEM(typ string, b []byte) []byte { return pem.EncodeToMemory(pb) } -// timeNow is useful for testing for fixed current time. +// timeNow is time.Now, except in tests which can mess with it. var timeNow = time.Now diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert.go b/vendor/golang.org/x/crypto/acme/autocert/autocert.go index 70ab355..0061c28 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/autocert.go +++ b/vendor/golang.org/x/crypto/acme/autocert/autocert.go @@ -35,6 +35,9 @@ import ( "golang.org/x/net/idna" ) +// DefaultACMEDirectory is the default ACME Directory URL used when the Manager's Client is nil. +const DefaultACMEDirectory = "https://acme-v02.api.letsencrypt.org/directory" + // createCertRetryAfter is how much time to wait before removing a failed state // entry due to an unsuccessful createCert call. // This is a variable instead of a const for testing. @@ -44,6 +47,8 @@ var createCertRetryAfter = time.Minute // pseudoRand is safe for concurrent use. var pseudoRand *lockedMathRand +var errPreRFC = errors.New("autocert: ACME server doesn't support RFC 8555") + func init() { src := mathrand.NewSource(time.Now().UnixNano()) pseudoRand = &lockedMathRand{rnd: mathrand.New(src)} @@ -88,9 +93,9 @@ func defaultHostPolicy(context.Context, string) error { } // Manager is a stateful certificate manager built on top of acme.Client. -// It obtains and refreshes certificates automatically using "tls-alpn-01", -// "tls-sni-01", "tls-sni-02" and "http-01" challenge types, -// as well as providing them to a TLS server via tls.Config. +// It obtains and refreshes certificates automatically using "tls-alpn-01" +// or "http-01" challenge types, as well as providing them to a TLS server +// via tls.Config. // // You must specify a cache implementation, such as DirCache, // to reuse obtained certificates across program restarts. @@ -135,9 +140,10 @@ type Manager struct { // Client is used to perform low-level operations, such as account registration // and requesting new certificates. // - // If Client is nil, a zero-value acme.Client is used with acme.LetsEncryptURL - // as directory endpoint. If the Client.Key is nil, a new ECDSA P-256 key is - // generated and, if Cache is not nil, stored in cache. + // If Client is nil, a zero-value acme.Client is used with DefaultACMEDirectory + // as the directory endpoint. + // If the Client.Key is nil, a new ECDSA P-256 key is generated and, + // if Cache is not nil, stored in cache. // // Mutating the field after the first call of GetCertificate method will have no effect. Client *acme.Client @@ -164,6 +170,11 @@ type Manager struct { // in the template's ExtraExtensions field as is. ExtraExtensions []pkix.Extension + // ExternalAccountBinding optionally represents an arbitrary binding to an + // account of the CA to which the ACME server is tied. + // See RFC 8555, Section 7.3.4 for more details. + ExternalAccountBinding *acme.ExternalAccountBinding + clientMu sync.Mutex client *acme.Client // initialized by acmeClient method @@ -174,8 +185,8 @@ type Manager struct { renewalMu sync.Mutex renewal map[certKey]*domainRenewal - // tokensMu guards the rest of the fields: tryHTTP01, certTokens and httpTokens. - tokensMu sync.RWMutex + // challengeMu guards tryHTTP01, certTokens and httpTokens. + challengeMu sync.RWMutex // tryHTTP01 indicates whether the Manager should try "http-01" challenge type // during the authorization flow. tryHTTP01 bool @@ -184,12 +195,11 @@ type Manager struct { // to be provisioned. // The entries are stored for the duration of the authorization flow. httpTokens map[string][]byte - // certTokens contains temporary certificates for tls-sni and tls-alpn challenges - // and is keyed by token domain name, which matches server name of ClientHello. - // Keys always have ".acme.invalid" suffix for tls-sni. Otherwise, they are domain names - // for tls-alpn. + // certTokens contains temporary certificates for tls-alpn-01 challenges + // and is keyed by the domain name which matches the ClientHello server name. // The entries are stored for the duration of the authorization flow. certTokens map[string]*tls.Certificate + // nowFunc, if not nil, returns the current time. This may be set for // testing purposes. nowFunc func() time.Time @@ -226,7 +236,7 @@ func (m *Manager) TLSConfig() *tls.Config { // GetCertificate implements the tls.Config.GetCertificate hook. // It provides a TLS certificate for hello.ServerName host, including answering -// tls-alpn-01 and *.acme.invalid (tls-sni-01 and tls-sni-02) challenges. +// tls-alpn-01 challenges. // All other fields of hello are ignored. // // If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting @@ -235,9 +245,7 @@ func (m *Manager) TLSConfig() *tls.Config { // This does not affect cached certs. See HostPolicy field description for more details. // // If GetCertificate is used directly, instead of via Manager.TLSConfig, package users will -// also have to add acme.ALPNProto to NextProtos for tls-alpn-01, or use HTTPHandler -// for http-01. (The tls-sni-* challenges have been deprecated by popular ACME providers -// due to security issues in the ecosystem.) +// also have to add acme.ALPNProto to NextProtos for tls-alpn-01, or use HTTPHandler for http-01. func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { if m.Prompt == nil { return nil, errors.New("acme/autocert: Manager.Prompt not set") @@ -269,13 +277,10 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() - // Check whether this is a token cert requested for TLS-SNI or TLS-ALPN challenge. + // Check whether this is a token cert requested for TLS-ALPN challenge. if wantsTokenCert(hello) { - m.tokensMu.RLock() - defer m.tokensMu.RUnlock() - // It's ok to use the same token cert key for both tls-sni and tls-alpn - // because there's always at most 1 token cert per on-going domain authorization. - // See m.verify for details. + m.challengeMu.RLock() + defer m.challengeMu.RUnlock() if cert := m.certTokens[name]; cert != nil { return cert, nil } @@ -318,8 +323,7 @@ func wantsTokenCert(hello *tls.ClientHelloInfo) bool { if len(hello.SupportedProtos) == 1 && hello.SupportedProtos[0] == acme.ALPNProto { return true } - // tls-sni-xx - return strings.HasSuffix(hello.ServerName, ".acme.invalid") + return false } func supportsECDSA(hello *tls.ClientHelloInfo) bool { @@ -384,8 +388,8 @@ func supportsECDSA(hello *tls.ClientHelloInfo) bool { // If HTTPHandler is never called, the Manager will only use the "tls-alpn-01" // challenge for domain verification. func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler { - m.tokensMu.Lock() - defer m.tokensMu.Unlock() + m.challengeMu.Lock() + defer m.challengeMu.Unlock() m.tryHTTP01 = true if fallback == nil { @@ -459,7 +463,7 @@ func (m *Manager) cert(ctx context.Context, ck certKey) (*tls.Certificate, error leaf: cert.Leaf, } m.state[ck] = s - go m.renew(ck, s.key, s.leaf.NotAfter) + go m.startRenew(ck, s.key, s.leaf.NotAfter) return cert, nil } @@ -585,8 +589,9 @@ func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate, if err != nil { // Remove the failed state after some time, // making the manager call createCert again on the following TLS hello. + didRemove := testDidRemoveState // The lifetime of this timer is untracked, so copy mutable local state to avoid races. time.AfterFunc(createCertRetryAfter, func() { - defer testDidRemoveState(ck) + defer didRemove(ck) m.stateMu.Lock() defer m.stateMu.Unlock() // Verify the state hasn't changed and it's still invalid @@ -604,7 +609,7 @@ func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate, } state.cert = der state.leaf = leaf - go m.renew(ck, state.key, state.leaf.NotAfter) + go m.startRenew(ck, state.key, state.leaf.NotAfter) return state.tlscert() } @@ -648,120 +653,152 @@ func (m *Manager) certState(ck certKey) (*certState, error) { // authorizedCert starts the domain ownership verification process and requests a new cert upon success. // The key argument is the certificate private key. func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, ck certKey) (der [][]byte, leaf *x509.Certificate, err error) { - client, err := m.acmeClient(ctx) + csr, err := certRequest(key, ck.domain, m.ExtraExtensions) if err != nil { return nil, nil, err } - if err := m.verify(ctx, client, ck.domain); err != nil { + client, err := m.acmeClient(ctx) + if err != nil { return nil, nil, err } - csr, err := certRequest(key, ck.domain, m.ExtraExtensions) + dir, err := client.Discover(ctx) if err != nil { return nil, nil, err } - der, _, err = client.CreateCert(ctx, csr, 0, true) + if dir.OrderURL == "" { + return nil, nil, errPreRFC + } + + o, err := m.verifyRFC(ctx, client, ck.domain) if err != nil { return nil, nil, err } - leaf, err = validCert(ck, der, key, m.now()) + chain, _, err := client.CreateOrderCert(ctx, o.FinalizeURL, csr, true) if err != nil { return nil, nil, err } - return der, leaf, nil -} -// revokePendingAuthz revokes all authorizations idenfied by the elements of uri slice. -// It ignores revocation errors. -func (m *Manager) revokePendingAuthz(ctx context.Context, uri []string) { - client, err := m.acmeClient(ctx) + leaf, err = validCert(ck, chain, key, m.now()) if err != nil { - return - } - for _, u := range uri { - client.RevokeAuthorization(ctx, u) + return nil, nil, err } + return chain, leaf, nil } -// verify runs the identifier (domain) authorization flow +// verifyRFC runs the identifier (domain) order-based authorization flow for RFC compliant CAs // using each applicable ACME challenge type. -func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error { - // The list of challenge types we'll try to fulfill - // in this specific order. - challengeTypes := []string{"tls-alpn-01", "tls-sni-02", "tls-sni-01"} - m.tokensMu.RLock() - if m.tryHTTP01 { - challengeTypes = append(challengeTypes, "http-01") - } - m.tokensMu.RUnlock() - - // Keep track of pending authzs and revoke the ones that did not validate. - pendingAuthzs := make(map[string]bool) - defer func() { - var uri []string - for k, pending := range pendingAuthzs { - if pending { - uri = append(uri, k) - } - } - if len(uri) > 0 { - // Use "detached" background context. - // The revocations need not happen in the current verification flow. - go m.revokePendingAuthz(context.Background(), uri) - } - }() - - // errs accumulates challenge failure errors, printed if all fail - errs := make(map[*acme.Challenge]error) - var nextTyp int // challengeType index of the next challenge type to try +func (m *Manager) verifyRFC(ctx context.Context, client *acme.Client, domain string) (*acme.Order, error) { + // Try each supported challenge type starting with a new order each time. + // The nextTyp index of the next challenge type to try is shared across + // all order authorizations: if we've tried a challenge type once and it didn't work, + // it will most likely not work on another order's authorization either. + challengeTypes := m.supportedChallengeTypes() + nextTyp := 0 // challengeTypes index +AuthorizeOrderLoop: for { - // Start domain authorization and get the challenge. - authz, err := client.Authorize(ctx, domain) + o, err := client.AuthorizeOrder(ctx, acme.DomainIDs(domain)) if err != nil { - return err + return nil, err } - // No point in accepting challenges if the authorization status - // is in a final state. - switch authz.Status { - case acme.StatusValid: - return nil // already authorized - case acme.StatusInvalid: - return fmt.Errorf("acme/autocert: invalid authorization %q", authz.URI) + // Remove all hanging authorizations to reduce rate limit quotas + // after we're done. + defer func(urls []string) { + go m.deactivatePendingAuthz(urls) + }(o.AuthzURLs) + + // Check if there's actually anything we need to do. + switch o.Status { + case acme.StatusReady: + // Already authorized. + return o, nil + case acme.StatusPending: + // Continue normal Order-based flow. + default: + return nil, fmt.Errorf("acme/autocert: invalid new order status %q; order URL: %q", o.Status, o.URI) } - pendingAuthzs[authz.URI] = true - - // Pick the next preferred challenge. - var chal *acme.Challenge - for chal == nil && nextTyp < len(challengeTypes) { - chal = pickChallenge(challengeTypes[nextTyp], authz.Challenges) - nextTyp++ - } - if chal == nil { - errorMsg := fmt.Sprintf("acme/autocert: unable to authorize %q", domain) - for chal, err := range errs { - errorMsg += fmt.Sprintf("; challenge %q failed with error: %v", chal.Type, err) + // Satisfy all pending authorizations. + for _, zurl := range o.AuthzURLs { + z, err := client.GetAuthorization(ctx, zurl) + if err != nil { + return nil, err + } + if z.Status != acme.StatusPending { + // We are interested only in pending authorizations. + continue + } + // Pick the next preferred challenge. + var chal *acme.Challenge + for chal == nil && nextTyp < len(challengeTypes) { + chal = pickChallenge(challengeTypes[nextTyp], z.Challenges) + nextTyp++ + } + if chal == nil { + return nil, fmt.Errorf("acme/autocert: unable to satisfy %q for domain %q: no viable challenge type found", z.URI, domain) + } + // Respond to the challenge and wait for validation result. + cleanup, err := m.fulfill(ctx, client, chal, domain) + if err != nil { + continue AuthorizeOrderLoop + } + defer cleanup() + if _, err := client.Accept(ctx, chal); err != nil { + continue AuthorizeOrderLoop + } + if _, err := client.WaitAuthorization(ctx, z.URI); err != nil { + continue AuthorizeOrderLoop } - return errors.New(errorMsg) } - cleanup, err := m.fulfill(ctx, client, chal, domain) + + // All authorizations are satisfied. + // Wait for the CA to update the order status. + o, err = client.WaitOrder(ctx, o.URI) if err != nil { - errs[chal] = err - continue + continue AuthorizeOrderLoop } - defer cleanup() - if _, err := client.Accept(ctx, chal); err != nil { - errs[chal] = err - continue + return o, nil + } +} + +func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge { + for _, c := range chal { + if c.Type == typ { + return c } + } + return nil +} - // A challenge is fulfilled and accepted: wait for the CA to validate. - if _, err := client.WaitAuthorization(ctx, authz.URI); err != nil { - errs[chal] = err - continue +func (m *Manager) supportedChallengeTypes() []string { + m.challengeMu.RLock() + defer m.challengeMu.RUnlock() + typ := []string{"tls-alpn-01"} + if m.tryHTTP01 { + typ = append(typ, "http-01") + } + return typ +} + +// deactivatePendingAuthz relinquishes all authorizations identified by the elements +// of the provided uri slice which are in "pending" state. +// It ignores revocation errors. +// +// deactivatePendingAuthz takes no context argument and instead runs with its own +// "detached" context because deactivations are done in a goroutine separate from +// that of the main issuance or renewal flow. +func (m *Manager) deactivatePendingAuthz(uri []string) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + client, err := m.acmeClient(ctx) + if err != nil { + return + } + for _, u := range uri { + z, err := client.GetAuthorization(ctx, u) + if err == nil && z.Status == acme.StatusPending { + client.RevokeAuthorization(ctx, u) } - delete(pendingAuthzs, authz.URI) - return nil } } @@ -776,20 +813,6 @@ func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.C } m.putCertToken(ctx, domain, &cert) return func() { go m.deleteCertToken(domain) }, nil - case "tls-sni-01": - cert, name, err := client.TLSSNI01ChallengeCert(chal.Token) - if err != nil { - return nil, err - } - m.putCertToken(ctx, name, &cert) - return func() { go m.deleteCertToken(name) }, nil - case "tls-sni-02": - cert, name, err := client.TLSSNI02ChallengeCert(chal.Token) - if err != nil { - return nil, err - } - m.putCertToken(ctx, name, &cert) - return func() { go m.deleteCertToken(name) }, nil case "http-01": resp, err := client.HTTP01ChallengeResponse(chal.Token) if err != nil { @@ -802,20 +825,11 @@ func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.C return nil, fmt.Errorf("acme/autocert: unknown challenge type %q", chal.Type) } -func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge { - for _, c := range chal { - if c.Type == typ { - return c - } - } - return nil -} - // putCertToken stores the token certificate with the specified name // in both m.certTokens map and m.Cache. func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certificate) { - m.tokensMu.Lock() - defer m.tokensMu.Unlock() + m.challengeMu.Lock() + defer m.challengeMu.Unlock() if m.certTokens == nil { m.certTokens = make(map[string]*tls.Certificate) } @@ -826,8 +840,8 @@ func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certi // deleteCertToken removes the token certificate with the specified name // from both m.certTokens map and m.Cache. func (m *Manager) deleteCertToken(name string) { - m.tokensMu.Lock() - defer m.tokensMu.Unlock() + m.challengeMu.Lock() + defer m.challengeMu.Unlock() delete(m.certTokens, name) if m.Cache != nil { ck := certKey{domain: name, isToken: true} @@ -838,8 +852,8 @@ func (m *Manager) deleteCertToken(name string) { // httpToken retrieves an existing http-01 token value from an in-memory map // or the optional cache. func (m *Manager) httpToken(ctx context.Context, tokenPath string) ([]byte, error) { - m.tokensMu.RLock() - defer m.tokensMu.RUnlock() + m.challengeMu.RLock() + defer m.challengeMu.RUnlock() if v, ok := m.httpTokens[tokenPath]; ok { return v, nil } @@ -854,8 +868,8 @@ func (m *Manager) httpToken(ctx context.Context, tokenPath string) ([]byte, erro // // It ignores any error returned from Cache.Put. func (m *Manager) putHTTPToken(ctx context.Context, tokenPath, val string) { - m.tokensMu.Lock() - defer m.tokensMu.Unlock() + m.challengeMu.Lock() + defer m.challengeMu.Unlock() if m.httpTokens == nil { m.httpTokens = make(map[string][]byte) } @@ -871,8 +885,8 @@ func (m *Manager) putHTTPToken(ctx context.Context, tokenPath, val string) { // // If m.Cache is non-nil, it blocks until Cache.Delete returns without a timeout. func (m *Manager) deleteHTTPToken(tokenPath string) { - m.tokensMu.Lock() - defer m.tokensMu.Unlock() + m.challengeMu.Lock() + defer m.challengeMu.Unlock() delete(m.httpTokens, tokenPath) if m.Cache != nil { m.Cache.Delete(context.Background(), httpTokenCacheKey(tokenPath)) @@ -885,7 +899,7 @@ func httpTokenCacheKey(tokenPath string) string { return path.Base(tokenPath) + "+http-01" } -// renew starts a cert renewal timer loop, one per domain. +// startRenew starts a cert renewal timer loop, one per domain. // // The loop is scheduled in two cases: // - a cert was fetched from cache for the first time (wasn't in m.state) @@ -893,7 +907,7 @@ func httpTokenCacheKey(tokenPath string) string { // // The key argument is a certificate private key. // The exp argument is the cert expiration time (NotAfter). -func (m *Manager) renew(ck certKey, key crypto.Signer, exp time.Time) { +func (m *Manager) startRenew(ck certKey, key crypto.Signer, exp time.Time) { m.renewalMu.Lock() defer m.renewalMu.Unlock() if m.renewal[ck] != nil { @@ -971,7 +985,7 @@ func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) { client := m.Client if client == nil { - client = &acme.Client{DirectoryURL: acme.LetsEncryptURL} + client = &acme.Client{DirectoryURL: DefaultACMEDirectory} } if client.Key == nil { var err error @@ -987,16 +1001,25 @@ func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) { if m.Email != "" { contact = []string{"mailto:" + m.Email} } - a := &acme.Account{Contact: contact} + a := &acme.Account{Contact: contact, ExternalAccountBinding: m.ExternalAccountBinding} _, err := client.Register(ctx, a, m.Prompt) - if ae, ok := err.(*acme.Error); err == nil || ok && ae.StatusCode == http.StatusConflict { - // conflict indicates the key is already registered + if err == nil || isAccountAlreadyExist(err) { m.client = client err = nil } return m.client, err } +// isAccountAlreadyExist reports whether the err, as returned from acme.Client.Register, +// indicates the account has already been registered. +func isAccountAlreadyExist(err error) bool { + if err == acme.ErrAccountAlreadyExists { + return true + } + ae, ok := err.(*acme.Error) + return ok && ae.StatusCode == http.StatusConflict +} + func (m *Manager) hostPolicy() HostPolicy { if m.HostPolicy != nil { return m.HostPolicy @@ -1043,11 +1066,11 @@ func (s *certState) tlscert() (*tls.Certificate, error) { }, nil } -// certRequest generates a CSR for the given common name cn and optional SANs. -func certRequest(key crypto.Signer, cn string, ext []pkix.Extension, san ...string) ([]byte, error) { +// certRequest generates a CSR for the given common name. +func certRequest(key crypto.Signer, name string, ext []pkix.Extension) ([]byte, error) { req := &x509.CertificateRequest{ - Subject: pkix.Name{CommonName: cn}, - DNSNames: san, + Subject: pkix.Name{CommonName: name}, + DNSNames: []string{name}, ExtraExtensions: ext, } return x509.CreateCertificateRequest(rand.Reader, req, key) @@ -1110,6 +1133,10 @@ func validCert(ck certKey, der [][]byte, key crypto.Signer, now time.Time) (leaf if err := leaf.VerifyHostname(ck.domain); err != nil { return nil, err } + // renew certificates revoked by Let's Encrypt in January 2022 + if isRevokedLetsEncrypt(leaf) { + return nil, errors.New("acme/autocert: certificate was probably revoked by Let's Encrypt") + } // ensure the leaf corresponds to the private key and matches the certKey type switch pub := leaf.PublicKey.(type) { case *rsa.PublicKey: @@ -1140,6 +1167,18 @@ func validCert(ck certKey, der [][]byte, key crypto.Signer, now time.Time) (leaf return leaf, nil } +// https://community.letsencrypt.org/t/2022-01-25-issue-with-tls-alpn-01-validation-method/170450 +var letsEncryptFixDeployTime = time.Date(2022, time.January, 26, 00, 48, 0, 0, time.UTC) + +// isRevokedLetsEncrypt returns whether the certificate is likely to be part of +// a batch of certificates revoked by Let's Encrypt in January 2022. This check +// can be safely removed from May 2022. +func isRevokedLetsEncrypt(cert *x509.Certificate) bool { + O := cert.Issuer.Organization + return len(O) == 1 && O[0] == "Let's Encrypt" && + cert.NotBefore.Before(letsEncryptFixDeployTime) +} + type lockedMathRand struct { sync.Mutex rnd *mathrand.Rand diff --git a/vendor/golang.org/x/crypto/acme/autocert/cache.go b/vendor/golang.org/x/crypto/acme/autocert/cache.go index aa9aa84..3156a08 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/cache.go +++ b/vendor/golang.org/x/crypto/acme/autocert/cache.go @@ -41,7 +41,7 @@ type DirCache string // Get reads a certificate data from the specified file name. func (d DirCache) Get(ctx context.Context, name string) ([]byte, error) { - name = filepath.Join(string(d), name) + name = filepath.Join(string(d), filepath.Clean("/"+name)) var ( data []byte err error @@ -77,11 +77,12 @@ func (d DirCache) Put(ctx context.Context, name string, data []byte) error { if tmp, err = d.writeTempFile(name, data); err != nil { return } + defer os.Remove(tmp) select { case <-ctx.Done(): // Don't overwrite the file if the context was canceled. default: - newName := filepath.Join(string(d), name) + newName := filepath.Join(string(d), filepath.Clean("/"+name)) err = os.Rename(tmp, newName) } }() @@ -95,7 +96,7 @@ func (d DirCache) Put(ctx context.Context, name string, data []byte) error { // Delete removes the specified file name. func (d DirCache) Delete(ctx context.Context, name string) error { - name = filepath.Join(string(d), name) + name = filepath.Join(string(d), filepath.Clean("/"+name)) var ( err error done = make(chan struct{}) @@ -116,12 +117,17 @@ func (d DirCache) Delete(ctx context.Context, name string) error { } // writeTempFile writes b to a temporary file, closes the file and returns its path. -func (d DirCache) writeTempFile(prefix string, b []byte) (string, error) { +func (d DirCache) writeTempFile(prefix string, b []byte) (name string, reterr error) { // TempFile uses 0600 permissions f, err := ioutil.TempFile(string(d), prefix) if err != nil { return "", err } + defer func() { + if reterr != nil { + os.Remove(f.Name()) + } + }() if _, err := f.Write(b); err != nil { f.Close() return "", err diff --git a/vendor/golang.org/x/crypto/acme/autocert/listener.go b/vendor/golang.org/x/crypto/acme/autocert/listener.go index 1e06981..9d62f8c 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/listener.go +++ b/vendor/golang.org/x/crypto/acme/autocert/listener.go @@ -20,7 +20,7 @@ import ( // // It enables one-line HTTPS servers: // -// log.Fatal(http.Serve(autocert.NewListener("example.com"), handler)) +// log.Fatal(http.Serve(autocert.NewListener("example.com"), handler)) // // NewListener is a convenience function for a common configuration. // More complex or custom configurations can use the autocert.Manager @@ -72,7 +72,6 @@ func NewListener(domains ...string) net.Listener { // the Manager m's Prompt, Cache, HostPolicy, and other desired options. func (m *Manager) Listener() net.Listener { ln := &listener{ - m: m, conf: m.TLSConfig(), } ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443") @@ -80,7 +79,6 @@ func (m *Manager) Listener() net.Listener { } type listener struct { - m *Manager conf *tls.Config tcpListener net.Listener diff --git a/vendor/golang.org/x/crypto/acme/autocert/renewal.go b/vendor/golang.org/x/crypto/acme/autocert/renewal.go index 665f870..0df7da7 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/renewal.go +++ b/vendor/golang.org/x/crypto/acme/autocert/renewal.go @@ -21,8 +21,9 @@ type domainRenewal struct { ck certKey key crypto.Signer - timerMu sync.Mutex - timer *time.Timer + timerMu sync.Mutex + timer *time.Timer + timerClose chan struct{} // if non-nil, renew closes this channel (and nils out the timer fields) instead of running } // start starts a cert renewal timer at the time @@ -38,16 +39,28 @@ func (dr *domainRenewal) start(exp time.Time) { dr.timer = time.AfterFunc(dr.next(exp), dr.renew) } -// stop stops the cert renewal timer. -// If the timer is already stopped, calling stop is a noop. +// stop stops the cert renewal timer and waits for any in-flight calls to renew +// to complete. If the timer is already stopped, calling stop is a noop. func (dr *domainRenewal) stop() { dr.timerMu.Lock() defer dr.timerMu.Unlock() - if dr.timer == nil { - return + for { + if dr.timer == nil { + return + } + if dr.timer.Stop() { + dr.timer = nil + return + } else { + // dr.timer fired, and we acquired dr.timerMu before the renew callback did. + // (We know this because otherwise the renew callback would have reset dr.timer!) + timerClose := make(chan struct{}) + dr.timerClose = timerClose + dr.timerMu.Unlock() + <-timerClose + dr.timerMu.Lock() + } } - dr.timer.Stop() - dr.timer = nil } // renew is called periodically by a timer. @@ -55,7 +68,9 @@ func (dr *domainRenewal) stop() { func (dr *domainRenewal) renew() { dr.timerMu.Lock() defer dr.timerMu.Unlock() - if dr.timer == nil { + if dr.timerClose != nil { + close(dr.timerClose) + dr.timer, dr.timerClose = nil, nil return } @@ -67,8 +82,8 @@ func (dr *domainRenewal) renew() { next = renewJitter / 2 next += time.Duration(pseudoRand.int63n(int64(next))) } - dr.timer = time.AfterFunc(next, dr.renew) testDidRenewLoop(next, err) + dr.timer = time.AfterFunc(next, dr.renew) } // updateState locks and replaces the relevant Manager.state item with the given diff --git a/vendor/golang.org/x/crypto/acme/http.go b/vendor/golang.org/x/crypto/acme/http.go index 600d579..2b4c1a1 100644 --- a/vendor/golang.org/x/crypto/acme/http.go +++ b/vendor/golang.org/x/crypto/acme/http.go @@ -10,6 +10,7 @@ import ( "crypto" "crypto/rand" "encoding/json" + "errors" "fmt" "io/ioutil" "math/big" @@ -155,8 +156,16 @@ func (c *Client) get(ctx context.Context, url string, ok resOkay) (*http.Respons } } +// postAsGet is POST-as-GET, a replacement for GET in RFC8555 +// as described in https://tools.ietf.org/html/rfc8555#section-6.3. +// It makes a POST request in KID form with zero JWS payload. +// See nopayload doc comments in jws.go. +func (c *Client) postAsGet(ctx context.Context, url string, ok resOkay) (*http.Response, error) { + return c.post(ctx, nil, url, noPayload, ok) +} + // post issues a signed POST request in JWS format using the provided key -// to the specified URL. +// to the specified URL. If key is nil, c.Key is used instead. // It returns a non-error value only when ok reports true. // // post retries unsuccessful attempts according to c.RetryBackoff @@ -193,14 +202,31 @@ func (c *Client) post(ctx context.Context, key crypto.Signer, url string, body i } // postNoRetry signs the body with the given key and POSTs it to the provided url. -// The body argument must be JSON-serializable. // It is used by c.post to retry unsuccessful attempts. +// The body argument must be JSON-serializable. +// +// If key argument is nil, c.Key is used to sign the request. +// If key argument is nil and c.accountKID returns a non-zero keyID, +// the request is sent in KID form. Otherwise, JWK form is used. +// +// In practice, when interfacing with RFC-compliant CAs most requests are sent in KID form +// and JWK is used only when KID is unavailable: new account endpoint and certificate +// revocation requests authenticated by a cert key. +// See jwsEncodeJSON for other details. func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, *http.Request, error) { + kid := noKeyID + if key == nil { + if c.Key == nil { + return nil, nil, errors.New("acme: Client.Key must be populated to make POST requests") + } + key = c.Key + kid = c.accountKID(ctx) + } nonce, err := c.popNonce(ctx, url) if err != nil { return nil, nil, err } - b, err := jwsEncodeJSON(body, key, nonce) + b, err := jwsEncodeJSON(body, key, kid, nonce, url) if err != nil { return nil, nil, err } diff --git a/vendor/golang.org/x/crypto/acme/jws.go b/vendor/golang.org/x/crypto/acme/jws.go index 1093b50..b38828d 100644 --- a/vendor/golang.org/x/crypto/acme/jws.go +++ b/vendor/golang.org/x/crypto/acme/jws.go @@ -7,47 +7,109 @@ package acme import ( "crypto" "crypto/ecdsa" + "crypto/hmac" "crypto/rand" "crypto/rsa" "crypto/sha256" _ "crypto/sha512" // need for EC keys + "encoding/asn1" "encoding/base64" "encoding/json" + "errors" "fmt" "math/big" ) +// KeyID is the account key identity provided by a CA during registration. +type KeyID string + +// noKeyID indicates that jwsEncodeJSON should compute and use JWK instead of a KID. +// See jwsEncodeJSON for details. +const noKeyID = KeyID("") + +// noPayload indicates jwsEncodeJSON will encode zero-length octet string +// in a JWS request. This is called POST-as-GET in RFC 8555 and is used to make +// authenticated GET requests via POSTing with an empty payload. +// See https://tools.ietf.org/html/rfc8555#section-6.3 for more details. +const noPayload = "" + +// noNonce indicates that the nonce should be omitted from the protected header. +// See jwsEncodeJSON for details. +const noNonce = "" + +// jsonWebSignature can be easily serialized into a JWS following +// https://tools.ietf.org/html/rfc7515#section-3.2. +type jsonWebSignature struct { + Protected string `json:"protected"` + Payload string `json:"payload"` + Sig string `json:"signature"` +} + // jwsEncodeJSON signs claimset using provided key and a nonce. -// The result is serialized in JSON format. +// The result is serialized in JSON format containing either kid or jwk +// fields based on the provided KeyID value. +// +// The claimset is marshalled using json.Marshal unless it is a string. +// In which case it is inserted directly into the message. +// +// If kid is non-empty, its quoted value is inserted in the protected header +// as "kid" field value. Otherwise, JWK is computed using jwkEncode and inserted +// as "jwk" field value. The "jwk" and "kid" fields are mutually exclusive. +// +// If nonce is non-empty, its quoted value is inserted in the protected header. +// // See https://tools.ietf.org/html/rfc7515#section-7. -func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byte, error) { - jwk, err := jwkEncode(key.Public()) - if err != nil { - return nil, err +func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid KeyID, nonce, url string) ([]byte, error) { + if key == nil { + return nil, errors.New("nil key") } alg, sha := jwsHasher(key.Public()) if alg == "" || !sha.Available() { return nil, ErrUnsupportedKey } - phead := fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q}`, alg, jwk, nonce) - phead = base64.RawURLEncoding.EncodeToString([]byte(phead)) - cs, err := json.Marshal(claimset) + headers := struct { + Alg string `json:"alg"` + KID string `json:"kid,omitempty"` + JWK json.RawMessage `json:"jwk,omitempty"` + Nonce string `json:"nonce,omitempty"` + URL string `json:"url"` + }{ + Alg: alg, + Nonce: nonce, + URL: url, + } + switch kid { + case noKeyID: + jwk, err := jwkEncode(key.Public()) + if err != nil { + return nil, err + } + headers.JWK = json.RawMessage(jwk) + default: + headers.KID = string(kid) + } + phJSON, err := json.Marshal(headers) if err != nil { return nil, err } - payload := base64.RawURLEncoding.EncodeToString(cs) + phead := base64.RawURLEncoding.EncodeToString([]byte(phJSON)) + var payload string + if val, ok := claimset.(string); ok { + payload = val + } else { + cs, err := json.Marshal(claimset) + if err != nil { + return nil, err + } + payload = base64.RawURLEncoding.EncodeToString(cs) + } hash := sha.New() hash.Write([]byte(phead + "." + payload)) sig, err := jwsSign(key, sha, hash.Sum(nil)) if err != nil { return nil, err } - - enc := struct { - Protected string `json:"protected"` - Payload string `json:"payload"` - Sig string `json:"signature"` - }{ + enc := jsonWebSignature{ Protected: phead, Payload: payload, Sig: base64.RawURLEncoding.EncodeToString(sig), @@ -55,6 +117,43 @@ func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byt return json.Marshal(&enc) } +// jwsWithMAC creates and signs a JWS using the given key and the HS256 +// algorithm. kid and url are included in the protected header. rawPayload +// should not be base64-URL-encoded. +func jwsWithMAC(key []byte, kid, url string, rawPayload []byte) (*jsonWebSignature, error) { + if len(key) == 0 { + return nil, errors.New("acme: cannot sign JWS with an empty MAC key") + } + header := struct { + Algorithm string `json:"alg"` + KID string `json:"kid"` + URL string `json:"url,omitempty"` + }{ + // Only HMAC-SHA256 is supported. + Algorithm: "HS256", + KID: kid, + URL: url, + } + rawProtected, err := json.Marshal(header) + if err != nil { + return nil, err + } + protected := base64.RawURLEncoding.EncodeToString(rawProtected) + payload := base64.RawURLEncoding.EncodeToString(rawPayload) + + h := hmac.New(sha256.New, key) + if _, err := h.Write([]byte(protected + "." + payload)); err != nil { + return nil, err + } + mac := h.Sum(nil) + + return &jsonWebSignature{ + Protected: protected, + Payload: payload, + Sig: base64.RawURLEncoding.EncodeToString(mac), + }, nil +} + // jwkEncode encodes public part of an RSA or ECDSA key into a JWK. // The result is also suitable for creating a JWK thumbprint. // https://tools.ietf.org/html/rfc7517 @@ -98,21 +197,23 @@ func jwkEncode(pub crypto.PublicKey) (string, error) { // jwsSign signs the digest using the given key. // The hash is unused for ECDSA keys. -// -// Note: non-stdlib crypto.Signer implementations are expected to return -// the signature in the format as specified in RFC7518. -// See https://tools.ietf.org/html/rfc7518 for more details. func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) { - if key, ok := key.(*ecdsa.PrivateKey); ok { - // The key.Sign method of ecdsa returns ASN1-encoded signature. - // So, we use the package Sign function instead - // to get R and S values directly and format the result accordingly. - r, s, err := ecdsa.Sign(rand.Reader, key, digest) + switch pub := key.Public().(type) { + case *rsa.PublicKey: + return key.Sign(rand.Reader, digest, hash) + case *ecdsa.PublicKey: + sigASN1, err := key.Sign(rand.Reader, digest, hash) if err != nil { return nil, err } - rb, sb := r.Bytes(), s.Bytes() - size := key.Params().BitSize / 8 + + var rs struct{ R, S *big.Int } + if _, err := asn1.Unmarshal(sigASN1, &rs); err != nil { + return nil, err + } + + rb, sb := rs.R.Bytes(), rs.S.Bytes() + size := pub.Params().BitSize / 8 if size%8 > 0 { size++ } @@ -121,7 +222,7 @@ func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) copy(sig[size*2-len(sb):], sb) return sig, nil } - return key.Sign(rand.Reader, digest, hash) + return nil, ErrUnsupportedKey } // jwsHasher indicates suitable JWS algorithm name and a hash function diff --git a/vendor/golang.org/x/crypto/acme/rfc8555.go b/vendor/golang.org/x/crypto/acme/rfc8555.go new file mode 100644 index 0000000..940e70b --- /dev/null +++ b/vendor/golang.org/x/crypto/acme/rfc8555.go @@ -0,0 +1,477 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package acme + +import ( + "context" + "crypto" + "encoding/base64" + "encoding/json" + "encoding/pem" + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + "time" +) + +// DeactivateReg permanently disables an existing account associated with c.Key. +// A deactivated account can no longer request certificate issuance or access +// resources related to the account, such as orders or authorizations. +// +// It only works with CAs implementing RFC 8555. +func (c *Client) DeactivateReg(ctx context.Context) error { + if _, err := c.Discover(ctx); err != nil { // required by c.accountKID + return err + } + url := string(c.accountKID(ctx)) + if url == "" { + return ErrNoAccount + } + req := json.RawMessage(`{"status": "deactivated"}`) + res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK)) + if err != nil { + return err + } + res.Body.Close() + return nil +} + +// registerRFC is equivalent to c.Register but for CAs implementing RFC 8555. +// It expects c.Discover to have already been called. +func (c *Client) registerRFC(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) { + c.cacheMu.Lock() // guard c.kid access + defer c.cacheMu.Unlock() + + req := struct { + TermsAgreed bool `json:"termsOfServiceAgreed,omitempty"` + Contact []string `json:"contact,omitempty"` + ExternalAccountBinding *jsonWebSignature `json:"externalAccountBinding,omitempty"` + }{ + Contact: acct.Contact, + } + if c.dir.Terms != "" { + req.TermsAgreed = prompt(c.dir.Terms) + } + + // set 'externalAccountBinding' field if requested + if acct.ExternalAccountBinding != nil { + eabJWS, err := c.encodeExternalAccountBinding(acct.ExternalAccountBinding) + if err != nil { + return nil, fmt.Errorf("acme: failed to encode external account binding: %v", err) + } + req.ExternalAccountBinding = eabJWS + } + + res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus( + http.StatusOK, // account with this key already registered + http.StatusCreated, // new account created + )) + if err != nil { + return nil, err + } + + defer res.Body.Close() + a, err := responseAccount(res) + if err != nil { + return nil, err + } + // Cache Account URL even if we return an error to the caller. + // It is by all means a valid and usable "kid" value for future requests. + c.KID = KeyID(a.URI) + if res.StatusCode == http.StatusOK { + return nil, ErrAccountAlreadyExists + } + return a, nil +} + +// encodeExternalAccountBinding will encode an external account binding stanza +// as described in https://tools.ietf.org/html/rfc8555#section-7.3.4. +func (c *Client) encodeExternalAccountBinding(eab *ExternalAccountBinding) (*jsonWebSignature, error) { + jwk, err := jwkEncode(c.Key.Public()) + if err != nil { + return nil, err + } + return jwsWithMAC(eab.Key, eab.KID, c.dir.RegURL, []byte(jwk)) +} + +// updateRegRFC is equivalent to c.UpdateReg but for CAs implementing RFC 8555. +// It expects c.Discover to have already been called. +func (c *Client) updateRegRFC(ctx context.Context, a *Account) (*Account, error) { + url := string(c.accountKID(ctx)) + if url == "" { + return nil, ErrNoAccount + } + req := struct { + Contact []string `json:"contact,omitempty"` + }{ + Contact: a.Contact, + } + res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK)) + if err != nil { + return nil, err + } + defer res.Body.Close() + return responseAccount(res) +} + +// getGegRFC is equivalent to c.GetReg but for CAs implementing RFC 8555. +// It expects c.Discover to have already been called. +func (c *Client) getRegRFC(ctx context.Context) (*Account, error) { + req := json.RawMessage(`{"onlyReturnExisting": true}`) + res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus(http.StatusOK)) + if e, ok := err.(*Error); ok && e.ProblemType == "urn:ietf:params:acme:error:accountDoesNotExist" { + return nil, ErrNoAccount + } + if err != nil { + return nil, err + } + + defer res.Body.Close() + return responseAccount(res) +} + +func responseAccount(res *http.Response) (*Account, error) { + var v struct { + Status string + Contact []string + Orders string + } + if err := json.NewDecoder(res.Body).Decode(&v); err != nil { + return nil, fmt.Errorf("acme: invalid account response: %v", err) + } + return &Account{ + URI: res.Header.Get("Location"), + Status: v.Status, + Contact: v.Contact, + OrdersURL: v.Orders, + }, nil +} + +// accountKeyRollover attempts to perform account key rollover. +// On success it will change client.Key to the new key. +func (c *Client) accountKeyRollover(ctx context.Context, newKey crypto.Signer) error { + dir, err := c.Discover(ctx) // Also required by c.accountKID + if err != nil { + return err + } + kid := c.accountKID(ctx) + if kid == noKeyID { + return ErrNoAccount + } + oldKey, err := jwkEncode(c.Key.Public()) + if err != nil { + return err + } + payload := struct { + Account string `json:"account"` + OldKey json.RawMessage `json:"oldKey"` + }{ + Account: string(kid), + OldKey: json.RawMessage(oldKey), + } + inner, err := jwsEncodeJSON(payload, newKey, noKeyID, noNonce, dir.KeyChangeURL) + if err != nil { + return err + } + + res, err := c.post(ctx, nil, dir.KeyChangeURL, base64.RawURLEncoding.EncodeToString(inner), wantStatus(http.StatusOK)) + if err != nil { + return err + } + defer res.Body.Close() + c.Key = newKey + return nil +} + +// AuthorizeOrder initiates the order-based application for certificate issuance, +// as opposed to pre-authorization in Authorize. +// It is only supported by CAs implementing RFC 8555. +// +// The caller then needs to fetch each authorization with GetAuthorization, +// identify those with StatusPending status and fulfill a challenge using Accept. +// Once all authorizations are satisfied, the caller will typically want to poll +// order status using WaitOrder until it's in StatusReady state. +// To finalize the order and obtain a certificate, the caller submits a CSR with CreateOrderCert. +func (c *Client) AuthorizeOrder(ctx context.Context, id []AuthzID, opt ...OrderOption) (*Order, error) { + dir, err := c.Discover(ctx) + if err != nil { + return nil, err + } + + req := struct { + Identifiers []wireAuthzID `json:"identifiers"` + NotBefore string `json:"notBefore,omitempty"` + NotAfter string `json:"notAfter,omitempty"` + }{} + for _, v := range id { + req.Identifiers = append(req.Identifiers, wireAuthzID{ + Type: v.Type, + Value: v.Value, + }) + } + for _, o := range opt { + switch o := o.(type) { + case orderNotBeforeOpt: + req.NotBefore = time.Time(o).Format(time.RFC3339) + case orderNotAfterOpt: + req.NotAfter = time.Time(o).Format(time.RFC3339) + default: + // Package's fault if we let this happen. + panic(fmt.Sprintf("unsupported order option type %T", o)) + } + } + + res, err := c.post(ctx, nil, dir.OrderURL, req, wantStatus(http.StatusCreated)) + if err != nil { + return nil, err + } + defer res.Body.Close() + return responseOrder(res) +} + +// GetOrder retrives an order identified by the given URL. +// For orders created with AuthorizeOrder, the url value is Order.URI. +// +// If a caller needs to poll an order until its status is final, +// see the WaitOrder method. +func (c *Client) GetOrder(ctx context.Context, url string) (*Order, error) { + if _, err := c.Discover(ctx); err != nil { + return nil, err + } + + res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK)) + if err != nil { + return nil, err + } + defer res.Body.Close() + return responseOrder(res) +} + +// WaitOrder polls an order from the given URL until it is in one of the final states, +// StatusReady, StatusValid or StatusInvalid, the CA responded with a non-retryable error +// or the context is done. +// +// It returns a non-nil Order only if its Status is StatusReady or StatusValid. +// In all other cases WaitOrder returns an error. +// If the Status is StatusInvalid, the returned error is of type *OrderError. +func (c *Client) WaitOrder(ctx context.Context, url string) (*Order, error) { + if _, err := c.Discover(ctx); err != nil { + return nil, err + } + for { + res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK)) + if err != nil { + return nil, err + } + o, err := responseOrder(res) + res.Body.Close() + switch { + case err != nil: + // Skip and retry. + case o.Status == StatusInvalid: + return nil, &OrderError{OrderURL: o.URI, Status: o.Status} + case o.Status == StatusReady || o.Status == StatusValid: + return o, nil + } + + d := retryAfter(res.Header.Get("Retry-After")) + if d == 0 { + // Default retry-after. + // Same reasoning as in WaitAuthorization. + d = time.Second + } + t := time.NewTimer(d) + select { + case <-ctx.Done(): + t.Stop() + return nil, ctx.Err() + case <-t.C: + // Retry. + } + } +} + +func responseOrder(res *http.Response) (*Order, error) { + var v struct { + Status string + Expires time.Time + Identifiers []wireAuthzID + NotBefore time.Time + NotAfter time.Time + Error *wireError + Authorizations []string + Finalize string + Certificate string + } + if err := json.NewDecoder(res.Body).Decode(&v); err != nil { + return nil, fmt.Errorf("acme: error reading order: %v", err) + } + o := &Order{ + URI: res.Header.Get("Location"), + Status: v.Status, + Expires: v.Expires, + NotBefore: v.NotBefore, + NotAfter: v.NotAfter, + AuthzURLs: v.Authorizations, + FinalizeURL: v.Finalize, + CertURL: v.Certificate, + } + for _, id := range v.Identifiers { + o.Identifiers = append(o.Identifiers, AuthzID{Type: id.Type, Value: id.Value}) + } + if v.Error != nil { + o.Error = v.Error.error(nil /* headers */) + } + return o, nil +} + +// CreateOrderCert submits the CSR (Certificate Signing Request) to a CA at the specified URL. +// The URL is the FinalizeURL field of an Order created with AuthorizeOrder. +// +// If the bundle argument is true, the returned value also contain the CA (issuer) +// certificate chain. Otherwise, only a leaf certificate is returned. +// The returned URL can be used to re-fetch the certificate using FetchCert. +// +// This method is only supported by CAs implementing RFC 8555. See CreateCert for pre-RFC CAs. +// +// CreateOrderCert returns an error if the CA's response is unreasonably large. +// Callers are encouraged to parse the returned value to ensure the certificate is valid and has the expected features. +func (c *Client) CreateOrderCert(ctx context.Context, url string, csr []byte, bundle bool) (der [][]byte, certURL string, err error) { + if _, err := c.Discover(ctx); err != nil { // required by c.accountKID + return nil, "", err + } + + // RFC describes this as "finalize order" request. + req := struct { + CSR string `json:"csr"` + }{ + CSR: base64.RawURLEncoding.EncodeToString(csr), + } + res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK)) + if err != nil { + return nil, "", err + } + defer res.Body.Close() + o, err := responseOrder(res) + if err != nil { + return nil, "", err + } + + // Wait for CA to issue the cert if they haven't. + if o.Status != StatusValid { + o, err = c.WaitOrder(ctx, o.URI) + } + if err != nil { + return nil, "", err + } + // The only acceptable status post finalize and WaitOrder is "valid". + if o.Status != StatusValid { + return nil, "", &OrderError{OrderURL: o.URI, Status: o.Status} + } + crt, err := c.fetchCertRFC(ctx, o.CertURL, bundle) + return crt, o.CertURL, err +} + +// fetchCertRFC downloads issued certificate from the given URL. +// It expects the CA to respond with PEM-encoded certificate chain. +// +// The URL argument is the CertURL field of Order. +func (c *Client) fetchCertRFC(ctx context.Context, url string, bundle bool) ([][]byte, error) { + res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK)) + if err != nil { + return nil, err + } + defer res.Body.Close() + + // Get all the bytes up to a sane maximum. + // Account very roughly for base64 overhead. + const max = maxCertChainSize + maxCertChainSize/33 + b, err := ioutil.ReadAll(io.LimitReader(res.Body, max+1)) + if err != nil { + return nil, fmt.Errorf("acme: fetch cert response stream: %v", err) + } + if len(b) > max { + return nil, errors.New("acme: certificate chain is too big") + } + + // Decode PEM chain. + var chain [][]byte + for { + var p *pem.Block + p, b = pem.Decode(b) + if p == nil { + break + } + if p.Type != "CERTIFICATE" { + return nil, fmt.Errorf("acme: invalid PEM cert type %q", p.Type) + } + + chain = append(chain, p.Bytes) + if !bundle { + return chain, nil + } + if len(chain) > maxChainLen { + return nil, errors.New("acme: certificate chain is too long") + } + } + if len(chain) == 0 { + return nil, errors.New("acme: certificate chain is empty") + } + return chain, nil +} + +// sends a cert revocation request in either JWK form when key is non-nil or KID form otherwise. +func (c *Client) revokeCertRFC(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error { + req := &struct { + Cert string `json:"certificate"` + Reason int `json:"reason"` + }{ + Cert: base64.RawURLEncoding.EncodeToString(cert), + Reason: int(reason), + } + res, err := c.post(ctx, key, c.dir.RevokeURL, req, wantStatus(http.StatusOK)) + if err != nil { + if isAlreadyRevoked(err) { + // Assume it is not an error to revoke an already revoked cert. + return nil + } + return err + } + defer res.Body.Close() + return nil +} + +func isAlreadyRevoked(err error) bool { + e, ok := err.(*Error) + return ok && e.ProblemType == "urn:ietf:params:acme:error:alreadyRevoked" +} + +// ListCertAlternates retrieves any alternate certificate chain URLs for the +// given certificate chain URL. These alternate URLs can be passed to FetchCert +// in order to retrieve the alternate certificate chains. +// +// If there are no alternate issuer certificate chains, a nil slice will be +// returned. +func (c *Client) ListCertAlternates(ctx context.Context, url string) ([]string, error) { + if _, err := c.Discover(ctx); err != nil { // required by c.accountKID + return nil, err + } + + res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK)) + if err != nil { + return nil, err + } + defer res.Body.Close() + + // We don't need the body but we need to discard it so we don't end up + // preventing keep-alive + if _, err := io.Copy(ioutil.Discard, res.Body); err != nil { + return nil, fmt.Errorf("acme: cert alternates response stream: %v", err) + } + alts := linkHeader(res.Header, "alternate") + return alts, nil +} diff --git a/vendor/golang.org/x/crypto/acme/types.go b/vendor/golang.org/x/crypto/acme/types.go index 54792c0..67b8252 100644 --- a/vendor/golang.org/x/crypto/acme/types.go +++ b/vendor/golang.org/x/crypto/acme/types.go @@ -14,14 +14,18 @@ import ( "time" ) -// ACME server response statuses used to describe Authorization and Challenge states. +// ACME status values of Account, Order, Authorization and Challenge objects. +// See https://tools.ietf.org/html/rfc8555#section-7.1.6 for details. const ( - StatusUnknown = "unknown" - StatusPending = "pending" - StatusProcessing = "processing" - StatusValid = "valid" - StatusInvalid = "invalid" - StatusRevoked = "revoked" + StatusDeactivated = "deactivated" + StatusExpired = "expired" + StatusInvalid = "invalid" + StatusPending = "pending" + StatusProcessing = "processing" + StatusReady = "ready" + StatusRevoked = "revoked" + StatusUnknown = "unknown" + StatusValid = "valid" ) // CRLReasonCode identifies the reason for a certificate revocation. @@ -41,8 +45,43 @@ const ( CRLReasonAACompromise CRLReasonCode = 10 ) -// ErrUnsupportedKey is returned when an unsupported key type is encountered. -var ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported") +var ( + // ErrUnsupportedKey is returned when an unsupported key type is encountered. + ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported") + + // ErrAccountAlreadyExists indicates that the Client's key has already been registered + // with the CA. It is returned by Register method. + ErrAccountAlreadyExists = errors.New("acme: account already exists") + + // ErrNoAccount indicates that the Client's key has not been registered with the CA. + ErrNoAccount = errors.New("acme: account does not exist") +) + +// A Subproblem describes an ACME subproblem as reported in an Error. +type Subproblem struct { + // Type is a URI reference that identifies the problem type, + // typically in a "urn:acme:error:xxx" form. + Type string + // Detail is a human-readable explanation specific to this occurrence of the problem. + Detail string + // Instance indicates a URL that the client should direct a human user to visit + // in order for instructions on how to agree to the updated Terms of Service. + // In such an event CA sets StatusCode to 403, Type to + // "urn:ietf:params:acme:error:userActionRequired", and adds a Link header with relation + // "terms-of-service" containing the latest TOS URL. + Instance string + // Identifier may contain the ACME identifier that the error is for. + Identifier *AuthzID +} + +func (sp Subproblem) String() string { + str := fmt.Sprintf("%s: ", sp.Type) + if sp.Identifier != nil { + str += fmt.Sprintf("[%s: %s] ", sp.Identifier.Type, sp.Identifier.Value) + } + str += sp.Detail + return str +} // Error is an ACME error, defined in Problem Details for HTTP APIs doc // http://tools.ietf.org/html/draft-ietf-appsawg-http-problem. @@ -54,13 +93,30 @@ type Error struct { ProblemType string // Detail is a human-readable explanation specific to this occurrence of the problem. Detail string + // Instance indicates a URL that the client should direct a human user to visit + // in order for instructions on how to agree to the updated Terms of Service. + // In such an event CA sets StatusCode to 403, ProblemType to + // "urn:ietf:params:acme:error:userActionRequired" and a Link header with relation + // "terms-of-service" containing the latest TOS URL. + Instance string // Header is the original server error response headers. // It may be nil. Header http.Header + // Subproblems may contain more detailed information about the individual problems + // that caused the error. This field is only sent by RFC 8555 compatible ACME + // servers. Defined in RFC 8555 Section 6.7.1. + Subproblems []Subproblem } func (e *Error) Error() string { - return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail) + str := fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail) + if len(e.Subproblems) > 0 { + str += fmt.Sprintf("; subproblems:") + for _, sp := range e.Subproblems { + str += fmt.Sprintf("\n\t%s", sp) + } + } + return str } // AuthorizationError indicates that an authorization for an identifier @@ -83,7 +139,27 @@ func (a *AuthorizationError) Error() string { for i, err := range a.Errors { e[i] = err.Error() } - return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; ")) + + if a.Identifier != "" { + return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; ")) + } + + return fmt.Sprintf("acme: authorization error: %s", strings.Join(e, "; ")) +} + +// OrderError is returned from Client's order related methods. +// It indicates the order is unusable and the clients should start over with +// AuthorizeOrder. +// +// The clients can still fetch the order object from CA using GetOrder +// to inspect its state. +type OrderError struct { + OrderURL string + Status string +} + +func (oe *OrderError) Error() string { + return fmt.Sprintf("acme: order %s status: %s", oe.OrderURL, oe.Status) } // RateLimit reports whether err represents a rate limit error and @@ -108,49 +184,110 @@ func RateLimit(err error) (time.Duration, bool) { } // Account is a user account. It is associated with a private key. +// Non-RFC 8555 fields are empty when interfacing with a compliant CA. type Account struct { // URI is the account unique ID, which is also a URL used to retrieve // account data from the CA. + // When interfacing with RFC 8555-compliant CAs, URI is the "kid" field + // value in JWS signed requests. URI string // Contact is a slice of contact info used during registration. + // See https://tools.ietf.org/html/rfc8555#section-7.3 for supported + // formats. Contact []string + // Status indicates current account status as returned by the CA. + // Possible values are StatusValid, StatusDeactivated, and StatusRevoked. + Status string + + // OrdersURL is a URL from which a list of orders submitted by this account + // can be fetched. + OrdersURL string + // The terms user has agreed to. // A value not matching CurrentTerms indicates that the user hasn't agreed // to the actual Terms of Service of the CA. + // + // It is non-RFC 8555 compliant. Package users can store the ToS they agree to + // during Client's Register call in the prompt callback function. AgreedTerms string // Actual terms of a CA. + // + // It is non-RFC 8555 compliant. Use Directory's Terms field. + // When a CA updates their terms and requires an account agreement, + // a URL at which instructions to do so is available in Error's Instance field. CurrentTerms string // Authz is the authorization URL used to initiate a new authz flow. + // + // It is non-RFC 8555 compliant. Use Directory's AuthzURL or OrderURL. Authz string // Authorizations is a URI from which a list of authorizations // granted to this account can be fetched via a GET request. + // + // It is non-RFC 8555 compliant and is obsoleted by OrdersURL. Authorizations string // Certificates is a URI from which a list of certificates // issued for this account can be fetched via a GET request. + // + // It is non-RFC 8555 compliant and is obsoleted by OrdersURL. Certificates string + + // ExternalAccountBinding represents an arbitrary binding to an account of + // the CA which the ACME server is tied to. + // See https://tools.ietf.org/html/rfc8555#section-7.3.4 for more details. + ExternalAccountBinding *ExternalAccountBinding +} + +// ExternalAccountBinding contains the data needed to form a request with +// an external account binding. +// See https://tools.ietf.org/html/rfc8555#section-7.3.4 for more details. +type ExternalAccountBinding struct { + // KID is the Key ID of the symmetric MAC key that the CA provides to + // identify an external account from ACME. + KID string + + // Key is the bytes of the symmetric key that the CA provides to identify + // the account. Key must correspond to the KID. + Key []byte +} + +func (e *ExternalAccountBinding) String() string { + return fmt.Sprintf("&{KID: %q, Key: redacted}", e.KID) } // Directory is ACME server discovery data. +// See https://tools.ietf.org/html/rfc8555#section-7.1.1 for more details. type Directory struct { - // RegURL is an account endpoint URL, allowing for creating new - // and modifying existing accounts. + // NonceURL indicates an endpoint where to fetch fresh nonce values from. + NonceURL string + + // RegURL is an account endpoint URL, allowing for creating new accounts. + // Pre-RFC 8555 CAs also allow modifying existing accounts at this URL. RegURL string - // AuthzURL is used to initiate Identifier Authorization flow. + // OrderURL is used to initiate the certificate issuance flow + // as described in RFC 8555. + OrderURL string + + // AuthzURL is used to initiate identifier pre-authorization flow. + // Empty string indicates the flow is unsupported by the CA. AuthzURL string // CertURL is a new certificate issuance endpoint URL. + // It is non-RFC 8555 compliant and is obsoleted by OrderURL. CertURL string // RevokeURL is used to initiate a certificate revocation flow. RevokeURL string + // KeyChangeURL allows to perform account key rollover flow. + KeyChangeURL string + // Term is a URI identifying the current terms of service. Terms string @@ -162,44 +299,118 @@ type Directory struct { // recognises as referring to itself for the purposes of CAA record validation // as defined in RFC6844. CAA []string -} -// Challenge encodes a returned CA challenge. -// Its Error field may be non-nil if the challenge is part of an Authorization -// with StatusInvalid. -type Challenge struct { - // Type is the challenge type, e.g. "http-01", "tls-sni-02", "dns-01". - Type string + // ExternalAccountRequired indicates that the CA requires for all account-related + // requests to include external account binding information. + ExternalAccountRequired bool +} - // URI is where a challenge response can be posted to. +// Order represents a client's request for a certificate. +// It tracks the request flow progress through to issuance. +type Order struct { + // URI uniquely identifies an order. URI string - // Token is a random value that uniquely identifies the challenge. - Token string - - // Status identifies the status of this challenge. + // Status represents the current status of the order. + // It indicates which action the client should take. + // + // Possible values are StatusPending, StatusReady, StatusProcessing, StatusValid and StatusInvalid. + // Pending means the CA does not believe that the client has fulfilled the requirements. + // Ready indicates that the client has fulfilled all the requirements and can submit a CSR + // to obtain a certificate. This is done with Client's CreateOrderCert. + // Processing means the certificate is being issued. + // Valid indicates the CA has issued the certificate. It can be downloaded + // from the Order's CertURL. This is done with Client's FetchCert. + // Invalid means the certificate will not be issued. Users should consider this order + // abandoned. Status string - // Error indicates the reason for an authorization failure - // when this challenge was used. - // The type of a non-nil value is *Error. - Error error + // Expires is the timestamp after which CA considers this order invalid. + Expires time.Time + + // Identifiers contains all identifier objects which the order pertains to. + Identifiers []AuthzID + + // NotBefore is the requested value of the notBefore field in the certificate. + NotBefore time.Time + + // NotAfter is the requested value of the notAfter field in the certificate. + NotAfter time.Time + + // AuthzURLs represents authorizations to complete before a certificate + // for identifiers specified in the order can be issued. + // It also contains unexpired authorizations that the client has completed + // in the past. + // + // Authorization objects can be fetched using Client's GetAuthorization method. + // + // The required authorizations are dictated by CA policies. + // There may not be a 1:1 relationship between the identifiers and required authorizations. + // Required authorizations can be identified by their StatusPending status. + // + // For orders in the StatusValid or StatusInvalid state these are the authorizations + // which were completed. + AuthzURLs []string + + // FinalizeURL is the endpoint at which a CSR is submitted to obtain a certificate + // once all the authorizations are satisfied. + FinalizeURL string + + // CertURL points to the certificate that has been issued in response to this order. + CertURL string + + // The error that occurred while processing the order as received from a CA, if any. + Error *Error +} + +// OrderOption allows customizing Client.AuthorizeOrder call. +type OrderOption interface { + privateOrderOpt() } +// WithOrderNotBefore sets order's NotBefore field. +func WithOrderNotBefore(t time.Time) OrderOption { + return orderNotBeforeOpt(t) +} + +// WithOrderNotAfter sets order's NotAfter field. +func WithOrderNotAfter(t time.Time) OrderOption { + return orderNotAfterOpt(t) +} + +type orderNotBeforeOpt time.Time + +func (orderNotBeforeOpt) privateOrderOpt() {} + +type orderNotAfterOpt time.Time + +func (orderNotAfterOpt) privateOrderOpt() {} + // Authorization encodes an authorization response. type Authorization struct { // URI uniquely identifies a authorization. URI string - // Status identifies the status of an authorization. + // Status is the current status of an authorization. + // Possible values are StatusPending, StatusValid, StatusInvalid, StatusDeactivated, + // StatusExpired and StatusRevoked. Status string // Identifier is what the account is authorized to represent. Identifier AuthzID + // The timestamp after which the CA considers the authorization invalid. + Expires time.Time + + // Wildcard is true for authorizations of a wildcard domain name. + Wildcard bool + // Challenges that the client needs to fulfill in order to prove possession // of the identifier (for pending authorizations). - // For final authorizations, the challenges that were used. + // For valid authorizations, the challenge that was validated. + // For invalid authorizations, the challenge that was attempted and failed. + // + // RFC 8555 compatible CAs require users to fuflfill only one of the challenges. Challenges []*Challenge // A collection of sets of challenges, each of which would be sufficient @@ -207,24 +418,52 @@ type Authorization struct { // Clients must complete a set of challenges that covers at least one set. // Challenges are identified by their indices in the challenges array. // If this field is empty, the client needs to complete all challenges. + // + // This field is unused in RFC 8555. Combinations [][]int } // AuthzID is an identifier that an account is authorized to represent. type AuthzID struct { - Type string // The type of identifier, e.g. "dns". + Type string // The type of identifier, "dns" or "ip". Value string // The identifier itself, e.g. "example.org". } +// DomainIDs creates a slice of AuthzID with "dns" identifier type. +func DomainIDs(names ...string) []AuthzID { + a := make([]AuthzID, len(names)) + for i, v := range names { + a[i] = AuthzID{Type: "dns", Value: v} + } + return a +} + +// IPIDs creates a slice of AuthzID with "ip" identifier type. +// Each element of addr is textual form of an address as defined +// in RFC1123 Section 2.1 for IPv4 and in RFC5952 Section 4 for IPv6. +func IPIDs(addr ...string) []AuthzID { + a := make([]AuthzID, len(addr)) + for i, v := range addr { + a[i] = AuthzID{Type: "ip", Value: v} + } + return a +} + +// wireAuthzID is ACME JSON representation of authorization identifier objects. +type wireAuthzID struct { + Type string `json:"type"` + Value string `json:"value"` +} + // wireAuthz is ACME JSON representation of Authorization objects. type wireAuthz struct { + Identifier wireAuthzID Status string + Expires time.Time + Wildcard bool Challenges []wireChallenge Combinations [][]int - Identifier struct { - Type string - Value string - } + Error *wireError } func (z *wireAuthz) authorization(uri string) *Authorization { @@ -232,8 +471,10 @@ func (z *wireAuthz) authorization(uri string) *Authorization { URI: uri, Status: z.Status, Identifier: AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value}, - Combinations: z.Combinations, // shallow copy + Expires: z.Expires, + Wildcard: z.Wildcard, Challenges: make([]*Challenge, len(z.Challenges)), + Combinations: z.Combinations, // shallow copy } for i, v := range z.Challenges { a.Challenges[i] = v.challenge() @@ -246,30 +487,69 @@ func (z *wireAuthz) error(uri string) *AuthorizationError { URI: uri, Identifier: z.Identifier.Value, } + + if z.Error != nil { + err.Errors = append(err.Errors, z.Error.error(nil)) + } + for _, raw := range z.Challenges { if raw.Error != nil { err.Errors = append(err.Errors, raw.Error.error(nil)) } } + return err } +// Challenge encodes a returned CA challenge. +// Its Error field may be non-nil if the challenge is part of an Authorization +// with StatusInvalid. +type Challenge struct { + // Type is the challenge type, e.g. "http-01", "tls-alpn-01", "dns-01". + Type string + + // URI is where a challenge response can be posted to. + URI string + + // Token is a random value that uniquely identifies the challenge. + Token string + + // Status identifies the status of this challenge. + // In RFC 8555, possible values are StatusPending, StatusProcessing, StatusValid, + // and StatusInvalid. + Status string + + // Validated is the time at which the CA validated this challenge. + // Always zero value in pre-RFC 8555. + Validated time.Time + + // Error indicates the reason for an authorization failure + // when this challenge was used. + // The type of a non-nil value is *Error. + Error error +} + // wireChallenge is ACME JSON challenge representation. type wireChallenge struct { - URI string `json:"uri"` - Type string - Token string - Status string - Error *wireError + URL string `json:"url"` // RFC + URI string `json:"uri"` // pre-RFC + Type string + Token string + Status string + Validated time.Time + Error *wireError } func (c *wireChallenge) challenge() *Challenge { v := &Challenge{ - URI: c.URI, + URI: c.URL, Type: c.Type, Token: c.Token, Status: c.Status, } + if v.URI == "" { + v.URI = c.URI // c.URL was empty; use legacy + } if v.Status == "" { v.Status = StatusPending } @@ -282,18 +562,23 @@ func (c *wireChallenge) challenge() *Challenge { // wireError is a subset of fields of the Problem Details object // as described in https://tools.ietf.org/html/rfc7807#section-3.1. type wireError struct { - Status int - Type string - Detail string + Status int + Type string + Detail string + Instance string + Subproblems []Subproblem } func (e *wireError) error(h http.Header) *Error { - return &Error{ + err := &Error{ StatusCode: e.Status, ProblemType: e.Type, Detail: e.Detail, + Instance: e.Instance, Header: h, + Subproblems: e.Subproblems, } + return err } // CertOption is an optional argument type for the TLS ChallengeCert methods for diff --git a/vendor/golang.org/x/crypto/acme/version_go112.go b/vendor/golang.org/x/crypto/acme/version_go112.go index b58f245..b9efdb5 100644 --- a/vendor/golang.org/x/crypto/acme/version_go112.go +++ b/vendor/golang.org/x/crypto/acme/version_go112.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.12 // +build go1.12 package acme diff --git a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go index 593f653..904b57e 100644 --- a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go +++ b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go @@ -32,7 +32,7 @@ import ( // can get a derived key for e.g. AES-256 (which needs a 32-byte key) by // doing: // -// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New) +// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New) // // Remember to get a good random salt. At least 8 bytes is recommended by the // RFC. diff --git a/vendor/golang.org/x/net/context/context.go b/vendor/golang.org/x/net/context/context.go index a3c021d..cf66309 100644 --- a/vendor/golang.org/x/net/context/context.go +++ b/vendor/golang.org/x/net/context/context.go @@ -21,9 +21,9 @@ // explicitly to each function that needs it. The Context should be the first // parameter, typically named ctx: // -// func DoSomething(ctx context.Context, arg Arg) error { -// // ... use ctx ... -// } +// func DoSomething(ctx context.Context, arg Arg) error { +// // ... use ctx ... +// } // // Do not pass a nil Context, even if a function permits it. Pass context.TODO // if you are unsure about which Context to use. diff --git a/vendor/golang.org/x/net/context/go17.go b/vendor/golang.org/x/net/context/go17.go index d20f52b..0a54bdb 100644 --- a/vendor/golang.org/x/net/context/go17.go +++ b/vendor/golang.org/x/net/context/go17.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.7 // +build go1.7 package context @@ -53,11 +54,11 @@ func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete: // -// func slowOperationWithTimeout(ctx context.Context) (Result, error) { -// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) -// defer cancel() // releases resources if slowOperation completes before timeout elapses -// return slowOperation(ctx) -// } +// func slowOperationWithTimeout(ctx context.Context) (Result, error) { +// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) +// defer cancel() // releases resources if slowOperation completes before timeout elapses +// return slowOperation(ctx) +// } func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { return WithDeadline(parent, time.Now().Add(timeout)) } diff --git a/vendor/golang.org/x/net/context/go19.go b/vendor/golang.org/x/net/context/go19.go index d88bd1d..64d31ec 100644 --- a/vendor/golang.org/x/net/context/go19.go +++ b/vendor/golang.org/x/net/context/go19.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.9 // +build go1.9 package context diff --git a/vendor/golang.org/x/net/context/pre_go17.go b/vendor/golang.org/x/net/context/pre_go17.go index 0f35592..7b6b685 100644 --- a/vendor/golang.org/x/net/context/pre_go17.go +++ b/vendor/golang.org/x/net/context/pre_go17.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !go1.7 // +build !go1.7 package context @@ -263,11 +264,11 @@ func (c *timerCtx) cancel(removeFromParent bool, err error) { // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete: // -// func slowOperationWithTimeout(ctx context.Context) (Result, error) { -// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) -// defer cancel() // releases resources if slowOperation completes before timeout elapses -// return slowOperation(ctx) -// } +// func slowOperationWithTimeout(ctx context.Context) (Result, error) { +// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) +// defer cancel() // releases resources if slowOperation completes before timeout elapses +// return slowOperation(ctx) +// } func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { return WithDeadline(parent, time.Now().Add(timeout)) } diff --git a/vendor/golang.org/x/net/context/pre_go19.go b/vendor/golang.org/x/net/context/pre_go19.go index b105f80..1f97153 100644 --- a/vendor/golang.org/x/net/context/pre_go19.go +++ b/vendor/golang.org/x/net/context/pre_go19.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !go1.9 // +build !go1.9 package context diff --git a/vendor/golang.org/x/net/html/const.go b/vendor/golang.org/x/net/html/const.go index a3a918f..ff7acf2 100644 --- a/vendor/golang.org/x/net/html/const.go +++ b/vendor/golang.org/x/net/html/const.go @@ -52,8 +52,7 @@ var isSpecialElementMap = map[string]bool{ "iframe": true, "img": true, "input": true, - "isindex": true, // The 'isindex' element has been removed, but keep it for backwards compatibility. - "keygen": true, + "keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility. "li": true, "link": true, "listing": true, diff --git a/vendor/golang.org/x/net/html/foreign.go b/vendor/golang.org/x/net/html/foreign.go index 01477a9..9da9e9d 100644 --- a/vendor/golang.org/x/net/html/foreign.go +++ b/vendor/golang.org/x/net/html/foreign.go @@ -161,66 +161,62 @@ var mathMLAttributeAdjustments = map[string]string{ } var svgAttributeAdjustments = map[string]string{ - "attributename": "attributeName", - "attributetype": "attributeType", - "basefrequency": "baseFrequency", - "baseprofile": "baseProfile", - "calcmode": "calcMode", - "clippathunits": "clipPathUnits", - "contentscripttype": "contentScriptType", - "contentstyletype": "contentStyleType", - "diffuseconstant": "diffuseConstant", - "edgemode": "edgeMode", - "externalresourcesrequired": "externalResourcesRequired", - "filterres": "filterRes", - "filterunits": "filterUnits", - "glyphref": "glyphRef", - "gradienttransform": "gradientTransform", - "gradientunits": "gradientUnits", - "kernelmatrix": "kernelMatrix", - "kernelunitlength": "kernelUnitLength", - "keypoints": "keyPoints", - "keysplines": "keySplines", - "keytimes": "keyTimes", - "lengthadjust": "lengthAdjust", - "limitingconeangle": "limitingConeAngle", - "markerheight": "markerHeight", - "markerunits": "markerUnits", - "markerwidth": "markerWidth", - "maskcontentunits": "maskContentUnits", - "maskunits": "maskUnits", - "numoctaves": "numOctaves", - "pathlength": "pathLength", - "patterncontentunits": "patternContentUnits", - "patterntransform": "patternTransform", - "patternunits": "patternUnits", - "pointsatx": "pointsAtX", - "pointsaty": "pointsAtY", - "pointsatz": "pointsAtZ", - "preservealpha": "preserveAlpha", - "preserveaspectratio": "preserveAspectRatio", - "primitiveunits": "primitiveUnits", - "refx": "refX", - "refy": "refY", - "repeatcount": "repeatCount", - "repeatdur": "repeatDur", - "requiredextensions": "requiredExtensions", - "requiredfeatures": "requiredFeatures", - "specularconstant": "specularConstant", - "specularexponent": "specularExponent", - "spreadmethod": "spreadMethod", - "startoffset": "startOffset", - "stddeviation": "stdDeviation", - "stitchtiles": "stitchTiles", - "surfacescale": "surfaceScale", - "systemlanguage": "systemLanguage", - "tablevalues": "tableValues", - "targetx": "targetX", - "targety": "targetY", - "textlength": "textLength", - "viewbox": "viewBox", - "viewtarget": "viewTarget", - "xchannelselector": "xChannelSelector", - "ychannelselector": "yChannelSelector", - "zoomandpan": "zoomAndPan", + "attributename": "attributeName", + "attributetype": "attributeType", + "basefrequency": "baseFrequency", + "baseprofile": "baseProfile", + "calcmode": "calcMode", + "clippathunits": "clipPathUnits", + "diffuseconstant": "diffuseConstant", + "edgemode": "edgeMode", + "filterunits": "filterUnits", + "glyphref": "glyphRef", + "gradienttransform": "gradientTransform", + "gradientunits": "gradientUnits", + "kernelmatrix": "kernelMatrix", + "kernelunitlength": "kernelUnitLength", + "keypoints": "keyPoints", + "keysplines": "keySplines", + "keytimes": "keyTimes", + "lengthadjust": "lengthAdjust", + "limitingconeangle": "limitingConeAngle", + "markerheight": "markerHeight", + "markerunits": "markerUnits", + "markerwidth": "markerWidth", + "maskcontentunits": "maskContentUnits", + "maskunits": "maskUnits", + "numoctaves": "numOctaves", + "pathlength": "pathLength", + "patterncontentunits": "patternContentUnits", + "patterntransform": "patternTransform", + "patternunits": "patternUnits", + "pointsatx": "pointsAtX", + "pointsaty": "pointsAtY", + "pointsatz": "pointsAtZ", + "preservealpha": "preserveAlpha", + "preserveaspectratio": "preserveAspectRatio", + "primitiveunits": "primitiveUnits", + "refx": "refX", + "refy": "refY", + "repeatcount": "repeatCount", + "repeatdur": "repeatDur", + "requiredextensions": "requiredExtensions", + "requiredfeatures": "requiredFeatures", + "specularconstant": "specularConstant", + "specularexponent": "specularExponent", + "spreadmethod": "spreadMethod", + "startoffset": "startOffset", + "stddeviation": "stdDeviation", + "stitchtiles": "stitchTiles", + "surfacescale": "surfaceScale", + "systemlanguage": "systemLanguage", + "tablevalues": "tableValues", + "targetx": "targetX", + "targety": "targetY", + "textlength": "textLength", + "viewbox": "viewBox", + "viewtarget": "viewTarget", + "xchannelselector": "xChannelSelector", + "ychannelselector": "yChannelSelector", + "zoomandpan": "zoomAndPan", } diff --git a/vendor/golang.org/x/net/html/node.go b/vendor/golang.org/x/net/html/node.go index 633ee15..1350eef 100644 --- a/vendor/golang.org/x/net/html/node.go +++ b/vendor/golang.org/x/net/html/node.go @@ -18,6 +18,11 @@ const ( ElementNode CommentNode DoctypeNode + // RawNode nodes are not returned by the parser, but can be part of the + // Node tree passed to func Render to insert raw HTML (without escaping). + // If so, this package makes no guarantee that the rendered HTML is secure + // (from e.g. Cross Site Scripting attacks) or well-formed. + RawNode scopeMarkerNode ) diff --git a/vendor/golang.org/x/net/html/parse.go b/vendor/golang.org/x/net/html/parse.go index 992cff2..038941d 100644 --- a/vendor/golang.org/x/net/html/parse.go +++ b/vendor/golang.org/x/net/html/parse.go @@ -184,6 +184,17 @@ func (p *parser) clearStackToContext(s scope) { } } +// parseGenericRawTextElements implements the generic raw text element parsing +// algorithm defined in 12.2.6.2. +// https://html.spec.whatwg.org/multipage/parsing.html#parsing-elements-that-contain-only-text +// TODO: Since both RAWTEXT and RCDATA states are treated as tokenizer's part +// officially, need to make tokenizer consider both states. +func (p *parser) parseGenericRawTextElement() { + p.addElement() + p.originalIM = p.im + p.im = textIM +} + // generateImpliedEndTags pops nodes off the stack of open elements as long as // the top node has a tag name of dd, dt, li, optgroup, option, p, rb, rp, rt or rtc. // If exceptions are specified, nodes with that name will not be popped off. @@ -192,16 +203,17 @@ func (p *parser) generateImpliedEndTags(exceptions ...string) { loop: for i = len(p.oe) - 1; i >= 0; i-- { n := p.oe[i] - if n.Type == ElementNode { - switch n.DataAtom { - case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc: - for _, except := range exceptions { - if n.Data == except { - break loop - } + if n.Type != ElementNode { + break + } + switch n.DataAtom { + case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc: + for _, except := range exceptions { + if n.Data == except { + break loop } - continue } + continue } break } @@ -369,8 +381,7 @@ findIdenticalElements: // Section 12.2.4.3. func (p *parser) clearActiveFormattingElements() { for { - n := p.afe.pop() - if len(p.afe) == 0 || n.Type == scopeMarkerNode { + if n := p.afe.pop(); len(p.afe) == 0 || n.Type == scopeMarkerNode { return } } @@ -625,29 +636,51 @@ func inHeadIM(p *parser) bool { switch p.tok.DataAtom { case a.Html: return inBodyIM(p) - case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta: + case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta: p.addElement() p.oe.pop() p.acknowledgeSelfClosingTag() return true case a.Noscript: - p.addElement() if p.scripting { - p.setOriginalIM() - p.im = textIM - } else { - p.im = inHeadNoscriptIM + p.parseGenericRawTextElement() + return true } + p.addElement() + p.im = inHeadNoscriptIM + // Don't let the tokenizer go into raw text mode when scripting is disabled. + p.tokenizer.NextIsNotRawText() return true - case a.Script, a.Title, a.Noframes, a.Style: + case a.Script, a.Title: p.addElement() p.setOriginalIM() p.im = textIM return true + case a.Noframes, a.Style: + p.parseGenericRawTextElement() + return true case a.Head: // Ignore the token. return true case a.Template: + // TODO: remove this divergence from the HTML5 spec. + // + // We don't handle all of the corner cases when mixing foreign + // content (i.e. or ) with