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

Reply via email to