diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3f5e96e..cdfac37 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,4 +18,4 @@ jobs: with: args: release --rm-dist env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.gitignore b/.gitignore index 1440505..4457a8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,16 @@ # Binaries for programs and plugins -bin/ -dist/ *.exe *.exe~ *.dll *.so *.dylib +bin/ # Test binary, build with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out + +# Dependency directories (remove the comment below to include it) +# vendor/ diff --git a/Makefile b/Makefile index b4b9c9f..5ce2ff0 100644 --- a/Makefile +++ b/Makefile @@ -14,15 +14,10 @@ lint: test: go test -race -cover ./... -.PHONY: build-docker -build-docker: +.PHONY: build-image +build-image: docker build -t s3manager . -.PHONY: deploy-cf -deploy-cf: - GOOS=linux go build -ldflags="-s -w" -o bin/s3manager - cf push -f deployments/cf/manifest.yml - .PHONY: clean clean: rm -rf bin diff --git a/README.md b/README.md index 0fa0c5c..5b91749 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ A Web GUI written in Go to manage S3 buckets from any provider. The application can be configured with the following environment variables: - `ENDPOINT`: The endpoint of your S3 server (defaults to `s3.amazonaws.com`) +- `REGION`: The region of your S3 server (defaults to `""`) - `ACCESS_KEY_ID`: Your S3 access key ID (required) - `SECRET_ACCESS_KEY`: Your S3 secret access key (required) - `USE_SSL`: Whether your S3 server uses SSL or not (defaults to `true`) @@ -26,15 +27,10 @@ The application can be configured with the following environment variables: 1. Run `make build` 1. Execute the created binary and visit -### Run Docker image +### Run Container image 1. Run `docker run -p 8080:8080 -e 'ACCESS_KEY_ID=XXX' -e 'SECRET_ACCESS_KEY=xxx' mastertinner/s3manager` -### Deploy to Cloud Foundry - -1. Modify `deployments/cf/*` to your liking -1. Run `make deploy-cf` - ## Development ### Lint Code @@ -45,11 +41,11 @@ The application can be configured with the following environment variables: 1. Run `make test` -### Build Docker Image +### Build Container Image The image is available on [Docker Hub](https://hub.docker.com/r/mastertinner/s3manager/) -1. Run `make build-docker` +1. Run `make build-image` ### Run Locally for Testing diff --git a/deployments/cf/entrypoint.sh b/deployments/cf/entrypoint.sh deleted file mode 100755 index 785f9ae..0000000 --- a/deployments/cf/entrypoint.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -set -e -u - -if [ -z "${PORT}" ]; then - echo "Error: No PORT found" >&2 - exit 1 -fi -if [ -z "${VCAP_SERVICES}" ]; then - echo "Error: No VCAP_SERVICES found" >&2 - exit 1 -fi - -# S3 -s3_credentials="$(echo "${VCAP_SERVICES}" | jq -r '.["dynstrg"][0].credentials // ""')" -if [ -z "${s3_credentials}" ]; then - echo "Error: Please bind an S3 service" >&2 - exit 1 -fi -s3_endpoint="$(echo "${s3_credentials}" | jq -r '.accessHost // ""')" -s3_endpoint="${s3_endpoint#'https://'}" -s3_access_key_id="$(echo "${s3_credentials}" | jq -r '.accessKey // ""')" -s3_secret_access_key="$(echo "${s3_credentials}" | jq -r '.sharedSecret // ""')" - -# Run binary -ENDPOINT="${s3_endpoint}" ACCESS_KEY_ID="${s3_access_key_id}" SECRET_ACCESS_KEY="${s3_secret_access_key}" ./s3manager diff --git a/deployments/cf/manifest.yml b/deployments/cf/manifest.yml deleted file mode 100644 index 4abc233..0000000 --- a/deployments/cf/manifest.yml +++ /dev/null @@ -1,8 +0,0 @@ -applications: - - name: s3-manager - buildpacks: - - https://github.com/cloudfoundry/binary-buildpack.git - memory: 64M - command: ./deployments/cf/entrypoint.sh - services: - - my-storage diff --git a/go.mod b/go.mod index 3bb0ad8..d7b3ad7 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,23 @@ module github.com/mastertinner/s3manager go 1.16 require ( - github.com/go-ini/ini v1.62.0 // indirect + github.com/google/uuid v1.3.0 // indirect github.com/gopherjs/gopherjs v0.0.0-20210803090616-8f023c250c89 // indirect - github.com/mastertinner/adapters v0.0.0-20210601115127-f9c5f1df5ec2 + github.com/json-iterator/go v1.1.11 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/mastertinner/adapters v0.0.0-20210813140839-f946b3f928f1 github.com/matryer/is v1.4.0 github.com/matryer/way v0.0.0-20180416093233-9632d0c407b0 - github.com/minio/minio-go v6.0.14+incompatible + github.com/minio/md5-simd v1.1.2 // indirect + github.com/minio/minio-go/v7 v7.0.12 + github.com/minio/sha256-simd v1.0.0 // indirect + github.com/rs/xid v1.3.0 // indirect github.com/smartystreets/assertions v1.2.0 // indirect - golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect - golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 // indirect - golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect + github.com/stretchr/testify v1.7.0 // indirect + golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e // indirect + golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect + golang.org/x/sys v0.0.0-20210817133320-13f9c583af74 // indirect + golang.org/x/text v0.3.7 // indirect gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index d63f6a8..b6876ab 100644 --- a/go.sum +++ b/go.sum @@ -58,9 +58,12 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +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/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -72,14 +75,13 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-ini/ini v1.62.0 h1:7VJT/ZXjzqSrvtraFp4ONq80hTcRQth1c9ZnQ3uNQvU= -github.com/go-ini/ini v1.62.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= 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-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 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.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -116,6 +118,7 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -126,6 +129,9 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -159,6 +165,9 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= @@ -166,14 +175,21 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= +github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= +github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mastertinner/adapters v0.0.0-20210601115127-f9c5f1df5ec2 h1:1xj8GPMA06VxvfKVUa3W1za7/eODStJG3lYWIYqypTo= -github.com/mastertinner/adapters v0.0.0-20210601115127-f9c5f1df5ec2/go.mod h1:CLHlHgTXdyVYGucevVppiRddQVtVop2ORWbgSXObP0I= +github.com/mastertinner/adapters v0.0.0-20210813140839-f946b3f928f1 h1:ZPvesDqKoVIeQFkfikuck4ILJTFUrRv5wV36bzSBQs8= +github.com/mastertinner/adapters v0.0.0-20210813140839-f946b3f928f1/go.mod h1:2wARZp3HPycyJvAbmX3k6ufim3fpiEJLqGUmNYuVUHA= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/matryer/way v0.0.0-20180416093233-9632d0c407b0 h1:KWiqy3hl8yCUPAq1frD0DKXKyn7d9h2nVhj2r5ISq2o= @@ -182,8 +198,14 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/minio/minio-go v6.0.14+incompatible h1:fnV+GD28LeqdN6vT2XdGKW8Qe/IfjJDswNVuni6km9o= -github.com/minio/minio-go v6.0.14+incompatible/go.mod h1:7guKYtitv8dktvNUGrhzmNlA5wrAABTQXCoesZdFQO8= +github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= +github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= +github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= +github.com/minio/minio-go/v7 v7.0.12 h1:/4pxUdwn9w0QEryNkrrWaodIESPRX+NxpO0Q6hVdaAA= +github.com/minio/minio-go/v7 v7.0.12/go.mod h1:S23iSP5/gbMwtxeY5FM71R+TkAYyzEdoNEDDwpt8yWs= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -193,7 +215,11 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= @@ -203,6 +229,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -217,6 +244,9 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= +github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -225,6 +255,8 @@ github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= @@ -244,6 +276,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -267,9 +301,10 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e h1:VvfwVmMH40bpMeizC9/K7ipM5Qjucuu16RWfneFPyhQ= +golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -332,8 +367,8 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -366,6 +401,7 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -380,6 +416,7 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -387,16 +424,18 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210817133320-13f9c583af74 h1:b3RvH1NpRl6xu9OF46sZVLhjgJ0G7DteZbCC5zFknyY= +golang.org/x/sys v0.0.0-20210817133320-13f9c583af74/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -527,6 +566,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -534,7 +574,11 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/app/s3manager/bucket_view.go b/internal/app/s3manager/bucket_view.go index 3a368ae..cd2294e 100644 --- a/internal/app/s3manager/bucket_view.go +++ b/internal/app/s3manager/bucket_view.go @@ -8,7 +8,7 @@ import ( "path" "github.com/matryer/way" - minio "github.com/minio/minio-go" + "github.com/minio/minio-go/v7" ) // HandleBucketView shows the details page of a bucket. @@ -29,7 +29,7 @@ func HandleBucketView(s3 S3, templates fs.FS) http.HandlerFunc { var objs []objectWithIcon doneCh := make(chan struct{}) defer close(doneCh) - objectCh := s3.ListObjectsV2(bucketName, "", true, doneCh) + objectCh := s3.ListObjects(r.Context(), bucketName, minio.ListObjectsOptions{}) for object := range objectCh { if object.Err != nil { handleHTTPError(w, fmt.Errorf("error listing objects: %w", object.Err)) diff --git a/internal/app/s3manager/bucket_view_test.go b/internal/app/s3manager/bucket_view_test.go index 53ca5a2..3b29016 100644 --- a/internal/app/s3manager/bucket_view_test.go +++ b/internal/app/s3manager/bucket_view_test.go @@ -1,6 +1,7 @@ package s3manager_test import ( + "context" "fmt" "io" "net/http" @@ -14,7 +15,7 @@ import ( "github.com/mastertinner/s3manager/internal/app/s3manager/mocks" "github.com/matryer/is" "github.com/matryer/way" - minio "github.com/minio/minio-go" + "github.com/minio/minio-go/v7" ) func TestHandleBucketView(t *testing.T) { @@ -22,14 +23,14 @@ func TestHandleBucketView(t *testing.T) { cases := []struct { it string - listObjectsV2Func func(string, string, bool, <-chan struct{}) <-chan minio.ObjectInfo + listObjectsFunc func(context.Context, string, minio.ListObjectsOptions) <-chan minio.ObjectInfo bucketName string expectedStatusCode int expectedBodyContains string }{ { it: "renders a bucket containing a file", - listObjectsV2Func: func(string, string, bool, <-chan struct{}) <-chan minio.ObjectInfo { + listObjectsFunc: func(context.Context, string, minio.ListObjectsOptions) <-chan minio.ObjectInfo { objCh := make(chan minio.ObjectInfo) go func() { objCh <- minio.ObjectInfo{Key: "testFile"} @@ -43,7 +44,7 @@ func TestHandleBucketView(t *testing.T) { }, { it: "renders placeholder for an empty bucket", - listObjectsV2Func: func(string, string, bool, <-chan struct{}) <-chan minio.ObjectInfo { + listObjectsFunc: func(context.Context, string, minio.ListObjectsOptions) <-chan minio.ObjectInfo { objCh := make(chan minio.ObjectInfo) close(objCh) return objCh @@ -54,7 +55,7 @@ func TestHandleBucketView(t *testing.T) { }, { it: "renders a bucket containing an archive", - listObjectsV2Func: func(string, string, bool, <-chan struct{}) <-chan minio.ObjectInfo { + listObjectsFunc: func(context.Context, string, minio.ListObjectsOptions) <-chan minio.ObjectInfo { objCh := make(chan minio.ObjectInfo) go func() { objCh <- minio.ObjectInfo{Key: "archive.tar.gz"} @@ -68,7 +69,7 @@ func TestHandleBucketView(t *testing.T) { }, { it: "renders a bucket containing an image", - listObjectsV2Func: func(string, string, bool, <-chan struct{}) <-chan minio.ObjectInfo { + listObjectsFunc: func(context.Context, string, minio.ListObjectsOptions) <-chan minio.ObjectInfo { objCh := make(chan minio.ObjectInfo) go func() { objCh <- minio.ObjectInfo{Key: "testImage.png"} @@ -82,7 +83,7 @@ func TestHandleBucketView(t *testing.T) { }, { it: "renders a bucket containing a sound file", - listObjectsV2Func: func(string, string, bool, <-chan struct{}) <-chan minio.ObjectInfo { + listObjectsFunc: func(context.Context, string, minio.ListObjectsOptions) <-chan minio.ObjectInfo { objCh := make(chan minio.ObjectInfo) go func() { objCh <- minio.ObjectInfo{Key: "testSound.mp3"} @@ -96,7 +97,7 @@ func TestHandleBucketView(t *testing.T) { }, { it: "returns error if the bucket doesn't exist", - listObjectsV2Func: func(string, string, bool, <-chan struct{}) <-chan minio.ObjectInfo { + listObjectsFunc: func(context.Context, string, minio.ListObjectsOptions) <-chan minio.ObjectInfo { objCh := make(chan minio.ObjectInfo) go func() { objCh <- minio.ObjectInfo{Err: errBucketDoesNotExist} @@ -110,7 +111,7 @@ func TestHandleBucketView(t *testing.T) { }, { it: "returns error if there is an S3 error", - listObjectsV2Func: func(string, string, bool, <-chan struct{}) <-chan minio.ObjectInfo { + listObjectsFunc: func(context.Context, string, minio.ListObjectsOptions) <-chan minio.ObjectInfo { objCh := make(chan minio.ObjectInfo) go func() { objCh <- minio.ObjectInfo{Err: errS3} @@ -131,7 +132,7 @@ func TestHandleBucketView(t *testing.T) { is := is.New(t) s3 := &mocks.S3Mock{ - ListObjectsV2Func: tc.listObjectsV2Func, + ListObjectsFunc: tc.listObjectsFunc, } templates := os.DirFS(filepath.Join("..", "..", "..", "web", "template")) diff --git a/internal/app/s3manager/buckets_view.go b/internal/app/s3manager/buckets_view.go index 1a75c2f..c99ab22 100644 --- a/internal/app/s3manager/buckets_view.go +++ b/internal/app/s3manager/buckets_view.go @@ -9,8 +9,8 @@ import ( // HandleBucketsView renders all buckets on an HTML page. func HandleBucketsView(s3 S3, templates fs.FS) http.HandlerFunc { - return func(w http.ResponseWriter, _ *http.Request) { - buckets, err := s3.ListBuckets() + return func(w http.ResponseWriter, r *http.Request) { + buckets, err := s3.ListBuckets(r.Context()) if err != nil { handleHTTPError(w, fmt.Errorf("error listing buckets: %w", err)) return diff --git a/internal/app/s3manager/buckets_view_test.go b/internal/app/s3manager/buckets_view_test.go index 99953d3..95a9da2 100644 --- a/internal/app/s3manager/buckets_view_test.go +++ b/internal/app/s3manager/buckets_view_test.go @@ -1,6 +1,7 @@ package s3manager_test import ( + "context" "io" "net/http" "net/http/httptest" @@ -12,7 +13,7 @@ import ( "github.com/mastertinner/s3manager/internal/app/s3manager" "github.com/mastertinner/s3manager/internal/app/s3manager/mocks" "github.com/matryer/is" - minio "github.com/minio/minio-go" + "github.com/minio/minio-go/v7" ) func TestHandleBucketsView(t *testing.T) { @@ -20,13 +21,13 @@ func TestHandleBucketsView(t *testing.T) { cases := []struct { it string - listBucketsFunc func() ([]minio.BucketInfo, error) + listBucketsFunc func(context.Context) ([]minio.BucketInfo, error) expectedStatusCode int expectedBodyContains string }{ { it: "renders a list of buckets", - listBucketsFunc: func() ([]minio.BucketInfo, error) { + listBucketsFunc: func(context.Context) ([]minio.BucketInfo, error) { return []minio.BucketInfo{{Name: "testBucket"}}, nil }, expectedStatusCode: http.StatusOK, @@ -34,7 +35,7 @@ func TestHandleBucketsView(t *testing.T) { }, { it: "renders placeholder if no buckets", - listBucketsFunc: func() ([]minio.BucketInfo, error) { + listBucketsFunc: func(context.Context) ([]minio.BucketInfo, error) { return []minio.BucketInfo{}, nil }, expectedStatusCode: http.StatusOK, @@ -42,7 +43,7 @@ func TestHandleBucketsView(t *testing.T) { }, { it: "returns error if there is an S3 error", - listBucketsFunc: func() ([]minio.BucketInfo, error) { + listBucketsFunc: func(context.Context) ([]minio.BucketInfo, error) { return []minio.BucketInfo{}, errS3 }, expectedStatusCode: http.StatusInternalServerError, diff --git a/internal/app/s3manager/create_bucket.go b/internal/app/s3manager/create_bucket.go index 398eb0c..a6a6416 100644 --- a/internal/app/s3manager/create_bucket.go +++ b/internal/app/s3manager/create_bucket.go @@ -5,7 +5,7 @@ import ( "fmt" "net/http" - minio "github.com/minio/minio-go" + "github.com/minio/minio-go/v7" ) // HandleCreateBucket creates a new bucket. @@ -18,7 +18,7 @@ func HandleCreateBucket(s3 S3) http.HandlerFunc { return } - err = s3.MakeBucket(bucket.Name, "") + err = s3.MakeBucket(r.Context(), bucket.Name, minio.MakeBucketOptions{}) if err != nil { handleHTTPError(w, fmt.Errorf("error making bucket: %w", err)) return diff --git a/internal/app/s3manager/create_bucket_test.go b/internal/app/s3manager/create_bucket_test.go index 609595e..a261f81 100644 --- a/internal/app/s3manager/create_bucket_test.go +++ b/internal/app/s3manager/create_bucket_test.go @@ -2,6 +2,7 @@ package s3manager_test import ( "bytes" + "context" "io" "net/http" "net/http/httptest" @@ -11,6 +12,7 @@ import ( "github.com/mastertinner/s3manager/internal/app/s3manager" "github.com/mastertinner/s3manager/internal/app/s3manager/mocks" "github.com/matryer/is" + "github.com/minio/minio-go/v7" ) func TestHandleCreateBucket(t *testing.T) { @@ -18,14 +20,14 @@ func TestHandleCreateBucket(t *testing.T) { cases := []struct { it string - makeBucketFunc func(string, string) error + makeBucketFunc func(context.Context, string, minio.MakeBucketOptions) error body string expectedStatusCode int expectedBodyContains string }{ { it: "creates a new bucket", - makeBucketFunc: func(string, string) error { + makeBucketFunc: func(context.Context, string, minio.MakeBucketOptions) error { return nil }, body: `{"name":"myBucket"}`, @@ -34,7 +36,7 @@ func TestHandleCreateBucket(t *testing.T) { }, { it: "returns error for empty request", - makeBucketFunc: func(string, string) error { + makeBucketFunc: func(context.Context, string, minio.MakeBucketOptions) error { return nil }, body: "", @@ -43,7 +45,7 @@ func TestHandleCreateBucket(t *testing.T) { }, { it: "returns error for malformed request", - makeBucketFunc: func(string, string) error { + makeBucketFunc: func(context.Context, string, minio.MakeBucketOptions) error { return nil }, body: "}", @@ -52,7 +54,7 @@ func TestHandleCreateBucket(t *testing.T) { }, { it: "returns error if there is an S3 error", - makeBucketFunc: func(string, string) error { + makeBucketFunc: func(context.Context, string, minio.MakeBucketOptions) error { return errS3 }, body: `{"name":"myBucket"}`, diff --git a/internal/app/s3manager/create_object.go b/internal/app/s3manager/create_object.go index 0f01917..2c098c6 100644 --- a/internal/app/s3manager/create_object.go +++ b/internal/app/s3manager/create_object.go @@ -5,7 +5,7 @@ import ( "net/http" "github.com/matryer/way" - minio "github.com/minio/minio-go" + "github.com/minio/minio-go/v7" ) // HandleCreateObject uploads a new object. @@ -26,7 +26,7 @@ func HandleCreateObject(s3 S3) http.HandlerFunc { defer file.Close() opts := minio.PutObjectOptions{ContentType: "application/octet-stream"} - _, err = s3.PutObject(bucketName, header.Filename, file, -1, opts) + _, err = s3.PutObject(r.Context(), bucketName, header.Filename, file, -1, opts) if err != nil { handleHTTPError(w, fmt.Errorf("error putting object: %w", err)) return diff --git a/internal/app/s3manager/delete_bucket.go b/internal/app/s3manager/delete_bucket.go index f5afe76..325504f 100644 --- a/internal/app/s3manager/delete_bucket.go +++ b/internal/app/s3manager/delete_bucket.go @@ -12,7 +12,7 @@ func HandleDeleteBucket(s3 S3) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { bucketName := way.Param(r.Context(), "bucketName") - err := s3.RemoveBucket(bucketName) + err := s3.RemoveBucket(r.Context(), bucketName) if err != nil { handleHTTPError(w, fmt.Errorf("error removing bucket: %w", err)) return diff --git a/internal/app/s3manager/delete_bucket_test.go b/internal/app/s3manager/delete_bucket_test.go index 7b6a71e..a58811a 100644 --- a/internal/app/s3manager/delete_bucket_test.go +++ b/internal/app/s3manager/delete_bucket_test.go @@ -1,6 +1,7 @@ package s3manager_test import ( + "context" "io" "net/http" "net/http/httptest" @@ -17,13 +18,13 @@ func TestHandleDeleteBucket(t *testing.T) { cases := []struct { it string - removeBucketFunc func(string) error + removeBucketFunc func(context.Context, string) error expectedStatusCode int expectedBodyContains string }{ { it: "deletes an existing bucket", - removeBucketFunc: func(string) error { + removeBucketFunc: func(context.Context, string) error { return nil }, expectedStatusCode: http.StatusNoContent, @@ -31,7 +32,7 @@ func TestHandleDeleteBucket(t *testing.T) { }, { it: "returns error if there is an S3 error", - removeBucketFunc: func(string) error { + removeBucketFunc: func(context.Context, string) error { return errS3 }, expectedStatusCode: http.StatusInternalServerError, diff --git a/internal/app/s3manager/delete_object.go b/internal/app/s3manager/delete_object.go index 7e6701c..db740ef 100644 --- a/internal/app/s3manager/delete_object.go +++ b/internal/app/s3manager/delete_object.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/matryer/way" + "github.com/minio/minio-go/v7" ) // HandleDeleteObject deletes an object. @@ -13,7 +14,7 @@ func HandleDeleteObject(s3 S3) http.HandlerFunc { bucketName := way.Param(r.Context(), "bucketName") objectName := way.Param(r.Context(), "objectName") - err := s3.RemoveObject(bucketName, objectName) + err := s3.RemoveObject(r.Context(), bucketName, objectName, minio.RemoveObjectOptions{}) if err != nil { handleHTTPError(w, fmt.Errorf("error removing object: %w", err)) return diff --git a/internal/app/s3manager/delete_object_test.go b/internal/app/s3manager/delete_object_test.go index daf4e71..c629307 100644 --- a/internal/app/s3manager/delete_object_test.go +++ b/internal/app/s3manager/delete_object_test.go @@ -1,6 +1,7 @@ package s3manager_test import ( + "context" "net/http" "net/http/httptest" "strings" @@ -9,6 +10,7 @@ import ( "github.com/mastertinner/s3manager/internal/app/s3manager" "github.com/mastertinner/s3manager/internal/app/s3manager/mocks" "github.com/matryer/is" + "github.com/minio/minio-go/v7" ) func TestHandleDeleteObject(t *testing.T) { @@ -16,13 +18,13 @@ func TestHandleDeleteObject(t *testing.T) { cases := []struct { it string - removeObjectFunc func(string, string) error + removeObjectFunc func(context.Context, string, string, minio.RemoveObjectOptions) error expectedStatusCode int expectedBodyContains string }{ { it: "deletes an existing object", - removeObjectFunc: func(string, string) error { + removeObjectFunc: func(context.Context, string, string, minio.RemoveObjectOptions) error { return nil }, expectedStatusCode: http.StatusNoContent, @@ -30,7 +32,7 @@ func TestHandleDeleteObject(t *testing.T) { }, { it: "returns error if there is an S3 error", - removeObjectFunc: func(string, string) error { + removeObjectFunc: func(context.Context, string, string, minio.RemoveObjectOptions) error { return errS3 }, expectedStatusCode: http.StatusInternalServerError, diff --git a/internal/app/s3manager/get_object.go b/internal/app/s3manager/get_object.go index 8f1c6fe..65022fd 100644 --- a/internal/app/s3manager/get_object.go +++ b/internal/app/s3manager/get_object.go @@ -6,7 +6,7 @@ import ( "net/http" "github.com/matryer/way" - minio "github.com/minio/minio-go" + "github.com/minio/minio-go/v7" ) // HandleGetObject downloads an object to the client. @@ -15,7 +15,7 @@ func HandleGetObject(s3 S3) http.HandlerFunc { bucketName := way.Param(r.Context(), "bucketName") objectName := way.Param(r.Context(), "objectName") - object, err := s3.GetObject(bucketName, objectName, minio.GetObjectOptions{}) + object, err := s3.GetObject(r.Context(), bucketName, objectName, minio.GetObjectOptions{}) if err != nil { handleHTTPError(w, fmt.Errorf("error getting object: %w", err)) return diff --git a/internal/app/s3manager/get_object_test.go b/internal/app/s3manager/get_object_test.go index 8454e27..82e006b 100644 --- a/internal/app/s3manager/get_object_test.go +++ b/internal/app/s3manager/get_object_test.go @@ -1,6 +1,7 @@ package s3manager_test import ( + "context" "fmt" "io" "net/http" @@ -12,7 +13,7 @@ import ( "github.com/mastertinner/s3manager/internal/app/s3manager/mocks" "github.com/matryer/is" "github.com/matryer/way" - minio "github.com/minio/minio-go" + "github.com/minio/minio-go/v7" ) func TestHandleGetObject(t *testing.T) { @@ -20,7 +21,7 @@ func TestHandleGetObject(t *testing.T) { cases := []struct { it string - getObjectFunc func(string, string, minio.GetObjectOptions) (*minio.Object, error) + getObjectFunc func(context.Context, string, string, minio.GetObjectOptions) (*minio.Object, error) bucketName string objectName string expectedStatusCode int @@ -28,7 +29,7 @@ func TestHandleGetObject(t *testing.T) { }{ { it: "returns error if there is an S3 error", - getObjectFunc: func(string, string, minio.GetObjectOptions) (*minio.Object, error) { + getObjectFunc: func(context.Context, string, string, minio.GetObjectOptions) (*minio.Object, error) { return nil, errS3 }, bucketName: "testBucket", diff --git a/internal/app/s3manager/mocks/s3.go b/internal/app/s3manager/mocks/s3.go index f6f692d..f9346dc 100644 --- a/internal/app/s3manager/mocks/s3.go +++ b/internal/app/s3manager/mocks/s3.go @@ -4,8 +4,9 @@ package mocks import ( + "context" "github.com/mastertinner/s3manager/internal/app/s3manager" - minio "github.com/minio/minio-go" + "github.com/minio/minio-go/v7" "io" "sync" ) @@ -20,25 +21,25 @@ var _ s3manager.S3 = &S3Mock{} // // // make and configure a mocked s3manager.S3 // mockedS3 := &S3Mock{ -// GetObjectFunc: func(bucketName string, objectName string, opts minio.GetObjectOptions) (*minio.Object, error) { +// GetObjectFunc: func(ctx context.Context, bucketName string, objectName string, opts minio.GetObjectOptions) (*minio.Object, error) { // panic("mock out the GetObject method") // }, -// ListBucketsFunc: func() ([]minio.BucketInfo, error) { +// ListBucketsFunc: func(ctx context.Context) ([]minio.BucketInfo, error) { // panic("mock out the ListBuckets method") // }, -// ListObjectsV2Func: func(bucketName string, objectPrefix string, recursive bool, doneCh <-chan struct{}) <-chan minio.ObjectInfo { -// panic("mock out the ListObjectsV2 method") +// ListObjectsFunc: func(ctx context.Context, bucketName string, opts minio.ListObjectsOptions) <-chan minio.ObjectInfo { +// panic("mock out the ListObjects method") // }, -// MakeBucketFunc: func(bucketName string, location string) error { +// MakeBucketFunc: func(ctx context.Context, bucketName string, opts minio.MakeBucketOptions) error { // panic("mock out the MakeBucket method") // }, -// PutObjectFunc: func(bucketName string, objectName string, reader io.Reader, objectSize int64, opts minio.PutObjectOptions) (int64, error) { +// PutObjectFunc: func(ctx context.Context, bucketName string, objectName string, reader io.Reader, objectSize int64, opts minio.PutObjectOptions) (minio.UploadInfo, error) { // panic("mock out the PutObject method") // }, -// RemoveBucketFunc: func(bucketName string) error { +// RemoveBucketFunc: func(ctx context.Context, bucketName string) error { // panic("mock out the RemoveBucket method") // }, -// RemoveObjectFunc: func(bucketName string, objectName string) error { +// RemoveObjectFunc: func(ctx context.Context, bucketName string, objectName string, opts minio.RemoveObjectOptions) error { // panic("mock out the RemoveObject method") // }, // } @@ -49,30 +50,32 @@ var _ s3manager.S3 = &S3Mock{} // } type S3Mock struct { // GetObjectFunc mocks the GetObject method. - GetObjectFunc func(bucketName string, objectName string, opts minio.GetObjectOptions) (*minio.Object, error) + GetObjectFunc func(ctx context.Context, bucketName string, objectName string, opts minio.GetObjectOptions) (*minio.Object, error) // ListBucketsFunc mocks the ListBuckets method. - ListBucketsFunc func() ([]minio.BucketInfo, error) + ListBucketsFunc func(ctx context.Context) ([]minio.BucketInfo, error) - // ListObjectsV2Func mocks the ListObjectsV2 method. - ListObjectsV2Func func(bucketName string, objectPrefix string, recursive bool, doneCh <-chan struct{}) <-chan minio.ObjectInfo + // ListObjectsFunc mocks the ListObjects method. + ListObjectsFunc func(ctx context.Context, bucketName string, opts minio.ListObjectsOptions) <-chan minio.ObjectInfo // MakeBucketFunc mocks the MakeBucket method. - MakeBucketFunc func(bucketName string, location string) error + MakeBucketFunc func(ctx context.Context, bucketName string, opts minio.MakeBucketOptions) error // PutObjectFunc mocks the PutObject method. - PutObjectFunc func(bucketName string, objectName string, reader io.Reader, objectSize int64, opts minio.PutObjectOptions) (int64, error) + PutObjectFunc func(ctx context.Context, bucketName string, objectName string, reader io.Reader, objectSize int64, opts minio.PutObjectOptions) (minio.UploadInfo, error) // RemoveBucketFunc mocks the RemoveBucket method. - RemoveBucketFunc func(bucketName string) error + RemoveBucketFunc func(ctx context.Context, bucketName string) error // RemoveObjectFunc mocks the RemoveObject method. - RemoveObjectFunc func(bucketName string, objectName string) error + RemoveObjectFunc func(ctx context.Context, bucketName string, objectName string, opts minio.RemoveObjectOptions) error // calls tracks calls to the methods. calls struct { // GetObject holds details about calls to the GetObject method. GetObject []struct { + // Ctx is the ctx argument value. + Ctx context.Context // BucketName is the bucketName argument value. BucketName string // ObjectName is the objectName argument value. @@ -82,27 +85,31 @@ type S3Mock struct { } // ListBuckets holds details about calls to the ListBuckets method. ListBuckets []struct { + // Ctx is the ctx argument value. + Ctx context.Context } - // ListObjectsV2 holds details about calls to the ListObjectsV2 method. - ListObjectsV2 []struct { + // ListObjects holds details about calls to the ListObjects method. + ListObjects []struct { + // Ctx is the ctx argument value. + Ctx context.Context // BucketName is the bucketName argument value. BucketName string - // ObjectPrefix is the objectPrefix argument value. - ObjectPrefix string - // Recursive is the recursive argument value. - Recursive bool - // DoneCh is the doneCh argument value. - DoneCh <-chan struct{} + // Opts is the opts argument value. + Opts minio.ListObjectsOptions } // MakeBucket holds details about calls to the MakeBucket method. MakeBucket []struct { + // Ctx is the ctx argument value. + Ctx context.Context // BucketName is the bucketName argument value. BucketName string - // Location is the location argument value. - Location string + // Opts is the opts argument value. + Opts minio.MakeBucketOptions } // PutObject holds details about calls to the PutObject method. PutObject []struct { + // Ctx is the ctx argument value. + Ctx context.Context // BucketName is the bucketName argument value. BucketName string // ObjectName is the objectName argument value. @@ -116,36 +123,44 @@ type S3Mock struct { } // RemoveBucket holds details about calls to the RemoveBucket method. RemoveBucket []struct { + // Ctx is the ctx argument value. + Ctx context.Context // BucketName is the bucketName argument value. BucketName string } // RemoveObject holds details about calls to the RemoveObject method. RemoveObject []struct { + // Ctx is the ctx argument value. + Ctx context.Context // BucketName is the bucketName argument value. BucketName string // ObjectName is the objectName argument value. ObjectName string + // Opts is the opts argument value. + Opts minio.RemoveObjectOptions } } - lockGetObject sync.RWMutex - lockListBuckets sync.RWMutex - lockListObjectsV2 sync.RWMutex - lockMakeBucket sync.RWMutex - lockPutObject sync.RWMutex - lockRemoveBucket sync.RWMutex - lockRemoveObject sync.RWMutex + lockGetObject sync.RWMutex + lockListBuckets sync.RWMutex + lockListObjects sync.RWMutex + lockMakeBucket sync.RWMutex + lockPutObject sync.RWMutex + lockRemoveBucket sync.RWMutex + lockRemoveObject sync.RWMutex } // GetObject calls GetObjectFunc. -func (mock *S3Mock) GetObject(bucketName string, objectName string, opts minio.GetObjectOptions) (*minio.Object, error) { +func (mock *S3Mock) GetObject(ctx context.Context, bucketName string, objectName string, opts minio.GetObjectOptions) (*minio.Object, error) { if mock.GetObjectFunc == nil { panic("S3Mock.GetObjectFunc: method is nil but S3.GetObject was just called") } callInfo := struct { + Ctx context.Context BucketName string ObjectName string Opts minio.GetObjectOptions }{ + Ctx: ctx, BucketName: bucketName, ObjectName: objectName, Opts: opts, @@ -153,18 +168,20 @@ func (mock *S3Mock) GetObject(bucketName string, objectName string, opts minio.G mock.lockGetObject.Lock() mock.calls.GetObject = append(mock.calls.GetObject, callInfo) mock.lockGetObject.Unlock() - return mock.GetObjectFunc(bucketName, objectName, opts) + return mock.GetObjectFunc(ctx, bucketName, objectName, opts) } // GetObjectCalls gets all the calls that were made to GetObject. // Check the length with: // len(mockedS3.GetObjectCalls()) func (mock *S3Mock) GetObjectCalls() []struct { + Ctx context.Context BucketName string ObjectName string Opts minio.GetObjectOptions } { var calls []struct { + Ctx context.Context BucketName string ObjectName string Opts minio.GetObjectOptions @@ -176,24 +193,29 @@ func (mock *S3Mock) GetObjectCalls() []struct { } // ListBuckets calls ListBucketsFunc. -func (mock *S3Mock) ListBuckets() ([]minio.BucketInfo, error) { +func (mock *S3Mock) ListBuckets(ctx context.Context) ([]minio.BucketInfo, error) { if mock.ListBucketsFunc == nil { panic("S3Mock.ListBucketsFunc: method is nil but S3.ListBuckets was just called") } callInfo := struct { - }{} + Ctx context.Context + }{ + Ctx: ctx, + } mock.lockListBuckets.Lock() mock.calls.ListBuckets = append(mock.calls.ListBuckets, callInfo) mock.lockListBuckets.Unlock() - return mock.ListBucketsFunc() + return mock.ListBucketsFunc(ctx) } // ListBucketsCalls gets all the calls that were made to ListBuckets. // Check the length with: // len(mockedS3.ListBucketsCalls()) func (mock *S3Mock) ListBucketsCalls() []struct { + Ctx context.Context } { var calls []struct { + Ctx context.Context } mock.lockListBuckets.RLock() calls = mock.calls.ListBuckets @@ -201,77 +223,77 @@ func (mock *S3Mock) ListBucketsCalls() []struct { return calls } -// ListObjectsV2 calls ListObjectsV2Func. -func (mock *S3Mock) ListObjectsV2(bucketName string, objectPrefix string, recursive bool, doneCh <-chan struct{}) <-chan minio.ObjectInfo { - if mock.ListObjectsV2Func == nil { - panic("S3Mock.ListObjectsV2Func: method is nil but S3.ListObjectsV2 was just called") +// ListObjects calls ListObjectsFunc. +func (mock *S3Mock) ListObjects(ctx context.Context, bucketName string, opts minio.ListObjectsOptions) <-chan minio.ObjectInfo { + if mock.ListObjectsFunc == nil { + panic("S3Mock.ListObjectsFunc: method is nil but S3.ListObjects was just called") } callInfo := struct { - BucketName string - ObjectPrefix string - Recursive bool - DoneCh <-chan struct{} + Ctx context.Context + BucketName string + Opts minio.ListObjectsOptions }{ - BucketName: bucketName, - ObjectPrefix: objectPrefix, - Recursive: recursive, - DoneCh: doneCh, + Ctx: ctx, + BucketName: bucketName, + Opts: opts, } - mock.lockListObjectsV2.Lock() - mock.calls.ListObjectsV2 = append(mock.calls.ListObjectsV2, callInfo) - mock.lockListObjectsV2.Unlock() - return mock.ListObjectsV2Func(bucketName, objectPrefix, recursive, doneCh) + mock.lockListObjects.Lock() + mock.calls.ListObjects = append(mock.calls.ListObjects, callInfo) + mock.lockListObjects.Unlock() + return mock.ListObjectsFunc(ctx, bucketName, opts) } -// ListObjectsV2Calls gets all the calls that were made to ListObjectsV2. +// ListObjectsCalls gets all the calls that were made to ListObjects. // Check the length with: -// len(mockedS3.ListObjectsV2Calls()) -func (mock *S3Mock) ListObjectsV2Calls() []struct { - BucketName string - ObjectPrefix string - Recursive bool - DoneCh <-chan struct{} +// len(mockedS3.ListObjectsCalls()) +func (mock *S3Mock) ListObjectsCalls() []struct { + Ctx context.Context + BucketName string + Opts minio.ListObjectsOptions } { var calls []struct { - BucketName string - ObjectPrefix string - Recursive bool - DoneCh <-chan struct{} + Ctx context.Context + BucketName string + Opts minio.ListObjectsOptions } - mock.lockListObjectsV2.RLock() - calls = mock.calls.ListObjectsV2 - mock.lockListObjectsV2.RUnlock() + mock.lockListObjects.RLock() + calls = mock.calls.ListObjects + mock.lockListObjects.RUnlock() return calls } // MakeBucket calls MakeBucketFunc. -func (mock *S3Mock) MakeBucket(bucketName string, location string) error { +func (mock *S3Mock) MakeBucket(ctx context.Context, bucketName string, opts minio.MakeBucketOptions) error { if mock.MakeBucketFunc == nil { panic("S3Mock.MakeBucketFunc: method is nil but S3.MakeBucket was just called") } callInfo := struct { + Ctx context.Context BucketName string - Location string + Opts minio.MakeBucketOptions }{ + Ctx: ctx, BucketName: bucketName, - Location: location, + Opts: opts, } mock.lockMakeBucket.Lock() mock.calls.MakeBucket = append(mock.calls.MakeBucket, callInfo) mock.lockMakeBucket.Unlock() - return mock.MakeBucketFunc(bucketName, location) + return mock.MakeBucketFunc(ctx, bucketName, opts) } // MakeBucketCalls gets all the calls that were made to MakeBucket. // Check the length with: // len(mockedS3.MakeBucketCalls()) func (mock *S3Mock) MakeBucketCalls() []struct { + Ctx context.Context BucketName string - Location string + Opts minio.MakeBucketOptions } { var calls []struct { + Ctx context.Context BucketName string - Location string + Opts minio.MakeBucketOptions } mock.lockMakeBucket.RLock() calls = mock.calls.MakeBucket @@ -280,17 +302,19 @@ func (mock *S3Mock) MakeBucketCalls() []struct { } // PutObject calls PutObjectFunc. -func (mock *S3Mock) PutObject(bucketName string, objectName string, reader io.Reader, objectSize int64, opts minio.PutObjectOptions) (int64, error) { +func (mock *S3Mock) PutObject(ctx context.Context, bucketName string, objectName string, reader io.Reader, objectSize int64, opts minio.PutObjectOptions) (minio.UploadInfo, error) { if mock.PutObjectFunc == nil { panic("S3Mock.PutObjectFunc: method is nil but S3.PutObject was just called") } callInfo := struct { + Ctx context.Context BucketName string ObjectName string Reader io.Reader ObjectSize int64 Opts minio.PutObjectOptions }{ + Ctx: ctx, BucketName: bucketName, ObjectName: objectName, Reader: reader, @@ -300,13 +324,14 @@ func (mock *S3Mock) PutObject(bucketName string, objectName string, reader io.Re mock.lockPutObject.Lock() mock.calls.PutObject = append(mock.calls.PutObject, callInfo) mock.lockPutObject.Unlock() - return mock.PutObjectFunc(bucketName, objectName, reader, objectSize, opts) + return mock.PutObjectFunc(ctx, bucketName, objectName, reader, objectSize, opts) } // PutObjectCalls gets all the calls that were made to PutObject. // Check the length with: // len(mockedS3.PutObjectCalls()) func (mock *S3Mock) PutObjectCalls() []struct { + Ctx context.Context BucketName string ObjectName string Reader io.Reader @@ -314,6 +339,7 @@ func (mock *S3Mock) PutObjectCalls() []struct { Opts minio.PutObjectOptions } { var calls []struct { + Ctx context.Context BucketName string ObjectName string Reader io.Reader @@ -327,28 +353,32 @@ func (mock *S3Mock) PutObjectCalls() []struct { } // RemoveBucket calls RemoveBucketFunc. -func (mock *S3Mock) RemoveBucket(bucketName string) error { +func (mock *S3Mock) RemoveBucket(ctx context.Context, bucketName string) error { if mock.RemoveBucketFunc == nil { panic("S3Mock.RemoveBucketFunc: method is nil but S3.RemoveBucket was just called") } callInfo := struct { + Ctx context.Context BucketName string }{ + Ctx: ctx, BucketName: bucketName, } mock.lockRemoveBucket.Lock() mock.calls.RemoveBucket = append(mock.calls.RemoveBucket, callInfo) mock.lockRemoveBucket.Unlock() - return mock.RemoveBucketFunc(bucketName) + return mock.RemoveBucketFunc(ctx, bucketName) } // RemoveBucketCalls gets all the calls that were made to RemoveBucket. // Check the length with: // len(mockedS3.RemoveBucketCalls()) func (mock *S3Mock) RemoveBucketCalls() []struct { + Ctx context.Context BucketName string } { var calls []struct { + Ctx context.Context BucketName string } mock.lockRemoveBucket.RLock() @@ -358,33 +388,41 @@ func (mock *S3Mock) RemoveBucketCalls() []struct { } // RemoveObject calls RemoveObjectFunc. -func (mock *S3Mock) RemoveObject(bucketName string, objectName string) error { +func (mock *S3Mock) RemoveObject(ctx context.Context, bucketName string, objectName string, opts minio.RemoveObjectOptions) error { if mock.RemoveObjectFunc == nil { panic("S3Mock.RemoveObjectFunc: method is nil but S3.RemoveObject was just called") } callInfo := struct { + Ctx context.Context BucketName string ObjectName string + Opts minio.RemoveObjectOptions }{ + Ctx: ctx, BucketName: bucketName, ObjectName: objectName, + Opts: opts, } mock.lockRemoveObject.Lock() mock.calls.RemoveObject = append(mock.calls.RemoveObject, callInfo) mock.lockRemoveObject.Unlock() - return mock.RemoveObjectFunc(bucketName, objectName) + return mock.RemoveObjectFunc(ctx, bucketName, objectName, opts) } // RemoveObjectCalls gets all the calls that were made to RemoveObject. // Check the length with: // len(mockedS3.RemoveObjectCalls()) func (mock *S3Mock) RemoveObjectCalls() []struct { + Ctx context.Context BucketName string ObjectName string + Opts minio.RemoveObjectOptions } { var calls []struct { + Ctx context.Context BucketName string ObjectName string + Opts minio.RemoveObjectOptions } mock.lockRemoveObject.RLock() calls = mock.calls.RemoveObject diff --git a/internal/app/s3manager/s3.go b/internal/app/s3manager/s3.go index 786a63d..3df068d 100644 --- a/internal/app/s3manager/s3.go +++ b/internal/app/s3manager/s3.go @@ -1,20 +1,21 @@ package s3manager import ( + "context" "io" - minio "github.com/minio/minio-go" + "github.com/minio/minio-go/v7" ) //go:generate moq -out mocks/s3.go -pkg mocks . S3 // S3 is a client to interact with S3 storage. type S3 interface { - GetObject(bucketName, objectName string, opts minio.GetObjectOptions) (*minio.Object, error) - ListBuckets() ([]minio.BucketInfo, error) - ListObjectsV2(bucketName, objectPrefix string, recursive bool, doneCh <-chan struct{}) <-chan minio.ObjectInfo - MakeBucket(bucketName, location string) error - PutObject(bucketName, objectName string, reader io.Reader, objectSize int64, opts minio.PutObjectOptions) (int64, error) - RemoveBucket(bucketName string) error - RemoveObject(bucketName, objectName string) error + GetObject(ctx context.Context, bucketName, objectName string, opts minio.GetObjectOptions) (*minio.Object, error) + ListBuckets(ctx context.Context) ([]minio.BucketInfo, error) + ListObjects(ctx context.Context, bucketName string, opts minio.ListObjectsOptions) <-chan minio.ObjectInfo + MakeBucket(ctx context.Context, bucketName string, opts minio.MakeBucketOptions) error + PutObject(ctx context.Context, bucketName, objectName string, reader io.Reader, objectSize int64, opts minio.PutObjectOptions) (minio.UploadInfo, error) + RemoveBucket(ctx context.Context, bucketName string) error + RemoveObject(ctx context.Context, bucketName, objectName string, opts minio.RemoveObjectOptions) error } diff --git a/main.go b/main.go index cdcbb59..2343d14 100644 --- a/main.go +++ b/main.go @@ -13,7 +13,8 @@ import ( "github.com/mastertinner/adapters/logging" "github.com/mastertinner/s3manager/internal/app/s3manager" "github.com/matryer/way" - minio "github.com/minio/minio-go" + "github.com/minio/minio-go/v7" + "github.com/minio/minio-go/v7/pkg/credentials" ) //go:embed web/template @@ -32,6 +33,7 @@ func main() { if !ok { log.Fatal("please provide SECRET_ACCESS_KEY") } + region := os.Getenv("REGION") useSSL := getBoolEnvWithDefault("USE_SSL", true) skipSSLVerification := getBoolEnvWithDefault("SKIP_SSL_VERIFICATION", false) port, ok := os.LookupEnv("PORT") @@ -46,12 +48,19 @@ func main() { } // Set up S3 client - s3, err := minio.New(endpoint, accessKeyID, secretAccessKey, useSSL) - if err != nil { - log.Fatalln(fmt.Errorf("error creating s3 client: %w", err)) + opts := &minio.Options{ + Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""), + Secure: useSSL, + } + if region != "" { + opts.Region = region } if useSSL && skipSSLVerification { - s3.SetCustomTransport(&http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}) //nolint:gosec + opts.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} //nolint:gosec + } + s3, err := minio.New(endpoint, opts) + if err != nil { + log.Fatalln(fmt.Errorf("error creating s3 client: %w", err)) } // Set up router