1
1
package nix
2
2
3
3
import (
4
+ "bytes"
4
5
"encoding/json"
5
6
"fmt"
6
7
"os"
7
8
"os/exec"
9
+ "path/filepath"
8
10
"strings"
9
11
10
12
"github.com/pkg/errors"
11
13
"go.jetpack.io/devbox/internal/debug"
14
+ "go.jetpack.io/devbox/internal/xdg"
12
15
)
13
16
14
17
var (
@@ -19,10 +22,10 @@ var (
19
22
type Info struct {
20
23
// attribute key is different in flakes vs legacy so we should only use it
21
24
// if we know exactly which version we are using
22
- AttributeKey string
23
- PName string
24
- Summary string
25
- Version string
25
+ AttributeKey string `json:"attribute"`
26
+ PName string `json:"pname"`
27
+ Summary string `json:"summary"`
28
+ Version string `json:"version"`
26
29
}
27
30
28
31
func (i * Info ) String () string {
@@ -34,7 +37,7 @@ func Search(url string) (map[string]*Info, error) {
34
37
// TODO implement runx search
35
38
return map [string ]* Info {}, nil
36
39
}
37
- return searchSystem (url , "" )
40
+ return searchSystemUsingCache (url , "" )
38
41
}
39
42
40
43
func parseSearchResults (data []byte ) map [string ]* Info {
@@ -106,3 +109,75 @@ func searchSystem(url, system string) (map[string]*Info, error) {
106
109
}
107
110
return parseSearchResults (out ), nil
108
111
}
112
+
113
+ type searchSystemCache struct {
114
+ QueryToInfo map [string ]map [string ]* Info `json:"query_to_info"`
115
+ }
116
+
117
+ const (
118
+ searchSystemCacheSubDir = "devbox/nix"
119
+ searchSystemCacheFileName = "search-system-cache.json"
120
+ )
121
+
122
+ var cache = searchSystemCache {}
123
+
124
+ func searchSystemUsingCache (url , system string ) (map [string ]* Info , error ) {
125
+ if system != "" {
126
+ return searchSystem (url , system )
127
+ }
128
+
129
+ if cache .QueryToInfo == nil {
130
+ contents , err := readSearchSystemCacheFile ()
131
+ if err != nil {
132
+ return nil , err
133
+ }
134
+ cache .QueryToInfo = contents
135
+ }
136
+
137
+ if result := cache .QueryToInfo [url ]; result != nil {
138
+ return result , nil
139
+ }
140
+
141
+ info , err := searchSystem (url , system )
142
+ if err != nil {
143
+ return nil , err
144
+ }
145
+
146
+ cache .QueryToInfo [url ] = info
147
+ if err := writeSearchSystemCacheFile (cache .QueryToInfo ); err != nil {
148
+ return nil , err
149
+ }
150
+
151
+ return info , nil
152
+ }
153
+
154
+ func readSearchSystemCacheFile () (map [string ]map [string ]* Info , error ) {
155
+ contents , err := os .ReadFile (xdg .CacheSubpath (filepath .Join (searchSystemCacheSubDir , searchSystemCacheFileName )))
156
+ if err != nil {
157
+ if os .IsNotExist (err ) {
158
+ return make (map [string ]map [string ]* Info ), nil
159
+ }
160
+ return nil , err
161
+ }
162
+ var result map [string ]map [string ]* Info
163
+ if err := json .Unmarshal (contents , & result ); err != nil {
164
+ return nil , err
165
+ }
166
+ return result , nil
167
+ }
168
+
169
+ func writeSearchSystemCacheFile (contents map [string ]map [string ]* Info ) error {
170
+ buf := bytes.Buffer {}
171
+ enc := json .NewEncoder (& buf )
172
+ enc .SetIndent ("" , " " )
173
+ err := enc .Encode (contents )
174
+ if err != nil {
175
+ return err
176
+ }
177
+ dir := xdg .CacheSubpath (searchSystemCacheSubDir )
178
+ if err := os .MkdirAll (dir , 0o755 ); err != nil {
179
+ return err
180
+ }
181
+ path := filepath .Join (dir , searchSystemCacheFileName )
182
+ return os .WriteFile (path , buf .Bytes (), 0o644 )
183
+ }
0 commit comments