Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.0.1-2020.1.5 / cmd / go-module-query / main.go
1 package main
2
3 import (
4         "encoding/json"
5         "fmt"
6         "io"
7         "io/ioutil"
8         "log"
9         "net/http"
10         "os"
11         "path"
12         "path/filepath"
13         "strings"
14         "sync"
15         "sync/atomic"
16         "time"
17
18         "github.com/google/renameio"
19         "github.com/rogpeppe/go-internal/modfile"
20         "golang.org/x/mod/module"
21 )
22
23 /*
24 Q: which versions of our module are being used
25 A: find the latest version of every Go module, find the dependency on our module
26
27 Q: what modules have stopped using our module
28 A: find every module where a version [0..N) uses us, but version N doesn't.
29 */
30
31 func Fetch(since time.Time) ([]module.Version, time.Time, error) {
32         var out []module.Version
33         for {
34                 out2, since2, err := fetch(since, out)
35                 if err != nil {
36                         return nil, since, err
37                 }
38                 if len(out) == len(out2) {
39                         break
40                 }
41                 out = out2
42                 since = since2
43         }
44         return out, since, nil
45 }
46
47 func fetch(since time.Time, out []module.Version) ([]module.Version, time.Time, error) {
48         // +1µs because of bug in index.golang.org that returns results
49         // >=since instead of >since
50         ts := since.Add(1 * time.Microsecond)
51         u := `https://index.golang.org/index?since=` + ts.Format(time.RFC3339Nano)
52         resp, err := http.Get(u)
53         if err != nil {
54                 return nil, since, err
55         }
56         defer resp.Body.Close()
57         dec := json.NewDecoder(resp.Body)
58
59         var entry struct {
60                 module.Version
61                 Timestamp time.Time
62         }
63         for {
64                 if err := dec.Decode(&entry); err != nil {
65                         if err == io.EOF {
66                                 break
67                         }
68                         return out, since, err
69                 }
70
71                 out = append(out, entry.Version)
72                 since = entry.Timestamp
73         }
74
75         return out, since, nil
76 }
77
78 func main() {
79         cache, err := os.UserCacheDir()
80         if err != nil {
81                 log.Fatal(err)
82         }
83
84         var since time.Time
85         b, err := ioutil.ReadFile(filepath.Join(cache, "go-module-query", "last"))
86         if err == nil {
87                 t, err := time.Parse(time.RFC3339Nano, string(b))
88                 if err != nil {
89                         log.Fatal(err)
90                 }
91                 since = t
92                 log.Println("Resuming at", since)
93         } else if !os.IsNotExist(err) {
94                 log.Fatal(err)
95         }
96
97         out, since, err := Fetch(since)
98         if err != nil {
99                 log.Fatal(err)
100         }
101
102         sem := make(chan struct{}, 8)
103         var wg sync.WaitGroup
104         var errs uint64
105         for _, v := range out {
106                 mpath, _ := module.EscapePath(v.Path)
107                 p := filepath.Join(cache, "go-module-query", mpath, "@v", v.Version+".mod")
108                 // XXX is this atomic?
109                 if err := os.MkdirAll(filepath.Join(cache, "go-module-query", mpath, "@v"), 0777); err != nil {
110                         log.Println(err)
111                         continue
112                 }
113                 if _, err := os.Stat(p); os.IsNotExist(err) {
114                         fmt.Println("Fetching", v)
115                         sem <- struct{}{}
116                         wg.Add(1)
117                         go func(p string, v module.Version) {
118                                 defer wg.Done()
119                                 defer func() { <-sem }()
120                                 resp, err := http.Get("https://proxy.golang.org/" + path.Join(mpath, "@v", v.Version+".mod"))
121                                 if err != nil {
122                                         atomic.AddUint64(&errs, 1)
123                                         log.Println(err)
124                                         return
125                                 }
126                                 defer resp.Body.Close()
127                                 // XXX handle response code
128                                 pf, err := renameio.TempFile("", p)
129                                 if err != nil {
130                                         atomic.AddUint64(&errs, 1)
131                                         log.Println(err)
132                                         return
133                                 }
134                                 defer pf.Cleanup()
135                                 if _, err := io.Copy(pf, resp.Body); err != nil {
136                                         atomic.AddUint64(&errs, 1)
137                                         log.Println(err)
138                                         return
139                                 }
140                                 if err := pf.CloseAtomicallyReplace(); err != nil {
141                                         atomic.AddUint64(&errs, 1)
142                                         log.Println("Couldn't store go.mod:", err)
143                                 }
144                         }(p, v)
145                 }
146         }
147
148         wg.Wait()
149
150         if errs > 0 {
151                 log.Println("Couldn't download all go.mod, not storing timestamp")
152                 return
153         }
154
155         if err := renameio.WriteFile(filepath.Join(cache, "go-module-query", "last"), []byte(since.Format(time.RFC3339Nano)), 0666); err != nil {
156                 log.Println("Couldn't store timestamp:", err)
157         }
158 }
159
160 func printGraph() {
161         cache, err := os.UserCacheDir()
162         if err != nil {
163                 log.Fatal(err)
164         }
165         filepath.Walk(filepath.Join(cache, "go-module-query"), func(path string, info os.FileInfo, err error) error {
166                 if err != nil {
167                         return nil
168                 }
169                 if strings.HasSuffix(path, ".mod") {
170                         name := filepath.Base(path)
171                         name = name[:len(name)-4]
172                         b, err := ioutil.ReadFile(path)
173                         if err != nil {
174                                 log.Println(err)
175                                 return nil
176                         }
177                         f, err := modfile.Parse(path, b, nil)
178                         if err != nil {
179                                 log.Println(err)
180                                 return nil
181                         }
182                         f.Module.Mod.Version = name
183                         for _, dep := range f.Require {
184                                 fmt.Printf("%s@%s %s@%s\n", f.Module.Mod.Path, f.Module.Mod.Version, dep.Mod.Path, dep.Mod.Version)
185                         }
186                 }
187                 return nil
188         })
189 }