Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package geoipupdate for openSUSE:Factory checked in at 2023-06-21 22:40:13 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/geoipupdate (Old) and /work/SRC/openSUSE:Factory/.geoipupdate.new.15902 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "geoipupdate" Wed Jun 21 22:40:13 2023 rev:23 rq:1094336 version:5.1.1 Changes: -------- --- /work/SRC/openSUSE:Factory/geoipupdate/geoipupdate.changes 2023-04-17 17:41:50.402411155 +0200 +++ /work/SRC/openSUSE:Factory/.geoipupdate.new.15902/geoipupdate.changes 2023-06-21 22:41:07.446827933 +0200 @@ -1,0 +2,24 @@ +Wed Jun 21 09:48:29 UTC 2023 - Valentin Lefebvre <valentin.lefeb...@suse.com> + +- Update to 5.1.1: + * Based on feedback, the change to use a non-root user in 5.1.0 when using + the Docker image has been reverted. There are no non-Docker changes in this + release. See GitHub #233. + +- Update to 5.1.0: + * Fixed the Docker health-check script to use the correct time of the last + update attempt. Reported by cford1080. GitHub #225. + * Added new --output flag to print JSON to standard output describing the + result of the run. + * Compilation with Go versions before 1.19 is no longer supported. + * When using the provided Docker images, geoipupdate no longer runs as root + in the container. Based on pull request by Andreas Grünenfelder. GitHub + #200. + +- Update to 5.0.4: + * On releases 4.9.0 through 5.0.3, the incorrect commit was tagged. This + release attempts to fix the release process to prevent this issue. There + are no code changes to the binaries provided by MaxMind, either on the + GitHub Release page or the MaxMind PPA. + +------------------------------------------------------------------- Old: ---- geoipupdate-5.0.3.tar.gz New: ---- geoipupdate-5.1.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ geoipupdate.spec ++++++ --- /var/tmp/diff_new_pack.ZReLw3/_old 2023-06-21 22:41:08.122832002 +0200 +++ /var/tmp/diff_new_pack.ZReLw3/_new 2023-06-21 22:41:08.130832050 +0200 @@ -18,7 +18,7 @@ # Common info Name: geoipupdate -Version: 5.0.3 +Version: 5.1.1 Release: 0 Summary: GeoIP update client code License: Apache-2.0 OR MIT @@ -55,6 +55,7 @@ + # Preparation step (unpackung and patching if necessary) %prep %setup -q -a1 ++++++ geoipupdate-5.0.3.tar.gz -> geoipupdate-5.1.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/.github/workflows/go.yml new/geoipupdate-5.1.1/.github/workflows/go.yml --- old/geoipupdate-5.0.3/.github/workflows/go.yml 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/.github/workflows/go.yml 2023-05-08 18:16:35.000000000 +0200 @@ -11,8 +11,7 @@ build: strategy: matrix: - # I think we need to keep 1.13 for Ubuntu Bionic for the PPA. - go-version: [1.13.x, 1.14.x, 1.15.x, 1.16.x, 1.17.x, 1.18.x, 1.19.x] + go-version: [1.19.x, 1.20.x] platform: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.platform }} name: "Build ${{ matrix.go-version }} test on ${{ matrix.platform }}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/.golangci.toml new/geoipupdate-5.1.1/.golangci.toml --- old/geoipupdate-5.0.3/.golangci.toml 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/.golangci.toml 2023-05-08 18:16:35.000000000 +0200 @@ -84,6 +84,17 @@ "wrapcheck", ] +# Please note that we only use depguard for stdlib as gomodguard only +# supports modules currently. See https://github.com/ryancurrah/gomodguard/issues/12 +[linters-settings.depguard] + list-type = "blacklist" + include-go-root = true + packages = [ + # ioutil is deprecated. The functions have been moved elsewhere: + # https://golang.org/doc/go1.16#ioutil + "io/ioutil", + ] + [linters-settings.errcheck] # Don't allow setting of error to the blank identifier. If there is a legitimate # reason, there should be a nolint with an explanation. @@ -252,7 +263,7 @@ [linters-settings.gofumpt] extra-rules = true - lang-version = "1.18" + lang-version = "1.19" [linters-settings.gomodguard] [[linters-settings.gomodguard.blocked.modules]] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/.goreleaser.yml new/geoipupdate-5.1.1/.goreleaser.yml --- old/geoipupdate-5.0.3/.goreleaser.yml 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/.goreleaser.yml 2023-05-08 18:16:35.000000000 +0200 @@ -93,6 +93,7 @@ goarch: amd64 extra_files: - docker/entry.sh + - docker/healthcheck.sh build_flag_templates: - "--platform=linux/amd64" - image_templates: @@ -103,6 +104,7 @@ goarch: arm64 extra_files: - docker/entry.sh + - docker/healthcheck.sh build_flag_templates: - "--platform=linux/arm64" - image_templates: @@ -114,6 +116,7 @@ goarm: 6 extra_files: - docker/entry.sh + - docker/healthcheck.sh build_flag_templates: - "--platform=linux/arm/v6" docker_manifests: @@ -195,3 +198,4 @@ type: config release: name_template: "{{.Version}}" + target_commitish: "{{ .FullCommit }}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/CHANGELOG.md new/geoipupdate-5.1.1/CHANGELOG.md --- old/geoipupdate-5.0.3/CHANGELOG.md 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/CHANGELOG.md 2023-05-08 18:16:35.000000000 +0200 @@ -1,5 +1,37 @@ # CHANGELOG +## 5.1.1 (2023-05-08) + +* Based on feedback, the change to use a non-root user in 5.1.0 + when using the Docker image has been reverted. There are no + non-Docker changes in this release. See GitHub #233. + +## 5.1.0 (2023-05-05) + +* Fixed the Docker health-check script to use the correct time of + the last update attempt. Reported by cford1080. GitHub #225. +* Added new `--output` flag to print JSON to standard output describing + the result of the run. +* Compilation with Go versions before 1.19 is no longer supported. +* When using the provided Docker images, `geoipupdate` no longer runs + as root in the container. Based on pull request by Andreas + Grünenfelder. GitHub #200. + +## 5.0.4 (2023-04-17) + +* On releases 4.9.0 through 5.0.3, the incorrect commit was tagged. + This release attempts to fix the release process to prevent this + issue. There are no code changes to the binaries provided by + MaxMind, either on the GitHub Release page or the MaxMind PPA. + +## 5.0.3 (2023-04-15) + +* On 5.0.0 through 5.0.2, the default database directory was not being + correctly set for Debian and RPM package builds. The directory + `/usr/local/share/GeoIP` was being used rather than `/usr/share/GeoIP`. + This build restores `/usr/share/GeoIP` as the default directory for + these builds. Reported by Yvan. GitHub #222. + ## 5.0.2 (2023-04-13) * "Database ... up to date" messages are now only shown if the verbose diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/README.dev.md new/geoipupdate-5.1.1/README.dev.md --- old/geoipupdate-5.0.3/README.dev.md 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/README.dev.md 2023-05-08 18:16:35.000000000 +0200 @@ -5,6 +5,9 @@ * Set release date in `CHANGELOG.md` and commit it. * Ensure you can run `docker` commands as your user (e.g., `docker images`). +* Ensure Docker is set up to do cross-compilation. You can verify this with + `docker buildx ls`. It should list `linux/arm64` as an available platform. + If not, follow [these instructions](https://docs.docker.com/build/building/multi-platform/). * Log in to your Docker Hub account (be sure to be in our organization): `docker login`. * Run `GITHUB_TOKEN=<your token> ./dev-bin/release.sh`. For `goreleaser` you diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/README.md new/geoipupdate-5.1.1/README.md --- old/geoipupdate-5.0.3/README.md 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/README.md 2023-05-08 18:16:35.000000000 +0200 @@ -102,12 +102,12 @@ ### Installation from source or Git -You need the Go compiler (1.13+). You can get it at the [Go +You need the Go compiler (1.19+). You can get it at the [Go website](https://golang.org). -The easiest way is via `go get`: +The easiest way is via `go install`: - $ env GO111MODULE=on go get -u github.com/maxmind/geoipupdate/v5/cmd/geoipupdate + $ go install github.com/maxmind/geoipupdate/v5/cmd/geoipupdate@latest This installs `geoipupdate` to `$GOPATH/bin/geoipupdate`. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/cmd/geoipupdate/args.go new/geoipupdate-5.1.1/cmd/geoipupdate/args.go --- old/geoipupdate-5.0.3/cmd/geoipupdate/args.go 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/cmd/geoipupdate/args.go 2023-05-08 18:16:35.000000000 +0200 @@ -4,6 +4,7 @@ "log" "os" + "github.com/maxmind/geoipupdate/v5/pkg/geoipupdate/vars" flag "github.com/spf13/pflag" ) @@ -13,6 +14,7 @@ DatabaseDirectory string StackTrace bool Verbose bool + Output bool Parallelism int } @@ -20,7 +22,7 @@ configFile := flag.StringP( "config-file", "f", - defaultConfigFile, + vars.DefaultConfigFile, "Configuration file", ) databaseDirectory := flag.StringP( @@ -30,10 +32,11 @@ "Store databases in this directory (uses config if not specified)", ) help := flag.BoolP("help", "h", false, "Display help and exit") - stackTrace := flag.Bool("stack-trace", false, "Show a stack trace along with any error message.") + stackTrace := flag.Bool("stack-trace", false, "Show a stack trace along with any error message") verbose := flag.BoolP("verbose", "v", false, "Use verbose output") + output := flag.BoolP("output", "o", false, "Output download/update results in JSON format") displayVersion := flag.BoolP("version", "V", false, "Display the version and exit") - parallelism := flag.Int("parallelism", 0, "Set the number of parallel database downloads.") + parallelism := flag.Int("parallelism", 0, "Set the number of parallel database downloads") flag.Parse() @@ -61,6 +64,7 @@ DatabaseDirectory: *databaseDirectory, StackTrace: *stackTrace, Verbose: *verbose, + Output: *output, Parallelism: *parallelism, } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/cmd/geoipupdate/end_to_end_test.go new/geoipupdate-5.1.1/cmd/geoipupdate/end_to_end_test.go --- old/geoipupdate-5.0.3/cmd/geoipupdate/end_to_end_test.go 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/cmd/geoipupdate/end_to_end_test.go 2023-05-08 18:16:35.000000000 +0200 @@ -7,7 +7,6 @@ "crypto/md5" "fmt" "io" - "io/ioutil" "log" "net/http" "net/http/httptest" @@ -61,12 +60,7 @@ ) defer server.Close() - tempDir, err := ioutil.TempDir("", "gutest-") - require.NoError(t, err) - defer func() { - err := os.RemoveAll(tempDir) - require.NoError(t, err) - }() + tempDir := t.TempDir() config := &geoipupdate.Config{ AccountID: 123, @@ -82,14 +76,14 @@ log.SetOutput(logOutput) client := geoipupdate.NewClient(config) - err = client.Run(context.Background()) + err := client.Run(context.Background()) assert.NoError(t, err, "run successfully") assert.Equal(t, "", logOutput.String(), "no logged output") for _, editionID := range config.EditionIDs { path := filepath.Join(config.DatabaseDirectory, editionID+".mmdb") - buf, err := ioutil.ReadFile(filepath.Clean(path)) + buf, err := os.ReadFile(filepath.Clean(path)) require.NoError(t, err, "read file") assert.Equal( t, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/cmd/geoipupdate/main.go new/geoipupdate-5.1.1/cmd/geoipupdate/main.go --- old/geoipupdate-5.0.3/cmd/geoipupdate/main.go 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/cmd/geoipupdate/main.go 2023-05-08 18:16:35.000000000 +0200 @@ -11,16 +11,23 @@ "github.com/maxmind/geoipupdate/v5/pkg/geoipupdate/vars" ) +// These values are set by build scripts. Changing the names of +// the variables should be considered a breaking change. var ( - version = "unknown" - defaultConfigFile string + version = "unknown" + defaultConfigFile string + defaultDatabaseDirectory string ) func main() { log.SetFlags(0) - if defaultConfigFile == "" { - defaultConfigFile = vars.DefaultConfigFile + if defaultConfigFile != "" { + vars.DefaultConfigFile = defaultConfigFile + } + + if defaultDatabaseDirectory != "" { + vars.DefaultDatabaseDirectory = defaultDatabaseDirectory } args := getArgs() @@ -38,6 +45,7 @@ geoipupdate.WithDatabaseDirectory(args.DatabaseDirectory), geoipupdate.WithParallelism(args.Parallelism), geoipupdate.WithVerbose(args.Verbose), + geoipupdate.WithOutput(args.Output), ) if err != nil { fatalLogger(fmt.Sprintf("error loading configuration file %s", args.ConfigFile), err) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/doc/geoipupdate.md new/geoipupdate-5.1.1/doc/geoipupdate.md --- old/geoipupdate-5.0.3/doc/geoipupdate.md 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/doc/geoipupdate.md 2023-05-08 18:16:35.000000000 +0200 @@ -49,6 +49,10 @@ : Enable verbose mode. Prints out the steps that `geoipupdate` takes. +`-o`, `--output` + +: Output download/update results in JSON format. + # EXIT STATUS `geoipupdate` returns 0 on success and 1 on error. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/docker/Dockerfile new/geoipupdate-5.1.1/docker/Dockerfile --- old/geoipupdate-5.0.3/docker/Dockerfile 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/docker/Dockerfile 2023-05-08 18:16:35.000000000 +0200 @@ -1,16 +1,14 @@ FROM alpine:3 +RUN apk update && \ + apk add jq +RUN adduser -D -h /var/lib/geoipupdate -u 1000 geoipupdate + COPY geoipupdate /usr/bin/geoipupdate COPY docker/entry.sh /usr/bin/entry.sh +COPY docker/healthcheck.sh /usr/bin/healthcheck.sh ENTRYPOINT ["/usr/bin/entry.sh"] - -# The health check is done by checking if the database directory is modified within the -# update period minus 1 minute. The 1 minute is a threshold for allowing slower starts. -# Without the LockFile in the database directory, this check is not going to be working -# since database files are not going to be modified when there are no updates. -HEALTHCHECK --interval=10s --timeout=10s \ - CMD test $(stat -c %Y /usr/share/GeoIP) -gt $(($(date +%s) - $GEOIPUPDATE_FREQUENCY * 60 * 61 )) \ - || exit 1; - +HEALTHCHECK --interval=10s --timeout=10s CMD [ "/usr/bin/healthcheck.sh" ] VOLUME [ "/usr/share/GeoIP" ] +WORKDIR /var/lib/geoipupdate diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/docker/entry.sh new/geoipupdate-5.1.1/docker/entry.sh --- old/geoipupdate-5.0.3/docker/entry.sh 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/docker/entry.sh 2023-05-08 18:16:35.000000000 +0200 @@ -14,9 +14,11 @@ trap 'kill ${!}; term_handler' SIGTERM pid=0 -conf_file=/etc/GeoIP.conf +conf_file=/var/lib/geoipupdate/GeoIP.conf database_dir=/usr/share/GeoIP -flags= +log_dir="/var/lib/geoipupdate" +log_file="$log_dir/.healthcheck" +flags="--output" frequency=$((GEOIPUPDATE_FREQUENCY * 60 * 60)) if ! [ -z "$GEOIPUPDATE_CONF_FILE" ]; then @@ -65,12 +67,14 @@ fi if [ "$GEOIPUPDATE_VERBOSE" ]; then - flags="-v" + flags="$flags -v" fi +mkdir -p $log_dir + while true; do echo "# STATE: Running geoipupdate" - /usr/bin/geoipupdate -d "$database_dir" -f "$conf_file" $flags + /usr/bin/geoipupdate -d "$database_dir" -f "$conf_file" $flags 1>$log_file if [ "$frequency" -eq 0 ]; then break fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/docker/healthcheck.sh new/geoipupdate-5.1.1/docker/healthcheck.sh --- old/geoipupdate-5.0.3/docker/healthcheck.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/geoipupdate-5.1.1/docker/healthcheck.sh 2023-05-08 18:16:35.000000000 +0200 @@ -0,0 +1,18 @@ +#!/bin/sh + +set -e + +# 2 minutes are added to the update frequency threshold to make room for slower starts. +cutoff_duration=$(($GEOIPUPDATE_FREQUENCY * 60 * 60 + 120)) +current_time=$(date +%s) +cutoff_date=$(($current_time - $cutoff_duration)) + +log_file="/var/lib/geoipupdate/.healthcheck" +editions=$(cat "$log_file" | jq -r '.[] | select(.checked_at > '$cutoff_date') | .edition_id') +checked_editions=$(echo "$editions" | wc -l) +desired_editions=$(echo "$GEOIPUPDATE_EDITION_IDS" | awk -F' ' '{print NF}') + +if [ "$checked_editions" != "$desired_editions" ]; then + echo "healtcheck editions number $checked_editions is less than the desired editions number $desired_editions" + exit 1 +fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/go.mod new/geoipupdate-5.1.1/go.mod --- old/geoipupdate-5.0.3/go.mod 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/go.mod 2023-05-08 18:16:35.000000000 +0200 @@ -1,14 +1,20 @@ module github.com/maxmind/geoipupdate/v5 -go 1.13 +go 1.19 require ( github.com/gofrs/flock v0.8.1 - github.com/kr/text v0.2.0 // indirect - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.2 - golang.org/x/sync v0.1.0 - golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25 // indirect + golang.org/x/sync v0.2.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/sys v0.8.0 // indirect gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/go.sum new/geoipupdate-5.1.1/go.sum --- old/geoipupdate-5.0.3/go.sum 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/go.sum 2023-05-08 18:16:35.000000000 +0200 @@ -21,10 +21,12 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25 h1:nwzwVf0l2Y/lkov/+IYgMMbFyI+QypZDds9RxlSmsFQ= golang.org/x/sys v0.0.0-20220926163933-8cfa568d3c25/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/pkg/geoipupdate/config.go new/geoipupdate-5.1.1/pkg/geoipupdate/config.go --- old/geoipupdate-5.0.3/pkg/geoipupdate/config.go 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/pkg/geoipupdate/config.go 2023-05-08 18:16:35.000000000 +0200 @@ -46,6 +46,8 @@ URL string // Verbose turns on debug statements. Verbose bool + // Output turns on sending the download/update result to stdout as JSON. + Output bool } // Option is a function type that modifies a configuration object. @@ -86,6 +88,15 @@ return nil } } + +// WithOutput returns an Option that sets the Output +// value of a config. +func WithOutput(val bool) Option { + return func(c *Config) error { + c.Output = val + return nil + } +} // NewConfig parses the configuration file. // flagOptions is provided to provide optional flag overrides to the config diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/pkg/geoipupdate/config_test.go new/geoipupdate-5.1.1/pkg/geoipupdate/config_test.go --- old/geoipupdate-5.0.3/pkg/geoipupdate/config_test.go 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/pkg/geoipupdate/config_test.go 2023-05-08 18:16:35.000000000 +0200 @@ -2,7 +2,6 @@ import ( "fmt" - "io/ioutil" "net/url" "os" "path/filepath" @@ -428,7 +427,7 @@ }, } - tempFh, err := ioutil.TempFile("", "conf-test") + tempFh, err := os.CreateTemp("", "conf-test") require.NoError(t, err) tempName := tempFh.Name() require.NoError(t, tempFh.Close()) @@ -438,7 +437,7 @@ for _, test := range tests { t.Run(test.Description, func(t *testing.T) { - require.NoError(t, ioutil.WriteFile(tempName, []byte(test.Input), 0o600)) + require.NoError(t, os.WriteFile(tempName, []byte(test.Input), 0o600)) config, err := NewConfig(tempName, test.Flags...) if test.Err == "" { assert.NoError(t, err, test.Description) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/pkg/geoipupdate/database/http_reader.go new/geoipupdate-5.1.1/pkg/geoipupdate/database/http_reader.go --- old/geoipupdate-5.0.3/pkg/geoipupdate/database/http_reader.go 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/pkg/geoipupdate/database/http_reader.go 2023-05-08 18:16:35.000000000 +0200 @@ -8,7 +8,6 @@ "errors" "fmt" "io" - "io/ioutil" "log" "net/http" "net/url" @@ -126,11 +125,11 @@ if r.verbose { log.Printf("No new updates available for %s", editionID) } - return &ReadResult{editionID: editionID, oldHash: hash, newHash: hash}, nil + return &ReadResult{EditionID: editionID, OldHash: hash, NewHash: hash}, nil case http.StatusOK: default: //nolint:errcheck // we are already returning an error. - buf, _ := ioutil.ReadAll(io.LimitReader(response.Body, 256)) + buf, _ := io.ReadAll(io.LimitReader(response.Body, 256)) httpErr := internal.HTTPError{ Body: string(buf), StatusCode: response.StatusCode, @@ -159,10 +158,10 @@ return &ReadResult{ reader: gzReader, - editionID: editionID, - oldHash: hash, - newHash: newHash, - modifiedAt: modifiedAt, + EditionID: editionID, + OldHash: hash, + NewHash: newHash, + ModifiedAt: modifiedAt, }, nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/pkg/geoipupdate/database/http_reader_test.go new/geoipupdate-5.1.1/pkg/geoipupdate/database/http_reader_test.go --- old/geoipupdate-5.0.3/pkg/geoipupdate/database/http_reader_test.go 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/pkg/geoipupdate/database/http_reader_test.go 2023-05-08 18:16:35.000000000 +0200 @@ -5,7 +5,6 @@ "compress/gzip" "context" "io" - "io/ioutil" "net/http" "net/http/httptest" "testing" @@ -40,10 +39,10 @@ responseTime: testTime.Format(time.RFC1123), result: &ReadResult{ reader: getReader(t, "database content"), - editionID: "GeoIP2-City", - oldHash: "fbe1786bfd80e1db9dc42ddaff868f38", - newHash: "cfa36ddc8279b5483a5aa25e9a6151f4", - modifiedAt: testTime, + EditionID: "GeoIP2-City", + OldHash: "fbe1786bfd80e1db9dc42ddaff868f38", + NewHash: "cfa36ddc8279b5483a5aa25e9a6151f4", + ModifiedAt: testTime, }, }, { description: "no new update", @@ -56,10 +55,10 @@ responseTime: "", result: &ReadResult{ reader: nil, - editionID: "GeoIP2-City", - oldHash: "fbe1786bfd80e1db9dc42ddaff868f38", - newHash: "fbe1786bfd80e1db9dc42ddaff868f38", - modifiedAt: time.Time{}, + EditionID: "GeoIP2-City", + OldHash: "fbe1786bfd80e1db9dc42ddaff868f38", + NewHash: "fbe1786bfd80e1db9dc42ddaff868f38", + ModifiedAt: time.Time{}, }, }, { description: "bad request", @@ -129,17 +128,17 @@ result, err := reader.Read(context.Background(), test.requestEdition, test.requestHash) test.checkErr(t, err) if err == nil { - require.Equal(t, result.editionID, test.result.editionID) - require.Equal(t, result.oldHash, test.result.oldHash) - require.Equal(t, result.newHash, test.result.newHash) - require.Equal(t, result.modifiedAt, test.result.modifiedAt) + require.Equal(t, result.EditionID, test.result.EditionID) + require.Equal(t, result.OldHash, test.result.OldHash) + require.Equal(t, result.NewHash, test.result.NewHash) + require.Equal(t, result.ModifiedAt, test.result.ModifiedAt) if test.result.reader != nil && result.reader != nil { defer result.reader.Close() defer test.result.reader.Close() - resultDatabase, err := ioutil.ReadAll(test.result.reader) + resultDatabase, err := io.ReadAll(test.result.reader) require.NoError(t, err) - expectedDatabase, err := ioutil.ReadAll(result.reader) + expectedDatabase, err := io.ReadAll(result.reader) require.NoError(t, err) require.Equal(t, resultDatabase, expectedDatabase) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/pkg/geoipupdate/database/local_file_writer.go new/geoipupdate-5.1.1/pkg/geoipupdate/database/local_file_writer.go --- old/geoipupdate-5.0.3/pkg/geoipupdate/database/local_file_writer.go 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/pkg/geoipupdate/database/local_file_writer.go 2023-05-08 18:16:35.000000000 +0200 @@ -47,25 +47,25 @@ // Write writes the result struct returned by a Reader to a database file. func (w *LocalFileWriter) Write(result *ReadResult) error { // exit early if we've got the latest database version. - if strings.EqualFold(result.oldHash, result.newHash) { + if strings.EqualFold(result.OldHash, result.NewHash) { if w.verbose { - log.Printf("Database %s up to date", result.editionID) + log.Printf("Database %s up to date", result.EditionID) } return nil } defer func() { if err := result.reader.Close(); err != nil { - log.Printf("error closing reader for %s: %+v", result.editionID, err) + log.Printf("error closing reader for %s: %+v", result.EditionID, err) } }() - databaseFilePath := w.getFilePath(result.editionID) + databaseFilePath := w.getFilePath(result.EditionID) // write the Reader's result into a temporary file. fw, err := newFileWriter(databaseFilePath + tempExtension) if err != nil { - return fmt.Errorf("error setting up database writer for %s: %w", result.editionID, err) + return fmt.Errorf("error setting up database writer for %s: %w", result.EditionID, err) } defer func() { if err := fw.close(); err != nil { @@ -74,12 +74,12 @@ }() if err := fw.write(result.reader); err != nil { - return fmt.Errorf("error writing to the temp file for %s: %w", result.editionID, err) + return fmt.Errorf("error writing to the temp file for %s: %w", result.EditionID, err) } // make sure the hash of the temp file matches the expected hash. - if err := fw.validateHash(result.newHash); err != nil { - return fmt.Errorf("error validating hash for %s: %w", result.editionID, err) + if err := fw.validateHash(result.NewHash); err != nil { + return fmt.Errorf("error validating hash for %s: %w", result.EditionID, err) } // move the temoporary database file into it's final location and @@ -95,13 +95,13 @@ // check if we need to set the file's modified at time if w.preserveFileTime { - if err := setModifiedAtTime(databaseFilePath, result.modifiedAt); err != nil { + if err := setModifiedAtTime(databaseFilePath, result.ModifiedAt); err != nil { return err } } if w.verbose { - log.Printf("Database %s successfully updated: %+v", result.editionID, result.newHash) + log.Printf("Database %s successfully updated: %+v", result.EditionID, result.NewHash) } return nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/pkg/geoipupdate/database/local_file_writer_test.go new/geoipupdate-5.1.1/pkg/geoipupdate/database/local_file_writer_test.go --- old/geoipupdate-5.0.3/pkg/geoipupdate/database/local_file_writer_test.go 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/pkg/geoipupdate/database/local_file_writer_test.go 2023-05-08 18:16:35.000000000 +0200 @@ -1,7 +1,6 @@ package database import ( - "io/ioutil" "os" "testing" "time" @@ -29,10 +28,10 @@ checkTime: require.Equal, result: &ReadResult{ reader: getReader(t, "database content"), - editionID: "GeoIP2-City", - oldHash: "", - newHash: "cfa36ddc8279b5483a5aa25e9a6151f4", - modifiedAt: testTime, + EditionID: "GeoIP2-City", + OldHash: "", + NewHash: "cfa36ddc8279b5483a5aa25e9a6151f4", + ModifiedAt: testTime, }, }, { description: "hash does not match", @@ -41,10 +40,10 @@ checkTime: require.Equal, result: &ReadResult{ reader: getReader(t, "database content"), - editionID: "GeoIP2-City", - oldHash: "", - newHash: "badhash", - modifiedAt: testTime, + EditionID: "GeoIP2-City", + OldHash: "", + NewHash: "badhash", + ModifiedAt: testTime, }, }, { description: "hash case does not matter", @@ -53,10 +52,10 @@ checkTime: require.Equal, result: &ReadResult{ reader: getReader(t, "database content"), - editionID: "GeoIP2-City", - oldHash: "", - newHash: "cfa36ddc8279b5483a5aa25e9a6151f4", - modifiedAt: testTime, + EditionID: "GeoIP2-City", + OldHash: "", + NewHash: "cfa36ddc8279b5483a5aa25e9a6151f4", + ModifiedAt: testTime, }, }, { description: "do not preserve file modification time", @@ -65,24 +64,18 @@ checkTime: require.NotEqual, result: &ReadResult{ reader: getReader(t, "database content"), - editionID: "GeoIP2-City", - oldHash: "", - newHash: "CFA36DDC8279B5483A5AA25E9A6151F4", - modifiedAt: testTime, + EditionID: "GeoIP2-City", + OldHash: "", + NewHash: "CFA36DDC8279B5483A5AA25E9A6151F4", + ModifiedAt: testTime, }, }, } for _, test := range tests { t.Run(test.description, func(t *testing.T) { - tempDir, err := ioutil.TempDir("", "gutest-") - require.NoError(t, err) - defer func() { - err := os.RemoveAll(tempDir) - require.NoError(t, err) - - test.result.reader.Close() - }() + tempDir := t.TempDir() + defer test.result.reader.Close() fw, err := NewLocalFileWriter(tempDir, test.preserveFileTime, false) require.NoError(t, err) @@ -90,7 +83,7 @@ err = fw.Write(test.result) test.checkErr(t, err) if err == nil { - database, err := os.Stat(fw.getFilePath(test.result.editionID)) + database, err := os.Stat(fw.getFilePath(test.result.EditionID)) require.NoError(t, err) test.checkTime(t, database.ModTime().UTC(), testTime) @@ -103,20 +96,15 @@ func TestLocalFileWriterGetHash(t *testing.T) { result := &ReadResult{ reader: getReader(t, "database content"), - editionID: "GeoIP2-City", - oldHash: "", - newHash: "cfa36ddc8279b5483a5aa25e9a6151f4", - modifiedAt: time.Time{}, + EditionID: "GeoIP2-City", + OldHash: "", + NewHash: "cfa36ddc8279b5483a5aa25e9a6151f4", + ModifiedAt: time.Time{}, } - tempDir, err := ioutil.TempDir("", "gutest-") - require.NoError(t, err) - defer func() { - err := os.RemoveAll(tempDir) - require.NoError(t, err) + tempDir := t.TempDir() - result.reader.Close() - }() + defer result.reader.Close() fw, err := NewLocalFileWriter(tempDir, false, false) require.NoError(t, err) @@ -125,9 +113,9 @@ require.NoError(t, err) // returns the correct hash for an existing database. - hash, err := fw.GetHash(result.editionID) + hash, err := fw.GetHash(result.EditionID) require.NoError(t, err) - require.Equal(t, hash, result.newHash) + require.Equal(t, hash, result.NewHash) // returns a zero hash for a non existing edition. hash, err = fw.GetHash("NewEdition") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/pkg/geoipupdate/database/reader.go new/geoipupdate-5.1.1/pkg/geoipupdate/database/reader.go --- old/geoipupdate-5.0.3/pkg/geoipupdate/database/reader.go 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/pkg/geoipupdate/database/reader.go 2023-05-08 18:16:35.000000000 +0200 @@ -2,6 +2,8 @@ import ( "context" + "encoding/json" + "fmt" "io" "time" ) @@ -15,8 +17,60 @@ // ReadResult is the struct returned by a Reader's Get method. type ReadResult struct { reader io.ReadCloser - editionID string - oldHash string - newHash string - modifiedAt time.Time + EditionID string `json:"edition_id"` + OldHash string `json:"old_hash"` + NewHash string `json:"new_hash"` + ModifiedAt time.Time `json:"modified_at"` + CheckedAt time.Time `json:"checked_at"` +} + +// MarshalJSON is a custom json marshaler that strips out zero time fields. +func (r ReadResult) MarshalJSON() ([]byte, error) { + type partialResult ReadResult + s := &struct { + partialResult + ModifiedAt int64 `json:"modified_at,omitempty"` + CheckedAt int64 `json:"checked_at,omitempty"` + }{ + partialResult: partialResult(r), + ModifiedAt: 0, + CheckedAt: 0, + } + + if !r.ModifiedAt.IsZero() { + s.ModifiedAt = r.ModifiedAt.Unix() + } + + if !r.CheckedAt.IsZero() { + s.CheckedAt = r.CheckedAt.Unix() + } + + res, err := json.Marshal(s) + if err != nil { + return nil, fmt.Errorf("error marshaling ReadResult: %w", err) + } + return res, nil +} + +// UnmarshalJSON is a custom json unmarshaler that converts timestamps to go +// time fields. +func (r *ReadResult) UnmarshalJSON(data []byte) error { + type partialResult ReadResult + s := &struct { + partialResult + ModifiedAt int64 `json:"modified_at,omitempty"` + CheckedAt int64 `json:"checked_at,omitempty"` + }{} + + err := json.Unmarshal(data, &s) + if err != nil { + return fmt.Errorf("error unmarshaling json into ReadResult: %w", err) + } + + result := ReadResult(s.partialResult) + result.ModifiedAt = time.Unix(s.ModifiedAt, 0).In(time.UTC) + result.CheckedAt = time.Unix(s.CheckedAt, 0).In(time.UTC) + *r = result + + return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/pkg/geoipupdate/geoip_updater.go new/geoipupdate-5.1.1/pkg/geoipupdate/geoip_updater.go --- old/geoipupdate-5.0.3/pkg/geoipupdate/geoip_updater.go 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/pkg/geoipupdate/geoip_updater.go 2023-05-08 18:16:35.000000000 +0200 @@ -4,8 +4,12 @@ import ( "context" + "encoding/json" "fmt" "log" + "os" + "sync" + "time" "github.com/maxmind/geoipupdate/v5/pkg/geoipupdate/database" "github.com/maxmind/geoipupdate/v5/pkg/geoipupdate/internal" @@ -14,12 +18,39 @@ // Client uses config data to initiate a download or update // process for GeoIP databases. type Client struct { - config *Config + config *Config + getReader func() (database.Reader, error) + getWriter func() (database.Writer, error) + output *log.Logger } // NewClient initialized a new Client struct. func NewClient(config *Config) *Client { - return &Client{config: config} + getReader := func() (database.Reader, error) { + return database.NewHTTPReader( + config.Proxy, + config.URL, + config.AccountID, + config.LicenseKey, + config.RetryFor, + config.Verbose, + ), nil + } + + getWriter := func() (database.Writer, error) { + return database.NewLocalFileWriter( + config.DatabaseDirectory, + config.PreserveFileTimes, + config.Verbose, + ) + } + + return &Client{ + config: config, + getReader: getReader, + getWriter: getWriter, + output: log.New(os.Stdout, "", 0), + } } // Run starts the download or update process. @@ -39,24 +70,18 @@ jobProcessor := internal.NewJobProcessor(ctx, c.config.Parallelism) - reader := database.NewHTTPReader( - c.config.Proxy, - c.config.URL, - c.config.AccountID, - c.config.LicenseKey, - c.config.RetryFor, - c.config.Verbose, - ) - - writer, err := database.NewLocalFileWriter( - c.config.DatabaseDirectory, - c.config.PreserveFileTimes, - c.config.Verbose, - ) + reader, err := c.getReader() + if err != nil { + return fmt.Errorf("error initializing database reader: %w", err) + } + + writer, err := c.getWriter() if err != nil { return fmt.Errorf("error initializing database writer: %w", err) } + var editions []database.ReadResult + var mu sync.Mutex for _, editionID := range c.config.EditionIDs { editionID := editionID processFunc := func(ctx context.Context) error { @@ -65,12 +90,21 @@ return err } - result, err := reader.Read(ctx, editionID, editionHash) + edition, err := reader.Read(ctx, editionID, editionHash) if err != nil { return err } - return writer.Write(result) + if err := writer.Write(edition); err != nil { + return err + } + + edition.CheckedAt = time.Now().In(time.UTC) + + mu.Lock() + editions = append(editions, *edition) + mu.Unlock() + return nil } jobProcessor.Add(processFunc) @@ -82,5 +116,13 @@ return fmt.Errorf("error running the job processor: %w", err) } + if c.config.Output { + result, err := json.Marshal(editions) + if err != nil { + return fmt.Errorf("error marshaling result log: %w", err) + } + c.output.Print(string(result)) + } + return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/pkg/geoipupdate/geoip_updater_test.go new/geoipupdate-5.1.1/pkg/geoipupdate/geoip_updater_test.go --- old/geoipupdate-5.0.3/pkg/geoipupdate/geoip_updater_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/geoipupdate-5.1.1/pkg/geoipupdate/geoip_updater_test.go 2023-05-08 18:16:35.000000000 +0200 @@ -0,0 +1,103 @@ +package geoipupdate + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "log" + "path/filepath" + "testing" + "time" + + "github.com/maxmind/geoipupdate/v5/pkg/geoipupdate/database" + "github.com/stretchr/testify/require" +) + +// TestClientOutput makes sure that the client outputs the result of it's +// operation to stdout in json format. +func TestClientOutput(t *testing.T) { + now := time.Now().Truncate(time.Second).In(time.UTC) + testTime := time.Date(2023, 4, 27, 12, 4, 48, 0, time.UTC) + databases := []database.ReadResult{ + { + EditionID: "GeoLite2-City", + OldHash: "A", + NewHash: "B", + ModifiedAt: testTime, + }, { + EditionID: "GeoIP2-Country", + OldHash: "C", + NewHash: "D", + ModifiedAt: testTime, + }, + } + + tempDir := t.TempDir() + + config := &Config{ + EditionIDs: []string{"GeoLite2-City", "GeoLite2-Country"}, + LockFile: filepath.Join(tempDir, ".geoipupdate.lock"), + Output: true, + Parallelism: 1, + } + + // capture the output of the `output` logger. + logOutput := &bytes.Buffer{} + + // create a fake client with a mocked database reader and writer. + c := &Client{ + config: config, + getReader: func() (database.Reader, error) { + return &mockReader{i: 0, result: databases}, nil + }, + getWriter: func() (database.Writer, error) { + return &mockWriter{}, nil + }, + output: log.New(logOutput, "", 0), + } + + // run the client + err := c.Run(context.Background()) + require.NoError(t, err) + + // make sure the expected output matches the input. + var outputDatabases []database.ReadResult + err = json.Unmarshal(logOutput.Bytes(), &outputDatabases) + require.NoError(t, err) + require.Equal(t, len(outputDatabases), len(databases)) + + for i := 0; i < len(databases); i++ { + require.Equal(t, databases[i].EditionID, outputDatabases[i].EditionID) + require.Equal(t, databases[i].OldHash, outputDatabases[i].OldHash) + require.Equal(t, databases[i].NewHash, outputDatabases[i].NewHash) + require.Equal(t, databases[i].ModifiedAt, outputDatabases[i].ModifiedAt) + // comparing time wasn't supported with require in older go versions. + if !afterOrEqual(outputDatabases[i].CheckedAt, now) { + t.Errorf("database %s was not updated", outputDatabases[i].EditionID) + } + } +} + +type mockReader struct { + i int + result []database.ReadResult +} + +func (mr *mockReader) Read(_ context.Context, _, _ string) (*database.ReadResult, error) { + if mr.i >= len(mr.result) { + return nil, errors.New("out of bounds") + } + res := mr.result[mr.i] + mr.i++ + return &res, nil +} + +type mockWriter struct{} + +func (w *mockWriter) Write(_ *database.ReadResult) error { return nil } +func (w mockWriter) GetHash(_ string) (string, error) { return "", nil } + +func afterOrEqual(t1, t2 time.Time) bool { + return t1.After(t2) || t1.Equal(t2) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/pkg/geoipupdate/internal/file_lock_test.go new/geoipupdate-5.1.1/pkg/geoipupdate/internal/file_lock_test.go --- old/geoipupdate-5.0.3/pkg/geoipupdate/internal/file_lock_test.go 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/pkg/geoipupdate/internal/file_lock_test.go 2023-05-08 18:16:35.000000000 +0200 @@ -1,8 +1,6 @@ package internal import ( - "io/ioutil" - "os" "path/filepath" "testing" @@ -12,12 +10,7 @@ // TestAcquireFileLock tests that a lock can be acquired multile times // within a same process. func TestAcquireFileLock(t *testing.T) { - tempDir, err := ioutil.TempDir("", "gutest-") - require.NoError(t, err) - defer func() { - err = os.RemoveAll(tempDir) - require.NoError(t, err) - }() + tempDir := t.TempDir() fl, err := NewFileLock(filepath.Join(tempDir, ".geoipupdate.lock"), false) require.NoError(t, err) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/geoipupdate-5.0.3/pkg/geoipupdate/vars/version.go new/geoipupdate-5.1.1/pkg/geoipupdate/vars/version.go --- old/geoipupdate-5.0.3/pkg/geoipupdate/vars/version.go 2023-04-13 20:43:38.000000000 +0200 +++ new/geoipupdate-5.1.1/pkg/geoipupdate/vars/version.go 2023-05-08 18:16:35.000000000 +0200 @@ -2,4 +2,4 @@ package vars // Version defines current geoipupdate version. -const Version = "5.0.2" +const Version = "5.1.1" ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/geoipupdate/vendor.tar.gz /work/SRC/openSUSE:Factory/.geoipupdate.new.15902/vendor.tar.gz differ: char 1, line 1