-
Notifications
You must be signed in to change notification settings - Fork 54
/
driver_install.go
179 lines (150 loc) · 4.42 KB
/
driver_install.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
package cmd
import (
"context"
"fmt"
"os"
"strings"
"sync"
"time"
"github.com/bblfsh/bblfshd/daemon/protocol"
"gopkg.in/bblfsh/sdk.v1/manifest/discovery"
"github.com/briandowns/spinner"
)
var (
// DefaultTransport is the default transport used when is missing on the
// image reference.
DefaultTransport = "docker://"
SupportedTransports = map[string]bool{
"docker": true,
"docker-daemon": true,
}
)
var (
drivers struct {
sync.Once
List []discovery.Driver
}
)
func getOfficialDrivers() []discovery.Driver {
drivers.Do(func() {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
list, err := discovery.OfficialDrivers(ctx, &discovery.Options{
NoMaintainers: true,
})
if err != nil {
fmt.Fprintf(os.Stderr, "Error, %s\n", err)
} else {
drivers.List = list
}
})
return drivers.List
}
func driverImage(id string) string {
return fmt.Sprintf("docker://bblfsh/%s-driver:latest", id)
}
// allDrivers returns the list of all the official bblfsh drivers that are usable.
func allDrivers() map[string]string {
list := getOfficialDrivers()
m := make(map[string]string, len(list))
for _, d := range list {
if d.InDevelopment() {
continue
}
m[d.Language] = driverImage(d.Language)
}
return m
}
// recommendedDrivers returns the list of drivers in beta state or better.
func recommendedDrivers() map[string]string {
list := getOfficialDrivers()
m := make(map[string]string, len(list))
for _, d := range list {
if !d.IsRecommended() {
continue
}
m[d.Language] = driverImage(d.Language)
}
return m
}
const (
DriverInstallCommandDescription = "Installs a new driver for a given language"
DriverInstallCommandHelp = DriverInstallCommandDescription + "\n\n" +
"Using `--all` all the official bblfsh driver are install in the \n" +
"daemon. Using `--recommended` will only install the recommended, \n" +
"more developed. Using `language` and `image` positional arguments \n" +
"one single driver can be installed or updated.\n\n" +
"Image reference format should be `[transport]name[:tag]`.\n" +
"Defaults are 'docker://' for transport and 'latest' for tag."
)
type DriverInstallCommand struct {
Args struct {
Language string `positional-arg-name:"language" description:"language supported by the driver"`
ImageReference string `positional-arg-name:"image" description:"driver's image reference"`
} `positional-args:"yes"`
Update bool `long:"update" description:"replace the current image for the language if any"`
All bool `long:"all" description:"installs all the official drivers"`
Recommended bool `long:"recommended" description:"install the recommended official drivers"`
DriverCommand
}
func (c *DriverInstallCommand) Execute(args []string) error {
if err := c.Validate(); err != nil {
return err
}
if err := c.ControlCommand.Execute(nil); err != nil {
return err
}
if c.All {
for lang, image := range allDrivers() {
if err := c.installDriver(lang, image); err != nil {
return err
}
}
} else if c.Recommended {
for lang, image := range recommendedDrivers() {
if err := c.installDriver(lang, image); err != nil {
return err
}
}
} else {
return c.installDriver(c.Args.Language, c.Args.ImageReference)
}
return nil
}
func (c *DriverInstallCommand) Validate() error {
if !c.All && !c.Recommended && (c.Args.Language == "" || c.Args.ImageReference == "") {
return fmt.Errorf("error `language` and `image` positional arguments are mandatory")
}
if c.All && c.Recommended {
return fmt.Errorf("error --all and --recommended are exclusive")
}
return nil
}
func (c *DriverInstallCommand) installDriver(lang, ref string) error {
fmt.Printf("Installing %s language driver from %q... ", lang, ref)
s := spinner.New(spinner.CharSets[9], 100*time.Millisecond) // Build our new spinner
s.Start()
ref = c.getImageReference(ref)
r, err := c.srv.InstallDriver(context.Background(), &protocol.InstallDriverRequest{
Language: lang,
ImageReference: ref,
Update: c.Update,
})
s.Stop()
if err == nil && len(r.Errors) == 0 {
fmt.Println("Done")
return nil
}
fmt.Println("Error")
for _, e := range r.Errors {
fmt.Fprintf(os.Stderr, "Error, %s\n", e)
}
return err
}
func (c *DriverInstallCommand) getImageReference(ref string) string {
parts := strings.SplitN(ref, ":", 2)
if _, ok := SupportedTransports[parts[0]]; !ok {
return DefaultTransport + ref
}
return ref
}