forked from burik666/gobin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
module.go
114 lines (89 loc) · 2.78 KB
/
module.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package mod
import (
"bytes"
"encoding/json"
"fmt"
"os"
"os/exec"
"time"
"github.com/burik666/gobin/internal/config"
)
type ModuleInfo struct {
Path string `json:",omitempty"` // module path
Version string `json:",omitempty"` // module version
Versions []string `json:",omitempty"` // available module versions
Replace *ModuleInfo `json:",omitempty"` // replaced by this module
Time *time.Time `json:",omitempty"` // time version was created
Update *ModuleInfo `json:",omitempty"` // available update (with -u)
Main bool `json:",omitempty"` // is this the main module?
Indirect bool `json:",omitempty"` // module is only indirectly needed by main module
Dir string `json:",omitempty"` // directory holding local copy of files, if any
GoMod string `json:",omitempty"` // path to go.mod file describing module, if any
GoVersion string `json:",omitempty"` // go version used in module
Retracted []string `json:",omitempty"` // retraction information, if any (with -retracted or -u)
Deprecated string `json:",omitempty"` // deprecation message, if any (with -u)
Error *ModuleError `json:",omitempty"` // error loading module
}
type ModuleError struct {
Err string // the error itself
}
var (
modulesCache = make(map[string]*ModuleInfo)
moduleErrors = make(map[string]error)
)
func getModuleInfo(path, version string) (rmi *ModuleInfo, rerr error) {
name := fmt.Sprintf("%s@%s", path, version)
if mi, ok := modulesCache[name]; ok {
return mi, nil
}
if err, ok := moduleErrors[name]; ok {
return nil, err
}
defer func() {
if rerr != nil {
moduleErrors[name] = rerr
}
}()
cmd := exec.Command(config.Go, "list", "-json", "-versions", "-m", "-u", name)
if config.Trace {
fmt.Fprintf(os.Stderr, "> %s\n", cmd.String())
}
var errb bytes.Buffer
cmd.Stderr = &errb
data, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("%s", errb.String())
}
fmt.Fprint(os.Stderr, errb.String())
var mi ModuleInfo
if err := json.Unmarshal(data, &mi); err != nil {
return nil, err
}
if mi.Version == "" {
return nil, fmt.Errorf("empty version")
}
modulesCache[name] = &mi
if mi.Update != nil {
mi.Update, err = getModuleInfo(mi.Path, mi.Update.Version)
if err != nil {
return nil, err
}
}
return &mi, nil
}
func Install(path, version string, args []string) error {
name := fmt.Sprintf("%s@%s", path, version)
cmdArgs := []string{"install", "-v"}
cmdArgs = append(cmdArgs, args...)
cmdArgs = append(cmdArgs, name)
cmd := exec.Command(config.Go, cmdArgs...)
if config.Trace {
fmt.Fprintf(os.Stderr, "> %s\n", cmd.String())
}
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
if err := cmd.Run(); err != nil {
return err
}
return nil
}