diff --git a/.dockerignore b/.dockerignore index dc21d2d81..25a005ec2 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,11 +8,13 @@ /assets/resources/nsfw /assets/testdata /assets/backups -Dockerfile /photoprism -docker-compose* /coverage.* +/frontend/tests/acceptance/screenshots .dockerignore .idea .DS_Store -/frontend/tests/acceptance/screenshots +*.db +*.db-journal +Dockerfile +docker-compose* diff --git a/.gitignore b/.gitignore index c830f1f4d..bd8144fe4 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,8 @@ /assets/resources/nsfw /package-lock.json *.log +*.db +*.db-journal # Binaries for programs and plugins *.exe diff --git a/Makefile b/Makefile index e16a0ca4c..d0b8089ed 100644 --- a/Makefile +++ b/Makefile @@ -96,8 +96,9 @@ acceptance-firefox: $(info Running JS acceptance tests in Firefox...) (cd frontend && npm run acceptance-firefox) reset-test-db: - $(info Purging test database...) + $(info Purging test databases...) mysql < scripts/reset-test-db.sql + find ./internal -type f -name '.test.*' -delete run-test-short: $(info Running short Go unit tests in parallel mode...) $(GOTEST) -parallel 2 -count 1 -cpu 2 -short -timeout 5m ./pkg/... ./internal/... diff --git a/assets/config/photoprism.yml b/assets/config/photoprism.yml index 2258e73a5..dff0ae59e 100644 --- a/assets/config/photoprism.yml +++ b/assets/config/photoprism.yml @@ -18,11 +18,7 @@ import-path: ~/Pictures/Import http-host: http-mode: release http-port: 2342 -tidb-host: localhost -tidb-port: 2343 -tidb-password: photoprism -database-driver: tidb -database-dsn: root:photoprism@tcp(localhost:2343)/photoprism?parseTime=true +database-driver: sqlite pid-filename: ~/.local/share/photoprism/photoprism.pid log-filename: ~/.local/share/photoprism/photoprism.log detach-server: false diff --git a/docker-compose.travis.yml b/docker-compose.travis.yml index c217d5022..c9e493428 100644 --- a/docker-compose.travis.yml +++ b/docker-compose.travis.yml @@ -22,12 +22,9 @@ services: PHOTOPRISM_DETACH_SERVER: "true" PHOTOPRISM_HTTP_HOST: "0.0.0.0" PHOTOPRISM_HTTP_PORT: 2342 - PHOTOPRISM_TIDB_HOST: "0.0.0.0" - PHOTOPRISM_TIDB_PORT: 2343 - PHOTOPRISM_TIDB_PASSWORD: "photoprism" - PHOTOPRISM_DATABASE_DRIVER: "tidb" - PHOTOPRISM_DATABASE_DSN: "root:photoprism@tcp(localhost:2343)/photoprism?parseTime=true" - PHOTOPRISM_TEST_DSN: "root:photoprism@tcp(photoprism-db:4001)/photoprism?parseTime=true" + PHOTOPRISM_DATABASE_DRIVER: "mysql" + PHOTOPRISM_DATABASE_DSN: "root:photoprism@tcp(photoprism-db:4001)/photoprism?parseTime=true" + PHOTOPRISM_TEST_DRIVER: "test" PHOTOPRISM_TITLE: "PhotoPrism" PHOTOPRISM_SUBTITLE: "Browse your life" PHOTOPRISM_DESCRIPTION: "Personal Photo Management tested by Travis CI." diff --git a/docker-compose.yml b/docker-compose.yml index 2144435bb..5d8d0550d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,6 @@ services: - photoprism-db ports: - "2342:2342" # Web Server (PhotoPrism) - - "2343:2343" # Database (built-in TiDB) volumes: - ".:/go/src/github.com/photoprism/photoprism" - "go-mod:/go/pkg/mod" @@ -25,12 +24,9 @@ services: PHOTOPRISM_SERVER_MODE: "debug" PHOTOPRISM_HTTP_HOST: "0.0.0.0" PHOTOPRISM_HTTP_PORT: 2342 - PHOTOPRISM_TIDB_HOST: "0.0.0.0" - PHOTOPRISM_TIDB_PORT: 2343 - PHOTOPRISM_TIDB_PASSWORD: "photoprism" - PHOTOPRISM_DATABASE_DRIVER: "tidb" - PHOTOPRISM_DATABASE_DSN: "root:photoprism@tcp(localhost:2343)/photoprism?parseTime=true" - PHOTOPRISM_TEST_DSN: "root:photoprism@tcp(photoprism-db:4001)/photoprism?parseTime=true" + PHOTOPRISM_DATABASE_DRIVER: "mysql" + PHOTOPRISM_DATABASE_DSN: "root:photoprism@tcp(photoprism-db:4001)/photoprism?parseTime=true" + PHOTOPRISM_TEST_DRIVER: "test" PHOTOPRISM_ASSETS_PATH: "/go/src/github.com/photoprism/photoprism/assets" PHOTOPRISM_CACHE_PATH: "/go/src/github.com/photoprism/photoprism/assets/cache" PHOTOPRISM_RESOURCES_PATH: "/go/src/github.com/photoprism/photoprism/assets/resources" diff --git a/docker/development/Dockerfile b/docker/development/Dockerfile index 0ca1d306a..2a76e192a 100644 --- a/docker/development/Dockerfile +++ b/docker/development/Dockerfile @@ -49,7 +49,8 @@ RUN apt-get update && apt-get upgrade && \ firefox \ libheif-examples \ exiftool \ - ffmpeg + ffmpeg \ + lsof # Install RAW to JPEG converter RUN sh -c "echo 'deb http://download.opensuse.org/repositories/graphics:/darktable/xUbuntu_18.04/ /' > /etc/apt/sources.list.d/graphics:darktable.list" && \ @@ -122,8 +123,8 @@ COPY /docker/development/.my.cnf /root/.my.cnf # Set up project directory WORKDIR "/go/src/github.com/photoprism/photoprism" -# Expose HTTP port 2342 plus 2343 for TiDB and 9515 for chromedriver -EXPOSE 2342 2343 9515 +# Expose HTTP port 2342 plus 9515 for chromedriver +EXPOSE 2342 9515 # Keep container running (services can be started manually using a terminal) CMD tail -f /dev/null diff --git a/docker/photoprism/Dockerfile b/docker/photoprism/Dockerfile index 12fbfba28..77942034e 100644 --- a/docker/photoprism/Dockerfile +++ b/docker/photoprism/Dockerfile @@ -56,7 +56,6 @@ ENV PATH /photoprism/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin ENV PHOTOPRISM_ORIGINALS_PATH /photoprism/originals ENV PHOTOPRISM_IMPORT_PATH /photoprism/import -ENV PHOTOPRISM_TIDB_PATH /photoprism/database ENV PHOTOPRISM_TEMP_PATH /photoprism/temp ENV PHOTOPRISM_CACHE_PATH /photoprism/cache ENV PHOTOPRISM_CONFIG_PATH /photoprism/config diff --git a/docker/photoprism/arm64/Dockerfile b/docker/photoprism/arm64/Dockerfile index 68650aa39..2068a3d87 100644 --- a/docker/photoprism/arm64/Dockerfile +++ b/docker/photoprism/arm64/Dockerfile @@ -140,7 +140,6 @@ ENV PATH /photoprism/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin ENV PHOTOPRISM_ORIGINALS_PATH /photoprism/originals ENV PHOTOPRISM_IMPORT_PATH /photoprism/import -ENV PHOTOPRISM_TIDB_PATH /photoprism/database ENV PHOTOPRISM_TEMP_PATH /photoprism/temp ENV PHOTOPRISM_CACHE_PATH /photoprism/cache ENV PHOTOPRISM_CONFIG_PATH /photoprism/config diff --git a/docker/photoprism/arm64/docker-compose.yml b/docker/photoprism/arm64/docker-compose.yml index 71d55d181..59dee5a61 100644 --- a/docker/photoprism/arm64/docker-compose.yml +++ b/docker/photoprism/arm64/docker-compose.yml @@ -13,7 +13,6 @@ services: - seccomp:unconfined ports: - 2342:2342 # [local port]:[container port] - # - 2343:2343 # Database (built-in TiDB) healthcheck: # Optional test: "photoprism status" interval: 60s @@ -34,14 +33,10 @@ services: PHOTOPRISM_DISABLE_SETTINGS: "false" PHOTOPRISM_HTTP_HOST: "0.0.0.0" PHOTOPRISM_HTTP_PORT: 2342 - PHOTOPRISM_TIDB_HOST: "0.0.0.0" - PHOTOPRISM_TIDB_PORT: 2343 # Port for built-in TiDB SQL server (driver "tidb") - PHOTOPRISM_TIDB_PASSWORD: "photoprism" # Plain text only (username "root") PHOTOPRISM_ADMIN_PASSWORD: "photoprism" # Plain text or bcrypt hash (escape "$" with "$$") PHOTOPRISM_WEBDAV_PASSWORD: "photoprism" # Plain text only (username "photoprism") - PHOTOPRISM_DATABASE_DRIVER: "tidb" # Change to "mysql" for external MySQL or MariaDB - PHOTOPRISM_DATABASE_DSN: "root:photoprism@tcp(localhost:2343)/photoprism?parseTime=true" - # PHOTOPRISM_DATABASE_DRIVER: "mysql" # Using MariaDB or MySQL instead of the internal TiDB is optional + PHOTOPRISM_DATABASE_DRIVER: "sqlite" # Change to "mysql" for external MySQL or MariaDB + # PHOTOPRISM_DATABASE_DRIVER: "mysql" # Using MariaDB or MySQL instead of SQLite is optional # PHOTOPRISM_DATABASE_DSN: "photoprism:photoprism@tcp(photoprism-db:3306)/photoprism?parseTime=true" # PHOTOPRISM_SIDECAR_JSON: "true" # Read metadata from JSON sidecar files created by exiftool # PHOTOPRISM_SIDECAR_YAML: "true" # Backup photo metadata to YAML sidecar files @@ -58,12 +53,9 @@ services: - "~/Pictures/Import:/photoprism/import" # [local path]:[container path] (optional) - "photoprism-config:/photoprism/config" # keep settings - "photoprism-cache:/photoprism/cache" # keep thumbnail cache - - "photoprism-database:/photoprism/database" # keep database files volumes: # keep this photoprism-config: driver: local photoprism-cache: driver: local - photoprism-database: - driver: local diff --git a/docker/photoprism/docker-compose.yml b/docker/photoprism/docker-compose.yml index 0bfd2bfef..4ebffbcca 100644 --- a/docker/photoprism/docker-compose.yml +++ b/docker/photoprism/docker-compose.yml @@ -12,7 +12,6 @@ services: restart: unless-stopped ports: - 2342:2342 # [local port]:[container port] - # - 2343:2343 # Database (built-in TiDB) healthcheck: # Optional test: "photoprism status" interval: 60s @@ -33,14 +32,10 @@ services: PHOTOPRISM_DISABLE_SETTINGS: "false" PHOTOPRISM_HTTP_HOST: "0.0.0.0" PHOTOPRISM_HTTP_PORT: 2342 - PHOTOPRISM_TIDB_HOST: "0.0.0.0" - PHOTOPRISM_TIDB_PORT: 2343 # Port for built-in TiDB SQL server (driver "tidb") - PHOTOPRISM_TIDB_PASSWORD: "photoprism" # Plain text only (username "root") PHOTOPRISM_ADMIN_PASSWORD: "photoprism" # Plain text or bcrypt hash (escape "$" with "$$") PHOTOPRISM_WEBDAV_PASSWORD: "photoprism" # Plain text only (username "photoprism") - PHOTOPRISM_DATABASE_DRIVER: "tidb" # Change to "mysql" for external MySQL or MariaDB - PHOTOPRISM_DATABASE_DSN: "root:photoprism@tcp(localhost:2343)/photoprism?parseTime=true" - # PHOTOPRISM_DATABASE_DRIVER: "mysql" # Using MariaDB or MySQL instead of the internal TiDB is optional + PHOTOPRISM_DATABASE_DRIVER: "sqlite" # Change to "mysql" for external MySQL or MariaDB + # PHOTOPRISM_DATABASE_DRIVER: "mysql" # Using MariaDB or MySQL instead of SQLite is optional # PHOTOPRISM_DATABASE_DSN: "photoprism:photoprism@tcp(photoprism-db:3306)/photoprism?parseTime=true" # PHOTOPRISM_SIDECAR_JSON: "true" # Read metadata from JSON sidecar files created by exiftool # PHOTOPRISM_SIDECAR_YAML: "true" # Backup photo metadata to YAML sidecar files @@ -57,9 +52,8 @@ services: - "~/Pictures/Import:/photoprism/import" # [local path]:[container path] (optional) - "photoprism-config:/photoprism/config" # keep settings - "photoprism-cache:/photoprism/cache" # keep thumbnail cache - - "photoprism-database:/photoprism/database" # TiDB database files, remove if you use MariaDB or MySQL - # photoprism-db: # Uncomment, if you want to use MariaDB instead of the internal TiDB + # photoprism-db: # Uncomment, if you want to use MariaDB instead of SQLite # image: mariadb:10.5 # Alternatively mysql:8.0 # restart: unless-stopped # command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=1024 --innodb-rollback-on-timeout=ON --innodb-lock-wait-timeout=120 @@ -76,5 +70,5 @@ volumes: # keep this driver: local photoprism-cache: driver: local - photoprism-database: - driver: local +# photoprism-database: +# driver: local diff --git a/go.mod b/go.mod index 5dc50ea04..698bcb841 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,7 @@ module github.com/photoprism/photoprism require ( github.com/allegro/bigcache v1.2.1 github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1 - github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect - github.com/coreos/etcd v3.3.10+incompatible // indirect - github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142 // indirect - github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect - github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect - github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8 // indirect github.com/disintegration/imaging v1.6.2 github.com/djherbis/times v1.2.0 github.com/dsoprea/go-exif/v2 v2.0.0-20200519064707-3cdb59fd80c7 @@ -17,18 +11,11 @@ require ( github.com/dsoprea/go-png-image-structure v0.0.0-20200518003737-91ceb687d379 github.com/dustin/go-humanize v1.0.0 github.com/gin-gonic/gin v1.6.3 - github.com/gogo/protobuf v1.2.0 // indirect github.com/golang/geo v0.0.0-20200319012246-673a6f80352d github.com/golang/protobuf v1.3.5 // indirect - github.com/golang/snappy v0.0.1 // indirect - github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect github.com/google/open-location-code/go v0.0.0-20191230190541-a6eb95b4d2f9 - github.com/gorilla/context v1.1.1 // indirect - github.com/gorilla/mux v1.6.2 // indirect github.com/gorilla/websocket v1.4.2 github.com/gosimple/slug v1.9.0 - github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 // indirect - github.com/grpc-ecosystem/grpc-gateway v1.5.1 // indirect github.com/jinzhu/gorm v1.9.12 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect github.com/karrick/godirwalk v1.15.6 @@ -39,50 +26,24 @@ require ( github.com/melihmucuk/geocache v0.0.0-20160621165317-521b336a001c github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect - github.com/montanaflynn/stats v0.0.0-20181214052348-945b007cb92f // indirect - github.com/myesui/uuid v1.0.0 // indirect - github.com/onsi/gomega v1.4.3 // indirect - github.com/opentracing/opentracing-go v1.0.2 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/paulmach/go.geojson v1.4.0 - github.com/pingcap/errors v0.11.1 - github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e // indirect - github.com/pingcap/parser v0.0.0-20190529073816-0550d84c65ad - github.com/pingcap/pd v2.1.0-rc.4+incompatible - github.com/pingcap/tidb v2.1.11+incompatible - github.com/pingcap/tidb-tools v2.1.3-0.20190116051332-34c808eef588+incompatible - github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 - github.com/remyoudompheng/bigfft v0.0.0-20190512091148-babf20351dd7 // indirect github.com/satori/go.uuid v1.2.0 github.com/sevlyar/go-daemon v0.1.5 github.com/shopspring/decimal v1.2.0 // indirect github.com/sirupsen/logrus v1.6.0 - github.com/soheilhy/cmux v0.1.4 // indirect - github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 // indirect - github.com/stretchr/objx v0.2.0 // indirect github.com/stretchr/testify v1.5.1 github.com/studio-b12/gowebdav v0.0.0-20200303150724-9380631c29a1 github.com/tensorflow/tensorflow v1.15.2 github.com/tidwall/gjson v1.6.0 github.com/tidwall/pretty v1.0.1 // indirect - github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 // indirect - github.com/twinj/uuid v1.0.0 // indirect - github.com/uber-go/atomic v1.3.2 // indirect - github.com/uber/jaeger-client-go v2.15.0+incompatible // indirect - github.com/uber/jaeger-lib v1.5.0 // indirect github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 - github.com/unrolled/render v0.0.0-20181210145518-4c664cb3ad2f // indirect github.com/urfave/cli v1.22.4 - go.uber.org/atomic v1.4.0 // indirect golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 golang.org/x/image v0.0.0-20200430140353-33d19683fad8 // indirect golang.org/x/net v0.0.0-20200513185701-a91f0712d120 golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 // indirect - golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect - golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d // indirect - google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect - gopkg.in/stretchr/testify.v1 v1.2.2 // indirect gopkg.in/ugjka/go-tz.v2 v2.0.9 gopkg.in/yaml.v2 v2.3.0 ) diff --git a/go.sum b/go.sum index 5a9c391fd..a927d1eb9 100644 --- a/go.sum +++ b/go.sum @@ -1,56 +1,18 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/apache/thrift v0.0.0-20161221203622-b2a4d4ae21c7 h1:Fv9bK1Q+ly/ROk4aJsVMeuIwPel4bEnD8EPiI91nZMg= -github.com/apache/thrift v0.0.0-20161221203622-b2a4d4ae21c7/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1 h1:TEBmxO80TM04L8IuMWk77SGL1HomBmKTdzdJLLWznxI= github.com/araddon/dateparse v0.0.0-20200409225146-d820a6159ab1/go.mod h1:SLqhdZcd+dF3TEVL2RMoob5bBP5R1P1qkox+HtCBgGI= -github.com/beorn7/perks v0.0.0-20160229213445-3ac7bf7a47d1/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d h1:rQlvB2AYWme2bIB18r/SipGiMEVJYE9U0z+MGoU/LtQ= -github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d/go.mod h1:VKt7CNAQxpFpSDz3sXyj9hY/GbVsQCr0sB3w59nE7lU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/cmux v0.0.0-20170110192607-30d10be49292/go.mod h1:qRiX68mZX1lGBkTWyp3CLcenw9I94W2dLeRvMzcn9N4= -github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/coreos/bbolt v1.3.1-coreos.6 h1:uTXKg9gY70s9jMAKdfljFQcuh4e/BXOM+V+d00KFj3A= -github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.2.18+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180202092358-40e2722dffea/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142 h1:3jFq2xL4ZajGK4aZY8jz+DAF0FHjI51BXjjSwCzS1Dk= -github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cznic/mathutil v0.0.0-20160613104831-78ad7f262603/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= -github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso= -github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= -github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= -github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8 h1:LpMLYGyy67BoAFGda1NeOBQwqlv7nUXpm+rIVHGxZZ4= -github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/djherbis/times v1.2.0 h1:xANXjsC/iBqbO00vkWlYwPWgBgEVU6m6AFYg0Pic+Mc= @@ -71,107 +33,47 @@ github.com/dsoprea/go-png-image-structure v0.0.0-20200518003737-91ceb687d379 h1: github.com/dsoprea/go-png-image-structure v0.0.0-20200518003737-91ceb687d379/go.mod h1:Tg1+KPxoNGpX2lVyapYmTNsX1VNVmlEeNqWNA0jwpsg= github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176 h1:CfXezFYb2STGOd1+n1HshvE191zVx+QX3A1nML5xxME= github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8= -github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= -github.com/etcd-io/gofail v0.0.0-20180808172546-51ce9a71510a h1:QNEenQIsGDEEfFNSnN+h6hE1OwnHqTg7Dl9gEk1Cko4= -github.com/etcd-io/gofail v0.0.0-20180808172546-51ce9a71510a/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.2 h1:88crIK23zO6TqlQBt+f9FrPJNKm9ZEr7qjp9vl/d5TM= -github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4= github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/overalls v0.0.0-20180201144345-22ec1a223b7c/go.mod h1:UqxAgEOt89sCiXlrc/ycnx00LVvUO/eS8tMUkWX4R7w= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-sql-driver/mysql v0.0.0-20170715192408-3955978caca4/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec h1:lJwO/92dFXWeXOZdoGXgptLmNLwynMSHUmU6besqtiw= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/geo v0.0.0-20200319012246-673a6f80352d h1:C/hKUcHT483btRbeGkrRjJz+Zbcj8audldIi9tRJDCc= github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff h1:kOkM9whyQYodu09SJ6W3NCsHG7crFaJILQ22Gozp3lg= -github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20161217183710-316fb6d3f031/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/open-location-code/go v0.0.0-20191230190541-a6eb95b4d2f9 h1:6ILzS4n0F17S38XvOB1BcyzB+0BtVzU77EyuMtkMffo= github.com/google/open-location-code/go v0.0.0-20191230190541-a6eb95b4d2f9/go.mod h1:eJfRN6aj+kR/rnua/rw9jAgYhqoMHldQkdTi+sePRKk= -github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= -github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v0.0.0-20170228224354-599cba5e7b61/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosimple/slug v1.9.0 h1:r5vDcYrFz9BmfIAMC829un9hq7hKM4cHUrsv36LbEqs= github.com/gosimple/slug v1.9.0/go.mod h1:AMZ+sOVe65uByN3kgEyf9WEBKBCSS+dJjMX9x4vDJbg= -github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20171020063731-82921fcf811d/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20160910222444-6b7015e65d36 h1:cwTrrTEhz13khQS3/UZMLFWwiqlcsdp/2sxFmSjAWeQ= -github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20160910222444-6b7015e65d36/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.4.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/grpc-ecosystem/grpc-gateway v1.5.1 h1:3scN4iuXkNOyP98jF55Lv8a9j1o/IwvnDIZ0LHJK1nk= -github.com/grpc-ecosystem/grpc-gateway v1.5.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= @@ -179,22 +81,14 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/karrick/godirwalk v1.15.6 h1:Yf2mmR8TJy+8Fa0SuQVto5SYap6IF7lNVX4Jdl8G1qA= github.com/karrick/godirwalk v1.15.6/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -215,8 +109,6 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/melihmucuk/geocache v0.0.0-20160621165317-521b336a001c h1:1ErTnOL2d0OvfUABvEjGcPM8cKSLxYZpJiYS4BfQ3o4= github.com/melihmucuk/geocache v0.0.0-20160621165317-521b336a001c/go.mod h1:CX2bLGC22DrgJTaYvKt+lOi3BACGNA60hbFXh2iWebs= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -225,83 +117,14 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/montanaflynn/stats v0.0.0-20151014174947-eeaced052adb/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/montanaflynn/stats v0.0.0-20181214052348-945b007cb92f h1:r//C+RGlxxi1gPODiDj/Y/uvv3OaZlZPSFz2SuwIees= -github.com/montanaflynn/stats v0.0.0-20181214052348-945b007cb92f/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/myesui/uuid v1.0.0 h1:xCBmH4l5KuvLYc5L7AS7SZg9/jKdIFubM7OVoLqaQUI= -github.com/myesui/uuid v1.0.0/go.mod h1:2CDfNgU0LR8mIdO8vdWd8i9gWWxLlcoIGGpSNgafq84= -github.com/ngaut/pools v0.0.0-20180318154953-b7bc8c42aac7 h1:7KAv7KMGTTqSmYZtNdcNTgsos+vFzULLwyElndwn+5c= -github.com/ngaut/pools v0.0.0-20180318154953-b7bc8c42aac7/go.mod h1:iWMfgwqYW+e8n5lC/jjNEhwcjbRDpl5NT7n2h+4UNcI= -github.com/ngaut/sync2 v0.0.0-20141008032647-7a24ed77b2ef h1:K0Fn+DoFqNqktdZtdV3bPQ/0cuYh2H4rkg0tytX/07k= -github.com/ngaut/sync2 v0.0.0-20141008032647-7a24ed77b2ef/go.mod h1:7WjlapSfwQyo6LNmIvEWzsW1hbBQfpUO4JWnuQRmva8= -github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo= -github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= -github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/paulmach/go.geojson v1.4.0 h1:5x5moCkCtDo5x8af62P9IOAYGQcYHtxz2QJ3x1DoCgY= github.com/paulmach/go.geojson v1.4.0/go.mod h1:YaKx1hKpWF+T2oj2lFJPsW/t1Q5e1jQI61eoQSTwpIs= -github.com/pelletier/go-toml v1.3.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= -github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8 h1:USx2/E1bX46VG32FIw034Au6seQ2fY9NEILmNh/UlQg= -github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8/go.mod h1:B1+S9LNcuMyLH/4HMTViQOJevkGiik3wW2AN9zb2fNQ= -github.com/pingcap/errors v0.11.0 h1:DCJQB8jrHbQ1VVlMFIrbj2ApScNNotVmkSNplu2yUt4= -github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= -github.com/pingcap/errors v0.11.1 h1:BXFZ6MdDd2U1uJUa2sRAWTmm+nieEzuyYM0R4aUTcC8= -github.com/pingcap/errors v0.11.1/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= -github.com/pingcap/failpoint v0.0.0-20190430075617-bf45ab20bfc4 h1:4dCk6ysGubtlSc9hE/t5Ptl6mMVxSoWSsTvGSbFJwJ8= -github.com/pingcap/failpoint v0.0.0-20190430075617-bf45ab20bfc4/go.mod h1:p2F6D0adua5g+596cw96U8hU8slkeJhboEV7ySGDeEg= -github.com/pingcap/goleveldb v0.0.0-20171020084629-8d44bfdf1030 h1:XJLuW0lsP7vAtQ2iPjZwvXZ14m5urp9No+Qr06ZZcTo= -github.com/pingcap/goleveldb v0.0.0-20171020084629-8d44bfdf1030/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw= -github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rGrobssy1nVy2VaVpNCuLpCbr+FEaTA8= -github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw= -github.com/pingcap/kvproto v0.0.0-20190226063853-f6c0b7ffff11 h1:e81flSfRbbMW5RUnz1cJl+8XKOVUCfF8FapFS8HnHLs= -github.com/pingcap/kvproto v0.0.0-20190226063853-f6c0b7ffff11/go.mod h1:0gwbe1F2iBIjuQ9AH0DbQhL+Dpr5GofU8fgYyXk+ykk= -github.com/pingcap/log v0.0.0-20190307075452-bd41d9273596 h1:t2OQTpPJnrPDGlvA+3FwJptMTt6MEPdzK1Wt99oaefQ= -github.com/pingcap/log v0.0.0-20190307075452-bd41d9273596/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw= -github.com/pingcap/parser v0.0.0-20190529073816-0550d84c65ad h1:XLVTXFsIYkKlV55mbBk84op/W67Cjh497d0zLt6jn/M= -github.com/pingcap/parser v0.0.0-20190529073816-0550d84c65ad/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= -github.com/pingcap/pd v2.1.0-rc.4+incompatible h1:/buwGk04aHO5odk/+O8ZOXGs4qkUjYTJ2UpCJXna8NE= -github.com/pingcap/pd v2.1.0-rc.4+incompatible/go.mod h1:nD3+EoYes4+aNNODO99ES59V83MZSI+dFbhyr667a0E= -github.com/pingcap/tidb v2.1.11+incompatible h1:gK+uPTQSG8brUbwx+HIPdQBvAWZjvIHqvxfNOvUxNOc= -github.com/pingcap/tidb v2.1.11+incompatible/go.mod h1:XcM8kyDXxZR+dkzsNuajtC2REDqMblOiFTKHxTX0LZ0= -github.com/pingcap/tidb-tools v2.1.3-0.20190116051332-34c808eef588+incompatible h1:e9Gi/LP9181HT3gBfSOeSBA+5JfemuE4aEAhqNgoE4k= -github.com/pingcap/tidb-tools v2.1.3-0.20190116051332-34c808eef588+incompatible/go.mod h1:XGdcy9+yqlDSEMTpOXnwf3hiTeqrV6MN/u1se9N8yIM= -github.com/pingcap/tipb v0.0.0-20180910045846-371b48b15d93 h1:gI5bOzLMxjUq6ui+md/JnT4pYpkzrABJ/PeYORWiYYs= -github.com/pingcap/tipb v0.0.0-20180910045846-371b48b15d93/go.mod h1:RtkHW8WbcNxj8lsbzjaILci01CtYnYbIkQhjyZWrWVI= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.0.0-20180426121432-d811d2e9bf89/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20180408092902-8b1c2da0d56d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ= github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q= -github.com/remyoudompheng/bigfft v0.0.0-20190512091148-babf20351dd7 h1:FUL3b97ZY2EPqg2NbXKuMHs5pXJB9hjj1fDHnF2vl28= -github.com/remyoudompheng/bigfft v0.0.0-20190512091148-babf20351dd7/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= @@ -312,23 +135,9 @@ github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXY github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v0.0.0-20170323161349-3bcb09397d6d/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= -github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q= -github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20150829172844-0d12bf811670/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= @@ -349,93 +158,33 @@ github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.1 h1:WE4RBSZ1x6McVVC8S/Md+Qse8YUv6HRObAx6ke00NY8= github.com/tidwall/pretty v1.0.1/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 h1:lYIiVDtZnyTWlNwiAxLj0bbpTcx1BWCFhXjfsvmPdNc= -github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/twinj/uuid v0.0.0-20150629100731-70cac2bcd273/go.mod h1:mMgcE1RHFUFqe5AfiwlINXisXfDGro23fWdPUfOMjRY= -github.com/twinj/uuid v1.0.0 h1:fzz7COZnDrXGTAOHGuUGYd6sG+JMq+AoE7+Jlu0przk= -github.com/twinj/uuid v1.0.0/go.mod h1:mMgcE1RHFUFqe5AfiwlINXisXfDGro23fWdPUfOMjRY= -github.com/uber-go/atomic v1.3.2 h1:Azu9lPBWRNKzYXSIwRfgRuDuS0YKsK4NFhiQv98gkxo= -github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= -github.com/uber/jaeger-client-go v2.8.0+incompatible h1:7DGH8Hqk6PirD+GE+bvCf0cLnspLuae7N1NcwMeQcyg= -github.com/uber/jaeger-client-go v2.8.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -github.com/uber/jaeger-client-go v2.15.0+incompatible h1:NP3qsSqNxh8VYr956ur1N/1C1PjvOJnJykCzcD5QHbk= -github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -github.com/uber/jaeger-lib v1.1.0 h1:k1oxbz5ToLJtwCGmTlNSmfciXv/SPe1tnmNe+FqTl5w= -github.com/uber/jaeger-lib v1.1.0/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= -github.com/uber/jaeger-lib v1.5.0 h1:OHbgr8l656Ub3Fw5k9SWnBfIEwvoHQ+W2y+Aa9D1Uyo= -github.com/uber/jaeger-lib v1.5.0/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= -github.com/ugorji/go v1.1.1 h1:gmervu+jDMvXTbcHQ0pd2wee85nEoE0BsVyEuzkfK8w= -github.com/ugorji/go v1.1.1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 h1:TtyC78WMafNW8QFfv3TeP3yWNDG+uxNkk9vOrnDu6JA= github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6/go.mod h1:h8272+G2omSmi30fBXiZDMkmHuOgonplfKIKjQWzlfs= -github.com/unrolled/render v0.0.0-20171102162132-65450fb6b2d3/go.mod h1:tu82oB5W2ykJRVioYsB+IQKcft7ryBr7w12qMBUPyXg= -github.com/unrolled/render v0.0.0-20181210145518-4c664cb3ad2f h1:+feYJlxPM00jEkdybexHiwIIOVuClwTEbh1WLiNr0mk= -github.com/unrolled/render v0.0.0-20181210145518-4c664cb3ad2f/go.mod h1:tu82oB5W2ykJRVioYsB+IQKcft7ryBr7w12qMBUPyXg= github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18 h1:MPPkRncZLN9Kh4MEFmbnK4h3BD7AUmskWv2+EeZJCCs= -github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/yookoala/realpath v1.0.0/go.mod h1:gJJMA9wuX7AcqLy1+ffPatSCySA1FQ2S8Ya9AIoYBpE= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180503215945-1f94bef427e3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88= -golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -448,56 +197,14 @@ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181105230042-78dc5bac0cac h1:0Nb35Izc6T6Yz1iGmRc4cg14cxRaFjbjD4hWFI6JNJ8= -golang.org/x/tools v0.0.0-20181105230042-78dc5bac0cac/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d h1:lzLdP95xJmMpwQ6LUHwrc5V7js93hTiY7gkznu0BgmY= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180427144745-86e600f69ee4/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 h1:xtNn7qFlagY2mQNFHMSRPjT2RkOV4OXM7P5TVy9xATo= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -gopkg.in/alecthomas/gometalinter.v2 v2.0.12/go.mod h1:NDRytsqEZyolNuAgTzJkZMkSQM7FIKyzVzGhjB/qfYo= -gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c/go.mod h1:3HH7i1SgMqlzxCcBmUHW657sD4Kvv9sC3HpL3YukzwA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/stretchr/testify.v1 v1.2.2 h1:yhQC6Uy5CqibAIlk1wlusa/MJ3iAN49/BsR/dCCKz3M= -gopkg.in/stretchr/testify.v1 v1.2.2/go.mod h1:QI5V/q6UbPmuhtm10CaFZxED9NreB8PnFYN9JcR6TxU= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/ugjka/go-tz.v2 v2.0.9 h1:2ECB40UPBRJ6G53XE6zf7LMsiI038orvYfJKx/eir3g= gopkg.in/ugjka/go-tz.v2 v2.0.9/go.mod h1:1iX2y1/xUdZjNIyGW/dLRRinbWrntuHYc9oIkGWFvz4= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= @@ -506,4 +213,3 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/api/batch.go b/internal/api/batch.go index a4264d421..87fb583a8 100644 --- a/internal/api/batch.go +++ b/internal/api/batch.go @@ -168,7 +168,8 @@ func BatchPhotosPrivate(router *gin.RouterGroup, conf *config.Config) { log.Infof("marking photos as private: %#v", f.Photos) - err := entity.Db().Model(entity.Photo{}).Where("photo_uid IN (?)", f.Photos).UpdateColumn("photo_private", gorm.Expr("IF (`photo_private`, 0, 1)")).Error + err := entity.Db().Model(entity.Photo{}).Where("photo_uid IN (?)", f.Photos).UpdateColumn("photo_private", + gorm.Expr("CASE WHEN photo_private > 0 THEN 0 ELSE 1 END")).Error if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, ErrSaveFailed) diff --git a/internal/api/label.go b/internal/api/label.go index 8a4c10d91..60376c7f2 100644 --- a/internal/api/label.go +++ b/internal/api/label.go @@ -103,12 +103,14 @@ func LikeLabel(router *gin.RouterGroup, conf *config.Config) { label, err := query.LabelByUID(id) if err != nil { - c.AbortWithStatusJSON(404, gin.H{"error": txt.UcFirst(err.Error())}) + c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": txt.UcFirst(err.Error())}) return } - label.LabelFavorite = true - entity.Db().Save(&label) + if err := label.Update("LabelFavorite", true); err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": txt.UcFirst(err.Error())}) + return + } if label.LabelPriority < 0 { event.Publish("count.labels", event.Data{ @@ -137,12 +139,14 @@ func DislikeLabel(router *gin.RouterGroup, conf *config.Config) { label, err := query.LabelByUID(id) if err != nil { - c.AbortWithStatusJSON(404, gin.H{"error": txt.UcFirst(err.Error())}) + c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": txt.UcFirst(err.Error())}) return } - label.LabelFavorite = false - entity.Db().Save(&label) + if err := label.Update("LabelFavorite", false); err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": txt.UcFirst(err.Error())}) + return + } if label.LabelPriority < 0 { event.Publish("count.labels", event.Data{ diff --git a/internal/api/label_test.go b/internal/api/label_test.go index d54cada20..a6cf675bc 100644 --- a/internal/api/label_test.go +++ b/internal/api/label_test.go @@ -93,7 +93,8 @@ func TestDislikeLabel(t *testing.T) { t.Run("dislike existing label", func(t *testing.T) { app, router, ctx := NewApiTest() GetLabels(router, ctx) - r2 := PerformRequest(app, "GET", "/api/v1/labels?count=1&q=landscape") + r2 := PerformRequest(app, "GET", "/api/v1/labels?count=3&q=landscape") + t.Logf("HTTP BODY: %s", r2.Body.String()) val := gjson.Get(r2.Body.String(), `#(Slug=="landscape").Favorite`) assert.Equal(t, "true", val.String()) @@ -102,7 +103,7 @@ func TestDislikeLabel(t *testing.T) { r := PerformRequest(app, "DELETE", "/api/v1/labels/lt9k3pw1wowuy3c2/like") assert.Equal(t, http.StatusOK, r.Code) - r3 := PerformRequest(app, "GET", "/api/v1/labels?count=1&q=landscape") + r3 := PerformRequest(app, "GET", "/api/v1/labels?count=3&q=landscape") val2 := gjson.Get(r3.Body.String(), `#(Slug=="landscape").Favorite`) assert.Equal(t, "false", val2.String()) }) diff --git a/internal/commands/config.go b/internal/commands/config.go index 47d58d794..5dbc48faf 100644 --- a/internal/commands/config.go +++ b/internal/commands/config.go @@ -19,8 +19,16 @@ var ConfigCommand = cli.Command{ func configAction(ctx *cli.Context) error { conf := config.NewConfig(ctx) + dbDriver := conf.DatabaseDriver() + dbDsn := conf.DatabaseDsn() + fmt.Printf("%-25s VALUE\n", "NAME") + // Database config + fmt.Printf("%-25s %s\n", "database-driver", dbDriver) + fmt.Printf("%-25s %s\n", "database-dsn", dbDsn) + fmt.Printf("%-25s %d\n", "database-conns", conf.DatabaseConns()) + // Description fmt.Printf("%-25s %s\n", "name", conf.Name()) fmt.Printf("%-25s %s\n", "url", conf.Url()) @@ -77,17 +85,6 @@ func configAction(ctx *cli.Context) error { fmt.Printf("%-25s %d\n", "http-port", conf.HttpServerPort()) fmt.Printf("%-25s %s\n", "http-mode", conf.HttpServerMode()) - // Built-in TiDB server config - fmt.Printf("%-25s %s\n", "tidb-host", conf.TidbServerHost()) - fmt.Printf("%-25s %d\n", "tidb-port", conf.TidbServerPort()) - fmt.Printf("%-25s %s\n", "tidb-password", conf.TidbServerPassword()) - fmt.Printf("%-25s %s\n", "tidb-path", conf.TidbServerPath()) - - // Database config - fmt.Printf("%-25s %s\n", "database-driver", conf.DatabaseDriver()) - fmt.Printf("%-25s %s\n", "database-dsn", conf.DatabaseDsn()) - fmt.Printf("%-25s %d\n", "database-conns", conf.DatabaseConns()) - // External binaries fmt.Printf("%-25s %s\n", "sips-bin", conf.SipsBin()) fmt.Printf("%-25s %s\n", "darktable-bin", conf.DarktableBin()) diff --git a/internal/commands/start.go b/internal/commands/start.go index 1ac8e698b..c82cb1799 100644 --- a/internal/commands/start.go +++ b/internal/commands/start.go @@ -53,11 +53,6 @@ func startAction(ctx *cli.Context) error { fmt.Printf("NAME VALUE\n") fmt.Printf("detach-server %t\n", conf.DetachServer()) - fmt.Printf("tidb-host %s\n", conf.TidbServerHost()) - fmt.Printf("tidb-port %d\n", conf.TidbServerPort()) - fmt.Printf("tidb-password %s\n", conf.TidbServerPassword()) - fmt.Printf("tidb-path %s\n", conf.TidbServerPath()) - fmt.Printf("http-host %s\n", conf.HttpServerHost()) fmt.Printf("http-port %d\n", conf.HttpServerPort()) fmt.Printf("http-mode %s\n", conf.HttpServerMode()) diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 94ef20391..06ef2bc95 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -118,38 +118,6 @@ func TestConfig_DetachServer(t *testing.T) { assert.Equal(t, false, detachServer) } -func TestConfig_TidbServerHost(t *testing.T) { - ctx := CliTestContext() - c := NewConfig(ctx) - - host := c.TidbServerHost() - assert.Equal(t, "127.0.0.1", host) -} - -func TestConfig_TidbServerPort(t *testing.T) { - ctx := CliTestContext() - c := NewConfig(ctx) - - port := c.TidbServerPort() - assert.Equal(t, uint(2343), port) -} - -func TestConfig_TidbServerPath(t *testing.T) { - ctx := CliTestContext() - c := NewConfig(ctx) - - path := c.TidbServerPath() - assert.Equal(t, "/go/src/github.com/photoprism/photoprism/assets/resources/database", path) -} - -func TestConfig_TidbServerPassword(t *testing.T) { - ctx := CliTestContext() - c := NewConfig(ctx) - - password := c.TidbServerPassword() - assert.Equal(t, "", password) -} - func TestConfig_HttpServerHost(t *testing.T) { ctx := CliTestContext() c := NewConfig(ctx) @@ -237,7 +205,7 @@ func TestConfig_DatabaseDriver(t *testing.T) { c := NewConfig(ctx) driver := c.DatabaseDriver() - assert.Equal(t, DriverTidb, driver) + assert.Equal(t, SQLite, driver) } func TestConfig_DatabaseDsn(t *testing.T) { @@ -245,7 +213,7 @@ func TestConfig_DatabaseDsn(t *testing.T) { c := NewConfig(ctx) dsn := c.DatabaseDriver() - assert.Equal(t, DriverTidb, dsn) + assert.Equal(t, SQLite, dsn) } func TestConfig_CachePath(t *testing.T) { diff --git a/internal/config/db.go b/internal/config/db.go index 55e7da71f..885f674b8 100644 --- a/internal/config/db.go +++ b/internal/config/db.go @@ -4,6 +4,8 @@ import ( "context" "errors" "io/ioutil" + "os" + "path/filepath" "runtime" "strings" "time" @@ -13,22 +15,46 @@ import ( _ "github.com/jinzhu/gorm/dialects/sqlite" "github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/mutex" - "github.com/photoprism/photoprism/internal/tidb" ) // DatabaseDriver returns the database driver name. func (c *Config) DatabaseDriver() string { - if strings.ToLower(c.params.DatabaseDriver) == "mysql" { - return DriverMysql + switch strings.ToLower(c.params.DatabaseDriver) { + case MySQL, "mariadb": + c.params.DatabaseDriver = MySQL + case SQLite, "sqlite", "sqllite", "test", "file", "": + c.params.DatabaseDriver = SQLite + case "tidb": + log.Warnf("config: database driver 'tidb' is deprecated, using sqlite") + c.params.DatabaseDriver = SQLite + c.params.DatabaseDsn = "" + default: + log.Warnf("config: unsupported database driver %s, using sqlite", c.params.DatabaseDriver) + c.params.DatabaseDriver = SQLite + c.params.DatabaseDsn = "" } - return DriverTidb + return c.params.DatabaseDriver } // DatabaseDsn returns the database data source name (DSN). func (c *Config) DatabaseDsn() string { if c.params.DatabaseDsn == "" { - return "root:photoprism@tcp(localhost:2343)/photoprism?parseTime=true" + switch c.DatabaseDriver() { + case MySQL: + return "photoprism:photoprism@tcp(photoprism-db:3306)/photoprism?parseTime=true" + case SQLite: + storagePath := filepath.Join(c.ConfigPath()) + + if err := os.MkdirAll(storagePath, os.ModePerm); err != nil { + log.Errorf("config: %s (database storage path)", err.Error()) + } else { + return filepath.Join(storagePath, "index.db") + } + default: + log.Errorf("config: empty database dsn") + return "" + } } return c.params.DatabaseDsn @@ -97,24 +123,8 @@ func (c *Config) connectToDatabase(ctx context.Context) error { return errors.New("config: database DSN not specified") } - isTiDB := false - initSuccess := false - - if dbDriver == DriverTidb { - isTiDB = true - dbDriver = DriverMysql - } - db, err := gorm.Open(dbDriver, dbDsn) if err != nil || db == nil { - if isTiDB { - log.Infof("starting database server at %s:%d\n", c.TidbServerHost(), c.TidbServerPort()) - - go tidb.Start(ctx, c.TidbServerPath(), c.TidbServerPort(), c.TidbServerHost(), c.Debug()) - - time.Sleep(5 * time.Second) - } - for i := 1; i <= 12; i++ { db, err = gorm.Open(dbDriver, dbDsn) @@ -122,16 +132,6 @@ func (c *Config) connectToDatabase(ctx context.Context) error { break } - if isTiDB && !initSuccess { - err = tidb.InitDatabase(c.TidbServerPort(), c.TidbServerPassword()) - - if err != nil { - log.Debug(err) - } else { - initSuccess = true - } - } - time.Sleep(5 * time.Second) } diff --git a/internal/config/filenames.go b/internal/config/filenames.go index 582536fa5..dd824ee36 100644 --- a/internal/config/filenames.go +++ b/internal/config/filenames.go @@ -62,10 +62,6 @@ func (c *Config) CreateDirectories() error { return createError(c.ResourcesPath(), err) } - if err := os.MkdirAll(c.TidbServerPath(), os.ModePerm); err != nil { - return createError(c.TidbServerPath(), err) - } - if err := os.MkdirAll(c.TensorFlowModelPath(), os.ModePerm); err != nil { return createError(c.TensorFlowModelPath(), err) } diff --git a/internal/config/flags.go b/internal/config/flags.go index 98b830a75..16d6b559d 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -6,6 +6,24 @@ import ( // GlobalFlags lists all CLI flags var GlobalFlags = []cli.Flag{ + cli.StringFlag{ + Name: "database-driver", + Usage: "database `DRIVER` (sqlite or mysql)", + Value: "sqlite", + EnvVar: "PHOTOPRISM_DATABASE_DRIVER", + }, + cli.StringFlag{ + Name: "database-dsn", + Usage: "database data source or file name (`DSN`)", + Value: "", + EnvVar: "PHOTOPRISM_DATABASE_DSN", + }, + cli.IntFlag{ + Name: "database-conns", + Usage: "maximum `NUMBER` of open connections to the database", + Value: 256, + EnvVar: "PHOTOPRISM_DATABASE_CONNS", + }, cli.StringFlag{ Name: "admin-password", Usage: "admin password", @@ -210,45 +228,6 @@ var GlobalFlags = []cli.Flag{ Usage: "debug, release or test", EnvVar: "PHOTOPRISM_HTTP_MODE", }, - cli.IntFlag{ - Name: "tidb-port", - Value: 2343, - Usage: "built-in TiDB server port", - EnvVar: "PHOTOPRISM_TIDB_PORT", - }, - cli.StringFlag{ - Name: "tidb-host", - Usage: "built-in TiDB server host", - EnvVar: "PHOTOPRISM_TIDB_HOST", - }, - cli.StringFlag{ - Name: "tidb-password", - Usage: "built-in TiDB server password", - EnvVar: "PHOTOPRISM_TIDB_PASSWORD", - }, - cli.StringFlag{ - Name: "tidb-path", - Usage: "built-in TiDB server storage `PATH`", - EnvVar: "PHOTOPRISM_TIDB_PATH", - }, - cli.StringFlag{ - Name: "database-driver", - Usage: "database `DRIVER` (tidb or mysql)", - Value: "tidb", - EnvVar: "PHOTOPRISM_DATABASE_DRIVER", - }, - cli.StringFlag{ - Name: "database-dsn", - Usage: "database data source name (`DSN`)", - Value: "root:@tcp(localhost:2343)/photoprism?parseTime=true", - EnvVar: "PHOTOPRISM_DATABASE_DSN", - }, - cli.IntFlag{ - Name: "database-conns", - Usage: "maximum `NUMBER` of open connections to the database", - Value: 256, - EnvVar: "PHOTOPRISM_DATABASE_CONNS", - }, cli.BoolFlag{ Name: "detect-nsfw", Usage: "flag photos as private that may be offensive", diff --git a/internal/config/params.go b/internal/config/params.go index dd01cccaa..ff5a2b147 100644 --- a/internal/config/params.go +++ b/internal/config/params.go @@ -13,10 +13,10 @@ import ( "gopkg.in/yaml.v2" ) -// define database drivers const +// Database drivers (sql dialects). const ( - DriverTidb = "tidb" - DriverMysql = "mysql" + MySQL = "mysql" + SQLite = "sqlite3" ) // Params provides a struct in which application configuration is stored. @@ -57,10 +57,6 @@ type Params struct { DatabaseDriver string `yaml:"database-driver" flag:"database-driver"` DatabaseDsn string `yaml:"database-dsn" flag:"database-dsn"` DatabaseConns int `yaml:"database-conns" flag:"database-conns"` - TidbServerHost string `yaml:"tidb-host" flag:"tidb-host"` - TidbServerPort uint `yaml:"tidb-port" flag:"tidb-port"` - TidbServerPassword string `yaml:"tidb-password" flag:"tidb-password"` - TidbServerPath string `yaml:"tidb-path" flag:"tidb-path"` HttpServerHost string `yaml:"http-host" flag:"http-host"` HttpServerPort int `yaml:"http-port" flag:"http-port"` HttpServerMode string `yaml:"http-mode" flag:"http-mode"` @@ -125,7 +121,6 @@ func (c *Params) expandFilenames() { c.OriginalsPath = fs.Abs(c.OriginalsPath) c.ImportPath = fs.Abs(c.ImportPath) c.TempPath = fs.Abs(c.TempPath) - c.TidbServerPath = fs.Abs(c.TidbServerPath) c.PIDFilename = fs.Abs(c.PIDFilename) c.LogFilename = fs.Abs(c.LogFilename) } diff --git a/internal/config/params_test.go b/internal/config/params_test.go index 23a7bb292..da139ab06 100644 --- a/internal/config/params_test.go +++ b/internal/config/params_test.go @@ -36,7 +36,7 @@ func TestParams_SetValuesFromFile(t *testing.T) { assert.Equal(t, "/srv/photoprism/photos/originals", c.OriginalsPath) assert.Equal(t, "/srv/photoprism/photos/import", c.ImportPath) assert.Equal(t, "/srv/photoprism/temp", c.TempPath) - assert.Equal(t, DriverTidb, c.DatabaseDriver) - assert.Equal(t, "root:photoprism@tcp(localhost:2343)/photoprism?parseTime=true", c.DatabaseDsn) + assert.NotEmpty(t, c.DatabaseDriver) + assert.NotEmpty(t, c.DatabaseDsn) assert.Equal(t, 81, c.HttpServerPort) } diff --git a/internal/config/server.go b/internal/config/server.go index 437378654..ef88f680e 100644 --- a/internal/config/server.go +++ b/internal/config/server.go @@ -80,35 +80,3 @@ func (c *Config) HttpStaticPath() string { func (c *Config) HttpStaticBuildPath() string { return filepath.Join(c.HttpStaticPath(), "build") } - -// TidbServerHost returns the host for the built-in TiDB server. (empty for all interfaces). -func (c *Config) TidbServerHost() string { - if c.params.TidbServerHost == "" { - return "127.0.0.1" - } - - return c.params.TidbServerHost -} - -// TidbServerPort returns the port for the built-in TiDB server. -func (c *Config) TidbServerPort() uint { - if c.params.TidbServerPort == 0 { - return 2343 - } - - return c.params.TidbServerPort -} - -// TidbServerPassword returns the password for the built-in TiDB server. -func (c *Config) TidbServerPassword() string { - return c.params.TidbServerPassword -} - -// TidbServerPath returns the database storage path for the built-in TiDB server. -func (c *Config) TidbServerPath() string { - if c.params.TidbServerPath == "" { - return filepath.Join(c.ResourcesPath(), "/database") - } - - return fs.Abs(c.params.TidbServerPath) -} diff --git a/internal/config/test.go b/internal/config/test.go index 6a09c0ac8..71e7e39bb 100644 --- a/internal/config/test.go +++ b/internal/config/test.go @@ -38,6 +38,18 @@ func NewTestParams() *Params { testDataPath := testDataPath(assetsPath) + dbDriver := os.Getenv("PHOTOPRISM_TEST_DRIVER") + dbDsn := os.Getenv("PHOTOPRISM_TEST_DSN") + + // Config example for MySQL / MariaDB: + // dbDriver = MySQL, + // dbDsn = "photoprism:photoprism@tcp(photoprism-db:4001)/photoprism?parseTime=true", + + if dbDriver == "test" || dbDriver == "sqlite" || dbDriver == "" || dbDsn == ""{ + dbDriver = SQLite + dbDsn = ".test.db" + } + c := &Params{ Name: "PhotoPrism", Version: "0.0.0", @@ -55,8 +67,8 @@ func NewTestParams() *Params { OriginalsPath: testDataPath + "/originals", ImportPath: testDataPath + "/import", TempPath: testDataPath + "/temp", - DatabaseDriver: "mysql", - DatabaseDsn: "photoprism:photoprism@tcp(photoprism-db:4001)/photoprism?parseTime=true", + DatabaseDriver: dbDriver, + DatabaseDsn: dbDsn, } return c @@ -75,7 +87,7 @@ func NewTestParamsError() *Params { OriginalsPath: testDataPath + "/originals", ImportPath: testDataPath + "/import", TempPath: testDataPath + "/temp", - DatabaseDriver: "mysql", + DatabaseDriver: MySQL, DatabaseDsn: "photoprism:photoprism@tcp(photoprism-db:4001)/photoprism?parseTime=true", } diff --git a/internal/config/testdata/config.yml b/internal/config/testdata/config.yml index 21e303ea2..ad75bca8c 100644 --- a/internal/config/testdata/config.yml +++ b/internal/config/testdata/config.yml @@ -9,10 +9,7 @@ http-host: http-mode: release http-port: 81 http-password: -tidb-host: localhost -tidb-port: 2343 -tidb-password: photoprism -database-driver: tidb -database-dsn: root:photoprism@tcp(localhost:2343)/photoprism?parseTime=true +database-driver: sqlite +database-dsn: .photoprism.db theme: lavendel language: english diff --git a/internal/entity/db.go b/internal/entity/db.go index 07e302f0d..1d061108a 100644 --- a/internal/entity/db.go +++ b/internal/entity/db.go @@ -7,6 +7,13 @@ import ( "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" + _ "github.com/jinzhu/gorm/dialects/sqlite" +) + +// Database drivers (sql dialects). +const ( + MySQL = "mysql" + SQLite = "sqlite3" ) var dbProvider DbProvider @@ -15,6 +22,16 @@ type DbProvider interface { Db() *gorm.DB } +// IsDialect returns true if the given sql dialect is used. +func IsDialect(name string) bool { + return name == Db().Dialect().GetName() +} + +// DbDialect returns the sql dialect name. +func DbDialect() string { + return Db().Dialect().GetName() +} + // SetDbProvider sets the provider to get a gorm db connection. func SetDbProvider(provider DbProvider) { dbProvider = provider @@ -78,7 +95,7 @@ func (g *Gorm) Connect() { db.LogMode(false) db.SetLogger(log) - db.DB().SetMaxIdleConns(0) + db.DB().SetMaxIdleConns(4) db.DB().SetMaxOpenConns(256) g.db = db diff --git a/internal/entity/entity.go b/internal/entity/entity.go index 9e4116920..31e3d9366 100644 --- a/internal/entity/entity.go +++ b/internal/entity/entity.go @@ -52,13 +52,17 @@ var Entities = Types{ "links": &Link{}, } +type RowCount struct { + Count int +} + // WaitForMigration waits for the database migration to be successful. func (list Types) WaitForMigration() { attempts := 100 - for name := range list { for i := 0; i <= attempts; i++ { - if err := Db().Raw(fmt.Sprintf("DESCRIBE `%s`", name)).Scan(&struct{}{}).Error; err == nil { + count := RowCount{} + if err := Db().Raw(fmt.Sprintf("SELECT COUNT(*) AS count FROM %s", name)).Scan(&count).Error; err == nil { // log.Debugf("entity: table %s migrated", name) break } else { @@ -77,7 +81,8 @@ func (list Types) WaitForMigration() { // Truncate removes all data from tables without dropping them. func (list Types) Truncate() { for name := range list { - if err := Db().Raw(fmt.Sprintf("TRUNCATE TABLE `%s`", name)).Scan(&struct{}{}).Error; err == nil { + row := RowCount{} + if err := Db().Raw(fmt.Sprintf("DELETE FROM %s WHERE 1", name)).Scan(&row).Error; err == nil { log.Debugf("entity: removed all data from %s", name) break } else if err.Error() != "record not found" { @@ -117,7 +122,7 @@ func CreateDefaultFixtures() { CreateUnknownCountry() CreateUnknownCamera() CreateUnknownLens() - CreateViews() + // CreateViews() } // MigrateDb creates all tables and inserts default entities as needed. @@ -140,13 +145,20 @@ func ResetTestFixtures() { } // InitTestDb connects to and completely initializes the test database incl fixtures. -func InitTestDb(dsn string) *Gorm { +func InitTestDb(driver, dsn string) *Gorm { if HasDbProvider() { return nil } + if driver == "test" || driver == "sqlite" || driver == "" || dsn == "" { + driver = "sqlite3" + dsn = ".test.db" + } + + log.Infof("initializing %s test db in %s", driver, dsn) + db := &Gorm{ - Driver: "mysql", + Driver: driver, Dsn: dsn, } diff --git a/internal/entity/entity_test.go b/internal/entity/entity_test.go index 20951f40a..608a1c7ca 100644 --- a/internal/entity/entity_test.go +++ b/internal/entity/entity_test.go @@ -2,7 +2,6 @@ package entity import ( "os" - "strings" "testing" "github.com/sirupsen/logrus" @@ -12,19 +11,10 @@ func TestMain(m *testing.M) { log = logrus.StandardLogger() log.SetLevel(logrus.DebugLevel) - dsn := os.Getenv("PHOTOPRISM_TEST_DSN") - - if dsn == "" { - panic("database dsn is empty") - } - - db := InitTestDb(strings.Replace(dsn, "/photoprism", "/entity", 1)) + db := InitTestDb(os.Getenv("PHOTOPRISM_TEST_DRIVER"), os.Getenv("PHOTOPRISM_TEST_DSN")) + defer db.Close() code := m.Run() - if db != nil { - db.Close() - } - os.Exit(code) } diff --git a/internal/entity/label.go b/internal/entity/label.go index 87c5c098e..6f77571d4 100644 --- a/internal/entity/label.go +++ b/internal/entity/label.go @@ -72,6 +72,11 @@ func (m *Label) Create() error { return Db().Create(m).Error } +// Updates a column in the database. +func (m *Label) Update(attr string, value interface{}) error { + return UnscopedDb().Model(m).UpdateColumn(attr, value).Error +} + // FirstOrCreateLabel returns the existing row, inserts a new row or nil in case of errors. func FirstOrCreateLabel(m *Label) *Label { result := Label{} diff --git a/internal/entity/photo_counts.go b/internal/entity/photo_counts.go index 52c66b3b1..07c2c2f53 100644 --- a/internal/entity/photo_counts.go +++ b/internal/entity/photo_counts.go @@ -1,6 +1,45 @@ package entity -import "github.com/jinzhu/gorm" +import ( + "fmt" + + "github.com/jinzhu/gorm" +) + +type LabelPhotoCount struct { + LabelID int + PhotoCount int +} + +type LabelPhotoCounts []LabelPhotoCount + +func LabelCounts() LabelPhotoCounts { + result := LabelPhotoCounts{} + + if err := UnscopedDb().Raw(` + SELECT label_id, SUM(photo_count) AS photo_count FROM ( + SELECT l.id AS label_id, COUNT(*) AS photo_count FROM labels l + JOIN photos_labels pl ON pl.label_id = l.id + JOIN photos ph ON pl.photo_id = ph.id + WHERE pl.uncertainty < 100 + AND ph.photo_quality >= 0 + AND ph.photo_private = 0 + AND ph.deleted_at IS NULL GROUP BY l.id + UNION ALL + SELECT l.id AS label_id, COUNT(*) AS photo_count FROM labels l + JOIN categories c ON c.category_id = l.id + JOIN photos_labels pl ON pl.label_id = c.label_id + JOIN photos ph ON pl.photo_id = ph.id + WHERE pl.uncertainty < 100 + AND ph.photo_quality >= 0 + AND ph.photo_private = 0 + AND ph.deleted_at IS NULL GROUP BY l.id) counts GROUP BY label_id + `).Scan(&result).Error; err != nil { + log.Errorf("label-count: %s", err.Error()) + } + + return result +} // UpdatePhotoCounts updates photos count in related tables as needed. func UpdatePhotoCounts() error { @@ -37,7 +76,7 @@ func UpdatePhotoCounts() error { AND ph.deleted_at IS NULL GROUP BY l.id)) counts GROUP BY label_id */ - /* TODO: Requires proper view support in TiDB + /* TODO: Requires view support if err := Db(). Table("labels"). @@ -46,10 +85,11 @@ func UpdatePhotoCounts() error { log.Warn(err) } */ - if err := Db(). - Table("labels"). - UpdateColumn("photo_count", - gorm.Expr(`(SELECT photo_count FROM ( + if IsDialect(MySQL) { + if err := Db(). + Table("labels"). + UpdateColumn("photo_count", + gorm.Expr(`(SELECT photo_count FROM ( SELECT label_id, SUM(photo_count) AS photo_count FROM ( (SELECT l.id AS label_id, COUNT(*) AS photo_count FROM labels l JOIN photos_labels pl ON pl.label_id = l.id @@ -68,7 +108,33 @@ func UpdatePhotoCounts() error { AND ph.photo_private = 0 AND ph.deleted_at IS NULL GROUP BY l.id)) counts GROUP BY label_id ) label_counts WHERE label_id = labels.id)`)).Error; err != nil { - return err + return err + } + } else if IsDialect(SQLite) { + if err := Db(). + Table("labels"). + UpdateColumn("photo_count", + gorm.Expr(`(SELECT photo_count FROM (SELECT label_id, SUM(photo_count) AS photo_count FROM ( + SELECT l.id AS label_id, COUNT(*) AS photo_count FROM labels l + JOIN photos_labels pl ON pl.label_id = l.id + JOIN photos ph ON pl.photo_id = ph.id + WHERE pl.uncertainty < 100 + AND ph.photo_quality >= 0 + AND ph.photo_private = 0 + AND ph.deleted_at IS NULL GROUP BY l.id + UNION ALL + SELECT l.id AS label_id, COUNT(*) AS photo_count FROM labels l + JOIN categories c ON c.category_id = l.id + JOIN photos_labels pl ON pl.label_id = c.label_id + JOIN photos ph ON pl.photo_id = ph.id + WHERE pl.uncertainty < 100 + AND ph.photo_quality >= 0 + AND ph.photo_private = 0 + AND ph.deleted_at IS NULL GROUP BY l.id) counts GROUP BY label_id) label_counts WHERE label_id = labels.id)`)).Error; err != nil { + return err + } + } else { + return fmt.Errorf("unknown sql dialect %s", DbDialect()) } return nil diff --git a/internal/entity/photo_counts_test.go b/internal/entity/photo_counts_test.go index c7c890045..a28f0f64d 100644 --- a/internal/entity/photo_counts_test.go +++ b/internal/entity/photo_counts_test.go @@ -4,6 +4,18 @@ import ( "testing" ) +func TestLabelCounts(t *testing.T) { + results := LabelCounts() + + if len(results) == 0 { + t.Fatal("at least one result expected") + } + + for _, result := range results { + t.Logf("LABEL COUNT: %+v", result) + } +} + func TestUpdatePhotoCounts(t *testing.T) { err := UpdatePhotoCounts() diff --git a/internal/entity/photo_maintain.go b/internal/entity/photo_maintain.go index 2698347ad..c4b05949a 100644 --- a/internal/entity/photo_maintain.go +++ b/internal/entity/photo_maintain.go @@ -12,11 +12,32 @@ import ( // EstimatePosition updates the photo with an estimated geolocation if possible. func (m *Photo) EstimatePosition() { var recentPhoto Photo + var dateExpr string - if result := UnscopedDb(). + switch DbDialect() { + case MySQL: + dateExpr = "ABS(DATEDIFF(taken_at, ?)) ASC" + case SQLite: + dateExpr = "ABS(JulianDay(taken_at) - JulianDay(?)) ASC" + default: + log.Errorf("photo: unknown sql dialect %s", DbDialect()) + return + } + + if err := UnscopedDb(). Where("place_id <> '' AND place_id <> 'zz' AND loc_src <> '' AND loc_src <> ?", SrcEstimate). - Order(gorm.Expr("ABS(DATEDIFF(taken_at, ?)) ASC", m.TakenAt)). - Preload("Place").First(&recentPhoto); result.Error == nil { + Order(gorm.Expr(dateExpr, m.TakenAt)). + Preload("Place").First(&recentPhoto).Error; err != nil { + log.Errorf("photo: %s", err.Error()) + } else { + if days := recentPhoto.TakenAt.Sub(m.TakenAt) / (time.Hour * 24); days < -7 { + log.Debugf("prism: can't estimate position of %s, time difference too big (%d days)", m.PhotoUID, -1*days) + return + } else if days > -7 { + log.Debugf("prism: can't estimate position of %s, time difference too big (%d days)", m.PhotoUID, days) + return + } + if recentPhoto.HasPlace() { m.Place = recentPhoto.Place m.PlaceID = recentPhoto.PlaceID diff --git a/internal/photoprism/moments.go b/internal/photoprism/moments.go index 614004d63..1d18bf86b 100644 --- a/internal/photoprism/moments.go +++ b/internal/photoprism/moments.go @@ -31,12 +31,6 @@ func NewMoments(conf *config.Config) *Moments { // Start creates albums based on popular locations, dates and categories. func (m *Moments) Start() (err error) { - defer func() { - if err := recover(); err != nil { - log.Errorf("moments: %s [panic]", err) - } - }() - if err := mutex.MainWorker.Start(); err != nil { err = fmt.Errorf("moments: %s", err.Error()) event.Error(err.Error()) @@ -56,9 +50,11 @@ func (m *Moments) Start() (err error) { counts := query.Counts{} counts.Refresh() - threshold := int(math.Log2(float64(counts.Photos))) + 1 + indexSize := counts.Photos + counts.Videos - log.Infof("moments: threshold %d / %d", threshold, counts.Photos) + threshold := int(math.Log2(float64(indexSize))) + 1 + + log.Infof("moments: index contains %d photos and videos, threshold %d", indexSize, threshold) // Important years and months. if results, err := query.MomentsTime(threshold); err != nil { @@ -149,7 +145,7 @@ func (m *Moments) Start() (err error) { if err := a.Update("AlbumFilter", f.Serialize()); err != nil { log.Errorf("moments: %s", err.Error()) } else { - log.Infof("moments: updated %s (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter) + log.Infof("moments: updated %s (%s)", txt.Quote(a.AlbumTitle), f.Serialize()) } } else if a := entity.NewMoment(mom.Title(), mom.Slug(), f.Serialize()); a != nil { if err := a.Create(); err != nil { diff --git a/internal/query/albums.go b/internal/query/albums.go index c56c30996..357f76975 100644 --- a/internal/query/albums.go +++ b/internal/query/albums.go @@ -53,22 +53,29 @@ func AlbumCoverByUID(albumUID string) (file entity.File, err error) { if err := Db().Where("album_uid = ?", albumUID).First(&a).Error; err != nil { return file, err - } else if a.IsMoment() { // TODO: Optimize - f := form.PhotoSearch{Album: a.AlbumUID, Filter: a.AlbumFilter, Order: entity.SortOrderRelevance, Count: 1, Offset: 0, Merged: true} + } else if a.AlbumType != entity.TypeAlbum { // TODO: Optimize + f := form.PhotoSearch{Album: a.AlbumUID, Filter: a.AlbumFilter, Order: entity.SortOrderRelevance, Count: 1, Offset: 0, Merged: false} if photos, _, err := PhotoSearch(f); err != nil { return file, err } else if len(photos) > 0 { + log.Debugf("PHOTOS: %+v", photos) + for _, photo := range photos { - return FileByPhotoUID(photo.PhotoUID) + log.Debugf("PHOTO: %+v", photo) + if err := Db().Where("photo_uid = ? AND file_primary = 1", photo.PhotoUID).First(&file).Error; err != nil { + log.Debugf("ERROR: %+v", err) + return file, err + } else { + return file, nil + } } } return file, fmt.Errorf("found no cover for moment") } - if err := Db(). - Where("files.file_primary = 1 AND files.file_missing = 0 AND files.file_type = 'jpg' AND files.deleted_at IS NULL"). + if err := Db().Where("files.file_primary = 1 AND files.file_missing = 0 AND files.file_type = 'jpg' AND files.deleted_at IS NULL"). Joins("JOIN albums ON albums.album_uid = ?", albumUID). Joins("JOIN photos_albums pa ON pa.album_uid = albums.album_uid AND pa.photo_uid = files.photo_uid"). Joins("JOIN photos ON photos.id = files.photo_id AND photos.photo_private = 0 AND photos.deleted_at IS NULL"). diff --git a/internal/query/photo_search.go b/internal/query/photo_search.go index f9b8f050a..d2738683d 100644 --- a/internal/query/photo_search.go +++ b/internal/query/photo_search.go @@ -319,8 +319,8 @@ func PhotoSearch(f form.PhotoSearch) (results PhotoResults, count int, err error s = s.Limit(100).Offset(0) } - if result := s.Scan(&results); result.Error != nil { - return results, 0, result.Error + if err := s.Scan(&results).Error; err != nil { + return results, 0, err } log.Infof("photos: found %d results for %s [%s]", len(results), f.SerializeAll(), time.Since(start)) diff --git a/internal/query/query.go b/internal/query/query.go index 5b49d5eb7..8114b6adb 100644 --- a/internal/query/query.go +++ b/internal/query/query.go @@ -21,6 +21,11 @@ import ( var log = event.Log +const ( + MySQL = "mysql" + SQLite = "sqlite3" +) + // About 1km ('good enough' for now) const SearchRadius = 0.009 @@ -53,6 +58,16 @@ func UnscopedDb() *gorm.DB { return entity.Db().Unscoped() } +// IsDialect returns true if the given sql dialect is used. +func IsDialect(name string) bool { + return name == Db().Dialect().GetName() +} + +// DbDialect returns the sql dialect name. +func DbDialect() string { + return Db().Dialect().GetName() +} + // LikeAny returns a where condition that matches any keyword in search. func LikeAny(col, search string) (where string) { var wheres []string diff --git a/internal/query/query_test.go b/internal/query/query_test.go index a234e3843..1d23061ed 100644 --- a/internal/query/query_test.go +++ b/internal/query/query_test.go @@ -2,7 +2,6 @@ package query import ( "os" - "strings" "testing" "github.com/photoprism/photoprism/internal/entity" @@ -14,20 +13,11 @@ func TestMain(m *testing.M) { log = logrus.StandardLogger() log.SetLevel(logrus.DebugLevel) - dsn := os.Getenv("PHOTOPRISM_TEST_DSN") - - if dsn == "" { - panic("database dsn is empty") - } - - db := entity.InitTestDb(strings.Replace(dsn, "/photoprism", "/query", 1)) + db := entity.InitTestDb(os.Getenv("PHOTOPRISM_TEST_DRIVER"), os.Getenv("PHOTOPRISM_TEST_DSN")) + defer db.Close() code := m.Run() - if db != nil { - db.Close() - } - os.Exit(code) } diff --git a/internal/query/selection.go b/internal/query/selection.go index dd3943c59..1cfb33b19 100644 --- a/internal/query/selection.go +++ b/internal/query/selection.go @@ -2,6 +2,7 @@ package query import ( "errors" + "fmt" "github.com/photoprism/photoprism/internal/form" ) @@ -12,20 +13,31 @@ func PhotoSelection(f form.Selection) (results Photos, err error) { return results, errors.New("no items selected") } - // Db().LogMode(true) + var concat string - s := UnscopedDb().Table("photos"). - Select("photos.*"). - Where(`photos.photo_uid IN (?) + switch DbDialect() { + case MySQL: + concat = "CONCAT(a.path, '/%')" + case SQLite: + concat = "a.path || '/%'" + default: + return results, fmt.Errorf("unknown sql dialect: %s", DbDialect()) + } + + where := fmt.Sprintf(`photos.photo_uid IN (?) OR photos.place_id IN (?) OR photos.photo_uid IN (SELECT photo_uid FROM files WHERE file_uid IN (?)) OR photos.photo_path IN ( SELECT a.path FROM folders a WHERE a.folder_uid IN (?) UNION - SELECT b.path FROM folders a JOIN folders b ON b.path LIKE CONCAT(a.path, '/%') WHERE a.folder_uid IN (?)) + SELECT b.path FROM folders a JOIN folders b ON b.path LIKE %s WHERE a.folder_uid IN (?)) OR photos.photo_uid IN (SELECT photo_uid FROM photos_albums WHERE album_uid IN (?)) OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN labels l ON pl.label_id = l.id AND l.deleted_at IS NULL WHERE l.label_uid IN (?)) OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN categories c ON c.label_id = pl.label_id JOIN labels lc ON lc.id = c.category_id AND lc.deleted_at IS NULL WHERE lc.label_uid IN (?))`, - f.Photos, f.Places, f.Files, f.Files, f.Files, f.Albums, f.Labels, f.Labels) + concat) + + s := UnscopedDb().Table("photos"). + Select("photos.*"). + Where(where, f.Photos, f.Places, f.Files, f.Files, f.Files, f.Albums, f.Labels, f.Labels) if result := s.Scan(&results); result.Error != nil { return results, result.Error @@ -40,23 +52,34 @@ func FileSelection(f form.Selection) (results Files, err error) { return results, errors.New("no items selected") } - // Db().LogMode(true) + var concat string + + switch DbDialect() { + case MySQL: + concat = "CONCAT(a.path, '/%')" + case SQLite: + concat = "a.path || '/%'" + default: + return results, fmt.Errorf("unknown sql dialect: %s", DbDialect()) + } + + where := fmt.Sprintf(`photos.photo_uid IN (?) + OR photos.place_id IN (?) + OR photos.photo_uid IN (SELECT photo_uid FROM files WHERE file_uid IN (?)) + OR photos.photo_path IN ( + SELECT a.path FROM folders a WHERE a.folder_uid IN (?) UNION + SELECT b.path FROM folders a JOIN folders b ON b.path LIKE %s WHERE a.folder_uid IN (?)) + OR photos.photo_uid IN (SELECT photo_uid FROM photos_albums WHERE album_uid IN (?)) + OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN labels l ON pl.label_id = l.id AND l.deleted_at IS NULL WHERE l.label_uid IN (?)) + OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN categories c ON c.label_id = pl.label_id JOIN labels lc ON lc.id = c.category_id AND lc.deleted_at IS NULL WHERE lc.label_uid IN (?))`, + concat) s := UnscopedDb().Table("files"). Select("files.*"). Joins("JOIN photos ON photos.id = files.photo_id"). Where("photos.deleted_at IS NULL"). Where("files.file_missing = 0"). - Where(`photos.photo_uid IN (?) - OR photos.place_id IN (?) - OR photos.photo_uid IN (SELECT photo_uid FROM files WHERE file_uid IN (?)) - OR photos.photo_path IN ( - SELECT a.path FROM folders a WHERE a.folder_uid IN (?) UNION - SELECT b.path FROM folders a JOIN folders b ON b.path LIKE CONCAT(a.path, '/%') WHERE a.folder_uid IN (?)) - OR photos.photo_uid IN (SELECT photo_uid FROM photos_albums WHERE album_uid IN (?)) - OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN labels l ON pl.label_id = l.id AND l.deleted_at IS NULL WHERE l.label_uid IN (?)) - OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN categories c ON c.label_id = pl.label_id JOIN labels lc ON lc.id = c.category_id AND lc.deleted_at IS NULL WHERE lc.label_uid IN (?))`, - f.Photos, f.Places, f.Files, f.Files, f.Files, f.Albums, f.Labels, f.Labels). + Where(where, f.Photos, f.Places, f.Files, f.Files, f.Files, f.Albums, f.Labels, f.Labels). Group("files.id") if result := s.Scan(&results); result.Error != nil { diff --git a/internal/tidb/server.go b/internal/tidb/server.go deleted file mode 100644 index 9709a53e6..000000000 --- a/internal/tidb/server.go +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright 2015 PingCAP, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -package tidb - -import ( - "context" - "flag" - "fmt" - "os" - "runtime" - "strconv" - "strings" - "time" - - "github.com/opentracing/opentracing-go" - "github.com/photoprism/photoprism/internal/event" - "github.com/pingcap/errors" - "github.com/pingcap/parser/mysql" - "github.com/pingcap/parser/terror" - pd "github.com/pingcap/pd/client" - pumpcli "github.com/pingcap/tidb-tools/tidb-binlog/pump_client" - "github.com/pingcap/tidb/config" - "github.com/pingcap/tidb/ddl" - "github.com/pingcap/tidb/domain" - "github.com/pingcap/tidb/kv" - "github.com/pingcap/tidb/metrics" - plannercore "github.com/pingcap/tidb/planner/core" - "github.com/pingcap/tidb/privilege/privileges" - "github.com/pingcap/tidb/server" - "github.com/pingcap/tidb/session" - "github.com/pingcap/tidb/sessionctx/binloginfo" - "github.com/pingcap/tidb/sessionctx/variable" - "github.com/pingcap/tidb/statistics" - "github.com/pingcap/tidb/store/mockstore" - "github.com/pingcap/tidb/store/tikv" - "github.com/pingcap/tidb/store/tikv/gcworker" - "github.com/pingcap/tidb/util/logutil" - "github.com/pingcap/tidb/util/printer" - xserver "github.com/pingcap/tidb/x-server" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/push" -) - -var log = event.Log - -var ( - cfg *config.Config - storage kv.Storage - dom *domain.Domain - svr *server.Server - xsvr *xserver.Server - graceful bool -) - -// Start the TiDB server using the configuration provided -func Start(ctx context.Context, path string, port uint, host string, debug bool) { - if err := logutil.SetLevel("fatal"); err != nil { - log.Error(err) - } - - registerStores() - registerMetrics() - loadConfig() - - cfg.Log.Level = log.GetLevel().String() - - // cfg.Security.SkipGrantTable = true - if debug { - cfg.Log.Level = "error" - host = "0.0.0.0" - } - - cfg.Path = path - cfg.Store = "mocktikv" - - if host == "" { - host = "localhost" - } - - cfg.Host = host - cfg.Port = port - cfg.Status.ReportStatus = false - - validateConfig() - setGlobalVars() - setupTracing() - - if debug { - printInfo() - } - - setupBinlogClient() - // setupMetrics() - createStoreAndDomain() - createServer() - go runServer() - - <-ctx.Done() - serverShutdown(true) - cleanup() - log.Info("tidb server shutdown complete") -} - -func registerStores() { - err := session.RegisterStore("tikv", tikv.Driver{}) - terror.MustNil(err) - tikv.NewGCHandlerFunc = gcworker.NewGCWorker - err = session.RegisterStore("mocktikv", mockstore.MockDriver{}) - terror.MustNil(err) -} - -func registerMetrics() { - metrics.RegisterMetrics() -} - -func createStoreAndDomain() { - fullPath := fmt.Sprintf("%s://%s", cfg.Store, cfg.Path) - var err error - storage, err = session.NewStore(fullPath) - terror.MustNil(err) - // Bootstrap a session to load information schema. - dom, err = session.BootstrapSession(storage) - terror.MustNil(err) -} - -func setupBinlogClient() { - if !cfg.Binlog.Enable { - return - } - - if cfg.Binlog.IgnoreError { - binloginfo.SetIgnoreError(true) - } - - client, err := pumpcli.NewPumpsClient(cfg.Path, parseDuration(cfg.Binlog.WriteTimeout), pd.SecurityOption{ - CAPath: cfg.Security.ClusterSSLCA, - CertPath: cfg.Security.ClusterSSLCert, - KeyPath: cfg.Security.ClusterSSLKey, - }) - terror.MustNil(err) - - binloginfo.SetPumpsClient(client) - log.Infof("create pumps client success, ignore binlog error %v", cfg.Binlog.IgnoreError) -} - -// Prometheus push. -const zeroDuration = time.Duration(0) - -// pushMetric pushes metrics in background. -func pushMetric(addr string, interval time.Duration) { - if interval == zeroDuration || len(addr) == 0 { - log.Info("disable Prometheus push client") - return - } - log.Infof("start Prometheus push client with server addr %s and interval %s", addr, interval) - go prometheusPushClient(addr, interval) -} - -// prometheusPushClient pushes metrics to Prometheus Pushgateway. -func prometheusPushClient(addr string, interval time.Duration) { - // TODO: TiDB do not have uniq name, so we use host+port to compose a name. - job := "tidb" - for { - err := push.AddFromGatherer( - job, - map[string]string{"instance": instanceName()}, - addr, - prometheus.DefaultGatherer, - ) - if err != nil { - log.Errorf("could not push metrics to Prometheus Pushgateway: %v", err) - } - time.Sleep(interval) - } -} - -func instanceName() string { - hostname, err := os.Hostname() - if err != nil { - return "unknown" - } - return fmt.Sprintf("%s_%d", hostname, cfg.Port) -} - -// parseDuration parses lease argument string. -func parseDuration(lease string) time.Duration { - dur, err := time.ParseDuration(lease) - if err != nil { - dur, err = time.ParseDuration(lease + "s") - } - if err != nil || dur < 0 { - log.Fatalf("invalid lease duration %s", lease) - } - return dur -} - -func hasRootPrivilege() bool { - return os.Geteuid() == 0 -} - -func flagBoolean(name string, defaultVal bool, usage string) *bool { - if defaultVal == false { - // Fix #4125, golang do not print default false value in usage, so we append it. - usage = fmt.Sprintf("%s (default false)", usage) - return flag.Bool(name, defaultVal, usage) - } - return flag.Bool(name, defaultVal, usage) -} - -func loadConfig() { - cfg = config.GetGlobalConfig() -} - -func validateConfig() { - if cfg.Security.SkipGrantTable && !hasRootPrivilege() { - log.Error("TiDB run with skip-grant-table need root privilege.") - os.Exit(-1) - } - if _, ok := config.ValidStorage[cfg.Store]; !ok { - nameList := make([]string, 0, len(config.ValidStorage)) - for k, v := range config.ValidStorage { - if v { - nameList = append(nameList, k) - } - } - log.Errorf("\"store\" should be in [%s] only", strings.Join(nameList, ", ")) - os.Exit(-1) - } - if cfg.Store == "mocktikv" && cfg.RunDDL == false { - log.Errorf("can't disable DDL on mocktikv") - os.Exit(-1) - } - if cfg.Log.File.MaxSize > config.MaxLogFileSize { - log.Errorf("log max-size should not be larger than %d MB", config.MaxLogFileSize) - os.Exit(-1) - } - if cfg.XProtocol.XServer { - log.Error("X Server is not available") - os.Exit(-1) - } - cfg.OOMAction = strings.ToLower(cfg.OOMAction) - - // lower_case_table_names is allowed to be 0, 1, 2 - if cfg.LowerCaseTableNames < 0 || cfg.LowerCaseTableNames > 2 { - log.Errorf("lower-case-table-names should be 0 or 1 or 2.") - os.Exit(-1) - } -} - -func setGlobalVars() { - ddlLeaseDuration := parseDuration(cfg.Lease) - session.SetSchemaLease(ddlLeaseDuration) - runtime.GOMAXPROCS(int(cfg.Performance.MaxProcs)) - statsLeaseDuration := parseDuration(cfg.Performance.StatsLease) - session.SetStatsLease(statsLeaseDuration) - domain.RunAutoAnalyze = cfg.Performance.RunAutoAnalyze - statistics.FeedbackProbability = cfg.Performance.FeedbackProbability - statistics.MaxQueryFeedbackCount = int(cfg.Performance.QueryFeedbackLimit) - statistics.RatioOfPseudoEstimate = cfg.Performance.PseudoEstimateRatio - ddl.RunWorker = cfg.RunDDL - ddl.EnableSplitTableRegion = cfg.SplitTable - plannercore.AllowCartesianProduct = cfg.Performance.CrossJoin - privileges.SkipWithGrant = cfg.Security.SkipGrantTable - variable.ForcePriority = int32(mysql.Str2Priority(cfg.Performance.ForcePriority)) - - variable.SysVars[variable.TIDBMemQuotaQuery].Value = strconv.FormatInt(cfg.MemQuotaQuery, 10) - variable.SysVars["lower_case_table_names"].Value = strconv.Itoa(cfg.LowerCaseTableNames) - - plannercore.SetPreparedPlanCache(cfg.PreparedPlanCache.Enabled) - if plannercore.PreparedPlanCacheEnabled() { - plannercore.PreparedPlanCacheCapacity = cfg.PreparedPlanCache.Capacity - } - - if cfg.TiKVClient.GrpcConnectionCount > 0 { - tikv.MaxConnectionCount = cfg.TiKVClient.GrpcConnectionCount - } - tikv.GrpcKeepAliveTime = time.Duration(cfg.TiKVClient.GrpcKeepAliveTime) * time.Second - tikv.GrpcKeepAliveTimeout = time.Duration(cfg.TiKVClient.GrpcKeepAliveTimeout) * time.Second - - tikv.CommitMaxBackoff = int(parseDuration(cfg.TiKVClient.CommitTimeout).Seconds() * 1000) -} - -func printInfo() { - // Make sure the TiDB info is always printed. - printer.PrintTiDBInfo() -} - -func createServer() { - var driver server.IDriver - driver = server.NewTiDBDriver(storage) - var err error - svr, err = server.NewServer(cfg, driver) - // Both domain and storage have started, so we have to clean them before exiting. - terror.MustNil(err, closeDomainAndStorage) - if cfg.XProtocol.XServer { - xcfg := &xserver.Config{ - Addr: fmt.Sprintf("%s:%d", cfg.XProtocol.XHost, cfg.XProtocol.XPort), - Socket: cfg.XProtocol.XSocket, - TokenLimit: cfg.TokenLimit, - } - xsvr, err = xserver.NewServer(xcfg) - terror.MustNil(err, closeDomainAndStorage) - } -} - -func serverShutdown(isgraceful bool) { - if isgraceful { - log.Info("graceful database shutdown") - graceful = true - } else { - log.Info("database shutdown") - } - - if xsvr != nil { - xsvr.Close() // Should close xserver before server. - } - - svr.Close() - - log.Info("database server closed") -} - -func setupTracing() { - tracingCfg := cfg.OpenTracing.ToTracingConfig() - tracer, _, err := tracingCfg.New("TiDB") - if err != nil { - log.Fatal("cannot initialize Jaeger Tracer", err) - } - opentracing.SetGlobalTracer(tracer) -} - -func runServer() { - err := svr.Run() - if err != nil { - log.Errorf("Server failed to run: %v", err) - } -} - -func closeDomainAndStorage() { - dom.Close() - if err := storage.Close(); err != nil { - log.Error(errors.Trace(err)) - } else { - log.Info("database storage closed") - } -} - -func cleanup() { - if graceful { - svr.GracefulDown() - } else { - svr.KillAllConnections() - } - closeDomainAndStorage() -} diff --git a/internal/tidb/tidb.go b/internal/tidb/tidb.go deleted file mode 100644 index 878472b70..000000000 --- a/internal/tidb/tidb.go +++ /dev/null @@ -1,51 +0,0 @@ -package tidb - -import ( - "database/sql" - "fmt" -) - -func InitDatabase(port uint, password string) error { - log.Info("init database") - - db, err := sql.Open("mysql", fmt.Sprintf("root:@tcp(localhost:%d)/", port)) - - if err != nil { - log.Debug(err.Error()) - log.Debug("database login as root with password") - db, err = sql.Open("mysql", fmt.Sprintf("root:%s@tcp(localhost:%d)/", password, port)) - } - - if err != nil { - log.Error(err.Error()) - return err - } - - defer db.Close() - - if password != "" { - log.Debug("set database password") - - _, err = db.Exec(fmt.Sprintf("SET PASSWORD FOR 'root'@'%%' = '%s'", password)) - - if err != nil { - log.Error(err.Error()) - } else { - log.Debug("flush database privileges") - - _, err = db.Exec("FLUSH PRIVILEGES") - } - } - - log.Debug("create database if not exists") - - _, err = db.Exec("CREATE DATABASE IF NOT EXISTS photoprism") - - if err != nil { - log.Error(err.Error()) - } - - log.Info("database created") - - return nil -} diff --git a/internal/workers/prism.go b/internal/workers/prism.go index de848777e..5b1a9a489 100644 --- a/internal/workers/prism.go +++ b/internal/workers/prism.go @@ -8,6 +8,7 @@ import ( "github.com/photoprism/photoprism/internal/config" "github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/mutex" + "github.com/photoprism/photoprism/internal/photoprism" "github.com/photoprism/photoprism/internal/query" ) @@ -104,6 +105,12 @@ func (worker *Prism) Start() (err error) { worker.logError(entity.UpdatePhotoCounts()) + moments := photoprism.NewMoments(worker.conf) + + if err := moments.Start(); err != nil { + log.Error(err) + } + runtime.GC() return nil diff --git a/internal/workers/prism_test.go b/internal/workers/prism_test.go index 1061af0e2..26c653ee6 100644 --- a/internal/workers/prism_test.go +++ b/internal/workers/prism_test.go @@ -11,6 +11,8 @@ import ( func TestPrism_Start(t *testing.T) { conf := config.TestConfig() + t.Logf("database-dsn: %s", conf.DatabaseDsn()) + worker := NewPrism(conf) assert.IsType(t, &Prism{}, worker)