diff --git a/client/changes.go b/client/changes.go index 47fdfd84f..5f096b031 100644 --- a/client/changes.go +++ b/client/changes.go @@ -89,7 +89,7 @@ type changeAndData struct { // Change fetches information about a Change given its ID. func (client *Client) Change(id string) (*Change, error) { var chgd changeAndData - _, err := client.doSync("GET", "/v1/changes/"+id, nil, nil, nil, &chgd) + _, err := client.DoSync("GET", "/v1/changes/"+id, nil, nil, nil, &chgd) if err != nil { return nil, err } @@ -111,7 +111,7 @@ func (client *Client) Abort(id string) (*Change, error) { } var chg Change - if _, err := client.doSync("POST", "/v1/changes/"+id, nil, nil, &body, &chg); err != nil { + if _, err := client.DoSync("POST", "/v1/changes/"+id, nil, nil, &body, &chg); err != nil { return nil, err } @@ -158,7 +158,7 @@ func (client *Client) Changes(opts *ChangesOptions) ([]*Change, error) { } var chgds []changeAndData - _, err := client.doSync("GET", "/v1/changes", query, nil, nil, &chgds) + _, err := client.DoSync("GET", "/v1/changes", query, nil, nil, &chgds) if err != nil { return nil, err } @@ -190,7 +190,7 @@ func (client *Client) WaitChange(id string, opts *WaitChangeOptions) (*Change, e query.Set("timeout", opts.Timeout.String()) } - _, err := client.doSync("GET", "/v1/changes/"+id+"/wait", query, nil, nil, &chgd) + _, err := client.DoSync("GET", "/v1/changes/"+id+"/wait", query, nil, nil, &chgd) if err != nil { return nil, err } diff --git a/client/checks.go b/client/checks.go index b86d656be..31ede6246 100644 --- a/client/checks.go +++ b/client/checks.go @@ -79,7 +79,7 @@ func (client *Client) Checks(opts *ChecksOptions) ([]*CheckInfo, error) { query["names"] = opts.Names } var checks []*CheckInfo - _, err := client.doSync("GET", "/v1/checks", query, nil, nil, &checks) + _, err := client.DoSync("GET", "/v1/checks", query, nil, nil, &checks) if err != nil { return nil, err } diff --git a/client/client.go b/client/client.go index 0e9cce91a..27fccb5bb 100644 --- a/client/client.go +++ b/client/client.go @@ -87,6 +87,11 @@ type doer interface { Do(*http.Request) (*http.Response, error) } +type ClientGetter interface { + // GetClient obtains a Pebble Client struct. + Client() *Client +} + // Config allows the user to customize client behavior. type Config struct { // BaseURL contains the base URL where the Pebble daemon is expected to be. @@ -118,6 +123,10 @@ type Client struct { getWebsocket getWebsocketFunc } +func (c *Client) Client() *Client { + return c +} + type getWebsocketFunc func(url string) (clientWebsocket, error) type clientWebsocket interface { @@ -326,11 +335,11 @@ func decodeInto(reader io.Reader, v interface{}) error { return nil } -// doSync performs a request to the given path using the specified HTTP method. +// DoSync performs a request to the given path using the specified HTTP method. // It expects a "sync" response from the API and on success decodes the JSON // response payload into the given value using the "UseNumber" json decoding // which produces json.Numbers instead of float64 types for numbers. -func (client *Client) doSync(method, path string, query url.Values, headers map[string]string, body io.Reader, v interface{}) (*ResultInfo, error) { +func (client *Client) DoSync(method, path string, query url.Values, headers map[string]string, body io.Reader, v interface{}) (*ResultInfo, error) { var rsp response if err := client.do(method, path, query, headers, body, &rsp); err != nil { return nil, err @@ -476,7 +485,7 @@ type SysInfo struct { func (client *Client) SysInfo() (*SysInfo, error) { var sysInfo SysInfo - if _, err := client.doSync("GET", "/v1/system-info", nil, nil, nil, &sysInfo); err != nil { + if _, err := client.DoSync("GET", "/v1/system-info", nil, nil, nil, &sysInfo); err != nil { return nil, fmt.Errorf("cannot obtain system details: %w", err) } @@ -498,7 +507,7 @@ func (client *Client) DebugPost(action string, params interface{}, result interf return err } - _, err = client.doSync("POST", "/v1/debug", nil, nil, bytes.NewReader(body), result) + _, err = client.DoSync("POST", "/v1/debug", nil, nil, bytes.NewReader(body), result) return err } @@ -508,6 +517,6 @@ func (client *Client) DebugGet(action string, result interface{}, params map[str for k, v := range params { urlParams.Set(k, v) } - _, err := client.doSync("GET", "/v1/debug", urlParams, nil, nil, &result) + _, err := client.DoSync("GET", "/v1/debug", urlParams, nil, nil, &result) return err } diff --git a/client/files.go b/client/files.go index cce33414d..8d8794ca5 100644 --- a/client/files.go +++ b/client/files.go @@ -121,7 +121,7 @@ func (client *Client) ListFiles(opts *ListFilesOptions) ([]*FileInfo, error) { } var results []fileInfoResult - _, err := client.doSync("GET", "/v1/files", q, nil, nil, &results) + _, err := client.DoSync("GET", "/v1/files", q, nil, nil, &results) if err != nil { return nil, err } @@ -280,7 +280,7 @@ func (client *Client) MakeDir(opts *MakeDirOptions) error { headers := map[string]string{ "Content-Type": "application/json", } - if _, err := client.doSync("POST", "/v1/files", nil, headers, &body, &result); err != nil { + if _, err := client.DoSync("POST", "/v1/files", nil, headers, &body, &result); err != nil { return err } @@ -347,7 +347,7 @@ func (client *Client) RemovePath(opts *RemovePathOptions) error { headers := map[string]string{ "Content-Type": "application/json", } - if _, err := client.doSync("POST", "/v1/files", nil, headers, &body, &result); err != nil { + if _, err := client.DoSync("POST", "/v1/files", nil, headers, &body, &result); err != nil { return err } diff --git a/client/plan.go b/client/plan.go index 25b447f08..a8d286c1e 100644 --- a/client/plan.go +++ b/client/plan.go @@ -52,7 +52,7 @@ func (client *Client) AddLayer(opts *AddLayerOptions) error { if err := json.NewEncoder(&body).Encode(&payload); err != nil { return err } - _, err := client.doSync("POST", "/v1/layers", nil, nil, &body, nil) + _, err := client.DoSync("POST", "/v1/layers", nil, nil, &body, nil) return err } @@ -64,7 +64,7 @@ func (client *Client) PlanBytes(_ *PlanOptions) (data []byte, err error) { "format": []string{"yaml"}, } var dataStr string - _, err = client.doSync("GET", "/v1/plan", query, nil, nil, &dataStr) + _, err = client.DoSync("GET", "/v1/plan", query, nil, nil, &dataStr) if err != nil { return nil, err } diff --git a/client/services.go b/client/services.go index 0be19d23e..8161f4a23 100644 --- a/client/services.go +++ b/client/services.go @@ -119,7 +119,7 @@ func (client *Client) Services(opts *ServicesOptions) ([]*ServiceInfo, error) { "names": []string{strings.Join(opts.Names, ",")}, } var services []*ServiceInfo - _, err := client.doSync("GET", "/v1/services", query, nil, nil, &services) + _, err := client.DoSync("GET", "/v1/services", query, nil, nil, &services) if err != nil { return nil, err } diff --git a/client/signals.go b/client/signals.go index 9452ad4f8..2c78a92c2 100644 --- a/client/signals.go +++ b/client/signals.go @@ -36,7 +36,7 @@ func (client *Client) SendSignal(opts *SendSignalOptions) error { if err != nil { return fmt.Errorf("cannot encode JSON payload: %w", err) } - _, err = client.doSync("POST", "/v1/signals", nil, nil, &body, nil) + _, err = client.DoSync("POST", "/v1/signals", nil, nil, &body, nil) return err } diff --git a/client/warnings.go b/client/warnings.go index d63da1238..9f30b8a5a 100644 --- a/client/warnings.go +++ b/client/warnings.go @@ -52,7 +52,7 @@ func (client *Client) Warnings(opts WarningsOptions) ([]*Warning, error) { if opts.All { q.Add("select", "all") } - _, err := client.doSync("GET", "/v1/warnings", q, nil, nil, &jws) + _, err := client.DoSync("GET", "/v1/warnings", q, nil, nil, &jws) ws := make([]*Warning, len(jws)) for i, jw := range jws { @@ -77,6 +77,6 @@ func (client *Client) Okay(t time.Time) error { if err := json.NewEncoder(&body).Encode(op); err != nil { return err } - _, err := client.doSync("POST", "/v1/warnings", nil, nil, &body, nil) + _, err := client.DoSync("POST", "/v1/warnings", nil, nil, &body, nil) return err } diff --git a/internals/cli/cli.go b/internals/cli/cli.go index e35a2baa4..d98ebf508 100644 --- a/internals/cli/cli.go +++ b/internals/cli/cli.go @@ -141,15 +141,15 @@ func fixupArg(optName string) string { } type clientSetter interface { - setClient(*client.Client) + setClient(client.ClientGetter) } -type clientMixin struct { - client *client.Client +type ClientMixin struct { + client.ClientGetter } -func (ch *clientMixin) setClient(cli *client.Client) { - ch.client = cli +func (ch *ClientMixin) setClient(cg client.ClientGetter) { + ch.ClientGetter = cg } type parserSetter interface { @@ -163,11 +163,11 @@ type defaultOptions struct { // Parser creates and populates a fresh parser. // Since commands have local state a fresh parser is required to isolate tests // from each other. -func Parser(cli *client.Client) *flags.Parser { +func Parser(cg client.ClientGetter) *flags.Parser { // Implement --version by default on every command defaultOpts := defaultOptions{ Version: func() { - printVersions(cli) + printVersions(cg.Client()) panic(&exitStatus{0}) }, } @@ -195,7 +195,7 @@ func Parser(cli *client.Client) *flags.Parser { for _, c := range commands { obj := c.Builder() if x, ok := obj.(clientSetter); ok { - x.setClient(cli) + x.setClient(cg) } if x, ok := obj.(parserSetter); ok { x.setParser(parser) @@ -276,7 +276,7 @@ func (e *exitStatus) Error() string { return fmt.Sprintf("internal error: exitStatus{%d} being handled as normal error", e.code) } -func Run() error { +func RunWithClient(cg client.ClientGetter) error { defer func() { if v := recover(); v != nil { if e, ok := v.(*exitStatus); ok { @@ -288,14 +288,7 @@ func Run() error { logger.SetLogger(logger.New(os.Stderr, "[pebble] ")) - _, clientConfig.Socket = getEnvPaths() - - cli, err := client.New(&clientConfig) - if err != nil { - return fmt.Errorf("cannot create client: %v", err) - } - - parser := Parser(cli) + parser := Parser(cg) xtra, err := parser.Parse() if err != nil { if e, ok := err.(*flags.Error); ok { @@ -328,8 +321,19 @@ func Run() error { return nil } - maybePresentWarnings(cli.WarningsSummary()) + return nil +} +func Run() error { + _, clientConfig.Socket = getEnvPaths() + cli, err := client.New(&clientConfig) + if err != nil { + return fmt.Errorf("cannot create client: %v", err) + } + if err := RunWithClient(cli); err != nil { + return err + } + maybePresentWarnings(cli.WarningsSummary()) return nil } diff --git a/internals/cli/cmd_add.go b/internals/cli/cmd_add.go index 88c01c127..b40be8a42 100644 --- a/internals/cli/cmd_add.go +++ b/internals/cli/cmd_add.go @@ -31,7 +31,7 @@ label (or append if the label is not found). ` type cmdAdd struct { - clientMixin + ClientMixin Combine bool `long:"combine"` Positional struct { Label string `positional-arg-name:"