-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathclient.go
More file actions
224 lines (194 loc) · 6 KB
/
client.go
File metadata and controls
224 lines (194 loc) · 6 KB
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
package dagger
import (
"context"
"io"
"github.com/Khan/genqlient/graphql"
"github.com/vektah/gqlparser/v2/gqlerror"
"dagger.io/dagger/engineconn"
"dagger.io/dagger/querybuilder"
)
// Client is the Dagger Engine Client
type Client struct {
*Query
conn engineconn.EngineConn
client graphql.Client
}
// ClientOpt holds a client option
type ClientOpt interface {
setClientOpt(cfg *engineconn.Config)
}
type clientOptFunc func(cfg *engineconn.Config)
func (fn clientOptFunc) setClientOpt(cfg *engineconn.Config) {
fn(cfg)
}
// WithWorkdir sets the engine workdir
func WithWorkdir(path string) ClientOpt {
return clientOptFunc(func(cfg *engineconn.Config) {
cfg.Workdir = path
})
}
// WithWorkspace sets the workspace binding for the engine session.
//
// The ref may be either a local path or a remote git ref.
//
// This only has effect when connecting via the CLI.
func WithWorkspace(ref string) ClientOpt {
return clientOptFunc(func(cfg *engineconn.Config) {
cfg.Workspace = ref
})
}
// WithLogOutput sets the progress writer
func WithLogOutput(writer io.Writer) ClientOpt {
return clientOptFunc(func(cfg *engineconn.Config) {
cfg.LogOutput = writer
})
}
// WithLoadWorkspaceModules opts this client into loading workspace modules
// based on the working directory when the session is created via the CLI.
func WithLoadWorkspaceModules() ClientOpt {
return clientOptFunc(func(cfg *engineconn.Config) {
cfg.LoadWorkspaceModules = true
})
}
// WithConn sets the engine connection explicitly
func WithConn(conn engineconn.EngineConn) ClientOpt {
return clientOptFunc(func(cfg *engineconn.Config) {
cfg.Conn = conn
})
}
// WithVersionOverride requests a specific schema version from the engine.
// Calling this may cause the schema to be out-of-sync from the codegen - this
// option is likely *not* desirable for most use cases.
//
// This only has effect when connecting via the CLI, and is only exposed for
// testing purposes.
func WithVersionOverride(version string) ClientOpt {
return clientOptFunc(func(cfg *engineconn.Config) {
cfg.VersionOverride = version
})
}
// WithVerbosity sets the verbosity level for the progress output
func WithVerbosity(level int) ClientOpt {
return clientOptFunc(func(cfg *engineconn.Config) {
cfg.Verbosity = level
})
}
// WithRunnerHost sets the runner host URL for provisioning and connecting to
// an engine.
//
// This only has effect when connecting via the CLI, and is only exposed for
// testing purposes.
func WithRunnerHost(runnerHost string) ClientOpt {
return clientOptFunc(func(cfg *engineconn.Config) {
cfg.RunnerHost = runnerHost
})
}
// Set this additional environment variable in the CLI subprocess for the session
func WithEnvironmentVariable(key, value string) ClientOpt {
return clientOptFunc(func(cfg *engineconn.Config) {
cfg.ExtraEnv = append(cfg.ExtraEnv, key+"="+value)
})
}
// Deprecated: workspace modules are core-only by default. Use
// WithLoadWorkspaceModules to opt into loading them when needed.
func WithSkipWorkspaceModules() ClientOpt {
return clientOptFunc(func(cfg *engineconn.Config) {
cfg.SkipWorkspaceModules = true
})
}
// Connect to a Dagger Engine
func Connect(ctx context.Context, opts ...ClientOpt) (*Client, error) {
cfg := &engineconn.Config{}
for _, o := range opts {
o.setClientOpt(cfg)
}
conn, err := engineconn.Get(ctx, cfg)
if err != nil {
return nil, err
}
gql := errorWrappedClient{graphql.NewClient("http://"+conn.Host()+"/query", conn)}
c := &Client{
Query: &Query{
query: querybuilder.Query().Client(gql),
},
client: gql,
conn: conn,
}
return c, nil
}
// GraphQLClient returns the underlying graphql.Client
func (c *Client) GraphQLClient() graphql.Client {
return c.client
}
func (c *Client) QueryBuilder() *querybuilder.Selection {
return c.Query.query
}
// Close the engine connection
func (c *Client) Close() error {
if c.conn != nil {
return c.conn.Close()
}
return nil
}
// Do sends a GraphQL request to the engine
func (c *Client) Do(ctx context.Context, req *Request, resp *Response) error {
r := graphql.Response{}
if resp != nil {
r.Data = resp.Data
r.Errors = resp.Errors
r.Extensions = resp.Extensions
}
return c.client.MakeRequest(ctx, &graphql.Request{
Query: req.Query,
Variables: req.Variables,
OpName: req.OpName,
}, &r)
}
// Request contains all the values required to build queries executed by
// the graphql.Client.
//
// Typically, GraphQL APIs will accept a JSON payload of the form
//
// {"query": "query myQuery { ... }", "variables": {...}}`
//
// and Request marshals to this format. However, MakeRequest may
// marshal the data in some other way desired by the backend.
type Request struct {
// The literal string representing the GraphQL query, e.g.
// `query myQuery { myField }`.
Query string `json:"query"`
// A JSON-marshalable value containing the variables to be sent
// along with the query, or nil if there are none.
Variables interface{} `json:"variables,omitempty"`
// The GraphQL operation name. The server typically doesn't
// require this unless there are multiple queries in the
// document, but genqlient sets it unconditionally anyway.
OpName string `json:"operationName"`
}
// Response that contains data returned by the GraphQL API.
//
// Typically, GraphQL APIs will return a JSON payload of the form
//
// {"data": {...}, "errors": {...}}
//
// It may additionally contain a key named "extensions", that
// might hold GraphQL protocol extensions. Extensions and Errors
// are optional, depending on the values returned by the server.
type Response struct {
Data interface{} `json:"data"`
Extensions map[string]interface{} `json:"extensions,omitempty"`
Errors gqlerror.List `json:"errors,omitempty"`
}
type errorWrappedClient struct {
graphql.Client
}
func (c errorWrappedClient) MakeRequest(ctx context.Context, req *graphql.Request, resp *graphql.Response) error {
err := c.Client.MakeRequest(ctx, req, resp)
if err != nil {
if e := getCustomError(err); e != nil {
return e
}
return err
}
return nil
}