Merge pull request #5786 from overbool/refactor/cmds/rm-old-lib

cmds: rm old lib
This commit is contained in:
Steven Allen 2018-11-27 21:33:01 -08:00 committed by GitHub
commit 496f1d1230
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 7 additions and 901 deletions

View File

@ -1,68 +0,0 @@
/*
Package commands provides an API for defining and parsing commands.
Supporting nested commands, options, arguments, etc. The commands
package also supports a collection of marshallers for presenting
output to the user, including text, JSON, and XML marshallers.
*/
package commands
import (
"io"
logging "gx/ipfs/QmcuXC5cxs79ro2cUuHs4HQ2bkDLJUYokwL8aivcX6HW3C/go-log"
cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
)
var log = logging.Logger("command")
// Function is the type of function that Commands use.
// It reads from the Request, and writes results to the Response.
type Function func(Request, Response)
// Marshaler is a function that takes in a Response, and returns an io.Reader
// (or an error on failure)
type Marshaler func(Response) (io.Reader, error)
// MarshalerMap is a map of Marshaler functions, keyed by EncodingType
// (or an error on failure)
type MarshalerMap map[EncodingType]Marshaler
// Command is a runnable command, with input arguments and options (flags).
// It can also have Subcommands, to group units of work into sets.
type Command struct {
Options []cmdkit.Option
Arguments []cmdkit.Argument
PreRun func(req Request) error
// Run is the function that processes the request to generate a response.
// Note that when executing the command over the HTTP API you can only read
// after writing when using multipart requests. The request body will not be
// available for reading after the HTTP connection has been written to.
Run Function
PostRun Function
Marshalers map[EncodingType]Marshaler
Helptext cmdkit.HelpText
// External denotes that a command is actually an external binary.
// fewer checks and validations will be performed on such commands.
External bool
// Type describes the type of the output of the Command's Run Function.
// In precise terms, the value of Type is an instance of the return type of
// the Run Function.
//
// ie. If command Run returns &Block{}, then Command.Type == &Block{}
Type interface{}
Subcommands map[string]*Command
}
// Subcommand returns the subcommand with the given id
func (c *Command) Subcommand(id string) *Command {
return c.Subcommands[id]
}
func ClientError(msg string) error {
return &cmdkit.Error{Code: cmdkit.ErrClient, Message: msg}
}

View File

@ -11,11 +11,13 @@ import (
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
config "gx/ipfs/QmXctaABKwgzmQgNM4bucMJf7zJnxxvhmPM1Pw95dxUfB5/go-ipfs-config"
files "gx/ipfs/QmZMWMvWMVKCbHetJ4RgndbuEF1io2UpUxwQwtNjtYPzSC/go-ipfs-files"
"gx/ipfs/Qma6uuSyjkecGhMFFLfzyJDPyoDtNJSHJNweDccZhaWkgU/go-ipfs-cmds"
"gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
logging "gx/ipfs/QmcuXC5cxs79ro2cUuHs4HQ2bkDLJUYokwL8aivcX6HW3C/go-log"
)
var log = logging.Logger("command")
// Context represents request context
type Context struct {
Online bool
ConfigRoot string
@ -55,9 +57,9 @@ func (c *Context) GetNode() (*core.IpfsNode, error) {
return c.node, err
}
// GetApi returns CoreAPI instance backed by ipfs node.
// GetAPI returns CoreAPI instance backed by ipfs node.
// It may construct the node with the provided function
func (c *Context) GetApi() (coreiface.CoreAPI, error) {
func (c *Context) GetAPI() (coreiface.CoreAPI, error) {
if c.api == nil {
n, err := c.GetNode()
if err != nil {
@ -109,16 +111,3 @@ func (c *Context) Close() {
c.node.Close()
}
}
// Request represents a call to a command from a consumer
type Request interface {
Path() []string
Option(name string) *cmdkit.OptionValue
Options() cmdkit.OptMap
Arguments() []string
StringArguments() []string
Files() files.File
Context() context.Context
InvocContext() *Context
Command() *Command
}

View File

@ -1,68 +0,0 @@
package legacy
import (
"io"
oldcmds "github.com/ipfs/go-ipfs/commands"
"gx/ipfs/Qma6uuSyjkecGhMFFLfzyJDPyoDtNJSHJNweDccZhaWkgU/go-ipfs-cmds"
logging "gx/ipfs/QmcuXC5cxs79ro2cUuHs4HQ2bkDLJUYokwL8aivcX6HW3C/go-log"
)
var log = logging.Logger("cmds/lgc")
// NewCommand returns a Command from an oldcmds.Command
func NewCommand(oldcmd *oldcmds.Command) *cmds.Command {
if oldcmd == nil {
return nil
}
var cmd *cmds.Command
cmd = &cmds.Command{
Options: oldcmd.Options,
Arguments: oldcmd.Arguments,
Helptext: oldcmd.Helptext,
External: oldcmd.External,
Type: oldcmd.Type,
Subcommands: make(map[string]*cmds.Command),
}
if oldcmd.Run != nil {
cmd.Run = func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error {
oldReq := &requestWrapper{req, OldContext(env)}
res := &fakeResponse{req: oldReq, re: re, wait: make(chan struct{})}
errCh := make(chan error)
go res.Send(errCh)
oldcmd.Run(oldReq, res)
return <-errCh
}
}
if oldcmd.PreRun != nil {
cmd.PreRun = func(req *cmds.Request, env cmds.Environment) error {
oldReq := &requestWrapper{req, OldContext(env)}
return oldcmd.PreRun(oldReq)
}
}
for name, sub := range oldcmd.Subcommands {
cmd.Subcommands[name] = NewCommand(sub)
}
cmd.Encoders = make(cmds.EncoderMap)
for encType, m := range oldcmd.Marshalers {
cmd.Encoders[cmds.EncodingType(encType)] = func(m oldcmds.Marshaler, encType oldcmds.EncodingType) func(req *cmds.Request) func(io.Writer) cmds.Encoder {
return func(req *cmds.Request) func(io.Writer) cmds.Encoder {
return func(w io.Writer) cmds.Encoder {
return NewMarshalerEncoder(req, m, w)
}
}
}(m, encType)
}
return cmd
}

View File

@ -1,57 +0,0 @@
package legacy
import (
"io"
"runtime/debug"
"gx/ipfs/Qma6uuSyjkecGhMFFLfzyJDPyoDtNJSHJNweDccZhaWkgU/go-ipfs-cmds"
oldcmds "github.com/ipfs/go-ipfs/commands"
)
// MarshalerEncoder implements Encoder from a Marshaler
type MarshalerEncoder struct {
m oldcmds.Marshaler
w io.Writer
req *cmds.Request
}
// NewMarshalerEncoder returns a new MarshalerEncoder
func NewMarshalerEncoder(req *cmds.Request, m oldcmds.Marshaler, w io.Writer) *MarshalerEncoder {
me := &MarshalerEncoder{
m: m,
w: w,
req: req,
}
return me
}
// Encode encodes v onto the io.Writer w using Marshaler m, with both m and w passed in NewMarshalerEncoder
func (me *MarshalerEncoder) Encode(v interface{}) error {
re, res := cmds.NewChanResponsePair(me.req)
go re.Emit(v)
r, err := me.m(&responseWrapper{Response: res})
if err != nil {
return err
}
if r == nil {
// behave like empty reader
return nil
}
_, err = io.Copy(me.w, r)
return err
}
// OldContext tries to cast the environment as a legacy command context,
// returning nil on failure.
func OldContext(env interface{}) *oldcmds.Context {
ctx, ok := env.(*oldcmds.Context)
if !ok {
log.Errorf("OldContext: env passed is not %T but %T\n%s", ctx, env, debug.Stack())
}
return ctx
}

View File

@ -1,215 +0,0 @@
package legacy
import (
"bytes"
"context"
"io"
"testing"
oldcmds "github.com/ipfs/go-ipfs/commands"
cmds "gx/ipfs/Qma6uuSyjkecGhMFFLfzyJDPyoDtNJSHJNweDccZhaWkgU/go-ipfs-cmds"
cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
)
type WriteNopCloser struct {
io.Writer
}
func (wc WriteNopCloser) Close() error {
return nil
}
func TestNewCommand(t *testing.T) {
root := &cmds.Command{
Subcommands: map[string]*cmds.Command{
"test": NewCommand(&oldcmds.Command{
Run: func(req oldcmds.Request, res oldcmds.Response) {
res.SetOutput("Test.")
},
Marshalers: map[oldcmds.EncodingType]oldcmds.Marshaler{
oldcmds.Text: func(res oldcmds.Response) (io.Reader, error) {
ch, ok := res.Output().(<-chan interface{})
if !ok {
t.Fatalf("output is not <-chan interface{} but %T", ch)
}
v := <-ch
str, ok := v.(string)
if !ok {
t.Fatalf("read value is not string but %T", v)
}
buf := bytes.NewBuffer(nil)
_, err := io.WriteString(buf, str)
if err != nil {
t.Fatal(err)
}
return buf, nil
},
},
Subcommands: map[string]*oldcmds.Command{
"sub": &oldcmds.Command{
Options: []cmdkit.Option{
cmdkit.NewOption(cmdkit.String, "test", "t", "some random test flag"),
},
},
},
}),
},
}
path := []string{"test"}
req, err := cmds.NewRequest(context.TODO(), path, nil, nil, nil, root)
if err != nil {
t.Fatal(err)
}
buf := bytes.NewBuffer(nil)
// test calling "test" command
testCmd := root.Subcommands["test"]
re, err := cmds.NewWriterResponseEmitter(WriteNopCloser{buf}, req)
if err != nil {
t.Fatal(err)
}
var env oldcmds.Context
root.Call(req, re, &env)
expected := `"Test."
`
if buf.String() != expected {
t.Fatalf("expected string %#v but got %#v", expected, buf.String())
}
// test getting subcommand
subCmd := testCmd.Subcommands["sub"]
if subCmd == nil {
t.Fatal("got nil subcommand")
}
if nOpts := len(subCmd.Options); nOpts != 1 {
t.Fatalf("subcommand has %v options, expected 1", nOpts)
}
opt := subCmd.Options[0]
if nNames := len(opt.Names()); nNames != 2 {
t.Fatalf("option has %v names, expected 2", nNames)
}
names := opt.Names()
if names[0] != "test" {
t.Fatalf("option has name %q, expected %q", names[0], "test")
}
if names[1] != "t" {
t.Fatalf("option has name %q, expected %q", names[1], "t")
}
}
func TestPipePair(t *testing.T) {
cmd := NewCommand(&oldcmds.Command{Type: "string"})
req, err := cmds.NewRequest(context.TODO(), nil, nil, nil, nil, cmd)
if err != nil {
t.Fatal(err)
}
r, w := io.Pipe()
re, err := cmds.NewWriterResponseEmitter(w, req)
if err != nil {
t.Fatal(err)
}
res, err := cmds.NewReaderResponse(r, req)
if err != nil {
t.Fatal(err)
}
wait := make(chan interface{})
expect := "abc"
go func() {
err := re.Emit(expect)
if err != nil {
t.Fatal(err)
}
err = re.Close()
if err != nil {
t.Fatal(err)
}
close(wait)
}()
v, err := res.Next()
if err != nil {
t.Fatal(err)
}
str, ok := v.(*string)
if !ok {
t.Fatalf("expected type %T but got %T", expect, v)
}
if *str != expect {
t.Fatalf("expected value %#v but got %#v", expect, v)
}
_, err = res.Next()
if err != io.EOF {
t.Fatal("expected io.EOF, got:", err)
}
<-wait
}
func TestChanPair(t *testing.T) {
cmd := NewCommand(&oldcmds.Command{Type: "string"})
req, err := cmds.NewRequest(context.TODO(), nil, nil, nil, nil, cmd)
if err != nil {
t.Fatal(err)
}
re, res := cmds.NewChanResponsePair(req)
wait := make(chan interface{})
expect := "abc"
go func() {
err := re.Emit(expect)
if err != nil {
t.Fatal(err)
}
err = re.Close()
if err != nil {
t.Fatal(err)
}
close(wait)
}()
v, err := res.Next()
if err != nil {
t.Fatal(err)
}
str, ok := v.(string)
if !ok {
t.Fatalf("expected type %T but got %T", expect, v)
}
if str != expect {
t.Fatalf("expected value %#v but got %#v", expect, v)
}
_, err = res.Next()
if err != io.EOF {
t.Fatal("expected io.EOF, got:", err)
}
<-wait
}

View File

@ -1,196 +0,0 @@
package legacy
import (
"context"
"fmt"
"io"
"os"
"reflect"
files "gx/ipfs/QmZMWMvWMVKCbHetJ4RgndbuEF1io2UpUxwQwtNjtYPzSC/go-ipfs-files"
"gx/ipfs/Qma6uuSyjkecGhMFFLfzyJDPyoDtNJSHJNweDccZhaWkgU/go-ipfs-cmds"
"gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
oldcmds "github.com/ipfs/go-ipfs/commands"
)
// requestWrapper implements a oldcmds.Request from an Request
type requestWrapper struct {
req *cmds.Request
ctx *oldcmds.Context
}
func (r *requestWrapper) String() string {
return fmt.Sprintf("{%v, %v}", r.req, r.ctx)
}
func (r *requestWrapper) GoString() string {
return fmt.Sprintf("lgc.Request{%#v, %#v}", r.req, r.ctx)
}
// InvocContext retuns the invocation context of the oldcmds.Request.
// It is faked using OldContext().
func (r *requestWrapper) InvocContext() *oldcmds.Context {
return r.ctx
}
// SetInvocContext sets the invocation context. First the context is converted
// to a Context using NewContext().
func (r *requestWrapper) SetInvocContext(ctx oldcmds.Context) {
r.ctx = &ctx
}
// Command is an empty stub.
func (r *requestWrapper) Command() *oldcmds.Command { return nil }
func (r *requestWrapper) Arguments() []string {
cmdArgs := r.req.Command.Arguments
reqArgs := r.req.Arguments
// TODO figure out the exaclt policy for when to use these automatically
// TODO once that's done, change the log.Debug below to log.Error
// read arguments from body if we don't have all of them or the command has variadic arguemnts
if len(reqArgs) < len(cmdArgs) ||
len(cmdArgs) > 0 && cmdArgs[len(cmdArgs)-1].Variadic {
err := r.req.ParseBodyArgs()
if err != nil {
log.Debug("error reading arguments from stdin: ", err)
}
}
return r.req.Arguments
}
func (r *requestWrapper) Context() context.Context {
return r.req.Context
}
func (r *requestWrapper) ConvertOptions() error {
return convertOptions(r.req)
}
func (r *requestWrapper) Files() files.File {
return r.req.Files
}
func (r *requestWrapper) Option(name string) *cmdkit.OptionValue {
var option cmdkit.Option
optDefs, err := r.req.Root.GetOptions(r.req.Path)
if err != nil {
return &cmdkit.OptionValue{}
}
for _, def := range optDefs {
for _, optName := range def.Names() {
if name == optName {
option = def
break
}
}
}
if option == nil {
return nil
}
// try all the possible names, break if we find a value
for _, n := range option.Names() {
val, found := r.req.Options[n]
if found {
return &cmdkit.OptionValue{
Value: val,
ValueFound: found,
Def: option,
}
}
}
return &cmdkit.OptionValue{
Value: option.Default(),
ValueFound: false,
Def: option,
}
}
func (r *requestWrapper) Options() cmdkit.OptMap {
return r.req.Options
}
func (r *requestWrapper) Path() []string {
return r.req.Path
}
func (r *requestWrapper) SetArguments(args []string) {
r.req.Arguments = args
}
func (r *requestWrapper) SetFiles(f files.File) {
r.req.Files = f
}
func (r *requestWrapper) SetOption(name string, v interface{}) {
r.req.SetOption(name, v)
}
func (r *requestWrapper) SetOptions(om cmdkit.OptMap) error {
r.req.Options = om
return convertOptions(r.req)
}
func (r *requestWrapper) Stdin() io.Reader {
return os.Stdin
}
func (r *requestWrapper) StringArguments() []string {
return r.req.Arguments
}
func (r *requestWrapper) Values() map[string]interface{} {
return nil
}
// copied from go-ipfs-cmds/request.go
func convertOptions(req *cmds.Request) error {
optDefSlice := req.Command.Options
optDefs := make(map[string]cmdkit.Option)
for _, def := range optDefSlice {
for _, name := range def.Names() {
optDefs[name] = def
}
}
for k, v := range req.Options {
opt, ok := optDefs[k]
if !ok {
continue
}
kind := reflect.TypeOf(v).Kind()
if kind != opt.Type() {
if str, ok := v.(string); ok {
val, err := opt.Parse(str)
if err != nil {
value := fmt.Sprintf("value %q", v)
if len(str) == 0 {
value = "empty value"
}
return fmt.Errorf("could not convert %q to type %q (for option %q)",
value, opt.Type().String(), "-"+k)
}
req.Options[k] = val
} else {
return fmt.Errorf("option %q should be type %q, but got type %q",
k, opt.Type().String(), kind.String())
}
}
for _, name := range opt.Names() {
if _, ok := req.Options[name]; name != k && ok {
return fmt.Errorf("duplicate command options were provided (%q and %q)",
k, name)
}
}
}
return nil
}

View File

@ -1,207 +0,0 @@
package legacy
import (
"context"
"io"
"os"
"reflect"
"sync"
"gx/ipfs/Qma6uuSyjkecGhMFFLfzyJDPyoDtNJSHJNweDccZhaWkgU/go-ipfs-cmds"
"gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
oldcmds "github.com/ipfs/go-ipfs/commands"
)
// responseWrapper wraps Response and implements olcdms.Response.
// It embeds a Response so some methods are taken from that.
type responseWrapper struct {
cmds.Response
out interface{}
}
// Request returns a (faked) oldcmds.Request
func (rw *responseWrapper) Request() oldcmds.Request {
return &requestWrapper{rw.Response.Request(), nil}
}
// Output returns either a <-chan interface{} on which you can receive the
// emitted values, or an emitted io.Reader
func (rw *responseWrapper) Output() interface{} {
//if not called before
if rw.out == nil {
// get first emitted value
x, err := rw.Next()
if err != nil {
ch := make(chan interface{})
log.Error(err)
close(ch)
return (<-chan interface{})(ch)
}
if e, ok := x.(*cmdkit.Error); ok {
ch := make(chan interface{})
log.Error(e)
close(ch)
return (<-chan interface{})(ch)
}
switch v := x.(type) {
case io.Reader:
// if it's a reader, set it
rw.out = v
case cmds.Single:
rw.out = v.Value
default:
// if it is something else, create a channel and copy values from next in there
ch := make(chan interface{})
rw.out = (<-chan interface{})(ch)
go func() {
defer close(ch)
ch <- v
for {
v, err := rw.Next()
if err == io.EOF || err == context.Canceled {
return
}
if err != nil {
log.Error(err)
return
}
ch <- v
}
}()
}
}
// if we have it already, return existing value
return rw.out
}
// SetError is an empty stub
func (rw *responseWrapper) SetError(error, cmdkit.ErrorType) {}
// SetOutput is an empty stub
func (rw *responseWrapper) SetOutput(interface{}) {}
// SetLength is an empty stub
func (rw *responseWrapper) SetLength(uint64) {}
// SetCloser is an empty stub
func (rw *responseWrapper) SetCloser(io.Closer) {}
// Close is an empty stub
func (rw *responseWrapper) Close() error { return nil }
// Marshal is an empty stub
func (rw *responseWrapper) Marshal() (io.Reader, error) { return nil, nil }
// Reader is an empty stub
func (rw *responseWrapper) Reader() (io.Reader, error) { return nil, nil }
// Stdout returns os.Stdout
func (rw *responseWrapper) Stdout() io.Writer { return os.Stdout }
// Stderr returns os.Stderr
func (rw *responseWrapper) Stderr() io.Writer { return os.Stderr }
// fakeResponse implements oldcmds.Response and takes a ResponseEmitter
type fakeResponse struct {
req oldcmds.Request
re cmds.ResponseEmitter
out interface{}
wait chan struct{}
once sync.Once
}
// Send emits the value(s) stored in r.out on the ResponseEmitter
func (r *fakeResponse) Send(errCh chan<- error) {
defer close(errCh)
out := r.Output()
// don't emit nil or Single{nil}
if out == nil || out == (cmds.Single{Value: nil}) {
return
}
errCh <- r.re.Emit(out)
return
}
// Request returns the oldcmds.Request that belongs to this Response
func (r *fakeResponse) Request() oldcmds.Request {
return r.req
}
// SetError forwards the call to the underlying ResponseEmitter
func (r *fakeResponse) SetError(err error, code cmdkit.ErrorType) {
defer r.once.Do(func() { close(r.wait) })
r.re.CloseWithError(cmdkit.Errorf(code, err.Error()))
}
// Error is an empty stub
func (r *fakeResponse) Error() *cmdkit.Error {
return nil
}
// SetOutput sets the output variable to the passed value
func (r *fakeResponse) SetOutput(v interface{}) {
t := reflect.TypeOf(v)
_, isReader := v.(io.Reader)
if t != nil && t.Kind() != reflect.Chan && !isReader {
v = cmds.Single{Value: v}
}
r.out = v
r.once.Do(func() { close(r.wait) })
}
// Output returns the output variable
func (r *fakeResponse) Output() interface{} {
<-r.wait
return r.out
}
// SetLength forwards the call to the underlying ResponseEmitter
func (r *fakeResponse) SetLength(l uint64) {
r.re.SetLength(l)
}
// Length is an empty stub
func (r *fakeResponse) Length() uint64 {
return 0
}
// Close forwards the call to the underlying ResponseEmitter
func (r *fakeResponse) Close() error {
return r.re.Close()
}
// SetCloser is an empty stub
func (r *fakeResponse) SetCloser(io.Closer) {}
// Reader is an empty stub
func (r *fakeResponse) Reader() (io.Reader, error) {
return nil, nil
}
// Marshal is an empty stub
func (r *fakeResponse) Marshal() (io.Reader, error) {
return nil, nil
}
// Stdout returns os.Stdout
func (r *fakeResponse) Stdout() io.Writer {
return os.Stdout
}
// Stderr returns os.Stderr
func (r *fakeResponse) Stderr() io.Writer {
return os.Stderr
}

View File

@ -1,7 +1,6 @@
package commands
import (
"strings"
"sync"
"time"
)
@ -34,22 +33,6 @@ type ReqLog struct {
keep time.Duration
}
// Add creates a ReqLogEntry from a request and adds it to the log
func (rl *ReqLog) Add(req Request) *ReqLogEntry {
rle := &ReqLogEntry{
StartTime: time.Now(),
Active: true,
Command: strings.Join(req.Path(), "/"),
Options: req.Options(),
Args: req.StringArguments(),
ID: rl.nextID,
log: rl,
}
rl.AddEntry(rle)
return rle
}
// AddEntry adds an entry to the log
func (rl *ReqLog) AddEntry(rle *ReqLogEntry) {
rl.lock.Lock()

View File

@ -1,55 +0,0 @@
package commands
import (
"io"
cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
)
// ErrorType signfies a category of errors
type ErrorType uint
// EncodingType defines a supported encoding
type EncodingType string
// Supported EncodingType constants.
const (
JSON = "json"
XML = "xml"
Protobuf = "protobuf"
Text = "text"
// TODO: support more encoding types
)
// Response is the result of a command request. Handlers write to the response,
// setting Error or Value. Response is returned to the client.
type Response interface {
Request() Request
// Set/Return the response Error
SetError(err error, code cmdkit.ErrorType)
Error() *cmdkit.Error
// Sets/Returns the response value
SetOutput(interface{})
Output() interface{}
// Sets/Returns the length of the output
SetLength(uint64)
Length() uint64
// underlying http connections need to be cleaned up, this is for that
Close() error
SetCloser(io.Closer)
// Marshal marshals out the response into a buffer. It uses the EncodingType
// on the Request to chose a Marshaler (Codec).
Marshal() (io.Reader, error)
// Gets a io.Reader that reads the marshalled output
Reader() (io.Reader, error)
// Gets Stdout and Stderr, for writing to console without using SetOutput
Stdout() io.Writer
Stderr() io.Writer
}

View File

@ -28,7 +28,7 @@ func GetApi(env cmds.Environment) (coreiface.CoreAPI, error) {
return nil, fmt.Errorf("expected env to be of type %T, got %T", ctx, env)
}
return ctx.GetApi()
return ctx.GetAPI()
}
// GetConfig extracts the config from the environment.