From a49fd77df4258af2a2594edef3488c216b11b158 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 16:57:32 +0000 Subject: [PATCH 1/9] Initial plan From 761bd3878044bf3b388cec653148cfc556820cee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 17:09:38 +0000 Subject: [PATCH 2/9] Replace BadgerDB with JSON file for persistent storage - Remove BadgerDB dependency from go.mod - Implement JSON-based storage for stats (loadFromJSON, syncToJSON) - Update main.go to use JSON file instead of BadgerDB - Update README to remove BadgerDB references and 64-bit requirement - Simplify code by removing unnecessary database complexity Co-authored-by: unknwon <2946214+unknwon@users.noreply.github.com> --- README.md | 6 ++- go.mod | 1 - go.sum | 49 -------------------- main.go | 24 ++++------ stats.go | 130 +++++++++++++++++++++++++----------------------------- 5 files changed, 72 insertions(+), 138 deletions(-) diff --git a/README.md b/README.md index f1a6398..6dffb02 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ HTTP server for canonical "go get" import path. It supports all versions of `go Install from source or download binaries on [GitHub Releases](https://github.com/unknwon/go-import-server/releases). -The minimum requirement of Go is **1.16**, and 64-bit system is required because of [a bug in BadgerDB](https://github.com/dgraph-io/badger/issues/953). +The minimum requirement of Go is **1.16**. ```sh $ go get unknwon.dev/go-import-server @@ -27,6 +27,8 @@ repo = "https://github.com/unknwon/go-import-server" branch = "main" ``` +Note: The `db_path` now points to a JSON file (not a directory) that stores statistics. + Assuming `$GOPATH/bin` has been added to your `$PATH` environment variable. ```sh @@ -70,7 +72,7 @@ auth_username = "superuser" auth_password = "supersecure" ``` -The [BadgerDB](https://github.com/dgraph-io/badger) is used to store total page views and number of `go get`s. +A JSON file is used to store total page views and number of `go get`s. Here is an example dump: diff --git a/go.mod b/go.mod index 611c1f8..ced6b68 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.16 require ( github.com/BurntSushi/toml v0.3.1 - github.com/dgraph-io/badger/v2 v2.2007.4 github.com/flamego/auth v0.0.0-20210831041357-158bdcabc1f1 github.com/flamego/flamego v1.0.1 github.com/flamego/template v1.0.0 diff --git a/go.sum b/go.sum index 8daf657..a9157de 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/participle/v2 v2.0.0-alpha5/go.mod h1:Z1zPLDbcGsVsBYsThKXY00i84575bN/nMczzIrU4rWU= github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= github.com/alecthomas/participle/v2 v2.0.0-alpha7/go.mod h1:NumScqsC42o9x+dGj8/YqsIfhrIQjFEOFovxotbBirA= @@ -11,30 +9,15 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA= github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= -github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= @@ -47,7 +30,6 @@ github.com/flamego/flamego v1.0.1 h1:rHcvSFcFHfoAEZUQoqXVyVig/xbsjF0/hm7Fo4oZCBo github.com/flamego/flamego v1.0.1/go.mod h1:sMqWT2ONQkZsCHte/k8hYmfnbbLgnfv7lL+VJpfv+EU= github.com/flamego/template v1.0.0 h1:geUpBq+j0L2Wp+AuAQ7QxpZedRwG/EeYFZJ4llkPmA4= github.com/flamego/template v1.0.0/go.mod h1:ZS9Li2amrupO/3sXS1LRNrAqAcxJI8lG1hhlDBZ4R2s= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -58,24 +40,14 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU= -github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= @@ -87,14 +59,11 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -116,18 +85,8 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -135,24 +94,17 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -162,7 +114,6 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= diff --git a/main.go b/main.go index b7afb59..6fbdf92 100644 --- a/main.go +++ b/main.go @@ -9,7 +9,6 @@ import ( "os/signal" "github.com/BurntSushi/toml" - "github.com/dgraph-io/badger/v2" "github.com/flamego/auth" "github.com/flamego/flamego" "github.com/flamego/template" @@ -35,11 +34,10 @@ func main() { log.Fatal("Failed to load config: %v", err) } - db, stats, err := getDBWithStats(config.DBPath) + stats, err := getStatsFromJSON(config.DBPath) if err != nil { - log.Fatal("Failed to get database with stats: %v", err) + log.Fatal("Failed to load stats: %v", err) } - defer func() { _ = db.Close() }() fs, err := template.EmbedFS(templates, "templates", []string{".tmpl"}) if err != nil { @@ -102,7 +100,7 @@ func main() { setupPrometheusMetrics(stats) done := make(chan struct{}) - go stats.start(db, done) + go stats.start(config.DBPath, done) s := newServer(config.Addr, f) log.Info("Listening on http://%s...", s.Addr) @@ -142,23 +140,17 @@ func loadConfig(path string) (*config, error) { return &c, nil } -func getDBWithStats(path string) (*badger.DB, *stats, error) { - opts := badger.DefaultOptions(path) - db, err := badger.Open(opts) - if err != nil { - return nil, nil, fmt.Errorf("open: %v", err) - } - - // Retrieve current stats in database. +func getStatsFromJSON(path string) (*stats, error) { + // Initialize stats s := &stats{ pkgsView: make(map[string]*int64), pkgsGet: make(map[string]*int64), } - if err = s.loadFromDB(db); err != nil { - return nil, nil, fmt.Errorf("load stats from DB: %v", err) + if err := s.loadFromJSON(path); err != nil { + return nil, fmt.Errorf("load stats from JSON: %v", err) } - return db, s, nil + return s, nil } func newServer(addr string, f *flamego.Flame) *http.Server { diff --git a/stats.go b/stats.go index 30a2590..0303d7c 100644 --- a/stats.go +++ b/stats.go @@ -1,12 +1,11 @@ package main import ( - "strconv" - "strings" + "encoding/json" + "os" "sync/atomic" "time" - "github.com/dgraph-io/badger/v2" log "unknwon.dev/clog/v2" ) @@ -49,51 +48,48 @@ func (s *stats) PkgGetIncr(improtPath string, n int64) { atomic.StoreInt64(&s.lastUpdated, time.Now().Unix()) } +// statsData is the structure for JSON serialization +type statsData struct { + TotalView int64 `json:"total_view"` + TotalGet int64 `json:"total_get"` + PkgsView map[string]int64 `json:"pkgs_view"` + PkgsGet map[string]int64 `json:"pkgs_get"` +} + // NOTE: atomic operation is not needed in this method since it is currently only // being called at init time. -func (s *stats) loadFromDB(db *badger.DB) error { - return db.View(func(tx *badger.Txn) error { - iter := tx.NewIterator(badger.DefaultIteratorOptions) - defer iter.Close() - - for iter.Rewind(); iter.Valid(); iter.Next() { - item := iter.Item() - k := item.Key() - err := item.Value(func(v []byte) (err error) { - ks := string(k) - if ks == "view_total" { - s.totalView, _ = strconv.ParseInt(string(v), 10, 64) - return nil - } else if ks == "get_total" { - s.totalGet, _ = strconv.ParseInt(string(v), 10, 64) - return nil - } - - if strings.HasPrefix(ks, "view_") { - importPath := strings.TrimPrefix(ks, "view_") - pkgView, _ := strconv.ParseInt(string(v), 10, 64) - s.pkgsView[importPath] = &pkgView - return nil - } - - if strings.HasPrefix(ks, "get_") { - importPath := strings.TrimPrefix(ks, "get_") - pkgGet, _ := strconv.ParseInt(string(v), 10, 64) - s.pkgsGet[importPath] = &pkgGet - return nil - } - - return nil - }) - if err != nil { - return err - } +func (s *stats) loadFromJSON(path string) error { + data, err := os.ReadFile(path) + if err != nil { + if os.IsNotExist(err) { + // File doesn't exist yet, which is fine + return nil } - return nil - }) + return err + } + + var sd statsData + if err := json.Unmarshal(data, &sd); err != nil { + return err + } + + s.totalView = sd.TotalView + s.totalGet = sd.TotalGet + + for importPath, view := range sd.PkgsView { + v := view + s.pkgsView[importPath] = &v + } + + for importPath, get := range sd.PkgsGet { + g := get + s.pkgsGet[importPath] = &g + } + + return nil } -func (s *stats) start(db *badger.DB, done chan struct{}) { +func (s *stats) start(path string, done chan struct{}) { defer func() { log.Info("Exiting stats syncing goroutine...") done <- struct{}{} @@ -103,48 +99,42 @@ func (s *stats) start(db *badger.DB, done chan struct{}) { for { select { case <-t.C: - s.syncToDB(db) + s.syncToJSON(path) case <-done: - s.syncToDB(db) + s.syncToJSON(path) return } } } -func (s *stats) syncToDB(db *badger.DB) { +func (s *stats) syncToJSON(path string) { lastSynced := atomic.LoadInt64(&s.lastSynced) lastUpdated := atomic.LoadInt64(&s.lastUpdated) if lastSynced == lastUpdated { - log.Trace("stats.syncToDB: nothing changed, DB is up-to-date") + log.Trace("stats.syncToJSON: nothing changed, file is up-to-date") return } - err := db.Update(func(tx *badger.Txn) error { - err := tx.Set([]byte("view_total"), []byte(strconv.FormatInt(s.TotalView(), 10))) - if err != nil { - return err - } - - err = tx.Set([]byte("get_total"), []byte(strconv.FormatInt(s.TotalGet(), 10))) - if err != nil { - return err - } + sd := statsData{ + TotalView: s.TotalView(), + TotalGet: s.TotalGet(), + PkgsView: make(map[string]int64), + PkgsGet: make(map[string]int64), + } - for p := range s.pkgsView { - err = tx.Set([]byte("view_"+p), []byte(strconv.FormatInt(s.PkgView(p), 10))) - if err != nil { - return err - } + for p := range s.pkgsView { + sd.PkgsView[p] = s.PkgView(p) + sd.PkgsGet[p] = s.PkgGet(p) + } - err = tx.Set([]byte("get_"+p), []byte(strconv.FormatInt(s.PkgGet(p), 10))) - if err != nil { - return err - } - } - return nil - }) + data, err := json.MarshalIndent(sd, "", " ") if err != nil { - log.Error("Failed to update DB: %v", err) + log.Error("Failed to marshal stats: %v", err) + return + } + + if err := os.WriteFile(path, data, 0644); err != nil { + log.Error("Failed to write stats file: %v", err) return } From b0ca3c997d55c982eab3dbdb3b43f46b1349e2ee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 17:13:44 +0000 Subject: [PATCH 3/9] Fix: Ensure both pkgsView and pkgsGet are fully synced to JSON Co-authored-by: unknwon <2946214+unknwon@users.noreply.github.com> --- stats.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stats.go b/stats.go index 0303d7c..425e112 100644 --- a/stats.go +++ b/stats.go @@ -124,6 +124,9 @@ func (s *stats) syncToJSON(path string) { for p := range s.pkgsView { sd.PkgsView[p] = s.PkgView(p) + } + + for p := range s.pkgsGet { sd.PkgsGet[p] = s.PkgGet(p) } From 24aa24062bcf19b9542f9bfa17cb0e0606d5c622 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 17:44:24 +0000 Subject: [PATCH 4/9] Update to Go 1.25 and add CI workflow - Update go.mod to use Go 1.25.0 - Add .github/workflows/go.yml for CI (lint and test jobs) - Add .golangci.yml for linter configuration - CI ensures Go code compiles on ubuntu and macos Co-authored-by: unknwon <2946214+unknwon@users.noreply.github.com> --- .github/workflows/go.yml | 62 ++++++++++++++++++++++++++++++++++++++++ .golangci.yml | 36 +++++++++++++++++++++++ go.mod | 18 +++++++++++- 3 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/go.yml create mode 100644 .golangci.yml diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 0000000..97a4adf --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,62 @@ +name: Go +on: + push: + branches: [ main ] + paths: + - '**.go' + - 'go.mod' + - '.golangci.yml' + - '.github/workflows/go.yml' + pull_request: + paths: + - '**.go' + - 'go.mod' + - '.golangci.yml' + - '.github/workflows/go.yml' +env: + GOPROXY: "https://proxy.golang.org" + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: 1.25.x + - name: Check Go module tidiness + shell: bash + run: | + go mod tidy + STATUS=$(git status --porcelain) + if [ ! -z "$STATUS" ]; then + echo "Unstaged files:" + echo $STATUS + echo "Run 'go mod tidy' commit them" + exit 1 + fi + - name: Run golangci-lint + uses: golangci/golangci-lint-action@v7 + with: + version: latest + args: --timeout=30m + + test: + name: Test + strategy: + matrix: + go-version: [ 1.25.x ] + platform: [ ubuntu-latest, macos-latest ] + runs-on: ${{ matrix.platform }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go-version }} + - name: Run tests with coverage + run: go test -shuffle=on -v -race -coverprofile=coverage -covermode=atomic ./... diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..fabbdb6 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,36 @@ +version: "2" +linters: + enable: + - nakedret + - rowserrcheck + - unconvert + - unparam + settings: + govet: + disable: + # printf: non-constant format string in call to fmt.Errorf (govet) + # showing up since golangci-lint version 1.60.1 + - printf + nakedret: + max-func-lines: 0 # Disallow any unnamed return statement + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/go.mod b/go.mod index ced6b68..f3c0a69 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module unknwon.dev/go-import-server -go 1.16 +go 1.25.0 require ( github.com/BurntSushi/toml v0.3.1 @@ -10,3 +10,19 @@ require ( github.com/prometheus/client_golang v1.2.1 unknwon.dev/clog/v2 v2.0.0 ) + +require ( + github.com/alecthomas/participle/v2 v2.0.0-alpha7 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.0 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/golang/protobuf v1.3.2 // indirect + github.com/mattn/go-colorable v0.1.9 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect + github.com/prometheus/common v0.7.0 // indirect + github.com/prometheus/procfs v0.0.5 // indirect + golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect +) From b6b8093263c7ca2f1a8c0a41d0f51918c445e876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=B4=8A=E1=B4=8F=E1=B4=87=20=E1=B4=84=CA=9C=E1=B4=87?= =?UTF-8?q?=C9=B4?= Date: Sun, 23 Nov 2025 12:52:23 -0500 Subject: [PATCH 5/9] Update Go version requirement and config paths Updated minimum Go version and configuration details. --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6dffb02..181fb60 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ HTTP server for canonical "go get" import path. It supports all versions of `go Install from source or download binaries on [GitHub Releases](https://github.com/unknwon/go-import-server/releases). -The minimum requirement of Go is **1.16**. +The minimum requirement of Go is **1.25**. ```sh -$ go get unknwon.dev/go-import-server +$ go install unknwon.dev/go-import-server@latest ``` ### Configuration @@ -18,7 +18,7 @@ Example for this tool itself (save as `app.toml`): ```toml addr = "127.0.0.1:4333" -db_path = "app.db" +stats_path = "stats.json" [[packages]] import_path = "unknwon.dev/go-import-server" @@ -27,7 +27,8 @@ repo = "https://github.com/unknwon/go-import-server" branch = "main" ``` -Note: The `db_path` now points to a JSON file (not a directory) that stores statistics. +>[!warning] +> Starting version 0.5.0, the `db_path` is removed and statistics are stored in a JSON file. Historical data will not be migrated automatically. Assuming `$GOPATH/bin` has been added to your `$PATH` environment variable. From 47a7e3bb121cda77ff274fedb794fae5e4224ff9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 17:57:46 +0000 Subject: [PATCH 6/9] Rename db_path to stats_path and remove LSIF workflow - Change config field from DBPath to StatsPath (toml: db_path -> stats_path) - Update all references in main.go to use StatsPath - Remove .github/workflows/lsif.yml workflow file - GitHub Actions in go.yml already use latest versions (v4, v5, v7) Co-authored-by: unknwon <2946214+unknwon@users.noreply.github.com> --- .github/workflows/lsif.yml | 23 ----------------------- main.go | 10 +++++----- 2 files changed, 5 insertions(+), 28 deletions(-) delete mode 100644 .github/workflows/lsif.yml diff --git a/.github/workflows/lsif.yml b/.github/workflows/lsif.yml deleted file mode 100644 index 49ecaa7..0000000 --- a/.github/workflows/lsif.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: LSIF -on: - push: - paths: - - '**.go' - - 'go.mod' - - '.github/workflows/lsif.yml' -env: - GOPROXY: "https://proxy.golang.org" - -jobs: - lsif-go: - if: github.repository == 'unknwon/go-import-server' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Generate LSIF data - uses: sourcegraph/lsif-go-action@master - - name: Upload LSIF data to sourcegraph.com - continue-on-error: true - uses: docker://sourcegraph/src-cli:latest - with: - args: lsif upload -github-token=${{ secrets.GITHUB_TOKEN }} diff --git a/main.go b/main.go index 6fbdf92..dde49a7 100644 --- a/main.go +++ b/main.go @@ -34,7 +34,7 @@ func main() { log.Fatal("Failed to load config: %v", err) } - stats, err := getStatsFromJSON(config.DBPath) + stats, err := getStatsFromJSON(config.StatsPath) if err != nil { log.Fatal("Failed to load stats: %v", err) } @@ -100,7 +100,7 @@ func main() { setupPrometheusMetrics(stats) done := make(chan struct{}) - go stats.start(config.DBPath, done) + go stats.start(config.StatsPath, done) s := newServer(config.Addr, f) log.Info("Listening on http://%s...", s.Addr) @@ -117,9 +117,9 @@ func main() { } type config struct { - Addr string - DBPath string `toml:"db_path"` - Packages []struct { + Addr string + StatsPath string `toml:"stats_path"` + Packages []struct { ImportPath string `toml:"import_path"` Subpath string Repo string From 39724df85e98238cc565e920adec602b6aff656c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=B4=8A=E1=B4=8F=E1=B4=87=20=E1=B4=84=CA=9C=E1=B4=87?= =?UTF-8?q?=C9=B4?= Date: Sun, 23 Nov 2025 13:02:32 -0500 Subject: [PATCH 7/9] Upgrade GitHub Actions and simplify test matrix Updated GitHub Actions to use the latest versions of checkout and setup-go actions. Removed macOS from the testing matrix. --- .github/workflows/go.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 97a4adf..be637d3 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -22,9 +22,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version: 1.25.x - name: Check Go module tidiness @@ -49,14 +49,14 @@ jobs: strategy: matrix: go-version: [ 1.25.x ] - platform: [ ubuntu-latest, macos-latest ] + platform: [ ubuntu-latest ] runs-on: ${{ matrix.platform }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version: ${{ matrix.go-version }} - name: Run tests with coverage - run: go test -shuffle=on -v -race -coverprofile=coverage -covermode=atomic ./... + run: go test -shuffle=on -v -race ./... From 368d9ffdc4ee9eaf616c1d7d8258692a7728e0b3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 18:08:22 +0000 Subject: [PATCH 8/9] Fix sigchanyzer linter error: use buffered channel for signal.Notify Make the os.Signal channel buffered with capacity 1 to prevent missing signals, as recommended by Go's signal.Notify documentation and detected by the sigchanyzer linter. Co-authored-by: unknwon <2946214+unknwon@users.noreply.github.com> --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index dde49a7..2986c52 100644 --- a/main.go +++ b/main.go @@ -159,7 +159,7 @@ func newServer(addr string, f *flamego.Flame) *http.Server { Handler: f, } - quit := make(chan os.Signal) + quit := make(chan os.Signal, 1) signal.Notify(quit, os.Interrupt) go func() { <-quit From 620bb5233da408d48f2acb625d65395aacb0a58b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=B4=8A=E1=B4=8F=E1=B4=87=20=E1=B4=84=CA=9C=E1=B4=87?= =?UTF-8?q?=C9=B4?= Date: Sun, 23 Nov 2025 13:15:28 -0500 Subject: [PATCH 9/9] Remove comment from getStatsFromJSON function Removed comment about initializing stats. --- main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/main.go b/main.go index 2986c52..386f9d6 100644 --- a/main.go +++ b/main.go @@ -141,7 +141,6 @@ func loadConfig(path string) (*config, error) { } func getStatsFromJSON(path string) (*stats, error) { - // Initialize stats s := &stats{ pkgsView: make(map[string]*int64), pkgsGet: make(map[string]*int64),