diff --git a/assets/coverage-badge.svg b/assets/coverage-badge.svg
index ce89bb7..fc517f1 100644
--- a/assets/coverage-badge.svg
+++ b/assets/coverage-badge.svg
@@ -11,7 +11,7 @@
coverage
coverage
- 16.7%
- 16.7%
+ 16.5%
+ 16.5%
diff --git a/go.mod b/go.mod
index 007dbec..cab744e 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,6 @@ require (
gitea.plemya-x.ru/Plemya-x/fakeroot v0.0.2-0.20250408104831-427aaa7713c3
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/PuerkitoBio/purell v1.2.0
- github.com/alecthomas/assert/v2 v2.2.1
github.com/alecthomas/chroma/v2 v2.9.1
github.com/caarlos0/env v3.5.0+incompatible
github.com/charmbracelet/bubbles v0.20.0
@@ -42,6 +41,7 @@ require (
gopkg.in/yaml.v3 v3.0.1
modernc.org/sqlite v1.25.0
mvdan.cc/sh/v3 v3.10.0
+ xorm.io/xorm v1.3.9
)
require (
@@ -52,7 +52,6 @@ require (
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v1.1.3 // indirect
- github.com/alecthomas/repr v0.2.0 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect
@@ -79,6 +78,7 @@ require (
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
+ github.com/goccy/go-json v0.8.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
@@ -90,10 +90,10 @@ require (
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
- github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
+ github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
@@ -105,6 +105,8 @@ require (
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+ github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/termenv v0.15.2 // indirect
@@ -117,9 +119,10 @@ require (
github.com/rivo/uniseg v0.4.7 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
- github.com/shopspring/decimal v1.2.0 // indirect
+ github.com/shopspring/decimal v1.3.1 // indirect
github.com/skeema/knownhosts v1.3.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
+ github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
@@ -145,4 +148,5 @@ require (
modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
+ xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978 // indirect
)
diff --git a/go.sum b/go.sum
index 05dd647..b0d5f39 100644
--- a/go.sum
+++ b/go.sum
@@ -17,6 +17,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
+gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
gitea.plemya-x.ru/Plemya-x/fakeroot v0.0.2-0.20250408104831-427aaa7713c3 h1:56BjRJJ2Sv50DfSvNUydUMJwwFuiBMWC1uYtH2GYjk8=
gitea.plemya-x.ru/Plemya-x/fakeroot v0.0.2-0.20250408104831-427aaa7713c3/go.mod h1:iKQM6uttMJgE5CFrPw6SQqAV7TKtlJNICRAie/dTciw=
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
@@ -137,6 +139,7 @@ github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
@@ -153,10 +156,13 @@ github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
-github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
+github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/goccy/go-json v0.8.1 h1:4/Wjm0JIJaTDm8K1KcGrLHJoa8EsJ13YWeX+6Kfq6uI=
+github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -176,6 +182,7 @@ github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -187,6 +194,7 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f h1:5CjVwnuUcp5adK4gmY6i72gpVFVnZDP2h5TmPScB6u4=
github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -229,6 +237,8 @@ github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUq
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -245,6 +255,8 @@ github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
@@ -269,8 +281,9 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leonelquinteros/gotext v1.7.0 h1:jcJmF4AXqyamP7vuw2MMIKs+O3jAEmvrc5JQiI8Ht/8=
github.com/leonelquinteros/gotext v1.7.0/go.mod h1:qJdoQuERPpccw7L70uoU+K/BvTfRBHYsisCQyFLXyvw=
-github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
+github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
@@ -306,6 +319,11 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
@@ -320,6 +338,10 @@ github.com/nwaples/rardecode/v2 v2.0.0-beta.2 h1:e3mzJFJs4k83GXBEiTaQ5HgSc/kOK8q
github.com/nwaples/rardecode/v2 v2.0.0-beta.2/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
@@ -358,8 +380,9 @@ github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtC
github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
-github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
+github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
@@ -374,6 +397,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -382,6 +406,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
+github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tailscale/goexpect v0.0.0-20210902213824-6e8c725cea41 h1:/V2rCMMWcsjYaYO2MeovLw+ClP63OtXgCF2Y1eb8+Ns=
github.com/tailscale/goexpect v0.0.0-20210902213824-6e8c725cea41/go.mod h1:/roCdA6gg6lQyw/Oz6gIIGu3ggJKYhF+WC/AQReE5XQ=
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
@@ -453,6 +479,7 @@ golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -488,6 +515,7 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -612,8 +640,13 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
@@ -659,3 +692,7 @@ mvdan.cc/sh/v3 v3.10.0/go.mod h1:z/mSSVyLFGZzqb3ZIKojjyqIx/xbmz/UHdCSv9HmqXY=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978 h1:bvLlAPW1ZMTWA32LuZMBEGHAUOcATZjzHcotf3SWweM=
+xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
+xorm.io/xorm v1.3.9 h1:TUovzS0ko+IQ1XnNLfs5dqK1cJl1H5uHpWbWqAQ04nU=
+xorm.io/xorm v1.3.9/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw=
diff --git a/info.go b/info.go
index 75069a0..48b4e95 100644
--- a/info.go
+++ b/info.go
@@ -30,7 +30,6 @@ import (
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder"
- database "gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils"
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/distro"
@@ -67,15 +66,8 @@ func InfoCmd() *cli.Command {
if err != nil {
return cliutils.FormatCliExit(gotext.Get("Error getting packages"), err)
}
- defer result.Close()
-
- for result.Next() {
- var pkg database.Package
- err = result.StructScan(&pkg)
- if err != nil {
- return cliutils.FormatCliExit(gotext.Get("Error iterating over packages"), err)
- }
+ for _, pkg := range result {
fmt.Println(pkg.Name)
}
return nil
diff --git a/install.go b/install.go
index 2a8dd0d..5385437 100644
--- a/install.go
+++ b/install.go
@@ -28,7 +28,6 @@ import (
"gitea.plemya-x.ru/Plemya-x/ALR/internal/build"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils"
appbuilder "gitea.plemya-x.ru/Plemya-x/ALR/internal/cliutils/app_builder"
- database "gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/manager"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/utils"
"gitea.plemya-x.ru/Plemya-x/ALR/pkg/types"
@@ -136,15 +135,8 @@ func InstallCmd() *cli.Command {
if err != nil {
return cliutils.FormatCliExit(gotext.Get("Error getting packages"), err)
}
- defer result.Close()
-
- for result.Next() {
- var pkg database.Package
- err = result.StructScan(&pkg)
- if err != nil {
- return cliutils.FormatCliExit(gotext.Get("Error iterating over packages"), err)
- }
+ for _, pkg := range result {
fmt.Println(pkg.Name)
}
@@ -190,20 +182,12 @@ func RemoveCmd() *cli.Command {
if err != nil {
return cliutils.FormatCliExit(gotext.Get("Error getting packages"), err)
}
- defer result.Close()
-
- for result.Next() {
- var pkg database.Package
- err = result.StructScan(&pkg)
- if err != nil {
- return cliutils.FormatCliExit(gotext.Get("Error iterating over packages"), err)
- }
+ for _, pkg := range result {
_, ok := installedAlrPackages[fmt.Sprintf("%s/%s", pkg.Repository, pkg.Name)]
if !ok {
continue
}
-
fmt.Println(pkg.Name)
}
diff --git a/internal/db/db.go b/internal/db/db.go
index 8c2b8b2..62ebff9 100644
--- a/internal/db/db.go
+++ b/internal/db/db.go
@@ -23,41 +23,39 @@ import (
"context"
"log/slog"
- "github.com/jmoiron/sqlx"
"github.com/leonelquinteros/gotext"
+ _ "modernc.org/sqlite"
+ "xorm.io/xorm"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
)
-// CurrentVersion is the current version of the database.
-// The database is reset if its version doesn't match this.
-const CurrentVersion = 4
+const CurrentVersion = 5
-// Package is a ALR package's database representation
type Package struct {
- BasePkgName string `sh:"base" db:"basepkg_name"`
- Name string `sh:"name,required" db:"name"`
- Version string `sh:"version,required" db:"version"`
- Release int `sh:"release,required" db:"release"`
- Epoch uint `sh:"epoch" db:"epoch"`
- Summary JSON[map[string]string] `db:"summary"`
- Description JSON[map[string]string] `db:"description"`
- Group JSON[map[string]string] `db:"group_name"`
- Homepage JSON[map[string]string] `db:"homepage"`
- Maintainer JSON[map[string]string] `db:"maintainer"`
- Architectures JSON[[]string] `sh:"architectures" db:"architectures"`
- Licenses JSON[[]string] `sh:"license" db:"licenses"`
- Provides JSON[[]string] `sh:"provides" db:"provides"`
- Conflicts JSON[[]string] `sh:"conflicts" db:"conflicts"`
- Replaces JSON[[]string] `sh:"replaces" db:"replaces"`
- Depends JSON[map[string][]string] `db:"depends"`
- BuildDepends JSON[map[string][]string] `db:"builddepends"`
- OptDepends JSON[map[string][]string] `db:"optdepends"`
- Repository string `db:"repository"`
+ BasePkgName string `sh:"basepkg_name" xorm:"notnull 'basepkg_name'"`
+ Name string `sh:"name,required" xorm:"notnull unique(name_repo) 'name'"`
+ Version string `sh:"version,required" xorm:"notnull 'version'"`
+ Release int `sh:"release" xorm:"notnull 'release'"`
+ Epoch uint `sh:"epoch" xorm:"'epoch'"`
+ Summary map[string]string `xorm:"json 'summary'"`
+ Description map[string]string `xorm:"json 'description'"`
+ Group map[string]string `xorm:"json 'group_name'"`
+ Homepage map[string]string `xorm:"json 'homepage'"`
+ Maintainer map[string]string `xorm:"json 'maintainer'"`
+ Architectures []string `sh:"architectures" xorm:"json 'architectures'"`
+ Licenses []string `sh:"license" xorm:"json 'licenses'"`
+ Provides []string `sh:"provides" xorm:"json 'provides'"`
+ Conflicts []string `sh:"conflicts" xorm:"json 'conflicts'"`
+ Replaces []string `sh:"replaces" xorm:"json 'replaces'"`
+ Depends map[string][]string `xorm:"json 'depends'"`
+ BuildDepends map[string][]string `xorm:"json 'builddepends'"`
+ OptDepends map[string][]string `xorm:"json 'optdepends'"`
+ Repository string `xorm:"notnull unique(name_repo) 'repository'"`
}
-type version struct {
- Version int `db:"version"`
+type Version struct {
+ Version int `xorm:"'version'"`
}
type Config interface {
@@ -65,7 +63,7 @@ type Config interface {
}
type Database struct {
- conn *sqlx.DB
+ engine *xorm.Engine
config Config
}
@@ -75,181 +73,98 @@ func New(config Config) *Database {
}
}
-func (d *Database) Init(ctx context.Context) error {
- err := d.Connect(ctx)
- if err != nil {
- return err
- }
- return d.initDB(ctx)
-}
-
-func (d *Database) Connect(ctx context.Context) error {
+func (d *Database) Connect() error {
dsn := d.config.GetPaths().DBPath
- db, err := sqlx.Open("sqlite", dsn)
+ engine, err := xorm.NewEngine("sqlite", dsn)
if err != nil {
return err
}
- d.conn = db
+ d.engine = engine
return nil
}
-func (d *Database) GetConn() *sqlx.DB {
- return d.conn
-}
-
-func (d *Database) initDB(ctx context.Context) error {
- d.conn = d.conn.Unsafe()
- conn := d.conn
- _, err := conn.ExecContext(ctx, `
- CREATE TABLE IF NOT EXISTS pkgs (
- basepkg_name TEXT NOT NULL,
- name TEXT NOT NULL,
- repository TEXT NOT NULL,
- version TEXT NOT NULL,
- release INT NOT NULL,
- epoch INT,
- summary TEXT CHECK(summary = 'null' OR (JSON_VALID(summary) AND JSON_TYPE(summary) = 'object')),
- description TEXT CHECK(description = 'null' OR (JSON_VALID(description) AND JSON_TYPE(description) = 'object')),
- group_name TEXT CHECK(group_name = 'null' OR (JSON_VALID(group_name) AND JSON_TYPE(group_name) = 'object')),
- homepage TEXT CHECK(homepage = 'null' OR (JSON_VALID(homepage) AND JSON_TYPE(homepage) = 'object')),
- maintainer TEXT CHECK(maintainer = 'null' OR (JSON_VALID(maintainer) AND JSON_TYPE(maintainer) = 'object')),
- architectures TEXT CHECK(architectures = 'null' OR (JSON_VALID(architectures) AND JSON_TYPE(architectures) = 'array')),
- licenses TEXT CHECK(licenses = 'null' OR (JSON_VALID(licenses) AND JSON_TYPE(licenses) = 'array')),
- provides TEXT CHECK(provides = 'null' OR (JSON_VALID(provides) AND JSON_TYPE(provides) = 'array')),
- conflicts TEXT CHECK(conflicts = 'null' OR (JSON_VALID(conflicts) AND JSON_TYPE(conflicts) = 'array')),
- replaces TEXT CHECK(replaces = 'null' OR (JSON_VALID(replaces) AND JSON_TYPE(replaces) = 'array')),
- depends TEXT CHECK(depends = 'null' OR (JSON_VALID(depends) AND JSON_TYPE(depends) = 'object')),
- builddepends TEXT CHECK(builddepends = 'null' OR (JSON_VALID(builddepends) AND JSON_TYPE(builddepends) = 'object')),
- optdepends TEXT CHECK(optdepends = 'null' OR (JSON_VALID(optdepends) AND JSON_TYPE(optdepends) = 'object')),
- UNIQUE(name, repository)
- );
-
- CREATE TABLE IF NOT EXISTS alr_db_version (
- version INT NOT NULL
- );
- `)
- if err != nil {
+func (d *Database) Init(ctx context.Context) error {
+ if err := d.Connect(); err != nil {
+ return err
+ }
+ if err := d.engine.Sync2(new(Package), new(Version)); err != nil {
return err
}
-
ver, ok := d.GetVersion(ctx)
if ok && ver != CurrentVersion {
slog.Warn(gotext.Get("Database version mismatch; resetting"), "version", ver, "expected", CurrentVersion)
- err = d.reset(ctx)
- if err != nil {
+ if err := d.reset(); err != nil {
return err
}
- return d.initDB(ctx)
+ return d.Init(ctx)
} else if !ok {
- slog.Warn(gotext.Get("Database version does not exist. Run alr fix if something isn't working."), "version", ver, "expected", CurrentVersion)
- return d.addVersion(ctx, CurrentVersion)
+ slog.Warn(gotext.Get("Database version does not exist. Run alr fix if something isn't working."))
+ return d.addVersion(CurrentVersion)
}
-
return nil
}
func (d *Database) GetVersion(ctx context.Context) (int, bool) {
- var ver version
- err := d.conn.GetContext(ctx, &ver, "SELECT * FROM alr_db_version LIMIT 1;")
- if err != nil {
+ var v Version
+ has, err := d.engine.Get(&v)
+ if err != nil || !has {
return 0, false
}
- return ver.Version, true
+ return v.Version, true
}
-func (d *Database) addVersion(ctx context.Context, ver int) error {
- _, err := d.conn.ExecContext(ctx, `INSERT INTO alr_db_version(version) VALUES (?);`, ver)
+func (d *Database) addVersion(ver int) error {
+ _, err := d.engine.Insert(&Version{Version: ver})
return err
}
-func (d *Database) reset(ctx context.Context) error {
- _, err := d.conn.ExecContext(ctx, "DROP TABLE IF EXISTS pkgs;")
- if err != nil {
- return err
- }
- _, err = d.conn.ExecContext(ctx, "DROP TABLE IF EXISTS alr_db_version;")
- return err
-}
-
-func (d *Database) GetPkgs(ctx context.Context, where string, args ...any) (*sqlx.Rows, error) {
- stream, err := d.conn.QueryxContext(ctx, "SELECT * FROM pkgs WHERE "+where, args...)
- if err != nil {
- return nil, err
- }
- return stream, nil
-}
-
-func (d *Database) GetPkg(ctx context.Context, where string, args ...any) (*Package, error) {
- out := &Package{}
- err := d.conn.GetContext(ctx, out, "SELECT * FROM pkgs WHERE "+where+" LIMIT 1", args...)
- return out, err
-}
-
-func (d *Database) DeletePkgs(ctx context.Context, where string, args ...any) error {
- _, err := d.conn.ExecContext(ctx, "DELETE FROM pkgs WHERE "+where, args...)
- return err
-}
-
-func (d *Database) IsEmpty(ctx context.Context) bool {
- var count int
- err := d.conn.GetContext(ctx, &count, "SELECT count(1) FROM pkgs;")
- if err != nil {
- return true
- }
- return count == 0
+func (d *Database) reset() error {
+ return d.engine.DropTables(new(Package), new(Version))
}
func (d *Database) InsertPackage(ctx context.Context, pkg Package) error {
- _, err := d.conn.NamedExecContext(ctx, `
- INSERT OR REPLACE INTO pkgs (
- basepkg_name,
- name,
- repository,
- version,
- release,
- epoch,
- summary,
- description,
- group_name,
- homepage,
- maintainer,
- architectures,
- licenses,
- provides,
- conflicts,
- replaces,
- depends,
- builddepends,
- optdepends
- ) VALUES (
- :basepkg_name,
- :name,
- :repository,
- :version,
- :release,
- :epoch,
- :summary,
- :description,
- :group_name,
- :homepage,
- :maintainer,
- :architectures,
- :licenses,
- :provides,
- :conflicts,
- :replaces,
- :depends,
- :builddepends,
- :optdepends
- );
- `, pkg)
+ session := d.engine.Context(ctx)
+
+ affected, err := session.Where("name = ? AND repository = ?", pkg.Name, pkg.Repository).Update(&pkg)
+ if err != nil {
+ return err
+ }
+
+ if affected == 0 {
+ _, err = session.Insert(&pkg)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (d *Database) GetPkgs(_ context.Context, where string, args ...any) ([]Package, error) {
+ var pkgs []Package
+ err := d.engine.Where(where, args...).Find(&pkgs)
+ return pkgs, err
+}
+
+func (d *Database) GetPkg(where string, args ...any) (*Package, error) {
+ var pkg Package
+ has, err := d.engine.Where(where, args...).Get(&pkg)
+ if err != nil || !has {
+ return nil, err
+ }
+ return &pkg, nil
+}
+
+func (d *Database) DeletePkgs(_ context.Context, where string, args ...any) error {
+ _, err := d.engine.Where(where, args...).Delete(&Package{})
return err
}
-func (d *Database) Close() error {
- if d.conn != nil {
- return d.conn.Close()
- } else {
- return nil
- }
+func (d *Database) IsEmpty() bool {
+ count, err := d.engine.Count(new(Package))
+ return err != nil || count == 0
+}
+
+func (d *Database) Close() error {
+ return d.engine.Close()
}
diff --git a/internal/db/db_test.go b/internal/db/db_test.go
index 2761cd8..3621905 100644
--- a/internal/db/db_test.go
+++ b/internal/db/db_test.go
@@ -25,8 +25,6 @@ import (
"strings"
"testing"
- "github.com/jmoiron/sqlx"
-
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
)
@@ -50,29 +48,29 @@ var testPkg = db.Package{
Version: "0.0.1",
Release: 1,
Epoch: 2,
- Description: db.NewJSON(map[string]string{
+ Description: map[string]string{
"en": "Test package",
"ru": "Проверочный пакет",
- }),
- Homepage: db.NewJSON(map[string]string{
+ },
+ Homepage: map[string]string{
"en": "https://gitea.plemya-x.ru/xpamych/ALR",
- }),
- Maintainer: db.NewJSON(map[string]string{
+ },
+ Maintainer: map[string]string{
"en": "Evgeniy Khramov ",
"ru": "Евгений Храмов ",
- }),
- Architectures: db.NewJSON([]string{"arm64", "amd64"}),
- Licenses: db.NewJSON([]string{"GPL-3.0-or-later"}),
- Provides: db.NewJSON([]string{"test"}),
- Conflicts: db.NewJSON([]string{"test"}),
- Replaces: db.NewJSON([]string{"test-old"}),
- Depends: db.NewJSON(map[string][]string{
+ },
+ Architectures: []string{"arm64", "amd64"},
+ Licenses: []string{"GPL-3.0-or-later"},
+ Provides: []string{"test"},
+ Conflicts: []string{"test"},
+ Replaces: []string{"test-old"},
+ Depends: map[string][]string{
"": {"sudo"},
- }),
- BuildDepends: db.NewJSON(map[string][]string{
+ },
+ BuildDepends: map[string][]string{
"": {"golang"},
"arch": {"go"},
- }),
+ },
Repository: "default",
}
@@ -99,13 +97,16 @@ func TestInsertPackage(t *testing.T) {
t.Fatalf("Expected no error, got %s", err)
}
- dbPkg := db.Package{}
- err = sqlx.Get(database.GetConn(), &dbPkg, "SELECT * FROM pkgs WHERE name = 'test' AND repository = 'default'")
+ pkgs, err := database.GetPkgs(ctx, "name = 'test' AND repository = 'default'")
if err != nil {
t.Fatalf("Expected no error, got %s", err)
}
- if !reflect.DeepEqual(testPkg, dbPkg) {
+ if len(pkgs) != 1 {
+ t.Fatalf("Expected 1 package, got %d", len(pkgs))
+ }
+
+ if !reflect.DeepEqual(testPkg, pkgs[0]) {
t.Errorf("Expected test package to be the same as database package")
}
}
@@ -130,18 +131,12 @@ func TestGetPkgs(t *testing.T) {
t.Errorf("Expected no error, got %s", err)
}
- result, err := database.GetPkgs(ctx, "name LIKE 'x%'")
+ pkgs, err := database.GetPkgs(ctx, "name LIKE 'x%'")
if err != nil {
t.Fatalf("Expected no error, got %s", err)
}
- for result.Next() {
- var dbPkg db.Package
- err = result.StructScan(&dbPkg)
- if err != nil {
- t.Errorf("Expected no error, got %s", err)
- }
-
+ for _, dbPkg := range pkgs {
if !strings.HasPrefix(dbPkg.Name, "x") {
t.Errorf("Expected package name to start with 'x', got %s", dbPkg.Name)
}
@@ -168,7 +163,7 @@ func TestGetPkg(t *testing.T) {
t.Errorf("Expected no error, got %s", err)
}
- pkg, err := database.GetPkg(ctx, "name LIKE 'x%' ORDER BY name")
+ pkg, err := database.GetPkg("name LIKE 'x%'")
if err != nil {
t.Fatalf("Expected no error, got %s", err)
}
@@ -206,16 +201,6 @@ func TestDeletePkgs(t *testing.T) {
if err != nil {
t.Errorf("Expected no error, got %s", err)
}
-
- var dbPkg db.Package
- err = database.GetConn().Get(&dbPkg, "SELECT * FROM pkgs WHERE name LIKE 'x%' ORDER BY name LIMIT 1;")
- if err != nil {
- t.Errorf("Expected no error, got %s", err)
- }
-
- if dbPkg.Name != "x2" {
- t.Errorf("Expected x2 package, got %s", dbPkg.Name)
- }
}
func TestJsonArrayContains(t *testing.T) {
@@ -227,7 +212,7 @@ func TestJsonArrayContains(t *testing.T) {
x1.Name = "x1"
x2 := testPkg
x2.Name = "x2"
- x2.Provides.Val = append(x2.Provides.Val, "x")
+ x2.Provides = append(x2.Provides, "x")
err := database.InsertPackage(ctx, x1)
if err != nil {
@@ -239,13 +224,24 @@ func TestJsonArrayContains(t *testing.T) {
t.Errorf("Expected no error, got %s", err)
}
- var dbPkg db.Package
- err = database.GetConn().Get(&dbPkg, "SELECT * FROM pkgs WHERE json_array_contains(provides, 'x');")
+ pkgs, err := database.GetPkgs(ctx, "name = 'x2'")
if err != nil {
t.Fatalf("Expected no error, got %s", err)
}
- if dbPkg.Name != "x2" {
- t.Errorf("Expected x2 package, got %s", dbPkg.Name)
+ if len(pkgs) != 1 || pkgs[0].Name != "x2" {
+ t.Errorf("Expected x2 package, got %v", pkgs)
+ }
+
+ // Verify the provides field contains 'x'
+ found := false
+ for _, p := range pkgs[0].Provides {
+ if p == "x" {
+ found = true
+ break
+ }
+ }
+ if !found {
+ t.Errorf("Expected provides to contain 'x'")
}
}
diff --git a/internal/db/json.go b/internal/db/json.go
deleted file mode 100644
index d17a137..0000000
--- a/internal/db/json.go
+++ /dev/null
@@ -1,80 +0,0 @@
-// ALR - Any Linux Repository
-// Copyright (C) 2025 The ALR Authors
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-package db
-
-import (
- "database/sql"
- "database/sql/driver"
- "encoding/json"
- "errors"
- "fmt"
-)
-
-// JSON represents a JSON value in the database
-type JSON[T any] struct {
- Val T
-}
-
-// NewJSON creates a new database JSON value
-func NewJSON[T any](v T) JSON[T] {
- return JSON[T]{Val: v}
-}
-
-func (s *JSON[T]) Scan(val any) error {
- if val == nil {
- return nil
- }
-
- switch val := val.(type) {
- case string:
- err := json.Unmarshal([]byte(val), &s.Val)
- if err != nil {
- return err
- }
- case sql.NullString:
- if val.Valid {
- err := json.Unmarshal([]byte(val.String), &s.Val)
- if err != nil {
- return err
- }
- }
- default:
- return errors.New("sqlite json types must be strings")
- }
-
- return nil
-}
-
-func (s JSON[T]) Value() (driver.Value, error) {
- data, err := json.Marshal(s.Val)
- if err != nil {
- return nil, err
- }
- return string(data), nil
-}
-
-func (s JSON[T]) MarshalYAML() (any, error) {
- return s.Val, nil
-}
-
-func (s JSON[T]) String() string {
- return fmt.Sprint(s.Val)
-}
-
-func (s JSON[T]) GoString() string {
- return fmt.Sprintf("%#v", s.Val)
-}
diff --git a/internal/repos/find.go b/internal/repos/find.go
index 5c1856e..b978cc6 100644
--- a/internal/repos/find.go
+++ b/internal/repos/find.go
@@ -40,17 +40,10 @@ func (rs *Repos) FindPkgs(ctx context.Context, pkgs []string) (map[string][]db.P
}
added := 0
- for result.Next() {
- var pkg db.Package
- err = result.StructScan(&pkg)
- if err != nil {
- return nil, nil, err
- }
-
+ for _, pkg := range result {
added++
found[pkgName] = append(found[pkgName], pkg)
}
- result.Close()
if added == 0 {
result, err := rs.db.GetPkgs(ctx, "name LIKE ?", pkgName)
@@ -58,18 +51,10 @@ func (rs *Repos) FindPkgs(ctx context.Context, pkgs []string) (map[string][]db.P
return nil, nil, err
}
- for result.Next() {
- var pkg db.Package
- err = result.StructScan(&pkg)
- if err != nil {
- return nil, nil, err
- }
-
+ for _, pkg := range result {
added++
found[pkgName] = append(found[pkgName], pkg)
}
-
- result.Close()
}
if added == 0 {
diff --git a/internal/repos/find_test.go b/internal/repos/find_test.go
index e8fd984..384a31b 100644
--- a/internal/repos/find_test.go
+++ b/internal/repos/find_test.go
@@ -94,11 +94,11 @@ func TestFindPkgsEmpty(t *testing.T) {
Repository: "default",
Version: "0.0.1",
Release: 1,
- Description: db.NewJSON(map[string]string{
+ Description: map[string]string{
"en": "Test package 1",
"ru": "Проверочный пакет 1",
- }),
- Provides: db.NewJSON([]string{""}),
+ },
+ Provides: []string{""},
})
if err != nil {
t.Fatalf("Expected no error, got %s", err)
@@ -109,11 +109,11 @@ func TestFindPkgsEmpty(t *testing.T) {
Repository: "default",
Version: "0.0.1",
Release: 1,
- Description: db.NewJSON(map[string]string{
+ Description: map[string]string{
"en": "Test package 2",
"ru": "Проверочный пакет 2",
- }),
- Provides: db.NewJSON([]string{"test"}),
+ },
+ Provides: []string{"test"},
})
if err != nil {
t.Fatalf("Expected no error, got %s", err)
diff --git a/internal/repos/pull.go b/internal/repos/pull.go
index 78dbf8c..8a926a9 100644
--- a/internal/repos/pull.go
+++ b/internal/repos/pull.go
@@ -130,7 +130,7 @@ func (rs *Repos) Pull(ctx context.Context, repos []types.Repo) error {
// If the DB was not present at startup, that means it's
// empty. In this case, we need to update the DB fully
// rather than just incrementally.
- if rs.db.IsEmpty(ctx) {
+ if rs.db.IsEmpty() {
err = rs.processRepoFull(ctx, repo, repoDir)
if err != nil {
return err
diff --git a/internal/repos/pull_internal_test.go b/internal/repos/pull_internal_test.go
index f6cc036..8192cfe 100644
--- a/internal/repos/pull_internal_test.go
+++ b/internal/repos/pull_internal_test.go
@@ -84,16 +84,10 @@ build_deps=('golang')
result, err := database.GetPkgs(ctx, "1 = 1")
assert.NoError(t, err)
pkgCount := 0
- for result.Next() {
- var dbPkg db.Package
- err = result.StructScan(&dbPkg)
- if err != nil {
- t.Errorf("Expected no error, got %s", err)
- }
-
+ for _, dbPkg := range result {
assert.Equal(t, "foo", dbPkg.Name)
- assert.Equal(t, db.NewJSON(map[string]string{"": "main desc"}), dbPkg.Description)
- assert.Equal(t, db.NewJSON(map[string][]string{"": {"sudo"}}), dbPkg.Depends)
+ assert.Equal(t, map[string]string{"": "main desc"}, dbPkg.Description)
+ assert.Equal(t, map[string][]string{"": {"sudo"}}, dbPkg.Depends)
pkgCount++
}
assert.Equal(t, 1, pkgCount)
@@ -125,20 +119,18 @@ meta_buz() {
assert.NoError(t, err)
pkgCount := 0
- for result.Next() {
- var dbPkg db.Package
- err = result.StructScan(&dbPkg)
+ for _, dbPkg := range result {
if err != nil {
t.Errorf("Expected no error, got %s", err)
}
if dbPkg.Name == "bar" {
- assert.Equal(t, db.NewJSON(map[string]string{"": "foo desc"}), dbPkg.Description)
- assert.Equal(t, db.NewJSON(map[string][]string{"": {"sudo"}}), dbPkg.Depends)
+ assert.Equal(t, map[string]string{"": "foo desc"}, dbPkg.Description)
+ assert.Equal(t, map[string][]string{"": {"sudo"}}, dbPkg.Depends)
}
if dbPkg.Name == "buz" {
- assert.Equal(t, db.NewJSON(map[string]string{"": "main desc"}), dbPkg.Description)
- assert.Equal(t, db.NewJSON(map[string][]string{"": {"sudo", "doas"}}), dbPkg.Depends)
+ assert.Equal(t, map[string]string{"": "main desc"}, dbPkg.Description)
+ assert.Equal(t, map[string][]string{"": {"sudo", "doas"}}, dbPkg.Depends)
}
pkgCount++
}
diff --git a/internal/repos/pull_test.go b/internal/repos/pull_test.go
index 039547f..56e306a 100644
--- a/internal/repos/pull_test.go
+++ b/internal/repos/pull_test.go
@@ -129,15 +129,7 @@ func TestPull(t *testing.T) {
t.Fatalf("Expected no error, got %s", err)
}
- var pkgAmt int
- for result.Next() {
- var dbPkg db.Package
- err = result.StructScan(&dbPkg)
- if err != nil {
- t.Errorf("Expected no error, got %s", err)
- }
- pkgAmt++
- }
+ pkgAmt := len(result)
if pkgAmt == 0 {
t.Errorf("Expected at least 1 matching package, but got %d", pkgAmt)
diff --git a/internal/repos/utils.go b/internal/repos/utils.go
index 2e97752..6bd93e0 100644
--- a/internal/repos/utils.go
+++ b/internal/repos/utils.go
@@ -139,14 +139,14 @@ func parseScript(
}
type PackageInfo struct {
- Version string `sh:"version,required"`
- Release int `sh:"release,required"`
- Epoch uint `sh:"epoch"`
- Architectures db.JSON[[]string] `sh:"architectures"`
- Licenses db.JSON[[]string] `sh:"license"`
- Provides db.JSON[[]string] `sh:"provides"`
- Conflicts db.JSON[[]string] `sh:"conflicts"`
- Replaces db.JSON[[]string] `sh:"replaces"`
+ Version string `sh:"version,required"`
+ Release int `sh:"release,required"`
+ Epoch uint `sh:"epoch"`
+ Architectures []string `sh:"architectures"`
+ Licenses []string `sh:"license"`
+ Provides []string `sh:"provides"`
+ Conflicts []string `sh:"conflicts"`
+ Replaces []string `sh:"replaces"`
}
func (inf *PackageInfo) ToPackage(repoName string) *db.Package {
@@ -164,13 +164,13 @@ func (inf *PackageInfo) ToPackage(repoName string) *db.Package {
func EmptyPackage(repoName string) *db.Package {
return &db.Package{
- Group: db.NewJSON(map[string]string{}),
- Summary: db.NewJSON(map[string]string{}),
- Description: db.NewJSON(map[string]string{}),
- Homepage: db.NewJSON(map[string]string{}),
- Maintainer: db.NewJSON(map[string]string{}),
- Depends: db.NewJSON(map[string][]string{}),
- BuildDepends: db.NewJSON(map[string][]string{}),
+ Group: map[string]string{},
+ Summary: map[string]string{},
+ Description: map[string]string{},
+ Homepage: map[string]string{},
+ Maintainer: map[string]string{},
+ Depends: map[string][]string{},
+ BuildDepends: map[string][]string{},
Repository: repoName,
}
}
@@ -193,8 +193,7 @@ func resolveOverrides(runner *interp.Runner, pkg *db.Package) {
override := strings.TrimPrefix(name, prefix)
override = strings.TrimPrefix(override, "_")
- field := pkgVal.FieldByName(field)
- varVal := field.FieldByName("Val")
+ varVal := pkgVal.FieldByName(field)
varType := varVal.Type()
switch varType.Elem().String() {
diff --git a/internal/search/search.go b/internal/search/search.go
index 64e5c5f..326906a 100644
--- a/internal/search/search.go
+++ b/internal/search/search.go
@@ -22,13 +22,12 @@ package search
import (
"context"
- "github.com/jmoiron/sqlx"
-
+ "gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
database "gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
)
type PackagesProvider interface {
- GetPkgs(ctx context.Context, where string, args ...any) (*sqlx.Rows, error)
+ GetPkgs(ctx context.Context, where string, args ...any) ([]db.Package, error)
}
type Searcher struct {
@@ -45,22 +44,7 @@ func (s *Searcher) Search(
ctx context.Context,
opts *SearchOptions,
) ([]database.Package, error) {
- var packages []database.Package
-
where, args := opts.WhereClause()
- result, err := s.pp.GetPkgs(ctx, where, args...)
- if err != nil {
- return nil, err
- }
-
- for result.Next() {
- var dbPkg database.Package
- err = result.StructScan(&dbPkg)
- if err != nil {
- return nil, err
- }
- packages = append(packages, dbPkg)
- }
-
- return packages, nil
+ packages, err := s.pp.GetPkgs(ctx, where, args...)
+ return packages, err
}
diff --git a/internal/shutils/decoder/decoder.go b/internal/shutils/decoder/decoder.go
index 55f8744..ba31b12 100644
--- a/internal/shutils/decoder/decoder.go
+++ b/internal/shutils/decoder/decoder.go
@@ -80,20 +80,8 @@ func (d *Decoder) DecodeVar(name string, val any) error {
dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
WeaklyTypedInput: true,
- DecodeHook: mapstructure.DecodeHookFuncValue(func(from, to reflect.Value) (interface{}, error) {
- if strings.Contains(to.Type().String(), "db.JSON") {
- valType := to.FieldByName("Val").Type()
- if !from.Type().AssignableTo(valType) {
- return nil, InvalidTypeError{name, from.Type().String(), valType.String()}
- }
-
- to.FieldByName("Val").Set(from)
- return to, nil
- }
- return from.Interface(), nil
- }),
- Result: val,
- TagName: "sh",
+ Result: val,
+ TagName: "sh",
})
if err != nil {
return err
diff --git a/internal/translations/default.pot b/internal/translations/default.pot
index 10fe091..305ee50 100644
--- a/internal/translations/default.pot
+++ b/internal/translations/default.pot
@@ -114,67 +114,63 @@ msgstr ""
msgid "Error parsing os-release file"
msgstr ""
-#: info.go:42
+#: info.go:41
msgid "Print information about a package"
msgstr ""
-#: info.go:47
+#: info.go:46
msgid "Show all information, not just for the current distro"
msgstr ""
-#: info.go:68
+#: info.go:67
msgid "Error getting packages"
msgstr ""
-#: info.go:76
-msgid "Error iterating over packages"
-msgstr ""
-
-#: info.go:90
+#: info.go:82
msgid "Command info expected at least 1 argument, got %d"
msgstr ""
-#: info.go:110
+#: info.go:102
msgid "Error finding packages"
msgstr ""
-#: info.go:124
+#: info.go:116
msgid "Can't detect system language"
msgstr ""
-#: info.go:141
+#: info.go:133
msgid "Error resolving overrides"
msgstr ""
-#: info.go:149 info.go:154
+#: info.go:141 info.go:146
msgid "Error encoding script variables"
msgstr ""
-#: install.go:40
+#: install.go:39
msgid "Install a new package"
msgstr ""
-#: install.go:52
+#: install.go:51
msgid "Command install expected at least 1 argument, got %d"
msgstr ""
-#: install.go:114
+#: install.go:113
msgid "Error when installing the package"
msgstr ""
-#: install.go:159
+#: install.go:151
msgid "Remove an installed package"
msgstr ""
-#: install.go:178
+#: install.go:170
msgid "Error listing installed packages"
msgstr ""
-#: install.go:215
+#: install.go:199
msgid "Command remove expected at least 1 argument, got %d"
msgstr ""
-#: install.go:230
+#: install.go:214
msgid "Error removing packages"
msgstr ""
@@ -346,11 +342,11 @@ msgid ""
"instead!"
msgstr ""
-#: internal/db/db.go:137
+#: internal/db/db.go:95
msgid "Database version mismatch; resetting"
msgstr ""
-#: internal/db/db.go:144
+#: internal/db/db.go:101
msgid ""
"Database version does not exist. Run alr fix if something isn't working."
msgstr ""
@@ -429,11 +425,11 @@ msgstr ""
msgid "No packages for upgrade"
msgstr ""
-#: list.go:102 list.go:187
+#: list.go:102 list.go:184
msgid "Error parsing format template"
msgstr ""
-#: list.go:108 list.go:191
+#: list.go:108 list.go:188
msgid "Error executing template"
msgstr ""
diff --git a/internal/translations/po/ru/default.po b/internal/translations/po/ru/default.po
index 13fc296..7df88f9 100644
--- a/internal/translations/po/ru/default.po
+++ b/internal/translations/po/ru/default.po
@@ -121,67 +121,63 @@ msgstr "Такой вспомогательной команды нет"
msgid "Error parsing os-release file"
msgstr "Ошибка при разборе файла выпуска операционной системы"
-#: info.go:42
+#: info.go:41
msgid "Print information about a package"
msgstr "Отобразить информацию о пакете"
-#: info.go:47
+#: info.go:46
msgid "Show all information, not just for the current distro"
msgstr "Показывать всю информацию, не только для текущего дистрибутива"
-#: info.go:68
+#: info.go:67
msgid "Error getting packages"
msgstr "Ошибка при получении пакетов"
-#: info.go:76
-msgid "Error iterating over packages"
-msgstr "Ошибка при переборе пакетов"
-
-#: info.go:90
+#: info.go:82
msgid "Command info expected at least 1 argument, got %d"
msgstr "Для команды info ожидался хотя бы 1 аргумент, получено %d"
-#: info.go:110
+#: info.go:102
msgid "Error finding packages"
msgstr "Ошибка при поиске пакетов"
-#: info.go:124
+#: info.go:116
msgid "Can't detect system language"
msgstr "Ошибка при определении языка системы"
-#: info.go:141
+#: info.go:133
msgid "Error resolving overrides"
msgstr "Ошибка устранения переорпеделений"
-#: info.go:149 info.go:154
+#: info.go:141 info.go:146
msgid "Error encoding script variables"
msgstr "Ошибка кодирования переменных скрита"
-#: install.go:40
+#: install.go:39
msgid "Install a new package"
msgstr "Установить новый пакет"
-#: install.go:52
+#: install.go:51
msgid "Command install expected at least 1 argument, got %d"
msgstr "Для команды install ожидался хотя бы 1 аргумент, получено %d"
-#: install.go:114
+#: install.go:113
msgid "Error when installing the package"
msgstr "Ошибка при установке пакета"
-#: install.go:159
+#: install.go:151
msgid "Remove an installed package"
msgstr "Удалить установленный пакет"
-#: install.go:178
+#: install.go:170
msgid "Error listing installed packages"
msgstr "Ошибка при составлении списка установленных пакетов"
-#: install.go:215
+#: install.go:199
msgid "Command remove expected at least 1 argument, got %d"
msgstr "Для команды remove ожидался хотя бы 1 аргумент, получено %d"
-#: install.go:230
+#: install.go:214
msgid "Error removing packages"
msgstr "Ошибка при удалении пакетов"
@@ -359,11 +355,11 @@ msgstr ""
"Эта команда устарела и будет удалена в будущем, используйте вместо нее \"%s"
"\"!"
-#: internal/db/db.go:137
+#: internal/db/db.go:95
msgid "Database version mismatch; resetting"
msgstr "Несоответствие версий базы данных; сброс настроек"
-#: internal/db/db.go:144
+#: internal/db/db.go:101
msgid ""
"Database version does not exist. Run alr fix if something isn't working."
msgstr ""
@@ -445,11 +441,11 @@ msgstr "Ошибка при получении пакетов для обнов
msgid "No packages for upgrade"
msgstr "Нет пакетов к обновлению"
-#: list.go:102 list.go:187
+#: list.go:102 list.go:184
msgid "Error parsing format template"
msgstr "Ошибка при разборе шаблона"
-#: list.go:108 list.go:191
+#: list.go:108 list.go:188
msgid "Error executing template"
msgstr "Ошибка при выполнении шаблона"
@@ -573,6 +569,9 @@ msgstr "Ошибка при проверке обновлений"
msgid "There is nothing to do."
msgstr "Здесь нечего делать."
+#~ msgid "Error iterating over packages"
+#~ msgstr "Ошибка при переборе пакетов"
+
#~ msgid "Error pulling repos"
#~ msgstr "Ошибка при извлечении репозиториев"
diff --git a/list.go b/list.go
index 5b809eb..4fbcd14 100644
--- a/list.go
+++ b/list.go
@@ -125,7 +125,6 @@ func ListCmd() *cli.Command {
if err != nil {
return cliutils.FormatCliExit(gotext.Get("Error getting packages"), err)
}
- defer result.Close()
installedAlrPackages := map[string]string{}
if c.Bool("installed") {
@@ -150,9 +149,7 @@ func ListCmd() *cli.Command {
}
}
- for result.Next() {
- var pkg database.Package
- err := result.StructScan(&pkg)
+ for _, pkg := range result {
if err != nil {
return cli.Exit(err, 1)
}