From 9840fc2341f125f64a6089366197ca9012a9026f Mon Sep 17 00:00:00 2001 From: kmeister Date: Thu, 13 Apr 2017 18:32:00 -0400 Subject: [docker-exampe] moved into examples repo https://github.com/ponzu-cms/examples --- examples/docker/README.md | 52 - examples/docker/admin/.dockerignore | 8 - examples/docker/admin/.gitignore | 5 - examples/docker/admin/Dockerfile | 15 - .../addons/github.com/bosssauce/reference/LICENSE | 29 - .../github.com/bosssauce/reference/README.md | 3 - .../github.com/bosssauce/reference/reference.go | 150 - examples/docker/admin/cmd/ponzu/LICENSE | 29 - examples/docker/admin/cmd/ponzu/add.go | 167 - examples/docker/admin/cmd/ponzu/cli_test.go | 65 - examples/docker/admin/cmd/ponzu/generate.go | 263 - examples/docker/admin/cmd/ponzu/main.go | 293 - examples/docker/admin/cmd/ponzu/options.go | 489 -- examples/docker/admin/cmd/ponzu/paths.go | 44 - examples/docker/admin/cmd/ponzu/ponzu.json | 3 - .../admin/cmd/ponzu/templates/gen-checkbox.tmpl | 5 - .../admin/cmd/ponzu/templates/gen-content.tmpl | 39 - .../admin/cmd/ponzu/templates/gen-custom.tmpl | 6 - .../docker/admin/cmd/ponzu/templates/gen-file.tmpl | 4 - .../admin/cmd/ponzu/templates/gen-hidden.tmpl | 3 - .../admin/cmd/ponzu/templates/gen-input.tmpl | 5 - .../admin/cmd/ponzu/templates/gen-richtext.tmpl | 4 - .../admin/cmd/ponzu/templates/gen-select.tmpl | 5 - .../docker/admin/cmd/ponzu/templates/gen-tags.tmpl | 4 - .../admin/cmd/ponzu/templates/gen-textarea.tmpl | 4 - examples/docker/admin/cmd/ponzu/usage.go | 201 - .../ponzu/vendor/github.com/boltdb/bolt/.gitignore | 4 - .../ponzu/vendor/github.com/boltdb/bolt/LICENSE | 20 - .../ponzu/vendor/github.com/boltdb/bolt/Makefile | 18 - .../ponzu/vendor/github.com/boltdb/bolt/README.md | 858 --- .../vendor/github.com/boltdb/bolt/appveyor.yml | 18 - .../vendor/github.com/boltdb/bolt/bolt_386.go | 10 - .../vendor/github.com/boltdb/bolt/bolt_amd64.go | 10 - .../vendor/github.com/boltdb/bolt/bolt_arm.go | 28 - .../vendor/github.com/boltdb/bolt/bolt_arm64.go | 12 - .../vendor/github.com/boltdb/bolt/bolt_linux.go | 10 - .../vendor/github.com/boltdb/bolt/bolt_openbsd.go | 27 - .../vendor/github.com/boltdb/bolt/bolt_ppc.go | 9 - .../vendor/github.com/boltdb/bolt/bolt_ppc64.go | 9 - .../vendor/github.com/boltdb/bolt/bolt_ppc64le.go | 12 - .../vendor/github.com/boltdb/bolt/bolt_s390x.go | 12 - .../vendor/github.com/boltdb/bolt/bolt_unix.go | 89 - .../github.com/boltdb/bolt/bolt_unix_solaris.go | 90 - .../vendor/github.com/boltdb/bolt/bolt_windows.go | 144 - .../vendor/github.com/boltdb/bolt/boltsync_unix.go | 8 - .../ponzu/vendor/github.com/boltdb/bolt/bucket.go | 778 -- .../vendor/github.com/boltdb/bolt/bucket_test.go | 1909 ----- .../vendor/github.com/boltdb/bolt/cmd/bolt/main.go | 1740 ----- .../github.com/boltdb/bolt/cmd/bolt/main_test.go | 356 - .../ponzu/vendor/github.com/boltdb/bolt/cursor.go | 400 - .../vendor/github.com/boltdb/bolt/cursor_test.go | 817 --- .../cmd/ponzu/vendor/github.com/boltdb/bolt/db.go | 1036 --- .../ponzu/vendor/github.com/boltdb/bolt/db_test.go | 1706 ----- .../cmd/ponzu/vendor/github.com/boltdb/bolt/doc.go | 44 - .../ponzu/vendor/github.com/boltdb/bolt/errors.go | 71 - .../vendor/github.com/boltdb/bolt/freelist.go | 248 - .../vendor/github.com/boltdb/bolt/freelist_test.go | 158 - .../ponzu/vendor/github.com/boltdb/bolt/node.go | 604 -- .../vendor/github.com/boltdb/bolt/node_test.go | 156 - .../ponzu/vendor/github.com/boltdb/bolt/page.go | 178 - .../vendor/github.com/boltdb/bolt/page_test.go | 72 - .../vendor/github.com/boltdb/bolt/quick_test.go | 79 - .../github.com/boltdb/bolt/simulation_test.go | 329 - .../cmd/ponzu/vendor/github.com/boltdb/bolt/tx.go | 682 -- .../ponzu/vendor/github.com/boltdb/bolt/tx_test.go | 716 -- .../vendor/github.com/bosssauce/reference/LICENSE | 29 - .../github.com/bosssauce/reference/README.md | 3 - .../github.com/bosssauce/reference/reference.go | 150 - .../vendor/github.com/gorilla/schema/.travis.yml | 19 - .../ponzu/vendor/github.com/gorilla/schema/LICENSE | 27 - .../vendor/github.com/gorilla/schema/README.md | 66 - .../vendor/github.com/gorilla/schema/cache.go | 261 - .../vendor/github.com/gorilla/schema/converter.go | 145 - .../vendor/github.com/gorilla/schema/decoder.go | 343 - .../github.com/gorilla/schema/decoder_test.go | 1460 ---- .../ponzu/vendor/github.com/gorilla/schema/doc.go | 148 - .../ponzu/vendor/github.com/nilslice/email/LICENSE | 21 - .../vendor/github.com/nilslice/email/README.md | 51 - .../vendor/github.com/nilslice/email/email.go | 119 - .../vendor/github.com/nilslice/email/email_test.go | 19 - .../ponzu/vendor/github.com/nilslice/jwt/LICENSE | 19 - .../ponzu/vendor/github.com/nilslice/jwt/README.md | 43 - .../ponzu/vendor/github.com/nilslice/jwt/doc.go | 40 - .../ponzu/vendor/github.com/nilslice/jwt/jwt.go | 204 - .../github.com/ponzu-cms/ponzu/content/.hold | 0 .../github.com/ponzu-cms/ponzu/content/song.go | 73 - .../ponzu-cms/ponzu/management/editor/dom.go | 297 - .../ponzu-cms/ponzu/management/editor/editor.go | 267 - .../ponzu-cms/ponzu/management/editor/elements.go | 520 -- .../ponzu-cms/ponzu/management/editor/repeaters.go | 442 -- .../ponzu-cms/ponzu/management/editor/values.go | 78 - .../ponzu-cms/ponzu/management/manager/manager.go | 154 - .../ponzu-cms/ponzu/system/addon/addon.go | 239 - .../github.com/ponzu-cms/ponzu/system/addon/api.go | 80 - .../ponzu-cms/ponzu/system/addon/manager.go | 117 - .../ponzu-cms/ponzu/system/admin/admin.go | 629 -- .../ponzu-cms/ponzu/system/admin/config/config.go | 186 - .../ponzu-cms/ponzu/system/admin/filesystem.go | 35 - .../ponzu-cms/ponzu/system/admin/handlers.go | 2277 ------ .../ponzu-cms/ponzu/system/admin/server.go | 59 - .../admin/static/common/js/jquery-2.1.4.min.js | 4 - .../ponzu/system/admin/static/common/js/util.js | 86 - .../system/admin/static/dashboard/css/admin.css | 249 - .../admin/static/dashboard/css/material-icons.css | 23 - .../admin/static/dashboard/css/materialize.min.css | 16 - .../static/dashboard/fonts/icons-regular.woff2 | Bin 46736 -> 0 bytes .../static/dashboard/fonts/roboto/Roboto-Bold.eot | Bin 20966 -> 0 bytes .../static/dashboard/fonts/roboto/Roboto-Bold.ttf | Bin 127744 -> 0 bytes .../static/dashboard/fonts/roboto/Roboto-Bold.woff | Bin 62876 -> 0 bytes .../dashboard/fonts/roboto/Roboto-Bold.woff2 | Bin 49976 -> 0 bytes .../static/dashboard/fonts/roboto/Roboto-Light.eot | Bin 20940 -> 0 bytes .../static/dashboard/fonts/roboto/Roboto-Light.ttf | Bin 126792 -> 0 bytes .../dashboard/fonts/roboto/Roboto-Light.woff | Bin 62316 -> 0 bytes .../dashboard/fonts/roboto/Roboto-Light.woff2 | Bin 49380 -> 0 bytes .../dashboard/fonts/roboto/Roboto-Medium.eot | Bin 21364 -> 0 bytes .../dashboard/fonts/roboto/Roboto-Medium.ttf | Bin 127488 -> 0 bytes .../dashboard/fonts/roboto/Roboto-Medium.woff | Bin 62980 -> 0 bytes .../dashboard/fonts/roboto/Roboto-Medium.woff2 | Bin 50224 -> 0 bytes .../dashboard/fonts/roboto/Roboto-Regular.eot | Bin 21320 -> 0 bytes .../dashboard/fonts/roboto/Roboto-Regular.ttf | Bin 126072 -> 0 bytes .../dashboard/fonts/roboto/Roboto-Regular.woff | Bin 61736 -> 0 bytes .../dashboard/fonts/roboto/Roboto-Regular.woff2 | Bin 49236 -> 0 bytes .../static/dashboard/fonts/roboto/Roboto-Thin.eot | Bin 21659 -> 0 bytes .../static/dashboard/fonts/roboto/Roboto-Thin.ttf | Bin 127584 -> 0 bytes .../static/dashboard/fonts/roboto/Roboto-Thin.woff | Bin 61628 -> 0 bytes .../dashboard/fonts/roboto/Roboto-Thin.woff2 | Bin 48524 -> 0 bytes .../admin/static/dashboard/img/ponzu-file.png | Bin 25752 -> 0 bytes .../admin/static/dashboard/js/chart.bundle.min.js | 15 - .../admin/static/dashboard/js/materialize.min.js | 10 - .../admin/static/editor/css/materialNote.css | 2160 ------ .../admin/static/editor/css/materialNote.css.map | 7 - .../static/editor/font/roboto/Roboto-Bold.ttf | Bin 127744 -> 0 bytes .../static/editor/font/roboto/Roboto-Bold.woff | Bin 62876 -> 0 bytes .../static/editor/font/roboto/Roboto-Bold.woff2 | Bin 49976 -> 0 bytes .../static/editor/font/roboto/Roboto-Light.ttf | Bin 126792 -> 0 bytes .../static/editor/font/roboto/Roboto-Light.woff | Bin 62316 -> 0 bytes .../static/editor/font/roboto/Roboto-Light.woff2 | Bin 49380 -> 0 bytes .../static/editor/font/roboto/Roboto-Medium.ttf | Bin 127488 -> 0 bytes .../static/editor/font/roboto/Roboto-Medium.woff | Bin 62980 -> 0 bytes .../static/editor/font/roboto/Roboto-Medium.woff2 | Bin 50224 -> 0 bytes .../static/editor/font/roboto/Roboto-Regular.ttf | Bin 126072 -> 0 bytes .../static/editor/font/roboto/Roboto-Regular.woff | Bin 61736 -> 0 bytes .../static/editor/font/roboto/Roboto-Regular.woff2 | Bin 49236 -> 0 bytes .../static/editor/font/roboto/Roboto-Thin.ttf | Bin 127584 -> 0 bytes .../static/editor/font/roboto/Roboto-Thin.woff | Bin 61628 -> 0 bytes .../static/editor/font/roboto/Roboto-Thin.woff2 | Bin 48524 -> 0 bytes .../static/editor/js/ckMaterializeOverrides.js | 172 - .../system/admin/static/editor/js/materialNote.js | 7473 ------------------- .../ponzu/system/admin/static/editor/license.txt | 21 - .../static/editor/sass/components/_buttons.scss | 157 - .../static/editor/sass/components/_cards.scss | 152 - .../editor/sass/components/_collapsible.scss | 85 - .../static/editor/sass/components/_color.scss | 412 -- .../static/editor/sass/components/_dropdown.scss | 40 - .../admin/static/editor/sass/components/_form.scss | 886 --- .../static/editor/sass/components/_global.scss | 718 -- .../admin/static/editor/sass/components/_grid.scss | 117 - .../sass/components/_icons-material-design.scss | 3257 --------- .../editor/sass/components/_materialbox.scss | 41 - .../static/editor/sass/components/_mixins.scss | 5 - .../static/editor/sass/components/_modal.scss | 90 - .../static/editor/sass/components/_navbar.scss | 144 - .../static/editor/sass/components/_normalize.scss | 427 -- .../static/editor/sass/components/_prefixer.scss | 376 - .../static/editor/sass/components/_preloader.scss | 332 - .../static/editor/sass/components/_roboto.scss | 38 - .../static/editor/sass/components/_sideNav.scss | 111 - .../static/editor/sass/components/_slider.scss | 92 - .../editor/sass/components/_table_of_contents.scss | 33 - .../admin/static/editor/sass/components/_tabs.scss | 47 - .../static/editor/sass/components/_toast.scss | 63 - .../static/editor/sass/components/_tooltip.scss | 34 - .../static/editor/sass/components/_typography.scss | 58 - .../static/editor/sass/components/_variables.scss | 152 - .../static/editor/sass/components/_waves.scss | 167 - .../sass/components/date_picker/_default.date.scss | 435 -- .../sass/components/date_picker/_default.scss | 201 - .../sass/components/date_picker/_default.time.scss | 125 - .../admin/static/editor/sass/materialNote.scss | 734 -- .../admin/static/editor/sass/materialize.scss | 38 - .../ponzu-cms/ponzu/system/admin/upload/backup.go | 113 - .../ponzu-cms/ponzu/system/admin/upload/upload.go | 96 - .../ponzu-cms/ponzu/system/admin/user/auth.go | 145 - .../ponzu-cms/ponzu/system/api/analytics/backup.go | 26 - .../ponzu-cms/ponzu/system/api/analytics/batch.go | 98 - .../ponzu-cms/ponzu/system/api/analytics/init.go | 349 - .../github.com/ponzu-cms/ponzu/system/api/cors.go | 74 - .../ponzu-cms/ponzu/system/api/create.go | 230 - .../ponzu-cms/ponzu/system/api/delete.go | 140 - .../github.com/ponzu-cms/ponzu/system/api/gzip.go | 64 - .../ponzu-cms/ponzu/system/api/handlers.go | 196 - .../github.com/ponzu-cms/ponzu/system/api/hide.go | 27 - .../github.com/ponzu-cms/ponzu/system/api/json.go | 57 - .../github.com/ponzu-cms/ponzu/system/api/omit.go | 41 - .../github.com/ponzu-cms/ponzu/system/api/push.go | 52 - .../ponzu-cms/ponzu/system/api/record.go | 16 - .../ponzu-cms/ponzu/system/api/search.go | 82 - .../ponzu-cms/ponzu/system/api/server.go | 18 - .../ponzu-cms/ponzu/system/api/update.go | 224 - .../github.com/ponzu-cms/ponzu/system/auth.go | 34 - .../github.com/ponzu-cms/ponzu/system/db/addon.go | 165 - .../github.com/ponzu-cms/ponzu/system/db/backup.go | 26 - .../github.com/ponzu-cms/ponzu/system/db/cache.go | 56 - .../github.com/ponzu-cms/ponzu/system/db/config.go | 256 - .../ponzu-cms/ponzu/system/db/content.go | 722 -- .../github.com/ponzu-cms/ponzu/system/db/index.go | 85 - .../github.com/ponzu-cms/ponzu/system/db/init.go | 121 - .../github.com/ponzu-cms/ponzu/system/db/search.go | 145 - .../github.com/ponzu-cms/ponzu/system/db/user.go | 266 - .../github.com/ponzu-cms/ponzu/system/item/item.go | 287 - .../ponzu-cms/ponzu/system/item/types.go | 39 - .../ponzu-cms/ponzu/system/tls/devcerts.go | 148 - .../ponzu-cms/ponzu/system/tls/enable.go | 78 - .../ponzu-cms/ponzu/system/tls/enabledev.go | 29 - .../vendor/github.com/satori/go.uuid/.travis.yml | 21 - .../ponzu/vendor/github.com/satori/go.uuid/LICENSE | 20 - .../vendor/github.com/satori/go.uuid/README.md | 65 - .../github.com/satori/go.uuid/benchmarks_test.go | 123 - .../ponzu/vendor/github.com/satori/go.uuid/uuid.go | 481 -- .../vendor/github.com/satori/go.uuid/uuid_test.go | 633 -- .../ponzu/vendor/github.com/tidwall/gjson/LICENSE | 20 - .../vendor/github.com/tidwall/gjson/README.md | 371 - .../ponzu/vendor/github.com/tidwall/gjson/gjson.go | 1942 ----- .../ponzu/vendor/github.com/tidwall/gjson/logo.png | Bin 15936 -> 0 bytes .../vendor/github.com/tidwall/sjson/.travis.yml | 1 - .../ponzu/vendor/github.com/tidwall/sjson/LICENSE | 21 - .../vendor/github.com/tidwall/sjson/README.md | 278 - .../ponzu/vendor/github.com/tidwall/sjson/logo.png | Bin 16874 -> 0 bytes .../ponzu/vendor/github.com/tidwall/sjson/sjson.go | 653 -- .../golang.org/x/crypto/autocert/autocert.go | 776 -- .../golang.org/x/crypto/autocert/autocert_test.go | 390 - .../vendor/golang.org/x/crypto/autocert/cache.go | 130 - .../golang.org/x/crypto/autocert/cache_test.go | 58 - .../vendor/golang.org/x/crypto/autocert/renewal.go | 125 - .../golang.org/x/crypto/autocert/renewal_test.go | 190 - .../vendor/golang.org/x/crypto/bcrypt/base64.go | 35 - .../vendor/golang.org/x/crypto/bcrypt/bcrypt.go | 294 - .../golang.org/x/crypto/bcrypt/bcrypt_test.go | 226 - .../vendor/golang.org/x/net/context/context.go | 156 - .../golang.org/x/net/context/context_test.go | 583 -- .../golang.org/x/net/context/ctxhttp/ctxhttp.go | 74 - .../x/net/context/ctxhttp/ctxhttp_17_test.go | 28 - .../x/net/context/ctxhttp/ctxhttp_pre17.go | 147 - .../x/net/context/ctxhttp/ctxhttp_pre17_test.go | 79 - .../x/net/context/ctxhttp/ctxhttp_test.go | 105 - .../ponzu/vendor/golang.org/x/net/context/go17.go | 72 - .../vendor/golang.org/x/net/context/pre_go17.go | 300 - .../golang.org/x/net/context/withtimeout_test.go | 26 - .../ponzu/vendor/golang.org/x/net/http2/.gitignore | 2 - .../ponzu/vendor/golang.org/x/net/http2/Dockerfile | 51 - .../ponzu/vendor/golang.org/x/net/http2/Makefile | 3 - .../cmd/ponzu/vendor/golang.org/x/net/http2/README | 20 - .../golang.org/x/net/http2/client_conn_pool.go | 256 - .../golang.org/x/net/http2/configure_transport.go | 80 - .../ponzu/vendor/golang.org/x/net/http2/errors.go | 130 - .../vendor/golang.org/x/net/http2/errors_test.go | 24 - .../vendor/golang.org/x/net/http2/fixed_buffer.go | 60 - .../golang.org/x/net/http2/fixed_buffer_test.go | 128 - .../ponzu/vendor/golang.org/x/net/http2/flow.go | 50 - .../vendor/golang.org/x/net/http2/flow_test.go | 53 - .../ponzu/vendor/golang.org/x/net/http2/frame.go | 1556 ---- .../vendor/golang.org/x/net/http2/frame_test.go | 1102 --- .../ponzu/vendor/golang.org/x/net/http2/go16.go | 43 - .../ponzu/vendor/golang.org/x/net/http2/go17.go | 106 - .../vendor/golang.org/x/net/http2/go17_not18.go | 36 - .../ponzu/vendor/golang.org/x/net/http2/go18.go | 50 - .../vendor/golang.org/x/net/http2/go18_test.go | 66 - .../ponzu/vendor/golang.org/x/net/http2/gotrack.go | 170 - .../vendor/golang.org/x/net/http2/gotrack_test.go | 33 - .../golang.org/x/net/http2/h2demo/.gitignore | 5 - .../vendor/golang.org/x/net/http2/h2demo/Makefile | 8 - .../vendor/golang.org/x/net/http2/h2demo/README | 16 - .../vendor/golang.org/x/net/http2/h2demo/h2demo.go | 486 -- .../vendor/golang.org/x/net/http2/h2demo/launch.go | 302 - .../golang.org/x/net/http2/h2demo/rootCA.key | 27 - .../golang.org/x/net/http2/h2demo/rootCA.pem | 26 - .../golang.org/x/net/http2/h2demo/rootCA.srl | 1 - .../golang.org/x/net/http2/h2demo/server.crt | 20 - .../golang.org/x/net/http2/h2demo/server.key | 27 - .../vendor/golang.org/x/net/http2/h2i/README.md | 97 - .../ponzu/vendor/golang.org/x/net/http2/h2i/h2i.go | 509 -- .../vendor/golang.org/x/net/http2/headermap.go | 78 - .../vendor/golang.org/x/net/http2/hpack/encode.go | 251 - .../golang.org/x/net/http2/hpack/encode_test.go | 330 - .../vendor/golang.org/x/net/http2/hpack/hpack.go | 542 -- .../golang.org/x/net/http2/hpack/hpack_test.go | 854 --- .../vendor/golang.org/x/net/http2/hpack/huffman.go | 212 - .../vendor/golang.org/x/net/http2/hpack/tables.go | 352 - .../ponzu/vendor/golang.org/x/net/http2/http2.go | 387 - .../vendor/golang.org/x/net/http2/http2_test.go | 199 - .../vendor/golang.org/x/net/http2/not_go16.go | 46 - .../vendor/golang.org/x/net/http2/not_go17.go | 87 - .../vendor/golang.org/x/net/http2/not_go18.go | 27 - .../ponzu/vendor/golang.org/x/net/http2/pipe.go | 153 - .../vendor/golang.org/x/net/http2/pipe_test.go | 109 - .../ponzu/vendor/golang.org/x/net/http2/server.go | 2753 ------- .../golang.org/x/net/http2/server_push_test.go | 521 -- .../vendor/golang.org/x/net/http2/server_test.go | 3610 --------- .../http2/testdata/draft-ietf-httpbis-http2.xml | 5021 ------------- .../vendor/golang.org/x/net/http2/transport.go | 2129 ------ .../golang.org/x/net/http2/transport_test.go | 2916 -------- .../ponzu/vendor/golang.org/x/net/http2/write.go | 370 - .../vendor/golang.org/x/net/http2/writesched.go | 242 - .../golang.org/x/net/http2/writesched_priority.go | 452 -- .../x/net/http2/writesched_priority_test.go | 541 -- .../golang.org/x/net/http2/writesched_random.go | 72 - .../x/net/http2/writesched_random_test.go | 44 - .../golang.org/x/net/http2/writesched_test.go | 125 - .../vendor/golang.org/x/net/http2/z_spec_test.go | 356 - .../golang.org/x/text/transform/examples_test.go | 37 - .../golang.org/x/text/transform/transform.go | 705 -- .../golang.org/x/text/transform/transform_test.go | 1317 ---- .../golang.org/x/text/unicode/norm/composition.go | 514 -- .../x/text/unicode/norm/composition_test.go | 130 - .../x/text/unicode/norm/example_iter_test.go | 82 - .../golang.org/x/text/unicode/norm/example_test.go | 27 - .../golang.org/x/text/unicode/norm/forminfo.go | 256 - .../x/text/unicode/norm/forminfo_test.go | 54 - .../vendor/golang.org/x/text/unicode/norm/input.go | 105 - .../vendor/golang.org/x/text/unicode/norm/iter.go | 450 -- .../golang.org/x/text/unicode/norm/iter_test.go | 98 - .../golang.org/x/text/unicode/norm/maketables.go | 978 --- .../golang.org/x/text/unicode/norm/norm_test.go | 14 - .../golang.org/x/text/unicode/norm/normalize.go | 608 -- .../x/text/unicode/norm/normalize_test.go | 1226 ---- .../golang.org/x/text/unicode/norm/readwriter.go | 126 - .../x/text/unicode/norm/readwriter_test.go | 56 - .../golang.org/x/text/unicode/norm/tables.go | 7627 -------------------- .../golang.org/x/text/unicode/norm/transform.go | 88 - .../x/text/unicode/norm/transform_test.go | 101 - .../vendor/golang.org/x/text/unicode/norm/trie.go | 54 - .../golang.org/x/text/unicode/norm/triegen.go | 117 - .../golang.org/x/text/unicode/norm/ucd_test.go | 275 - examples/docker/admin/content/.hold | 0 examples/docker/admin/content/song.go | 73 - examples/docker/admin/deployment/README.md | 11 - examples/docker/admin/deployment/sysv/ponzu-server | 68 - examples/docker/admin/start_admin.sh | 26 - examples/docker/docker-compose.yml | 32 - examples/docker/web/Dockerfile | 2 - examples/docker/web/nginx.conf | 34 - examples/docker/web/public/css/main.css | 22 - examples/docker/web/public/css/normalize.css | 427 -- examples/docker/web/public/css/skeleton.css | 418 -- examples/docker/web/public/index.html | 34 - examples/docker/web/public/js/main.js | 43 - 346 files changed, 101270 deletions(-) delete mode 100644 examples/docker/README.md delete mode 100644 examples/docker/admin/.dockerignore delete mode 100644 examples/docker/admin/.gitignore delete mode 100644 examples/docker/admin/Dockerfile delete mode 100644 examples/docker/admin/addons/github.com/bosssauce/reference/LICENSE delete mode 100644 examples/docker/admin/addons/github.com/bosssauce/reference/README.md delete mode 100644 examples/docker/admin/addons/github.com/bosssauce/reference/reference.go delete mode 100644 examples/docker/admin/cmd/ponzu/LICENSE delete mode 100644 examples/docker/admin/cmd/ponzu/add.go delete mode 100644 examples/docker/admin/cmd/ponzu/cli_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/generate.go delete mode 100644 examples/docker/admin/cmd/ponzu/main.go delete mode 100644 examples/docker/admin/cmd/ponzu/options.go delete mode 100644 examples/docker/admin/cmd/ponzu/paths.go delete mode 100644 examples/docker/admin/cmd/ponzu/ponzu.json delete mode 100644 examples/docker/admin/cmd/ponzu/templates/gen-checkbox.tmpl delete mode 100644 examples/docker/admin/cmd/ponzu/templates/gen-content.tmpl delete mode 100644 examples/docker/admin/cmd/ponzu/templates/gen-custom.tmpl delete mode 100644 examples/docker/admin/cmd/ponzu/templates/gen-file.tmpl delete mode 100644 examples/docker/admin/cmd/ponzu/templates/gen-hidden.tmpl delete mode 100644 examples/docker/admin/cmd/ponzu/templates/gen-input.tmpl delete mode 100644 examples/docker/admin/cmd/ponzu/templates/gen-richtext.tmpl delete mode 100644 examples/docker/admin/cmd/ponzu/templates/gen-select.tmpl delete mode 100644 examples/docker/admin/cmd/ponzu/templates/gen-tags.tmpl delete mode 100644 examples/docker/admin/cmd/ponzu/templates/gen-textarea.tmpl delete mode 100644 examples/docker/admin/cmd/ponzu/usage.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/.gitignore delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/LICENSE delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/Makefile delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/README.md delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/appveyor.yml delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_386.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_amd64.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm64.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_linux.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_openbsd.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64le.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_s390x.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix_solaris.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_windows.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/boltsync_unix.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/doc.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/errors.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/quick_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/simulation_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/LICENSE delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/README.md delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/reference.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/.travis.yml delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/LICENSE delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/README.md delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/cache.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/converter.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/doc.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/LICENSE delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/README.md delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/LICENSE delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/README.md delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/doc.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/jwt.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/.hold delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/song.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/dom.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/editor.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/elements.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/repeaters.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/values.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/manager/manager.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/addon.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/api.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/addon/manager.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/admin.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/config/config.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/filesystem.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/handlers.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/server.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/common/js/jquery-2.1.4.min.js delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/common/js/util.js delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/admin.css delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/material-icons.css delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/css/materialize.min.css delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/icons-regular.woff2 delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.eot delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.ttf delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.woff delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Bold.woff2 delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.eot delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.ttf delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.woff delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Light.woff2 delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.eot delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.ttf delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.woff delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Medium.woff2 delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.eot delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.ttf delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.woff delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Regular.woff2 delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.eot delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.ttf delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.woff delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/fonts/roboto/Roboto-Thin.woff2 delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/img/ponzu-file.png delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/js/chart.bundle.min.js delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/dashboard/js/materialize.min.js delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/css/materialNote.css delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/css/materialNote.css.map delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.ttf delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.woff delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Bold.woff2 delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.ttf delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.woff delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Light.woff2 delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.ttf delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.woff delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Medium.woff2 delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.ttf delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.woff delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Regular.woff2 delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.ttf delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.woff delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/font/roboto/Roboto-Thin.woff2 delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/js/ckMaterializeOverrides.js delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/js/materialNote.js delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/license.txt delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_buttons.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_cards.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_collapsible.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_color.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_dropdown.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_form.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_global.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_grid.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_icons-material-design.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_materialbox.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_mixins.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_modal.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_navbar.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_normalize.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_prefixer.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_preloader.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_roboto.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_sideNav.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_slider.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_table_of_contents.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_tabs.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_toast.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_tooltip.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_typography.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_variables.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/_waves.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.date.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/components/date_picker/_default.time.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/materialNote.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/static/editor/sass/materialize.scss delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/upload/backup.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/upload/upload.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/admin/user/auth.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/backup.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/batch.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/analytics/init.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/cors.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/create.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/delete.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/gzip.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/handlers.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/hide.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/json.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/omit.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/push.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/record.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/search.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/server.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/api/update.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/auth.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/addon.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/backup.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/cache.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/config.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/content.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/index.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/init.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/search.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/db/user.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/item/item.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/item/types.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/devcerts.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/enable.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/system/tls/enabledev.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/.travis.yml delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/LICENSE delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/README.md delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/benchmarks_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/uuid.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/satori/go.uuid/uuid_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/LICENSE delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/README.md delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/gjson.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/gjson/logo.png delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/.travis.yml delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/LICENSE delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/README.md delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/logo.png delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/github.com/tidwall/sjson/sjson.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/autocert_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/cache_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/autocert/renewal_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/base64.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/bcrypt.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/context.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/context_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/go17.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/pre_go17.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/context/withtimeout_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/.gitignore delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/Dockerfile delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/Makefile delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/README delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/client_conn_pool.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/configure_transport.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/errors.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/errors_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/fixed_buffer.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/fixed_buffer_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/flow.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/flow_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/frame.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/frame_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go16.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go17.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go17_not18.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go18.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/go18_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/gotrack.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/gotrack_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/.gitignore delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/Makefile delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/README delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/h2demo.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/launch.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.key delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.pem delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/rootCA.srl delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/server.crt delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2demo/server.key delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2i/README.md delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/h2i/h2i.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/headermap.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/encode.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/encode_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/hpack.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/hpack_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/huffman.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/hpack/tables.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/http2.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/http2_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go16.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go17.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/not_go18.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/pipe.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/pipe_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server_push_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/server_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/testdata/draft-ietf-httpbis-http2.xml delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/transport.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/transport_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/write.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_priority.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_priority_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_random.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_random_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/writesched_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/net/http2/z_spec_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/examples_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/transform.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/transform/transform_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/composition.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/composition_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/example_iter_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/example_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/forminfo.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/forminfo_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/input.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/iter.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/iter_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/maketables.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/norm_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/normalize.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/normalize_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/readwriter.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/readwriter_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/tables.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/transform.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/transform_test.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/trie.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/triegen.go delete mode 100644 examples/docker/admin/cmd/ponzu/vendor/golang.org/x/text/unicode/norm/ucd_test.go delete mode 100644 examples/docker/admin/content/.hold delete mode 100644 examples/docker/admin/content/song.go delete mode 100644 examples/docker/admin/deployment/README.md delete mode 100644 examples/docker/admin/deployment/sysv/ponzu-server delete mode 100755 examples/docker/admin/start_admin.sh delete mode 100644 examples/docker/docker-compose.yml delete mode 100644 examples/docker/web/Dockerfile delete mode 100644 examples/docker/web/nginx.conf delete mode 100644 examples/docker/web/public/css/main.css delete mode 100644 examples/docker/web/public/css/normalize.css delete mode 100644 examples/docker/web/public/css/skeleton.css delete mode 100644 examples/docker/web/public/index.html delete mode 100644 examples/docker/web/public/js/main.js (limited to 'examples') diff --git a/examples/docker/README.md b/examples/docker/README.md deleted file mode 100644 index 55566b1..0000000 --- a/examples/docker/README.md +++ /dev/null @@ -1,52 +0,0 @@ -## Example of Running Ponzu with Docker - -This docker-compose contains 2 docker containers: - -1. web - a basic nginx front end, with Javascript ajax accessing the /api -2. admin - an example ponzu container - -The admin contain is based on the official Ponzu Docker image **NEEDS LINK** - -### Running the example - -```bash -# build the containers -docker-compose build - -#start the containers in the background -docker-compose start -d -``` - -#### Then follow these steps: -1. Visit the http://localhost:3000/admin to configure Ponzu. -2. Add several songs http://localhost:3000/admin/contents?type=Song -3. Visit http://localhost:3000/ to see the rest service accessed via AJAX - -Stop the containers: -``` -docker-compose stop -``` - -### Web Container -This nginx web container takes any incoming requests and if it matches `/api*` or `/admin*` it will then route it to the exposed ports :8080 on the ponzu container - -### Ponzu - Admin Container - -The ponzu container has a small [startup script](./admin/start_admin_.sh) which symlinks and logs or database files into a Docker Volume. If you need access to the ponzu logs, it is exposed a Volume. - -#### Accessing the Ponzu terminal in Development - -Make sure you have no running docker images `docker ps`. Then use the following command to start an interactive shell into the docker container. - -```bash -# make sure the containers are built -docker-compose build - -# start and tty into the container -docker run -v $(pwd)/admin:/go/src/project -it docker_admin - -# run a ponzu command -ponzu generate content message title:"string" description:"string" -``` - -After the above generate command `message.go` content type is now available in your local filesystem. Use `docker-compose build` then `docker-compose up -d` to see the new model in the admin. diff --git a/examples/docker/admin/.dockerignore b/examples/docker/admin/.dockerignore deleted file mode 100644 index 771d49f..0000000 --- a/examples/docker/admin/.dockerignore +++ /dev/null @@ -1,8 +0,0 @@ -# These directories should not be copied over from the local machine -uploads -search -system.db -analytics.db - -# ponzu-server should be built from each startup -ponzu-server \ No newline at end of file diff --git a/examples/docker/admin/.gitignore b/examples/docker/admin/.gitignore deleted file mode 100644 index bcc10dc..0000000 --- a/examples/docker/admin/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -search -uploads -analytics.db -system.db -ponzu-server \ No newline at end of file diff --git a/examples/docker/admin/Dockerfile b/examples/docker/admin/Dockerfile deleted file mode 100644 index 5130818..0000000 --- a/examples/docker/admin/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM krismeister/ponzu - -ENV PONZU_SHARE /ponzu-share - -# This is where you want to mount your project: -ENV PROJECT_FOLDER /go/src/project - -VOLUME $PONZU_SHARE -RUN mkdir $PROJECT_FOLDER - -WORKDIR $PROJECT_FOLDER -EXPOSE 8080 - -# its better to run this in compose -# CMD [ "bash" , "/go/src/project/start_admin.sh start" ] \ No newline at end of file diff --git a/examples/docker/admin/addons/github.com/bosssauce/reference/LICENSE b/examples/docker/admin/addons/github.com/bosssauce/reference/LICENSE deleted file mode 100644 index 720d6cd..0000000 --- a/examples/docker/admin/addons/github.com/bosssauce/reference/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2016 Boss Sauce Creative, LLC. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/examples/docker/admin/addons/github.com/bosssauce/reference/README.md b/examples/docker/admin/addons/github.com/bosssauce/reference/README.md deleted file mode 100644 index 57f008c..0000000 --- a/examples/docker/admin/addons/github.com/bosssauce/reference/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Reference - -A Ponzu addon to embed a reference to a content type from within another content type in the CMS. diff --git a/examples/docker/admin/addons/github.com/bosssauce/reference/reference.go b/examples/docker/admin/addons/github.com/bosssauce/reference/reference.go deleted file mode 100644 index 753fa41..0000000 --- a/examples/docker/admin/addons/github.com/bosssauce/reference/reference.go +++ /dev/null @@ -1,150 +0,0 @@ -// Package reference is a Ponzu addon to enable content editors to create -// references to other content types which are stored as query strings within -// the referencer's content DB -package reference - -import ( - "bytes" - "encoding/json" - "fmt" - "html/template" - "log" - "strings" - - "github.com/ponzu-cms/ponzu/management/editor" - "github.com/ponzu-cms/ponzu/system/addon" -) - -// Select returns the []byte of a HTML element plus internal with a label. -// It also includes repeat controllers (+ / -) so the element can be -// dynamically multiplied or reduced. -// IMPORTANT: -// The `fieldName` argument will cause a panic if it is not exactly the string -// form of the struct field that this editor input is representing -func SelectRepeater(fieldName string, p interface{}, attrs map[string]string, contentType, tmplString string) []byte { - scope := editor.TagNameFromStructField(fieldName, p) - html := bytes.Buffer{} - _, err := html.WriteString(``) - if err != nil { - log.Println("Error writing HTML string to SelectRepeater buffer") - return nil - } - - if _, ok := attrs["class"]; ok { - attrs["class"] += " browser-default" - } else { - attrs["class"] = "browser-default" - } - - // find the field values in p to determine if an option is pre-selected - fieldVals := editor.ValueFromStructField(fieldName, p) - vals := strings.Split(fieldVals, "__ponzu") - - options, err := encodeDataToOptions(contentType, tmplString) - if err != nil { - log.Println("Error encoding data to options for", contentType, err) - return nil - } - - for _, val := range vals { - sel := editor.NewElement("select", attrs["label"], fieldName, p, attrs) - var opts []*editor.Element - - // provide a call to action for the select element - cta := &editor.Element{ - TagName: "option", - Attrs: map[string]string{"disabled": "true", "selected": "true"}, - Data: "Select an option...", - ViewBuf: &bytes.Buffer{}, - } - - // provide a selection reset (will store empty string in db) - reset := &editor.Element{ - TagName: "option", - Attrs: map[string]string{"value": ""}, - Data: "None", - ViewBuf: &bytes.Buffer{}, - } - - opts = append(opts, cta, reset) - - for k, v := range options { - optAttrs := map[string]string{"value": k} - if k == val { - optAttrs["selected"] = "true" - } - opt := &editor.Element{ - TagName: "option", - Attrs: optAttrs, - Data: v, - ViewBuf: &bytes.Buffer{}, - } - - opts = append(opts, opt) - } - - _, err := html.Write(editor.DOMElementWithChildrenSelect(sel, opts)) - if err != nil { - log.Println("Error writing DOMElementWithChildrenSelect to SelectRepeater buffer") - return nil - } - } - - _, err = html.WriteString("") - if err != nil { - log.Println("Error writing HTML string to SelectRepeater buffer") - return nil - } - - return append(html.Bytes(), editor.RepeatController(fieldName, p, "select", ".input-field")...) -} - -func encodeDataToOptions(contentType, tmplString string) (map[string]string, error) { - // encode all content type from db into options map - // options in form of map["/api/content?type=&id="]t.String() - options := make(map[string]string) - - var all map[string]interface{} - j := addon.ContentAll(contentType) - - err := json.Unmarshal(j, &all) - if err != nil { - return nil, err - } - - // make template for option html display - tmpl := template.Must(template.New(contentType).Parse(tmplString)) - - // make data something usable to iterate over and assign options - data := all["data"].([]interface{}) - - for i := range data { - item := data[i].(map[string]interface{}) - k := fmt.Sprintf("/api/content?type=%s&id=%.0f", contentType, item["id"].(float64)) - v := &bytes.Buffer{} - err := tmpl.Execute(v, item) - if err != nil { - return nil, fmt.Errorf( - "Error executing template for reference of %s: %s", - contentType, err.Error()) - } - - options[k] = v.String() - } - - return options, nil -} diff --git a/examples/docker/admin/cmd/ponzu/LICENSE b/examples/docker/admin/cmd/ponzu/LICENSE deleted file mode 100644 index 720d6cd..0000000 --- a/examples/docker/admin/cmd/ponzu/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2016 Boss Sauce Creative, LLC. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/examples/docker/admin/cmd/ponzu/add.go b/examples/docker/admin/cmd/ponzu/add.go deleted file mode 100644 index 05d6f16..0000000 --- a/examples/docker/admin/cmd/ponzu/add.go +++ /dev/null @@ -1,167 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "io" - "os" - "os/exec" - "path/filepath" - "strings" -) - -// use `go get` to download addon and add to $GOPATH/src, useful -// for IDE auto-import and code completion, then copy entire directory -// tree to project's ./addons folder -func getAddon(args []string) error { - - var cmdOptions []string - var addonPath = args[1] - - // Go get - cmdOptions = append(cmdOptions, "get", addonPath) - get := exec.Command(gocmd, cmdOptions...) - get.Stderr = os.Stderr - get.Stdout = os.Stdout - - err := get.Start() - if err != nil { - return addError(err) - } - err = get.Wait() - if err != nil { - return addError(err) - } - - // copy to ./addons folder - // resolve GOPATH - gopath, err := getGOPATH() - if err != nil { - return addError(err) - } - - pwd, err := os.Getwd() - if err != nil { - return addError(err) - } - - src := filepath.Join(gopath, "src", addonPath) - - // Need to strip the addon name for copyAll? - last := filepath.Base(addonPath) - dest := filepath.Join(pwd, "addons", strings.Replace(addonPath, last, "", 1)) - - err = replicateAll(src, dest) - if err != nil { - return addError(err) - } - return nil -} - -// this is distinct from copyAll() in that files are copied, not moved, -// since we also need them to remain in $GOPATH/src -// thanks to @markc of stack overflow for the copyFile and copyFileContents functions -func replicateAll(src, dst string) error { - err := filepath.Walk(src, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - sep := string(filepath.Separator) - - // base == the ponzu project dir + string(filepath.Separator) - parts := strings.Split(src, sep) - base := strings.Join(parts[:len(parts)-1], sep) - base += sep - - target := filepath.Join(dst, path[len(base):]) - - // if its a directory, make dir in dst - if info.IsDir() { - err := os.MkdirAll(target, os.ModeDir|os.ModePerm) - if err != nil { - return err - } - } else { - // if its a file, copy file to dir of dst - err = copyFile(path, target) - if err != nil { - return err - } - } - - return nil - }) - if err != nil { - return err - } - - return nil -} - -// copyFile copies a file from src to dst. if src and dst files exist, and are -// the same, then return success. Otherise, attempt to create a hard link -// between the two files. If that fail, copy the file contents from src to dst. -// thanks to Stack Overflow -func copyFile(src, dst string) (err error) { - sfi, err := os.Stat(src) - if err != nil { - return - } - if !sfi.Mode().IsRegular() { - // cannot copy non-regular files (e.g., directories, - // symlinks, devices, etc.) - return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String()) - } - dfi, err := os.Stat(dst) - if err != nil { - if !os.IsNotExist(err) { - return - } - } else { - if !(dfi.Mode().IsRegular()) { - return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String()) - } - if os.SameFile(sfi, dfi) { - return - } - } - if err = os.Link(src, dst); err == nil { - return - } - err = copyFileContents(src, dst) - return -} - -// copyFileContents copies the contents of the file named src to the file named -// by dst. The file will be created if it does not already exist. If the -// destination file exists, all it's contents will be replaced by the contents -// of the source file. -// Thanks for Stack Overflow -func copyFileContents(src, dst string) (err error) { - in, err := os.Open(src) - if err != nil { - return - } - defer in.Close() - out, err := os.Create(dst) - if err != nil { - return - } - defer func() { - cerr := out.Close() - if err == nil { - err = cerr - } - }() - if _, err = io.Copy(out, in); err != nil { - return - } - err = out.Sync() - return -} - -// generic error return -func addError(err error) error { - return errors.New("Ponzu add failed. " + "\n" + err.Error()) -} diff --git a/examples/docker/admin/cmd/ponzu/cli_test.go b/examples/docker/admin/cmd/ponzu/cli_test.go deleted file mode 100644 index 76feac3..0000000 --- a/examples/docker/admin/cmd/ponzu/cli_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package main - -import "testing" - -func TestParseType(t *testing.T) { - // blog title:string Author:string PostCategory:string content:string some_thing:int - args := []string{ - "blog", "title:string", "Author:string", - "PostCategory:string", "content:string", - "some_thing:int", "Some_otherThing:float64", - } - - gt, err := parseType(args) - if err != nil { - t.Errorf("Failed: %s", err.Error()) - } - - if gt.Name != "Blog" { - t.Errorf("Expected %s, got: %s", "Blog", gt.Name) - } -} - -func TestFieldJSONName(t *testing.T) { - cases := map[string]string{ - "_T": "t", - "T": "t", - "_tT_": "t_t_", - "TestCapsNoSym": "test_caps_no_sym", - "test_Some_caps_Sym": "test_some_caps_sym", - "testnocaps": "testnocaps", - "_Test_Caps_Sym_odd": "test_caps_sym_odd", - "test-hyphen": "test-hyphen", - "Test-hyphen-Caps": "test-hyphen-caps", - "Test-Hyphen_Sym-Caps": "test-hyphen_sym-caps", - } - - for input, expected := range cases { - output := fieldJSONName(input) - if output != expected { - t.Errorf("Expected: %s, got: %s", expected, output) - } - } -} - -func TestFieldName(t *testing.T) { - cases := map[string]string{ - "_T": "T", - "T": "T", - "_tT_": "TT", - "TestCapsNoSym": "TestCapsNoSym", - "test_Some_caps_Sym": "TestSomeCapsSym", - "testnocaps": "Testnocaps", - "_Test_Caps_Sym_odd": "TestCapsSymOdd", - "test-hyphen": "TestHyphen", - "Test-hyphen-Caps": "TestHyphenCaps", - "Test-Hyphen_Sym-Caps": "TestHyphenSymCaps", - } - - for input, expected := range cases { - output := fieldName(input) - if output != expected { - t.Errorf("Expected: %s, got: %s", expected, output) - } - } -} diff --git a/examples/docker/admin/cmd/ponzu/generate.go b/examples/docker/admin/cmd/ponzu/generate.go deleted file mode 100644 index a4a9d2c..0000000 --- a/examples/docker/admin/cmd/ponzu/generate.go +++ /dev/null @@ -1,263 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "go/format" - "os" - "path/filepath" - "strings" - "text/template" -) - -type generateType struct { - Name string - Initial string - Fields []generateField -} - -type generateField struct { - Name string - Initial string - TypeName string - JSONName string - View string -} - -// blog title:string Author:string PostCategory:string content:string some_thing:int -func parseType(args []string) (generateType, error) { - t := generateType{ - Name: fieldName(args[0]), - } - t.Initial = strings.ToLower(string(t.Name[0])) - - fields := args[1:] - for _, field := range fields { - f, err := parseField(field, t) - if err != nil { - return generateType{}, err - } - // NEW - // set initial (1st character of the type's name) on field so we don't need - // to set the template variable like was done in prior version - f.Initial = t.Initial - - t.Fields = append(t.Fields, f) - } - - return t, nil -} - -func parseField(raw string, gt generateType) (generateField, error) { - // contents:string or // contents:string:richtext - if !strings.Contains(raw, ":") { - return generateField{}, fmt.Errorf("Invalid generate argument. [%s]", raw) - } - - data := strings.Split(raw, ":") - - field := generateField{ - Name: fieldName(data[0]), - Initial: gt.Initial, - TypeName: strings.ToLower(data[1]), - JSONName: fieldJSONName(data[0]), - } - - fieldType := "input" - if len(data) == 3 { - fieldType = data[2] - } - - err := setFieldView(&field, fieldType) - if err != nil { - return generateField{}, err - } - - return field, nil -} - -// get the initial field name passed and check it for all possible cases -// MyTitle:string myTitle:string my_title:string -> MyTitle -// error-message:string -> ErrorMessage -func fieldName(name string) string { - // remove _ or - if first character - if name[0] == '-' || name[0] == '_' { - name = name[1:] - } - - // remove _ or - if last character - if name[len(name)-1] == '-' || name[len(name)-1] == '_' { - name = name[:len(name)-1] - } - - // upcase the first character - name = strings.ToUpper(string(name[0])) + name[1:] - - // remove _ or - character, and upcase the character immediately following - for i := 0; i < len(name); i++ { - r := rune(name[i]) - if isUnderscore(r) || isHyphen(r) { - up := strings.ToUpper(string(name[i+1])) - name = name[:i] + up + name[i+2:] - } - } - - return name -} - -// get the initial field name passed and convert to json-like name -// MyTitle:string myTitle:string my_title:string -> my_title -// error-message:string -> error-message -func fieldJSONName(name string) string { - // remove _ or - if first character - if name[0] == '-' || name[0] == '_' { - name = name[1:] - } - - // downcase the first character - name = strings.ToLower(string(name[0])) + name[1:] - - // check for uppercase character, downcase and insert _ before it if i-1 - // isn't already _ or - - for i := 0; i < len(name); i++ { - r := rune(name[i]) - if isUpper(r) { - low := strings.ToLower(string(r)) - if name[i-1] == '_' || name[i-1] == '-' { - name = name[:i] + low + name[i+1:] - } else { - name = name[:i] + "_" + low + name[i+1:] - } - } - } - - return name -} - -// set the specified view inside the editor field for a generated field for a type -func setFieldView(field *generateField, viewType string) error { - var err error - var tmpl *template.Template - buf := &bytes.Buffer{} - - pwd, err := os.Getwd() - if err != nil { - return err - } - - tmplDir := filepath.Join(pwd, "cmd", "ponzu", "templates") - tmplFrom := func(filename string) (*template.Template, error) { - return template.ParseFiles(filepath.Join(tmplDir, filename)) - } - - viewType = strings.ToLower(viewType) - switch viewType { - case "checkbox": - tmpl, err = tmplFrom("gen-checkbox.tmpl") - case "custom": - tmpl, err = tmplFrom("gen-custom.tmpl") - case "file": - tmpl, err = tmplFrom("gen-file.tmpl") - case "hidden": - tmpl, err = tmplFrom("gen-hidden.tmpl") - case "input", "text": - tmpl, err = tmplFrom("gen-input.tmpl") - case "richtext": - tmpl, err = tmplFrom("gen-richtext.tmpl") - case "select": - tmpl, err = tmplFrom("gen-select.tmpl") - case "textarea": - tmpl, err = tmplFrom("gen-textarea.tmpl") - case "tags": - tmpl, err = tmplFrom("gen-tags.tmpl") - default: - msg := fmt.Sprintf("'%s' is not a recognized view type. Using 'input' instead.", viewType) - fmt.Println(msg) - tmpl, err = tmplFrom("gen-input.tmpl") - } - - if err != nil { - return err - } - - err = tmpl.Execute(buf, field) - if err != nil { - return err - } - - field.View = buf.String() - - return nil -} - -func isUpper(char rune) bool { - if char >= 'A' && char <= 'Z' { - return true - } - - return false -} - -func isUnderscore(char rune) bool { - return char == '_' -} - -func isHyphen(char rune) bool { - return char == '-' -} - -func generateContentType(args []string) error { - name := args[0] - fileName := strings.ToLower(name) + ".go" - - // open file in ./content/ dir - // if exists, alert user of conflict - pwd, err := os.Getwd() - if err != nil { - return err - } - - contentDir := filepath.Join(pwd, "content") - filePath := filepath.Join(contentDir, fileName) - - if _, err := os.Stat(filePath); !os.IsNotExist(err) { - return fmt.Errorf("Please remove '%s' before executing this command.", fileName) - } - - // no file exists.. ok to write new one - file, err := os.Create(filePath) - defer file.Close() - if err != nil { - return err - } - - // parse type info from args - gt, err := parseType(args) - if err != nil { - return fmt.Errorf("Failed to parse type args: %s", err.Error()) - } - - tmplPath := filepath.Join(pwd, "cmd", "ponzu", "templates", "gen-content.tmpl") - tmpl, err := template.ParseFiles(tmplPath) - if err != nil { - return fmt.Errorf("Failed to parse template: %s", err.Error()) - } - - buf := &bytes.Buffer{} - err = tmpl.Execute(buf, gt) - if err != nil { - return fmt.Errorf("Failed to execute template: %s", err.Error()) - } - - fmtBuf, err := format.Source(buf.Bytes()) - if err != nil { - return fmt.Errorf("Failed to format template: %s", err.Error()) - } - - _, err = file.Write(fmtBuf) - if err != nil { - return fmt.Errorf("Failed to write generated file buffer: %s", err.Error()) - } - - return nil -} diff --git a/examples/docker/admin/cmd/ponzu/main.go b/examples/docker/admin/cmd/ponzu/main.go deleted file mode 100644 index b3dc708..0000000 --- a/examples/docker/admin/cmd/ponzu/main.go +++ /dev/null @@ -1,293 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "log" - "net/http" - "os" - "os/exec" - "path/filepath" - "strings" - - "github.com/ponzu-cms/ponzu/system/admin" - "github.com/ponzu-cms/ponzu/system/api" - "github.com/ponzu-cms/ponzu/system/api/analytics" - "github.com/ponzu-cms/ponzu/system/db" - "github.com/ponzu-cms/ponzu/system/tls" - - _ "github.com/ponzu-cms/ponzu/content" -) - -var ( - usage = usageHeader + usageNew + usageGenerate + - usageBuild + usageRun + usageUpgrade + usageAdd + usageVersion - port int - httpsport int - https bool - devhttps bool - cli bool - - // for ponzu internal / core development - dev bool - fork string - gocmd string -) - -func main() { - flag.Usage = func() { - fmt.Println(usage) - } - - flag.IntVar(&port, "port", 8080, "port for ponzu to bind its HTTP listener") - flag.IntVar(&httpsport, "httpsport", 443, "port for ponzu to bind its HTTPS listener") - flag.BoolVar(&https, "https", false, "enable automatic TLS/SSL certificate management") - flag.BoolVar(&devhttps, "devhttps", false, "[dev environment] enable automatic TLS/SSL certificate management") - flag.BoolVar(&dev, "dev", false, "modify environment for Ponzu core development") - flag.BoolVar(&cli, "cli", false, "specify that information should be returned about the CLI, not project") - flag.StringVar(&fork, "fork", "", "modify repo source for Ponzu core development") - flag.StringVar(&gocmd, "gocmd", "go", "custom go command if using beta or new release of Go") - flag.Parse() - - args := flag.Args() - - if len(args) < 1 { - fmt.Println(usage) - os.Exit(0) - } - - switch args[0] { - case "help", "h": - if len(args) < 2 { - fmt.Println(usageHelp) - fmt.Println(usage) - os.Exit(0) - } - - switch args[1] { - case "new": - fmt.Println(usageNew) - os.Exit(0) - - case "generate", "gen", "g": - fmt.Println(usageGenerate) - os.Exit(0) - - case "build": - fmt.Println(usageBuild) - os.Exit(0) - - case "run": - fmt.Println(usageRun) - os.Exit(0) - - case "upgrade": - fmt.Println(usageUpgrade) - os.Exit(0) - - case "version", "v": - fmt.Println(usageVersion) - os.Exit(0) - - case "add", "a": - fmt.Println(usageAdd) - os.Exit(0) - } - - case "new": - if len(args) < 2 { - fmt.Println(usageNew) - os.Exit(0) - } - - err := newProjectInDir(args[1]) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - case "generate", "gen", "g": - if len(args) < 3 { - fmt.Println(usageGenerate) - os.Exit(0) - } - - // check what we are asked to generate - switch args[1] { - case "content", "c": - err := generateContentType(args[2:]) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - default: - msg := fmt.Sprintf("Generator '%s' is not implemented.", args[1]) - fmt.Println(msg) - } - - case "build": - err := buildPonzuServer(args) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - case "run": - var addTLS string - if https { - addTLS = "--https" - } else { - addTLS = "--https=false" - } - - if devhttps { - addTLS = "--devhttps" - } - - var services string - if len(args) > 1 { - services = args[1] - } else { - services = "admin,api" - } - - name := buildOutputName() - buildPathName := strings.Join([]string{".", name}, string(filepath.Separator)) - serve := exec.Command(buildPathName, - fmt.Sprintf("--port=%d", port), - fmt.Sprintf("--httpsport=%d", httpsport), - addTLS, - "serve", - services, - ) - serve.Stderr = os.Stderr - serve.Stdout = os.Stdout - - err := serve.Run() - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - case "serve", "s": - db.Init() - defer db.Close() - - analytics.Init() - defer analytics.Close() - - if len(args) > 1 { - services := strings.Split(args[1], ",") - - for _, service := range services { - if service == "api" { - api.Run() - } else if service == "admin" { - admin.Run() - } else { - fmt.Println("To execute 'ponzu serve', you must specify which service to run.") - fmt.Println("$ ponzu --help") - os.Exit(1) - } - } - } - - // save the https port the system is listening on - err := db.PutConfig("https_port", fmt.Sprintf("%d", httpsport)) - if err != nil { - log.Fatalln("System failed to save config. Please try to run again.", err) - } - - // cannot run production HTTPS and development HTTPS together - if devhttps { - fmt.Println("Enabling self-signed HTTPS... [DEV]") - - go tls.EnableDev() - fmt.Println("Server listening on https://localhost:10443 for requests... [DEV]") - fmt.Println("----") - fmt.Println("If your browser rejects HTTPS requests, try allowing insecure connections on localhost.") - fmt.Println("on Chrome, visit chrome://flags/#allow-insecure-localhost") - - } else if https { - fmt.Println("Enabling HTTPS...") - - go tls.Enable() - fmt.Printf("Server listening on :%s for HTTPS requests...\n", db.ConfigCache("https_port").(string)) - } - - // save the https port the system is listening on so internal system can make - // HTTP api calls while in dev or production w/o adding more cli flags - err = db.PutConfig("http_port", fmt.Sprintf("%d", port)) - if err != nil { - log.Fatalln("System failed to save config. Please try to run again.", err) - } - - fmt.Printf("Server listening on :%d for HTTP requests...\n", port) - fmt.Println("\nvisit `/admin` to get started.") - log.Fatalln(http.ListenAndServe(fmt.Sprintf(":%d", port), nil)) - - case "version", "v": - // read ponzu.json value to Stdout - - p, err := ponzu(cli) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - fmt.Fprintf(os.Stdout, "Ponzu v%s\n", p["version"]) - - case "upgrade": - // confirm since upgrade will replace Ponzu core files - path, err := os.Getwd() - if err != nil { - fmt.Println("Failed to find current directory.", err) - os.Exit(1) - } - - fmt.Println("Only files you added to this directory, 'addons' and 'content' will be preserved.") - fmt.Println("Upgrade this project? (y/N):") - - answer, err := getAnswer() - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - switch answer { - case "n", "no", "\r\n", "\n", "": - fmt.Println("") - - case "y", "yes": - err := upgradePonzuProjectDir(path) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - default: - fmt.Println("Input not recognized. No upgrade made. Answer as 'y' or 'n' only.") - } - - case "add", "a": - // expecting two args, add and the go gettable package uri - if len(args) < 2 { - fmt.Println(usageAdd) - os.Exit(0) - } - - err := getAddon(args) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - case "": - fmt.Println(usage) - fmt.Println(usageHelp) - - default: - fmt.Println(usage) - fmt.Println(usageHelp) - } -} diff --git a/examples/docker/admin/cmd/ponzu/options.go b/examples/docker/admin/cmd/ponzu/options.go deleted file mode 100644 index 77e842c..0000000 --- a/examples/docker/admin/cmd/ponzu/options.go +++ /dev/null @@ -1,489 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "strings" - "time" -) - -func newProjectInDir(path string) error { - // set path to be nested inside $GOPATH/src - gopath, err := getGOPATH() - if err != nil { - return err - } - path = filepath.Join(gopath, "src", path) - - // check if anything exists at the path, ask if it should be overwritten - if _, err = os.Stat(path); !os.IsNotExist(err) { - fmt.Println("Path exists, overwrite contents? (y/N):") - - answer, err := getAnswer() - if err != nil { - return err - } - - switch answer { - case "n", "no", "\r\n", "\n", "": - fmt.Println("") - - case "y", "yes": - err := os.RemoveAll(path) - if err != nil { - return fmt.Errorf("Failed to overwrite %s. \n%s", path, err) - } - - return createProjectInDir(path) - - default: - fmt.Println("Input not recognized. No files overwritten. Answer as 'y' or 'n' only.") - } - - return nil - } - - return createProjectInDir(path) -} - -var ponzuRepo = []string{"github.com", "ponzu-cms", "ponzu"} - -func getAnswer() (string, error) { - var answer string - _, err := fmt.Scanf("%s\n", &answer) - if err != nil { - if err.Error() == "unexpected newline" { - answer = "" - } else { - return "", err - } - } - - answer = strings.ToLower(answer) - - return answer, nil -} - -func createProjectInDir(path string) error { - gopath, err := getGOPATH() - if err != nil { - return err - } - repo := ponzuRepo - local := filepath.Join(gopath, "src", filepath.Join(repo...)) - network := "https://" + strings.Join(repo, "/") + ".git" - if !strings.HasPrefix(path, gopath) { - path = filepath.Join(gopath, path) - } - - // create the directory or overwrite it - err = os.MkdirAll(path, os.ModeDir|os.ModePerm) - if err != nil { - return err - } - - if dev { - if fork != "" { - local = filepath.Join(gopath, "src", fork) - } - - devClone := exec.Command("git", "clone", local, "--branch", "ponzu-dev", "--single-branch", path) - devClone.Stdout = os.Stdout - devClone.Stderr = os.Stderr - - err = devClone.Start() - if err != nil { - return err - } - - err = devClone.Wait() - if err != nil { - return err - } - - err = vendorCorePackages(path) - if err != nil { - return err - } - - fmt.Println("Dev build cloned from " + local + ":ponzu-dev") - return nil - } - - // try to git clone the repository from the local machine's $GOPATH - localClone := exec.Command("git", "clone", local, path) - localClone.Stdout = os.Stdout - localClone.Stderr = os.Stderr - - err = localClone.Start() - if err != nil { - return err - } - err = localClone.Wait() - if err != nil { - fmt.Println("Couldn't clone from", local, "- trying network...") - - // try to git clone the repository over the network - networkClone := exec.Command("git", "clone", network, path) - networkClone.Stdout = os.Stdout - networkClone.Stderr = os.Stderr - - err = networkClone.Start() - if err != nil { - fmt.Println("Network clone failed to start. Try again and make sure you have a network connection.") - return err - } - err = networkClone.Wait() - if err != nil { - fmt.Println("Network clone failure.") - // failed - return fmt.Errorf("Failed to clone files from local machine [%s] and over the network [%s].\n%s", local, network, err) - } - } - - // create an internal vendor directory in ./cmd/ponzu and move content, - // management and system packages into it - err = vendorCorePackages(path) - if err != nil { - return err - } - - gitDir := filepath.Join(path, ".git") - err = os.RemoveAll(gitDir) - if err != nil { - fmt.Println("Failed to remove .git directory from your project path. Consider removing it manually.") - } - - fmt.Println("New ponzu project created at", path) - return nil -} - -func vendorCorePackages(path string) error { - vendorPath := filepath.Join(path, "cmd", "ponzu", "vendor", "github.com", "ponzu-cms", "ponzu") - err := os.MkdirAll(vendorPath, os.ModeDir|os.ModePerm) - if err != nil { - return err - } - - dirs := []string{"content", "management", "system"} - for _, dir := range dirs { - err = os.Rename(filepath.Join(path, dir), filepath.Join(vendorPath, dir)) - if err != nil { - return err - } - } - - // create a user content directory at project root - contentPath := filepath.Join(path, "content") - err = os.Mkdir(contentPath, os.ModeDir|os.ModePerm) - if err != nil { - return err - } - - return nil -} - -func copyFileNoRoot(src, dst string) error { - noRoot := strings.Split(src, string(filepath.Separator))[1:] - path := filepath.Join(noRoot...) - dstFile, err := os.Create(filepath.Join(dst, path)) - defer dstFile.Close() - if err != nil { - return err - } - - srcFile, err := os.Open(src) - defer srcFile.Close() - if err != nil { - return err - } - - _, err = io.Copy(dstFile, srcFile) - if err != nil { - return err - } - - return nil -} - -func copyFilesWarnConflicts(srcDir, dstDir string, conflicts []string) error { - err := filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - for _, conflict := range conflicts { - if info.Name() == conflict { - fmt.Println("Ponzu couldn't fully build your project:") - fmt.Println("You must rename the following file, as it conflicts with Ponzu core:") - fmt.Println(path) - fmt.Println("") - fmt.Println("Once the files above have been renamed, run '$ ponzu build' to retry.") - return errors.New("Ponzu has very few internal conflicts, sorry for the inconvenience.") - } - } - - if info.IsDir() { - // don't copy root directory - if path == srcDir { - return nil - } - - if len(path) > len(srcDir) { - path = path[len(srcDir)+1:] - } - dir := filepath.Join(dstDir, path) - err := os.MkdirAll(dir, os.ModeDir|os.ModePerm) - if err != nil { - return err - } - - return nil - } - - err = copyFileNoRoot(path, dstDir) - if err != nil { - return err - } - - return nil - }) - if err != nil { - return err - } - - return nil -} - -func emptyDir(path string) error { - d, err := os.Open(path) - if err != nil { - return err - } - defer d.Close() - - names, err := d.Readdirnames(-1) - if err != nil { - return err - } - for _, name := range names { - err = os.RemoveAll(filepath.Join(path, name)) - if err != nil { - return err - } - } - - return nil -} - -func buildPonzuServer(args []string) error { - pwd, err := os.Getwd() - if err != nil { - return err - } - - // copy all ./content files to internal vendor directory - src := "content" - dst := filepath.Join("cmd", "ponzu", "vendor", "github.com", "ponzu-cms", "ponzu", "content") - err = emptyDir(dst) - if err != nil { - return err - } - err = copyFilesWarnConflicts(src, dst, []string{"doc.go"}) - if err != nil { - return err - } - - // copy all ./addons files & dirs to internal vendor directory - src = "addons" - dst = filepath.Join("cmd", "ponzu", "vendor") - err = copyFilesWarnConflicts(src, dst, nil) - if err != nil { - return err - } - - // execute go build -o ponzu-cms cmd/ponzu/*.go - buildOptions := []string{"build", "-o", buildOutputName()} - cmdBuildFiles := []string{ - "main.go", "options.go", "generate.go", - "usage.go", "paths.go", "add.go", - } - var cmdBuildFilePaths []string - for _, file := range cmdBuildFiles { - p := filepath.Join(pwd, "cmd", "ponzu", file) - cmdBuildFilePaths = append(cmdBuildFilePaths, p) - } - - build := exec.Command(gocmd, append(buildOptions, cmdBuildFilePaths...)...) - build.Stderr = os.Stderr - build.Stdout = os.Stdout - - err = build.Start() - if err != nil { - return errors.New("Ponzu build step failed. Please try again. " + "\n" + err.Error()) - - } - err = build.Wait() - if err != nil { - return errors.New("Ponzu build step failed. Please try again. " + "\n" + err.Error()) - - } - - return nil -} - -func copyAll(src, dst string) error { - err := filepath.Walk(src, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - sep := string(filepath.Separator) - - // base == the ponzu project dir + string(filepath.Separator) - parts := strings.Split(src, sep) - base := strings.Join(parts[:len(parts)-1], sep) - base += sep - - target := filepath.Join(dst, path[len(base):]) - - // if its a directory, make dir in dst - if info.IsDir() { - err := os.MkdirAll(target, os.ModeDir|os.ModePerm) - if err != nil { - return err - } - } else { - // if its a file, move file to dir of dst - err = os.Rename(path, target) - if err != nil { - return err - } - } - - return nil - }) - if err != nil { - return err - } - - return nil -} - -func upgradePonzuProjectDir(path string) error { - core := []string{ - ".gitattributes", - "LICENSE", - "ponzu-banner.png", - "README.md", - "cmd", - "deployment", - "management", - "system", - } - - stamp := fmt.Sprintf("ponzu-%d.bak", time.Now().Unix()) - temp := filepath.Join(os.TempDir(), stamp) - err := os.Mkdir(temp, os.ModeDir|os.ModePerm) - if err != nil { - return err - } - - // track non-Ponzu core items (added by user) - var user []os.FileInfo - list, err := ioutil.ReadDir(path) - if err != nil { - return err - } - - for _, item := range list { - // check if in core - var isCore bool - for _, name := range core { - if item.Name() == name { - isCore = true - break - } - } - - if !isCore { - user = append(user, item) - } - } - - // move non-Ponzu files to temp location - fmt.Println("Preserving files to be restored after upgrade...") - for _, item := range user { - src := filepath.Join(path, item.Name()) - if item.IsDir() { - err := os.Mkdir(filepath.Join(temp, item.Name()), os.ModeDir|os.ModePerm) - if err != nil { - return err - } - } - - err := copyAll(src, temp) - if err != nil { - return err - } - - fmt.Println(" [-]", item.Name()) - - } - - // remove all files in path - for _, item := range list { - err := os.RemoveAll(filepath.Join(path, item.Name())) - if err != nil { - return fmt.Errorf("Failed to remove old Ponzu files.\n%s", err) - } - } - - err = createProjectInDir(path) - if err != nil { - fmt.Println("") - fmt.Println("Upgrade failed...") - fmt.Println("Your code is backed up at the following location:") - fmt.Println(temp) - fmt.Println("") - fmt.Println("Manually create a new Ponzu project here and copy those files within it to fully restore.") - fmt.Println("") - return err - } - - // move non-Ponzu files from temp location backed - restore, err := ioutil.ReadDir(temp) - if err != nil { - return err - } - - fmt.Println("Restoring files preserved before upgrade...") - for _, r := range restore { - p := filepath.Join(temp, r.Name()) - err = copyAll(p, path) - if err != nil { - fmt.Println("Couldn't merge your previous project files with upgraded one.") - fmt.Println("Manually copy your files from the following directory:") - fmt.Println(temp) - return err - } - - fmt.Println(" [+]", r.Name()) - } - - // clean-up - backups := []string{filepath.Join(path, stamp), temp} - for _, bak := range backups { - err := os.RemoveAll(bak) - if err != nil { - return err - } - } - - return nil -} diff --git a/examples/docker/admin/cmd/ponzu/paths.go b/examples/docker/admin/cmd/ponzu/paths.go deleted file mode 100644 index 8d5407f..0000000 --- a/examples/docker/admin/cmd/ponzu/paths.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "os" - "os/user" - "path/filepath" - "runtime" - "strings" -) - -// buildOutputName returns the correct ponzu-server file name -// based on the host Operating System -func buildOutputName() string { - if runtime.GOOS == "windows" { - return "ponzu-server.exe" - } - - return "ponzu-server" -} - -// resolve GOPATH. In 1.8 can be default, or custom. A custom GOPATH can -// also contain multiple paths, in which case 'go get' uses the first -func getGOPATH() (string, error) { - var gopath string - gopath = os.Getenv("GOPATH") - if gopath == "" { - // not set, find the default - usr, err := user.Current() - if err != nil { - return gopath, err - } - gopath = filepath.Join(usr.HomeDir, "go") - } else { - // parse out in case of multiple, retain first - if runtime.GOOS == "windows" { - gopaths := strings.Split(gopath, ";") - gopath = gopaths[0] - } else { - gopaths := strings.Split(gopath, ":") - gopath = gopaths[0] - } - } - return gopath, nil -} diff --git a/examples/docker/admin/cmd/ponzu/ponzu.json b/examples/docker/admin/cmd/ponzu/ponzu.json deleted file mode 100644 index 3b76ad7..0000000 --- a/examples/docker/admin/cmd/ponzu/ponzu.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "version": "0.9.1" -} diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-checkbox.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-checkbox.tmpl deleted file mode 100644 index 23713dc..0000000 --- a/examples/docker/admin/cmd/ponzu/templates/gen-checkbox.tmpl +++ /dev/null @@ -1,5 +0,0 @@ -View: editor.Checkbox("{{ .Name }}", {{ .Initial }}, map[string]string{ - "label": "{{ .Name }}", -}, map[string]string{ - // "value": "Display Name", -}), \ No newline at end of file diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-content.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-content.tmpl deleted file mode 100644 index 2d92b88..0000000 --- a/examples/docker/admin/cmd/ponzu/templates/gen-content.tmpl +++ /dev/null @@ -1,39 +0,0 @@ -package content - -import ( - "fmt" - - "github.com/ponzu-cms/ponzu/management/editor" - "github.com/ponzu-cms/ponzu/system/item" -) - -type {{ .Name }} struct { - item.Item - - {{ range .Fields }}{{ .Name }} {{ .TypeName }} `json:"{{ .JSONName }}"` - {{ end }} -} - -// MarshalEditor writes a buffer of html to edit a {{ .Name }} within the CMS -// and implements editor.Editable -func ({{ .Initial }} *{{ .Name }}) MarshalEditor() ([]byte, error) { - view, err := editor.Form({{ .Initial }}, - // Take note that the first argument to these Input-like functions - // is the string version of each {{ .Name }} field, and must follow - // this pattern for auto-decoding and auto-encoding reasons: - {{ range .Fields }}editor.Field{ - {{ .View }} - }, - {{ end }} - ) - - if err != nil { - return nil, fmt.Errorf("Failed to render {{ .Name }} editor view: %s", err.Error()) - } - - return view, nil -} - -func init() { - item.Types["{{ .Name }}"] = func() interface{} { return new({{ .Name }}) } -} \ No newline at end of file diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-custom.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-custom.tmpl deleted file mode 100644 index 6079f8b..0000000 --- a/examples/docker/admin/cmd/ponzu/templates/gen-custom.tmpl +++ /dev/null @@ -1,6 +0,0 @@ -View: []byte(` -
- - -
- `), \ No newline at end of file diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-file.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-file.tmpl deleted file mode 100644 index 7bcaa4c..0000000 --- a/examples/docker/admin/cmd/ponzu/templates/gen-file.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -View: editor.File("{{ .Name }}", {{ .Initial }}, map[string]string{ - "label": "{{ .Name }}", - "placeholder": "Upload the {{ .Name }} here", -}), \ No newline at end of file diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-hidden.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-hidden.tmpl deleted file mode 100644 index 4b00456..0000000 --- a/examples/docker/admin/cmd/ponzu/templates/gen-hidden.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -View: editor.Input("{{ .Name }}", {{ .Initial }}, map[string]string{ - "type": "hidden", -}), \ No newline at end of file diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-input.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-input.tmpl deleted file mode 100644 index 8bea12a..0000000 --- a/examples/docker/admin/cmd/ponzu/templates/gen-input.tmpl +++ /dev/null @@ -1,5 +0,0 @@ -View: editor.Input("{{ .Name }}", {{ .Initial }}, map[string]string{ - "label": "{{ .Name }}", - "type": "text", - "placeholder": "Enter the {{ .Name }} here", -}), \ No newline at end of file diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-richtext.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-richtext.tmpl deleted file mode 100644 index c7ec18c..0000000 --- a/examples/docker/admin/cmd/ponzu/templates/gen-richtext.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -View: editor.Richtext("{{ .Name }}", {{ .Initial }}, map[string]string{ - "label": "{{ .Name }}", - "placeholder": "Enter the {{ .Name }} here", -}), \ No newline at end of file diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-select.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-select.tmpl deleted file mode 100644 index 509eb30..0000000 --- a/examples/docker/admin/cmd/ponzu/templates/gen-select.tmpl +++ /dev/null @@ -1,5 +0,0 @@ -View: editor.Select("{{ .Name }}", {{ .Initial }}, map[string]string{ - "label": "{{ .Name }}", -}, map[string]string{ - // "value": "Display Name", -}), \ No newline at end of file diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-tags.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-tags.tmpl deleted file mode 100644 index ca92c94..0000000 --- a/examples/docker/admin/cmd/ponzu/templates/gen-tags.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -View: editor.Tags("{{ .Name }}", {{ .Initial }}, map[string]string{ - "label": "{{ .Name }}", - "placeholder": "+{{ .Name }}", -}), \ No newline at end of file diff --git a/examples/docker/admin/cmd/ponzu/templates/gen-textarea.tmpl b/examples/docker/admin/cmd/ponzu/templates/gen-textarea.tmpl deleted file mode 100644 index af3dad8..0000000 --- a/examples/docker/admin/cmd/ponzu/templates/gen-textarea.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -View: editor.Textarea("{{ .Name }}", {{ .Initial }}, map[string]string{ - "label": "{{ .Name }}", - "placeholder": "Enter the {{ .Name }} here", -}), \ No newline at end of file diff --git a/examples/docker/admin/cmd/ponzu/usage.go b/examples/docker/admin/cmd/ponzu/usage.go deleted file mode 100644 index 939b0c0..0000000 --- a/examples/docker/admin/cmd/ponzu/usage.go +++ /dev/null @@ -1,201 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "path/filepath" - "time" -) - -var year = fmt.Sprintf("%d", time.Now().Year()) - -var usageHeader = ` -$ ponzu [flags] command - -Ponzu is a powerful and efficient open-source HTTP server framework and CMS. It -provides automatic, free, and secure HTTP/2 over TLS (certificates obtained via -[Let's Encrypt](https://letsencrypt.org)), a useful CMS and scaffolding to -generate set-up code, and a fast HTTP API on which to build modern applications. - -Ponzu is released under the BSD-3-Clause license (see LICENSE). -(c) 2016 - ` + year + ` Boss Sauce Creative, LLC - -COMMANDS: - -` - -var usageHelp = ` -help, h (command) - - Help command will print the usage for Ponzu, or if a command is entered, it - will show only the usage for that specific command. - - Example: - $ ponzu help generate - - -` - -var usageNew = ` -new - - Creates a 'ponzu' directory, or one by the name supplied as a parameter - immediately following the 'new' option in the $GOPATH/src directory. Note: - 'new' depends on the program 'git' and possibly a network connection. If - there is no local repository to clone from at the local machine's $GOPATH, - 'new' will attempt to clone the 'github.com/ponzu-cms/ponzu' package from - over the network. - - Example: - $ ponzu new myProject - > New ponzu project created at $GOPATH/src/myProject - - Errors will be reported, but successful commands retrun nothing. - - -` - -var usageGenerate = ` -generate, gen, g - - Generate boilerplate code for various Ponzu components, such as 'content'. - - Example: - $ ponzu gen content review title:"string" body:"string" rating:"int" tags:"[]string" - - The command above will generate a file 'content/review.go' with boilerplate - methods, as well as struct definition, and corresponding field tags like: - - type Review struct { - Title string ` + "`json:" + `"title"` + "`" + ` - Body string ` + "`json:" + `"body"` + "`" + ` - Rating int ` + "`json:" + `"rating"` + "`" + ` - Tags []string ` + "`json:" + `"tags"` + "`" + ` - } - - The generate command will intelligently parse more sophisticated field names - such as 'field_name' and convert it to 'FieldName' and vice versa, only where - appropriate as per common Go idioms. Errors will be reported, but successful - generate commands retrun nothing. - - -` - -var usageBuild = ` -[-gocmd=go] build - - From within your Ponzu project directory, running build will copy and move - the necessary files from your workspace into the vendored directory, and - will build/compile the project to then be run. - - Example: - $ ponzu build - (or) - $ ponzu -gocmd=go1.8rc1 build - - By providing the 'gocmd' flag, you can specify which Go command to build the - project, if testing a different release of Go. - - Errors will be reported, but successful build commands return nothing. - - -` - -var usageRun = ` -[[-port=8080] [--https|--devhttps]] run - - Starts the 'ponzu' HTTP server for the JSON API, Admin System, or both. - The segments, separated by a comma, describe which services to start, either - 'admin' (Admin System / CMS backend) or 'api' (JSON API), and, optionally, - if the server should utilize TLS encryption - served over HTTPS, which is - automatically managed using Let's Encrypt (https://letsencrypt.org) - - Example: - $ ponzu run - (or) - $ ponzu -port=8080 --https run admin,api - (or) - $ ponzu run admin - (or) - $ ponzu -port=8888 run api - - Defaults to '-port=8080 run admin,api' (running Admin & API on port 8080, without TLS) - - Note: - Admin and API cannot run on separate processes unless you use a copy of the - database, since the first process to open it receives a lock. If you intend - to run the Admin and API on separate processes, you must call them with the - 'ponzu' command independently. - - -` - -var usageUpgrade = ` -upgrade - - Will backup your own custom project code (like content, addons, uploads, etc) so - we can safely re-clone Ponzu from the latest version you have or from the network - if necessary. Before running '$ ponzu upgrade', you should update the 'ponzu' - package by running '$ go get -u github.com/ponzu-cms/ponzu/...' - - Example: - $ ponzu upgrade - - -` - -var usageVersion = ` -[--cli] version, v - - Prints the version of Ponzu your project is using. Must be called from - within a Ponzu project directory. - - Example: - $ ponzu version - > Ponzu v0.7.1 - (or) - $ ponzu --cli version - > Ponzu v0.7.2 - - -` - -var usageAdd = ` -add, a - - Downloads addon from specified import path to $GOPATH/src and copys it to the - current project's ./addons directory. Must be called from within a - Ponzu project directory. - - Example: - $ ponzu add github.com/bosssauce/fbscheduler - - -` - -func ponzu(isCLI bool) (map[string]interface{}, error) { - kv := make(map[string]interface{}) - - info := filepath.Join("cmd", "ponzu", "ponzu.json") - if isCLI { - gopath, err := getGOPATH() - if err != nil { - return nil, err - } - repo := filepath.Join(gopath, "src", "github.com", "ponzu-cms", "ponzu") - info = filepath.Join(repo, "cmd", "ponzu", "ponzu.json") - } - - b, err := ioutil.ReadFile(info) - if err != nil { - return nil, err - } - - err = json.Unmarshal(b, &kv) - if err != nil { - return nil, err - } - - return kv, nil -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/.gitignore b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/.gitignore deleted file mode 100644 index c7bd2b7..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -*.prof -*.test -*.swp -/bin/ diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/LICENSE b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/LICENSE deleted file mode 100644 index 004e77f..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 Ben Johnson - -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/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/Makefile b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/Makefile deleted file mode 100644 index e035e63..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -BRANCH=`git rev-parse --abbrev-ref HEAD` -COMMIT=`git rev-parse --short HEAD` -GOLDFLAGS="-X main.branch $(BRANCH) -X main.commit $(COMMIT)" - -default: build - -race: - @go test -v -race -test.run="TestSimulate_(100op|1000op)" - -# go get github.com/kisielk/errcheck -errcheck: - @errcheck -ignorepkg=bytes -ignore=os:Remove github.com/boltdb/bolt - -test: - @go test -v -cover . - @go test -v ./cmd/bolt - -.PHONY: fmt test diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/README.md b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/README.md deleted file mode 100644 index b654502..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/README.md +++ /dev/null @@ -1,858 +0,0 @@ -Bolt [![Coverage Status](https://coveralls.io/repos/boltdb/bolt/badge.svg?branch=master)](https://coveralls.io/r/boltdb/bolt?branch=master) [![GoDoc](https://godoc.org/github.com/boltdb/bolt?status.svg)](https://godoc.org/github.com/boltdb/bolt) ![Version](https://img.shields.io/badge/version-1.2.1-green.svg) -==== - -Bolt is a pure Go key/value store inspired by [Howard Chu's][hyc_symas] -[LMDB project][lmdb]. The goal of the project is to provide a simple, -fast, and reliable database for projects that don't require a full database -server such as Postgres or MySQL. - -Since Bolt is meant to be used as such a low-level piece of functionality, -simplicity is key. The API will be small and only focus on getting values -and setting values. That's it. - -[hyc_symas]: https://twitter.com/hyc_symas -[lmdb]: http://symas.com/mdb/ - -## Project Status - -Bolt is stable, the API is fixed, and the file format is fixed. Full unit -test coverage and randomized black box testing are used to ensure database -consistency and thread safety. Bolt is currently used in high-load production -environments serving databases as large as 1TB. Many companies such as -Shopify and Heroku use Bolt-backed services every day. - -## Table of Contents - -- [Getting Started](#getting-started) - - [Installing](#installing) - - [Opening a database](#opening-a-database) - - [Transactions](#transactions) - - [Read-write transactions](#read-write-transactions) - - [Read-only transactions](#read-only-transactions) - - [Batch read-write transactions](#batch-read-write-transactions) - - [Managing transactions manually](#managing-transactions-manually) - - [Using buckets](#using-buckets) - - [Using key/value pairs](#using-keyvalue-pairs) - - [Autoincrementing integer for the bucket](#autoincrementing-integer-for-the-bucket) - - [Iterating over keys](#iterating-over-keys) - - [Prefix scans](#prefix-scans) - - [Range scans](#range-scans) - - [ForEach()](#foreach) - - [Nested buckets](#nested-buckets) - - [Database backups](#database-backups) - - [Statistics](#statistics) - - [Read-Only Mode](#read-only-mode) - - [Mobile Use (iOS/Android)](#mobile-use-iosandroid) -- [Resources](#resources) -- [Comparison with other databases](#comparison-with-other-databases) - - [Postgres, MySQL, & other relational databases](#postgres-mysql--other-relational-databases) - - [LevelDB, RocksDB](#leveldb-rocksdb) - - [LMDB](#lmdb) -- [Caveats & Limitations](#caveats--limitations) -- [Reading the Source](#reading-the-source) -- [Other Projects Using Bolt](#other-projects-using-bolt) - -## Getting Started - -### Installing - -To start using Bolt, install Go and run `go get`: - -```sh -$ go get github.com/boltdb/bolt/... -``` - -This will retrieve the library and install the `bolt` command line utility into -your `$GOBIN` path. - - -### Opening a database - -The top-level object in Bolt is a `DB`. It is represented as a single file on -your disk and represents a consistent snapshot of your data. - -To open your database, simply use the `bolt.Open()` function: - -```go -package main - -import ( - "log" - - "github.com/boltdb/bolt" -) - -func main() { - // Open the my.db data file in your current directory. - // It will be created if it doesn't exist. - db, err := bolt.Open("my.db", 0600, nil) - if err != nil { - log.Fatal(err) - } - defer db.Close() - - ... -} -``` - -Please note that Bolt obtains a file lock on the data file so multiple processes -cannot open the same database at the same time. Opening an already open Bolt -database will cause it to hang until the other process closes it. To prevent -an indefinite wait you can pass a timeout option to the `Open()` function: - -```go -db, err := bolt.Open("my.db", 0600, &bolt.Options{Timeout: 1 * time.Second}) -``` - - -### Transactions - -Bolt allows only one read-write transaction at a time but allows as many -read-only transactions as you want at a time. Each transaction has a consistent -view of the data as it existed when the transaction started. - -Individual transactions and all objects created from them (e.g. buckets, keys) -are not thread safe. To work with data in multiple goroutines you must start -a transaction for each one or use locking to ensure only one goroutine accesses -a transaction at a time. Creating transaction from the `DB` is thread safe. - -Read-only transactions and read-write transactions should not depend on one -another and generally shouldn't be opened simultaneously in the same goroutine. -This can cause a deadlock as the read-write transaction needs to periodically -re-map the data file but it cannot do so while a read-only transaction is open. - - -#### Read-write transactions - -To start a read-write transaction, you can use the `DB.Update()` function: - -```go -err := db.Update(func(tx *bolt.Tx) error { - ... - return nil -}) -``` - -Inside the closure, you have a consistent view of the database. You commit the -transaction by returning `nil` at the end. You can also rollback the transaction -at any point by returning an error. All database operations are allowed inside -a read-write transaction. - -Always check the return error as it will report any disk failures that can cause -your transaction to not complete. If you return an error within your closure -it will be passed through. - - -#### Read-only transactions - -To start a read-only transaction, you can use the `DB.View()` function: - -```go -err := db.View(func(tx *bolt.Tx) error { - ... - return nil -}) -``` - -You also get a consistent view of the database within this closure, however, -no mutating operations are allowed within a read-only transaction. You can only -retrieve buckets, retrieve values, and copy the database within a read-only -transaction. - - -#### Batch read-write transactions - -Each `DB.Update()` waits for disk to commit the writes. This overhead -can be minimized by combining multiple updates with the `DB.Batch()` -function: - -```go -err := db.Batch(func(tx *bolt.Tx) error { - ... - return nil -}) -``` - -Concurrent Batch calls are opportunistically combined into larger -transactions. Batch is only useful when there are multiple goroutines -calling it. - -The trade-off is that `Batch` can call the given -function multiple times, if parts of the transaction fail. The -function must be idempotent and side effects must take effect only -after a successful return from `DB.Batch()`. - -For example: don't display messages from inside the function, instead -set variables in the enclosing scope: - -```go -var id uint64 -err := db.Batch(func(tx *bolt.Tx) error { - // Find last key in bucket, decode as bigendian uint64, increment - // by one, encode back to []byte, and add new key. - ... - id = newValue - return nil -}) -if err != nil { - return ... -} -fmt.Println("Allocated ID %d", id) -``` - - -#### Managing transactions manually - -The `DB.View()` and `DB.Update()` functions are wrappers around the `DB.Begin()` -function. These helper functions will start the transaction, execute a function, -and then safely close your transaction if an error is returned. This is the -recommended way to use Bolt transactions. - -However, sometimes you may want to manually start and end your transactions. -You can use the `DB.Begin()` function directly but **please** be sure to close -the transaction. - -```go -// Start a writable transaction. -tx, err := db.Begin(true) -if err != nil { - return err -} -defer tx.Rollback() - -// Use the transaction... -_, err := tx.CreateBucket([]byte("MyBucket")) -if err != nil { - return err -} - -// Commit the transaction and check for error. -if err := tx.Commit(); err != nil { - return err -} -``` - -The first argument to `DB.Begin()` is a boolean stating if the transaction -should be writable. - - -### Using buckets - -Buckets are collections of key/value pairs within the database. All keys in a -bucket must be unique. You can create a bucket using the `DB.CreateBucket()` -function: - -```go -db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("MyBucket")) - if err != nil { - return fmt.Errorf("create bucket: %s", err) - } - return nil -}) -``` - -You can also create a bucket only if it doesn't exist by using the -`Tx.CreateBucketIfNotExists()` function. It's a common pattern to call this -function for all your top-level buckets after you open your database so you can -guarantee that they exist for future transactions. - -To delete a bucket, simply call the `Tx.DeleteBucket()` function. - - -### Using key/value pairs - -To save a key/value pair to a bucket, use the `Bucket.Put()` function: - -```go -db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("MyBucket")) - err := b.Put([]byte("answer"), []byte("42")) - return err -}) -``` - -This will set the value of the `"answer"` key to `"42"` in the `MyBucket` -bucket. To retrieve this value, we can use the `Bucket.Get()` function: - -```go -db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("MyBucket")) - v := b.Get([]byte("answer")) - fmt.Printf("The answer is: %s\n", v) - return nil -}) -``` - -The `Get()` function does not return an error because its operation is -guaranteed to work (unless there is some kind of system failure). If the key -exists then it will return its byte slice value. If it doesn't exist then it -will return `nil`. It's important to note that you can have a zero-length value -set to a key which is different than the key not existing. - -Use the `Bucket.Delete()` function to delete a key from the bucket. - -Please note that values returned from `Get()` are only valid while the -transaction is open. If you need to use a value outside of the transaction -then you must use `copy()` to copy it to another byte slice. - - -### Autoincrementing integer for the bucket -By using the `NextSequence()` function, you can let Bolt determine a sequence -which can be used as the unique identifier for your key/value pairs. See the -example below. - -```go -// CreateUser saves u to the store. The new user ID is set on u once the data is persisted. -func (s *Store) CreateUser(u *User) error { - return s.db.Update(func(tx *bolt.Tx) error { - // Retrieve the users bucket. - // This should be created when the DB is first opened. - b := tx.Bucket([]byte("users")) - - // Generate ID for the user. - // This returns an error only if the Tx is closed or not writeable. - // That can't happen in an Update() call so I ignore the error check. - id, _ := b.NextSequence() - u.ID = int(id) - - // Marshal user data into bytes. - buf, err := json.Marshal(u) - if err != nil { - return err - } - - // Persist bytes to users bucket. - return b.Put(itob(u.ID), buf) - }) -} - -// itob returns an 8-byte big endian representation of v. -func itob(v int) []byte { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, uint64(v)) - return b -} - -type User struct { - ID int - ... -} -``` - -### Iterating over keys - -Bolt stores its keys in byte-sorted order within a bucket. This makes sequential -iteration over these keys extremely fast. To iterate over keys we'll use a -`Cursor`: - -```go -db.View(func(tx *bolt.Tx) error { - // Assume bucket exists and has keys - b := tx.Bucket([]byte("MyBucket")) - - c := b.Cursor() - - for k, v := c.First(); k != nil; k, v = c.Next() { - fmt.Printf("key=%s, value=%s\n", k, v) - } - - return nil -}) -``` - -The cursor allows you to move to a specific point in the list of keys and move -forward or backward through the keys one at a time. - -The following functions are available on the cursor: - -``` -First() Move to the first key. -Last() Move to the last key. -Seek() Move to a specific key. -Next() Move to the next key. -Prev() Move to the previous key. -``` - -Each of those functions has a return signature of `(key []byte, value []byte)`. -When you have iterated to the end of the cursor then `Next()` will return a -`nil` key. You must seek to a position using `First()`, `Last()`, or `Seek()` -before calling `Next()` or `Prev()`. If you do not seek to a position then -these functions will return a `nil` key. - -During iteration, if the key is non-`nil` but the value is `nil`, that means -the key refers to a bucket rather than a value. Use `Bucket.Bucket()` to -access the sub-bucket. - - -#### Prefix scans - -To iterate over a key prefix, you can combine `Seek()` and `bytes.HasPrefix()`: - -```go -db.View(func(tx *bolt.Tx) error { - // Assume bucket exists and has keys - c := tx.Bucket([]byte("MyBucket")).Cursor() - - prefix := []byte("1234") - for k, v := c.Seek(prefix); bytes.HasPrefix(k, prefix); k, v = c.Next() { - fmt.Printf("key=%s, value=%s\n", k, v) - } - - return nil -}) -``` - -#### Range scans - -Another common use case is scanning over a range such as a time range. If you -use a sortable time encoding such as RFC3339 then you can query a specific -date range like this: - -```go -db.View(func(tx *bolt.Tx) error { - // Assume our events bucket exists and has RFC3339 encoded time keys. - c := tx.Bucket([]byte("Events")).Cursor() - - // Our time range spans the 90's decade. - min := []byte("1990-01-01T00:00:00Z") - max := []byte("2000-01-01T00:00:00Z") - - // Iterate over the 90's. - for k, v := c.Seek(min); k != nil && bytes.Compare(k, max) <= 0; k, v = c.Next() { - fmt.Printf("%s: %s\n", k, v) - } - - return nil -}) -``` - -Note that, while RFC3339 is sortable, the Golang implementation of RFC3339Nano does not use a fixed number of digits after the decimal point and is therefore not sortable. - - -#### ForEach() - -You can also use the function `ForEach()` if you know you'll be iterating over -all the keys in a bucket: - -```go -db.View(func(tx *bolt.Tx) error { - // Assume bucket exists and has keys - b := tx.Bucket([]byte("MyBucket")) - - b.ForEach(func(k, v []byte) error { - fmt.Printf("key=%s, value=%s\n", k, v) - return nil - }) - return nil -}) -``` - -Please note that keys and values in `ForEach()` are only valid while -the transaction is open. If you need to use a key or value outside of -the transaction, you must use `copy()` to copy it to another byte -slice. - -### Nested buckets - -You can also store a bucket in a key to create nested buckets. The API is the -same as the bucket management API on the `DB` object: - -```go -func (*Bucket) CreateBucket(key []byte) (*Bucket, error) -func (*Bucket) CreateBucketIfNotExists(key []byte) (*Bucket, error) -func (*Bucket) DeleteBucket(key []byte) error -``` - - -### Database backups - -Bolt is a single file so it's easy to backup. You can use the `Tx.WriteTo()` -function to write a consistent view of the database to a writer. If you call -this from a read-only transaction, it will perform a hot backup and not block -your other database reads and writes. - -By default, it will use a regular file handle which will utilize the operating -system's page cache. See the [`Tx`](https://godoc.org/github.com/boltdb/bolt#Tx) -documentation for information about optimizing for larger-than-RAM datasets. - -One common use case is to backup over HTTP so you can use tools like `cURL` to -do database backups: - -```go -func BackupHandleFunc(w http.ResponseWriter, req *http.Request) { - err := db.View(func(tx *bolt.Tx) error { - w.Header().Set("Content-Type", "application/octet-stream") - w.Header().Set("Content-Disposition", `attachment; filename="my.db"`) - w.Header().Set("Content-Length", strconv.Itoa(int(tx.Size()))) - _, err := tx.WriteTo(w) - return err - }) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } -} -``` - -Then you can backup using this command: - -```sh -$ curl http://localhost/backup > my.db -``` - -Or you can open your browser to `http://localhost/backup` and it will download -automatically. - -If you want to backup to another file you can use the `Tx.CopyFile()` helper -function. - - -### Statistics - -The database keeps a running count of many of the internal operations it -performs so you can better understand what's going on. By grabbing a snapshot -of these stats at two points in time we can see what operations were performed -in that time range. - -For example, we could start a goroutine to log stats every 10 seconds: - -```go -go func() { - // Grab the initial stats. - prev := db.Stats() - - for { - // Wait for 10s. - time.Sleep(10 * time.Second) - - // Grab the current stats and diff them. - stats := db.Stats() - diff := stats.Sub(&prev) - - // Encode stats to JSON and print to STDERR. - json.NewEncoder(os.Stderr).Encode(diff) - - // Save stats for the next loop. - prev = stats - } -}() -``` - -It's also useful to pipe these stats to a service such as statsd for monitoring -or to provide an HTTP endpoint that will perform a fixed-length sample. - - -### Read-Only Mode - -Sometimes it is useful to create a shared, read-only Bolt database. To this, -set the `Options.ReadOnly` flag when opening your database. Read-only mode -uses a shared lock to allow multiple processes to read from the database but -it will block any processes from opening the database in read-write mode. - -```go -db, err := bolt.Open("my.db", 0666, &bolt.Options{ReadOnly: true}) -if err != nil { - log.Fatal(err) -} -``` - -### Mobile Use (iOS/Android) - -Bolt is able to run on mobile devices by leveraging the binding feature of the -[gomobile](https://github.com/golang/mobile) tool. Create a struct that will -contain your database logic and a reference to a `*bolt.DB` with a initializing -constructor that takes in a filepath where the database file will be stored. -Neither Android nor iOS require extra permissions or cleanup from using this method. - -```go -func NewBoltDB(filepath string) *BoltDB { - db, err := bolt.Open(filepath+"/demo.db", 0600, nil) - if err != nil { - log.Fatal(err) - } - - return &BoltDB{db} -} - -type BoltDB struct { - db *bolt.DB - ... -} - -func (b *BoltDB) Path() string { - return b.db.Path() -} - -func (b *BoltDB) Close() { - b.db.Close() -} -``` - -Database logic should be defined as methods on this wrapper struct. - -To initialize this struct from the native language (both platforms now sync -their local storage to the cloud. These snippets disable that functionality for the -database file): - -#### Android - -```java -String path; -if (android.os.Build.VERSION.SDK_INT >=android.os.Build.VERSION_CODES.LOLLIPOP){ - path = getNoBackupFilesDir().getAbsolutePath(); -} else{ - path = getFilesDir().getAbsolutePath(); -} -Boltmobiledemo.BoltDB boltDB = Boltmobiledemo.NewBoltDB(path) -``` - -#### iOS - -```objc -- (void)demo { - NSString* path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, - NSUserDomainMask, - YES) objectAtIndex:0]; - GoBoltmobiledemoBoltDB * demo = GoBoltmobiledemoNewBoltDB(path); - [self addSkipBackupAttributeToItemAtPath:demo.path]; - //Some DB Logic would go here - [demo close]; -} - -- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *) filePathString -{ - NSURL* URL= [NSURL fileURLWithPath: filePathString]; - assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]); - - NSError *error = nil; - BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES] - forKey: NSURLIsExcludedFromBackupKey error: &error]; - if(!success){ - NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error); - } - return success; -} - -``` - -## Resources - -For more information on getting started with Bolt, check out the following articles: - -* [Intro to BoltDB: Painless Performant Persistence](http://npf.io/2014/07/intro-to-boltdb-painless-performant-persistence/) by [Nate Finch](https://github.com/natefinch). -* [Bolt -- an embedded key/value database for Go](https://www.progville.com/go/bolt-embedded-db-golang/) by Progville - - -## Comparison with other databases - -### Postgres, MySQL, & other relational databases - -Relational databases structure data into rows and are only accessible through -the use of SQL. This approach provides flexibility in how you store and query -your data but also incurs overhead in parsing and planning SQL statements. Bolt -accesses all data by a byte slice key. This makes Bolt fast to read and write -data by key but provides no built-in support for joining values together. - -Most relational databases (with the exception of SQLite) are standalone servers -that run separately from your application. This gives your systems -flexibility to connect multiple application servers to a single database -server but also adds overhead in serializing and transporting data over the -network. Bolt runs as a library included in your application so all data access -has to go through your application's process. This brings data closer to your -application but limits multi-process access to the data. - - -### LevelDB, RocksDB - -LevelDB and its derivatives (RocksDB, HyperLevelDB) are similar to Bolt in that -they are libraries bundled into the application, however, their underlying -structure is a log-structured merge-tree (LSM tree). An LSM tree optimizes -random writes by using a write ahead log and multi-tiered, sorted files called -SSTables. Bolt uses a B+tree internally and only a single file. Both approaches -have trade-offs. - -If you require a high random write throughput (>10,000 w/sec) or you need to use -spinning disks then LevelDB could be a good choice. If your application is -read-heavy or does a lot of range scans then Bolt could be a good choice. - -One other important consideration is that LevelDB does not have transactions. -It supports batch writing of key/values pairs and it supports read snapshots -but it will not give you the ability to do a compare-and-swap operation safely. -Bolt supports fully serializable ACID transactions. - - -### LMDB - -Bolt was originally a port of LMDB so it is architecturally similar. Both use -a B+tree, have ACID semantics with fully serializable transactions, and support -lock-free MVCC using a single writer and multiple readers. - -The two projects have somewhat diverged. LMDB heavily focuses on raw performance -while Bolt has focused on simplicity and ease of use. For example, LMDB allows -several unsafe actions such as direct writes for the sake of performance. Bolt -opts to disallow actions which can leave the database in a corrupted state. The -only exception to this in Bolt is `DB.NoSync`. - -There are also a few differences in API. LMDB requires a maximum mmap size when -opening an `mdb_env` whereas Bolt will handle incremental mmap resizing -automatically. LMDB overloads the getter and setter functions with multiple -flags whereas Bolt splits these specialized cases into their own functions. - - -## Caveats & Limitations - -It's important to pick the right tool for the job and Bolt is no exception. -Here are a few things to note when evaluating and using Bolt: - -* Bolt is good for read intensive workloads. Sequential write performance is - also fast but random writes can be slow. You can use `DB.Batch()` or add a - write-ahead log to help mitigate this issue. - -* Bolt uses a B+tree internally so there can be a lot of random page access. - SSDs provide a significant performance boost over spinning disks. - -* Try to avoid long running read transactions. Bolt uses copy-on-write so - old pages cannot be reclaimed while an old transaction is using them. - -* Byte slices returned from Bolt are only valid during a transaction. Once the - transaction has been committed or rolled back then the memory they point to - can be reused by a new page or can be unmapped from virtual memory and you'll - see an `unexpected fault address` panic when accessing it. - -* Be careful when using `Bucket.FillPercent`. Setting a high fill percent for - buckets that have random inserts will cause your database to have very poor - page utilization. - -* Use larger buckets in general. Smaller buckets causes poor page utilization - once they become larger than the page size (typically 4KB). - -* Bulk loading a lot of random writes into a new bucket can be slow as the - page will not split until the transaction is committed. Randomly inserting - more than 100,000 key/value pairs into a single new bucket in a single - transaction is not advised. - -* Bolt uses a memory-mapped file so the underlying operating system handles the - caching of the data. Typically, the OS will cache as much of the file as it - can in memory and will release memory as needed to other processes. This means - that Bolt can show very high memory usage when working with large databases. - However, this is expected and the OS will release memory as needed. Bolt can - handle databases much larger than the available physical RAM, provided its - memory-map fits in the process virtual address space. It may be problematic - on 32-bits systems. - -* The data structures in the Bolt database are memory mapped so the data file - will be endian specific. This means that you cannot copy a Bolt file from a - little endian machine to a big endian machine and have it work. For most - users this is not a concern since most modern CPUs are little endian. - -* Because of the way pages are laid out on disk, Bolt cannot truncate data files - and return free pages back to the disk. Instead, Bolt maintains a free list - of unused pages within its data file. These free pages can be reused by later - transactions. This works well for many use cases as databases generally tend - to grow. However, it's important to note that deleting large chunks of data - will not allow you to reclaim that space on disk. - - For more information on page allocation, [see this comment][page-allocation]. - -[page-allocation]: https://github.com/boltdb/bolt/issues/308#issuecomment-74811638 - - -## Reading the Source - -Bolt is a relatively small code base (<3KLOC) for an embedded, serializable, -transactional key/value database so it can be a good starting point for people -interested in how databases work. - -The best places to start are the main entry points into Bolt: - -- `Open()` - Initializes the reference to the database. It's responsible for - creating the database if it doesn't exist, obtaining an exclusive lock on the - file, reading the meta pages, & memory-mapping the file. - -- `DB.Begin()` - Starts a read-only or read-write transaction depending on the - value of the `writable` argument. This requires briefly obtaining the "meta" - lock to keep track of open transactions. Only one read-write transaction can - exist at a time so the "rwlock" is acquired during the life of a read-write - transaction. - -- `Bucket.Put()` - Writes a key/value pair into a bucket. After validating the - arguments, a cursor is used to traverse the B+tree to the page and position - where they key & value will be written. Once the position is found, the bucket - materializes the underlying page and the page's parent pages into memory as - "nodes". These nodes are where mutations occur during read-write transactions. - These changes get flushed to disk during commit. - -- `Bucket.Get()` - Retrieves a key/value pair from a bucket. This uses a cursor - to move to the page & position of a key/value pair. During a read-only - transaction, the key and value data is returned as a direct reference to the - underlying mmap file so there's no allocation overhead. For read-write - transactions, this data may reference the mmap file or one of the in-memory - node values. - -- `Cursor` - This object is simply for traversing the B+tree of on-disk pages - or in-memory nodes. It can seek to a specific key, move to the first or last - value, or it can move forward or backward. The cursor handles the movement up - and down the B+tree transparently to the end user. - -- `Tx.Commit()` - Converts the in-memory dirty nodes and the list of free pages - into pages to be written to disk. Writing to disk then occurs in two phases. - First, the dirty pages are written to disk and an `fsync()` occurs. Second, a - new meta page with an incremented transaction ID is written and another - `fsync()` occurs. This two phase write ensures that partially written data - pages are ignored in the event of a crash since the meta page pointing to them - is never written. Partially written meta pages are invalidated because they - are written with a checksum. - -If you have additional notes that could be helpful for others, please submit -them via pull request. - - -## Other Projects Using Bolt - -Below is a list of public, open source projects that use Bolt: - -* [BoltDbWeb](https://github.com/evnix/boltdbweb) - A web based GUI for BoltDB files. -* [Operation Go: A Routine Mission](http://gocode.io) - An online programming game for Golang using Bolt for user accounts and a leaderboard. -* [Bazil](https://bazil.org/) - A file system that lets your data reside where it is most convenient for it to reside. -* [DVID](https://github.com/janelia-flyem/dvid) - Added Bolt as optional storage engine and testing it against Basho-tuned leveldb. -* [Skybox Analytics](https://github.com/skybox/skybox) - A standalone funnel analysis tool for web analytics. -* [Scuttlebutt](https://github.com/benbjohnson/scuttlebutt) - Uses Bolt to store and process all Twitter mentions of GitHub projects. -* [Wiki](https://github.com/peterhellberg/wiki) - A tiny wiki using Goji, BoltDB and Blackfriday. -* [ChainStore](https://github.com/pressly/chainstore) - Simple key-value interface to a variety of storage engines organized as a chain of operations. -* [MetricBase](https://github.com/msiebuhr/MetricBase) - Single-binary version of Graphite. -* [Gitchain](https://github.com/gitchain/gitchain) - Decentralized, peer-to-peer Git repositories aka "Git meets Bitcoin". -* [event-shuttle](https://github.com/sclasen/event-shuttle) - A Unix system service to collect and reliably deliver messages to Kafka. -* [ipxed](https://github.com/kelseyhightower/ipxed) - Web interface and api for ipxed. -* [BoltStore](https://github.com/yosssi/boltstore) - Session store using Bolt. -* [photosite/session](https://godoc.org/bitbucket.org/kardianos/photosite/session) - Sessions for a photo viewing site. -* [LedisDB](https://github.com/siddontang/ledisdb) - A high performance NoSQL, using Bolt as optional storage. -* [ipLocator](https://github.com/AndreasBriese/ipLocator) - A fast ip-geo-location-server using bolt with bloom filters. -* [cayley](https://github.com/google/cayley) - Cayley is an open-source graph database using Bolt as optional backend. -* [bleve](http://www.blevesearch.com/) - A pure Go search engine similar to ElasticSearch that uses Bolt as the default storage backend. -* [tentacool](https://github.com/optiflows/tentacool) - REST api server to manage system stuff (IP, DNS, Gateway...) on a linux server. -* [Seaweed File System](https://github.com/chrislusf/seaweedfs) - Highly scalable distributed key~file system with O(1) disk read. -* [InfluxDB](https://influxdata.com) - Scalable datastore for metrics, events, and real-time analytics. -* [Freehold](http://tshannon.bitbucket.org/freehold/) - An open, secure, and lightweight platform for your files and data. -* [Prometheus Annotation Server](https://github.com/oliver006/prom_annotation_server) - Annotation server for PromDash & Prometheus service monitoring system. -* [Consul](https://github.com/hashicorp/consul) - Consul is service discovery and configuration made easy. Distributed, highly available, and datacenter-aware. -* [Kala](https://github.com/ajvb/kala) - Kala is a modern job scheduler optimized to run on a single node. It is persistent, JSON over HTTP API, ISO 8601 duration notation, and dependent jobs. -* [drive](https://github.com/odeke-em/drive) - drive is an unofficial Google Drive command line client for \*NIX operating systems. -* [stow](https://github.com/djherbis/stow) - a persistence manager for objects - backed by boltdb. -* [buckets](https://github.com/joyrexus/buckets) - a bolt wrapper streamlining - simple tx and key scans. -* [mbuckets](https://github.com/abhigupta912/mbuckets) - A Bolt wrapper that allows easy operations on multi level (nested) buckets. -* [Request Baskets](https://github.com/darklynx/request-baskets) - A web service to collect arbitrary HTTP requests and inspect them via REST API or simple web UI, similar to [RequestBin](http://requestb.in/) service -* [Go Report Card](https://goreportcard.com/) - Go code quality report cards as a (free and open source) service. -* [Boltdb Boilerplate](https://github.com/bobintornado/boltdb-boilerplate) - Boilerplate wrapper around bolt aiming to make simple calls one-liners. -* [lru](https://github.com/crowdriff/lru) - Easy to use Bolt-backed Least-Recently-Used (LRU) read-through cache with chainable remote stores. -* [Storm](https://github.com/asdine/storm) - Simple and powerful ORM for BoltDB. -* [GoWebApp](https://github.com/josephspurrier/gowebapp) - A basic MVC web application in Go using BoltDB. -* [SimpleBolt](https://github.com/xyproto/simplebolt) - A simple way to use BoltDB. Deals mainly with strings. -* [Algernon](https://github.com/xyproto/algernon) - A HTTP/2 web server with built-in support for Lua. Uses BoltDB as the default database backend. -* [MuLiFS](https://github.com/dankomiocevic/mulifs) - Music Library Filesystem creates a filesystem to organise your music files. -* [GoShort](https://github.com/pankajkhairnar/goShort) - GoShort is a URL shortener written in Golang and BoltDB for persistent key/value storage and for routing it's using high performent HTTPRouter. -* [torrent](https://github.com/anacrolix/torrent) - Full-featured BitTorrent client package and utilities in Go. BoltDB is a storage backend in development. -* [gopherpit](https://github.com/gopherpit/gopherpit) - A web service to manage Go remote import paths with custom domains - -If you are using Bolt in a project please send a pull request to add it to the list. diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/appveyor.yml b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/appveyor.yml deleted file mode 100644 index 6e26e94..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/appveyor.yml +++ /dev/null @@ -1,18 +0,0 @@ -version: "{build}" - -os: Windows Server 2012 R2 - -clone_folder: c:\gopath\src\github.com\boltdb\bolt - -environment: - GOPATH: c:\gopath - -install: - - echo %PATH% - - echo %GOPATH% - - go version - - go env - - go get -v -t ./... - -build_script: - - go test -v ./... diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_386.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_386.go deleted file mode 100644 index 820d533..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_386.go +++ /dev/null @@ -1,10 +0,0 @@ -package bolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0x7FFFFFFF // 2GB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0xFFFFFFF - -// Are unaligned load/stores broken on this arch? -var brokenUnaligned = false diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_amd64.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_amd64.go deleted file mode 100644 index 98fafdb..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_amd64.go +++ /dev/null @@ -1,10 +0,0 @@ -package bolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0xFFFFFFFFFFFF // 256TB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0x7FFFFFFF - -// Are unaligned load/stores broken on this arch? -var brokenUnaligned = false diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm.go deleted file mode 100644 index 7e5cb4b..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm.go +++ /dev/null @@ -1,28 +0,0 @@ -package bolt - -import "unsafe" - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0x7FFFFFFF // 2GB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0xFFFFFFF - -// Are unaligned load/stores broken on this arch? -var brokenUnaligned bool - -func init() { - // Simple check to see whether this arch handles unaligned load/stores - // correctly. - - // ARM9 and older devices require load/stores to be from/to aligned - // addresses. If not, the lower 2 bits are cleared and that address is - // read in a jumbled up order. - - // See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html - - raw := [6]byte{0xfe, 0xef, 0x11, 0x22, 0x22, 0x11} - val := *(*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(&raw)) + 2)) - - brokenUnaligned = val != 0x11222211 -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm64.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm64.go deleted file mode 100644 index b26d84f..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_arm64.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build arm64 - -package bolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0xFFFFFFFFFFFF // 256TB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0x7FFFFFFF - -// Are unaligned load/stores broken on this arch? -var brokenUnaligned = false diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_linux.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_linux.go deleted file mode 100644 index 2b67666..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_linux.go +++ /dev/null @@ -1,10 +0,0 @@ -package bolt - -import ( - "syscall" -) - -// fdatasync flushes written data to a file descriptor. -func fdatasync(db *DB) error { - return syscall.Fdatasync(int(db.file.Fd())) -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_openbsd.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_openbsd.go deleted file mode 100644 index 7058c3d..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_openbsd.go +++ /dev/null @@ -1,27 +0,0 @@ -package bolt - -import ( - "syscall" - "unsafe" -) - -const ( - msAsync = 1 << iota // perform asynchronous writes - msSync // perform synchronous writes - msInvalidate // invalidate cached data -) - -func msync(db *DB) error { - _, _, errno := syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(db.data)), uintptr(db.datasz), msInvalidate) - if errno != 0 { - return errno - } - return nil -} - -func fdatasync(db *DB) error { - if db.data != nil { - return msync(db) - } - return db.file.Sync() -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc.go deleted file mode 100644 index 645ddc3..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build ppc - -package bolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0x7FFFFFFF // 2GB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0xFFFFFFF diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64.go deleted file mode 100644 index 2dc6be0..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build ppc64 - -package bolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0xFFFFFFFFFFFF // 256TB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0x7FFFFFFF diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64le.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64le.go deleted file mode 100644 index 8c143bc..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_ppc64le.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build ppc64le - -package bolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0xFFFFFFFFFFFF // 256TB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0x7FFFFFFF - -// Are unaligned load/stores broken on this arch? -var brokenUnaligned = false diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_s390x.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_s390x.go deleted file mode 100644 index d7c39af..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_s390x.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build s390x - -package bolt - -// maxMapSize represents the largest mmap size supported by Bolt. -const maxMapSize = 0xFFFFFFFFFFFF // 256TB - -// maxAllocSize is the size used when creating array pointers. -const maxAllocSize = 0x7FFFFFFF - -// Are unaligned load/stores broken on this arch? -var brokenUnaligned = false diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix.go deleted file mode 100644 index cad62dd..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix.go +++ /dev/null @@ -1,89 +0,0 @@ -// +build !windows,!plan9,!solaris - -package bolt - -import ( - "fmt" - "os" - "syscall" - "time" - "unsafe" -) - -// flock acquires an advisory lock on a file descriptor. -func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error { - var t time.Time - for { - // If we're beyond our timeout then return an error. - // This can only occur after we've attempted a flock once. - if t.IsZero() { - t = time.Now() - } else if timeout > 0 && time.Since(t) > timeout { - return ErrTimeout - } - flag := syscall.LOCK_SH - if exclusive { - flag = syscall.LOCK_EX - } - - // Otherwise attempt to obtain an exclusive lock. - err := syscall.Flock(int(db.file.Fd()), flag|syscall.LOCK_NB) - if err == nil { - return nil - } else if err != syscall.EWOULDBLOCK { - return err - } - - // Wait for a bit and try again. - time.Sleep(50 * time.Millisecond) - } -} - -// funlock releases an advisory lock on a file descriptor. -func funlock(db *DB) error { - return syscall.Flock(int(db.file.Fd()), syscall.LOCK_UN) -} - -// mmap memory maps a DB's data file. -func mmap(db *DB, sz int) error { - // Map the data file to memory. - b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags) - if err != nil { - return err - } - - // Advise the kernel that the mmap is accessed randomly. - if err := madvise(b, syscall.MADV_RANDOM); err != nil { - return fmt.Errorf("madvise: %s", err) - } - - // Save the original byte slice and convert to a byte array pointer. - db.dataref = b - db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0])) - db.datasz = sz - return nil -} - -// munmap unmaps a DB's data file from memory. -func munmap(db *DB) error { - // Ignore the unmap if we have no mapped data. - if db.dataref == nil { - return nil - } - - // Unmap using the original byte slice. - err := syscall.Munmap(db.dataref) - db.dataref = nil - db.data = nil - db.datasz = 0 - return err -} - -// NOTE: This function is copied from stdlib because it is not available on darwin. -func madvise(b []byte, advice int) (err error) { - _, _, e1 := syscall.Syscall(syscall.SYS_MADVISE, uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), uintptr(advice)) - if e1 != 0 { - err = e1 - } - return -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix_solaris.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix_solaris.go deleted file mode 100644 index 307bf2b..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_unix_solaris.go +++ /dev/null @@ -1,90 +0,0 @@ -package bolt - -import ( - "fmt" - "os" - "syscall" - "time" - "unsafe" - - "golang.org/x/sys/unix" -) - -// flock acquires an advisory lock on a file descriptor. -func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error { - var t time.Time - for { - // If we're beyond our timeout then return an error. - // This can only occur after we've attempted a flock once. - if t.IsZero() { - t = time.Now() - } else if timeout > 0 && time.Since(t) > timeout { - return ErrTimeout - } - var lock syscall.Flock_t - lock.Start = 0 - lock.Len = 0 - lock.Pid = 0 - lock.Whence = 0 - lock.Pid = 0 - if exclusive { - lock.Type = syscall.F_WRLCK - } else { - lock.Type = syscall.F_RDLCK - } - err := syscall.FcntlFlock(db.file.Fd(), syscall.F_SETLK, &lock) - if err == nil { - return nil - } else if err != syscall.EAGAIN { - return err - } - - // Wait for a bit and try again. - time.Sleep(50 * time.Millisecond) - } -} - -// funlock releases an advisory lock on a file descriptor. -func funlock(db *DB) error { - var lock syscall.Flock_t - lock.Start = 0 - lock.Len = 0 - lock.Type = syscall.F_UNLCK - lock.Whence = 0 - return syscall.FcntlFlock(uintptr(db.file.Fd()), syscall.F_SETLK, &lock) -} - -// mmap memory maps a DB's data file. -func mmap(db *DB, sz int) error { - // Map the data file to memory. - b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags) - if err != nil { - return err - } - - // Advise the kernel that the mmap is accessed randomly. - if err := unix.Madvise(b, syscall.MADV_RANDOM); err != nil { - return fmt.Errorf("madvise: %s", err) - } - - // Save the original byte slice and convert to a byte array pointer. - db.dataref = b - db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0])) - db.datasz = sz - return nil -} - -// munmap unmaps a DB's data file from memory. -func munmap(db *DB) error { - // Ignore the unmap if we have no mapped data. - if db.dataref == nil { - return nil - } - - // Unmap using the original byte slice. - err := unix.Munmap(db.dataref) - db.dataref = nil - db.data = nil - db.datasz = 0 - return err -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_windows.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_windows.go deleted file mode 100644 index b00fb07..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bolt_windows.go +++ /dev/null @@ -1,144 +0,0 @@ -package bolt - -import ( - "fmt" - "os" - "syscall" - "time" - "unsafe" -) - -// LockFileEx code derived from golang build filemutex_windows.go @ v1.5.1 -var ( - modkernel32 = syscall.NewLazyDLL("kernel32.dll") - procLockFileEx = modkernel32.NewProc("LockFileEx") - procUnlockFileEx = modkernel32.NewProc("UnlockFileEx") -) - -const ( - lockExt = ".lock" - - // see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx - flagLockExclusive = 2 - flagLockFailImmediately = 1 - - // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx - errLockViolation syscall.Errno = 0x21 -) - -func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) { - r, _, err := procLockFileEx.Call(uintptr(h), uintptr(flags), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol))) - if r == 0 { - return err - } - return nil -} - -func unlockFileEx(h syscall.Handle, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) { - r, _, err := procUnlockFileEx.Call(uintptr(h), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)), 0) - if r == 0 { - return err - } - return nil -} - -// fdatasync flushes written data to a file descriptor. -func fdatasync(db *DB) error { - return db.file.Sync() -} - -// flock acquires an advisory lock on a file descriptor. -func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error { - // Create a separate lock file on windows because a process - // cannot share an exclusive lock on the same file. This is - // needed during Tx.WriteTo(). - f, err := os.OpenFile(db.path+lockExt, os.O_CREATE, mode) - if err != nil { - return err - } - db.lockfile = f - - var t time.Time - for { - // If we're beyond our timeout then return an error. - // This can only occur after we've attempted a flock once. - if t.IsZero() { - t = time.Now() - } else if timeout > 0 && time.Since(t) > timeout { - return ErrTimeout - } - - var flag uint32 = flagLockFailImmediately - if exclusive { - flag |= flagLockExclusive - } - - err := lockFileEx(syscall.Handle(db.lockfile.Fd()), flag, 0, 1, 0, &syscall.Overlapped{}) - if err == nil { - return nil - } else if err != errLockViolation { - return err - } - - // Wait for a bit and try again. - time.Sleep(50 * time.Millisecond) - } -} - -// funlock releases an advisory lock on a file descriptor. -func funlock(db *DB) error { - err := unlockFileEx(syscall.Handle(db.lockfile.Fd()), 0, 1, 0, &syscall.Overlapped{}) - db.lockfile.Close() - os.Remove(db.path + lockExt) - return err -} - -// mmap memory maps a DB's data file. -// Based on: https://github.com/edsrzf/mmap-go -func mmap(db *DB, sz int) error { - if !db.readOnly { - // Truncate the database to the size of the mmap. - if err := db.file.Truncate(int64(sz)); err != nil { - return fmt.Errorf("truncate: %s", err) - } - } - - // Open a file mapping handle. - sizelo := uint32(sz >> 32) - sizehi := uint32(sz) & 0xffffffff - h, errno := syscall.CreateFileMapping(syscall.Handle(db.file.Fd()), nil, syscall.PAGE_READONLY, sizelo, sizehi, nil) - if h == 0 { - return os.NewSyscallError("CreateFileMapping", errno) - } - - // Create the memory map. - addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, uintptr(sz)) - if addr == 0 { - return os.NewSyscallError("MapViewOfFile", errno) - } - - // Close mapping handle. - if err := syscall.CloseHandle(syscall.Handle(h)); err != nil { - return os.NewSyscallError("CloseHandle", err) - } - - // Convert to a byte array. - db.data = ((*[maxMapSize]byte)(unsafe.Pointer(addr))) - db.datasz = sz - - return nil -} - -// munmap unmaps a pointer from a file. -// Based on: https://github.com/edsrzf/mmap-go -func munmap(db *DB) error { - if db.data == nil { - return nil - } - - addr := (uintptr)(unsafe.Pointer(&db.data[0])) - if err := syscall.UnmapViewOfFile(addr); err != nil { - return os.NewSyscallError("UnmapViewOfFile", err) - } - return nil -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/boltsync_unix.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/boltsync_unix.go deleted file mode 100644 index f504425..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/boltsync_unix.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build !windows,!plan9,!linux,!openbsd - -package bolt - -// fdatasync flushes written data to a file descriptor. -func fdatasync(db *DB) error { - return db.file.Sync() -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket.go deleted file mode 100644 index 511ce72..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket.go +++ /dev/null @@ -1,778 +0,0 @@ -package bolt - -import ( - "bytes" - "fmt" - "unsafe" -) - -const ( - // MaxKeySize is the maximum length of a key, in bytes. - MaxKeySize = 32768 - - // MaxValueSize is the maximum length of a value, in bytes. - MaxValueSize = (1 << 31) - 2 -) - -const ( - maxUint = ^uint(0) - minUint = 0 - maxInt = int(^uint(0) >> 1) - minInt = -maxInt - 1 -) - -const bucketHeaderSize = int(unsafe.Sizeof(bucket{})) - -const ( - minFillPercent = 0.1 - maxFillPercent = 1.0 -) - -// DefaultFillPercent is the percentage that split pages are filled. -// This value can be changed by setting Bucket.FillPercent. -const DefaultFillPercent = 0.5 - -// Bucket represents a collection of key/value pairs inside the database. -type Bucket struct { - *bucket - tx *Tx // the associated transaction - buckets map[string]*Bucket // subbucket cache - page *page // inline page reference - rootNode *node // materialized node for the root page. - nodes map[pgid]*node // node cache - - // Sets the threshold for filling nodes when they split. By default, - // the bucket will fill to 50% but it can be useful to increase this - // amount if you know that your write workloads are mostly append-only. - // - // This is non-persisted across transactions so it must be set in every Tx. - FillPercent float64 -} - -// bucket represents the on-file representation of a bucket. -// This is stored as the "value" of a bucket key. If the bucket is small enough, -// then its root page can be stored inline in the "value", after the bucket -// header. In the case of inline buckets, the "root" will be 0. -type bucket struct { - root pgid // page id of the bucket's root-level page - sequence uint64 // monotonically incrementing, used by NextSequence() -} - -// newBucket returns a new bucket associated with a transaction. -func newBucket(tx *Tx) Bucket { - var b = Bucket{tx: tx, FillPercent: DefaultFillPercent} - if tx.writable { - b.buckets = make(map[string]*Bucket) - b.nodes = make(map[pgid]*node) - } - return b -} - -// Tx returns the tx of the bucket. -func (b *Bucket) Tx() *Tx { - return b.tx -} - -// Root returns the root of the bucket. -func (b *Bucket) Root() pgid { - return b.root -} - -// Writable returns whether the bucket is writable. -func (b *Bucket) Writable() bool { - return b.tx.writable -} - -// Cursor creates a cursor associated with the bucket. -// The cursor is only valid as long as the transaction is open. -// Do not use a cursor after the transaction is closed. -func (b *Bucket) Cursor() *Cursor { - // Update transaction statistics. - b.tx.stats.CursorCount++ - - // Allocate and return a cursor. - return &Cursor{ - bucket: b, - stack: make([]elemRef, 0), - } -} - -// Bucket retrieves a nested bucket by name. -// Returns nil if the bucket does not exist. -// The bucket instance is only valid for the lifetime of the transaction. -func (b *Bucket) Bucket(name []byte) *Bucket { - if b.buckets != nil { - if child := b.buckets[string(name)]; child != nil { - return child - } - } - - // Move cursor to key. - c := b.Cursor() - k, v, flags := c.seek(name) - - // Return nil if the key doesn't exist or it is not a bucket. - if !bytes.Equal(name, k) || (flags&bucketLeafFlag) == 0 { - return nil - } - - // Otherwise create a bucket and cache it. - var child = b.openBucket(v) - if b.buckets != nil { - b.buckets[string(name)] = child - } - - return child -} - -// Helper method that re-interprets a sub-bucket value -// from a parent into a Bucket -func (b *Bucket) openBucket(value []byte) *Bucket { - var child = newBucket(b.tx) - - // If unaligned load/stores are broken on this arch and value is - // unaligned simply clone to an aligned byte array. - unaligned := brokenUnaligned && uintptr(unsafe.Pointer(&value[0]))&3 != 0 - - if unaligned { - value = cloneBytes(value) - } - - // If this is a writable transaction then we need to copy the bucket entry. - // Read-only transactions can point directly at the mmap entry. - if b.tx.writable && !unaligned { - child.bucket = &bucket{} - *child.bucket = *(*bucket)(unsafe.Pointer(&value[0])) - } else { - child.bucket = (*bucket)(unsafe.Pointer(&value[0])) - } - - // Save a reference to the inline page if the bucket is inline. - if child.root == 0 { - child.page = (*page)(unsafe.Pointer(&value[bucketHeaderSize])) - } - - return &child -} - -// CreateBucket creates a new bucket at the given key and returns the new bucket. -// Returns an error if the key already exists, if the bucket name is blank, or if the bucket name is too long. -// The bucket instance is only valid for the lifetime of the transaction. -func (b *Bucket) CreateBucket(key []byte) (*Bucket, error) { - if b.tx.db == nil { - return nil, ErrTxClosed - } else if !b.tx.writable { - return nil, ErrTxNotWritable - } else if len(key) == 0 { - return nil, ErrBucketNameRequired - } - - // Move cursor to correct position. - c := b.Cursor() - k, _, flags := c.seek(key) - - // Return an error if there is an existing key. - if bytes.Equal(key, k) { - if (flags & bucketLeafFlag) != 0 { - return nil, ErrBucketExists - } else { - return nil, ErrIncompatibleValue - } - } - - // Create empty, inline bucket. - var bucket = Bucket{ - bucket: &bucket{}, - rootNode: &node{isLeaf: true}, - FillPercent: DefaultFillPercent, - } - var value = bucket.write() - - // Insert into node. - key = cloneBytes(key) - c.node().put(key, key, value, 0, bucketLeafFlag) - - // Since subbuckets are not allowed on inline buckets, we need to - // dereference the inline page, if it exists. This will cause the bucket - // to be treated as a regular, non-inline bucket for the rest of the tx. - b.page = nil - - return b.Bucket(key), nil -} - -// CreateBucketIfNotExists creates a new bucket if it doesn't already exist and returns a reference to it. -// Returns an error if the bucket name is blank, or if the bucket name is too long. -// The bucket instance is only valid for the lifetime of the transaction. -func (b *Bucket) CreateBucketIfNotExists(key []byte) (*Bucket, error) { - child, err := b.CreateBucket(key) - if err == ErrBucketExists { - return b.Bucket(key), nil - } else if err != nil { - return nil, err - } - return child, nil -} - -// DeleteBucket deletes a bucket at the given key. -// Returns an error if the bucket does not exists, or if the key represents a non-bucket value. -func (b *Bucket) DeleteBucket(key []byte) error { - if b.tx.db == nil { - return ErrTxClosed - } else if !b.Writable() { - return ErrTxNotWritable - } - - // Move cursor to correct position. - c := b.Cursor() - k, _, flags := c.seek(key) - - // Return an error if bucket doesn't exist or is not a bucket. - if !bytes.Equal(key, k) { - return ErrBucketNotFound - } else if (flags & bucketLeafFlag) == 0 { - return ErrIncompatibleValue - } - - // Recursively delete all child buckets. - child := b.Bucket(key) - err := child.ForEach(func(k, v []byte) error { - if v == nil { - if err := child.DeleteBucket(k); err != nil { - return fmt.Errorf("delete bucket: %s", err) - } - } - return nil - }) - if err != nil { - return err - } - - // Remove cached copy. - delete(b.buckets, string(key)) - - // Release all bucket pages to freelist. - child.nodes = nil - child.rootNode = nil - child.free() - - // Delete the node if we have a matching key. - c.node().del(key) - - return nil -} - -// Get retrieves the value for a key in the bucket. -// Returns a nil value if the key does not exist or if the key is a nested bucket. -// The returned value is only valid for the life of the transaction. -func (b *Bucket) Get(key []byte) []byte { - k, v, flags := b.Cursor().seek(key) - - // Return nil if this is a bucket. - if (flags & bucketLeafFlag) != 0 { - return nil - } - - // If our target node isn't the same key as what's passed in then return nil. - if !bytes.Equal(key, k) { - return nil - } - return v -} - -// Put sets the value for a key in the bucket. -// If the key exist then its previous value will be overwritten. -// Supplied value must remain valid for the life of the transaction. -// Returns an error if the bucket was created from a read-only transaction, if the key is blank, if the key is too large, or if the value is too large. -func (b *Bucket) Put(key []byte, value []byte) error { - if b.tx.db == nil { - return ErrTxClosed - } else if !b.Writable() { - return ErrTxNotWritable - } else if len(key) == 0 { - return ErrKeyRequired - } else if len(key) > MaxKeySize { - return ErrKeyTooLarge - } else if int64(len(value)) > MaxValueSize { - return ErrValueTooLarge - } - - // Move cursor to correct position. - c := b.Cursor() - k, _, flags := c.seek(key) - - // Return an error if there is an existing key with a bucket value. - if bytes.Equal(key, k) && (flags&bucketLeafFlag) != 0 { - return ErrIncompatibleValue - } - - // Insert into node. - key = cloneBytes(key) - c.node().put(key, key, value, 0, 0) - - return nil -} - -// Delete removes a key from the bucket. -// If the key does not exist then nothing is done and a nil error is returned. -// Returns an error if the bucket was created from a read-only transaction. -func (b *Bucket) Delete(key []byte) error { - if b.tx.db == nil { - return ErrTxClosed - } else if !b.Writable() { - return ErrTxNotWritable - } - - // Move cursor to correct position. - c := b.Cursor() - _, _, flags := c.seek(key) - - // Return an error if there is already existing bucket value. - if (flags & bucketLeafFlag) != 0 { - return ErrIncompatibleValue - } - - // Delete the node if we have a matching key. - c.node().del(key) - - return nil -} - -// Sequence returns the current integer for the bucket without incrementing it. -func (b *Bucket) Sequence() uint64 { return b.bucket.sequence } - -// SetSequence updates the sequence number for the bucket. -func (b *Bucket) SetSequence(v uint64) error { - if b.tx.db == nil { - return ErrTxClosed - } else if !b.Writable() { - return ErrTxNotWritable - } - - // Materialize the root node if it hasn't been already so that the - // bucket will be saved during commit. - if b.rootNode == nil { - _ = b.node(b.root, nil) - } - - // Increment and return the sequence. - b.bucket.sequence = v - return nil -} - -// NextSequence returns an autoincrementing integer for the bucket. -func (b *Bucket) NextSequence() (uint64, error) { - if b.tx.db == nil { - return 0, ErrTxClosed - } else if !b.Writable() { - return 0, ErrTxNotWritable - } - - // Materialize the root node if it hasn't been already so that the - // bucket will be saved during commit. - if b.rootNode == nil { - _ = b.node(b.root, nil) - } - - // Increment and return the sequence. - b.bucket.sequence++ - return b.bucket.sequence, nil -} - -// ForEach executes a function for each key/value pair in a bucket. -// If the provided function returns an error then the iteration is stopped and -// the error is returned to the caller. The provided function must not modify -// the bucket; this will result in undefined behavior. -func (b *Bucket) ForEach(fn func(k, v []byte) error) error { - if b.tx.db == nil { - return ErrTxClosed - } - c := b.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - if err := fn(k, v); err != nil { - return err - } - } - return nil -} - -// Stat returns stats on a bucket. -func (b *Bucket) Stats() BucketStats { - var s, subStats BucketStats - pageSize := b.tx.db.pageSize - s.BucketN += 1 - if b.root == 0 { - s.InlineBucketN += 1 - } - b.forEachPage(func(p *page, depth int) { - if (p.flags & leafPageFlag) != 0 { - s.KeyN += int(p.count) - - // used totals the used bytes for the page - used := pageHeaderSize - - if p.count != 0 { - // If page has any elements, add all element headers. - used += leafPageElementSize * int(p.count-1) - - // Add all element key, value sizes. - // The computation takes advantage of the fact that the position - // of the last element's key/value equals to the total of the sizes - // of all previous elements' keys and values. - // It also includes the last element's header. - lastElement := p.leafPageElement(p.count - 1) - used += int(lastElement.pos + lastElement.ksize + lastElement.vsize) - } - - if b.root == 0 { - // For inlined bucket just update the inline stats - s.InlineBucketInuse += used - } else { - // For non-inlined bucket update all the leaf stats - s.LeafPageN++ - s.LeafInuse += used - s.LeafOverflowN += int(p.overflow) - - // Collect stats from sub-buckets. - // Do that by iterating over all element headers - // looking for the ones with the bucketLeafFlag. - for i := uint16(0); i < p.count; i++ { - e := p.leafPageElement(i) - if (e.flags & bucketLeafFlag) != 0 { - // For any bucket element, open the element value - // and recursively call Stats on the contained bucket. - subStats.Add(b.openBucket(e.value()).Stats()) - } - } - } - } else if (p.flags & branchPageFlag) != 0 { - s.BranchPageN++ - lastElement := p.branchPageElement(p.count - 1) - - // used totals the used bytes for the page - // Add header and all element headers. - used := pageHeaderSize + (branchPageElementSize * int(p.count-1)) - - // Add size of all keys and values. - // Again, use the fact that last element's position equals to - // the total of key, value sizes of all previous elements. - used += int(lastElement.pos + lastElement.ksize) - s.BranchInuse += used - s.BranchOverflowN += int(p.overflow) - } - - // Keep track of maximum page depth. - if depth+1 > s.Depth { - s.Depth = (depth + 1) - } - }) - - // Alloc stats can be computed from page counts and pageSize. - s.BranchAlloc = (s.BranchPageN + s.BranchOverflowN) * pageSize - s.LeafAlloc = (s.LeafPageN + s.LeafOverflowN) * pageSize - - // Add the max depth of sub-buckets to get total nested depth. - s.Depth += subStats.Depth - // Add the stats for all sub-buckets - s.Add(subStats) - return s -} - -// forEachPage iterates over every page in a bucket, including inline pages. -func (b *Bucket) forEachPage(fn func(*page, int)) { - // If we have an inline page then just use that. - if b.page != nil { - fn(b.page, 0) - return - } - - // Otherwise traverse the page hierarchy. - b.tx.forEachPage(b.root, 0, fn) -} - -// forEachPageNode iterates over every page (or node) in a bucket. -// This also includes inline pages. -func (b *Bucket) forEachPageNode(fn func(*page, *node, int)) { - // If we have an inline page or root node then just use that. - if b.page != nil { - fn(b.page, nil, 0) - return - } - b._forEachPageNode(b.root, 0, fn) -} - -func (b *Bucket) _forEachPageNode(pgid pgid, depth int, fn func(*page, *node, int)) { - var p, n = b.pageNode(pgid) - - // Execute function. - fn(p, n, depth) - - // Recursively loop over children. - if p != nil { - if (p.flags & branchPageFlag) != 0 { - for i := 0; i < int(p.count); i++ { - elem := p.branchPageElement(uint16(i)) - b._forEachPageNode(elem.pgid, depth+1, fn) - } - } - } else { - if !n.isLeaf { - for _, inode := range n.inodes { - b._forEachPageNode(inode.pgid, depth+1, fn) - } - } - } -} - -// spill writes all the nodes for this bucket to dirty pages. -func (b *Bucket) spill() error { - // Spill all child buckets first. - for name, child := range b.buckets { - // If the child bucket is small enough and it has no child buckets then - // write it inline into the parent bucket's page. Otherwise spill it - // like a normal bucket and make the parent value a pointer to the page. - var value []byte - if child.inlineable() { - child.free() - value = child.write() - } else { - if err := child.spill(); err != nil { - return err - } - - // Update the child bucket header in this bucket. - value = make([]byte, unsafe.Sizeof(bucket{})) - var bucket = (*bucket)(unsafe.Pointer(&value[0])) - *bucket = *child.bucket - } - - // Skip writing the bucket if there are no materialized nodes. - if child.rootNode == nil { - continue - } - - // Update parent node. - var c = b.Cursor() - k, _, flags := c.seek([]byte(name)) - if !bytes.Equal([]byte(name), k) { - panic(fmt.Sprintf("misplaced bucket header: %x -> %x", []byte(name), k)) - } - if flags&bucketLeafFlag == 0 { - panic(fmt.Sprintf("unexpected bucket header flag: %x", flags)) - } - c.node().put([]byte(name), []byte(name), value, 0, bucketLeafFlag) - } - - // Ignore if there's not a materialized root node. - if b.rootNode == nil { - return nil - } - - // Spill nodes. - if err := b.rootNode.spill(); err != nil { - return err - } - b.rootNode = b.rootNode.root() - - // Update the root node for this bucket. - if b.rootNode.pgid >= b.tx.meta.pgid { - panic(fmt.Sprintf("pgid (%d) above high water mark (%d)", b.rootNode.pgid, b.tx.meta.pgid)) - } - b.root = b.rootNode.pgid - - return nil -} - -// inlineable returns true if a bucket is small enough to be written inline -// and if it contains no subbuckets. Otherwise returns false. -func (b *Bucket) inlineable() bool { - var n = b.rootNode - - // Bucket must only contain a single leaf node. - if n == nil || !n.isLeaf { - return false - } - - // Bucket is not inlineable if it contains subbuckets or if it goes beyond - // our threshold for inline bucket size. - var size = pageHeaderSize - for _, inode := range n.inodes { - size += leafPageElementSize + len(inode.key) + len(inode.value) - - if inode.flags&bucketLeafFlag != 0 { - return false - } else if size > b.maxInlineBucketSize() { - return false - } - } - - return true -} - -// Returns the maximum total size of a bucket to make it a candidate for inlining. -func (b *Bucket) maxInlineBucketSize() int { - return b.tx.db.pageSize / 4 -} - -// write allocates and writes a bucket to a byte slice. -func (b *Bucket) write() []byte { - // Allocate the appropriate size. - var n = b.rootNode - var value = make([]byte, bucketHeaderSize+n.size()) - - // Write a bucket header. - var bucket = (*bucket)(unsafe.Pointer(&value[0])) - *bucket = *b.bucket - - // Convert byte slice to a fake page and write the root node. - var p = (*page)(unsafe.Pointer(&value[bucketHeaderSize])) - n.write(p) - - return value -} - -// rebalance attempts to balance all nodes. -func (b *Bucket) rebalance() { - for _, n := range b.nodes { - n.rebalance() - } - for _, child := range b.buckets { - child.rebalance() - } -} - -// node creates a node from a page and associates it with a given parent. -func (b *Bucket) node(pgid pgid, parent *node) *node { - _assert(b.nodes != nil, "nodes map expected") - - // Retrieve node if it's already been created. - if n := b.nodes[pgid]; n != nil { - return n - } - - // Otherwise create a node and cache it. - n := &node{bucket: b, parent: parent} - if parent == nil { - b.rootNode = n - } else { - parent.children = append(parent.children, n) - } - - // Use the inline page if this is an inline bucket. - var p = b.page - if p == nil { - p = b.tx.page(pgid) - } - - // Read the page into the node and cache it. - n.read(p) - b.nodes[pgid] = n - - // Update statistics. - b.tx.stats.NodeCount++ - - return n -} - -// free recursively frees all pages in the bucket. -func (b *Bucket) free() { - if b.root == 0 { - return - } - - var tx = b.tx - b.forEachPageNode(func(p *page, n *node, _ int) { - if p != nil { - tx.db.freelist.free(tx.meta.txid, p) - } else { - n.free() - } - }) - b.root = 0 -} - -// dereference removes all references to the old mmap. -func (b *Bucket) dereference() { - if b.rootNode != nil { - b.rootNode.root().dereference() - } - - for _, child := range b.buckets { - child.dereference() - } -} - -// pageNode returns the in-memory node, if it exists. -// Otherwise returns the underlying page. -func (b *Bucket) pageNode(id pgid) (*page, *node) { - // Inline buckets have a fake page embedded in their value so treat them - // differently. We'll return the rootNode (if available) or the fake page. - if b.root == 0 { - if id != 0 { - panic(fmt.Sprintf("inline bucket non-zero page access(2): %d != 0", id)) - } - if b.rootNode != nil { - return nil, b.rootNode - } - return b.page, nil - } - - // Check the node cache for non-inline buckets. - if b.nodes != nil { - if n := b.nodes[id]; n != nil { - return nil, n - } - } - - // Finally lookup the page from the transaction if no node is materialized. - return b.tx.page(id), nil -} - -// BucketStats records statistics about resources used by a bucket. -type BucketStats struct { - // Page count statistics. - BranchPageN int // number of logical branch pages - BranchOverflowN int // number of physical branch overflow pages - LeafPageN int // number of logical leaf pages - LeafOverflowN int // number of physical leaf overflow pages - - // Tree statistics. - KeyN int // number of keys/value pairs - Depth int // number of levels in B+tree - - // Page size utilization. - BranchAlloc int // bytes allocated for physical branch pages - BranchInuse int // bytes actually used for branch data - LeafAlloc int // bytes allocated for physical leaf pages - LeafInuse int // bytes actually used for leaf data - - // Bucket statistics - BucketN int // total number of buckets including the top bucket - InlineBucketN int // total number on inlined buckets - InlineBucketInuse int // bytes used for inlined buckets (also accounted for in LeafInuse) -} - -func (s *BucketStats) Add(other BucketStats) { - s.BranchPageN += other.BranchPageN - s.BranchOverflowN += other.BranchOverflowN - s.LeafPageN += other.LeafPageN - s.LeafOverflowN += other.LeafOverflowN - s.KeyN += other.KeyN - if s.Depth < other.Depth { - s.Depth = other.Depth - } - s.BranchAlloc += other.BranchAlloc - s.BranchInuse += other.BranchInuse - s.LeafAlloc += other.LeafAlloc - s.LeafInuse += other.LeafInuse - - s.BucketN += other.BucketN - s.InlineBucketN += other.InlineBucketN - s.InlineBucketInuse += other.InlineBucketInuse -} - -// cloneBytes returns a copy of a given slice. -func cloneBytes(v []byte) []byte { - var clone = make([]byte, len(v)) - copy(clone, v) - return clone -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket_test.go deleted file mode 100644 index cddbe27..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/bucket_test.go +++ /dev/null @@ -1,1909 +0,0 @@ -package bolt_test - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - "log" - "math/rand" - "os" - "strconv" - "strings" - "testing" - "testing/quick" - - "github.com/boltdb/bolt" -) - -// Ensure that a bucket that gets a non-existent key returns nil. -func TestBucket_Get_NonExistent(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if v := b.Get([]byte("foo")); v != nil { - t.Fatal("expected nil value") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can read a value that is not flushed yet. -func TestBucket_Get_FromNode(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if v := b.Get([]byte("foo")); !bytes.Equal(v, []byte("bar")) { - t.Fatalf("unexpected value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket retrieved via Get() returns a nil. -func TestBucket_Get_IncompatibleValue(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")); err != nil { - t.Fatal(err) - } - - if tx.Bucket([]byte("widgets")).Get([]byte("foo")) != nil { - t.Fatal("expected nil value") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a slice returned from a bucket has a capacity equal to its length. -// This also allows slices to be appended to since it will require a realloc by Go. -// -// https://github.com/boltdb/bolt/issues/544 -func TestBucket_Get_Capacity(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - // Write key to a bucket. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("bucket")) - if err != nil { - return err - } - return b.Put([]byte("key"), []byte("val")) - }); err != nil { - t.Fatal(err) - } - - // Retrieve value and attempt to append to it. - if err := db.Update(func(tx *bolt.Tx) error { - k, v := tx.Bucket([]byte("bucket")).Cursor().First() - - // Verify capacity. - if len(k) != cap(k) { - t.Fatalf("unexpected key slice capacity: %d", cap(k)) - } else if len(v) != cap(v) { - t.Fatalf("unexpected value slice capacity: %d", cap(v)) - } - - // Ensure slice can be appended to without a segfault. - k = append(k, []byte("123")...) - v = append(v, []byte("123")...) - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can write a key/value. -func TestBucket_Put(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - - v := tx.Bucket([]byte("widgets")).Get([]byte("foo")) - if !bytes.Equal([]byte("bar"), v) { - t.Fatalf("unexpected value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can rewrite a key in the same transaction. -func TestBucket_Put_Repeat(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("baz")); err != nil { - t.Fatal(err) - } - - value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) - if !bytes.Equal([]byte("baz"), value) { - t.Fatalf("unexpected value: %v", value) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can write a bunch of large values. -func TestBucket_Put_Large(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - count, factor := 100, 200 - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - for i := 1; i < count; i++ { - if err := b.Put([]byte(strings.Repeat("0", i*factor)), []byte(strings.Repeat("X", (count-i)*factor))); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for i := 1; i < count; i++ { - value := b.Get([]byte(strings.Repeat("0", i*factor))) - if !bytes.Equal(value, []byte(strings.Repeat("X", (count-i)*factor))) { - t.Fatalf("unexpected value: %v", value) - } - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a database can perform multiple large appends safely. -func TestDB_Put_VeryLarge(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - n, batchN := 400000, 200000 - ksize, vsize := 8, 500 - - db := MustOpenDB() - defer db.MustClose() - - for i := 0; i < n; i += batchN { - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucketIfNotExists([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - for j := 0; j < batchN; j++ { - k, v := make([]byte, ksize), make([]byte, vsize) - binary.BigEndian.PutUint32(k, uint32(i+j)) - if err := b.Put(k, v); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - } -} - -// Ensure that a setting a value on a key with a bucket value returns an error. -func TestBucket_Put_IncompatibleValue(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b0, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")); err != nil { - t.Fatal(err) - } - if err := b0.Put([]byte("foo"), []byte("bar")); err != bolt.ErrIncompatibleValue { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a setting a value while the transaction is closed returns an error. -func TestBucket_Put_Closed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - - if err := b.Put([]byte("foo"), []byte("bar")); err != bolt.ErrTxClosed { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that setting a value on a read-only bucket returns an error. -func TestBucket_Put_ReadOnly(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - if err := b.Put([]byte("foo"), []byte("bar")); err != bolt.ErrTxNotWritable { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can delete an existing key. -func TestBucket_Delete(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if err := b.Delete([]byte("foo")); err != nil { - t.Fatal(err) - } - if v := b.Get([]byte("foo")); v != nil { - t.Fatalf("unexpected value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that deleting a large set of keys will work correctly. -func TestBucket_Delete_Large(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - for i := 0; i < 100; i++ { - if err := b.Put([]byte(strconv.Itoa(i)), []byte(strings.Repeat("*", 1024))); err != nil { - t.Fatal(err) - } - } - - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for i := 0; i < 100; i++ { - if err := b.Delete([]byte(strconv.Itoa(i))); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for i := 0; i < 100; i++ { - if v := b.Get([]byte(strconv.Itoa(i))); v != nil { - t.Fatalf("unexpected value: %v, i=%d", v, i) - } - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Deleting a very large list of keys will cause the freelist to use overflow. -func TestBucket_Delete_FreelistOverflow(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - db := MustOpenDB() - defer db.MustClose() - - k := make([]byte, 16) - for i := uint64(0); i < 10000; i++ { - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucketIfNotExists([]byte("0")) - if err != nil { - t.Fatalf("bucket error: %s", err) - } - - for j := uint64(0); j < 1000; j++ { - binary.BigEndian.PutUint64(k[:8], i) - binary.BigEndian.PutUint64(k[8:], j) - if err := b.Put(k, nil); err != nil { - t.Fatalf("put error: %s", err) - } - } - - return nil - }); err != nil { - t.Fatal(err) - } - } - - // Delete all of them in one large transaction - if err := db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("0")) - c := b.Cursor() - for k, _ := c.First(); k != nil; k, _ = c.Next() { - if err := c.Delete(); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that accessing and updating nested buckets is ok across transactions. -func TestBucket_Nested(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - // Create a widgets bucket. - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - // Create a widgets/foo bucket. - _, err = b.CreateBucket([]byte("foo")) - if err != nil { - t.Fatal(err) - } - - // Create a widgets/bar key. - if err := b.Put([]byte("bar"), []byte("0000")); err != nil { - t.Fatal(err) - } - - return nil - }); err != nil { - t.Fatal(err) - } - db.MustCheck() - - // Update widgets/bar. - if err := db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - if err := b.Put([]byte("bar"), []byte("xxxx")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - db.MustCheck() - - // Cause a split. - if err := db.Update(func(tx *bolt.Tx) error { - var b = tx.Bucket([]byte("widgets")) - for i := 0; i < 10000; i++ { - if err := b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - db.MustCheck() - - // Insert into widgets/foo/baz. - if err := db.Update(func(tx *bolt.Tx) error { - var b = tx.Bucket([]byte("widgets")) - if err := b.Bucket([]byte("foo")).Put([]byte("baz"), []byte("yyyy")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - db.MustCheck() - - // Verify. - if err := db.View(func(tx *bolt.Tx) error { - var b = tx.Bucket([]byte("widgets")) - if v := b.Bucket([]byte("foo")).Get([]byte("baz")); !bytes.Equal(v, []byte("yyyy")) { - t.Fatalf("unexpected value: %v", v) - } - if v := b.Get([]byte("bar")); !bytes.Equal(v, []byte("xxxx")) { - t.Fatalf("unexpected value: %v", v) - } - for i := 0; i < 10000; i++ { - if v := b.Get([]byte(strconv.Itoa(i))); !bytes.Equal(v, []byte(strconv.Itoa(i))) { - t.Fatalf("unexpected value: %v", v) - } - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that deleting a bucket using Delete() returns an error. -func TestBucket_Delete_Bucket(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if _, err := b.CreateBucket([]byte("foo")); err != nil { - t.Fatal(err) - } - if err := b.Delete([]byte("foo")); err != bolt.ErrIncompatibleValue { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that deleting a key on a read-only bucket returns an error. -func TestBucket_Delete_ReadOnly(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - if err := tx.Bucket([]byte("widgets")).Delete([]byte("foo")); err != bolt.ErrTxNotWritable { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a deleting value while the transaction is closed returns an error. -func TestBucket_Delete_Closed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - if err := b.Delete([]byte("foo")); err != bolt.ErrTxClosed { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that deleting a bucket causes nested buckets to be deleted. -func TestBucket_DeleteBucket_Nested(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - widgets, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - foo, err := widgets.CreateBucket([]byte("foo")) - if err != nil { - t.Fatal(err) - } - - bar, err := foo.CreateBucket([]byte("bar")) - if err != nil { - t.Fatal(err) - } - if err := bar.Put([]byte("baz"), []byte("bat")); err != nil { - t.Fatal(err) - } - if err := tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that deleting a bucket causes nested buckets to be deleted after they have been committed. -func TestBucket_DeleteBucket_Nested2(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - widgets, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - foo, err := widgets.CreateBucket([]byte("foo")) - if err != nil { - t.Fatal(err) - } - - bar, err := foo.CreateBucket([]byte("bar")) - if err != nil { - t.Fatal(err) - } - - if err := bar.Put([]byte("baz"), []byte("bat")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - widgets := tx.Bucket([]byte("widgets")) - if widgets == nil { - t.Fatal("expected widgets bucket") - } - - foo := widgets.Bucket([]byte("foo")) - if foo == nil { - t.Fatal("expected foo bucket") - } - - bar := foo.Bucket([]byte("bar")) - if bar == nil { - t.Fatal("expected bar bucket") - } - - if v := bar.Get([]byte("baz")); !bytes.Equal(v, []byte("bat")) { - t.Fatalf("unexpected value: %v", v) - } - if err := tx.DeleteBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - if tx.Bucket([]byte("widgets")) != nil { - t.Fatal("expected bucket to be deleted") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that deleting a child bucket with multiple pages causes all pages to get collected. -// NOTE: Consistency check in bolt_test.DB.Close() will panic if pages not freed properly. -func TestBucket_DeleteBucket_Large(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - widgets, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - foo, err := widgets.CreateBucket([]byte("foo")) - if err != nil { - t.Fatal(err) - } - - for i := 0; i < 1000; i++ { - if err := foo.Put([]byte(fmt.Sprintf("%d", i)), []byte(fmt.Sprintf("%0100d", i))); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - if err := tx.DeleteBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a simple value retrieved via Bucket() returns a nil. -func TestBucket_Bucket_IncompatibleValue(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - widgets, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if b := tx.Bucket([]byte("widgets")).Bucket([]byte("foo")); b != nil { - t.Fatal("expected nil bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that creating a bucket on an existing non-bucket key returns an error. -func TestBucket_CreateBucket_IncompatibleValue(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - widgets, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if _, err := widgets.CreateBucket([]byte("foo")); err != bolt.ErrIncompatibleValue { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that deleting a bucket on an existing non-bucket key returns an error. -func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - widgets, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if err := tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")); err != bolt.ErrIncompatibleValue { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure bucket can set and update its sequence number. -func TestBucket_Sequence(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - bkt, err := tx.CreateBucket([]byte("0")) - if err != nil { - t.Fatal(err) - } - - // Retrieve sequence. - if v := bkt.Sequence(); v != 0 { - t.Fatalf("unexpected sequence: %d", v) - } - - // Update sequence. - if err := bkt.SetSequence(1000); err != nil { - t.Fatal(err) - } - - // Read sequence again. - if v := bkt.Sequence(); v != 1000 { - t.Fatalf("unexpected sequence: %d", v) - } - - return nil - }); err != nil { - t.Fatal(err) - } - - // Verify sequence in separate transaction. - if err := db.View(func(tx *bolt.Tx) error { - if v := tx.Bucket([]byte("0")).Sequence(); v != 1000 { - t.Fatalf("unexpected sequence: %d", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can return an autoincrementing sequence. -func TestBucket_NextSequence(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - widgets, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - woojits, err := tx.CreateBucket([]byte("woojits")) - if err != nil { - t.Fatal(err) - } - - // Make sure sequence increments. - if seq, err := widgets.NextSequence(); err != nil { - t.Fatal(err) - } else if seq != 1 { - t.Fatalf("unexpecte sequence: %d", seq) - } - - if seq, err := widgets.NextSequence(); err != nil { - t.Fatal(err) - } else if seq != 2 { - t.Fatalf("unexpected sequence: %d", seq) - } - - // Buckets should be separate. - if seq, err := woojits.NextSequence(); err != nil { - t.Fatal(err) - } else if seq != 1 { - t.Fatalf("unexpected sequence: %d", 1) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket will persist an autoincrementing sequence even if its -// the only thing updated on the bucket. -// https://github.com/boltdb/bolt/issues/296 -func TestBucket_NextSequence_Persist(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.Bucket([]byte("widgets")).NextSequence(); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - seq, err := tx.Bucket([]byte("widgets")).NextSequence() - if err != nil { - t.Fatalf("unexpected error: %s", err) - } else if seq != 2 { - t.Fatalf("unexpected sequence: %d", seq) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that retrieving the next sequence on a read-only bucket returns an error. -func TestBucket_NextSequence_ReadOnly(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - _, err := tx.Bucket([]byte("widgets")).NextSequence() - if err != bolt.ErrTxNotWritable { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that retrieving the next sequence for a bucket on a closed database return an error. -func TestBucket_NextSequence_Closed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - if _, err := b.NextSequence(); err != bolt.ErrTxClosed { - t.Fatal(err) - } -} - -// Ensure a user can loop over all key/value pairs in a bucket. -func TestBucket_ForEach(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("0000")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte("0001")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("bar"), []byte("0002")); err != nil { - t.Fatal(err) - } - - var index int - if err := b.ForEach(func(k, v []byte) error { - switch index { - case 0: - if !bytes.Equal(k, []byte("bar")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte("0002")) { - t.Fatalf("unexpected value: %v", v) - } - case 1: - if !bytes.Equal(k, []byte("baz")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte("0001")) { - t.Fatalf("unexpected value: %v", v) - } - case 2: - if !bytes.Equal(k, []byte("foo")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte("0000")) { - t.Fatalf("unexpected value: %v", v) - } - } - index++ - return nil - }); err != nil { - t.Fatal(err) - } - - if index != 3 { - t.Fatalf("unexpected index: %d", index) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a database can stop iteration early. -func TestBucket_ForEach_ShortCircuit(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("bar"), []byte("0000")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte("0000")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("0000")); err != nil { - t.Fatal(err) - } - - var index int - if err := tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error { - index++ - if bytes.Equal(k, []byte("baz")) { - return errors.New("marker") - } - return nil - }); err == nil || err.Error() != "marker" { - t.Fatalf("unexpected error: %s", err) - } - if index != 2 { - t.Fatalf("unexpected index: %d", index) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that looping over a bucket on a closed database returns an error. -func TestBucket_ForEach_Closed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - - if err := b.ForEach(func(k, v []byte) error { return nil }); err != bolt.ErrTxClosed { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that an error is returned when inserting with an empty key. -func TestBucket_Put_EmptyKey(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte(""), []byte("bar")); err != bolt.ErrKeyRequired { - t.Fatalf("unexpected error: %s", err) - } - if err := b.Put(nil, []byte("bar")); err != bolt.ErrKeyRequired { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that an error is returned when inserting with a key that's too large. -func TestBucket_Put_KeyTooLarge(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put(make([]byte, 32769), []byte("bar")); err != bolt.ErrKeyTooLarge { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that an error is returned when inserting a value that's too large. -func TestBucket_Put_ValueTooLarge(t *testing.T) { - // Skip this test on DroneCI because the machine is resource constrained. - if os.Getenv("DRONE") == "true" { - t.Skip("not enough RAM for test") - } - - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), make([]byte, bolt.MaxValueSize+1)); err != bolt.ErrValueTooLarge { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a bucket can calculate stats. -func TestBucket_Stats(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - // Add bucket with fewer keys but one big value. - bigKey := []byte("really-big-value") - for i := 0; i < 500; i++ { - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucketIfNotExists([]byte("woojits")) - if err != nil { - t.Fatal(err) - } - - if err := b.Put([]byte(fmt.Sprintf("%03d", i)), []byte(strconv.Itoa(i))); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - } - if err := db.Update(func(tx *bolt.Tx) error { - if err := tx.Bucket([]byte("woojits")).Put(bigKey, []byte(strings.Repeat("*", 10000))); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - db.MustCheck() - - if err := db.View(func(tx *bolt.Tx) error { - stats := tx.Bucket([]byte("woojits")).Stats() - if stats.BranchPageN != 1 { - t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) - } else if stats.BranchOverflowN != 0 { - t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) - } else if stats.LeafPageN != 7 { - t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) - } else if stats.LeafOverflowN != 2 { - t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) - } else if stats.KeyN != 501 { - t.Fatalf("unexpected KeyN: %d", stats.KeyN) - } else if stats.Depth != 2 { - t.Fatalf("unexpected Depth: %d", stats.Depth) - } - - branchInuse := 16 // branch page header - branchInuse += 7 * 16 // branch elements - branchInuse += 7 * 3 // branch keys (6 3-byte keys) - if stats.BranchInuse != branchInuse { - t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) - } - - leafInuse := 7 * 16 // leaf page header - leafInuse += 501 * 16 // leaf elements - leafInuse += 500*3 + len(bigKey) // leaf keys - leafInuse += 1*10 + 2*90 + 3*400 + 10000 // leaf values - if stats.LeafInuse != leafInuse { - t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) - } - - // Only check allocations for 4KB pages. - if os.Getpagesize() == 4096 { - if stats.BranchAlloc != 4096 { - t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) - } else if stats.LeafAlloc != 36864 { - t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) - } - } - - if stats.BucketN != 1 { - t.Fatalf("unexpected BucketN: %d", stats.BucketN) - } else if stats.InlineBucketN != 0 { - t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) - } else if stats.InlineBucketInuse != 0 { - t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a bucket with random insertion utilizes fill percentage correctly. -func TestBucket_Stats_RandomFill(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } else if os.Getpagesize() != 4096 { - t.Skip("invalid page size for test") - } - - db := MustOpenDB() - defer db.MustClose() - - // Add a set of values in random order. It will be the same random - // order so we can maintain consistency between test runs. - var count int - rand := rand.New(rand.NewSource(42)) - for _, i := range rand.Perm(1000) { - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucketIfNotExists([]byte("woojits")) - if err != nil { - t.Fatal(err) - } - b.FillPercent = 0.9 - for _, j := range rand.Perm(100) { - index := (j * 10000) + i - if err := b.Put([]byte(fmt.Sprintf("%d000000000000000", index)), []byte("0000000000")); err != nil { - t.Fatal(err) - } - count++ - } - return nil - }); err != nil { - t.Fatal(err) - } - } - - db.MustCheck() - - if err := db.View(func(tx *bolt.Tx) error { - stats := tx.Bucket([]byte("woojits")).Stats() - if stats.KeyN != 100000 { - t.Fatalf("unexpected KeyN: %d", stats.KeyN) - } - - if stats.BranchPageN != 98 { - t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) - } else if stats.BranchOverflowN != 0 { - t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) - } else if stats.BranchInuse != 130984 { - t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) - } else if stats.BranchAlloc != 401408 { - t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) - } - - if stats.LeafPageN != 3412 { - t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) - } else if stats.LeafOverflowN != 0 { - t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) - } else if stats.LeafInuse != 4742482 { - t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) - } else if stats.LeafAlloc != 13975552 { - t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a bucket can calculate stats. -func TestBucket_Stats_Small(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - // Add a bucket that fits on a single root leaf. - b, err := tx.CreateBucket([]byte("whozawhats")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - - return nil - }); err != nil { - t.Fatal(err) - } - - db.MustCheck() - - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("whozawhats")) - stats := b.Stats() - if stats.BranchPageN != 0 { - t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) - } else if stats.BranchOverflowN != 0 { - t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) - } else if stats.LeafPageN != 0 { - t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) - } else if stats.LeafOverflowN != 0 { - t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) - } else if stats.KeyN != 1 { - t.Fatalf("unexpected KeyN: %d", stats.KeyN) - } else if stats.Depth != 1 { - t.Fatalf("unexpected Depth: %d", stats.Depth) - } else if stats.BranchInuse != 0 { - t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) - } else if stats.LeafInuse != 0 { - t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) - } - - if os.Getpagesize() == 4096 { - if stats.BranchAlloc != 0 { - t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) - } else if stats.LeafAlloc != 0 { - t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) - } - } - - if stats.BucketN != 1 { - t.Fatalf("unexpected BucketN: %d", stats.BucketN) - } else if stats.InlineBucketN != 1 { - t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) - } else if stats.InlineBucketInuse != 16+16+6 { - t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -func TestBucket_Stats_EmptyBucket(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - // Add a bucket that fits on a single root leaf. - if _, err := tx.CreateBucket([]byte("whozawhats")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - db.MustCheck() - - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("whozawhats")) - stats := b.Stats() - if stats.BranchPageN != 0 { - t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) - } else if stats.BranchOverflowN != 0 { - t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) - } else if stats.LeafPageN != 0 { - t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) - } else if stats.LeafOverflowN != 0 { - t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) - } else if stats.KeyN != 0 { - t.Fatalf("unexpected KeyN: %d", stats.KeyN) - } else if stats.Depth != 1 { - t.Fatalf("unexpected Depth: %d", stats.Depth) - } else if stats.BranchInuse != 0 { - t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) - } else if stats.LeafInuse != 0 { - t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) - } - - if os.Getpagesize() == 4096 { - if stats.BranchAlloc != 0 { - t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) - } else if stats.LeafAlloc != 0 { - t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) - } - } - - if stats.BucketN != 1 { - t.Fatalf("unexpected BucketN: %d", stats.BucketN) - } else if stats.InlineBucketN != 1 { - t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) - } else if stats.InlineBucketInuse != 16 { - t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a bucket can calculate stats. -func TestBucket_Stats_Nested(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("foo")) - if err != nil { - t.Fatal(err) - } - for i := 0; i < 100; i++ { - if err := b.Put([]byte(fmt.Sprintf("%02d", i)), []byte(fmt.Sprintf("%02d", i))); err != nil { - t.Fatal(err) - } - } - - bar, err := b.CreateBucket([]byte("bar")) - if err != nil { - t.Fatal(err) - } - for i := 0; i < 10; i++ { - if err := bar.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil { - t.Fatal(err) - } - } - - baz, err := bar.CreateBucket([]byte("baz")) - if err != nil { - t.Fatal(err) - } - for i := 0; i < 10; i++ { - if err := baz.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil { - t.Fatal(err) - } - } - - return nil - }); err != nil { - t.Fatal(err) - } - - db.MustCheck() - - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("foo")) - stats := b.Stats() - if stats.BranchPageN != 0 { - t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) - } else if stats.BranchOverflowN != 0 { - t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) - } else if stats.LeafPageN != 2 { - t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) - } else if stats.LeafOverflowN != 0 { - t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) - } else if stats.KeyN != 122 { - t.Fatalf("unexpected KeyN: %d", stats.KeyN) - } else if stats.Depth != 3 { - t.Fatalf("unexpected Depth: %d", stats.Depth) - } else if stats.BranchInuse != 0 { - t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) - } - - foo := 16 // foo (pghdr) - foo += 101 * 16 // foo leaf elements - foo += 100*2 + 100*2 // foo leaf key/values - foo += 3 + 16 // foo -> bar key/value - - bar := 16 // bar (pghdr) - bar += 11 * 16 // bar leaf elements - bar += 10 + 10 // bar leaf key/values - bar += 3 + 16 // bar -> baz key/value - - baz := 16 // baz (inline) (pghdr) - baz += 10 * 16 // baz leaf elements - baz += 10 + 10 // baz leaf key/values - - if stats.LeafInuse != foo+bar+baz { - t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) - } - - if os.Getpagesize() == 4096 { - if stats.BranchAlloc != 0 { - t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) - } else if stats.LeafAlloc != 8192 { - t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) - } - } - - if stats.BucketN != 3 { - t.Fatalf("unexpected BucketN: %d", stats.BucketN) - } else if stats.InlineBucketN != 1 { - t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) - } else if stats.InlineBucketInuse != baz { - t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a large bucket can calculate stats. -func TestBucket_Stats_Large(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - db := MustOpenDB() - defer db.MustClose() - - var index int - for i := 0; i < 100; i++ { - // Add bucket with lots of keys. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucketIfNotExists([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - for i := 0; i < 1000; i++ { - if err := b.Put([]byte(strconv.Itoa(index)), []byte(strconv.Itoa(index))); err != nil { - t.Fatal(err) - } - index++ - } - return nil - }); err != nil { - t.Fatal(err) - } - } - - db.MustCheck() - - if err := db.View(func(tx *bolt.Tx) error { - stats := tx.Bucket([]byte("widgets")).Stats() - if stats.BranchPageN != 13 { - t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) - } else if stats.BranchOverflowN != 0 { - t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) - } else if stats.LeafPageN != 1196 { - t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) - } else if stats.LeafOverflowN != 0 { - t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) - } else if stats.KeyN != 100000 { - t.Fatalf("unexpected KeyN: %d", stats.KeyN) - } else if stats.Depth != 3 { - t.Fatalf("unexpected Depth: %d", stats.Depth) - } else if stats.BranchInuse != 25257 { - t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) - } else if stats.LeafInuse != 2596916 { - t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) - } - - if os.Getpagesize() == 4096 { - if stats.BranchAlloc != 53248 { - t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) - } else if stats.LeafAlloc != 4898816 { - t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) - } - } - - if stats.BucketN != 1 { - t.Fatalf("unexpected BucketN: %d", stats.BucketN) - } else if stats.InlineBucketN != 0 { - t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) - } else if stats.InlineBucketInuse != 0 { - t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can write random keys and values across multiple transactions. -func TestBucket_Put_Single(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - index := 0 - if err := quick.Check(func(items testdata) bool { - db := MustOpenDB() - defer db.MustClose() - - m := make(map[string][]byte) - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - for _, item := range items { - if err := db.Update(func(tx *bolt.Tx) error { - if err := tx.Bucket([]byte("widgets")).Put(item.Key, item.Value); err != nil { - panic("put error: " + err.Error()) - } - m[string(item.Key)] = item.Value - return nil - }); err != nil { - t.Fatal(err) - } - - // Verify all key/values so far. - if err := db.View(func(tx *bolt.Tx) error { - i := 0 - for k, v := range m { - value := tx.Bucket([]byte("widgets")).Get([]byte(k)) - if !bytes.Equal(value, v) { - t.Logf("value mismatch [run %d] (%d of %d):\nkey: %x\ngot: %x\nexp: %x", index, i, len(m), []byte(k), value, v) - db.CopyTempFile() - t.FailNow() - } - i++ - } - return nil - }); err != nil { - t.Fatal(err) - } - } - - index++ - return true - }, nil); err != nil { - t.Error(err) - } -} - -// Ensure that a transaction can insert multiple key/value pairs at once. -func TestBucket_Put_Multiple(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - if err := quick.Check(func(items testdata) bool { - db := MustOpenDB() - defer db.MustClose() - - // Bulk insert all values. - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for _, item := range items { - if err := b.Put(item.Key, item.Value); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Verify all items exist. - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for _, item := range items { - value := b.Get(item.Key) - if !bytes.Equal(item.Value, value) { - db.CopyTempFile() - t.Fatalf("exp=%x; got=%x", item.Value, value) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - return true - }, qconfig()); err != nil { - t.Error(err) - } -} - -// Ensure that a transaction can delete all key/value pairs and return to a single leaf page. -func TestBucket_Delete_Quick(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - if err := quick.Check(func(items testdata) bool { - db := MustOpenDB() - defer db.MustClose() - - // Bulk insert all values. - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for _, item := range items { - if err := b.Put(item.Key, item.Value); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Remove items one at a time and check consistency. - for _, item := range items { - if err := db.Update(func(tx *bolt.Tx) error { - return tx.Bucket([]byte("widgets")).Delete(item.Key) - }); err != nil { - t.Fatal(err) - } - } - - // Anything before our deletion index should be nil. - if err := db.View(func(tx *bolt.Tx) error { - if err := tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error { - t.Fatalf("bucket should be empty; found: %06x", trunc(k, 3)) - return nil - }); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - return true - }, qconfig()); err != nil { - t.Error(err) - } -} - -func ExampleBucket_Put() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Start a write transaction. - if err := db.Update(func(tx *bolt.Tx) error { - // Create a bucket. - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - return err - } - - // Set the value "bar" for the key "foo". - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - return err - } - return nil - }); err != nil { - log.Fatal(err) - } - - // Read value back in a different read-only transaction. - if err := db.View(func(tx *bolt.Tx) error { - value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) - fmt.Printf("The value of 'foo' is: %s\n", value) - return nil - }); err != nil { - log.Fatal(err) - } - - // Close database to release file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // The value of 'foo' is: bar -} - -func ExampleBucket_Delete() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Start a write transaction. - if err := db.Update(func(tx *bolt.Tx) error { - // Create a bucket. - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - return err - } - - // Set the value "bar" for the key "foo". - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - return err - } - - // Retrieve the key back from the database and verify it. - value := b.Get([]byte("foo")) - fmt.Printf("The value of 'foo' was: %s\n", value) - - return nil - }); err != nil { - log.Fatal(err) - } - - // Delete the key in a different write transaction. - if err := db.Update(func(tx *bolt.Tx) error { - return tx.Bucket([]byte("widgets")).Delete([]byte("foo")) - }); err != nil { - log.Fatal(err) - } - - // Retrieve the key again. - if err := db.View(func(tx *bolt.Tx) error { - value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) - if value == nil { - fmt.Printf("The value of 'foo' is now: nil\n") - } - return nil - }); err != nil { - log.Fatal(err) - } - - // Close database to release file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // The value of 'foo' was: bar - // The value of 'foo' is now: nil -} - -func ExampleBucket_ForEach() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Insert data into a bucket. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("animals")) - if err != nil { - return err - } - - if err := b.Put([]byte("dog"), []byte("fun")); err != nil { - return err - } - if err := b.Put([]byte("cat"), []byte("lame")); err != nil { - return err - } - if err := b.Put([]byte("liger"), []byte("awesome")); err != nil { - return err - } - - // Iterate over items in sorted key order. - if err := b.ForEach(func(k, v []byte) error { - fmt.Printf("A %s is %s.\n", k, v) - return nil - }); err != nil { - return err - } - - return nil - }); err != nil { - log.Fatal(err) - } - - // Close database to release file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // A cat is lame. - // A dog is fun. - // A liger is awesome. -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main.go deleted file mode 100644 index 29e393f..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main.go +++ /dev/null @@ -1,1740 +0,0 @@ -package main - -import ( - "bytes" - "encoding/binary" - "errors" - "flag" - "fmt" - "io" - "io/ioutil" - "math/rand" - "os" - "runtime" - "runtime/pprof" - "strconv" - "strings" - "time" - "unicode" - "unicode/utf8" - "unsafe" - - "github.com/boltdb/bolt" -) - -var ( - // ErrUsage is returned when a usage message was printed and the process - // should simply exit with an error. - ErrUsage = errors.New("usage") - - // ErrUnknownCommand is returned when a CLI command is not specified. - ErrUnknownCommand = errors.New("unknown command") - - // ErrPathRequired is returned when the path to a Bolt database is not specified. - ErrPathRequired = errors.New("path required") - - // ErrFileNotFound is returned when a Bolt database does not exist. - ErrFileNotFound = errors.New("file not found") - - // ErrInvalidValue is returned when a benchmark reads an unexpected value. - ErrInvalidValue = errors.New("invalid value") - - // ErrCorrupt is returned when a checking a data file finds errors. - ErrCorrupt = errors.New("invalid value") - - // ErrNonDivisibleBatchSize is returned when the batch size can't be evenly - // divided by the iteration count. - ErrNonDivisibleBatchSize = errors.New("number of iterations must be divisible by the batch size") - - // ErrPageIDRequired is returned when a required page id is not specified. - ErrPageIDRequired = errors.New("page id required") - - // ErrPageNotFound is returned when specifying a page above the high water mark. - ErrPageNotFound = errors.New("page not found") - - // ErrPageFreed is returned when reading a page that has already been freed. - ErrPageFreed = errors.New("page freed") -) - -// PageHeaderSize represents the size of the bolt.page header. -const PageHeaderSize = 16 - -func main() { - m := NewMain() - if err := m.Run(os.Args[1:]...); err == ErrUsage { - os.Exit(2) - } else if err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } -} - -// Main represents the main program execution. -type Main struct { - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer -} - -// NewMain returns a new instance of Main connect to the standard input/output. -func NewMain() *Main { - return &Main{ - Stdin: os.Stdin, - Stdout: os.Stdout, - Stderr: os.Stderr, - } -} - -// Run executes the program. -func (m *Main) Run(args ...string) error { - // Require a command at the beginning. - if len(args) == 0 || strings.HasPrefix(args[0], "-") { - fmt.Fprintln(m.Stderr, m.Usage()) - return ErrUsage - } - - // Execute command. - switch args[0] { - case "help": - fmt.Fprintln(m.Stderr, m.Usage()) - return ErrUsage - case "bench": - return newBenchCommand(m).Run(args[1:]...) - case "check": - return newCheckCommand(m).Run(args[1:]...) - case "compact": - return newCompactCommand(m).Run(args[1:]...) - case "dump": - return newDumpCommand(m).Run(args[1:]...) - case "info": - return newInfoCommand(m).Run(args[1:]...) - case "page": - return newPageCommand(m).Run(args[1:]...) - case "pages": - return newPagesCommand(m).Run(args[1:]...) - case "stats": - return newStatsCommand(m).Run(args[1:]...) - default: - return ErrUnknownCommand - } -} - -// Usage returns the help message. -func (m *Main) Usage() string { - return strings.TrimLeft(` -Bolt is a tool for inspecting bolt databases. - -Usage: - - bolt command [arguments] - -The commands are: - - bench run synthetic benchmark against bolt - check verifies integrity of bolt database - compact copies a bolt database, compacting it in the process - info print basic info - help print this screen - pages print list of pages with their types - stats iterate over all pages and generate usage stats - -Use "bolt [command] -h" for more information about a command. -`, "\n") -} - -// CheckCommand represents the "check" command execution. -type CheckCommand struct { - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer -} - -// NewCheckCommand returns a CheckCommand. -func newCheckCommand(m *Main) *CheckCommand { - return &CheckCommand{ - Stdin: m.Stdin, - Stdout: m.Stdout, - Stderr: m.Stderr, - } -} - -// Run executes the command. -func (cmd *CheckCommand) Run(args ...string) error { - // Parse flags. - fs := flag.NewFlagSet("", flag.ContinueOnError) - help := fs.Bool("h", false, "") - if err := fs.Parse(args); err != nil { - return err - } else if *help { - fmt.Fprintln(cmd.Stderr, cmd.Usage()) - return ErrUsage - } - - // Require database path. - path := fs.Arg(0) - if path == "" { - return ErrPathRequired - } else if _, err := os.Stat(path); os.IsNotExist(err) { - return ErrFileNotFound - } - - // Open database. - db, err := bolt.Open(path, 0666, nil) - if err != nil { - return err - } - defer db.Close() - - // Perform consistency check. - return db.View(func(tx *bolt.Tx) error { - var count int - ch := tx.Check() - loop: - for { - select { - case err, ok := <-ch: - if !ok { - break loop - } - fmt.Fprintln(cmd.Stdout, err) - count++ - } - } - - // Print summary of errors. - if count > 0 { - fmt.Fprintf(cmd.Stdout, "%d errors found\n", count) - return ErrCorrupt - } - - // Notify user that database is valid. - fmt.Fprintln(cmd.Stdout, "OK") - return nil - }) -} - -// Usage returns the help message. -func (cmd *CheckCommand) Usage() string { - return strings.TrimLeft(` -usage: bolt check PATH - -Check opens a database at PATH and runs an exhaustive check to verify that -all pages are accessible or are marked as freed. It also verifies that no -pages are double referenced. - -Verification errors will stream out as they are found and the process will -return after all pages have been checked. -`, "\n") -} - -// InfoCommand represents the "info" command execution. -type InfoCommand struct { - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer -} - -// NewInfoCommand returns a InfoCommand. -func newInfoCommand(m *Main) *InfoCommand { - return &InfoCommand{ - Stdin: m.Stdin, - Stdout: m.Stdout, - Stderr: m.Stderr, - } -} - -// Run executes the command. -func (cmd *InfoCommand) Run(args ...string) error { - // Parse flags. - fs := flag.NewFlagSet("", flag.ContinueOnError) - help := fs.Bool("h", false, "") - if err := fs.Parse(args); err != nil { - return err - } else if *help { - fmt.Fprintln(cmd.Stderr, cmd.Usage()) - return ErrUsage - } - - // Require database path. - path := fs.Arg(0) - if path == "" { - return ErrPathRequired - } else if _, err := os.Stat(path); os.IsNotExist(err) { - return ErrFileNotFound - } - - // Open the database. - db, err := bolt.Open(path, 0666, nil) - if err != nil { - return err - } - defer db.Close() - - // Print basic database info. - info := db.Info() - fmt.Fprintf(cmd.Stdout, "Page Size: %d\n", info.PageSize) - - return nil -} - -// Usage returns the help message. -func (cmd *InfoCommand) Usage() string { - return strings.TrimLeft(` -usage: bolt info PATH - -Info prints basic information about the Bolt database at PATH. -`, "\n") -} - -// DumpCommand represents the "dump" command execution. -type DumpCommand struct { - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer -} - -// newDumpCommand returns a DumpCommand. -func newDumpCommand(m *Main) *DumpCommand { - return &DumpCommand{ - Stdin: m.Stdin, - Stdout: m.Stdout, - Stderr: m.Stderr, - } -} - -// Run executes the command. -func (cmd *DumpCommand) Run(args ...string) error { - // Parse flags. - fs := flag.NewFlagSet("", flag.ContinueOnError) - help := fs.Bool("h", false, "") - if err := fs.Parse(args); err != nil { - return err - } else if *help { - fmt.Fprintln(cmd.Stderr, cmd.Usage()) - return ErrUsage - } - - // Require database path and page id. - path := fs.Arg(0) - if path == "" { - return ErrPathRequired - } else if _, err := os.Stat(path); os.IsNotExist(err) { - return ErrFileNotFound - } - - // Read page ids. - pageIDs, err := atois(fs.Args()[1:]) - if err != nil { - return err - } else if len(pageIDs) == 0 { - return ErrPageIDRequired - } - - // Open database to retrieve page size. - pageSize, err := ReadPageSize(path) - if err != nil { - return err - } - - // Open database file handler. - f, err := os.Open(path) - if err != nil { - return err - } - defer func() { _ = f.Close() }() - - // Print each page listed. - for i, pageID := range pageIDs { - // Print a separator. - if i > 0 { - fmt.Fprintln(cmd.Stdout, "===============================================") - } - - // Print page to stdout. - if err := cmd.PrintPage(cmd.Stdout, f, pageID, pageSize); err != nil { - return err - } - } - - return nil -} - -// PrintPage prints a given page as hexidecimal. -func (cmd *DumpCommand) PrintPage(w io.Writer, r io.ReaderAt, pageID int, pageSize int) error { - const bytesPerLineN = 16 - - // Read page into buffer. - buf := make([]byte, pageSize) - addr := pageID * pageSize - if n, err := r.ReadAt(buf, int64(addr)); err != nil { - return err - } else if n != pageSize { - return io.ErrUnexpectedEOF - } - - // Write out to writer in 16-byte lines. - var prev []byte - var skipped bool - for offset := 0; offset < pageSize; offset += bytesPerLineN { - // Retrieve current 16-byte line. - line := buf[offset : offset+bytesPerLineN] - isLastLine := (offset == (pageSize - bytesPerLineN)) - - // If it's the same as the previous line then print a skip. - if bytes.Equal(line, prev) && !isLastLine { - if !skipped { - fmt.Fprintf(w, "%07x *\n", addr+offset) - skipped = true - } - } else { - // Print line as hexadecimal in 2-byte groups. - fmt.Fprintf(w, "%07x %04x %04x %04x %04x %04x %04x %04x %04x\n", addr+offset, - line[0:2], line[2:4], line[4:6], line[6:8], - line[8:10], line[10:12], line[12:14], line[14:16], - ) - - skipped = false - } - - // Save the previous line. - prev = line - } - fmt.Fprint(w, "\n") - - return nil -} - -// Usage returns the help message. -func (cmd *DumpCommand) Usage() string { - return strings.TrimLeft(` -usage: bolt dump -page PAGEID PATH - -Dump prints a hexidecimal dump of a single page. -`, "\n") -} - -// PageCommand represents the "page" command execution. -type PageCommand struct { - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer -} - -// newPageCommand returns a PageCommand. -func newPageCommand(m *Main) *PageCommand { - return &PageCommand{ - Stdin: m.Stdin, - Stdout: m.Stdout, - Stderr: m.Stderr, - } -} - -// Run executes the command. -func (cmd *PageCommand) Run(args ...string) error { - // Parse flags. - fs := flag.NewFlagSet("", flag.ContinueOnError) - help := fs.Bool("h", false, "") - if err := fs.Parse(args); err != nil { - return err - } else if *help { - fmt.Fprintln(cmd.Stderr, cmd.Usage()) - return ErrUsage - } - - // Require database path and page id. - path := fs.Arg(0) - if path == "" { - return ErrPathRequired - } else if _, err := os.Stat(path); os.IsNotExist(err) { - return ErrFileNotFound - } - - // Read page ids. - pageIDs, err := atois(fs.Args()[1:]) - if err != nil { - return err - } else if len(pageIDs) == 0 { - return ErrPageIDRequired - } - - // Open database file handler. - f, err := os.Open(path) - if err != nil { - return err - } - defer func() { _ = f.Close() }() - - // Print each page listed. - for i, pageID := range pageIDs { - // Print a separator. - if i > 0 { - fmt.Fprintln(cmd.Stdout, "===============================================") - } - - // Retrieve page info and page size. - p, buf, err := ReadPage(path, pageID) - if err != nil { - return err - } - - // Print basic page info. - fmt.Fprintf(cmd.Stdout, "Page ID: %d\n", p.id) - fmt.Fprintf(cmd.Stdout, "Page Type: %s\n", p.Type()) - fmt.Fprintf(cmd.Stdout, "Total Size: %d bytes\n", len(buf)) - - // Print type-specific data. - switch p.Type() { - case "meta": - err = cmd.PrintMeta(cmd.Stdout, buf) - case "leaf": - err = cmd.PrintLeaf(cmd.Stdout, buf) - case "branch": - err = cmd.PrintBranch(cmd.Stdout, buf) - case "freelist": - err = cmd.PrintFreelist(cmd.Stdout, buf) - } - if err != nil { - return err - } - } - - return nil -} - -// PrintMeta prints the data from the meta page. -func (cmd *PageCommand) PrintMeta(w io.Writer, buf []byte) error { - m := (*meta)(unsafe.Pointer(&buf[PageHeaderSize])) - fmt.Fprintf(w, "Version: %d\n", m.version) - fmt.Fprintf(w, "Page Size: %d bytes\n", m.pageSize) - fmt.Fprintf(w, "Flags: %08x\n", m.flags) - fmt.Fprintf(w, "Root: \n", m.root.root) - fmt.Fprintf(w, "Freelist: \n", m.freelist) - fmt.Fprintf(w, "HWM: \n", m.pgid) - fmt.Fprintf(w, "Txn ID: %d\n", m.txid) - fmt.Fprintf(w, "Checksum: %016x\n", m.checksum) - fmt.Fprintf(w, "\n") - return nil -} - -// PrintLeaf prints the data for a leaf page. -func (cmd *PageCommand) PrintLeaf(w io.Writer, buf []byte) error { - p := (*page)(unsafe.Pointer(&buf[0])) - - // Print number of items. - fmt.Fprintf(w, "Item Count: %d\n", p.count) - fmt.Fprintf(w, "\n") - - // Print each key/value. - for i := uint16(0); i < p.count; i++ { - e := p.leafPageElement(i) - - // Format key as string. - var k string - if isPrintable(string(e.key())) { - k = fmt.Sprintf("%q", string(e.key())) - } else { - k = fmt.Sprintf("%x", string(e.key())) - } - - // Format value as string. - var v string - if (e.flags & uint32(bucketLeafFlag)) != 0 { - b := (*bucket)(unsafe.Pointer(&e.value()[0])) - v = fmt.Sprintf("", b.root, b.sequence) - } else if isPrintable(string(e.value())) { - v = fmt.Sprintf("%q", string(e.value())) - } else { - v = fmt.Sprintf("%x", string(e.value())) - } - - fmt.Fprintf(w, "%s: %s\n", k, v) - } - fmt.Fprintf(w, "\n") - return nil -} - -// PrintBranch prints the data for a leaf page. -func (cmd *PageCommand) PrintBranch(w io.Writer, buf []byte) error { - p := (*page)(unsafe.Pointer(&buf[0])) - - // Print number of items. - fmt.Fprintf(w, "Item Count: %d\n", p.count) - fmt.Fprintf(w, "\n") - - // Print each key/value. - for i := uint16(0); i < p.count; i++ { - e := p.branchPageElement(i) - - // Format key as string. - var k string - if isPrintable(string(e.key())) { - k = fmt.Sprintf("%q", string(e.key())) - } else { - k = fmt.Sprintf("%x", string(e.key())) - } - - fmt.Fprintf(w, "%s: \n", k, e.pgid) - } - fmt.Fprintf(w, "\n") - return nil -} - -// PrintFreelist prints the data for a freelist page. -func (cmd *PageCommand) PrintFreelist(w io.Writer, buf []byte) error { - p := (*page)(unsafe.Pointer(&buf[0])) - - // Print number of items. - fmt.Fprintf(w, "Item Count: %d\n", p.count) - fmt.Fprintf(w, "\n") - - // Print each page in the freelist. - ids := (*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)) - for i := uint16(0); i < p.count; i++ { - fmt.Fprintf(w, "%d\n", ids[i]) - } - fmt.Fprintf(w, "\n") - return nil -} - -// PrintPage prints a given page as hexidecimal. -func (cmd *PageCommand) PrintPage(w io.Writer, r io.ReaderAt, pageID int, pageSize int) error { - const bytesPerLineN = 16 - - // Read page into buffer. - buf := make([]byte, pageSize) - addr := pageID * pageSize - if n, err := r.ReadAt(buf, int64(addr)); err != nil { - return err - } else if n != pageSize { - return io.ErrUnexpectedEOF - } - - // Write out to writer in 16-byte lines. - var prev []byte - var skipped bool - for offset := 0; offset < pageSize; offset += bytesPerLineN { - // Retrieve current 16-byte line. - line := buf[offset : offset+bytesPerLineN] - isLastLine := (offset == (pageSize - bytesPerLineN)) - - // If it's the same as the previous line then print a skip. - if bytes.Equal(line, prev) && !isLastLine { - if !skipped { - fmt.Fprintf(w, "%07x *\n", addr+offset) - skipped = true - } - } else { - // Print line as hexadecimal in 2-byte groups. - fmt.Fprintf(w, "%07x %04x %04x %04x %04x %04x %04x %04x %04x\n", addr+offset, - line[0:2], line[2:4], line[4:6], line[6:8], - line[8:10], line[10:12], line[12:14], line[14:16], - ) - - skipped = false - } - - // Save the previous line. - prev = line - } - fmt.Fprint(w, "\n") - - return nil -} - -// Usage returns the help message. -func (cmd *PageCommand) Usage() string { - return strings.TrimLeft(` -usage: bolt page -page PATH pageid [pageid...] - -Page prints one or more pages in human readable format. -`, "\n") -} - -// PagesCommand represents the "pages" command execution. -type PagesCommand struct { - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer -} - -// NewPagesCommand returns a PagesCommand. -func newPagesCommand(m *Main) *PagesCommand { - return &PagesCommand{ - Stdin: m.Stdin, - Stdout: m.Stdout, - Stderr: m.Stderr, - } -} - -// Run executes the command. -func (cmd *PagesCommand) Run(args ...string) error { - // Parse flags. - fs := flag.NewFlagSet("", flag.ContinueOnError) - help := fs.Bool("h", false, "") - if err := fs.Parse(args); err != nil { - return err - } else if *help { - fmt.Fprintln(cmd.Stderr, cmd.Usage()) - return ErrUsage - } - - // Require database path. - path := fs.Arg(0) - if path == "" { - return ErrPathRequired - } else if _, err := os.Stat(path); os.IsNotExist(err) { - return ErrFileNotFound - } - - // Open database. - db, err := bolt.Open(path, 0666, nil) - if err != nil { - return err - } - defer func() { _ = db.Close() }() - - // Write header. - fmt.Fprintln(cmd.Stdout, "ID TYPE ITEMS OVRFLW") - fmt.Fprintln(cmd.Stdout, "======== ========== ====== ======") - - return db.Update(func(tx *bolt.Tx) error { - var id int - for { - p, err := tx.Page(id) - if err != nil { - return &PageError{ID: id, Err: err} - } else if p == nil { - break - } - - // Only display count and overflow if this is a non-free page. - var count, overflow string - if p.Type != "free" { - count = strconv.Itoa(p.Count) - if p.OverflowCount > 0 { - overflow = strconv.Itoa(p.OverflowCount) - } - } - - // Print table row. - fmt.Fprintf(cmd.Stdout, "%-8d %-10s %-6s %-6s\n", p.ID, p.Type, count, overflow) - - // Move to the next non-overflow page. - id += 1 - if p.Type != "free" { - id += p.OverflowCount - } - } - return nil - }) -} - -// Usage returns the help message. -func (cmd *PagesCommand) Usage() string { - return strings.TrimLeft(` -usage: bolt pages PATH - -Pages prints a table of pages with their type (meta, leaf, branch, freelist). -Leaf and branch pages will show a key count in the "items" column while the -freelist will show the number of free pages in the "items" column. - -The "overflow" column shows the number of blocks that the page spills over -into. Normally there is no overflow but large keys and values can cause -a single page to take up multiple blocks. -`, "\n") -} - -// StatsCommand represents the "stats" command execution. -type StatsCommand struct { - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer -} - -// NewStatsCommand returns a StatsCommand. -func newStatsCommand(m *Main) *StatsCommand { - return &StatsCommand{ - Stdin: m.Stdin, - Stdout: m.Stdout, - Stderr: m.Stderr, - } -} - -// Run executes the command. -func (cmd *StatsCommand) Run(args ...string) error { - // Parse flags. - fs := flag.NewFlagSet("", flag.ContinueOnError) - help := fs.Bool("h", false, "") - if err := fs.Parse(args); err != nil { - return err - } else if *help { - fmt.Fprintln(cmd.Stderr, cmd.Usage()) - return ErrUsage - } - - // Require database path. - path, prefix := fs.Arg(0), fs.Arg(1) - if path == "" { - return ErrPathRequired - } else if _, err := os.Stat(path); os.IsNotExist(err) { - return ErrFileNotFound - } - - // Open database. - db, err := bolt.Open(path, 0666, nil) - if err != nil { - return err - } - defer db.Close() - - return db.View(func(tx *bolt.Tx) error { - var s bolt.BucketStats - var count int - if err := tx.ForEach(func(name []byte, b *bolt.Bucket) error { - if bytes.HasPrefix(name, []byte(prefix)) { - s.Add(b.Stats()) - count += 1 - } - return nil - }); err != nil { - return err - } - - fmt.Fprintf(cmd.Stdout, "Aggregate statistics for %d buckets\n\n", count) - - fmt.Fprintln(cmd.Stdout, "Page count statistics") - fmt.Fprintf(cmd.Stdout, "\tNumber of logical branch pages: %d\n", s.BranchPageN) - fmt.Fprintf(cmd.Stdout, "\tNumber of physical branch overflow pages: %d\n", s.BranchOverflowN) - fmt.Fprintf(cmd.Stdout, "\tNumber of logical leaf pages: %d\n", s.LeafPageN) - fmt.Fprintf(cmd.Stdout, "\tNumber of physical leaf overflow pages: %d\n", s.LeafOverflowN) - - fmt.Fprintln(cmd.Stdout, "Tree statistics") - fmt.Fprintf(cmd.Stdout, "\tNumber of keys/value pairs: %d\n", s.KeyN) - fmt.Fprintf(cmd.Stdout, "\tNumber of levels in B+tree: %d\n", s.Depth) - - fmt.Fprintln(cmd.Stdout, "Page size utilization") - fmt.Fprintf(cmd.Stdout, "\tBytes allocated for physical branch pages: %d\n", s.BranchAlloc) - var percentage int - if s.BranchAlloc != 0 { - percentage = int(float32(s.BranchInuse) * 100.0 / float32(s.BranchAlloc)) - } - fmt.Fprintf(cmd.Stdout, "\tBytes actually used for branch data: %d (%d%%)\n", s.BranchInuse, percentage) - fmt.Fprintf(cmd.Stdout, "\tBytes allocated for physical leaf pages: %d\n", s.LeafAlloc) - percentage = 0 - if s.LeafAlloc != 0 { - percentage = int(float32(s.LeafInuse) * 100.0 / float32(s.LeafAlloc)) - } - fmt.Fprintf(cmd.Stdout, "\tBytes actually used for leaf data: %d (%d%%)\n", s.LeafInuse, percentage) - - fmt.Fprintln(cmd.Stdout, "Bucket statistics") - fmt.Fprintf(cmd.Stdout, "\tTotal number of buckets: %d\n", s.BucketN) - percentage = 0 - if s.BucketN != 0 { - percentage = int(float32(s.InlineBucketN) * 100.0 / float32(s.BucketN)) - } - fmt.Fprintf(cmd.Stdout, "\tTotal number on inlined buckets: %d (%d%%)\n", s.InlineBucketN, percentage) - percentage = 0 - if s.LeafInuse != 0 { - percentage = int(float32(s.InlineBucketInuse) * 100.0 / float32(s.LeafInuse)) - } - fmt.Fprintf(cmd.Stdout, "\tBytes used for inlined buckets: %d (%d%%)\n", s.InlineBucketInuse, percentage) - - return nil - }) -} - -// Usage returns the help message. -func (cmd *StatsCommand) Usage() string { - return strings.TrimLeft(` -usage: bolt stats PATH - -Stats performs an extensive search of the database to track every page -reference. It starts at the current meta page and recursively iterates -through every accessible bucket. - -The following errors can be reported: - - already freed - The page is referenced more than once in the freelist. - - unreachable unfreed - The page is not referenced by a bucket or in the freelist. - - reachable freed - The page is referenced by a bucket but is also in the freelist. - - out of bounds - A page is referenced that is above the high water mark. - - multiple references - A page is referenced by more than one other page. - - invalid type - The page type is not "meta", "leaf", "branch", or "freelist". - -No errors should occur in your database. However, if for some reason you -experience corruption, please submit a ticket to the Bolt project page: - - https://github.com/boltdb/bolt/issues -`, "\n") -} - -var benchBucketName = []byte("bench") - -// BenchCommand represents the "bench" command execution. -type BenchCommand struct { - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer -} - -// NewBenchCommand returns a BenchCommand using the -func newBenchCommand(m *Main) *BenchCommand { - return &BenchCommand{ - Stdin: m.Stdin, - Stdout: m.Stdout, - Stderr: m.Stderr, - } -} - -// Run executes the "bench" command. -func (cmd *BenchCommand) Run(args ...string) error { - // Parse CLI arguments. - options, err := cmd.ParseFlags(args) - if err != nil { - return err - } - - // Remove path if "-work" is not set. Otherwise keep path. - if options.Work { - fmt.Fprintf(cmd.Stdout, "work: %s\n", options.Path) - } else { - defer os.Remove(options.Path) - } - - // Create database. - db, err := bolt.Open(options.Path, 0666, nil) - if err != nil { - return err - } - db.NoSync = options.NoSync - defer db.Close() - - // Write to the database. - var results BenchResults - if err := cmd.runWrites(db, options, &results); err != nil { - return fmt.Errorf("write: %v", err) - } - - // Read from the database. - if err := cmd.runReads(db, options, &results); err != nil { - return fmt.Errorf("bench: read: %s", err) - } - - // Print results. - fmt.Fprintf(os.Stderr, "# Write\t%v\t(%v/op)\t(%v op/sec)\n", results.WriteDuration, results.WriteOpDuration(), results.WriteOpsPerSecond()) - fmt.Fprintf(os.Stderr, "# Read\t%v\t(%v/op)\t(%v op/sec)\n", results.ReadDuration, results.ReadOpDuration(), results.ReadOpsPerSecond()) - fmt.Fprintln(os.Stderr, "") - return nil -} - -// ParseFlags parses the command line flags. -func (cmd *BenchCommand) ParseFlags(args []string) (*BenchOptions, error) { - var options BenchOptions - - // Parse flagset. - fs := flag.NewFlagSet("", flag.ContinueOnError) - fs.StringVar(&options.ProfileMode, "profile-mode", "rw", "") - fs.StringVar(&options.WriteMode, "write-mode", "seq", "") - fs.StringVar(&options.ReadMode, "read-mode", "seq", "") - fs.IntVar(&options.Iterations, "count", 1000, "") - fs.IntVar(&options.BatchSize, "batch-size", 0, "") - fs.IntVar(&options.KeySize, "key-size", 8, "") - fs.IntVar(&options.ValueSize, "value-size", 32, "") - fs.StringVar(&options.CPUProfile, "cpuprofile", "", "") - fs.StringVar(&options.MemProfile, "memprofile", "", "") - fs.StringVar(&options.BlockProfile, "blockprofile", "", "") - fs.Float64Var(&options.FillPercent, "fill-percent", bolt.DefaultFillPercent, "") - fs.BoolVar(&options.NoSync, "no-sync", false, "") - fs.BoolVar(&options.Work, "work", false, "") - fs.StringVar(&options.Path, "path", "", "") - fs.SetOutput(cmd.Stderr) - if err := fs.Parse(args); err != nil { - return nil, err - } - - // Set batch size to iteration size if not set. - // Require that batch size can be evenly divided by the iteration count. - if options.BatchSize == 0 { - options.BatchSize = options.Iterations - } else if options.Iterations%options.BatchSize != 0 { - return nil, ErrNonDivisibleBatchSize - } - - // Generate temp path if one is not passed in. - if options.Path == "" { - f, err := ioutil.TempFile("", "bolt-bench-") - if err != nil { - return nil, fmt.Errorf("temp file: %s", err) - } - f.Close() - os.Remove(f.Name()) - options.Path = f.Name() - } - - return &options, nil -} - -// Writes to the database. -func (cmd *BenchCommand) runWrites(db *bolt.DB, options *BenchOptions, results *BenchResults) error { - // Start profiling for writes. - if options.ProfileMode == "rw" || options.ProfileMode == "w" { - cmd.startProfiling(options) - } - - t := time.Now() - - var err error - switch options.WriteMode { - case "seq": - err = cmd.runWritesSequential(db, options, results) - case "rnd": - err = cmd.runWritesRandom(db, options, results) - case "seq-nest": - err = cmd.runWritesSequentialNested(db, options, results) - case "rnd-nest": - err = cmd.runWritesRandomNested(db, options, results) - default: - return fmt.Errorf("invalid write mode: %s", options.WriteMode) - } - - // Save time to write. - results.WriteDuration = time.Since(t) - - // Stop profiling for writes only. - if options.ProfileMode == "w" { - cmd.stopProfiling() - } - - return err -} - -func (cmd *BenchCommand) runWritesSequential(db *bolt.DB, options *BenchOptions, results *BenchResults) error { - var i = uint32(0) - return cmd.runWritesWithSource(db, options, results, func() uint32 { i++; return i }) -} - -func (cmd *BenchCommand) runWritesRandom(db *bolt.DB, options *BenchOptions, results *BenchResults) error { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - return cmd.runWritesWithSource(db, options, results, func() uint32 { return r.Uint32() }) -} - -func (cmd *BenchCommand) runWritesSequentialNested(db *bolt.DB, options *BenchOptions, results *BenchResults) error { - var i = uint32(0) - return cmd.runWritesWithSource(db, options, results, func() uint32 { i++; return i }) -} - -func (cmd *BenchCommand) runWritesRandomNested(db *bolt.DB, options *BenchOptions, results *BenchResults) error { - r := rand.New(rand.NewSource(time.Now().UnixNano())) - return cmd.runWritesWithSource(db, options, results, func() uint32 { return r.Uint32() }) -} - -func (cmd *BenchCommand) runWritesWithSource(db *bolt.DB, options *BenchOptions, results *BenchResults, keySource func() uint32) error { - results.WriteOps = options.Iterations - - for i := 0; i < options.Iterations; i += options.BatchSize { - if err := db.Update(func(tx *bolt.Tx) error { - b, _ := tx.CreateBucketIfNotExists(benchBucketName) - b.FillPercent = options.FillPercent - - for j := 0; j < options.BatchSize; j++ { - key := make([]byte, options.KeySize) - value := make([]byte, options.ValueSize) - - // Write key as uint32. - binary.BigEndian.PutUint32(key, keySource()) - - // Insert key/value. - if err := b.Put(key, value); err != nil { - return err - } - } - - return nil - }); err != nil { - return err - } - } - return nil -} - -func (cmd *BenchCommand) runWritesNestedWithSource(db *bolt.DB, options *BenchOptions, results *BenchResults, keySource func() uint32) error { - results.WriteOps = options.Iterations - - for i := 0; i < options.Iterations; i += options.BatchSize { - if err := db.Update(func(tx *bolt.Tx) error { - top, err := tx.CreateBucketIfNotExists(benchBucketName) - if err != nil { - return err - } - top.FillPercent = options.FillPercent - - // Create bucket key. - name := make([]byte, options.KeySize) - binary.BigEndian.PutUint32(name, keySource()) - - // Create bucket. - b, err := top.CreateBucketIfNotExists(name) - if err != nil { - return err - } - b.FillPercent = options.FillPercent - - for j := 0; j < options.BatchSize; j++ { - var key = make([]byte, options.KeySize) - var value = make([]byte, options.ValueSize) - - // Generate key as uint32. - binary.BigEndian.PutUint32(key, keySource()) - - // Insert value into subbucket. - if err := b.Put(key, value); err != nil { - return err - } - } - - return nil - }); err != nil { - return err - } - } - return nil -} - -// Reads from the database. -func (cmd *BenchCommand) runReads(db *bolt.DB, options *BenchOptions, results *BenchResults) error { - // Start profiling for reads. - if options.ProfileMode == "r" { - cmd.startProfiling(options) - } - - t := time.Now() - - var err error - switch options.ReadMode { - case "seq": - switch options.WriteMode { - case "seq-nest", "rnd-nest": - err = cmd.runReadsSequentialNested(db, options, results) - default: - err = cmd.runReadsSequential(db, options, results) - } - default: - return fmt.Errorf("invalid read mode: %s", options.ReadMode) - } - - // Save read time. - results.ReadDuration = time.Since(t) - - // Stop profiling for reads. - if options.ProfileMode == "rw" || options.ProfileMode == "r" { - cmd.stopProfiling() - } - - return err -} - -func (cmd *BenchCommand) runReadsSequential(db *bolt.DB, options *BenchOptions, results *BenchResults) error { - return db.View(func(tx *bolt.Tx) error { - t := time.Now() - - for { - var count int - - c := tx.Bucket(benchBucketName).Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - if v == nil { - return errors.New("invalid value") - } - count++ - } - - if options.WriteMode == "seq" && count != options.Iterations { - return fmt.Errorf("read seq: iter mismatch: expected %d, got %d", options.Iterations, count) - } - - results.ReadOps += count - - // Make sure we do this for at least a second. - if time.Since(t) >= time.Second { - break - } - } - - return nil - }) -} - -func (cmd *BenchCommand) runReadsSequentialNested(db *bolt.DB, options *BenchOptions, results *BenchResults) error { - return db.View(func(tx *bolt.Tx) error { - t := time.Now() - - for { - var count int - var top = tx.Bucket(benchBucketName) - if err := top.ForEach(func(name, _ []byte) error { - c := top.Bucket(name).Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - if v == nil { - return ErrInvalidValue - } - count++ - } - return nil - }); err != nil { - return err - } - - if options.WriteMode == "seq-nest" && count != options.Iterations { - return fmt.Errorf("read seq-nest: iter mismatch: expected %d, got %d", options.Iterations, count) - } - - results.ReadOps += count - - // Make sure we do this for at least a second. - if time.Since(t) >= time.Second { - break - } - } - - return nil - }) -} - -// File handlers for the various profiles. -var cpuprofile, memprofile, blockprofile *os.File - -// Starts all profiles set on the options. -func (cmd *BenchCommand) startProfiling(options *BenchOptions) { - var err error - - // Start CPU profiling. - if options.CPUProfile != "" { - cpuprofile, err = os.Create(options.CPUProfile) - if err != nil { - fmt.Fprintf(cmd.Stderr, "bench: could not create cpu profile %q: %v\n", options.CPUProfile, err) - os.Exit(1) - } - pprof.StartCPUProfile(cpuprofile) - } - - // Start memory profiling. - if options.MemProfile != "" { - memprofile, err = os.Create(options.MemProfile) - if err != nil { - fmt.Fprintf(cmd.Stderr, "bench: could not create memory profile %q: %v\n", options.MemProfile, err) - os.Exit(1) - } - runtime.MemProfileRate = 4096 - } - - // Start fatal profiling. - if options.BlockProfile != "" { - blockprofile, err = os.Create(options.BlockProfile) - if err != nil { - fmt.Fprintf(cmd.Stderr, "bench: could not create block profile %q: %v\n", options.BlockProfile, err) - os.Exit(1) - } - runtime.SetBlockProfileRate(1) - } -} - -// Stops all profiles. -func (cmd *BenchCommand) stopProfiling() { - if cpuprofile != nil { - pprof.StopCPUProfile() - cpuprofile.Close() - cpuprofile = nil - } - - if memprofile != nil { - pprof.Lookup("heap").WriteTo(memprofile, 0) - memprofile.Close() - memprofile = nil - } - - if blockprofile != nil { - pprof.Lookup("block").WriteTo(blockprofile, 0) - blockprofile.Close() - blockprofile = nil - runtime.SetBlockProfileRate(0) - } -} - -// BenchOptions represents the set of options that can be passed to "bolt bench". -type BenchOptions struct { - ProfileMode string - WriteMode string - ReadMode string - Iterations int - BatchSize int - KeySize int - ValueSize int - CPUProfile string - MemProfile string - BlockProfile string - StatsInterval time.Duration - FillPercent float64 - NoSync bool - Work bool - Path string -} - -// BenchResults represents the performance results of the benchmark. -type BenchResults struct { - WriteOps int - WriteDuration time.Duration - ReadOps int - ReadDuration time.Duration -} - -// Returns the duration for a single write operation. -func (r *BenchResults) WriteOpDuration() time.Duration { - if r.WriteOps == 0 { - return 0 - } - return r.WriteDuration / time.Duration(r.WriteOps) -} - -// Returns average number of write operations that can be performed per second. -func (r *BenchResults) WriteOpsPerSecond() int { - var op = r.WriteOpDuration() - if op == 0 { - return 0 - } - return int(time.Second) / int(op) -} - -// Returns the duration for a single read operation. -func (r *BenchResults) ReadOpDuration() time.Duration { - if r.ReadOps == 0 { - return 0 - } - return r.ReadDuration / time.Duration(r.ReadOps) -} - -// Returns average number of read operations that can be performed per second. -func (r *BenchResults) ReadOpsPerSecond() int { - var op = r.ReadOpDuration() - if op == 0 { - return 0 - } - return int(time.Second) / int(op) -} - -type PageError struct { - ID int - Err error -} - -func (e *PageError) Error() string { - return fmt.Sprintf("page error: id=%d, err=%s", e.ID, e.Err) -} - -// isPrintable returns true if the string is valid unicode and contains only printable runes. -func isPrintable(s string) bool { - if !utf8.ValidString(s) { - return false - } - for _, ch := range s { - if !unicode.IsPrint(ch) { - return false - } - } - return true -} - -// ReadPage reads page info & full page data from a path. -// This is not transactionally safe. -func ReadPage(path string, pageID int) (*page, []byte, error) { - // Find page size. - pageSize, err := ReadPageSize(path) - if err != nil { - return nil, nil, fmt.Errorf("read page size: %s", err) - } - - // Open database file. - f, err := os.Open(path) - if err != nil { - return nil, nil, err - } - defer f.Close() - - // Read one block into buffer. - buf := make([]byte, pageSize) - if n, err := f.ReadAt(buf, int64(pageID*pageSize)); err != nil { - return nil, nil, err - } else if n != len(buf) { - return nil, nil, io.ErrUnexpectedEOF - } - - // Determine total number of blocks. - p := (*page)(unsafe.Pointer(&buf[0])) - overflowN := p.overflow - - // Re-read entire page (with overflow) into buffer. - buf = make([]byte, (int(overflowN)+1)*pageSize) - if n, err := f.ReadAt(buf, int64(pageID*pageSize)); err != nil { - return nil, nil, err - } else if n != len(buf) { - return nil, nil, io.ErrUnexpectedEOF - } - p = (*page)(unsafe.Pointer(&buf[0])) - - return p, buf, nil -} - -// ReadPageSize reads page size a path. -// This is not transactionally safe. -func ReadPageSize(path string) (int, error) { - // Open database file. - f, err := os.Open(path) - if err != nil { - return 0, err - } - defer f.Close() - - // Read 4KB chunk. - buf := make([]byte, 4096) - if _, err := io.ReadFull(f, buf); err != nil { - return 0, err - } - - // Read page size from metadata. - m := (*meta)(unsafe.Pointer(&buf[PageHeaderSize])) - return int(m.pageSize), nil -} - -// atois parses a slice of strings into integers. -func atois(strs []string) ([]int, error) { - var a []int - for _, str := range strs { - i, err := strconv.Atoi(str) - if err != nil { - return nil, err - } - a = append(a, i) - } - return a, nil -} - -// DO NOT EDIT. Copied from the "bolt" package. -const maxAllocSize = 0xFFFFFFF - -// DO NOT EDIT. Copied from the "bolt" package. -const ( - branchPageFlag = 0x01 - leafPageFlag = 0x02 - metaPageFlag = 0x04 - freelistPageFlag = 0x10 -) - -// DO NOT EDIT. Copied from the "bolt" package. -const bucketLeafFlag = 0x01 - -// DO NOT EDIT. Copied from the "bolt" package. -type pgid uint64 - -// DO NOT EDIT. Copied from the "bolt" package. -type txid uint64 - -// DO NOT EDIT. Copied from the "bolt" package. -type meta struct { - magic uint32 - version uint32 - pageSize uint32 - flags uint32 - root bucket - freelist pgid - pgid pgid - txid txid - checksum uint64 -} - -// DO NOT EDIT. Copied from the "bolt" package. -type bucket struct { - root pgid - sequence uint64 -} - -// DO NOT EDIT. Copied from the "bolt" package. -type page struct { - id pgid - flags uint16 - count uint16 - overflow uint32 - ptr uintptr -} - -// DO NOT EDIT. Copied from the "bolt" package. -func (p *page) Type() string { - if (p.flags & branchPageFlag) != 0 { - return "branch" - } else if (p.flags & leafPageFlag) != 0 { - return "leaf" - } else if (p.flags & metaPageFlag) != 0 { - return "meta" - } else if (p.flags & freelistPageFlag) != 0 { - return "freelist" - } - return fmt.Sprintf("unknown<%02x>", p.flags) -} - -// DO NOT EDIT. Copied from the "bolt" package. -func (p *page) leafPageElement(index uint16) *leafPageElement { - n := &((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[index] - return n -} - -// DO NOT EDIT. Copied from the "bolt" package. -func (p *page) branchPageElement(index uint16) *branchPageElement { - return &((*[0x7FFFFFF]branchPageElement)(unsafe.Pointer(&p.ptr)))[index] -} - -// DO NOT EDIT. Copied from the "bolt" package. -type branchPageElement struct { - pos uint32 - ksize uint32 - pgid pgid -} - -// DO NOT EDIT. Copied from the "bolt" package. -func (n *branchPageElement) key() []byte { - buf := (*[maxAllocSize]byte)(unsafe.Pointer(n)) - return buf[n.pos : n.pos+n.ksize] -} - -// DO NOT EDIT. Copied from the "bolt" package. -type leafPageElement struct { - flags uint32 - pos uint32 - ksize uint32 - vsize uint32 -} - -// DO NOT EDIT. Copied from the "bolt" package. -func (n *leafPageElement) key() []byte { - buf := (*[maxAllocSize]byte)(unsafe.Pointer(n)) - return buf[n.pos : n.pos+n.ksize] -} - -// DO NOT EDIT. Copied from the "bolt" package. -func (n *leafPageElement) value() []byte { - buf := (*[maxAllocSize]byte)(unsafe.Pointer(n)) - return buf[n.pos+n.ksize : n.pos+n.ksize+n.vsize] -} - -// CompactCommand represents the "compact" command execution. -type CompactCommand struct { - Stdin io.Reader - Stdout io.Writer - Stderr io.Writer - - SrcPath string - DstPath string - TxMaxSize int64 -} - -// newCompactCommand returns a CompactCommand. -func newCompactCommand(m *Main) *CompactCommand { - return &CompactCommand{ - Stdin: m.Stdin, - Stdout: m.Stdout, - Stderr: m.Stderr, - } -} - -// Run executes the command. -func (cmd *CompactCommand) Run(args ...string) (err error) { - // Parse flags. - fs := flag.NewFlagSet("", flag.ContinueOnError) - fs.SetOutput(ioutil.Discard) - fs.StringVar(&cmd.DstPath, "o", "", "") - fs.Int64Var(&cmd.TxMaxSize, "tx-max-size", 65536, "") - if err := fs.Parse(args); err == flag.ErrHelp { - fmt.Fprintln(cmd.Stderr, cmd.Usage()) - return ErrUsage - } else if err != nil { - return err - } else if cmd.DstPath == "" { - return fmt.Errorf("output file required") - } - - // Require database paths. - cmd.SrcPath = fs.Arg(0) - if cmd.SrcPath == "" { - return ErrPathRequired - } - - // Ensure source file exists. - fi, err := os.Stat(cmd.SrcPath) - if os.IsNotExist(err) { - return ErrFileNotFound - } else if err != nil { - return err - } - initialSize := fi.Size() - - // Open source database. - src, err := bolt.Open(cmd.SrcPath, 0444, nil) - if err != nil { - return err - } - defer src.Close() - - // Open destination database. - dst, err := bolt.Open(cmd.DstPath, fi.Mode(), nil) - if err != nil { - return err - } - defer dst.Close() - - // Run compaction. - if err := cmd.compact(dst, src); err != nil { - return err - } - - // Report stats on new size. - fi, err = os.Stat(cmd.DstPath) - if err != nil { - return err - } else if fi.Size() == 0 { - return fmt.Errorf("zero db size") - } - fmt.Fprintf(cmd.Stdout, "%d -> %d bytes (gain=%.2fx)\n", initialSize, fi.Size(), float64(initialSize)/float64(fi.Size())) - - return nil -} - -func (cmd *CompactCommand) compact(dst, src *bolt.DB) error { - // commit regularly, or we'll run out of memory for large datasets if using one transaction. - var size int64 - tx, err := dst.Begin(true) - if err != nil { - return err - } - defer tx.Rollback() - - if err := cmd.walk(src, func(keys [][]byte, k, v []byte, seq uint64) error { - // On each key/value, check if we have exceeded tx size. - sz := int64(len(k) + len(v)) - if size+sz > cmd.TxMaxSize && cmd.TxMaxSize != 0 { - // Commit previous transaction. - if err := tx.Commit(); err != nil { - return err - } - - // Start new transaction. - tx, err = dst.Begin(true) - if err != nil { - return err - } - size = 0 - } - size += sz - - // Create bucket on the root transaction if this is the first level. - nk := len(keys) - if nk == 0 { - bkt, err := tx.CreateBucket(k) - if err != nil { - return err - } - if err := bkt.SetSequence(seq); err != nil { - return err - } - return nil - } - - // Create buckets on subsequent levels, if necessary. - b := tx.Bucket(keys[0]) - if nk > 1 { - for _, k := range keys[1:] { - b = b.Bucket(k) - } - } - - // If there is no value then this is a bucket call. - if v == nil { - bkt, err := b.CreateBucket(k) - if err != nil { - return err - } - if err := bkt.SetSequence(seq); err != nil { - return err - } - return nil - } - - // Otherwise treat it as a key/value pair. - return b.Put(k, v) - }); err != nil { - return err - } - - return tx.Commit() -} - -// walkFunc is the type of the function called for keys (buckets and "normal" -// values) discovered by Walk. keys is the list of keys to descend to the bucket -// owning the discovered key/value pair k/v. -type walkFunc func(keys [][]byte, k, v []byte, seq uint64) error - -// walk walks recursively the bolt database db, calling walkFn for each key it finds. -func (cmd *CompactCommand) walk(db *bolt.DB, walkFn walkFunc) error { - return db.View(func(tx *bolt.Tx) error { - return tx.ForEach(func(name []byte, b *bolt.Bucket) error { - return cmd.walkBucket(b, nil, name, nil, b.Sequence(), walkFn) - }) - }) -} - -func (cmd *CompactCommand) walkBucket(b *bolt.Bucket, keypath [][]byte, k, v []byte, seq uint64, fn walkFunc) error { - // Execute callback. - if err := fn(keypath, k, v, seq); err != nil { - return err - } - - // If this is not a bucket then stop. - if v != nil { - return nil - } - - // Iterate over each child key/value. - keypath = append(keypath, k) - return b.ForEach(func(k, v []byte) error { - if v == nil { - bkt := b.Bucket(k) - return cmd.walkBucket(bkt, keypath, k, nil, bkt.Sequence(), fn) - } - return cmd.walkBucket(b, keypath, k, v, b.Sequence(), fn) - }) -} - -// Usage returns the help message. -func (cmd *CompactCommand) Usage() string { - return strings.TrimLeft(` -usage: bolt compact [options] -o DST SRC - -Compact opens a database at SRC path and walks it recursively, copying keys -as they are found from all buckets, to a newly created database at DST path. - -The original database is left untouched. - -Additional options include: - - -tx-max-size NUM - Specifies the maximum size of individual transactions. - Defaults to 64KB. -`, "\n") -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main_test.go deleted file mode 100644 index 0a11ff3..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cmd/bolt/main_test.go +++ /dev/null @@ -1,356 +0,0 @@ -package main_test - -import ( - "bytes" - crypto "crypto/rand" - "encoding/binary" - "fmt" - "io" - "io/ioutil" - "math/rand" - "os" - "strconv" - "testing" - - "github.com/boltdb/bolt" - "github.com/boltdb/bolt/cmd/bolt" -) - -// Ensure the "info" command can print information about a database. -func TestInfoCommand_Run(t *testing.T) { - db := MustOpen(0666, nil) - db.DB.Close() - defer db.Close() - - // Run the info command. - m := NewMain() - if err := m.Run("info", db.Path); err != nil { - t.Fatal(err) - } -} - -// Ensure the "stats" command executes correctly with an empty database. -func TestStatsCommand_Run_EmptyDatabase(t *testing.T) { - // Ignore - if os.Getpagesize() != 4096 { - t.Skip("system does not use 4KB page size") - } - - db := MustOpen(0666, nil) - defer db.Close() - db.DB.Close() - - // Generate expected result. - exp := "Aggregate statistics for 0 buckets\n\n" + - "Page count statistics\n" + - "\tNumber of logical branch pages: 0\n" + - "\tNumber of physical branch overflow pages: 0\n" + - "\tNumber of logical leaf pages: 0\n" + - "\tNumber of physical leaf overflow pages: 0\n" + - "Tree statistics\n" + - "\tNumber of keys/value pairs: 0\n" + - "\tNumber of levels in B+tree: 0\n" + - "Page size utilization\n" + - "\tBytes allocated for physical branch pages: 0\n" + - "\tBytes actually used for branch data: 0 (0%)\n" + - "\tBytes allocated for physical leaf pages: 0\n" + - "\tBytes actually used for leaf data: 0 (0%)\n" + - "Bucket statistics\n" + - "\tTotal number of buckets: 0\n" + - "\tTotal number on inlined buckets: 0 (0%)\n" + - "\tBytes used for inlined buckets: 0 (0%)\n" - - // Run the command. - m := NewMain() - if err := m.Run("stats", db.Path); err != nil { - t.Fatal(err) - } else if m.Stdout.String() != exp { - t.Fatalf("unexpected stdout:\n\n%s", m.Stdout.String()) - } -} - -// Ensure the "stats" command can execute correctly. -func TestStatsCommand_Run(t *testing.T) { - // Ignore - if os.Getpagesize() != 4096 { - t.Skip("system does not use 4KB page size") - } - - db := MustOpen(0666, nil) - defer db.Close() - - if err := db.Update(func(tx *bolt.Tx) error { - // Create "foo" bucket. - b, err := tx.CreateBucket([]byte("foo")) - if err != nil { - return err - } - for i := 0; i < 10; i++ { - if err := b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil { - return err - } - } - - // Create "bar" bucket. - b, err = tx.CreateBucket([]byte("bar")) - if err != nil { - return err - } - for i := 0; i < 100; i++ { - if err := b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil { - return err - } - } - - // Create "baz" bucket. - b, err = tx.CreateBucket([]byte("baz")) - if err != nil { - return err - } - if err := b.Put([]byte("key"), []byte("value")); err != nil { - return err - } - - return nil - }); err != nil { - t.Fatal(err) - } - db.DB.Close() - - // Generate expected result. - exp := "Aggregate statistics for 3 buckets\n\n" + - "Page count statistics\n" + - "\tNumber of logical branch pages: 0\n" + - "\tNumber of physical branch overflow pages: 0\n" + - "\tNumber of logical leaf pages: 1\n" + - "\tNumber of physical leaf overflow pages: 0\n" + - "Tree statistics\n" + - "\tNumber of keys/value pairs: 111\n" + - "\tNumber of levels in B+tree: 1\n" + - "Page size utilization\n" + - "\tBytes allocated for physical branch pages: 0\n" + - "\tBytes actually used for branch data: 0 (0%)\n" + - "\tBytes allocated for physical leaf pages: 4096\n" + - "\tBytes actually used for leaf data: 1996 (48%)\n" + - "Bucket statistics\n" + - "\tTotal number of buckets: 3\n" + - "\tTotal number on inlined buckets: 2 (66%)\n" + - "\tBytes used for inlined buckets: 236 (11%)\n" - - // Run the command. - m := NewMain() - if err := m.Run("stats", db.Path); err != nil { - t.Fatal(err) - } else if m.Stdout.String() != exp { - t.Fatalf("unexpected stdout:\n\n%s", m.Stdout.String()) - } -} - -// Main represents a test wrapper for main.Main that records output. -type Main struct { - *main.Main - Stdin bytes.Buffer - Stdout bytes.Buffer - Stderr bytes.Buffer -} - -// NewMain returns a new instance of Main. -func NewMain() *Main { - m := &Main{Main: main.NewMain()} - m.Main.Stdin = &m.Stdin - m.Main.Stdout = &m.Stdout - m.Main.Stderr = &m.Stderr - return m -} - -// MustOpen creates a Bolt database in a temporary location. -func MustOpen(mode os.FileMode, options *bolt.Options) *DB { - // Create temporary path. - f, _ := ioutil.TempFile("", "bolt-") - f.Close() - os.Remove(f.Name()) - - db, err := bolt.Open(f.Name(), mode, options) - if err != nil { - panic(err.Error()) - } - return &DB{DB: db, Path: f.Name()} -} - -// DB is a test wrapper for bolt.DB. -type DB struct { - *bolt.DB - Path string -} - -// Close closes and removes the database. -func (db *DB) Close() error { - defer os.Remove(db.Path) - return db.DB.Close() -} - -func TestCompactCommand_Run(t *testing.T) { - var s int64 - if err := binary.Read(crypto.Reader, binary.BigEndian, &s); err != nil { - t.Fatal(err) - } - rand.Seed(s) - - dstdb := MustOpen(0666, nil) - dstdb.Close() - - // fill the db - db := MustOpen(0666, nil) - if err := db.Update(func(tx *bolt.Tx) error { - n := 2 + rand.Intn(5) - for i := 0; i < n; i++ { - k := []byte(fmt.Sprintf("b%d", i)) - b, err := tx.CreateBucketIfNotExists(k) - if err != nil { - return err - } - if err := b.SetSequence(uint64(i)); err != nil { - return err - } - if err := fillBucket(b, append(k, '.')); err != nil { - return err - } - } - return nil - }); err != nil { - db.Close() - t.Fatal(err) - } - - // make the db grow by adding large values, and delete them. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucketIfNotExists([]byte("large_vals")) - if err != nil { - return err - } - n := 5 + rand.Intn(5) - for i := 0; i < n; i++ { - v := make([]byte, 1000*1000*(1+rand.Intn(5))) - _, err := crypto.Read(v) - if err != nil { - return err - } - if err := b.Put([]byte(fmt.Sprintf("l%d", i)), v); err != nil { - return err - } - } - return nil - }); err != nil { - db.Close() - t.Fatal(err) - } - if err := db.Update(func(tx *bolt.Tx) error { - c := tx.Bucket([]byte("large_vals")).Cursor() - for k, _ := c.First(); k != nil; k, _ = c.Next() { - if err := c.Delete(); err != nil { - return err - } - } - return tx.DeleteBucket([]byte("large_vals")) - }); err != nil { - db.Close() - t.Fatal(err) - } - db.DB.Close() - defer db.Close() - defer dstdb.Close() - - dbChk, err := chkdb(db.Path) - if err != nil { - t.Fatal(err) - } - - m := NewMain() - if err := m.Run("compact", "-o", dstdb.Path, db.Path); err != nil { - t.Fatal(err) - } - - dbChkAfterCompact, err := chkdb(db.Path) - if err != nil { - t.Fatal(err) - } - - dstdbChk, err := chkdb(dstdb.Path) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(dbChk, dbChkAfterCompact) { - t.Error("the original db has been touched") - } - if !bytes.Equal(dbChk, dstdbChk) { - t.Error("the compacted db data isn't the same than the original db") - } -} - -func fillBucket(b *bolt.Bucket, prefix []byte) error { - n := 10 + rand.Intn(50) - for i := 0; i < n; i++ { - v := make([]byte, 10*(1+rand.Intn(4))) - _, err := crypto.Read(v) - if err != nil { - return err - } - k := append(prefix, []byte(fmt.Sprintf("k%d", i))...) - if err := b.Put(k, v); err != nil { - return err - } - } - // limit depth of subbuckets - s := 2 + rand.Intn(4) - if len(prefix) > (2*s + 1) { - return nil - } - n = 1 + rand.Intn(3) - for i := 0; i < n; i++ { - k := append(prefix, []byte(fmt.Sprintf("b%d", i))...) - sb, err := b.CreateBucket(k) - if err != nil { - return err - } - if err := fillBucket(sb, append(k, '.')); err != nil { - return err - } - } - return nil -} - -func chkdb(path string) ([]byte, error) { - db, err := bolt.Open(path, 0666, nil) - if err != nil { - return nil, err - } - defer db.Close() - var buf bytes.Buffer - err = db.View(func(tx *bolt.Tx) error { - return tx.ForEach(func(name []byte, b *bolt.Bucket) error { - return walkBucket(b, name, nil, &buf) - }) - }) - if err != nil { - return nil, err - } - return buf.Bytes(), nil -} - -func walkBucket(parent *bolt.Bucket, k []byte, v []byte, w io.Writer) error { - if _, err := fmt.Fprintf(w, "%d:%x=%x\n", parent.Sequence(), k, v); err != nil { - return err - } - - // not a bucket, exit. - if v != nil { - return nil - } - return parent.ForEach(func(k, v []byte) error { - if v == nil { - return walkBucket(parent.Bucket(k), k, nil, w) - } - return walkBucket(parent, k, v, w) - }) -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor.go deleted file mode 100644 index 1be9f35..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor.go +++ /dev/null @@ -1,400 +0,0 @@ -package bolt - -import ( - "bytes" - "fmt" - "sort" -) - -// Cursor represents an iterator that can traverse over all key/value pairs in a bucket in sorted order. -// Cursors see nested buckets with value == nil. -// Cursors can be obtained from a transaction and are valid as long as the transaction is open. -// -// Keys and values returned from the cursor are only valid for the life of the transaction. -// -// Changing data while traversing with a cursor may cause it to be invalidated -// and return unexpected keys and/or values. You must reposition your cursor -// after mutating data. -type Cursor struct { - bucket *Bucket - stack []elemRef -} - -// Bucket returns the bucket that this cursor was created from. -func (c *Cursor) Bucket() *Bucket { - return c.bucket -} - -// First moves the cursor to the first item in the bucket and returns its key and value. -// If the bucket is empty then a nil key and value are returned. -// The returned key and value are only valid for the life of the transaction. -func (c *Cursor) First() (key []byte, value []byte) { - _assert(c.bucket.tx.db != nil, "tx closed") - c.stack = c.stack[:0] - p, n := c.bucket.pageNode(c.bucket.root) - c.stack = append(c.stack, elemRef{page: p, node: n, index: 0}) - c.first() - - // If we land on an empty page then move to the next value. - // https://github.com/boltdb/bolt/issues/450 - if c.stack[len(c.stack)-1].count() == 0 { - c.next() - } - - k, v, flags := c.keyValue() - if (flags & uint32(bucketLeafFlag)) != 0 { - return k, nil - } - return k, v - -} - -// Last moves the cursor to the last item in the bucket and returns its key and value. -// If the bucket is empty then a nil key and value are returned. -// The returned key and value are only valid for the life of the transaction. -func (c *Cursor) Last() (key []byte, value []byte) { - _assert(c.bucket.tx.db != nil, "tx closed") - c.stack = c.stack[:0] - p, n := c.bucket.pageNode(c.bucket.root) - ref := elemRef{page: p, node: n} - ref.index = ref.count() - 1 - c.stack = append(c.stack, ref) - c.last() - k, v, flags := c.keyValue() - if (flags & uint32(bucketLeafFlag)) != 0 { - return k, nil - } - return k, v -} - -// Next moves the cursor to the next item in the bucket and returns its key and value. -// If the cursor is at the end of the bucket then a nil key and value are returned. -// The returned key and value are only valid for the life of the transaction. -func (c *Cursor) Next() (key []byte, value []byte) { - _assert(c.bucket.tx.db != nil, "tx closed") - k, v, flags := c.next() - if (flags & uint32(bucketLeafFlag)) != 0 { - return k, nil - } - return k, v -} - -// Prev moves the cursor to the previous item in the bucket and returns its key and value. -// If the cursor is at the beginning of the bucket then a nil key and value are returned. -// The returned key and value are only valid for the life of the transaction. -func (c *Cursor) Prev() (key []byte, value []byte) { - _assert(c.bucket.tx.db != nil, "tx closed") - - // Attempt to move back one element until we're successful. - // Move up the stack as we hit the beginning of each page in our stack. - for i := len(c.stack) - 1; i >= 0; i-- { - elem := &c.stack[i] - if elem.index > 0 { - elem.index-- - break - } - c.stack = c.stack[:i] - } - - // If we've hit the end then return nil. - if len(c.stack) == 0 { - return nil, nil - } - - // Move down the stack to find the last element of the last leaf under this branch. - c.last() - k, v, flags := c.keyValue() - if (flags & uint32(bucketLeafFlag)) != 0 { - return k, nil - } - return k, v -} - -// Seek moves the cursor to a given key and returns it. -// If the key does not exist then the next key is used. If no keys -// follow, a nil key is returned. -// The returned key and value are only valid for the life of the transaction. -func (c *Cursor) Seek(seek []byte) (key []byte, value []byte) { - k, v, flags := c.seek(seek) - - // If we ended up after the last element of a page then move to the next one. - if ref := &c.stack[len(c.stack)-1]; ref.index >= ref.count() { - k, v, flags = c.next() - } - - if k == nil { - return nil, nil - } else if (flags & uint32(bucketLeafFlag)) != 0 { - return k, nil - } - return k, v -} - -// Delete removes the current key/value under the cursor from the bucket. -// Delete fails if current key/value is a bucket or if the transaction is not writable. -func (c *Cursor) Delete() error { - if c.bucket.tx.db == nil { - return ErrTxClosed - } else if !c.bucket.Writable() { - return ErrTxNotWritable - } - - key, _, flags := c.keyValue() - // Return an error if current value is a bucket. - if (flags & bucketLeafFlag) != 0 { - return ErrIncompatibleValue - } - c.node().del(key) - - return nil -} - -// seek moves the cursor to a given key and returns it. -// If the key does not exist then the next key is used. -func (c *Cursor) seek(seek []byte) (key []byte, value []byte, flags uint32) { - _assert(c.bucket.tx.db != nil, "tx closed") - - // Start from root page/node and traverse to correct page. - c.stack = c.stack[:0] - c.search(seek, c.bucket.root) - ref := &c.stack[len(c.stack)-1] - - // If the cursor is pointing to the end of page/node then return nil. - if ref.index >= ref.count() { - return nil, nil, 0 - } - - // If this is a bucket then return a nil value. - return c.keyValue() -} - -// first moves the cursor to the first leaf element under the last page in the stack. -func (c *Cursor) first() { - for { - // Exit when we hit a leaf page. - var ref = &c.stack[len(c.stack)-1] - if ref.isLeaf() { - break - } - - // Keep adding pages pointing to the first element to the stack. - var pgid pgid - if ref.node != nil { - pgid = ref.node.inodes[ref.index].pgid - } else { - pgid = ref.page.branchPageElement(uint16(ref.index)).pgid - } - p, n := c.bucket.pageNode(pgid) - c.stack = append(c.stack, elemRef{page: p, node: n, index: 0}) - } -} - -// last moves the cursor to the last leaf element under the last page in the stack. -func (c *Cursor) last() { - for { - // Exit when we hit a leaf page. - ref := &c.stack[len(c.stack)-1] - if ref.isLeaf() { - break - } - - // Keep adding pages pointing to the last element in the stack. - var pgid pgid - if ref.node != nil { - pgid = ref.node.inodes[ref.index].pgid - } else { - pgid = ref.page.branchPageElement(uint16(ref.index)).pgid - } - p, n := c.bucket.pageNode(pgid) - - var nextRef = elemRef{page: p, node: n} - nextRef.index = nextRef.count() - 1 - c.stack = append(c.stack, nextRef) - } -} - -// next moves to the next leaf element and returns the key and value. -// If the cursor is at the last leaf element then it stays there and returns nil. -func (c *Cursor) next() (key []byte, value []byte, flags uint32) { - for { - // Attempt to move over one element until we're successful. - // Move up the stack as we hit the end of each page in our stack. - var i int - for i = len(c.stack) - 1; i >= 0; i-- { - elem := &c.stack[i] - if elem.index < elem.count()-1 { - elem.index++ - break - } - } - - // If we've hit the root page then stop and return. This will leave the - // cursor on the last element of the last page. - if i == -1 { - return nil, nil, 0 - } - - // Otherwise start from where we left off in the stack and find the - // first element of the first leaf page. - c.stack = c.stack[:i+1] - c.first() - - // If this is an empty page then restart and move back up the stack. - // https://github.com/boltdb/bolt/issues/450 - if c.stack[len(c.stack)-1].count() == 0 { - continue - } - - return c.keyValue() - } -} - -// search recursively performs a binary search against a given page/node until it finds a given key. -func (c *Cursor) search(key []byte, pgid pgid) { - p, n := c.bucket.pageNode(pgid) - if p != nil && (p.flags&(branchPageFlag|leafPageFlag)) == 0 { - panic(fmt.Sprintf("invalid page type: %d: %x", p.id, p.flags)) - } - e := elemRef{page: p, node: n} - c.stack = append(c.stack, e) - - // If we're on a leaf page/node then find the specific node. - if e.isLeaf() { - c.nsearch(key) - return - } - - if n != nil { - c.searchNode(key, n) - return - } - c.searchPage(key, p) -} - -func (c *Cursor) searchNode(key []byte, n *node) { - var exact bool - index := sort.Search(len(n.inodes), func(i int) bool { - // TODO(benbjohnson): Optimize this range search. It's a bit hacky right now. - // sort.Search() finds the lowest index where f() != -1 but we need the highest index. - ret := bytes.Compare(n.inodes[i].key, key) - if ret == 0 { - exact = true - } - return ret != -1 - }) - if !exact && index > 0 { - index-- - } - c.stack[len(c.stack)-1].index = index - - // Recursively search to the next page. - c.search(key, n.inodes[index].pgid) -} - -func (c *Cursor) searchPage(key []byte, p *page) { - // Binary search for the correct range. - inodes := p.branchPageElements() - - var exact bool - index := sort.Search(int(p.count), func(i int) bool { - // TODO(benbjohnson): Optimize this range search. It's a bit hacky right now. - // sort.Search() finds the lowest index where f() != -1 but we need the highest index. - ret := bytes.Compare(inodes[i].key(), key) - if ret == 0 { - exact = true - } - return ret != -1 - }) - if !exact && index > 0 { - index-- - } - c.stack[len(c.stack)-1].index = index - - // Recursively search to the next page. - c.search(key, inodes[index].pgid) -} - -// nsearch searches the leaf node on the top of the stack for a key. -func (c *Cursor) nsearch(key []byte) { - e := &c.stack[len(c.stack)-1] - p, n := e.page, e.node - - // If we have a node then search its inodes. - if n != nil { - index := sort.Search(len(n.inodes), func(i int) bool { - return bytes.Compare(n.inodes[i].key, key) != -1 - }) - e.index = index - return - } - - // If we have a page then search its leaf elements. - inodes := p.leafPageElements() - index := sort.Search(int(p.count), func(i int) bool { - return bytes.Compare(inodes[i].key(), key) != -1 - }) - e.index = index -} - -// keyValue returns the key and value of the current leaf element. -func (c *Cursor) keyValue() ([]byte, []byte, uint32) { - ref := &c.stack[len(c.stack)-1] - if ref.count() == 0 || ref.index >= ref.count() { - return nil, nil, 0 - } - - // Retrieve value from node. - if ref.node != nil { - inode := &ref.node.inodes[ref.index] - return inode.key, inode.value, inode.flags - } - - // Or retrieve value from page. - elem := ref.page.leafPageElement(uint16(ref.index)) - return elem.key(), elem.value(), elem.flags -} - -// node returns the node that the cursor is currently positioned on. -func (c *Cursor) node() *node { - _assert(len(c.stack) > 0, "accessing a node with a zero-length cursor stack") - - // If the top of the stack is a leaf node then just return it. - if ref := &c.stack[len(c.stack)-1]; ref.node != nil && ref.isLeaf() { - return ref.node - } - - // Start from root and traverse down the hierarchy. - var n = c.stack[0].node - if n == nil { - n = c.bucket.node(c.stack[0].page.id, nil) - } - for _, ref := range c.stack[:len(c.stack)-1] { - _assert(!n.isLeaf, "expected branch node") - n = n.childAt(int(ref.index)) - } - _assert(n.isLeaf, "expected leaf node") - return n -} - -// elemRef represents a reference to an element on a given page/node. -type elemRef struct { - page *page - node *node - index int -} - -// isLeaf returns whether the ref is pointing at a leaf page/node. -func (r *elemRef) isLeaf() bool { - if r.node != nil { - return r.node.isLeaf - } - return (r.page.flags & leafPageFlag) != 0 -} - -// count returns the number of inodes or page elements. -func (r *elemRef) count() int { - if r.node != nil { - return len(r.node.inodes) - } - return int(r.page.count) -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor_test.go deleted file mode 100644 index 562d60f..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/cursor_test.go +++ /dev/null @@ -1,817 +0,0 @@ -package bolt_test - -import ( - "bytes" - "encoding/binary" - "fmt" - "log" - "os" - "reflect" - "sort" - "testing" - "testing/quick" - - "github.com/boltdb/bolt" -) - -// Ensure that a cursor can return a reference to the bucket that created it. -func TestCursor_Bucket(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if cb := b.Cursor().Bucket(); !reflect.DeepEqual(cb, b) { - t.Fatal("cursor bucket mismatch") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx cursor can seek to the appropriate keys. -func TestCursor_Seek(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("0001")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("bar"), []byte("0002")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte("0003")); err != nil { - t.Fatal(err) - } - - if _, err := b.CreateBucket([]byte("bkt")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - c := tx.Bucket([]byte("widgets")).Cursor() - - // Exact match should go to the key. - if k, v := c.Seek([]byte("bar")); !bytes.Equal(k, []byte("bar")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte("0002")) { - t.Fatalf("unexpected value: %v", v) - } - - // Inexact match should go to the next key. - if k, v := c.Seek([]byte("bas")); !bytes.Equal(k, []byte("baz")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte("0003")) { - t.Fatalf("unexpected value: %v", v) - } - - // Low key should go to the first key. - if k, v := c.Seek([]byte("")); !bytes.Equal(k, []byte("bar")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte("0002")) { - t.Fatalf("unexpected value: %v", v) - } - - // High key should return no key. - if k, v := c.Seek([]byte("zzz")); k != nil { - t.Fatalf("expected nil key: %v", k) - } else if v != nil { - t.Fatalf("expected nil value: %v", v) - } - - // Buckets should return their key but no value. - if k, v := c.Seek([]byte("bkt")); !bytes.Equal(k, []byte("bkt")) { - t.Fatalf("unexpected key: %v", k) - } else if v != nil { - t.Fatalf("expected nil value: %v", v) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -func TestCursor_Delete(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - const count = 1000 - - // Insert every other key between 0 and $count. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - for i := 0; i < count; i += 1 { - k := make([]byte, 8) - binary.BigEndian.PutUint64(k, uint64(i)) - if err := b.Put(k, make([]byte, 100)); err != nil { - t.Fatal(err) - } - } - if _, err := b.CreateBucket([]byte("sub")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - c := tx.Bucket([]byte("widgets")).Cursor() - bound := make([]byte, 8) - binary.BigEndian.PutUint64(bound, uint64(count/2)) - for key, _ := c.First(); bytes.Compare(key, bound) < 0; key, _ = c.Next() { - if err := c.Delete(); err != nil { - t.Fatal(err) - } - } - - c.Seek([]byte("sub")) - if err := c.Delete(); err != bolt.ErrIncompatibleValue { - t.Fatalf("unexpected error: %s", err) - } - - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - stats := tx.Bucket([]byte("widgets")).Stats() - if stats.KeyN != count/2+1 { - t.Fatalf("unexpected KeyN: %d", stats.KeyN) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx cursor can seek to the appropriate keys when there are a -// large number of keys. This test also checks that seek will always move -// forward to the next key. -// -// Related: https://github.com/boltdb/bolt/pull/187 -func TestCursor_Seek_Large(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var count = 10000 - - // Insert every other key between 0 and $count. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - for i := 0; i < count; i += 100 { - for j := i; j < i+100; j += 2 { - k := make([]byte, 8) - binary.BigEndian.PutUint64(k, uint64(j)) - if err := b.Put(k, make([]byte, 100)); err != nil { - t.Fatal(err) - } - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - c := tx.Bucket([]byte("widgets")).Cursor() - for i := 0; i < count; i++ { - seek := make([]byte, 8) - binary.BigEndian.PutUint64(seek, uint64(i)) - - k, _ := c.Seek(seek) - - // The last seek is beyond the end of the the range so - // it should return nil. - if i == count-1 { - if k != nil { - t.Fatal("expected nil key") - } - continue - } - - // Otherwise we should seek to the exact key or the next key. - num := binary.BigEndian.Uint64(k) - if i%2 == 0 { - if num != uint64(i) { - t.Fatalf("unexpected num: %d", num) - } - } else { - if num != uint64(i+1) { - t.Fatalf("unexpected num: %d", num) - } - } - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a cursor can iterate over an empty bucket without error. -func TestCursor_EmptyBucket(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - c := tx.Bucket([]byte("widgets")).Cursor() - k, v := c.First() - if k != nil { - t.Fatalf("unexpected key: %v", k) - } else if v != nil { - t.Fatalf("unexpected value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx cursor can reverse iterate over an empty bucket without error. -func TestCursor_EmptyBucketReverse(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - t.Fatal(err) - } - if err := db.View(func(tx *bolt.Tx) error { - c := tx.Bucket([]byte("widgets")).Cursor() - k, v := c.Last() - if k != nil { - t.Fatalf("unexpected key: %v", k) - } else if v != nil { - t.Fatalf("unexpected value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx cursor can iterate over a single root with a couple elements. -func TestCursor_Iterate_Leaf(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte{}); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte{0}); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("bar"), []byte{1}); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - tx, err := db.Begin(false) - if err != nil { - t.Fatal(err) - } - defer func() { _ = tx.Rollback() }() - - c := tx.Bucket([]byte("widgets")).Cursor() - - k, v := c.First() - if !bytes.Equal(k, []byte("bar")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte{1}) { - t.Fatalf("unexpected value: %v", v) - } - - k, v = c.Next() - if !bytes.Equal(k, []byte("baz")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte{}) { - t.Fatalf("unexpected value: %v", v) - } - - k, v = c.Next() - if !bytes.Equal(k, []byte("foo")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte{0}) { - t.Fatalf("unexpected value: %v", v) - } - - k, v = c.Next() - if k != nil { - t.Fatalf("expected nil key: %v", k) - } else if v != nil { - t.Fatalf("expected nil value: %v", v) - } - - k, v = c.Next() - if k != nil { - t.Fatalf("expected nil key: %v", k) - } else if v != nil { - t.Fatalf("expected nil value: %v", v) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx cursor can iterate in reverse over a single root with a couple elements. -func TestCursor_LeafRootReverse(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte{}); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte{0}); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("bar"), []byte{1}); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - tx, err := db.Begin(false) - if err != nil { - t.Fatal(err) - } - c := tx.Bucket([]byte("widgets")).Cursor() - - if k, v := c.Last(); !bytes.Equal(k, []byte("foo")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte{0}) { - t.Fatalf("unexpected value: %v", v) - } - - if k, v := c.Prev(); !bytes.Equal(k, []byte("baz")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte{}) { - t.Fatalf("unexpected value: %v", v) - } - - if k, v := c.Prev(); !bytes.Equal(k, []byte("bar")) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, []byte{1}) { - t.Fatalf("unexpected value: %v", v) - } - - if k, v := c.Prev(); k != nil { - t.Fatalf("expected nil key: %v", k) - } else if v != nil { - t.Fatalf("expected nil value: %v", v) - } - - if k, v := c.Prev(); k != nil { - t.Fatalf("expected nil key: %v", k) - } else if v != nil { - t.Fatalf("expected nil value: %v", v) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx cursor can restart from the beginning. -func TestCursor_Restart(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("bar"), []byte{}); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte{}); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - tx, err := db.Begin(false) - if err != nil { - t.Fatal(err) - } - c := tx.Bucket([]byte("widgets")).Cursor() - - if k, _ := c.First(); !bytes.Equal(k, []byte("bar")) { - t.Fatalf("unexpected key: %v", k) - } - if k, _ := c.Next(); !bytes.Equal(k, []byte("foo")) { - t.Fatalf("unexpected key: %v", k) - } - - if k, _ := c.First(); !bytes.Equal(k, []byte("bar")) { - t.Fatalf("unexpected key: %v", k) - } - if k, _ := c.Next(); !bytes.Equal(k, []byte("foo")) { - t.Fatalf("unexpected key: %v", k) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } -} - -// Ensure that a cursor can skip over empty pages that have been deleted. -func TestCursor_First_EmptyPages(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - // Create 1000 keys in the "widgets" bucket. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - for i := 0; i < 1000; i++ { - if err := b.Put(u64tob(uint64(i)), []byte{}); err != nil { - t.Fatal(err) - } - } - - return nil - }); err != nil { - t.Fatal(err) - } - - // Delete half the keys and then try to iterate. - if err := db.Update(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for i := 0; i < 600; i++ { - if err := b.Delete(u64tob(uint64(i))); err != nil { - t.Fatal(err) - } - } - - c := b.Cursor() - var n int - for k, _ := c.First(); k != nil; k, _ = c.Next() { - n++ - } - if n != 400 { - t.Fatalf("unexpected key count: %d", n) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx can iterate over all elements in a bucket. -func TestCursor_QuickCheck(t *testing.T) { - f := func(items testdata) bool { - db := MustOpenDB() - defer db.MustClose() - - // Bulk insert all values. - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - for _, item := range items { - if err := b.Put(item.Key, item.Value); err != nil { - t.Fatal(err) - } - } - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - - // Sort test data. - sort.Sort(items) - - // Iterate over all items and check consistency. - var index = 0 - tx, err = db.Begin(false) - if err != nil { - t.Fatal(err) - } - - c := tx.Bucket([]byte("widgets")).Cursor() - for k, v := c.First(); k != nil && index < len(items); k, v = c.Next() { - if !bytes.Equal(k, items[index].Key) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, items[index].Value) { - t.Fatalf("unexpected value: %v", v) - } - index++ - } - if len(items) != index { - t.Fatalf("unexpected item count: %v, expected %v", len(items), index) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - - return true - } - if err := quick.Check(f, qconfig()); err != nil { - t.Error(err) - } -} - -// Ensure that a transaction can iterate over all elements in a bucket in reverse. -func TestCursor_QuickCheck_Reverse(t *testing.T) { - f := func(items testdata) bool { - db := MustOpenDB() - defer db.MustClose() - - // Bulk insert all values. - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - for _, item := range items { - if err := b.Put(item.Key, item.Value); err != nil { - t.Fatal(err) - } - } - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - - // Sort test data. - sort.Sort(revtestdata(items)) - - // Iterate over all items and check consistency. - var index = 0 - tx, err = db.Begin(false) - if err != nil { - t.Fatal(err) - } - c := tx.Bucket([]byte("widgets")).Cursor() - for k, v := c.Last(); k != nil && index < len(items); k, v = c.Prev() { - if !bytes.Equal(k, items[index].Key) { - t.Fatalf("unexpected key: %v", k) - } else if !bytes.Equal(v, items[index].Value) { - t.Fatalf("unexpected value: %v", v) - } - index++ - } - if len(items) != index { - t.Fatalf("unexpected item count: %v, expected %v", len(items), index) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - - return true - } - if err := quick.Check(f, qconfig()); err != nil { - t.Error(err) - } -} - -// Ensure that a Tx cursor can iterate over subbuckets. -func TestCursor_QuickCheck_BucketsOnly(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if _, err := b.CreateBucket([]byte("foo")); err != nil { - t.Fatal(err) - } - if _, err := b.CreateBucket([]byte("bar")); err != nil { - t.Fatal(err) - } - if _, err := b.CreateBucket([]byte("baz")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - var names []string - c := tx.Bucket([]byte("widgets")).Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - names = append(names, string(k)) - if v != nil { - t.Fatalf("unexpected value: %v", v) - } - } - if !reflect.DeepEqual(names, []string{"bar", "baz", "foo"}) { - t.Fatalf("unexpected names: %+v", names) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx cursor can reverse iterate over subbuckets. -func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if _, err := b.CreateBucket([]byte("foo")); err != nil { - t.Fatal(err) - } - if _, err := b.CreateBucket([]byte("bar")); err != nil { - t.Fatal(err) - } - if _, err := b.CreateBucket([]byte("baz")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - var names []string - c := tx.Bucket([]byte("widgets")).Cursor() - for k, v := c.Last(); k != nil; k, v = c.Prev() { - names = append(names, string(k)) - if v != nil { - t.Fatalf("unexpected value: %v", v) - } - } - if !reflect.DeepEqual(names, []string{"foo", "baz", "bar"}) { - t.Fatalf("unexpected names: %+v", names) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -func ExampleCursor() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Start a read-write transaction. - if err := db.Update(func(tx *bolt.Tx) error { - // Create a new bucket. - b, err := tx.CreateBucket([]byte("animals")) - if err != nil { - return err - } - - // Insert data into a bucket. - if err := b.Put([]byte("dog"), []byte("fun")); err != nil { - log.Fatal(err) - } - if err := b.Put([]byte("cat"), []byte("lame")); err != nil { - log.Fatal(err) - } - if err := b.Put([]byte("liger"), []byte("awesome")); err != nil { - log.Fatal(err) - } - - // Create a cursor for iteration. - c := b.Cursor() - - // Iterate over items in sorted key order. This starts from the - // first key/value pair and updates the k/v variables to the - // next key/value on each iteration. - // - // The loop finishes at the end of the cursor when a nil key is returned. - for k, v := c.First(); k != nil; k, v = c.Next() { - fmt.Printf("A %s is %s.\n", k, v) - } - - return nil - }); err != nil { - log.Fatal(err) - } - - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // A cat is lame. - // A dog is fun. - // A liger is awesome. -} - -func ExampleCursor_reverse() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Start a read-write transaction. - if err := db.Update(func(tx *bolt.Tx) error { - // Create a new bucket. - b, err := tx.CreateBucket([]byte("animals")) - if err != nil { - return err - } - - // Insert data into a bucket. - if err := b.Put([]byte("dog"), []byte("fun")); err != nil { - log.Fatal(err) - } - if err := b.Put([]byte("cat"), []byte("lame")); err != nil { - log.Fatal(err) - } - if err := b.Put([]byte("liger"), []byte("awesome")); err != nil { - log.Fatal(err) - } - - // Create a cursor for iteration. - c := b.Cursor() - - // Iterate over items in reverse sorted key order. This starts - // from the last key/value pair and updates the k/v variables to - // the previous key/value on each iteration. - // - // The loop finishes at the beginning of the cursor when a nil key - // is returned. - for k, v := c.Last(); k != nil; k, v = c.Prev() { - fmt.Printf("A %s is %s.\n", k, v) - } - - return nil - }); err != nil { - log.Fatal(err) - } - - // Close the database to release the file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // A liger is awesome. - // A dog is fun. - // A cat is lame. -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db.go deleted file mode 100644 index 48da059..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db.go +++ /dev/null @@ -1,1036 +0,0 @@ -package bolt - -import ( - "errors" - "fmt" - "hash/fnv" - "log" - "os" - "runtime" - "runtime/debug" - "strings" - "sync" - "time" - "unsafe" -) - -// The largest step that can be taken when remapping the mmap. -const maxMmapStep = 1 << 30 // 1GB - -// The data file format version. -const version = 2 - -// Represents a marker value to indicate that a file is a Bolt DB. -const magic uint32 = 0xED0CDAED - -// IgnoreNoSync specifies whether the NoSync field of a DB is ignored when -// syncing changes to a file. This is required as some operating systems, -// such as OpenBSD, do not have a unified buffer cache (UBC) and writes -// must be synchronized using the msync(2) syscall. -const IgnoreNoSync = runtime.GOOS == "openbsd" - -// Default values if not set in a DB instance. -const ( - DefaultMaxBatchSize int = 1000 - DefaultMaxBatchDelay = 10 * time.Millisecond - DefaultAllocSize = 16 * 1024 * 1024 -) - -// default page size for db is set to the OS page size. -var defaultPageSize = os.Getpagesize() - -// DB represents a collection of buckets persisted to a file on disk. -// All data access is performed through transactions which can be obtained through the DB. -// All the functions on DB will return a ErrDatabaseNotOpen if accessed before Open() is called. -type DB struct { - // When enabled, the database will perform a Check() after every commit. - // A panic is issued if the database is in an inconsistent state. This - // flag has a large performance impact so it should only be used for - // debugging purposes. - StrictMode bool - - // Setting the NoSync flag will cause the database to skip fsync() - // calls after each commit. This can be useful when bulk loading data - // into a database and you can restart the bulk load in the event of - // a system failure or database corruption. Do not set this flag for - // normal use. - // - // If the package global IgnoreNoSync constant is true, this value is - // ignored. See the comment on that constant for more details. - // - // THIS IS UNSAFE. PLEASE USE WITH CAUTION. - NoSync bool - - // When true, skips the truncate call when growing the database. - // Setting this to true is only safe on non-ext3/ext4 systems. - // Skipping truncation avoids preallocation of hard drive space and - // bypasses a truncate() and fsync() syscall on remapping. - // - // https://github.com/boltdb/bolt/issues/284 - NoGrowSync bool - - // If you want to read the entire database fast, you can set MmapFlag to - // syscall.MAP_POPULATE on Linux 2.6.23+ for sequential read-ahead. - MmapFlags int - - // MaxBatchSize is the maximum size of a batch. Default value is - // copied from DefaultMaxBatchSize in Open. - // - // If <=0, disables batching. - // - // Do not change concurrently with calls to Batch. - MaxBatchSize int - - // MaxBatchDelay is the maximum delay before a batch starts. - // Default value is copied from DefaultMaxBatchDelay in Open. - // - // If <=0, effectively disables batching. - // - // Do not change concurrently with calls to Batch. - MaxBatchDelay time.Duration - - // AllocSize is the amount of space allocated when the database - // needs to create new pages. This is done to amortize the cost - // of truncate() and fsync() when growing the data file. - AllocSize int - - path string - file *os.File - lockfile *os.File // windows only - dataref []byte // mmap'ed readonly, write throws SEGV - data *[maxMapSize]byte - datasz int - filesz int // current on disk file size - meta0 *meta - meta1 *meta - pageSize int - opened bool - rwtx *Tx - txs []*Tx - freelist *freelist - stats Stats - - pagePool sync.Pool - - batchMu sync.Mutex - batch *batch - - rwlock sync.Mutex // Allows only one writer at a time. - metalock sync.Mutex // Protects meta page access. - mmaplock sync.RWMutex // Protects mmap access during remapping. - statlock sync.RWMutex // Protects stats access. - - ops struct { - writeAt func(b []byte, off int64) (n int, err error) - } - - // Read only mode. - // When true, Update() and Begin(true) return ErrDatabaseReadOnly immediately. - readOnly bool -} - -// Path returns the path to currently open database file. -func (db *DB) Path() string { - return db.path -} - -// GoString returns the Go string representation of the database. -func (db *DB) GoString() string { - return fmt.Sprintf("bolt.DB{path:%q}", db.path) -} - -// String returns the string representation of the database. -func (db *DB) String() string { - return fmt.Sprintf("DB<%q>", db.path) -} - -// Open creates and opens a database at the given path. -// If the file does not exist then it will be created automatically. -// Passing in nil options will cause Bolt to open the database with the default options. -func Open(path string, mode os.FileMode, options *Options) (*DB, error) { - var db = &DB{opened: true} - - // Set default options if no options are provided. - if options == nil { - options = DefaultOptions - } - db.NoGrowSync = options.NoGrowSync - db.MmapFlags = options.MmapFlags - - // Set default values for later DB operations. - db.MaxBatchSize = DefaultMaxBatchSize - db.MaxBatchDelay = DefaultMaxBatchDelay - db.AllocSize = DefaultAllocSize - - flag := os.O_RDWR - if options.ReadOnly { - flag = os.O_RDONLY - db.readOnly = true - } - - // Open data file and separate sync handler for metadata writes. - db.path = path - var err error - if db.file, err = os.OpenFile(db.path, flag|os.O_CREATE, mode); err != nil { - _ = db.close() - return nil, err - } - - // Lock file so that other processes using Bolt in read-write mode cannot - // use the database at the same time. This would cause corruption since - // the two processes would write meta pages and free pages separately. - // The database file is locked exclusively (only one process can grab the lock) - // if !options.ReadOnly. - // The database file is locked using the shared lock (more than one process may - // hold a lock at the same time) otherwise (options.ReadOnly is set). - if err := flock(db, mode, !db.readOnly, options.Timeout); err != nil { - _ = db.close() - return nil, err - } - - // Default values for test hooks - db.ops.writeAt = db.file.WriteAt - - // Initialize the database if it doesn't exist. - if info, err := db.file.Stat(); err != nil { - return nil, err - } else if info.Size() == 0 { - // Initialize new files with meta pages. - if err := db.init(); err != nil { - return nil, err - } - } else { - // Read the first meta page to determine the page size. - var buf [0x1000]byte - if _, err := db.file.ReadAt(buf[:], 0); err == nil { - m := db.pageInBuffer(buf[:], 0).meta() - if err := m.validate(); err != nil { - // If we can't read the page size, we can assume it's the same - // as the OS -- since that's how the page size was chosen in the - // first place. - // - // If the first page is invalid and this OS uses a different - // page size than what the database was created with then we - // are out of luck and cannot access the database. - db.pageSize = os.Getpagesize() - } else { - db.pageSize = int(m.pageSize) - } - } - } - - // Initialize page pool. - db.pagePool = sync.Pool{ - New: func() interface{} { - return make([]byte, db.pageSize) - }, - } - - // Memory map the data file. - if err := db.mmap(options.InitialMmapSize); err != nil { - _ = db.close() - return nil, err - } - - // Read in the freelist. - db.freelist = newFreelist() - db.freelist.read(db.page(db.meta().freelist)) - - // Mark the database as opened and return. - return db, nil -} - -// mmap opens the underlying memory-mapped file and initializes the meta references. -// minsz is the minimum size that the new mmap can be. -func (db *DB) mmap(minsz int) error { - db.mmaplock.Lock() - defer db.mmaplock.Unlock() - - info, err := db.file.Stat() - if err != nil { - return fmt.Errorf("mmap stat error: %s", err) - } else if int(info.Size()) < db.pageSize*2 { - return fmt.Errorf("file size too small") - } - - // Ensure the size is at least the minimum size. - var size = int(info.Size()) - if size < minsz { - size = minsz - } - size, err = db.mmapSize(size) - if err != nil { - return err - } - - // Dereference all mmap references before unmapping. - if db.rwtx != nil { - db.rwtx.root.dereference() - } - - // Unmap existing data before continuing. - if err := db.munmap(); err != nil { - return err - } - - // Memory-map the data file as a byte slice. - if err := mmap(db, size); err != nil { - return err - } - - // Save references to the meta pages. - db.meta0 = db.page(0).meta() - db.meta1 = db.page(1).meta() - - // Validate the meta pages. We only return an error if both meta pages fail - // validation, since meta0 failing validation means that it wasn't saved - // properly -- but we can recover using meta1. And vice-versa. - err0 := db.meta0.validate() - err1 := db.meta1.validate() - if err0 != nil && err1 != nil { - return err0 - } - - return nil -} - -// munmap unmaps the data file from memory. -func (db *DB) munmap() error { - if err := munmap(db); err != nil { - return fmt.Errorf("unmap error: " + err.Error()) - } - return nil -} - -// mmapSize determines the appropriate size for the mmap given the current size -// of the database. The minimum size is 32KB and doubles until it reaches 1GB. -// Returns an error if the new mmap size is greater than the max allowed. -func (db *DB) mmapSize(size int) (int, error) { - // Double the size from 32KB until 1GB. - for i := uint(15); i <= 30; i++ { - if size <= 1< maxMapSize { - return 0, fmt.Errorf("mmap too large") - } - - // If larger than 1GB then grow by 1GB at a time. - sz := int64(size) - if remainder := sz % int64(maxMmapStep); remainder > 0 { - sz += int64(maxMmapStep) - remainder - } - - // Ensure that the mmap size is a multiple of the page size. - // This should always be true since we're incrementing in MBs. - pageSize := int64(db.pageSize) - if (sz % pageSize) != 0 { - sz = ((sz / pageSize) + 1) * pageSize - } - - // If we've exceeded the max size then only grow up to the max size. - if sz > maxMapSize { - sz = maxMapSize - } - - return int(sz), nil -} - -// init creates a new database file and initializes its meta pages. -func (db *DB) init() error { - // Set the page size to the OS page size. - db.pageSize = os.Getpagesize() - - // Create two meta pages on a buffer. - buf := make([]byte, db.pageSize*4) - for i := 0; i < 2; i++ { - p := db.pageInBuffer(buf[:], pgid(i)) - p.id = pgid(i) - p.flags = metaPageFlag - - // Initialize the meta page. - m := p.meta() - m.magic = magic - m.version = version - m.pageSize = uint32(db.pageSize) - m.freelist = 2 - m.root = bucket{root: 3} - m.pgid = 4 - m.txid = txid(i) - m.checksum = m.sum64() - } - - // Write an empty freelist at page 3. - p := db.pageInBuffer(buf[:], pgid(2)) - p.id = pgid(2) - p.flags = freelistPageFlag - p.count = 0 - - // Write an empty leaf page at page 4. - p = db.pageInBuffer(buf[:], pgid(3)) - p.id = pgid(3) - p.flags = leafPageFlag - p.count = 0 - - // Write the buffer to our data file. - if _, err := db.ops.writeAt(buf, 0); err != nil { - return err - } - if err := fdatasync(db); err != nil { - return err - } - - return nil -} - -// Close releases all database resources. -// All transactions must be closed before closing the database. -func (db *DB) Close() error { - db.rwlock.Lock() - defer db.rwlock.Unlock() - - db.metalock.Lock() - defer db.metalock.Unlock() - - db.mmaplock.RLock() - defer db.mmaplock.RUnlock() - - return db.close() -} - -func (db *DB) close() error { - if !db.opened { - return nil - } - - db.opened = false - - db.freelist = nil - - // Clear ops. - db.ops.writeAt = nil - - // Close the mmap. - if err := db.munmap(); err != nil { - return err - } - - // Close file handles. - if db.file != nil { - // No need to unlock read-only file. - if !db.readOnly { - // Unlock the file. - if err := funlock(db); err != nil { - log.Printf("bolt.Close(): funlock error: %s", err) - } - } - - // Close the file descriptor. - if err := db.file.Close(); err != nil { - return fmt.Errorf("db file close: %s", err) - } - db.file = nil - } - - db.path = "" - return nil -} - -// Begin starts a new transaction. -// Multiple read-only transactions can be used concurrently but only one -// write transaction can be used at a time. Starting multiple write transactions -// will cause the calls to block and be serialized until the current write -// transaction finishes. -// -// Transactions should not be dependent on one another. Opening a read -// transaction and a write transaction in the same goroutine can cause the -// writer to deadlock because the database periodically needs to re-mmap itself -// as it grows and it cannot do that while a read transaction is open. -// -// If a long running read transaction (for example, a snapshot transaction) is -// needed, you might want to set DB.InitialMmapSize to a large enough value -// to avoid potential blocking of write transaction. -// -// IMPORTANT: You must close read-only transactions after you are finished or -// else the database will not reclaim old pages. -func (db *DB) Begin(writable bool) (*Tx, error) { - if writable { - return db.beginRWTx() - } - return db.beginTx() -} - -func (db *DB) beginTx() (*Tx, error) { - // Lock the meta pages while we initialize the transaction. We obtain - // the meta lock before the mmap lock because that's the order that the - // write transaction will obtain them. - db.metalock.Lock() - - // Obtain a read-only lock on the mmap. When the mmap is remapped it will - // obtain a write lock so all transactions must finish before it can be - // remapped. - db.mmaplock.RLock() - - // Exit if the database is not open yet. - if !db.opened { - db.mmaplock.RUnlock() - db.metalock.Unlock() - return nil, ErrDatabaseNotOpen - } - - // Create a transaction associated with the database. - t := &Tx{} - t.init(db) - - // Keep track of transaction until it closes. - db.txs = append(db.txs, t) - n := len(db.txs) - - // Unlock the meta pages. - db.metalock.Unlock() - - // Update the transaction stats. - db.statlock.Lock() - db.stats.TxN++ - db.stats.OpenTxN = n - db.statlock.Unlock() - - return t, nil -} - -func (db *DB) beginRWTx() (*Tx, error) { - // If the database was opened with Options.ReadOnly, return an error. - if db.readOnly { - return nil, ErrDatabaseReadOnly - } - - // Obtain writer lock. This is released by the transaction when it closes. - // This enforces only one writer transaction at a time. - db.rwlock.Lock() - - // Once we have the writer lock then we can lock the meta pages so that - // we can set up the transaction. - db.metalock.Lock() - defer db.metalock.Unlock() - - // Exit if the database is not open yet. - if !db.opened { - db.rwlock.Unlock() - return nil, ErrDatabaseNotOpen - } - - // Create a transaction associated with the database. - t := &Tx{writable: true} - t.init(db) - db.rwtx = t - - // Free any pages associated with closed read-only transactions. - var minid txid = 0xFFFFFFFFFFFFFFFF - for _, t := range db.txs { - if t.meta.txid < minid { - minid = t.meta.txid - } - } - if minid > 0 { - db.freelist.release(minid - 1) - } - - return t, nil -} - -// removeTx removes a transaction from the database. -func (db *DB) removeTx(tx *Tx) { - // Release the read lock on the mmap. - db.mmaplock.RUnlock() - - // Use the meta lock to restrict access to the DB object. - db.metalock.Lock() - - // Remove the transaction. - for i, t := range db.txs { - if t == tx { - db.txs = append(db.txs[:i], db.txs[i+1:]...) - break - } - } - n := len(db.txs) - - // Unlock the meta pages. - db.metalock.Unlock() - - // Merge statistics. - db.statlock.Lock() - db.stats.OpenTxN = n - db.stats.TxStats.add(&tx.stats) - db.statlock.Unlock() -} - -// Update executes a function within the context of a read-write managed transaction. -// If no error is returned from the function then the transaction is committed. -// If an error is returned then the entire transaction is rolled back. -// Any error that is returned from the function or returned from the commit is -// returned from the Update() method. -// -// Attempting to manually commit or rollback within the function will cause a panic. -func (db *DB) Update(fn func(*Tx) error) error { - t, err := db.Begin(true) - if err != nil { - return err - } - - // Make sure the transaction rolls back in the event of a panic. - defer func() { - if t.db != nil { - t.rollback() - } - }() - - // Mark as a managed tx so that the inner function cannot manually commit. - t.managed = true - - // If an error is returned from the function then rollback and return error. - err = fn(t) - t.managed = false - if err != nil { - _ = t.Rollback() - return err - } - - return t.Commit() -} - -// View executes a function within the context of a managed read-only transaction. -// Any error that is returned from the function is returned from the View() method. -// -// Attempting to manually rollback within the function will cause a panic. -func (db *DB) View(fn func(*Tx) error) error { - t, err := db.Begin(false) - if err != nil { - return err - } - - // Make sure the transaction rolls back in the event of a panic. - defer func() { - if t.db != nil { - t.rollback() - } - }() - - // Mark as a managed tx so that the inner function cannot manually rollback. - t.managed = true - - // If an error is returned from the function then pass it through. - err = fn(t) - t.managed = false - if err != nil { - _ = t.Rollback() - return err - } - - if err := t.Rollback(); err != nil { - return err - } - - return nil -} - -// Batch calls fn as part of a batch. It behaves similar to Update, -// except: -// -// 1. concurrent Batch calls can be combined into a single Bolt -// transaction. -// -// 2. the function passed to Batch may be called multiple times, -// regardless of whether it returns error or not. -// -// This means that Batch function side effects must be idempotent and -// take permanent effect only after a successful return is seen in -// caller. -// -// The maximum batch size and delay can be adjusted with DB.MaxBatchSize -// and DB.MaxBatchDelay, respectively. -// -// Batch is only useful when there are multiple goroutines calling it. -func (db *DB) Batch(fn func(*Tx) error) error { - errCh := make(chan error, 1) - - db.batchMu.Lock() - if (db.batch == nil) || (db.batch != nil && len(db.batch.calls) >= db.MaxBatchSize) { - // There is no existing batch, or the existing batch is full; start a new one. - db.batch = &batch{ - db: db, - } - db.batch.timer = time.AfterFunc(db.MaxBatchDelay, db.batch.trigger) - } - db.batch.calls = append(db.batch.calls, call{fn: fn, err: errCh}) - if len(db.batch.calls) >= db.MaxBatchSize { - // wake up batch, it's ready to run - go db.batch.trigger() - } - db.batchMu.Unlock() - - err := <-errCh - if err == trySolo { - err = db.Update(fn) - } - return err -} - -type call struct { - fn func(*Tx) error - err chan<- error -} - -type batch struct { - db *DB - timer *time.Timer - start sync.Once - calls []call -} - -// trigger runs the batch if it hasn't already been run. -func (b *batch) trigger() { - b.start.Do(b.run) -} - -// run performs the transactions in the batch and communicates results -// back to DB.Batch. -func (b *batch) run() { - b.db.batchMu.Lock() - b.timer.Stop() - // Make sure no new work is added to this batch, but don't break - // other batches. - if b.db.batch == b { - b.db.batch = nil - } - b.db.batchMu.Unlock() - -retry: - for len(b.calls) > 0 { - var failIdx = -1 - err := b.db.Update(func(tx *Tx) error { - for i, c := range b.calls { - if err := safelyCall(c.fn, tx); err != nil { - failIdx = i - return err - } - } - return nil - }) - - if failIdx >= 0 { - // take the failing transaction out of the batch. it's - // safe to shorten b.calls here because db.batch no longer - // points to us, and we hold the mutex anyway. - c := b.calls[failIdx] - b.calls[failIdx], b.calls = b.calls[len(b.calls)-1], b.calls[:len(b.calls)-1] - // tell the submitter re-run it solo, continue with the rest of the batch - c.err <- trySolo - continue retry - } - - // pass success, or bolt internal errors, to all callers - for _, c := range b.calls { - if c.err != nil { - c.err <- err - } - } - break retry - } -} - -// trySolo is a special sentinel error value used for signaling that a -// transaction function should be re-run. It should never be seen by -// callers. -var trySolo = errors.New("batch function returned an error and should be re-run solo") - -type panicked struct { - reason interface{} -} - -func (p panicked) Error() string { - if err, ok := p.reason.(error); ok { - return err.Error() - } - return fmt.Sprintf("panic: %v", p.reason) -} - -func safelyCall(fn func(*Tx) error, tx *Tx) (err error) { - defer func() { - if p := recover(); p != nil { - err = panicked{p} - } - }() - return fn(tx) -} - -// Sync executes fdatasync() against the database file handle. -// -// This is not necessary under normal operation, however, if you use NoSync -// then it allows you to force the database file to sync against the disk. -func (db *DB) Sync() error { return fdatasync(db) } - -// Stats retrieves ongoing performance stats for the database. -// This is only updated when a transaction closes. -func (db *DB) Stats() Stats { - db.statlock.RLock() - defer db.statlock.RUnlock() - return db.stats -} - -// This is for internal access to the raw data bytes from the C cursor, use -// carefully, or not at all. -func (db *DB) Info() *Info { - return &Info{uintptr(unsafe.Pointer(&db.data[0])), db.pageSize} -} - -// page retrieves a page reference from the mmap based on the current page size. -func (db *DB) page(id pgid) *page { - pos := id * pgid(db.pageSize) - return (*page)(unsafe.Pointer(&db.data[pos])) -} - -// pageInBuffer retrieves a page reference from a given byte array based on the current page size. -func (db *DB) pageInBuffer(b []byte, id pgid) *page { - return (*page)(unsafe.Pointer(&b[id*pgid(db.pageSize)])) -} - -// meta retrieves the current meta page reference. -func (db *DB) meta() *meta { - // We have to return the meta with the highest txid which doesn't fail - // validation. Otherwise, we can cause errors when in fact the database is - // in a consistent state. metaA is the one with the higher txid. - metaA := db.meta0 - metaB := db.meta1 - if db.meta1.txid > db.meta0.txid { - metaA = db.meta1 - metaB = db.meta0 - } - - // Use higher meta page if valid. Otherwise fallback to previous, if valid. - if err := metaA.validate(); err == nil { - return metaA - } else if err := metaB.validate(); err == nil { - return metaB - } - - // This should never be reached, because both meta1 and meta0 were validated - // on mmap() and we do fsync() on every write. - panic("bolt.DB.meta(): invalid meta pages") -} - -// allocate returns a contiguous block of memory starting at a given page. -func (db *DB) allocate(count int) (*page, error) { - // Allocate a temporary buffer for the page. - var buf []byte - if count == 1 { - buf = db.pagePool.Get().([]byte) - } else { - buf = make([]byte, count*db.pageSize) - } - p := (*page)(unsafe.Pointer(&buf[0])) - p.overflow = uint32(count - 1) - - // Use pages from the freelist if they are available. - if p.id = db.freelist.allocate(count); p.id != 0 { - return p, nil - } - - // Resize mmap() if we're at the end. - p.id = db.rwtx.meta.pgid - var minsz = int((p.id+pgid(count))+1) * db.pageSize - if minsz >= db.datasz { - if err := db.mmap(minsz); err != nil { - return nil, fmt.Errorf("mmap allocate error: %s", err) - } - } - - // Move the page id high water mark. - db.rwtx.meta.pgid += pgid(count) - - return p, nil -} - -// grow grows the size of the database to the given sz. -func (db *DB) grow(sz int) error { - // Ignore if the new size is less than available file size. - if sz <= db.filesz { - return nil - } - - // If the data is smaller than the alloc size then only allocate what's needed. - // Once it goes over the allocation size then allocate in chunks. - if db.datasz < db.AllocSize { - sz = db.datasz - } else { - sz += db.AllocSize - } - - // Truncate and fsync to ensure file size metadata is flushed. - // https://github.com/boltdb/bolt/issues/284 - if !db.NoGrowSync && !db.readOnly { - if runtime.GOOS != "windows" { - if err := db.file.Truncate(int64(sz)); err != nil { - return fmt.Errorf("file resize error: %s", err) - } - } - if err := db.file.Sync(); err != nil { - return fmt.Errorf("file sync error: %s", err) - } - } - - db.filesz = sz - return nil -} - -func (db *DB) IsReadOnly() bool { - return db.readOnly -} - -// Options represents the options that can be set when opening a database. -type Options struct { - // Timeout is the amount of time to wait to obtain a file lock. - // When set to zero it will wait indefinitely. This option is only - // available on Darwin and Linux. - Timeout time.Duration - - // Sets the DB.NoGrowSync flag before memory mapping the file. - NoGrowSync bool - - // Open database in read-only mode. Uses flock(..., LOCK_SH |LOCK_NB) to - // grab a shared lock (UNIX). - ReadOnly bool - - // Sets the DB.MmapFlags flag before memory mapping the file. - MmapFlags int - - // InitialMmapSize is the initial mmap size of the database - // in bytes. Read transactions won't block write transaction - // if the InitialMmapSize is large enough to hold database mmap - // size. (See DB.Begin for more information) - // - // If <=0, the initial map size is 0. - // If initialMmapSize is smaller than the previous database size, - // it takes no effect. - InitialMmapSize int -} - -// DefaultOptions represent the options used if nil options are passed into Open(). -// No timeout is used which will cause Bolt to wait indefinitely for a lock. -var DefaultOptions = &Options{ - Timeout: 0, - NoGrowSync: false, -} - -// Stats represents statistics about the database. -type Stats struct { - // Freelist stats - FreePageN int // total number of free pages on the freelist - PendingPageN int // total number of pending pages on the freelist - FreeAlloc int // total bytes allocated in free pages - FreelistInuse int // total bytes used by the freelist - - // Transaction stats - TxN int // total number of started read transactions - OpenTxN int // number of currently open read transactions - - TxStats TxStats // global, ongoing stats. -} - -// Sub calculates and returns the difference between two sets of database stats. -// This is useful when obtaining stats at two different points and time and -// you need the performance counters that occurred within that time span. -func (s *Stats) Sub(other *Stats) Stats { - if other == nil { - return *s - } - var diff Stats - diff.FreePageN = s.FreePageN - diff.PendingPageN = s.PendingPageN - diff.FreeAlloc = s.FreeAlloc - diff.FreelistInuse = s.FreelistInuse - diff.TxN = s.TxN - other.TxN - diff.TxStats = s.TxStats.Sub(&other.TxStats) - return diff -} - -func (s *Stats) add(other *Stats) { - s.TxStats.add(&other.TxStats) -} - -type Info struct { - Data uintptr - PageSize int -} - -type meta struct { - magic uint32 - version uint32 - pageSize uint32 - flags uint32 - root bucket - freelist pgid - pgid pgid - txid txid - checksum uint64 -} - -// validate checks the marker bytes and version of the meta page to ensure it matches this binary. -func (m *meta) validate() error { - if m.magic != magic { - return ErrInvalid - } else if m.version != version { - return ErrVersionMismatch - } else if m.checksum != 0 && m.checksum != m.sum64() { - return ErrChecksum - } - return nil -} - -// copy copies one meta object to another. -func (m *meta) copy(dest *meta) { - *dest = *m -} - -// write writes the meta onto a page. -func (m *meta) write(p *page) { - if m.root.root >= m.pgid { - panic(fmt.Sprintf("root bucket pgid (%d) above high water mark (%d)", m.root.root, m.pgid)) - } else if m.freelist >= m.pgid { - panic(fmt.Sprintf("freelist pgid (%d) above high water mark (%d)", m.freelist, m.pgid)) - } - - // Page id is either going to be 0 or 1 which we can determine by the transaction ID. - p.id = pgid(m.txid % 2) - p.flags |= metaPageFlag - - // Calculate the checksum. - m.checksum = m.sum64() - - m.copy(p.meta()) -} - -// generates the checksum for the meta. -func (m *meta) sum64() uint64 { - var h = fnv.New64a() - _, _ = h.Write((*[unsafe.Offsetof(meta{}.checksum)]byte)(unsafe.Pointer(m))[:]) - return h.Sum64() -} - -// _assert will panic with a given formatted message if the given condition is false. -func _assert(condition bool, msg string, v ...interface{}) { - if !condition { - panic(fmt.Sprintf("assertion failed: "+msg, v...)) - } -} - -func warn(v ...interface{}) { fmt.Fprintln(os.Stderr, v...) } -func warnf(msg string, v ...interface{}) { fmt.Fprintf(os.Stderr, msg+"\n", v...) } - -func printstack() { - stack := strings.Join(strings.Split(string(debug.Stack()), "\n")[2:], "\n") - fmt.Fprintln(os.Stderr, stack) -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db_test.go deleted file mode 100644 index 74ff93a..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/db_test.go +++ /dev/null @@ -1,1706 +0,0 @@ -package bolt_test - -import ( - "bytes" - "encoding/binary" - "errors" - "flag" - "fmt" - "hash/fnv" - "io/ioutil" - "log" - "os" - "path/filepath" - "regexp" - "runtime" - "sort" - "strings" - "sync" - "testing" - "time" - "unsafe" - - "github.com/boltdb/bolt" -) - -var statsFlag = flag.Bool("stats", false, "show performance stats") - -// version is the data file format version. -const version = 2 - -// magic is the marker value to indicate that a file is a Bolt DB. -const magic uint32 = 0xED0CDAED - -// pageSize is the size of one page in the data file. -const pageSize = 4096 - -// pageHeaderSize is the size of a page header. -const pageHeaderSize = 16 - -// meta represents a simplified version of a database meta page for testing. -type meta struct { - magic uint32 - version uint32 - _ uint32 - _ uint32 - _ [16]byte - _ uint64 - pgid uint64 - _ uint64 - checksum uint64 -} - -// Ensure that a database can be opened without error. -func TestOpen(t *testing.T) { - path := tempfile() - db, err := bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } else if db == nil { - t.Fatal("expected db") - } - - if s := db.Path(); s != path { - t.Fatalf("unexpected path: %s", s) - } - - if err := db.Close(); err != nil { - t.Fatal(err) - } -} - -// Ensure that opening a database with a blank path returns an error. -func TestOpen_ErrPathRequired(t *testing.T) { - _, err := bolt.Open("", 0666, nil) - if err == nil { - t.Fatalf("expected error") - } -} - -// Ensure that opening a database with a bad path returns an error. -func TestOpen_ErrNotExists(t *testing.T) { - _, err := bolt.Open(filepath.Join(tempfile(), "bad-path"), 0666, nil) - if err == nil { - t.Fatal("expected error") - } -} - -// Ensure that opening a file that is not a Bolt database returns ErrInvalid. -func TestOpen_ErrInvalid(t *testing.T) { - path := tempfile() - - f, err := os.Create(path) - if err != nil { - t.Fatal(err) - } - if _, err := fmt.Fprintln(f, "this is not a bolt database"); err != nil { - t.Fatal(err) - } - if err := f.Close(); err != nil { - t.Fatal(err) - } - defer os.Remove(path) - - if _, err := bolt.Open(path, 0666, nil); err != bolt.ErrInvalid { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that opening a file with two invalid versions returns ErrVersionMismatch. -func TestOpen_ErrVersionMismatch(t *testing.T) { - if pageSize != os.Getpagesize() { - t.Skip("page size mismatch") - } - - // Create empty database. - db := MustOpenDB() - path := db.Path() - defer db.MustClose() - - // Close database. - if err := db.DB.Close(); err != nil { - t.Fatal(err) - } - - // Read data file. - buf, err := ioutil.ReadFile(path) - if err != nil { - t.Fatal(err) - } - - // Rewrite meta pages. - meta0 := (*meta)(unsafe.Pointer(&buf[pageHeaderSize])) - meta0.version++ - meta1 := (*meta)(unsafe.Pointer(&buf[pageSize+pageHeaderSize])) - meta1.version++ - if err := ioutil.WriteFile(path, buf, 0666); err != nil { - t.Fatal(err) - } - - // Reopen data file. - if _, err := bolt.Open(path, 0666, nil); err != bolt.ErrVersionMismatch { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that opening a file with two invalid checksums returns ErrChecksum. -func TestOpen_ErrChecksum(t *testing.T) { - if pageSize != os.Getpagesize() { - t.Skip("page size mismatch") - } - - // Create empty database. - db := MustOpenDB() - path := db.Path() - defer db.MustClose() - - // Close database. - if err := db.DB.Close(); err != nil { - t.Fatal(err) - } - - // Read data file. - buf, err := ioutil.ReadFile(path) - if err != nil { - t.Fatal(err) - } - - // Rewrite meta pages. - meta0 := (*meta)(unsafe.Pointer(&buf[pageHeaderSize])) - meta0.pgid++ - meta1 := (*meta)(unsafe.Pointer(&buf[pageSize+pageHeaderSize])) - meta1.pgid++ - if err := ioutil.WriteFile(path, buf, 0666); err != nil { - t.Fatal(err) - } - - // Reopen data file. - if _, err := bolt.Open(path, 0666, nil); err != bolt.ErrChecksum { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that opening an already open database file will timeout. -func TestOpen_Timeout(t *testing.T) { - if runtime.GOOS == "solaris" { - t.Skip("solaris fcntl locks don't support intra-process locking") - } - - path := tempfile() - - // Open a data file. - db0, err := bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } else if db0 == nil { - t.Fatal("expected database") - } - - // Attempt to open the database again. - start := time.Now() - db1, err := bolt.Open(path, 0666, &bolt.Options{Timeout: 100 * time.Millisecond}) - if err != bolt.ErrTimeout { - t.Fatalf("unexpected timeout: %s", err) - } else if db1 != nil { - t.Fatal("unexpected database") - } else if time.Since(start) <= 100*time.Millisecond { - t.Fatal("expected to wait at least timeout duration") - } - - if err := db0.Close(); err != nil { - t.Fatal(err) - } -} - -// Ensure that opening an already open database file will wait until its closed. -func TestOpen_Wait(t *testing.T) { - if runtime.GOOS == "solaris" { - t.Skip("solaris fcntl locks don't support intra-process locking") - } - - path := tempfile() - - // Open a data file. - db0, err := bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } - - // Close it in just a bit. - time.AfterFunc(100*time.Millisecond, func() { _ = db0.Close() }) - - // Attempt to open the database again. - start := time.Now() - db1, err := bolt.Open(path, 0666, &bolt.Options{Timeout: 200 * time.Millisecond}) - if err != nil { - t.Fatal(err) - } else if time.Since(start) <= 100*time.Millisecond { - t.Fatal("expected to wait at least timeout duration") - } - - if err := db1.Close(); err != nil { - t.Fatal(err) - } -} - -// Ensure that opening a database does not increase its size. -// https://github.com/boltdb/bolt/issues/291 -func TestOpen_Size(t *testing.T) { - // Open a data file. - db := MustOpenDB() - path := db.Path() - defer db.MustClose() - - pagesize := db.Info().PageSize - - // Insert until we get above the minimum 4MB size. - if err := db.Update(func(tx *bolt.Tx) error { - b, _ := tx.CreateBucketIfNotExists([]byte("data")) - for i := 0; i < 10000; i++ { - if err := b.Put([]byte(fmt.Sprintf("%04d", i)), make([]byte, 1000)); err != nil { - t.Fatal(err) - } - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Close database and grab the size. - if err := db.DB.Close(); err != nil { - t.Fatal(err) - } - sz := fileSize(path) - if sz == 0 { - t.Fatalf("unexpected new file size: %d", sz) - } - - // Reopen database, update, and check size again. - db0, err := bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } - if err := db0.Update(func(tx *bolt.Tx) error { - if err := tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0}); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - if err := db0.Close(); err != nil { - t.Fatal(err) - } - newSz := fileSize(path) - if newSz == 0 { - t.Fatalf("unexpected new file size: %d", newSz) - } - - // Compare the original size with the new size. - // db size might increase by a few page sizes due to the new small update. - if sz < newSz-5*int64(pagesize) { - t.Fatalf("unexpected file growth: %d => %d", sz, newSz) - } -} - -// Ensure that opening a database beyond the max step size does not increase its size. -// https://github.com/boltdb/bolt/issues/303 -func TestOpen_Size_Large(t *testing.T) { - if testing.Short() { - t.Skip("short mode") - } - - // Open a data file. - db := MustOpenDB() - path := db.Path() - defer db.MustClose() - - pagesize := db.Info().PageSize - - // Insert until we get above the minimum 4MB size. - var index uint64 - for i := 0; i < 10000; i++ { - if err := db.Update(func(tx *bolt.Tx) error { - b, _ := tx.CreateBucketIfNotExists([]byte("data")) - for j := 0; j < 1000; j++ { - if err := b.Put(u64tob(index), make([]byte, 50)); err != nil { - t.Fatal(err) - } - index++ - } - return nil - }); err != nil { - t.Fatal(err) - } - } - - // Close database and grab the size. - if err := db.DB.Close(); err != nil { - t.Fatal(err) - } - sz := fileSize(path) - if sz == 0 { - t.Fatalf("unexpected new file size: %d", sz) - } else if sz < (1 << 30) { - t.Fatalf("expected larger initial size: %d", sz) - } - - // Reopen database, update, and check size again. - db0, err := bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } - if err := db0.Update(func(tx *bolt.Tx) error { - return tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0}) - }); err != nil { - t.Fatal(err) - } - if err := db0.Close(); err != nil { - t.Fatal(err) - } - - newSz := fileSize(path) - if newSz == 0 { - t.Fatalf("unexpected new file size: %d", newSz) - } - - // Compare the original size with the new size. - // db size might increase by a few page sizes due to the new small update. - if sz < newSz-5*int64(pagesize) { - t.Fatalf("unexpected file growth: %d => %d", sz, newSz) - } -} - -// Ensure that a re-opened database is consistent. -func TestOpen_Check(t *testing.T) { - path := tempfile() - - db, err := bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } - if err := db.View(func(tx *bolt.Tx) error { return <-tx.Check() }); err != nil { - t.Fatal(err) - } - if err := db.Close(); err != nil { - t.Fatal(err) - } - - db, err = bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } - if err := db.View(func(tx *bolt.Tx) error { return <-tx.Check() }); err != nil { - t.Fatal(err) - } - if err := db.Close(); err != nil { - t.Fatal(err) - } -} - -// Ensure that write errors to the meta file handler during initialization are returned. -func TestOpen_MetaInitWriteError(t *testing.T) { - t.Skip("pending") -} - -// Ensure that a database that is too small returns an error. -func TestOpen_FileTooSmall(t *testing.T) { - path := tempfile() - - db, err := bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } - if err := db.Close(); err != nil { - t.Fatal(err) - } - - // corrupt the database - if err := os.Truncate(path, int64(os.Getpagesize())); err != nil { - t.Fatal(err) - } - - db, err = bolt.Open(path, 0666, nil) - if err == nil || err.Error() != "file size too small" { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that a database can be opened in read-only mode by multiple processes -// and that a database can not be opened in read-write mode and in read-only -// mode at the same time. -func TestOpen_ReadOnly(t *testing.T) { - if runtime.GOOS == "solaris" { - t.Skip("solaris fcntl locks don't support intra-process locking") - } - - bucket, key, value := []byte(`bucket`), []byte(`key`), []byte(`value`) - - path := tempfile() - - // Open in read-write mode. - db, err := bolt.Open(path, 0666, nil) - if err != nil { - t.Fatal(err) - } else if db.IsReadOnly() { - t.Fatal("db should not be in read only mode") - } - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket(bucket) - if err != nil { - return err - } - if err := b.Put(key, value); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - if err := db.Close(); err != nil { - t.Fatal(err) - } - - // Open in read-only mode. - db0, err := bolt.Open(path, 0666, &bolt.Options{ReadOnly: true}) - if err != nil { - t.Fatal(err) - } - - // Opening in read-write mode should return an error. - if _, err = bolt.Open(path, 0666, &bolt.Options{Timeout: time.Millisecond * 100}); err == nil { - t.Fatal("expected error") - } - - // And again (in read-only mode). - db1, err := bolt.Open(path, 0666, &bolt.Options{ReadOnly: true}) - if err != nil { - t.Fatal(err) - } - - // Verify both read-only databases are accessible. - for _, db := range []*bolt.DB{db0, db1} { - // Verify is is in read only mode indeed. - if !db.IsReadOnly() { - t.Fatal("expected read only mode") - } - - // Read-only databases should not allow updates. - if err := db.Update(func(*bolt.Tx) error { - panic(`should never get here`) - }); err != bolt.ErrDatabaseReadOnly { - t.Fatalf("unexpected error: %s", err) - } - - // Read-only databases should not allow beginning writable txns. - if _, err := db.Begin(true); err != bolt.ErrDatabaseReadOnly { - t.Fatalf("unexpected error: %s", err) - } - - // Verify the data. - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket(bucket) - if b == nil { - return fmt.Errorf("expected bucket `%s`", string(bucket)) - } - - got := string(b.Get(key)) - expected := string(value) - if got != expected { - return fmt.Errorf("expected `%s`, got `%s`", expected, got) - } - return nil - }); err != nil { - t.Fatal(err) - } - } - - if err := db0.Close(); err != nil { - t.Fatal(err) - } - if err := db1.Close(); err != nil { - t.Fatal(err) - } -} - -// TestDB_Open_InitialMmapSize tests if having InitialMmapSize large enough -// to hold data from concurrent write transaction resolves the issue that -// read transaction blocks the write transaction and causes deadlock. -// This is a very hacky test since the mmap size is not exposed. -func TestDB_Open_InitialMmapSize(t *testing.T) { - path := tempfile() - defer os.Remove(path) - - initMmapSize := 1 << 31 // 2GB - testWriteSize := 1 << 27 // 134MB - - db, err := bolt.Open(path, 0666, &bolt.Options{InitialMmapSize: initMmapSize}) - if err != nil { - t.Fatal(err) - } - - // create a long-running read transaction - // that never gets closed while writing - rtx, err := db.Begin(false) - if err != nil { - t.Fatal(err) - } - - // create a write transaction - wtx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - - b, err := wtx.CreateBucket([]byte("test")) - if err != nil { - t.Fatal(err) - } - - // and commit a large write - err = b.Put([]byte("foo"), make([]byte, testWriteSize)) - if err != nil { - t.Fatal(err) - } - - done := make(chan struct{}) - - go func() { - if err := wtx.Commit(); err != nil { - t.Fatal(err) - } - done <- struct{}{} - }() - - select { - case <-time.After(5 * time.Second): - t.Errorf("unexpected that the reader blocks writer") - case <-done: - } - - if err := rtx.Rollback(); err != nil { - t.Fatal(err) - } -} - -// Ensure that a database cannot open a transaction when it's not open. -func TestDB_Begin_ErrDatabaseNotOpen(t *testing.T) { - var db bolt.DB - if _, err := db.Begin(false); err != bolt.ErrDatabaseNotOpen { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that a read-write transaction can be retrieved. -func TestDB_BeginRW(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } else if tx == nil { - t.Fatal("expected tx") - } - - if tx.DB() != db.DB { - t.Fatal("unexpected tx database") - } else if !tx.Writable() { - t.Fatal("expected writable tx") - } - - if err := tx.Commit(); err != nil { - t.Fatal(err) - } -} - -// Ensure that opening a transaction while the DB is closed returns an error. -func TestDB_BeginRW_Closed(t *testing.T) { - var db bolt.DB - if _, err := db.Begin(true); err != bolt.ErrDatabaseNotOpen { - t.Fatalf("unexpected error: %s", err) - } -} - -func TestDB_Close_PendingTx_RW(t *testing.T) { testDB_Close_PendingTx(t, true) } -func TestDB_Close_PendingTx_RO(t *testing.T) { testDB_Close_PendingTx(t, false) } - -// Ensure that a database cannot close while transactions are open. -func testDB_Close_PendingTx(t *testing.T, writable bool) { - db := MustOpenDB() - defer db.MustClose() - - // Start transaction. - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - - // Open update in separate goroutine. - done := make(chan struct{}) - go func() { - if err := db.Close(); err != nil { - t.Fatal(err) - } - close(done) - }() - - // Ensure database hasn't closed. - time.Sleep(100 * time.Millisecond) - select { - case <-done: - t.Fatal("database closed too early") - default: - } - - // Commit transaction. - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - - // Ensure database closed now. - time.Sleep(100 * time.Millisecond) - select { - case <-done: - default: - t.Fatal("database did not close") - } -} - -// Ensure a database can provide a transactional block. -func TestDB_Update(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte("bat")); err != nil { - t.Fatal(err) - } - if err := b.Delete([]byte("foo")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - if v := b.Get([]byte("foo")); v != nil { - t.Fatalf("expected nil value, got: %v", v) - } - if v := b.Get([]byte("baz")); !bytes.Equal(v, []byte("bat")) { - t.Fatalf("unexpected value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a closed database returns an error while running a transaction block -func TestDB_Update_Closed(t *testing.T) { - var db bolt.DB - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != bolt.ErrDatabaseNotOpen { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure a panic occurs while trying to commit a managed transaction. -func TestDB_Update_ManualCommit(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var panicked bool - if err := db.Update(func(tx *bolt.Tx) error { - func() { - defer func() { - if r := recover(); r != nil { - panicked = true - } - }() - - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - }() - return nil - }); err != nil { - t.Fatal(err) - } else if !panicked { - t.Fatal("expected panic") - } -} - -// Ensure a panic occurs while trying to rollback a managed transaction. -func TestDB_Update_ManualRollback(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var panicked bool - if err := db.Update(func(tx *bolt.Tx) error { - func() { - defer func() { - if r := recover(); r != nil { - panicked = true - } - }() - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - }() - return nil - }); err != nil { - t.Fatal(err) - } else if !panicked { - t.Fatal("expected panic") - } -} - -// Ensure a panic occurs while trying to commit a managed transaction. -func TestDB_View_ManualCommit(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var panicked bool - if err := db.View(func(tx *bolt.Tx) error { - func() { - defer func() { - if r := recover(); r != nil { - panicked = true - } - }() - - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - }() - return nil - }); err != nil { - t.Fatal(err) - } else if !panicked { - t.Fatal("expected panic") - } -} - -// Ensure a panic occurs while trying to rollback a managed transaction. -func TestDB_View_ManualRollback(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var panicked bool - if err := db.View(func(tx *bolt.Tx) error { - func() { - defer func() { - if r := recover(); r != nil { - panicked = true - } - }() - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - }() - return nil - }); err != nil { - t.Fatal(err) - } else if !panicked { - t.Fatal("expected panic") - } -} - -// Ensure a write transaction that panics does not hold open locks. -func TestDB_Update_Panic(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - // Panic during update but recover. - func() { - defer func() { - if r := recover(); r != nil { - t.Log("recover: update", r) - } - }() - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - panic("omg") - }); err != nil { - t.Fatal(err) - } - }() - - // Verify we can update again. - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Verify that our change persisted. - if err := db.Update(func(tx *bolt.Tx) error { - if tx.Bucket([]byte("widgets")) == nil { - t.Fatal("expected bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure a database can return an error through a read-only transactional block. -func TestDB_View_Error(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.View(func(tx *bolt.Tx) error { - return errors.New("xxx") - }); err == nil || err.Error() != "xxx" { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure a read transaction that panics does not hold open locks. -func TestDB_View_Panic(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Panic during view transaction but recover. - func() { - defer func() { - if r := recover(); r != nil { - t.Log("recover: view", r) - } - }() - - if err := db.View(func(tx *bolt.Tx) error { - if tx.Bucket([]byte("widgets")) == nil { - t.Fatal("expected bucket") - } - panic("omg") - }); err != nil { - t.Fatal(err) - } - }() - - // Verify that we can still use read transactions. - if err := db.View(func(tx *bolt.Tx) error { - if tx.Bucket([]byte("widgets")) == nil { - t.Fatal("expected bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that DB stats can be returned. -func TestDB_Stats(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - t.Fatal(err) - } - - stats := db.Stats() - if stats.TxStats.PageCount != 2 { - t.Fatalf("unexpected TxStats.PageCount: %d", stats.TxStats.PageCount) - } else if stats.FreePageN != 0 { - t.Fatalf("unexpected FreePageN != 0: %d", stats.FreePageN) - } else if stats.PendingPageN != 2 { - t.Fatalf("unexpected PendingPageN != 2: %d", stats.PendingPageN) - } -} - -// Ensure that database pages are in expected order and type. -func TestDB_Consistency(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - t.Fatal(err) - } - - for i := 0; i < 10; i++ { - if err := db.Update(func(tx *bolt.Tx) error { - if err := tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - } - - if err := db.Update(func(tx *bolt.Tx) error { - if p, _ := tx.Page(0); p == nil { - t.Fatal("expected page") - } else if p.Type != "meta" { - t.Fatalf("unexpected page type: %s", p.Type) - } - - if p, _ := tx.Page(1); p == nil { - t.Fatal("expected page") - } else if p.Type != "meta" { - t.Fatalf("unexpected page type: %s", p.Type) - } - - if p, _ := tx.Page(2); p == nil { - t.Fatal("expected page") - } else if p.Type != "free" { - t.Fatalf("unexpected page type: %s", p.Type) - } - - if p, _ := tx.Page(3); p == nil { - t.Fatal("expected page") - } else if p.Type != "free" { - t.Fatalf("unexpected page type: %s", p.Type) - } - - if p, _ := tx.Page(4); p == nil { - t.Fatal("expected page") - } else if p.Type != "leaf" { - t.Fatalf("unexpected page type: %s", p.Type) - } - - if p, _ := tx.Page(5); p == nil { - t.Fatal("expected page") - } else if p.Type != "freelist" { - t.Fatalf("unexpected page type: %s", p.Type) - } - - if p, _ := tx.Page(6); p != nil { - t.Fatal("unexpected page") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that DB stats can be subtracted from one another. -func TestDBStats_Sub(t *testing.T) { - var a, b bolt.Stats - a.TxStats.PageCount = 3 - a.FreePageN = 4 - b.TxStats.PageCount = 10 - b.FreePageN = 14 - diff := b.Sub(&a) - if diff.TxStats.PageCount != 7 { - t.Fatalf("unexpected TxStats.PageCount: %d", diff.TxStats.PageCount) - } - - // free page stats are copied from the receiver and not subtracted - if diff.FreePageN != 14 { - t.Fatalf("unexpected FreePageN: %d", diff.FreePageN) - } -} - -// Ensure two functions can perform updates in a single batch. -func TestDB_Batch(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Iterate over multiple updates in separate goroutines. - n := 2 - ch := make(chan error) - for i := 0; i < n; i++ { - go func(i int) { - ch <- db.Batch(func(tx *bolt.Tx) error { - return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{}) - }) - }(i) - } - - // Check all responses to make sure there's no error. - for i := 0; i < n; i++ { - if err := <-ch; err != nil { - t.Fatal(err) - } - } - - // Ensure data is correct. - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for i := 0; i < n; i++ { - if v := b.Get(u64tob(uint64(i))); v == nil { - t.Errorf("key not found: %d", i) - } - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -func TestDB_Batch_Panic(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var sentinel int - var bork = &sentinel - var problem interface{} - var err error - - // Execute a function inside a batch that panics. - func() { - defer func() { - if p := recover(); p != nil { - problem = p - } - }() - err = db.Batch(func(tx *bolt.Tx) error { - panic(bork) - }) - }() - - // Verify there is no error. - if g, e := err, error(nil); g != e { - t.Fatalf("wrong error: %v != %v", g, e) - } - // Verify the panic was captured. - if g, e := problem, bork; g != e { - t.Fatalf("wrong error: %v != %v", g, e) - } -} - -func TestDB_BatchFull(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - t.Fatal(err) - } - - const size = 3 - // buffered so we never leak goroutines - ch := make(chan error, size) - put := func(i int) { - ch <- db.Batch(func(tx *bolt.Tx) error { - return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{}) - }) - } - - db.MaxBatchSize = size - // high enough to never trigger here - db.MaxBatchDelay = 1 * time.Hour - - go put(1) - go put(2) - - // Give the batch a chance to exhibit bugs. - time.Sleep(10 * time.Millisecond) - - // not triggered yet - select { - case <-ch: - t.Fatalf("batch triggered too early") - default: - } - - go put(3) - - // Check all responses to make sure there's no error. - for i := 0; i < size; i++ { - if err := <-ch; err != nil { - t.Fatal(err) - } - } - - // Ensure data is correct. - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for i := 1; i <= size; i++ { - if v := b.Get(u64tob(uint64(i))); v == nil { - t.Errorf("key not found: %d", i) - } - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -func TestDB_BatchTime(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - t.Fatal(err) - } - - const size = 1 - // buffered so we never leak goroutines - ch := make(chan error, size) - put := func(i int) { - ch <- db.Batch(func(tx *bolt.Tx) error { - return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{}) - }) - } - - db.MaxBatchSize = 1000 - db.MaxBatchDelay = 0 - - go put(1) - - // Batch must trigger by time alone. - - // Check all responses to make sure there's no error. - for i := 0; i < size; i++ { - if err := <-ch; err != nil { - t.Fatal(err) - } - } - - // Ensure data is correct. - if err := db.View(func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("widgets")) - for i := 1; i <= size; i++ { - if v := b.Get(u64tob(uint64(i))); v == nil { - t.Errorf("key not found: %d", i) - } - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -func ExampleDB_Update() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Execute several commands within a read-write transaction. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - return err - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - return err - } - return nil - }); err != nil { - log.Fatal(err) - } - - // Read the value back from a separate read-only transaction. - if err := db.View(func(tx *bolt.Tx) error { - value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) - fmt.Printf("The value of 'foo' is: %s\n", value) - return nil - }); err != nil { - log.Fatal(err) - } - - // Close database to release the file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // The value of 'foo' is: bar -} - -func ExampleDB_View() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Insert data into a bucket. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("people")) - if err != nil { - return err - } - if err := b.Put([]byte("john"), []byte("doe")); err != nil { - return err - } - if err := b.Put([]byte("susy"), []byte("que")); err != nil { - return err - } - return nil - }); err != nil { - log.Fatal(err) - } - - // Access data from within a read-only transactional block. - if err := db.View(func(tx *bolt.Tx) error { - v := tx.Bucket([]byte("people")).Get([]byte("john")) - fmt.Printf("John's last name is %s.\n", v) - return nil - }); err != nil { - log.Fatal(err) - } - - // Close database to release the file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // John's last name is doe. -} - -func ExampleDB_Begin_ReadOnly() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Create a bucket using a read-write transaction. - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - log.Fatal(err) - } - - // Create several keys in a transaction. - tx, err := db.Begin(true) - if err != nil { - log.Fatal(err) - } - b := tx.Bucket([]byte("widgets")) - if err := b.Put([]byte("john"), []byte("blue")); err != nil { - log.Fatal(err) - } - if err := b.Put([]byte("abby"), []byte("red")); err != nil { - log.Fatal(err) - } - if err := b.Put([]byte("zephyr"), []byte("purple")); err != nil { - log.Fatal(err) - } - if err := tx.Commit(); err != nil { - log.Fatal(err) - } - - // Iterate over the values in sorted key order. - tx, err = db.Begin(false) - if err != nil { - log.Fatal(err) - } - c := tx.Bucket([]byte("widgets")).Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - fmt.Printf("%s likes %s\n", k, v) - } - - if err := tx.Rollback(); err != nil { - log.Fatal(err) - } - - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // abby likes red - // john likes blue - // zephyr likes purple -} - -func BenchmarkDBBatchAutomatic(b *testing.B) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("bench")) - return err - }); err != nil { - b.Fatal(err) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - start := make(chan struct{}) - var wg sync.WaitGroup - - for round := 0; round < 1000; round++ { - wg.Add(1) - - go func(id uint32) { - defer wg.Done() - <-start - - h := fnv.New32a() - buf := make([]byte, 4) - binary.LittleEndian.PutUint32(buf, id) - _, _ = h.Write(buf[:]) - k := h.Sum(nil) - insert := func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("bench")) - return b.Put(k, []byte("filler")) - } - if err := db.Batch(insert); err != nil { - b.Error(err) - return - } - }(uint32(round)) - } - close(start) - wg.Wait() - } - - b.StopTimer() - validateBatchBench(b, db) -} - -func BenchmarkDBBatchSingle(b *testing.B) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("bench")) - return err - }); err != nil { - b.Fatal(err) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - start := make(chan struct{}) - var wg sync.WaitGroup - - for round := 0; round < 1000; round++ { - wg.Add(1) - go func(id uint32) { - defer wg.Done() - <-start - - h := fnv.New32a() - buf := make([]byte, 4) - binary.LittleEndian.PutUint32(buf, id) - _, _ = h.Write(buf[:]) - k := h.Sum(nil) - insert := func(tx *bolt.Tx) error { - b := tx.Bucket([]byte("bench")) - return b.Put(k, []byte("filler")) - } - if err := db.Update(insert); err != nil { - b.Error(err) - return - } - }(uint32(round)) - } - close(start) - wg.Wait() - } - - b.StopTimer() - validateBatchBench(b, db) -} - -func BenchmarkDBBatchManual10x100(b *testing.B) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("bench")) - return err - }); err != nil { - b.Fatal(err) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - start := make(chan struct{}) - var wg sync.WaitGroup - - for major := 0; major < 10; major++ { - wg.Add(1) - go func(id uint32) { - defer wg.Done() - <-start - - insert100 := func(tx *bolt.Tx) error { - h := fnv.New32a() - buf := make([]byte, 4) - for minor := uint32(0); minor < 100; minor++ { - binary.LittleEndian.PutUint32(buf, uint32(id*100+minor)) - h.Reset() - _, _ = h.Write(buf[:]) - k := h.Sum(nil) - b := tx.Bucket([]byte("bench")) - if err := b.Put(k, []byte("filler")); err != nil { - return err - } - } - return nil - } - if err := db.Update(insert100); err != nil { - b.Fatal(err) - } - }(uint32(major)) - } - close(start) - wg.Wait() - } - - b.StopTimer() - validateBatchBench(b, db) -} - -func validateBatchBench(b *testing.B, db *DB) { - var rollback = errors.New("sentinel error to cause rollback") - validate := func(tx *bolt.Tx) error { - bucket := tx.Bucket([]byte("bench")) - h := fnv.New32a() - buf := make([]byte, 4) - for id := uint32(0); id < 1000; id++ { - binary.LittleEndian.PutUint32(buf, id) - h.Reset() - _, _ = h.Write(buf[:]) - k := h.Sum(nil) - v := bucket.Get(k) - if v == nil { - b.Errorf("not found id=%d key=%x", id, k) - continue - } - if g, e := v, []byte("filler"); !bytes.Equal(g, e) { - b.Errorf("bad value for id=%d key=%x: %s != %q", id, k, g, e) - } - if err := bucket.Delete(k); err != nil { - return err - } - } - // should be empty now - c := bucket.Cursor() - for k, v := c.First(); k != nil; k, v = c.Next() { - b.Errorf("unexpected key: %x = %q", k, v) - } - return rollback - } - if err := db.Update(validate); err != nil && err != rollback { - b.Error(err) - } -} - -// DB is a test wrapper for bolt.DB. -type DB struct { - *bolt.DB -} - -// MustOpenDB returns a new, open DB at a temporary location. -func MustOpenDB() *DB { - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - panic(err) - } - return &DB{db} -} - -// Close closes the database and deletes the underlying file. -func (db *DB) Close() error { - // Log statistics. - if *statsFlag { - db.PrintStats() - } - - // Check database consistency after every test. - db.MustCheck() - - // Close database and remove file. - defer os.Remove(db.Path()) - return db.DB.Close() -} - -// MustClose closes the database and deletes the underlying file. Panic on error. -func (db *DB) MustClose() { - if err := db.Close(); err != nil { - panic(err) - } -} - -// PrintStats prints the database stats -func (db *DB) PrintStats() { - var stats = db.Stats() - fmt.Printf("[db] %-20s %-20s %-20s\n", - fmt.Sprintf("pg(%d/%d)", stats.TxStats.PageCount, stats.TxStats.PageAlloc), - fmt.Sprintf("cur(%d)", stats.TxStats.CursorCount), - fmt.Sprintf("node(%d/%d)", stats.TxStats.NodeCount, stats.TxStats.NodeDeref), - ) - fmt.Printf(" %-20s %-20s %-20s\n", - fmt.Sprintf("rebal(%d/%v)", stats.TxStats.Rebalance, truncDuration(stats.TxStats.RebalanceTime)), - fmt.Sprintf("spill(%d/%v)", stats.TxStats.Spill, truncDuration(stats.TxStats.SpillTime)), - fmt.Sprintf("w(%d/%v)", stats.TxStats.Write, truncDuration(stats.TxStats.WriteTime)), - ) -} - -// MustCheck runs a consistency check on the database and panics if any errors are found. -func (db *DB) MustCheck() { - if err := db.Update(func(tx *bolt.Tx) error { - // Collect all the errors. - var errors []error - for err := range tx.Check() { - errors = append(errors, err) - if len(errors) > 10 { - break - } - } - - // If errors occurred, copy the DB and print the errors. - if len(errors) > 0 { - var path = tempfile() - if err := tx.CopyFile(path, 0600); err != nil { - panic(err) - } - - // Print errors. - fmt.Print("\n\n") - fmt.Printf("consistency check failed (%d errors)\n", len(errors)) - for _, err := range errors { - fmt.Println(err) - } - fmt.Println("") - fmt.Println("db saved to:") - fmt.Println(path) - fmt.Print("\n\n") - os.Exit(-1) - } - - return nil - }); err != nil && err != bolt.ErrDatabaseNotOpen { - panic(err) - } -} - -// CopyTempFile copies a database to a temporary file. -func (db *DB) CopyTempFile() { - path := tempfile() - if err := db.View(func(tx *bolt.Tx) error { - return tx.CopyFile(path, 0600) - }); err != nil { - panic(err) - } - fmt.Println("db copied to: ", path) -} - -// tempfile returns a temporary file path. -func tempfile() string { - f, err := ioutil.TempFile("", "bolt-") - if err != nil { - panic(err) - } - if err := f.Close(); err != nil { - panic(err) - } - if err := os.Remove(f.Name()); err != nil { - panic(err) - } - return f.Name() -} - -// mustContainKeys checks that a bucket contains a given set of keys. -func mustContainKeys(b *bolt.Bucket, m map[string]string) { - found := make(map[string]string) - if err := b.ForEach(func(k, _ []byte) error { - found[string(k)] = "" - return nil - }); err != nil { - panic(err) - } - - // Check for keys found in bucket that shouldn't be there. - var keys []string - for k, _ := range found { - if _, ok := m[string(k)]; !ok { - keys = append(keys, k) - } - } - if len(keys) > 0 { - sort.Strings(keys) - panic(fmt.Sprintf("keys found(%d): %s", len(keys), strings.Join(keys, ","))) - } - - // Check for keys not found in bucket that should be there. - for k, _ := range m { - if _, ok := found[string(k)]; !ok { - keys = append(keys, k) - } - } - if len(keys) > 0 { - sort.Strings(keys) - panic(fmt.Sprintf("keys not found(%d): %s", len(keys), strings.Join(keys, ","))) - } -} - -func trunc(b []byte, length int) []byte { - if length < len(b) { - return b[:length] - } - return b -} - -func truncDuration(d time.Duration) string { - return regexp.MustCompile(`^(\d+)(\.\d+)`).ReplaceAllString(d.String(), "$1") -} - -func fileSize(path string) int64 { - fi, err := os.Stat(path) - if err != nil { - return 0 - } - return fi.Size() -} - -func warn(v ...interface{}) { fmt.Fprintln(os.Stderr, v...) } -func warnf(msg string, v ...interface{}) { fmt.Fprintf(os.Stderr, msg+"\n", v...) } - -// u64tob converts a uint64 into an 8-byte slice. -func u64tob(v uint64) []byte { - b := make([]byte, 8) - binary.BigEndian.PutUint64(b, v) - return b -} - -// btou64 converts an 8-byte slice into an uint64. -func btou64(b []byte) uint64 { return binary.BigEndian.Uint64(b) } diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/doc.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/doc.go deleted file mode 100644 index cc93784..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/doc.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Package bolt implements a low-level key/value store in pure Go. It supports -fully serializable transactions, ACID semantics, and lock-free MVCC with -multiple readers and a single writer. Bolt can be used for projects that -want a simple data store without the need to add large dependencies such as -Postgres or MySQL. - -Bolt is a single-level, zero-copy, B+tree data store. This means that Bolt is -optimized for fast read access and does not require recovery in the event of a -system crash. Transactions which have not finished committing will simply be -rolled back in the event of a crash. - -The design of Bolt is based on Howard Chu's LMDB database project. - -Bolt currently works on Windows, Mac OS X, and Linux. - - -Basics - -There are only a few types in Bolt: DB, Bucket, Tx, and Cursor. The DB is -a collection of buckets and is represented by a single file on disk. A bucket is -a collection of unique keys that are associated with values. - -Transactions provide either read-only or read-write access to the database. -Read-only transactions can retrieve key/value pairs and can use Cursors to -iterate over the dataset sequentially. Read-write transactions can create and -delete buckets and can insert and remove keys. Only one read-write transaction -is allowed at a time. - - -Caveats - -The database uses a read-only, memory-mapped data file to ensure that -applications cannot corrupt the database, however, this means that keys and -values returned from Bolt cannot be changed. Writing to a read-only byte slice -will cause Go to panic. - -Keys and values retrieved from the database are only valid for the life of -the transaction. When used outside the transaction, these byte slices can -point to different data or can point to invalid memory which will cause a panic. - - -*/ -package bolt diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/errors.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/errors.go deleted file mode 100644 index a3620a3..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/errors.go +++ /dev/null @@ -1,71 +0,0 @@ -package bolt - -import "errors" - -// These errors can be returned when opening or calling methods on a DB. -var ( - // ErrDatabaseNotOpen is returned when a DB instance is accessed before it - // is opened or after it is closed. - ErrDatabaseNotOpen = errors.New("database not open") - - // ErrDatabaseOpen is returned when opening a database that is - // already open. - ErrDatabaseOpen = errors.New("database already open") - - // ErrInvalid is returned when both meta pages on a database are invalid. - // This typically occurs when a file is not a bolt database. - ErrInvalid = errors.New("invalid database") - - // ErrVersionMismatch is returned when the data file was created with a - // different version of Bolt. - ErrVersionMismatch = errors.New("version mismatch") - - // ErrChecksum is returned when either meta page checksum does not match. - ErrChecksum = errors.New("checksum error") - - // ErrTimeout is returned when a database cannot obtain an exclusive lock - // on the data file after the timeout passed to Open(). - ErrTimeout = errors.New("timeout") -) - -// These errors can occur when beginning or committing a Tx. -var ( - // ErrTxNotWritable is returned when performing a write operation on a - // read-only transaction. - ErrTxNotWritable = errors.New("tx not writable") - - // ErrTxClosed is returned when committing or rolling back a transaction - // that has already been committed or rolled back. - ErrTxClosed = errors.New("tx closed") - - // ErrDatabaseReadOnly is returned when a mutating transaction is started on a - // read-only database. - ErrDatabaseReadOnly = errors.New("database is in read-only mode") -) - -// These errors can occur when putting or deleting a value or a bucket. -var ( - // ErrBucketNotFound is returned when trying to access a bucket that has - // not been created yet. - ErrBucketNotFound = errors.New("bucket not found") - - // ErrBucketExists is returned when creating a bucket that already exists. - ErrBucketExists = errors.New("bucket already exists") - - // ErrBucketNameRequired is returned when creating a bucket with a blank name. - ErrBucketNameRequired = errors.New("bucket name required") - - // ErrKeyRequired is returned when inserting a zero-length key. - ErrKeyRequired = errors.New("key required") - - // ErrKeyTooLarge is returned when inserting a key that is larger than MaxKeySize. - ErrKeyTooLarge = errors.New("key too large") - - // ErrValueTooLarge is returned when inserting a value that is larger than MaxValueSize. - ErrValueTooLarge = errors.New("value too large") - - // ErrIncompatibleValue is returned when trying create or delete a bucket - // on an existing non-bucket key or when trying to create or delete a - // non-bucket key on an existing bucket key. - ErrIncompatibleValue = errors.New("incompatible value") -) diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist.go deleted file mode 100644 index d32f6cd..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist.go +++ /dev/null @@ -1,248 +0,0 @@ -package bolt - -import ( - "fmt" - "sort" - "unsafe" -) - -// freelist represents a list of all pages that are available for allocation. -// It also tracks pages that have been freed but are still in use by open transactions. -type freelist struct { - ids []pgid // all free and available free page ids. - pending map[txid][]pgid // mapping of soon-to-be free page ids by tx. - cache map[pgid]bool // fast lookup of all free and pending page ids. -} - -// newFreelist returns an empty, initialized freelist. -func newFreelist() *freelist { - return &freelist{ - pending: make(map[txid][]pgid), - cache: make(map[pgid]bool), - } -} - -// size returns the size of the page after serialization. -func (f *freelist) size() int { - return pageHeaderSize + (int(unsafe.Sizeof(pgid(0))) * f.count()) -} - -// count returns count of pages on the freelist -func (f *freelist) count() int { - return f.free_count() + f.pending_count() -} - -// free_count returns count of free pages -func (f *freelist) free_count() int { - return len(f.ids) -} - -// pending_count returns count of pending pages -func (f *freelist) pending_count() int { - var count int - for _, list := range f.pending { - count += len(list) - } - return count -} - -// all returns a list of all free ids and all pending ids in one sorted list. -func (f *freelist) all() []pgid { - m := make(pgids, 0) - - for _, list := range f.pending { - m = append(m, list...) - } - - sort.Sort(m) - return pgids(f.ids).merge(m) -} - -// allocate returns the starting page id of a contiguous list of pages of a given size. -// If a contiguous block cannot be found then 0 is returned. -func (f *freelist) allocate(n int) pgid { - if len(f.ids) == 0 { - return 0 - } - - var initial, previd pgid - for i, id := range f.ids { - if id <= 1 { - panic(fmt.Sprintf("invalid page allocation: %d", id)) - } - - // Reset initial page if this is not contiguous. - if previd == 0 || id-previd != 1 { - initial = id - } - - // If we found a contiguous block then remove it and return it. - if (id-initial)+1 == pgid(n) { - // If we're allocating off the beginning then take the fast path - // and just adjust the existing slice. This will use extra memory - // temporarily but the append() in free() will realloc the slice - // as is necessary. - if (i + 1) == n { - f.ids = f.ids[i+1:] - } else { - copy(f.ids[i-n+1:], f.ids[i+1:]) - f.ids = f.ids[:len(f.ids)-n] - } - - // Remove from the free cache. - for i := pgid(0); i < pgid(n); i++ { - delete(f.cache, initial+i) - } - - return initial - } - - previd = id - } - return 0 -} - -// free releases a page and its overflow for a given transaction id. -// If the page is already free then a panic will occur. -func (f *freelist) free(txid txid, p *page) { - if p.id <= 1 { - panic(fmt.Sprintf("cannot free page 0 or 1: %d", p.id)) - } - - // Free page and all its overflow pages. - var ids = f.pending[txid] - for id := p.id; id <= p.id+pgid(p.overflow); id++ { - // Verify that page is not already free. - if f.cache[id] { - panic(fmt.Sprintf("page %d already freed", id)) - } - - // Add to the freelist and cache. - ids = append(ids, id) - f.cache[id] = true - } - f.pending[txid] = ids -} - -// release moves all page ids for a transaction id (or older) to the freelist. -func (f *freelist) release(txid txid) { - m := make(pgids, 0) - for tid, ids := range f.pending { - if tid <= txid { - // Move transaction's pending pages to the available freelist. - // Don't remove from the cache since the page is still free. - m = append(m, ids...) - delete(f.pending, tid) - } - } - sort.Sort(m) - f.ids = pgids(f.ids).merge(m) -} - -// rollback removes the pages from a given pending tx. -func (f *freelist) rollback(txid txid) { - // Remove page ids from cache. - for _, id := range f.pending[txid] { - delete(f.cache, id) - } - - // Remove pages from pending list. - delete(f.pending, txid) -} - -// freed returns whether a given page is in the free list. -func (f *freelist) freed(pgid pgid) bool { - return f.cache[pgid] -} - -// read initializes the freelist from a freelist page. -func (f *freelist) read(p *page) { - // If the page.count is at the max uint16 value (64k) then it's considered - // an overflow and the size of the freelist is stored as the first element. - idx, count := 0, int(p.count) - if count == 0xFFFF { - idx = 1 - count = int(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[0]) - } - - // Copy the list of page ids from the freelist. - if count == 0 { - f.ids = nil - } else { - ids := ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[idx:count] - f.ids = make([]pgid, len(ids)) - copy(f.ids, ids) - - // Make sure they're sorted. - sort.Sort(pgids(f.ids)) - } - - // Rebuild the page cache. - f.reindex() -} - -// write writes the page ids onto a freelist page. All free and pending ids are -// saved to disk since in the event of a program crash, all pending ids will -// become free. -func (f *freelist) write(p *page) error { - // Combine the old free pgids and pgids waiting on an open transaction. - ids := f.all() - - // Update the header flag. - p.flags |= freelistPageFlag - - // The page.count can only hold up to 64k elements so if we overflow that - // number then we handle it by putting the size in the first element. - if len(ids) == 0 { - p.count = uint16(len(ids)) - } else if len(ids) < 0xFFFF { - p.count = uint16(len(ids)) - copy(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[:], ids) - } else { - p.count = 0xFFFF - ((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[0] = pgid(len(ids)) - copy(((*[maxAllocSize]pgid)(unsafe.Pointer(&p.ptr)))[1:], ids) - } - - return nil -} - -// reload reads the freelist from a page and filters out pending items. -func (f *freelist) reload(p *page) { - f.read(p) - - // Build a cache of only pending pages. - pcache := make(map[pgid]bool) - for _, pendingIDs := range f.pending { - for _, pendingID := range pendingIDs { - pcache[pendingID] = true - } - } - - // Check each page in the freelist and build a new available freelist - // with any pages not in the pending lists. - var a []pgid - for _, id := range f.ids { - if !pcache[id] { - a = append(a, id) - } - } - f.ids = a - - // Once the available list is rebuilt then rebuild the free cache so that - // it includes the available and pending free pages. - f.reindex() -} - -// reindex rebuilds the free cache based on available and pending free lists. -func (f *freelist) reindex() { - f.cache = make(map[pgid]bool, len(f.ids)) - for _, id := range f.ids { - f.cache[id] = true - } - for _, pendingIDs := range f.pending { - for _, pendingID := range pendingIDs { - f.cache[pendingID] = true - } - } -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist_test.go deleted file mode 100644 index 4e9b3a8..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/freelist_test.go +++ /dev/null @@ -1,158 +0,0 @@ -package bolt - -import ( - "math/rand" - "reflect" - "sort" - "testing" - "unsafe" -) - -// Ensure that a page is added to a transaction's freelist. -func TestFreelist_free(t *testing.T) { - f := newFreelist() - f.free(100, &page{id: 12}) - if !reflect.DeepEqual([]pgid{12}, f.pending[100]) { - t.Fatalf("exp=%v; got=%v", []pgid{12}, f.pending[100]) - } -} - -// Ensure that a page and its overflow is added to a transaction's freelist. -func TestFreelist_free_overflow(t *testing.T) { - f := newFreelist() - f.free(100, &page{id: 12, overflow: 3}) - if exp := []pgid{12, 13, 14, 15}; !reflect.DeepEqual(exp, f.pending[100]) { - t.Fatalf("exp=%v; got=%v", exp, f.pending[100]) - } -} - -// Ensure that a transaction's free pages can be released. -func TestFreelist_release(t *testing.T) { - f := newFreelist() - f.free(100, &page{id: 12, overflow: 1}) - f.free(100, &page{id: 9}) - f.free(102, &page{id: 39}) - f.release(100) - f.release(101) - if exp := []pgid{9, 12, 13}; !reflect.DeepEqual(exp, f.ids) { - t.Fatalf("exp=%v; got=%v", exp, f.ids) - } - - f.release(102) - if exp := []pgid{9, 12, 13, 39}; !reflect.DeepEqual(exp, f.ids) { - t.Fatalf("exp=%v; got=%v", exp, f.ids) - } -} - -// Ensure that a freelist can find contiguous blocks of pages. -func TestFreelist_allocate(t *testing.T) { - f := &freelist{ids: []pgid{3, 4, 5, 6, 7, 9, 12, 13, 18}} - if id := int(f.allocate(3)); id != 3 { - t.Fatalf("exp=3; got=%v", id) - } - if id := int(f.allocate(1)); id != 6 { - t.Fatalf("exp=6; got=%v", id) - } - if id := int(f.allocate(3)); id != 0 { - t.Fatalf("exp=0; got=%v", id) - } - if id := int(f.allocate(2)); id != 12 { - t.Fatalf("exp=12; got=%v", id) - } - if id := int(f.allocate(1)); id != 7 { - t.Fatalf("exp=7; got=%v", id) - } - if id := int(f.allocate(0)); id != 0 { - t.Fatalf("exp=0; got=%v", id) - } - if id := int(f.allocate(0)); id != 0 { - t.Fatalf("exp=0; got=%v", id) - } - if exp := []pgid{9, 18}; !reflect.DeepEqual(exp, f.ids) { - t.Fatalf("exp=%v; got=%v", exp, f.ids) - } - - if id := int(f.allocate(1)); id != 9 { - t.Fatalf("exp=9; got=%v", id) - } - if id := int(f.allocate(1)); id != 18 { - t.Fatalf("exp=18; got=%v", id) - } - if id := int(f.allocate(1)); id != 0 { - t.Fatalf("exp=0; got=%v", id) - } - if exp := []pgid{}; !reflect.DeepEqual(exp, f.ids) { - t.Fatalf("exp=%v; got=%v", exp, f.ids) - } -} - -// Ensure that a freelist can deserialize from a freelist page. -func TestFreelist_read(t *testing.T) { - // Create a page. - var buf [4096]byte - page := (*page)(unsafe.Pointer(&buf[0])) - page.flags = freelistPageFlag - page.count = 2 - - // Insert 2 page ids. - ids := (*[3]pgid)(unsafe.Pointer(&page.ptr)) - ids[0] = 23 - ids[1] = 50 - - // Deserialize page into a freelist. - f := newFreelist() - f.read(page) - - // Ensure that there are two page ids in the freelist. - if exp := []pgid{23, 50}; !reflect.DeepEqual(exp, f.ids) { - t.Fatalf("exp=%v; got=%v", exp, f.ids) - } -} - -// Ensure that a freelist can serialize into a freelist page. -func TestFreelist_write(t *testing.T) { - // Create a freelist and write it to a page. - var buf [4096]byte - f := &freelist{ids: []pgid{12, 39}, pending: make(map[txid][]pgid)} - f.pending[100] = []pgid{28, 11} - f.pending[101] = []pgid{3} - p := (*page)(unsafe.Pointer(&buf[0])) - if err := f.write(p); err != nil { - t.Fatal(err) - } - - // Read the page back out. - f2 := newFreelist() - f2.read(p) - - // Ensure that the freelist is correct. - // All pages should be present and in reverse order. - if exp := []pgid{3, 11, 12, 28, 39}; !reflect.DeepEqual(exp, f2.ids) { - t.Fatalf("exp=%v; got=%v", exp, f2.ids) - } -} - -func Benchmark_FreelistRelease10K(b *testing.B) { benchmark_FreelistRelease(b, 10000) } -func Benchmark_FreelistRelease100K(b *testing.B) { benchmark_FreelistRelease(b, 100000) } -func Benchmark_FreelistRelease1000K(b *testing.B) { benchmark_FreelistRelease(b, 1000000) } -func Benchmark_FreelistRelease10000K(b *testing.B) { benchmark_FreelistRelease(b, 10000000) } - -func benchmark_FreelistRelease(b *testing.B, size int) { - ids := randomPgids(size) - pending := randomPgids(len(ids) / 400) - b.ResetTimer() - for i := 0; i < b.N; i++ { - f := &freelist{ids: ids, pending: map[txid][]pgid{1: pending}} - f.release(1) - } -} - -func randomPgids(n int) []pgid { - rand.Seed(42) - pgids := make(pgids, n) - for i := range pgids { - pgids[i] = pgid(rand.Int63()) - } - sort.Sort(pgids) - return pgids -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node.go deleted file mode 100644 index 159318b..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node.go +++ /dev/null @@ -1,604 +0,0 @@ -package bolt - -import ( - "bytes" - "fmt" - "sort" - "unsafe" -) - -// node represents an in-memory, deserialized page. -type node struct { - bucket *Bucket - isLeaf bool - unbalanced bool - spilled bool - key []byte - pgid pgid - parent *node - children nodes - inodes inodes -} - -// root returns the top-level node this node is attached to. -func (n *node) root() *node { - if n.parent == nil { - return n - } - return n.parent.root() -} - -// minKeys returns the minimum number of inodes this node should have. -func (n *node) minKeys() int { - if n.isLeaf { - return 1 - } - return 2 -} - -// size returns the size of the node after serialization. -func (n *node) size() int { - sz, elsz := pageHeaderSize, n.pageElementSize() - for i := 0; i < len(n.inodes); i++ { - item := &n.inodes[i] - sz += elsz + len(item.key) + len(item.value) - } - return sz -} - -// sizeLessThan returns true if the node is less than a given size. -// This is an optimization to avoid calculating a large node when we only need -// to know if it fits inside a certain page size. -func (n *node) sizeLessThan(v int) bool { - sz, elsz := pageHeaderSize, n.pageElementSize() - for i := 0; i < len(n.inodes); i++ { - item := &n.inodes[i] - sz += elsz + len(item.key) + len(item.value) - if sz >= v { - return false - } - } - return true -} - -// pageElementSize returns the size of each page element based on the type of node. -func (n *node) pageElementSize() int { - if n.isLeaf { - return leafPageElementSize - } - return branchPageElementSize -} - -// childAt returns the child node at a given index. -func (n *node) childAt(index int) *node { - if n.isLeaf { - panic(fmt.Sprintf("invalid childAt(%d) on a leaf node", index)) - } - return n.bucket.node(n.inodes[index].pgid, n) -} - -// childIndex returns the index of a given child node. -func (n *node) childIndex(child *node) int { - index := sort.Search(len(n.inodes), func(i int) bool { return bytes.Compare(n.inodes[i].key, child.key) != -1 }) - return index -} - -// numChildren returns the number of children. -func (n *node) numChildren() int { - return len(n.inodes) -} - -// nextSibling returns the next node with the same parent. -func (n *node) nextSibling() *node { - if n.parent == nil { - return nil - } - index := n.parent.childIndex(n) - if index >= n.parent.numChildren()-1 { - return nil - } - return n.parent.childAt(index + 1) -} - -// prevSibling returns the previous node with the same parent. -func (n *node) prevSibling() *node { - if n.parent == nil { - return nil - } - index := n.parent.childIndex(n) - if index == 0 { - return nil - } - return n.parent.childAt(index - 1) -} - -// put inserts a key/value. -func (n *node) put(oldKey, newKey, value []byte, pgid pgid, flags uint32) { - if pgid >= n.bucket.tx.meta.pgid { - panic(fmt.Sprintf("pgid (%d) above high water mark (%d)", pgid, n.bucket.tx.meta.pgid)) - } else if len(oldKey) <= 0 { - panic("put: zero-length old key") - } else if len(newKey) <= 0 { - panic("put: zero-length new key") - } - - // Find insertion index. - index := sort.Search(len(n.inodes), func(i int) bool { return bytes.Compare(n.inodes[i].key, oldKey) != -1 }) - - // Add capacity and shift nodes if we don't have an exact match and need to insert. - exact := (len(n.inodes) > 0 && index < len(n.inodes) && bytes.Equal(n.inodes[index].key, oldKey)) - if !exact { - n.inodes = append(n.inodes, inode{}) - copy(n.inodes[index+1:], n.inodes[index:]) - } - - inode := &n.inodes[index] - inode.flags = flags - inode.key = newKey - inode.value = value - inode.pgid = pgid - _assert(len(inode.key) > 0, "put: zero-length inode key") -} - -// del removes a key from the node. -func (n *node) del(key []byte) { - // Find index of key. - index := sort.Search(len(n.inodes), func(i int) bool { return bytes.Compare(n.inodes[i].key, key) != -1 }) - - // Exit if the key isn't found. - if index >= len(n.inodes) || !bytes.Equal(n.inodes[index].key, key) { - return - } - - // Delete inode from the node. - n.inodes = append(n.inodes[:index], n.inodes[index+1:]...) - - // Mark the node as needing rebalancing. - n.unbalanced = true -} - -// read initializes the node from a page. -func (n *node) read(p *page) { - n.pgid = p.id - n.isLeaf = ((p.flags & leafPageFlag) != 0) - n.inodes = make(inodes, int(p.count)) - - for i := 0; i < int(p.count); i++ { - inode := &n.inodes[i] - if n.isLeaf { - elem := p.leafPageElement(uint16(i)) - inode.flags = elem.flags - inode.key = elem.key() - inode.value = elem.value() - } else { - elem := p.branchPageElement(uint16(i)) - inode.pgid = elem.pgid - inode.key = elem.key() - } - _assert(len(inode.key) > 0, "read: zero-length inode key") - } - - // Save first key so we can find the node in the parent when we spill. - if len(n.inodes) > 0 { - n.key = n.inodes[0].key - _assert(len(n.key) > 0, "read: zero-length node key") - } else { - n.key = nil - } -} - -// write writes the items onto one or more pages. -func (n *node) write(p *page) { - // Initialize page. - if n.isLeaf { - p.flags |= leafPageFlag - } else { - p.flags |= branchPageFlag - } - - if len(n.inodes) >= 0xFFFF { - panic(fmt.Sprintf("inode overflow: %d (pgid=%d)", len(n.inodes), p.id)) - } - p.count = uint16(len(n.inodes)) - - // Stop here if there are no items to write. - if p.count == 0 { - return - } - - // Loop over each item and write it to the page. - b := (*[maxAllocSize]byte)(unsafe.Pointer(&p.ptr))[n.pageElementSize()*len(n.inodes):] - for i, item := range n.inodes { - _assert(len(item.key) > 0, "write: zero-length inode key") - - // Write the page element. - if n.isLeaf { - elem := p.leafPageElement(uint16(i)) - elem.pos = uint32(uintptr(unsafe.Pointer(&b[0])) - uintptr(unsafe.Pointer(elem))) - elem.flags = item.flags - elem.ksize = uint32(len(item.key)) - elem.vsize = uint32(len(item.value)) - } else { - elem := p.branchPageElement(uint16(i)) - elem.pos = uint32(uintptr(unsafe.Pointer(&b[0])) - uintptr(unsafe.Pointer(elem))) - elem.ksize = uint32(len(item.key)) - elem.pgid = item.pgid - _assert(elem.pgid != p.id, "write: circular dependency occurred") - } - - // If the length of key+value is larger than the max allocation size - // then we need to reallocate the byte array pointer. - // - // See: https://github.com/boltdb/bolt/pull/335 - klen, vlen := len(item.key), len(item.value) - if len(b) < klen+vlen { - b = (*[maxAllocSize]byte)(unsafe.Pointer(&b[0]))[:] - } - - // Write data for the element to the end of the page. - copy(b[0:], item.key) - b = b[klen:] - copy(b[0:], item.value) - b = b[vlen:] - } - - // DEBUG ONLY: n.dump() -} - -// split breaks up a node into multiple smaller nodes, if appropriate. -// This should only be called from the spill() function. -func (n *node) split(pageSize int) []*node { - var nodes []*node - - node := n - for { - // Split node into two. - a, b := node.splitTwo(pageSize) - nodes = append(nodes, a) - - // If we can't split then exit the loop. - if b == nil { - break - } - - // Set node to b so it gets split on the next iteration. - node = b - } - - return nodes -} - -// splitTwo breaks up a node into two smaller nodes, if appropriate. -// This should only be called from the split() function. -func (n *node) splitTwo(pageSize int) (*node, *node) { - // Ignore the split if the page doesn't have at least enough nodes for - // two pages or if the nodes can fit in a single page. - if len(n.inodes) <= (minKeysPerPage*2) || n.sizeLessThan(pageSize) { - return n, nil - } - - // Determine the threshold before starting a new node. - var fillPercent = n.bucket.FillPercent - if fillPercent < minFillPercent { - fillPercent = minFillPercent - } else if fillPercent > maxFillPercent { - fillPercent = maxFillPercent - } - threshold := int(float64(pageSize) * fillPercent) - - // Determine split position and sizes of the two pages. - splitIndex, _ := n.splitIndex(threshold) - - // Split node into two separate nodes. - // If there's no parent then we'll need to create one. - if n.parent == nil { - n.parent = &node{bucket: n.bucket, children: []*node{n}} - } - - // Create a new node and add it to the parent. - next := &node{bucket: n.bucket, isLeaf: n.isLeaf, parent: n.parent} - n.parent.children = append(n.parent.children, next) - - // Split inodes across two nodes. - next.inodes = n.inodes[splitIndex:] - n.inodes = n.inodes[:splitIndex] - - // Update the statistics. - n.bucket.tx.stats.Split++ - - return n, next -} - -// splitIndex finds the position where a page will fill a given threshold. -// It returns the index as well as the size of the first page. -// This is only be called from split(). -func (n *node) splitIndex(threshold int) (index, sz int) { - sz = pageHeaderSize - - // Loop until we only have the minimum number of keys required for the second page. - for i := 0; i < len(n.inodes)-minKeysPerPage; i++ { - index = i - inode := n.inodes[i] - elsize := n.pageElementSize() + len(inode.key) + len(inode.value) - - // If we have at least the minimum number of keys and adding another - // node would put us over the threshold then exit and return. - if i >= minKeysPerPage && sz+elsize > threshold { - break - } - - // Add the element size to the total size. - sz += elsize - } - - return -} - -// spill writes the nodes to dirty pages and splits nodes as it goes. -// Returns an error if dirty pages cannot be allocated. -func (n *node) spill() error { - var tx = n.bucket.tx - if n.spilled { - return nil - } - - // Spill child nodes first. Child nodes can materialize sibling nodes in - // the case of split-merge so we cannot use a range loop. We have to check - // the children size on every loop iteration. - sort.Sort(n.children) - for i := 0; i < len(n.children); i++ { - if err := n.children[i].spill(); err != nil { - return err - } - } - - // We no longer need the child list because it's only used for spill tracking. - n.children = nil - - // Split nodes into appropriate sizes. The first node will always be n. - var nodes = n.split(tx.db.pageSize) - for _, node := range nodes { - // Add node's page to the freelist if it's not new. - if node.pgid > 0 { - tx.db.freelist.free(tx.meta.txid, tx.page(node.pgid)) - node.pgid = 0 - } - - // Allocate contiguous space for the node. - p, err := tx.allocate((node.size() / tx.db.pageSize) + 1) - if err != nil { - return err - } - - // Write the node. - if p.id >= tx.meta.pgid { - panic(fmt.Sprintf("pgid (%d) above high water mark (%d)", p.id, tx.meta.pgid)) - } - node.pgid = p.id - node.write(p) - node.spilled = true - - // Insert into parent inodes. - if node.parent != nil { - var key = node.key - if key == nil { - key = node.inodes[0].key - } - - node.parent.put(key, node.inodes[0].key, nil, node.pgid, 0) - node.key = node.inodes[0].key - _assert(len(node.key) > 0, "spill: zero-length node key") - } - - // Update the statistics. - tx.stats.Spill++ - } - - // If the root node split and created a new root then we need to spill that - // as well. We'll clear out the children to make sure it doesn't try to respill. - if n.parent != nil && n.parent.pgid == 0 { - n.children = nil - return n.parent.spill() - } - - return nil -} - -// rebalance attempts to combine the node with sibling nodes if the node fill -// size is below a threshold or if there are not enough keys. -func (n *node) rebalance() { - if !n.unbalanced { - return - } - n.unbalanced = false - - // Update statistics. - n.bucket.tx.stats.Rebalance++ - - // Ignore if node is above threshold (25%) and has enough keys. - var threshold = n.bucket.tx.db.pageSize / 4 - if n.size() > threshold && len(n.inodes) > n.minKeys() { - return - } - - // Root node has special handling. - if n.parent == nil { - // If root node is a branch and only has one node then collapse it. - if !n.isLeaf && len(n.inodes) == 1 { - // Move root's child up. - child := n.bucket.node(n.inodes[0].pgid, n) - n.isLeaf = child.isLeaf - n.inodes = child.inodes[:] - n.children = child.children - - // Reparent all child nodes being moved. - for _, inode := range n.inodes { - if child, ok := n.bucket.nodes[inode.pgid]; ok { - child.parent = n - } - } - - // Remove old child. - child.parent = nil - delete(n.bucket.nodes, child.pgid) - child.free() - } - - return - } - - // If node has no keys then just remove it. - if n.numChildren() == 0 { - n.parent.del(n.key) - n.parent.removeChild(n) - delete(n.bucket.nodes, n.pgid) - n.free() - n.parent.rebalance() - return - } - - _assert(n.parent.numChildren() > 1, "parent must have at least 2 children") - - // Destination node is right sibling if idx == 0, otherwise left sibling. - var target *node - var useNextSibling = (n.parent.childIndex(n) == 0) - if useNextSibling { - target = n.nextSibling() - } else { - target = n.prevSibling() - } - - // If both this node and the target node are too small then merge them. - if useNextSibling { - // Reparent all child nodes being moved. - for _, inode := range target.inodes { - if child, ok := n.bucket.nodes[inode.pgid]; ok { - child.parent.removeChild(child) - child.parent = n - child.parent.children = append(child.parent.children, child) - } - } - - // Copy over inodes from target and remove target. - n.inodes = append(n.inodes, target.inodes...) - n.parent.del(target.key) - n.parent.removeChild(target) - delete(n.bucket.nodes, target.pgid) - target.free() - } else { - // Reparent all child nodes being moved. - for _, inode := range n.inodes { - if child, ok := n.bucket.nodes[inode.pgid]; ok { - child.parent.removeChild(child) - child.parent = target - child.parent.children = append(child.parent.children, child) - } - } - - // Copy over inodes to target and remove node. - target.inodes = append(target.inodes, n.inodes...) - n.parent.del(n.key) - n.parent.removeChild(n) - delete(n.bucket.nodes, n.pgid) - n.free() - } - - // Either this node or the target node was deleted from the parent so rebalance it. - n.parent.rebalance() -} - -// removes a node from the list of in-memory children. -// This does not affect the inodes. -func (n *node) removeChild(target *node) { - for i, child := range n.children { - if child == target { - n.children = append(n.children[:i], n.children[i+1:]...) - return - } - } -} - -// dereference causes the node to copy all its inode key/value references to heap memory. -// This is required when the mmap is reallocated so inodes are not pointing to stale data. -func (n *node) dereference() { - if n.key != nil { - key := make([]byte, len(n.key)) - copy(key, n.key) - n.key = key - _assert(n.pgid == 0 || len(n.key) > 0, "dereference: zero-length node key on existing node") - } - - for i := range n.inodes { - inode := &n.inodes[i] - - key := make([]byte, len(inode.key)) - copy(key, inode.key) - inode.key = key - _assert(len(inode.key) > 0, "dereference: zero-length inode key") - - value := make([]byte, len(inode.value)) - copy(value, inode.value) - inode.value = value - } - - // Recursively dereference children. - for _, child := range n.children { - child.dereference() - } - - // Update statistics. - n.bucket.tx.stats.NodeDeref++ -} - -// free adds the node's underlying page to the freelist. -func (n *node) free() { - if n.pgid != 0 { - n.bucket.tx.db.freelist.free(n.bucket.tx.meta.txid, n.bucket.tx.page(n.pgid)) - n.pgid = 0 - } -} - -// dump writes the contents of the node to STDERR for debugging purposes. -/* -func (n *node) dump() { - // Write node header. - var typ = "branch" - if n.isLeaf { - typ = "leaf" - } - warnf("[NODE %d {type=%s count=%d}]", n.pgid, typ, len(n.inodes)) - - // Write out abbreviated version of each item. - for _, item := range n.inodes { - if n.isLeaf { - if item.flags&bucketLeafFlag != 0 { - bucket := (*bucket)(unsafe.Pointer(&item.value[0])) - warnf("+L %08x -> (bucket root=%d)", trunc(item.key, 4), bucket.root) - } else { - warnf("+L %08x -> %08x", trunc(item.key, 4), trunc(item.value, 4)) - } - } else { - warnf("+B %08x -> pgid=%d", trunc(item.key, 4), item.pgid) - } - } - warn("") -} -*/ - -type nodes []*node - -func (s nodes) Len() int { return len(s) } -func (s nodes) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s nodes) Less(i, j int) bool { return bytes.Compare(s[i].inodes[0].key, s[j].inodes[0].key) == -1 } - -// inode represents an internal node inside of a node. -// It can be used to point to elements in a page or point -// to an element which hasn't been added to a page yet. -type inode struct { - flags uint32 - pgid pgid - key []byte - value []byte -} - -type inodes []inode diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node_test.go deleted file mode 100644 index fa5d10f..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/node_test.go +++ /dev/null @@ -1,156 +0,0 @@ -package bolt - -import ( - "testing" - "unsafe" -) - -// Ensure that a node can insert a key/value. -func TestNode_put(t *testing.T) { - n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{meta: &meta{pgid: 1}}}} - n.put([]byte("baz"), []byte("baz"), []byte("2"), 0, 0) - n.put([]byte("foo"), []byte("foo"), []byte("0"), 0, 0) - n.put([]byte("bar"), []byte("bar"), []byte("1"), 0, 0) - n.put([]byte("foo"), []byte("foo"), []byte("3"), 0, leafPageFlag) - - if len(n.inodes) != 3 { - t.Fatalf("exp=3; got=%d", len(n.inodes)) - } - if k, v := n.inodes[0].key, n.inodes[0].value; string(k) != "bar" || string(v) != "1" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } - if k, v := n.inodes[1].key, n.inodes[1].value; string(k) != "baz" || string(v) != "2" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } - if k, v := n.inodes[2].key, n.inodes[2].value; string(k) != "foo" || string(v) != "3" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } - if n.inodes[2].flags != uint32(leafPageFlag) { - t.Fatalf("not a leaf: %d", n.inodes[2].flags) - } -} - -// Ensure that a node can deserialize from a leaf page. -func TestNode_read_LeafPage(t *testing.T) { - // Create a page. - var buf [4096]byte - page := (*page)(unsafe.Pointer(&buf[0])) - page.flags = leafPageFlag - page.count = 2 - - // Insert 2 elements at the beginning. sizeof(leafPageElement) == 16 - nodes := (*[3]leafPageElement)(unsafe.Pointer(&page.ptr)) - nodes[0] = leafPageElement{flags: 0, pos: 32, ksize: 3, vsize: 4} // pos = sizeof(leafPageElement) * 2 - nodes[1] = leafPageElement{flags: 0, pos: 23, ksize: 10, vsize: 3} // pos = sizeof(leafPageElement) + 3 + 4 - - // Write data for the nodes at the end. - data := (*[4096]byte)(unsafe.Pointer(&nodes[2])) - copy(data[:], []byte("barfooz")) - copy(data[7:], []byte("helloworldbye")) - - // Deserialize page into a leaf. - n := &node{} - n.read(page) - - // Check that there are two inodes with correct data. - if !n.isLeaf { - t.Fatal("expected leaf") - } - if len(n.inodes) != 2 { - t.Fatalf("exp=2; got=%d", len(n.inodes)) - } - if k, v := n.inodes[0].key, n.inodes[0].value; string(k) != "bar" || string(v) != "fooz" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } - if k, v := n.inodes[1].key, n.inodes[1].value; string(k) != "helloworld" || string(v) != "bye" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } -} - -// Ensure that a node can serialize into a leaf page. -func TestNode_write_LeafPage(t *testing.T) { - // Create a node. - n := &node{isLeaf: true, inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}} - n.put([]byte("susy"), []byte("susy"), []byte("que"), 0, 0) - n.put([]byte("ricki"), []byte("ricki"), []byte("lake"), 0, 0) - n.put([]byte("john"), []byte("john"), []byte("johnson"), 0, 0) - - // Write it to a page. - var buf [4096]byte - p := (*page)(unsafe.Pointer(&buf[0])) - n.write(p) - - // Read the page back in. - n2 := &node{} - n2.read(p) - - // Check that the two pages are the same. - if len(n2.inodes) != 3 { - t.Fatalf("exp=3; got=%d", len(n2.inodes)) - } - if k, v := n2.inodes[0].key, n2.inodes[0].value; string(k) != "john" || string(v) != "johnson" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } - if k, v := n2.inodes[1].key, n2.inodes[1].value; string(k) != "ricki" || string(v) != "lake" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } - if k, v := n2.inodes[2].key, n2.inodes[2].value; string(k) != "susy" || string(v) != "que" { - t.Fatalf("exp=; got=<%s,%s>", k, v) - } -} - -// Ensure that a node can split into appropriate subgroups. -func TestNode_split(t *testing.T) { - // Create a node. - n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}} - n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000003"), []byte("00000003"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000004"), []byte("00000004"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000005"), []byte("00000005"), []byte("0123456701234567"), 0, 0) - - // Split between 2 & 3. - n.split(100) - - var parent = n.parent - if len(parent.children) != 2 { - t.Fatalf("exp=2; got=%d", len(parent.children)) - } - if len(parent.children[0].inodes) != 2 { - t.Fatalf("exp=2; got=%d", len(parent.children[0].inodes)) - } - if len(parent.children[1].inodes) != 3 { - t.Fatalf("exp=3; got=%d", len(parent.children[1].inodes)) - } -} - -// Ensure that a page with the minimum number of inodes just returns a single node. -func TestNode_split_MinKeys(t *testing.T) { - // Create a node. - n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}} - n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0) - - // Split. - n.split(20) - if n.parent != nil { - t.Fatalf("expected nil parent") - } -} - -// Ensure that a node that has keys that all fit on a page just returns one leaf. -func TestNode_split_SinglePage(t *testing.T) { - // Create a node. - n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, meta: &meta{pgid: 1}}}} - n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000003"), []byte("00000003"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000004"), []byte("00000004"), []byte("0123456701234567"), 0, 0) - n.put([]byte("00000005"), []byte("00000005"), []byte("0123456701234567"), 0, 0) - - // Split. - n.split(4096) - if n.parent != nil { - t.Fatalf("expected nil parent") - } -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page.go deleted file mode 100644 index 7651a6b..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page.go +++ /dev/null @@ -1,178 +0,0 @@ -package bolt - -import ( - "fmt" - "os" - "sort" - "unsafe" -) - -const pageHeaderSize = int(unsafe.Offsetof(((*page)(nil)).ptr)) - -const minKeysPerPage = 2 - -const branchPageElementSize = int(unsafe.Sizeof(branchPageElement{})) -const leafPageElementSize = int(unsafe.Sizeof(leafPageElement{})) - -const ( - branchPageFlag = 0x01 - leafPageFlag = 0x02 - metaPageFlag = 0x04 - freelistPageFlag = 0x10 -) - -const ( - bucketLeafFlag = 0x01 -) - -type pgid uint64 - -type page struct { - id pgid - flags uint16 - count uint16 - overflow uint32 - ptr uintptr -} - -// typ returns a human readable page type string used for debugging. -func (p *page) typ() string { - if (p.flags & branchPageFlag) != 0 { - return "branch" - } else if (p.flags & leafPageFlag) != 0 { - return "leaf" - } else if (p.flags & metaPageFlag) != 0 { - return "meta" - } else if (p.flags & freelistPageFlag) != 0 { - return "freelist" - } - return fmt.Sprintf("unknown<%02x>", p.flags) -} - -// meta returns a pointer to the metadata section of the page. -func (p *page) meta() *meta { - return (*meta)(unsafe.Pointer(&p.ptr)) -} - -// leafPageElement retrieves the leaf node by index -func (p *page) leafPageElement(index uint16) *leafPageElement { - n := &((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[index] - return n -} - -// leafPageElements retrieves a list of leaf nodes. -func (p *page) leafPageElements() []leafPageElement { - if p.count == 0 { - return nil - } - return ((*[0x7FFFFFF]leafPageElement)(unsafe.Pointer(&p.ptr)))[:] -} - -// branchPageElement retrieves the branch node by index -func (p *page) branchPageElement(index uint16) *branchPageElement { - return &((*[0x7FFFFFF]branchPageElement)(unsafe.Pointer(&p.ptr)))[index] -} - -// branchPageElements retrieves a list of branch nodes. -func (p *page) branchPageElements() []branchPageElement { - if p.count == 0 { - return nil - } - return ((*[0x7FFFFFF]branchPageElement)(unsafe.Pointer(&p.ptr)))[:] -} - -// dump writes n bytes of the page to STDERR as hex output. -func (p *page) hexdump(n int) { - buf := (*[maxAllocSize]byte)(unsafe.Pointer(p))[:n] - fmt.Fprintf(os.Stderr, "%x\n", buf) -} - -type pages []*page - -func (s pages) Len() int { return len(s) } -func (s pages) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s pages) Less(i, j int) bool { return s[i].id < s[j].id } - -// branchPageElement represents a node on a branch page. -type branchPageElement struct { - pos uint32 - ksize uint32 - pgid pgid -} - -// key returns a byte slice of the node key. -func (n *branchPageElement) key() []byte { - buf := (*[maxAllocSize]byte)(unsafe.Pointer(n)) - return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize] -} - -// leafPageElement represents a node on a leaf page. -type leafPageElement struct { - flags uint32 - pos uint32 - ksize uint32 - vsize uint32 -} - -// key returns a byte slice of the node key. -func (n *leafPageElement) key() []byte { - buf := (*[maxAllocSize]byte)(unsafe.Pointer(n)) - return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos]))[:n.ksize:n.ksize] -} - -// value returns a byte slice of the node value. -func (n *leafPageElement) value() []byte { - buf := (*[maxAllocSize]byte)(unsafe.Pointer(n)) - return (*[maxAllocSize]byte)(unsafe.Pointer(&buf[n.pos+n.ksize]))[:n.vsize:n.vsize] -} - -// PageInfo represents human readable information about a page. -type PageInfo struct { - ID int - Type string - Count int - OverflowCount int -} - -type pgids []pgid - -func (s pgids) Len() int { return len(s) } -func (s pgids) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s pgids) Less(i, j int) bool { return s[i] < s[j] } - -// merge returns the sorted union of a and b. -func (a pgids) merge(b pgids) pgids { - // Return the opposite slice if one is nil. - if len(a) == 0 { - return b - } else if len(b) == 0 { - return a - } - - // Create a list to hold all elements from both lists. - merged := make(pgids, 0, len(a)+len(b)) - - // Assign lead to the slice with a lower starting value, follow to the higher value. - lead, follow := a, b - if b[0] < a[0] { - lead, follow = b, a - } - - // Continue while there are elements in the lead. - for len(lead) > 0 { - // Merge largest prefix of lead that is ahead of follow[0]. - n := sort.Search(len(lead), func(i int) bool { return lead[i] > follow[0] }) - merged = append(merged, lead[:n]...) - if n >= len(lead) { - break - } - - // Swap lead and follow. - lead, follow = follow, lead[n:] - } - - // Append what's left in follow. - merged = append(merged, follow...) - - return merged -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page_test.go deleted file mode 100644 index 59f4a30..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/page_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package bolt - -import ( - "reflect" - "sort" - "testing" - "testing/quick" -) - -// Ensure that the page type can be returned in human readable format. -func TestPage_typ(t *testing.T) { - if typ := (&page{flags: branchPageFlag}).typ(); typ != "branch" { - t.Fatalf("exp=branch; got=%v", typ) - } - if typ := (&page{flags: leafPageFlag}).typ(); typ != "leaf" { - t.Fatalf("exp=leaf; got=%v", typ) - } - if typ := (&page{flags: metaPageFlag}).typ(); typ != "meta" { - t.Fatalf("exp=meta; got=%v", typ) - } - if typ := (&page{flags: freelistPageFlag}).typ(); typ != "freelist" { - t.Fatalf("exp=freelist; got=%v", typ) - } - if typ := (&page{flags: 20000}).typ(); typ != "unknown<4e20>" { - t.Fatalf("exp=unknown<4e20>; got=%v", typ) - } -} - -// Ensure that the hexdump debugging function doesn't blow up. -func TestPage_dump(t *testing.T) { - (&page{id: 256}).hexdump(16) -} - -func TestPgids_merge(t *testing.T) { - a := pgids{4, 5, 6, 10, 11, 12, 13, 27} - b := pgids{1, 3, 8, 9, 25, 30} - c := a.merge(b) - if !reflect.DeepEqual(c, pgids{1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 25, 27, 30}) { - t.Errorf("mismatch: %v", c) - } - - a = pgids{4, 5, 6, 10, 11, 12, 13, 27, 35, 36} - b = pgids{8, 9, 25, 30} - c = a.merge(b) - if !reflect.DeepEqual(c, pgids{4, 5, 6, 8, 9, 10, 11, 12, 13, 25, 27, 30, 35, 36}) { - t.Errorf("mismatch: %v", c) - } -} - -func TestPgids_merge_quick(t *testing.T) { - if err := quick.Check(func(a, b pgids) bool { - // Sort incoming lists. - sort.Sort(a) - sort.Sort(b) - - // Merge the two lists together. - got := a.merge(b) - - // The expected value should be the two lists combined and sorted. - exp := append(a, b...) - sort.Sort(exp) - - if !reflect.DeepEqual(exp, got) { - t.Errorf("\nexp=%+v\ngot=%+v\n", exp, got) - return false - } - - return true - }, nil); err != nil { - t.Fatal(err) - } -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/quick_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/quick_test.go deleted file mode 100644 index 4da5817..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/quick_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package bolt_test - -import ( - "bytes" - "flag" - "fmt" - "math/rand" - "os" - "reflect" - "testing/quick" - "time" -) - -// testing/quick defaults to 5 iterations and a random seed. -// You can override these settings from the command line: -// -// -quick.count The number of iterations to perform. -// -quick.seed The seed to use for randomizing. -// -quick.maxitems The maximum number of items to insert into a DB. -// -quick.maxksize The maximum size of a key. -// -quick.maxvsize The maximum size of a value. -// - -var qcount, qseed, qmaxitems, qmaxksize, qmaxvsize int - -func init() { - flag.IntVar(&qcount, "quick.count", 5, "") - flag.IntVar(&qseed, "quick.seed", int(time.Now().UnixNano())%100000, "") - flag.IntVar(&qmaxitems, "quick.maxitems", 1000, "") - flag.IntVar(&qmaxksize, "quick.maxksize", 1024, "") - flag.IntVar(&qmaxvsize, "quick.maxvsize", 1024, "") - flag.Parse() - fmt.Fprintln(os.Stderr, "seed:", qseed) - fmt.Fprintf(os.Stderr, "quick settings: count=%v, items=%v, ksize=%v, vsize=%v\n", qcount, qmaxitems, qmaxksize, qmaxvsize) -} - -func qconfig() *quick.Config { - return &quick.Config{ - MaxCount: qcount, - Rand: rand.New(rand.NewSource(int64(qseed))), - } -} - -type testdata []testdataitem - -func (t testdata) Len() int { return len(t) } -func (t testdata) Swap(i, j int) { t[i], t[j] = t[j], t[i] } -func (t testdata) Less(i, j int) bool { return bytes.Compare(t[i].Key, t[j].Key) == -1 } - -func (t testdata) Generate(rand *rand.Rand, size int) reflect.Value { - n := rand.Intn(qmaxitems-1) + 1 - items := make(testdata, n) - for i := 0; i < n; i++ { - item := &items[i] - item.Key = randByteSlice(rand, 1, qmaxksize) - item.Value = randByteSlice(rand, 0, qmaxvsize) - } - return reflect.ValueOf(items) -} - -type revtestdata []testdataitem - -func (t revtestdata) Len() int { return len(t) } -func (t revtestdata) Swap(i, j int) { t[i], t[j] = t[j], t[i] } -func (t revtestdata) Less(i, j int) bool { return bytes.Compare(t[i].Key, t[j].Key) == 1 } - -type testdataitem struct { - Key []byte - Value []byte -} - -func randByteSlice(rand *rand.Rand, minSize, maxSize int) []byte { - n := rand.Intn(maxSize-minSize) + minSize - b := make([]byte, n) - for i := 0; i < n; i++ { - b[i] = byte(rand.Intn(255)) - } - return b -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/simulation_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/simulation_test.go deleted file mode 100644 index 3831016..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/simulation_test.go +++ /dev/null @@ -1,329 +0,0 @@ -package bolt_test - -import ( - "bytes" - "fmt" - "math/rand" - "sync" - "testing" - - "github.com/boltdb/bolt" -) - -func TestSimulate_1op_1p(t *testing.T) { testSimulate(t, 1, 1) } -func TestSimulate_10op_1p(t *testing.T) { testSimulate(t, 10, 1) } -func TestSimulate_100op_1p(t *testing.T) { testSimulate(t, 100, 1) } -func TestSimulate_1000op_1p(t *testing.T) { testSimulate(t, 1000, 1) } -func TestSimulate_10000op_1p(t *testing.T) { testSimulate(t, 10000, 1) } - -func TestSimulate_10op_10p(t *testing.T) { testSimulate(t, 10, 10) } -func TestSimulate_100op_10p(t *testing.T) { testSimulate(t, 100, 10) } -func TestSimulate_1000op_10p(t *testing.T) { testSimulate(t, 1000, 10) } -func TestSimulate_10000op_10p(t *testing.T) { testSimulate(t, 10000, 10) } - -func TestSimulate_100op_100p(t *testing.T) { testSimulate(t, 100, 100) } -func TestSimulate_1000op_100p(t *testing.T) { testSimulate(t, 1000, 100) } -func TestSimulate_10000op_100p(t *testing.T) { testSimulate(t, 10000, 100) } - -func TestSimulate_10000op_1000p(t *testing.T) { testSimulate(t, 10000, 1000) } - -// Randomly generate operations on a given database with multiple clients to ensure consistency and thread safety. -func testSimulate(t *testing.T, threadCount, parallelism int) { - if testing.Short() { - t.Skip("skipping test in short mode.") - } - - rand.Seed(int64(qseed)) - - // A list of operations that readers and writers can perform. - var readerHandlers = []simulateHandler{simulateGetHandler} - var writerHandlers = []simulateHandler{simulateGetHandler, simulatePutHandler} - - var versions = make(map[int]*QuickDB) - versions[1] = NewQuickDB() - - db := MustOpenDB() - defer db.MustClose() - - var mutex sync.Mutex - - // Run n threads in parallel, each with their own operation. - var wg sync.WaitGroup - var threads = make(chan bool, parallelism) - var i int - for { - threads <- true - wg.Add(1) - writable := ((rand.Int() % 100) < 20) // 20% writers - - // Choose an operation to execute. - var handler simulateHandler - if writable { - handler = writerHandlers[rand.Intn(len(writerHandlers))] - } else { - handler = readerHandlers[rand.Intn(len(readerHandlers))] - } - - // Execute a thread for the given operation. - go func(writable bool, handler simulateHandler) { - defer wg.Done() - - // Start transaction. - tx, err := db.Begin(writable) - if err != nil { - t.Fatal("tx begin: ", err) - } - - // Obtain current state of the dataset. - mutex.Lock() - var qdb = versions[tx.ID()] - if writable { - qdb = versions[tx.ID()-1].Copy() - } - mutex.Unlock() - - // Make sure we commit/rollback the tx at the end and update the state. - if writable { - defer func() { - mutex.Lock() - versions[tx.ID()] = qdb - mutex.Unlock() - - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - }() - } else { - defer func() { _ = tx.Rollback() }() - } - - // Ignore operation if we don't have data yet. - if qdb == nil { - return - } - - // Execute handler. - handler(tx, qdb) - - // Release a thread back to the scheduling loop. - <-threads - }(writable, handler) - - i++ - if i > threadCount { - break - } - } - - // Wait until all threads are done. - wg.Wait() -} - -type simulateHandler func(tx *bolt.Tx, qdb *QuickDB) - -// Retrieves a key from the database and verifies that it is what is expected. -func simulateGetHandler(tx *bolt.Tx, qdb *QuickDB) { - // Randomly retrieve an existing exist. - keys := qdb.Rand() - if len(keys) == 0 { - return - } - - // Retrieve root bucket. - b := tx.Bucket(keys[0]) - if b == nil { - panic(fmt.Sprintf("bucket[0] expected: %08x\n", trunc(keys[0], 4))) - } - - // Drill into nested buckets. - for _, key := range keys[1 : len(keys)-1] { - b = b.Bucket(key) - if b == nil { - panic(fmt.Sprintf("bucket[n] expected: %v -> %v\n", keys, key)) - } - } - - // Verify key/value on the final bucket. - expected := qdb.Get(keys) - actual := b.Get(keys[len(keys)-1]) - if !bytes.Equal(actual, expected) { - fmt.Println("=== EXPECTED ===") - fmt.Println(expected) - fmt.Println("=== ACTUAL ===") - fmt.Println(actual) - fmt.Println("=== END ===") - panic("value mismatch") - } -} - -// Inserts a key into the database. -func simulatePutHandler(tx *bolt.Tx, qdb *QuickDB) { - var err error - keys, value := randKeys(), randValue() - - // Retrieve root bucket. - b := tx.Bucket(keys[0]) - if b == nil { - b, err = tx.CreateBucket(keys[0]) - if err != nil { - panic("create bucket: " + err.Error()) - } - } - - // Create nested buckets, if necessary. - for _, key := range keys[1 : len(keys)-1] { - child := b.Bucket(key) - if child != nil { - b = child - } else { - b, err = b.CreateBucket(key) - if err != nil { - panic("create bucket: " + err.Error()) - } - } - } - - // Insert into database. - if err := b.Put(keys[len(keys)-1], value); err != nil { - panic("put: " + err.Error()) - } - - // Insert into in-memory database. - qdb.Put(keys, value) -} - -// QuickDB is an in-memory database that replicates the functionality of the -// Bolt DB type except that it is entirely in-memory. It is meant for testing -// that the Bolt database is consistent. -type QuickDB struct { - sync.RWMutex - m map[string]interface{} -} - -// NewQuickDB returns an instance of QuickDB. -func NewQuickDB() *QuickDB { - return &QuickDB{m: make(map[string]interface{})} -} - -// Get retrieves the value at a key path. -func (db *QuickDB) Get(keys [][]byte) []byte { - db.RLock() - defer db.RUnlock() - - m := db.m - for _, key := range keys[:len(keys)-1] { - value := m[string(key)] - if value == nil { - return nil - } - switch value := value.(type) { - case map[string]interface{}: - m = value - case []byte: - return nil - } - } - - // Only return if it's a simple value. - if value, ok := m[string(keys[len(keys)-1])].([]byte); ok { - return value - } - return nil -} - -// Put inserts a value into a key path. -func (db *QuickDB) Put(keys [][]byte, value []byte) { - db.Lock() - defer db.Unlock() - - // Build buckets all the way down the key path. - m := db.m - for _, key := range keys[:len(keys)-1] { - if _, ok := m[string(key)].([]byte); ok { - return // Keypath intersects with a simple value. Do nothing. - } - - if m[string(key)] == nil { - m[string(key)] = make(map[string]interface{}) - } - m = m[string(key)].(map[string]interface{}) - } - - // Insert value into the last key. - m[string(keys[len(keys)-1])] = value -} - -// Rand returns a random key path that points to a simple value. -func (db *QuickDB) Rand() [][]byte { - db.RLock() - defer db.RUnlock() - if len(db.m) == 0 { - return nil - } - var keys [][]byte - db.rand(db.m, &keys) - return keys -} - -func (db *QuickDB) rand(m map[string]interface{}, keys *[][]byte) { - i, index := 0, rand.Intn(len(m)) - for k, v := range m { - if i == index { - *keys = append(*keys, []byte(k)) - if v, ok := v.(map[string]interface{}); ok { - db.rand(v, keys) - } - return - } - i++ - } - panic("quickdb rand: out-of-range") -} - -// Copy copies the entire database. -func (db *QuickDB) Copy() *QuickDB { - db.RLock() - defer db.RUnlock() - return &QuickDB{m: db.copy(db.m)} -} - -func (db *QuickDB) copy(m map[string]interface{}) map[string]interface{} { - clone := make(map[string]interface{}, len(m)) - for k, v := range m { - switch v := v.(type) { - case map[string]interface{}: - clone[k] = db.copy(v) - default: - clone[k] = v - } - } - return clone -} - -func randKey() []byte { - var min, max = 1, 1024 - n := rand.Intn(max-min) + min - b := make([]byte, n) - for i := 0; i < n; i++ { - b[i] = byte(rand.Intn(255)) - } - return b -} - -func randKeys() [][]byte { - var keys [][]byte - var count = rand.Intn(2) + 2 - for i := 0; i < count; i++ { - keys = append(keys, randKey()) - } - return keys -} - -func randValue() []byte { - n := rand.Intn(8192) - b := make([]byte, n) - for i := 0; i < n; i++ { - b[i] = byte(rand.Intn(255)) - } - return b -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx.go deleted file mode 100644 index 1cfb4cd..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx.go +++ /dev/null @@ -1,682 +0,0 @@ -package bolt - -import ( - "fmt" - "io" - "os" - "sort" - "strings" - "time" - "unsafe" -) - -// txid represents the internal transaction identifier. -type txid uint64 - -// Tx represents a read-only or read/write transaction on the database. -// Read-only transactions can be used for retrieving values for keys and creating cursors. -// Read/write transactions can create and remove buckets and create and remove keys. -// -// IMPORTANT: You must commit or rollback transactions when you are done with -// them. Pages can not be reclaimed by the writer until no more transactions -// are using them. A long running read transaction can cause the database to -// quickly grow. -type Tx struct { - writable bool - managed bool - db *DB - meta *meta - root Bucket - pages map[pgid]*page - stats TxStats - commitHandlers []func() - - // WriteFlag specifies the flag for write-related methods like WriteTo(). - // Tx opens the database file with the specified flag to copy the data. - // - // By default, the flag is unset, which works well for mostly in-memory - // workloads. For databases that are much larger than available RAM, - // set the flag to syscall.O_DIRECT to avoid trashing the page cache. - WriteFlag int -} - -// init initializes the transaction. -func (tx *Tx) init(db *DB) { - tx.db = db - tx.pages = nil - - // Copy the meta page since it can be changed by the writer. - tx.meta = &meta{} - db.meta().copy(tx.meta) - - // Copy over the root bucket. - tx.root = newBucket(tx) - tx.root.bucket = &bucket{} - *tx.root.bucket = tx.meta.root - - // Increment the transaction id and add a page cache for writable transactions. - if tx.writable { - tx.pages = make(map[pgid]*page) - tx.meta.txid += txid(1) - } -} - -// ID returns the transaction id. -func (tx *Tx) ID() int { - return int(tx.meta.txid) -} - -// DB returns a reference to the database that created the transaction. -func (tx *Tx) DB() *DB { - return tx.db -} - -// Size returns current database size in bytes as seen by this transaction. -func (tx *Tx) Size() int64 { - return int64(tx.meta.pgid) * int64(tx.db.pageSize) -} - -// Writable returns whether the transaction can perform write operations. -func (tx *Tx) Writable() bool { - return tx.writable -} - -// Cursor creates a cursor associated with the root bucket. -// All items in the cursor will return a nil value because all root bucket keys point to buckets. -// The cursor is only valid as long as the transaction is open. -// Do not use a cursor after the transaction is closed. -func (tx *Tx) Cursor() *Cursor { - return tx.root.Cursor() -} - -// Stats retrieves a copy of the current transaction statistics. -func (tx *Tx) Stats() TxStats { - return tx.stats -} - -// Bucket retrieves a bucket by name. -// Returns nil if the bucket does not exist. -// The bucket instance is only valid for the lifetime of the transaction. -func (tx *Tx) Bucket(name []byte) *Bucket { - return tx.root.Bucket(name) -} - -// CreateBucket creates a new bucket. -// Returns an error if the bucket already exists, if the bucket name is blank, or if the bucket name is too long. -// The bucket instance is only valid for the lifetime of the transaction. -func (tx *Tx) CreateBucket(name []byte) (*Bucket, error) { - return tx.root.CreateBucket(name) -} - -// CreateBucketIfNotExists creates a new bucket if it doesn't already exist. -// Returns an error if the bucket name is blank, or if the bucket name is too long. -// The bucket instance is only valid for the lifetime of the transaction. -func (tx *Tx) CreateBucketIfNotExists(name []byte) (*Bucket, error) { - return tx.root.CreateBucketIfNotExists(name) -} - -// DeleteBucket deletes a bucket. -// Returns an error if the bucket cannot be found or if the key represents a non-bucket value. -func (tx *Tx) DeleteBucket(name []byte) error { - return tx.root.DeleteBucket(name) -} - -// ForEach executes a function for each bucket in the root. -// If the provided function returns an error then the iteration is stopped and -// the error is returned to the caller. -func (tx *Tx) ForEach(fn func(name []byte, b *Bucket) error) error { - return tx.root.ForEach(func(k, v []byte) error { - if err := fn(k, tx.root.Bucket(k)); err != nil { - return err - } - return nil - }) -} - -// OnCommit adds a handler function to be executed after the transaction successfully commits. -func (tx *Tx) OnCommit(fn func()) { - tx.commitHandlers = append(tx.commitHandlers, fn) -} - -// Commit writes all changes to disk and updates the meta page. -// Returns an error if a disk write error occurs, or if Commit is -// called on a read-only transaction. -func (tx *Tx) Commit() error { - _assert(!tx.managed, "managed tx commit not allowed") - if tx.db == nil { - return ErrTxClosed - } else if !tx.writable { - return ErrTxNotWritable - } - - // TODO(benbjohnson): Use vectorized I/O to write out dirty pages. - - // Rebalance nodes which have had deletions. - var startTime = time.Now() - tx.root.rebalance() - if tx.stats.Rebalance > 0 { - tx.stats.RebalanceTime += time.Since(startTime) - } - - // spill data onto dirty pages. - startTime = time.Now() - if err := tx.root.spill(); err != nil { - tx.rollback() - return err - } - tx.stats.SpillTime += time.Since(startTime) - - // Free the old root bucket. - tx.meta.root.root = tx.root.root - - opgid := tx.meta.pgid - - // Free the freelist and allocate new pages for it. This will overestimate - // the size of the freelist but not underestimate the size (which would be bad). - tx.db.freelist.free(tx.meta.txid, tx.db.page(tx.meta.freelist)) - p, err := tx.allocate((tx.db.freelist.size() / tx.db.pageSize) + 1) - if err != nil { - tx.rollback() - return err - } - if err := tx.db.freelist.write(p); err != nil { - tx.rollback() - return err - } - tx.meta.freelist = p.id - - // If the high water mark has moved up then attempt to grow the database. - if tx.meta.pgid > opgid { - if err := tx.db.grow(int(tx.meta.pgid+1) * tx.db.pageSize); err != nil { - tx.rollback() - return err - } - } - - // Write dirty pages to disk. - startTime = time.Now() - if err := tx.write(); err != nil { - tx.rollback() - return err - } - - // If strict mode is enabled then perform a consistency check. - // Only the first consistency error is reported in the panic. - if tx.db.StrictMode { - ch := tx.Check() - var errs []string - for { - err, ok := <-ch - if !ok { - break - } - errs = append(errs, err.Error()) - } - if len(errs) > 0 { - panic("check fail: " + strings.Join(errs, "\n")) - } - } - - // Write meta to disk. - if err := tx.writeMeta(); err != nil { - tx.rollback() - return err - } - tx.stats.WriteTime += time.Since(startTime) - - // Finalize the transaction. - tx.close() - - // Execute commit handlers now that the locks have been removed. - for _, fn := range tx.commitHandlers { - fn() - } - - return nil -} - -// Rollback closes the transaction and ignores all previous updates. Read-only -// transactions must be rolled back and not committed. -func (tx *Tx) Rollback() error { - _assert(!tx.managed, "managed tx rollback not allowed") - if tx.db == nil { - return ErrTxClosed - } - tx.rollback() - return nil -} - -func (tx *Tx) rollback() { - if tx.db == nil { - return - } - if tx.writable { - tx.db.freelist.rollback(tx.meta.txid) - tx.db.freelist.reload(tx.db.page(tx.db.meta().freelist)) - } - tx.close() -} - -func (tx *Tx) close() { - if tx.db == nil { - return - } - if tx.writable { - // Grab freelist stats. - var freelistFreeN = tx.db.freelist.free_count() - var freelistPendingN = tx.db.freelist.pending_count() - var freelistAlloc = tx.db.freelist.size() - - // Remove transaction ref & writer lock. - tx.db.rwtx = nil - tx.db.rwlock.Unlock() - - // Merge statistics. - tx.db.statlock.Lock() - tx.db.stats.FreePageN = freelistFreeN - tx.db.stats.PendingPageN = freelistPendingN - tx.db.stats.FreeAlloc = (freelistFreeN + freelistPendingN) * tx.db.pageSize - tx.db.stats.FreelistInuse = freelistAlloc - tx.db.stats.TxStats.add(&tx.stats) - tx.db.statlock.Unlock() - } else { - tx.db.removeTx(tx) - } - - // Clear all references. - tx.db = nil - tx.meta = nil - tx.root = Bucket{tx: tx} - tx.pages = nil -} - -// Copy writes the entire database to a writer. -// This function exists for backwards compatibility. Use WriteTo() instead. -func (tx *Tx) Copy(w io.Writer) error { - _, err := tx.WriteTo(w) - return err -} - -// WriteTo writes the entire database to a writer. -// If err == nil then exactly tx.Size() bytes will be written into the writer. -func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) { - // Attempt to open reader with WriteFlag - f, err := os.OpenFile(tx.db.path, os.O_RDONLY|tx.WriteFlag, 0) - if err != nil { - return 0, err - } - defer func() { _ = f.Close() }() - - // Generate a meta page. We use the same page data for both meta pages. - buf := make([]byte, tx.db.pageSize) - page := (*page)(unsafe.Pointer(&buf[0])) - page.flags = metaPageFlag - *page.meta() = *tx.meta - - // Write meta 0. - page.id = 0 - page.meta().checksum = page.meta().sum64() - nn, err := w.Write(buf) - n += int64(nn) - if err != nil { - return n, fmt.Errorf("meta 0 copy: %s", err) - } - - // Write meta 1 with a lower transaction id. - page.id = 1 - page.meta().txid -= 1 - page.meta().checksum = page.meta().sum64() - nn, err = w.Write(buf) - n += int64(nn) - if err != nil { - return n, fmt.Errorf("meta 1 copy: %s", err) - } - - // Move past the meta pages in the file. - if _, err := f.Seek(int64(tx.db.pageSize*2), os.SEEK_SET); err != nil { - return n, fmt.Errorf("seek: %s", err) - } - - // Copy data pages. - wn, err := io.CopyN(w, f, tx.Size()-int64(tx.db.pageSize*2)) - n += wn - if err != nil { - return n, err - } - - return n, f.Close() -} - -// CopyFile copies the entire database to file at the given path. -// A reader transaction is maintained during the copy so it is safe to continue -// using the database while a copy is in progress. -func (tx *Tx) CopyFile(path string, mode os.FileMode) error { - f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode) - if err != nil { - return err - } - - err = tx.Copy(f) - if err != nil { - _ = f.Close() - return err - } - return f.Close() -} - -// Check performs several consistency checks on the database for this transaction. -// An error is returned if any inconsistency is found. -// -// It can be safely run concurrently on a writable transaction. However, this -// incurs a high cost for large databases and databases with a lot of subbuckets -// because of caching. This overhead can be removed if running on a read-only -// transaction, however, it is not safe to execute other writer transactions at -// the same time. -func (tx *Tx) Check() <-chan error { - ch := make(chan error) - go tx.check(ch) - return ch -} - -func (tx *Tx) check(ch chan error) { - // Check if any pages are double freed. - freed := make(map[pgid]bool) - for _, id := range tx.db.freelist.all() { - if freed[id] { - ch <- fmt.Errorf("page %d: already freed", id) - } - freed[id] = true - } - - // Track every reachable page. - reachable := make(map[pgid]*page) - reachable[0] = tx.page(0) // meta0 - reachable[1] = tx.page(1) // meta1 - for i := uint32(0); i <= tx.page(tx.meta.freelist).overflow; i++ { - reachable[tx.meta.freelist+pgid(i)] = tx.page(tx.meta.freelist) - } - - // Recursively check buckets. - tx.checkBucket(&tx.root, reachable, freed, ch) - - // Ensure all pages below high water mark are either reachable or freed. - for i := pgid(0); i < tx.meta.pgid; i++ { - _, isReachable := reachable[i] - if !isReachable && !freed[i] { - ch <- fmt.Errorf("page %d: unreachable unfreed", int(i)) - } - } - - // Close the channel to signal completion. - close(ch) -} - -func (tx *Tx) checkBucket(b *Bucket, reachable map[pgid]*page, freed map[pgid]bool, ch chan error) { - // Ignore inline buckets. - if b.root == 0 { - return - } - - // Check every page used by this bucket. - b.tx.forEachPage(b.root, 0, func(p *page, _ int) { - if p.id > tx.meta.pgid { - ch <- fmt.Errorf("page %d: out of bounds: %d", int(p.id), int(b.tx.meta.pgid)) - } - - // Ensure each page is only referenced once. - for i := pgid(0); i <= pgid(p.overflow); i++ { - var id = p.id + i - if _, ok := reachable[id]; ok { - ch <- fmt.Errorf("page %d: multiple references", int(id)) - } - reachable[id] = p - } - - // We should only encounter un-freed leaf and branch pages. - if freed[p.id] { - ch <- fmt.Errorf("page %d: reachable freed", int(p.id)) - } else if (p.flags&branchPageFlag) == 0 && (p.flags&leafPageFlag) == 0 { - ch <- fmt.Errorf("page %d: invalid type: %s", int(p.id), p.typ()) - } - }) - - // Check each bucket within this bucket. - _ = b.ForEach(func(k, v []byte) error { - if child := b.Bucket(k); child != nil { - tx.checkBucket(child, reachable, freed, ch) - } - return nil - }) -} - -// allocate returns a contiguous block of memory starting at a given page. -func (tx *Tx) allocate(count int) (*page, error) { - p, err := tx.db.allocate(count) - if err != nil { - return nil, err - } - - // Save to our page cache. - tx.pages[p.id] = p - - // Update statistics. - tx.stats.PageCount++ - tx.stats.PageAlloc += count * tx.db.pageSize - - return p, nil -} - -// write writes any dirty pages to disk. -func (tx *Tx) write() error { - // Sort pages by id. - pages := make(pages, 0, len(tx.pages)) - for _, p := range tx.pages { - pages = append(pages, p) - } - // Clear out page cache early. - tx.pages = make(map[pgid]*page) - sort.Sort(pages) - - // Write pages to disk in order. - for _, p := range pages { - size := (int(p.overflow) + 1) * tx.db.pageSize - offset := int64(p.id) * int64(tx.db.pageSize) - - // Write out page in "max allocation" sized chunks. - ptr := (*[maxAllocSize]byte)(unsafe.Pointer(p)) - for { - // Limit our write to our max allocation size. - sz := size - if sz > maxAllocSize-1 { - sz = maxAllocSize - 1 - } - - // Write chunk to disk. - buf := ptr[:sz] - if _, err := tx.db.ops.writeAt(buf, offset); err != nil { - return err - } - - // Update statistics. - tx.stats.Write++ - - // Exit inner for loop if we've written all the chunks. - size -= sz - if size == 0 { - break - } - - // Otherwise move offset forward and move pointer to next chunk. - offset += int64(sz) - ptr = (*[maxAllocSize]byte)(unsafe.Pointer(&ptr[sz])) - } - } - - // Ignore file sync if flag is set on DB. - if !tx.db.NoSync || IgnoreNoSync { - if err := fdatasync(tx.db); err != nil { - return err - } - } - - // Put small pages back to page pool. - for _, p := range pages { - // Ignore page sizes over 1 page. - // These are allocated using make() instead of the page pool. - if int(p.overflow) != 0 { - continue - } - - buf := (*[maxAllocSize]byte)(unsafe.Pointer(p))[:tx.db.pageSize] - - // See https://go.googlesource.com/go/+/f03c9202c43e0abb130669852082117ca50aa9b1 - for i := range buf { - buf[i] = 0 - } - tx.db.pagePool.Put(buf) - } - - return nil -} - -// writeMeta writes the meta to the disk. -func (tx *Tx) writeMeta() error { - // Create a temporary buffer for the meta page. - buf := make([]byte, tx.db.pageSize) - p := tx.db.pageInBuffer(buf, 0) - tx.meta.write(p) - - // Write the meta page to file. - if _, err := tx.db.ops.writeAt(buf, int64(p.id)*int64(tx.db.pageSize)); err != nil { - return err - } - if !tx.db.NoSync || IgnoreNoSync { - if err := fdatasync(tx.db); err != nil { - return err - } - } - - // Update statistics. - tx.stats.Write++ - - return nil -} - -// page returns a reference to the page with a given id. -// If page has been written to then a temporary buffered page is returned. -func (tx *Tx) page(id pgid) *page { - // Check the dirty pages first. - if tx.pages != nil { - if p, ok := tx.pages[id]; ok { - return p - } - } - - // Otherwise return directly from the mmap. - return tx.db.page(id) -} - -// forEachPage iterates over every page within a given page and executes a function. -func (tx *Tx) forEachPage(pgid pgid, depth int, fn func(*page, int)) { - p := tx.page(pgid) - - // Execute function. - fn(p, depth) - - // Recursively loop over children. - if (p.flags & branchPageFlag) != 0 { - for i := 0; i < int(p.count); i++ { - elem := p.branchPageElement(uint16(i)) - tx.forEachPage(elem.pgid, depth+1, fn) - } - } -} - -// Page returns page information for a given page number. -// This is only safe for concurrent use when used by a writable transaction. -func (tx *Tx) Page(id int) (*PageInfo, error) { - if tx.db == nil { - return nil, ErrTxClosed - } else if pgid(id) >= tx.meta.pgid { - return nil, nil - } - - // Build the page info. - p := tx.db.page(pgid(id)) - info := &PageInfo{ - ID: id, - Count: int(p.count), - OverflowCount: int(p.overflow), - } - - // Determine the type (or if it's free). - if tx.db.freelist.freed(pgid(id)) { - info.Type = "free" - } else { - info.Type = p.typ() - } - - return info, nil -} - -// TxStats represents statistics about the actions performed by the transaction. -type TxStats struct { - // Page statistics. - PageCount int // number of page allocations - PageAlloc int // total bytes allocated - - // Cursor statistics. - CursorCount int // number of cursors created - - // Node statistics - NodeCount int // number of node allocations - NodeDeref int // number of node dereferences - - // Rebalance statistics. - Rebalance int // number of node rebalances - RebalanceTime time.Duration // total time spent rebalancing - - // Split/Spill statistics. - Split int // number of nodes split - Spill int // number of nodes spilled - SpillTime time.Duration // total time spent spilling - - // Write statistics. - Write int // number of writes performed - WriteTime time.Duration // total time spent writing to disk -} - -func (s *TxStats) add(other *TxStats) { - s.PageCount += other.PageCount - s.PageAlloc += other.PageAlloc - s.CursorCount += other.CursorCount - s.NodeCount += other.NodeCount - s.NodeDeref += other.NodeDeref - s.Rebalance += other.Rebalance - s.RebalanceTime += other.RebalanceTime - s.Split += other.Split - s.Spill += other.Spill - s.SpillTime += other.SpillTime - s.Write += other.Write - s.WriteTime += other.WriteTime -} - -// Sub calculates and returns the difference between two sets of transaction stats. -// This is useful when obtaining stats at two different points and time and -// you need the performance counters that occurred within that time span. -func (s *TxStats) Sub(other *TxStats) TxStats { - var diff TxStats - diff.PageCount = s.PageCount - other.PageCount - diff.PageAlloc = s.PageAlloc - other.PageAlloc - diff.CursorCount = s.CursorCount - other.CursorCount - diff.NodeCount = s.NodeCount - other.NodeCount - diff.NodeDeref = s.NodeDeref - other.NodeDeref - diff.Rebalance = s.Rebalance - other.Rebalance - diff.RebalanceTime = s.RebalanceTime - other.RebalanceTime - diff.Split = s.Split - other.Split - diff.Spill = s.Spill - other.Spill - diff.SpillTime = s.SpillTime - other.SpillTime - diff.Write = s.Write - other.Write - diff.WriteTime = s.WriteTime - other.WriteTime - return diff -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx_test.go deleted file mode 100644 index 2201e79..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/boltdb/bolt/tx_test.go +++ /dev/null @@ -1,716 +0,0 @@ -package bolt_test - -import ( - "bytes" - "errors" - "fmt" - "log" - "os" - "testing" - - "github.com/boltdb/bolt" -) - -// Ensure that committing a closed transaction returns an error. -func TestTx_Commit_ErrTxClosed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - - if _, err := tx.CreateBucket([]byte("foo")); err != nil { - t.Fatal(err) - } - - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - - if err := tx.Commit(); err != bolt.ErrTxClosed { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that rolling back a closed transaction returns an error. -func TestTx_Rollback_ErrTxClosed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - if err := tx.Rollback(); err != bolt.ErrTxClosed { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that committing a read-only transaction returns an error. -func TestTx_Commit_ErrTxNotWritable(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - tx, err := db.Begin(false) - if err != nil { - t.Fatal(err) - } - if err := tx.Commit(); err != bolt.ErrTxNotWritable { - t.Fatal(err) - } -} - -// Ensure that a transaction can retrieve a cursor on the root bucket. -func TestTx_Cursor(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - - if _, err := tx.CreateBucket([]byte("woojits")); err != nil { - t.Fatal(err) - } - - c := tx.Cursor() - if k, v := c.First(); !bytes.Equal(k, []byte("widgets")) { - t.Fatalf("unexpected key: %v", k) - } else if v != nil { - t.Fatalf("unexpected value: %v", v) - } - - if k, v := c.Next(); !bytes.Equal(k, []byte("woojits")) { - t.Fatalf("unexpected key: %v", k) - } else if v != nil { - t.Fatalf("unexpected value: %v", v) - } - - if k, v := c.Next(); k != nil { - t.Fatalf("unexpected key: %v", k) - } else if v != nil { - t.Fatalf("unexpected value: %v", k) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that creating a bucket with a read-only transaction returns an error. -func TestTx_CreateBucket_ErrTxNotWritable(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.View(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("foo")) - if err != bolt.ErrTxNotWritable { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that creating a bucket on a closed transaction returns an error. -func TestTx_CreateBucket_ErrTxClosed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - - if _, err := tx.CreateBucket([]byte("foo")); err != bolt.ErrTxClosed { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that a Tx can retrieve a bucket. -func TestTx_Bucket(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - if tx.Bucket([]byte("widgets")) == nil { - t.Fatal("expected bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a Tx retrieving a non-existent key returns nil. -func TestTx_Get_NotFound(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if b.Get([]byte("no_such_key")) != nil { - t.Fatal("expected nil value") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can be created and retrieved. -func TestTx_CreateBucket(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - // Create a bucket. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } else if b == nil { - t.Fatal("expected bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Read the bucket through a separate transaction. - if err := db.View(func(tx *bolt.Tx) error { - if tx.Bucket([]byte("widgets")) == nil { - t.Fatal("expected bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can be created if it doesn't already exist. -func TestTx_CreateBucketIfNotExists(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - // Create bucket. - if b, err := tx.CreateBucketIfNotExists([]byte("widgets")); err != nil { - t.Fatal(err) - } else if b == nil { - t.Fatal("expected bucket") - } - - // Create bucket again. - if b, err := tx.CreateBucketIfNotExists([]byte("widgets")); err != nil { - t.Fatal(err) - } else if b == nil { - t.Fatal("expected bucket") - } - - return nil - }); err != nil { - t.Fatal(err) - } - - // Read the bucket through a separate transaction. - if err := db.View(func(tx *bolt.Tx) error { - if tx.Bucket([]byte("widgets")) == nil { - t.Fatal("expected bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure transaction returns an error if creating an unnamed bucket. -func TestTx_CreateBucketIfNotExists_ErrBucketNameRequired(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucketIfNotExists([]byte{}); err != bolt.ErrBucketNameRequired { - t.Fatalf("unexpected error: %s", err) - } - - if _, err := tx.CreateBucketIfNotExists(nil); err != bolt.ErrBucketNameRequired { - t.Fatalf("unexpected error: %s", err) - } - - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket cannot be created twice. -func TestTx_CreateBucket_ErrBucketExists(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - // Create a bucket. - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Create the same bucket again. - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket([]byte("widgets")); err != bolt.ErrBucketExists { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket is created with a non-blank name. -func TestTx_CreateBucket_ErrBucketNameRequired(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - if _, err := tx.CreateBucket(nil); err != bolt.ErrBucketNameRequired { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that a bucket can be deleted. -func TestTx_DeleteBucket(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - // Create a bucket and add a value. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - // Delete the bucket and make sure we can't get the value. - if err := db.Update(func(tx *bolt.Tx) error { - if err := tx.DeleteBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - if tx.Bucket([]byte("widgets")) != nil { - t.Fatal("unexpected bucket") - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.Update(func(tx *bolt.Tx) error { - // Create the bucket again and make sure there's not a phantom value. - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if v := b.Get([]byte("foo")); v != nil { - t.Fatalf("unexpected phantom value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that deleting a bucket on a closed transaction returns an error. -func TestTx_DeleteBucket_ErrTxClosed(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - tx, err := db.Begin(true) - if err != nil { - t.Fatal(err) - } - if err := tx.Commit(); err != nil { - t.Fatal(err) - } - if err := tx.DeleteBucket([]byte("foo")); err != bolt.ErrTxClosed { - t.Fatalf("unexpected error: %s", err) - } -} - -// Ensure that deleting a bucket with a read-only transaction returns an error. -func TestTx_DeleteBucket_ReadOnly(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.View(func(tx *bolt.Tx) error { - if err := tx.DeleteBucket([]byte("foo")); err != bolt.ErrTxNotWritable { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that nothing happens when deleting a bucket that doesn't exist. -func TestTx_DeleteBucket_NotFound(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - if err := tx.DeleteBucket([]byte("widgets")); err != bolt.ErrBucketNotFound { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that no error is returned when a tx.ForEach function does not return -// an error. -func TestTx_ForEach_NoError(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - - if err := tx.ForEach(func(name []byte, b *bolt.Bucket) error { - return nil - }); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that an error is returned when a tx.ForEach function returns an error. -func TestTx_ForEach_WithError(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - - marker := errors.New("marker") - if err := tx.ForEach(func(name []byte, b *bolt.Bucket) error { - return marker - }); err != marker { - t.Fatalf("unexpected error: %s", err) - } - return nil - }); err != nil { - t.Fatal(err) - } -} - -// Ensure that Tx commit handlers are called after a transaction successfully commits. -func TestTx_OnCommit(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var x int - if err := db.Update(func(tx *bolt.Tx) error { - tx.OnCommit(func() { x += 1 }) - tx.OnCommit(func() { x += 2 }) - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } else if x != 3 { - t.Fatalf("unexpected x: %d", x) - } -} - -// Ensure that Tx commit handlers are NOT called after a transaction rolls back. -func TestTx_OnCommit_Rollback(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - var x int - if err := db.Update(func(tx *bolt.Tx) error { - tx.OnCommit(func() { x += 1 }) - tx.OnCommit(func() { x += 2 }) - if _, err := tx.CreateBucket([]byte("widgets")); err != nil { - t.Fatal(err) - } - return errors.New("rollback this commit") - }); err == nil || err.Error() != "rollback this commit" { - t.Fatalf("unexpected error: %s", err) - } else if x != 0 { - t.Fatalf("unexpected x: %d", x) - } -} - -// Ensure that the database can be copied to a file path. -func TestTx_CopyFile(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - - path := tempfile() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte("bat")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - return tx.CopyFile(path, 0600) - }); err != nil { - t.Fatal(err) - } - - db2, err := bolt.Open(path, 0600, nil) - if err != nil { - t.Fatal(err) - } - - if err := db2.View(func(tx *bolt.Tx) error { - if v := tx.Bucket([]byte("widgets")).Get([]byte("foo")); !bytes.Equal(v, []byte("bar")) { - t.Fatalf("unexpected value: %v", v) - } - if v := tx.Bucket([]byte("widgets")).Get([]byte("baz")); !bytes.Equal(v, []byte("bat")) { - t.Fatalf("unexpected value: %v", v) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db2.Close(); err != nil { - t.Fatal(err) - } -} - -type failWriterError struct{} - -func (failWriterError) Error() string { - return "error injected for tests" -} - -type failWriter struct { - // fail after this many bytes - After int -} - -func (f *failWriter) Write(p []byte) (n int, err error) { - n = len(p) - if n > f.After { - n = f.After - err = failWriterError{} - } - f.After -= n - return n, err -} - -// Ensure that Copy handles write errors right. -func TestTx_CopyFile_Error_Meta(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte("bat")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - return tx.Copy(&failWriter{}) - }); err == nil || err.Error() != "meta 0 copy: error injected for tests" { - t.Fatalf("unexpected error: %v", err) - } -} - -// Ensure that Copy handles write errors right. -func TestTx_CopyFile_Error_Normal(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - t.Fatal(err) - } - if err := b.Put([]byte("baz"), []byte("bat")); err != nil { - t.Fatal(err) - } - return nil - }); err != nil { - t.Fatal(err) - } - - if err := db.View(func(tx *bolt.Tx) error { - return tx.Copy(&failWriter{3 * db.Info().PageSize}) - }); err == nil || err.Error() != "error injected for tests" { - t.Fatalf("unexpected error: %v", err) - } -} - -func ExampleTx_Rollback() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Create a bucket. - if err := db.Update(func(tx *bolt.Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }); err != nil { - log.Fatal(err) - } - - // Set a value for a key. - if err := db.Update(func(tx *bolt.Tx) error { - return tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")) - }); err != nil { - log.Fatal(err) - } - - // Update the key but rollback the transaction so it never saves. - tx, err := db.Begin(true) - if err != nil { - log.Fatal(err) - } - b := tx.Bucket([]byte("widgets")) - if err := b.Put([]byte("foo"), []byte("baz")); err != nil { - log.Fatal(err) - } - if err := tx.Rollback(); err != nil { - log.Fatal(err) - } - - // Ensure that our original value is still set. - if err := db.View(func(tx *bolt.Tx) error { - value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) - fmt.Printf("The value for 'foo' is still: %s\n", value) - return nil - }); err != nil { - log.Fatal(err) - } - - // Close database to release file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // The value for 'foo' is still: bar -} - -func ExampleTx_CopyFile() { - // Open the database. - db, err := bolt.Open(tempfile(), 0666, nil) - if err != nil { - log.Fatal(err) - } - defer os.Remove(db.Path()) - - // Create a bucket and a key. - if err := db.Update(func(tx *bolt.Tx) error { - b, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - return err - } - if err := b.Put([]byte("foo"), []byte("bar")); err != nil { - return err - } - return nil - }); err != nil { - log.Fatal(err) - } - - // Copy the database to another file. - toFile := tempfile() - if err := db.View(func(tx *bolt.Tx) error { - return tx.CopyFile(toFile, 0666) - }); err != nil { - log.Fatal(err) - } - defer os.Remove(toFile) - - // Open the cloned database. - db2, err := bolt.Open(toFile, 0666, nil) - if err != nil { - log.Fatal(err) - } - - // Ensure that the key exists in the copy. - if err := db2.View(func(tx *bolt.Tx) error { - value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) - fmt.Printf("The value for 'foo' in the clone is: %s\n", value) - return nil - }); err != nil { - log.Fatal(err) - } - - // Close database to release file lock. - if err := db.Close(); err != nil { - log.Fatal(err) - } - - if err := db2.Close(); err != nil { - log.Fatal(err) - } - - // Output: - // The value for 'foo' in the clone is: bar -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/LICENSE b/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/LICENSE deleted file mode 100644 index 720d6cd..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2016 Boss Sauce Creative, LLC. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/README.md b/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/README.md deleted file mode 100644 index 57f008c..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Reference - -A Ponzu addon to embed a reference to a content type from within another content type in the CMS. diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/reference.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/reference.go deleted file mode 100644 index 753fa41..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/bosssauce/reference/reference.go +++ /dev/null @@ -1,150 +0,0 @@ -// Package reference is a Ponzu addon to enable content editors to create -// references to other content types which are stored as query strings within -// the referencer's content DB -package reference - -import ( - "bytes" - "encoding/json" - "fmt" - "html/template" - "log" - "strings" - - "github.com/ponzu-cms/ponzu/management/editor" - "github.com/ponzu-cms/ponzu/system/addon" -) - -// Select returns the []byte of a HTML element plus internal with a label. -// It also includes repeat controllers (+ / -) so the element can be -// dynamically multiplied or reduced. -// IMPORTANT: -// The `fieldName` argument will cause a panic if it is not exactly the string -// form of the struct field that this editor input is representing -func SelectRepeater(fieldName string, p interface{}, attrs map[string]string, contentType, tmplString string) []byte { - scope := editor.TagNameFromStructField(fieldName, p) - html := bytes.Buffer{} - _, err := html.WriteString(``) - if err != nil { - log.Println("Error writing HTML string to SelectRepeater buffer") - return nil - } - - if _, ok := attrs["class"]; ok { - attrs["class"] += " browser-default" - } else { - attrs["class"] = "browser-default" - } - - // find the field values in p to determine if an option is pre-selected - fieldVals := editor.ValueFromStructField(fieldName, p) - vals := strings.Split(fieldVals, "__ponzu") - - options, err := encodeDataToOptions(contentType, tmplString) - if err != nil { - log.Println("Error encoding data to options for", contentType, err) - return nil - } - - for _, val := range vals { - sel := editor.NewElement("select", attrs["label"], fieldName, p, attrs) - var opts []*editor.Element - - // provide a call to action for the select element - cta := &editor.Element{ - TagName: "option", - Attrs: map[string]string{"disabled": "true", "selected": "true"}, - Data: "Select an option...", - ViewBuf: &bytes.Buffer{}, - } - - // provide a selection reset (will store empty string in db) - reset := &editor.Element{ - TagName: "option", - Attrs: map[string]string{"value": ""}, - Data: "None", - ViewBuf: &bytes.Buffer{}, - } - - opts = append(opts, cta, reset) - - for k, v := range options { - optAttrs := map[string]string{"value": k} - if k == val { - optAttrs["selected"] = "true" - } - opt := &editor.Element{ - TagName: "option", - Attrs: optAttrs, - Data: v, - ViewBuf: &bytes.Buffer{}, - } - - opts = append(opts, opt) - } - - _, err := html.Write(editor.DOMElementWithChildrenSelect(sel, opts)) - if err != nil { - log.Println("Error writing DOMElementWithChildrenSelect to SelectRepeater buffer") - return nil - } - } - - _, err = html.WriteString("") - if err != nil { - log.Println("Error writing HTML string to SelectRepeater buffer") - return nil - } - - return append(html.Bytes(), editor.RepeatController(fieldName, p, "select", ".input-field")...) -} - -func encodeDataToOptions(contentType, tmplString string) (map[string]string, error) { - // encode all content type from db into options map - // options in form of map["/api/content?type=&id="]t.String() - options := make(map[string]string) - - var all map[string]interface{} - j := addon.ContentAll(contentType) - - err := json.Unmarshal(j, &all) - if err != nil { - return nil, err - } - - // make template for option html display - tmpl := template.Must(template.New(contentType).Parse(tmplString)) - - // make data something usable to iterate over and assign options - data := all["data"].([]interface{}) - - for i := range data { - item := data[i].(map[string]interface{}) - k := fmt.Sprintf("/api/content?type=%s&id=%.0f", contentType, item["id"].(float64)) - v := &bytes.Buffer{} - err := tmpl.Execute(v, item) - if err != nil { - return nil, fmt.Errorf( - "Error executing template for reference of %s: %s", - contentType, err.Error()) - } - - options[k] = v.String() - } - - return options, nil -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/.travis.yml b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/.travis.yml deleted file mode 100644 index 6f440f1..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: go -sudo: false - -matrix: - include: - - go: 1.3 - - go: 1.4 - - go: 1.5 - - go: 1.6 - - go: 1.7 - - 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/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/LICENSE b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/LICENSE deleted file mode 100644 index 0e5fb87..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2012 Rodrigo Moraes. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/README.md b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/README.md deleted file mode 100644 index e9936d9..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/README.md +++ /dev/null @@ -1,66 +0,0 @@ -schema -====== -[![GoDoc](https://godoc.org/github.com/gorilla/schema?status.svg)](https://godoc.org/github.com/gorilla/schema) [![Build Status](https://travis-ci.org/gorilla/schema.png?branch=master)](https://travis-ci.org/gorilla/schema) - -Package gorilla/schema fills a struct with form values. - -## Example - -Here's a quick example: we parse POST form values and then decode them into a struct: - -```go -// Set a Decoder instance as a package global, because it caches -// meta-data about structs, and an instance can be shared safely. -var decoder = schema.NewDecoder() - -type Person struct { - Name string - Phone string -} - -func MyHandler(w http.ResponseWriter, r *http.Request) { - err := r.ParseForm() - if err != nil { - // Handle error - } - - var person Person - - // r.PostForm is a map of our POST form values - err := decoder.Decode(&person, r.PostForm) - if err != nil { - // Handle error - } - - // Do something with person.Name or person.Phone -} -``` - -To define custom names for fields, use a struct tag "schema". To not populate certain fields, use a dash for the name and it will be ignored: - -```go -type Person struct { - Name string `schema:"name"` // custom name - Phone string `schema:"phone"` // custom name - Admin bool `schema:"-"` // this field is never set -} -``` - -The supported field types in the destination struct are: - -* bool -* float variants (float32, float64) -* int variants (int, int8, int16, int32, int64) -* string -* uint variants (uint, uint8, uint16, uint32, uint64) -* struct -* a pointer to one of the above types -* a slice or a pointer to a slice of one of the above types - -Unsupported types are simply ignored, however custom types can be registered to be converted. - -More examples are available on the Gorilla website: http://www.gorillatoolkit.org/pkg/schema - -## License - -BSD licensed. See the LICENSE file for details. diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/cache.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/cache.go deleted file mode 100644 index e0f7566..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/cache.go +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2012 The Gorilla 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 schema - -import ( - "errors" - "reflect" - "strconv" - "strings" - "sync" -) - -var invalidPath = errors.New("schema: invalid path") - -// newCache returns a new cache. -func newCache() *cache { - c := cache{ - m: make(map[reflect.Type]*structInfo), - conv: make(map[reflect.Kind]Converter), - regconv: make(map[reflect.Type]Converter), - tag: "schema", - } - for k, v := range converters { - c.conv[k] = v - } - return &c -} - -// cache caches meta-data about a struct. -type cache struct { - l sync.RWMutex - m map[reflect.Type]*structInfo - conv map[reflect.Kind]Converter - regconv map[reflect.Type]Converter - tag string -} - -// parsePath parses a path in dotted notation verifying that it is a valid -// path to a struct field. -// -// It returns "path parts" which contain indices to fields to be used by -// reflect.Value.FieldByString(). Multiple parts are required for slices of -// structs. -func (c *cache) parsePath(p string, t reflect.Type) ([]pathPart, error) { - var struc *structInfo - var field *fieldInfo - var index64 int64 - var err error - parts := make([]pathPart, 0) - path := make([]string, 0) - keys := strings.Split(p, ".") - for i := 0; i < len(keys); i++ { - if t.Kind() != reflect.Struct { - return nil, invalidPath - } - if struc = c.get(t); struc == nil { - return nil, invalidPath - } - if field = struc.get(keys[i]); field == nil { - return nil, invalidPath - } - // Valid field. Append index. - path = append(path, field.name) - if field.ss { - // Parse a special case: slices of structs. - // i+1 must be the slice index. - // - // Now that struct can implements TextUnmarshaler interface, - // we don't need to force the struct's fields to appear in the path. - // So checking i+2 is not necessary anymore. - i++ - if i+1 > len(keys) { - return nil, invalidPath - } - if index64, err = strconv.ParseInt(keys[i], 10, 0); err != nil { - return nil, invalidPath - } - parts = append(parts, pathPart{ - path: path, - field: field, - index: int(index64), - }) - path = make([]string, 0) - - // Get the next struct type, dropping ptrs. - if field.typ.Kind() == reflect.Ptr { - t = field.typ.Elem() - } else { - t = field.typ - } - if t.Kind() == reflect.Slice { - t = t.Elem() - if t.Kind() == reflect.Ptr { - t = t.Elem() - } - } - } else if field.typ.Kind() == reflect.Ptr { - t = field.typ.Elem() - } else { - t = field.typ - } - } - // Add the remaining. - parts = append(parts, pathPart{ - path: path, - field: field, - index: -1, - }) - return parts, nil -} - -// get returns a cached structInfo, creating it if necessary. -func (c *cache) get(t reflect.Type) *structInfo { - c.l.RLock() - info := c.m[t] - c.l.RUnlock() - if info == nil { - info = c.create(t, nil) - c.l.Lock() - c.m[t] = info - c.l.Unlock() - } - return info -} - -// create creates a structInfo with meta-data about a struct. -func (c *cache) create(t reflect.Type, info *structInfo) *structInfo { - if info == nil { - info = &structInfo{fields: []*fieldInfo{}} - } - for i := 0; i < t.NumField(); i++ { - field := t.Field(i) - if field.Anonymous { - ft := field.Type - if ft.Kind() == reflect.Ptr { - ft = ft.Elem() - } - if ft.Kind() == reflect.Struct { - c.create(ft, info) - } - } - c.createField(field, info) - } - return info -} - -// createField creates a fieldInfo for the given field. -func (c *cache) createField(field reflect.StructField, info *structInfo) { - alias, options := fieldAlias(field, c.tag) - if alias == "-" { - // Ignore this field. - return - } - // Check if the type is supported and don't cache it if not. - // First let's get the basic type. - isSlice, isStruct := false, false - ft := field.Type - if ft.Kind() == reflect.Ptr { - ft = ft.Elem() - } - if isSlice = ft.Kind() == reflect.Slice; isSlice { - ft = ft.Elem() - if ft.Kind() == reflect.Ptr { - ft = ft.Elem() - } - } - if ft.Kind() == reflect.Array { - ft = ft.Elem() - if ft.Kind() == reflect.Ptr { - ft = ft.Elem() - } - } - if isStruct = ft.Kind() == reflect.Struct; !isStruct { - if conv := c.conv[ft.Kind()]; conv == nil { - // Type is not supported. - return - } - } - - info.fields = append(info.fields, &fieldInfo{ - typ: field.Type, - name: field.Name, - ss: isSlice && isStruct, - alias: alias, - required: options.Contains("required"), - }) -} - -// converter returns the converter for a type. -func (c *cache) converter(t reflect.Type) Converter { - conv := c.regconv[t] - if conv == nil { - conv = c.conv[t.Kind()] - } - return conv -} - -// ---------------------------------------------------------------------------- - -type structInfo struct { - fields []*fieldInfo -} - -func (i *structInfo) get(alias string) *fieldInfo { - for _, field := range i.fields { - if strings.EqualFold(field.alias, alias) { - return field - } - } - return nil -} - -type fieldInfo struct { - typ reflect.Type - name string // field name in the struct. - ss bool // true if this is a slice of structs. - alias string - required bool // tag option -} - -type pathPart struct { - field *fieldInfo - path []string // path to the field: walks structs using field names. - index int // struct index in slices of structs. -} - -// ---------------------------------------------------------------------------- - -// fieldAlias parses a field tag to get a field alias. -func fieldAlias(field reflect.StructField, tagName string) (alias string, options tagOptions) { - if tag := field.Tag.Get(tagName); tag != "" { - alias, options = parseTag(tag) - } - if alias == "" { - alias = field.Name - } - return alias, options -} - -// tagOptions is the string following a comma in a struct field's tag, or -// the empty string. It does not include the leading comma. -type tagOptions []string - -// parseTag splits a struct field's url tag into its name and comma-separated -// options. -func parseTag(tag string) (string, tagOptions) { - s := strings.Split(tag, ",") - return s[0], s[1:] -} - -// Contains checks whether the tagOptions contains the specified option. -func (o tagOptions) Contains(option string) bool { - for _, s := range o { - if s == option { - return true - } - } - return false -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/converter.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/converter.go deleted file mode 100644 index b33e942..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/converter.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2012 The Gorilla 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 schema - -import ( - "reflect" - "strconv" -) - -type Converter func(string) reflect.Value - -var ( - invalidValue = reflect.Value{} - boolType = reflect.Bool - float32Type = reflect.Float32 - float64Type = reflect.Float64 - intType = reflect.Int - int8Type = reflect.Int8 - int16Type = reflect.Int16 - int32Type = reflect.Int32 - int64Type = reflect.Int64 - stringType = reflect.String - uintType = reflect.Uint - uint8Type = reflect.Uint8 - uint16Type = reflect.Uint16 - uint32Type = reflect.Uint32 - uint64Type = reflect.Uint64 -) - -// Default converters for basic types. -var converters = map[reflect.Kind]Converter{ - boolType: convertBool, - float32Type: convertFloat32, - float64Type: convertFloat64, - intType: convertInt, - int8Type: convertInt8, - int16Type: convertInt16, - int32Type: convertInt32, - int64Type: convertInt64, - stringType: convertString, - uintType: convertUint, - uint8Type: convertUint8, - uint16Type: convertUint16, - uint32Type: convertUint32, - uint64Type: convertUint64, -} - -func convertBool(value string) reflect.Value { - if value == "on" { - return reflect.ValueOf(true) - } else if v, err := strconv.ParseBool(value); err == nil { - return reflect.ValueOf(v) - } - return invalidValue -} - -func convertFloat32(value string) reflect.Value { - if v, err := strconv.ParseFloat(value, 32); err == nil { - return reflect.ValueOf(float32(v)) - } - return invalidValue -} - -func convertFloat64(value string) reflect.Value { - if v, err := strconv.ParseFloat(value, 64); err == nil { - return reflect.ValueOf(v) - } - return invalidValue -} - -func convertInt(value string) reflect.Value { - if v, err := strconv.ParseInt(value, 10, 0); err == nil { - return reflect.ValueOf(int(v)) - } - return invalidValue -} - -func convertInt8(value string) reflect.Value { - if v, err := strconv.ParseInt(value, 10, 8); err == nil { - return reflect.ValueOf(int8(v)) - } - return invalidValue -} - -func convertInt16(value string) reflect.Value { - if v, err := strconv.ParseInt(value, 10, 16); err == nil { - return reflect.ValueOf(int16(v)) - } - return invalidValue -} - -func convertInt32(value string) reflect.Value { - if v, err := strconv.ParseInt(value, 10, 32); err == nil { - return reflect.ValueOf(int32(v)) - } - return invalidValue -} - -func convertInt64(value string) reflect.Value { - if v, err := strconv.ParseInt(value, 10, 64); err == nil { - return reflect.ValueOf(v) - } - return invalidValue -} - -func convertString(value string) reflect.Value { - return reflect.ValueOf(value) -} - -func convertUint(value string) reflect.Value { - if v, err := strconv.ParseUint(value, 10, 0); err == nil { - return reflect.ValueOf(uint(v)) - } - return invalidValue -} - -func convertUint8(value string) reflect.Value { - if v, err := strconv.ParseUint(value, 10, 8); err == nil { - return reflect.ValueOf(uint8(v)) - } - return invalidValue -} - -func convertUint16(value string) reflect.Value { - if v, err := strconv.ParseUint(value, 10, 16); err == nil { - return reflect.ValueOf(uint16(v)) - } - return invalidValue -} - -func convertUint32(value string) reflect.Value { - if v, err := strconv.ParseUint(value, 10, 32); err == nil { - return reflect.ValueOf(uint32(v)) - } - return invalidValue -} - -func convertUint64(value string) reflect.Value { - if v, err := strconv.ParseUint(value, 10, 64); err == nil { - return reflect.ValueOf(v) - } - return invalidValue -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder.go deleted file mode 100644 index 7ebe1b1..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder.go +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright 2012 The Gorilla 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 schema - -import ( - "encoding" - "errors" - "fmt" - "reflect" - "strings" -) - -// NewDecoder returns a new Decoder. -func NewDecoder() *Decoder { - return &Decoder{cache: newCache()} -} - -// Decoder decodes values from a map[string][]string to a struct. -type Decoder struct { - cache *cache - zeroEmpty bool - ignoreUnknownKeys bool -} - -// SetAliasTag changes the tag used to locate custom field aliases. -// The default tag is "schema". -func (d *Decoder) SetAliasTag(tag string) { - d.cache.tag = tag -} - -// ZeroEmpty controls the behaviour when the decoder encounters empty values -// in a map. -// If z is true and a key in the map has the empty string as a value -// then the corresponding struct field is set to the zero value. -// If z is false then empty strings are ignored. -// -// The default value is false, that is empty values do not change -// the value of the struct field. -func (d *Decoder) ZeroEmpty(z bool) { - d.zeroEmpty = z -} - -// IgnoreUnknownKeys controls the behaviour when the decoder encounters unknown -// keys in the map. -// If i is true and an unknown field is encountered, it is ignored. This is -// similar to how unknown keys are handled by encoding/json. -// If i is false then Decode will return an error. Note that any valid keys -// will still be decoded in to the target struct. -// -// To preserve backwards compatibility, the default value is false. -func (d *Decoder) IgnoreUnknownKeys(i bool) { - d.ignoreUnknownKeys = i -} - -// RegisterConverter registers a converter function for a custom type. -func (d *Decoder) RegisterConverter(value interface{}, converterFunc Converter) { - d.cache.regconv[reflect.TypeOf(value)] = converterFunc -} - -// Decode decodes a map[string][]string to a struct. -// -// The first parameter must be a pointer to a struct. -// -// The second parameter is a map, typically url.Values from an HTTP request. -// Keys are "paths" in dotted notation to the struct fields and nested structs. -// -// See the package documentation for a full explanation of the mechanics. -func (d *Decoder) Decode(dst interface{}, src map[string][]string) error { - v := reflect.ValueOf(dst) - if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { - return errors.New("schema: interface must be a pointer to struct") - } - v = v.Elem() - t := v.Type() - errors := MultiError{} - for path, values := range src { - if parts, err := d.cache.parsePath(path, t); err == nil { - if err = d.decode(v, path, parts, values); err != nil { - errors[path] = err - } - } else if !d.ignoreUnknownKeys { - errors[path] = fmt.Errorf("schema: invalid path %q", path) - } - } - if len(errors) > 0 { - return errors - } - return d.checkRequired(t, src, "") -} - -// checkRequired checks whether requred field empty -// -// check type t recursively if t has struct fields, and prefix is same as parsePath: in dotted notation -// -// src is the source map for decoding, we use it here to see if those required fields are included in src -func (d *Decoder) checkRequired(t reflect.Type, src map[string][]string, prefix string) error { - struc := d.cache.get(t) - if struc == nil { - // unexpect, cache.get never return nil - return errors.New("cache fail") - } - - for _, f := range struc.fields { - if f.typ.Kind() == reflect.Struct { - err := d.checkRequired(f.typ, src, prefix+f.alias+".") - if err != nil { - return err - } - } - if f.required { - key := f.alias - if prefix != "" { - key = prefix + key - } - if isEmpty(f.typ, src[key]) { - return fmt.Errorf("%v is empty", key) - } - } - } - return nil -} - -// isEmpty returns true if value is empty for specific type -func isEmpty(t reflect.Type, value []string) bool { - if len(value) == 0 { - return true - } - switch t.Kind() { - case boolType, float32Type, float64Type, intType, int8Type, int32Type, int64Type, stringType, uint8Type, uint16Type, uint32Type, uint64Type: - return len(value[0]) == 0 - } - return false -} - -// decode fills a struct field using a parsed path. -func (d *Decoder) decode(v reflect.Value, path string, parts []pathPart, values []string) error { - // Get the field walking the struct fields by index. - for _, name := range parts[0].path { - if v.Type().Kind() == reflect.Ptr { - if v.IsNil() { - v.Set(reflect.New(v.Type().Elem())) - } - v = v.Elem() - } - v = v.FieldByName(name) - } - - // Don't even bother for unexported fields. - if !v.CanSet() { - return nil - } - - // Dereference if needed. - t := v.Type() - if t.Kind() == reflect.Ptr { - t = t.Elem() - if v.IsNil() { - v.Set(reflect.New(t)) - } - v = v.Elem() - } - - // Slice of structs. Let's go recursive. - if len(parts) > 1 { - idx := parts[0].index - if v.IsNil() || v.Len() < idx+1 { - value := reflect.MakeSlice(t, idx+1, idx+1) - if v.Len() < idx+1 { - // Resize it. - reflect.Copy(value, v) - } - v.Set(value) - } - return d.decode(v.Index(idx), path, parts[1:], values) - } - - // Get the converter early in case there is one for a slice type. - conv := d.cache.converter(t) - if conv == nil && t.Kind() == reflect.Slice { - var items []reflect.Value - elemT := t.Elem() - isPtrElem := elemT.Kind() == reflect.Ptr - if isPtrElem { - elemT = elemT.Elem() - } - - // Try to get a converter for the element type. - conv := d.cache.converter(elemT) - if conv == nil { - // As we are not dealing with slice of structs here, we don't need to check if the type - // implements TextUnmarshaler interface - return fmt.Errorf("schema: converter not found for %v", elemT) - } - - for key, value := range values { - if value == "" { - if d.zeroEmpty { - items = append(items, reflect.Zero(elemT)) - } - } else if item := conv(value); item.IsValid() { - if isPtrElem { - ptr := reflect.New(elemT) - ptr.Elem().Set(item) - item = ptr - } - if item.Type() != elemT && !isPtrElem { - item = item.Convert(elemT) - } - items = append(items, item) - } else { - if strings.Contains(value, ",") { - values := strings.Split(value, ",") - for _, value := range values { - if value == "" { - if d.zeroEmpty { - items = append(items, reflect.Zero(elemT)) - } - } else if item := conv(value); item.IsValid() { - if isPtrElem { - ptr := reflect.New(elemT) - ptr.Elem().Set(item) - item = ptr - } - if item.Type() != elemT && !isPtrElem { - item = item.Convert(elemT) - } - items = append(items, item) - } else { - return ConversionError{ - Key: path, - Type: elemT, - Index: key, - } - } - } - } else { - return ConversionError{ - Key: path, - Type: elemT, - Index: key, - } - } - } - } - value := reflect.Append(reflect.MakeSlice(t, 0, 0), items...) - v.Set(value) - } else { - val := "" - // Use the last value provided if any values were provided - if len(values) > 0 { - val = values[len(values)-1] - } - - if val == "" { - if d.zeroEmpty { - v.Set(reflect.Zero(t)) - } - } else if conv != nil { - if value := conv(val); value.IsValid() { - v.Set(value.Convert(t)) - } else { - return ConversionError{ - Key: path, - Type: t, - Index: -1, - } - } - } else { - // When there's no registered conversion for the custom type, we will check if the type - // implements the TextUnmarshaler interface. As the UnmarshalText function should be applied - // to the pointer of the type, we convert the value to pointer. - if v.CanAddr() { - v = v.Addr() - } - - if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { - if err := u.UnmarshalText([]byte(val)); err != nil { - return ConversionError{ - Key: path, - Type: t, - Index: -1, - Err: err, - } - } - - } else { - return fmt.Errorf("schema: converter not found for %v", t) - } - } - } - return nil -} - -// Errors --------------------------------------------------------------------- - -// ConversionError stores information about a failed conversion. -type ConversionError struct { - Key string // key from the source map. - Type reflect.Type // expected type of elem - Index int // index for multi-value fields; -1 for single-value fields. - Err error // low-level error (when it exists) -} - -func (e ConversionError) Error() string { - var output string - - if e.Index < 0 { - output = fmt.Sprintf("schema: error converting value for %q", e.Key) - } else { - output = fmt.Sprintf("schema: error converting value for index %d of %q", - e.Index, e.Key) - } - - if e.Err != nil { - output = fmt.Sprintf("%s. Details: %s", output, e.Err) - } - - return output -} - -// MultiError stores multiple decoding errors. -// -// Borrowed from the App Engine SDK. -type MultiError map[string]error - -func (e MultiError) Error() string { - s := "" - for _, err := range e { - s = err.Error() - break - } - switch len(e) { - case 0: - return "(0 errors)" - case 1: - return s - case 2: - return s + " (and 1 other error)" - } - return fmt.Sprintf("%s (and %d other errors)", s, len(e)-1) -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder_test.go deleted file mode 100644 index 4593916..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/decoder_test.go +++ /dev/null @@ -1,1460 +0,0 @@ -// Copyright 2012 The Gorilla 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 schema - -import ( - "encoding/hex" - "errors" - "reflect" - "strings" - "testing" - "time" -) - -type IntAlias int - -// All cases we want to cover, in a nutshell. -type S1 struct { - F01 int `schema:"f1"` - F02 *int `schema:"f2"` - F03 []int `schema:"f3"` - F04 []*int `schema:"f4"` - F05 *[]int `schema:"f5"` - F06 *[]*int `schema:"f6"` - F07 S2 `schema:"f7"` - F08 *S1 `schema:"f8"` - F09 int `schema:"-"` - F10 []S1 `schema:"f10"` - F11 []*S1 `schema:"f11"` - F12 *[]S1 `schema:"f12"` - F13 *[]*S1 `schema:"f13"` - F14 int `schema:"f14"` - F15 IntAlias `schema:"f15"` - F16 []IntAlias `schema:"f16"` - F17 S19 `schema:"f17"` -} - -type S2 struct { - F01 *[]*int `schema:"f1"` -} - -type S19 [2]byte - -func (id *S19) UnmarshalText(text []byte) error { - buf, err := hex.DecodeString(string(text)) - if err != nil { - return err - } - if len(buf) > len(*id) { - return errors.New("out of range") - } - for i := range buf { - (*id)[i] = buf[i] - } - return nil -} - -func TestAll(t *testing.T) { - v := map[string][]string{ - "f1": {"1"}, - "f2": {"2"}, - "f3": {"31", "32"}, - "f4": {"41", "42"}, - "f5": {"51", "52"}, - "f6": {"61", "62"}, - "f7.f1": {"71", "72"}, - "f8.f8.f7.f1": {"81", "82"}, - "f9": {"9"}, - "f10.0.f10.0.f6": {"101", "102"}, - "f10.0.f10.1.f6": {"103", "104"}, - "f11.0.f11.0.f6": {"111", "112"}, - "f11.0.f11.1.f6": {"113", "114"}, - "f12.0.f12.0.f6": {"121", "122"}, - "f12.0.f12.1.f6": {"123", "124"}, - "f13.0.f13.0.f6": {"131", "132"}, - "f13.0.f13.1.f6": {"133", "134"}, - "f14": {}, - "f15": {"151"}, - "f16": {"161", "162"}, - "f17": {"1a2b"}, - } - f2 := 2 - f41, f42 := 41, 42 - f61, f62 := 61, 62 - f71, f72 := 71, 72 - f81, f82 := 81, 82 - f101, f102, f103, f104 := 101, 102, 103, 104 - f111, f112, f113, f114 := 111, 112, 113, 114 - f121, f122, f123, f124 := 121, 122, 123, 124 - f131, f132, f133, f134 := 131, 132, 133, 134 - var f151 IntAlias = 151 - var f161, f162 IntAlias = 161, 162 - e := S1{ - F01: 1, - F02: &f2, - F03: []int{31, 32}, - F04: []*int{&f41, &f42}, - F05: &[]int{51, 52}, - F06: &[]*int{&f61, &f62}, - F07: S2{ - F01: &[]*int{&f71, &f72}, - }, - F08: &S1{ - F08: &S1{ - F07: S2{ - F01: &[]*int{&f81, &f82}, - }, - }, - }, - F09: 0, - F10: []S1{ - S1{ - F10: []S1{ - S1{F06: &[]*int{&f101, &f102}}, - S1{F06: &[]*int{&f103, &f104}}, - }, - }, - }, - F11: []*S1{ - &S1{ - F11: []*S1{ - &S1{F06: &[]*int{&f111, &f112}}, - &S1{F06: &[]*int{&f113, &f114}}, - }, - }, - }, - F12: &[]S1{ - S1{ - F12: &[]S1{ - S1{F06: &[]*int{&f121, &f122}}, - S1{F06: &[]*int{&f123, &f124}}, - }, - }, - }, - F13: &[]*S1{ - &S1{ - F13: &[]*S1{ - &S1{F06: &[]*int{&f131, &f132}}, - &S1{F06: &[]*int{&f133, &f134}}, - }, - }, - }, - F14: 0, - F15: f151, - F16: []IntAlias{f161, f162}, - F17: S19{0x1a, 0x2b}, - } - - s := &S1{} - _ = NewDecoder().Decode(s, v) - - vals := func(values []*int) []int { - r := make([]int, len(values)) - for k, v := range values { - r[k] = *v - } - return r - } - - if s.F01 != e.F01 { - t.Errorf("f1: expected %v, got %v", e.F01, s.F01) - } - if s.F02 == nil { - t.Errorf("f2: expected %v, got nil", *e.F02) - } else if *s.F02 != *e.F02 { - t.Errorf("f2: expected %v, got %v", *e.F02, *s.F02) - } - if s.F03 == nil { - t.Errorf("f3: expected %v, got nil", e.F03) - } else if len(s.F03) != 2 || s.F03[0] != e.F03[0] || s.F03[1] != e.F03[1] { - t.Errorf("f3: expected %v, got %v", e.F03, s.F03) - } - if s.F04 == nil { - t.Errorf("f4: expected %v, got nil", e.F04) - } else { - if len(s.F04) != 2 || *(s.F04)[0] != *(e.F04)[0] || *(s.F04)[1] != *(e.F04)[1] { - t.Errorf("f4: expected %v, got %v", vals(e.F04), vals(s.F04)) - } - } - if s.F05 == nil { - t.Errorf("f5: expected %v, got nil", e.F05) - } else { - sF05, eF05 := *s.F05, *e.F05 - if len(sF05) != 2 || sF05[0] != eF05[0] || sF05[1] != eF05[1] { - t.Errorf("f5: expected %v, got %v", eF05, sF05) - } - } - if s.F06 == nil { - t.Errorf("f6: expected %v, got nil", vals(*e.F06)) - } else { - sF06, eF06 := *s.F06, *e.F06 - if len(sF06) != 2 || *(sF06)[0] != *(eF06)[0] || *(sF06)[1] != *(eF06)[1] { - t.Errorf("f6: expected %v, got %v", vals(eF06), vals(sF06)) - } - } - if s.F07.F01 == nil { - t.Errorf("f7.f1: expected %v, got nil", vals(*e.F07.F01)) - } else { - sF07, eF07 := *s.F07.F01, *e.F07.F01 - if len(sF07) != 2 || *(sF07)[0] != *(eF07)[0] || *(sF07)[1] != *(eF07)[1] { - t.Errorf("f7.f1: expected %v, got %v", vals(eF07), vals(sF07)) - } - } - if s.F08 == nil { - t.Errorf("f8: got nil") - } else if s.F08.F08 == nil { - t.Errorf("f8.f8: got nil") - } else if s.F08.F08.F07.F01 == nil { - t.Errorf("f8.f8.f7.f1: expected %v, got nil", vals(*e.F08.F08.F07.F01)) - } else { - sF08, eF08 := *s.F08.F08.F07.F01, *e.F08.F08.F07.F01 - if len(sF08) != 2 || *(sF08)[0] != *(eF08)[0] || *(sF08)[1] != *(eF08)[1] { - t.Errorf("f8.f8.f7.f1: expected %v, got %v", vals(eF08), vals(sF08)) - } - } - if s.F09 != e.F09 { - t.Errorf("f9: expected %v, got %v", e.F09, s.F09) - } - if s.F10 == nil { - t.Errorf("f10: got nil") - } else if len(s.F10) != 1 { - t.Errorf("f10: expected 1 element, got %v", s.F10) - } else { - if len(s.F10[0].F10) != 2 { - t.Errorf("f10.0.f10: expected 1 element, got %v", s.F10[0].F10) - } else { - sF10, eF10 := *s.F10[0].F10[0].F06, *e.F10[0].F10[0].F06 - if sF10 == nil { - t.Errorf("f10.0.f10.0.f6: expected %v, got nil", vals(eF10)) - } else { - if len(sF10) != 2 || *(sF10)[0] != *(eF10)[0] || *(sF10)[1] != *(eF10)[1] { - t.Errorf("f10.0.f10.0.f6: expected %v, got %v", vals(eF10), vals(sF10)) - } - } - sF10, eF10 = *s.F10[0].F10[1].F06, *e.F10[0].F10[1].F06 - if sF10 == nil { - t.Errorf("f10.0.f10.0.f6: expected %v, got nil", vals(eF10)) - } else { - if len(sF10) != 2 || *(sF10)[0] != *(eF10)[0] || *(sF10)[1] != *(eF10)[1] { - t.Errorf("f10.0.f10.0.f6: expected %v, got %v", vals(eF10), vals(sF10)) - } - } - } - } - if s.F11 == nil { - t.Errorf("f11: got nil") - } else if len(s.F11) != 1 { - t.Errorf("f11: expected 1 element, got %v", s.F11) - } else { - if len(s.F11[0].F11) != 2 { - t.Errorf("f11.0.f11: expected 1 element, got %v", s.F11[0].F11) - } else { - sF11, eF11 := *s.F11[0].F11[0].F06, *e.F11[0].F11[0].F06 - if sF11 == nil { - t.Errorf("f11.0.f11.0.f6: expected %v, got nil", vals(eF11)) - } else { - if len(sF11) != 2 || *(sF11)[0] != *(eF11)[0] || *(sF11)[1] != *(eF11)[1] { - t.Errorf("f11.0.f11.0.f6: expected %v, got %v", vals(eF11), vals(sF11)) - } - } - sF11, eF11 = *s.F11[0].F11[1].F06, *e.F11[0].F11[1].F06 - if sF11 == nil { - t.Errorf("f11.0.f11.0.f6: expected %v, got nil", vals(eF11)) - } else { - if len(sF11) != 2 || *(sF11)[0] != *(eF11)[0] || *(sF11)[1] != *(eF11)[1] { - t.Errorf("f11.0.f11.0.f6: expected %v, got %v", vals(eF11), vals(sF11)) - } - } - } - } - if s.F12 == nil { - t.Errorf("f12: got nil") - } else if len(*s.F12) != 1 { - t.Errorf("f12: expected 1 element, got %v", *s.F12) - } else { - sF12, eF12 := *(s.F12), *(e.F12) - if len(*sF12[0].F12) != 2 { - t.Errorf("f12.0.f12: expected 1 element, got %v", *sF12[0].F12) - } else { - sF122, eF122 := *(*sF12[0].F12)[0].F06, *(*eF12[0].F12)[0].F06 - if sF122 == nil { - t.Errorf("f12.0.f12.0.f6: expected %v, got nil", vals(eF122)) - } else { - if len(sF122) != 2 || *(sF122)[0] != *(eF122)[0] || *(sF122)[1] != *(eF122)[1] { - t.Errorf("f12.0.f12.0.f6: expected %v, got %v", vals(eF122), vals(sF122)) - } - } - sF122, eF122 = *(*sF12[0].F12)[1].F06, *(*eF12[0].F12)[1].F06 - if sF122 == nil { - t.Errorf("f12.0.f12.0.f6: expected %v, got nil", vals(eF122)) - } else { - if len(sF122) != 2 || *(sF122)[0] != *(eF122)[0] || *(sF122)[1] != *(eF122)[1] { - t.Errorf("f12.0.f12.0.f6: expected %v, got %v", vals(eF122), vals(sF122)) - } - } - } - } - if s.F13 == nil { - t.Errorf("f13: got nil") - } else if len(*s.F13) != 1 { - t.Errorf("f13: expected 1 element, got %v", *s.F13) - } else { - sF13, eF13 := *(s.F13), *(e.F13) - if len(*sF13[0].F13) != 2 { - t.Errorf("f13.0.f13: expected 1 element, got %v", *sF13[0].F13) - } else { - sF132, eF132 := *(*sF13[0].F13)[0].F06, *(*eF13[0].F13)[0].F06 - if sF132 == nil { - t.Errorf("f13.0.f13.0.f6: expected %v, got nil", vals(eF132)) - } else { - if len(sF132) != 2 || *(sF132)[0] != *(eF132)[0] || *(sF132)[1] != *(eF132)[1] { - t.Errorf("f13.0.f13.0.f6: expected %v, got %v", vals(eF132), vals(sF132)) - } - } - sF132, eF132 = *(*sF13[0].F13)[1].F06, *(*eF13[0].F13)[1].F06 - if sF132 == nil { - t.Errorf("f13.0.f13.0.f6: expected %v, got nil", vals(eF132)) - } else { - if len(sF132) != 2 || *(sF132)[0] != *(eF132)[0] || *(sF132)[1] != *(eF132)[1] { - t.Errorf("f13.0.f13.0.f6: expected %v, got %v", vals(eF132), vals(sF132)) - } - } - } - } - if s.F14 != e.F14 { - t.Errorf("f14: expected %v, got %v", e.F14, s.F14) - } - if s.F15 != e.F15 { - t.Errorf("f15: expected %v, got %v", e.F15, s.F15) - } - if s.F16 == nil { - t.Errorf("f16: nil") - } else if len(s.F16) != len(e.F16) { - t.Errorf("f16: expected len %d, got %d", len(e.F16), len(s.F16)) - } else if !reflect.DeepEqual(s.F16, e.F16) { - t.Errorf("f16: expected %v, got %v", e.F16, s.F16) - } - if s.F17 != e.F17 { - t.Errorf("f17: expected %v, got %v", e.F17, s.F17) - } -} - -func BenchmarkAll(b *testing.B) { - v := map[string][]string{ - "f1": {"1"}, - "f2": {"2"}, - "f3": {"31", "32"}, - "f4": {"41", "42"}, - "f5": {"51", "52"}, - "f6": {"61", "62"}, - "f7.f1": {"71", "72"}, - "f8.f8.f7.f1": {"81", "82"}, - "f9": {"9"}, - "f10.0.f10.0.f6": {"101", "102"}, - "f10.0.f10.1.f6": {"103", "104"}, - "f11.0.f11.0.f6": {"111", "112"}, - "f11.0.f11.1.f6": {"113", "114"}, - "f12.0.f12.0.f6": {"121", "122"}, - "f12.0.f12.1.f6": {"123", "124"}, - "f13.0.f13.0.f6": {"131", "132"}, - "f13.0.f13.1.f6": {"133", "134"}, - } - - b.ResetTimer() - - for i := 0; i < b.N; i++ { - s := &S1{} - _ = NewDecoder().Decode(s, v) - } -} - -// ---------------------------------------------------------------------------- - -type S3 struct { - F01 bool - F02 float32 - F03 float64 - F04 int - F05 int8 - F06 int16 - F07 int32 - F08 int64 - F09 string - F10 uint - F11 uint8 - F12 uint16 - F13 uint32 - F14 uint64 -} - -func TestDefaultConverters(t *testing.T) { - v := map[string][]string{ - "F01": {"true"}, - "F02": {"4.2"}, - "F03": {"4.3"}, - "F04": {"-42"}, - "F05": {"-43"}, - "F06": {"-44"}, - "F07": {"-45"}, - "F08": {"-46"}, - "F09": {"foo"}, - "F10": {"42"}, - "F11": {"43"}, - "F12": {"44"}, - "F13": {"45"}, - "F14": {"46"}, - } - e := S3{ - F01: true, - F02: 4.2, - F03: 4.3, - F04: -42, - F05: -43, - F06: -44, - F07: -45, - F08: -46, - F09: "foo", - F10: 42, - F11: 43, - F12: 44, - F13: 45, - F14: 46, - } - s := &S3{} - _ = NewDecoder().Decode(s, v) - if s.F01 != e.F01 { - t.Errorf("F01: expected %v, got %v", e.F01, s.F01) - } - if s.F02 != e.F02 { - t.Errorf("F02: expected %v, got %v", e.F02, s.F02) - } - if s.F03 != e.F03 { - t.Errorf("F03: expected %v, got %v", e.F03, s.F03) - } - if s.F04 != e.F04 { - t.Errorf("F04: expected %v, got %v", e.F04, s.F04) - } - if s.F05 != e.F05 { - t.Errorf("F05: expected %v, got %v", e.F05, s.F05) - } - if s.F06 != e.F06 { - t.Errorf("F06: expected %v, got %v", e.F06, s.F06) - } - if s.F07 != e.F07 { - t.Errorf("F07: expected %v, got %v", e.F07, s.F07) - } - if s.F08 != e.F08 { - t.Errorf("F08: expected %v, got %v", e.F08, s.F08) - } - if s.F09 != e.F09 { - t.Errorf("F09: expected %v, got %v", e.F09, s.F09) - } - if s.F10 != e.F10 { - t.Errorf("F10: expected %v, got %v", e.F10, s.F10) - } - if s.F11 != e.F11 { - t.Errorf("F11: expected %v, got %v", e.F11, s.F11) - } - if s.F12 != e.F12 { - t.Errorf("F12: expected %v, got %v", e.F12, s.F12) - } - if s.F13 != e.F13 { - t.Errorf("F13: expected %v, got %v", e.F13, s.F13) - } - if s.F14 != e.F14 { - t.Errorf("F14: expected %v, got %v", e.F14, s.F14) - } -} - -func TestOn(t *testing.T) { - v := map[string][]string{ - "F01": {"on"}, - } - s := S3{} - err := NewDecoder().Decode(&s, v) - if err != nil { - t.Fatal(err) - } - if !s.F01 { - t.Fatal("Value was not set to true") - } -} - -// ---------------------------------------------------------------------------- - -func TestInlineStruct(t *testing.T) { - s1 := &struct { - F01 bool - }{} - s2 := &struct { - F01 int - }{} - v1 := map[string][]string{ - "F01": {"true"}, - } - v2 := map[string][]string{ - "F01": {"42"}, - } - decoder := NewDecoder() - _ = decoder.Decode(s1, v1) - if s1.F01 != true { - t.Errorf("s1: expected %v, got %v", true, s1.F01) - } - _ = decoder.Decode(s2, v2) - if s2.F01 != 42 { - t.Errorf("s2: expected %v, got %v", 42, s2.F01) - } -} - -// ---------------------------------------------------------------------------- - -type Foo struct { - F01 int - F02 Bar - Bif []Baz -} - -type Bar struct { - F01 string - F02 string - F03 string - F14 string - S05 string - Str string -} - -type Baz struct { - F99 []string -} - -func TestSimpleExample(t *testing.T) { - data := map[string][]string{ - "F01": {"1"}, - "F02.F01": {"S1"}, - "F02.F02": {"S2"}, - "F02.F03": {"S3"}, - "F02.F14": {"S4"}, - "F02.S05": {"S5"}, - "F02.Str": {"Str"}, - "Bif.0.F99": {"A", "B", "C"}, - } - - e := &Foo{ - F01: 1, - F02: Bar{ - F01: "S1", - F02: "S2", - F03: "S3", - F14: "S4", - S05: "S5", - Str: "Str", - }, - Bif: []Baz{{ - F99: []string{"A", "B", "C"}}, - }, - } - - s := &Foo{} - _ = NewDecoder().Decode(s, data) - - if s.F01 != e.F01 { - t.Errorf("F01: expected %v, got %v", e.F01, s.F01) - } - if s.F02.F01 != e.F02.F01 { - t.Errorf("F02.F01: expected %v, got %v", e.F02.F01, s.F02.F01) - } - if s.F02.F02 != e.F02.F02 { - t.Errorf("F02.F02: expected %v, got %v", e.F02.F02, s.F02.F02) - } - if s.F02.F03 != e.F02.F03 { - t.Errorf("F02.F03: expected %v, got %v", e.F02.F03, s.F02.F03) - } - if s.F02.F14 != e.F02.F14 { - t.Errorf("F02.F14: expected %v, got %v", e.F02.F14, s.F02.F14) - } - if s.F02.S05 != e.F02.S05 { - t.Errorf("F02.S05: expected %v, got %v", e.F02.S05, s.F02.S05) - } - if s.F02.Str != e.F02.Str { - t.Errorf("F02.Str: expected %v, got %v", e.F02.Str, s.F02.Str) - } - if len(s.Bif) != len(e.Bif) { - t.Errorf("Bif len: expected %d, got %d", len(e.Bif), len(s.Bif)) - } else { - if len(s.Bif[0].F99) != len(e.Bif[0].F99) { - t.Errorf("Bif[0].F99 len: expected %d, got %d", len(e.Bif[0].F99), len(s.Bif[0].F99)) - } - } -} - -// ---------------------------------------------------------------------------- - -type S4 struct { - F01 int64 - F02 float64 - F03 bool -} - -func TestConversionError(t *testing.T) { - data := map[string][]string{ - "F01": {"foo"}, - "F02": {"bar"}, - "F03": {"baz"}, - } - s := &S4{} - e := NewDecoder().Decode(s, data) - - m := e.(MultiError) - if len(m) != 3 { - t.Errorf("Expected 3 errors, got %v", m) - } -} - -// ---------------------------------------------------------------------------- - -type S5 struct { - F01 []string -} - -func TestEmptyValue(t *testing.T) { - data := map[string][]string{ - "F01": {"", "foo"}, - } - s := &S5{} - NewDecoder().Decode(s, data) - if len(s.F01) != 1 { - t.Errorf("Expected 1 values in F01") - } -} - -func TestEmptyValueZeroEmpty(t *testing.T) { - data := map[string][]string{ - "F01": {"", "foo"}, - } - s := S5{} - d := NewDecoder() - d.ZeroEmpty(true) - err := d.Decode(&s, data) - if err != nil { - t.Fatal(err) - } - if len(s.F01) != 2 { - t.Errorf("Expected 1 values in F01") - } -} - -// ---------------------------------------------------------------------------- - -type S6 struct { - id string -} - -func TestUnexportedField(t *testing.T) { - data := map[string][]string{ - "id": {"identifier"}, - } - s := &S6{} - NewDecoder().Decode(s, data) - if s.id != "" { - t.Errorf("Unexported field expected to be ignored") - } -} - -// ---------------------------------------------------------------------------- - -type S7 struct { - ID string -} - -func TestMultipleValues(t *testing.T) { - data := map[string][]string{ - "ID": {"0", "1"}, - } - - s := S7{} - NewDecoder().Decode(&s, data) - if s.ID != "1" { - t.Errorf("Last defined value must be used when multiple values for same field are provided") - } -} - -type S8 struct { - ID string `json:"id"` -} - -func TestSetAliasTag(t *testing.T) { - data := map[string][]string{ - "id": {"foo"}, - } - - s := S8{} - dec := NewDecoder() - dec.SetAliasTag("json") - dec.Decode(&s, data) - if s.ID != "foo" { - t.Fatalf("Bad value: got %q, want %q", s.ID, "foo") - } -} - -func TestZeroEmpty(t *testing.T) { - data := map[string][]string{ - "F01": {""}, - "F03": {"true"}, - } - s := S4{1, 1, false} - d := NewDecoder() - d.ZeroEmpty(true) - - err := d.Decode(&s, data) - if err != nil { - t.Fatal(err) - } - if s.F01 != 0 { - t.Errorf("F01: got %v, want %v", s.F01, 0) - } - if s.F02 != 1 { - t.Errorf("F02: got %v, want %v", s.F02, 1) - } - if s.F03 != true { - t.Errorf("F03: got %v, want %v", s.F03, true) - } -} - -func TestNoZeroEmpty(t *testing.T) { - data := map[string][]string{ - "F01": {""}, - "F03": {"true"}, - } - s := S4{1, 1, false} - d := NewDecoder() - d.ZeroEmpty(false) - err := d.Decode(&s, data) - if err != nil { - t.Fatal(err) - } - if s.F01 != 1 { - t.Errorf("F01: got %v, want %v", s.F01, 1) - } - if s.F02 != 1 { - t.Errorf("F02: got %v, want %v", s.F02, 1) - } - if s.F03 != true { - t.Errorf("F03: got %v, want %v", s.F03, true) - } -} - -// ---------------------------------------------------------------------------- - -type S9 struct { - Id string -} - -type S10 struct { - S9 -} - -func TestEmbeddedField(t *testing.T) { - data := map[string][]string{ - "Id": {"identifier"}, - } - s := &S10{} - NewDecoder().Decode(s, data) - if s.Id != "identifier" { - t.Errorf("Missing support for embedded fields") - } -} - -type S11 struct { - S10 -} - -func TestMultipleLevelEmbeddedField(t *testing.T) { - data := map[string][]string{ - "Id": {"identifier"}, - } - s := &S11{} - err := NewDecoder().Decode(s, data) - if s.Id != "identifier" { - t.Errorf("Missing support for multiple-level embedded fields (%v)", err) - } -} - -func TestInvalidPath(t *testing.T) { - data := map[string][]string{ - "Foo.Bar": {"baz"}, - } - s := S9{} - err := NewDecoder().Decode(&s, data) - expectedErr := `schema: invalid path "Foo.Bar"` - if err.Error() != expectedErr { - t.Fatalf("got %q, want %q", err, expectedErr) - } -} - -func TestInvalidPathIgnoreUnknownKeys(t *testing.T) { - data := map[string][]string{ - "Foo.Bar": {"baz"}, - } - s := S9{} - dec := NewDecoder() - dec.IgnoreUnknownKeys(true) - err := dec.Decode(&s, data) - if err != nil { - t.Fatal(err) - } -} - -// ---------------------------------------------------------------------------- - -type S1NT struct { - F1 int - F2 *int - F3 []int - F4 []*int - F5 *[]int - F6 *[]*int - F7 S2 - F8 *S1 - F9 int `schema:"-"` - F10 []S1 - F11 []*S1 - F12 *[]S1 - F13 *[]*S1 -} - -func TestAllNT(t *testing.T) { - v := map[string][]string{ - "f1": {"1"}, - "f2": {"2"}, - "f3": {"31", "32"}, - "f4": {"41", "42"}, - "f5": {"51", "52"}, - "f6": {"61", "62"}, - "f7.f1": {"71", "72"}, - "f8.f8.f7.f1": {"81", "82"}, - "f9": {"9"}, - "f10.0.f10.0.f6": {"101", "102"}, - "f10.0.f10.1.f6": {"103", "104"}, - "f11.0.f11.0.f6": {"111", "112"}, - "f11.0.f11.1.f6": {"113", "114"}, - "f12.0.f12.0.f6": {"121", "122"}, - "f12.0.f12.1.f6": {"123", "124"}, - "f13.0.f13.0.f6": {"131", "132"}, - "f13.0.f13.1.f6": {"133", "134"}, - } - f2 := 2 - f41, f42 := 41, 42 - f61, f62 := 61, 62 - f71, f72 := 71, 72 - f81, f82 := 81, 82 - f101, f102, f103, f104 := 101, 102, 103, 104 - f111, f112, f113, f114 := 111, 112, 113, 114 - f121, f122, f123, f124 := 121, 122, 123, 124 - f131, f132, f133, f134 := 131, 132, 133, 134 - e := S1NT{ - F1: 1, - F2: &f2, - F3: []int{31, 32}, - F4: []*int{&f41, &f42}, - F5: &[]int{51, 52}, - F6: &[]*int{&f61, &f62}, - F7: S2{ - F01: &[]*int{&f71, &f72}, - }, - F8: &S1{ - F08: &S1{ - F07: S2{ - F01: &[]*int{&f81, &f82}, - }, - }, - }, - F9: 0, - F10: []S1{ - S1{ - F10: []S1{ - S1{F06: &[]*int{&f101, &f102}}, - S1{F06: &[]*int{&f103, &f104}}, - }, - }, - }, - F11: []*S1{ - &S1{ - F11: []*S1{ - &S1{F06: &[]*int{&f111, &f112}}, - &S1{F06: &[]*int{&f113, &f114}}, - }, - }, - }, - F12: &[]S1{ - S1{ - F12: &[]S1{ - S1{F06: &[]*int{&f121, &f122}}, - S1{F06: &[]*int{&f123, &f124}}, - }, - }, - }, - F13: &[]*S1{ - &S1{ - F13: &[]*S1{ - &S1{F06: &[]*int{&f131, &f132}}, - &S1{F06: &[]*int{&f133, &f134}}, - }, - }, - }, - } - - s := &S1NT{} - _ = NewDecoder().Decode(s, v) - - vals := func(values []*int) []int { - r := make([]int, len(values)) - for k, v := range values { - r[k] = *v - } - return r - } - - if s.F1 != e.F1 { - t.Errorf("f1: expected %v, got %v", e.F1, s.F1) - } - if s.F2 == nil { - t.Errorf("f2: expected %v, got nil", *e.F2) - } else if *s.F2 != *e.F2 { - t.Errorf("f2: expected %v, got %v", *e.F2, *s.F2) - } - if s.F3 == nil { - t.Errorf("f3: expected %v, got nil", e.F3) - } else if len(s.F3) != 2 || s.F3[0] != e.F3[0] || s.F3[1] != e.F3[1] { - t.Errorf("f3: expected %v, got %v", e.F3, s.F3) - } - if s.F4 == nil { - t.Errorf("f4: expected %v, got nil", e.F4) - } else { - if len(s.F4) != 2 || *(s.F4)[0] != *(e.F4)[0] || *(s.F4)[1] != *(e.F4)[1] { - t.Errorf("f4: expected %v, got %v", vals(e.F4), vals(s.F4)) - } - } - if s.F5 == nil { - t.Errorf("f5: expected %v, got nil", e.F5) - } else { - sF5, eF5 := *s.F5, *e.F5 - if len(sF5) != 2 || sF5[0] != eF5[0] || sF5[1] != eF5[1] { - t.Errorf("f5: expected %v, got %v", eF5, sF5) - } - } - if s.F6 == nil { - t.Errorf("f6: expected %v, got nil", vals(*e.F6)) - } else { - sF6, eF6 := *s.F6, *e.F6 - if len(sF6) != 2 || *(sF6)[0] != *(eF6)[0] || *(sF6)[1] != *(eF6)[1] { - t.Errorf("f6: expected %v, got %v", vals(eF6), vals(sF6)) - } - } - if s.F7.F01 == nil { - t.Errorf("f7.f1: expected %v, got nil", vals(*e.F7.F01)) - } else { - sF7, eF7 := *s.F7.F01, *e.F7.F01 - if len(sF7) != 2 || *(sF7)[0] != *(eF7)[0] || *(sF7)[1] != *(eF7)[1] { - t.Errorf("f7.f1: expected %v, got %v", vals(eF7), vals(sF7)) - } - } - if s.F8 == nil { - t.Errorf("f8: got nil") - } else if s.F8.F08 == nil { - t.Errorf("f8.f8: got nil") - } else if s.F8.F08.F07.F01 == nil { - t.Errorf("f8.f8.f7.f1: expected %v, got nil", vals(*e.F8.F08.F07.F01)) - } else { - sF8, eF8 := *s.F8.F08.F07.F01, *e.F8.F08.F07.F01 - if len(sF8) != 2 || *(sF8)[0] != *(eF8)[0] || *(sF8)[1] != *(eF8)[1] { - t.Errorf("f8.f8.f7.f1: expected %v, got %v", vals(eF8), vals(sF8)) - } - } - if s.F9 != e.F9 { - t.Errorf("f9: expected %v, got %v", e.F9, s.F9) - } - if s.F10 == nil { - t.Errorf("f10: got nil") - } else if len(s.F10) != 1 { - t.Errorf("f10: expected 1 element, got %v", s.F10) - } else { - if len(s.F10[0].F10) != 2 { - t.Errorf("f10.0.f10: expected 1 element, got %v", s.F10[0].F10) - } else { - sF10, eF10 := *s.F10[0].F10[0].F06, *e.F10[0].F10[0].F06 - if sF10 == nil { - t.Errorf("f10.0.f10.0.f6: expected %v, got nil", vals(eF10)) - } else { - if len(sF10) != 2 || *(sF10)[0] != *(eF10)[0] || *(sF10)[1] != *(eF10)[1] { - t.Errorf("f10.0.f10.0.f6: expected %v, got %v", vals(eF10), vals(sF10)) - } - } - sF10, eF10 = *s.F10[0].F10[1].F06, *e.F10[0].F10[1].F06 - if sF10 == nil { - t.Errorf("f10.0.f10.0.f6: expected %v, got nil", vals(eF10)) - } else { - if len(sF10) != 2 || *(sF10)[0] != *(eF10)[0] || *(sF10)[1] != *(eF10)[1] { - t.Errorf("f10.0.f10.0.f6: expected %v, got %v", vals(eF10), vals(sF10)) - } - } - } - } - if s.F11 == nil { - t.Errorf("f11: got nil") - } else if len(s.F11) != 1 { - t.Errorf("f11: expected 1 element, got %v", s.F11) - } else { - if len(s.F11[0].F11) != 2 { - t.Errorf("f11.0.f11: expected 1 element, got %v", s.F11[0].F11) - } else { - sF11, eF11 := *s.F11[0].F11[0].F06, *e.F11[0].F11[0].F06 - if sF11 == nil { - t.Errorf("f11.0.f11.0.f6: expected %v, got nil", vals(eF11)) - } else { - if len(sF11) != 2 || *(sF11)[0] != *(eF11)[0] || *(sF11)[1] != *(eF11)[1] { - t.Errorf("f11.0.f11.0.f6: expected %v, got %v", vals(eF11), vals(sF11)) - } - } - sF11, eF11 = *s.F11[0].F11[1].F06, *e.F11[0].F11[1].F06 - if sF11 == nil { - t.Errorf("f11.0.f11.0.f6: expected %v, got nil", vals(eF11)) - } else { - if len(sF11) != 2 || *(sF11)[0] != *(eF11)[0] || *(sF11)[1] != *(eF11)[1] { - t.Errorf("f11.0.f11.0.f6: expected %v, got %v", vals(eF11), vals(sF11)) - } - } - } - } - if s.F12 == nil { - t.Errorf("f12: got nil") - } else if len(*s.F12) != 1 { - t.Errorf("f12: expected 1 element, got %v", *s.F12) - } else { - sF12, eF12 := *(s.F12), *(e.F12) - if len(*sF12[0].F12) != 2 { - t.Errorf("f12.0.f12: expected 1 element, got %v", *sF12[0].F12) - } else { - sF122, eF122 := *(*sF12[0].F12)[0].F06, *(*eF12[0].F12)[0].F06 - if sF122 == nil { - t.Errorf("f12.0.f12.0.f6: expected %v, got nil", vals(eF122)) - } else { - if len(sF122) != 2 || *(sF122)[0] != *(eF122)[0] || *(sF122)[1] != *(eF122)[1] { - t.Errorf("f12.0.f12.0.f6: expected %v, got %v", vals(eF122), vals(sF122)) - } - } - sF122, eF122 = *(*sF12[0].F12)[1].F06, *(*eF12[0].F12)[1].F06 - if sF122 == nil { - t.Errorf("f12.0.f12.0.f6: expected %v, got nil", vals(eF122)) - } else { - if len(sF122) != 2 || *(sF122)[0] != *(eF122)[0] || *(sF122)[1] != *(eF122)[1] { - t.Errorf("f12.0.f12.0.f6: expected %v, got %v", vals(eF122), vals(sF122)) - } - } - } - } - if s.F13 == nil { - t.Errorf("f13: got nil") - } else if len(*s.F13) != 1 { - t.Errorf("f13: expected 1 element, got %v", *s.F13) - } else { - sF13, eF13 := *(s.F13), *(e.F13) - if len(*sF13[0].F13) != 2 { - t.Errorf("f13.0.f13: expected 1 element, got %v", *sF13[0].F13) - } else { - sF132, eF132 := *(*sF13[0].F13)[0].F06, *(*eF13[0].F13)[0].F06 - if sF132 == nil { - t.Errorf("f13.0.f13.0.f6: expected %v, got nil", vals(eF132)) - } else { - if len(sF132) != 2 || *(sF132)[0] != *(eF132)[0] || *(sF132)[1] != *(eF132)[1] { - t.Errorf("f13.0.f13.0.f6: expected %v, got %v", vals(eF132), vals(sF132)) - } - } - sF132, eF132 = *(*sF13[0].F13)[1].F06, *(*eF13[0].F13)[1].F06 - if sF132 == nil { - t.Errorf("f13.0.f13.0.f6: expected %v, got nil", vals(eF132)) - } else { - if len(sF132) != 2 || *(sF132)[0] != *(eF132)[0] || *(sF132)[1] != *(eF132)[1] { - t.Errorf("f13.0.f13.0.f6: expected %v, got %v", vals(eF132), vals(sF132)) - } - } - } - } -} - -// ---------------------------------------------------------------------------- - -type S12A struct { - ID []int -} - -func TestCSVSlice(t *testing.T) { - data := map[string][]string{ - "ID": {"0,1"}, - } - - s := S12A{} - NewDecoder().Decode(&s, data) - if len(s.ID) != 2 { - t.Errorf("Expected two values in the result list, got %+v", s.ID) - } - if s.ID[0] != 0 || s.ID[1] != 1 { - t.Errorf("Expected []{0, 1} got %+v", s) - } -} - -type S12B struct { - ID []string -} - -//Decode should not split on , into a slice for string only -func TestCSVStringSlice(t *testing.T) { - data := map[string][]string{ - "ID": {"0,1"}, - } - - s := S12B{} - NewDecoder().Decode(&s, data) - if len(s.ID) != 1 { - t.Errorf("Expected one value in the result list, got %+v", s.ID) - } - if s.ID[0] != "0,1" { - t.Errorf("Expected []{0, 1} got %+v", s) - } -} - -//Invalid data provided by client should not panic (github issue 33) -func TestInvalidDataProvidedByClient(t *testing.T) { - defer func() { - if r := recover(); r != nil { - t.Errorf("Panicked calling decoder.Decode: %v", r) - } - }() - - type S struct { - f string - } - - data := map[string][]string{ - "f.f": {"v"}, - } - - err := NewDecoder().Decode(new(S), data) - if err == nil { - t.Errorf("invalid path in decoder.Decode should return an error.") - } -} - -// underlying cause of error in issue 33 -func TestInvalidPathInCacheParsePath(t *testing.T) { - type S struct { - f string - } - - typ := reflect.ValueOf(new(S)).Elem().Type() - c := newCache() - _, err := c.parsePath("f.f", typ) - if err == nil { - t.Errorf("invalid path in cache.parsePath should return an error.") - } -} - -// issue 32 -func TestDecodeToTypedField(t *testing.T) { - type Aa bool - s1 := &struct{ Aa }{} - v1 := map[string][]string{"Aa": {"true"}} - NewDecoder().Decode(s1, v1) - if s1.Aa != Aa(true) { - t.Errorf("s1: expected %v, got %v", true, s1.Aa) - } -} - -// issue 37 -func TestRegisterConverter(t *testing.T) { - type Aa int - type Bb int - s1 := &struct { - Aa - Bb - }{} - decoder := NewDecoder() - - decoder.RegisterConverter(s1.Aa, func(s string) reflect.Value { return reflect.ValueOf(1) }) - decoder.RegisterConverter(s1.Bb, func(s string) reflect.Value { return reflect.ValueOf(2) }) - - v1 := map[string][]string{"Aa": {"4"}, "Bb": {"5"}} - decoder.Decode(s1, v1) - - if s1.Aa != Aa(1) { - t.Errorf("s1.Aa: expected %v, got %v", 1, s1.Aa) - } - if s1.Bb != Bb(2) { - t.Errorf("s1.Bb: expected %v, got %v", 2, s1.Bb) - } -} - -// Issue #40 -func TestRegisterConverterSlice(t *testing.T) { - decoder := NewDecoder() - decoder.RegisterConverter([]string{}, func(input string) reflect.Value { - return reflect.ValueOf(strings.Split(input, ",")) - }) - - result := struct { - Multiple []string `schema:"multiple"` - }{} - - expected := []string{"one", "two", "three"} - decoder.Decode(&result, map[string][]string{ - "multiple": []string{"one,two,three"}, - }) - for i := range expected { - if got, want := expected[i], result.Multiple[i]; got != want { - t.Errorf("%d: got %s, want %s", i, got, want) - } - } -} - -type S13 struct { - Value []S14 -} - -type S14 struct { - F1 string - F2 string -} - -func (n *S14) UnmarshalText(text []byte) error { - textParts := strings.Split(string(text), " ") - if len(textParts) < 2 { - return errors.New("Not a valid name!") - } - - n.F1, n.F2 = textParts[0], textParts[len(textParts)-1] - return nil -} - -type S15 struct { - Value []S16 -} - -type S16 struct { - F1 string - F2 string -} - -func TestCustomTypeSlice(t *testing.T) { - data := map[string][]string{ - "Value.0": []string{"Louisa May Alcott"}, - "Value.1": []string{"Florence Nightingale"}, - "Value.2": []string{"Clara Barton"}, - } - - s := S13{} - decoder := NewDecoder() - - if err := decoder.Decode(&s, data); err != nil { - t.Fatal(err) - } - - if len(s.Value) != 3 { - t.Fatalf("Expected 3 values in the result list, got %+v", s.Value) - } - if s.Value[0].F1 != "Louisa" || s.Value[0].F2 != "Alcott" { - t.Errorf("Expected S14{'Louisa', 'Alcott'} got %+v", s.Value[0]) - } - if s.Value[1].F1 != "Florence" || s.Value[1].F2 != "Nightingale" { - t.Errorf("Expected S14{'Florence', 'Nightingale'} got %+v", s.Value[1]) - } - if s.Value[2].F1 != "Clara" || s.Value[2].F2 != "Barton" { - t.Errorf("Expected S14{'Clara', 'Barton'} got %+v", s.Value[2]) - } -} - -func TestCustomTypeSliceWithError(t *testing.T) { - data := map[string][]string{ - "Value.0": []string{"Louisa May Alcott"}, - "Value.1": []string{"Florence Nightingale"}, - "Value.2": []string{"Clara"}, - } - - s := S13{} - decoder := NewDecoder() - - if err := decoder.Decode(&s, data); err == nil { - t.Error("Not detecting error in conversion") - } -} - -func TestNoTextUnmarshalerTypeSlice(t *testing.T) { - data := map[string][]string{ - "Value.0": []string{"Louisa May Alcott"}, - "Value.1": []string{"Florence Nightingale"}, - "Value.2": []string{"Clara Barton"}, - } - - s := S15{} - decoder := NewDecoder() - - if err := decoder.Decode(&s, data); err == nil { - t.Error("Not detecting when there's no converter") - } -} - -// ---------------------------------------------------------------------------- - -type S17 struct { - Value S14 -} - -type S18 struct { - Value S16 -} - -func TestCustomType(t *testing.T) { - data := map[string][]string{ - "Value": []string{"Louisa May Alcott"}, - } - - s := S17{} - decoder := NewDecoder() - - if err := decoder.Decode(&s, data); err != nil { - t.Fatal(err) - } - - if s.Value.F1 != "Louisa" || s.Value.F2 != "Alcott" { - t.Errorf("Expected S14{'Louisa', 'Alcott'} got %+v", s.Value) - } -} - -func TestCustomTypeWithError(t *testing.T) { - data := map[string][]string{ - "Value": []string{"Louisa"}, - } - - s := S17{} - decoder := NewDecoder() - - if err := decoder.Decode(&s, data); err == nil { - t.Error("Not detecting error in conversion") - } -} - -func TestNoTextUnmarshalerType(t *testing.T) { - data := map[string][]string{ - "Value": []string{"Louisa May Alcott"}, - } - - s := S18{} - decoder := NewDecoder() - - if err := decoder.Decode(&s, data); err == nil { - t.Error("Not detecting when there's no converter") - } -} - -func TestExpectedType(t *testing.T) { - data := map[string][]string{ - "bools": []string{"1", "a"}, - "date": []string{"invalid"}, - "Foo.Bar": []string{"a", "b"}, - } - - type B struct { - Bar *int - } - type A struct { - Bools []bool `schema:"bools"` - Date time.Time `schema:"date"` - Foo B - } - - a := A{} - - err := NewDecoder().Decode(&a, data) - - e := err.(MultiError)["bools"].(ConversionError) - if e.Type != reflect.TypeOf(false) && e.Index == 1 { - t.Errorf("Expected bool, index: 1 got %+v, index: %d", e.Type, e.Index) - } - e = err.(MultiError)["date"].(ConversionError) - if e.Type != reflect.TypeOf(time.Time{}) { - t.Errorf("Expected time.Time got %+v", e.Type) - } - e = err.(MultiError)["Foo.Bar"].(ConversionError) - if e.Type != reflect.TypeOf(0) { - t.Errorf("Expected int got %+v", e.Type) - } -} - -type R1 struct { - A string `schema:"a,required"` - B struct { - C int `schema:"c,required"` - D float64 `schema:"d"` - E string `schema:"e,required"` - } `schema:"b"` - F []string `schema:"f,required"` - G []int `schema:"g,othertag"` - H bool `schema:"h,required"` -} - -func TestRequiredField(t *testing.T) { - var a R1 - v := map[string][]string{ - "a": []string{"bbb"}, - "b.c": []string{"88"}, - "b.d": []string{"9"}, - "f": []string{""}, - "h": []string{"true"}, - } - err := NewDecoder().Decode(&a, v) - if err == nil { - t.Errorf("error nil, b.e is empty expect") - return - } - // b.e empty - v["b.e"] = []string{""} // empty string - err = NewDecoder().Decode(&a, v) - if err == nil { - t.Errorf("error nil, b.e is empty expect") - return - } - - // all fields ok - v["b.e"] = []string{"nonempty"} - err = NewDecoder().Decode(&a, v) - if err != nil { - t.Errorf("error: %v", err) - return - } - - // set f empty - v["f"] = []string{} - err = NewDecoder().Decode(&a, v) - if err == nil { - t.Errorf("error nil, f is empty expect") - return - } - v["f"] = []string{"nonempty"} - - // b.c type int with empty string - v["b.c"] = []string{""} - err = NewDecoder().Decode(&a, v) - if err == nil { - t.Errorf("error nil, b.c is empty expect") - return - } - v["b.c"] = []string{"3"} - - // h type bool with empty string - v["h"] = []string{""} - err = NewDecoder().Decode(&a, v) - if err == nil { - t.Errorf("error nil, h is empty expect") - return - } -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/doc.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/doc.go deleted file mode 100644 index a95e87b..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/gorilla/schema/doc.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2012 The Gorilla 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 gorilla/schema fills a struct with form values. - -The basic usage is really simple. Given this struct: - - type Person struct { - Name string - Phone string - } - -...we can fill it passing a map to the Decode() function: - - values := map[string][]string{ - "Name": {"John"}, - "Phone": {"999-999-999"}, - } - person := new(Person) - decoder := schema.NewDecoder() - decoder.Decode(person, values) - -This is just a simple example and it doesn't make a lot of sense to create -the map manually. Typically it will come from a http.Request object and -will be of type url.Values: http.Request.Form or http.Request.MultipartForm: - - func MyHandler(w http.ResponseWriter, r *http.Request) { - err := r.ParseForm() - - if err != nil { - // Handle error - } - - decoder := schema.NewDecoder() - // r.PostForm is a map of our POST form values - err := decoder.Decode(person, r.PostForm) - - if err != nil { - // Handle error - } - - // Do something with person.Name or person.Phone - } - -Note: it is a good idea to set a Decoder instance as a package global, -because it caches meta-data about structs, and a instance can be shared safely: - - var decoder = schema.NewDecoder() - -To define custom names for fields, use a struct tag "schema". To not populate -certain fields, use a dash for the name and it will be ignored: - - type Person struct { - Name string `schema:"name"` // custom name - Phone string `schema:"phone"` // custom name - Admin bool `schema:"-"` // this field is never set - } - -The supported field types in the destination struct are: - - * bool - * float variants (float32, float64) - * int variants (int, int8, int16, int32, int64) - * string - * uint variants (uint, uint8, uint16, uint32, uint64) - * struct - * a pointer to one of the above types - * a slice or a pointer to a slice of one of the above types - -Non-supported types are simply ignored, however custom types can be registered -to be converted. - -To fill nested structs, keys must use a dotted notation as the "path" for the -field. So for example, to fill the struct Person below: - - type Phone struct { - Label string - Number string - } - - type Person struct { - Name string - Phone Phone - } - -...the source map must have the keys "Name", "Phone.Label" and "Phone.Number". -This means that an HTML form to fill a Person struct must look like this: - -
- - - -
- -Single values are filled using the first value for a key from the source map. -Slices are filled using all values for a key from the source map. So to fill -a Person with multiple Phone values, like: - - type Person struct { - Name string - Phones []Phone - } - -...an HTML form that accepts three Phone values would look like this: - -
- - - - - - - -
- -Notice that only for slices of structs the slice index is required. -This is needed for disambiguation: if the nested struct also had a slice -field, we could not translate multiple values to it if we did not use an -index for the parent struct. - -There's also the possibility to create a custom type that implements the -TextUnmarshaler interface, and in this case there's no need to registry -a converter, like: - - type Person struct { - Emails []Email - } - - type Email struct { - *mail.Address - } - - func (e *Email) UnmarshalText(text []byte) (err error) { - e.Address, err = mail.ParseAddress(string(text)) - return - } - -...an HTML form that accepts three Email values would look like this: - -
- - - -
-*/ -package schema diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/LICENSE b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/LICENSE deleted file mode 100644 index 6ac9da6..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2016 Steve Manuel - -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/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/README.md b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/README.md deleted file mode 100644 index 190c61f..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/README.md +++ /dev/null @@ -1,51 +0,0 @@ -## Email - -I needed a way to send email from a [Ponzu](https://ponzu-cms.org) installation -running on all kinds of systems without shelling out. `sendmail` or `postfix` et -al are not standard on all systems, and I didn't want to force users to add API -keys from a third-party just to send something like an account recovery email. - -### Usage: -`$ go get github.com/nilslice/email` - -```go -package main - -import ( - "fmt" - "github.com/nilslice/email" -) - -func main() { - msg := email.Message{ - To: "you@server.name", // do not add < > or name in quotes - From: "me@server.name", // do not add < > or name in quotes - Subject: "A simple email", - Body: "Plain text email body. HTML not yet supported, but send a PR!", - } - - err := msg.Send() - if err != nil { - fmt.Println(err) - } -} - -``` - -### Under the hood -`email` looks at a `Message`'s `To` field, splits the string on the @ symbol and -issues an MX lookup to find the mail exchange server(s). Then it iterates over -all the possibilities in combination with commonly used SMTP ports for non-SSL -clients: `25, 2525, & 587` - -It stops once it has an active client connected to a mail server and sends the -initial information, the message, and then closes the connection. - -Currently, this doesn't support any additional headers or `To` field formatting -(the recipient's email must be the only string `To` takes). Although these would -be fairly strightforward to implement, I don't need them yet.. so feel free to -contribute anything you find useful. - -#### Warning -Be cautious of how often you run this locally or in testing, as it's quite -likely your IP will be blocked/blacklisted if it is not already. \ No newline at end of file diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email.go deleted file mode 100644 index 15f0a49..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email.go +++ /dev/null @@ -1,119 +0,0 @@ -package email - -import ( - "fmt" - "net" - "net/smtp" - "strings" -) - -// Message creates a email to be sent -type Message struct { - To string - From string - Subject string - Body string -} - -var ( - ports = []int{25, 2525, 587} -) - -// Send sends a message to recipient(s) listed in the 'To' field of a Message -func (m Message) Send() error { - if !strings.Contains(m.To, "@") { - return fmt.Errorf("Invalid recipient address: <%s>", m.To) - } - - host := strings.Split(m.To, "@")[1] - addrs, err := net.LookupMX(host) - if err != nil { - return err - } - - c, err := newClient(addrs, ports) - if err != nil { - return err - } - - err = send(m, c) - if err != nil { - return err - } - - return nil -} - -func newClient(mx []*net.MX, ports []int) (*smtp.Client, error) { - for i := range mx { - for j := range ports { - server := strings.TrimSuffix(mx[i].Host, ".") - hostPort := fmt.Sprintf("%s:%d", server, ports[j]) - client, err := smtp.Dial(hostPort) - if err != nil { - if j == len(ports)-1 { - return nil, err - } - - continue - } - - return client, nil - } - } - - return nil, fmt.Errorf("Couldn't connect to servers %v on any common port.", mx) -} - -func send(m Message, c *smtp.Client) error { - if err := c.Mail(m.From); err != nil { - return err - } - - if err := c.Rcpt(m.To); err != nil { - return err - } - - msg, err := c.Data() - if err != nil { - return err - } - - if m.Subject != "" { - _, err = msg.Write([]byte("Subject: " + m.Subject + "\r\n")) - if err != nil { - return err - } - } - - if m.From != "" { - _, err = msg.Write([]byte("From: <" + m.From + ">\r\n")) - if err != nil { - return err - } - } - - if m.To != "" { - _, err = msg.Write([]byte("To: <" + m.To + ">\r\n")) - if err != nil { - return err - } - } - - _, err = fmt.Fprint(msg, m.Body) - if err != nil { - return err - } - - err = msg.Close() - if err != nil { - return err - } - - err = c.Quit() - if err != nil { - return err - } - - return nil -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email_test.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email_test.go deleted file mode 100644 index 3576a79..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/email/email_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package email - -import ( - "testing" -) - -func TestSend(t *testing.T) { - m := Message{ - To: "", - From: "", - Subject: "", - Body: "", - } - - err := m.Send() - if err != nil { - t.Fatal("Send returned error:", err) - } -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/LICENSE b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/LICENSE deleted file mode 100644 index f67119e..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (C) 2015 Steve Manuel - -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/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/README.md b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/README.md deleted file mode 100644 index a384dd1..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# JWT - -### Usage - $ go get github.com/nilslice/jwt - -package jwt provides methods to create and check JSON Web Tokens. It only implements HMAC 256 encryption and has a very small footprint, ideal for simple usage when authorizing clients - -```go - package main - - import ( - auth "github.com/nilslice/jwt" - "fmt" - "net/http" - "strings" - ) - - func main() { - http.HandleFunc("/auth/new", func(res http.ResponseWriter, req *http.Request) { - claims := map[string]interface{}{"exp": time.Now().Add(time.Hour * 24).Unix()} - token, err := auth.New(claims) - if err != nil { - http.Error(res, "Error", 500) - return - } - res.Header().Add("Authorization", "Bearer "+token) - - res.WriteHeader(http.StatusOK) - }) - - http.HandleFunc("/auth", func(res http.ResponseWriter, req *http.Request) { - userToken := strings.Split(req.Header.Get("Authorization"), " ")[1] - - if auth.Passes(userToken) { - fmt.Println("ok") - } else { - fmt.Println("no") - } - }) - - http.ListenAndServe(":8080", nil) - } -``` diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/doc.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/doc.go deleted file mode 100644 index aa9a5c8..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/doc.go +++ /dev/null @@ -1,40 +0,0 @@ -// Package jwt provides methods to create and check JSON Web Tokens (JWT). It only implements HMAC 256 encryption and has a very small footprint, ideal for simple usage when authorizing clients -/* - - package main - - import ( - auth "github.com/nilslice/jwt" - "fmt" - "net/http" - "strings" - "time" - ) - - func main() { - http.HandleFunc("/auth/new", func(res http.ResponseWriter, req *http.Request) { - claims := map[string]interface{}{"exp": time.Now().Add(time.Hour * 24).Unix()} - token, err := auth.New(claims) - if err != nil { - http.Error(res, "Error", 500) - return - } - res.Header().Add("Authorization", "Bearer "+token) - - res.WriteHeader(http.StatusOK) - }) - - http.HandleFunc("/auth", func(res http.ResponseWriter, req *http.Request) { - userToken := strings.Split(req.Header.Get("Authorization"), " ")[1] - - if auth.Passes(userToken) { - fmt.Println("ok") - } else { - fmt.Println("no") - } - }) - - http.ListenAndServe(":8080", nil) - } -*/ -package jwt diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/jwt.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/jwt.go deleted file mode 100644 index 6d7eaa3..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/nilslice/jwt/jwt.go +++ /dev/null @@ -1,204 +0,0 @@ -package jwt - -import ( - "crypto/hmac" - "crypto/sha256" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "strings" -) - -var ( - privateKey = []byte("") - defaultHeader = header{Typ: "JWT", Alg: "HS256"} - registeredClaims = []string{"iss", "sub", "aud", "exp", "nbf", "iat", "jti"} -) - -type header struct { - Typ string `json:"typ"` - Alg string `json:"alg"` -} - -type payload map[string]interface{} - -type encoded struct { - token string -} -type decoded struct { - header string - payload string -} - -type signedDecoded struct { - decoded - signature string -} - -func newEncoded(claims map[string]interface{}) (encoded, error) { - header, err := json.Marshal(defaultHeader) - if err != nil { - return encoded{}, err - } - - for _, claim := range registeredClaims { - if _, ok := claims[claim]; !ok { - claims[claim] = nil - } - } - - payload, err := json.Marshal(claims) - if err != nil { - return encoded{}, err - } - - d := decoded{header: string(header), payload: string(payload)} - - d.encodeInternal() - signed, err := d.sign() - if err != nil { - return encoded{}, err - } - - token := signed.token() - e := encoded{token: token} - return e, nil -} - -func newDecoded(token string) (decoded, error) { - e := encoded{token: token} - d, err := e.parseToken() - if err != nil { - return d, nil - } - - return d, nil -} - -func encodeToString(src []byte) string { - return base64.RawURLEncoding.EncodeToString(src) -} - -func (d decoded) getHeader() []byte { - return []byte(d.header) -} - -func (d decoded) getPayload() []byte { - return []byte(d.payload) -} - -func (sd signedDecoded) getSignature() []byte { - return []byte(sd.signature) -} - -func (d *decoded) encodeInternal() { - d.header = encodeToString(d.getHeader()) - d.payload = encodeToString(d.getPayload()) -} - -func (d decoded) dot(internals ...string) string { - return strings.Join(internals, ".") -} - -func (d *decoded) sign() (signedDecoded, error) { - if d.header == "" || d.payload == "" { - return signedDecoded{}, errors.New("Missing header or payload on Decoded") - } - - unsigned := d.dot(d.header, d.payload) - - hash := hmac.New(sha256.New, privateKey) - _, err := hash.Write([]byte(unsigned)) - if err != nil { - return signedDecoded{}, err - } - - signed := signedDecoded{decoded: *d} - signed.signature = encodeToString(hash.Sum(nil)) - - return signed, nil -} - -func (sd signedDecoded) token() string { - return fmt.Sprintf("%s.%s.%s", sd.getHeader(), sd.getPayload(), sd.getSignature()) -} - -func (sd signedDecoded) verify(enc encoded) bool { - if sd.token() == enc.token { - return true - } - return false -} - -func (e encoded) parseToken() (decoded, error) { - parts := strings.Split(e.token, ".") - if len(parts) != 3 { - return decoded{}, errors.New("Error: incorrect # of results from string parsing") - } - - d := decoded{ - header: parts[0], - payload: parts[1], - } - - return d, nil -} - -// New returns a token (string) and error. The token is a fully qualified JWT to be sent to a client via HTTP Header or other method. Error returned will be from the newEncoded unexported function. -func New(claims map[string]interface{}) (string, error) { - enc, err := newEncoded(claims) - if err != nil { - return "", err - } - - return enc.token, nil -} - -// Passes returns a bool indicating whether a token (string) provided has been signed by our server. If true, the client is authenticated and may proceed. -func Passes(token string) bool { - dec, err := newDecoded(token) - if err != nil { - // may want to log some error here so we have visibility - // intentionally simplifying return type to bool for ease - // of use in API. Caller should only do `if auth.Passes(str) {}` - return false - } - signed, err := dec.sign() - if err != nil { - return false - } - - return signed.verify(encoded{token: token}) -} - -// GetClaims() returns a token's claims, allowing -// you to check the values to make sure they match -func GetClaims(token string) map[string]interface{} { - // decode the token - dec, err := newDecoded(token) - if err != nil { - return nil - } - - // base64 decode payload - payload, err := base64.RawURLEncoding.DecodeString(dec.payload) - if err != nil { - return nil - } - - dst := map[string]interface{}{} - err = json.Unmarshal(payload, &dst) - if err != nil { - return nil - } - - return dst - -} - -// Secret is a helper function to set the unexported privateKey variable used when signing and verifying tokens. -// Its argument is type []byte since we expect users to read this value from a file which can be excluded from source code. -func Secret(key []byte) { - privateKey = key -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/.hold b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/.hold deleted file mode 100644 index e69de29..0000000 diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/song.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/song.go deleted file mode 100644 index fa5e802..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/content/song.go +++ /dev/null @@ -1,73 +0,0 @@ -package content - -import ( - "fmt" - - "github.com/ponzu-cms/ponzu/management/editor" - "github.com/ponzu-cms/ponzu/system/item" -) - -type Song struct { - item.Item - - Title string `json:"title"` - Artist string `json:"artist"` - Rating int `json:"rating"` - Opinion string `json:"opinion"` - SpotifyUrl string `json:"spotify_url"` -} - -// MarshalEditor writes a buffer of html to edit a Song within the CMS -// and implements editor.Editable -func (s *Song) MarshalEditor() ([]byte, error) { - view, err := editor.Form(s, - // Take note that the first argument to these Input-like functions - // is the string version of each Song field, and must follow - // this pattern for auto-decoding and auto-encoding reasons: - editor.Field{ - View: editor.Input("Title", s, map[string]string{ - "label": "Title", - "type": "text", - "placeholder": "Enter the Title here", - }), - }, - editor.Field{ - View: editor.Input("Artist", s, map[string]string{ - "label": "Artist", - "type": "text", - "placeholder": "Enter the Artist here", - }), - }, - editor.Field{ - View: editor.Input("Rating", s, map[string]string{ - "label": "Rating", - "type": "text", - "placeholder": "Enter the Rating here", - }), - }, - editor.Field{ - View: editor.Input("Opinion", s, map[string]string{ - "label": "Opinion", - "type": "text", - "placeholder": "Enter the Opinion here", - }), - }, - editor.Field{ - View: editor.Input("SpotifyUrl", s, map[string]string{ - "label": "SpotifyUrl", - "type": "text", - "placeholder": "Enter the SpotifyUrl here", - }), - }, - ) - - if err != nil { - return nil, fmt.Errorf("Failed to render Song editor view: %s", err.Error()) - } - - return view, nil -} - -func init() { - item.Types["Song"] = func() interface{} { return new(Song) } -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/dom.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/dom.go deleted file mode 100644 index 5888db5..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/dom.go +++ /dev/null @@ -1,297 +0,0 @@ -package editor - -import ( - "bytes" - "html" - "log" - "strings" -) - -// Element is a basic struct for representing DOM elements -type Element struct { - TagName string - Attrs map[string]string - Name string - Label string - Data string - ViewBuf *bytes.Buffer -} - -// NewElement returns an Element with Name and Data already processed from the -// fieldName and content interface provided -func NewElement(tagName, label, fieldName string, p interface{}, attrs map[string]string) *Element { - return &Element{ - TagName: tagName, - Attrs: attrs, - Name: TagNameFromStructField(fieldName, p), - Label: label, - Data: ValueFromStructField(fieldName, p), - ViewBuf: &bytes.Buffer{}, - } -} - -// DOMElementSelfClose is a special DOM element which is parsed as a -// self-closing tag and thus needs to be created differently -func DOMElementSelfClose(e *Element) []byte { - _, err := e.ViewBuf.WriteString(`
`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementSelfClose") - return nil - } - - if e.Label != "" { - _, err = e.ViewBuf.WriteString( - ``) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementSelfClose") - return nil - } - } - - _, err = e.ViewBuf.WriteString(`<` + e.TagName + ` value="`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementSelfClose") - return nil - } - - _, err = e.ViewBuf.WriteString(html.EscapeString(e.Data) + `" `) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementSelfClose") - return nil - } - - for attr, value := range e.Attrs { - _, err := e.ViewBuf.WriteString(attr + `="` + value + `" `) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementSelfClose") - return nil - } - } - _, err = e.ViewBuf.WriteString(` name="` + e.Name + `" />`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementSelfClose") - return nil - } - - _, err = e.ViewBuf.WriteString(`
`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementSelfClose") - return nil - } - - return e.ViewBuf.Bytes() -} - -// DOMElementCheckbox is a special DOM element which is parsed as a -// checkbox input tag and thus needs to be created differently -func DOMElementCheckbox(e *Element) []byte { - _, err := e.ViewBuf.WriteString(`

`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementCheckbox") - return nil - } - - _, err = e.ViewBuf.WriteString(`<` + e.TagName + ` `) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementCheckbox") - return nil - } - - for attr, value := range e.Attrs { - _, err := e.ViewBuf.WriteString(attr + `="` + value + `" `) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementCheckbox") - return nil - } - } - _, err = e.ViewBuf.WriteString(` name="` + e.Name + `" />`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementCheckbox") - return nil - } - - if e.Label != "" { - _, err = e.ViewBuf.WriteString( - ``) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementCheckbox") - return nil - } - } - - _, err = e.ViewBuf.WriteString(`

`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementCheckbox") - return nil - } - - return e.ViewBuf.Bytes() -} - -// DOMElement creates a DOM element -func DOMElement(e *Element) []byte { - _, err := e.ViewBuf.WriteString(`
`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElement") - return nil - } - - if e.Label != "" { - _, err = e.ViewBuf.WriteString( - ``) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElement") - return nil - } - } - - _, err = e.ViewBuf.WriteString(`<` + e.TagName + ` `) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElement") - return nil - } - - for attr, value := range e.Attrs { - _, err = e.ViewBuf.WriteString(attr + `="` + string(value) + `" `) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElement") - return nil - } - } - _, err = e.ViewBuf.WriteString(` name="` + e.Name + `" >`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElement") - return nil - } - - _, err = e.ViewBuf.WriteString(html.EscapeString(e.Data)) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElement") - return nil - } - - _, err = e.ViewBuf.WriteString(``) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElement") - return nil - } - - _, err = e.ViewBuf.WriteString(`
`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElement") - return nil - } - - return e.ViewBuf.Bytes() -} - -func DOMElementWithChildrenSelect(e *Element, children []*Element) []byte { - _, err := e.ViewBuf.WriteString(`
`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementWithChildrenSelect") - return nil - } - - _, err = e.ViewBuf.WriteString(`<` + e.TagName + ` `) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementWithChildrenSelect") - return nil - } - - for attr, value := range e.Attrs { - _, err = e.ViewBuf.WriteString(attr + `="` + value + `" `) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementWithChildrenSelect") - return nil - } - } - _, err = e.ViewBuf.WriteString(` name="` + e.Name + `" >`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementWithChildrenSelect") - return nil - } - - // loop over children and create DOMElement for each child - for _, child := range children { - _, err = e.ViewBuf.Write(DOMElement(child)) - if err != nil { - log.Println("Error writing HTML DOMElement to buffer: DOMElementWithChildrenSelect") - return nil - } - } - - _, err = e.ViewBuf.WriteString(``) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementWithChildrenSelect") - return nil - } - - if e.Label != "" { - _, err = e.ViewBuf.WriteString(``) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementWithChildrenSelect") - return nil - } - } - - _, err = e.ViewBuf.WriteString(`
`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementWithChildrenSelect") - return nil - } - - return e.ViewBuf.Bytes() -} - -func DOMElementWithChildrenCheckbox(e *Element, children []*Element) []byte { - _, err := e.ViewBuf.WriteString(`<` + e.TagName + ` `) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementWithChildrenCheckbox") - return nil - } - - for attr, value := range e.Attrs { - _, err = e.ViewBuf.WriteString(attr + `="` + value + `" `) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementWithChildrenCheckbox") - return nil - } - } - - _, err = e.ViewBuf.WriteString(` >`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementWithChildrenCheckbox") - return nil - } - - if e.Label != "" { - _, err = e.ViewBuf.WriteString(``) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementWithChildrenCheckbox") - return nil - } - } - - // loop over children and create DOMElement for each child - for _, child := range children { - _, err = e.ViewBuf.Write(DOMElementCheckbox(child)) - if err != nil { - log.Println("Error writing HTML DOMElementCheckbox to buffer: DOMElementWithChildrenCheckbox") - return nil - } - } - - _, err = e.ViewBuf.WriteString(`
 
`) - if err != nil { - log.Println("Error writing HTML string to buffer: DOMElementWithChildrenCheckbox") - return nil - } - - return e.ViewBuf.Bytes() -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/editor.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/editor.go deleted file mode 100644 index 39bb25f..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/editor.go +++ /dev/null @@ -1,267 +0,0 @@ -// Package editor enables users to create edit views from their content -// structs so that admins can manage content -package editor - -import ( - "bytes" - "log" - "net/http" -) - -// Editable ensures data is editable -type Editable interface { - MarshalEditor() ([]byte, error) -} - -// Mergeable allows external post content to be approved and published through -// the public-facing API -type Mergeable interface { - // Approve copies an external post to the internal collection and triggers - // a re-sort of its content type posts - Approve(http.ResponseWriter, *http.Request) error -} - -// Editor is a view containing fields to manage content -type Editor struct { - ViewBuf *bytes.Buffer -} - -// Field is used to create the editable view for a field -// within a particular content struct -type Field struct { - View []byte -} - -// Form takes editable content and any number of Field funcs to describe the edit -// page for any content struct added by a user -func Form(post Editable, fields ...Field) ([]byte, error) { - editor := &Editor{} - - editor.ViewBuf = &bytes.Buffer{} - _, err := editor.ViewBuf.WriteString(``) - if err != nil { - log.Println("Error writing HTML string to editor Form buffer") - return nil, err - } - - // content items with Item embedded have some default fields we need to render - _, err = editor.ViewBuf.WriteString(`
`) - if err != nil { - log.Println("Error writing HTML string to editor Form buffer") - return nil, err - } - - for _, f := range fields { - addFieldToEditorView(editor, f) - } - - _, err = editor.ViewBuf.WriteString(`
`) - if err != nil { - log.Println("Error writing HTML string to editor Form buffer") - return nil, err - } - - publishTime := ` -
-
- - -
-
- - -
-
- - -
-
- -
-
- - -
-
:
-
- - -
-
- - -
-
- ` - - _, err = editor.ViewBuf.WriteString(publishTime) - if err != nil { - log.Println("Error writing HTML string to editor Form buffer") - return nil, err - } - - err = addPostDefaultFieldsToEditorView(post, editor) - if err != nil { - return nil, err - } - - submit := ` -
- - -
-` - _, ok := post.(Mergeable) - if ok { - submit += - ` -
-
- - -
- -
-` - } - - script := ` - -` - _, err = editor.ViewBuf.WriteString(submit + script + `
`) - if err != nil { - log.Println("Error writing HTML string to editor Form buffer") - return nil, err - } - - return editor.ViewBuf.Bytes(), nil -} - -func addFieldToEditorView(e *Editor, f Field) error { - _, err := e.ViewBuf.Write(f.View) - if err != nil { - log.Println("Error writing field view to editor view buffer") - return err - } - - return nil -} - -func addPostDefaultFieldsToEditorView(p Editable, e *Editor) error { - defaults := []Field{ - { - View: Input("Slug", p, map[string]string{ - "label": "URL Slug", - "type": "text", - "disabled": "true", - "placeholder": "Will be set automatically", - }), - }, - { - View: Timestamp("Timestamp", p, map[string]string{ - "type": "hidden", - "class": "timestamp __ponzu", - }), - }, - { - View: Timestamp("Updated", p, map[string]string{ - "type": "hidden", - "class": "updated __ponzu", - }), - }, - } - - for _, f := range defaults { - err := addFieldToEditorView(e, f) - if err != nil { - return err - } - } - - return nil -} diff --git a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/elements.go b/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/elements.go deleted file mode 100644 index b179960..0000000 --- a/examples/docker/admin/cmd/ponzu/vendor/github.com/ponzu-cms/ponzu/management/editor/elements.go +++ /dev/null @@ -1,520 +0,0 @@ -package editor - -import ( - "bytes" - "html" - "strings" -) - -// Input returns the []byte of an HTML element with a label. -// IMPORTANT: -// The `fieldName` argument will cause a panic if it is not exactly the string -// form of the struct field that this editor input is representing -// type Person struct { -// item.Item -// editor editor.Editor -// -// Name string `json:"name"` -// //... -// } -// -// func (p *Person) MarshalEditor() ([]byte, error) { -// view, err := editor.Form(p, -// editor.Field{ -// View: editor.Input("Name", p, map[string]string{ -// "label": "Name", -// "type": "text", -// "placeholder": "Enter the Name here", -// }), -// } -// ) -// } -func Input(fieldName string, p interface{}, attrs map[string]string) []byte { - e := NewElement("input", attrs["label"], fieldName, p, attrs) - - return DOMElementSelfClose(e) -} - -// Textarea returns the []byte of a ",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,ba=/<([\w:]+)/,ca=/<|&#?\w+;/,da=/<(?:script|style|link)/i,ea=/checked\s*(?:[^=]|=\s*.checked.)/i,fa=/^$|\/(?:java|ecma)script/i,ga=/^true\/(.*)/,ha=/^\s*\s*$/g,ia={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ia.optgroup=ia.option,ia.tbody=ia.tfoot=ia.colgroup=ia.caption=ia.thead,ia.th=ia.td;function ja(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function ka(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function la(a){var b=ga.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function ma(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function na(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function oa(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pa(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=oa(h),f=oa(a),d=0,e=f.length;e>d;d++)pa(f[d],g[d]);if(b)if(c)for(f=f||oa(a),g=g||oa(h),d=0,e=f.length;e>d;d++)na(f[d],g[d]);else na(a,h);return g=oa(h,"script"),g.length>0&&ma(g,!i&&oa(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(ca.test(e)){f=f||k.appendChild(b.createElement("div")),g=(ba.exec(e)||["",""])[1].toLowerCase(),h=ia[g]||ia._default,f.innerHTML=h[1]+e.replace(aa,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=oa(k.appendChild(e),"script"),i&&ma(f),c)){j=0;while(e=f[j++])fa.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(oa(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&ma(oa(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(oa(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!da.test(a)&&!ia[(ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(aa,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(oa(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(oa(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&ea.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(oa(c,"script"),ka),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,oa(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,la),j=0;g>j;j++)h=f[j],fa.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(ha,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qa,ra={};function sa(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function ta(a){var b=l,c=ra[a];return c||(c=sa(a,b),"none"!==c&&c||(qa=(qa||n("